Example usage of the privacy features in the GAP.

Privacy - example usage of the privacy feature

Demonstration of privacy features in Gap. It shows how to use private addresses when advertising and connecting and how filtering ties in with these operations.

The application will start by repeatedly trying to connect to the same application running on another board. It will do this by advertising and scanning for random intervals waiting until the difference in intervals between the boards will make them meet when one is advertising and the other scanning.

Two devices will be operating using random resolvable addresses. The application will connect to the peer and pair. It will attempt bonding and if possible create a whitelist based on the bond.

Subsequent connections will turn on filtering if the whitelist has been successfully created.

Running the application

Requirements

Application requires two devices. Each one should be loaded with the same example. The application will alternate between scanning and advertising until the two devices find each other and the demonstration proceeds.

Information about activity is printed over the serial connection - please have two clients open, each connected to a device. You may use:

- Tera Term

Hardware requirements are in the main readme.

Building instructions

Building instructions for all samples are in the main readme.

Note: example currently doesn't use ST provided stack and instead uses a Cordio port for the ST.

Committer:
mbed_official
Date:
Mon Feb 25 17:44:26 2019 +0000
Revision:
0:2a36ad25fd97
Merge pull request #217 from adbridge/master

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

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 0:2a36ad25fd97 1 /* mbed Microcontroller Library
mbed_official 0:2a36ad25fd97 2 * Copyright (c) 2006-2013 ARM Limited
mbed_official 0:2a36ad25fd97 3 *
mbed_official 0:2a36ad25fd97 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 0:2a36ad25fd97 5 * you may not use this file except in compliance with the License.
mbed_official 0:2a36ad25fd97 6 * You may obtain a copy of the License at
mbed_official 0:2a36ad25fd97 7 *
mbed_official 0:2a36ad25fd97 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 0:2a36ad25fd97 9 *
mbed_official 0:2a36ad25fd97 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 0:2a36ad25fd97 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 0:2a36ad25fd97 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 0:2a36ad25fd97 13 * See the License for the specific language governing permissions and
mbed_official 0:2a36ad25fd97 14 * limitations under the License.
mbed_official 0:2a36ad25fd97 15 */
mbed_official 0:2a36ad25fd97 16
mbed_official 0:2a36ad25fd97 17 #include <events/mbed_events.h>
mbed_official 0:2a36ad25fd97 18 #include <mbed.h>
mbed_official 0:2a36ad25fd97 19 #include "ble/BLE.h"
mbed_official 0:2a36ad25fd97 20 #include "SecurityManager.h"
mbed_official 0:2a36ad25fd97 21 #include <algorithm>
mbed_official 0:2a36ad25fd97 22 #include "pretty_printer.h"
mbed_official 0:2a36ad25fd97 23 #include "ble/gap/AdvertisingDataParser.h"
mbed_official 0:2a36ad25fd97 24
mbed_official 0:2a36ad25fd97 25 /** This example demonstrates privacy features in Gap. It shows how to use
mbed_official 0:2a36ad25fd97 26 * private addresses when advertising and connecting and how filtering ties
mbed_official 0:2a36ad25fd97 27 * in with these operations.
mbed_official 0:2a36ad25fd97 28 *
mbed_official 0:2a36ad25fd97 29 * The application will start by repeatedly trying to connect to the same
mbed_official 0:2a36ad25fd97 30 * application running on another board. It will do this by advertising and
mbed_official 0:2a36ad25fd97 31 * scanning for random intervals waiting until the difference in intervals
mbed_official 0:2a36ad25fd97 32 * between the boards will make them meet when one is advertising and the
mbed_official 0:2a36ad25fd97 33 * other scanning.
mbed_official 0:2a36ad25fd97 34 *
mbed_official 0:2a36ad25fd97 35 * Two devices will be operating using random resolvable addresses. The
mbed_official 0:2a36ad25fd97 36 * applications will connect to the peer and pair. It will attempt bonding
mbed_official 0:2a36ad25fd97 37 * to store the IRK that resolve the peer. Subsequent connections will
mbed_official 0:2a36ad25fd97 38 * turn on filtering based on stored IRKs.
mbed_official 0:2a36ad25fd97 39 */
mbed_official 0:2a36ad25fd97 40
mbed_official 0:2a36ad25fd97 41 static const char DEVICE_NAME[] = "Privacy";
mbed_official 0:2a36ad25fd97 42
mbed_official 0:2a36ad25fd97 43 /* we have to specify the disconnect call because of ambiguous overloads */
mbed_official 0:2a36ad25fd97 44 typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t);
mbed_official 0:2a36ad25fd97 45 const static disconnect_call_t disconnect_call = &Gap::disconnect;
mbed_official 0:2a36ad25fd97 46
mbed_official 0:2a36ad25fd97 47 /** Base class for both peripheral and central. The same class that provides
mbed_official 0:2a36ad25fd97 48 * the logic for the application also implements the SecurityManagerEventHandler
mbed_official 0:2a36ad25fd97 49 * which is the interface used by the Security Manager to communicate events
mbed_official 0:2a36ad25fd97 50 * back to the applications. You can provide overrides for a selection of events
mbed_official 0:2a36ad25fd97 51 * your application is interested in.
mbed_official 0:2a36ad25fd97 52 */
mbed_official 0:2a36ad25fd97 53 class PrivacyDevice : private mbed::NonCopyable<PrivacyDevice>,
mbed_official 0:2a36ad25fd97 54 public SecurityManager::EventHandler,
mbed_official 0:2a36ad25fd97 55 public ble::Gap::EventHandler
mbed_official 0:2a36ad25fd97 56 {
mbed_official 0:2a36ad25fd97 57 public:
mbed_official 0:2a36ad25fd97 58 PrivacyDevice(BLE &ble, events::EventQueue &event_queue) :
mbed_official 0:2a36ad25fd97 59 _ble(ble),
mbed_official 0:2a36ad25fd97 60 _event_queue(event_queue),
mbed_official 0:2a36ad25fd97 61 _handle(0),
mbed_official 0:2a36ad25fd97 62 _bonded(false),
mbed_official 0:2a36ad25fd97 63 _led1(LED1, 0) { };
mbed_official 0:2a36ad25fd97 64
mbed_official 0:2a36ad25fd97 65 virtual ~PrivacyDevice() {
mbed_official 0:2a36ad25fd97 66 _ble.onEventsToProcess(NULL);
mbed_official 0:2a36ad25fd97 67 };
mbed_official 0:2a36ad25fd97 68
mbed_official 0:2a36ad25fd97 69 /** Start BLE interface initialisation */
mbed_official 0:2a36ad25fd97 70 void run()
mbed_official 0:2a36ad25fd97 71 {
mbed_official 0:2a36ad25fd97 72 /* to show we're running we'll blink every 500ms */
mbed_official 0:2a36ad25fd97 73 _event_queue.call_every(500, this, &PrivacyDevice::blink);
mbed_official 0:2a36ad25fd97 74
mbed_official 0:2a36ad25fd97 75 /* this will inform us off all events so we can schedule their handling
mbed_official 0:2a36ad25fd97 76 * using our event queue */
mbed_official 0:2a36ad25fd97 77 _ble.onEventsToProcess(
mbed_official 0:2a36ad25fd97 78 makeFunctionPointer(this, &PrivacyDevice::schedule_ble_events)
mbed_official 0:2a36ad25fd97 79 );
mbed_official 0:2a36ad25fd97 80
mbed_official 0:2a36ad25fd97 81 /* handle gap events */
mbed_official 0:2a36ad25fd97 82 _ble.gap().setEventHandler(this);
mbed_official 0:2a36ad25fd97 83
mbed_official 0:2a36ad25fd97 84 if (_ble.hasInitialized()) {
mbed_official 0:2a36ad25fd97 85 /* ble instance already initialised, skip init and start activity */
mbed_official 0:2a36ad25fd97 86 start();
mbed_official 0:2a36ad25fd97 87 } else {
mbed_official 0:2a36ad25fd97 88 ble_error_t error = _ble.init(this, &PrivacyDevice::on_init_complete);
mbed_official 0:2a36ad25fd97 89
mbed_official 0:2a36ad25fd97 90 if (error) {
mbed_official 0:2a36ad25fd97 91 printf("Error returned by BLE::init.\r\n");
mbed_official 0:2a36ad25fd97 92 return;
mbed_official 0:2a36ad25fd97 93 }
mbed_official 0:2a36ad25fd97 94 }
mbed_official 0:2a36ad25fd97 95
mbed_official 0:2a36ad25fd97 96 /* this will not return until shutdown */
mbed_official 0:2a36ad25fd97 97 _event_queue.dispatch_forever();
mbed_official 0:2a36ad25fd97 98 };
mbed_official 0:2a36ad25fd97 99
mbed_official 0:2a36ad25fd97 100 /** Override to start chosen activity when initialisation completes */
mbed_official 0:2a36ad25fd97 101 virtual void start() = 0;
mbed_official 0:2a36ad25fd97 102
mbed_official 0:2a36ad25fd97 103 /** Override to start chosen activity after initial bonding */
mbed_official 0:2a36ad25fd97 104 virtual void start_after_bonding() = 0;
mbed_official 0:2a36ad25fd97 105
mbed_official 0:2a36ad25fd97 106 /* callbacks */
mbed_official 0:2a36ad25fd97 107
mbed_official 0:2a36ad25fd97 108 /** This is called when BLE interface is initialised and starts the demonstration */
mbed_official 0:2a36ad25fd97 109 void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
mbed_official 0:2a36ad25fd97 110 {
mbed_official 0:2a36ad25fd97 111 ble_error_t error;
mbed_official 0:2a36ad25fd97 112
mbed_official 0:2a36ad25fd97 113 if (event->error) {
mbed_official 0:2a36ad25fd97 114 printf("Error during the initialisation\r\n");
mbed_official 0:2a36ad25fd97 115 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 116 return;
mbed_official 0:2a36ad25fd97 117 }
mbed_official 0:2a36ad25fd97 118
mbed_official 0:2a36ad25fd97 119 /* for use by tools we print out own address and also use it
mbed_official 0:2a36ad25fd97 120 * to seed RNG as the address is unique */
mbed_official 0:2a36ad25fd97 121 print_local_address();
mbed_official 0:2a36ad25fd97 122
mbed_official 0:2a36ad25fd97 123 /* Privacy requires the security manager */
mbed_official 0:2a36ad25fd97 124
mbed_official 0:2a36ad25fd97 125 error = _ble.securityManager().init(
mbed_official 0:2a36ad25fd97 126 /* enableBonding */ true,
mbed_official 0:2a36ad25fd97 127 /* requireMITM */ false,
mbed_official 0:2a36ad25fd97 128 /* iocaps */ SecurityManager::IO_CAPS_NONE,
mbed_official 0:2a36ad25fd97 129 /* passkey */ NULL,
mbed_official 0:2a36ad25fd97 130 /* signing */ false,
mbed_official 0:2a36ad25fd97 131 /* dbFilepath */ NULL
mbed_official 0:2a36ad25fd97 132 );
mbed_official 0:2a36ad25fd97 133
mbed_official 0:2a36ad25fd97 134 if (error) {
mbed_official 0:2a36ad25fd97 135 printf("Error during security manager initialisation\r\n");
mbed_official 0:2a36ad25fd97 136 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 137 return;
mbed_official 0:2a36ad25fd97 138 }
mbed_official 0:2a36ad25fd97 139
mbed_official 0:2a36ad25fd97 140 /* Tell the security manager to use methods in this class to inform us
mbed_official 0:2a36ad25fd97 141 * of any events. Class needs to implement SecurityManagerEventHandler. */
mbed_official 0:2a36ad25fd97 142 _ble.securityManager().setSecurityManagerEventHandler(this);
mbed_official 0:2a36ad25fd97 143
mbed_official 0:2a36ad25fd97 144 /* gap events also handled by this class */
mbed_official 0:2a36ad25fd97 145 _ble.gap().setEventHandler(this);
mbed_official 0:2a36ad25fd97 146
mbed_official 0:2a36ad25fd97 147 /* privacy */
mbed_official 0:2a36ad25fd97 148
mbed_official 0:2a36ad25fd97 149 error = _ble.gap().enablePrivacy(true);
mbed_official 0:2a36ad25fd97 150
mbed_official 0:2a36ad25fd97 151 if (error) {
mbed_official 0:2a36ad25fd97 152 printf("Error enabling privacy.\r\n");
mbed_official 0:2a36ad25fd97 153 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 154 return;
mbed_official 0:2a36ad25fd97 155 }
mbed_official 0:2a36ad25fd97 156
mbed_official 0:2a36ad25fd97 157 start();
mbed_official 0:2a36ad25fd97 158 };
mbed_official 0:2a36ad25fd97 159
mbed_official 0:2a36ad25fd97 160 /** Schedule processing of events from the BLE in the event queue. */
mbed_official 0:2a36ad25fd97 161 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
mbed_official 0:2a36ad25fd97 162 {
mbed_official 0:2a36ad25fd97 163 _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
mbed_official 0:2a36ad25fd97 164 };
mbed_official 0:2a36ad25fd97 165
mbed_official 0:2a36ad25fd97 166 /** Blink LED to show we're running */
mbed_official 0:2a36ad25fd97 167 void blink(void)
mbed_official 0:2a36ad25fd97 168 {
mbed_official 0:2a36ad25fd97 169 _led1 = !_led1;
mbed_official 0:2a36ad25fd97 170 };
mbed_official 0:2a36ad25fd97 171
mbed_official 0:2a36ad25fd97 172 void print_local_address()
mbed_official 0:2a36ad25fd97 173 {
mbed_official 0:2a36ad25fd97 174 /* show what address we are using now */
mbed_official 0:2a36ad25fd97 175 Gap::AddressType_t addr_type;
mbed_official 0:2a36ad25fd97 176 Gap::Address_t addr;
mbed_official 0:2a36ad25fd97 177 _ble.gap().getAddress(&addr_type, addr);
mbed_official 0:2a36ad25fd97 178 printf("Device address: ");
mbed_official 0:2a36ad25fd97 179 print_address(addr);
mbed_official 0:2a36ad25fd97 180
mbed_official 0:2a36ad25fd97 181 if (!_seeded) {
mbed_official 0:2a36ad25fd97 182 _seeded = true;
mbed_official 0:2a36ad25fd97 183 /* use the address as a seed */
mbed_official 0:2a36ad25fd97 184 uint8_t* random_data = addr;
mbed_official 0:2a36ad25fd97 185 srand(*((unsigned int*)random_data));
mbed_official 0:2a36ad25fd97 186 }
mbed_official 0:2a36ad25fd97 187 }
mbed_official 0:2a36ad25fd97 188
mbed_official 0:2a36ad25fd97 189 private:
mbed_official 0:2a36ad25fd97 190 /* Event handler */
mbed_official 0:2a36ad25fd97 191
mbed_official 0:2a36ad25fd97 192 /** Inform the application of pairing */
mbed_official 0:2a36ad25fd97 193 virtual void pairingResult(
mbed_official 0:2a36ad25fd97 194 ble::connection_handle_t connectionHandle,
mbed_official 0:2a36ad25fd97 195 SecurityManager::SecurityCompletionStatus_t result
mbed_official 0:2a36ad25fd97 196 ) {
mbed_official 0:2a36ad25fd97 197 if (result == SecurityManager::SEC_STATUS_SUCCESS) {
mbed_official 0:2a36ad25fd97 198 printf("Pairing successful\r\n");
mbed_official 0:2a36ad25fd97 199 _bonded = true;
mbed_official 0:2a36ad25fd97 200 } else {
mbed_official 0:2a36ad25fd97 201 printf("Pairing failed\r\n");
mbed_official 0:2a36ad25fd97 202 }
mbed_official 0:2a36ad25fd97 203
mbed_official 0:2a36ad25fd97 204 /* disconnect in 2s */
mbed_official 0:2a36ad25fd97 205 _event_queue.call_in(
mbed_official 0:2a36ad25fd97 206 2000,
mbed_official 0:2a36ad25fd97 207 &_ble.gap(),
mbed_official 0:2a36ad25fd97 208 disconnect_call,
mbed_official 0:2a36ad25fd97 209 connectionHandle,
mbed_official 0:2a36ad25fd97 210 ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION)
mbed_official 0:2a36ad25fd97 211 );
mbed_official 0:2a36ad25fd97 212 }
mbed_official 0:2a36ad25fd97 213
mbed_official 0:2a36ad25fd97 214 /** This is called by Gap to notify the application we connected */
mbed_official 0:2a36ad25fd97 215 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event)
mbed_official 0:2a36ad25fd97 216 {
mbed_official 0:2a36ad25fd97 217 printf("Connected to peer: ");
mbed_official 0:2a36ad25fd97 218 print_address(event.getPeerAddress().data());
mbed_official 0:2a36ad25fd97 219 printf("Peer random resolvable address: ");
mbed_official 0:2a36ad25fd97 220 print_address(event.getPeerResolvablePrivateAddress().data());
mbed_official 0:2a36ad25fd97 221
mbed_official 0:2a36ad25fd97 222 _handle = event.getConnectionHandle();
mbed_official 0:2a36ad25fd97 223
mbed_official 0:2a36ad25fd97 224 if (_bonded) {
mbed_official 0:2a36ad25fd97 225 /* disconnect in 2s */
mbed_official 0:2a36ad25fd97 226 _event_queue.call_in(
mbed_official 0:2a36ad25fd97 227 2000,
mbed_official 0:2a36ad25fd97 228 &_ble.gap(),
mbed_official 0:2a36ad25fd97 229 disconnect_call,
mbed_official 0:2a36ad25fd97 230 _handle,
mbed_official 0:2a36ad25fd97 231 ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION)
mbed_official 0:2a36ad25fd97 232 );
mbed_official 0:2a36ad25fd97 233 }
mbed_official 0:2a36ad25fd97 234 };
mbed_official 0:2a36ad25fd97 235
mbed_official 0:2a36ad25fd97 236 /** This is called by Gap to notify the application we disconnected */
mbed_official 0:2a36ad25fd97 237 virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event)
mbed_official 0:2a36ad25fd97 238 {
mbed_official 0:2a36ad25fd97 239 if (_bonded) {
mbed_official 0:2a36ad25fd97 240 /* we have connected to and bonded with the other device, from now
mbed_official 0:2a36ad25fd97 241 * on we will use the second start function and stay in the same role
mbed_official 0:2a36ad25fd97 242 * as peripheral or central */
mbed_official 0:2a36ad25fd97 243 printf("Disconnected.\r\n");
mbed_official 0:2a36ad25fd97 244 _event_queue.call_in(2000, this, &PrivacyDevice::start_after_bonding);
mbed_official 0:2a36ad25fd97 245 } else {
mbed_official 0:2a36ad25fd97 246 printf("Failed to bond.\r\n");
mbed_official 0:2a36ad25fd97 247 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 248 }
mbed_official 0:2a36ad25fd97 249 };
mbed_official 0:2a36ad25fd97 250
mbed_official 0:2a36ad25fd97 251 virtual void onScanTimeout(const ble::ScanTimeoutEvent &)
mbed_official 0:2a36ad25fd97 252 {
mbed_official 0:2a36ad25fd97 253 /* if we failed to find the other device, abort so that we change roles */
mbed_official 0:2a36ad25fd97 254 printf("Haven't seen other device, switch modes.\r\n");
mbed_official 0:2a36ad25fd97 255 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 256 }
mbed_official 0:2a36ad25fd97 257
mbed_official 0:2a36ad25fd97 258 public:
mbed_official 0:2a36ad25fd97 259 static bool _seeded;
mbed_official 0:2a36ad25fd97 260
mbed_official 0:2a36ad25fd97 261 protected:
mbed_official 0:2a36ad25fd97 262 BLE &_ble;
mbed_official 0:2a36ad25fd97 263 events::EventQueue &_event_queue;
mbed_official 0:2a36ad25fd97 264 ble::connection_handle_t _handle;
mbed_official 0:2a36ad25fd97 265 bool _bonded;
mbed_official 0:2a36ad25fd97 266
mbed_official 0:2a36ad25fd97 267 private:
mbed_official 0:2a36ad25fd97 268 DigitalOut _led1;
mbed_official 0:2a36ad25fd97 269 };
mbed_official 0:2a36ad25fd97 270
mbed_official 0:2a36ad25fd97 271 /** A peripheral device will advertise and accept the connections */
mbed_official 0:2a36ad25fd97 272 class PrivacyPeripheral : public PrivacyDevice {
mbed_official 0:2a36ad25fd97 273 public:
mbed_official 0:2a36ad25fd97 274 PrivacyPeripheral(BLE &ble, events::EventQueue &event_queue)
mbed_official 0:2a36ad25fd97 275 : PrivacyDevice(ble, event_queue) { }
mbed_official 0:2a36ad25fd97 276
mbed_official 0:2a36ad25fd97 277 /** Set up and start advertising accepting anyone */
mbed_official 0:2a36ad25fd97 278 virtual void start()
mbed_official 0:2a36ad25fd97 279 {
mbed_official 0:2a36ad25fd97 280 if (!set_advertising_data()) {
mbed_official 0:2a36ad25fd97 281 return;
mbed_official 0:2a36ad25fd97 282 }
mbed_official 0:2a36ad25fd97 283
mbed_official 0:2a36ad25fd97 284 Gap::PeripheralPrivacyConfiguration_t privacy_configuration = {
mbed_official 0:2a36ad25fd97 285 /* use_non_resolvable_random_address */ false,
mbed_official 0:2a36ad25fd97 286 Gap::PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE
mbed_official 0:2a36ad25fd97 287 };
mbed_official 0:2a36ad25fd97 288
mbed_official 0:2a36ad25fd97 289 _ble.gap().setPeripheralPrivacyConfiguration(&privacy_configuration);
mbed_official 0:2a36ad25fd97 290
mbed_official 0:2a36ad25fd97 291 start_advertising();
mbed_official 0:2a36ad25fd97 292 };
mbed_official 0:2a36ad25fd97 293
mbed_official 0:2a36ad25fd97 294 /** advertise and filter based on known devices */
mbed_official 0:2a36ad25fd97 295 virtual void start_after_bonding()
mbed_official 0:2a36ad25fd97 296 {
mbed_official 0:2a36ad25fd97 297 Gap::PeripheralPrivacyConfiguration_t privacy_configuration = {
mbed_official 0:2a36ad25fd97 298 /* use_non_resolvable_random_address */ false,
mbed_official 0:2a36ad25fd97 299 Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS
mbed_official 0:2a36ad25fd97 300 };
mbed_official 0:2a36ad25fd97 301
mbed_official 0:2a36ad25fd97 302 _ble.gap().setPeripheralPrivacyConfiguration(&privacy_configuration);
mbed_official 0:2a36ad25fd97 303
mbed_official 0:2a36ad25fd97 304 start_advertising();
mbed_official 0:2a36ad25fd97 305 }
mbed_official 0:2a36ad25fd97 306
mbed_official 0:2a36ad25fd97 307 /* helper functions */
mbed_official 0:2a36ad25fd97 308
mbed_official 0:2a36ad25fd97 309 private:
mbed_official 0:2a36ad25fd97 310 bool set_advertising_data()
mbed_official 0:2a36ad25fd97 311 {
mbed_official 0:2a36ad25fd97 312 uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
mbed_official 0:2a36ad25fd97 313 /* use the helper to build the payload */
mbed_official 0:2a36ad25fd97 314 ble::AdvertisingDataBuilder adv_data_builder(
mbed_official 0:2a36ad25fd97 315 adv_buffer
mbed_official 0:2a36ad25fd97 316 );
mbed_official 0:2a36ad25fd97 317
mbed_official 0:2a36ad25fd97 318 adv_data_builder.setFlags();
mbed_official 0:2a36ad25fd97 319 adv_data_builder.setName(DEVICE_NAME);
mbed_official 0:2a36ad25fd97 320
mbed_official 0:2a36ad25fd97 321 /* Set payload for the set */
mbed_official 0:2a36ad25fd97 322 ble_error_t error = _ble.gap().setAdvertisingPayload(
mbed_official 0:2a36ad25fd97 323 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 0:2a36ad25fd97 324 adv_data_builder.getAdvertisingData()
mbed_official 0:2a36ad25fd97 325 );
mbed_official 0:2a36ad25fd97 326
mbed_official 0:2a36ad25fd97 327 if (error) {
mbed_official 0:2a36ad25fd97 328 print_error(error, "Gap::setAdvertisingPayload() failed");
mbed_official 0:2a36ad25fd97 329 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 330 return false;
mbed_official 0:2a36ad25fd97 331 }
mbed_official 0:2a36ad25fd97 332
mbed_official 0:2a36ad25fd97 333 return true;
mbed_official 0:2a36ad25fd97 334 }
mbed_official 0:2a36ad25fd97 335
mbed_official 0:2a36ad25fd97 336 bool start_advertising()
mbed_official 0:2a36ad25fd97 337 {
mbed_official 0:2a36ad25fd97 338 ble::AdvertisingParameters adv_parameters(
mbed_official 0:2a36ad25fd97 339 ble::advertising_type_t::CONNECTABLE_UNDIRECTED
mbed_official 0:2a36ad25fd97 340 );
mbed_official 0:2a36ad25fd97 341
mbed_official 0:2a36ad25fd97 342 ble_error_t error = _ble.gap().setAdvertisingParameters(
mbed_official 0:2a36ad25fd97 343 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 0:2a36ad25fd97 344 adv_parameters
mbed_official 0:2a36ad25fd97 345 );
mbed_official 0:2a36ad25fd97 346
mbed_official 0:2a36ad25fd97 347 if (error) {
mbed_official 0:2a36ad25fd97 348 print_error(error, "Gap::setAdvertisingParameters() failed");
mbed_official 0:2a36ad25fd97 349 return false;
mbed_official 0:2a36ad25fd97 350 }
mbed_official 0:2a36ad25fd97 351
mbed_official 0:2a36ad25fd97 352 if (_bonded) {
mbed_official 0:2a36ad25fd97 353 /* if we bonded it means we have found the other device, from now on
mbed_official 0:2a36ad25fd97 354 * wait at each step until completion */
mbed_official 0:2a36ad25fd97 355 error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 0:2a36ad25fd97 356 } else {
mbed_official 0:2a36ad25fd97 357 /* since we have two boards which might start running this example at the same time
mbed_official 0:2a36ad25fd97 358 * we randomise the interval of advertising to have them meet when one is advertising
mbed_official 0:2a36ad25fd97 359 * and the other one is scanning (we use their random address as source of randomness) */
mbed_official 0:2a36ad25fd97 360 ble::millisecond_t random_duration_ms((1 + rand() % 5) * 1000);
mbed_official 0:2a36ad25fd97 361 ble::adv_duration_t random_duration(random_duration_ms);
mbed_official 0:2a36ad25fd97 362 error = _ble.gap().startAdvertising(
mbed_official 0:2a36ad25fd97 363 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 0:2a36ad25fd97 364 random_duration
mbed_official 0:2a36ad25fd97 365 );
mbed_official 0:2a36ad25fd97 366 }
mbed_official 0:2a36ad25fd97 367
mbed_official 0:2a36ad25fd97 368 if (error) {
mbed_official 0:2a36ad25fd97 369 print_error(error, "Gap::startAdvertising() failed");
mbed_official 0:2a36ad25fd97 370 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 371 return false;
mbed_official 0:2a36ad25fd97 372 }
mbed_official 0:2a36ad25fd97 373
mbed_official 0:2a36ad25fd97 374 printf("Advertising...\r\n");
mbed_official 0:2a36ad25fd97 375
mbed_official 0:2a36ad25fd97 376 return true;
mbed_official 0:2a36ad25fd97 377 }
mbed_official 0:2a36ad25fd97 378
mbed_official 0:2a36ad25fd97 379 };
mbed_official 0:2a36ad25fd97 380
mbed_official 0:2a36ad25fd97 381 /** A central device will scan and connect to a peer. */
mbed_official 0:2a36ad25fd97 382 class PrivacyCentral : public PrivacyDevice {
mbed_official 0:2a36ad25fd97 383 public:
mbed_official 0:2a36ad25fd97 384 PrivacyCentral(BLE &ble, events::EventQueue &event_queue)
mbed_official 0:2a36ad25fd97 385 : PrivacyDevice(ble, event_queue),
mbed_official 0:2a36ad25fd97 386 _is_connecting(false) { }
mbed_official 0:2a36ad25fd97 387
mbed_official 0:2a36ad25fd97 388 /** start scanning and attach a callback that will handle advertisements
mbed_official 0:2a36ad25fd97 389 * and scan requests responses */
mbed_official 0:2a36ad25fd97 390 virtual void start()
mbed_official 0:2a36ad25fd97 391 {
mbed_official 0:2a36ad25fd97 392 Gap::CentralPrivacyConfiguration_t privacy_configuration = {
mbed_official 0:2a36ad25fd97 393 /* use_non_resolvable_random_address */ false,
mbed_official 0:2a36ad25fd97 394 Gap::CentralPrivacyConfiguration_t::DO_NOT_RESOLVE
mbed_official 0:2a36ad25fd97 395 };
mbed_official 0:2a36ad25fd97 396
mbed_official 0:2a36ad25fd97 397 _ble.gap().setCentralPrivacyConfiguration(&privacy_configuration);
mbed_official 0:2a36ad25fd97 398
mbed_official 0:2a36ad25fd97 399 start_scanning();
mbed_official 0:2a36ad25fd97 400 }
mbed_official 0:2a36ad25fd97 401
mbed_official 0:2a36ad25fd97 402 virtual void start_after_bonding()
mbed_official 0:2a36ad25fd97 403 {
mbed_official 0:2a36ad25fd97 404 Gap::CentralPrivacyConfiguration_t privacy_configuration = {
mbed_official 0:2a36ad25fd97 405 /* use_non_resolvable_random_address */ false,
mbed_official 0:2a36ad25fd97 406 Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FILTER
mbed_official 0:2a36ad25fd97 407 };
mbed_official 0:2a36ad25fd97 408
mbed_official 0:2a36ad25fd97 409 _ble.gap().setCentralPrivacyConfiguration(&privacy_configuration);
mbed_official 0:2a36ad25fd97 410
mbed_official 0:2a36ad25fd97 411 start_scanning();
mbed_official 0:2a36ad25fd97 412 }
mbed_official 0:2a36ad25fd97 413
mbed_official 0:2a36ad25fd97 414 /* helper functions */
mbed_official 0:2a36ad25fd97 415 private:
mbed_official 0:2a36ad25fd97 416 bool start_scanning() {
mbed_official 0:2a36ad25fd97 417 ble_error_t error;
mbed_official 0:2a36ad25fd97 418 ble::ScanParameters scan_params;
mbed_official 0:2a36ad25fd97 419 _ble.gap().setScanParameters(scan_params);
mbed_official 0:2a36ad25fd97 420
mbed_official 0:2a36ad25fd97 421 _is_connecting = false;
mbed_official 0:2a36ad25fd97 422
mbed_official 0:2a36ad25fd97 423 if (_bonded) {
mbed_official 0:2a36ad25fd97 424 /* if we bonded it means we have found the other device, from now on
mbed_official 0:2a36ad25fd97 425 * wait at each step until completion */
mbed_official 0:2a36ad25fd97 426 error = _ble.gap().startScan(ble::scan_duration_t::forever());
mbed_official 0:2a36ad25fd97 427 } else {
mbed_official 0:2a36ad25fd97 428 /* otherwise only scan for a limited time before changing roles again
mbed_official 0:2a36ad25fd97 429 * if we fail to find the other device */
mbed_official 0:2a36ad25fd97 430 error = _ble.gap().startScan(
mbed_official 0:2a36ad25fd97 431 ble::scan_duration_t(ble::millisecond_t(4000))
mbed_official 0:2a36ad25fd97 432 );
mbed_official 0:2a36ad25fd97 433 }
mbed_official 0:2a36ad25fd97 434
mbed_official 0:2a36ad25fd97 435 if (error) {
mbed_official 0:2a36ad25fd97 436 printf("Error during Gap::startScan %d\r\n", error);
mbed_official 0:2a36ad25fd97 437 _event_queue.break_dispatch();
mbed_official 0:2a36ad25fd97 438 return false;
mbed_official 0:2a36ad25fd97 439 }
mbed_official 0:2a36ad25fd97 440
mbed_official 0:2a36ad25fd97 441 printf("Scanning...\r\n");
mbed_official 0:2a36ad25fd97 442
mbed_official 0:2a36ad25fd97 443 return true;
mbed_official 0:2a36ad25fd97 444 }
mbed_official 0:2a36ad25fd97 445
mbed_official 0:2a36ad25fd97 446 private:
mbed_official 0:2a36ad25fd97 447 /* Event handler */
mbed_official 0:2a36ad25fd97 448
mbed_official 0:2a36ad25fd97 449 /** Look at scan payload to find a peer device and connect to it */
mbed_official 0:2a36ad25fd97 450 virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event)
mbed_official 0:2a36ad25fd97 451 {
mbed_official 0:2a36ad25fd97 452 /* don't bother with analysing scan result if we're already connecting */
mbed_official 0:2a36ad25fd97 453 if (_is_connecting) {
mbed_official 0:2a36ad25fd97 454 return;
mbed_official 0:2a36ad25fd97 455 }
mbed_official 0:2a36ad25fd97 456
mbed_official 0:2a36ad25fd97 457 ble::AdvertisingDataParser adv_data(event.getPayload());
mbed_official 0:2a36ad25fd97 458
mbed_official 0:2a36ad25fd97 459 /* parse the advertising payload, looking for a discoverable device */
mbed_official 0:2a36ad25fd97 460 while (adv_data.hasNext()) {
mbed_official 0:2a36ad25fd97 461 ble::AdvertisingDataParser::element_t field = adv_data.next();
mbed_official 0:2a36ad25fd97 462
mbed_official 0:2a36ad25fd97 463 /* connect to a known device by name */
mbed_official 0:2a36ad25fd97 464 if (field.type == ble::adv_data_type_t::COMPLETE_LOCAL_NAME &&
mbed_official 0:2a36ad25fd97 465 field.value.size() == strlen(DEVICE_NAME) &&
mbed_official 0:2a36ad25fd97 466 (memcmp(field.value.data(), DEVICE_NAME, field.value.size()) == 0)) {
mbed_official 0:2a36ad25fd97 467
mbed_official 0:2a36ad25fd97 468 printf("We found a connectable device\r\n");
mbed_official 0:2a36ad25fd97 469
mbed_official 0:2a36ad25fd97 470 ble_error_t error = _ble.gap().stopScan();
mbed_official 0:2a36ad25fd97 471
mbed_official 0:2a36ad25fd97 472 if (error) {
mbed_official 0:2a36ad25fd97 473 print_error(error, "Error caused by Gap::stopScan");
mbed_official 0:2a36ad25fd97 474 return;
mbed_official 0:2a36ad25fd97 475 }
mbed_official 0:2a36ad25fd97 476
mbed_official 0:2a36ad25fd97 477 const ble::ConnectionParameters connection_params;
mbed_official 0:2a36ad25fd97 478
mbed_official 0:2a36ad25fd97 479 error = _ble.gap().connect(
mbed_official 0:2a36ad25fd97 480 event.getPeerAddressType(),
mbed_official 0:2a36ad25fd97 481 event.getPeerAddress(),
mbed_official 0:2a36ad25fd97 482 connection_params
mbed_official 0:2a36ad25fd97 483 );
mbed_official 0:2a36ad25fd97 484
mbed_official 0:2a36ad25fd97 485 if (error) {
mbed_official 0:2a36ad25fd97 486 print_error(error, "Error caused by Gap::connect");
mbed_official 0:2a36ad25fd97 487 return;
mbed_official 0:2a36ad25fd97 488 }
mbed_official 0:2a36ad25fd97 489
mbed_official 0:2a36ad25fd97 490 /* we may have already scan events waiting
mbed_official 0:2a36ad25fd97 491 * to be processed so we need to remember
mbed_official 0:2a36ad25fd97 492 * that we are already connecting and ignore them */
mbed_official 0:2a36ad25fd97 493 _is_connecting = true;
mbed_official 0:2a36ad25fd97 494
mbed_official 0:2a36ad25fd97 495 return;
mbed_official 0:2a36ad25fd97 496
mbed_official 0:2a36ad25fd97 497 }
mbed_official 0:2a36ad25fd97 498 }
mbed_official 0:2a36ad25fd97 499 }
mbed_official 0:2a36ad25fd97 500
mbed_official 0:2a36ad25fd97 501 private:
mbed_official 0:2a36ad25fd97 502 bool _is_connecting;
mbed_official 0:2a36ad25fd97 503 };
mbed_official 0:2a36ad25fd97 504
mbed_official 0:2a36ad25fd97 505 /* only seed the random number generation once per application run */
mbed_official 0:2a36ad25fd97 506 bool PrivacyDevice::_seeded = false;
mbed_official 0:2a36ad25fd97 507
mbed_official 0:2a36ad25fd97 508 int main()
mbed_official 0:2a36ad25fd97 509 {
mbed_official 0:2a36ad25fd97 510 BLE& ble = BLE::Instance();
mbed_official 0:2a36ad25fd97 511
mbed_official 0:2a36ad25fd97 512 while(1) {
mbed_official 0:2a36ad25fd97 513 {
mbed_official 0:2a36ad25fd97 514 events::EventQueue queue;
mbed_official 0:2a36ad25fd97 515 printf("\r\n * Device is a peripheral *\r\n\r\n");
mbed_official 0:2a36ad25fd97 516 PrivacyPeripheral peripheral(ble, queue);
mbed_official 0:2a36ad25fd97 517 peripheral.run();
mbed_official 0:2a36ad25fd97 518 }
mbed_official 0:2a36ad25fd97 519 {
mbed_official 0:2a36ad25fd97 520 events::EventQueue queue;
mbed_official 0:2a36ad25fd97 521 printf("\r\n * Device is a central *\r\n\r\n");
mbed_official 0:2a36ad25fd97 522 PrivacyCentral central(ble, queue);
mbed_official 0:2a36ad25fd97 523 central.run();
mbed_official 0:2a36ad25fd97 524 }
mbed_official 0:2a36ad25fd97 525 }
mbed_official 0:2a36ad25fd97 526
mbed_official 0:2a36ad25fd97 527 return 0;
mbed_official 0:2a36ad25fd97 528 }