
BLE Client UART function
This is a BLE Client (Central) program for nRF51.
You can communicate with mbed BLE using "BLE_Uart_Server" program as follows.
/users/kenjiArai/code/BLE_Uart_Server/
Please refer following my notebook.
/users/kenjiArai/notebook/ble-client-and-peripheral-using-switch-sience-ty51/#
Revision 4:342b665fb826, committed 2018-02-09
- Comitter:
- kenjiArai
- Date:
- Fri Feb 09 22:31:19 2018 +0000
- Parent:
- 3:9236f8e65c80
- Child:
- 5:e90d7b6f83cb
- Commit message:
- Not set mac addr but use device name
Changed in this revision
--- a/main.cpp Sun Oct 22 09:45:44 2017 +0000 +++ b/main.cpp Fri Feb 09 22:31:19 2018 +0000 @@ -5,11 +5,12 @@ * * Modified by Kenji Arai * http://www.page.sannet.ne.jp/kenjia/index.html - * http://mbed.org/users/kenjiArai/ + * https://os.mbed.com/users/kenjiArai/ * * Started: April 8th, 2016 * Revised: June 13th, 2016 * Revised: October 22nd, 2017 Run on mbed-OS-5.6.2 + * Revised: Feburary 10th, 2018 Not set mac addr but use device name * * Original program (see original.cpp file): * S130 potential unstability case [closed] by Fabien Comte @@ -17,22 +18,27 @@ * 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://developer.mbed.org/users/kenjiArai/code/BLE_Uart_Server/ + * https://os.mbed.com/users/kenjiArai/code/BLE_Uart_Server/ */ // Include -------------------------------------------------------------------- #include "mbed.h" #include "BLE.h" +#include "DiscoveredCharacteristic.h" +#include "DiscoveredService.h" #include "UARTService.h" -#include "ble/DiscoveredCharacteristic.h" -#include "ble/DiscoveredService.h" #include "RingBuffer.h" // Definition ----------------------------------------------------------------- -#define NUM_ONCE 20 -#define BFSIZE (NUM_ONCE+4) +//#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 @@ -44,7 +50,7 @@ #define SOFT_DEVICE_FATHER_HANDLE 3 // Object --------------------------------------------------------------------- -BLE ble; +BLE& ble_uart = BLE::Instance(); DigitalOut alivenessLED(LED1, 1); DigitalOut connectedLED(D10, 0); Serial pc(USBTX, USBRX, 115200); @@ -54,12 +60,16 @@ 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; @@ -107,27 +117,28 @@ ticker.attach(periodicCallback, 1); tsk.start(pc_ser_rx); // clear terminal output - for (int k = 0; k < 5; k++) { pc.printf("\r\n");} + 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 Sever module (run BLE_Uart_Sever program)\r\n"); + pc.printf(" need Server module (run BLE_Uart_Server program)\r\n"); // Mixed role ************************************************************** - ble.init(); - ble.gap().onConnection(connectionCallback); - ble.gap().onDisconnection(disconnectionCallback); + ble_uart.init(); + ble_uart.gap().onConnection(connectionCallback); + ble_uart.gap().onDisconnection(disconnectionCallback); // Client(Central) role **************************************************** - ble.gattClient().onHVX(onReceivedDataFromDeviceCallback); - ble.gap().setScanParams(500, 450); - ble.gap().startScan(advertisementCallback); + 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.gattClient().isServiceDiscoveryActive()) - { + !ble_uart.gattClient().isServiceDiscoveryActive()) { // need to do the following only once foundUartRXCharacteristic = false; uint16_t value = BLE_HVX_NOTIFICATION; - ble.gattClient().write( + ble_uart.gattClient().write( GattClient::GATT_OP_WRITE_REQ, connectionHandle, uartRXCharacteristic.getValueHandle() + 1, @@ -135,27 +146,27 @@ reinterpret_cast<const uint8_t *>(&value) ); } - if (received_uart_dat == true){ + if (received_uart_dat == true) { received_uart_dat = false; - for(int i = 0; i < uart_bf_len; i++){ + for(int i = 0; i < uart_bf_len; i++) { //pc.printf("%c", uart_buffer[i]); pc.putc(uart_buffer[i]); } } - ble.waitForEvent(); + ble_uart.waitForEvent(); } } void periodicCallback(void) { // Do blinky on alivenessLED to indicate system aliveness - alivenessLED = !alivenessLED; - if (connected2server){ + alivenessLED = !alivenessLED; + if (connected2server) { connectedLED = 1; } else { connectedLED = 0; } - if (rx_isr_busy == true){ + if (rx_isr_busy == true) { rx_isr_busy = false; } else { tsk.signal_set(0x01); @@ -174,27 +185,27 @@ static uint8_t linebf_irq[BFSIZE]; static volatile uint8_t linebf_irq_len = 0; - while(true){ + while(true) { Thread::signal_wait(0x01); - if (ser_bf.check() == 0){ - if (linebf_irq_len != 0){ + if (ser_bf.check() == 0) { + 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.check() != 0){ + while(ser_bf.check() != 0) { char c = ser_bf.read(); - if (c == '\b'){ + if (c == '\b') { linebf_irq_len--; pc.putc(c); pc.putc(' '); pc.putc(c); - } else if ((c >= ' ') || (c == '\r') || (c == '\n')){ + } 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 + if (linebf_irq_len == NUM_ONCE - 1) { // remain only 1 buffer overflow = true; linebf_irq[linebf_irq_len++] = '\r'; pc.putc('\r'); @@ -208,11 +219,11 @@ linebf_irq[linebf_irq_len++] = c; pc.putc(c); } - if (linebf_irq_len >= NUM_ONCE ){ + 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){ + if (overflow == true) { overflow = false; linebf_irq[linebf_irq_len++] = '\n'; pc.putc('\n'); @@ -227,11 +238,15 @@ { uint8_t i, c; - for (i = 0; i <NUM_ONCE; bf++, i++){ + for (i = 0; i <NUM_ONCE; bf++, i++) { c = *bf; - if (c == 0){ break;} + if (c == 0) { + break; + } } - for (; i < NUM_ONCE; bf++, i++){ *bf = 0x11;} + for (; i < NUM_ONCE; bf++, i++) { + *bf = 0x11; + } *(bf + 1) = 0; } @@ -242,26 +257,27 @@ params->handle, (params->type == BLE_HVX_NOTIFICATION) ? "notification" : "indication" ); - if (params->type == BLE_HVX_NOTIFICATION){ + if (params->type == BLE_HVX_NOTIFICATION) { if ((params->handle - == uartRXCharacteristic.getValueHandle()) && (params->len > 0)) - { + == 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++){ + 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]){ + 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 { @@ -273,11 +289,21 @@ 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;} + 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; } @@ -286,26 +312,80 @@ { // connections int peer_board_index = get_board_index(params->peerAddr); - if (peer_board_index != -1){ + 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] + 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.gap().connect( + 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){ + if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { DBG( "Service UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), @@ -319,7 +399,7 @@ DBG("%02x", longUUIDBytes[i]); } DBG(" attrs[%u %u]\r\n", - service->getStartHandle(), service->getEndHandle()); + service->getStartHandle(), service->getEndHandle()); } } @@ -333,14 +413,12 @@ (uint8_t)characteristicP->getProperties().broadcast() ); if (characteristicP->getUUID().getShortUUID() - == UARTServiceTXCharacteristicShortUUID) - { + == UARTServiceTXCharacteristicShortUUID) { DBG("Sevice TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID); uartTXCharacteristic = *characteristicP; connection_tx = true; } else if (characteristicP->getUUID().getShortUUID() - == UARTServiceRXCharacteristicShortUUID) - { + == UARTServiceRXCharacteristicShortUUID) { DBG("Sevice RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID); uartRXCharacteristic = *characteristicP; foundUartRXCharacteristic = true; @@ -358,24 +436,24 @@ { if (params->role == Gap::CENTRAL) { pc.printf("connected as Client(Central) (handle = %d)\r\n\r", - params->handle); + params->handle); connected2server = true; connectionHandle = params->handle; - ble.gattClient().onServiceDiscoveryTermination( - discoveryTerminationCallback); - ble.gattClient().launchServiceDiscovery( - params->handle, - serviceDiscoveryCallback, - characteristicDiscoveryCallback + 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", + "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 Sever(peripheral) %02x:%02x:%02x:%02x:%02x:%02x\r\n", + "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] ); @@ -390,8 +468,8 @@ connection_tx = false; connection_rx = false; if (params->handle == SOFT_DEVICE_FATHER_HANDLE) { - ble.startAdvertising(); // restart advertising + ble_uart.startAdvertising(); // restart advertising } else { - ble.gap().startScan(advertisementCallback); // restart scan + ble_uart.gap().startScan(advertisementCallback);// restart scan } }
--- a/mbed-os.lib Sun Oct 22 09:45:44 2017 +0000 +++ b/mbed-os.lib Fri Feb 09 22:31:19 2018 +0000 @@ -1,1 +1,1 @@ -https://github.com/ARMmbed/mbed-os/#6e0d01cd13e8aca7bf4d697c3699ec9225386881 +https://github.com/ARMmbed/mbed-os/#caeaa49d68c67ee00275cece10cd88e0ed0f6ed3
--- a/original.cpp Sun Oct 22 09:45:44 2017 +0000 +++ b/original.cpp Fri Feb 09 22:31:19 2018 +0000 @@ -9,7 +9,7 @@ #include "UARTService.h" #include "ble/DiscoveredCharacteristic.h" #include "ble/DiscoveredService.h" -#include "UARTService.h" +#include "ble/service/UARTService.h" #define SOFT_DEVICE_FATHER_HANDLE 3