Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include <events/mbed_events.h> 00018 #include <mbed.h> 00019 #include "ble/BLE.h" 00020 #include "SecurityManager.h" 00021 #include <algorithm> 00022 #include "pretty_printer.h" 00023 #include "ble/gap/AdvertisingDataParser.h" 00024 00025 /** This example demonstrates privacy features in Gap. It shows how to use 00026 * private addresses when advertising and connecting and how filtering ties 00027 * in with these operations. 00028 * 00029 * The application will start by repeatedly trying to connect to the same 00030 * application running on another board. It will do this by advertising and 00031 * scanning for random intervals waiting until the difference in intervals 00032 * between the boards will make them meet when one is advertising and the 00033 * other scanning. 00034 * 00035 * Two devices will be operating using random resolvable addresses. The 00036 * applications will connect to the peer and pair. It will attempt bonding 00037 * to store the IRK that resolve the peer. Subsequent connections will 00038 * turn on filtering based on stored IRKs. 00039 */ 00040 00041 static const char DEVICE_NAME[] = "Privacy"; 00042 00043 /* we have to specify the disconnect call because of ambiguous overloads */ 00044 typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); 00045 const static disconnect_call_t disconnect_call = &Gap::disconnect; 00046 00047 /** Base class for both peripheral and central. The same class that provides 00048 * the logic for the application also implements the SecurityManagerEventHandler 00049 * which is the interface used by the Security Manager to communicate events 00050 * back to the applications. You can provide overrides for a selection of events 00051 * your application is interested in. 00052 */ 00053 class PrivacyDevice : private mbed::NonCopyable<PrivacyDevice>, 00054 public SecurityManager::EventHandler, 00055 public ble::Gap::EventHandler 00056 { 00057 public: 00058 PrivacyDevice(BLE &ble, events::EventQueue &event_queue) : 00059 _ble(ble), 00060 _event_queue(event_queue), 00061 _handle(0), 00062 _bonded(false), 00063 _led1(LED1, 0) { }; 00064 00065 virtual ~PrivacyDevice() { 00066 _ble.onEventsToProcess(NULL); 00067 }; 00068 00069 /** Start BLE interface initialisation */ 00070 void run() 00071 { 00072 /* to show we're running we'll blink every 500ms */ 00073 _event_queue.call_every(500, this, &PrivacyDevice::blink); 00074 00075 /* this will inform us off all events so we can schedule their handling 00076 * using our event queue */ 00077 _ble.onEventsToProcess( 00078 makeFunctionPointer(this, &PrivacyDevice::schedule_ble_events) 00079 ); 00080 00081 /* handle gap events */ 00082 _ble.gap().setEventHandler(this); 00083 00084 if (_ble.hasInitialized()) { 00085 /* ble instance already initialised, skip init and start activity */ 00086 start(); 00087 } else { 00088 ble_error_t error = _ble.init(this, &PrivacyDevice::on_init_complete); 00089 00090 if (error) { 00091 printf("Error returned by BLE::init.\r\n"); 00092 return; 00093 } 00094 } 00095 00096 /* this will not return until shutdown */ 00097 _event_queue.dispatch_forever(); 00098 }; 00099 00100 /** Override to start chosen activity when initialisation completes */ 00101 virtual void start() = 0; 00102 00103 /** Override to start chosen activity after initial bonding */ 00104 virtual void start_after_bonding() = 0; 00105 00106 /* callbacks */ 00107 00108 /** This is called when BLE interface is initialised and starts the demonstration */ 00109 void on_init_complete(BLE::InitializationCompleteCallbackContext *event) 00110 { 00111 ble_error_t error; 00112 00113 if (event->error) { 00114 printf("Error during the initialisation\r\n"); 00115 _event_queue.break_dispatch(); 00116 return; 00117 } 00118 00119 /* for use by tools we print out own address and also use it 00120 * to seed RNG as the address is unique */ 00121 print_local_address(); 00122 00123 /* Privacy requires the security manager */ 00124 00125 error = _ble.securityManager().init( 00126 /* enableBonding */ true, 00127 /* requireMITM */ false, 00128 /* iocaps */ SecurityManager::IO_CAPS_NONE, 00129 /* passkey */ NULL, 00130 /* signing */ false, 00131 /* dbFilepath */ NULL 00132 ); 00133 00134 if (error) { 00135 printf("Error during security manager initialisation\r\n"); 00136 _event_queue.break_dispatch(); 00137 return; 00138 } 00139 00140 /* Tell the security manager to use methods in this class to inform us 00141 * of any events. Class needs to implement SecurityManagerEventHandler. */ 00142 _ble.securityManager().setSecurityManagerEventHandler(this); 00143 00144 /* gap events also handled by this class */ 00145 _ble.gap().setEventHandler(this); 00146 00147 /* privacy */ 00148 00149 error = _ble.gap().enablePrivacy(true); 00150 00151 if (error) { 00152 printf("Error enabling privacy.\r\n"); 00153 _event_queue.break_dispatch(); 00154 return; 00155 } 00156 00157 start(); 00158 }; 00159 00160 /** Schedule processing of events from the BLE in the event queue. */ 00161 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 00162 { 00163 _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents)); 00164 }; 00165 00166 /** Blink LED to show we're running */ 00167 void blink(void) 00168 { 00169 _led1 = !_led1; 00170 }; 00171 00172 void print_local_address() 00173 { 00174 /* show what address we are using now */ 00175 Gap::AddressType_t addr_type; 00176 Gap::Address_t addr; 00177 _ble.gap().getAddress(&addr_type, addr); 00178 printf("Device address: "); 00179 print_address(addr); 00180 00181 if (!_seeded) { 00182 _seeded = true; 00183 /* use the address as a seed */ 00184 uint8_t* random_data = addr; 00185 srand(*((unsigned int*)random_data)); 00186 } 00187 } 00188 00189 private: 00190 /* Event handler */ 00191 00192 /** Inform the application of pairing */ 00193 virtual void pairingResult( 00194 ble::connection_handle_t connectionHandle, 00195 SecurityManager::SecurityCompletionStatus_t result 00196 ) { 00197 if (result == SecurityManager::SEC_STATUS_SUCCESS) { 00198 printf("Pairing successful\r\n"); 00199 _bonded = true; 00200 } else { 00201 printf("Pairing failed\r\n"); 00202 } 00203 00204 /* disconnect in 2s */ 00205 _event_queue.call_in( 00206 2000, 00207 &_ble.gap(), 00208 disconnect_call, 00209 connectionHandle, 00210 ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) 00211 ); 00212 } 00213 00214 /** This is called by Gap to notify the application we connected */ 00215 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) 00216 { 00217 printf("Connected to peer: "); 00218 print_address(event.getPeerAddress().data()); 00219 printf("Peer random resolvable address: "); 00220 print_address(event.getPeerResolvablePrivateAddress().data()); 00221 00222 _handle = event.getConnectionHandle(); 00223 00224 if (_bonded) { 00225 /* disconnect in 2s */ 00226 _event_queue.call_in( 00227 2000, 00228 &_ble.gap(), 00229 disconnect_call, 00230 _handle, 00231 ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) 00232 ); 00233 } 00234 }; 00235 00236 /** This is called by Gap to notify the application we disconnected */ 00237 virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) 00238 { 00239 if (_bonded) { 00240 /* we have connected to and bonded with the other device, from now 00241 * on we will use the second start function and stay in the same role 00242 * as peripheral or central */ 00243 printf("Disconnected.\r\n"); 00244 _event_queue.call_in(2000, this, &PrivacyDevice::start_after_bonding); 00245 } else { 00246 printf("Failed to bond.\r\n"); 00247 _event_queue.break_dispatch(); 00248 } 00249 }; 00250 00251 virtual void onScanTimeout(const ble::ScanTimeoutEvent &) 00252 { 00253 /* if we failed to find the other device, abort so that we change roles */ 00254 printf("Haven't seen other device, switch modes.\r\n"); 00255 _event_queue.break_dispatch(); 00256 } 00257 00258 public: 00259 static bool _seeded; 00260 00261 protected: 00262 BLE &_ble; 00263 events::EventQueue &_event_queue; 00264 ble::connection_handle_t _handle; 00265 bool _bonded; 00266 00267 private: 00268 DigitalOut _led1; 00269 }; 00270 00271 /** A peripheral device will advertise and accept the connections */ 00272 class PrivacyPeripheral : public PrivacyDevice { 00273 public: 00274 PrivacyPeripheral(BLE &ble, events::EventQueue &event_queue) 00275 : PrivacyDevice(ble, event_queue) { } 00276 00277 /** Set up and start advertising accepting anyone */ 00278 virtual void start() 00279 { 00280 if (!set_advertising_data()) { 00281 return; 00282 } 00283 00284 Gap::PeripheralPrivacyConfiguration_t privacy_configuration = { 00285 /* use_non_resolvable_random_address */ false, 00286 Gap::PeripheralPrivacyConfiguration_t::PERFORM_PAIRING_PROCEDURE 00287 }; 00288 00289 _ble.gap().setPeripheralPrivacyConfiguration(&privacy_configuration); 00290 00291 start_advertising(); 00292 }; 00293 00294 /** advertise and filter based on known devices */ 00295 virtual void start_after_bonding() 00296 { 00297 Gap::PeripheralPrivacyConfiguration_t privacy_configuration = { 00298 /* use_non_resolvable_random_address */ false, 00299 Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS 00300 }; 00301 00302 _ble.gap().setPeripheralPrivacyConfiguration(&privacy_configuration); 00303 00304 start_advertising(); 00305 } 00306 00307 /* helper functions */ 00308 00309 private: 00310 bool set_advertising_data() 00311 { 00312 uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 00313 /* use the helper to build the payload */ 00314 ble::AdvertisingDataBuilder adv_data_builder( 00315 adv_buffer 00316 ); 00317 00318 adv_data_builder.setFlags(); 00319 adv_data_builder.setName(DEVICE_NAME); 00320 00321 /* Set payload for the set */ 00322 ble_error_t error = _ble.gap().setAdvertisingPayload( 00323 ble::LEGACY_ADVERTISING_HANDLE, 00324 adv_data_builder.getAdvertisingData() 00325 ); 00326 00327 if (error) { 00328 print_error(error, "Gap::setAdvertisingPayload() failed"); 00329 _event_queue.break_dispatch(); 00330 return false; 00331 } 00332 00333 return true; 00334 } 00335 00336 bool start_advertising() 00337 { 00338 ble::AdvertisingParameters adv_parameters( 00339 ble::advertising_type_t::CONNECTABLE_UNDIRECTED 00340 ); 00341 00342 ble_error_t error = _ble.gap().setAdvertisingParameters( 00343 ble::LEGACY_ADVERTISING_HANDLE, 00344 adv_parameters 00345 ); 00346 00347 if (error) { 00348 print_error(error, "Gap::setAdvertisingParameters() failed"); 00349 return false; 00350 } 00351 00352 if (_bonded) { 00353 /* if we bonded it means we have found the other device, from now on 00354 * wait at each step until completion */ 00355 error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 00356 } else { 00357 /* since we have two boards which might start running this example at the same time 00358 * we randomise the interval of advertising to have them meet when one is advertising 00359 * and the other one is scanning (we use their random address as source of randomness) */ 00360 ble::millisecond_t random_duration_ms((1 + rand() % 5) * 1000); 00361 ble::adv_duration_t random_duration(random_duration_ms); 00362 error = _ble.gap().startAdvertising( 00363 ble::LEGACY_ADVERTISING_HANDLE, 00364 random_duration 00365 ); 00366 } 00367 00368 if (error) { 00369 print_error(error, "Gap::startAdvertising() failed"); 00370 _event_queue.break_dispatch(); 00371 return false; 00372 } 00373 00374 printf("Advertising...\r\n"); 00375 00376 return true; 00377 } 00378 00379 }; 00380 00381 /** A central device will scan and connect to a peer. */ 00382 class PrivacyCentral : public PrivacyDevice { 00383 public: 00384 PrivacyCentral(BLE &ble, events::EventQueue &event_queue) 00385 : PrivacyDevice(ble, event_queue), 00386 _is_connecting(false) { } 00387 00388 /** start scanning and attach a callback that will handle advertisements 00389 * and scan requests responses */ 00390 virtual void start() 00391 { 00392 Gap::CentralPrivacyConfiguration_t privacy_configuration = { 00393 /* use_non_resolvable_random_address */ false, 00394 Gap::CentralPrivacyConfiguration_t::DO_NOT_RESOLVE 00395 }; 00396 00397 _ble.gap().setCentralPrivacyConfiguration(&privacy_configuration); 00398 00399 start_scanning(); 00400 } 00401 00402 virtual void start_after_bonding() 00403 { 00404 Gap::CentralPrivacyConfiguration_t privacy_configuration = { 00405 /* use_non_resolvable_random_address */ false, 00406 Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FILTER 00407 }; 00408 00409 _ble.gap().setCentralPrivacyConfiguration(&privacy_configuration); 00410 00411 start_scanning(); 00412 } 00413 00414 /* helper functions */ 00415 private: 00416 bool start_scanning() { 00417 ble_error_t error; 00418 ble::ScanParameters scan_params; 00419 _ble.gap().setScanParameters(scan_params); 00420 00421 _is_connecting = false; 00422 00423 if (_bonded) { 00424 /* if we bonded it means we have found the other device, from now on 00425 * wait at each step until completion */ 00426 error = _ble.gap().startScan(ble::scan_duration_t::forever()); 00427 } else { 00428 /* otherwise only scan for a limited time before changing roles again 00429 * if we fail to find the other device */ 00430 error = _ble.gap().startScan( 00431 ble::scan_duration_t(ble::millisecond_t(4000)) 00432 ); 00433 } 00434 00435 if (error) { 00436 printf("Error during Gap::startScan %d\r\n", error); 00437 _event_queue.break_dispatch(); 00438 return false; 00439 } 00440 00441 printf("Scanning...\r\n"); 00442 00443 return true; 00444 } 00445 00446 private: 00447 /* Event handler */ 00448 00449 /** Look at scan payload to find a peer device and connect to it */ 00450 virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event) 00451 { 00452 /* don't bother with analysing scan result if we're already connecting */ 00453 if (_is_connecting) { 00454 return; 00455 } 00456 00457 ble::AdvertisingDataParser adv_data(event.getPayload()); 00458 00459 /* parse the advertising payload, looking for a discoverable device */ 00460 while (adv_data.hasNext()) { 00461 ble::AdvertisingDataParser::element_t field = adv_data.next(); 00462 00463 /* connect to a known device by name */ 00464 if (field.type == ble::adv_data_type_t::COMPLETE_LOCAL_NAME && 00465 field.value.size() == strlen(DEVICE_NAME) && 00466 (memcmp(field.value.data(), DEVICE_NAME, field.value.size()) == 0)) { 00467 00468 printf("We found a connectable device\r\n"); 00469 00470 ble_error_t error = _ble.gap().stopScan(); 00471 00472 if (error) { 00473 print_error(error, "Error caused by Gap::stopScan"); 00474 return; 00475 } 00476 00477 const ble::ConnectionParameters connection_params; 00478 00479 error = _ble.gap().connect( 00480 event.getPeerAddressType(), 00481 event.getPeerAddress(), 00482 connection_params 00483 ); 00484 00485 if (error) { 00486 print_error(error, "Error caused by Gap::connect"); 00487 return; 00488 } 00489 00490 /* we may have already scan events waiting 00491 * to be processed so we need to remember 00492 * that we are already connecting and ignore them */ 00493 _is_connecting = true; 00494 00495 return; 00496 00497 } 00498 } 00499 } 00500 00501 private: 00502 bool _is_connecting; 00503 }; 00504 00505 /* only seed the random number generation once per application run */ 00506 bool PrivacyDevice::_seeded = false; 00507 00508 int main() 00509 { 00510 BLE& ble = BLE::Instance(); 00511 00512 while(1) { 00513 { 00514 events::EventQueue queue; 00515 printf("\r\n * Device is a peripheral *\r\n\r\n"); 00516 PrivacyPeripheral peripheral(ble, queue); 00517 peripheral.run(); 00518 } 00519 { 00520 events::EventQueue queue; 00521 printf("\r\n * Device is a central *\r\n\r\n"); 00522 PrivacyCentral central(ble, queue); 00523 central.run(); 00524 } 00525 } 00526 00527 return 0; 00528 }
Generated on Sat Jul 16 2022 20:51:17 by
1.7.2