Demonstration of possible usage of the Security Manager. Security Manager deals with pairing, authentication and encryption.

SM - example usage of the Security Manager to pair and encrypt

Demonstration of possible usage of the Security Manager. Security Manager deals with pairing, authentication and encryption.

The application demonstrates usage as a central and a peripheral. The central will connect to any connectable device present. Please have one ready and advertising. Application will attempt pairing. Please authorise your peer device to pair.

Upon success it will disconnect and start advertising to demonstrate usage as a peripheral. Please scan and connect using your peer device. Upon connection grant pairing if prompted. Upon success the application will disconnect. Observe the terminal to keep track of the sequence.

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:
Donatien Garnier
Date:
Fri Jun 01 13:54:04 2018 -0500
Revision:
1:916188eae2bb
Parent:
0:fcb1e0b995a9
Child:
9:674ab70e0f36
Update ST support status

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Donatien Garnier 1:916188eae2bb 1 /* mbed Microcontroller Library
Donatien Garnier 1:916188eae2bb 2 * Copyright (c) 2006-2013 ARM Limited
Donatien Garnier 1:916188eae2bb 3 *
Donatien Garnier 1:916188eae2bb 4 * Licensed under the Apache License, Version 2.0 (the "License");
Donatien Garnier 1:916188eae2bb 5 * you may not use this file except in compliance with the License.
Donatien Garnier 1:916188eae2bb 6 * You may obtain a copy of the License at
Donatien Garnier 1:916188eae2bb 7 *
Donatien Garnier 1:916188eae2bb 8 * http://www.apache.org/licenses/LICENSE-2.0
Donatien Garnier 1:916188eae2bb 9 *
Donatien Garnier 1:916188eae2bb 10 * Unless required by applicable law or agreed to in writing, software
Donatien Garnier 1:916188eae2bb 11 * distributed under the License is distributed on an "AS IS" BASIS,
Donatien Garnier 1:916188eae2bb 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Donatien Garnier 1:916188eae2bb 13 * See the License for the specific language governing permissions and
Donatien Garnier 1:916188eae2bb 14 * limitations under the License.
Donatien Garnier 1:916188eae2bb 15 */
Donatien Garnier 1:916188eae2bb 16
Donatien Garnier 1:916188eae2bb 17 #include <events/mbed_events.h>
Donatien Garnier 1:916188eae2bb 18 #include <mbed.h>
Donatien Garnier 1:916188eae2bb 19 #include "ble/BLE.h"
Donatien Garnier 1:916188eae2bb 20 #include "SecurityManager.h"
Donatien Garnier 1:916188eae2bb 21
Donatien Garnier 1:916188eae2bb 22 /** This example demonstrates all the basic setup required
Donatien Garnier 1:916188eae2bb 23 * for pairing and setting up link security both as a central and peripheral
Donatien Garnier 1:916188eae2bb 24 *
Donatien Garnier 1:916188eae2bb 25 * The example is implemented as two classes, one for the peripheral and one
Donatien Garnier 1:916188eae2bb 26 * for central inheriting from a common base. They are run in sequence and
Donatien Garnier 1:916188eae2bb 27 * require a peer device to connect to. During the peripheral device demonstration
Donatien Garnier 1:916188eae2bb 28 * a peer device is required to connect. In the central device demonstration
Donatien Garnier 1:916188eae2bb 29 * this peer device will be scanned for and connected to - therefore it should
Donatien Garnier 1:916188eae2bb 30 * be advertising with the same address as when it connected.
Donatien Garnier 1:916188eae2bb 31 *
Donatien Garnier 1:916188eae2bb 32 * During the test output is written on the serial connection to monitor its
Donatien Garnier 1:916188eae2bb 33 * progress.
Donatien Garnier 1:916188eae2bb 34 */
Donatien Garnier 1:916188eae2bb 35
Donatien Garnier 1:916188eae2bb 36 static const uint8_t DEVICE_NAME[] = "SM_device";
Donatien Garnier 1:916188eae2bb 37
Donatien Garnier 1:916188eae2bb 38 /* for demonstration purposes we will store the peer device address
Donatien Garnier 1:916188eae2bb 39 * of the device that connects to us in the first demonstration
Donatien Garnier 1:916188eae2bb 40 * so we can use its address to reconnect to it later */
Donatien Garnier 1:916188eae2bb 41 static BLEProtocol::AddressBytes_t peer_address;
Donatien Garnier 1:916188eae2bb 42
Donatien Garnier 1:916188eae2bb 43 /** Base class for both peripheral and central. The same class that provides
Donatien Garnier 1:916188eae2bb 44 * the logic for the application also implements the SecurityManagerEventHandler
Donatien Garnier 1:916188eae2bb 45 * which is the interface used by the Security Manager to communicate events
Donatien Garnier 1:916188eae2bb 46 * back to the applications. You can provide overrides for a selection of events
Donatien Garnier 1:916188eae2bb 47 * your application is interested in.
Donatien Garnier 1:916188eae2bb 48 */
Donatien Garnier 1:916188eae2bb 49 class SMDevice : private mbed::NonCopyable<SMDevice>,
Donatien Garnier 1:916188eae2bb 50 public SecurityManager::EventHandler
Donatien Garnier 1:916188eae2bb 51 {
Donatien Garnier 1:916188eae2bb 52 public:
Donatien Garnier 1:916188eae2bb 53 SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) :
Donatien Garnier 1:916188eae2bb 54 _led1(LED1, 0),
Donatien Garnier 1:916188eae2bb 55 _ble(ble),
Donatien Garnier 1:916188eae2bb 56 _event_queue(event_queue),
Donatien Garnier 1:916188eae2bb 57 _peer_address(peer_address),
Donatien Garnier 1:916188eae2bb 58 _handle(0),
Donatien Garnier 1:916188eae2bb 59 _is_connecting(false) { };
Donatien Garnier 1:916188eae2bb 60
Donatien Garnier 1:916188eae2bb 61 virtual ~SMDevice()
Donatien Garnier 1:916188eae2bb 62 {
Donatien Garnier 1:916188eae2bb 63 if (_ble.hasInitialized()) {
Donatien Garnier 1:916188eae2bb 64 _ble.shutdown();
Donatien Garnier 1:916188eae2bb 65 }
Donatien Garnier 1:916188eae2bb 66 };
Donatien Garnier 1:916188eae2bb 67
Donatien Garnier 1:916188eae2bb 68 /** Start BLE interface initialisation */
Donatien Garnier 1:916188eae2bb 69 void run()
Donatien Garnier 1:916188eae2bb 70 {
Donatien Garnier 1:916188eae2bb 71 ble_error_t error;
Donatien Garnier 1:916188eae2bb 72
Donatien Garnier 1:916188eae2bb 73 /* to show we're running we'll blink every 500ms */
Donatien Garnier 1:916188eae2bb 74 _event_queue.call_every(500, this, &SMDevice::blink);
Donatien Garnier 1:916188eae2bb 75
Donatien Garnier 1:916188eae2bb 76 if (_ble.hasInitialized()) {
Donatien Garnier 1:916188eae2bb 77 printf("Ble instance already initialised.\r\n");
Donatien Garnier 1:916188eae2bb 78 return;
Donatien Garnier 1:916188eae2bb 79 }
Donatien Garnier 1:916188eae2bb 80
Donatien Garnier 1:916188eae2bb 81 /* this will inform us off all events so we can schedule their handling
Donatien Garnier 1:916188eae2bb 82 * using our event queue */
Donatien Garnier 1:916188eae2bb 83 _ble.onEventsToProcess(
Donatien Garnier 1:916188eae2bb 84 makeFunctionPointer(this, &SMDevice::schedule_ble_events)
Donatien Garnier 1:916188eae2bb 85 );
Donatien Garnier 1:916188eae2bb 86
Donatien Garnier 1:916188eae2bb 87 /* handle timeouts, for example when connection attempts fail */
Donatien Garnier 1:916188eae2bb 88 _ble.gap().onTimeout(
Donatien Garnier 1:916188eae2bb 89 makeFunctionPointer(this, &SMDevice::on_timeout)
Donatien Garnier 1:916188eae2bb 90 );
Donatien Garnier 1:916188eae2bb 91
Donatien Garnier 1:916188eae2bb 92 error = _ble.init(this, &SMDevice::on_init_complete);
Donatien Garnier 1:916188eae2bb 93
Donatien Garnier 1:916188eae2bb 94 if (error) {
Donatien Garnier 1:916188eae2bb 95 printf("Error returned by BLE::init.\r\n");
Donatien Garnier 1:916188eae2bb 96 return;
Donatien Garnier 1:916188eae2bb 97 }
Donatien Garnier 1:916188eae2bb 98
Donatien Garnier 1:916188eae2bb 99 /* this will not return until shutdown */
Donatien Garnier 1:916188eae2bb 100 _event_queue.dispatch_forever();
Donatien Garnier 1:916188eae2bb 101 };
Donatien Garnier 1:916188eae2bb 102
Donatien Garnier 1:916188eae2bb 103 /* event handler functions */
Donatien Garnier 1:916188eae2bb 104
Donatien Garnier 1:916188eae2bb 105 /** Respond to a pairing request. This will be called by the stack
Donatien Garnier 1:916188eae2bb 106 * when a pairing request arrives and expects the application to
Donatien Garnier 1:916188eae2bb 107 * call acceptPairingRequest or cancelPairingRequest */
Donatien Garnier 1:916188eae2bb 108 virtual void pairingRequest(
Donatien Garnier 1:916188eae2bb 109 ble::connection_handle_t connectionHandle
Donatien Garnier 1:916188eae2bb 110 ) {
Donatien Garnier 1:916188eae2bb 111 printf("Pairing requested. Authorising.\r\n");
Donatien Garnier 1:916188eae2bb 112 _ble.securityManager().acceptPairingRequest(connectionHandle);
Donatien Garnier 1:916188eae2bb 113 }
Donatien Garnier 1:916188eae2bb 114
Donatien Garnier 1:916188eae2bb 115 /** Inform the application of a successful pairing. Terminate the demonstration. */
Donatien Garnier 1:916188eae2bb 116 virtual void pairingResult(
Donatien Garnier 1:916188eae2bb 117 ble::connection_handle_t connectionHandle,
Donatien Garnier 1:916188eae2bb 118 SecurityManager::SecurityCompletionStatus_t result
Donatien Garnier 1:916188eae2bb 119 ) {
Donatien Garnier 1:916188eae2bb 120 if (result == SecurityManager::SEC_STATUS_SUCCESS) {
Donatien Garnier 1:916188eae2bb 121 printf("Pairing successful\r\n");
Donatien Garnier 1:916188eae2bb 122 } else {
Donatien Garnier 1:916188eae2bb 123 printf("Pairing failed\r\n");
Donatien Garnier 1:916188eae2bb 124 }
Donatien Garnier 1:916188eae2bb 125
Donatien Garnier 1:916188eae2bb 126 /* disconnect in 500 ms */
Donatien Garnier 1:916188eae2bb 127 _event_queue.call_in(
Donatien Garnier 1:916188eae2bb 128 500, &_ble.gap(),
Donatien Garnier 1:916188eae2bb 129 &Gap::disconnect, _handle, Gap::REMOTE_USER_TERMINATED_CONNECTION
Donatien Garnier 1:916188eae2bb 130 );
Donatien Garnier 1:916188eae2bb 131 }
Donatien Garnier 1:916188eae2bb 132
Donatien Garnier 1:916188eae2bb 133 /** Inform the application of change in encryption status. This will be
Donatien Garnier 1:916188eae2bb 134 * communicated through the serial port */
Donatien Garnier 1:916188eae2bb 135 virtual void linkEncryptionResult(
Donatien Garnier 1:916188eae2bb 136 ble::connection_handle_t connectionHandle,
Donatien Garnier 1:916188eae2bb 137 ble::link_encryption_t result
Donatien Garnier 1:916188eae2bb 138 ) {
Donatien Garnier 1:916188eae2bb 139 if (result == ble::link_encryption_t::ENCRYPTED) {
Donatien Garnier 1:916188eae2bb 140 printf("Link ENCRYPTED\r\n");
Donatien Garnier 1:916188eae2bb 141 } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
Donatien Garnier 1:916188eae2bb 142 printf("Link ENCRYPTED_WITH_MITM\r\n");
Donatien Garnier 1:916188eae2bb 143 } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) {
Donatien Garnier 1:916188eae2bb 144 printf("Link NOT_ENCRYPTED\r\n");
Donatien Garnier 1:916188eae2bb 145 }
Donatien Garnier 1:916188eae2bb 146 }
Donatien Garnier 1:916188eae2bb 147
Donatien Garnier 1:916188eae2bb 148 private:
Donatien Garnier 1:916188eae2bb 149 /** Override to start chosen activity when initialisation completes */
Donatien Garnier 1:916188eae2bb 150 virtual void start() = 0;
Donatien Garnier 1:916188eae2bb 151
Donatien Garnier 1:916188eae2bb 152 /** This is called when BLE interface is initialised and starts the demonstration */
Donatien Garnier 1:916188eae2bb 153 void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
Donatien Garnier 1:916188eae2bb 154 {
Donatien Garnier 1:916188eae2bb 155 ble_error_t error;
Donatien Garnier 1:916188eae2bb 156
Donatien Garnier 1:916188eae2bb 157 if (event->error) {
Donatien Garnier 1:916188eae2bb 158 printf("Error during the initialisation\r\n");
Donatien Garnier 1:916188eae2bb 159 return;
Donatien Garnier 1:916188eae2bb 160 }
Donatien Garnier 1:916188eae2bb 161
Donatien Garnier 1:916188eae2bb 162 /* If the security manager is required this needs to be called before any
Donatien Garnier 1:916188eae2bb 163 * calls to the Security manager happen. */
Donatien Garnier 1:916188eae2bb 164 error = _ble.securityManager().init();
Donatien Garnier 1:916188eae2bb 165
Donatien Garnier 1:916188eae2bb 166 if (error) {
Donatien Garnier 1:916188eae2bb 167 printf("Error during init %d\r\n", error);
Donatien Garnier 1:916188eae2bb 168 return;
Donatien Garnier 1:916188eae2bb 169 }
Donatien Garnier 1:916188eae2bb 170
Donatien Garnier 1:916188eae2bb 171 /* Tell the security manager to use methods in this class to inform us
Donatien Garnier 1:916188eae2bb 172 * of any events. Class needs to implement SecurityManagerEventHandler. */
Donatien Garnier 1:916188eae2bb 173 _ble.securityManager().setSecurityManagerEventHandler(this);
Donatien Garnier 1:916188eae2bb 174
Donatien Garnier 1:916188eae2bb 175 /* print device address */
Donatien Garnier 1:916188eae2bb 176 Gap::AddressType_t addr_type;
Donatien Garnier 1:916188eae2bb 177 Gap::Address_t addr;
Donatien Garnier 1:916188eae2bb 178 _ble.gap().getAddress(&addr_type, addr);
Donatien Garnier 1:916188eae2bb 179 printf("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
Donatien Garnier 1:916188eae2bb 180 addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
Donatien Garnier 1:916188eae2bb 181
Donatien Garnier 1:916188eae2bb 182 /* when scanning we want to connect to a peer device so we need to
Donatien Garnier 1:916188eae2bb 183 * attach callbacks that are used by Gap to notify us of events */
Donatien Garnier 1:916188eae2bb 184 _ble.gap().onConnection(this, &SMDevice::on_connect);
Donatien Garnier 1:916188eae2bb 185 _ble.gap().onDisconnection(this, &SMDevice::on_disconnect);
Donatien Garnier 1:916188eae2bb 186
Donatien Garnier 1:916188eae2bb 187 /* start test in 500 ms */
Donatien Garnier 1:916188eae2bb 188 _event_queue.call_in(500, this, &SMDevice::start);
Donatien Garnier 1:916188eae2bb 189 };
Donatien Garnier 1:916188eae2bb 190
Donatien Garnier 1:916188eae2bb 191 /** This is called by Gap to notify the application we connected */
Donatien Garnier 1:916188eae2bb 192 virtual void on_connect(const Gap::ConnectionCallbackParams_t *connection_event) = 0;
Donatien Garnier 1:916188eae2bb 193
Donatien Garnier 1:916188eae2bb 194 /** This is called by Gap to notify the application we disconnected,
Donatien Garnier 1:916188eae2bb 195 * in our case it ends the demonstration. */
Donatien Garnier 1:916188eae2bb 196 void on_disconnect(const Gap::DisconnectionCallbackParams_t *event)
Donatien Garnier 1:916188eae2bb 197 {
Donatien Garnier 1:916188eae2bb 198 printf("Disconnected - demonstration ended \r\n");
Donatien Garnier 1:916188eae2bb 199 _event_queue.break_dispatch();
Donatien Garnier 1:916188eae2bb 200 };
Donatien Garnier 1:916188eae2bb 201
Donatien Garnier 1:916188eae2bb 202 /** End demonstration unexpectedly. Called if timeout is reached during advertising,
Donatien Garnier 1:916188eae2bb 203 * scanning or connection initiation */
Donatien Garnier 1:916188eae2bb 204 void on_timeout(const Gap::TimeoutSource_t source)
Donatien Garnier 1:916188eae2bb 205 {
Donatien Garnier 1:916188eae2bb 206 printf("Unexpected timeout - aborting \r\n");
Donatien Garnier 1:916188eae2bb 207 _event_queue.break_dispatch();
Donatien Garnier 1:916188eae2bb 208 };
Donatien Garnier 1:916188eae2bb 209
Donatien Garnier 1:916188eae2bb 210 /** Schedule processing of events from the BLE in the event queue. */
Donatien Garnier 1:916188eae2bb 211 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
Donatien Garnier 1:916188eae2bb 212 {
Donatien Garnier 1:916188eae2bb 213 _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
Donatien Garnier 1:916188eae2bb 214 };
Donatien Garnier 1:916188eae2bb 215
Donatien Garnier 1:916188eae2bb 216 /** Blink LED to show we're running */
Donatien Garnier 1:916188eae2bb 217 void blink(void)
Donatien Garnier 1:916188eae2bb 218 {
Donatien Garnier 1:916188eae2bb 219 _led1 = !_led1;
Donatien Garnier 1:916188eae2bb 220 };
Donatien Garnier 1:916188eae2bb 221
Donatien Garnier 1:916188eae2bb 222 private:
Donatien Garnier 1:916188eae2bb 223 DigitalOut _led1;
Donatien Garnier 1:916188eae2bb 224
Donatien Garnier 1:916188eae2bb 225 protected:
Donatien Garnier 1:916188eae2bb 226 BLE &_ble;
Donatien Garnier 1:916188eae2bb 227 events::EventQueue &_event_queue;
Donatien Garnier 1:916188eae2bb 228 BLEProtocol::AddressBytes_t &_peer_address;
Donatien Garnier 1:916188eae2bb 229 ble::connection_handle_t _handle;
Donatien Garnier 1:916188eae2bb 230 bool _is_connecting;
Donatien Garnier 1:916188eae2bb 231 };
Donatien Garnier 1:916188eae2bb 232
Donatien Garnier 1:916188eae2bb 233 /** A peripheral device will advertise, accept the connection and request
Donatien Garnier 1:916188eae2bb 234 * a change in link security. */
Donatien Garnier 1:916188eae2bb 235 class SMDevicePeripheral : public SMDevice {
Donatien Garnier 1:916188eae2bb 236 public:
Donatien Garnier 1:916188eae2bb 237 SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
Donatien Garnier 1:916188eae2bb 238 : SMDevice(ble, event_queue, peer_address) { }
Donatien Garnier 1:916188eae2bb 239
Donatien Garnier 1:916188eae2bb 240 virtual void start()
Donatien Garnier 1:916188eae2bb 241 {
Donatien Garnier 1:916188eae2bb 242 /* Set up and start advertising */
Donatien Garnier 1:916188eae2bb 243
Donatien Garnier 1:916188eae2bb 244 ble_error_t error;
Donatien Garnier 1:916188eae2bb 245 GapAdvertisingData advertising_data;
Donatien Garnier 1:916188eae2bb 246
Donatien Garnier 1:916188eae2bb 247 /* add advertising flags */
Donatien Garnier 1:916188eae2bb 248 advertising_data.addFlags(GapAdvertisingData::LE_GENERAL_DISCOVERABLE
Donatien Garnier 1:916188eae2bb 249 | GapAdvertisingData::BREDR_NOT_SUPPORTED);
Donatien Garnier 1:916188eae2bb 250
Donatien Garnier 1:916188eae2bb 251 /* add device name */
Donatien Garnier 1:916188eae2bb 252 advertising_data.addData(
Donatien Garnier 1:916188eae2bb 253 GapAdvertisingData::COMPLETE_LOCAL_NAME,
Donatien Garnier 1:916188eae2bb 254 DEVICE_NAME,
Donatien Garnier 1:916188eae2bb 255 sizeof(DEVICE_NAME)
Donatien Garnier 1:916188eae2bb 256 );
Donatien Garnier 1:916188eae2bb 257
Donatien Garnier 1:916188eae2bb 258 error = _ble.gap().setAdvertisingPayload(advertising_data);
Donatien Garnier 1:916188eae2bb 259
Donatien Garnier 1:916188eae2bb 260 if (error) {
Donatien Garnier 1:916188eae2bb 261 printf("Error during Gap::setAdvertisingPayload\r\n");
Donatien Garnier 1:916188eae2bb 262 return;
Donatien Garnier 1:916188eae2bb 263 }
Donatien Garnier 1:916188eae2bb 264
Donatien Garnier 1:916188eae2bb 265 /* advertise to everyone */
Donatien Garnier 1:916188eae2bb 266 _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Donatien Garnier 1:916188eae2bb 267 /* how many milliseconds between advertisements, lower interval
Donatien Garnier 1:916188eae2bb 268 * increases the chances of being seen at the cost of more power */
Donatien Garnier 1:916188eae2bb 269 _ble.gap().setAdvertisingInterval(20);
Donatien Garnier 1:916188eae2bb 270 _ble.gap().setAdvertisingTimeout(0);
Donatien Garnier 1:916188eae2bb 271
Donatien Garnier 1:916188eae2bb 272 error = _ble.gap().startAdvertising();
Donatien Garnier 1:916188eae2bb 273
Donatien Garnier 1:916188eae2bb 274 if (error) {
Donatien Garnier 1:916188eae2bb 275 printf("Error during Gap::startAdvertising.\r\n");
Donatien Garnier 1:916188eae2bb 276 return;
Donatien Garnier 1:916188eae2bb 277 }
Donatien Garnier 1:916188eae2bb 278
Donatien Garnier 1:916188eae2bb 279 /** This tells the stack to generate a pairingRequest event
Donatien Garnier 1:916188eae2bb 280 * which will require this application to respond before pairing
Donatien Garnier 1:916188eae2bb 281 * can proceed. Setting it to false will automatically accept
Donatien Garnier 1:916188eae2bb 282 * pairing. */
Donatien Garnier 1:916188eae2bb 283 _ble.securityManager().setPairingRequestAuthorisation(true);
Donatien Garnier 1:916188eae2bb 284 };
Donatien Garnier 1:916188eae2bb 285
Donatien Garnier 1:916188eae2bb 286 /** This is called by Gap to notify the application we connected,
Donatien Garnier 1:916188eae2bb 287 * in our case it immediately requests a change in link security */
Donatien Garnier 1:916188eae2bb 288 virtual void on_connect(const Gap::ConnectionCallbackParams_t *connection_event)
Donatien Garnier 1:916188eae2bb 289 {
Donatien Garnier 1:916188eae2bb 290 ble_error_t error;
Donatien Garnier 1:916188eae2bb 291
Donatien Garnier 1:916188eae2bb 292 /* remember the device that connects to us now so we can connect to it
Donatien Garnier 1:916188eae2bb 293 * during the next demonstration */
Donatien Garnier 1:916188eae2bb 294 memcpy(_peer_address, connection_event->peerAddr, sizeof(_peer_address));
Donatien Garnier 1:916188eae2bb 295
Donatien Garnier 1:916188eae2bb 296 /* store the handle for future Security Manager requests */
Donatien Garnier 1:916188eae2bb 297 _handle = connection_event->handle;
Donatien Garnier 1:916188eae2bb 298
Donatien Garnier 1:916188eae2bb 299 /* Request a change in link security. This will be done
Donatien Garnier 1:916188eae2bb 300 * indirectly by asking the master of the connection to
Donatien Garnier 1:916188eae2bb 301 * change it. Depending on circumstances different actions
Donatien Garnier 1:916188eae2bb 302 * may be taken by the master which will trigger events
Donatien Garnier 1:916188eae2bb 303 * which the applications should deal with. */
Donatien Garnier 1:916188eae2bb 304 error = _ble.securityManager().setLinkSecurity(
Donatien Garnier 1:916188eae2bb 305 _handle,
Donatien Garnier 1:916188eae2bb 306 SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM
Donatien Garnier 1:916188eae2bb 307 );
Donatien Garnier 1:916188eae2bb 308
Donatien Garnier 1:916188eae2bb 309 if (error) {
Donatien Garnier 1:916188eae2bb 310 printf("Error during SM::setLinkSecurity %d\r\n", error);
Donatien Garnier 1:916188eae2bb 311 return;
Donatien Garnier 1:916188eae2bb 312 }
Donatien Garnier 1:916188eae2bb 313 };
Donatien Garnier 1:916188eae2bb 314 };
Donatien Garnier 1:916188eae2bb 315
Donatien Garnier 1:916188eae2bb 316 /** A central device will scan, connect to a peer and request pairing. */
Donatien Garnier 1:916188eae2bb 317 class SMDeviceCentral : public SMDevice {
Donatien Garnier 1:916188eae2bb 318 public:
Donatien Garnier 1:916188eae2bb 319 SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
Donatien Garnier 1:916188eae2bb 320 : SMDevice(ble, event_queue, peer_address) { }
Donatien Garnier 1:916188eae2bb 321
Donatien Garnier 1:916188eae2bb 322 virtual void start()
Donatien Garnier 1:916188eae2bb 323 {
Donatien Garnier 1:916188eae2bb 324 /* start scanning and attach a callback that will handle advertisements
Donatien Garnier 1:916188eae2bb 325 * and scan requests responses */
Donatien Garnier 1:916188eae2bb 326 ble_error_t error = _ble.gap().startScan(this, &SMDeviceCentral::on_scan);
Donatien Garnier 1:916188eae2bb 327
Donatien Garnier 1:916188eae2bb 328 if (error) {
Donatien Garnier 1:916188eae2bb 329 printf("Error during Gap::startScan %d\r\n", error);
Donatien Garnier 1:916188eae2bb 330 return;
Donatien Garnier 1:916188eae2bb 331 }
Donatien Garnier 1:916188eae2bb 332 }
Donatien Garnier 1:916188eae2bb 333
Donatien Garnier 1:916188eae2bb 334 /** Look at scan payload to find a peer device and connect to it */
Donatien Garnier 1:916188eae2bb 335 void on_scan(const Gap::AdvertisementCallbackParams_t *params)
Donatien Garnier 1:916188eae2bb 336 {
Donatien Garnier 1:916188eae2bb 337 /* don't bother with analysing scan result if we're already connecting */
Donatien Garnier 1:916188eae2bb 338 if (_is_connecting) {
Donatien Garnier 1:916188eae2bb 339 return;
Donatien Garnier 1:916188eae2bb 340 }
Donatien Garnier 1:916188eae2bb 341
Donatien Garnier 1:916188eae2bb 342 /* parse the advertising payload, looking for a discoverable device */
Donatien Garnier 1:916188eae2bb 343 for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
Donatien Garnier 1:916188eae2bb 344 /* The advertising payload is a collection of key/value records where
Donatien Garnier 1:916188eae2bb 345 * byte 0: length of the record excluding this byte
Donatien Garnier 1:916188eae2bb 346 * byte 1: The key, it is the type of the data
Donatien Garnier 1:916188eae2bb 347 * byte [2..N] The value. N is equal to byte0 - 1 */
Donatien Garnier 1:916188eae2bb 348 const uint8_t record_length = params->advertisingData[i];
Donatien Garnier 1:916188eae2bb 349 if (record_length == 0) {
Donatien Garnier 1:916188eae2bb 350 continue;
Donatien Garnier 1:916188eae2bb 351 }
Donatien Garnier 1:916188eae2bb 352
Donatien Garnier 1:916188eae2bb 353 /* connect to the same device that connected to us */
Donatien Garnier 1:916188eae2bb 354 if (memcmp(params->peerAddr, _peer_address, sizeof(_peer_address)) == 0) {
Donatien Garnier 1:916188eae2bb 355
Donatien Garnier 1:916188eae2bb 356 ble_error_t error = _ble.gap().connect(
Donatien Garnier 1:916188eae2bb 357 params->peerAddr, params->addressType,
Donatien Garnier 1:916188eae2bb 358 NULL, NULL
Donatien Garnier 1:916188eae2bb 359 );
Donatien Garnier 1:916188eae2bb 360
Donatien Garnier 1:916188eae2bb 361 if (error) {
Donatien Garnier 1:916188eae2bb 362 printf("Error during Gap::connect %d\r\n", error);
Donatien Garnier 1:916188eae2bb 363 return;
Donatien Garnier 1:916188eae2bb 364 }
Donatien Garnier 1:916188eae2bb 365
Donatien Garnier 1:916188eae2bb 366 /* we may have already scan events waiting
Donatien Garnier 1:916188eae2bb 367 * to be processed so we need to remember
Donatien Garnier 1:916188eae2bb 368 * that we are already connecting and ignore them */
Donatien Garnier 1:916188eae2bb 369 _is_connecting = true;
Donatien Garnier 1:916188eae2bb 370
Donatien Garnier 1:916188eae2bb 371 return;
Donatien Garnier 1:916188eae2bb 372 }
Donatien Garnier 1:916188eae2bb 373
Donatien Garnier 1:916188eae2bb 374 i += record_length;
Donatien Garnier 1:916188eae2bb 375 }
Donatien Garnier 1:916188eae2bb 376 };
Donatien Garnier 1:916188eae2bb 377
Donatien Garnier 1:916188eae2bb 378 /** This is called by Gap to notify the application we connected,
Donatien Garnier 1:916188eae2bb 379 * in our case it immediately request pairing */
Donatien Garnier 1:916188eae2bb 380 virtual void on_connect(const Gap::ConnectionCallbackParams_t *connection_event)
Donatien Garnier 1:916188eae2bb 381 {
Donatien Garnier 1:916188eae2bb 382 ble_error_t error;
Donatien Garnier 1:916188eae2bb 383
Donatien Garnier 1:916188eae2bb 384 /* store the handle for future Security Manager requests */
Donatien Garnier 1:916188eae2bb 385 _handle = connection_event->handle;
Donatien Garnier 1:916188eae2bb 386
Donatien Garnier 1:916188eae2bb 387 /* in this example the local device is the master so we request pairing */
Donatien Garnier 1:916188eae2bb 388 error = _ble.securityManager().requestPairing(_handle);
Donatien Garnier 1:916188eae2bb 389
Donatien Garnier 1:916188eae2bb 390 if (error) {
Donatien Garnier 1:916188eae2bb 391 printf("Error during SM::requestPairing %d\r\n", error);
Donatien Garnier 1:916188eae2bb 392 return;
Donatien Garnier 1:916188eae2bb 393 }
Donatien Garnier 1:916188eae2bb 394
Donatien Garnier 1:916188eae2bb 395 /* upon pairing success the application will disconnect */
Donatien Garnier 1:916188eae2bb 396 };
Donatien Garnier 1:916188eae2bb 397 };
Donatien Garnier 1:916188eae2bb 398
Donatien Garnier 1:916188eae2bb 399 int main()
Donatien Garnier 1:916188eae2bb 400 {
Donatien Garnier 1:916188eae2bb 401 BLE& ble = BLE::Instance();
Donatien Garnier 1:916188eae2bb 402 events::EventQueue queue;
Donatien Garnier 1:916188eae2bb 403
Donatien Garnier 1:916188eae2bb 404 {
Donatien Garnier 1:916188eae2bb 405 printf("\r\n PERIPHERAL \r\n\r\n");
Donatien Garnier 1:916188eae2bb 406 SMDevicePeripheral peripheral(ble, queue, peer_address);
Donatien Garnier 1:916188eae2bb 407 peripheral.run();
Donatien Garnier 1:916188eae2bb 408 }
Donatien Garnier 1:916188eae2bb 409
Donatien Garnier 1:916188eae2bb 410 {
Donatien Garnier 1:916188eae2bb 411 printf("\r\n CENTRAL \r\n\r\n");
Donatien Garnier 1:916188eae2bb 412 SMDeviceCentral central(ble, queue, peer_address);
Donatien Garnier 1:916188eae2bb 413 central.run();
Donatien Garnier 1:916188eae2bb 414 }
Donatien Garnier 1:916188eae2bb 415
Donatien Garnier 1:916188eae2bb 416 return 0;
Donatien Garnier 1:916188eae2bb 417 }