
this is a new program based on BLE_Uart_Peripheral. Change program name due to relation Client&Peripheral to Client&Server
Dependencies: RingBuffer nRF51_Vdd nRF51_WakeUp
This is a BLE Server (Device) program for nRF51.
You can communicate with mbed BLE using "BLE_Uart_Client" program as follows.
/users/kenjiArai/code/BLE_Uart_Client/
Please refer following my notebook.
/users/kenjiArai/notebook/ble-client-and-peripheral-using-switch-sience-ty51/#
Revision 6:16e1f9d065a3, committed 2017-10-22
- Comitter:
- kenjiArai
- Date:
- Sun Oct 22 09:47:18 2017 +0000
- Parent:
- 5:394920d6a82f
- Child:
- 7:0d94f4cf2a69
- Commit message:
- Run on Mbed-os5. Extend pc serial buffer. Delete low power related lib.
Changed in this revision
--- a/BLE_API.lib Mon Jun 13 09:54:32 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#66159681aa21
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RingBuffer.lib Sun Oct 22 09:47:18 2017 +0000 @@ -0,0 +1,1 @@ +http://os.mbed.com/users/ykuroda/code/RingBuffer/#ea6d02ba96ae
--- a/main.cpp Mon Jun 13 09:54:32 2016 +0000 +++ b/main.cpp Sun Oct 22 09:47:18 2017 +0000 @@ -15,7 +15,8 @@ */ /* - * ------- BLE Server UART function ------------------------------------------ + * ------- BLE Peripheral/Server UART function -------------------------------- + * communicate with BLE_UART_Client program * --- Tested on Switch Science mbed TY51822r3 --- * * http://www.page.sannet.ne.jp/kenjia/index.html @@ -23,160 +24,126 @@ * * Started: March 7th, 2016 * Revised: June 13th, 2016 + * Revised: October 22nd, 2017 Run on mbed-OS-5.6.2 * * Original program: * BLE_LoopbackUART - * https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_LoopbackUART/ + * https://developer.mbed.org/teams/Bluetooth-Low-Energy/ + * code/BLE_LoopbackUART/ * Tested Controller Device: * BLE_Uart_Client * https://developer.mbed.org/users/kenjiArai/code/BLE_Uart_Client/ - * */ -// Include --------------------------------------------------------------------------------------- +// Include -------------------------------------------------------------------- #include "mbed.h" #include "BLE.h" #include "UARTService.h" #include "nRF51_Vdd.h" #include "nRF51_WakeUp.h" -#include "nRF51_lowpwr.h" +#include "RingBuffer.h" + +// Definition ----------------------------------------------------------------- +#define NUM_ONCE 20 +#define BFSIZE (NUM_ONCE+4) -// Definition ------------------------------------------------------------------------------------ -// Before using this function, please specify your program are used following functions or not. -#define USE_DEVICE_STDIO_MESSAGES 0 // printf -#define USE_DEVICE_SERIAL 1 // Serial or DEBUG & etc. -#define USE_DEVICE_I2C 0 // Sensors with I2C, LCD, EEPROM, Driver chips & etc. -#define USE_DEVICE_SPI 0 // Sensors with SPI, LCD, EEPROM, Driver chips & etc. -#define USE_DEVICE_SPISLAVE 0 // Communication with master vis SPI -#define USE_DEVICE_PWMOUT 0 // PWM duty output, Serve & etc. -#define USE_DEVICE_ANALOGIN 0 // Analog adc - -#define GOTO_SLEEP_MODE 0 // If you set 1, you need to connected LED1 and P0_0 - // Please refer nRF51_WakeUP library - -#if USE_DEVICE_STDIO_MESSAGES +// If you set 1, you need to connected LED1 and P_0 +// Please refer nRF51_WakeUP library +#define GOTO_SLEEP_MODE 0 + +//#define USE_DEBUG_MODE +#ifdef USE_DEBUG_MODE #define DEBUG(...) { printf(__VA_ARGS__); } #else #define DEBUG(...) #endif -// Object ---------------------------------------------------------------------------------------- +// Object --------------------------------------------------------------------- BLE ble; DigitalOut connectedLED(LED2); InterruptIn wake_up_sw(P0_1); nRF51_WakeUp wakeup(LED1, P0_0); nRF51_Vdd vdd(3.0f, 2.2f); -Serial pc(USBTX, USBRX); +Serial pc(USBTX, USBRX, 115200); UARTService *uartServicePtr; Ticker ticker; +RingBuffer ser_bf(1024); +Thread tsk; +Mutex bletx_mutex; -// ROM / Constant data --------------------------------------------------------------------------- +// ROM / Constant data -------------------------------------------------------- #warning "You need to confirm your device name." -const static char DEVICE_NAME[] = "UART_S"; -const nRF51_LOWPWR_TypeDef lowpwr_table = - { - #if USE_DEVICE_STDIO_MESSAGES - true, - #else - false, - #endif - #if USE_DEVICE_SERIAL - true, - #else - false, - #endif - #if USE_DEVICE_I2C - true, - #else - false, - #endif - #if USE_DEVICE_SPI - true, - #else - false, - #endif - #if USE_DEVICE_SPISLAVE - true, - #else - false, - #endif - #if USE_DEVICE_PWMOUT - true, - #else - false, - #endif - #if USE_DEVICE_ANALOGIN - true - #else - false - #endif - }; +const static char DEVICE_NAME[] = "UART_S"; -// RAM ------------------------------------------------------------------------------------------- -Gap::Address_t my_mac; -uint8_t tx_buf[24]; -uint8_t tx_len = 0; -uint8_t rx_buf[24]; -uint8_t rx_len = 0; -volatile bool trigger_transmit = false; -volatile bool trigger_receive = false; -volatile uint8_t command_continue = 0; -uint16_t time_out_cntr = 3600; -volatile bool time_out = false; -bool line_input = false; -uint8_t linebuf_irq[24]; -int linebf_irq_len = 0; -uint8_t linebuf[24]; -int linebf_len = 0; -uint32_t sleep_time = 30; // unit:second +// RAM ------------------------------------------------------------------------ +Gap::Address_t my_mac; +uint8_t tx_buf[BFSIZE]; +uint8_t tx_len = 0; +uint8_t rx_buf[BFSIZE]; +volatile bool trigger_transmit = false; +volatile bool trigger_receive = false; +volatile uint8_t command_continue = 0; +uint16_t time_out_cntr = 3600; +volatile bool time_out = false; +uint32_t sleep_time = 30; // unit:second +volatile bool rx_isr_busy = false; -// Function prototypes --------------------------------------------------------------------------- +// Function prototypes -------------------------------------------------------- // BLE -void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params); -void onDataWritten(const GattWriteCallbackParams *params); -void periodicCallback(void); +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *); +void onDataWritten_action(const GattWriteCallbackParams *); +// Tasks +void pc_ser_rx(void); +void data_from_ble(void); +void Update_Values(void); // Application related -void adjust_line(uint8_t *bf); +void command(uint8_t *cmd); void action_tx_help(void); void action_tx_vdd(void); void action_tx_temperature(void); -void action_tx_wait_time(void); -void fill_space_n(uint8_t *bf, uint8_t n); -void Update_Values(void); -int xatoi (char **str, int32_t *res); +void action_tx_wait_time(uint8_t *); +void action_tx_quit(void); +int xatoi (char **, int32_t *); +void adjust_line(uint8_t *); // Interrupt related -void action_tx_quit(void); void interrupt_by_sw(void); void serialRxCallback(void); +void periodicCallback(void); -//------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------ // Control Program -//------------------------------------------------------------------------------------------------- -int main(void){ - LowPwr set_lowpwr(&lowpwr_table); +//------------------------------------------------------------------------------ +int main(void) +{ connectedLED = 0; pc.attach(&serialRxCallback, Serial::RxIrq); ticker.attach(periodicCallback, 1); - for (int k = 0; k < 20; k++) { pc.printf("\r\n");} // clear terminal output - pc.printf("UART Communication / Server side\r\n"); // opening message - pc.printf(" Client(Central) and Server(Peripheral)\r\n"); // opening message + tsk.start(pc_ser_rx); + // clear terminal output + for (int k = 0; k < 5; k++) { pc.printf("\r\n");} + // opening message + pc.printf("UART Communication / Server(Peripheral) side\r\n"); + pc.printf(" need Client module (run BLE_Uart_Client program)\r\n"); // Interrupt by switch wake_up_sw.fall(&interrupt_by_sw); ble.init(); Gap::AddressType_t my_mac_type; ble.gap().getAddress(&my_mac_type, my_mac); - pc.printf( + DEBUG( " my_MAC %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n", my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0], (my_mac_type == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random" ); pc.printf( - " mac_board_? = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x};\r\n", + " mac_board_n = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x};\r\n", my_mac[0], my_mac[1], my_mac[2], my_mac[3], my_mac[4], my_mac[5] ); - pc.printf(" Please write above mac_board_?(?=1,2,...) data into Client main.cpp\r\n"); + pc.printf( + " Please write above data(mac_board_n line) into mac_board_0\r\n"); + pc.printf( + " or follows(n=1,2,...)) in Client/main.cpp\r\n"); ble.onDisconnection(disconnectionCallback); - ble.onDataWritten(onDataWritten); + ble.onDataWritten(onDataWritten_action); /* setup advertising */ ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED); ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); @@ -205,38 +172,29 @@ } #endif } - if (line_input){ - line_input = false; - adjust_line(linebuf); - ble.updateCharacteristicValue( - uartServicePtr->getRXCharacteristicHandle(), - linebuf, - 20 - ); - } if (trigger_transmit){ + static uint8_t cmd_buf[BFSIZE]; + static volatile bool flag_continue = 0; trigger_transmit = false; - pc.printf("%s\r\n", rx_buf); - if ((rx_buf[0] == '*') || (rx_buf[0] == '&')){ - switch (rx_buf[1]){ - case 'v': - action_tx_vdd(); - break; - case 't': - action_tx_temperature(); - break; - case 'q': - action_tx_quit(); - break; - case 'w': - action_tx_wait_time(); - break; - case 'h': - case '?': - action_tx_help(); - break; - default: - break; + pc.printf((const char*)rx_buf); + if (flag_continue == true){ + strcat((char *)cmd_buf, (char *)rx_buf); + if (strchr((const char*)cmd_buf,(int)'\r') == 0){ + flag_continue = true; + } else { + command(cmd_buf); + for(uint8_t i = 0; i < BFSIZE; i++){ cmd_buf[i] = 0;} + flag_continue = false; + } + } + if ((rx_buf[0] == '~')){ + strcpy((char *)cmd_buf, (char *)rx_buf); + if (strchr((const char*)cmd_buf,(int)'\r') == 0){ + flag_continue = true; + } else { + command(cmd_buf); + for(uint8_t i = 0; i < BFSIZE; i++){ cmd_buf[i] = 0;} + flag_continue = false; } } } @@ -244,109 +202,243 @@ } } -void serialRxCallback(){ - char c = pc.getc(); - if (c == '\r') { - linebuf_irq[linebf_irq_len++] = c; - pc.printf("\r\n"); - linebf_len = linebf_irq_len; - strcpy((char *)linebuf, (char *)linebuf_irq); - linebf_irq_len = 0; - line_input = true; - } else if ((c == '\b') && linebf_irq_len) { - linebf_irq_len--; - pc.putc(c); - pc.putc(' '); - pc.putc(c); - } else if (((uint8_t)c >= ' ') && (linebf_irq_len < 20)) { - linebuf_irq[linebf_irq_len++] = c; - pc.putc(c); - } else if ( c == 0x1f ){ // Control+? - SCB->AIRCR = 0x05fa0004; // System RESET!! +void command(uint8_t *cmd) +{ + uint8_t *p = cmd; + + while(*p == ' '){ ++p;} // skip space + if (*p++ == '~'){ + while(*p < '!'){ ++p;} // skip space + uint8_t c = *p; + //pc.printf("c=%c\r\n", c); + switch (c){ + case 'v': + action_tx_vdd(); + break; + case 't': + action_tx_temperature(); + break; + case 'q': + action_tx_quit(); + break; + case 'w': + action_tx_wait_time(cmd); + break; + case 'h': + case '?': + action_tx_help(); + break; + default: + //pc.printf("\r\nStep(%u)\r\n", __LINE__); + break; + } } - linebuf_irq[linebf_irq_len] = 0; +} + +void periodicCallback(void) +{ +#if GOTO_SLEEP_MODE + if (--time_out_cntr == 0){ + time_out = true; + } +#endif + if (rx_isr_busy == true){ + rx_isr_busy = false; + } else { + tsk.signal_set(0x01); + } +} + +void serialRxCallback() +{ + ser_bf.save(pc.getc()); + rx_isr_busy = true; + tsk.signal_set(0x01); } -void adjust_line(uint8_t *bf){ +void pc_ser_rx() +{ + static uint8_t linebf_irq[BFSIZE]; + static volatile uint8_t linebf_irq_len = 0; + + while(true){ + Thread::signal_wait(0x01); + if (ser_bf.check() == 0){ + if (linebf_irq_len != 0){ + linebf_irq[linebf_irq_len] = 0; + adjust_line(linebf_irq); + linebf_irq_len = 0; + bletx_mutex.lock(); + ble.updateCharacteristicValue( + uartServicePtr->getRXCharacteristicHandle(), + linebf_irq, + NUM_ONCE + ); + bletx_mutex.unlock(); + } + } + while(ser_bf.check() != 0){ + char c = ser_bf.read(); + if (c == '\b'){ + linebf_irq_len--; + pc.putc(c); + pc.putc(' '); + pc.putc(c); + } else if ((c >= ' ') || (c == '\r') || (c == '\n')){ + bool overflow = false; + if ((c == '\r') || (c == '\n')) { + if (linebf_irq_len == NUM_ONCE - 1){// remain only 1 buffer + overflow = true; + linebf_irq[linebf_irq_len++] = '\r'; + pc.putc('\r'); + } else { + overflow = false; + linebf_irq[linebf_irq_len++] = '\r'; + linebf_irq[linebf_irq_len++] = '\n'; + pc.printf("\r\n"); + } + } else { + linebf_irq[linebf_irq_len++] = c; + pc.putc(c); + } + if (linebf_irq_len >= NUM_ONCE ){ + linebf_irq[linebf_irq_len] = 0; + adjust_line(linebf_irq); + linebf_irq_len = 0; + bletx_mutex.lock(); + ble.updateCharacteristicValue( + uartServicePtr->getRXCharacteristicHandle(), + linebf_irq, + NUM_ONCE + ); + bletx_mutex.unlock(); + if (overflow == true){ + overflow = false; + linebf_irq[linebf_irq_len++] = '\n'; + pc.putc('\n'); + } + } + } + } + } +} + +void adjust_line(uint8_t *bf) +{ uint8_t i, c; - for (i = 0; i <20; bf++, i++){ + for (i = 0; i <NUM_ONCE; bf++, i++){ c = *bf; - if ( (c == '\r') || (c == '\n') || (c == 0)){ - break; - } + if (c == 0){ break;} } - for (; i < 20; bf++, i++){ - *bf = ' '; - } + for (; i < NUM_ONCE; bf++, i++){ *bf = 0x11;} *(bf + 1) = 0; } -void onDataWritten(const GattWriteCallbackParams *params){ +void onDataWritten_action(const GattWriteCallbackParams *params) +{ if ((uartServicePtr != NULL) && (params->handle == uartServicePtr->getTXCharacteristicHandle())) { strcpy((char *)rx_buf, (const char *)params->data); - rx_len = params->len; trigger_transmit = true; - DEBUG("RX_data\r\n"); - DEBUG("Length: %d\r\n", rx_len); - DEBUG("Data: "); - DEBUG("%s", rx_buf); - DEBUG("\r\n"); } } -void action_tx_help(){ +void action_tx_help() +{ // 12345678901234567890 - sprintf((char *)tx_buf,"*? or &?:help"); + sprintf((char *)tx_buf," ~?:help\r\n"); tx_len = strlen((const char *)tx_buf); Update_Values(); wait(0.2); // 12345678901234567890 - sprintf((char *)tx_buf,"*v:vdd"); + sprintf((char *)tx_buf," ~v:vdd\r\n"); tx_len = strlen((const char *)tx_buf); Update_Values(); wait(0.2); // 12345678901234567890 - sprintf((char *)tx_buf,"*t:temperature"); + sprintf((char *)tx_buf," ~t:temperature\r\n"); tx_len = strlen((const char *)tx_buf); Update_Values(); wait(0.2); // 12345678901234567890 - sprintf((char *)tx_buf,"*w:wait time/ w 120"); + sprintf((char *)tx_buf," ~w:wait, w 120\r\n"); tx_len = strlen((const char *)tx_buf); Update_Values(); wait(0.2); // 12345678901234567890 - sprintf((char *)tx_buf,"*q:quit/sleep"); + sprintf((char *)tx_buf," ~q:quit/sleep\r\n"); tx_len = strlen((const char *)tx_buf); Update_Values(); wait(0.2); } -void action_tx_vdd(){ - sprintf((char *)tx_buf,"Vdd:%3.2fV", vdd.read_real_value()); +void action_tx_vdd() +{ + sprintf((char *)tx_buf,"Vdd: %3.2f V\r\n", vdd.read_real_value()); + tx_len = strlen((const char *)tx_buf); + Update_Values(); +} + +void action_tx_temperature() +{ + int32_t p_temp; + float temperature; + + // Update a temperature (inside nRF51822 chip) + sd_temp_get(&p_temp); + // -16.0f is offset vale for chip die temp + // to ambient temp (depend on your board) + temperature = float(p_temp) / 4; // Original = float(p_temp)/4.0f - 16.0f; + sprintf((char *)tx_buf,"T: %+4.1f dC\r\n", temperature); tx_len = strlen((const char *)tx_buf); Update_Values(); } -void action_tx_temperature(){ - int32_t p_temp; - float temperature; - - // Update a temperature (inside nRF51822 chip) - sd_temp_get(&p_temp); - // -16.0f is offset vale for chip die temp to ambient temp (depend on your board) - temperature = float(p_temp) / 4; // Original = float(p_temp)/4.0f - 16.0f; - sprintf((char *)tx_buf,"T:%+4.1fdC", temperature); +void action_tx_wait_time(uint8_t *cmd) +{ + int32_t dt; + char *p; + + p = (char *)(cmd); + p += 2; // point to time value + if (xatoi(&p, &dt)){ + if (dt <= 5){ dt = 5;} + sleep_time = dt; // set next wake-up period + } else { + DEBUG("data is unknown!\r\n"); + sleep_time = 30; + } + DEBUG("slp_t:%d\r\n", sleep_time); + //pc.printf("slp_t:%d\r\n", sleep_time); + // 12345678901234567890 + sprintf((char *)tx_buf, "W: %d sec\r\n", sleep_time); tx_len = strlen((const char *)tx_buf); Update_Values(); } +void action_tx_quit() +{ +#if GOTO_SLEEP_MODE + ticker.detach(); + // 12345678901234567890 + sprintf((char *)tx_buf,"Terminated the BLE"); + tx_len = strlen((const char *)tx_buf); + Update_Values(); + wait(1.0); + wakeup.set_and_wait(sleep_time); + while(true){ // never come here but just in case + deepsleep(); + } +#else + SCB->AIRCR = 0x05fa0004; // System RESET!! +#endif +} // Change string -> integer -int xatoi (char **str, int32_t *res){ +int xatoi (char **str, int32_t *res) +{ unsigned long val; unsigned char c, radix, s = 0; @@ -413,68 +505,28 @@ return 1; } -void action_tx_wait_time(){ - int32_t dt; - char *p; - - p = (char *)(rx_buf); - p += 2; // point to rx_buf[2] - if (xatoi(&p, &dt)){ - sleep_time = dt; // set next wake-up period - } else { - DEBUG("data is unknown!\r\n"); - } - DEBUG("slp_t:%d\r\n", sleep_time); - // 12345678901234567890 - sprintf((char *)tx_buf, "W=%d", sleep_time); - tx_len = strlen((const char *)tx_buf); - Update_Values(); +void interrupt_by_sw() // Go to sleep +{ + NVIC_SystemReset(); + // Not come here (Just in case) + sleep(); } -void action_tx_quit(){ -#if GOTO_SLEEP_MODE - ticker.detach(); - // 12345678901234567890 - sprintf((char *)tx_buf,"Terminated the BLE"); - tx_len = strlen((const char *)tx_buf); - Update_Values(); - wait(1.0); - wakeup.set_and_wait(sleep_time); - while(true){ // never come here but just in case - deepsleep(); - } -#else - SCB->AIRCR = 0x05fa0004; // System RESET!! -#endif -} - -void interrupt_by_sw(){ // Go to sleep - NVIC_SystemReset(); - // Not come here (Just in case) - deepsleep(); -} - -void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params){ +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) +{ DEBUG("Disconnected!\r\n"); DEBUG("Restarting the advertising process\r\n"); ble.startAdvertising(); } -void periodicCallback(void){ -#if GOTO_SLEEP_MODE - if (--time_out_cntr == 0){ - time_out = true; - } -#endif -} - -void Update_Values(void){ +void Update_Values(void) +{ + bletx_mutex.lock(); ble.updateCharacteristicValue( uartServicePtr->getRXCharacteristicHandle(), tx_buf, tx_len ); - DEBUG("TX_data: %s\r\n", tx_buf); - DEBUG("Length: %d\r\n", tx_len); + bletx_mutex.unlock(); tx_len = 0; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Sun Oct 22 09:47:18 2017 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#6e0d01cd13e8aca7bf4d697c3699ec9225386881
--- a/mbed.bld Mon Jun 13 09:54:32 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/6c34061e7c34 \ No newline at end of file
--- a/nRF51822.lib Mon Jun 13 09:54:32 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#f7faad332abc
--- a/nRF51_LowPwr.lib Mon Jun 13 09:54:32 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/kenjiArai/code/nRF51_LowPwr/#ffd5168de563