среда, 30 октября 2013 г.

Памятка разработчикам Android NDK

В этом посте постараюсь собрать ответы на основные вопросы, возникающие при разработке на С++ для андройда (пост будет обновляться).

Как написать в лог из С++?

#include
__android_log_print(ANDROID_LOG_VERBOSE, "my_application name", "Hello, %s !", "android");

В Android.mk:

LOCAL_LDLIBS := -llog

суббота, 14 сентября 2013 г.

Просто об Android NDK

Иногда у разработчиков Android-приложений возникает необходимость писать часть кода не на Java, а на C\C++. Для этого нам помимо Android SDK понадобиться Android NDK (Native Development Kit).
Итак:

1.Скачиваем Android NDK. http://developer.android.com/tools/sdk/ndk/index.html
2.Распаковываем
3.В проект добавляем два новых файла - Android.mk и hello.c. В первом будут храниться настройки сборки, его содержание должно быть таким:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello
LOCAL_SRC_FILES := hello.c


include $(BUILD_SHARED_LIBRARY)
А в файле hello.c:

#include
#include
jstring Java_com_example_hellojni_MainActivity_helloFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    return (env)->NewStringUTF("I am from C Language!");
}

В данном случае имя функции строится так: Java_<название пакета>_<имя класса откуда будет вызываться функция>_<имя функции>.
4.Теперь в нашем классе (например, MainActivity.java) пишем:
public native int helloFromJNI();

static {
System.loadLibrary("hello");
}
5. Затем собираем наш нативный код: 
cd <папка с проектом>
<путь к ndk>/ndk-build


Всё! Осталось собрать и запустить Android-приложение из Eclipse, как если бы оно было обычным Java-приложением=)

воскресенье, 21 апреля 2013 г.

"Контракту требуется свойство Duplex, однако..." (WCF)

Известно, что технология WCF (Windows Communication Foundation) поддерживает дуплексный режим общения сервера с клиентом. В таком случае не только клиент может обращаться к функциям сервера, но и сервер может вызывать функции на машине клиента. И если в обычном случае перед объявлением интерфейса контракта мы пишем аттрибут [Service Contract], то для дуплексного соединения нам необходимо написать что-то подобное:[ServiceContract(CallbackContract = typeof(IDuplexCallback))]
IDuplexCallback - это имя класса, обеспечивающего обратный вызов, его объявление аналогично объявлению других контрактов.
Однако, думаю, что у многих при попытке обновить Service Reference возникало сообщение вроде:
 "Контракту требуется свойство Duplex, однако привязка "BasicHttpBinding" его не поддерживает или этого не позволяет неправильная настройка."

Например, так:



Известно, что BasicHttpBinding не поддерживает дуплекс, нам нужен другой тип биндинга - wsDualHttpBinding. Открываем файл web.config (в проекте сервера - например, WCF Application и др.) Вот как он выглядит у меня:
Видимо, главное здесь - описать endpoint`ы.  Параметр binding имеет нужный нам тип - wsDualHttpBinding.
Вместо названия контракта (contract) duplexWCF.IDuplexService подставьте имя своего интерфейса-контракта, а вместо названия сервиса (service name) duplexWCF.DuplexService имя класса-реализации интерфейса-контракта (возможно, есть и другие варианты, но этот работает =) ). Endpoint MetaDataTcpEndpoint так же и оставляем - видимо, он нужен для получения каких-либо метаданных.
Обновляем Service Reference - работает =)

На сервере доступ к классу реализации функций обратной связи можно следующим способом:
OperationContext.Current.GetCallbackChannel();
IDuplexCallback - интерфейс класса обратной связи.
Возникает вопрос - а если клиентов несколько?  В таком случае эта функция при вызове серверной функции будет возвращать экземпляр класса того клиента, который производит вызов серверной функции. Нам остается только их хранить, например, в списке.

Теперь о клиентской реализации. Просто так объявить экземпляр сервиса-контракта не получится - ему нужно будет передать ссылку на нашу реализацию класса обратной связи.
Так что наследуемся от интерфейса и пишем нечто вроде:



Вот и всё)
Возможно, кому-нибудь поможет.

среда, 27 марта 2013 г.

Пишем в USART на STM32F3

Какое-то время я работал с STM32F100, однако стало необходимо освоить STM32F3.
Вот код инициализации всех USART-ов, если кому необходимо :)


void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
    /* enable usart clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_7);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7);

 
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_Init(USART1, &USART_InitStructure);

    USART_Cmd(USART1, ENABLE);

    NVIC_EnableIRQ(USART1_IRQn);
}
void USART2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
    /* enable usart clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_7);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_7);
   
 
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_Init(USART2, &USART_InitStructure);

    USART_Cmd(USART2, ENABLE);

    NVIC_EnableIRQ(USART2_IRQn);
}
void USART3_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
    /* enable usart clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

 
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_7);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_7);

 
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_Init(USART3, &USART_InitStructure);

    USART_Cmd(USART3, ENABLE);

    NVIC_EnableIRQ(USART3_IRQn);
}
void UART4_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
    /* enable usart clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

 
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_5);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_5);

 
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_Init(UART4, &USART_InitStructure);

    USART_Cmd(UART4, ENABLE);

    NVIC_EnableIRQ(UART4_IRQn);
}
void UART5_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStructureC,GPIO_InitStructureD;
 USART_InitTypeDef USART_InitStructure;
    /* enable usart clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
 
    GPIO_InitStructureC.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructureC.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructureC.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructureC.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructureC.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructureC);

GPIO_InitStructureD.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructureD.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructureD.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructureD.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructureD.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &GPIO_InitStructureD);
 

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_5);
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_5);

 
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.USART_BaudRate = 9600;
    USART_Init(UART5, &USART_InitStructure);

    USART_Cmd(UART5, ENABLE);

    NVIC_EnableIRQ(UART5_IRQn);
}

Записываем так:
void USART1putc(const char ch)
{
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, ch);
}
(конечно же, меняем номер порта на необходимый).
Чтение, скорее всего, аналогично.

вторник, 26 февраля 2013 г.

Робот "STAR"


Ученые Калифорнийского университета Беркли разработали шестиногого бионического робота длиной в 12 сантиметров. Ему дали имя "STAR", что означает "Sprawl Tuned Autonomous Robot" (на русский можно перевести как "автономный робот с настраиваемым раскидыванием"). Робот может растягивать свои конечности под разными углами, чтобы приспосабливаться к различным типам поверхностей. 
"С помощью своих конечностей робот может достичь высокой производительности при передвижении через неровные поверхности и препятствия, раскинув свои конечности под большим углом; и достичь производительности подобной колесным роботам на гладкой поверхности, растянувшись на небольшой угол. Изменив угол раскидывания, он может карабкаться через препятствия либо ползти под ними. "STAR" может двигаться со скоростью 5.2 метров в секунду (43 длины корпуса в секунду, число Фруда -  9.8) по гладкой поверхности, что делает его самым быстрым неуправляемым ползущим роботом." - сообщают нам в описании видео.

Оригинал здесь - робохаб.

понедельник, 4 февраля 2013 г.

STM32, UM6, SPI...

В сегодняшнем посте я опишу способ получения данных с платы навигации UM6 по протоколу SPI.
Вначале инициализация:

void SPI1_Init(void)
{
RCC->APB2ENR |=  RCC_APB2ENR_AFIOEN;     //включить тактирование льтернативных функций        /
RCC->APB2ENR |=  RCC_APB2ENR_IOPAEN;     //включить тактирование порта А
//вывод управления SS: выход двухтактный, общего назначения,50MHz                             /
GPIOA->CRL   |=  GPIO_CRL_MODE4;    //
GPIOA->CRL   &= ~GPIO_CRL_CNF4;     //
GPIOA->BSRR   =  GPIO_BSRR_BS4;     //

//вывод SCK: выход двухтактный, альтернативная функция, 50MHz
GPIOA->CRL   |=  GPIO_CRL_MODE5;    //
GPIOA->CRL   &= ~GPIO_CRL_CNF5;     //
GPIOA->CRL   |=  GPIO_CRL_CNF5_1;   //

//вывод MISO: вход цифровой с подтягивающим резистором, подтяжка к плюсу
GPIOA->CRL   &= ~GPIO_CRL_MODE6;    //
GPIOA->CRL   &= ~GPIO_CRL_CNF6;     //
GPIOA->CRL   |=  GPIO_CRL_CNF6_1;   //
GPIOA->BSRR   =  GPIO_BSRR_BS6;     //

//вывод MOSI: выход двухтактный, альтернативная функция, 50MHz
GPIOA->CRL   |=  GPIO_CRL_MODE7;    //
GPIOA->CRL   &= ~GPIO_CRL_CNF7;     //
GPIOA->CRL   |=  GPIO_CRL_CNF7_1;   //

RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; //подать тактирование                                      /
SPI1->CR1     = 0x0000;             //очистить первый управляющий регистр
SPI1->CR2     = 0x0000;             //очистить второй управляющий регистр
SPI1->CR1    |= SPI_CR1_MSTR;       //контроллер должен быть мастером  
SPI1->CR1    |= SPI_CR1_BR;         //задаем скорость
SPI1->CR1    |= SPI_CR1_SSI;        //обеспечить высокий уровень программного NSS
SPI1->CR1    |= SPI_CR1_SSM;        //разрешить программное формирование NSS
SPI1->CR1    |= SPI_CR1_SPE;        //разрешить работу модуля SPI
}
Инициализация взята с одного из сайтов про STM32, однако там не было указанного главного: для того, чтобы читать с этой платы, необходимо устанавливать SS в 0.

Пример получения регистра Yaw(0x63):

float getYaw()
{
u8 b3,b2,b1,b0,temp1,temp2;
short tempshort;
float angle;
GPIOA->BSRR   =  GPIO_BSRR_BR4;
temp1=send_spi1(0x00);
temp2=send_spi1(0x63);
b3=send_spi1(0x00);
b2=send_spi1(0x00);
b1=send_spi1(0x00);
b0=send_spi1(0x00);
GPIOA->BSRR   =  GPIO_BSRR_BS4;
        tempshot=(b3*256)+b2;// глюк блоггера, не могу опубликовать код со смещением
angle=tempshort*0.0109863;
return angle;
}
Функция send_spi1 (взята с одного из форумов по контроллерам) одновременно пишет и читает данные:

u8 send_spi1(u8 byte)
{
    unsigned char rxbyte;
    while (!(SPI1->SR & SPI_SR_TXE));
    SPI1->DR = byte;
    while (!(SPI1->SR & SPI_SR_RXNE));
    rxbyte = SPI1->DR;
    return rxbyte;
}



среда, 23 января 2013 г.

Простой способ работы с I2C в STM32. Часть 2.

В предыдущем посте я кратко описал простой способ работы с протоколом I2C в STM32.
В этом сообщении я добавил несколько ссылок на необходимые файлы и документацию, а также код-примере работы с 
платой Pololu MinIMU-9.

1. Итак, для начала качаем AN2824 "STM32F101xx and STM32F103xx medium- and high-density devices: advanced I²C examples", он же "STM32F10xxx I2C optimized examples" вот отсюда.
Скаченный файл представляет собой архив с примерами работы по протоколу I2C. Распаковываем архив. Если у вас Keil, то вам необходим файл "папка_куда_вы_распаковали_архив\STM32F10x_AN2824_FW_V4.0.0\Project\OptimizedI2Cexamples\MDK-ARM\Optimized I2C examples.uvproj".

Документация здесь.

В файле main.c  находим следующий код.

2. Важные для нас функции:
I2C_LowLevel_Init(I2C1); - инициализируем I2C1 или I2C2
I2C_Master_BufferWrite(I2C1, Buffer_Tx1,1,Interrupt, _ADDRESS); - записываем данные из буфера. 
I2C_Master_BufferRead(I2C1,Buffer_Rx1,1,Polling, _ADDRESS); - читаем данные в буфер.


Читать или писать мы можем тремя способами - Interrupt, Polling или DMA. Все эти функции описываются и реализуются в файлах I2CRoutines.h и I2CRoutines.с (можно посмотреть код реализации).

3. А вот, собственно, и функции для работы с гироскопом, акселерометром и магнитометром. Вначале устройства инициализируются, затем происходит чтение данных в переменные x,y,z. 
Вот и сам код: http://pastebin.com/70rhVxNF