Demonstration of possible usage of the Security Manager. Security Manager deals with pairing, authentication and encryption.
SM - example usage of the Security Manager to pair and encrypt
Demonstration of possible usage of the Security Manager. Security Manager deals with pairing, authentication and encryption.
The application demonstrates usage as a central and a peripheral. The central will connect to any connectable device present. Please have one ready and advertising. Application will attempt pairing. Please authorise your peer device to pair.
Upon success it will disconnect and start advertising to demonstrate usage as a peripheral. Please scan and connect using your peer device. Upon connection grant pairing if prompted. Upon success the application will disconnect. Observe the terminal to keep track of the sequence.
Running the application
Requirements
The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install :
- nRF Master Control Panel for Android.
- LightBlue for iPhone.
Information about activity is printed over the serial connection - please have a client open. You may use:
Hardware requirements are in the main readme.
Building instructions
Building instructions for all samples are in the main readme.
source/main.cpp@21:152f7ff52ac1, 2019-02-27 (annotated)
- Committer:
- mbed_official
- Date:
- Wed Feb 27 13:02:46 2019 +0000
- Revision:
- 21:152f7ff52ac1
- Parent:
- 17:6bf7972c4d0e
Updating mbed-os to mbed-os-5.11.5
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-ble
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Donatien Garnier |
1:916188eae2bb | 1 | /* mbed Microcontroller Library |
Donatien Garnier |
1:916188eae2bb | 2 | * Copyright (c) 2006-2013 ARM Limited |
Donatien Garnier |
1:916188eae2bb | 3 | * |
Donatien Garnier |
1:916188eae2bb | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
Donatien Garnier |
1:916188eae2bb | 5 | * you may not use this file except in compliance with the License. |
Donatien Garnier |
1:916188eae2bb | 6 | * You may obtain a copy of the License at |
Donatien Garnier |
1:916188eae2bb | 7 | * |
Donatien Garnier |
1:916188eae2bb | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
Donatien Garnier |
1:916188eae2bb | 9 | * |
Donatien Garnier |
1:916188eae2bb | 10 | * Unless required by applicable law or agreed to in writing, software |
Donatien Garnier |
1:916188eae2bb | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
Donatien Garnier |
1:916188eae2bb | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
Donatien Garnier |
1:916188eae2bb | 13 | * See the License for the specific language governing permissions and |
Donatien Garnier |
1:916188eae2bb | 14 | * limitations under the License. |
Donatien Garnier |
1:916188eae2bb | 15 | */ |
Donatien Garnier |
1:916188eae2bb | 16 | |
Donatien Garnier |
1:916188eae2bb | 17 | #include <events/mbed_events.h> |
Donatien Garnier |
1:916188eae2bb | 18 | #include <mbed.h> |
Donatien Garnier |
1:916188eae2bb | 19 | #include "ble/BLE.h" |
Donatien Garnier |
1:916188eae2bb | 20 | #include "SecurityManager.h" |
mbed_official | 17:6bf7972c4d0e | 21 | #include "pretty_printer.h" |
Donatien Garnier |
1:916188eae2bb | 22 | |
mbed_official | 9:674ab70e0f36 | 23 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
mbed_official | 9:674ab70e0f36 | 24 | #include "LittleFileSystem.h" |
mbed_official | 9:674ab70e0f36 | 25 | #include "HeapBlockDevice.h" |
mbed_official | 9:674ab70e0f36 | 26 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT |
mbed_official | 9:674ab70e0f36 | 27 | |
Donatien Garnier |
1:916188eae2bb | 28 | /** This example demonstrates all the basic setup required |
Donatien Garnier |
1:916188eae2bb | 29 | * for pairing and setting up link security both as a central and peripheral |
Donatien Garnier |
1:916188eae2bb | 30 | * |
Donatien Garnier |
1:916188eae2bb | 31 | * The example is implemented as two classes, one for the peripheral and one |
Donatien Garnier |
1:916188eae2bb | 32 | * for central inheriting from a common base. They are run in sequence and |
Donatien Garnier |
1:916188eae2bb | 33 | * require a peer device to connect to. During the peripheral device demonstration |
Donatien Garnier |
1:916188eae2bb | 34 | * a peer device is required to connect. In the central device demonstration |
Donatien Garnier |
1:916188eae2bb | 35 | * this peer device will be scanned for and connected to - therefore it should |
Donatien Garnier |
1:916188eae2bb | 36 | * be advertising with the same address as when it connected. |
Donatien Garnier |
1:916188eae2bb | 37 | * |
Donatien Garnier |
1:916188eae2bb | 38 | * During the test output is written on the serial connection to monitor its |
Donatien Garnier |
1:916188eae2bb | 39 | * progress. |
Donatien Garnier |
1:916188eae2bb | 40 | */ |
Donatien Garnier |
1:916188eae2bb | 41 | |
mbed_official | 17:6bf7972c4d0e | 42 | static const char DEVICE_NAME[] = "SM_device"; |
mbed_official | 17:6bf7972c4d0e | 43 | |
mbed_official | 17:6bf7972c4d0e | 44 | /* we have to specify the disconnect call because of ambiguous overloads */ |
mbed_official | 17:6bf7972c4d0e | 45 | typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t); |
mbed_official | 17:6bf7972c4d0e | 46 | const static disconnect_call_t disconnect_call = &Gap::disconnect; |
Donatien Garnier |
1:916188eae2bb | 47 | |
Donatien Garnier |
1:916188eae2bb | 48 | /* for demonstration purposes we will store the peer device address |
Donatien Garnier |
1:916188eae2bb | 49 | * of the device that connects to us in the first demonstration |
Donatien Garnier |
1:916188eae2bb | 50 | * so we can use its address to reconnect to it later */ |
Donatien Garnier |
1:916188eae2bb | 51 | static BLEProtocol::AddressBytes_t peer_address; |
Donatien Garnier |
1:916188eae2bb | 52 | |
Donatien Garnier |
1:916188eae2bb | 53 | /** Base class for both peripheral and central. The same class that provides |
Donatien Garnier |
1:916188eae2bb | 54 | * the logic for the application also implements the SecurityManagerEventHandler |
Donatien Garnier |
1:916188eae2bb | 55 | * which is the interface used by the Security Manager to communicate events |
Donatien Garnier |
1:916188eae2bb | 56 | * back to the applications. You can provide overrides for a selection of events |
Donatien Garnier |
1:916188eae2bb | 57 | * your application is interested in. |
Donatien Garnier |
1:916188eae2bb | 58 | */ |
Donatien Garnier |
1:916188eae2bb | 59 | class SMDevice : private mbed::NonCopyable<SMDevice>, |
mbed_official | 17:6bf7972c4d0e | 60 | public SecurityManager::EventHandler, |
mbed_official | 17:6bf7972c4d0e | 61 | public ble::Gap::EventHandler |
Donatien Garnier |
1:916188eae2bb | 62 | { |
Donatien Garnier |
1:916188eae2bb | 63 | public: |
Donatien Garnier |
1:916188eae2bb | 64 | SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) : |
Donatien Garnier |
1:916188eae2bb | 65 | _led1(LED1, 0), |
Donatien Garnier |
1:916188eae2bb | 66 | _ble(ble), |
Donatien Garnier |
1:916188eae2bb | 67 | _event_queue(event_queue), |
Donatien Garnier |
1:916188eae2bb | 68 | _peer_address(peer_address), |
Donatien Garnier |
1:916188eae2bb | 69 | _handle(0), |
Donatien Garnier |
1:916188eae2bb | 70 | _is_connecting(false) { }; |
Donatien Garnier |
1:916188eae2bb | 71 | |
Donatien Garnier |
1:916188eae2bb | 72 | virtual ~SMDevice() |
Donatien Garnier |
1:916188eae2bb | 73 | { |
Donatien Garnier |
1:916188eae2bb | 74 | if (_ble.hasInitialized()) { |
Donatien Garnier |
1:916188eae2bb | 75 | _ble.shutdown(); |
Donatien Garnier |
1:916188eae2bb | 76 | } |
Donatien Garnier |
1:916188eae2bb | 77 | }; |
Donatien Garnier |
1:916188eae2bb | 78 | |
Donatien Garnier |
1:916188eae2bb | 79 | /** Start BLE interface initialisation */ |
Donatien Garnier |
1:916188eae2bb | 80 | void run() |
Donatien Garnier |
1:916188eae2bb | 81 | { |
Donatien Garnier |
1:916188eae2bb | 82 | ble_error_t error; |
Donatien Garnier |
1:916188eae2bb | 83 | |
Donatien Garnier |
1:916188eae2bb | 84 | /* to show we're running we'll blink every 500ms */ |
Donatien Garnier |
1:916188eae2bb | 85 | _event_queue.call_every(500, this, &SMDevice::blink); |
Donatien Garnier |
1:916188eae2bb | 86 | |
Donatien Garnier |
1:916188eae2bb | 87 | if (_ble.hasInitialized()) { |
Donatien Garnier |
1:916188eae2bb | 88 | printf("Ble instance already initialised.\r\n"); |
Donatien Garnier |
1:916188eae2bb | 89 | return; |
Donatien Garnier |
1:916188eae2bb | 90 | } |
Donatien Garnier |
1:916188eae2bb | 91 | |
Donatien Garnier |
1:916188eae2bb | 92 | /* this will inform us off all events so we can schedule their handling |
Donatien Garnier |
1:916188eae2bb | 93 | * using our event queue */ |
Donatien Garnier |
1:916188eae2bb | 94 | _ble.onEventsToProcess( |
Donatien Garnier |
1:916188eae2bb | 95 | makeFunctionPointer(this, &SMDevice::schedule_ble_events) |
Donatien Garnier |
1:916188eae2bb | 96 | ); |
Donatien Garnier |
1:916188eae2bb | 97 | |
mbed_official | 17:6bf7972c4d0e | 98 | /* handle gap events */ |
mbed_official | 17:6bf7972c4d0e | 99 | _ble.gap().setEventHandler(this); |
Donatien Garnier |
1:916188eae2bb | 100 | |
Donatien Garnier |
1:916188eae2bb | 101 | error = _ble.init(this, &SMDevice::on_init_complete); |
Donatien Garnier |
1:916188eae2bb | 102 | |
Donatien Garnier |
1:916188eae2bb | 103 | if (error) { |
Donatien Garnier |
1:916188eae2bb | 104 | printf("Error returned by BLE::init.\r\n"); |
Donatien Garnier |
1:916188eae2bb | 105 | return; |
Donatien Garnier |
1:916188eae2bb | 106 | } |
Donatien Garnier |
1:916188eae2bb | 107 | |
Donatien Garnier |
1:916188eae2bb | 108 | /* this will not return until shutdown */ |
Donatien Garnier |
1:916188eae2bb | 109 | _event_queue.dispatch_forever(); |
Donatien Garnier |
1:916188eae2bb | 110 | }; |
Donatien Garnier |
1:916188eae2bb | 111 | |
Donatien Garnier |
1:916188eae2bb | 112 | private: |
Donatien Garnier |
1:916188eae2bb | 113 | /** Override to start chosen activity when initialisation completes */ |
Donatien Garnier |
1:916188eae2bb | 114 | virtual void start() = 0; |
Donatien Garnier |
1:916188eae2bb | 115 | |
Donatien Garnier |
1:916188eae2bb | 116 | /** This is called when BLE interface is initialised and starts the demonstration */ |
Donatien Garnier |
1:916188eae2bb | 117 | void on_init_complete(BLE::InitializationCompleteCallbackContext *event) |
Donatien Garnier |
1:916188eae2bb | 118 | { |
Donatien Garnier |
1:916188eae2bb | 119 | ble_error_t error; |
Donatien Garnier |
1:916188eae2bb | 120 | |
Donatien Garnier |
1:916188eae2bb | 121 | if (event->error) { |
Donatien Garnier |
1:916188eae2bb | 122 | printf("Error during the initialisation\r\n"); |
Donatien Garnier |
1:916188eae2bb | 123 | return; |
Donatien Garnier |
1:916188eae2bb | 124 | } |
Donatien Garnier |
1:916188eae2bb | 125 | |
mbed_official | 9:674ab70e0f36 | 126 | /* This path will be used to store bonding information but will fallback |
mbed_official | 9:674ab70e0f36 | 127 | * to storing in memory if file access fails (for example due to lack of a filesystem) */ |
mbed_official | 9:674ab70e0f36 | 128 | const char* db_path = "/fs/bt_sec_db"; |
Donatien Garnier |
1:916188eae2bb | 129 | /* If the security manager is required this needs to be called before any |
Donatien Garnier |
1:916188eae2bb | 130 | * calls to the Security manager happen. */ |
mbed_official | 9:674ab70e0f36 | 131 | error = _ble.securityManager().init( |
mbed_official | 9:674ab70e0f36 | 132 | true, |
mbed_official | 9:674ab70e0f36 | 133 | false, |
mbed_official | 9:674ab70e0f36 | 134 | SecurityManager::IO_CAPS_NONE, |
mbed_official | 9:674ab70e0f36 | 135 | NULL, |
mbed_official | 9:674ab70e0f36 | 136 | false, |
mbed_official | 9:674ab70e0f36 | 137 | db_path |
mbed_official | 9:674ab70e0f36 | 138 | ); |
Donatien Garnier |
1:916188eae2bb | 139 | |
Donatien Garnier |
1:916188eae2bb | 140 | if (error) { |
Donatien Garnier |
1:916188eae2bb | 141 | printf("Error during init %d\r\n", error); |
Donatien Garnier |
1:916188eae2bb | 142 | return; |
Donatien Garnier |
1:916188eae2bb | 143 | } |
Donatien Garnier |
1:916188eae2bb | 144 | |
mbed_official | 9:674ab70e0f36 | 145 | error = _ble.securityManager().preserveBondingStateOnReset(true); |
mbed_official | 9:674ab70e0f36 | 146 | |
mbed_official | 9:674ab70e0f36 | 147 | if (error) { |
mbed_official | 9:674ab70e0f36 | 148 | printf("Error during preserveBondingStateOnReset %d\r\n", error); |
mbed_official | 9:674ab70e0f36 | 149 | } |
mbed_official | 9:674ab70e0f36 | 150 | |
mbed_official | 9:674ab70e0f36 | 151 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
mbed_official | 9:674ab70e0f36 | 152 | /* Enable privacy so we can find the keys */ |
mbed_official | 9:674ab70e0f36 | 153 | error = _ble.gap().enablePrivacy(true); |
mbed_official | 9:674ab70e0f36 | 154 | |
mbed_official | 9:674ab70e0f36 | 155 | if (error) { |
mbed_official | 9:674ab70e0f36 | 156 | printf("Error enabling privacy\r\n"); |
mbed_official | 9:674ab70e0f36 | 157 | } |
mbed_official | 9:674ab70e0f36 | 158 | |
mbed_official | 9:674ab70e0f36 | 159 | Gap::PeripheralPrivacyConfiguration_t configuration_p = { |
mbed_official | 9:674ab70e0f36 | 160 | /* use_non_resolvable_random_address */ false, |
mbed_official | 9:674ab70e0f36 | 161 | Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS |
mbed_official | 9:674ab70e0f36 | 162 | }; |
mbed_official | 9:674ab70e0f36 | 163 | _ble.gap().setPeripheralPrivacyConfiguration(&configuration_p); |
mbed_official | 9:674ab70e0f36 | 164 | |
mbed_official | 9:674ab70e0f36 | 165 | Gap::CentralPrivacyConfiguration_t configuration_c = { |
mbed_official | 9:674ab70e0f36 | 166 | /* use_non_resolvable_random_address */ false, |
mbed_official | 9:674ab70e0f36 | 167 | Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD |
mbed_official | 9:674ab70e0f36 | 168 | }; |
mbed_official | 9:674ab70e0f36 | 169 | _ble.gap().setCentralPrivacyConfiguration(&configuration_c); |
mbed_official | 9:674ab70e0f36 | 170 | |
mbed_official | 9:674ab70e0f36 | 171 | /* this demo switches between being master and slave */ |
mbed_official | 9:674ab70e0f36 | 172 | _ble.securityManager().setHintFutureRoleReversal(true); |
mbed_official | 9:674ab70e0f36 | 173 | #endif |
mbed_official | 9:674ab70e0f36 | 174 | |
Donatien Garnier |
1:916188eae2bb | 175 | /* Tell the security manager to use methods in this class to inform us |
Donatien Garnier |
1:916188eae2bb | 176 | * of any events. Class needs to implement SecurityManagerEventHandler. */ |
Donatien Garnier |
1:916188eae2bb | 177 | _ble.securityManager().setSecurityManagerEventHandler(this); |
Donatien Garnier |
1:916188eae2bb | 178 | |
mbed_official | 17:6bf7972c4d0e | 179 | /* gap events also handled by this class */ |
mbed_official | 17:6bf7972c4d0e | 180 | _ble.gap().setEventHandler(this); |
mbed_official | 17:6bf7972c4d0e | 181 | |
Donatien Garnier |
1:916188eae2bb | 182 | /* print device address */ |
Donatien Garnier |
1:916188eae2bb | 183 | Gap::AddressType_t addr_type; |
Donatien Garnier |
1:916188eae2bb | 184 | Gap::Address_t addr; |
Donatien Garnier |
1:916188eae2bb | 185 | _ble.gap().getAddress(&addr_type, addr); |
mbed_official | 17:6bf7972c4d0e | 186 | print_address(addr); |
Donatien Garnier |
1:916188eae2bb | 187 | |
Donatien Garnier |
1:916188eae2bb | 188 | /* start test in 500 ms */ |
Donatien Garnier |
1:916188eae2bb | 189 | _event_queue.call_in(500, this, &SMDevice::start); |
Donatien Garnier |
1:916188eae2bb | 190 | }; |
Donatien Garnier |
1:916188eae2bb | 191 | |
Donatien Garnier |
1:916188eae2bb | 192 | /** Schedule processing of events from the BLE in the event queue. */ |
Donatien Garnier |
1:916188eae2bb | 193 | void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) |
Donatien Garnier |
1:916188eae2bb | 194 | { |
Donatien Garnier |
1:916188eae2bb | 195 | _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents)); |
Donatien Garnier |
1:916188eae2bb | 196 | }; |
Donatien Garnier |
1:916188eae2bb | 197 | |
Donatien Garnier |
1:916188eae2bb | 198 | /** Blink LED to show we're running */ |
Donatien Garnier |
1:916188eae2bb | 199 | void blink(void) |
Donatien Garnier |
1:916188eae2bb | 200 | { |
Donatien Garnier |
1:916188eae2bb | 201 | _led1 = !_led1; |
Donatien Garnier |
1:916188eae2bb | 202 | }; |
Donatien Garnier |
1:916188eae2bb | 203 | |
Donatien Garnier |
1:916188eae2bb | 204 | private: |
mbed_official | 17:6bf7972c4d0e | 205 | /* Event handler */ |
mbed_official | 17:6bf7972c4d0e | 206 | |
mbed_official | 17:6bf7972c4d0e | 207 | /** Respond to a pairing request. This will be called by the stack |
mbed_official | 17:6bf7972c4d0e | 208 | * when a pairing request arrives and expects the application to |
mbed_official | 17:6bf7972c4d0e | 209 | * call acceptPairingRequest or cancelPairingRequest */ |
mbed_official | 17:6bf7972c4d0e | 210 | virtual void pairingRequest( |
mbed_official | 17:6bf7972c4d0e | 211 | ble::connection_handle_t connectionHandle |
mbed_official | 17:6bf7972c4d0e | 212 | ) { |
mbed_official | 17:6bf7972c4d0e | 213 | printf("Pairing requested - authorising\r\n"); |
mbed_official | 17:6bf7972c4d0e | 214 | _ble.securityManager().acceptPairingRequest(connectionHandle); |
mbed_official | 17:6bf7972c4d0e | 215 | } |
mbed_official | 17:6bf7972c4d0e | 216 | |
mbed_official | 17:6bf7972c4d0e | 217 | /** Inform the application of a successful pairing. Terminate the demonstration. */ |
mbed_official | 17:6bf7972c4d0e | 218 | virtual void pairingResult( |
mbed_official | 17:6bf7972c4d0e | 219 | ble::connection_handle_t connectionHandle, |
mbed_official | 17:6bf7972c4d0e | 220 | SecurityManager::SecurityCompletionStatus_t result |
mbed_official | 17:6bf7972c4d0e | 221 | ) { |
mbed_official | 17:6bf7972c4d0e | 222 | if (result == SecurityManager::SEC_STATUS_SUCCESS) { |
mbed_official | 17:6bf7972c4d0e | 223 | printf("Pairing successful\r\n"); |
mbed_official | 17:6bf7972c4d0e | 224 | } else { |
mbed_official | 17:6bf7972c4d0e | 225 | printf("Pairing failed\r\n"); |
mbed_official | 17:6bf7972c4d0e | 226 | } |
mbed_official | 17:6bf7972c4d0e | 227 | } |
mbed_official | 17:6bf7972c4d0e | 228 | |
mbed_official | 17:6bf7972c4d0e | 229 | /** Inform the application of change in encryption status. This will be |
mbed_official | 17:6bf7972c4d0e | 230 | * communicated through the serial port */ |
mbed_official | 17:6bf7972c4d0e | 231 | virtual void linkEncryptionResult( |
mbed_official | 17:6bf7972c4d0e | 232 | ble::connection_handle_t connectionHandle, |
mbed_official | 17:6bf7972c4d0e | 233 | ble::link_encryption_t result |
mbed_official | 17:6bf7972c4d0e | 234 | ) { |
mbed_official | 17:6bf7972c4d0e | 235 | if (result == ble::link_encryption_t::ENCRYPTED) { |
mbed_official | 17:6bf7972c4d0e | 236 | printf("Link ENCRYPTED\r\n"); |
mbed_official | 17:6bf7972c4d0e | 237 | } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) { |
mbed_official | 17:6bf7972c4d0e | 238 | printf("Link ENCRYPTED_WITH_MITM\r\n"); |
mbed_official | 17:6bf7972c4d0e | 239 | } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) { |
mbed_official | 17:6bf7972c4d0e | 240 | printf("Link NOT_ENCRYPTED\r\n"); |
mbed_official | 17:6bf7972c4d0e | 241 | } |
mbed_official | 17:6bf7972c4d0e | 242 | |
mbed_official | 17:6bf7972c4d0e | 243 | /* disconnect in 2 s */ |
mbed_official | 17:6bf7972c4d0e | 244 | _event_queue.call_in( |
mbed_official | 17:6bf7972c4d0e | 245 | 2000, |
mbed_official | 17:6bf7972c4d0e | 246 | &_ble.gap(), |
mbed_official | 17:6bf7972c4d0e | 247 | disconnect_call, |
mbed_official | 17:6bf7972c4d0e | 248 | _handle, |
mbed_official | 17:6bf7972c4d0e | 249 | ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION) |
mbed_official | 17:6bf7972c4d0e | 250 | ); |
mbed_official | 17:6bf7972c4d0e | 251 | } |
mbed_official | 17:6bf7972c4d0e | 252 | |
mbed_official | 17:6bf7972c4d0e | 253 | /** This is called by Gap to notify the application we disconnected, |
mbed_official | 17:6bf7972c4d0e | 254 | * in our case it ends the demonstration. */ |
mbed_official | 17:6bf7972c4d0e | 255 | virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &) |
mbed_official | 17:6bf7972c4d0e | 256 | { |
mbed_official | 17:6bf7972c4d0e | 257 | printf("Diconnected\r\n"); |
mbed_official | 17:6bf7972c4d0e | 258 | _event_queue.break_dispatch(); |
mbed_official | 17:6bf7972c4d0e | 259 | }; |
mbed_official | 17:6bf7972c4d0e | 260 | |
mbed_official | 17:6bf7972c4d0e | 261 | virtual void onAdvertisingEnd(const ble::AdvertisingEndEvent &) |
mbed_official | 17:6bf7972c4d0e | 262 | { |
mbed_official | 17:6bf7972c4d0e | 263 | printf("Advertising timed out - aborting\r\n"); |
mbed_official | 17:6bf7972c4d0e | 264 | _event_queue.break_dispatch(); |
mbed_official | 17:6bf7972c4d0e | 265 | } |
mbed_official | 17:6bf7972c4d0e | 266 | |
mbed_official | 17:6bf7972c4d0e | 267 | virtual void onScanTimeout(const ble::ScanTimeoutEvent &) |
mbed_official | 17:6bf7972c4d0e | 268 | { |
mbed_official | 17:6bf7972c4d0e | 269 | printf("Scan timed out - aborting\r\n"); |
mbed_official | 17:6bf7972c4d0e | 270 | _event_queue.break_dispatch(); |
mbed_official | 17:6bf7972c4d0e | 271 | } |
mbed_official | 17:6bf7972c4d0e | 272 | |
mbed_official | 17:6bf7972c4d0e | 273 | private: |
Donatien Garnier |
1:916188eae2bb | 274 | DigitalOut _led1; |
Donatien Garnier |
1:916188eae2bb | 275 | |
Donatien Garnier |
1:916188eae2bb | 276 | protected: |
Donatien Garnier |
1:916188eae2bb | 277 | BLE &_ble; |
Donatien Garnier |
1:916188eae2bb | 278 | events::EventQueue &_event_queue; |
Donatien Garnier |
1:916188eae2bb | 279 | BLEProtocol::AddressBytes_t &_peer_address; |
Donatien Garnier |
1:916188eae2bb | 280 | ble::connection_handle_t _handle; |
Donatien Garnier |
1:916188eae2bb | 281 | bool _is_connecting; |
Donatien Garnier |
1:916188eae2bb | 282 | }; |
Donatien Garnier |
1:916188eae2bb | 283 | |
Donatien Garnier |
1:916188eae2bb | 284 | /** A peripheral device will advertise, accept the connection and request |
Donatien Garnier |
1:916188eae2bb | 285 | * a change in link security. */ |
Donatien Garnier |
1:916188eae2bb | 286 | class SMDevicePeripheral : public SMDevice { |
Donatien Garnier |
1:916188eae2bb | 287 | public: |
Donatien Garnier |
1:916188eae2bb | 288 | SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) |
Donatien Garnier |
1:916188eae2bb | 289 | : SMDevice(ble, event_queue, peer_address) { } |
Donatien Garnier |
1:916188eae2bb | 290 | |
Donatien Garnier |
1:916188eae2bb | 291 | virtual void start() |
Donatien Garnier |
1:916188eae2bb | 292 | { |
Donatien Garnier |
1:916188eae2bb | 293 | /* Set up and start advertising */ |
mbed_official | 17:6bf7972c4d0e | 294 | uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE]; |
mbed_official | 17:6bf7972c4d0e | 295 | /* use the helper to build the payload */ |
mbed_official | 17:6bf7972c4d0e | 296 | ble::AdvertisingDataBuilder adv_data_builder( |
mbed_official | 17:6bf7972c4d0e | 297 | adv_buffer |
Donatien Garnier |
1:916188eae2bb | 298 | ); |
Donatien Garnier |
1:916188eae2bb | 299 | |
mbed_official | 17:6bf7972c4d0e | 300 | adv_data_builder.setFlags(); |
mbed_official | 17:6bf7972c4d0e | 301 | adv_data_builder.setName(DEVICE_NAME); |
mbed_official | 17:6bf7972c4d0e | 302 | |
mbed_official | 17:6bf7972c4d0e | 303 | /* Set payload for the set */ |
mbed_official | 17:6bf7972c4d0e | 304 | ble_error_t error = _ble.gap().setAdvertisingPayload( |
mbed_official | 17:6bf7972c4d0e | 305 | ble::LEGACY_ADVERTISING_HANDLE, |
mbed_official | 17:6bf7972c4d0e | 306 | adv_data_builder.getAdvertisingData() |
mbed_official | 17:6bf7972c4d0e | 307 | ); |
Donatien Garnier |
1:916188eae2bb | 308 | |
Donatien Garnier |
1:916188eae2bb | 309 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 310 | print_error(error, "Gap::setAdvertisingPayload() failed"); |
mbed_official | 17:6bf7972c4d0e | 311 | _event_queue.break_dispatch(); |
Donatien Garnier |
1:916188eae2bb | 312 | return; |
Donatien Garnier |
1:916188eae2bb | 313 | } |
Donatien Garnier |
1:916188eae2bb | 314 | |
mbed_official | 17:6bf7972c4d0e | 315 | ble::AdvertisingParameters adv_parameters( |
mbed_official | 17:6bf7972c4d0e | 316 | ble::advertising_type_t::CONNECTABLE_UNDIRECTED |
mbed_official | 17:6bf7972c4d0e | 317 | ); |
Donatien Garnier |
1:916188eae2bb | 318 | |
mbed_official | 17:6bf7972c4d0e | 319 | error = _ble.gap().setAdvertisingParameters( |
mbed_official | 17:6bf7972c4d0e | 320 | ble::LEGACY_ADVERTISING_HANDLE, |
mbed_official | 17:6bf7972c4d0e | 321 | adv_parameters |
mbed_official | 17:6bf7972c4d0e | 322 | ); |
Donatien Garnier |
1:916188eae2bb | 323 | |
Donatien Garnier |
1:916188eae2bb | 324 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 325 | print_error(error, "Gap::setAdvertisingParameters() failed"); |
mbed_official | 17:6bf7972c4d0e | 326 | return; |
mbed_official | 17:6bf7972c4d0e | 327 | } |
mbed_official | 17:6bf7972c4d0e | 328 | |
mbed_official | 17:6bf7972c4d0e | 329 | error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); |
mbed_official | 17:6bf7972c4d0e | 330 | |
mbed_official | 17:6bf7972c4d0e | 331 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 332 | print_error(error, "Gap::startAdvertising() failed"); |
Donatien Garnier |
1:916188eae2bb | 333 | return; |
Donatien Garnier |
1:916188eae2bb | 334 | } |
Donatien Garnier |
1:916188eae2bb | 335 | |
mbed_official | 9:674ab70e0f36 | 336 | printf("Please connect to device\r\n"); |
mbed_official | 9:674ab70e0f36 | 337 | |
Donatien Garnier |
1:916188eae2bb | 338 | /** This tells the stack to generate a pairingRequest event |
Donatien Garnier |
1:916188eae2bb | 339 | * which will require this application to respond before pairing |
Donatien Garnier |
1:916188eae2bb | 340 | * can proceed. Setting it to false will automatically accept |
Donatien Garnier |
1:916188eae2bb | 341 | * pairing. */ |
Donatien Garnier |
1:916188eae2bb | 342 | _ble.securityManager().setPairingRequestAuthorisation(true); |
Donatien Garnier |
1:916188eae2bb | 343 | }; |
Donatien Garnier |
1:916188eae2bb | 344 | |
Donatien Garnier |
1:916188eae2bb | 345 | /** This is called by Gap to notify the application we connected, |
Donatien Garnier |
1:916188eae2bb | 346 | * in our case it immediately requests a change in link security */ |
mbed_official | 17:6bf7972c4d0e | 347 | virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) |
Donatien Garnier |
1:916188eae2bb | 348 | { |
Donatien Garnier |
1:916188eae2bb | 349 | ble_error_t error; |
Donatien Garnier |
1:916188eae2bb | 350 | |
Donatien Garnier |
1:916188eae2bb | 351 | /* remember the device that connects to us now so we can connect to it |
Donatien Garnier |
1:916188eae2bb | 352 | * during the next demonstration */ |
mbed_official | 17:6bf7972c4d0e | 353 | memcpy(_peer_address, event.getPeerAddress().data(), sizeof(_peer_address)); |
Donatien Garnier |
1:916188eae2bb | 354 | |
mbed_official | 17:6bf7972c4d0e | 355 | printf("Connected to peer: "); |
mbed_official | 17:6bf7972c4d0e | 356 | print_address(event.getPeerAddress().data()); |
mbed_official | 9:674ab70e0f36 | 357 | |
mbed_official | 17:6bf7972c4d0e | 358 | _handle = event.getConnectionHandle(); |
Donatien Garnier |
1:916188eae2bb | 359 | |
Donatien Garnier |
1:916188eae2bb | 360 | /* Request a change in link security. This will be done |
Donatien Garnier |
1:916188eae2bb | 361 | * indirectly by asking the master of the connection to |
Donatien Garnier |
1:916188eae2bb | 362 | * change it. Depending on circumstances different actions |
Donatien Garnier |
1:916188eae2bb | 363 | * may be taken by the master which will trigger events |
Donatien Garnier |
1:916188eae2bb | 364 | * which the applications should deal with. */ |
Donatien Garnier |
1:916188eae2bb | 365 | error = _ble.securityManager().setLinkSecurity( |
Donatien Garnier |
1:916188eae2bb | 366 | _handle, |
Donatien Garnier |
1:916188eae2bb | 367 | SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM |
Donatien Garnier |
1:916188eae2bb | 368 | ); |
Donatien Garnier |
1:916188eae2bb | 369 | |
Donatien Garnier |
1:916188eae2bb | 370 | if (error) { |
Donatien Garnier |
1:916188eae2bb | 371 | printf("Error during SM::setLinkSecurity %d\r\n", error); |
Donatien Garnier |
1:916188eae2bb | 372 | return; |
Donatien Garnier |
1:916188eae2bb | 373 | } |
Donatien Garnier |
1:916188eae2bb | 374 | }; |
Donatien Garnier |
1:916188eae2bb | 375 | }; |
Donatien Garnier |
1:916188eae2bb | 376 | |
Donatien Garnier |
1:916188eae2bb | 377 | /** A central device will scan, connect to a peer and request pairing. */ |
Donatien Garnier |
1:916188eae2bb | 378 | class SMDeviceCentral : public SMDevice { |
Donatien Garnier |
1:916188eae2bb | 379 | public: |
Donatien Garnier |
1:916188eae2bb | 380 | SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) |
Donatien Garnier |
1:916188eae2bb | 381 | : SMDevice(ble, event_queue, peer_address) { } |
Donatien Garnier |
1:916188eae2bb | 382 | |
Donatien Garnier |
1:916188eae2bb | 383 | virtual void start() |
Donatien Garnier |
1:916188eae2bb | 384 | { |
mbed_official | 17:6bf7972c4d0e | 385 | ble::ScanParameters params; |
mbed_official | 17:6bf7972c4d0e | 386 | ble_error_t error = _ble.gap().setScanParameters(params); |
mbed_official | 17:6bf7972c4d0e | 387 | |
mbed_official | 17:6bf7972c4d0e | 388 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 389 | print_error(error, "Error in Gap::startScan %d\r\n"); |
mbed_official | 17:6bf7972c4d0e | 390 | return; |
mbed_official | 17:6bf7972c4d0e | 391 | } |
mbed_official | 17:6bf7972c4d0e | 392 | |
mbed_official | 17:6bf7972c4d0e | 393 | /* start scanning, results will be handled by onAdvertisingReport */ |
mbed_official | 17:6bf7972c4d0e | 394 | error = _ble.gap().startScan(); |
mbed_official | 17:6bf7972c4d0e | 395 | |
mbed_official | 17:6bf7972c4d0e | 396 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 397 | print_error(error, "Error in Gap::startScan %d\r\n"); |
mbed_official | 17:6bf7972c4d0e | 398 | return; |
mbed_official | 17:6bf7972c4d0e | 399 | } |
Donatien Garnier |
1:916188eae2bb | 400 | |
mbed_official | 9:674ab70e0f36 | 401 | printf("Please advertise\r\n"); |
mbed_official | 9:674ab70e0f36 | 402 | |
mbed_official | 17:6bf7972c4d0e | 403 | printf("Scanning for: "); |
mbed_official | 17:6bf7972c4d0e | 404 | print_address(_peer_address); |
Donatien Garnier |
1:916188eae2bb | 405 | } |
Donatien Garnier |
1:916188eae2bb | 406 | |
mbed_official | 17:6bf7972c4d0e | 407 | private: |
mbed_official | 17:6bf7972c4d0e | 408 | /* Gap::EventHandler */ |
mbed_official | 17:6bf7972c4d0e | 409 | |
Donatien Garnier |
1:916188eae2bb | 410 | /** Look at scan payload to find a peer device and connect to it */ |
mbed_official | 17:6bf7972c4d0e | 411 | virtual void onAdvertisingReport(const ble::AdvertisingReportEvent &event) |
Donatien Garnier |
1:916188eae2bb | 412 | { |
Donatien Garnier |
1:916188eae2bb | 413 | /* don't bother with analysing scan result if we're already connecting */ |
Donatien Garnier |
1:916188eae2bb | 414 | if (_is_connecting) { |
Donatien Garnier |
1:916188eae2bb | 415 | return; |
Donatien Garnier |
1:916188eae2bb | 416 | } |
Donatien Garnier |
1:916188eae2bb | 417 | |
mbed_official | 17:6bf7972c4d0e | 418 | /* parse the advertising payload, looking for a discoverable device */ |
mbed_official | 17:6bf7972c4d0e | 419 | if (memcmp(event.getPeerAddress().data(), _peer_address, sizeof(_peer_address)) == 0) { |
mbed_official | 17:6bf7972c4d0e | 420 | ble_error_t error = _ble.gap().stopScan(); |
mbed_official | 17:6bf7972c4d0e | 421 | |
mbed_official | 17:6bf7972c4d0e | 422 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 423 | print_error(error, "Error caused by Gap::stopScan"); |
mbed_official | 17:6bf7972c4d0e | 424 | return; |
mbed_official | 17:6bf7972c4d0e | 425 | } |
Donatien Garnier |
1:916188eae2bb | 426 | |
mbed_official | 17:6bf7972c4d0e | 427 | ble::ConnectionParameters connection_params( |
mbed_official | 17:6bf7972c4d0e | 428 | ble::phy_t::LE_1M, |
mbed_official | 17:6bf7972c4d0e | 429 | ble::scan_interval_t(50), |
mbed_official | 17:6bf7972c4d0e | 430 | ble::scan_window_t(50), |
mbed_official | 17:6bf7972c4d0e | 431 | ble::conn_interval_t(50), |
mbed_official | 17:6bf7972c4d0e | 432 | ble::conn_interval_t(100), |
mbed_official | 17:6bf7972c4d0e | 433 | ble::slave_latency_t(0), |
mbed_official | 17:6bf7972c4d0e | 434 | ble::supervision_timeout_t(100) |
mbed_official | 17:6bf7972c4d0e | 435 | ); |
mbed_official | 17:6bf7972c4d0e | 436 | connection_params.setOwnAddressType(ble::own_address_type_t::RANDOM); |
mbed_official | 17:6bf7972c4d0e | 437 | |
mbed_official | 17:6bf7972c4d0e | 438 | error = _ble.gap().connect( |
mbed_official | 17:6bf7972c4d0e | 439 | event.getPeerAddressType(), |
mbed_official | 17:6bf7972c4d0e | 440 | event.getPeerAddress(), |
mbed_official | 17:6bf7972c4d0e | 441 | connection_params |
mbed_official | 9:674ab70e0f36 | 442 | ); |
Donatien Garnier |
1:916188eae2bb | 443 | |
mbed_official | 9:674ab70e0f36 | 444 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 445 | print_error(error, "Error caused by Gap::connect"); |
Donatien Garnier |
1:916188eae2bb | 446 | return; |
Donatien Garnier |
1:916188eae2bb | 447 | } |
Donatien Garnier |
1:916188eae2bb | 448 | |
mbed_official | 9:674ab70e0f36 | 449 | /* we may have already scan events waiting |
mbed_official | 9:674ab70e0f36 | 450 | * to be processed so we need to remember |
mbed_official | 9:674ab70e0f36 | 451 | * that we are already connecting and ignore them */ |
mbed_official | 9:674ab70e0f36 | 452 | _is_connecting = true; |
mbed_official | 9:674ab70e0f36 | 453 | |
mbed_official | 9:674ab70e0f36 | 454 | return; |
Donatien Garnier |
1:916188eae2bb | 455 | } |
mbed_official | 17:6bf7972c4d0e | 456 | } |
Donatien Garnier |
1:916188eae2bb | 457 | |
Donatien Garnier |
1:916188eae2bb | 458 | /** This is called by Gap to notify the application we connected, |
Donatien Garnier |
1:916188eae2bb | 459 | * in our case it immediately request pairing */ |
mbed_official | 17:6bf7972c4d0e | 460 | virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) |
Donatien Garnier |
1:916188eae2bb | 461 | { |
mbed_official | 17:6bf7972c4d0e | 462 | if (event.getStatus() == BLE_ERROR_NONE) { |
mbed_official | 17:6bf7972c4d0e | 463 | /* store the handle for future Security Manager requests */ |
mbed_official | 17:6bf7972c4d0e | 464 | _handle = event.getConnectionHandle(); |
mbed_official | 17:6bf7972c4d0e | 465 | |
mbed_official | 17:6bf7972c4d0e | 466 | printf("Connected\r\n"); |
mbed_official | 17:6bf7972c4d0e | 467 | |
mbed_official | 17:6bf7972c4d0e | 468 | /* in this example the local device is the master so we request pairing */ |
mbed_official | 17:6bf7972c4d0e | 469 | ble_error_t error = _ble.securityManager().requestPairing(_handle); |
Donatien Garnier |
1:916188eae2bb | 470 | |
mbed_official | 17:6bf7972c4d0e | 471 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 472 | printf("Error during SM::requestPairing %d\r\n", error); |
mbed_official | 17:6bf7972c4d0e | 473 | return; |
mbed_official | 17:6bf7972c4d0e | 474 | } |
Donatien Garnier |
1:916188eae2bb | 475 | |
mbed_official | 17:6bf7972c4d0e | 476 | /* upon pairing success the application will disconnect */ |
mbed_official | 17:6bf7972c4d0e | 477 | } |
Donatien Garnier |
1:916188eae2bb | 478 | |
mbed_official | 17:6bf7972c4d0e | 479 | /* failed to connect - restart scan */ |
mbed_official | 17:6bf7972c4d0e | 480 | ble_error_t error = _ble.gap().startScan(); |
mbed_official | 9:674ab70e0f36 | 481 | |
Donatien Garnier |
1:916188eae2bb | 482 | if (error) { |
mbed_official | 17:6bf7972c4d0e | 483 | print_error(error, "Error in Gap::startScan %d\r\n"); |
Donatien Garnier |
1:916188eae2bb | 484 | return; |
Donatien Garnier |
1:916188eae2bb | 485 | } |
Donatien Garnier |
1:916188eae2bb | 486 | }; |
Donatien Garnier |
1:916188eae2bb | 487 | }; |
Donatien Garnier |
1:916188eae2bb | 488 | |
mbed_official | 9:674ab70e0f36 | 489 | |
mbed_official | 9:674ab70e0f36 | 490 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
mbed_official | 9:674ab70e0f36 | 491 | bool create_filesystem() |
mbed_official | 9:674ab70e0f36 | 492 | { |
mbed_official | 9:674ab70e0f36 | 493 | static LittleFileSystem fs("fs"); |
mbed_official | 9:674ab70e0f36 | 494 | |
mbed_official | 9:674ab70e0f36 | 495 | /* replace this with any physical block device your board supports (like an SD card) */ |
mbed_official | 9:674ab70e0f36 | 496 | static HeapBlockDevice bd(4096, 256); |
mbed_official | 9:674ab70e0f36 | 497 | |
mbed_official | 9:674ab70e0f36 | 498 | int err = bd.init(); |
mbed_official | 9:674ab70e0f36 | 499 | |
mbed_official | 9:674ab70e0f36 | 500 | if (err) { |
mbed_official | 9:674ab70e0f36 | 501 | return false; |
mbed_official | 9:674ab70e0f36 | 502 | } |
mbed_official | 9:674ab70e0f36 | 503 | |
mbed_official | 9:674ab70e0f36 | 504 | err = bd.erase(0, bd.size()); |
mbed_official | 9:674ab70e0f36 | 505 | |
mbed_official | 9:674ab70e0f36 | 506 | if (err) { |
mbed_official | 9:674ab70e0f36 | 507 | return false; |
mbed_official | 9:674ab70e0f36 | 508 | } |
mbed_official | 9:674ab70e0f36 | 509 | |
mbed_official | 9:674ab70e0f36 | 510 | err = fs.mount(&bd); |
mbed_official | 9:674ab70e0f36 | 511 | |
mbed_official | 9:674ab70e0f36 | 512 | if (err) { |
mbed_official | 9:674ab70e0f36 | 513 | /* Reformat if we can't mount the filesystem */ |
mbed_official | 9:674ab70e0f36 | 514 | printf("No filesystem found, formatting...\r\n"); |
mbed_official | 9:674ab70e0f36 | 515 | |
mbed_official | 9:674ab70e0f36 | 516 | err = fs.reformat(&bd); |
mbed_official | 9:674ab70e0f36 | 517 | |
mbed_official | 9:674ab70e0f36 | 518 | if (err) { |
mbed_official | 9:674ab70e0f36 | 519 | return false; |
mbed_official | 9:674ab70e0f36 | 520 | } |
mbed_official | 9:674ab70e0f36 | 521 | } |
mbed_official | 9:674ab70e0f36 | 522 | |
mbed_official | 9:674ab70e0f36 | 523 | return true; |
mbed_official | 9:674ab70e0f36 | 524 | } |
mbed_official | 9:674ab70e0f36 | 525 | #endif //MBED_CONF_APP_FILESYSTEM_SUPPORT |
mbed_official | 9:674ab70e0f36 | 526 | |
Donatien Garnier |
1:916188eae2bb | 527 | int main() |
Donatien Garnier |
1:916188eae2bb | 528 | { |
Donatien Garnier |
1:916188eae2bb | 529 | BLE& ble = BLE::Instance(); |
Donatien Garnier |
1:916188eae2bb | 530 | events::EventQueue queue; |
Donatien Garnier |
1:916188eae2bb | 531 | |
mbed_official | 9:674ab70e0f36 | 532 | #if MBED_CONF_APP_FILESYSTEM_SUPPORT |
mbed_official | 9:674ab70e0f36 | 533 | /* if filesystem creation fails or there is no filesystem the security manager |
mbed_official | 9:674ab70e0f36 | 534 | * will fallback to storing the security database in memory */ |
mbed_official | 9:674ab70e0f36 | 535 | if (!create_filesystem()) { |
mbed_official | 9:674ab70e0f36 | 536 | printf("Filesystem creation failed, will use memory storage\r\n"); |
Donatien Garnier |
1:916188eae2bb | 537 | } |
mbed_official | 9:674ab70e0f36 | 538 | #endif |
Donatien Garnier |
1:916188eae2bb | 539 | |
mbed_official | 9:674ab70e0f36 | 540 | while(1) { |
mbed_official | 9:674ab70e0f36 | 541 | { |
mbed_official | 9:674ab70e0f36 | 542 | printf("\r\n PERIPHERAL \r\n\r\n"); |
mbed_official | 9:674ab70e0f36 | 543 | SMDevicePeripheral peripheral(ble, queue, peer_address); |
mbed_official | 9:674ab70e0f36 | 544 | peripheral.run(); |
mbed_official | 9:674ab70e0f36 | 545 | } |
mbed_official | 9:674ab70e0f36 | 546 | |
mbed_official | 9:674ab70e0f36 | 547 | { |
mbed_official | 9:674ab70e0f36 | 548 | printf("\r\n CENTRAL \r\n\r\n"); |
mbed_official | 9:674ab70e0f36 | 549 | SMDeviceCentral central(ble, queue, peer_address); |
mbed_official | 9:674ab70e0f36 | 550 | central.run(); |
mbed_official | 9:674ab70e0f36 | 551 | } |
Donatien Garnier |
1:916188eae2bb | 552 | } |
Donatien Garnier |
1:916188eae2bb | 553 | |
Donatien Garnier |
1:916188eae2bb | 554 | return 0; |
Donatien Garnier |
1:916188eae2bb | 555 | } |