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 "pretty_printer.h" 00022 00023 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00024 #include "LittleFileSystem.h" 00025 #include "HeapBlockDevice.h" 00026 #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT 00027 00028 /** This example demonstrates all the basic setup required 00029 * for pairing and setting up link security both as a central and peripheral 00030 * 00031 * The example is implemented as two classes, one for the peripheral and one 00032 * for central inheriting from a common base. They are run in sequence and 00033 * require a peer device to connect to. During the peripheral device demonstration 00034 * a peer device is required to connect. In the central device demonstration 00035 * this peer device will be scanned for and connected to - therefore it should 00036 * be advertising with the same address as when it connected. 00037 * 00038 * During the test output is written on the serial connection to monitor its 00039 * progress. 00040 */ 00041 00042 static const char DEVICE_NAME[] = "SM_device"; 00043 00044 /* we have to specify the disconnect call because of ambiguous overloads */ 00045 typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); 00046 const static disconnect_call_t disconnect_call = &Gap::disconnect; 00047 00048 /* for demonstration purposes we will store the peer device address 00049 * of the device that connects to us in the first demonstration 00050 * so we can use its address to reconnect to it later */ 00051 static BLEProtocol::AddressBytes_t peer_address; 00052 00053 /** Base class for both peripheral and central. The same class that provides 00054 * the logic for the application also implements the SecurityManagerEventHandler 00055 * which is the interface used by the Security Manager to communicate events 00056 * back to the applications. You can provide overrides for a selection of events 00057 * your application is interested in. 00058 */ 00059 class SMDevice : private mbed::NonCopyable<SMDevice>, 00060 public SecurityManager::EventHandler, 00061 public ble::Gap::EventHandler 00062 { 00063 public: 00064 SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) : 00065 _led1(LED1, 0), 00066 _ble(ble), 00067 _event_queue(event_queue), 00068 _peer_address(peer_address), 00069 _handle(0), 00070 _is_connecting(false) { }; 00071 00072 virtual ~SMDevice() 00073 { 00074 if (_ble.hasInitialized()) { 00075 _ble.shutdown(); 00076 } 00077 }; 00078 00079 /** Start BLE interface initialisation */ 00080 void run() 00081 { 00082 ble_error_t error; 00083 00084 /* to show we're running we'll blink every 500ms */ 00085 _event_queue.call_every(500, this, &SMDevice::blink); 00086 00087 if (_ble.hasInitialized()) { 00088 printf("Ble instance already initialised.\r\n"); 00089 return; 00090 } 00091 00092 /* this will inform us off all events so we can schedule their handling 00093 * using our event queue */ 00094 _ble.onEventsToProcess( 00095 makeFunctionPointer(this, &SMDevice::schedule_ble_events) 00096 ); 00097 00098 /* handle gap events */ 00099 _ble.gap().setEventHandler(this); 00100 00101 error = _ble.init(this, &SMDevice::on_init_complete); 00102 00103 if (error) { 00104 printf("Error returned by BLE::init.\r\n"); 00105 return; 00106 } 00107 00108 /* this will not return until shutdown */ 00109 _event_queue.dispatch_forever(); 00110 }; 00111 00112 private: 00113 /** Override to start chosen activity when initialisation completes */ 00114 virtual void start() = 0; 00115 00116 /** This is called when BLE interface is initialised and starts the demonstration */ 00117 void on_init_complete(BLE::InitializationCompleteCallbackContext *event) 00118 { 00119 ble_error_t error; 00120 00121 if (event->error) { 00122 printf("Error during the initialisation\r\n"); 00123 return; 00124 } 00125 00126 /* This path will be used to store bonding information but will fallback 00127 * to storing in memory if file access fails (for example due to lack of a filesystem) */ 00128 const char* db_path = "/fs/bt_sec_db"; 00129 /* If the security manager is required this needs to be called before any 00130 * calls to the Security manager happen. */ 00131 error = _ble.securityManager().init( 00132 true, 00133 false, 00134 SecurityManager::IO_CAPS_NONE, 00135 NULL, 00136 false, 00137 db_path 00138 ); 00139 00140 if (error) { 00141 printf("Error during init %d\r\n", error); 00142 return; 00143 } 00144 00145 error = _ble.securityManager().preserveBondingStateOnReset(true); 00146 00147 if (error) { 00148 printf("Error during preserveBondingStateOnReset %d\r\n", error); 00149 } 00150 00151 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00152 /* Enable privacy so we can find the keys */ 00153 error = _ble.gap().enablePrivacy(true); 00154 00155 if (error) { 00156 printf("Error enabling privacy\r\n"); 00157 } 00158 00159 Gap::PeripheralPrivacyConfiguration_t configuration_p = { 00160 /* use_non_resolvable_random_address */ false, 00161 Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS 00162 }; 00163 _ble.gap().setPeripheralPrivacyConfiguration(&configuration_p); 00164 00165 Gap::CentralPrivacyConfiguration_t configuration_c = { 00166 /* use_non_resolvable_random_address */ false, 00167 Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD 00168 }; 00169 _ble.gap().setCentralPrivacyConfiguration(&configuration_c); 00170 00171 /* this demo switches between being master and slave */ 00172 _ble.securityManager().setHintFutureRoleReversal(true); 00173 #endif 00174 00175 /* Tell the security manager to use methods in this class to inform us 00176 * of any events. Class needs to implement SecurityManagerEventHandler. */ 00177 _ble.securityManager().setSecurityManagerEventHandler(this); 00178 00179 /* gap events also handled by this class */ 00180 _ble.gap().setEventHandler(this); 00181 00182 /* print device address */ 00183 Gap::AddressType_t addr_type; 00184 Gap::Address_t addr; 00185 _ble.gap().getAddress(&addr_type, addr); 00186 print_address(addr); 00187 00188 /* start test in 500 ms */ 00189 _event_queue.call_in(500, this, &SMDevice::start); 00190 }; 00191 00192 /** Schedule processing of events from the BLE in the event queue. */ 00193 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) 00194 { 00195 _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents)); 00196 }; 00197 00198 /** Blink LED to show we're running */ 00199 void blink(void) 00200 { 00201 _led1 = !_led1; 00202 }; 00203 00204 private: 00205 /* Event handler */ 00206 00207 /** Respond to a pairing request. This will be called by the stack 00208 * when a pairing request arrives and expects the application to 00209 * call acceptPairingRequest or cancelPairingRequest */ 00210 virtual void pairingRequest( 00211 ble::connection_handle_t connectionHandle 00212 ) { 00213 printf("Pairing requested - authorising\r\n"); 00214 _ble.securityManager().acceptPairingRequest(connectionHandle); 00215 } 00216 00217 /** Inform the application of a successful pairing. Terminate the demonstration. */ 00218 virtual void pairingResult( 00219 ble::connection_handle_t connectionHandle, 00220 SecurityManager::SecurityCompletionStatus_t result 00221 ) { 00222 if (result == SecurityManager::SEC_STATUS_SUCCESS) { 00223 printf("Pairing successful\r\n"); 00224 } else { 00225 printf("Pairing failed\r\n"); 00226 } 00227 } 00228 00229 /** Inform the application of change in encryption status. This will be 00230 * communicated through the serial port */ 00231 virtual void linkEncryptionResult( 00232 ble::connection_handle_t connectionHandle, 00233 ble::link_encryption_t result 00234 ) { 00235 if (result == ble::link_encryption_t::ENCRYPTED) { 00236 printf("Link ENCRYPTED\r\n"); 00237 } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { 00238 printf("Link ENCRYPTED_WITH_MITM\r\n"); 00239 } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) { 00240 printf("Link NOT_ENCRYPTED\r\n"); 00241 } 00242 00243 /* disconnect in 2 s */ 00244 _event_queue.call_in( 00245 2000, 00246 &_ble.gap(), 00247 disconnect_call, 00248 _handle, 00249 ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) 00250 ); 00251 } 00252 00253 /** This is called by Gap to notify the application we disconnected, 00254 * in our case it ends the demonstration. */ 00255 virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &) 00256 { 00257 printf("Diconnected\r\n"); 00258 _event_queue.break_dispatch(); 00259 }; 00260 00261 virtual void onAdvertisingEnd(const ble::AdvertisingEndEvent &) 00262 { 00263 printf("Advertising timed out - aborting\r\n"); 00264 _event_queue.break_dispatch(); 00265 } 00266 00267 virtual void onScanTimeout(const ble::ScanTimeoutEvent &) 00268 { 00269 printf("Scan timed out - aborting\r\n"); 00270 _event_queue.break_dispatch(); 00271 } 00272 00273 private: 00274 DigitalOut _led1; 00275 00276 protected: 00277 BLE &_ble; 00278 events::EventQueue &_event_queue; 00279 BLEProtocol::AddressBytes_t &_peer_address; 00280 ble::connection_handle_t _handle; 00281 bool _is_connecting; 00282 }; 00283 00284 /** A peripheral device will advertise, accept the connection and request 00285 * a change in link security. */ 00286 class SMDevicePeripheral : public SMDevice { 00287 public: 00288 SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) 00289 : SMDevice(ble, event_queue, peer_address) { } 00290 00291 virtual void start() 00292 { 00293 /* Set up and start advertising */ 00294 uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; 00295 /* use the helper to build the payload */ 00296 ble::AdvertisingDataBuilder adv_data_builder( 00297 adv_buffer 00298 ); 00299 00300 adv_data_builder.setFlags(); 00301 adv_data_builder.setName(DEVICE_NAME); 00302 00303 /* Set payload for the set */ 00304 ble_error_t error = _ble.gap().setAdvertisingPayload( 00305 ble::LEGACY_ADVERTISING_HANDLE, 00306 adv_data_builder.getAdvertisingData() 00307 ); 00308 00309 if (error) { 00310 print_error(error, "Gap::setAdvertisingPayload() failed"); 00311 _event_queue.break_dispatch(); 00312 return; 00313 } 00314 00315 ble::AdvertisingParameters adv_parameters( 00316 ble::advertising_type_t::CONNECTABLE_UNDIRECTED 00317 ); 00318 00319 error = _ble.gap().setAdvertisingParameters( 00320 ble::LEGACY_ADVERTISING_HANDLE, 00321 adv_parameters 00322 ); 00323 00324 if (error) { 00325 print_error(error, "Gap::setAdvertisingParameters() failed"); 00326 return; 00327 } 00328 00329 error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); 00330 00331 if (error) { 00332 print_error(error, "Gap::startAdvertising() failed"); 00333 return; 00334 } 00335 00336 printf("Please connect to device\r\n"); 00337 00338 /** This tells the stack to generate a pairingRequest event 00339 * which will require this application to respond before pairing 00340 * can proceed. Setting it to false will automatically accept 00341 * pairing. */ 00342 _ble.securityManager().setPairingRequestAuthorisation(true); 00343 }; 00344 00345 /** This is called by Gap to notify the application we connected, 00346 * in our case it immediately requests a change in link security */ 00347 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) 00348 { 00349 ble_error_t error; 00350 00351 /* remember the device that connects to us now so we can connect to it 00352 * during the next demonstration */ 00353 memcpy(_peer_address, event.getPeerAddress().data(), sizeof(_peer_address)); 00354 00355 printf("Connected to peer: "); 00356 print_address(event.getPeerAddress().data()); 00357 00358 _handle = event.getConnectionHandle(); 00359 00360 /* Request a change in link security. This will be done 00361 * indirectly by asking the master of the connection to 00362 * change it. Depending on circumstances different actions 00363 * may be taken by the master which will trigger events 00364 * which the applications should deal with. */ 00365 error = _ble.securityManager().setLinkSecurity( 00366 _handle, 00367 SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM 00368 ); 00369 00370 if (error) { 00371 printf("Error during SM::setLinkSecurity %d\r\n", error); 00372 return; 00373 } 00374 }; 00375 }; 00376 00377 /** A central device will scan, connect to a peer and request pairing. */ 00378 class SMDeviceCentral : public SMDevice { 00379 public: 00380 SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) 00381 : SMDevice(ble, event_queue, peer_address) { } 00382 00383 virtual void start() 00384 { 00385 ble::ScanParameters params; 00386 ble_error_t error = _ble.gap().setScanParameters(params); 00387 00388 if (error) { 00389 print_error(error, "Error in Gap::startScan %d\r\n"); 00390 return; 00391 } 00392 00393 /* start scanning, results will be handled by onAdvertisingReport */ 00394 error = _ble.gap().startScan(); 00395 00396 if (error) { 00397 print_error(error, "Error in Gap::startScan %d\r\n"); 00398 return; 00399 } 00400 00401 printf("Please advertise\r\n"); 00402 00403 printf("Scanning for: "); 00404 print_address(_peer_address); 00405 } 00406 00407 private: 00408 /* Gap::EventHandler */ 00409 00410 /** Look at scan payload to find a peer device and connect to it */ 00411 virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event) 00412 { 00413 /* don't bother with analysing scan result if we're already connecting */ 00414 if (_is_connecting) { 00415 return; 00416 } 00417 printf("found someone "); 00418 printf("%02x:%02x:%02x:%02x:%02x:%02x\r\n", 00419 event.getPeerAddress().data()[5], event.getPeerAddress().data()[4], event.getPeerAddress().data()[3], event.getPeerAddress().data()[2], event.getPeerAddress().data()[1], event.getPeerAddress().data()[0]); 00420 /* parse the advertising payload, looking for a discoverable device */ 00421 if (memcmp(event.getPeerAddress().data(), _peer_address, sizeof(_peer_address)) == 0) { 00422 ble_error_t error = _ble.gap().stopScan(); 00423 00424 if (error) { 00425 print_error(error, "Error caused by Gap::stopScan"); 00426 return; 00427 } 00428 00429 ble::ConnectionParameters connection_params( 00430 ble::phy_t::LE_1M, 00431 ble::scan_interval_t(50), 00432 ble::scan_window_t(50), 00433 ble::conn_interval_t(50), 00434 ble::conn_interval_t(100), 00435 ble::slave_latency_t(0), 00436 ble::supervision_timeout_t(100) 00437 ); 00438 connection_params.setOwnAddressType(ble::own_address_type_t::RANDOM); 00439 00440 error = _ble.gap().connect( 00441 event.getPeerAddressType(), 00442 event.getPeerAddress(), 00443 connection_params 00444 ); 00445 00446 if (error) { 00447 print_error(error, "Error caused by Gap::connect"); 00448 return; 00449 } 00450 00451 /* we may have already scan events waiting 00452 * to be processed so we need to remember 00453 * that we are already connecting and ignore them */ 00454 _is_connecting = true; 00455 00456 return; 00457 } 00458 } 00459 00460 /** This is called by Gap to notify the application we connected, 00461 * in our case it immediately request pairing */ 00462 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) 00463 { 00464 if (event.getStatus() == BLE_ERROR_NONE) { 00465 /* store the handle for future Security Manager requests */ 00466 _handle = event.getConnectionHandle(); 00467 00468 printf("Connected\r\n"); 00469 00470 /* in this example the local device is the master so we request pairing */ 00471 ble_error_t error = _ble.securityManager().requestPairing(_handle); 00472 00473 if (error) { 00474 printf("Error during SM::requestPairing %d\r\n", error); 00475 return; 00476 } 00477 00478 /* upon pairing success the application will disconnect */ 00479 } 00480 00481 /* failed to connect - restart scan */ 00482 ble_error_t error = _ble.gap().startScan(); 00483 00484 if (error) { 00485 print_error(error, "Error in Gap::startScan %d\r\n"); 00486 return; 00487 } 00488 }; 00489 }; 00490 00491 00492 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00493 bool create_filesystem() 00494 { 00495 static LittleFileSystem fs("fs"); 00496 00497 /* replace this with any physical block device your board supports (like an SD card) */ 00498 static HeapBlockDevice bd(4096, 256); 00499 00500 int err = bd.init(); 00501 00502 if (err) { 00503 return false; 00504 } 00505 00506 err = bd.erase(0, bd.size()); 00507 00508 if (err) { 00509 return false; 00510 } 00511 00512 err = fs.mount(&bd); 00513 00514 if (err) { 00515 /* Reformat if we can't mount the filesystem */ 00516 printf("No filesystem found, formatting...\r\n"); 00517 00518 err = fs.reformat(&bd); 00519 00520 if (err) { 00521 return false; 00522 } 00523 } 00524 00525 return true; 00526 } 00527 #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT 00528 00529 int main() 00530 { 00531 BLE& ble = BLE::Instance(); 00532 events::EventQueue queue; 00533 00534 #if MBED_CONF_APP_FILESYSTEM_SUPPORT 00535 /* if filesystem creation fails or there is no filesystem the security manager 00536 * will fallback to storing the security database in memory */ 00537 if (!create_filesystem()) { 00538 printf("Filesystem creation failed, will use memory storage\r\n"); 00539 } 00540 #endif 00541 00542 while(1) { 00543 // { 00544 // printf("\r\n PERIPHERAL \r\n\r\n"); 00545 // SMDevicePeripheral peripheral(ble, queue, peer_address); 00546 // peripheral.run(); 00547 // } 00548 00549 { 00550 printf("\r\n CENTRAL \r\n\r\n"); 00551 SMDeviceCentral central(ble, queue, peer_address); 00552 central.run(); 00553 } 00554 } 00555 00556 return 0; 00557 }
Generated on Wed Jul 13 2022 05:14:54 by
