Kenji Arai
/
BLE_Uart_Client
BLE Client UART function
Embed:
(wiki syntax)
Show/hide line numbers
original.cpp
00001 #if 0 00002 //------------------------------------------------------------------------------------------------- 00003 // ORIGINAL PROGRAM 00004 // S130 potential unstability case [closed] by Fabien Comte 00005 // https://devzone.nordicsemi.com/question/49705/s130-potential-unstability-case/ 00006 // 00007 #include "mbed.h" 00008 #include "BLE.h" 00009 #include "UARTService.h" 00010 #include "ble/DiscoveredCharacteristic.h" 00011 #include "ble/DiscoveredService.h" 00012 #include "ble/service/UARTService.h" 00013 00014 #define SOFT_DEVICE_FATHER_HANDLE 3 00015 00016 #define BOARDS_COUNT 3 00017 00018 const Gap::Address_t mac_board_0 = {0xb8, 0xac, 0x4e, 0x8d, 0x8b, 0xeb}; 00019 const Gap::Address_t mac_board_1 = {0x9c, 0x43, 0x62, 0x30, 0xaf, 0xd2}; 00020 const Gap::Address_t mac_board_2 = {0x5f, 0x1a, 0x9e, 0x6a, 0x63, 0xdd}; 00021 00022 00023 // tiny ble board 00024 #define LED_GREEN p21 00025 #define LED_RED p22 00026 #define LED_BLUE p23 00027 #define BUTTON_PIN p17 00028 #define BATTERY_PIN p1 00029 00030 #define MPU6050_SDA p12 00031 #define MPU6050_SCL p13 00032 00033 #define UART_TX p9 00034 #define UART_RX p11 00035 #define UART_CTS p8 00036 #define UART_RTS p10 00037 00038 DigitalOut led(LED_RED); 00039 DigitalOut alivenessLED(LED_GREEN); 00040 InterruptIn button(BUTTON_PIN); 00041 AnalogIn battery(BATTERY_PIN); 00042 Serial pc(UART_TX, UART_RX); 00043 00044 bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2) 00045 { 00046 #if 0 00047 if (mac_1[0] != mac_2[0]) 00048 { 00049 return false; 00050 } 00051 if (mac_1[1] != mac_2[1]) 00052 { 00053 return false; 00054 } 00055 if (mac_1[2] != mac_2[2]) 00056 { 00057 return false; 00058 } 00059 if (mac_1[3] != mac_2[3]) 00060 { 00061 return false; 00062 } 00063 if (mac_1[4] != mac_2[4]) 00064 { 00065 return false; 00066 } 00067 if (mac_1[5] != mac_2[5]) 00068 { 00069 return false; 00070 } 00071 #else 00072 for (int i = 0; i < 6; i++) 00073 { 00074 if (mac_1[i] != mac_2[i]) 00075 { 00076 //pc.printf("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i); 00077 return false; 00078 } 00079 else 00080 { 00081 //pc.printf("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i); 00082 } 00083 } 00084 #endif 00085 return true; 00086 } 00087 00088 int get_board_index(const Gap::Address_t mac) 00089 { 00090 if (mac_equals(mac, mac_board_0)) 00091 { 00092 return 0; 00093 } 00094 if (mac_equals(mac, mac_board_1)) 00095 { 00096 return 1; 00097 } 00098 if (mac_equals(mac, mac_board_2)) 00099 { 00100 return 2; 00101 } 00102 00103 return -1; 00104 } 00105 00106 void periodicCallback(void) 00107 { 00108 alivenessLED = !alivenessLED; /* do blinky on alivenessLED while we're waiting for BLE events */ 00109 } 00110 00111 00112 // Mixed role **************************************************** 00113 BLE ble; 00114 Gap::Address_t my_mac; 00115 int my_board_index = -1; 00116 00117 // Device role **************************************************** 00118 UARTService * uartServicePtr = NULL; 00119 const static char DEVICE_NAME[] = "ChangeMe!!"; // change this 00120 static const uint16_t uuid16_list[] = {UARTServiceShortUUID}; 00121 volatile int central_handle = -1; 00122 00123 00124 // Central role **************************************************** 00125 Gap::Handle_t connectionHandle = 0xFFFF; 00126 DiscoveredCharacteristic uartTXCharacteristic; 00127 DiscoveredCharacteristic uartRXCharacteristic; 00128 bool foundUartRXCharacteristic = false; 00129 volatile int device_handle = -1; 00130 00131 00132 // Device role **************************************************** 00133 void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params) 00134 { 00135 if (uartServicePtr != NULL) 00136 { 00137 if ((params->handle == uartServicePtr->getTXCharacteristicHandle()) && (params->len >= 1)) 00138 { 00139 if (params->data[0] != '0') 00140 { 00141 led = 1; 00142 } 00143 else 00144 { 00145 led = 0; 00146 } 00147 00148 for(int i = 0; i < params->len; i++) 00149 { 00150 pc.printf("%c", params->data[i]); 00151 } 00152 00153 pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle); 00154 } 00155 } 00156 } 00157 00158 // Central role **************************************************** 00159 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) 00160 { 00161 // do connections like a triangle 00162 int peer_board_index = get_board_index(params->peerAddr); 00163 00164 int next_board_index = my_board_index + 1; 00165 if (next_board_index >= BOARDS_COUNT) 00166 { 00167 next_board_index = 0; 00168 } 00169 00170 //pc.printf("adv %d, %d, %d\r\n", peer_board_index, my_board_index, next_board_index); 00171 00172 // force order 00173 if ((central_handle != -1) || (peer_board_index == 0)) 00174 { 00175 if (peer_board_index == next_board_index) 00176 { 00177 //pc.printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n", 00178 // params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0], 00179 // params->rssi, params->isScanResponse, params->type); 00180 00181 ble.gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); 00182 } 00183 } 00184 } 00185 00186 void serviceDiscoveryCallback(const DiscoveredService *service) 00187 { 00188 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) 00189 { 00190 pc.printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); 00191 } 00192 else 00193 { 00194 //pc.printf("S UUID-"); 00195 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); 00196 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) 00197 { 00198 pc.printf("%02x", longUUIDBytes[i]); 00199 } 00200 pc.printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); 00201 } 00202 } 00203 00204 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) 00205 { 00206 //pc.printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast()); 00207 if (characteristicP->getUUID().getShortUUID() == UARTServiceTXCharacteristicShortUUID) 00208 { 00209 pc.printf("fit TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID); 00210 /* !ALERT! Alter this filter to suit your device. */ 00211 uartTXCharacteristic = *characteristicP; 00212 } 00213 else if (characteristicP->getUUID().getShortUUID() == UARTServiceRXCharacteristicShortUUID) 00214 { 00215 pc.printf("fit RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID); 00216 /* !ALERT! Alter this filter to suit your device. */ 00217 uartRXCharacteristic = *characteristicP; 00218 foundUartRXCharacteristic = true; 00219 } 00220 } 00221 00222 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) 00223 { 00224 pc.printf("terminated SD for handle %u\r\n", connectionHandle); 00225 } 00226 00227 void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params) 00228 { 00229 //pc.printf("received HVX callback for handle %u; type %s\r\r\n", params->handle, (params->type == BLE_HVX_NOTIFICATION) ? "notification" : "indication"); 00230 if (params->type == BLE_HVX_NOTIFICATION) 00231 { 00232 if ((params->handle == uartRXCharacteristic.getValueHandle()) && (params->len > 0)) 00233 { 00234 for (int i = 0; i < params->len; i++) 00235 { 00236 pc.printf("%c", params->data[i]); 00237 } 00238 00239 pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle); 00240 } 00241 } 00242 else 00243 { 00244 pc.printf("%d\r\n", params->type); 00245 } 00246 } 00247 00248 // Mixed role **************************************************** 00249 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) 00250 { 00251 if (params->role == Gap::CENTRAL) 00252 { 00253 if (central_handle == -1) 00254 { 00255 ble.stopAdvertising(); // stop advertising during discovery, incoming connection breaks discovery 00256 } 00257 00258 device_handle = params->handle; 00259 pc.printf("connected as central (handle = %d)\r\n\r", params->handle); 00260 connectionHandle = params->handle; 00261 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback); 00262 int ret = ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, UARTServiceShortUUID/*, 0xa001*/); 00263 00264 if (ret != BLE_ERROR_NONE) 00265 { 00266 pc.printf("launchServiceDiscovery failed error = %d\r\n\r", ret); 00267 } 00268 } 00269 else 00270 { 00271 central_handle = params->handle; 00272 pc.printf("connected as device (handle = %d)\r\n\r", params->handle); 00273 00274 //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); 00275 /* 00276 Gap::ConnectionParams_t connectionParams; 00277 connectionParams.minConnectionInterval = 6; 00278 connectionParams.maxConnectionInterval = 12; 00279 connectionParams.slaveLatency = 40; 00280 connectionParams.connectionSupervisionTimeout = 500; 00281 00282 int ret = ble.updateConnectionParams(params->handle, &connectionParams); 00283 if (ret != BLE_ERROR_NONE) 00284 { 00285 pc.printf("failed to update connection parameter\r\n"); 00286 } 00287 */ 00288 } 00289 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"); 00290 } 00291 00292 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) 00293 { 00294 char * ascii_reason = "?"; 00295 switch (reason) 00296 { 00297 case Gap::CONNECTION_TIMEOUT: 00298 ascii_reason = "connection timeout"; 00299 break; 00300 case Gap::REMOTE_USER_TERMINATED_CONNECTION: 00301 ascii_reason = "user terminated connection"; 00302 break; 00303 case Gap::REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES: 00304 ascii_reason = "low resources"; 00305 break; 00306 case Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF: 00307 ascii_reason = "power off"; 00308 break; 00309 case Gap::LOCAL_HOST_TERMINATED_CONNECTION: 00310 ascii_reason = "host terminated connection"; 00311 break; 00312 case Gap::CONN_INTERVAL_UNACCEPTABLE: 00313 ascii_reason = "interval unacceptable"; 00314 break; 00315 default: 00316 ascii_reason = "unknown"; 00317 break; 00318 } 00319 00320 pc.printf("disconnected (reason = %s, handle = %d)\r\n", ascii_reason, handle); 00321 00322 00323 if (handle == SOFT_DEVICE_FATHER_HANDLE) 00324 { 00325 central_handle = -1; 00326 // restart advertising 00327 ble.startAdvertising(); 00328 } 00329 else 00330 { 00331 device_handle = -1; 00332 // restart scan 00333 ble.gap().startScan(advertisementCallback); 00334 } 00335 } 00336 00337 00338 00339 void serialTxCallback() 00340 { 00341 00342 } 00343 00344 int rx_char = -1; 00345 void serialRxCallback() 00346 { 00347 if (rx_char != -1) 00348 { 00349 pc.printf("overflow\r\n"); 00350 } 00351 00352 //computer.putc(computer.getc()); 00353 rx_char = pc.getc(); 00354 } 00355 00356 /* 00357 void gattServerOnDataSent(unsigned count) 00358 { 00359 00360 } 00361 */ 00362 00363 00364 int main(void) 00365 { 00366 alivenessLED = 0; 00367 00368 pc.baud(115200); 00369 //pc.attach(&serialTxCallback, Serial::TxIrq); 00370 pc.attach(&serialRxCallback, Serial::RxIrq); 00371 00372 // clear terminal output 00373 for (int k = 0; k < 32; k++) 00374 { 00375 pc.printf("\r\n"); 00376 } 00377 00378 pc.printf("Central and device\r\n"); 00379 00380 Ticker ticker; 00381 ticker.attach(periodicCallback, 1); 00382 00383 00384 // Mixed role **************************************************** 00385 ble.init(); 00386 00387 Gap::AddressType_t my_mac_type; 00388 ble.gap().getAddress(&my_mac_type, my_mac); 00389 my_board_index = get_board_index(my_mac); 00390 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"); 00391 00392 00393 // try to speed up but looks like if it was ignored 00394 Gap::ConnectionParams_t fast; 00395 if (ble.getPreferredConnectionParams(&fast) != BLE_ERROR_NONE) 00396 { 00397 pc.printf("getPreferredConnectionParams failed\r\n"); 00398 } 00399 else 00400 { 00401 fast.minConnectionInterval = 16; // 20 ms 00402 fast.maxConnectionInterval = 32; // 40 ms 00403 fast.slaveLatency = 0; 00404 if (ble.gap().setPreferredConnectionParams(&fast) != BLE_ERROR_NONE) 00405 { 00406 pc.printf("setPreferredConnectionParams failed\r\n"); 00407 } 00408 } 00409 ble.gap().onConnection(connectionCallback); 00410 ble.gap().onDisconnection(disconnectionCallback); 00411 00412 // Device role **************************************************** 00413 ble.gattServer().onDataWritten(onReceivedDataFromCentralCallback); 00414 //ble.gattServer().onDataSent(gattServerOnDataSent); 00415 00416 UARTService uartService(ble); 00417 uartServicePtr = &uartService; 00418 00419 // setup advertising 00420 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); // BLE only, no classic BT 00421 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); // add name 00422 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // UUID's broadcast in advertising packet 00423 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // advertising type 00424 ble.setAdvertisingInterval(100); 00425 00426 // Central role **************************************************** 00427 ble.gattClient().onHVX(onReceivedDataFromDeviceCallback); 00428 ble.gap().setScanParams(500, 450); 00429 00430 00431 // start advertising and scan 00432 ble.startAdvertising(); 00433 ble.gap().startScan(advertisementCallback); 00434 00435 while (true) 00436 { 00437 // allow notifications from device 00438 if (foundUartRXCharacteristic && !ble.gattClient().isServiceDiscoveryActive()) 00439 { 00440 foundUartRXCharacteristic = false; /* need to do the following only once */ 00441 00442 uint16_t value = BLE_HVX_NOTIFICATION; 00443 int ret = ble.gattClient().write(GattClient::GATT_OP_WRITE_REQ, 00444 connectionHandle, 00445 uartRXCharacteristic.getValueHandle() + 1, /* HACK Alert. We're assuming that CCCD descriptor immediately follows the value attribute. */ 00446 sizeof(uint16_t), /* HACK Alert! size should be made into a BLE_API constant. */ 00447 reinterpret_cast<const uint8_t *>(&value)); 00448 00449 if (ret == BLE_ERROR_NONE) 00450 { 00451 pc.printf("\r\ndevice notifications enabled\r\n"); 00452 } 00453 else 00454 { 00455 switch (ret) 00456 { 00457 case BLE_STACK_BUSY: 00458 foundUartRXCharacteristic = true; // retry later 00459 break; 00460 case BLE_ERROR_NO_MEM: 00461 foundUartRXCharacteristic = true; // retry later 00462 break; 00463 case BLE_ERROR_INVALID_STATE: 00464 pc.printf("\r\ndevice notifications enable failed\r\n"); 00465 break; 00466 default: 00467 break; 00468 } 00469 } 00470 00471 if (!foundUartRXCharacteristic) 00472 { 00473 if (central_handle == -1) 00474 { 00475 ble.startAdvertising(); 00476 } 00477 } 00478 } 00479 00480 // while a new char from computer is available 00481 while (rx_char != -1) 00482 { 00483 uint8_t temp[20]; 00484 int length = 1; 00485 00486 uint8_t command = rx_char; 00487 rx_char = -1; 00488 00489 // if special char to test a 20 bytes frame 00490 /* 00491 if (command == '*') 00492 { 00493 pc.printf("20 chars\r\n"); 00494 00495 int c = 0; 00496 for (c = 0; c < 20; c++) 00497 { 00498 temp[c] = 'a' + c; 00499 } 00500 length = 20; 00501 } 00502 else 00503 { 00504 temp[0] = command; 00505 } 00506 */ 00507 temp[0] = command; 00508 00509 // to central 00510 //if (command == '1') 00511 { 00512 if (central_handle != -1) 00513 { 00514 // device to central 00515 while (1) 00516 { 00517 if (central_handle == -1) 00518 { 00519 pc.printf("\r\ndisconnected 1 (to central)\r\n"); 00520 break; 00521 } 00522 if (!ble.gap().getState().connected) 00523 { 00524 pc.printf("\r\ndisconnected 2 (to central)\r\n"); 00525 break; 00526 } 00527 int ret = ble.gattServer().write(uartServicePtr->getRXCharacteristicHandle(), temp, length); 00528 00529 if (ret == BLE_ERROR_NONE) 00530 { 00531 //pc.printf("\r\nok (to central)\r\n"); 00532 break; 00533 } 00534 else if (ret == BLE_STACK_BUSY) 00535 { 00536 //pc.printf("\r\nbusy (to central)\r\n"); 00537 //break; 00538 } 00539 else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED) 00540 { 00541 pc.printf("\r\nnot permitted (to central)\r\n"); 00542 break; 00543 } 00544 else if (ret == BLE_ERROR_INVALID_STATE) 00545 { 00546 pc.printf("\r\ninvalid state (to central)\r\n"); 00547 break; 00548 } 00549 else 00550 { 00551 pc.printf("\r\ncode %d (to central)\r\n", ret); 00552 break; 00553 } 00554 } 00555 } 00556 else 00557 { 00558 pc.printf("\r\nnot connected with central\r\n"); 00559 } 00560 } 00561 00562 // to device 00563 //if (command == '2') 00564 { 00565 if (device_handle != -1) 00566 { 00567 // central to device 00568 while (1) 00569 { 00570 if (device_handle == -1) 00571 { 00572 pc.printf("\r\ndisconnected (to device)\r\n"); 00573 break; 00574 } 00575 int ret = uartTXCharacteristic.write(length, temp); 00576 if (ret == BLE_ERROR_NONE) 00577 { 00578 //pc.printf("\r\nok (to device)\r\n"); 00579 break; 00580 } 00581 else if (ret == BLE_STACK_BUSY) 00582 { 00583 //pc.printf("\r\nbusy (to device)\r\n"); 00584 //break; 00585 } 00586 else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED) 00587 { 00588 pc.printf("\r\nnot permitted (to device)\r\n"); 00589 break; 00590 } 00591 else if (ret == BLE_ERROR_INVALID_STATE) 00592 { 00593 pc.printf("\r\ninvalid state (to device)\r\n"); 00594 break; 00595 } 00596 else 00597 { 00598 pc.printf("\r\ncode %d (to device)\r\n", ret); 00599 break; 00600 } 00601 } 00602 } 00603 else 00604 { 00605 pc.printf("\r\nnot connected with device\r\n"); 00606 } 00607 } 00608 } 00609 00610 ble.waitForEvent(); // save power 00611 } 00612 } 00613 00614 #endif
Generated on Fri Jul 15 2022 16:37:01 by 1.7.2