
this is using the mbed os version 5-13-1
source/BleManager.cpp@75:08eff6258e1b, 2019-03-14 (annotated)
- Committer:
- ocomeni
- Date:
- Thu Mar 14 21:34:06 2019 +0000
- Revision:
- 75:08eff6258e1b
- Parent:
- 74:f26e846adfe9
- Child:
- 76:6afda865fbf8
Ble Security example now working!
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ocomeni | 74:f26e846adfe9 | 1 | /* mbed Microcontroller Library |
ocomeni | 74:f26e846adfe9 | 2 | * Copyright (c) 2006-2013 ARM Limited |
ocomeni | 74:f26e846adfe9 | 3 | * |
ocomeni | 74:f26e846adfe9 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
ocomeni | 74:f26e846adfe9 | 5 | * you may not use this file except in compliance with the License. |
ocomeni | 74:f26e846adfe9 | 6 | * You may obtain a copy of the License at |
ocomeni | 74:f26e846adfe9 | 7 | * |
ocomeni | 74:f26e846adfe9 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
ocomeni | 74:f26e846adfe9 | 9 | * |
ocomeni | 74:f26e846adfe9 | 10 | * Unless required by applicable law or agreed to in writing, software |
ocomeni | 74:f26e846adfe9 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
ocomeni | 74:f26e846adfe9 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
ocomeni | 74:f26e846adfe9 | 13 | * See the License for the specific language governing permissions and |
ocomeni | 74:f26e846adfe9 | 14 | * limitations under the License. |
ocomeni | 74:f26e846adfe9 | 15 | */ |
ocomeni | 75:08eff6258e1b | 16 | |
ocomeni | 74:f26e846adfe9 | 17 | #include <events/mbed_events.h> |
ocomeni | 74:f26e846adfe9 | 18 | #include <mbed.h> |
ocomeni | 74:f26e846adfe9 | 19 | #include "ble/BLE.h" |
ocomeni | 74:f26e846adfe9 | 20 | #include "SecurityManager.h" |
ocomeni | 75:08eff6258e1b | 21 | #include "BleManager.h" |
ocomeni | 75:08eff6258e1b | 22 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 75:08eff6258e1b | 23 | #include "LittleFileSystem.h" |
ocomeni | 75:08eff6258e1b | 24 | #include "HeapBlockDevice.h" |
ocomeni | 75:08eff6258e1b | 25 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 75:08eff6258e1b | 26 | |
ocomeni | 75:08eff6258e1b | 27 | |
ocomeni | 75:08eff6258e1b | 28 | static const uint8_t DEVICE_NAME[] = "SM_device"; |
ocomeni | 75:08eff6258e1b | 29 | |
ocomeni | 75:08eff6258e1b | 30 | /** This example demonstrates all the basic setup required |
ocomeni | 75:08eff6258e1b | 31 | * for pairing and setting up link security both as a central and peripheral |
ocomeni | 75:08eff6258e1b | 32 | * |
ocomeni | 75:08eff6258e1b | 33 | * The example is implemented as two classes, one for the peripheral and one |
ocomeni | 75:08eff6258e1b | 34 | * for central inheriting from a common base. They are run in sequence and |
ocomeni | 75:08eff6258e1b | 35 | * require a peer device to connect to. During the peripheral device demonstration |
ocomeni | 75:08eff6258e1b | 36 | * a peer device is required to connect. In the central device demonstration |
ocomeni | 75:08eff6258e1b | 37 | * this peer device will be scanned for and connected to - therefore it should |
ocomeni | 75:08eff6258e1b | 38 | * be advertising with the same address as when it connected. |
ocomeni | 75:08eff6258e1b | 39 | * |
ocomeni | 75:08eff6258e1b | 40 | * During the test output is written on the serial connection to monitor its |
ocomeni | 75:08eff6258e1b | 41 | * progress. |
ocomeni | 75:08eff6258e1b | 42 | */ |
ocomeni | 75:08eff6258e1b | 43 | |
ocomeni | 75:08eff6258e1b | 44 | //static const uint8_t DEVICE_NAME[] = "SM_device"; |
ocomeni | 75:08eff6258e1b | 45 | |
ocomeni | 75:08eff6258e1b | 46 | /* for demonstration purposes we will store the peer device address |
ocomeni | 75:08eff6258e1b | 47 | * of the device that connects to us in the first demonstration |
ocomeni | 75:08eff6258e1b | 48 | * so we can use its address to reconnect to it later */ |
ocomeni | 75:08eff6258e1b | 49 | //static BLEProtocol::AddressBytes_t peer_address; |
ocomeni | 75:08eff6258e1b | 50 | |
ocomeni | 75:08eff6258e1b | 51 | /** Base class for both peripheral and central. The same class that provides |
ocomeni | 75:08eff6258e1b | 52 | * the logic for the application also implements the SecurityManagerEventHandler |
ocomeni | 75:08eff6258e1b | 53 | * which is the interface used by the Security Manager to communicate events |
ocomeni | 75:08eff6258e1b | 54 | * back to the applications. You can provide overrides for a selection of events |
ocomeni | 75:08eff6258e1b | 55 | * your application is interested in. |
ocomeni | 75:08eff6258e1b | 56 | */ |
ocomeni | 75:08eff6258e1b | 57 | SMDevice::SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) : |
ocomeni | 75:08eff6258e1b | 58 | _led1(LED1, 0), |
ocomeni | 75:08eff6258e1b | 59 | _ble(ble), |
ocomeni | 75:08eff6258e1b | 60 | _event_queue(event_queue), |
ocomeni | 75:08eff6258e1b | 61 | _peer_address(peer_address), |
ocomeni | 75:08eff6258e1b | 62 | _handle(0), |
ocomeni | 75:08eff6258e1b | 63 | _is_connecting(false) { } |
ocomeni | 75:08eff6258e1b | 64 | |
ocomeni | 75:08eff6258e1b | 65 | SMDevice::~SMDevice() |
ocomeni | 75:08eff6258e1b | 66 | { |
ocomeni | 75:08eff6258e1b | 67 | if (_ble.hasInitialized()) { |
ocomeni | 75:08eff6258e1b | 68 | _ble.shutdown(); |
ocomeni | 75:08eff6258e1b | 69 | } |
ocomeni | 75:08eff6258e1b | 70 | } |
ocomeni | 75:08eff6258e1b | 71 | |
ocomeni | 75:08eff6258e1b | 72 | /** Start BLE interface initialisation */ |
ocomeni | 75:08eff6258e1b | 73 | void SMDevice::run() |
ocomeni | 75:08eff6258e1b | 74 | { |
ocomeni | 75:08eff6258e1b | 75 | ble_error_t error; |
ocomeni | 75:08eff6258e1b | 76 | |
ocomeni | 75:08eff6258e1b | 77 | /* to show we're running we'll blink every 500ms */ |
ocomeni | 75:08eff6258e1b | 78 | _event_queue.call_every(500, this, &SMDevice::blink); |
ocomeni | 75:08eff6258e1b | 79 | |
ocomeni | 75:08eff6258e1b | 80 | if (_ble.hasInitialized()) { |
ocomeni | 75:08eff6258e1b | 81 | printf("Ble instance already initialised.\r\n"); |
ocomeni | 75:08eff6258e1b | 82 | return; |
ocomeni | 75:08eff6258e1b | 83 | } |
ocomeni | 75:08eff6258e1b | 84 | |
ocomeni | 75:08eff6258e1b | 85 | /* this will inform us off all events so we can schedule their handling |
ocomeni | 75:08eff6258e1b | 86 | * using our event queue */ |
ocomeni | 75:08eff6258e1b | 87 | _ble.onEventsToProcess( |
ocomeni | 75:08eff6258e1b | 88 | makeFunctionPointer(this, &SMDevice::schedule_ble_events) |
ocomeni | 75:08eff6258e1b | 89 | ); |
ocomeni | 75:08eff6258e1b | 90 | |
ocomeni | 75:08eff6258e1b | 91 | /* handle timeouts, for example when connection attempts fail */ |
ocomeni | 75:08eff6258e1b | 92 | _ble.gap().onTimeout( |
ocomeni | 75:08eff6258e1b | 93 | makeFunctionPointer(this, &SMDevice::on_timeout) |
ocomeni | 75:08eff6258e1b | 94 | ); |
ocomeni | 75:08eff6258e1b | 95 | |
ocomeni | 75:08eff6258e1b | 96 | error = _ble.init(this, &SMDevice::on_init_complete); |
ocomeni | 75:08eff6258e1b | 97 | |
ocomeni | 75:08eff6258e1b | 98 | if (error) { |
ocomeni | 75:08eff6258e1b | 99 | printf("Error returned by BLE::init.\r\n"); |
ocomeni | 75:08eff6258e1b | 100 | return; |
ocomeni | 75:08eff6258e1b | 101 | } |
ocomeni | 75:08eff6258e1b | 102 | |
ocomeni | 75:08eff6258e1b | 103 | /* this will not return until shutdown */ |
ocomeni | 75:08eff6258e1b | 104 | _event_queue.dispatch_forever(); |
ocomeni | 75:08eff6258e1b | 105 | } |
ocomeni | 75:08eff6258e1b | 106 | |
ocomeni | 75:08eff6258e1b | 107 | /* event handler functions */ |
ocomeni | 75:08eff6258e1b | 108 | |
ocomeni | 75:08eff6258e1b | 109 | /** Respond to a pairing request. This will be called by the stack |
ocomeni | 75:08eff6258e1b | 110 | * when a pairing request arrives and expects the application to |
ocomeni | 75:08eff6258e1b | 111 | * call acceptPairingRequest or cancelPairingRequest */ |
ocomeni | 75:08eff6258e1b | 112 | void SMDevice::pairingRequest( |
ocomeni | 75:08eff6258e1b | 113 | ble::connection_handle_t connectionHandle |
ocomeni | 75:08eff6258e1b | 114 | ) { |
ocomeni | 75:08eff6258e1b | 115 | printf("Pairing requested - authorising\r\n"); |
ocomeni | 75:08eff6258e1b | 116 | _ble.securityManager().acceptPairingRequest(connectionHandle); |
ocomeni | 75:08eff6258e1b | 117 | } |
ocomeni | 75:08eff6258e1b | 118 | |
ocomeni | 75:08eff6258e1b | 119 | /** Inform the application of a successful pairing. Terminate the demonstration. */ |
ocomeni | 75:08eff6258e1b | 120 | void SMDevice::pairingResult( |
ocomeni | 75:08eff6258e1b | 121 | ble::connection_handle_t connectionHandle, |
ocomeni | 75:08eff6258e1b | 122 | SecurityManager::SecurityCompletionStatus_t result |
ocomeni | 75:08eff6258e1b | 123 | ) { |
ocomeni | 75:08eff6258e1b | 124 | if (result == SecurityManager::SEC_STATUS_SUCCESS) { |
ocomeni | 75:08eff6258e1b | 125 | printf("Pairing successful\r\n"); |
ocomeni | 75:08eff6258e1b | 126 | } else { |
ocomeni | 75:08eff6258e1b | 127 | printf("Pairing failed\r\n"); |
ocomeni | 75:08eff6258e1b | 128 | } |
ocomeni | 75:08eff6258e1b | 129 | } |
ocomeni | 75:08eff6258e1b | 130 | |
ocomeni | 75:08eff6258e1b | 131 | /** Inform the application of change in encryption status. This will be |
ocomeni | 75:08eff6258e1b | 132 | * communicated through the serial port */ |
ocomeni | 75:08eff6258e1b | 133 | void SMDevice::linkEncryptionResult( |
ocomeni | 75:08eff6258e1b | 134 | ble::connection_handle_t connectionHandle, |
ocomeni | 75:08eff6258e1b | 135 | ble::link_encryption_t result |
ocomeni | 75:08eff6258e1b | 136 | ) { |
ocomeni | 75:08eff6258e1b | 137 | if (result == ble::link_encryption_t::ENCRYPTED) { |
ocomeni | 75:08eff6258e1b | 138 | printf("Link ENCRYPTED\r\n"); |
ocomeni | 75:08eff6258e1b | 139 | } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { |
ocomeni | 75:08eff6258e1b | 140 | printf("Link ENCRYPTED_WITH_MITM\r\n"); |
ocomeni | 75:08eff6258e1b | 141 | } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) { |
ocomeni | 75:08eff6258e1b | 142 | printf("Link NOT_ENCRYPTED\r\n"); |
ocomeni | 75:08eff6258e1b | 143 | } |
ocomeni | 75:08eff6258e1b | 144 | |
ocomeni | 75:08eff6258e1b | 145 | /* disconnect in 2 s */ |
ocomeni | 75:08eff6258e1b | 146 | _event_queue.call_in( |
ocomeni | 75:08eff6258e1b | 147 | 2000, &_ble.gap(), |
ocomeni | 75:08eff6258e1b | 148 | &Gap::disconnect, _handle, Gap::REMOTE_USER_TERMINATED_CONNECTION |
ocomeni | 75:08eff6258e1b | 149 | ); |
ocomeni | 75:08eff6258e1b | 150 | } |
ocomeni | 75:08eff6258e1b | 151 | |
ocomeni | 75:08eff6258e1b | 152 | /** Override to start chosen activity when initialisation completes */ |
ocomeni | 75:08eff6258e1b | 153 | //void SMDevice::start() = 0; |
ocomeni | 75:08eff6258e1b | 154 | |
ocomeni | 75:08eff6258e1b | 155 | /** This is called when BLE interface is initialised and starts the demonstration */ |
ocomeni | 75:08eff6258e1b | 156 | void SMDevice::on_init_complete(BLE::InitializationCompleteCallbackContext *event) |
ocomeni | 75:08eff6258e1b | 157 | { |
ocomeni | 75:08eff6258e1b | 158 | ble_error_t error; |
ocomeni | 75:08eff6258e1b | 159 | |
ocomeni | 75:08eff6258e1b | 160 | if (event->error) { |
ocomeni | 75:08eff6258e1b | 161 | printf("Error during the initialisation\r\n"); |
ocomeni | 75:08eff6258e1b | 162 | return; |
ocomeni | 75:08eff6258e1b | 163 | } |
ocomeni | 75:08eff6258e1b | 164 | |
ocomeni | 75:08eff6258e1b | 165 | /* This path will be used to store bonding information but will fallback |
ocomeni | 75:08eff6258e1b | 166 | * to storing in memory if file access fails (for example due to lack of a filesystem) */ |
ocomeni | 75:08eff6258e1b | 167 | const char* db_path = "/fs/bt_sec_db"; |
ocomeni | 75:08eff6258e1b | 168 | /* If the security manager is required this needs to be called before any |
ocomeni | 75:08eff6258e1b | 169 | * calls to the Security manager happen. */ |
ocomeni | 75:08eff6258e1b | 170 | error = _ble.securityManager().init( |
ocomeni | 75:08eff6258e1b | 171 | true, |
ocomeni | 75:08eff6258e1b | 172 | false, |
ocomeni | 75:08eff6258e1b | 173 | SecurityManager::IO_CAPS_NONE, |
ocomeni | 75:08eff6258e1b | 174 | NULL, |
ocomeni | 75:08eff6258e1b | 175 | false, |
ocomeni | 75:08eff6258e1b | 176 | db_path |
ocomeni | 75:08eff6258e1b | 177 | ); |
ocomeni | 75:08eff6258e1b | 178 | |
ocomeni | 75:08eff6258e1b | 179 | if (error) { |
ocomeni | 75:08eff6258e1b | 180 | printf("Error during init %d\r\n", error); |
ocomeni | 75:08eff6258e1b | 181 | return; |
ocomeni | 75:08eff6258e1b | 182 | } |
ocomeni | 75:08eff6258e1b | 183 | |
ocomeni | 75:08eff6258e1b | 184 | error = _ble.securityManager().preserveBondingStateOnReset(true); |
ocomeni | 75:08eff6258e1b | 185 | |
ocomeni | 75:08eff6258e1b | 186 | if (error) { |
ocomeni | 75:08eff6258e1b | 187 | printf("Error during preserveBondingStateOnReset %d\r\n", error); |
ocomeni | 75:08eff6258e1b | 188 | } |
ocomeni | 75:08eff6258e1b | 189 | |
ocomeni | 75:08eff6258e1b | 190 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 75:08eff6258e1b | 191 | /* Enable privacy so we can find the keys */ |
ocomeni | 75:08eff6258e1b | 192 | error = _ble.gap().enablePrivacy(true); |
ocomeni | 75:08eff6258e1b | 193 | |
ocomeni | 75:08eff6258e1b | 194 | if (error) { |
ocomeni | 75:08eff6258e1b | 195 | printf("Error enabling privacy\r\n"); |
ocomeni | 75:08eff6258e1b | 196 | } |
ocomeni | 75:08eff6258e1b | 197 | |
ocomeni | 75:08eff6258e1b | 198 | Gap::PeripheralPrivacyConfiguration_t configuration_p = { |
ocomeni | 75:08eff6258e1b | 199 | /* use_non_resolvable_random_address */ false, |
ocomeni | 75:08eff6258e1b | 200 | Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS |
ocomeni | 75:08eff6258e1b | 201 | }; |
ocomeni | 75:08eff6258e1b | 202 | _ble.gap().setPeripheralPrivacyConfiguration(&configuration_p); |
ocomeni | 75:08eff6258e1b | 203 | |
ocomeni | 75:08eff6258e1b | 204 | Gap::CentralPrivacyConfiguration_t configuration_c = { |
ocomeni | 75:08eff6258e1b | 205 | /* use_non_resolvable_random_address */ false, |
ocomeni | 75:08eff6258e1b | 206 | Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD |
ocomeni | 75:08eff6258e1b | 207 | }; |
ocomeni | 75:08eff6258e1b | 208 | _ble.gap().setCentralPrivacyConfiguration(&configuration_c); |
ocomeni | 75:08eff6258e1b | 209 | |
ocomeni | 75:08eff6258e1b | 210 | /* this demo switches between being master and slave */ |
ocomeni | 75:08eff6258e1b | 211 | _ble.securityManager().setHintFutureRoleReversal(true); |
ocomeni | 75:08eff6258e1b | 212 | #endif |
ocomeni | 75:08eff6258e1b | 213 | |
ocomeni | 75:08eff6258e1b | 214 | /* Tell the security manager to use methods in this class to inform us |
ocomeni | 75:08eff6258e1b | 215 | * of any events. Class needs to implement SecurityManagerEventHandler. */ |
ocomeni | 75:08eff6258e1b | 216 | _ble.securityManager().setSecurityManagerEventHandler(this); |
ocomeni | 75:08eff6258e1b | 217 | |
ocomeni | 75:08eff6258e1b | 218 | /* print device address */ |
ocomeni | 75:08eff6258e1b | 219 | Gap::AddressType_t addr_type; |
ocomeni | 75:08eff6258e1b | 220 | Gap::Address_t addr; |
ocomeni | 75:08eff6258e1b | 221 | _ble.gap().getAddress(&addr_type, addr); |
ocomeni | 75:08eff6258e1b | 222 | printf("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n", |
ocomeni | 75:08eff6258e1b | 223 | addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]); |
ocomeni | 75:08eff6258e1b | 224 | |
ocomeni | 75:08eff6258e1b | 225 | /* when scanning we want to connect to a peer device so we need to |
ocomeni | 75:08eff6258e1b | 226 | * attach callbacks that are used by Gap to notify us of events */ |
ocomeni | 75:08eff6258e1b | 227 | _ble.gap().onConnection(this, &SMDevice::on_connect); |
ocomeni | 75:08eff6258e1b | 228 | _ble.gap().onDisconnection(this, &SMDevice::on_disconnect); |
ocomeni | 75:08eff6258e1b | 229 | |
ocomeni | 75:08eff6258e1b | 230 | /* start test in 500 ms */ |
ocomeni | 75:08eff6258e1b | 231 | _event_queue.call_in(500, this, &SMDevice::start); |
ocomeni | 75:08eff6258e1b | 232 | } |
ocomeni | 75:08eff6258e1b | 233 | |
ocomeni | 75:08eff6258e1b | 234 | /** This is called by Gap to notify the application we connected */ |
ocomeni | 75:08eff6258e1b | 235 | //void SMDevice::on_connect(const Gap::ConnectionCallbackParams_t *connection_event); |
ocomeni | 75:08eff6258e1b | 236 | |
ocomeni | 75:08eff6258e1b | 237 | /** This is called by Gap to notify the application we disconnected, |
ocomeni | 75:08eff6258e1b | 238 | * in our case it ends the demonstration. */ |
ocomeni | 75:08eff6258e1b | 239 | void SMDevice::on_disconnect(const Gap::DisconnectionCallbackParams_t *event) |
ocomeni | 75:08eff6258e1b | 240 | { |
ocomeni | 75:08eff6258e1b | 241 | printf("Disconnected\r\n"); |
ocomeni | 75:08eff6258e1b | 242 | _event_queue.break_dispatch(); |
ocomeni | 75:08eff6258e1b | 243 | } |
ocomeni | 75:08eff6258e1b | 244 | |
ocomeni | 75:08eff6258e1b | 245 | /** End demonstration unexpectedly. Called if timeout is reached during advertising, |
ocomeni | 75:08eff6258e1b | 246 | * scanning or connection initiation */ |
ocomeni | 75:08eff6258e1b | 247 | void SMDevice::on_timeout(const Gap::TimeoutSource_t source) |
ocomeni | 75:08eff6258e1b | 248 | { |
ocomeni | 75:08eff6258e1b | 249 | printf("Unexpected timeout - aborting\r\n"); |
ocomeni | 75:08eff6258e1b | 250 | _event_queue.break_dispatch(); |
ocomeni | 75:08eff6258e1b | 251 | } |
ocomeni | 75:08eff6258e1b | 252 | |
ocomeni | 75:08eff6258e1b | 253 | /** Schedule processing of events from the BLE in the event queue. */ |
ocomeni | 75:08eff6258e1b | 254 | void SMDevice::schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) |
ocomeni | 75:08eff6258e1b | 255 | { |
ocomeni | 75:08eff6258e1b | 256 | _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents)); |
ocomeni | 75:08eff6258e1b | 257 | }; |
ocomeni | 75:08eff6258e1b | 258 | |
ocomeni | 75:08eff6258e1b | 259 | /** Blink LED to show we're running */ |
ocomeni | 75:08eff6258e1b | 260 | void SMDevice::blink(void) |
ocomeni | 75:08eff6258e1b | 261 | { |
ocomeni | 75:08eff6258e1b | 262 | _led1 = !_led1; |
ocomeni | 75:08eff6258e1b | 263 | } |
ocomeni | 75:08eff6258e1b | 264 | |
ocomeni | 75:08eff6258e1b | 265 | |
ocomeni | 75:08eff6258e1b | 266 | /** A peripheral device will advertise, accept the connection and request |
ocomeni | 75:08eff6258e1b | 267 | * a change in link security. */ |
ocomeni | 75:08eff6258e1b | 268 | SMDevicePeripheral::SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) |
ocomeni | 75:08eff6258e1b | 269 | : SMDevice(ble, event_queue, peer_address) { } |
ocomeni | 75:08eff6258e1b | 270 | |
ocomeni | 75:08eff6258e1b | 271 | void SMDevicePeripheral::start() |
ocomeni | 75:08eff6258e1b | 272 | { |
ocomeni | 75:08eff6258e1b | 273 | /* Set up and start advertising */ |
ocomeni | 75:08eff6258e1b | 274 | |
ocomeni | 75:08eff6258e1b | 275 | ble_error_t error; |
ocomeni | 75:08eff6258e1b | 276 | GapAdvertisingData advertising_data; |
ocomeni | 75:08eff6258e1b | 277 | |
ocomeni | 75:08eff6258e1b | 278 | /* add advertising flags */ |
ocomeni | 75:08eff6258e1b | 279 | advertising_data.addFlags(GapAdvertisingData::LE_GENERAL_DISCOVERABLE |
ocomeni | 75:08eff6258e1b | 280 | | GapAdvertisingData::BREDR_NOT_SUPPORTED); |
ocomeni | 75:08eff6258e1b | 281 | |
ocomeni | 75:08eff6258e1b | 282 | /* add device name */ |
ocomeni | 75:08eff6258e1b | 283 | advertising_data.addData( |
ocomeni | 75:08eff6258e1b | 284 | GapAdvertisingData::COMPLETE_LOCAL_NAME, |
ocomeni | 75:08eff6258e1b | 285 | DEVICE_NAME, |
ocomeni | 75:08eff6258e1b | 286 | sizeof(DEVICE_NAME) |
ocomeni | 75:08eff6258e1b | 287 | ); |
ocomeni | 75:08eff6258e1b | 288 | |
ocomeni | 75:08eff6258e1b | 289 | error = _ble.gap().setAdvertisingPayload(advertising_data); |
ocomeni | 75:08eff6258e1b | 290 | |
ocomeni | 75:08eff6258e1b | 291 | if (error) { |
ocomeni | 75:08eff6258e1b | 292 | printf("Error during Gap::setAdvertisingPayload\r\n"); |
ocomeni | 75:08eff6258e1b | 293 | return; |
ocomeni | 75:08eff6258e1b | 294 | } |
ocomeni | 75:08eff6258e1b | 295 | |
ocomeni | 75:08eff6258e1b | 296 | /* advertise to everyone */ |
ocomeni | 75:08eff6258e1b | 297 | _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
ocomeni | 75:08eff6258e1b | 298 | /* how many milliseconds between advertisements, lower interval |
ocomeni | 75:08eff6258e1b | 299 | * increases the chances of being seen at the cost of more power */ |
ocomeni | 75:08eff6258e1b | 300 | _ble.gap().setAdvertisingInterval(20); |
ocomeni | 75:08eff6258e1b | 301 | _ble.gap().setAdvertisingTimeout(0); |
ocomeni | 75:08eff6258e1b | 302 | |
ocomeni | 75:08eff6258e1b | 303 | error = _ble.gap().startAdvertising(); |
ocomeni | 75:08eff6258e1b | 304 | |
ocomeni | 75:08eff6258e1b | 305 | if (error) { |
ocomeni | 75:08eff6258e1b | 306 | printf("Error during Gap::startAdvertising.\r\n"); |
ocomeni | 75:08eff6258e1b | 307 | return; |
ocomeni | 75:08eff6258e1b | 308 | } |
ocomeni | 75:08eff6258e1b | 309 | |
ocomeni | 75:08eff6258e1b | 310 | printf("Please connect to device\r\n"); |
ocomeni | 75:08eff6258e1b | 311 | |
ocomeni | 75:08eff6258e1b | 312 | /** This tells the stack to generate a pairingRequest event |
ocomeni | 75:08eff6258e1b | 313 | * which will require this application to respond before pairing |
ocomeni | 75:08eff6258e1b | 314 | * can proceed. Setting it to false will automatically accept |
ocomeni | 75:08eff6258e1b | 315 | * pairing. */ |
ocomeni | 75:08eff6258e1b | 316 | _ble.securityManager().setPairingRequestAuthorisation(true); |
ocomeni | 75:08eff6258e1b | 317 | } |
ocomeni | 75:08eff6258e1b | 318 | |
ocomeni | 75:08eff6258e1b | 319 | /** This is called by Gap to notify the application we connected, |
ocomeni | 75:08eff6258e1b | 320 | * in our case it immediately requests a change in link security */ |
ocomeni | 75:08eff6258e1b | 321 | void SMDevicePeripheral::on_connect(const Gap::ConnectionCallbackParams_t *connection_event) |
ocomeni | 75:08eff6258e1b | 322 | { |
ocomeni | 75:08eff6258e1b | 323 | ble_error_t error; |
ocomeni | 75:08eff6258e1b | 324 | |
ocomeni | 75:08eff6258e1b | 325 | /* remember the device that connects to us now so we can connect to it |
ocomeni | 75:08eff6258e1b | 326 | * during the next demonstration */ |
ocomeni | 75:08eff6258e1b | 327 | memcpy(_peer_address, connection_event->peerAddr, sizeof(_peer_address)); |
ocomeni | 75:08eff6258e1b | 328 | |
ocomeni | 75:08eff6258e1b | 329 | printf("Connected to: %02x:%02x:%02x:%02x:%02x:%02x\r\n", |
ocomeni | 75:08eff6258e1b | 330 | _peer_address[5], _peer_address[4], _peer_address[3], |
ocomeni | 75:08eff6258e1b | 331 | _peer_address[2], _peer_address[1], _peer_address[0]); |
ocomeni | 75:08eff6258e1b | 332 | |
ocomeni | 75:08eff6258e1b | 333 | /* store the handle for future Security Manager requests */ |
ocomeni | 75:08eff6258e1b | 334 | _handle = connection_event->handle; |
ocomeni | 75:08eff6258e1b | 335 | |
ocomeni | 75:08eff6258e1b | 336 | /* Request a change in link security. This will be done |
ocomeni | 75:08eff6258e1b | 337 | * indirectly by asking the master of the connection to |
ocomeni | 75:08eff6258e1b | 338 | * change it. Depending on circumstances different actions |
ocomeni | 75:08eff6258e1b | 339 | * may be taken by the master which will trigger events |
ocomeni | 75:08eff6258e1b | 340 | * which the applications should deal with. */ |
ocomeni | 75:08eff6258e1b | 341 | error = _ble.securityManager().setLinkSecurity( |
ocomeni | 75:08eff6258e1b | 342 | _handle, |
ocomeni | 75:08eff6258e1b | 343 | SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM |
ocomeni | 75:08eff6258e1b | 344 | ); |
ocomeni | 75:08eff6258e1b | 345 | |
ocomeni | 75:08eff6258e1b | 346 | if (error) { |
ocomeni | 75:08eff6258e1b | 347 | printf("Error during SM::setLinkSecurity %d\r\n", error); |
ocomeni | 75:08eff6258e1b | 348 | return; |
ocomeni | 75:08eff6258e1b | 349 | } |
ocomeni | 75:08eff6258e1b | 350 | } |
ocomeni | 75:08eff6258e1b | 351 | |
ocomeni | 75:08eff6258e1b | 352 | /** A central device will scan, connect to a peer and request pairing. */ |
ocomeni | 75:08eff6258e1b | 353 | |
ocomeni | 75:08eff6258e1b | 354 | SMDeviceCentral::SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) |
ocomeni | 75:08eff6258e1b | 355 | : SMDevice(ble, event_queue, peer_address) { }; |
ocomeni | 75:08eff6258e1b | 356 | |
ocomeni | 75:08eff6258e1b | 357 | void SMDeviceCentral::start() |
ocomeni | 75:08eff6258e1b | 358 | { |
ocomeni | 75:08eff6258e1b | 359 | /* start scanning and attach a callback that will handle advertisements |
ocomeni | 75:08eff6258e1b | 360 | * and scan requests responses */ |
ocomeni | 75:08eff6258e1b | 361 | ble_error_t error = _ble.gap().startScan(this, &SMDeviceCentral::on_scan); |
ocomeni | 75:08eff6258e1b | 362 | |
ocomeni | 75:08eff6258e1b | 363 | printf("Please advertise\r\n"); |
ocomeni | 75:08eff6258e1b | 364 | |
ocomeni | 75:08eff6258e1b | 365 | printf("Scanning for: %02x:%02x:%02x:%02x:%02x:%02x\r\n", |
ocomeni | 75:08eff6258e1b | 366 | _peer_address[5], _peer_address[4], _peer_address[3], |
ocomeni | 75:08eff6258e1b | 367 | _peer_address[2], _peer_address[1], _peer_address[0]); |
ocomeni | 75:08eff6258e1b | 368 | |
ocomeni | 75:08eff6258e1b | 369 | if (error) { |
ocomeni | 75:08eff6258e1b | 370 | printf("Error during Gap::startScan %d\r\n", error); |
ocomeni | 75:08eff6258e1b | 371 | return; |
ocomeni | 75:08eff6258e1b | 372 | } |
ocomeni | 75:08eff6258e1b | 373 | } |
ocomeni | 75:08eff6258e1b | 374 | |
ocomeni | 75:08eff6258e1b | 375 | /** Look at scan payload to find a peer device and connect to it */ |
ocomeni | 75:08eff6258e1b | 376 | void SMDeviceCentral::on_scan(const Gap::AdvertisementCallbackParams_t *params) |
ocomeni | 75:08eff6258e1b | 377 | { |
ocomeni | 75:08eff6258e1b | 378 | /* don't bother with analysing scan result if we're already connecting */ |
ocomeni | 75:08eff6258e1b | 379 | if (_is_connecting) { |
ocomeni | 75:08eff6258e1b | 380 | return; |
ocomeni | 75:08eff6258e1b | 381 | } |
ocomeni | 75:08eff6258e1b | 382 | |
ocomeni | 75:08eff6258e1b | 383 | /* connect to the same device that connected to us */ |
ocomeni | 75:08eff6258e1b | 384 | if (memcmp(params->peerAddr, _peer_address, sizeof(_peer_address)) == 0) { |
ocomeni | 75:08eff6258e1b | 385 | |
ocomeni | 75:08eff6258e1b | 386 | ble_error_t error = _ble.gap().connect( |
ocomeni | 75:08eff6258e1b | 387 | params->peerAddr, params->peerAddrType, |
ocomeni | 75:08eff6258e1b | 388 | NULL, NULL |
ocomeni | 75:08eff6258e1b | 389 | ); |
ocomeni | 75:08eff6258e1b | 390 | |
ocomeni | 75:08eff6258e1b | 391 | if (error) { |
ocomeni | 75:08eff6258e1b | 392 | printf("Error during Gap::connect %d\r\n", error); |
ocomeni | 75:08eff6258e1b | 393 | return; |
ocomeni | 75:08eff6258e1b | 394 | } |
ocomeni | 75:08eff6258e1b | 395 | |
ocomeni | 75:08eff6258e1b | 396 | printf("Connecting... "); |
ocomeni | 75:08eff6258e1b | 397 | |
ocomeni | 75:08eff6258e1b | 398 | /* we may have already scan events waiting |
ocomeni | 75:08eff6258e1b | 399 | * to be processed so we need to remember |
ocomeni | 75:08eff6258e1b | 400 | * that we are already connecting and ignore them */ |
ocomeni | 75:08eff6258e1b | 401 | _is_connecting = true; |
ocomeni | 75:08eff6258e1b | 402 | |
ocomeni | 75:08eff6258e1b | 403 | return; |
ocomeni | 75:08eff6258e1b | 404 | } |
ocomeni | 75:08eff6258e1b | 405 | } |
ocomeni | 75:08eff6258e1b | 406 | |
ocomeni | 75:08eff6258e1b | 407 | /** This is called by Gap to notify the application we connected, |
ocomeni | 75:08eff6258e1b | 408 | * in our case it immediately request pairing */ |
ocomeni | 75:08eff6258e1b | 409 | void SMDeviceCentral::on_connect(const Gap::ConnectionCallbackParams_t *connection_event) |
ocomeni | 75:08eff6258e1b | 410 | { |
ocomeni | 75:08eff6258e1b | 411 | ble_error_t error; |
ocomeni | 75:08eff6258e1b | 412 | |
ocomeni | 75:08eff6258e1b | 413 | /* store the handle for future Security Manager requests */ |
ocomeni | 75:08eff6258e1b | 414 | _handle = connection_event->handle; |
ocomeni | 75:08eff6258e1b | 415 | |
ocomeni | 75:08eff6258e1b | 416 | /* in this example the local device is the master so we request pairing */ |
ocomeni | 75:08eff6258e1b | 417 | error = _ble.securityManager().requestPairing(_handle); |
ocomeni | 75:08eff6258e1b | 418 | |
ocomeni | 75:08eff6258e1b | 419 | printf("Connected\r\n"); |
ocomeni | 75:08eff6258e1b | 420 | |
ocomeni | 75:08eff6258e1b | 421 | if (error) { |
ocomeni | 75:08eff6258e1b | 422 | printf("Error during SM::requestPairing %d\r\n", error); |
ocomeni | 75:08eff6258e1b | 423 | return; |
ocomeni | 75:08eff6258e1b | 424 | } |
ocomeni | 75:08eff6258e1b | 425 | |
ocomeni | 75:08eff6258e1b | 426 | /* upon pairing success the application will disconnect */ |
ocomeni | 75:08eff6258e1b | 427 | } |
ocomeni | 75:08eff6258e1b | 428 | |
ocomeni | 75:08eff6258e1b | 429 | |
ocomeni | 75:08eff6258e1b | 430 | |
ocomeni | 75:08eff6258e1b | 431 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 75:08eff6258e1b | 432 | bool create_filesystem() |
ocomeni | 75:08eff6258e1b | 433 | { |
ocomeni | 75:08eff6258e1b | 434 | static LittleFileSystem fs("fs"); |
ocomeni | 75:08eff6258e1b | 435 | |
ocomeni | 75:08eff6258e1b | 436 | /* replace this with any physical block device your board supports (like an SD card) */ |
ocomeni | 75:08eff6258e1b | 437 | static HeapBlockDevice bd(4096, 256); |
ocomeni | 75:08eff6258e1b | 438 | |
ocomeni | 75:08eff6258e1b | 439 | int err = bd.init(); |
ocomeni | 75:08eff6258e1b | 440 | |
ocomeni | 75:08eff6258e1b | 441 | if (err) { |
ocomeni | 75:08eff6258e1b | 442 | return false; |
ocomeni | 75:08eff6258e1b | 443 | } |
ocomeni | 75:08eff6258e1b | 444 | |
ocomeni | 75:08eff6258e1b | 445 | err = bd.erase(0, bd.size()); |
ocomeni | 75:08eff6258e1b | 446 | |
ocomeni | 75:08eff6258e1b | 447 | if (err) { |
ocomeni | 75:08eff6258e1b | 448 | return false; |
ocomeni | 75:08eff6258e1b | 449 | } |
ocomeni | 75:08eff6258e1b | 450 | |
ocomeni | 75:08eff6258e1b | 451 | err = fs.mount(&bd); |
ocomeni | 75:08eff6258e1b | 452 | |
ocomeni | 75:08eff6258e1b | 453 | if (err) { |
ocomeni | 75:08eff6258e1b | 454 | /* Reformat if we can't mount the filesystem */ |
ocomeni | 75:08eff6258e1b | 455 | printf("No filesystem found, formatting...\r\n"); |
ocomeni | 75:08eff6258e1b | 456 | |
ocomeni | 75:08eff6258e1b | 457 | err = fs.reformat(&bd); |
ocomeni | 75:08eff6258e1b | 458 | |
ocomeni | 75:08eff6258e1b | 459 | if (err) { |
ocomeni | 75:08eff6258e1b | 460 | return false; |
ocomeni | 75:08eff6258e1b | 461 | } |
ocomeni | 75:08eff6258e1b | 462 | } |
ocomeni | 75:08eff6258e1b | 463 | |
ocomeni | 75:08eff6258e1b | 464 | return true; |
ocomeni | 75:08eff6258e1b | 465 | } |
ocomeni | 75:08eff6258e1b | 466 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 75:08eff6258e1b | 467 | #ifdef BLE_SECURITY_MAIN |
ocomeni | 75:08eff6258e1b | 468 | int main() |
ocomeni | 75:08eff6258e1b | 469 | { |
ocomeni | 75:08eff6258e1b | 470 | BLE& ble = BLE::Instance(); |
ocomeni | 75:08eff6258e1b | 471 | events::EventQueue queue; |
ocomeni | 75:08eff6258e1b | 472 | |
ocomeni | 75:08eff6258e1b | 473 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 75:08eff6258e1b | 474 | /* if filesystem creation fails or there is no filesystem the security manager |
ocomeni | 75:08eff6258e1b | 475 | * will fallback to storing the security database in memory */ |
ocomeni | 75:08eff6258e1b | 476 | if (!create_filesystem()) { |
ocomeni | 75:08eff6258e1b | 477 | printf("Filesystem creation failed, will use memory storage\r\n"); |
ocomeni | 75:08eff6258e1b | 478 | } |
ocomeni | 75:08eff6258e1b | 479 | #endif |
ocomeni | 75:08eff6258e1b | 480 | |
ocomeni | 75:08eff6258e1b | 481 | while(1) { |
ocomeni | 75:08eff6258e1b | 482 | { |
ocomeni | 75:08eff6258e1b | 483 | printf("\r\n PERIPHERAL \r\n\r\n"); |
ocomeni | 75:08eff6258e1b | 484 | SMDevicePeripheral peripheral(ble, queue, peer_address); |
ocomeni | 75:08eff6258e1b | 485 | peripheral.run(); |
ocomeni | 75:08eff6258e1b | 486 | } |
ocomeni | 75:08eff6258e1b | 487 | |
ocomeni | 75:08eff6258e1b | 488 | { |
ocomeni | 75:08eff6258e1b | 489 | printf("\r\n CENTRAL \r\n\r\n"); |
ocomeni | 75:08eff6258e1b | 490 | SMDeviceCentral central(ble, queue, peer_address); |
ocomeni | 75:08eff6258e1b | 491 | central.run(); |
ocomeni | 75:08eff6258e1b | 492 | } |
ocomeni | 75:08eff6258e1b | 493 | } |
ocomeni | 75:08eff6258e1b | 494 | |
ocomeni | 75:08eff6258e1b | 495 | return 0; |
ocomeni | 75:08eff6258e1b | 496 | } |
ocomeni | 75:08eff6258e1b | 497 | #endif |
ocomeni | 75:08eff6258e1b | 498 | |
ocomeni | 75:08eff6258e1b | 499 | #ifdef OLD_BLE_SECURITY |
ocomeni | 75:08eff6258e1b | 500 | /* mbed Microcontroller Library |
ocomeni | 75:08eff6258e1b | 501 | * Copyright (c) 2006-2013 ARM Limited |
ocomeni | 75:08eff6258e1b | 502 | * |
ocomeni | 75:08eff6258e1b | 503 | * Licensed under the Apache License, Version 2.0 (the "License"); |
ocomeni | 75:08eff6258e1b | 504 | * you may not use this file except in compliance with the License. |
ocomeni | 75:08eff6258e1b | 505 | * You may obtain a copy of the License at |
ocomeni | 75:08eff6258e1b | 506 | * |
ocomeni | 75:08eff6258e1b | 507 | * http://www.apache.org/licenses/LICENSE-2.0 |
ocomeni | 75:08eff6258e1b | 508 | * |
ocomeni | 75:08eff6258e1b | 509 | * Unless required by applicable law or agreed to in writing, software |
ocomeni | 75:08eff6258e1b | 510 | * distributed under the License is distributed on an "AS IS" BASIS, |
ocomeni | 75:08eff6258e1b | 511 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
ocomeni | 75:08eff6258e1b | 512 | * See the License for the specific language governing permissions and |
ocomeni | 75:08eff6258e1b | 513 | * limitations under the License. |
ocomeni | 75:08eff6258e1b | 514 | */ |
ocomeni | 75:08eff6258e1b | 515 | //#ifdef BLE_SECURITY_ENABLED |
ocomeni | 75:08eff6258e1b | 516 | #include <events/mbed_events.h> |
ocomeni | 75:08eff6258e1b | 517 | #include <mbed.h> |
ocomeni | 75:08eff6258e1b | 518 | #include "ble/BLE.h" |
ocomeni | 75:08eff6258e1b | 519 | #include "ble/Gap.h" |
ocomeni | 75:08eff6258e1b | 520 | #include "Types.h" |
ocomeni | 75:08eff6258e1b | 521 | #include "ble/services/UARTService.h" |
ocomeni | 75:08eff6258e1b | 522 | |
ocomeni | 75:08eff6258e1b | 523 | //#include "ble/gap/Types.h" |
ocomeni | 75:08eff6258e1b | 524 | #include "SecurityManager.h" |
ocomeni | 74:f26e846adfe9 | 525 | #include "pretty_printer.h" |
ocomeni | 74:f26e846adfe9 | 526 | |
ocomeni | 74:f26e846adfe9 | 527 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 74:f26e846adfe9 | 528 | #include "LittleFileSystem.h" |
ocomeni | 74:f26e846adfe9 | 529 | #include "HeapBlockDevice.h" |
ocomeni | 74:f26e846adfe9 | 530 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 74:f26e846adfe9 | 531 | |
ocomeni | 74:f26e846adfe9 | 532 | /** This example demonstrates all the basic setup required |
ocomeni | 74:f26e846adfe9 | 533 | * for pairing and setting up link security both as a central and peripheral |
ocomeni | 74:f26e846adfe9 | 534 | * |
ocomeni | 74:f26e846adfe9 | 535 | * The example is implemented as two classes, one for the peripheral and one |
ocomeni | 74:f26e846adfe9 | 536 | * for central inheriting from a common base. They are run in sequence and |
ocomeni | 74:f26e846adfe9 | 537 | * require a peer device to connect to. During the peripheral device demonstration |
ocomeni | 74:f26e846adfe9 | 538 | * a peer device is required to connect. In the central device demonstration |
ocomeni | 74:f26e846adfe9 | 539 | * this peer device will be scanned for and connected to - therefore it should |
ocomeni | 74:f26e846adfe9 | 540 | * be advertising with the same address as when it connected. |
ocomeni | 74:f26e846adfe9 | 541 | * |
ocomeni | 74:f26e846adfe9 | 542 | * During the test output is written on the serial connection to monitor its |
ocomeni | 74:f26e846adfe9 | 543 | * progress. |
ocomeni | 74:f26e846adfe9 | 544 | */ |
ocomeni | 74:f26e846adfe9 | 545 | |
ocomeni | 74:f26e846adfe9 | 546 | static const char DEVICE_NAME[] = "SM_device"; |
ocomeni | 74:f26e846adfe9 | 547 | |
ocomeni | 74:f26e846adfe9 | 548 | /* we have to specify the disconnect call because of ambiguous overloads */ |
ocomeni | 75:08eff6258e1b | 549 | //typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); |
ocomeni | 75:08eff6258e1b | 550 | //const static disconnect_call_t disconnect_call = &Gap::disconnect; |
ocomeni | 75:08eff6258e1b | 551 | //typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); |
ocomeni | 75:08eff6258e1b | 552 | //const static (Gap::*disconnect_call_t) disconnect_call = &Gap::disconnect; |
ocomeni | 74:f26e846adfe9 | 553 | |
ocomeni | 74:f26e846adfe9 | 554 | /* for demonstration purposes we will store the peer device address |
ocomeni | 74:f26e846adfe9 | 555 | * of the device that connects to us in the first demonstration |
ocomeni | 74:f26e846adfe9 | 556 | * so we can use its address to reconnect to it later */ |
ocomeni | 74:f26e846adfe9 | 557 | static BLEProtocol::AddressBytes_t peer_address; |
ocomeni | 74:f26e846adfe9 | 558 | |
ocomeni | 74:f26e846adfe9 | 559 | /** Base class for both peripheral and central. The same class that provides |
ocomeni | 74:f26e846adfe9 | 560 | * the logic for the application also implements the SecurityManagerEventHandler |
ocomeni | 74:f26e846adfe9 | 561 | * which is the interface used by the Security Manager to communicate events |
ocomeni | 74:f26e846adfe9 | 562 | * back to the applications. You can provide overrides for a selection of events |
ocomeni | 74:f26e846adfe9 | 563 | * your application is interested in. |
ocomeni | 74:f26e846adfe9 | 564 | */ |
ocomeni | 74:f26e846adfe9 | 565 | class SMDevice : private mbed::NonCopyable<SMDevice>, |
ocomeni | 74:f26e846adfe9 | 566 | public SecurityManager::EventHandler, |
ocomeni | 75:08eff6258e1b | 567 | public Gap::EventHandler |
ocomeni | 74:f26e846adfe9 | 568 | { |
ocomeni | 74:f26e846adfe9 | 569 | public: |
ocomeni | 74:f26e846adfe9 | 570 | SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) : |
ocomeni | 74:f26e846adfe9 | 571 | _led1(LED1, 0), |
ocomeni | 74:f26e846adfe9 | 572 | _ble(ble), |
ocomeni | 74:f26e846adfe9 | 573 | _event_queue(event_queue), |
ocomeni | 74:f26e846adfe9 | 574 | _peer_address(peer_address), |
ocomeni | 74:f26e846adfe9 | 575 | _handle(0), |
ocomeni | 74:f26e846adfe9 | 576 | _is_connecting(false) { }; |
ocomeni | 74:f26e846adfe9 | 577 | |
ocomeni | 74:f26e846adfe9 | 578 | virtual ~SMDevice() |
ocomeni | 74:f26e846adfe9 | 579 | { |
ocomeni | 74:f26e846adfe9 | 580 | if (_ble.hasInitialized()) { |
ocomeni | 74:f26e846adfe9 | 581 | _ble.shutdown(); |
ocomeni | 74:f26e846adfe9 | 582 | } |
ocomeni | 74:f26e846adfe9 | 583 | }; |
ocomeni | 74:f26e846adfe9 | 584 | |
ocomeni | 74:f26e846adfe9 | 585 | /** Start BLE interface initialisation */ |
ocomeni | 74:f26e846adfe9 | 586 | void run() |
ocomeni | 74:f26e846adfe9 | 587 | { |
ocomeni | 74:f26e846adfe9 | 588 | ble_error_t error; |
ocomeni | 74:f26e846adfe9 | 589 | |
ocomeni | 74:f26e846adfe9 | 590 | /* to show we're running we'll blink every 500ms */ |
ocomeni | 74:f26e846adfe9 | 591 | _event_queue.call_every(500, this, &SMDevice::blink); |
ocomeni | 74:f26e846adfe9 | 592 | |
ocomeni | 74:f26e846adfe9 | 593 | if (_ble.hasInitialized()) { |
ocomeni | 74:f26e846adfe9 | 594 | printf("Ble instance already initialised.\r\n"); |
ocomeni | 74:f26e846adfe9 | 595 | return; |
ocomeni | 74:f26e846adfe9 | 596 | } |
ocomeni | 74:f26e846adfe9 | 597 | |
ocomeni | 74:f26e846adfe9 | 598 | /* this will inform us off all events so we can schedule their handling |
ocomeni | 74:f26e846adfe9 | 599 | * using our event queue */ |
ocomeni | 74:f26e846adfe9 | 600 | _ble.onEventsToProcess( |
ocomeni | 74:f26e846adfe9 | 601 | makeFunctionPointer(this, &SMDevice::schedule_ble_events) |
ocomeni | 74:f26e846adfe9 | 602 | ); |
ocomeni | 74:f26e846adfe9 | 603 | |
ocomeni | 74:f26e846adfe9 | 604 | /* handle gap events */ |
ocomeni | 74:f26e846adfe9 | 605 | _ble.gap().setEventHandler(this); |
ocomeni | 74:f26e846adfe9 | 606 | |
ocomeni | 74:f26e846adfe9 | 607 | error = _ble.init(this, &SMDevice::on_init_complete); |
ocomeni | 74:f26e846adfe9 | 608 | |
ocomeni | 74:f26e846adfe9 | 609 | if (error) { |
ocomeni | 74:f26e846adfe9 | 610 | printf("Error returned by BLE::init.\r\n"); |
ocomeni | 74:f26e846adfe9 | 611 | return; |
ocomeni | 74:f26e846adfe9 | 612 | } |
ocomeni | 74:f26e846adfe9 | 613 | |
ocomeni | 74:f26e846adfe9 | 614 | /* this will not return until shutdown */ |
ocomeni | 74:f26e846adfe9 | 615 | _event_queue.dispatch_forever(); |
ocomeni | 74:f26e846adfe9 | 616 | }; |
ocomeni | 74:f26e846adfe9 | 617 | |
ocomeni | 74:f26e846adfe9 | 618 | private: |
ocomeni | 74:f26e846adfe9 | 619 | /** Override to start chosen activity when initialisation completes */ |
ocomeni | 74:f26e846adfe9 | 620 | virtual void start() = 0; |
ocomeni | 74:f26e846adfe9 | 621 | |
ocomeni | 74:f26e846adfe9 | 622 | /** This is called when BLE interface is initialised and starts the demonstration */ |
ocomeni | 74:f26e846adfe9 | 623 | void on_init_complete(BLE::InitializationCompleteCallbackContext *event) |
ocomeni | 74:f26e846adfe9 | 624 | { |
ocomeni | 74:f26e846adfe9 | 625 | ble_error_t error; |
ocomeni | 74:f26e846adfe9 | 626 | |
ocomeni | 74:f26e846adfe9 | 627 | if (event->error) { |
ocomeni | 74:f26e846adfe9 | 628 | printf("Error during the initialisation\r\n"); |
ocomeni | 74:f26e846adfe9 | 629 | return; |
ocomeni | 74:f26e846adfe9 | 630 | } |
ocomeni | 74:f26e846adfe9 | 631 | |
ocomeni | 74:f26e846adfe9 | 632 | /* This path will be used to store bonding information but will fallback |
ocomeni | 74:f26e846adfe9 | 633 | * to storing in memory if file access fails (for example due to lack of a filesystem) */ |
ocomeni | 74:f26e846adfe9 | 634 | const char* db_path = "/fs/bt_sec_db"; |
ocomeni | 74:f26e846adfe9 | 635 | /* If the security manager is required this needs to be called before any |
ocomeni | 74:f26e846adfe9 | 636 | * calls to the Security manager happen. */ |
ocomeni | 74:f26e846adfe9 | 637 | error = _ble.securityManager().init( |
ocomeni | 74:f26e846adfe9 | 638 | true, |
ocomeni | 74:f26e846adfe9 | 639 | false, |
ocomeni | 74:f26e846adfe9 | 640 | SecurityManager::IO_CAPS_NONE, |
ocomeni | 74:f26e846adfe9 | 641 | NULL, |
ocomeni | 74:f26e846adfe9 | 642 | false, |
ocomeni | 74:f26e846adfe9 | 643 | db_path |
ocomeni | 74:f26e846adfe9 | 644 | ); |
ocomeni | 74:f26e846adfe9 | 645 | |
ocomeni | 74:f26e846adfe9 | 646 | if (error) { |
ocomeni | 74:f26e846adfe9 | 647 | printf("Error during init %d\r\n", error); |
ocomeni | 74:f26e846adfe9 | 648 | return; |
ocomeni | 74:f26e846adfe9 | 649 | } |
ocomeni | 74:f26e846adfe9 | 650 | |
ocomeni | 74:f26e846adfe9 | 651 | error = _ble.securityManager().preserveBondingStateOnReset(true); |
ocomeni | 74:f26e846adfe9 | 652 | |
ocomeni | 74:f26e846adfe9 | 653 | if (error) { |
ocomeni | 74:f26e846adfe9 | 654 | printf("Error during preserveBondingStateOnReset %d\r\n", error); |
ocomeni | 74:f26e846adfe9 | 655 | } |
ocomeni | 74:f26e846adfe9 | 656 | |
ocomeni | 74:f26e846adfe9 | 657 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 74:f26e846adfe9 | 658 | /* Enable privacy so we can find the keys */ |
ocomeni | 74:f26e846adfe9 | 659 | error = _ble.gap().enablePrivacy(true); |
ocomeni | 74:f26e846adfe9 | 660 | |
ocomeni | 74:f26e846adfe9 | 661 | if (error) { |
ocomeni | 74:f26e846adfe9 | 662 | printf("Error enabling privacy\r\n"); |
ocomeni | 74:f26e846adfe9 | 663 | } |
ocomeni | 74:f26e846adfe9 | 664 | |
ocomeni | 74:f26e846adfe9 | 665 | Gap::PeripheralPrivacyConfiguration_t configuration_p = { |
ocomeni | 74:f26e846adfe9 | 666 | /* use_non_resolvable_random_address */ false, |
ocomeni | 74:f26e846adfe9 | 667 | Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS |
ocomeni | 74:f26e846adfe9 | 668 | }; |
ocomeni | 74:f26e846adfe9 | 669 | _ble.gap().setPeripheralPrivacyConfiguration(&configuration_p); |
ocomeni | 74:f26e846adfe9 | 670 | |
ocomeni | 74:f26e846adfe9 | 671 | Gap::CentralPrivacyConfiguration_t configuration_c = { |
ocomeni | 74:f26e846adfe9 | 672 | /* use_non_resolvable_random_address */ false, |
ocomeni | 74:f26e846adfe9 | 673 | Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD |
ocomeni | 74:f26e846adfe9 | 674 | }; |
ocomeni | 74:f26e846adfe9 | 675 | _ble.gap().setCentralPrivacyConfiguration(&configuration_c); |
ocomeni | 74:f26e846adfe9 | 676 | |
ocomeni | 74:f26e846adfe9 | 677 | /* this demo switches between being master and slave */ |
ocomeni | 74:f26e846adfe9 | 678 | _ble.securityManager().setHintFutureRoleReversal(true); |
ocomeni | 74:f26e846adfe9 | 679 | #endif |
ocomeni | 74:f26e846adfe9 | 680 | |
ocomeni | 74:f26e846adfe9 | 681 | /* Tell the security manager to use methods in this class to inform us |
ocomeni | 74:f26e846adfe9 | 682 | * of any events. Class needs to implement SecurityManagerEventHandler. */ |
ocomeni | 74:f26e846adfe9 | 683 | _ble.securityManager().setSecurityManagerEventHandler(this); |
ocomeni | 74:f26e846adfe9 | 684 | |
ocomeni | 74:f26e846adfe9 | 685 | /* gap events also handled by this class */ |
ocomeni | 74:f26e846adfe9 | 686 | _ble.gap().setEventHandler(this); |
ocomeni | 74:f26e846adfe9 | 687 | |
ocomeni | 74:f26e846adfe9 | 688 | /* print device address */ |
ocomeni | 74:f26e846adfe9 | 689 | Gap::AddressType_t addr_type; |
ocomeni | 74:f26e846adfe9 | 690 | Gap::Address_t addr; |
ocomeni | 74:f26e846adfe9 | 691 | _ble.gap().getAddress(&addr_type, addr); |
ocomeni | 74:f26e846adfe9 | 692 | print_address(addr); |
ocomeni | 74:f26e846adfe9 | 693 | |
ocomeni | 74:f26e846adfe9 | 694 | /* start test in 500 ms */ |
ocomeni | 74:f26e846adfe9 | 695 | _event_queue.call_in(500, this, &SMDevice::start); |
ocomeni | 74:f26e846adfe9 | 696 | }; |
ocomeni | 74:f26e846adfe9 | 697 | |
ocomeni | 74:f26e846adfe9 | 698 | /** Schedule processing of events from the BLE in the event queue. */ |
ocomeni | 74:f26e846adfe9 | 699 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) |
ocomeni | 74:f26e846adfe9 | 700 | { |
ocomeni | 74:f26e846adfe9 | 701 | _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents)); |
ocomeni | 74:f26e846adfe9 | 702 | }; |
ocomeni | 74:f26e846adfe9 | 703 | |
ocomeni | 74:f26e846adfe9 | 704 | /** Blink LED to show we're running */ |
ocomeni | 74:f26e846adfe9 | 705 | void blink(void) |
ocomeni | 74:f26e846adfe9 | 706 | { |
ocomeni | 74:f26e846adfe9 | 707 | _led1 = !_led1; |
ocomeni | 74:f26e846adfe9 | 708 | }; |
ocomeni | 74:f26e846adfe9 | 709 | |
ocomeni | 74:f26e846adfe9 | 710 | private: |
ocomeni | 74:f26e846adfe9 | 711 | /* Event handler */ |
ocomeni | 74:f26e846adfe9 | 712 | |
ocomeni | 74:f26e846adfe9 | 713 | /** Respond to a pairing request. This will be called by the stack |
ocomeni | 74:f26e846adfe9 | 714 | * when a pairing request arrives and expects the application to |
ocomeni | 74:f26e846adfe9 | 715 | * call acceptPairingRequest or cancelPairingRequest */ |
ocomeni | 74:f26e846adfe9 | 716 | virtual void pairingRequest( |
ocomeni | 74:f26e846adfe9 | 717 | ble::connection_handle_t connectionHandle |
ocomeni | 74:f26e846adfe9 | 718 | ) { |
ocomeni | 74:f26e846adfe9 | 719 | printf("Pairing requested - authorising\r\n"); |
ocomeni | 74:f26e846adfe9 | 720 | _ble.securityManager().acceptPairingRequest(connectionHandle); |
ocomeni | 74:f26e846adfe9 | 721 | } |
ocomeni | 74:f26e846adfe9 | 722 | |
ocomeni | 74:f26e846adfe9 | 723 | /** Inform the application of a successful pairing. Terminate the demonstration. */ |
ocomeni | 74:f26e846adfe9 | 724 | virtual void pairingResult( |
ocomeni | 74:f26e846adfe9 | 725 | ble::connection_handle_t connectionHandle, |
ocomeni | 74:f26e846adfe9 | 726 | SecurityManager::SecurityCompletionStatus_t result |
ocomeni | 74:f26e846adfe9 | 727 | ) { |
ocomeni | 74:f26e846adfe9 | 728 | if (result == SecurityManager::SEC_STATUS_SUCCESS) { |
ocomeni | 74:f26e846adfe9 | 729 | printf("Pairing successful\r\n"); |
ocomeni | 74:f26e846adfe9 | 730 | } else { |
ocomeni | 74:f26e846adfe9 | 731 | printf("Pairing failed\r\n"); |
ocomeni | 74:f26e846adfe9 | 732 | } |
ocomeni | 74:f26e846adfe9 | 733 | } |
ocomeni | 74:f26e846adfe9 | 734 | |
ocomeni | 74:f26e846adfe9 | 735 | /** Inform the application of change in encryption status. This will be |
ocomeni | 74:f26e846adfe9 | 736 | * communicated through the serial port */ |
ocomeni | 74:f26e846adfe9 | 737 | virtual void linkEncryptionResult( |
ocomeni | 74:f26e846adfe9 | 738 | ble::connection_handle_t connectionHandle, |
ocomeni | 74:f26e846adfe9 | 739 | ble::link_encryption_t result |
ocomeni | 74:f26e846adfe9 | 740 | ) { |
ocomeni | 74:f26e846adfe9 | 741 | if (result == ble::link_encryption_t::ENCRYPTED) { |
ocomeni | 74:f26e846adfe9 | 742 | printf("Link ENCRYPTED\r\n"); |
ocomeni | 74:f26e846adfe9 | 743 | } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { |
ocomeni | 74:f26e846adfe9 | 744 | printf("Link ENCRYPTED_WITH_MITM\r\n"); |
ocomeni | 74:f26e846adfe9 | 745 | } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) { |
ocomeni | 74:f26e846adfe9 | 746 | printf("Link NOT_ENCRYPTED\r\n"); |
ocomeni | 74:f26e846adfe9 | 747 | } |
ocomeni | 74:f26e846adfe9 | 748 | |
ocomeni | 74:f26e846adfe9 | 749 | /* disconnect in 2 s */ |
ocomeni | 74:f26e846adfe9 | 750 | _event_queue.call_in( |
ocomeni | 74:f26e846adfe9 | 751 | 2000, |
ocomeni | 74:f26e846adfe9 | 752 | &_ble.gap(), |
ocomeni | 75:08eff6258e1b | 753 | &Gap::disconnect, //disconnect_call, |
ocomeni | 74:f26e846adfe9 | 754 | _handle, |
ocomeni | 75:08eff6258e1b | 755 | (Gap::DisconnectionReason_t)0x13 |
ocomeni | 75:08eff6258e1b | 756 | //Gap::DisconnectionReason_t::REMOTE_USER_TERMINATED_CONNECTION) |
ocomeni | 75:08eff6258e1b | 757 | //ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) |
ocomeni | 74:f26e846adfe9 | 758 | ); |
ocomeni | 74:f26e846adfe9 | 759 | } |
ocomeni | 75:08eff6258e1b | 760 | |
ocomeni | 75:08eff6258e1b | 761 | |
ocomeni | 74:f26e846adfe9 | 762 | |
ocomeni | 74:f26e846adfe9 | 763 | /** This is called by Gap to notify the application we disconnected, |
ocomeni | 74:f26e846adfe9 | 764 | * in our case it ends the demonstration. */ |
ocomeni | 75:08eff6258e1b | 765 | //virtual void onDisconnectionComplete(const Gap::DisconnectionCompleteEvent &) |
ocomeni | 75:08eff6258e1b | 766 | virtual void onDisconnectionComplete(const Gap::DisconnectionCallbackParams_t *params) |
ocomeni | 74:f26e846adfe9 | 767 | { |
ocomeni | 75:08eff6258e1b | 768 | printf("Disconnected\r\n"); |
ocomeni | 74:f26e846adfe9 | 769 | _event_queue.break_dispatch(); |
ocomeni | 74:f26e846adfe9 | 770 | }; |
ocomeni | 74:f26e846adfe9 | 771 | |
ocomeni | 75:08eff6258e1b | 772 | //virtual void onAdvertisingEnd(const ble::AdvertisingEndEvent &) |
ocomeni | 75:08eff6258e1b | 773 | //void onAdvertisingEnd(const ble::AdvertisingEndEvent &) |
ocomeni | 75:08eff6258e1b | 774 | //{ |
ocomeni | 75:08eff6258e1b | 775 | // printf("Advertising timed out - aborting\r\n"); |
ocomeni | 75:08eff6258e1b | 776 | // _event_queue.break_dispatch(); |
ocomeni | 75:08eff6258e1b | 777 | //} |
ocomeni | 74:f26e846adfe9 | 778 | |
ocomeni | 75:08eff6258e1b | 779 | //virtual void onScanTimeout(const ble::ScanTimeoutEvent &) |
ocomeni | 75:08eff6258e1b | 780 | //{ |
ocomeni | 75:08eff6258e1b | 781 | // printf("Scan timed out - aborting\r\n"); |
ocomeni | 75:08eff6258e1b | 782 | // _event_queue.break_dispatch(); |
ocomeni | 75:08eff6258e1b | 783 | //} |
ocomeni | 74:f26e846adfe9 | 784 | |
ocomeni | 74:f26e846adfe9 | 785 | private: |
ocomeni | 74:f26e846adfe9 | 786 | DigitalOut _led1; |
ocomeni | 74:f26e846adfe9 | 787 | |
ocomeni | 74:f26e846adfe9 | 788 | protected: |
ocomeni | 74:f26e846adfe9 | 789 | BLE &_ble; |
ocomeni | 74:f26e846adfe9 | 790 | events::EventQueue &_event_queue; |
ocomeni | 74:f26e846adfe9 | 791 | BLEProtocol::AddressBytes_t &_peer_address; |
ocomeni | 74:f26e846adfe9 | 792 | ble::connection_handle_t _handle; |
ocomeni | 74:f26e846adfe9 | 793 | bool _is_connecting; |
ocomeni | 74:f26e846adfe9 | 794 | }; |
ocomeni | 74:f26e846adfe9 | 795 | |
ocomeni | 74:f26e846adfe9 | 796 | /** A peripheral device will advertise, accept the connection and request |
ocomeni | 74:f26e846adfe9 | 797 | * a change in link security. */ |
ocomeni | 74:f26e846adfe9 | 798 | class SMDevicePeripheral : public SMDevice { |
ocomeni | 74:f26e846adfe9 | 799 | public: |
ocomeni | 74:f26e846adfe9 | 800 | SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) |
ocomeni | 74:f26e846adfe9 | 801 | : SMDevice(ble, event_queue, peer_address) { } |
ocomeni | 74:f26e846adfe9 | 802 | |
ocomeni | 74:f26e846adfe9 | 803 | virtual void start() |
ocomeni | 74:f26e846adfe9 | 804 | { |
ocomeni | 74:f26e846adfe9 | 805 | /* Set up and start advertising */ |
ocomeni | 75:08eff6258e1b | 806 | #ifdef NEW_BLE5_API |
ocomeni | 75:08eff6258e1b | 807 | //uint8_t adv_buffer[Gap::LEGACY_ADVERTISING_MAX_SIZE]; |
ocomeni | 75:08eff6258e1b | 808 | uint8_t adv_buffer[32]; |
ocomeni | 74:f26e846adfe9 | 809 | /* use the helper to build the payload */ |
ocomeni | 75:08eff6258e1b | 810 | ble::Gap::AdvertisingDataBuilder adv_data_builder( |
ocomeni | 75:08eff6258e1b | 811 | adv_buffer, 32 |
ocomeni | 74:f26e846adfe9 | 812 | ); |
ocomeni | 74:f26e846adfe9 | 813 | |
ocomeni | 74:f26e846adfe9 | 814 | adv_data_builder.setFlags(); |
ocomeni | 74:f26e846adfe9 | 815 | adv_data_builder.setName(DEVICE_NAME); |
ocomeni | 74:f26e846adfe9 | 816 | |
ocomeni | 74:f26e846adfe9 | 817 | /* Set payload for the set */ |
ocomeni | 74:f26e846adfe9 | 818 | ble_error_t error = _ble.gap().setAdvertisingPayload( |
ocomeni | 74:f26e846adfe9 | 819 | ble::LEGACY_ADVERTISING_HANDLE, |
ocomeni | 74:f26e846adfe9 | 820 | adv_data_builder.getAdvertisingData() |
ocomeni | 74:f26e846adfe9 | 821 | ); |
ocomeni | 74:f26e846adfe9 | 822 | |
ocomeni | 74:f26e846adfe9 | 823 | if (error) { |
ocomeni | 74:f26e846adfe9 | 824 | print_error(error, "Gap::setAdvertisingPayload() failed"); |
ocomeni | 74:f26e846adfe9 | 825 | _event_queue.break_dispatch(); |
ocomeni | 74:f26e846adfe9 | 826 | return; |
ocomeni | 74:f26e846adfe9 | 827 | } |
ocomeni | 74:f26e846adfe9 | 828 | |
ocomeni | 75:08eff6258e1b | 829 | ble::gap::AdvertisingParameters adv_parameters( |
ocomeni | 74:f26e846adfe9 | 830 | ble::advertising_type_t::CONNECTABLE_UNDIRECTED |
ocomeni | 74:f26e846adfe9 | 831 | ); |
ocomeni | 74:f26e846adfe9 | 832 | |
ocomeni | 74:f26e846adfe9 | 833 | error = _ble.gap().setAdvertisingParameters( |
ocomeni | 74:f26e846adfe9 | 834 | ble::LEGACY_ADVERTISING_HANDLE, |
ocomeni | 74:f26e846adfe9 | 835 | adv_parameters |
ocomeni | 74:f26e846adfe9 | 836 | ); |
ocomeni | 74:f26e846adfe9 | 837 | |
ocomeni | 74:f26e846adfe9 | 838 | if (error) { |
ocomeni | 74:f26e846adfe9 | 839 | print_error(error, "Gap::setAdvertisingParameters() failed"); |
ocomeni | 74:f26e846adfe9 | 840 | return; |
ocomeni | 74:f26e846adfe9 | 841 | } |
ocomeni | 74:f26e846adfe9 | 842 | |
ocomeni | 74:f26e846adfe9 | 843 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); |
ocomeni | 74:f26e846adfe9 | 844 | |
ocomeni | 74:f26e846adfe9 | 845 | if (error) { |
ocomeni | 74:f26e846adfe9 | 846 | print_error(error, "Gap::startAdvertising() failed"); |
ocomeni | 74:f26e846adfe9 | 847 | return; |
ocomeni | 74:f26e846adfe9 | 848 | } |
ocomeni | 75:08eff6258e1b | 849 | #else |
ocomeni | 75:08eff6258e1b | 850 | /* setup advertising */ |
ocomeni | 75:08eff6258e1b | 851 | _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
ocomeni | 75:08eff6258e1b | 852 | //_ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
ocomeni | 75:08eff6258e1b | 853 | _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
ocomeni | 75:08eff6258e1b | 854 | /* set up the services that can be discovered */ |
ocomeni | 75:08eff6258e1b | 855 | _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed)); |
ocomeni | 75:08eff6258e1b | 856 | _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
ocomeni | 75:08eff6258e1b | 857 | _ble.gap().setAdvertisingInterval(1000); /* 1000ms. */ |
ocomeni | 75:08eff6258e1b | 858 | _ble.gap().setAdvertisingTimeout(300); /* 16 * 1000ms. */ |
ocomeni | 75:08eff6258e1b | 859 | _ble.gap().startAdvertising(); |
ocomeni | 74:f26e846adfe9 | 860 | |
ocomeni | 75:08eff6258e1b | 861 | #endif |
ocomeni | 74:f26e846adfe9 | 862 | printf("Please connect to device\r\n"); |
ocomeni | 74:f26e846adfe9 | 863 | |
ocomeni | 74:f26e846adfe9 | 864 | /** This tells the stack to generate a pairingRequest event |
ocomeni | 74:f26e846adfe9 | 865 | * which will require this application to respond before pairing |
ocomeni | 74:f26e846adfe9 | 866 | * can proceed. Setting it to false will automatically accept |
ocomeni | 74:f26e846adfe9 | 867 | * pairing. */ |
ocomeni | 74:f26e846adfe9 | 868 | _ble.securityManager().setPairingRequestAuthorisation(true); |
ocomeni | 74:f26e846adfe9 | 869 | }; |
ocomeni | 74:f26e846adfe9 | 870 | |
ocomeni | 74:f26e846adfe9 | 871 | /** This is called by Gap to notify the application we connected, |
ocomeni | 74:f26e846adfe9 | 872 | * in our case it immediately requests a change in link security */ |
ocomeni | 75:08eff6258e1b | 873 | //virtual void onConnectionComplete(const ble::ConnectionCompleteEvent_t &event) |
ocomeni | 75:08eff6258e1b | 874 | virtual void onConnectionComplete(const Gap::ConnectionCallbackParams_t &event) |
ocomeni | 74:f26e846adfe9 | 875 | { |
ocomeni | 74:f26e846adfe9 | 876 | ble_error_t error; |
ocomeni | 74:f26e846adfe9 | 877 | |
ocomeni | 74:f26e846adfe9 | 878 | /* remember the device that connects to us now so we can connect to it |
ocomeni | 74:f26e846adfe9 | 879 | * during the next demonstration */ |
ocomeni | 75:08eff6258e1b | 880 | memcpy(_peer_address, event.peerAddr, 6); |
ocomeni | 74:f26e846adfe9 | 881 | |
ocomeni | 74:f26e846adfe9 | 882 | printf("Connected to peer: "); |
ocomeni | 75:08eff6258e1b | 883 | print_address(event.peerAddr); |
ocomeni | 74:f26e846adfe9 | 884 | |
ocomeni | 75:08eff6258e1b | 885 | _handle = event.handle; |
ocomeni | 74:f26e846adfe9 | 886 | |
ocomeni | 74:f26e846adfe9 | 887 | /* Request a change in link security. This will be done |
ocomeni | 74:f26e846adfe9 | 888 | * indirectly by asking the master of the connection to |
ocomeni | 74:f26e846adfe9 | 889 | * change it. Depending on circumstances different actions |
ocomeni | 74:f26e846adfe9 | 890 | * may be taken by the master which will trigger events |
ocomeni | 74:f26e846adfe9 | 891 | * which the applications should deal with. */ |
ocomeni | 74:f26e846adfe9 | 892 | error = _ble.securityManager().setLinkSecurity( |
ocomeni | 74:f26e846adfe9 | 893 | _handle, |
ocomeni | 74:f26e846adfe9 | 894 | SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM |
ocomeni | 74:f26e846adfe9 | 895 | ); |
ocomeni | 74:f26e846adfe9 | 896 | |
ocomeni | 74:f26e846adfe9 | 897 | if (error) { |
ocomeni | 74:f26e846adfe9 | 898 | printf("Error during SM::setLinkSecurity %d\r\n", error); |
ocomeni | 74:f26e846adfe9 | 899 | return; |
ocomeni | 74:f26e846adfe9 | 900 | } |
ocomeni | 74:f26e846adfe9 | 901 | }; |
ocomeni | 74:f26e846adfe9 | 902 | }; |
ocomeni | 74:f26e846adfe9 | 903 | |
ocomeni | 74:f26e846adfe9 | 904 | /** A central device will scan, connect to a peer and request pairing. */ |
ocomeni | 74:f26e846adfe9 | 905 | class SMDeviceCentral : public SMDevice { |
ocomeni | 74:f26e846adfe9 | 906 | public: |
ocomeni | 74:f26e846adfe9 | 907 | SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) |
ocomeni | 74:f26e846adfe9 | 908 | : SMDevice(ble, event_queue, peer_address) { } |
ocomeni | 74:f26e846adfe9 | 909 | |
ocomeni | 74:f26e846adfe9 | 910 | virtual void start() |
ocomeni | 74:f26e846adfe9 | 911 | { |
ocomeni | 74:f26e846adfe9 | 912 | ble::ScanParameters params; |
ocomeni | 74:f26e846adfe9 | 913 | ble_error_t error = _ble.gap().setScanParameters(params); |
ocomeni | 74:f26e846adfe9 | 914 | |
ocomeni | 74:f26e846adfe9 | 915 | if (error) { |
ocomeni | 74:f26e846adfe9 | 916 | print_error(error, "Error in Gap::startScan %d\r\n"); |
ocomeni | 74:f26e846adfe9 | 917 | return; |
ocomeni | 74:f26e846adfe9 | 918 | } |
ocomeni | 74:f26e846adfe9 | 919 | |
ocomeni | 74:f26e846adfe9 | 920 | /* start scanning, results will be handled by onAdvertisingReport */ |
ocomeni | 74:f26e846adfe9 | 921 | error = _ble.gap().startScan(); |
ocomeni | 74:f26e846adfe9 | 922 | |
ocomeni | 74:f26e846adfe9 | 923 | if (error) { |
ocomeni | 74:f26e846adfe9 | 924 | print_error(error, "Error in Gap::startScan %d\r\n"); |
ocomeni | 74:f26e846adfe9 | 925 | return; |
ocomeni | 74:f26e846adfe9 | 926 | } |
ocomeni | 74:f26e846adfe9 | 927 | |
ocomeni | 74:f26e846adfe9 | 928 | printf("Please advertise\r\n"); |
ocomeni | 74:f26e846adfe9 | 929 | |
ocomeni | 74:f26e846adfe9 | 930 | printf("Scanning for: "); |
ocomeni | 74:f26e846adfe9 | 931 | print_address(_peer_address); |
ocomeni | 74:f26e846adfe9 | 932 | } |
ocomeni | 74:f26e846adfe9 | 933 | |
ocomeni | 74:f26e846adfe9 | 934 | private: |
ocomeni | 74:f26e846adfe9 | 935 | /* Gap::EventHandler */ |
ocomeni | 74:f26e846adfe9 | 936 | |
ocomeni | 74:f26e846adfe9 | 937 | /** Look at scan payload to find a peer device and connect to it */ |
ocomeni | 75:08eff6258e1b | 938 | virtual void onAdvertisingReport(const Gap::AdvertisementCallbackParams_t &event) |
ocomeni | 74:f26e846adfe9 | 939 | { |
ocomeni | 74:f26e846adfe9 | 940 | /* don't bother with analysing scan result if we're already connecting */ |
ocomeni | 74:f26e846adfe9 | 941 | if (_is_connecting) { |
ocomeni | 74:f26e846adfe9 | 942 | return; |
ocomeni | 74:f26e846adfe9 | 943 | } |
ocomeni | 74:f26e846adfe9 | 944 | |
ocomeni | 74:f26e846adfe9 | 945 | /* parse the advertising payload, looking for a discoverable device */ |
ocomeni | 75:08eff6258e1b | 946 | if (memcmp(event.peerAddr, _peer_address, sizeof(_peer_address)) == 0) { |
ocomeni | 74:f26e846adfe9 | 947 | ble_error_t error = _ble.gap().stopScan(); |
ocomeni | 74:f26e846adfe9 | 948 | |
ocomeni | 74:f26e846adfe9 | 949 | if (error) { |
ocomeni | 74:f26e846adfe9 | 950 | print_error(error, "Error caused by Gap::stopScan"); |
ocomeni | 74:f26e846adfe9 | 951 | return; |
ocomeni | 74:f26e846adfe9 | 952 | } |
ocomeni | 74:f26e846adfe9 | 953 | |
ocomeni | 74:f26e846adfe9 | 954 | ble::ConnectionParameters connection_params( |
ocomeni | 74:f26e846adfe9 | 955 | ble::phy_t::LE_1M, |
ocomeni | 74:f26e846adfe9 | 956 | ble::scan_interval_t(50), |
ocomeni | 74:f26e846adfe9 | 957 | ble::scan_window_t(50), |
ocomeni | 74:f26e846adfe9 | 958 | ble::conn_interval_t(50), |
ocomeni | 74:f26e846adfe9 | 959 | ble::conn_interval_t(100), |
ocomeni | 74:f26e846adfe9 | 960 | ble::slave_latency_t(0), |
ocomeni | 74:f26e846adfe9 | 961 | ble::supervision_timeout_t(100) |
ocomeni | 74:f26e846adfe9 | 962 | ); |
ocomeni | 74:f26e846adfe9 | 963 | connection_params.setOwnAddressType(ble::own_address_type_t::RANDOM); |
ocomeni | 74:f26e846adfe9 | 964 | |
ocomeni | 74:f26e846adfe9 | 965 | error = _ble.gap().connect( |
ocomeni | 74:f26e846adfe9 | 966 | event.getPeerAddressType(), |
ocomeni | 74:f26e846adfe9 | 967 | event.getPeerAddress(), |
ocomeni | 74:f26e846adfe9 | 968 | connection_params |
ocomeni | 74:f26e846adfe9 | 969 | ); |
ocomeni | 74:f26e846adfe9 | 970 | |
ocomeni | 74:f26e846adfe9 | 971 | if (error) { |
ocomeni | 74:f26e846adfe9 | 972 | print_error(error, "Error caused by Gap::connect"); |
ocomeni | 74:f26e846adfe9 | 973 | return; |
ocomeni | 74:f26e846adfe9 | 974 | } |
ocomeni | 74:f26e846adfe9 | 975 | |
ocomeni | 74:f26e846adfe9 | 976 | /* we may have already scan events waiting |
ocomeni | 74:f26e846adfe9 | 977 | * to be processed so we need to remember |
ocomeni | 74:f26e846adfe9 | 978 | * that we are already connecting and ignore them */ |
ocomeni | 74:f26e846adfe9 | 979 | _is_connecting = true; |
ocomeni | 74:f26e846adfe9 | 980 | |
ocomeni | 74:f26e846adfe9 | 981 | return; |
ocomeni | 74:f26e846adfe9 | 982 | } |
ocomeni | 74:f26e846adfe9 | 983 | } |
ocomeni | 74:f26e846adfe9 | 984 | |
ocomeni | 74:f26e846adfe9 | 985 | /** This is called by Gap to notify the application we connected, |
ocomeni | 74:f26e846adfe9 | 986 | * in our case it immediately request pairing */ |
ocomeni | 75:08eff6258e1b | 987 | virtual void onConnectionComplete(const Gap::ConnectionCallbackParams_t &event) |
ocomeni | 74:f26e846adfe9 | 988 | { |
ocomeni | 74:f26e846adfe9 | 989 | if (event.getStatus() == BLE_ERROR_NONE) { |
ocomeni | 74:f26e846adfe9 | 990 | /* store the handle for future Security Manager requests */ |
ocomeni | 74:f26e846adfe9 | 991 | _handle = event.getConnectionHandle(); |
ocomeni | 74:f26e846adfe9 | 992 | |
ocomeni | 74:f26e846adfe9 | 993 | printf("Connected\r\n"); |
ocomeni | 74:f26e846adfe9 | 994 | |
ocomeni | 74:f26e846adfe9 | 995 | /* in this example the local device is the master so we request pairing */ |
ocomeni | 74:f26e846adfe9 | 996 | ble_error_t error = _ble.securityManager().requestPairing(_handle); |
ocomeni | 74:f26e846adfe9 | 997 | |
ocomeni | 74:f26e846adfe9 | 998 | if (error) { |
ocomeni | 74:f26e846adfe9 | 999 | printf("Error during SM::requestPairing %d\r\n", error); |
ocomeni | 74:f26e846adfe9 | 1000 | return; |
ocomeni | 74:f26e846adfe9 | 1001 | } |
ocomeni | 74:f26e846adfe9 | 1002 | |
ocomeni | 74:f26e846adfe9 | 1003 | /* upon pairing success the application will disconnect */ |
ocomeni | 74:f26e846adfe9 | 1004 | } |
ocomeni | 74:f26e846adfe9 | 1005 | |
ocomeni | 74:f26e846adfe9 | 1006 | /* failed to connect - restart scan */ |
ocomeni | 74:f26e846adfe9 | 1007 | ble_error_t error = _ble.gap().startScan(); |
ocomeni | 74:f26e846adfe9 | 1008 | |
ocomeni | 74:f26e846adfe9 | 1009 | if (error) { |
ocomeni | 74:f26e846adfe9 | 1010 | print_error(error, "Error in Gap::startScan %d\r\n"); |
ocomeni | 74:f26e846adfe9 | 1011 | return; |
ocomeni | 74:f26e846adfe9 | 1012 | } |
ocomeni | 74:f26e846adfe9 | 1013 | }; |
ocomeni | 74:f26e846adfe9 | 1014 | }; |
ocomeni | 74:f26e846adfe9 | 1015 | |
ocomeni | 74:f26e846adfe9 | 1016 | |
ocomeni | 74:f26e846adfe9 | 1017 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 74:f26e846adfe9 | 1018 | bool create_filesystem() |
ocomeni | 74:f26e846adfe9 | 1019 | { |
ocomeni | 74:f26e846adfe9 | 1020 | static LittleFileSystem fs("fs"); |
ocomeni | 74:f26e846adfe9 | 1021 | |
ocomeni | 74:f26e846adfe9 | 1022 | /* replace this with any physical block device your board supports (like an SD card) */ |
ocomeni | 74:f26e846adfe9 | 1023 | static HeapBlockDevice bd(4096, 256); |
ocomeni | 74:f26e846adfe9 | 1024 | |
ocomeni | 74:f26e846adfe9 | 1025 | int err = bd.init(); |
ocomeni | 74:f26e846adfe9 | 1026 | |
ocomeni | 74:f26e846adfe9 | 1027 | if (err) { |
ocomeni | 74:f26e846adfe9 | 1028 | return false; |
ocomeni | 74:f26e846adfe9 | 1029 | } |
ocomeni | 74:f26e846adfe9 | 1030 | |
ocomeni | 74:f26e846adfe9 | 1031 | err = bd.erase(0, bd.size()); |
ocomeni | 74:f26e846adfe9 | 1032 | |
ocomeni | 74:f26e846adfe9 | 1033 | if (err) { |
ocomeni | 74:f26e846adfe9 | 1034 | return false; |
ocomeni | 74:f26e846adfe9 | 1035 | } |
ocomeni | 74:f26e846adfe9 | 1036 | |
ocomeni | 74:f26e846adfe9 | 1037 | err = fs.mount(&bd); |
ocomeni | 74:f26e846adfe9 | 1038 | |
ocomeni | 74:f26e846adfe9 | 1039 | if (err) { |
ocomeni | 74:f26e846adfe9 | 1040 | /* Reformat if we can't mount the filesystem */ |
ocomeni | 74:f26e846adfe9 | 1041 | printf("No filesystem found, formatting...\r\n"); |
ocomeni | 74:f26e846adfe9 | 1042 | |
ocomeni | 74:f26e846adfe9 | 1043 | err = fs.reformat(&bd); |
ocomeni | 74:f26e846adfe9 | 1044 | |
ocomeni | 74:f26e846adfe9 | 1045 | if (err) { |
ocomeni | 74:f26e846adfe9 | 1046 | return false; |
ocomeni | 74:f26e846adfe9 | 1047 | } |
ocomeni | 74:f26e846adfe9 | 1048 | } |
ocomeni | 74:f26e846adfe9 | 1049 | |
ocomeni | 74:f26e846adfe9 | 1050 | return true; |
ocomeni | 74:f26e846adfe9 | 1051 | } |
ocomeni | 74:f26e846adfe9 | 1052 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 75:08eff6258e1b | 1053 | #ifdef BLE_MAIN |
ocomeni | 74:f26e846adfe9 | 1054 | int main() |
ocomeni | 74:f26e846adfe9 | 1055 | { |
ocomeni | 74:f26e846adfe9 | 1056 | BLE& ble = BLE::Instance(); |
ocomeni | 74:f26e846adfe9 | 1057 | events::EventQueue queue; |
ocomeni | 74:f26e846adfe9 | 1058 | |
ocomeni | 74:f26e846adfe9 | 1059 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
ocomeni | 74:f26e846adfe9 | 1060 | /* if filesystem creation fails or there is no filesystem the security manager |
ocomeni | 74:f26e846adfe9 | 1061 | * will fallback to storing the security database in memory */ |
ocomeni | 74:f26e846adfe9 | 1062 | if (!create_filesystem()) { |
ocomeni | 74:f26e846adfe9 | 1063 | printf("Filesystem creation failed, will use memory storage\r\n"); |
ocomeni | 74:f26e846adfe9 | 1064 | } |
ocomeni | 74:f26e846adfe9 | 1065 | #endif |
ocomeni | 74:f26e846adfe9 | 1066 | |
ocomeni | 74:f26e846adfe9 | 1067 | while(1) { |
ocomeni | 74:f26e846adfe9 | 1068 | { |
ocomeni | 74:f26e846adfe9 | 1069 | printf("\r\n PERIPHERAL \r\n\r\n"); |
ocomeni | 74:f26e846adfe9 | 1070 | SMDevicePeripheral peripheral(ble, queue, peer_address); |
ocomeni | 74:f26e846adfe9 | 1071 | peripheral.run(); |
ocomeni | 74:f26e846adfe9 | 1072 | } |
ocomeni | 74:f26e846adfe9 | 1073 | |
ocomeni | 74:f26e846adfe9 | 1074 | { |
ocomeni | 74:f26e846adfe9 | 1075 | printf("\r\n CENTRAL \r\n\r\n"); |
ocomeni | 74:f26e846adfe9 | 1076 | SMDeviceCentral central(ble, queue, peer_address); |
ocomeni | 74:f26e846adfe9 | 1077 | central.run(); |
ocomeni | 74:f26e846adfe9 | 1078 | } |
ocomeni | 74:f26e846adfe9 | 1079 | } |
ocomeni | 74:f26e846adfe9 | 1080 | |
ocomeni | 74:f26e846adfe9 | 1081 | return 0; |
ocomeni | 74:f26e846adfe9 | 1082 | } |
ocomeni | 74:f26e846adfe9 | 1083 | |
ocomeni | 75:08eff6258e1b | 1084 | #endif |
ocomeni | 75:08eff6258e1b | 1085 | |
ocomeni | 74:f26e846adfe9 | 1086 | #endif |