this is using the mbed os version 5-13-1
Diff: source/BleManager.cpp
- Revision:
- 74:f26e846adfe9
- Child:
- 75:08eff6258e1b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/source/BleManager.cpp Sun Mar 10 09:46:06 2019 +0000
@@ -0,0 +1,557 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifdef BLE_SECURITY_ENABLED
+#include <events/mbed_events.h>
+#include <mbed.h>
+#include "ble/BLE.h"
+#include "SecurityManager.h"
+#include "pretty_printer.h"
+
+#if MBED_CONF_APP_FILESYSTEM_SUPPORT
+#include "LittleFileSystem.h"
+#include "HeapBlockDevice.h"
+#endif //MBED_CONF_APP_FILESYSTEM_SUPPORT
+
+/** This example demonstrates all the basic setup required
+ * for pairing and setting up link security both as a central and peripheral
+ *
+ * The example is implemented as two classes, one for the peripheral and one
+ * for central inheriting from a common base. They are run in sequence and
+ * require a peer device to connect to. During the peripheral device demonstration
+ * a peer device is required to connect. In the central device demonstration
+ * this peer device will be scanned for and connected to - therefore it should
+ * be advertising with the same address as when it connected.
+ *
+ * During the test output is written on the serial connection to monitor its
+ * progress.
+ */
+
+static const char DEVICE_NAME[] = "SM_device";
+
+/* we have to specify the disconnect call because of ambiguous overloads */
+typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t);
+const static disconnect_call_t disconnect_call = &Gap::disconnect;
+
+/* for demonstration purposes we will store the peer device address
+ * of the device that connects to us in the first demonstration
+ * so we can use its address to reconnect to it later */
+static BLEProtocol::AddressBytes_t peer_address;
+
+/** Base class for both peripheral and central. The same class that provides
+ * the logic for the application also implements the SecurityManagerEventHandler
+ * which is the interface used by the Security Manager to communicate events
+ * back to the applications. You can provide overrides for a selection of events
+ * your application is interested in.
+ */
+class SMDevice : private mbed::NonCopyable<SMDevice>,
+ public SecurityManager::EventHandler,
+ public ble::Gap::EventHandler
+{
+public:
+ SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) :
+ _led1(LED1, 0),
+ _ble(ble),
+ _event_queue(event_queue),
+ _peer_address(peer_address),
+ _handle(0),
+ _is_connecting(false) { };
+
+ virtual ~SMDevice()
+ {
+ if (_ble.hasInitialized()) {
+ _ble.shutdown();
+ }
+ };
+
+ /** Start BLE interface initialisation */
+ void run()
+ {
+ ble_error_t error;
+
+ /* to show we're running we'll blink every 500ms */
+ _event_queue.call_every(500, this, &SMDevice::blink);
+
+ if (_ble.hasInitialized()) {
+ printf("Ble instance already initialised.\r\n");
+ return;
+ }
+
+ /* this will inform us off all events so we can schedule their handling
+ * using our event queue */
+ _ble.onEventsToProcess(
+ makeFunctionPointer(this, &SMDevice::schedule_ble_events)
+ );
+
+ /* handle gap events */
+ _ble.gap().setEventHandler(this);
+
+ error = _ble.init(this, &SMDevice::on_init_complete);
+
+ if (error) {
+ printf("Error returned by BLE::init.\r\n");
+ return;
+ }
+
+ /* this will not return until shutdown */
+ _event_queue.dispatch_forever();
+ };
+
+private:
+ /** Override to start chosen activity when initialisation completes */
+ virtual void start() = 0;
+
+ /** This is called when BLE interface is initialised and starts the demonstration */
+ void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
+ {
+ ble_error_t error;
+
+ if (event->error) {
+ printf("Error during the initialisation\r\n");
+ return;
+ }
+
+ /* This path will be used to store bonding information but will fallback
+ * to storing in memory if file access fails (for example due to lack of a filesystem) */
+ const char* db_path = "/fs/bt_sec_db";
+ /* If the security manager is required this needs to be called before any
+ * calls to the Security manager happen. */
+ error = _ble.securityManager().init(
+ true,
+ false,
+ SecurityManager::IO_CAPS_NONE,
+ NULL,
+ false,
+ db_path
+ );
+
+ if (error) {
+ printf("Error during init %d\r\n", error);
+ return;
+ }
+
+ error = _ble.securityManager().preserveBondingStateOnReset(true);
+
+ if (error) {
+ printf("Error during preserveBondingStateOnReset %d\r\n", error);
+ }
+
+#if MBED_CONF_APP_FILESYSTEM_SUPPORT
+ /* Enable privacy so we can find the keys */
+ error = _ble.gap().enablePrivacy(true);
+
+ if (error) {
+ printf("Error enabling privacy\r\n");
+ }
+
+ Gap::PeripheralPrivacyConfiguration_t configuration_p = {
+ /* use_non_resolvable_random_address */ false,
+ Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS
+ };
+ _ble.gap().setPeripheralPrivacyConfiguration(&configuration_p);
+
+ Gap::CentralPrivacyConfiguration_t configuration_c = {
+ /* use_non_resolvable_random_address */ false,
+ Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD
+ };
+ _ble.gap().setCentralPrivacyConfiguration(&configuration_c);
+
+ /* this demo switches between being master and slave */
+ _ble.securityManager().setHintFutureRoleReversal(true);
+#endif
+
+ /* Tell the security manager to use methods in this class to inform us
+ * of any events. Class needs to implement SecurityManagerEventHandler. */
+ _ble.securityManager().setSecurityManagerEventHandler(this);
+
+ /* gap events also handled by this class */
+ _ble.gap().setEventHandler(this);
+
+ /* print device address */
+ Gap::AddressType_t addr_type;
+ Gap::Address_t addr;
+ _ble.gap().getAddress(&addr_type, addr);
+ print_address(addr);
+
+ /* start test in 500 ms */
+ _event_queue.call_in(500, this, &SMDevice::start);
+ };
+
+ /** Schedule processing of events from the BLE in the event queue. */
+ void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
+ {
+ _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
+ };
+
+ /** Blink LED to show we're running */
+ void blink(void)
+ {
+ _led1 = !_led1;
+ };
+
+private:
+ /* Event handler */
+
+ /** Respond to a pairing request. This will be called by the stack
+ * when a pairing request arrives and expects the application to
+ * call acceptPairingRequest or cancelPairingRequest */
+ virtual void pairingRequest(
+ ble::connection_handle_t connectionHandle
+ ) {
+ printf("Pairing requested - authorising\r\n");
+ _ble.securityManager().acceptPairingRequest(connectionHandle);
+ }
+
+ /** Inform the application of a successful pairing. Terminate the demonstration. */
+ virtual void pairingResult(
+ ble::connection_handle_t connectionHandle,
+ SecurityManager::SecurityCompletionStatus_t result
+ ) {
+ if (result == SecurityManager::SEC_STATUS_SUCCESS) {
+ printf("Pairing successful\r\n");
+ } else {
+ printf("Pairing failed\r\n");
+ }
+ }
+
+ /** Inform the application of change in encryption status. This will be
+ * communicated through the serial port */
+ virtual void linkEncryptionResult(
+ ble::connection_handle_t connectionHandle,
+ ble::link_encryption_t result
+ ) {
+ if (result == ble::link_encryption_t::ENCRYPTED) {
+ printf("Link ENCRYPTED\r\n");
+ } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
+ printf("Link ENCRYPTED_WITH_MITM\r\n");
+ } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) {
+ printf("Link NOT_ENCRYPTED\r\n");
+ }
+
+ /* disconnect in 2 s */
+ _event_queue.call_in(
+ 2000,
+ &_ble.gap(),
+ disconnect_call,
+ _handle,
+ ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION)
+ );
+ }
+
+ /** This is called by Gap to notify the application we disconnected,
+ * in our case it ends the demonstration. */
+ virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &)
+ {
+ printf("Diconnected\r\n");
+ _event_queue.break_dispatch();
+ };
+
+ virtual void onAdvertisingEnd(const ble::AdvertisingEndEvent &)
+ {
+ printf("Advertising timed out - aborting\r\n");
+ _event_queue.break_dispatch();
+ }
+
+ virtual void onScanTimeout(const ble::ScanTimeoutEvent &)
+ {
+ printf("Scan timed out - aborting\r\n");
+ _event_queue.break_dispatch();
+ }
+
+private:
+ DigitalOut _led1;
+
+protected:
+ BLE &_ble;
+ events::EventQueue &_event_queue;
+ BLEProtocol::AddressBytes_t &_peer_address;
+ ble::connection_handle_t _handle;
+ bool _is_connecting;
+};
+
+/** A peripheral device will advertise, accept the connection and request
+ * a change in link security. */
+class SMDevicePeripheral : public SMDevice {
+public:
+ SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
+ : SMDevice(ble, event_queue, peer_address) { }
+
+ virtual void start()
+ {
+ /* Set up and start advertising */
+ uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
+ /* use the helper to build the payload */
+ ble::AdvertisingDataBuilder adv_data_builder(
+ adv_buffer
+ );
+
+ adv_data_builder.setFlags();
+ adv_data_builder.setName(DEVICE_NAME);
+
+ /* Set payload for the set */
+ ble_error_t error = _ble.gap().setAdvertisingPayload(
+ ble::LEGACY_ADVERTISING_HANDLE,
+ adv_data_builder.getAdvertisingData()
+ );
+
+ if (error) {
+ print_error(error, "Gap::setAdvertisingPayload() failed");
+ _event_queue.break_dispatch();
+ return;
+ }
+
+ ble::AdvertisingParameters adv_parameters(
+ ble::advertising_type_t::CONNECTABLE_UNDIRECTED
+ );
+
+ error = _ble.gap().setAdvertisingParameters(
+ ble::LEGACY_ADVERTISING_HANDLE,
+ adv_parameters
+ );
+
+ if (error) {
+ print_error(error, "Gap::setAdvertisingParameters() failed");
+ return;
+ }
+
+ error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
+
+ if (error) {
+ print_error(error, "Gap::startAdvertising() failed");
+ return;
+ }
+
+ printf("Please connect to device\r\n");
+
+ /** This tells the stack to generate a pairingRequest event
+ * which will require this application to respond before pairing
+ * can proceed. Setting it to false will automatically accept
+ * pairing. */
+ _ble.securityManager().setPairingRequestAuthorisation(true);
+ };
+
+ /** This is called by Gap to notify the application we connected,
+ * in our case it immediately requests a change in link security */
+ virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event)
+ {
+ ble_error_t error;
+
+ /* remember the device that connects to us now so we can connect to it
+ * during the next demonstration */
+ memcpy(_peer_address, event.getPeerAddress().data(), sizeof(_peer_address));
+
+ printf("Connected to peer: ");
+ print_address(event.getPeerAddress().data());
+
+ _handle = event.getConnectionHandle();
+
+ /* Request a change in link security. This will be done
+ * indirectly by asking the master of the connection to
+ * change it. Depending on circumstances different actions
+ * may be taken by the master which will trigger events
+ * which the applications should deal with. */
+ error = _ble.securityManager().setLinkSecurity(
+ _handle,
+ SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM
+ );
+
+ if (error) {
+ printf("Error during SM::setLinkSecurity %d\r\n", error);
+ return;
+ }
+ };
+};
+
+/** A central device will scan, connect to a peer and request pairing. */
+class SMDeviceCentral : public SMDevice {
+public:
+ SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
+ : SMDevice(ble, event_queue, peer_address) { }
+
+ virtual void start()
+ {
+ ble::ScanParameters params;
+ ble_error_t error = _ble.gap().setScanParameters(params);
+
+ if (error) {
+ print_error(error, "Error in Gap::startScan %d\r\n");
+ return;
+ }
+
+ /* start scanning, results will be handled by onAdvertisingReport */
+ error = _ble.gap().startScan();
+
+ if (error) {
+ print_error(error, "Error in Gap::startScan %d\r\n");
+ return;
+ }
+
+ printf("Please advertise\r\n");
+
+ printf("Scanning for: ");
+ print_address(_peer_address);
+ }
+
+private:
+ /* Gap::EventHandler */
+
+ /** Look at scan payload to find a peer device and connect to it */
+ virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event)
+ {
+ /* don't bother with analysing scan result if we're already connecting */
+ if (_is_connecting) {
+ return;
+ }
+
+ /* parse the advertising payload, looking for a discoverable device */
+ if (memcmp(event.getPeerAddress().data(), _peer_address, sizeof(_peer_address)) == 0) {
+ ble_error_t error = _ble.gap().stopScan();
+
+ if (error) {
+ print_error(error, "Error caused by Gap::stopScan");
+ return;
+ }
+
+ ble::ConnectionParameters connection_params(
+ ble::phy_t::LE_1M,
+ ble::scan_interval_t(50),
+ ble::scan_window_t(50),
+ ble::conn_interval_t(50),
+ ble::conn_interval_t(100),
+ ble::slave_latency_t(0),
+ ble::supervision_timeout_t(100)
+ );
+ connection_params.setOwnAddressType(ble::own_address_type_t::RANDOM);
+
+ error = _ble.gap().connect(
+ event.getPeerAddressType(),
+ event.getPeerAddress(),
+ connection_params
+ );
+
+ if (error) {
+ print_error(error, "Error caused by Gap::connect");
+ return;
+ }
+
+ /* we may have already scan events waiting
+ * to be processed so we need to remember
+ * that we are already connecting and ignore them */
+ _is_connecting = true;
+
+ return;
+ }
+ }
+
+ /** This is called by Gap to notify the application we connected,
+ * in our case it immediately request pairing */
+ virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event)
+ {
+ if (event.getStatus() == BLE_ERROR_NONE) {
+ /* store the handle for future Security Manager requests */
+ _handle = event.getConnectionHandle();
+
+ printf("Connected\r\n");
+
+ /* in this example the local device is the master so we request pairing */
+ ble_error_t error = _ble.securityManager().requestPairing(_handle);
+
+ if (error) {
+ printf("Error during SM::requestPairing %d\r\n", error);
+ return;
+ }
+
+ /* upon pairing success the application will disconnect */
+ }
+
+ /* failed to connect - restart scan */
+ ble_error_t error = _ble.gap().startScan();
+
+ if (error) {
+ print_error(error, "Error in Gap::startScan %d\r\n");
+ return;
+ }
+ };
+};
+
+
+#if MBED_CONF_APP_FILESYSTEM_SUPPORT
+bool create_filesystem()
+{
+ static LittleFileSystem fs("fs");
+
+ /* replace this with any physical block device your board supports (like an SD card) */
+ static HeapBlockDevice bd(4096, 256);
+
+ int err = bd.init();
+
+ if (err) {
+ return false;
+ }
+
+ err = bd.erase(0, bd.size());
+
+ if (err) {
+ return false;
+ }
+
+ err = fs.mount(&bd);
+
+ if (err) {
+ /* Reformat if we can't mount the filesystem */
+ printf("No filesystem found, formatting...\r\n");
+
+ err = fs.reformat(&bd);
+
+ if (err) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif //MBED_CONF_APP_FILESYSTEM_SUPPORT
+
+int main()
+{
+ BLE& ble = BLE::Instance();
+ events::EventQueue queue;
+
+#if MBED_CONF_APP_FILESYSTEM_SUPPORT
+ /* if filesystem creation fails or there is no filesystem the security manager
+ * will fallback to storing the security database in memory */
+ if (!create_filesystem()) {
+ printf("Filesystem creation failed, will use memory storage\r\n");
+ }
+#endif
+
+ while(1) {
+ {
+ printf("\r\n PERIPHERAL \r\n\r\n");
+ SMDevicePeripheral peripheral(ble, queue, peer_address);
+ peripheral.run();
+ }
+
+ {
+ printf("\r\n CENTRAL \r\n\r\n");
+ SMDeviceCentral central(ble, queue, peer_address);
+ central.run();
+ }
+ }
+
+ return 0;
+}
+
+#endif
\ No newline at end of file