ENSMM / Mbed OS BLE-GAP

Fork of BLE-GAP by Joël Imbaud

Committer:
mbed_official
Date:
Wed Jun 20 11:03:19 2018 +0100
Revision:
1:d4bb1e33950e
Parent:
0:8539ba0984da
Child:
10:6f1c573093c1
Merge pull request #158 from adbridge/master

Updating mbed-os to mbed-os-5.8.6
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-ble

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 1:d4bb1e33950e 1 /* mbed Microcontroller Library
mbed_official 1:d4bb1e33950e 2 * Copyright (c) 2006-2013 ARM Limited
mbed_official 1:d4bb1e33950e 3 *
mbed_official 1:d4bb1e33950e 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 1:d4bb1e33950e 5 * you may not use this file except in compliance with the License.
mbed_official 1:d4bb1e33950e 6 * You may obtain a copy of the License at
mbed_official 1:d4bb1e33950e 7 *
mbed_official 1:d4bb1e33950e 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 1:d4bb1e33950e 9 *
mbed_official 1:d4bb1e33950e 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 1:d4bb1e33950e 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 1:d4bb1e33950e 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 1:d4bb1e33950e 13 * See the License for the specific language governing permissions and
mbed_official 1:d4bb1e33950e 14 * limitations under the License.
mbed_official 1:d4bb1e33950e 15 */
mbed_official 1:d4bb1e33950e 16
mbed_official 1:d4bb1e33950e 17 #include <events/mbed_events.h>
mbed_official 1:d4bb1e33950e 18 #include <mbed.h>
mbed_official 1:d4bb1e33950e 19 #include "ble/BLE.h"
mbed_official 1:d4bb1e33950e 20
mbed_official 1:d4bb1e33950e 21 /** This example demonstrates all the basic setup required
mbed_official 1:d4bb1e33950e 22 * to advertise, scan and connect to other devices.
mbed_official 1:d4bb1e33950e 23 *
mbed_official 1:d4bb1e33950e 24 * It contains a single class that performs both scans and advertisements.
mbed_official 1:d4bb1e33950e 25 *
mbed_official 1:d4bb1e33950e 26 * The demonstrations happens in sequence, after each "mode" ends
mbed_official 1:d4bb1e33950e 27 * the demo jumps to the next mode to continue. There are several modes
mbed_official 1:d4bb1e33950e 28 * that show scanning and several showing advertising. These are configured
mbed_official 1:d4bb1e33950e 29 * according to the two arrays containing parameters. During scanning
mbed_official 1:d4bb1e33950e 30 * a connection will be made to a connectable device upon its discovery.
mbed_official 1:d4bb1e33950e 31 */
mbed_official 1:d4bb1e33950e 32
mbed_official 1:d4bb1e33950e 33 static const uint8_t DEVICE_NAME[] = "GAP_device";
mbed_official 1:d4bb1e33950e 34
mbed_official 1:d4bb1e33950e 35 /* Duration of each mode in milliseconds */
mbed_official 1:d4bb1e33950e 36 static const size_t MODE_DURATION_MS = 6000;
mbed_official 1:d4bb1e33950e 37
mbed_official 1:d4bb1e33950e 38 /* Time between each mode in milliseconds */
mbed_official 1:d4bb1e33950e 39 static const size_t TIME_BETWEEN_MODES_MS = 2000;
mbed_official 1:d4bb1e33950e 40
mbed_official 1:d4bb1e33950e 41 /* how long to wait before disconnecting in milliseconds */
mbed_official 1:d4bb1e33950e 42 static const size_t CONNECTION_DURATION = 3000;
mbed_official 1:d4bb1e33950e 43
mbed_official 1:d4bb1e33950e 44 typedef struct {
mbed_official 1:d4bb1e33950e 45 GapAdvertisingParams::AdvertisingType_t adv_type;
mbed_official 1:d4bb1e33950e 46 uint16_t interval;
mbed_official 1:d4bb1e33950e 47 uint16_t timeout;
mbed_official 1:d4bb1e33950e 48 } AdvModeParam_t;
mbed_official 1:d4bb1e33950e 49
mbed_official 1:d4bb1e33950e 50 typedef struct {
mbed_official 1:d4bb1e33950e 51 uint16_t interval;
mbed_official 1:d4bb1e33950e 52 uint16_t window;
mbed_official 1:d4bb1e33950e 53 uint16_t timeout;
mbed_official 1:d4bb1e33950e 54 bool active;
mbed_official 1:d4bb1e33950e 55 } ScanModeParam_t;
mbed_official 1:d4bb1e33950e 56
mbed_official 1:d4bb1e33950e 57 /** the entries in this array are used to configure our advertising
mbed_official 1:d4bb1e33950e 58 * parameters for each of the modes we use in our demo */
mbed_official 1:d4bb1e33950e 59 static const AdvModeParam_t advertising_params[] = {
mbed_official 1:d4bb1e33950e 60 /* advertising type interval timeout */
mbed_official 1:d4bb1e33950e 61 { GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED, 40,/*ms*/ 3/*s*/},
mbed_official 1:d4bb1e33950e 62 { GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED, 100, 4 },
mbed_official 1:d4bb1e33950e 63 { GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED, 100, 0 }
mbed_official 1:d4bb1e33950e 64 };
mbed_official 1:d4bb1e33950e 65
mbed_official 1:d4bb1e33950e 66 /* when we cycle through all our advertising modes we will move to scanning modes */
mbed_official 1:d4bb1e33950e 67
mbed_official 1:d4bb1e33950e 68 /** the entries in this array are used to configure our scanning
mbed_official 1:d4bb1e33950e 69 * parameters for each of the modes we use in our demo */
mbed_official 1:d4bb1e33950e 70 static const ScanModeParam_t scanning_params[] = {
mbed_official 1:d4bb1e33950e 71 /* interval window timeout active */
mbed_official 1:d4bb1e33950e 72 { 4,/*ms*/ 4,/*ms*/ 0,/*s*/ false },
mbed_official 1:d4bb1e33950e 73 { 160, 100, 3, false },
mbed_official 1:d4bb1e33950e 74 { 160, 40, 0, true },
mbed_official 1:d4bb1e33950e 75 { 500, 10, 0, false }
mbed_official 1:d4bb1e33950e 76 };
mbed_official 1:d4bb1e33950e 77
mbed_official 1:d4bb1e33950e 78 /* parameters to use when attempting to connect to maximise speed of connection */
mbed_official 1:d4bb1e33950e 79 static const GapScanningParams connection_scan_params(
mbed_official 1:d4bb1e33950e 80 GapScanningParams::SCAN_INTERVAL_MAX,
mbed_official 1:d4bb1e33950e 81 GapScanningParams::SCAN_WINDOW_MAX,
mbed_official 1:d4bb1e33950e 82 3,
mbed_official 1:d4bb1e33950e 83 false
mbed_official 1:d4bb1e33950e 84 );
mbed_official 1:d4bb1e33950e 85
mbed_official 1:d4bb1e33950e 86 /* get number of items in our arrays */
mbed_official 1:d4bb1e33950e 87 static const size_t SCAN_PARAM_SET_MAX =
mbed_official 1:d4bb1e33950e 88 sizeof(scanning_params) / sizeof(GapScanningParams);
mbed_official 1:d4bb1e33950e 89 static const size_t ADV_PARAM_SET_MAX =
mbed_official 1:d4bb1e33950e 90 sizeof(advertising_params) / sizeof(GapAdvertisingParams);
mbed_official 1:d4bb1e33950e 91
mbed_official 1:d4bb1e33950e 92
mbed_official 1:d4bb1e33950e 93 /** Demonstrate advertising, scanning and connecting
mbed_official 1:d4bb1e33950e 94 */
mbed_official 1:d4bb1e33950e 95 class GAPDevice : private mbed::NonCopyable<GAPDevice>
mbed_official 1:d4bb1e33950e 96 {
mbed_official 1:d4bb1e33950e 97 public:
mbed_official 1:d4bb1e33950e 98 GAPDevice() :
mbed_official 1:d4bb1e33950e 99 _ble(BLE::Instance()),
mbed_official 1:d4bb1e33950e 100 _led1(LED1, 0),
mbed_official 1:d4bb1e33950e 101 _set_index(0),
mbed_official 1:d4bb1e33950e 102 _is_in_scanning_mode(false),
mbed_official 1:d4bb1e33950e 103 _is_connecting(false),
mbed_official 1:d4bb1e33950e 104 _on_duration_end_id(0),
mbed_official 1:d4bb1e33950e 105 _scan_count(0) { };
mbed_official 1:d4bb1e33950e 106
mbed_official 1:d4bb1e33950e 107 ~GAPDevice()
mbed_official 1:d4bb1e33950e 108 {
mbed_official 1:d4bb1e33950e 109 if (_ble.hasInitialized()) {
mbed_official 1:d4bb1e33950e 110 _ble.shutdown();
mbed_official 1:d4bb1e33950e 111 }
mbed_official 1:d4bb1e33950e 112 };
mbed_official 1:d4bb1e33950e 113
mbed_official 1:d4bb1e33950e 114 /** Start BLE interface initialisation */
mbed_official 1:d4bb1e33950e 115 void run()
mbed_official 1:d4bb1e33950e 116 {
mbed_official 1:d4bb1e33950e 117 ble_error_t error;
mbed_official 1:d4bb1e33950e 118
mbed_official 1:d4bb1e33950e 119 if (_ble.hasInitialized()) {
mbed_official 1:d4bb1e33950e 120 printf("Ble instance already initialised.\r\n");
mbed_official 1:d4bb1e33950e 121 return;
mbed_official 1:d4bb1e33950e 122 }
mbed_official 1:d4bb1e33950e 123
mbed_official 1:d4bb1e33950e 124 /* this will inform us off all events so we can schedule their handling
mbed_official 1:d4bb1e33950e 125 * using our event queue */
mbed_official 1:d4bb1e33950e 126 _ble.onEventsToProcess(
mbed_official 1:d4bb1e33950e 127 makeFunctionPointer(this, &GAPDevice::schedule_ble_events)
mbed_official 1:d4bb1e33950e 128 );
mbed_official 1:d4bb1e33950e 129
mbed_official 1:d4bb1e33950e 130 /* handle timeouts, for example when connection attempts fail */
mbed_official 1:d4bb1e33950e 131 _ble.gap().onTimeout(
mbed_official 1:d4bb1e33950e 132 makeFunctionPointer(this, &GAPDevice::on_timeout)
mbed_official 1:d4bb1e33950e 133 );
mbed_official 1:d4bb1e33950e 134
mbed_official 1:d4bb1e33950e 135 error = _ble.init(this, &GAPDevice::on_init_complete);
mbed_official 1:d4bb1e33950e 136
mbed_official 1:d4bb1e33950e 137 if (error) {
mbed_official 1:d4bb1e33950e 138 printf("Error returned by BLE::init.\r\n");
mbed_official 1:d4bb1e33950e 139 return;
mbed_official 1:d4bb1e33950e 140 }
mbed_official 1:d4bb1e33950e 141
mbed_official 1:d4bb1e33950e 142 /* to show we're running we'll blink every 500ms */
mbed_official 1:d4bb1e33950e 143 _event_queue.call_every(500, this, &GAPDevice::blink);
mbed_official 1:d4bb1e33950e 144
mbed_official 1:d4bb1e33950e 145 /* this will not return until shutdown */
mbed_official 1:d4bb1e33950e 146 _event_queue.dispatch_forever();
mbed_official 1:d4bb1e33950e 147 };
mbed_official 1:d4bb1e33950e 148
mbed_official 1:d4bb1e33950e 149 private:
mbed_official 1:d4bb1e33950e 150 /** This is called when BLE interface is initialised and starts the first mode */
mbed_official 1:d4bb1e33950e 151 void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
mbed_official 1:d4bb1e33950e 152 {
mbed_official 1:d4bb1e33950e 153 if (event->error) {
mbed_official 1:d4bb1e33950e 154 printf("Error during the initialisation\r\n");
mbed_official 1:d4bb1e33950e 155 return;
mbed_official 1:d4bb1e33950e 156 }
mbed_official 1:d4bb1e33950e 157
mbed_official 1:d4bb1e33950e 158 /* print device address */
mbed_official 1:d4bb1e33950e 159 Gap::AddressType_t addr_type;
mbed_official 1:d4bb1e33950e 160 Gap::Address_t addr;
mbed_official 1:d4bb1e33950e 161 _ble.gap().getAddress(&addr_type, addr);
mbed_official 1:d4bb1e33950e 162 printf("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
mbed_official 1:d4bb1e33950e 163 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
mbed_official 1:d4bb1e33950e 164
mbed_official 1:d4bb1e33950e 165 /* all calls are serialised on the user thread through the event queue */
mbed_official 1:d4bb1e33950e 166 _event_queue.call(this, &GAPDevice::demo_mode_start);
mbed_official 1:d4bb1e33950e 167 };
mbed_official 1:d4bb1e33950e 168
mbed_official 1:d4bb1e33950e 169 /** queue up start of the current demo mode */
mbed_official 1:d4bb1e33950e 170 void demo_mode_start()
mbed_official 1:d4bb1e33950e 171 {
mbed_official 1:d4bb1e33950e 172 if (_is_in_scanning_mode) {
mbed_official 1:d4bb1e33950e 173 /* when scanning we want to connect to a peer device so we need to
mbed_official 1:d4bb1e33950e 174 * attach callbacks that are used by Gap to notify us of events */
mbed_official 1:d4bb1e33950e 175 _ble.gap().onConnection(this, &GAPDevice::on_connect);
mbed_official 1:d4bb1e33950e 176 _ble.gap().onDisconnection(this, &GAPDevice::on_disconnect);
mbed_official 1:d4bb1e33950e 177
mbed_official 1:d4bb1e33950e 178 _event_queue.call(this, &GAPDevice::scan);
mbed_official 1:d4bb1e33950e 179 } else {
mbed_official 1:d4bb1e33950e 180 _event_queue.call(this, &GAPDevice::advertise);
mbed_official 1:d4bb1e33950e 181 }
mbed_official 1:d4bb1e33950e 182
mbed_official 1:d4bb1e33950e 183 /* for performance measurement keep track of duration of the demo mode */
mbed_official 1:d4bb1e33950e 184 _demo_duration.start();
mbed_official 1:d4bb1e33950e 185 /* keep track of our state */
mbed_official 1:d4bb1e33950e 186 _is_connecting = false;
mbed_official 1:d4bb1e33950e 187
mbed_official 1:d4bb1e33950e 188 /* queue up next demo mode */
mbed_official 1:d4bb1e33950e 189 _on_duration_end_id = _event_queue.call_in(
mbed_official 1:d4bb1e33950e 190 MODE_DURATION_MS, this, &GAPDevice::on_duration_end
mbed_official 1:d4bb1e33950e 191 );
mbed_official 1:d4bb1e33950e 192
mbed_official 1:d4bb1e33950e 193 printf("\r\n");
mbed_official 1:d4bb1e33950e 194 }
mbed_official 1:d4bb1e33950e 195
mbed_official 1:d4bb1e33950e 196 /** Set up and start advertising */
mbed_official 1:d4bb1e33950e 197 void advertise()
mbed_official 1:d4bb1e33950e 198 {
mbed_official 1:d4bb1e33950e 199 ble_error_t error;
mbed_official 1:d4bb1e33950e 200 GapAdvertisingData advertising_data;
mbed_official 1:d4bb1e33950e 201
mbed_official 1:d4bb1e33950e 202 /* add advertising flags */
mbed_official 1:d4bb1e33950e 203 advertising_data.addFlags(GapAdvertisingData::LE_GENERAL_DISCOVERABLE
mbed_official 1:d4bb1e33950e 204 | GapAdvertisingData::BREDR_NOT_SUPPORTED);
mbed_official 1:d4bb1e33950e 205
mbed_official 1:d4bb1e33950e 206 /* add device name */
mbed_official 1:d4bb1e33950e 207 advertising_data.addData(
mbed_official 1:d4bb1e33950e 208 GapAdvertisingData::COMPLETE_LOCAL_NAME,
mbed_official 1:d4bb1e33950e 209 DEVICE_NAME,
mbed_official 1:d4bb1e33950e 210 sizeof(DEVICE_NAME)
mbed_official 1:d4bb1e33950e 211 );
mbed_official 1:d4bb1e33950e 212
mbed_official 1:d4bb1e33950e 213 error = _ble.gap().setAdvertisingPayload(advertising_data);
mbed_official 1:d4bb1e33950e 214
mbed_official 1:d4bb1e33950e 215 if (error) {
mbed_official 1:d4bb1e33950e 216 printf("Error during Gap::setAdvertisingPayload\r\n");
mbed_official 1:d4bb1e33950e 217 return;
mbed_official 1:d4bb1e33950e 218 }
mbed_official 1:d4bb1e33950e 219
mbed_official 1:d4bb1e33950e 220 /* set the advertising parameters according to currently selected set,
mbed_official 1:d4bb1e33950e 221 * see @AdvertisingType_t for explanation of modes */
mbed_official 1:d4bb1e33950e 222 GapAdvertisingParams::AdvertisingType_t adv_type =
mbed_official 1:d4bb1e33950e 223 advertising_params[_set_index].adv_type;
mbed_official 1:d4bb1e33950e 224
mbed_official 1:d4bb1e33950e 225 /* how many milliseconds between advertisements, lower interval
mbed_official 1:d4bb1e33950e 226 * increases the chances of being seen at the cost of more power */
mbed_official 1:d4bb1e33950e 227 uint16_t interval = advertising_params[_set_index].interval;
mbed_official 1:d4bb1e33950e 228
mbed_official 1:d4bb1e33950e 229 /* advertising will continue for this many seconds or until connected */
mbed_official 1:d4bb1e33950e 230 uint16_t timeout = advertising_params[_set_index].timeout;
mbed_official 1:d4bb1e33950e 231
mbed_official 1:d4bb1e33950e 232 _ble.gap().setAdvertisingType(adv_type);
mbed_official 1:d4bb1e33950e 233 _ble.gap().setAdvertisingInterval(interval);
mbed_official 1:d4bb1e33950e 234 _ble.gap().setAdvertisingTimeout(timeout);
mbed_official 1:d4bb1e33950e 235
mbed_official 1:d4bb1e33950e 236 error = _ble.gap().startAdvertising();
mbed_official 1:d4bb1e33950e 237
mbed_official 1:d4bb1e33950e 238 if (error) {
mbed_official 1:d4bb1e33950e 239 printf("Error during Gap::startAdvertising.\r\n");
mbed_official 1:d4bb1e33950e 240 return;
mbed_official 1:d4bb1e33950e 241 }
mbed_official 1:d4bb1e33950e 242
mbed_official 1:d4bb1e33950e 243 printf("Advertising started (type: 0x%x, interval: %dms, timeout: %ds)\r\n",
mbed_official 1:d4bb1e33950e 244 adv_type, interval, timeout);
mbed_official 1:d4bb1e33950e 245 };
mbed_official 1:d4bb1e33950e 246
mbed_official 1:d4bb1e33950e 247 /** Set up and start scanning */
mbed_official 1:d4bb1e33950e 248 void scan()
mbed_official 1:d4bb1e33950e 249 {
mbed_official 1:d4bb1e33950e 250 ble_error_t error;
mbed_official 1:d4bb1e33950e 251
mbed_official 1:d4bb1e33950e 252 /* scanning happens repeatedly, interval is the number of milliseconds
mbed_official 1:d4bb1e33950e 253 * between each cycle of scanning */
mbed_official 1:d4bb1e33950e 254 uint16_t interval = scanning_params[_set_index].interval;
mbed_official 1:d4bb1e33950e 255
mbed_official 1:d4bb1e33950e 256 /* number of milliseconds we scan for each time we enter
mbed_official 1:d4bb1e33950e 257 * the scanning cycle after the interval set above */
mbed_official 1:d4bb1e33950e 258 uint16_t window = scanning_params[_set_index].window;
mbed_official 1:d4bb1e33950e 259
mbed_official 1:d4bb1e33950e 260 /* how long to repeat the cycles of scanning in seconds */
mbed_official 1:d4bb1e33950e 261 uint16_t timeout = scanning_params[_set_index].timeout;
mbed_official 1:d4bb1e33950e 262
mbed_official 1:d4bb1e33950e 263 /* active scanning will send a scan request to any scanable devices that
mbed_official 1:d4bb1e33950e 264 * we see advertising */
mbed_official 1:d4bb1e33950e 265 bool active = scanning_params[_set_index].active;
mbed_official 1:d4bb1e33950e 266
mbed_official 1:d4bb1e33950e 267 /* set the scanning parameters according to currently selected set */
mbed_official 1:d4bb1e33950e 268 error = _ble.gap().setScanParams(interval, window, timeout, active);
mbed_official 1:d4bb1e33950e 269
mbed_official 1:d4bb1e33950e 270 if (error) {
mbed_official 1:d4bb1e33950e 271 printf("Error during Gap::setScanParams\r\n");
mbed_official 1:d4bb1e33950e 272 return;
mbed_official 1:d4bb1e33950e 273 }
mbed_official 1:d4bb1e33950e 274
mbed_official 1:d4bb1e33950e 275 /* start scanning and attach a callback that will handle advertisements
mbed_official 1:d4bb1e33950e 276 * and scan requests responses */
mbed_official 1:d4bb1e33950e 277 error = _ble.gap().startScan(this, &GAPDevice::on_scan);
mbed_official 1:d4bb1e33950e 278
mbed_official 1:d4bb1e33950e 279 if (error) {
mbed_official 1:d4bb1e33950e 280 printf("Error during Gap::startScan\r\n");
mbed_official 1:d4bb1e33950e 281 return;
mbed_official 1:d4bb1e33950e 282 }
mbed_official 1:d4bb1e33950e 283
mbed_official 1:d4bb1e33950e 284 printf("Scanning started (interval: %dms, window: %dms, timeout: %ds).\r\n",
mbed_official 1:d4bb1e33950e 285 interval, window, timeout);
mbed_official 1:d4bb1e33950e 286 };
mbed_official 1:d4bb1e33950e 287
mbed_official 1:d4bb1e33950e 288 /** After a set duration this cycles to the next demo mode
mbed_official 1:d4bb1e33950e 289 * unless a connection happened first */
mbed_official 1:d4bb1e33950e 290 void on_duration_end()
mbed_official 1:d4bb1e33950e 291 {
mbed_official 1:d4bb1e33950e 292 print_performance();
mbed_official 1:d4bb1e33950e 293
mbed_official 1:d4bb1e33950e 294 /* alloted time has elapsed, move to next demo mode */
mbed_official 1:d4bb1e33950e 295 _event_queue.call(this, &GAPDevice::demo_mode_end);
mbed_official 1:d4bb1e33950e 296 };
mbed_official 1:d4bb1e33950e 297
mbed_official 1:d4bb1e33950e 298 /** Look at scan payload to find a peer device and connect to it */
mbed_official 1:d4bb1e33950e 299 void on_scan(const Gap::AdvertisementCallbackParams_t *params)
mbed_official 1:d4bb1e33950e 300 {
mbed_official 1:d4bb1e33950e 301 /* keep track of scan events for performance reporting */
mbed_official 1:d4bb1e33950e 302 _scan_count++;
mbed_official 1:d4bb1e33950e 303
mbed_official 1:d4bb1e33950e 304 /* don't bother with analysing scan result if we're already connecting */
mbed_official 1:d4bb1e33950e 305 if (_is_connecting) {
mbed_official 1:d4bb1e33950e 306 return;
mbed_official 1:d4bb1e33950e 307 }
mbed_official 1:d4bb1e33950e 308
mbed_official 1:d4bb1e33950e 309 /* parse the advertising payload, looking for a discoverable device */
mbed_official 1:d4bb1e33950e 310 for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
mbed_official 1:d4bb1e33950e 311 /* The advertising payload is a collection of key/value records where
mbed_official 1:d4bb1e33950e 312 * byte 0: length of the record excluding this byte
mbed_official 1:d4bb1e33950e 313 * byte 1: The key, it is the type of the data
mbed_official 1:d4bb1e33950e 314 * byte [2..N] The value. N is equal to byte0 - 1 */
mbed_official 1:d4bb1e33950e 315 const uint8_t record_length = params->advertisingData[i];
mbed_official 1:d4bb1e33950e 316 if (record_length == 0) {
mbed_official 1:d4bb1e33950e 317 continue;
mbed_official 1:d4bb1e33950e 318 }
mbed_official 1:d4bb1e33950e 319 const uint8_t type = params->advertisingData[i + 1];
mbed_official 1:d4bb1e33950e 320 const uint8_t *value = params->advertisingData + i + 2;
mbed_official 1:d4bb1e33950e 321
mbed_official 1:d4bb1e33950e 322 /* connect to a discoverable device */
mbed_official 1:d4bb1e33950e 323 if ((type == GapAdvertisingData::FLAGS)
mbed_official 1:d4bb1e33950e 324 && (*value & GapAdvertisingData::LE_GENERAL_DISCOVERABLE)) {
mbed_official 1:d4bb1e33950e 325
mbed_official 1:d4bb1e33950e 326 /* abort timeout as the mode will end on disconnection */
mbed_official 1:d4bb1e33950e 327 _event_queue.cancel(_on_duration_end_id);
mbed_official 1:d4bb1e33950e 328
mbed_official 1:d4bb1e33950e 329 printf("We found a connectable device\r\n");
mbed_official 1:d4bb1e33950e 330
mbed_official 1:d4bb1e33950e 331 ble_error_t error = _ble.gap().connect(
mbed_official 1:d4bb1e33950e 332 params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC,
mbed_official 1:d4bb1e33950e 333 NULL, &connection_scan_params
mbed_official 1:d4bb1e33950e 334 );
mbed_official 1:d4bb1e33950e 335
mbed_official 1:d4bb1e33950e 336 if (error) {
mbed_official 1:d4bb1e33950e 337 printf("Error during Gap::connect\r\n");
mbed_official 1:d4bb1e33950e 338 /* since no connection will be attempted end the mode */
mbed_official 1:d4bb1e33950e 339 _event_queue.call(this, &GAPDevice::demo_mode_end);
mbed_official 1:d4bb1e33950e 340 return;
mbed_official 1:d4bb1e33950e 341 }
mbed_official 1:d4bb1e33950e 342
mbed_official 1:d4bb1e33950e 343 /* we may have already scan events waiting
mbed_official 1:d4bb1e33950e 344 * to be processed so we need to remember
mbed_official 1:d4bb1e33950e 345 * that we are already connecting and ignore them */
mbed_official 1:d4bb1e33950e 346 _is_connecting = true;
mbed_official 1:d4bb1e33950e 347
mbed_official 1:d4bb1e33950e 348 return;
mbed_official 1:d4bb1e33950e 349 }
mbed_official 1:d4bb1e33950e 350
mbed_official 1:d4bb1e33950e 351 i += record_length;
mbed_official 1:d4bb1e33950e 352 }
mbed_official 1:d4bb1e33950e 353 };
mbed_official 1:d4bb1e33950e 354
mbed_official 1:d4bb1e33950e 355 /** This is called by Gap to notify the application we connected,
mbed_official 1:d4bb1e33950e 356 * in our case it immediately disconnects */
mbed_official 1:d4bb1e33950e 357 void on_connect(const Gap::ConnectionCallbackParams_t *connection_event)
mbed_official 1:d4bb1e33950e 358 {
mbed_official 1:d4bb1e33950e 359 print_performance();
mbed_official 1:d4bb1e33950e 360
mbed_official 1:d4bb1e33950e 361 printf("Connected in %dms\r\n", _demo_duration.read_ms());
mbed_official 1:d4bb1e33950e 362
mbed_official 1:d4bb1e33950e 363 /* cancel the connect timeout since we connected */
mbed_official 1:d4bb1e33950e 364 _event_queue.cancel(_on_duration_end_id);
mbed_official 1:d4bb1e33950e 365
mbed_official 1:d4bb1e33950e 366 _event_queue.call_in(
mbed_official 1:d4bb1e33950e 367 CONNECTION_DURATION, &_ble.gap(), &Gap::disconnect, Gap::REMOTE_USER_TERMINATED_CONNECTION
mbed_official 1:d4bb1e33950e 368 );
mbed_official 1:d4bb1e33950e 369 };
mbed_official 1:d4bb1e33950e 370
mbed_official 1:d4bb1e33950e 371 /** This is called by Gap to notify the application we disconnected,
mbed_official 1:d4bb1e33950e 372 * in our case it calls demo_mode_end() to progress the demo */
mbed_official 1:d4bb1e33950e 373 void on_disconnect(const Gap::DisconnectionCallbackParams_t *event)
mbed_official 1:d4bb1e33950e 374 {
mbed_official 1:d4bb1e33950e 375 printf("Disconnected\r\n");
mbed_official 1:d4bb1e33950e 376
mbed_official 1:d4bb1e33950e 377 /* we have successfully disconnected ending the demo, move to next mode */
mbed_official 1:d4bb1e33950e 378 _event_queue.call(this, &GAPDevice::demo_mode_end);
mbed_official 1:d4bb1e33950e 379 };
mbed_official 1:d4bb1e33950e 380
mbed_official 1:d4bb1e33950e 381 /** called if timeout is reached during advertising, scanning
mbed_official 1:d4bb1e33950e 382 * or connection initiation */
mbed_official 1:d4bb1e33950e 383 void on_timeout(const Gap::TimeoutSource_t source)
mbed_official 1:d4bb1e33950e 384 {
mbed_official 1:d4bb1e33950e 385 _demo_duration.stop();
mbed_official 1:d4bb1e33950e 386
mbed_official 1:d4bb1e33950e 387 switch (source) {
mbed_official 1:d4bb1e33950e 388 case Gap::TIMEOUT_SRC_ADVERTISING:
mbed_official 1:d4bb1e33950e 389 printf("Stopped advertising early due to timeout parameter\r\n");
mbed_official 1:d4bb1e33950e 390 break;
mbed_official 1:d4bb1e33950e 391 case Gap::TIMEOUT_SRC_SCAN:
mbed_official 1:d4bb1e33950e 392 printf("Stopped scanning early due to timeout parameter\r\n");
mbed_official 1:d4bb1e33950e 393 break;
mbed_official 1:d4bb1e33950e 394 case Gap::TIMEOUT_SRC_CONN:
mbed_official 1:d4bb1e33950e 395 printf("Failed to connect after scanning %d advertisements\r\n", _scan_count);
mbed_official 1:d4bb1e33950e 396 _event_queue.call(this, &GAPDevice::print_performance);
mbed_official 1:d4bb1e33950e 397 _event_queue.call(this, &GAPDevice::demo_mode_end);
mbed_official 1:d4bb1e33950e 398 break;
mbed_official 1:d4bb1e33950e 399 default:
mbed_official 1:d4bb1e33950e 400 printf("Unexpected timeout\r\n");
mbed_official 1:d4bb1e33950e 401 break;
mbed_official 1:d4bb1e33950e 402 }
mbed_official 1:d4bb1e33950e 403 };
mbed_official 1:d4bb1e33950e 404
mbed_official 1:d4bb1e33950e 405 /** clean up after last run, cycle to the next mode and launch it */
mbed_official 1:d4bb1e33950e 406 void demo_mode_end()
mbed_official 1:d4bb1e33950e 407 {
mbed_official 1:d4bb1e33950e 408 /* reset the demo ready for the next mode */
mbed_official 1:d4bb1e33950e 409 _scan_count = 0;
mbed_official 1:d4bb1e33950e 410 _demo_duration.stop();
mbed_official 1:d4bb1e33950e 411 _demo_duration.reset();
mbed_official 1:d4bb1e33950e 412
mbed_official 1:d4bb1e33950e 413 /* cycle through all demo modes */
mbed_official 1:d4bb1e33950e 414 _set_index++;
mbed_official 1:d4bb1e33950e 415
mbed_official 1:d4bb1e33950e 416 /* switch between advertising and scanning when we go
mbed_official 1:d4bb1e33950e 417 * through all the params in the array */
mbed_official 1:d4bb1e33950e 418 if (_set_index >= (_is_in_scanning_mode? SCAN_PARAM_SET_MAX : ADV_PARAM_SET_MAX)) {
mbed_official 1:d4bb1e33950e 419 _set_index = 0;
mbed_official 1:d4bb1e33950e 420 _is_in_scanning_mode = !_is_in_scanning_mode;
mbed_official 1:d4bb1e33950e 421 }
mbed_official 1:d4bb1e33950e 422
mbed_official 1:d4bb1e33950e 423 _ble.shutdown();
mbed_official 1:d4bb1e33950e 424 _event_queue.break_dispatch();
mbed_official 1:d4bb1e33950e 425 };
mbed_official 1:d4bb1e33950e 426
mbed_official 1:d4bb1e33950e 427 /** print some information about our radio activity */
mbed_official 1:d4bb1e33950e 428 void print_performance()
mbed_official 1:d4bb1e33950e 429 {
mbed_official 1:d4bb1e33950e 430 /* measure time from mode start, may have been stopped by timeout */
mbed_official 1:d4bb1e33950e 431 uint16_t duration = _demo_duration.read_ms();
mbed_official 1:d4bb1e33950e 432
mbed_official 1:d4bb1e33950e 433 if (_is_in_scanning_mode) {
mbed_official 1:d4bb1e33950e 434 /* convert ms into timeslots for accurate calculation as internally
mbed_official 1:d4bb1e33950e 435 * all durations are in timeslots (0.625ms) */
mbed_official 1:d4bb1e33950e 436 uint16_t interval_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
mbed_official 1:d4bb1e33950e 437 scanning_params[_set_index].interval
mbed_official 1:d4bb1e33950e 438 );
mbed_official 1:d4bb1e33950e 439 uint16_t window_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
mbed_official 1:d4bb1e33950e 440 scanning_params[_set_index].window
mbed_official 1:d4bb1e33950e 441 );
mbed_official 1:d4bb1e33950e 442 uint16_t duration_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
mbed_official 1:d4bb1e33950e 443 duration
mbed_official 1:d4bb1e33950e 444 );
mbed_official 1:d4bb1e33950e 445 /* this is how long we scanned for in timeslots */
mbed_official 1:d4bb1e33950e 446 uint16_t rx_ts = (duration_ts / interval_ts) * window_ts;
mbed_official 1:d4bb1e33950e 447 /* convert to milliseconds */
mbed_official 1:d4bb1e33950e 448 uint16_t rx_ms = (rx_ts * GapScanningParams::UNIT_0_625_MS) / 1000;
mbed_official 1:d4bb1e33950e 449
mbed_official 1:d4bb1e33950e 450 printf("We have scanned for %dms with an interval of %d"
mbed_official 1:d4bb1e33950e 451 " timeslot and a window of %d timeslots\r\n",
mbed_official 1:d4bb1e33950e 452 duration, interval_ts, window_ts);
mbed_official 1:d4bb1e33950e 453
mbed_official 1:d4bb1e33950e 454 printf("We have been listening on the radio for at least %dms\r\n", rx_ms);
mbed_official 1:d4bb1e33950e 455
mbed_official 1:d4bb1e33950e 456 } else /* advertising */ {
mbed_official 1:d4bb1e33950e 457
mbed_official 1:d4bb1e33950e 458 /* convert ms into timeslots for accurate calculation as internally
mbed_official 1:d4bb1e33950e 459 * all durations are in timeslots (0.625ms) */
mbed_official 1:d4bb1e33950e 460 uint16_t interval_ts = GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(
mbed_official 1:d4bb1e33950e 461 advertising_params[_set_index].interval
mbed_official 1:d4bb1e33950e 462 );
mbed_official 1:d4bb1e33950e 463 uint16_t duration_ts = GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(
mbed_official 1:d4bb1e33950e 464 duration
mbed_official 1:d4bb1e33950e 465 );
mbed_official 1:d4bb1e33950e 466 /* this is how many times we advertised */
mbed_official 1:d4bb1e33950e 467 uint16_t events = duration_ts / interval_ts;
mbed_official 1:d4bb1e33950e 468
mbed_official 1:d4bb1e33950e 469 printf("We have advertised for %dms"
mbed_official 1:d4bb1e33950e 470 " with an interval of %d timeslots\r\n",
mbed_official 1:d4bb1e33950e 471 duration, interval_ts);
mbed_official 1:d4bb1e33950e 472
mbed_official 1:d4bb1e33950e 473 /* non-scannable and non-connectable advertising
mbed_official 1:d4bb1e33950e 474 * skips rx events saving on power consumption */
mbed_official 1:d4bb1e33950e 475 if (advertising_params[_set_index].adv_type
mbed_official 1:d4bb1e33950e 476 == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) {
mbed_official 1:d4bb1e33950e 477 printf("We created at least %d tx events\r\n", events);
mbed_official 1:d4bb1e33950e 478 } else {
mbed_official 1:d4bb1e33950e 479 printf("We created at least %d tx and rx events\r\n", events);
mbed_official 1:d4bb1e33950e 480 }
mbed_official 1:d4bb1e33950e 481 }
mbed_official 1:d4bb1e33950e 482 };
mbed_official 1:d4bb1e33950e 483
mbed_official 1:d4bb1e33950e 484 /** Schedule processing of events from the BLE middleware in the event queue. */
mbed_official 1:d4bb1e33950e 485 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
mbed_official 1:d4bb1e33950e 486 {
mbed_official 1:d4bb1e33950e 487 _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
mbed_official 1:d4bb1e33950e 488 };
mbed_official 1:d4bb1e33950e 489
mbed_official 1:d4bb1e33950e 490 /** Blink LED to show we're running */
mbed_official 1:d4bb1e33950e 491 void blink(void)
mbed_official 1:d4bb1e33950e 492 {
mbed_official 1:d4bb1e33950e 493 _led1 = !_led1;
mbed_official 1:d4bb1e33950e 494 };
mbed_official 1:d4bb1e33950e 495
mbed_official 1:d4bb1e33950e 496 private:
mbed_official 1:d4bb1e33950e 497 BLE &_ble;
mbed_official 1:d4bb1e33950e 498 events::EventQueue _event_queue;
mbed_official 1:d4bb1e33950e 499 DigitalOut _led1;
mbed_official 1:d4bb1e33950e 500
mbed_official 1:d4bb1e33950e 501 /* Keep track of our progress through demo modes */
mbed_official 1:d4bb1e33950e 502 size_t _set_index;
mbed_official 1:d4bb1e33950e 503 bool _is_in_scanning_mode;
mbed_official 1:d4bb1e33950e 504 bool _is_connecting;
mbed_official 1:d4bb1e33950e 505
mbed_official 1:d4bb1e33950e 506 /* Remember the call id of the function on _event_queue
mbed_official 1:d4bb1e33950e 507 * so we can cancel it if we need to end the mode early */
mbed_official 1:d4bb1e33950e 508 int _on_duration_end_id;
mbed_official 1:d4bb1e33950e 509
mbed_official 1:d4bb1e33950e 510 /* Measure performance of our advertising/scanning */
mbed_official 1:d4bb1e33950e 511 Timer _demo_duration;
mbed_official 1:d4bb1e33950e 512 size_t _scan_count;
mbed_official 1:d4bb1e33950e 513 };
mbed_official 1:d4bb1e33950e 514
mbed_official 1:d4bb1e33950e 515 int main()
mbed_official 1:d4bb1e33950e 516 {
mbed_official 1:d4bb1e33950e 517 GAPDevice gap_device;
mbed_official 1:d4bb1e33950e 518
mbed_official 1:d4bb1e33950e 519 while (1) {
mbed_official 1:d4bb1e33950e 520 gap_device.run();
mbed_official 1:d4bb1e33950e 521 wait_ms(TIME_BETWEEN_MODES_MS);
mbed_official 1:d4bb1e33950e 522 printf("\r\nStarting next GAP demo mode\r\n");
mbed_official 1:d4bb1e33950e 523 };
mbed_official 1:d4bb1e33950e 524
mbed_official 1:d4bb1e33950e 525 return 0;
mbed_official 1:d4bb1e33950e 526 }