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 Feb 27 13:01:18 2019 +0000
Revision:
20:d2c272f79611
Parent:
16:4dd4ecbc8efb
Child:
21:59235cb6afd2
Updating mbed-os to mbed-os-5.11.5

.
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 16:4dd4ecbc8efb 2 * Copyright (c) 2006-2018 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 16:4dd4ecbc8efb 20 #include "gap/Gap.h"
mbed_official 16:4dd4ecbc8efb 21 #include "gap/AdvertisingDataParser.h"
mbed_official 16:4dd4ecbc8efb 22 #include "pretty_printer.h"
mbed_official 1:d4bb1e33950e 23
mbed_official 1:d4bb1e33950e 24 /** This example demonstrates all the basic setup required
mbed_official 1:d4bb1e33950e 25 * to advertise, scan and connect to other devices.
mbed_official 1:d4bb1e33950e 26 *
mbed_official 1:d4bb1e33950e 27 * It contains a single class that performs both scans and advertisements.
mbed_official 1:d4bb1e33950e 28 *
mbed_official 1:d4bb1e33950e 29 * The demonstrations happens in sequence, after each "mode" ends
mbed_official 1:d4bb1e33950e 30 * the demo jumps to the next mode to continue. There are several modes
mbed_official 1:d4bb1e33950e 31 * that show scanning and several showing advertising. These are configured
mbed_official 1:d4bb1e33950e 32 * according to the two arrays containing parameters. During scanning
mbed_official 1:d4bb1e33950e 33 * a connection will be made to a connectable device upon its discovery.
mbed_official 1:d4bb1e33950e 34 */
mbed_official 1:d4bb1e33950e 35
mbed_official 16:4dd4ecbc8efb 36 events::EventQueue event_queue;
mbed_official 1:d4bb1e33950e 37
mbed_official 1:d4bb1e33950e 38 /* Duration of each mode in milliseconds */
mbed_official 1:d4bb1e33950e 39 static const size_t MODE_DURATION_MS = 6000;
mbed_official 1:d4bb1e33950e 40
mbed_official 1:d4bb1e33950e 41 /* Time between each mode in milliseconds */
mbed_official 1:d4bb1e33950e 42 static const size_t TIME_BETWEEN_MODES_MS = 2000;
mbed_official 1:d4bb1e33950e 43
mbed_official 1:d4bb1e33950e 44 /* how long to wait before disconnecting in milliseconds */
mbed_official 16:4dd4ecbc8efb 45 static const size_t CONNECTION_DURATION = 3000;
mbed_official 16:4dd4ecbc8efb 46
mbed_official 16:4dd4ecbc8efb 47 /* how many advertising sets we want to crate at once */
mbed_official 16:4dd4ecbc8efb 48 static const uint8_t ADV_SET_NUMBER = 2;
mbed_official 16:4dd4ecbc8efb 49
mbed_official 16:4dd4ecbc8efb 50 static const uint16_t MAX_ADVERTISING_PAYLOAD_SIZE = 1000;
mbed_official 1:d4bb1e33950e 51
mbed_official 1:d4bb1e33950e 52 typedef struct {
mbed_official 16:4dd4ecbc8efb 53 ble::advertising_type_t type;
mbed_official 16:4dd4ecbc8efb 54 ble::adv_interval_t min_interval;
mbed_official 16:4dd4ecbc8efb 55 ble::adv_interval_t max_interval;
mbed_official 16:4dd4ecbc8efb 56 } DemoAdvParams_t;
mbed_official 1:d4bb1e33950e 57
mbed_official 1:d4bb1e33950e 58 typedef struct {
mbed_official 16:4dd4ecbc8efb 59 ble::scan_interval_t interval;
mbed_official 16:4dd4ecbc8efb 60 ble::scan_window_t window;
mbed_official 16:4dd4ecbc8efb 61 ble::scan_duration_t duration;
mbed_official 1:d4bb1e33950e 62 bool active;
mbed_official 16:4dd4ecbc8efb 63 } DemoScanParam_t;
mbed_official 1:d4bb1e33950e 64
mbed_official 1:d4bb1e33950e 65 /** the entries in this array are used to configure our advertising
mbed_official 1:d4bb1e33950e 66 * parameters for each of the modes we use in our demo */
mbed_official 16:4dd4ecbc8efb 67 static const DemoAdvParams_t advertising_params[] = {
mbed_official 16:4dd4ecbc8efb 68 /* advertising type | min interval - 0.625us | max interval - 0.625us */
mbed_official 16:4dd4ecbc8efb 69 { ble::advertising_type_t::CONNECTABLE_UNDIRECTED, ble::adv_interval_t(40), ble::adv_interval_t(80) },
mbed_official 16:4dd4ecbc8efb 70 { ble::advertising_type_t::SCANNABLE_UNDIRECTED, ble::adv_interval_t(100), ble::adv_interval_t(200) },
mbed_official 16:4dd4ecbc8efb 71 { ble::advertising_type_t::NON_CONNECTABLE_UNDIRECTED, ble::adv_interval_t(100), ble::adv_interval_t(200) }
mbed_official 1:d4bb1e33950e 72 };
mbed_official 1:d4bb1e33950e 73
mbed_official 1:d4bb1e33950e 74 /* when we cycle through all our advertising modes we will move to scanning modes */
mbed_official 1:d4bb1e33950e 75
mbed_official 1:d4bb1e33950e 76 /** the entries in this array are used to configure our scanning
mbed_official 1:d4bb1e33950e 77 * parameters for each of the modes we use in our demo */
mbed_official 16:4dd4ecbc8efb 78 static const DemoScanParam_t scanning_params[] = {
mbed_official 16:4dd4ecbc8efb 79 /* interval window duration active */
mbed_official 16:4dd4ecbc8efb 80 /* 0.625ms 0.625ms 10ms */
mbed_official 16:4dd4ecbc8efb 81 { ble::scan_interval_t(4), ble::scan_window_t(4), ble::scan_duration_t(0), false },
mbed_official 16:4dd4ecbc8efb 82 { ble::scan_interval_t(160), ble::scan_window_t(100), ble::scan_duration_t(300), false },
mbed_official 16:4dd4ecbc8efb 83 { ble::scan_interval_t(160), ble::scan_window_t(40), ble::scan_duration_t(0), true },
mbed_official 16:4dd4ecbc8efb 84 { ble::scan_interval_t(500), ble::scan_window_t(10), ble::scan_duration_t(0), false }
mbed_official 1:d4bb1e33950e 85 };
mbed_official 1:d4bb1e33950e 86
mbed_official 16:4dd4ecbc8efb 87 /* helper that gets the number of items in arrays */
mbed_official 16:4dd4ecbc8efb 88 template<class T, size_t N>
mbed_official 16:4dd4ecbc8efb 89 size_t size(const T (&)[N])
mbed_official 16:4dd4ecbc8efb 90 {
mbed_official 16:4dd4ecbc8efb 91 return N;
mbed_official 10:6f1c573093c1 92 }
mbed_official 1:d4bb1e33950e 93
mbed_official 1:d4bb1e33950e 94 /** Demonstrate advertising, scanning and connecting
mbed_official 1:d4bb1e33950e 95 */
mbed_official 16:4dd4ecbc8efb 96 class GapDemo : private mbed::NonCopyable<GapDemo>, public ble::Gap::EventHandler
mbed_official 1:d4bb1e33950e 97 {
mbed_official 1:d4bb1e33950e 98 public:
mbed_official 16:4dd4ecbc8efb 99 GapDemo(BLE& ble, events::EventQueue& event_queue) :
mbed_official 16:4dd4ecbc8efb 100 _ble(ble),
mbed_official 16:4dd4ecbc8efb 101 _gap(ble.gap()),
mbed_official 16:4dd4ecbc8efb 102 _event_queue(event_queue),
mbed_official 1:d4bb1e33950e 103 _led1(LED1, 0),
mbed_official 1:d4bb1e33950e 104 _set_index(0),
mbed_official 16:4dd4ecbc8efb 105 _is_in_scanning_mode(true),
mbed_official 1:d4bb1e33950e 106 _is_connecting(false),
mbed_official 1:d4bb1e33950e 107 _on_duration_end_id(0),
mbed_official 16:4dd4ecbc8efb 108 _scan_count(0),
mbed_official 16:4dd4ecbc8efb 109 _blink_event(0) {
mbed_official 16:4dd4ecbc8efb 110 for (uint8_t i = 0; i < size(_adv_handles); ++i) {
mbed_official 16:4dd4ecbc8efb 111 _adv_handles[i] = ble::INVALID_ADVERTISING_HANDLE;
mbed_official 16:4dd4ecbc8efb 112 }
mbed_official 16:4dd4ecbc8efb 113 }
mbed_official 1:d4bb1e33950e 114
mbed_official 16:4dd4ecbc8efb 115 ~GapDemo()
mbed_official 1:d4bb1e33950e 116 {
mbed_official 1:d4bb1e33950e 117 if (_ble.hasInitialized()) {
mbed_official 1:d4bb1e33950e 118 _ble.shutdown();
mbed_official 1:d4bb1e33950e 119 }
mbed_official 16:4dd4ecbc8efb 120 }
mbed_official 1:d4bb1e33950e 121
mbed_official 1:d4bb1e33950e 122 /** Start BLE interface initialisation */
mbed_official 1:d4bb1e33950e 123 void run()
mbed_official 1:d4bb1e33950e 124 {
mbed_official 1:d4bb1e33950e 125 if (_ble.hasInitialized()) {
mbed_official 1:d4bb1e33950e 126 printf("Ble instance already initialised.\r\n");
mbed_official 1:d4bb1e33950e 127 return;
mbed_official 1:d4bb1e33950e 128 }
mbed_official 1:d4bb1e33950e 129
mbed_official 16:4dd4ecbc8efb 130 /* handle gap events */
mbed_official 16:4dd4ecbc8efb 131 _gap.setEventHandler(this);
mbed_official 1:d4bb1e33950e 132
mbed_official 16:4dd4ecbc8efb 133 ble_error_t error = _ble.init(this, &GapDemo::on_init_complete);
mbed_official 1:d4bb1e33950e 134 if (error) {
mbed_official 16:4dd4ecbc8efb 135 print_error(error, "Error returned by BLE::init");
mbed_official 1:d4bb1e33950e 136 return;
mbed_official 1:d4bb1e33950e 137 }
mbed_official 1:d4bb1e33950e 138
mbed_official 1:d4bb1e33950e 139 /* to show we're running we'll blink every 500ms */
mbed_official 16:4dd4ecbc8efb 140 _blink_event = _event_queue.call_every(500, this, &GapDemo::blink);
mbed_official 1:d4bb1e33950e 141
mbed_official 1:d4bb1e33950e 142 /* this will not return until shutdown */
mbed_official 1:d4bb1e33950e 143 _event_queue.dispatch_forever();
mbed_official 16:4dd4ecbc8efb 144 }
mbed_official 1:d4bb1e33950e 145
mbed_official 1:d4bb1e33950e 146 private:
mbed_official 1:d4bb1e33950e 147 /** This is called when BLE interface is initialised and starts the first mode */
mbed_official 1:d4bb1e33950e 148 void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
mbed_official 1:d4bb1e33950e 149 {
mbed_official 1:d4bb1e33950e 150 if (event->error) {
mbed_official 16:4dd4ecbc8efb 151 print_error(event->error, "Error during the initialisation");
mbed_official 1:d4bb1e33950e 152 return;
mbed_official 1:d4bb1e33950e 153 }
mbed_official 1:d4bb1e33950e 154
mbed_official 16:4dd4ecbc8efb 155 print_mac_address();
mbed_official 1:d4bb1e33950e 156
mbed_official 10:6f1c573093c1 157 /* setup the default phy used in connection to 2M to reduce power consumption */
mbed_official 16:4dd4ecbc8efb 158 if (is_2m_phy_supported()) {
mbed_official 16:4dd4ecbc8efb 159 ble::phy_set_t phys(/* 1M */ false, /* 2M */ true, /* coded */ false);
mbed_official 16:4dd4ecbc8efb 160
mbed_official 16:4dd4ecbc8efb 161 ble_error_t error = _gap.setPreferredPhys(/* tx */&phys, /* rx */&phys);
mbed_official 16:4dd4ecbc8efb 162 if (error) {
mbed_official 16:4dd4ecbc8efb 163 print_error(error, "GAP::setPreferedPhys failed");
mbed_official 16:4dd4ecbc8efb 164 }
mbed_official 10:6f1c573093c1 165 }
mbed_official 10:6f1c573093c1 166
mbed_official 1:d4bb1e33950e 167 /* all calls are serialised on the user thread through the event queue */
mbed_official 16:4dd4ecbc8efb 168 _event_queue.call(this, &GapDemo::demo_mode_start);
mbed_official 16:4dd4ecbc8efb 169 }
mbed_official 1:d4bb1e33950e 170
mbed_official 1:d4bb1e33950e 171 /** queue up start of the current demo mode */
mbed_official 1:d4bb1e33950e 172 void demo_mode_start()
mbed_official 1:d4bb1e33950e 173 {
mbed_official 1:d4bb1e33950e 174 if (_is_in_scanning_mode) {
mbed_official 16:4dd4ecbc8efb 175 _event_queue.call(this, &GapDemo::scan);
mbed_official 1:d4bb1e33950e 176 } else {
mbed_official 16:4dd4ecbc8efb 177 _event_queue.call(this, &GapDemo::advertise);
mbed_official 1:d4bb1e33950e 178 }
mbed_official 1:d4bb1e33950e 179
mbed_official 1:d4bb1e33950e 180 /* for performance measurement keep track of duration of the demo mode */
mbed_official 1:d4bb1e33950e 181 _demo_duration.start();
mbed_official 1:d4bb1e33950e 182 /* keep track of our state */
mbed_official 1:d4bb1e33950e 183 _is_connecting = false;
mbed_official 1:d4bb1e33950e 184
mbed_official 1:d4bb1e33950e 185 /* queue up next demo mode */
mbed_official 1:d4bb1e33950e 186 _on_duration_end_id = _event_queue.call_in(
mbed_official 16:4dd4ecbc8efb 187 MODE_DURATION_MS,
mbed_official 16:4dd4ecbc8efb 188 this,
mbed_official 16:4dd4ecbc8efb 189 &GapDemo::end_demo_mode
mbed_official 1:d4bb1e33950e 190 );
mbed_official 1:d4bb1e33950e 191
mbed_official 1:d4bb1e33950e 192 printf("\r\n");
mbed_official 1:d4bb1e33950e 193 }
mbed_official 1:d4bb1e33950e 194
mbed_official 1:d4bb1e33950e 195 /** Set up and start advertising */
mbed_official 1:d4bb1e33950e 196 void advertise()
mbed_official 1:d4bb1e33950e 197 {
mbed_official 16:4dd4ecbc8efb 198 const DemoAdvParams_t &adv_params = advertising_params[_set_index];
mbed_official 1:d4bb1e33950e 199
mbed_official 16:4dd4ecbc8efb 200 /*
mbed_official 16:4dd4ecbc8efb 201 * Advertising parameters are mainly defined by an advertising type and
mbed_official 16:4dd4ecbc8efb 202 * and an interval between advertisements. lower interval increases the
mbed_official 16:4dd4ecbc8efb 203 * chances of being seen at the cost of more power.
mbed_official 16:4dd4ecbc8efb 204 * The Bluetooth controller may run concurrent operations with the radio;
mbed_official 16:4dd4ecbc8efb 205 * to help it, a minimum and maximum advertising interval should be
mbed_official 16:4dd4ecbc8efb 206 * provided.
mbed_official 16:4dd4ecbc8efb 207 *
mbed_official 16:4dd4ecbc8efb 208 * With Bluetooth 5; it is possible to advertise concurrently multiple
mbed_official 16:4dd4ecbc8efb 209 * payloads at different rate. The combination of payload and its associated
mbed_official 16:4dd4ecbc8efb 210 * parameters is named an advertising set. To refer to these advertising
mbed_official 16:4dd4ecbc8efb 211 * sets the Bluetooth system use an advertising set handle that needs to
mbed_official 16:4dd4ecbc8efb 212 * be created first.
mbed_official 16:4dd4ecbc8efb 213 * The only exception is the legacy advertising handle which is usable
mbed_official 16:4dd4ecbc8efb 214 * on Bluetooth 4 and Bluetooth 5 system. It is created at startup and
mbed_official 16:4dd4ecbc8efb 215 * its lifecycle is managed by the system.
mbed_official 16:4dd4ecbc8efb 216 */
mbed_official 16:4dd4ecbc8efb 217 ble_error_t error = _gap.setAdvertisingParameters(
mbed_official 16:4dd4ecbc8efb 218 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 16:4dd4ecbc8efb 219 ble::AdvertisingParameters(
mbed_official 16:4dd4ecbc8efb 220 adv_params.type,
mbed_official 16:4dd4ecbc8efb 221 adv_params.min_interval,
mbed_official 16:4dd4ecbc8efb 222 adv_params.max_interval
mbed_official 16:4dd4ecbc8efb 223 )
mbed_official 1:d4bb1e33950e 224 );
mbed_official 16:4dd4ecbc8efb 225 if (error) {
mbed_official 16:4dd4ecbc8efb 226 print_error(error, "Gap::setAdvertisingParameters() failed");
mbed_official 16:4dd4ecbc8efb 227 return;
mbed_official 16:4dd4ecbc8efb 228 }
mbed_official 1:d4bb1e33950e 229
mbed_official 16:4dd4ecbc8efb 230 /* Set payload for the set */
mbed_official 16:4dd4ecbc8efb 231 /* Use the simple builder to construct the payload; it fails at runtime
mbed_official 16:4dd4ecbc8efb 232 * if there is not enough space left in the buffer */
mbed_official 16:4dd4ecbc8efb 233 error = _gap.setAdvertisingPayload(
mbed_official 16:4dd4ecbc8efb 234 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 16:4dd4ecbc8efb 235 ble::AdvertisingDataSimpleBuilder<ble::LEGACY_ADVERTISING_MAX_SIZE>()
mbed_official 16:4dd4ecbc8efb 236 .setFlags()
mbed_official 16:4dd4ecbc8efb 237 .setName("Legacy advertiser")
mbed_official 16:4dd4ecbc8efb 238 .getAdvertisingData()
mbed_official 16:4dd4ecbc8efb 239 );
mbed_official 1:d4bb1e33950e 240 if (error) {
mbed_official 16:4dd4ecbc8efb 241 print_error(error, "Gap::setAdvertisingPayload() failed");
mbed_official 16:4dd4ecbc8efb 242 return;
mbed_official 16:4dd4ecbc8efb 243 }
mbed_official 16:4dd4ecbc8efb 244
mbed_official 16:4dd4ecbc8efb 245 /* Start advertising the set */
mbed_official 16:4dd4ecbc8efb 246 error = _gap.startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 16:4dd4ecbc8efb 247 if (error) {
mbed_official 16:4dd4ecbc8efb 248 print_error(error, "Gap::startAdvertising() failed");
mbed_official 1:d4bb1e33950e 249 return;
mbed_official 1:d4bb1e33950e 250 }
mbed_official 1:d4bb1e33950e 251
mbed_official 16:4dd4ecbc8efb 252 printf("Advertising started (type: 0x%x, interval: [%d : %d]ms)\r\n",
mbed_official 16:4dd4ecbc8efb 253 adv_params.type.value(),
mbed_official 16:4dd4ecbc8efb 254 adv_params.min_interval.valueInMs(), adv_params.max_interval.valueInMs() );
mbed_official 1:d4bb1e33950e 255
mbed_official 16:4dd4ecbc8efb 256 if (is_extended_advertising_supported()) {
mbed_official 16:4dd4ecbc8efb 257 advertise_extended();
mbed_official 16:4dd4ecbc8efb 258 }
mbed_official 16:4dd4ecbc8efb 259 }
mbed_official 1:d4bb1e33950e 260
mbed_official 16:4dd4ecbc8efb 261 void advertise_extended()
mbed_official 16:4dd4ecbc8efb 262 {
mbed_official 16:4dd4ecbc8efb 263 const DemoAdvParams_t &adv_params = advertising_params[_set_index];
mbed_official 16:4dd4ecbc8efb 264
mbed_official 16:4dd4ecbc8efb 265 /* this is the memory backing for the payload */
mbed_official 16:4dd4ecbc8efb 266 uint8_t adv_buffer[MAX_ADVERTISING_PAYLOAD_SIZE];
mbed_official 1:d4bb1e33950e 267
mbed_official 16:4dd4ecbc8efb 268 /* how many sets */
mbed_official 16:4dd4ecbc8efb 269 uint8_t max_adv_set = std::min(
mbed_official 16:4dd4ecbc8efb 270 _gap.getMaxAdvertisingSetNumber(),
mbed_official 16:4dd4ecbc8efb 271 (uint8_t) size(_adv_handles)
mbed_official 16:4dd4ecbc8efb 272 );
mbed_official 1:d4bb1e33950e 273
mbed_official 16:4dd4ecbc8efb 274 /* one advertising set is reserved for legacy advertising */
mbed_official 16:4dd4ecbc8efb 275 if (max_adv_set < 2) {
mbed_official 1:d4bb1e33950e 276 return;
mbed_official 1:d4bb1e33950e 277 }
mbed_official 1:d4bb1e33950e 278
mbed_official 16:4dd4ecbc8efb 279 /* how much payload in a set */
mbed_official 16:4dd4ecbc8efb 280 uint16_t max_adv_size = std::min(
mbed_official 16:4dd4ecbc8efb 281 (uint16_t) _gap.getMaxAdvertisingDataLength(),
mbed_official 16:4dd4ecbc8efb 282 MAX_ADVERTISING_PAYLOAD_SIZE
mbed_official 16:4dd4ecbc8efb 283 );
mbed_official 16:4dd4ecbc8efb 284
mbed_official 16:4dd4ecbc8efb 285 /* create and start all requested (and possible) advertising sets */
mbed_official 16:4dd4ecbc8efb 286 for (uint8_t i = 0; i < (max_adv_set - 1); ++i) {
mbed_official 16:4dd4ecbc8efb 287 /* create the advertising set with its parameter */
mbed_official 16:4dd4ecbc8efb 288 /* this time we do not use legacy PDUs */
mbed_official 16:4dd4ecbc8efb 289 ble_error_t error = _gap.createAdvertisingSet(
mbed_official 16:4dd4ecbc8efb 290 &_adv_handles[i],
mbed_official 16:4dd4ecbc8efb 291 ble::AdvertisingParameters(
mbed_official 16:4dd4ecbc8efb 292 adv_params.type,
mbed_official 16:4dd4ecbc8efb 293 adv_params.min_interval,
mbed_official 16:4dd4ecbc8efb 294 adv_params.max_interval
mbed_official 16:4dd4ecbc8efb 295 ).setUseLegacyPDU(false)
mbed_official 16:4dd4ecbc8efb 296 );
mbed_official 16:4dd4ecbc8efb 297 if (error) {
mbed_official 16:4dd4ecbc8efb 298 print_error(error, "Gap::createAdvertisingSet() failed");
mbed_official 16:4dd4ecbc8efb 299 return;
mbed_official 16:4dd4ecbc8efb 300 }
mbed_official 16:4dd4ecbc8efb 301
mbed_official 16:4dd4ecbc8efb 302 /* use the helper to build the payload */
mbed_official 16:4dd4ecbc8efb 303 ble::AdvertisingDataBuilder adv_data_builder(
mbed_official 16:4dd4ecbc8efb 304 adv_buffer,
mbed_official 16:4dd4ecbc8efb 305 max_adv_size
mbed_official 16:4dd4ecbc8efb 306 );
mbed_official 16:4dd4ecbc8efb 307
mbed_official 16:4dd4ecbc8efb 308 /* set the flags */
mbed_official 16:4dd4ecbc8efb 309 error = adv_data_builder.setFlags();
mbed_official 16:4dd4ecbc8efb 310 if (error) {
mbed_official 16:4dd4ecbc8efb 311 print_error(error, "AdvertisingDataBuilder::setFlags() failed");
mbed_official 16:4dd4ecbc8efb 312 return;
mbed_official 16:4dd4ecbc8efb 313 }
mbed_official 16:4dd4ecbc8efb 314
mbed_official 16:4dd4ecbc8efb 315 /* set different name for each set */
mbed_official 16:4dd4ecbc8efb 316 MBED_ASSERT(i < 9);
mbed_official 16:4dd4ecbc8efb 317 char device_name[] = "Advertiser x";
mbed_official 16:4dd4ecbc8efb 318 snprintf(device_name, size(device_name), "Advertiser %d", i%10);
mbed_official 16:4dd4ecbc8efb 319 error = adv_data_builder.setName(device_name);
mbed_official 16:4dd4ecbc8efb 320 if (error) {
mbed_official 16:4dd4ecbc8efb 321 print_error(error, "AdvertisingDataBuilder::setName() failed");
mbed_official 16:4dd4ecbc8efb 322 return;
mbed_official 16:4dd4ecbc8efb 323 }
mbed_official 16:4dd4ecbc8efb 324
mbed_official 16:4dd4ecbc8efb 325 /* Set payload for the set */
mbed_official 16:4dd4ecbc8efb 326 error = _gap.setAdvertisingPayload(
mbed_official 16:4dd4ecbc8efb 327 _adv_handles[i],
mbed_official 16:4dd4ecbc8efb 328 adv_data_builder.getAdvertisingData()
mbed_official 16:4dd4ecbc8efb 329 );
mbed_official 16:4dd4ecbc8efb 330 if (error) {
mbed_official 16:4dd4ecbc8efb 331 print_error(error, "Gap::setAdvertisingPayload() failed");
mbed_official 16:4dd4ecbc8efb 332 return;
mbed_official 16:4dd4ecbc8efb 333 }
mbed_official 16:4dd4ecbc8efb 334
mbed_official 16:4dd4ecbc8efb 335 /* Start advertising the set */
mbed_official 16:4dd4ecbc8efb 336 error = _gap.startAdvertising(_adv_handles[i]);
mbed_official 16:4dd4ecbc8efb 337 if (error) {
mbed_official 16:4dd4ecbc8efb 338 print_error(error, "Gap::startAdvertising() failed");
mbed_official 16:4dd4ecbc8efb 339 return;
mbed_official 16:4dd4ecbc8efb 340 }
mbed_official 16:4dd4ecbc8efb 341
mbed_official 16:4dd4ecbc8efb 342 printf("Advertising started (type: 0x%x, interval: [%d : %d]ms)\r\n",
mbed_official 16:4dd4ecbc8efb 343 adv_params.type.value(),
mbed_official 16:4dd4ecbc8efb 344 adv_params.min_interval.valueInMs(), adv_params.max_interval.valueInMs() );
mbed_official 16:4dd4ecbc8efb 345 }
mbed_official 16:4dd4ecbc8efb 346 }
mbed_official 1:d4bb1e33950e 347
mbed_official 1:d4bb1e33950e 348 /** Set up and start scanning */
mbed_official 1:d4bb1e33950e 349 void scan()
mbed_official 1:d4bb1e33950e 350 {
mbed_official 16:4dd4ecbc8efb 351 const DemoScanParam_t &scan_params = scanning_params[_set_index];
mbed_official 1:d4bb1e33950e 352
mbed_official 16:4dd4ecbc8efb 353 /*
mbed_official 16:4dd4ecbc8efb 354 * Scanning happens repeatedly and is defined by:
mbed_official 16:4dd4ecbc8efb 355 * - The scan interval which is the time (in 0.625us) between each scan cycle.
mbed_official 16:4dd4ecbc8efb 356 * - The scan window which is the scanning time (in 0.625us) during a cycle.
mbed_official 16:4dd4ecbc8efb 357 * If the scanning process is active, the local device sends scan requests
mbed_official 16:4dd4ecbc8efb 358 * to discovered peer to get additional data.
mbed_official 16:4dd4ecbc8efb 359 */
mbed_official 16:4dd4ecbc8efb 360 ble_error_t error = _gap.setScanParameters(
mbed_official 16:4dd4ecbc8efb 361 ble::ScanParameters(
mbed_official 16:4dd4ecbc8efb 362 ble::phy_t::LE_1M, // scan on the 1M PHY
mbed_official 16:4dd4ecbc8efb 363 scan_params.interval,
mbed_official 16:4dd4ecbc8efb 364 scan_params.window,
mbed_official 16:4dd4ecbc8efb 365 scan_params.active
mbed_official 16:4dd4ecbc8efb 366 )
mbed_official 16:4dd4ecbc8efb 367 );
mbed_official 1:d4bb1e33950e 368 if (error) {
mbed_official 16:4dd4ecbc8efb 369 print_error(error, "Error caused by Gap::setScanParameters");
mbed_official 1:d4bb1e33950e 370 return;
mbed_official 1:d4bb1e33950e 371 }
mbed_official 1:d4bb1e33950e 372
mbed_official 1:d4bb1e33950e 373 /* start scanning and attach a callback that will handle advertisements
mbed_official 1:d4bb1e33950e 374 * and scan requests responses */
mbed_official 16:4dd4ecbc8efb 375 error = _gap.startScan(scan_params.duration);
mbed_official 1:d4bb1e33950e 376 if (error) {
mbed_official 16:4dd4ecbc8efb 377 print_error(error, "Error caused by Gap::startScan");
mbed_official 1:d4bb1e33950e 378 return;
mbed_official 1:d4bb1e33950e 379 }
mbed_official 1:d4bb1e33950e 380
mbed_official 16:4dd4ecbc8efb 381 printf("Scanning started (interval: %dms, window: %dms, timeout: %dms).\r\n",
mbed_official 16:4dd4ecbc8efb 382 scan_params.interval.valueInMs(), scan_params.window.valueInMs(), scan_params.duration.valueInMs());
mbed_official 16:4dd4ecbc8efb 383 }
mbed_official 16:4dd4ecbc8efb 384
mbed_official 16:4dd4ecbc8efb 385 /** Finish the mode by shutting down advertising or scanning and move to the next mode. */
mbed_official 16:4dd4ecbc8efb 386 void end_demo_mode()
mbed_official 16:4dd4ecbc8efb 387 {
mbed_official 16:4dd4ecbc8efb 388 if (_is_in_scanning_mode) {
mbed_official 16:4dd4ecbc8efb 389 end_scanning_mode();
mbed_official 16:4dd4ecbc8efb 390 } else {
mbed_official 16:4dd4ecbc8efb 391 end_advertising_mode();
mbed_official 16:4dd4ecbc8efb 392 }
mbed_official 16:4dd4ecbc8efb 393
mbed_official 16:4dd4ecbc8efb 394 /* alloted time has elapsed or be connected, move to next demo mode */
mbed_official 16:4dd4ecbc8efb 395 _event_queue.call(this, &GapDemo::next_demo_mode);
mbed_official 16:4dd4ecbc8efb 396 }
mbed_official 1:d4bb1e33950e 397
mbed_official 16:4dd4ecbc8efb 398 /** Execute the disconnection */
mbed_official 16:4dd4ecbc8efb 399 void do_disconnect(ble::connection_handle_t handle)
mbed_official 16:4dd4ecbc8efb 400 {
mbed_official 16:4dd4ecbc8efb 401 printf("Disconnecting\r\n");
mbed_official 16:4dd4ecbc8efb 402 _gap.disconnect(handle, ble::local_disconnection_reason_t::USER_TERMINATION);
mbed_official 16:4dd4ecbc8efb 403 }
mbed_official 16:4dd4ecbc8efb 404
mbed_official 16:4dd4ecbc8efb 405 bool is_2m_phy_supported()
mbed_official 1:d4bb1e33950e 406 {
mbed_official 16:4dd4ecbc8efb 407 return _gap.isFeatureSupported(ble::controller_supported_features_t::LE_2M_PHY);
mbed_official 16:4dd4ecbc8efb 408 }
mbed_official 1:d4bb1e33950e 409
mbed_official 16:4dd4ecbc8efb 410 bool is_extended_advertising_supported()
mbed_official 16:4dd4ecbc8efb 411 {
mbed_official 16:4dd4ecbc8efb 412 return _gap.isFeatureSupported(ble::controller_supported_features_t::LE_EXTENDED_ADVERTISING);
mbed_official 16:4dd4ecbc8efb 413 }
mbed_official 16:4dd4ecbc8efb 414
mbed_official 16:4dd4ecbc8efb 415
mbed_official 16:4dd4ecbc8efb 416 private:
mbed_official 16:4dd4ecbc8efb 417 /* Gap::EventHandler */
mbed_official 1:d4bb1e33950e 418
mbed_official 1:d4bb1e33950e 419 /** Look at scan payload to find a peer device and connect to it */
mbed_official 16:4dd4ecbc8efb 420 virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event)
mbed_official 1:d4bb1e33950e 421 {
mbed_official 1:d4bb1e33950e 422 /* keep track of scan events for performance reporting */
mbed_official 1:d4bb1e33950e 423 _scan_count++;
mbed_official 1:d4bb1e33950e 424
mbed_official 1:d4bb1e33950e 425 /* don't bother with analysing scan result if we're already connecting */
mbed_official 1:d4bb1e33950e 426 if (_is_connecting) {
mbed_official 1:d4bb1e33950e 427 return;
mbed_official 1:d4bb1e33950e 428 }
mbed_official 1:d4bb1e33950e 429
mbed_official 16:4dd4ecbc8efb 430 /* only look at events from devices at a close range */
mbed_official 16:4dd4ecbc8efb 431 if (event.getRssi() < -65) {
mbed_official 16:4dd4ecbc8efb 432 return;
mbed_official 16:4dd4ecbc8efb 433 }
mbed_official 16:4dd4ecbc8efb 434
mbed_official 16:4dd4ecbc8efb 435 ble::AdvertisingDataParser adv_parser(event.getPayload());
mbed_official 16:4dd4ecbc8efb 436
mbed_official 1:d4bb1e33950e 437 /* parse the advertising payload, looking for a discoverable device */
mbed_official 16:4dd4ecbc8efb 438 while (adv_parser.hasNext()) {
mbed_official 16:4dd4ecbc8efb 439 ble::AdvertisingDataParser::element_t field = adv_parser.next();
mbed_official 16:4dd4ecbc8efb 440
mbed_official 16:4dd4ecbc8efb 441 /* skip non discoverable device */
mbed_official 16:4dd4ecbc8efb 442 if (field.type != ble::adv_data_type_t::FLAGS ||
mbed_official 16:4dd4ecbc8efb 443 field.value.size() != 1 ||
mbed_official 16:4dd4ecbc8efb 444 !(field.value[0] & GapAdvertisingData::LE_GENERAL_DISCOVERABLE)) {
mbed_official 1:d4bb1e33950e 445 continue;
mbed_official 1:d4bb1e33950e 446 }
mbed_official 1:d4bb1e33950e 447
mbed_official 1:d4bb1e33950e 448 /* connect to a discoverable device */
mbed_official 1:d4bb1e33950e 449
mbed_official 16:4dd4ecbc8efb 450 /* abort timeout as the mode will end on disconnection */
mbed_official 16:4dd4ecbc8efb 451 _event_queue.cancel(_on_duration_end_id);
mbed_official 1:d4bb1e33950e 452
mbed_official 16:4dd4ecbc8efb 453 printf("We found a connectable device\r\n");
mbed_official 16:4dd4ecbc8efb 454 ble_error_t error = _gap.connect(
mbed_official 16:4dd4ecbc8efb 455 event.getPeerAddressType(),
mbed_official 16:4dd4ecbc8efb 456 event.getPeerAddress(),
mbed_official 16:4dd4ecbc8efb 457 ble::ConnectionParameters() // use the default connection parameters
mbed_official 16:4dd4ecbc8efb 458 );
mbed_official 16:4dd4ecbc8efb 459 if (error) {
mbed_official 16:4dd4ecbc8efb 460 print_error(error, "Error caused by Gap::connect");
mbed_official 16:4dd4ecbc8efb 461 /* since no connection will be attempted end the mode */
mbed_official 16:4dd4ecbc8efb 462 _event_queue.call(this, &GapDemo::end_demo_mode);
mbed_official 1:d4bb1e33950e 463 return;
mbed_official 1:d4bb1e33950e 464 }
mbed_official 1:d4bb1e33950e 465
mbed_official 16:4dd4ecbc8efb 466 /* we may have already scan events waiting
mbed_official 16:4dd4ecbc8efb 467 * to be processed so we need to remember
mbed_official 16:4dd4ecbc8efb 468 * that we are already connecting and ignore them */
mbed_official 16:4dd4ecbc8efb 469 _is_connecting = true;
mbed_official 16:4dd4ecbc8efb 470 return;
mbed_official 1:d4bb1e33950e 471 }
mbed_official 16:4dd4ecbc8efb 472 }
mbed_official 16:4dd4ecbc8efb 473
mbed_official 16:4dd4ecbc8efb 474 virtual void onAdvertisingEnd(const ble::AdvertisingEndEvent &event)
mbed_official 16:4dd4ecbc8efb 475 {
mbed_official 16:4dd4ecbc8efb 476 if (event.isConnected()) {
mbed_official 16:4dd4ecbc8efb 477 printf("Stopped advertising early due to connection\r\n");
mbed_official 16:4dd4ecbc8efb 478 }
mbed_official 16:4dd4ecbc8efb 479 }
mbed_official 16:4dd4ecbc8efb 480
mbed_official 16:4dd4ecbc8efb 481 virtual void onScanTimeout(const ble::ScanTimeoutEvent&)
mbed_official 16:4dd4ecbc8efb 482 {
mbed_official 16:4dd4ecbc8efb 483 printf("Stopped scanning early due to timeout parameter\r\n");
mbed_official 16:4dd4ecbc8efb 484 _demo_duration.stop();
mbed_official 16:4dd4ecbc8efb 485 }
mbed_official 1:d4bb1e33950e 486
mbed_official 1:d4bb1e33950e 487 /** This is called by Gap to notify the application we connected,
mbed_official 1:d4bb1e33950e 488 * in our case it immediately disconnects */
mbed_official 16:4dd4ecbc8efb 489 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event)
mbed_official 1:d4bb1e33950e 490 {
mbed_official 16:4dd4ecbc8efb 491 _demo_duration.stop();
mbed_official 1:d4bb1e33950e 492
mbed_official 16:4dd4ecbc8efb 493 if (event.getStatus() == BLE_ERROR_NONE) {
mbed_official 16:4dd4ecbc8efb 494 printf("Connected in %dms\r\n", _demo_duration.read_ms());
mbed_official 16:4dd4ecbc8efb 495
mbed_official 16:4dd4ecbc8efb 496 /* cancel the connect timeout since we connected */
mbed_official 16:4dd4ecbc8efb 497 _event_queue.cancel(_on_duration_end_id);
mbed_official 1:d4bb1e33950e 498
mbed_official 16:4dd4ecbc8efb 499 _event_queue.call_in(
mbed_official 16:4dd4ecbc8efb 500 CONNECTION_DURATION,
mbed_official 16:4dd4ecbc8efb 501 this,
mbed_official 16:4dd4ecbc8efb 502 &GapDemo::do_disconnect,
mbed_official 16:4dd4ecbc8efb 503 event.getConnectionHandle()
mbed_official 16:4dd4ecbc8efb 504 );
mbed_official 16:4dd4ecbc8efb 505 } else {
mbed_official 16:4dd4ecbc8efb 506 printf("Failed to connect after scanning %d advertisements\r\n", _scan_count);
mbed_official 16:4dd4ecbc8efb 507 _event_queue.call(this, &GapDemo::end_demo_mode);
mbed_official 16:4dd4ecbc8efb 508 }
mbed_official 16:4dd4ecbc8efb 509 }
mbed_official 1:d4bb1e33950e 510
mbed_official 1:d4bb1e33950e 511 /** This is called by Gap to notify the application we disconnected,
mbed_official 16:4dd4ecbc8efb 512 * in our case it calls next_demo_mode() to progress the demo */
mbed_official 16:4dd4ecbc8efb 513 virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event)
mbed_official 1:d4bb1e33950e 514 {
mbed_official 1:d4bb1e33950e 515 printf("Disconnected\r\n");
mbed_official 1:d4bb1e33950e 516
mbed_official 1:d4bb1e33950e 517 /* we have successfully disconnected ending the demo, move to next mode */
mbed_official 16:4dd4ecbc8efb 518 _event_queue.call(this, &GapDemo::end_demo_mode);
mbed_official 16:4dd4ecbc8efb 519 }
mbed_official 1:d4bb1e33950e 520
mbed_official 10:6f1c573093c1 521 /**
mbed_official 10:6f1c573093c1 522 * Implementation of Gap::EventHandler::onReadPhy
mbed_official 10:6f1c573093c1 523 */
mbed_official 10:6f1c573093c1 524 virtual void onReadPhy(
mbed_official 10:6f1c573093c1 525 ble_error_t error,
mbed_official 16:4dd4ecbc8efb 526 ble::connection_handle_t connectionHandle,
mbed_official 16:4dd4ecbc8efb 527 ble::phy_t txPhy,
mbed_official 16:4dd4ecbc8efb 528 ble::phy_t rxPhy
mbed_official 10:6f1c573093c1 529 ) {
mbed_official 10:6f1c573093c1 530 if (error) {
mbed_official 10:6f1c573093c1 531 printf(
mbed_official 10:6f1c573093c1 532 "Phy read on connection %d failed with error code %s\r\n",
mbed_official 10:6f1c573093c1 533 connectionHandle,
mbed_official 10:6f1c573093c1 534 BLE::errorToString(error)
mbed_official 10:6f1c573093c1 535 );
mbed_official 10:6f1c573093c1 536 } else {
mbed_official 10:6f1c573093c1 537 printf(
mbed_official 10:6f1c573093c1 538 "Phy read on connection %d - Tx Phy: %s, Rx Phy: %s\r\n",
mbed_official 10:6f1c573093c1 539 connectionHandle,
mbed_official 16:4dd4ecbc8efb 540 phy_to_string(txPhy),
mbed_official 16:4dd4ecbc8efb 541 phy_to_string(rxPhy)
mbed_official 10:6f1c573093c1 542 );
mbed_official 10:6f1c573093c1 543 }
mbed_official 10:6f1c573093c1 544 }
mbed_official 10:6f1c573093c1 545
mbed_official 10:6f1c573093c1 546 /**
mbed_official 10:6f1c573093c1 547 * Implementation of Gap::EventHandler::onPhyUpdateComplete
mbed_official 10:6f1c573093c1 548 */
mbed_official 10:6f1c573093c1 549 virtual void onPhyUpdateComplete(
mbed_official 10:6f1c573093c1 550 ble_error_t error,
mbed_official 16:4dd4ecbc8efb 551 ble::connection_handle_t connectionHandle,
mbed_official 16:4dd4ecbc8efb 552 ble::phy_t txPhy,
mbed_official 16:4dd4ecbc8efb 553 ble::phy_t rxPhy
mbed_official 10:6f1c573093c1 554 ) {
mbed_official 10:6f1c573093c1 555 if (error) {
mbed_official 10:6f1c573093c1 556 printf(
mbed_official 10:6f1c573093c1 557 "Phy update on connection: %d failed with error code %s\r\n",
mbed_official 10:6f1c573093c1 558 connectionHandle,
mbed_official 10:6f1c573093c1 559 BLE::errorToString(error)
mbed_official 10:6f1c573093c1 560 );
mbed_official 10:6f1c573093c1 561 } else {
mbed_official 10:6f1c573093c1 562 printf(
mbed_official 10:6f1c573093c1 563 "Phy update on connection %d - Tx Phy: %s, Rx Phy: %s\r\n",
mbed_official 10:6f1c573093c1 564 connectionHandle,
mbed_official 16:4dd4ecbc8efb 565 phy_to_string(txPhy),
mbed_official 16:4dd4ecbc8efb 566 phy_to_string(rxPhy)
mbed_official 10:6f1c573093c1 567 );
mbed_official 10:6f1c573093c1 568 }
mbed_official 10:6f1c573093c1 569 }
mbed_official 10:6f1c573093c1 570
mbed_official 16:4dd4ecbc8efb 571 private:
mbed_official 1:d4bb1e33950e 572
mbed_official 16:4dd4ecbc8efb 573 /** Clean up internal state after last run, cycle to the next mode and launch it */
mbed_official 16:4dd4ecbc8efb 574 void next_demo_mode()
mbed_official 1:d4bb1e33950e 575 {
mbed_official 1:d4bb1e33950e 576 /* reset the demo ready for the next mode */
mbed_official 1:d4bb1e33950e 577 _scan_count = 0;
mbed_official 1:d4bb1e33950e 578 _demo_duration.stop();
mbed_official 1:d4bb1e33950e 579 _demo_duration.reset();
mbed_official 1:d4bb1e33950e 580
mbed_official 1:d4bb1e33950e 581 /* cycle through all demo modes */
mbed_official 1:d4bb1e33950e 582 _set_index++;
mbed_official 1:d4bb1e33950e 583
mbed_official 1:d4bb1e33950e 584 /* switch between advertising and scanning when we go
mbed_official 1:d4bb1e33950e 585 * through all the params in the array */
mbed_official 16:4dd4ecbc8efb 586 if (_set_index >= (_is_in_scanning_mode ? size(scanning_params) : size(advertising_params))) {
mbed_official 1:d4bb1e33950e 587 _set_index = 0;
mbed_official 1:d4bb1e33950e 588 _is_in_scanning_mode = !_is_in_scanning_mode;
mbed_official 1:d4bb1e33950e 589 }
mbed_official 1:d4bb1e33950e 590
mbed_official 1:d4bb1e33950e 591 _ble.shutdown();
mbed_official 16:4dd4ecbc8efb 592 _event_queue.cancel(_blink_event);
mbed_official 1:d4bb1e33950e 593 _event_queue.break_dispatch();
mbed_official 16:4dd4ecbc8efb 594 }
mbed_official 16:4dd4ecbc8efb 595
mbed_official 16:4dd4ecbc8efb 596 /** Finish the mode by shutting down advertising or scanning and move to the next mode. */
mbed_official 16:4dd4ecbc8efb 597 void end_scanning_mode()
mbed_official 16:4dd4ecbc8efb 598 {
mbed_official 16:4dd4ecbc8efb 599 print_scanning_performance();
mbed_official 16:4dd4ecbc8efb 600 ble_error_t error = _gap.stopScan();
mbed_official 16:4dd4ecbc8efb 601
mbed_official 16:4dd4ecbc8efb 602 if (error) {
mbed_official 16:4dd4ecbc8efb 603 print_error(error, "Error caused by Gap::stopScan");
mbed_official 16:4dd4ecbc8efb 604 }
mbed_official 16:4dd4ecbc8efb 605 }
mbed_official 16:4dd4ecbc8efb 606
mbed_official 16:4dd4ecbc8efb 607 void end_advertising_mode()
mbed_official 16:4dd4ecbc8efb 608 {
mbed_official 16:4dd4ecbc8efb 609 print_advertising_performance();
mbed_official 16:4dd4ecbc8efb 610
mbed_official 16:4dd4ecbc8efb 611 _gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 16:4dd4ecbc8efb 612
mbed_official 16:4dd4ecbc8efb 613 if (is_extended_advertising_supported()) {
mbed_official 16:4dd4ecbc8efb 614 end_extended_advertising();
mbed_official 16:4dd4ecbc8efb 615 }
mbed_official 16:4dd4ecbc8efb 616 }
mbed_official 16:4dd4ecbc8efb 617
mbed_official 16:4dd4ecbc8efb 618 void end_extended_advertising()
mbed_official 16:4dd4ecbc8efb 619 {
mbed_official 16:4dd4ecbc8efb 620 /* iterate over the advertising handles */
mbed_official 16:4dd4ecbc8efb 621 for (uint8_t i = 0; i < size(_adv_handles); ++i) {
mbed_official 16:4dd4ecbc8efb 622 /* check if the set has been sucesfully created */
mbed_official 16:4dd4ecbc8efb 623 if (_adv_handles[i] == ble::INVALID_ADVERTISING_HANDLE) {
mbed_official 16:4dd4ecbc8efb 624 continue;
mbed_official 16:4dd4ecbc8efb 625 }
mbed_official 16:4dd4ecbc8efb 626
mbed_official 16:4dd4ecbc8efb 627 /* if it's still active, stop it */
mbed_official 16:4dd4ecbc8efb 628 if (_gap.isAdvertisingActive(_adv_handles[i])) {
mbed_official 16:4dd4ecbc8efb 629 ble_error_t error = _gap.stopAdvertising(_adv_handles[i]);
mbed_official 16:4dd4ecbc8efb 630 if (error) {
mbed_official 16:4dd4ecbc8efb 631 print_error(error, "Error caused by Gap::stopAdvertising");
mbed_official 16:4dd4ecbc8efb 632 continue;
mbed_official 16:4dd4ecbc8efb 633 }
mbed_official 16:4dd4ecbc8efb 634 }
mbed_official 16:4dd4ecbc8efb 635
mbed_official 16:4dd4ecbc8efb 636 ble_error_t error = _gap.destroyAdvertisingSet(_adv_handles[i]);
mbed_official 16:4dd4ecbc8efb 637 if (error) {
mbed_official 16:4dd4ecbc8efb 638 print_error(error, "Error caused by Gap::destroyAdvertisingSet");
mbed_official 16:4dd4ecbc8efb 639 continue;
mbed_official 16:4dd4ecbc8efb 640 }
mbed_official 16:4dd4ecbc8efb 641
mbed_official 16:4dd4ecbc8efb 642 _adv_handles[i] = ble::INVALID_ADVERTISING_HANDLE;
mbed_official 16:4dd4ecbc8efb 643 }
mbed_official 16:4dd4ecbc8efb 644 }
mbed_official 1:d4bb1e33950e 645
mbed_official 1:d4bb1e33950e 646 /** print some information about our radio activity */
mbed_official 16:4dd4ecbc8efb 647 void print_scanning_performance()
mbed_official 1:d4bb1e33950e 648 {
mbed_official 1:d4bb1e33950e 649 /* measure time from mode start, may have been stopped by timeout */
mbed_official 16:4dd4ecbc8efb 650 uint16_t duration_ms = _demo_duration.read_ms();
mbed_official 1:d4bb1e33950e 651
mbed_official 16:4dd4ecbc8efb 652 /* convert ms into timeslots for accurate calculation as internally
mbed_official 16:4dd4ecbc8efb 653 * all durations are in timeslots (0.625ms) */
mbed_official 16:4dd4ecbc8efb 654 uint16_t duration_ts = ble::scan_interval_t(ble::millisecond_t(duration_ms)).value();
mbed_official 16:4dd4ecbc8efb 655 uint16_t interval_ts = scanning_params[_set_index].interval.value();
mbed_official 16:4dd4ecbc8efb 656 uint16_t window_ts = scanning_params[_set_index].window.value();
mbed_official 16:4dd4ecbc8efb 657 /* this is how long we scanned for in timeslots */
mbed_official 16:4dd4ecbc8efb 658 uint16_t rx_ts = (duration_ts / interval_ts) * window_ts;
mbed_official 16:4dd4ecbc8efb 659 /* convert to milliseconds */
mbed_official 16:4dd4ecbc8efb 660 uint16_t rx_ms = ble::scan_interval_t(rx_ts).valueInMs();
mbed_official 1:d4bb1e33950e 661
mbed_official 16:4dd4ecbc8efb 662 printf("We have scanned for %dms with an interval of %d"
mbed_official 16:4dd4ecbc8efb 663 " timeslots and a window of %d timeslots\r\n",
mbed_official 16:4dd4ecbc8efb 664 duration_ms, interval_ts, window_ts);
mbed_official 1:d4bb1e33950e 665
mbed_official 16:4dd4ecbc8efb 666 printf("We have been listening on the radio for at least %dms\r\n", rx_ms);
mbed_official 16:4dd4ecbc8efb 667 }
mbed_official 1:d4bb1e33950e 668
mbed_official 16:4dd4ecbc8efb 669 /** print some information about our radio activity */
mbed_official 16:4dd4ecbc8efb 670 void print_advertising_performance()
mbed_official 16:4dd4ecbc8efb 671 {
mbed_official 16:4dd4ecbc8efb 672 /* measure time from mode start, may have been stopped by timeout */
mbed_official 16:4dd4ecbc8efb 673 uint16_t duration_ms = _demo_duration.read_ms();
mbed_official 16:4dd4ecbc8efb 674 uint8_t number_of_active_sets = 0;
mbed_official 1:d4bb1e33950e 675
mbed_official 16:4dd4ecbc8efb 676 for (uint8_t i = 0; i < size(_adv_handles); ++i) {
mbed_official 16:4dd4ecbc8efb 677 if (_adv_handles[i] != ble::INVALID_ADVERTISING_HANDLE) {
mbed_official 16:4dd4ecbc8efb 678 if (_gap.isAdvertisingActive(_adv_handles[i])) {
mbed_official 16:4dd4ecbc8efb 679 number_of_active_sets++;
mbed_official 16:4dd4ecbc8efb 680 }
mbed_official 1:d4bb1e33950e 681 }
mbed_official 1:d4bb1e33950e 682 }
mbed_official 16:4dd4ecbc8efb 683
mbed_official 16:4dd4ecbc8efb 684 /* convert ms into timeslots for accurate calculation as internally
mbed_official 16:4dd4ecbc8efb 685 * all durations are in timeslots (0.625ms) */
mbed_official 16:4dd4ecbc8efb 686 uint16_t duration_ts = ble::adv_interval_t(ble::millisecond_t(duration_ms)).value();
mbed_official 16:4dd4ecbc8efb 687 uint16_t interval_ts = advertising_params[_set_index].max_interval.value();
mbed_official 16:4dd4ecbc8efb 688 /* this is how many times we advertised */
mbed_official 16:4dd4ecbc8efb 689 uint16_t events = (duration_ts / interval_ts) * number_of_active_sets;
mbed_official 16:4dd4ecbc8efb 690
mbed_official 16:4dd4ecbc8efb 691 printf("We have advertised for %dms with an interval of at least %d timeslots\r\n",
mbed_official 16:4dd4ecbc8efb 692 duration_ms, interval_ts);
mbed_official 1:d4bb1e33950e 693
mbed_official 16:4dd4ecbc8efb 694 if (number_of_active_sets > 1) {
mbed_official 16:4dd4ecbc8efb 695 printf("We had %d active advertising sets\r\n", number_of_active_sets);
mbed_official 16:4dd4ecbc8efb 696 }
mbed_official 16:4dd4ecbc8efb 697
mbed_official 16:4dd4ecbc8efb 698 /* non-scannable and non-connectable advertising
mbed_official 16:4dd4ecbc8efb 699 * skips rx events saving on power consumption */
mbed_official 16:4dd4ecbc8efb 700 if (advertising_params[_set_index].type == ble::advertising_type_t::NON_CONNECTABLE_UNDIRECTED) {
mbed_official 16:4dd4ecbc8efb 701 printf("We created at least %d tx events\r\n", events);
mbed_official 16:4dd4ecbc8efb 702 } else {
mbed_official 16:4dd4ecbc8efb 703 printf("We created at least %d tx and rx events\r\n", events);
mbed_official 16:4dd4ecbc8efb 704 }
mbed_official 16:4dd4ecbc8efb 705 }
mbed_official 1:d4bb1e33950e 706
mbed_official 1:d4bb1e33950e 707 /** Blink LED to show we're running */
mbed_official 1:d4bb1e33950e 708 void blink(void)
mbed_official 1:d4bb1e33950e 709 {
mbed_official 1:d4bb1e33950e 710 _led1 = !_led1;
mbed_official 16:4dd4ecbc8efb 711 }
mbed_official 1:d4bb1e33950e 712
mbed_official 1:d4bb1e33950e 713 private:
mbed_official 1:d4bb1e33950e 714 BLE &_ble;
mbed_official 16:4dd4ecbc8efb 715 ble::Gap &_gap;
mbed_official 16:4dd4ecbc8efb 716 events::EventQueue &_event_queue;
mbed_official 1:d4bb1e33950e 717 DigitalOut _led1;
mbed_official 1:d4bb1e33950e 718
mbed_official 1:d4bb1e33950e 719 /* Keep track of our progress through demo modes */
mbed_official 1:d4bb1e33950e 720 size_t _set_index;
mbed_official 1:d4bb1e33950e 721 bool _is_in_scanning_mode;
mbed_official 1:d4bb1e33950e 722 bool _is_connecting;
mbed_official 1:d4bb1e33950e 723
mbed_official 1:d4bb1e33950e 724 /* Remember the call id of the function on _event_queue
mbed_official 1:d4bb1e33950e 725 * so we can cancel it if we need to end the mode early */
mbed_official 1:d4bb1e33950e 726 int _on_duration_end_id;
mbed_official 1:d4bb1e33950e 727
mbed_official 1:d4bb1e33950e 728 /* Measure performance of our advertising/scanning */
mbed_official 1:d4bb1e33950e 729 Timer _demo_duration;
mbed_official 1:d4bb1e33950e 730 size_t _scan_count;
mbed_official 16:4dd4ecbc8efb 731
mbed_official 16:4dd4ecbc8efb 732 int _blink_event;
mbed_official 16:4dd4ecbc8efb 733
mbed_official 16:4dd4ecbc8efb 734 ble::advertising_handle_t _adv_handles[ADV_SET_NUMBER];
mbed_official 1:d4bb1e33950e 735 };
mbed_official 1:d4bb1e33950e 736
mbed_official 16:4dd4ecbc8efb 737 /** Schedule processing of events from the BLE middleware in the event queue. */
mbed_official 16:4dd4ecbc8efb 738 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
mbed_official 16:4dd4ecbc8efb 739 event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
mbed_official 16:4dd4ecbc8efb 740 }
mbed_official 16:4dd4ecbc8efb 741
mbed_official 1:d4bb1e33950e 742 int main()
mbed_official 1:d4bb1e33950e 743 {
mbed_official 16:4dd4ecbc8efb 744 BLE &ble = BLE::Instance();
mbed_official 16:4dd4ecbc8efb 745
mbed_official 16:4dd4ecbc8efb 746 /* this will inform us off all events so we can schedule their handling
mbed_official 16:4dd4ecbc8efb 747 * using our event queue */
mbed_official 16:4dd4ecbc8efb 748 ble.onEventsToProcess(schedule_ble_events);
mbed_official 16:4dd4ecbc8efb 749
mbed_official 16:4dd4ecbc8efb 750 GapDemo demo(ble, event_queue);
mbed_official 1:d4bb1e33950e 751
mbed_official 1:d4bb1e33950e 752 while (1) {
mbed_official 16:4dd4ecbc8efb 753 demo.run();
mbed_official 1:d4bb1e33950e 754 wait_ms(TIME_BETWEEN_MODES_MS);
mbed_official 1:d4bb1e33950e 755 printf("\r\nStarting next GAP demo mode\r\n");
mbed_official 1:d4bb1e33950e 756 };
mbed_official 1:d4bb1e33950e 757
mbed_official 1:d4bb1e33950e 758 return 0;
mbed_official 1:d4bb1e33950e 759 }