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: 7_Uart_Client/main.cpp
- Revision:
- 1:9011c83e4178
diff -r 6eea047171a3 -r 9011c83e4178 7_Uart_Client/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/7_Uart_Client/main.cpp Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,482 @@ +/* + * ------- BLE Central/Client UART function ----------------------------------- + * communicate with BLE_UART_Server program + * --- Tested on Switch Science mbed TY51822r3 --- + * + * Modified by Kenji Arai + * http://www.page.sannet.ne.jp/kenjia/index.html + * https://os.mbed.com/users/kenjiArai/ + * + * Started: April 8th, 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 only for TYBLE16 + * + * Original program (see original.cpp file): + * S130 potential unstability case [closed] by Fabien Comte + * https://devzone.nordicsemi.com/question/49705/ + * s130-potential-unstability-case/ + * GitHub Q&A by Fabien COMTE + * https://github.com/ARMmbed/ble/issues/69 + * Reference program: + * BLE_Central_test by noboru koshinaka + * https://os.mbed.com/users/noboruk/code/BLE_Central_test/ + * Tested Server Device: + * BLE_Uart_Server + * https://os.mbed.com/users/kenjiArai/code/BLE_Uart_Server/ + */ + +//#define EXAMPLE_7_UART_CLIENT +#ifdef EXAMPLE_7_UART_CLIENT + +// Include -------------------------------------------------------------------- +#include "mbed.h" +#include "BLE.h" +#include "DiscoveredCharacteristic.h" +#include "DiscoveredService.h" +#include "UARTService.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) + +//#define USE_DEBUG_MODE +#ifdef USE_DEBUG_MODE +#define DBG(...) { pc.printf(__VA_ARGS__); } +#else +#define DBG(...) +#endif + +#define SOFT_DEVICE_FATHER_HANDLE 3 + +// Object --------------------------------------------------------------------- +BLE& ble_uart = BLE::Instance(); +DigitalOut alivenessLED(LED1, 1); +DigitalOut connectedLED(D0, 0); +Serial pc(USBTX, USBRX, 115200); +//Serial pc(P0_3, P0_1, 115200); // for another board +Ticker ticker; +CircularBuffer<char, 1536> ser_bf; +Thread tsk; + +// ROM / Constant data -------------------------------------------------------- +#ifdef USE_MAC +#warning "You need to modify below value based on your board." +const Gap::Address_t mac_board_0 = {0x50, 0x2b, 0xea, 0x14, 0x95, 0xd2}; +const Gap::Address_t mac_board_1 = {0x59, 0x2c, 0xa8, 0x0e, 0xe2, 0xef}; +const Gap::Address_t mac_board_2 = {0x0f, 0x72, 0xbf, 0x43, 0xbc, 0xd0}; +const Gap::Address_t mac_board_3 = {0x83, 0xc9, 0x1a, 0x90, 0xdf, 0xd6}; +const Gap::Address_t mac_board_4 = {0x43, 0xa4, 0x36, 0x11, 0x5b, 0xeb}; +#else +const char PEER_NAME[] = "UART_PJL"; +#endif + +// RAM ------------------------------------------------------------------------ +Gap::Handle_t connectionHandle = 0xFFFF; +DiscoveredCharacteristic uartTXCharacteristic; +DiscoveredCharacteristic uartRXCharacteristic; +bool foundUartRXCharacteristic = false; +bool connected2server = false; +bool connection_tx = false; +bool connection_rx = false; +UARTService * uartServicePtr = NULL; +Gap::Address_t my_mac; +int my_board_index = -1; +bool received_uart_dat = false; +int8_t uart_buffer[BFSIZE]; +uint8_t uart_bf_len; +volatile bool rx_isr_busy = false; + +// Function prototypes -------------------------------------------------------- +// BLE +void advertisementCallback(const Gap::AdvertisementCallbackParams_t *); +void serviceDiscoveryCallback(const DiscoveredService *); +void characteristicDiscoveryCallback(const DiscoveredCharacteristic *); +void discoveryTerminationCallback(Gap::Handle_t ); +void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *); +void connectionCallback(const Gap::ConnectionCallbackParams_t *); +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *); +// Interrupt related +void periodicCallback(void); +void serialRxCallback(void); +// serial receiving +void pc_ser_rx(void); +void preparation_sending_data(void); +// Pre-check +bool mac_equals(const Gap::Address_t, const Gap::Address_t); +int get_board_index(const Gap::Address_t); +void adjust_line(uint8_t *); + +//------------------------------------------------------------------------------ +// Control Program +//------------------------------------------------------------------------------ +int main(void) +{ + alivenessLED = 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 / Client(Central) side\r\n"); + pc.printf(" need Server module (run BLE_Uart_Server program)\r\n"); + // Mixed role ************************************************************** + ble_uart.init(); + ble_uart.gap().onConnection(connectionCallback); + ble_uart.gap().onDisconnection(disconnectionCallback); + // Client(Central) role **************************************************** + ble_uart.gattClient().onHVX(onReceivedDataFromDeviceCallback); + ble_uart.gap().setScanParams(500, 450); + ble_uart.gap().startScan(advertisementCallback); + while(true) { + // allow notifications from Server(Peripheral) + if (foundUartRXCharacteristic && + !ble_uart.gattClient().isServiceDiscoveryActive()) { + // need to do the following only once + foundUartRXCharacteristic = false; + uint16_t value = BLE_HVX_NOTIFICATION; + ble_uart.gattClient().write( + GattClient::GATT_OP_WRITE_REQ, + connectionHandle, + uartRXCharacteristic.getValueHandle() + 1, + sizeof(uint16_t), + reinterpret_cast<const uint8_t *>(&value) + ); + } + if (received_uart_dat == true) { + received_uart_dat = false; + for(int i = 0; i < uart_bf_len; i++) { + //pc.printf("%c", uart_buffer[i]); + pc.putc(uart_buffer[i]); + } + } + ble_uart.waitForEvent(); + } +} + +void periodicCallback(void) +{ + // Do blinky on alivenessLED to indicate system aliveness + alivenessLED = !alivenessLED; + if (connected2server) { + connectedLED = 1; + } else { + connectedLED = 0; + } + 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; + uartTXCharacteristic.write(NUM_ONCE, linebf_irq); + } + } + 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; + uartTXCharacteristic.write(linebf_irq_len, linebf_irq); + linebf_irq_len = 0; + 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 onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params) +{ + DBG( + "received HVX callback for handle %u; type %s\r\r\n", + params->handle, + (params->type == BLE_HVX_NOTIFICATION) ? "notification" : "indication" + ); + if (params->type == BLE_HVX_NOTIFICATION) { + if ((params->handle + == uartRXCharacteristic.getValueHandle()) && (params->len > 0)) { + uart_bf_len = params->len; + strcpy((char *)uart_buffer, (char *)params->data); + received_uart_dat = true; + } + } +} + +#ifdef USE_MAC + +bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2) +{ + DBG("Address: "); + for (int i = 0; i < 6; i++) { + DBG("0x%02x ", mac_1[i]); + } + DBG("\r\n"); + for (int i = 0; i < 6; i++) { + if (mac_1[i] != mac_2[i]) { + DBG("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i); + return false; + } else { + DBG("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i); + } + } + return true; +} + +int get_board_index(const Gap::Address_t mac) +{ + if (mac_equals(mac, mac_board_0)) { + return 0; + } + if (mac_equals(mac, mac_board_1)) { + return 1; + } + if (mac_equals(mac, mac_board_2)) { + return 2; + } + if (mac_equals(mac, mac_board_3)) { + return 3; + } + if (mac_equals(mac, mac_board_4)) { + return 4; + } + return -1; +} + +// Client(Central) role ******************************************************** +void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) +{ + // connections + int peer_board_index = get_board_index(params->peerAddr); + if (peer_board_index != -1) { + pc.printf(""); + pc.printf( + "adv peerAddr [%02x %02x %02x %02x %02x %02x]\r\n", + params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], + params->peerAddr[2], params->peerAddr[1], params->peerAddr[0] + ); + pc.printf( + "rssi=%+4d, isScanResponse %u, AdvertisementType %u\r\n", + params->rssi, params->isScanResponse, params->type + ); + ble_uart.gap().connect( + params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); + } +} + +#else + +// Client(Central) role ******************************************************** +void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) +{ + bool name_match = false; + + // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME + // The advertising payload is a collection of key/value records where + // byte 0: length of the record excluding this byte + // byte 1: The key, it is the type of the data + // byte [2..N] The value. N is equal to byte0 - 1 + + for( uint8_t i = 0; i < params->advertisingDataLen; ++i) { + const uint8_t record_length = params->advertisingData[i]; + if (record_length == 0) { + continue; + } + const uint8_t type = params->advertisingData[i + 1]; + const uint8_t* value = params->advertisingData + i + 2; + const uint8_t value_length = record_length - 1; + + if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) { + if ((value_length == sizeof(PEER_NAME)) + && (memcmp(value, PEER_NAME, value_length) == 0)) { + pc.printf( + "\r\nadv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, ", + params->peerAddr[5], params->peerAddr[4], + params->peerAddr[3], params->peerAddr[2], + params->peerAddr[1], params->peerAddr[0], + params->rssi + ); + pc.printf( + "isScanResponse %u, AdvertisementType %u\r\n", + params->isScanResponse, params->type + ); + name_match = true; + break; + } + } + i += record_length; + } + if( name_match != true ) { + return; + } + + pc.printf("Found device name : %s\r\n",PEER_NAME); + // connections + ble_uart.gap().connect(params->peerAddr, + Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); +} + +#endif + +void serviceDiscoveryCallback(const DiscoveredService *service) +{ + DBG("service found...\r\n"); + if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { + DBG( + "Service UUID-%x attrs[%u %u]\r\n", + service->getUUID().getShortUUID(), + service->getStartHandle(), + service->getEndHandle() + ); + } else { + DBG("Service UUID-"); + const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); + for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { + DBG("%02x", longUUIDBytes[i]); + } + DBG(" attrs[%u %u]\r\n", + service->getStartHandle(), service->getEndHandle()); + } +} + +void characteristicDiscoveryCallback( + const DiscoveredCharacteristic *characteristicP) +{ + DBG( + " C UUID-%x valueAttr[%u] props[%x]\r\n", + characteristicP->getUUID().getShortUUID(), + characteristicP->getValueHandle(), + (uint8_t)characteristicP->getProperties().broadcast() + ); + if (characteristicP->getUUID().getShortUUID() + == UARTServiceTXCharacteristicShortUUID) { + DBG("Sevice TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID); + uartTXCharacteristic = *characteristicP; + connection_tx = true; + } else if (characteristicP->getUUID().getShortUUID() + == UARTServiceRXCharacteristicShortUUID) { + DBG("Sevice RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID); + uartRXCharacteristic = *characteristicP; + foundUartRXCharacteristic = true; + connection_rx = true; + } +} + +void discoveryTerminationCallback(Gap::Handle_t connectionHandle) +{ + DBG("terminated SD for handle=%u\r\n", connectionHandle); +} + +// Mixed role ****************************************************************** +void connectionCallback(const Gap::ConnectionCallbackParams_t *params) +{ + if (params->role == Gap::CENTRAL) { + pc.printf("connected as Client(Central) (handle = %d)\r\n\r", + params->handle); + connected2server = true; + connectionHandle = params->handle; + ble_uart.gattClient().onServiceDiscoveryTermination( + discoveryTerminationCallback); + ble_uart.gattClient().launchServiceDiscovery( + params->handle, + serviceDiscoveryCallback, + characteristicDiscoveryCallback + ); + } + pc.printf( + "Client(Central/Myself) %02x:%02x:%02x:%02x:%02x:%02x\r\n", + params->ownAddr[5], params->ownAddr[4], params->ownAddr[3], + params->ownAddr[2], params->ownAddr[1], params->ownAddr[0] + ); + pc.printf( + "Connected Server(Peripheral) %02x:%02x:%02x:%02x:%02x:%02x\r\n", + params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], + params->peerAddr[2], params->peerAddr[1], params->peerAddr[0] + ); +} + +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) +{ + DBG("handle = %d ", params->handle); + pc.printf(" -> disconnected\r\n", params->handle); + connected2server = false; +// connection_1st = false; + connection_tx = false; + connection_rx = false; + if (params->handle == SOFT_DEVICE_FATHER_HANDLE) { + ble_uart.startAdvertising(); // restart advertising + } else { + ble_uart.gap().startScan(advertisementCallback);// restart scan + } +} + +#endif