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/#

Committer:
kenjiArai
Date:
Mon Jun 13 09:53:27 2016 +0000
Revision:
2:6fb0b87b041d
Parent:
1:f68a5e55a60e
Child:
3:9236f8e65c80
added nRF51_LowPwr library and updated other libraries.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:0ef6455cbb4d 1 /*
kenjiArai 2:6fb0b87b041d 2 * ------- BLE Client UART function -------------------------------------
kenjiArai 0:0ef6455cbb4d 3 * --- Tested on Switch Science mbed TY51822r3 ---
kenjiArai 0:0ef6455cbb4d 4 *
kenjiArai 0:0ef6455cbb4d 5 * Modified by Kenji Arai
kenjiArai 0:0ef6455cbb4d 6 * http://www.page.sannet.ne.jp/kenjia/index.html
kenjiArai 0:0ef6455cbb4d 7 * http://mbed.org/users/kenjiArai/
kenjiArai 0:0ef6455cbb4d 8 *
kenjiArai 0:0ef6455cbb4d 9 * Started: April 8th, 2016
kenjiArai 2:6fb0b87b041d 10 * Revised: June 13th, 2016
kenjiArai 0:0ef6455cbb4d 11 *
kenjiArai 0:0ef6455cbb4d 12 * Original program (see original.cpp file):
kenjiArai 0:0ef6455cbb4d 13 * S130 potential unstability case [closed] by Fabien Comte
kenjiArai 0:0ef6455cbb4d 14 * https://devzone.nordicsemi.com/question/49705/s130-potential-unstability-case/
kenjiArai 0:0ef6455cbb4d 15 * GitHub Q&A by Fabien COMTE
kenjiArai 0:0ef6455cbb4d 16 * https://github.com/ARMmbed/ble/issues/69
kenjiArai 1:f68a5e55a60e 17 * Tested Server Device:
kenjiArai 1:f68a5e55a60e 18 * BLE_Uart_Server
kenjiArai 1:f68a5e55a60e 19 * https://developer.mbed.org/users/kenjiArai/code/BLE_Uart_Server/
kenjiArai 0:0ef6455cbb4d 20 *
kenjiArai 0:0ef6455cbb4d 21 */
kenjiArai 0:0ef6455cbb4d 22
kenjiArai 0:0ef6455cbb4d 23 // Include ---------------------------------------------------------------------------------------
kenjiArai 0:0ef6455cbb4d 24 #include "mbed.h"
kenjiArai 0:0ef6455cbb4d 25 #include "BLE.h"
kenjiArai 0:0ef6455cbb4d 26 #include "UARTService.h"
kenjiArai 0:0ef6455cbb4d 27 #include "ble/DiscoveredCharacteristic.h"
kenjiArai 0:0ef6455cbb4d 28 #include "ble/DiscoveredService.h"
kenjiArai 2:6fb0b87b041d 29 #include "nRF51_lowpwr.h"
kenjiArai 0:0ef6455cbb4d 30
kenjiArai 0:0ef6455cbb4d 31 // Definition ------------------------------------------------------------------------------------
kenjiArai 2:6fb0b87b041d 32 // Before using this function, please specify your program are used following functions or not.
kenjiArai 2:6fb0b87b041d 33 #define USE_DEVICE_STDIO_MESSAGES 0 // printf
kenjiArai 2:6fb0b87b041d 34 #define USE_DEVICE_SERIAL 1 // Serial or DEBUG & etc.
kenjiArai 2:6fb0b87b041d 35 #define USE_DEVICE_I2C 0 // Sensors with I2C, LCD, EEPROM, Driver chips & etc.
kenjiArai 2:6fb0b87b041d 36 #define USE_DEVICE_SPI 0 // Sensors with SPI, LCD, EEPROM, Driver chips & etc.
kenjiArai 2:6fb0b87b041d 37 #define USE_DEVICE_SPISLAVE 0 // Communication with master vis SPI
kenjiArai 2:6fb0b87b041d 38 #define USE_DEVICE_PWMOUT 0 // PWM duty output, Serve & etc.
kenjiArai 2:6fb0b87b041d 39 #define USE_DEVICE_ANALOGIN 0 // Analog adc
kenjiArai 0:0ef6455cbb4d 40
kenjiArai 2:6fb0b87b041d 41 #if USE_DEVICE_STDIO_MESSAGES
kenjiArai 2:6fb0b87b041d 42 #define DEBUG(...) { printf(__VA_ARGS__); }
kenjiArai 0:0ef6455cbb4d 43 #else
kenjiArai 0:0ef6455cbb4d 44 #define DEBUG(...)
kenjiArai 0:0ef6455cbb4d 45 #endif
kenjiArai 0:0ef6455cbb4d 46
kenjiArai 2:6fb0b87b041d 47 #if USE_DEVICE_SERIAL
kenjiArai 2:6fb0b87b041d 48 #define BAUD(x) pc.baud(x)
kenjiArai 2:6fb0b87b041d 49 #define GETC(x) pc.getc(x)
kenjiArai 2:6fb0b87b041d 50 #define PUTC(x) pc.putc(x)
kenjiArai 2:6fb0b87b041d 51 #define PRINTF(...) { pc.printf(__VA_ARGS__); }
kenjiArai 2:6fb0b87b041d 52 #define READABLE(x) pc.readable(x)
kenjiArai 2:6fb0b87b041d 53 #define ATTACH(x,y) pc.attach(x, y);
kenjiArai 2:6fb0b87b041d 54 #else
kenjiArai 2:6fb0b87b041d 55 #define BAUD(x)
kenjiArai 2:6fb0b87b041d 56 #define GETC(x) 'c'
kenjiArai 2:6fb0b87b041d 57 #define PUTC(x)
kenjiArai 2:6fb0b87b041d 58 #define PRINTF(...)
kenjiArai 2:6fb0b87b041d 59 #define READABLE(x)
kenjiArai 2:6fb0b87b041d 60 #define ATTACH(x,y)
kenjiArai 2:6fb0b87b041d 61 #endif
kenjiArai 2:6fb0b87b041d 62
kenjiArai 0:0ef6455cbb4d 63 #define SOFT_DEVICE_FATHER_HANDLE 3
kenjiArai 0:0ef6455cbb4d 64 #define BOARDS_COUNT 3
kenjiArai 0:0ef6455cbb4d 65
kenjiArai 0:0ef6455cbb4d 66 // Object ----------------------------------------------------------------------------------------
kenjiArai 0:0ef6455cbb4d 67 BLE ble;
kenjiArai 0:0ef6455cbb4d 68 DigitalOut alivenessLED(LED1, 1);
kenjiArai 0:0ef6455cbb4d 69 DigitalOut connectedLED(D10, 0);
kenjiArai 0:0ef6455cbb4d 70 DigitalIn sw(D12, PullUp);
kenjiArai 0:0ef6455cbb4d 71 InterruptIn signal_sw(D12); // duplicated!!
kenjiArai 0:0ef6455cbb4d 72 Serial pc(USBTX, USBRX);
kenjiArai 0:0ef6455cbb4d 73 Ticker ticker;
kenjiArai 0:0ef6455cbb4d 74
kenjiArai 0:0ef6455cbb4d 75 // ROM / Constant data ---------------------------------------------------------------------------
kenjiArai 0:0ef6455cbb4d 76 #warning "You need to modify below value based on your board."
kenjiArai 0:0ef6455cbb4d 77 const Gap::Address_t mac_board_0 = {0x59, 0x2c, 0xa8, 0x0e, 0xe2, 0xef};
kenjiArai 2:6fb0b87b041d 78 //const Gap::Address_t mac_board_0 = {0x30, 0x74, 0x6d, 0xbd, 0x83, 0xf4};
kenjiArai 2:6fb0b87b041d 79 //const Gap::Address_t mac_board_0 = {0xe4, 0x34, 0xbc, 0xb9, 0xc4, 0xf1};
kenjiArai 0:0ef6455cbb4d 80 const Gap::Address_t mac_board_1 = {0x50, 0x2b, 0xea, 0x14, 0x95, 0xd2};
kenjiArai 2:6fb0b87b041d 81 const Gap::Address_t mac_board_2 = {0x0f, 0x72, 0xbf, 0x43, 0xbc, 0xd0};
kenjiArai 2:6fb0b87b041d 82 const Gap::Address_t mac_board_3 = {0x83, 0xc9, 0x1a, 0x90, 0xdf, 0xd6}; // TY small with LiC
kenjiArai 2:6fb0b87b041d 83 const Gap::Address_t mac_board_4 = {0x43, 0xa4, 0x36, 0x11, 0x5b, 0xeb}; // TY small
kenjiArai 2:6fb0b87b041d 84 //const Gap::Address_t mac_board_4 = {0x98, 0x1a, 0x92, 0x10, 0x7f, 0xd5};
kenjiArai 0:0ef6455cbb4d 85 #warning "You need to confirm your device name."
kenjiArai 0:0ef6455cbb4d 86 const static char DEVICE_NAME[] = "UART_C";
kenjiArai 0:0ef6455cbb4d 87 static const uint16_t uuid16_list[] = {UARTServiceShortUUID};
kenjiArai 2:6fb0b87b041d 88 const nRF51_LOWPWR_TypeDef lowpwr_table =
kenjiArai 2:6fb0b87b041d 89 {
kenjiArai 2:6fb0b87b041d 90 #if USE_DEVICE_STDIO_MESSAGES
kenjiArai 2:6fb0b87b041d 91 true,
kenjiArai 2:6fb0b87b041d 92 #else
kenjiArai 2:6fb0b87b041d 93 false,
kenjiArai 2:6fb0b87b041d 94 #endif
kenjiArai 2:6fb0b87b041d 95 #if USE_DEVICE_SERIAL
kenjiArai 2:6fb0b87b041d 96 true,
kenjiArai 2:6fb0b87b041d 97 #else
kenjiArai 2:6fb0b87b041d 98 false,
kenjiArai 2:6fb0b87b041d 99 #endif
kenjiArai 2:6fb0b87b041d 100 #if USE_DEVICE_I2C
kenjiArai 2:6fb0b87b041d 101 true,
kenjiArai 2:6fb0b87b041d 102 #else
kenjiArai 2:6fb0b87b041d 103 false,
kenjiArai 2:6fb0b87b041d 104 #endif
kenjiArai 2:6fb0b87b041d 105 #if USE_DEVICE_SPI
kenjiArai 2:6fb0b87b041d 106 true,
kenjiArai 2:6fb0b87b041d 107 #else
kenjiArai 2:6fb0b87b041d 108 false,
kenjiArai 2:6fb0b87b041d 109 #endif
kenjiArai 2:6fb0b87b041d 110 #if USE_DEVICE_SPISLAVE
kenjiArai 2:6fb0b87b041d 111 true,
kenjiArai 2:6fb0b87b041d 112 #else
kenjiArai 2:6fb0b87b041d 113 false,
kenjiArai 2:6fb0b87b041d 114 #endif
kenjiArai 2:6fb0b87b041d 115 #if USE_DEVICE_PWMOUT
kenjiArai 2:6fb0b87b041d 116 true,
kenjiArai 2:6fb0b87b041d 117 #else
kenjiArai 2:6fb0b87b041d 118 false,
kenjiArai 2:6fb0b87b041d 119 #endif
kenjiArai 2:6fb0b87b041d 120 #if USE_DEVICE_ANALOGIN
kenjiArai 2:6fb0b87b041d 121 true
kenjiArai 2:6fb0b87b041d 122 #else
kenjiArai 2:6fb0b87b041d 123 false
kenjiArai 2:6fb0b87b041d 124 #endif
kenjiArai 2:6fb0b87b041d 125 };
kenjiArai 0:0ef6455cbb4d 126
kenjiArai 0:0ef6455cbb4d 127 // RAM -------------------------------------------------------------------------------------------
kenjiArai 0:0ef6455cbb4d 128 Gap::Handle_t connectionHandle = 0xFFFF;
kenjiArai 0:0ef6455cbb4d 129 DiscoveredCharacteristic uartTXCharacteristic;
kenjiArai 0:0ef6455cbb4d 130 DiscoveredCharacteristic uartRXCharacteristic;
kenjiArai 0:0ef6455cbb4d 131 bool foundUartRXCharacteristic = false;
kenjiArai 2:6fb0b87b041d 132 bool connected2server = false;
kenjiArai 2:6fb0b87b041d 133 bool connection_1st = false;
kenjiArai 2:6fb0b87b041d 134 bool connection_tx = false;
kenjiArai 2:6fb0b87b041d 135 bool connection_rx = false;
kenjiArai 0:0ef6455cbb4d 136 UARTService * uartServicePtr = NULL;
kenjiArai 0:0ef6455cbb4d 137 Gap::Address_t my_mac;
kenjiArai 0:0ef6455cbb4d 138 int my_board_index = -1;
kenjiArai 0:0ef6455cbb4d 139 bool recieved_uart_dat0 = false;
kenjiArai 0:0ef6455cbb4d 140 int8_t uart_buffer0[24];
kenjiArai 0:0ef6455cbb4d 141 uint8_t uart_bf0_len;
kenjiArai 0:0ef6455cbb4d 142 bool recieved_uart_dat1 = false;
kenjiArai 0:0ef6455cbb4d 143 int8_t uart_buffer1[24];
kenjiArai 0:0ef6455cbb4d 144 uint8_t uart_bf1_len;
kenjiArai 0:0ef6455cbb4d 145 bool line_input = false;
kenjiArai 0:0ef6455cbb4d 146 uint8_t linebuf_irq[24];
kenjiArai 0:0ef6455cbb4d 147 int linebf_irq_len = 0;
kenjiArai 0:0ef6455cbb4d 148 uint8_t linebuf[24];
kenjiArai 0:0ef6455cbb4d 149 int linebf_len = 0;
kenjiArai 0:0ef6455cbb4d 150
kenjiArai 0:0ef6455cbb4d 151 // Function prototypes ---------------------------------------------------------------------------
kenjiArai 0:0ef6455cbb4d 152 // BLE
kenjiArai 0:0ef6455cbb4d 153 void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params);
kenjiArai 0:0ef6455cbb4d 154 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params);
kenjiArai 0:0ef6455cbb4d 155 void serviceDiscoveryCallback(const DiscoveredService *service);
kenjiArai 0:0ef6455cbb4d 156 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP);
kenjiArai 0:0ef6455cbb4d 157 void discoveryTerminationCallback(Gap::Handle_t connectionHandle);
kenjiArai 0:0ef6455cbb4d 158 void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params);
kenjiArai 0:0ef6455cbb4d 159 void connectionCallback(const Gap::ConnectionCallbackParams_t *params);
kenjiArai 0:0ef6455cbb4d 160 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params);
kenjiArai 0:0ef6455cbb4d 161 // Interrupt related
kenjiArai 0:0ef6455cbb4d 162 void periodicCallback(void);
kenjiArai 0:0ef6455cbb4d 163 void serialRxCallback(void);
kenjiArai 0:0ef6455cbb4d 164 // Pre-check
kenjiArai 0:0ef6455cbb4d 165 bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2);
kenjiArai 0:0ef6455cbb4d 166 int get_board_index(const Gap::Address_t mac);
kenjiArai 0:0ef6455cbb4d 167 void adjust_line(uint8_t *bf);
kenjiArai 0:0ef6455cbb4d 168
kenjiArai 0:0ef6455cbb4d 169 //-------------------------------------------------------------------------------------------------
kenjiArai 0:0ef6455cbb4d 170 // Control Program
kenjiArai 0:0ef6455cbb4d 171 //-------------------------------------------------------------------------------------------------
kenjiArai 0:0ef6455cbb4d 172 int main(void){
kenjiArai 2:6fb0b87b041d 173 LowPwr set_lowpwr(&lowpwr_table);
kenjiArai 0:0ef6455cbb4d 174 alivenessLED = 0;
kenjiArai 2:6fb0b87b041d 175 ATTACH(&serialRxCallback, Serial::RxIrq);
kenjiArai 0:0ef6455cbb4d 176 ticker.attach(periodicCallback, 1);
kenjiArai 2:6fb0b87b041d 177 for (int k = 0; k < 20; k++) { PRINTF("\r\n");} // clear terminal output
kenjiArai 2:6fb0b87b041d 178 PRINTF("UART Communication / Client side\r\n"); // opening message
kenjiArai 2:6fb0b87b041d 179 PRINTF(" Client(Central) and Server(Peripheral)\r\n"); // opening message
kenjiArai 0:0ef6455cbb4d 180 // Mixed role *************************************************************
kenjiArai 0:0ef6455cbb4d 181 ble.init();
kenjiArai 0:0ef6455cbb4d 182 Gap::AddressType_t my_mac_type;
kenjiArai 0:0ef6455cbb4d 183 ble.gap().getAddress(&my_mac_type, my_mac);
kenjiArai 0:0ef6455cbb4d 184 my_board_index = get_board_index(my_mac);
kenjiArai 0:0ef6455cbb4d 185 DEBUG(
kenjiArai 0:0ef6455cbb4d 186 "me %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n",
kenjiArai 0:0ef6455cbb4d 187 my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0],
kenjiArai 0:0ef6455cbb4d 188 (my_mac_type == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random"
kenjiArai 0:0ef6455cbb4d 189 );
kenjiArai 0:0ef6455cbb4d 190 ble.gap().onConnection(connectionCallback);
kenjiArai 0:0ef6455cbb4d 191 ble.gap().onDisconnection(disconnectionCallback);
kenjiArai 1:f68a5e55a60e 192 // Server(Peripheral) role ************************************************
kenjiArai 0:0ef6455cbb4d 193 ble.gattServer().onDataWritten(onReceivedDataFromCentralCallback);
kenjiArai 0:0ef6455cbb4d 194 UARTService uartService(ble);
kenjiArai 0:0ef6455cbb4d 195 uartServicePtr = &uartService;
kenjiArai 0:0ef6455cbb4d 196 // setup advertising
kenjiArai 0:0ef6455cbb4d 197 ble.accumulateAdvertisingPayload(
kenjiArai 0:0ef6455cbb4d 198 GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE
kenjiArai 0:0ef6455cbb4d 199 );
kenjiArai 0:0ef6455cbb4d 200 ble.accumulateAdvertisingPayload(
kenjiArai 0:0ef6455cbb4d 201 GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)
kenjiArai 0:0ef6455cbb4d 202 );
kenjiArai 0:0ef6455cbb4d 203 ble.accumulateAdvertisingPayload(
kenjiArai 0:0ef6455cbb4d 204 GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
kenjiArai 0:0ef6455cbb4d 205 (uint8_t *)uuid16_list,
kenjiArai 0:0ef6455cbb4d 206 sizeof(uuid16_list)
kenjiArai 0:0ef6455cbb4d 207 ); // UUID's broadcast in advertising packet (set advertising type)
kenjiArai 0:0ef6455cbb4d 208 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
kenjiArai 0:0ef6455cbb4d 209 ble.setAdvertisingInterval(100);
kenjiArai 0:0ef6455cbb4d 210 // Client(Central) role ***************************************************
kenjiArai 0:0ef6455cbb4d 211 ble.gattClient().onHVX(onReceivedDataFromDeviceCallback);
kenjiArai 0:0ef6455cbb4d 212 ble.gap().setScanParams(500, 450);
kenjiArai 0:0ef6455cbb4d 213 ble.startAdvertising(); // start advertising and scan
kenjiArai 0:0ef6455cbb4d 214 ble.gap().startScan(advertisementCallback);
kenjiArai 0:0ef6455cbb4d 215 while(true) {
kenjiArai 1:f68a5e55a60e 216 // allow notifications from Server(Peripheral)
kenjiArai 0:0ef6455cbb4d 217 if (foundUartRXCharacteristic && !ble.gattClient().isServiceDiscoveryActive()){
kenjiArai 0:0ef6455cbb4d 218 foundUartRXCharacteristic = false; // need to do the following only once
kenjiArai 0:0ef6455cbb4d 219 uint16_t value = BLE_HVX_NOTIFICATION;
kenjiArai 0:0ef6455cbb4d 220 ble.gattClient().write(
kenjiArai 0:0ef6455cbb4d 221 GattClient::GATT_OP_WRITE_REQ,
kenjiArai 0:0ef6455cbb4d 222 connectionHandle,
kenjiArai 0:0ef6455cbb4d 223 uartRXCharacteristic.getValueHandle() + 1,
kenjiArai 0:0ef6455cbb4d 224 sizeof(uint16_t),
kenjiArai 0:0ef6455cbb4d 225 reinterpret_cast<const uint8_t *>(&value)
kenjiArai 0:0ef6455cbb4d 226 );
kenjiArai 0:0ef6455cbb4d 227 }
kenjiArai 0:0ef6455cbb4d 228 if (recieved_uart_dat0 == true){
kenjiArai 0:0ef6455cbb4d 229 recieved_uart_dat0 = false;
kenjiArai 0:0ef6455cbb4d 230 for(int i = 0; i < uart_bf0_len; i++){
kenjiArai 2:6fb0b87b041d 231 PRINTF("%c", uart_buffer0[i]);
kenjiArai 0:0ef6455cbb4d 232 }
kenjiArai 2:6fb0b87b041d 233 PRINTF("\r\n");
kenjiArai 0:0ef6455cbb4d 234 }
kenjiArai 0:0ef6455cbb4d 235 if (recieved_uart_dat1 == true){
kenjiArai 0:0ef6455cbb4d 236 recieved_uart_dat1 = false;
kenjiArai 0:0ef6455cbb4d 237 for(int i = 0; i < uart_bf1_len; i++){
kenjiArai 2:6fb0b87b041d 238 PRINTF("%c", uart_buffer1[i]);
kenjiArai 0:0ef6455cbb4d 239 }
kenjiArai 2:6fb0b87b041d 240 PRINTF("\r\n");
kenjiArai 0:0ef6455cbb4d 241 }
kenjiArai 0:0ef6455cbb4d 242 if (line_input == true){
kenjiArai 0:0ef6455cbb4d 243 line_input = false;
kenjiArai 1:f68a5e55a60e 244 // Client to Server(central to peripheral)
kenjiArai 0:0ef6455cbb4d 245 adjust_line(linebuf);
kenjiArai 0:0ef6455cbb4d 246 int ret = uartTXCharacteristic.write(20, linebuf);
kenjiArai 0:0ef6455cbb4d 247 if (ret == BLE_ERROR_NONE){
kenjiArai 0:0ef6455cbb4d 248 DEBUG("\r\ndone (c2p)\r\n");
kenjiArai 0:0ef6455cbb4d 249 } else if (ret == BLE_STACK_BUSY){
kenjiArai 0:0ef6455cbb4d 250 DEBUG("\r\nbusy (c2p)\r\n");
kenjiArai 0:0ef6455cbb4d 251 } else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED) {
kenjiArai 0:0ef6455cbb4d 252 DEBUG("\r\nnot connected (c2d)\r\n");
kenjiArai 0:0ef6455cbb4d 253 } else {
kenjiArai 0:0ef6455cbb4d 254 DEBUG("\r\ncode %d (c2d)\r\n", ret);
kenjiArai 0:0ef6455cbb4d 255 }
kenjiArai 1:f68a5e55a60e 256 // Server to Client(peripheral to central)
kenjiArai 0:0ef6455cbb4d 257 if (ble.gap().getState().connected){
kenjiArai 0:0ef6455cbb4d 258 int ret = ble.gattServer().write(
kenjiArai 0:0ef6455cbb4d 259 uartServicePtr->getRXCharacteristicHandle(),
kenjiArai 0:0ef6455cbb4d 260 linebuf,
kenjiArai 0:0ef6455cbb4d 261 linebf_len
kenjiArai 0:0ef6455cbb4d 262 );
kenjiArai 0:0ef6455cbb4d 263 if (ret == BLE_ERROR_NONE){
kenjiArai 0:0ef6455cbb4d 264 DEBUG("\r\ndone (p2c)\r\n");
kenjiArai 0:0ef6455cbb4d 265 } else if (ret == BLE_STACK_BUSY){
kenjiArai 0:0ef6455cbb4d 266 DEBUG("\r\nbusy (p2c)\r\n");
kenjiArai 0:0ef6455cbb4d 267 } else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED){
kenjiArai 0:0ef6455cbb4d 268 DEBUG("\r\nnot connected (p2c)\r\n");
kenjiArai 0:0ef6455cbb4d 269 } else {
kenjiArai 0:0ef6455cbb4d 270 DEBUG("\r\ncode %d (p2c)\r\n", ret);
kenjiArai 0:0ef6455cbb4d 271 }
kenjiArai 0:0ef6455cbb4d 272 }
kenjiArai 0:0ef6455cbb4d 273 }
kenjiArai 2:6fb0b87b041d 274 if ((connection_tx == true) && (connection_rx == true) && (connection_1st == false)){
kenjiArai 2:6fb0b87b041d 275 PRINTF("Send *? Command\r\n");
kenjiArai 2:6fb0b87b041d 276 connection_1st = true;
kenjiArai 2:6fb0b87b041d 277 wait(3.0);
kenjiArai 2:6fb0b87b041d 278 // Client to Server(central to peripheral)
kenjiArai 2:6fb0b87b041d 279 // 12345678901234567890
kenjiArai 2:6fb0b87b041d 280 const uint8_t *msg = "*? ";
kenjiArai 2:6fb0b87b041d 281 uartTXCharacteristic.write(20, msg);
kenjiArai 2:6fb0b87b041d 282 }
kenjiArai 0:0ef6455cbb4d 283 ble.waitForEvent(); // save power
kenjiArai 0:0ef6455cbb4d 284 }
kenjiArai 0:0ef6455cbb4d 285 }
kenjiArai 0:0ef6455cbb4d 286
kenjiArai 0:0ef6455cbb4d 287 void serialRxCallback(){
kenjiArai 2:6fb0b87b041d 288 char c = GETC();
kenjiArai 0:0ef6455cbb4d 289 if (c == '\r') {
kenjiArai 0:0ef6455cbb4d 290 linebuf_irq[linebf_irq_len++] = c;
kenjiArai 2:6fb0b87b041d 291 PRINTF("\r\n");
kenjiArai 0:0ef6455cbb4d 292 linebf_len = linebf_irq_len;
kenjiArai 0:0ef6455cbb4d 293 strcpy((char *)linebuf, (char *)linebuf_irq);
kenjiArai 0:0ef6455cbb4d 294 linebf_irq_len = 0;
kenjiArai 0:0ef6455cbb4d 295 line_input = true;
kenjiArai 0:0ef6455cbb4d 296 } else if ((c == '\b') && linebf_irq_len) {
kenjiArai 0:0ef6455cbb4d 297 linebf_irq_len--;
kenjiArai 2:6fb0b87b041d 298 PUTC(c);
kenjiArai 2:6fb0b87b041d 299 PUTC(' ');
kenjiArai 2:6fb0b87b041d 300 PUTC(c);
kenjiArai 0:0ef6455cbb4d 301 } else if (((uint8_t)c >= ' ') && (linebf_irq_len < 20)) {
kenjiArai 0:0ef6455cbb4d 302 linebuf_irq[linebf_irq_len++] = c;
kenjiArai 2:6fb0b87b041d 303 PUTC(c);
kenjiArai 0:0ef6455cbb4d 304 } else if ( c == 0x1f ){ // Control+?
kenjiArai 2:6fb0b87b041d 305 NVIC_SystemReset(); // Reset
kenjiArai 0:0ef6455cbb4d 306 }
kenjiArai 0:0ef6455cbb4d 307 linebuf_irq[linebf_irq_len] = 0;
kenjiArai 0:0ef6455cbb4d 308 }
kenjiArai 0:0ef6455cbb4d 309
kenjiArai 0:0ef6455cbb4d 310 void adjust_line(uint8_t *bf){
kenjiArai 0:0ef6455cbb4d 311 uint8_t i, c;
kenjiArai 0:0ef6455cbb4d 312
kenjiArai 0:0ef6455cbb4d 313 for (i = 0; i <20; bf++, i++){
kenjiArai 0:0ef6455cbb4d 314 c = *bf;
kenjiArai 0:0ef6455cbb4d 315 if ( (c == '\r') || (c == '\n') || (c == 0)){
kenjiArai 0:0ef6455cbb4d 316 break;
kenjiArai 0:0ef6455cbb4d 317 }
kenjiArai 0:0ef6455cbb4d 318 }
kenjiArai 0:0ef6455cbb4d 319 for (; i < 20; bf++, i++){
kenjiArai 0:0ef6455cbb4d 320 *bf = ' ';
kenjiArai 0:0ef6455cbb4d 321 }
kenjiArai 0:0ef6455cbb4d 322 *(bf + 1) = 0;
kenjiArai 0:0ef6455cbb4d 323 }
kenjiArai 0:0ef6455cbb4d 324
kenjiArai 1:f68a5e55a60e 325 // Server(Peripheral) role ****************************************************
kenjiArai 0:0ef6455cbb4d 326 void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params){
kenjiArai 0:0ef6455cbb4d 327 if (uartServicePtr != NULL){
kenjiArai 0:0ef6455cbb4d 328 if ((params->handle ==
kenjiArai 0:0ef6455cbb4d 329 uartServicePtr->getTXCharacteristicHandle()) && (params->len >= 1))
kenjiArai 0:0ef6455cbb4d 330 {
kenjiArai 0:0ef6455cbb4d 331 uart_bf0_len = params->len;
kenjiArai 0:0ef6455cbb4d 332 strcpy((char *)uart_buffer0, (char *)params->data);
kenjiArai 0:0ef6455cbb4d 333 recieved_uart_dat0 = true;
kenjiArai 0:0ef6455cbb4d 334 }
kenjiArai 0:0ef6455cbb4d 335 }
kenjiArai 0:0ef6455cbb4d 336 }
kenjiArai 0:0ef6455cbb4d 337
kenjiArai 0:0ef6455cbb4d 338 void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params){
kenjiArai 0:0ef6455cbb4d 339 DEBUG(
kenjiArai 0:0ef6455cbb4d 340 "received HVX callback for handle %u; type %s\r\r\n",
kenjiArai 0:0ef6455cbb4d 341 params->handle,
kenjiArai 0:0ef6455cbb4d 342 (params->type == BLE_HVX_NOTIFICATION) ? "notification" : "indication"
kenjiArai 0:0ef6455cbb4d 343 );
kenjiArai 0:0ef6455cbb4d 344 if (params->type == BLE_HVX_NOTIFICATION){
kenjiArai 0:0ef6455cbb4d 345 if ((params->handle
kenjiArai 0:0ef6455cbb4d 346 == uartRXCharacteristic.getValueHandle()) && (params->len > 0))
kenjiArai 0:0ef6455cbb4d 347 {
kenjiArai 0:0ef6455cbb4d 348 uart_bf1_len = params->len;
kenjiArai 0:0ef6455cbb4d 349 strcpy((char *)uart_buffer1, (char *)params->data);
kenjiArai 0:0ef6455cbb4d 350 recieved_uart_dat1 = true;
kenjiArai 0:0ef6455cbb4d 351 }
kenjiArai 0:0ef6455cbb4d 352 }
kenjiArai 0:0ef6455cbb4d 353 }
kenjiArai 0:0ef6455cbb4d 354
kenjiArai 0:0ef6455cbb4d 355 void periodicCallback(void){
kenjiArai 0:0ef6455cbb4d 356 alivenessLED = !alivenessLED; // Do blinky on alivenessLED to indicate system aliveness
kenjiArai 1:f68a5e55a60e 357 if (connected2server){
kenjiArai 0:0ef6455cbb4d 358 connectedLED = 1;
kenjiArai 0:0ef6455cbb4d 359 } else {
kenjiArai 0:0ef6455cbb4d 360 connectedLED = 0;
kenjiArai 0:0ef6455cbb4d 361 }
kenjiArai 0:0ef6455cbb4d 362 }
kenjiArai 0:0ef6455cbb4d 363
kenjiArai 0:0ef6455cbb4d 364 bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2){
kenjiArai 0:0ef6455cbb4d 365 DEBUG("Address: ");
kenjiArai 0:0ef6455cbb4d 366 for (int i = 0; i < 6; i++){
kenjiArai 0:0ef6455cbb4d 367 DEBUG("0x%02x ", mac_1[i]);
kenjiArai 0:0ef6455cbb4d 368 }
kenjiArai 0:0ef6455cbb4d 369 DEBUG("\r\n");
kenjiArai 0:0ef6455cbb4d 370 for (int i = 0; i < 6; i++){
kenjiArai 0:0ef6455cbb4d 371 if (mac_1[i] != mac_2[i]){
kenjiArai 0:0ef6455cbb4d 372 DEBUG("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
kenjiArai 0:0ef6455cbb4d 373 return false;
kenjiArai 0:0ef6455cbb4d 374 } else {
kenjiArai 0:0ef6455cbb4d 375 DEBUG("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
kenjiArai 0:0ef6455cbb4d 376 }
kenjiArai 0:0ef6455cbb4d 377 }
kenjiArai 0:0ef6455cbb4d 378 return true;
kenjiArai 0:0ef6455cbb4d 379 }
kenjiArai 0:0ef6455cbb4d 380
kenjiArai 0:0ef6455cbb4d 381 int get_board_index(const Gap::Address_t mac){
kenjiArai 0:0ef6455cbb4d 382 if (mac_equals(mac, mac_board_0)) { return 0;}
kenjiArai 0:0ef6455cbb4d 383 if (mac_equals(mac, mac_board_1)) { return 1;}
kenjiArai 0:0ef6455cbb4d 384 if (mac_equals(mac, mac_board_2)) { return 2;}
kenjiArai 1:f68a5e55a60e 385 if (mac_equals(mac, mac_board_3)) { return 3;}
kenjiArai 1:f68a5e55a60e 386 if (mac_equals(mac, mac_board_4)) { return 4;}
kenjiArai 0:0ef6455cbb4d 387 return -1;
kenjiArai 0:0ef6455cbb4d 388 }
kenjiArai 0:0ef6455cbb4d 389
kenjiArai 0:0ef6455cbb4d 390 // Client(Central) role *******************************************************
kenjiArai 0:0ef6455cbb4d 391 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params){
kenjiArai 0:0ef6455cbb4d 392 // connections
kenjiArai 0:0ef6455cbb4d 393 int peer_board_index = get_board_index(params->peerAddr);
kenjiArai 0:0ef6455cbb4d 394 if (peer_board_index != -1){
kenjiArai 2:6fb0b87b041d 395 PRINTF("adv peerAddr");
kenjiArai 2:6fb0b87b041d 396 PRINTF(
kenjiArai 0:0ef6455cbb4d 397 "[%02x %02x %02x %02x %02x %02x] rssi %+4d, isScanResponse %u, AdvertisementType %u",
kenjiArai 0:0ef6455cbb4d 398 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3],
kenjiArai 0:0ef6455cbb4d 399 params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
kenjiArai 0:0ef6455cbb4d 400 params->rssi,
kenjiArai 0:0ef6455cbb4d 401 params->isScanResponse,
kenjiArai 0:0ef6455cbb4d 402 params->type
kenjiArai 0:0ef6455cbb4d 403 );
kenjiArai 2:6fb0b87b041d 404 PRINTF("\r\n");
kenjiArai 0:0ef6455cbb4d 405 ble.gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
kenjiArai 0:0ef6455cbb4d 406 }
kenjiArai 0:0ef6455cbb4d 407 }
kenjiArai 0:0ef6455cbb4d 408
kenjiArai 0:0ef6455cbb4d 409 void serviceDiscoveryCallback(const DiscoveredService *service) {
kenjiArai 0:0ef6455cbb4d 410 DEBUG("service found...\r\n");
kenjiArai 0:0ef6455cbb4d 411 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
kenjiArai 0:0ef6455cbb4d 412 DEBUG(
kenjiArai 0:0ef6455cbb4d 413 "Service UUID-%x attrs[%u %u]\r\n",
kenjiArai 0:0ef6455cbb4d 414 service->getUUID().getShortUUID(),
kenjiArai 0:0ef6455cbb4d 415 service->getStartHandle(),
kenjiArai 0:0ef6455cbb4d 416 service->getEndHandle()
kenjiArai 0:0ef6455cbb4d 417 );
kenjiArai 0:0ef6455cbb4d 418 } else {
kenjiArai 0:0ef6455cbb4d 419 DEBUG("Service UUID-");
kenjiArai 0:0ef6455cbb4d 420 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
kenjiArai 0:0ef6455cbb4d 421 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
kenjiArai 0:0ef6455cbb4d 422 DEBUG("%02x", longUUIDBytes[i]);
kenjiArai 0:0ef6455cbb4d 423 }
kenjiArai 0:0ef6455cbb4d 424 DEBUG(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
kenjiArai 0:0ef6455cbb4d 425 }
kenjiArai 0:0ef6455cbb4d 426 }
kenjiArai 0:0ef6455cbb4d 427
kenjiArai 0:0ef6455cbb4d 428 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP){
kenjiArai 0:0ef6455cbb4d 429 DEBUG(
kenjiArai 0:0ef6455cbb4d 430 " C UUID-%x valueAttr[%u] props[%x]\r\n",
kenjiArai 0:0ef6455cbb4d 431 characteristicP->getUUID().getShortUUID(),
kenjiArai 0:0ef6455cbb4d 432 characteristicP->getValueHandle(),
kenjiArai 0:0ef6455cbb4d 433 (uint8_t)characteristicP->getProperties().broadcast()
kenjiArai 0:0ef6455cbb4d 434 );
kenjiArai 0:0ef6455cbb4d 435 if (characteristicP->getUUID().getShortUUID()
kenjiArai 0:0ef6455cbb4d 436 == UARTServiceTXCharacteristicShortUUID)
kenjiArai 0:0ef6455cbb4d 437 {
kenjiArai 2:6fb0b87b041d 438 PRINTF("Sevice TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID);
kenjiArai 0:0ef6455cbb4d 439 uartTXCharacteristic = *characteristicP;
kenjiArai 2:6fb0b87b041d 440 connection_tx = true;
kenjiArai 0:0ef6455cbb4d 441 } else if (characteristicP->getUUID().getShortUUID()
kenjiArai 0:0ef6455cbb4d 442 == UARTServiceRXCharacteristicShortUUID)
kenjiArai 0:0ef6455cbb4d 443 {
kenjiArai 2:6fb0b87b041d 444 PRINTF("Sevice RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID);
kenjiArai 0:0ef6455cbb4d 445 uartRXCharacteristic = *characteristicP;
kenjiArai 0:0ef6455cbb4d 446 foundUartRXCharacteristic = true;
kenjiArai 2:6fb0b87b041d 447 connection_rx = true;
kenjiArai 0:0ef6455cbb4d 448 }
kenjiArai 0:0ef6455cbb4d 449 }
kenjiArai 0:0ef6455cbb4d 450
kenjiArai 0:0ef6455cbb4d 451 void discoveryTerminationCallback(Gap::Handle_t connectionHandle){
kenjiArai 0:0ef6455cbb4d 452 DEBUG("terminated SD for handle=%u\r\n", connectionHandle);
kenjiArai 0:0ef6455cbb4d 453 }
kenjiArai 0:0ef6455cbb4d 454
kenjiArai 0:0ef6455cbb4d 455 // Mixed role *****************************************************************
kenjiArai 0:0ef6455cbb4d 456 void connectionCallback(const Gap::ConnectionCallbackParams_t *params){
kenjiArai 0:0ef6455cbb4d 457 if (params->role == Gap::CENTRAL) {
kenjiArai 0:0ef6455cbb4d 458 DEBUG("connected as Client(central) (handle = %d)\r\n\r", params->handle);
kenjiArai 1:f68a5e55a60e 459 connected2server = true;
kenjiArai 0:0ef6455cbb4d 460 connectionHandle = params->handle;
kenjiArai 0:0ef6455cbb4d 461 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
kenjiArai 0:0ef6455cbb4d 462 ble.gattClient().launchServiceDiscovery(
kenjiArai 0:0ef6455cbb4d 463 params->handle,
kenjiArai 0:0ef6455cbb4d 464 serviceDiscoveryCallback,
kenjiArai 0:0ef6455cbb4d 465 characteristicDiscoveryCallback/*,
kenjiArai 0:0ef6455cbb4d 466 0xa000, 0xa001*/
kenjiArai 0:0ef6455cbb4d 467 );
kenjiArai 0:0ef6455cbb4d 468 } else {
kenjiArai 1:f68a5e55a60e 469 DEBUG("connected as Server (handle = %d)\r\n\r", params->handle);
kenjiArai 0:0ef6455cbb4d 470 DEBUG(
kenjiArai 0:0ef6455cbb4d 471 "Conn. params => min=%d, max=%d, slave=%d, supervision=%d\r\n",
kenjiArai 0:0ef6455cbb4d 472 params->connectionParams->minConnectionInterval,
kenjiArai 0:0ef6455cbb4d 473 params->connectionParams->maxConnectionInterval,
kenjiArai 0:0ef6455cbb4d 474 params->connectionParams->slaveLatency,
kenjiArai 0:0ef6455cbb4d 475 params->connectionParams->connectionSupervisionTimeout
kenjiArai 0:0ef6455cbb4d 476 );
kenjiArai 0:0ef6455cbb4d 477 Gap::ConnectionParams_t connectionParams;
kenjiArai 0:0ef6455cbb4d 478 connectionParams.minConnectionInterval = 6;
kenjiArai 0:0ef6455cbb4d 479 connectionParams.maxConnectionInterval = 12;
kenjiArai 0:0ef6455cbb4d 480 connectionParams.slaveLatency = 0;
kenjiArai 0:0ef6455cbb4d 481 connectionParams.connectionSupervisionTimeout = 500;
kenjiArai 0:0ef6455cbb4d 482 if (ble.updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE){
kenjiArai 0:0ef6455cbb4d 483 DEBUG("failed to update connection parameter\r\n");
kenjiArai 0:0ef6455cbb4d 484 }
kenjiArai 0:0ef6455cbb4d 485 }
kenjiArai 0:0ef6455cbb4d 486 DEBUG(
kenjiArai 0:0ef6455cbb4d 487 "own %02x:%02x:%02x:%02x:%02x:%02x (%s), peer %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n",
kenjiArai 0:0ef6455cbb4d 488 params->ownAddr[5], params->ownAddr[4], params->ownAddr[3],
kenjiArai 0:0ef6455cbb4d 489 params->ownAddr[2], params->ownAddr[1], params->ownAddr[0],
kenjiArai 0:0ef6455cbb4d 490 (params->ownAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random",
kenjiArai 0:0ef6455cbb4d 491 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3],
kenjiArai 0:0ef6455cbb4d 492 params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
kenjiArai 0:0ef6455cbb4d 493 (params->peerAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random"
kenjiArai 0:0ef6455cbb4d 494 );
kenjiArai 0:0ef6455cbb4d 495 }
kenjiArai 0:0ef6455cbb4d 496
kenjiArai 0:0ef6455cbb4d 497 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params){
kenjiArai 0:0ef6455cbb4d 498 DEBUG("handle = %d ", params->handle);
kenjiArai 2:6fb0b87b041d 499 PRINTF(" -> disconnected\r\n", params->handle);
kenjiArai 1:f68a5e55a60e 500 connected2server = false;
kenjiArai 2:6fb0b87b041d 501 connection_1st = false;
kenjiArai 2:6fb0b87b041d 502 connection_tx = false;
kenjiArai 2:6fb0b87b041d 503 connection_rx = false;
kenjiArai 0:0ef6455cbb4d 504 if (params->handle == SOFT_DEVICE_FATHER_HANDLE) {
kenjiArai 0:0ef6455cbb4d 505 ble.startAdvertising(); // restart advertising
kenjiArai 0:0ef6455cbb4d 506 } else {
kenjiArai 0:0ef6455cbb4d 507 ble.gap().startScan(advertisementCallback); // restart scan
kenjiArai 0:0ef6455cbb4d 508 }
kenjiArai 0:0ef6455cbb4d 509 }