With this example the latency time of a simple toggle command can be measured. Central device is looking for a peripheral called LED, connects with it and toggles the LED periodically. The time until the service of the peripheral is updated, is measured as latency time

Dependencies:   BLE_API mbed nRF51822

Committer:
Alexgerni
Date:
Fri Dec 01 17:15:02 2017 +0000
Revision:
1:e79b40b523b4
Parent:
0:c201f85a188c
Updated software in a way that the latency time is measured via pin interrupts with a external uC. Also the connectionParameters can be adjusted.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Alexgerni 0:c201f85a188c 1 /* mbed Microcontroller Library
Alexgerni 0:c201f85a188c 2 * Copyright (c) 2006-2015 ARM Limited
Alexgerni 0:c201f85a188c 3 *
Alexgerni 0:c201f85a188c 4 * Licensed under the Apache License, Version 2.0 (the "License");
Alexgerni 0:c201f85a188c 5 * you may not use this file except in compliance with the License.
Alexgerni 0:c201f85a188c 6 * You may obtain a copy of the License at
Alexgerni 0:c201f85a188c 7 *
Alexgerni 0:c201f85a188c 8 * http://www.apache.org/licenses/LICENSE-2.0
Alexgerni 0:c201f85a188c 9 *
Alexgerni 0:c201f85a188c 10 * Unless required by applicable law or agreed to in writing, software
Alexgerni 0:c201f85a188c 11 * distributed under the License is distributed on an "AS IS" BASIS,
Alexgerni 0:c201f85a188c 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Alexgerni 0:c201f85a188c 13 * See the License for the specific language governing permissions and
Alexgerni 0:c201f85a188c 14 * limitations under the License.
Alexgerni 0:c201f85a188c 15 */
Alexgerni 0:c201f85a188c 16
Alexgerni 0:c201f85a188c 17 #include "mbed.h"
Alexgerni 0:c201f85a188c 18 #include "ble/BLE.h"
Alexgerni 0:c201f85a188c 19 #include "ble/DiscoveredCharacteristic.h"
Alexgerni 1:e79b40b523b4 20 #include "ble/Gap.h"
Alexgerni 0:c201f85a188c 21
Alexgerni 0:c201f85a188c 22 DigitalOut alivenessLED(p16, 1);
Alexgerni 0:c201f85a188c 23 DigitalOut gateLED(p15,1);
Alexgerni 1:e79b40b523b4 24 DigitalOut flagStart(p2, 0);
Alexgerni 1:e79b40b523b4 25 DigitalOut flagStop(p3, 1);
Alexgerni 1:e79b40b523b4 26
Alexgerni 1:e79b40b523b4 27
Alexgerni 0:c201f85a188c 28 //InterruptIn button(p9);
Alexgerni 0:c201f85a188c 29 Serial pc(p5, p4);
Alexgerni 0:c201f85a188c 30 Ticker ticker, loop;
Alexgerni 0:c201f85a188c 31 Timer latency;
Alexgerni 0:c201f85a188c 32
Alexgerni 1:e79b40b523b4 33 timestamp_t latencyTime;
Alexgerni 0:c201f85a188c 34 uint8_t toggledValue = 0x1;
Alexgerni 0:c201f85a188c 35 uint8_t counter = 0;
Alexgerni 0:c201f85a188c 36 uint8_t randNumber = 5;
Alexgerni 0:c201f85a188c 37 uint8_t randCount = 10;
Alexgerni 0:c201f85a188c 38
Alexgerni 0:c201f85a188c 39 static DiscoveredCharacteristic ledCharacteristic;
Alexgerni 0:c201f85a188c 40 static const char PEER_NAME[] = "LED";
Alexgerni 1:e79b40b523b4 41 static Gap::ConnectionParams_t para;
Alexgerni 0:c201f85a188c 42
Alexgerni 0:c201f85a188c 43 void periodicCallback(void)
Alexgerni 0:c201f85a188c 44 {
Alexgerni 1:e79b40b523b4 45 if(!BLE::Instance().getGapState().connected){
Alexgerni 0:c201f85a188c 46 alivenessLED = !alivenessLED; /* Do blinky on LED1 while waiting for BLE events */
Alexgerni 0:c201f85a188c 47 gateLED = 1;
Alexgerni 0:c201f85a188c 48 }
Alexgerni 0:c201f85a188c 49 counter += 1;
Alexgerni 0:c201f85a188c 50 }
Alexgerni 0:c201f85a188c 51
Alexgerni 1:e79b40b523b4 52 void triggerCallback(void)
Alexgerni 0:c201f85a188c 53 {
Alexgerni 0:c201f85a188c 54 randCount = 0;
Alexgerni 1:e79b40b523b4 55 if(!BLE::Instance().getGapState().connected){
Alexgerni 0:c201f85a188c 56 //pc.printf("not connected \n");
Alexgerni 0:c201f85a188c 57 return;
Alexgerni 0:c201f85a188c 58 }
Alexgerni 0:c201f85a188c 59 else{
Alexgerni 1:e79b40b523b4 60 if(counter > 5 && flagStop.read()){
Alexgerni 0:c201f85a188c 61 alivenessLED = 1;
Alexgerni 1:e79b40b523b4 62 //latency.start();
Alexgerni 1:e79b40b523b4 63 flagStart = 1;
Alexgerni 1:e79b40b523b4 64 flagStop = 0;
Alexgerni 0:c201f85a188c 65 toggledValue = toggledValue ^ 0x1;
Alexgerni 0:c201f85a188c 66 ledCharacteristic.write(1, &toggledValue);
Alexgerni 1:e79b40b523b4 67 //pc.printf("AckStatus = %i \n", AckStatus);
Alexgerni 0:c201f85a188c 68 }
Alexgerni 0:c201f85a188c 69 }
Alexgerni 0:c201f85a188c 70 }
Alexgerni 0:c201f85a188c 71
Alexgerni 0:c201f85a188c 72 void randCallback(void)
Alexgerni 0:c201f85a188c 73 {
Alexgerni 1:e79b40b523b4 74 //Gap::GapState_t GapInfo; //class Gap with struct GapState_t
Alexgerni 0:c201f85a188c 75 randCount += 1;
Alexgerni 1:e79b40b523b4 76 if(randCount > randNumber+1 && BLE::Instance().getGapState().connected){
Alexgerni 1:e79b40b523b4 77 //if(BLE::Instance().getGapState().connected){
Alexgerni 1:e79b40b523b4 78
Alexgerni 1:e79b40b523b4 79 triggerCallback();
Alexgerni 0:c201f85a188c 80 gateLED = !gateLED;
Alexgerni 0:c201f85a188c 81 }
Alexgerni 0:c201f85a188c 82 }
Alexgerni 0:c201f85a188c 83
Alexgerni 0:c201f85a188c 84 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params)
Alexgerni 0:c201f85a188c 85 {
Alexgerni 0:c201f85a188c 86 for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
Alexgerni 0:c201f85a188c 87
Alexgerni 0:c201f85a188c 88 const uint8_t record_length = params->advertisingData[i];
Alexgerni 0:c201f85a188c 89 if (record_length == 0) {
Alexgerni 0:c201f85a188c 90 continue;
Alexgerni 0:c201f85a188c 91 }
Alexgerni 1:e79b40b523b4 92 const uint8_t type = params->advertisingData[i + 1]; // PDU Advertising // AD length 1B / AD type 1B / AD data 0-22B //
Alexgerni 1:e79b40b523b4 93 const uint8_t* value = params->advertisingData + i + 2; //pointer adresse + i + 2, so AD data
Alexgerni 0:c201f85a188c 94 const uint8_t value_length = record_length - 1;
Alexgerni 0:c201f85a188c 95
Alexgerni 1:e79b40b523b4 96 if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) { //0x09 is type of complete local name
Alexgerni 0:c201f85a188c 97 if ((value_length == sizeof(PEER_NAME)) && (memcmp(value, PEER_NAME, value_length) == 0)) { /* compares name LED with advertisingData*/
Alexgerni 0:c201f85a188c 98 pc.printf(
Alexgerni 1:e79b40b523b4 99 "adv peerAddr[%02x %02x %02x %02x %02x %02x], LocalName %s, rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
Alexgerni 0:c201f85a188c 100 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2],
Alexgerni 1:e79b40b523b4 101 params->peerAddr[1], params->peerAddr[0], value, params->rssi, params->isScanResponse, params->type
Alexgerni 0:c201f85a188c 102 );
Alexgerni 1:e79b40b523b4 103 printf("\r\n");
Alexgerni 1:e79b40b523b4 104
Alexgerni 1:e79b40b523b4 105 //create wanted ConnectionParameters (defined in nrf51822/target_nrf5/source/nrf5xGap.cpp)
Alexgerni 1:e79b40b523b4 106 para.minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(100);
Alexgerni 1:e79b40b523b4 107 para.maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(100);
Alexgerni 1:e79b40b523b4 108 para.slaveLatency = 0;
Alexgerni 1:e79b40b523b4 109 para.connectionSupervisionTimeout = 600;
Alexgerni 1:e79b40b523b4 110
Alexgerni 1:e79b40b523b4 111 BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, &para, NULL);
Alexgerni 0:c201f85a188c 112 break;
Alexgerni 0:c201f85a188c 113 }
Alexgerni 0:c201f85a188c 114 }
Alexgerni 0:c201f85a188c 115 i += record_length;
Alexgerni 0:c201f85a188c 116 }
Alexgerni 0:c201f85a188c 117 }
Alexgerni 0:c201f85a188c 118
Alexgerni 0:c201f85a188c 119 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP)
Alexgerni 0:c201f85a188c 120 {
Alexgerni 1:e79b40b523b4 121 pc.printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().read());
Alexgerni 0:c201f85a188c 122 if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* LED characteristic of device (Read/Write) */
Alexgerni 0:c201f85a188c 123 ledCharacteristic = *characteristicP;
Alexgerni 0:c201f85a188c 124 }
Alexgerni 0:c201f85a188c 125 }
Alexgerni 0:c201f85a188c 126
Alexgerni 1:e79b40b523b4 127 void writeResponseCallback(const GattWriteCallbackParams *response)
Alexgerni 0:c201f85a188c 128 {
Alexgerni 1:e79b40b523b4 129 if (response->handle == ledCharacteristic.getValueHandle()) { //handle is ID of connection
Alexgerni 1:e79b40b523b4 130 //ledCharacteristic.read();
Alexgerni 1:e79b40b523b4 131 //latency.stop();
Alexgerni 1:e79b40b523b4 132 flagStart = 0;
Alexgerni 1:e79b40b523b4 133 flagStop = 1;
Alexgerni 1:e79b40b523b4 134 //latencyTime = latency.read_high_resolution_us();
Alexgerni 1:e79b40b523b4 135 //latency.reset();
Alexgerni 0:c201f85a188c 136
Alexgerni 0:c201f85a188c 137 //pc.printf("ledCharacteristic: %d %d\r\n",response->data[0],response->data[1]);
Alexgerni 1:e79b40b523b4 138 //pc.printf("Latency Time: %d us \n",latencyTime);
Alexgerni 0:c201f85a188c 139 //writeVal(latencyTime);
Alexgerni 0:c201f85a188c 140 randNumber = rand()%10; //number between 0 and 9
Alexgerni 1:e79b40b523b4 141 /*pc.printf("triggerRead: handle %u, writeOp %u \r\n", response->connHandle, response->writeOp);
Alexgerni 1:e79b40b523b4 142 for (unsigned index = 0; index < response->len; index++) {
Alexgerni 1:e79b40b523b4 143 printf("%c[%02x]", response->data[index], response->data[index]);
Alexgerni 1:e79b40b523b4 144 }
Alexgerni 1:e79b40b523b4 145 pc.printf("\r\n");*/
Alexgerni 0:c201f85a188c 146 }
Alexgerni 0:c201f85a188c 147 }
Alexgerni 0:c201f85a188c 148
Alexgerni 0:c201f85a188c 149 void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
Alexgerni 0:c201f85a188c 150 {
Alexgerni 0:c201f85a188c 151 if (params->role == Gap::CENTRAL) {
Alexgerni 0:c201f85a188c 152 BLE &ble = BLE::Instance();
Alexgerni 0:c201f85a188c 153 //ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
Alexgerni 0:c201f85a188c 154 ble.gattClient().launchServiceDiscovery(params->handle, NULL, characteristicDiscoveryCallback, 0xa000, 0xa001);
Alexgerni 1:e79b40b523b4 155
Alexgerni 1:e79b40b523b4 156 uint16_t slaveLat = params->connectionParams->slaveLatency;
Alexgerni 1:e79b40b523b4 157 uint16_t maxConnectionInt = params->connectionParams->maxConnectionInterval;
Alexgerni 1:e79b40b523b4 158 uint16_t minConnectionInt = params->connectionParams->minConnectionInterval;
Alexgerni 1:e79b40b523b4 159 uint16_t connectionTimeout = params->connectionParams->connectionSupervisionTimeout;
Alexgerni 1:e79b40b523b4 160
Alexgerni 1:e79b40b523b4 161 pc.printf("slaveLatency %u, minConnection %u, maxConnection %u, connectionTimeout %u \n", slaveLat, minConnectionInt, maxConnectionInt, connectionTimeout);
Alexgerni 1:e79b40b523b4 162 pc.printf("handle %u, role %u \n", params->handle, params->role);
Alexgerni 1:e79b40b523b4 163 pc.printf("connected\r\n");
Alexgerni 1:e79b40b523b4 164 pc.printf("\r\n");
Alexgerni 0:c201f85a188c 165 }
Alexgerni 0:c201f85a188c 166 }
Alexgerni 0:c201f85a188c 167
Alexgerni 0:c201f85a188c 168 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
Alexgerni 0:c201f85a188c 169 {
Alexgerni 0:c201f85a188c 170 pc.printf("disconnected\r\n");
Alexgerni 0:c201f85a188c 171 /* Start scanning and try to connect again */
Alexgerni 0:c201f85a188c 172 BLE::Instance().gap().startScan(advertisementCallback);
Alexgerni 0:c201f85a188c 173 counter = 0;
Alexgerni 0:c201f85a188c 174 }
Alexgerni 0:c201f85a188c 175
Alexgerni 0:c201f85a188c 176 void onBleInitError(BLE &ble, ble_error_t error)
Alexgerni 0:c201f85a188c 177 {
Alexgerni 0:c201f85a188c 178 /* Initialization error handling should go here */
Alexgerni 0:c201f85a188c 179 }
Alexgerni 0:c201f85a188c 180
Alexgerni 0:c201f85a188c 181 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
Alexgerni 0:c201f85a188c 182 {
Alexgerni 0:c201f85a188c 183 BLE& ble = params->ble;
Alexgerni 0:c201f85a188c 184 ble_error_t error = params->error;
Alexgerni 0:c201f85a188c 185
Alexgerni 0:c201f85a188c 186 if (error != BLE_ERROR_NONE) {
Alexgerni 0:c201f85a188c 187 /* In case of error, forward the error handling to onBleInitError */
Alexgerni 0:c201f85a188c 188 onBleInitError(ble, error);
Alexgerni 0:c201f85a188c 189 return;
Alexgerni 0:c201f85a188c 190 }
Alexgerni 0:c201f85a188c 191
Alexgerni 0:c201f85a188c 192 /* Ensure that it is the default instance of BLE */
Alexgerni 0:c201f85a188c 193 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
Alexgerni 0:c201f85a188c 194 return;
Alexgerni 0:c201f85a188c 195 }
Alexgerni 0:c201f85a188c 196
Alexgerni 0:c201f85a188c 197 ble.gap().onDisconnection(disconnectionCallback);
Alexgerni 0:c201f85a188c 198 ble.gap().onConnection(connectionCallback);
Alexgerni 0:c201f85a188c 199
Alexgerni 1:e79b40b523b4 200 ble.gattClient().onDataWritten(writeResponseCallback);
Alexgerni 0:c201f85a188c 201
Alexgerni 0:c201f85a188c 202 // scan interval: 400ms and scan window: 400ms.
Alexgerni 0:c201f85a188c 203 // Every 400ms the device will scan for 400ms
Alexgerni 0:c201f85a188c 204 // This means that the device will scan continuously.
Alexgerni 0:c201f85a188c 205 ble.gap().setScanParams(400, 400);
Alexgerni 0:c201f85a188c 206 ble.gap().startScan(advertisementCallback);
Alexgerni 1:e79b40b523b4 207
Alexgerni 0:c201f85a188c 208 }
Alexgerni 0:c201f85a188c 209
Alexgerni 0:c201f85a188c 210
Alexgerni 0:c201f85a188c 211 int main(void) {
Alexgerni 0:c201f85a188c 212 pc.baud(115200);
Alexgerni 0:c201f85a188c 213
Alexgerni 0:c201f85a188c 214 ticker.attach(periodicCallback, 1); /* Blink LED every second */
Alexgerni 0:c201f85a188c 215 //button.rise(buttonPressedCallback);
Alexgerni 1:e79b40b523b4 216 loop.attach(randCallback, 0.01);
Alexgerni 0:c201f85a188c 217 srand(time(NULL));
Alexgerni 0:c201f85a188c 218
Alexgerni 0:c201f85a188c 219 BLE &ble = BLE::Instance();
Alexgerni 0:c201f85a188c 220 ble.init(bleInitComplete);
Alexgerni 1:e79b40b523b4 221 pc.printf("Initialization complete... \n");
Alexgerni 1:e79b40b523b4 222
Alexgerni 0:c201f85a188c 223 counter = 0;
Alexgerni 1:e79b40b523b4 224 //latency.reset();
Alexgerni 0:c201f85a188c 225
Alexgerni 0:c201f85a188c 226 while (true) {
Alexgerni 0:c201f85a188c 227 ble.waitForEvent();
Alexgerni 0:c201f85a188c 228 }
Alexgerni 0:c201f85a188c 229 }