Okundu Omeni
/
wifi-https-ble-sm-uart-atcmd-5-13-1
Diff: source/BleManager.cpp
- Revision:
- 75:08eff6258e1b
- Parent:
- 74:f26e846adfe9
- Child:
- 76:6afda865fbf8
--- a/source/BleManager.cpp Sun Mar 10 09:46:06 2019 +0000 +++ b/source/BleManager.cpp Thu Mar 14 21:34:06 2019 +0000 @@ -13,11 +13,515 @@ * 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 "BleManager.h" +#if MBED_CONF_APP_FILESYSTEM_SUPPORT +#include "LittleFileSystem.h" +#include "HeapBlockDevice.h" +#endif //MBED_CONF_APP_FILESYSTEM_SUPPORT + + +static const uint8_t DEVICE_NAME[] = "SM_device"; + +/** 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 uint8_t DEVICE_NAME[] = "SM_device"; + +/* 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. + */ +SMDevice::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) { } + +SMDevice::~SMDevice() +{ + if (_ble.hasInitialized()) { + _ble.shutdown(); + } +} + +/** Start BLE interface initialisation */ +void SMDevice::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 timeouts, for example when connection attempts fail */ + _ble.gap().onTimeout( + makeFunctionPointer(this, &SMDevice::on_timeout) + ); + + 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(); +} + +/* event handler functions */ + +/** 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 */ +void SMDevice::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. */ +void SMDevice::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 */ +void SMDevice::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(), + &Gap::disconnect, _handle, Gap::REMOTE_USER_TERMINATED_CONNECTION + ); +} + +/** Override to start chosen activity when initialisation completes */ +//void SMDevice::start() = 0; + +/** This is called when BLE interface is initialised and starts the demonstration */ +void SMDevice::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); + + /* print device address */ + Gap::AddressType_t addr_type; + Gap::Address_t addr; + _ble.gap().getAddress(&addr_type, addr); + printf("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n", + addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]); + + /* when scanning we want to connect to a peer device so we need to + * attach callbacks that are used by Gap to notify us of events */ + _ble.gap().onConnection(this, &SMDevice::on_connect); + _ble.gap().onDisconnection(this, &SMDevice::on_disconnect); + + /* start test in 500 ms */ + _event_queue.call_in(500, this, &SMDevice::start); +} + +/** This is called by Gap to notify the application we connected */ +//void SMDevice::on_connect(const Gap::ConnectionCallbackParams_t *connection_event); + +/** This is called by Gap to notify the application we disconnected, + * in our case it ends the demonstration. */ +void SMDevice::on_disconnect(const Gap::DisconnectionCallbackParams_t *event) +{ + printf("Disconnected\r\n"); + _event_queue.break_dispatch(); +} + +/** End demonstration unexpectedly. Called if timeout is reached during advertising, + * scanning or connection initiation */ +void SMDevice::on_timeout(const Gap::TimeoutSource_t source) +{ + printf("Unexpected timeout - aborting\r\n"); + _event_queue.break_dispatch(); +} + +/** Schedule processing of events from the BLE in the event queue. */ +void SMDevice::schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) +{ + _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents)); +}; + +/** Blink LED to show we're running */ +void SMDevice::blink(void) +{ + _led1 = !_led1; +} + + +/** A peripheral device will advertise, accept the connection and request + * a change in link security. */ +SMDevicePeripheral::SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) + : SMDevice(ble, event_queue, peer_address) { } + +void SMDevicePeripheral::start() +{ + /* Set up and start advertising */ + + ble_error_t error; + GapAdvertisingData advertising_data; + + /* add advertising flags */ + advertising_data.addFlags(GapAdvertisingData::LE_GENERAL_DISCOVERABLE + | GapAdvertisingData::BREDR_NOT_SUPPORTED); + + /* add device name */ + advertising_data.addData( + GapAdvertisingData::COMPLETE_LOCAL_NAME, + DEVICE_NAME, + sizeof(DEVICE_NAME) + ); + + error = _ble.gap().setAdvertisingPayload(advertising_data); + + if (error) { + printf("Error during Gap::setAdvertisingPayload\r\n"); + return; + } + + /* advertise to everyone */ + _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + /* how many milliseconds between advertisements, lower interval + * increases the chances of being seen at the cost of more power */ + _ble.gap().setAdvertisingInterval(20); + _ble.gap().setAdvertisingTimeout(0); + + error = _ble.gap().startAdvertising(); + + if (error) { + printf("Error during Gap::startAdvertising.\r\n"); + 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 */ +void SMDevicePeripheral::on_connect(const Gap::ConnectionCallbackParams_t *connection_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, connection_event->peerAddr, sizeof(_peer_address)); + + printf("Connected to: %02x:%02x:%02x:%02x:%02x:%02x\r\n", + _peer_address[5], _peer_address[4], _peer_address[3], + _peer_address[2], _peer_address[1], _peer_address[0]); + + /* store the handle for future Security Manager requests */ + _handle = connection_event->handle; + + /* 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. */ + +SMDeviceCentral::SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) + : SMDevice(ble, event_queue, peer_address) { }; + +void SMDeviceCentral::start() +{ + /* start scanning and attach a callback that will handle advertisements + * and scan requests responses */ + ble_error_t error = _ble.gap().startScan(this, &SMDeviceCentral::on_scan); + + printf("Please advertise\r\n"); + + printf("Scanning for: %02x:%02x:%02x:%02x:%02x:%02x\r\n", + _peer_address[5], _peer_address[4], _peer_address[3], + _peer_address[2], _peer_address[1], _peer_address[0]); + + if (error) { + printf("Error during Gap::startScan %d\r\n", error); + return; + } +} + +/** Look at scan payload to find a peer device and connect to it */ +void SMDeviceCentral::on_scan(const Gap::AdvertisementCallbackParams_t *params) +{ + /* don't bother with analysing scan result if we're already connecting */ + if (_is_connecting) { + return; + } + + /* connect to the same device that connected to us */ + if (memcmp(params->peerAddr, _peer_address, sizeof(_peer_address)) == 0) { + + ble_error_t error = _ble.gap().connect( + params->peerAddr, params->peerAddrType, + NULL, NULL + ); + + if (error) { + printf("Error during Gap::connect %d\r\n", error); + return; + } + + printf("Connecting... "); + + /* 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 */ +void SMDeviceCentral::on_connect(const Gap::ConnectionCallbackParams_t *connection_event) +{ + ble_error_t error; + + /* store the handle for future Security Manager requests */ + _handle = connection_event->handle; + + /* in this example the local device is the master so we request pairing */ + error = _ble.securityManager().requestPairing(_handle); + + printf("Connected\r\n"); + + if (error) { + printf("Error during SM::requestPairing %d\r\n", error); + return; + } + + /* upon pairing success the application will disconnect */ +} + + + +#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 +#ifdef BLE_SECURITY_MAIN +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 + +#ifdef OLD_BLE_SECURITY +/* 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 "ble/Gap.h" +#include "Types.h" +#include "ble/services/UARTService.h" + +//#include "ble/gap/Types.h" +#include "SecurityManager.h" #include "pretty_printer.h" #if MBED_CONF_APP_FILESYSTEM_SUPPORT @@ -42,8 +546,10 @@ 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; +//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; +//typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); +//const static (Gap::*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 @@ -58,7 +564,7 @@ */ class SMDevice : private mbed::NonCopyable<SMDevice>, public SecurityManager::EventHandler, - public ble::Gap::EventHandler + public Gap::EventHandler { public: SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) : @@ -244,31 +750,37 @@ _event_queue.call_in( 2000, &_ble.gap(), - disconnect_call, + &Gap::disconnect, //disconnect_call, _handle, - ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) + (Gap::DisconnectionReason_t)0x13 + //Gap::DisconnectionReason_t::REMOTE_USER_TERMINATED_CONNECTION) + //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 &) + //virtual void onDisconnectionComplete(const Gap::DisconnectionCompleteEvent &) + virtual void onDisconnectionComplete(const Gap::DisconnectionCallbackParams_t *params) { - printf("Diconnected\r\n"); + printf("Disconnected\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 onAdvertisingEnd(const ble::AdvertisingEndEvent &) + //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(); - } + //virtual void onScanTimeout(const ble::ScanTimeoutEvent &) + //{ + // printf("Scan timed out - aborting\r\n"); + // _event_queue.break_dispatch(); + //} private: DigitalOut _led1; @@ -291,10 +803,12 @@ virtual void start() { /* Set up and start advertising */ - uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; +#ifdef NEW_BLE5_API + //uint8_t adv_buffer[Gap::LEGACY_ADVERTISING_MAX_SIZE]; + uint8_t adv_buffer[32]; /* use the helper to build the payload */ - ble::AdvertisingDataBuilder adv_data_builder( - adv_buffer + ble::Gap::AdvertisingDataBuilder adv_data_builder( + adv_buffer, 32 ); adv_data_builder.setFlags(); @@ -312,7 +826,7 @@ return; } - ble::AdvertisingParameters adv_parameters( + ble::gap::AdvertisingParameters adv_parameters( ble::advertising_type_t::CONNECTABLE_UNDIRECTED ); @@ -332,7 +846,19 @@ print_error(error, "Gap::startAdvertising() failed"); return; } +#else + /* setup advertising */ + _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + //_ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); + _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); + /* set up the services that can be discovered */ + _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed)); + _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + _ble.gap().setAdvertisingInterval(1000); /* 1000ms. */ + _ble.gap().setAdvertisingTimeout(300); /* 16 * 1000ms. */ + _ble.gap().startAdvertising(); +#endif printf("Please connect to device\r\n"); /** This tells the stack to generate a pairingRequest event @@ -344,18 +870,19 @@ /** 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) + //virtual void onConnectionComplete(const ble::ConnectionCompleteEvent_t &event) + virtual void onConnectionComplete(const Gap::ConnectionCallbackParams_t &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)); + memcpy(_peer_address, event.peerAddr, 6); printf("Connected to peer: "); - print_address(event.getPeerAddress().data()); + print_address(event.peerAddr); - _handle = event.getConnectionHandle(); + _handle = event.handle; /* Request a change in link security. This will be done * indirectly by asking the master of the connection to @@ -408,7 +935,7 @@ /* Gap::EventHandler */ /** Look at scan payload to find a peer device and connect to it */ - virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event) + virtual void onAdvertisingReport(const Gap::AdvertisementCallbackParams_t &event) { /* don't bother with analysing scan result if we're already connecting */ if (_is_connecting) { @@ -416,7 +943,7 @@ } /* parse the advertising payload, looking for a discoverable device */ - if (memcmp(event.getPeerAddress().data(), _peer_address, sizeof(_peer_address)) == 0) { + if (memcmp(event.peerAddr, _peer_address, sizeof(_peer_address)) == 0) { ble_error_t error = _ble.gap().stopScan(); if (error) { @@ -457,7 +984,7 @@ /** 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) + virtual void onConnectionComplete(const Gap::ConnectionCallbackParams_t &event) { if (event.getStatus() == BLE_ERROR_NONE) { /* store the handle for future Security Manager requests */ @@ -523,7 +1050,7 @@ return true; } #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT - +#ifdef BLE_MAIN int main() { BLE& ble = BLE::Instance(); @@ -554,4 +1081,6 @@ return 0; } +#endif + #endif \ No newline at end of file