TYBLE16 on os5 sample programs
Dependencies: BME280 TextLCD nRF51_Vdd
Fork of TYBLE16_mbedlized_os5_BASE by
Please refer following notebook.
/users/kenjiArai/notebook/tyble16-module-as-mbed-os-5-board-mbedlization/
Diff: 8_Uart_Server/main.cpp
- Revision:
- 1:9011c83e4178
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/8_Uart_Server/main.cpp Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,585 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * ------- 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 + * https://os.mbed.com/users/kenjiArai/ + * + * Started: March 7th, 2016 + * Revised: June 13th, 2016 + * Revised: Feburary 10th, 2018 Not set mac addr but use device name + * Revised: Feburary 11th, 2018 use mbed-os5.7.4 with CircularBuffer + * Revised: April 14th, 2018 modification only for TYBLE16 + * + * Original program: + * BLE_LoopbackUART + * https://developer.mbed.org/teams/Bluetooth-Low-Energy/ + * code/BLE_LoopbackUART/ + * Reference program: + * BLE_Peripheral_test by noboru koshinaka + * https://os.mbed.com/users/noboruk/code/BLE_Peripheral_test/ + * Tested Client Device: + * BLE_Uart_Client + * https://os.mbed.com/users/kenjiArai/code/BLE_Uart_Client/ + */ + +//#define EXAMPLE_8_UART_SERVER +#ifdef EXAMPLE_8_UART_SERVER + +// Include -------------------------------------------------------------------- +#include "mbed.h" +#include "BLE.h" +#include "UARTService.h" +#include "nRF51_Vdd.h" +#include "nRF51_WakeUp.h" +#include "CircularBuffer.h" + +// Definition ----------------------------------------------------------------- +//#define USE_MAC // if you use mac address, please define it + +#define NUM_ONCE 20 +#define BFSIZE (NUM_ONCE+4) + +// Please refer nRF51_WakeUP library +#define GOTO_SLEEP_MODE 0 +#if GOTO_SLEEP_MODE +#warning "Make sure!! -> You need to connected P0_21(LED1) and P0_0" +#endif + +//#define USE_DEBUG_MODE +#ifdef USE_DEBUG_MODE +#define DEBUG(...) { printf(__VA_ARGS__); } +#else +#define DEBUG(...) +#endif + +// Object --------------------------------------------------------------------- +BLE& ble_uart = BLE::Instance(); +DigitalOut connectedLED(LED1); +//InterruptIn wake_up_sw(P0_1); +//nRF51_WakeUp wakeup(P0_21, P0_0); +nRF51_Vdd vdd(3.0f, 2.2f); +Serial pc(USBTX, USBRX, 115200); +//Serial pc(P0_3, P0_1, 115200); // for another board +UARTService *uartServicePtr; +Ticker ticker; +CircularBuffer<char, 1536> ser_bf; +Thread tsk; +Mutex bletx_mutex; + +// ROM / Constant data -------------------------------------------------------- +#warning "You need to confirm your device name." +const static char DEVICE_NAME[] = "UART_PJL"; + +// 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 -------------------------------------------------------- +// BLE +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 command(uint8_t *cmd); +void action_tx_help(void); +void action_tx_vdd(void); +void action_tx_temperature(void); +//void action_tx_wait_time(uint8_t *); +void action_tx_quit(void); +static int xatoi (char **, int32_t *); +void adjust_line(uint8_t *); +// Interrupt related +//void interrupt_by_sw(void); +void serialRxCallback(void); +void periodicCallback(void); + +//------------------------------------------------------------------------------ +// Control Program +//------------------------------------------------------------------------------ +int main(void) +{ + connectedLED = 0; + pc.attach(&serialRxCallback, Serial::RxIrq); + ticker.attach(periodicCallback, 1); + tsk.start(pc_ser_rx); + // clear terminal output + for (int k = 0; k < 3; 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_uart.init(); + Gap::AddressType_t my_mac_type; + ble_uart.gap().getAddress(&my_mac_type, my_mac); + 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( + " My device name : %s\r\n", DEVICE_NAME); + pc.printf( + " My mac data %02x:%02x:%02x:%02x:%02x:%02x\r\n", + my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0] + ); +#ifdef USE_MAC + pc.printf( + " mac_board_x = {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 data(mac_board_x line (x=0,1,2,...))\r\n"); + pc.printf( + " into Client/main.cpp [ROM / Constant data] area\r\n"); +#endif + ble_uart.onDisconnection(disconnectionCallback); + ble_uart.onDataWritten(onDataWritten_action); + /* setup advertising */ + ble_uart.accumulateAdvertisingPayload( + GapAdvertisingData::BREDR_NOT_SUPPORTED); + ble_uart.setAdvertisingType( + GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + ble_uart.accumulateAdvertisingPayload( + GapAdvertisingData::COMPLETE_LOCAL_NAME, + (const uint8_t *)DEVICE_NAME, + sizeof(DEVICE_NAME) + ); + ble_uart.accumulateAdvertisingPayload( + GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, + (const uint8_t *)UARTServiceUUID_reversed, + sizeof(UARTServiceUUID_reversed) + ); + // Advertize Interval + ble_uart.setAdvertisingInterval(1000); /* 1000ms;in multiples of 0.625ms.*/ + // Start + ble_uart.startAdvertising(); + UARTService uartService(ble_uart); + uartServicePtr = &uartService; + while(true) { + if (time_out) { +#if GOTO_SLEEP_MODE + wakeup.set_and_wait(sleep_time); + while(true) { // never come here but just in case + deepsleep(); + } +#endif + } + if (trigger_transmit) { + static uint8_t cmd_buf[BFSIZE]; + static volatile bool flag_continue = 0; + trigger_transmit = false; + 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; + } + } + } + ble_uart.waitForEvent(); + } +} + +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; +#if 0 + case 'w': + action_tx_wait_time(cmd); + break; +#endif + case 'h': + case '?': + action_tx_help(); + break; + default: + //pc.printf("\r\nStep(%u)\r\n", __LINE__); + break; + } + } +} + +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.push(pc.getc()); + rx_isr_busy = true; + tsk.signal_set(0x01); +} + +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.empty()) { + if (linebf_irq_len != 0) { + linebf_irq[linebf_irq_len] = 0; + adjust_line(linebf_irq); + linebf_irq_len = 0; + bletx_mutex.lock(); + ble_uart.updateCharacteristicValue( + uartServicePtr->getRXCharacteristicHandle(), + linebf_irq, + NUM_ONCE + ); + bletx_mutex.unlock(); + } + } + while(!ser_bf.empty()) { + char c; + ser_bf.pop(c); + 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_uart.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 <NUM_ONCE; bf++, i++) { + c = *bf; + if (c == 0) { + break; + } + } + for (; i < NUM_ONCE; bf++, i++) { + *bf = 0x11; + } + *(bf + 1) = 0; +} + +void onDataWritten_action(const GattWriteCallbackParams *params) +{ + if ((uartServicePtr != NULL) && + (params->handle == uartServicePtr->getTXCharacteristicHandle())) { + strcpy((char *)rx_buf, (const char *)params->data); + trigger_transmit = true; + } +} + +void action_tx_help() +{ + // 12345678901234567890 + sprintf((char *)tx_buf," ~?:help\r\n"); + tx_len = strlen((const char *)tx_buf); + Update_Values(); + Thread::wait(200); + // 12345678901234567890 + sprintf((char *)tx_buf," ~v:vdd\r\n"); + tx_len = strlen((const char *)tx_buf); + Update_Values(); + Thread::wait(200); + // 12345678901234567890 + sprintf((char *)tx_buf," ~t:temperature\r\n"); + tx_len = strlen((const char *)tx_buf); + Update_Values(); + Thread::wait(200); +#if 0 + // 12345678901234567890 + sprintf((char *)tx_buf," ~w:wait, w 120\r\n"); + tx_len = strlen((const char *)tx_buf); + Update_Values(); + Thread::wait(200); +#endif + // 12345678901234567890 + sprintf((char *)tx_buf," ~q:quit/sleep\r\n"); + tx_len = strlen((const char *)tx_buf); + Update_Values(); + Thread::wait(200); +} + +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(); +} + +#if 0 +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(); +} +#endif + +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(); + Thread::wait(1000); + 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 +static int xatoi (char **str, int32_t *res) +{ + unsigned long val; + unsigned char c, radix, s = 0; + + for (;;) { + c = **str; + if (c == 0) { + return 0; + } + if (c == '-') { + break; + } + if (c == '+') { + (*str)++; + c = **str; + } + if (c>='0'&& c<='9') { + break; + } else { + (*str)++; + c = **str; + } + } + if (c == '-') { + s = 1; + c = *(++(*str)); + } + if (c == '0') { + c = *(++(*str)); + if (c <= ' ') { + *res = 0; + return 1; + } + if (c == 'x') { + radix = 16; + c = *(++(*str)); + } else { + if (c == 'b') { + radix = 2; + c = *(++(*str)); + } else { + if ((c >= '0')&&(c <= '9')) { + radix = 8; + } else { + return 0; + } + } + } + } else { + if ((c < '1')||(c > '9')) { + return 0; + } + radix = 10; + } + val = 0; + while (c > ' ') { + if (c >= 'a') c -= 0x20; + c -= '0'; + if (c >= 17) { + c -= 7; + if (c <= 9) return 0; + } + if (c >= radix) return 0; + val = val * radix + c; + c = *(++(*str)); + } + if (s) val = -val; + *res = val; + return 1; +} + +#if 0 +void interrupt_by_sw() // Go to sleep +{ + NVIC_SystemReset(); + // Not come here (Just in case) + sleep(); +} +#endif + +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) +{ + DEBUG("Disconnected!\r\n"); + DEBUG("Restarting the advertising process\r\n"); + ble_uart.startAdvertising(); +} + +void Update_Values(void) +{ + bletx_mutex.lock(); + ble_uart.updateCharacteristicValue( + uartServicePtr->getRXCharacteristicHandle(), + tx_buf, + tx_len + ); + bletx_mutex.unlock(); + tx_len = 0; +} + +#endif