Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:0ef6455cbb4d, committed 2016-04-16
- Comitter:
- kenjiArai
- Date:
- Sat Apr 16 07:32:21 2016 +0000
- Child:
- 1:f68a5e55a60e
- Commit message:
- BLE Client UART function
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BLE_API.lib Sat Apr 16 07:32:21 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#66159681aa21
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Sat Apr 16 07:32:21 2016 +0000
@@ -0,0 +1,422 @@
+/*
+ * ------- BLE Client UART function --------------------------------
+ * --- Tested on Switch Science mbed TY51822r3 ---
+ *
+ * Modified by Kenji Arai
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * http://mbed.org/users/kenjiArai/
+ *
+ * Started: April 8th, 2016
+ * Revised: April 16th, 2016
+ *
+ * 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
+ * Tested Peripheral Device:
+ * BLE_Uart_Peripheral
+ * https://developer.mbed.org/users/kenjiArai/code/BLE_Uart_Peripheral/
+ *
+ */
+
+// Include ---------------------------------------------------------------------------------------
+#include "mbed.h"
+#include "BLE.h"
+#include "UARTService.h"
+#include "ble/DiscoveredCharacteristic.h"
+#include "ble/DiscoveredService.h"
+
+// Definition ------------------------------------------------------------------------------------
+#define NEED_CONSOLE_OUTPUT 0
+
+#if NEED_CONSOLE_OUTPUT
+#define DEBUG(...) { printf(__VA_ARGS__); }
+#else
+#define DEBUG(...)
+#endif
+
+#define SOFT_DEVICE_FATHER_HANDLE 3
+#define BOARDS_COUNT 3
+
+// Object ----------------------------------------------------------------------------------------
+BLE ble;
+DigitalOut alivenessLED(LED1, 1);
+DigitalOut connectedLED(D10, 0);
+DigitalIn sw(D12, PullUp);
+InterruptIn signal_sw(D12); // duplicated!!
+Serial pc(USBTX, USBRX);
+Ticker ticker;
+
+// ROM / Constant data ---------------------------------------------------------------------------
+#warning "You need to modify below value based on your board."
+const Gap::Address_t mac_board_0 = {0x59, 0x2c, 0xa8, 0x0e, 0xe2, 0xef};
+const Gap::Address_t mac_board_1 = {0x50, 0x2b, 0xea, 0x14, 0x95, 0xd2};
+const Gap::Address_t mac_board_2 = {0x30, 0x74, 0x6d, 0xbd, 0x83, 0xf4};
+#warning "You need to confirm your device name."
+const static char DEVICE_NAME[] = "UART_C";
+static const uint16_t uuid16_list[] = {UARTServiceShortUUID};
+
+// RAM -------------------------------------------------------------------------------------------
+Gap::Handle_t connectionHandle = 0xFFFF;
+DiscoveredCharacteristic uartTXCharacteristic;
+DiscoveredCharacteristic uartRXCharacteristic;
+bool foundUartRXCharacteristic = false;
+bool connected2peripheral = false;
+UARTService * uartServicePtr = NULL;
+Gap::Address_t my_mac;
+int my_board_index = -1;
+bool recieved_uart_dat0 = false;
+int8_t uart_buffer0[24];
+uint8_t uart_bf0_len;
+bool recieved_uart_dat1 = false;
+int8_t uart_buffer1[24];
+uint8_t uart_bf1_len;
+bool line_input = false;
+uint8_t linebuf_irq[24];
+int linebf_irq_len = 0;
+uint8_t linebuf[24];
+int linebf_len = 0;
+
+// Function prototypes ---------------------------------------------------------------------------
+// BLE
+void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params);
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params);
+void serviceDiscoveryCallback(const DiscoveredService *service);
+void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP);
+void discoveryTerminationCallback(Gap::Handle_t connectionHandle);
+void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params);
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params);
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params);
+// Interrupt related
+void periodicCallback(void);
+void serialRxCallback(void);
+// Pre-check
+bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2);
+int get_board_index(const Gap::Address_t mac);
+void adjust_line(uint8_t *bf);
+
+//-------------------------------------------------------------------------------------------------
+// Control Program
+//-------------------------------------------------------------------------------------------------
+int main(void){
+ alivenessLED = 0;
+ pc.attach(&serialRxCallback, Serial::RxIrq);
+ ticker.attach(periodicCallback, 1);
+ for (int k = 0; k < 20; k++) { pc.printf("\r\n");} // clear terminal output
+ pc.printf("UART Communication / Client side\r\n"); // opening message
+ pc.printf(" Client(Central) and Peripheral(device)\r\n"); // opening message
+ // Mixed role *************************************************************
+ ble.init();
+ Gap::AddressType_t my_mac_type;
+ ble.gap().getAddress(&my_mac_type, my_mac);
+ my_board_index = get_board_index(my_mac);
+ DEBUG(
+ "me %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"
+ );
+ ble.gap().onConnection(connectionCallback);
+ ble.gap().onDisconnection(disconnectionCallback);
+ // Peripheral(Device) role ************************************************
+ ble.gattServer().onDataWritten(onReceivedDataFromCentralCallback);
+ UARTService uartService(ble);
+ uartServicePtr = &uartService;
+ // setup advertising
+ ble.accumulateAdvertisingPayload(
+ GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE
+ );
+ ble.accumulateAdvertisingPayload(
+ GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)
+ );
+ ble.accumulateAdvertisingPayload(
+ GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
+ (uint8_t *)uuid16_list,
+ sizeof(uuid16_list)
+ ); // UUID's broadcast in advertising packet (set advertising type)
+ ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+ ble.setAdvertisingInterval(100);
+ // Client(Central) role ***************************************************
+ ble.gattClient().onHVX(onReceivedDataFromDeviceCallback);
+ ble.gap().setScanParams(500, 450);
+ ble.startAdvertising(); // start advertising and scan
+ ble.gap().startScan(advertisementCallback);
+ while(true) {
+ // allow notifications from Peripheral(device)
+ if (foundUartRXCharacteristic && !ble.gattClient().isServiceDiscoveryActive()){
+ foundUartRXCharacteristic = false; // need to do the following only once
+ uint16_t value = BLE_HVX_NOTIFICATION;
+ ble.gattClient().write(
+ GattClient::GATT_OP_WRITE_REQ,
+ connectionHandle,
+ uartRXCharacteristic.getValueHandle() + 1,
+ sizeof(uint16_t),
+ reinterpret_cast<const uint8_t *>(&value)
+ );
+ }
+ if (recieved_uart_dat0 == true){
+ recieved_uart_dat0 = false;
+ for(int i = 0; i < uart_bf0_len; i++){
+ pc.printf("%c", uart_buffer0[i]);
+ }
+ pc.printf("\r\n");
+ }
+ if (recieved_uart_dat1 == true){
+ recieved_uart_dat1 = false;
+ for(int i = 0; i < uart_bf1_len; i++){
+ pc.printf("%c", uart_buffer1[i]);
+ }
+ pc.printf("\r\n");
+ }
+ if (line_input == true){
+ line_input = false;
+ // Client to Peripheral(central to device)
+ adjust_line(linebuf);
+ int ret = uartTXCharacteristic.write(20, linebuf);
+ if (ret == BLE_ERROR_NONE){
+ DEBUG("\r\ndone (c2p)\r\n");
+ } else if (ret == BLE_STACK_BUSY){
+ DEBUG("\r\nbusy (c2p)\r\n");
+ } else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED) {
+ DEBUG("\r\nnot connected (c2d)\r\n");
+ } else {
+ DEBUG("\r\ncode %d (c2d)\r\n", ret);
+ }
+ // Peripheral to Client(device to central)
+ if (ble.gap().getState().connected){
+ int ret = ble.gattServer().write(
+ uartServicePtr->getRXCharacteristicHandle(),
+ linebuf,
+ linebf_len
+ );
+ if (ret == BLE_ERROR_NONE){
+ DEBUG("\r\ndone (p2c)\r\n");
+ } else if (ret == BLE_STACK_BUSY){
+ DEBUG("\r\nbusy (p2c)\r\n");
+ } else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED){
+ DEBUG("\r\nnot connected (p2c)\r\n");
+ } else {
+ DEBUG("\r\ncode %d (p2c)\r\n", ret);
+ }
+ }
+ }
+ ble.waitForEvent(); // save power
+ }
+}
+
+void serialRxCallback(){
+ char c = pc.getc();
+ if (c == '\r') {
+ linebuf_irq[linebf_irq_len++] = c;
+ pc.printf("\r\n");
+ linebf_len = linebf_irq_len;
+ strcpy((char *)linebuf, (char *)linebuf_irq);
+ linebf_irq_len = 0;
+ line_input = true;
+ } else if ((c == '\b') && linebf_irq_len) {
+ linebf_irq_len--;
+ pc.putc(c);
+ pc.putc(' ');
+ pc.putc(c);
+ } else if (((uint8_t)c >= ' ') && (linebf_irq_len < 20)) {
+ linebuf_irq[linebf_irq_len++] = c;
+ pc.putc(c);
+ } else if ( c == 0x1f ){ // Control+?
+ SCB->AIRCR = 0x05fa0004; // System RESET!!
+ }
+ linebuf_irq[linebf_irq_len] = 0;
+}
+
+void adjust_line(uint8_t *bf){
+uint8_t i, c;
+
+ for (i = 0; i <20; bf++, i++){
+ c = *bf;
+ if ( (c == '\r') || (c == '\n') || (c == 0)){
+ break;
+ }
+ }
+ for (; i < 20; bf++, i++){
+ *bf = ' ';
+ }
+ *(bf + 1) = 0;
+}
+
+// Peripheral(Device) role ****************************************************
+void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params){
+ if (uartServicePtr != NULL){
+ if ((params->handle ==
+ uartServicePtr->getTXCharacteristicHandle()) && (params->len >= 1))
+ {
+ uart_bf0_len = params->len;
+ strcpy((char *)uart_buffer0, (char *)params->data);
+ recieved_uart_dat0 = true;
+ }
+ }
+}
+
+void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params){
+ DEBUG(
+ "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_bf1_len = params->len;
+ strcpy((char *)uart_buffer1, (char *)params->data);
+ recieved_uart_dat1 = true;
+ }
+ }
+}
+
+void periodicCallback(void){
+ alivenessLED = !alivenessLED; // Do blinky on alivenessLED to indicate system aliveness
+ if (connected2peripheral){
+ connectedLED = 1;
+ } else {
+ connectedLED = 0;
+ }
+}
+
+bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2){
+ DEBUG("Address: ");
+ for (int i = 0; i < 6; i++){
+ DEBUG("0x%02x ", mac_1[i]);
+ }
+ DEBUG("\r\n");
+ for (int i = 0; i < 6; i++){
+ if (mac_1[i] != mac_2[i]){
+ DEBUG("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
+ return false;
+ } else {
+ DEBUG("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;}
+ 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("adv peerAddr");
+ pc.printf(
+ "[%02x %02x %02x %02x %02x %02x] rssi %+4d, isScanResponse %u, AdvertisementType %u",
+ params->peerAddr[5], params->peerAddr[4], params->peerAddr[3],
+ params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
+ params->rssi,
+ params->isScanResponse,
+ params->type
+ );
+ pc.printf("\r\n");
+ ble.gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
+ }
+}
+
+void serviceDiscoveryCallback(const DiscoveredService *service) {
+ DEBUG("service found...\r\n");
+ if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
+ DEBUG(
+ "Service UUID-%x attrs[%u %u]\r\n",
+ service->getUUID().getShortUUID(),
+ service->getStartHandle(),
+ service->getEndHandle()
+ );
+ } else {
+ DEBUG("Service UUID-");
+ const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
+ for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
+ DEBUG("%02x", longUUIDBytes[i]);
+ }
+ DEBUG(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
+ }
+}
+
+void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP){
+ DEBUG(
+ " C UUID-%x valueAttr[%u] props[%x]\r\n",
+ characteristicP->getUUID().getShortUUID(),
+ characteristicP->getValueHandle(),
+ (uint8_t)characteristicP->getProperties().broadcast()
+ );
+ if (characteristicP->getUUID().getShortUUID()
+ == UARTServiceTXCharacteristicShortUUID)
+ {
+ pc.printf("Sevice TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID);
+ uartTXCharacteristic = *characteristicP;
+ } else if (characteristicP->getUUID().getShortUUID()
+ == UARTServiceRXCharacteristicShortUUID)
+ {
+ pc.printf("Sevice RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID);
+ uartRXCharacteristic = *characteristicP;
+ foundUartRXCharacteristic = true;
+ }
+}
+
+void discoveryTerminationCallback(Gap::Handle_t connectionHandle){
+ DEBUG("terminated SD for handle=%u\r\n", connectionHandle);
+}
+
+// Mixed role *****************************************************************
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params){
+ if (params->role == Gap::CENTRAL) {
+ DEBUG("connected as Client(central) (handle = %d)\r\n\r", params->handle);
+ connected2peripheral = true;
+ connectionHandle = params->handle;
+ ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
+ ble.gattClient().launchServiceDiscovery(
+ params->handle,
+ serviceDiscoveryCallback,
+ characteristicDiscoveryCallback/*,
+ 0xa000, 0xa001*/
+ );
+ } else {
+ DEBUG("connected as device (handle = %d)\r\n\r", params->handle);
+ DEBUG(
+ "Conn. params => min=%d, max=%d, slave=%d, supervision=%d\r\n",
+ params->connectionParams->minConnectionInterval,
+ params->connectionParams->maxConnectionInterval,
+ params->connectionParams->slaveLatency,
+ params->connectionParams->connectionSupervisionTimeout
+ );
+ Gap::ConnectionParams_t connectionParams;
+ connectionParams.minConnectionInterval = 6;
+ connectionParams.maxConnectionInterval = 12;
+ connectionParams.slaveLatency = 0;
+ connectionParams.connectionSupervisionTimeout = 500;
+ if (ble.updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE){
+ DEBUG("failed to update connection parameter\r\n");
+ }
+ }
+ DEBUG(
+ "own %02x:%02x:%02x:%02x:%02x:%02x (%s), peer %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n",
+ params->ownAddr[5], params->ownAddr[4], params->ownAddr[3],
+ params->ownAddr[2], params->ownAddr[1], params->ownAddr[0],
+ (params->ownAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random",
+ params->peerAddr[5], params->peerAddr[4], params->peerAddr[3],
+ params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
+ (params->peerAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random"
+ );
+}
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params){
+ DEBUG("handle = %d ", params->handle);
+ pc.printf(" -> disconnected\r\n", params->handle);
+ connected2peripheral = false;
+ if (params->handle == SOFT_DEVICE_FATHER_HANDLE) {
+ ble.startAdvertising(); // restart advertising
+ } else {
+ ble.gap().startScan(advertisementCallback); // restart scan
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sat Apr 16 07:32:21 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/082adc85693f \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRF51822.lib Sat Apr 16 07:32:21 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#f7faad332abc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/original.cpp Sat Apr 16 07:32:21 2016 +0000
@@ -0,0 +1,613 @@
+#if 0
+//-------------------------------------------------------------------------------------------------
+// ORIGINAL PROGRAM
+// S130 potential unstability case [closed] by Fabien Comte
+// https://devzone.nordicsemi.com/question/49705/s130-potential-unstability-case/
+//
+#include "mbed.h"
+#include "BLE.h"
+#include "UARTService.h"
+#include "ble/DiscoveredCharacteristic.h"
+#include "ble/DiscoveredService.h"
+#include "UARTService.h"
+
+#define SOFT_DEVICE_FATHER_HANDLE 3
+
+#define BOARDS_COUNT 3
+
+const Gap::Address_t mac_board_0 = {0xb8, 0xac, 0x4e, 0x8d, 0x8b, 0xeb};
+const Gap::Address_t mac_board_1 = {0x9c, 0x43, 0x62, 0x30, 0xaf, 0xd2};
+const Gap::Address_t mac_board_2 = {0x5f, 0x1a, 0x9e, 0x6a, 0x63, 0xdd};
+
+
+// tiny ble board
+#define LED_GREEN p21
+#define LED_RED p22
+#define LED_BLUE p23
+#define BUTTON_PIN p17
+#define BATTERY_PIN p1
+
+#define MPU6050_SDA p12
+#define MPU6050_SCL p13
+
+#define UART_TX p9
+#define UART_RX p11
+#define UART_CTS p8
+#define UART_RTS p10
+
+DigitalOut led(LED_RED);
+DigitalOut alivenessLED(LED_GREEN);
+InterruptIn button(BUTTON_PIN);
+AnalogIn battery(BATTERY_PIN);
+Serial pc(UART_TX, UART_RX);
+
+bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2)
+{
+ #if 0
+ if (mac_1[0] != mac_2[0])
+ {
+ return false;
+ }
+ if (mac_1[1] != mac_2[1])
+ {
+ return false;
+ }
+ if (mac_1[2] != mac_2[2])
+ {
+ return false;
+ }
+ if (mac_1[3] != mac_2[3])
+ {
+ return false;
+ }
+ if (mac_1[4] != mac_2[4])
+ {
+ return false;
+ }
+ if (mac_1[5] != mac_2[5])
+ {
+ return false;
+ }
+ #else
+ for (int i = 0; i < 6; i++)
+ {
+ if (mac_1[i] != mac_2[i])
+ {
+ //pc.printf("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
+ return false;
+ }
+ else
+ {
+ //pc.printf("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
+ }
+ }
+ #endif
+ 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;
+ }
+
+ return -1;
+}
+
+void periodicCallback(void)
+{
+ alivenessLED = !alivenessLED; /* do blinky on alivenessLED while we're waiting for BLE events */
+}
+
+
+// Mixed role ****************************************************
+BLE ble;
+Gap::Address_t my_mac;
+int my_board_index = -1;
+
+// Device role ****************************************************
+UARTService * uartServicePtr = NULL;
+const static char DEVICE_NAME[] = "ChangeMe!!"; // change this
+static const uint16_t uuid16_list[] = {UARTServiceShortUUID};
+volatile int central_handle = -1;
+
+
+// Central role ****************************************************
+Gap::Handle_t connectionHandle = 0xFFFF;
+DiscoveredCharacteristic uartTXCharacteristic;
+DiscoveredCharacteristic uartRXCharacteristic;
+bool foundUartRXCharacteristic = false;
+volatile int device_handle = -1;
+
+
+// Device role ****************************************************
+void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params)
+{
+ if (uartServicePtr != NULL)
+ {
+ if ((params->handle == uartServicePtr->getTXCharacteristicHandle()) && (params->len >= 1))
+ {
+ if (params->data[0] != '0')
+ {
+ led = 1;
+ }
+ else
+ {
+ led = 0;
+ }
+
+ for(int i = 0; i < params->len; i++)
+ {
+ pc.printf("%c", params->data[i]);
+ }
+
+ pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle);
+ }
+ }
+}
+
+// Central role ****************************************************
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params)
+{
+ // do connections like a triangle
+ int peer_board_index = get_board_index(params->peerAddr);
+
+ int next_board_index = my_board_index + 1;
+ if (next_board_index >= BOARDS_COUNT)
+ {
+ next_board_index = 0;
+ }
+
+ //pc.printf("adv %d, %d, %d\r\n", peer_board_index, my_board_index, next_board_index);
+
+ // force order
+ if ((central_handle != -1) || (peer_board_index == 0))
+ {
+ if (peer_board_index == next_board_index)
+ {
+ //pc.printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
+ // params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
+ // params->rssi, params->isScanResponse, params->type);
+
+ ble.gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
+ }
+ }
+}
+
+void serviceDiscoveryCallback(const DiscoveredService *service)
+{
+ if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT)
+ {
+ pc.printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
+ }
+ else
+ {
+ //pc.printf("S UUID-");
+ const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
+ for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++)
+ {
+ pc.printf("%02x", longUUIDBytes[i]);
+ }
+ pc.printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
+ }
+}
+
+void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP)
+{
+ //pc.printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
+ if (characteristicP->getUUID().getShortUUID() == UARTServiceTXCharacteristicShortUUID)
+ {
+ pc.printf("fit TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID);
+ /* !ALERT! Alter this filter to suit your device. */
+ uartTXCharacteristic = *characteristicP;
+ }
+ else if (characteristicP->getUUID().getShortUUID() == UARTServiceRXCharacteristicShortUUID)
+ {
+ pc.printf("fit RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID);
+ /* !ALERT! Alter this filter to suit your device. */
+ uartRXCharacteristic = *characteristicP;
+ foundUartRXCharacteristic = true;
+ }
+}
+
+void discoveryTerminationCallback(Gap::Handle_t connectionHandle)
+{
+ pc.printf("terminated SD for handle %u\r\n", connectionHandle);
+}
+
+void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params)
+{
+ //pc.printf("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))
+ {
+ for (int i = 0; i < params->len; i++)
+ {
+ pc.printf("%c", params->data[i]);
+ }
+
+ pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle);
+ }
+ }
+ else
+ {
+ pc.printf("%d\r\n", params->type);
+ }
+}
+
+// Mixed role ****************************************************
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+ if (params->role == Gap::CENTRAL)
+ {
+ if (central_handle == -1)
+ {
+ ble.stopAdvertising(); // stop advertising during discovery, incoming connection breaks discovery
+ }
+
+ device_handle = params->handle;
+ pc.printf("connected as central (handle = %d)\r\n\r", params->handle);
+ connectionHandle = params->handle;
+ ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
+ int ret = ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, UARTServiceShortUUID/*, 0xa001*/);
+
+ if (ret != BLE_ERROR_NONE)
+ {
+ pc.printf("launchServiceDiscovery failed error = %d\r\n\r", ret);
+ }
+ }
+ else
+ {
+ central_handle = params->handle;
+ pc.printf("connected as device (handle = %d)\r\n\r", params->handle);
+
+ //pc.printf("Conn. params => min=%d, max=%d, slave=%d, supervision=%d\r\n", params->connectionParams->minConnectionInterval, params->connectionParams->maxConnectionInterval, params->connectionParams->slaveLatency, params->connectionParams->connectionSupervisionTimeout);
+ /*
+ Gap::ConnectionParams_t connectionParams;
+ connectionParams.minConnectionInterval = 6;
+ connectionParams.maxConnectionInterval = 12;
+ connectionParams.slaveLatency = 40;
+ connectionParams.connectionSupervisionTimeout = 500;
+
+ int ret = ble.updateConnectionParams(params->handle, &connectionParams);
+ if (ret != BLE_ERROR_NONE)
+ {
+ pc.printf("failed to update connection parameter\r\n");
+ }
+ */
+ }
+ pc.printf("own %02x:%02x:%02x:%02x:%02x:%02x (%s), peer %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n", params->ownAddr[5], params->ownAddr[4], params->ownAddr[3], params->ownAddr[2], params->ownAddr[1], params->ownAddr[0], (params->ownAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random", params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0], (params->peerAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random");
+}
+
+void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
+{
+ char * ascii_reason = "?";
+ switch (reason)
+ {
+ case Gap::CONNECTION_TIMEOUT:
+ ascii_reason = "connection timeout";
+ break;
+ case Gap::REMOTE_USER_TERMINATED_CONNECTION:
+ ascii_reason = "user terminated connection";
+ break;
+ case Gap::REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES:
+ ascii_reason = "low resources";
+ break;
+ case Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF:
+ ascii_reason = "power off";
+ break;
+ case Gap::LOCAL_HOST_TERMINATED_CONNECTION:
+ ascii_reason = "host terminated connection";
+ break;
+ case Gap::CONN_INTERVAL_UNACCEPTABLE:
+ ascii_reason = "interval unacceptable";
+ break;
+ default:
+ ascii_reason = "unknown";
+ break;
+ }
+
+ pc.printf("disconnected (reason = %s, handle = %d)\r\n", ascii_reason, handle);
+
+
+ if (handle == SOFT_DEVICE_FATHER_HANDLE)
+ {
+ central_handle = -1;
+ // restart advertising
+ ble.startAdvertising();
+ }
+ else
+ {
+ device_handle = -1;
+ // restart scan
+ ble.gap().startScan(advertisementCallback);
+ }
+}
+
+
+
+void serialTxCallback()
+{
+
+}
+
+int rx_char = -1;
+void serialRxCallback()
+{
+ if (rx_char != -1)
+ {
+ pc.printf("overflow\r\n");
+ }
+
+ //computer.putc(computer.getc());
+ rx_char = pc.getc();
+}
+
+/*
+void gattServerOnDataSent(unsigned count)
+{
+
+}
+*/
+
+
+int main(void)
+{
+ alivenessLED = 0;
+
+ pc.baud(115200);
+ //pc.attach(&serialTxCallback, Serial::TxIrq);
+ pc.attach(&serialRxCallback, Serial::RxIrq);
+
+ // clear terminal output
+ for (int k = 0; k < 32; k++)
+ {
+ pc.printf("\r\n");
+ }
+
+ pc.printf("Central and device\r\n");
+
+ Ticker ticker;
+ ticker.attach(periodicCallback, 1);
+
+
+ // Mixed role ****************************************************
+ ble.init();
+
+ Gap::AddressType_t my_mac_type;
+ ble.gap().getAddress(&my_mac_type, my_mac);
+ my_board_index = get_board_index(my_mac);
+ pc.printf("me %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");
+
+
+ // try to speed up but looks like if it was ignored
+ Gap::ConnectionParams_t fast;
+ if (ble.getPreferredConnectionParams(&fast) != BLE_ERROR_NONE)
+ {
+ pc.printf("getPreferredConnectionParams failed\r\n");
+ }
+ else
+ {
+ fast.minConnectionInterval = 16; // 20 ms
+ fast.maxConnectionInterval = 32; // 40 ms
+ fast.slaveLatency = 0;
+ if (ble.gap().setPreferredConnectionParams(&fast) != BLE_ERROR_NONE)
+ {
+ pc.printf("setPreferredConnectionParams failed\r\n");
+ }
+ }
+ ble.gap().onConnection(connectionCallback);
+ ble.gap().onDisconnection(disconnectionCallback);
+
+ // Device role ****************************************************
+ ble.gattServer().onDataWritten(onReceivedDataFromCentralCallback);
+ //ble.gattServer().onDataSent(gattServerOnDataSent);
+
+ UARTService uartService(ble);
+ uartServicePtr = &uartService;
+
+ // setup advertising
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); // BLE only, no classic BT
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); // add name
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // UUID's broadcast in advertising packet
+ ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // advertising type
+ ble.setAdvertisingInterval(100);
+
+ // Central role ****************************************************
+ ble.gattClient().onHVX(onReceivedDataFromDeviceCallback);
+ ble.gap().setScanParams(500, 450);
+
+
+ // start advertising and scan
+ ble.startAdvertising();
+ ble.gap().startScan(advertisementCallback);
+
+ while (true)
+ {
+ // allow notifications from device
+ if (foundUartRXCharacteristic && !ble.gattClient().isServiceDiscoveryActive())
+ {
+ foundUartRXCharacteristic = false; /* need to do the following only once */
+
+ uint16_t value = BLE_HVX_NOTIFICATION;
+ int ret = ble.gattClient().write(GattClient::GATT_OP_WRITE_REQ,
+ connectionHandle,
+ uartRXCharacteristic.getValueHandle() + 1, /* HACK Alert. We're assuming that CCCD descriptor immediately follows the value attribute. */
+ sizeof(uint16_t), /* HACK Alert! size should be made into a BLE_API constant. */
+ reinterpret_cast<const uint8_t *>(&value));
+
+ if (ret == BLE_ERROR_NONE)
+ {
+ pc.printf("\r\ndevice notifications enabled\r\n");
+ }
+ else
+ {
+ switch (ret)
+ {
+ case BLE_STACK_BUSY:
+ foundUartRXCharacteristic = true; // retry later
+ break;
+ case BLE_ERROR_NO_MEM:
+ foundUartRXCharacteristic = true; // retry later
+ break;
+ case BLE_ERROR_INVALID_STATE:
+ pc.printf("\r\ndevice notifications enable failed\r\n");
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!foundUartRXCharacteristic)
+ {
+ if (central_handle == -1)
+ {
+ ble.startAdvertising();
+ }
+ }
+ }
+
+ // while a new char from computer is available
+ while (rx_char != -1)
+ {
+ uint8_t temp[20];
+ int length = 1;
+
+ uint8_t command = rx_char;
+ rx_char = -1;
+
+ // if special char to test a 20 bytes frame
+ /*
+ if (command == '*')
+ {
+ pc.printf("20 chars\r\n");
+
+ int c = 0;
+ for (c = 0; c < 20; c++)
+ {
+ temp[c] = 'a' + c;
+ }
+ length = 20;
+ }
+ else
+ {
+ temp[0] = command;
+ }
+ */
+ temp[0] = command;
+
+ // to central
+ //if (command == '1')
+ {
+ if (central_handle != -1)
+ {
+ // device to central
+ while (1)
+ {
+ if (central_handle == -1)
+ {
+ pc.printf("\r\ndisconnected 1 (to central)\r\n");
+ break;
+ }
+ if (!ble.gap().getState().connected)
+ {
+ pc.printf("\r\ndisconnected 2 (to central)\r\n");
+ break;
+ }
+ int ret = ble.gattServer().write(uartServicePtr->getRXCharacteristicHandle(), temp, length);
+
+ if (ret == BLE_ERROR_NONE)
+ {
+ //pc.printf("\r\nok (to central)\r\n");
+ break;
+ }
+ else if (ret == BLE_STACK_BUSY)
+ {
+ //pc.printf("\r\nbusy (to central)\r\n");
+ //break;
+ }
+ else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED)
+ {
+ pc.printf("\r\nnot permitted (to central)\r\n");
+ break;
+ }
+ else if (ret == BLE_ERROR_INVALID_STATE)
+ {
+ pc.printf("\r\ninvalid state (to central)\r\n");
+ break;
+ }
+ else
+ {
+ pc.printf("\r\ncode %d (to central)\r\n", ret);
+ break;
+ }
+ }
+ }
+ else
+ {
+ pc.printf("\r\nnot connected with central\r\n");
+ }
+ }
+
+ // to device
+ //if (command == '2')
+ {
+ if (device_handle != -1)
+ {
+ // central to device
+ while (1)
+ {
+ if (device_handle == -1)
+ {
+ pc.printf("\r\ndisconnected (to device)\r\n");
+ break;
+ }
+ int ret = uartTXCharacteristic.write(length, temp);
+ if (ret == BLE_ERROR_NONE)
+ {
+ //pc.printf("\r\nok (to device)\r\n");
+ break;
+ }
+ else if (ret == BLE_STACK_BUSY)
+ {
+ //pc.printf("\r\nbusy (to device)\r\n");
+ //break;
+ }
+ else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED)
+ {
+ pc.printf("\r\nnot permitted (to device)\r\n");
+ break;
+ }
+ else if (ret == BLE_ERROR_INVALID_STATE)
+ {
+ pc.printf("\r\ninvalid state (to device)\r\n");
+ break;
+ }
+ else
+ {
+ pc.printf("\r\ncode %d (to device)\r\n", ret);
+ break;
+ }
+ }
+ }
+ else
+ {
+ pc.printf("\r\nnot connected with device\r\n");
+ }
+ }
+ }
+
+ ble.waitForEvent(); // save power
+ }
+}
+#endif