BLE Client UART function

Dependencies:   RingBuffer

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers original.cpp Source File

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