TYBLE16 on os5 sample programs

Dependencies:   BME280 TextLCD nRF51_Vdd

Fork of TYBLE16_mbedlized_os5_BASE by Kenji Arai

Please refer following notebook.
/users/kenjiArai/notebook/tyble16-module-as-mbed-os-5-board-mbedlization/

Revision:
1:9011c83e4178
--- /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