Demonstration of the GAP profile. It shows advertising, scanning and connecting. The demo will cycle through several modes and print over the serial connection information about current activity.

GAP - Advertising, Scanning, Connecting

Demonstration of GAP API usage. It shows advertising, scanning and connecting. The demo will cycle through several modes and print over the serial connection information about current activity.

Running the application

Requirements

The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install :

- nRF Master Control Panel for Android.

- LightBlue for iPhone.

Information about activity is printed over the serial connection - please have a client open. You may use:

- Tera Term

Hardware requirements are in the main readme.

Building instructions

Building instructions for all samples are in the main readme.

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 }