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:
Thu Aug 15 17:01:11 2019 +0100
Revision:
22:973b10dc67f7
Parent:
21:59235cb6afd2
Merge pull request #252 from donatieng/mbed_os_update

Update Master branch to use Mbed OS 5.13.1
.
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 21:59235cb6afd2 89 size_t arraysize(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 21:59235cb6afd2 110 for (uint8_t i = 0; i < arraysize(_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 21:59235cb6afd2 271 (uint8_t) arraysize(_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 21:59235cb6afd2 318 snprintf(device_name, arraysize(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 21:59235cb6afd2 571 /**
mbed_official 21:59235cb6afd2 572 * Implementation of Gap::EventHandler::onDataLengthChange
mbed_official 21:59235cb6afd2 573 */
mbed_official 21:59235cb6afd2 574 virtual void onDataLengthChange(
mbed_official 21:59235cb6afd2 575 ble::connection_handle_t connectionHandle,
mbed_official 21:59235cb6afd2 576 uint16_t txSize,
mbed_official 21:59235cb6afd2 577 uint16_t rxSize
mbed_official 21:59235cb6afd2 578 ) {
mbed_official 21:59235cb6afd2 579 printf(
mbed_official 21:59235cb6afd2 580 "Data length changed on the connection %d.\r\n"
mbed_official 21:59235cb6afd2 581 "Maximum sizes for over the air packets are:\r\n"
mbed_official 21:59235cb6afd2 582 "%d octets for transmit and %d octets for receive.\r\n",
mbed_official 21:59235cb6afd2 583 connectionHandle,
mbed_official 21:59235cb6afd2 584 txSize,
mbed_official 21:59235cb6afd2 585 rxSize
mbed_official 21:59235cb6afd2 586 );
mbed_official 21:59235cb6afd2 587 }
mbed_official 21:59235cb6afd2 588
mbed_official 16:4dd4ecbc8efb 589 private:
mbed_official 1:d4bb1e33950e 590
mbed_official 16:4dd4ecbc8efb 591 /** Clean up internal state after last run, cycle to the next mode and launch it */
mbed_official 16:4dd4ecbc8efb 592 void next_demo_mode()
mbed_official 1:d4bb1e33950e 593 {
mbed_official 1:d4bb1e33950e 594 /* reset the demo ready for the next mode */
mbed_official 1:d4bb1e33950e 595 _scan_count = 0;
mbed_official 1:d4bb1e33950e 596 _demo_duration.stop();
mbed_official 1:d4bb1e33950e 597 _demo_duration.reset();
mbed_official 1:d4bb1e33950e 598
mbed_official 1:d4bb1e33950e 599 /* cycle through all demo modes */
mbed_official 1:d4bb1e33950e 600 _set_index++;
mbed_official 1:d4bb1e33950e 601
mbed_official 1:d4bb1e33950e 602 /* switch between advertising and scanning when we go
mbed_official 1:d4bb1e33950e 603 * through all the params in the array */
mbed_official 21:59235cb6afd2 604 if (_set_index >= (_is_in_scanning_mode ? arraysize(scanning_params) : arraysize(advertising_params))) {
mbed_official 1:d4bb1e33950e 605 _set_index = 0;
mbed_official 1:d4bb1e33950e 606 _is_in_scanning_mode = !_is_in_scanning_mode;
mbed_official 1:d4bb1e33950e 607 }
mbed_official 1:d4bb1e33950e 608
mbed_official 1:d4bb1e33950e 609 _ble.shutdown();
mbed_official 16:4dd4ecbc8efb 610 _event_queue.cancel(_blink_event);
mbed_official 1:d4bb1e33950e 611 _event_queue.break_dispatch();
mbed_official 16:4dd4ecbc8efb 612 }
mbed_official 16:4dd4ecbc8efb 613
mbed_official 16:4dd4ecbc8efb 614 /** Finish the mode by shutting down advertising or scanning and move to the next mode. */
mbed_official 16:4dd4ecbc8efb 615 void end_scanning_mode()
mbed_official 16:4dd4ecbc8efb 616 {
mbed_official 16:4dd4ecbc8efb 617 print_scanning_performance();
mbed_official 16:4dd4ecbc8efb 618 ble_error_t error = _gap.stopScan();
mbed_official 16:4dd4ecbc8efb 619
mbed_official 16:4dd4ecbc8efb 620 if (error) {
mbed_official 16:4dd4ecbc8efb 621 print_error(error, "Error caused by Gap::stopScan");
mbed_official 16:4dd4ecbc8efb 622 }
mbed_official 16:4dd4ecbc8efb 623 }
mbed_official 16:4dd4ecbc8efb 624
mbed_official 16:4dd4ecbc8efb 625 void end_advertising_mode()
mbed_official 16:4dd4ecbc8efb 626 {
mbed_official 16:4dd4ecbc8efb 627 print_advertising_performance();
mbed_official 16:4dd4ecbc8efb 628
mbed_official 16:4dd4ecbc8efb 629 _gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 16:4dd4ecbc8efb 630
mbed_official 16:4dd4ecbc8efb 631 if (is_extended_advertising_supported()) {
mbed_official 16:4dd4ecbc8efb 632 end_extended_advertising();
mbed_official 16:4dd4ecbc8efb 633 }
mbed_official 16:4dd4ecbc8efb 634 }
mbed_official 16:4dd4ecbc8efb 635
mbed_official 16:4dd4ecbc8efb 636 void end_extended_advertising()
mbed_official 16:4dd4ecbc8efb 637 {
mbed_official 16:4dd4ecbc8efb 638 /* iterate over the advertising handles */
mbed_official 21:59235cb6afd2 639 for (uint8_t i = 0; i < arraysize(_adv_handles); ++i) {
mbed_official 16:4dd4ecbc8efb 640 /* check if the set has been sucesfully created */
mbed_official 16:4dd4ecbc8efb 641 if (_adv_handles[i] == ble::INVALID_ADVERTISING_HANDLE) {
mbed_official 16:4dd4ecbc8efb 642 continue;
mbed_official 16:4dd4ecbc8efb 643 }
mbed_official 16:4dd4ecbc8efb 644
mbed_official 16:4dd4ecbc8efb 645 /* if it's still active, stop it */
mbed_official 16:4dd4ecbc8efb 646 if (_gap.isAdvertisingActive(_adv_handles[i])) {
mbed_official 16:4dd4ecbc8efb 647 ble_error_t error = _gap.stopAdvertising(_adv_handles[i]);
mbed_official 16:4dd4ecbc8efb 648 if (error) {
mbed_official 16:4dd4ecbc8efb 649 print_error(error, "Error caused by Gap::stopAdvertising");
mbed_official 16:4dd4ecbc8efb 650 continue;
mbed_official 16:4dd4ecbc8efb 651 }
mbed_official 16:4dd4ecbc8efb 652 }
mbed_official 16:4dd4ecbc8efb 653
mbed_official 16:4dd4ecbc8efb 654 ble_error_t error = _gap.destroyAdvertisingSet(_adv_handles[i]);
mbed_official 16:4dd4ecbc8efb 655 if (error) {
mbed_official 16:4dd4ecbc8efb 656 print_error(error, "Error caused by Gap::destroyAdvertisingSet");
mbed_official 16:4dd4ecbc8efb 657 continue;
mbed_official 16:4dd4ecbc8efb 658 }
mbed_official 16:4dd4ecbc8efb 659
mbed_official 16:4dd4ecbc8efb 660 _adv_handles[i] = ble::INVALID_ADVERTISING_HANDLE;
mbed_official 16:4dd4ecbc8efb 661 }
mbed_official 16:4dd4ecbc8efb 662 }
mbed_official 1:d4bb1e33950e 663
mbed_official 1:d4bb1e33950e 664 /** print some information about our radio activity */
mbed_official 16:4dd4ecbc8efb 665 void print_scanning_performance()
mbed_official 1:d4bb1e33950e 666 {
mbed_official 1:d4bb1e33950e 667 /* measure time from mode start, may have been stopped by timeout */
mbed_official 16:4dd4ecbc8efb 668 uint16_t duration_ms = _demo_duration.read_ms();
mbed_official 1:d4bb1e33950e 669
mbed_official 16:4dd4ecbc8efb 670 /* convert ms into timeslots for accurate calculation as internally
mbed_official 16:4dd4ecbc8efb 671 * all durations are in timeslots (0.625ms) */
mbed_official 16:4dd4ecbc8efb 672 uint16_t duration_ts = ble::scan_interval_t(ble::millisecond_t(duration_ms)).value();
mbed_official 16:4dd4ecbc8efb 673 uint16_t interval_ts = scanning_params[_set_index].interval.value();
mbed_official 16:4dd4ecbc8efb 674 uint16_t window_ts = scanning_params[_set_index].window.value();
mbed_official 16:4dd4ecbc8efb 675 /* this is how long we scanned for in timeslots */
mbed_official 16:4dd4ecbc8efb 676 uint16_t rx_ts = (duration_ts / interval_ts) * window_ts;
mbed_official 16:4dd4ecbc8efb 677 /* convert to milliseconds */
mbed_official 16:4dd4ecbc8efb 678 uint16_t rx_ms = ble::scan_interval_t(rx_ts).valueInMs();
mbed_official 1:d4bb1e33950e 679
mbed_official 16:4dd4ecbc8efb 680 printf("We have scanned for %dms with an interval of %d"
mbed_official 16:4dd4ecbc8efb 681 " timeslots and a window of %d timeslots\r\n",
mbed_official 16:4dd4ecbc8efb 682 duration_ms, interval_ts, window_ts);
mbed_official 1:d4bb1e33950e 683
mbed_official 16:4dd4ecbc8efb 684 printf("We have been listening on the radio for at least %dms\r\n", rx_ms);
mbed_official 16:4dd4ecbc8efb 685 }
mbed_official 1:d4bb1e33950e 686
mbed_official 16:4dd4ecbc8efb 687 /** print some information about our radio activity */
mbed_official 16:4dd4ecbc8efb 688 void print_advertising_performance()
mbed_official 16:4dd4ecbc8efb 689 {
mbed_official 16:4dd4ecbc8efb 690 /* measure time from mode start, may have been stopped by timeout */
mbed_official 16:4dd4ecbc8efb 691 uint16_t duration_ms = _demo_duration.read_ms();
mbed_official 16:4dd4ecbc8efb 692 uint8_t number_of_active_sets = 0;
mbed_official 1:d4bb1e33950e 693
mbed_official 21:59235cb6afd2 694 for (uint8_t i = 0; i < arraysize(_adv_handles); ++i) {
mbed_official 16:4dd4ecbc8efb 695 if (_adv_handles[i] != ble::INVALID_ADVERTISING_HANDLE) {
mbed_official 16:4dd4ecbc8efb 696 if (_gap.isAdvertisingActive(_adv_handles[i])) {
mbed_official 16:4dd4ecbc8efb 697 number_of_active_sets++;
mbed_official 16:4dd4ecbc8efb 698 }
mbed_official 1:d4bb1e33950e 699 }
mbed_official 1:d4bb1e33950e 700 }
mbed_official 16:4dd4ecbc8efb 701
mbed_official 16:4dd4ecbc8efb 702 /* convert ms into timeslots for accurate calculation as internally
mbed_official 16:4dd4ecbc8efb 703 * all durations are in timeslots (0.625ms) */
mbed_official 16:4dd4ecbc8efb 704 uint16_t duration_ts = ble::adv_interval_t(ble::millisecond_t(duration_ms)).value();
mbed_official 16:4dd4ecbc8efb 705 uint16_t interval_ts = advertising_params[_set_index].max_interval.value();
mbed_official 16:4dd4ecbc8efb 706 /* this is how many times we advertised */
mbed_official 16:4dd4ecbc8efb 707 uint16_t events = (duration_ts / interval_ts) * number_of_active_sets;
mbed_official 16:4dd4ecbc8efb 708
mbed_official 16:4dd4ecbc8efb 709 printf("We have advertised for %dms with an interval of at least %d timeslots\r\n",
mbed_official 16:4dd4ecbc8efb 710 duration_ms, interval_ts);
mbed_official 1:d4bb1e33950e 711
mbed_official 16:4dd4ecbc8efb 712 if (number_of_active_sets > 1) {
mbed_official 16:4dd4ecbc8efb 713 printf("We had %d active advertising sets\r\n", number_of_active_sets);
mbed_official 16:4dd4ecbc8efb 714 }
mbed_official 16:4dd4ecbc8efb 715
mbed_official 16:4dd4ecbc8efb 716 /* non-scannable and non-connectable advertising
mbed_official 16:4dd4ecbc8efb 717 * skips rx events saving on power consumption */
mbed_official 16:4dd4ecbc8efb 718 if (advertising_params[_set_index].type == ble::advertising_type_t::NON_CONNECTABLE_UNDIRECTED) {
mbed_official 16:4dd4ecbc8efb 719 printf("We created at least %d tx events\r\n", events);
mbed_official 16:4dd4ecbc8efb 720 } else {
mbed_official 16:4dd4ecbc8efb 721 printf("We created at least %d tx and rx events\r\n", events);
mbed_official 16:4dd4ecbc8efb 722 }
mbed_official 16:4dd4ecbc8efb 723 }
mbed_official 1:d4bb1e33950e 724
mbed_official 1:d4bb1e33950e 725 /** Blink LED to show we're running */
mbed_official 1:d4bb1e33950e 726 void blink(void)
mbed_official 1:d4bb1e33950e 727 {
mbed_official 1:d4bb1e33950e 728 _led1 = !_led1;
mbed_official 16:4dd4ecbc8efb 729 }
mbed_official 1:d4bb1e33950e 730
mbed_official 1:d4bb1e33950e 731 private:
mbed_official 1:d4bb1e33950e 732 BLE &_ble;
mbed_official 16:4dd4ecbc8efb 733 ble::Gap &_gap;
mbed_official 16:4dd4ecbc8efb 734 events::EventQueue &_event_queue;
mbed_official 1:d4bb1e33950e 735 DigitalOut _led1;
mbed_official 1:d4bb1e33950e 736
mbed_official 1:d4bb1e33950e 737 /* Keep track of our progress through demo modes */
mbed_official 1:d4bb1e33950e 738 size_t _set_index;
mbed_official 1:d4bb1e33950e 739 bool _is_in_scanning_mode;
mbed_official 1:d4bb1e33950e 740 bool _is_connecting;
mbed_official 1:d4bb1e33950e 741
mbed_official 1:d4bb1e33950e 742 /* Remember the call id of the function on _event_queue
mbed_official 1:d4bb1e33950e 743 * so we can cancel it if we need to end the mode early */
mbed_official 1:d4bb1e33950e 744 int _on_duration_end_id;
mbed_official 1:d4bb1e33950e 745
mbed_official 1:d4bb1e33950e 746 /* Measure performance of our advertising/scanning */
mbed_official 1:d4bb1e33950e 747 Timer _demo_duration;
mbed_official 1:d4bb1e33950e 748 size_t _scan_count;
mbed_official 16:4dd4ecbc8efb 749
mbed_official 16:4dd4ecbc8efb 750 int _blink_event;
mbed_official 16:4dd4ecbc8efb 751
mbed_official 16:4dd4ecbc8efb 752 ble::advertising_handle_t _adv_handles[ADV_SET_NUMBER];
mbed_official 1:d4bb1e33950e 753 };
mbed_official 1:d4bb1e33950e 754
mbed_official 16:4dd4ecbc8efb 755 /** Schedule processing of events from the BLE middleware in the event queue. */
mbed_official 16:4dd4ecbc8efb 756 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
mbed_official 16:4dd4ecbc8efb 757 event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
mbed_official 16:4dd4ecbc8efb 758 }
mbed_official 16:4dd4ecbc8efb 759
mbed_official 1:d4bb1e33950e 760 int main()
mbed_official 1:d4bb1e33950e 761 {
mbed_official 16:4dd4ecbc8efb 762 BLE &ble = BLE::Instance();
mbed_official 16:4dd4ecbc8efb 763
mbed_official 16:4dd4ecbc8efb 764 /* this will inform us off all events so we can schedule their handling
mbed_official 16:4dd4ecbc8efb 765 * using our event queue */
mbed_official 16:4dd4ecbc8efb 766 ble.onEventsToProcess(schedule_ble_events);
mbed_official 16:4dd4ecbc8efb 767
mbed_official 16:4dd4ecbc8efb 768 GapDemo demo(ble, event_queue);
mbed_official 1:d4bb1e33950e 769
mbed_official 1:d4bb1e33950e 770 while (1) {
mbed_official 16:4dd4ecbc8efb 771 demo.run();
mbed_official 1:d4bb1e33950e 772 wait_ms(TIME_BETWEEN_MODES_MS);
mbed_official 1:d4bb1e33950e 773 printf("\r\nStarting next GAP demo mode\r\n");
mbed_official 1:d4bb1e33950e 774 };
mbed_official 1:d4bb1e33950e 775
mbed_official 1:d4bb1e33950e 776 return 0;
mbed_official 1:d4bb1e33950e 777 }