BLE Client UART function

Dependencies:   RingBuffer

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
Parent:
3:9236f8e65c80
Child:
5:e90d7b6f83cb
--- 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
     }
 }