Eddystone test using modified DAL
Dependencies: BLE_API mbed-dev-bin nRF51822
Dependents: microbit-eddystone
Fork of microbit-dal by
source/bluetooth/MicroBitBLEManager.cpp@35:8ce23bc1af38, 2016-07-13 (annotated)
- Committer:
- LancasterUniversity
- Date:
- Wed Jul 13 12:18:14 2016 +0100
- Revision:
- 35:8ce23bc1af38
- Parent:
- 32:ece16b5987dd
- Child:
- 37:b624ae5e94a5
Synchronized with git rev 732971e7
Author: James Devine
microbit-dal: Added events to MicroBitPin
Added rise, fall, pulse HI and LO events.
The pulse Hi and LO event timestamp given in the MicroBitEvent is the
duration for which the input was HI or LO for.
eventOn(int eventType) is used to configure the events generated
from the pin instance.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Jonathan Austin |
1:8aa5cdb4ab67 | 1 | /* |
Jonathan Austin |
1:8aa5cdb4ab67 | 2 | The MIT License (MIT) |
Jonathan Austin |
1:8aa5cdb4ab67 | 3 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 4 | Copyright (c) 2016 British Broadcasting Corporation. |
Jonathan Austin |
1:8aa5cdb4ab67 | 5 | This software is provided by Lancaster University by arrangement with the BBC. |
Jonathan Austin |
1:8aa5cdb4ab67 | 6 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 7 | Permission is hereby granted, free of charge, to any person obtaining a |
Jonathan Austin |
1:8aa5cdb4ab67 | 8 | copy of this software and associated documentation files (the "Software"), |
Jonathan Austin |
1:8aa5cdb4ab67 | 9 | to deal in the Software without restriction, including without limitation |
Jonathan Austin |
1:8aa5cdb4ab67 | 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, |
Jonathan Austin |
1:8aa5cdb4ab67 | 11 | and/or sell copies of the Software, and to permit persons to whom the |
Jonathan Austin |
1:8aa5cdb4ab67 | 12 | Software is furnished to do so, subject to the following conditions: |
Jonathan Austin |
1:8aa5cdb4ab67 | 13 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 14 | The above copyright notice and this permission notice shall be included in |
Jonathan Austin |
1:8aa5cdb4ab67 | 15 | all copies or substantial portions of the Software. |
Jonathan Austin |
1:8aa5cdb4ab67 | 16 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
Jonathan Austin |
1:8aa5cdb4ab67 | 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
Jonathan Austin |
1:8aa5cdb4ab67 | 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
Jonathan Austin |
1:8aa5cdb4ab67 | 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
Jonathan Austin |
1:8aa5cdb4ab67 | 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
Jonathan Austin |
1:8aa5cdb4ab67 | 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
Jonathan Austin |
1:8aa5cdb4ab67 | 23 | DEALINGS IN THE SOFTWARE. |
Jonathan Austin |
1:8aa5cdb4ab67 | 24 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 25 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 26 | #include "MicroBitConfig.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 27 | #include "MicroBitBLEManager.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 28 | #include "MicroBitStorage.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 29 | #include "MicroBitFiber.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 30 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 31 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 32 | /* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ. |
Jonathan Austin |
1:8aa5cdb4ab67 | 33 | * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 34 | * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this |
Jonathan Austin |
1:8aa5cdb4ab67 | 35 | * as a compatability option, but does not support the options used... |
Jonathan Austin |
1:8aa5cdb4ab67 | 36 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 37 | #if !defined(__arm) |
Jonathan Austin |
1:8aa5cdb4ab67 | 38 | #pragma GCC diagnostic ignored "-Wunused-function" |
Jonathan Austin |
1:8aa5cdb4ab67 | 39 | #pragma GCC diagnostic push |
Jonathan Austin |
1:8aa5cdb4ab67 | 40 | #pragma GCC diagnostic ignored "-Wunused-parameter" |
Jonathan Austin |
1:8aa5cdb4ab67 | 41 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 42 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 43 | #include "ble.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 44 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 45 | extern "C" |
Jonathan Austin |
1:8aa5cdb4ab67 | 46 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 47 | #include "device_manager.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 48 | uint32_t btle_set_gatt_table_size(uint32_t size); |
Jonathan Austin |
1:8aa5cdb4ab67 | 49 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 50 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 51 | /* |
Jonathan Austin |
1:8aa5cdb4ab67 | 52 | * Return to our predefined compiler settings. |
Jonathan Austin |
1:8aa5cdb4ab67 | 53 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 54 | #if !defined(__arm) |
Jonathan Austin |
1:8aa5cdb4ab67 | 55 | #pragma GCC diagnostic pop |
Jonathan Austin |
1:8aa5cdb4ab67 | 56 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 57 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 58 | #define MICROBIT_PAIRING_FADE_SPEED 4 |
Jonathan Austin |
1:8aa5cdb4ab67 | 59 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 60 | const char* MICROBIT_BLE_MANUFACTURER = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 61 | const char* MICROBIT_BLE_MODEL = "BBC micro:bit"; |
Jonathan Austin |
1:8aa5cdb4ab67 | 62 | const char* MICROBIT_BLE_HARDWARE_VERSION = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 63 | const char* MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION; |
Jonathan Austin |
1:8aa5cdb4ab67 | 64 | const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 65 | const int8_t MICROBIT_BLE_POWER_LEVEL[] = {-30, -20, -16, -12, -8, -4, 0, 4}; |
Jonathan Austin |
1:8aa5cdb4ab67 | 66 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 67 | /* |
Jonathan Austin |
1:8aa5cdb4ab67 | 68 | * Many of the mbed interfaces we need to use only support callbacks to plain C functions, rather than C++ methods. |
Jonathan Austin |
1:8aa5cdb4ab67 | 69 | * So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit |
Jonathan Austin |
1:8aa5cdb4ab67 | 70 | * whilst keeping the code modular. |
Jonathan Austin |
1:8aa5cdb4ab67 | 71 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 72 | static MicroBitBLEManager *manager = NULL; // Singleton reference to the BLE manager. many mbed BLE API callbacks still do not support member funcions yet. :-( |
Jonathan Austin |
1:8aa5cdb4ab67 | 73 | static uint8_t deviceID = 255; // Unique ID for the peer that has connected to us. |
Jonathan Austin |
1:8aa5cdb4ab67 | 74 | static Gap::Handle_t pairingHandle = 0; // The connection handle used during a pairing process. Used to ensure that connections are dropped elegantly. |
Jonathan Austin |
1:8aa5cdb4ab67 | 75 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 76 | static void storeSystemAttributes(Gap::Handle_t handle) |
Jonathan Austin |
1:8aa5cdb4ab67 | 77 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 78 | if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS) |
Jonathan Austin |
1:8aa5cdb4ab67 | 79 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 80 | ManagedString key("bleSysAttrs"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 81 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 82 | KeyValuePair* bleSysAttrs = manager->storage->get(key); |
Jonathan Austin |
1:8aa5cdb4ab67 | 83 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 84 | BLESysAttribute attrib; |
Jonathan Austin |
1:8aa5cdb4ab67 | 85 | BLESysAttributeStore attribStore; |
Jonathan Austin |
1:8aa5cdb4ab67 | 86 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 87 | uint16_t len = sizeof(attrib.sys_attr); |
Jonathan Austin |
1:8aa5cdb4ab67 | 88 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 89 | sd_ble_gatts_sys_attr_get(handle, attrib.sys_attr, &len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); |
Jonathan Austin |
1:8aa5cdb4ab67 | 90 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 91 | //copy our stored sysAttrs |
Jonathan Austin |
1:8aa5cdb4ab67 | 92 | if(bleSysAttrs != NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 93 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 94 | memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore)); |
Jonathan Austin |
1:8aa5cdb4ab67 | 95 | delete bleSysAttrs; |
Jonathan Austin |
1:8aa5cdb4ab67 | 96 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 97 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 98 | //check if we need to update |
Jonathan Austin |
1:8aa5cdb4ab67 | 99 | if(memcmp(attribStore.sys_attrs[deviceID].sys_attr, attrib.sys_attr, len) != 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 100 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 101 | attribStore.sys_attrs[deviceID] = attrib; |
LancasterUniversity | 35:8ce23bc1af38 | 102 | manager->storage->put(key, (uint8_t *)&attribStore); |
Jonathan Austin |
1:8aa5cdb4ab67 | 103 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 104 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 105 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 106 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 107 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 108 | * Callback when a BLE GATT disconnect occurs. |
Jonathan Austin |
1:8aa5cdb4ab67 | 109 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 110 | static void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *reason) |
Jonathan Austin |
1:8aa5cdb4ab67 | 111 | { |
LancasterUniversity | 23:6055f6c19fa6 | 112 | MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_DISCONNECTED); |
LancasterUniversity | 26:493daf8966fd | 113 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 114 | storeSystemAttributes(reason->handle); |
Jonathan Austin |
1:8aa5cdb4ab67 | 115 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 116 | if (manager) |
Jonathan Austin |
1:8aa5cdb4ab67 | 117 | manager->advertise(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 118 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 119 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 120 | /** |
LancasterUniversity | 23:6055f6c19fa6 | 121 | * Callback when a BLE connection is established. |
LancasterUniversity | 23:6055f6c19fa6 | 122 | */ |
LancasterUniversity | 26:493daf8966fd | 123 | static void bleConnectionCallback(const Gap::ConnectionCallbackParams_t*) |
LancasterUniversity | 23:6055f6c19fa6 | 124 | { |
LancasterUniversity | 23:6055f6c19fa6 | 125 | MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_CONNECTED); |
LancasterUniversity | 23:6055f6c19fa6 | 126 | } |
LancasterUniversity | 23:6055f6c19fa6 | 127 | |
LancasterUniversity | 23:6055f6c19fa6 | 128 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 129 | * Callback when a BLE SYS_ATTR_MISSING. |
Jonathan Austin |
1:8aa5cdb4ab67 | 130 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 131 | static void bleSysAttrMissingCallback(const GattSysAttrMissingCallbackParams *params) |
Jonathan Austin |
1:8aa5cdb4ab67 | 132 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 133 | int complete = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 134 | deviceID = 255; |
Jonathan Austin |
1:8aa5cdb4ab67 | 135 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 136 | dm_handle_t dm_handle = {0,0,0,0}; |
Jonathan Austin |
1:8aa5cdb4ab67 | 137 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 138 | int ret = dm_handle_get(params->connHandle, &dm_handle); |
Jonathan Austin |
1:8aa5cdb4ab67 | 139 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 140 | if (ret == 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 141 | deviceID = dm_handle.device_id; |
Jonathan Austin |
1:8aa5cdb4ab67 | 142 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 143 | if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS) |
Jonathan Austin |
1:8aa5cdb4ab67 | 144 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 145 | ManagedString key("bleSysAttrs"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 146 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 147 | KeyValuePair* bleSysAttrs = manager->storage->get(key); |
Jonathan Austin |
1:8aa5cdb4ab67 | 148 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 149 | BLESysAttributeStore attribStore; |
Jonathan Austin |
1:8aa5cdb4ab67 | 150 | BLESysAttribute attrib; |
Jonathan Austin |
1:8aa5cdb4ab67 | 151 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 152 | if(bleSysAttrs != NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 153 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 154 | //restore our sysAttrStore |
Jonathan Austin |
1:8aa5cdb4ab67 | 155 | memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore)); |
Jonathan Austin |
1:8aa5cdb4ab67 | 156 | delete bleSysAttrs; |
Jonathan Austin |
1:8aa5cdb4ab67 | 157 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 158 | attrib = attribStore.sys_attrs[deviceID]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 159 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 160 | ret = sd_ble_gatts_sys_attr_set(params->connHandle, attrib.sys_attr, sizeof(attrib.sys_attr), BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); |
Jonathan Austin |
1:8aa5cdb4ab67 | 161 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 162 | complete = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 163 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 164 | if(ret == 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 165 | ret = sd_ble_gatts_service_changed(params->connHandle, 0x000c, 0xffff); |
Jonathan Austin |
1:8aa5cdb4ab67 | 166 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 167 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 168 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 169 | if (!complete) |
Jonathan Austin |
1:8aa5cdb4ab67 | 170 | sd_ble_gatts_sys_attr_set(params->connHandle, NULL, 0, 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 171 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 172 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 173 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 174 | static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) |
Jonathan Austin |
1:8aa5cdb4ab67 | 175 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 176 | (void) handle; /* -Wunused-param */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 177 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 178 | ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN); |
Jonathan Austin |
1:8aa5cdb4ab67 | 179 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 180 | if (manager) |
Jonathan Austin |
1:8aa5cdb4ab67 | 181 | manager->pairingRequested(passKey); |
Jonathan Austin |
1:8aa5cdb4ab67 | 182 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 183 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 184 | static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) |
Jonathan Austin |
1:8aa5cdb4ab67 | 185 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 186 | (void) handle; /* -Wunused-param */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 187 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 188 | dm_handle_t dm_handle = {0,0,0,0}; |
Jonathan Austin |
1:8aa5cdb4ab67 | 189 | int ret = dm_handle_get(handle, &dm_handle); |
Jonathan Austin |
1:8aa5cdb4ab67 | 190 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 191 | if (ret == 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 192 | deviceID = dm_handle.device_id; |
Jonathan Austin |
1:8aa5cdb4ab67 | 193 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 194 | if (manager) |
Jonathan Austin |
1:8aa5cdb4ab67 | 195 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 196 | pairingHandle = handle; |
Jonathan Austin |
1:8aa5cdb4ab67 | 197 | manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS); |
Jonathan Austin |
1:8aa5cdb4ab67 | 198 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 199 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 200 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 201 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 202 | * Constructor. |
Jonathan Austin |
1:8aa5cdb4ab67 | 203 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 204 | * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack. |
Jonathan Austin |
1:8aa5cdb4ab67 | 205 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 206 | * @param _storage an instance of MicroBitStorage used to persist sys attribute information. (This is required for compatability with iOS). |
Jonathan Austin |
1:8aa5cdb4ab67 | 207 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 208 | * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself). |
Jonathan Austin |
1:8aa5cdb4ab67 | 209 | * Hence, the init() member function should be used to initialise the BLE stack. |
Jonathan Austin |
1:8aa5cdb4ab67 | 210 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 211 | MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage& _storage) : |
Jonathan Austin |
1:8aa5cdb4ab67 | 212 | storage(&_storage) |
Jonathan Austin |
1:8aa5cdb4ab67 | 213 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 214 | manager = this; |
Jonathan Austin |
1:8aa5cdb4ab67 | 215 | this->ble = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 216 | this->pairingStatus = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 217 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 218 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 219 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 220 | * Constructor. |
Jonathan Austin |
1:8aa5cdb4ab67 | 221 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 222 | * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack. |
Jonathan Austin |
1:8aa5cdb4ab67 | 223 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 224 | * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself). |
Jonathan Austin |
1:8aa5cdb4ab67 | 225 | * Hence, the init() member function should be used to initialise the BLE stack. |
Jonathan Austin |
1:8aa5cdb4ab67 | 226 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 227 | MicroBitBLEManager::MicroBitBLEManager() : |
Jonathan Austin |
1:8aa5cdb4ab67 | 228 | storage(NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 229 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 230 | manager = this; |
Jonathan Austin |
1:8aa5cdb4ab67 | 231 | this->ble = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 232 | this->pairingStatus = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 233 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 234 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 235 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 236 | * When called, the micro:bit will begin advertising for a predefined period, |
Jonathan Austin |
1:8aa5cdb4ab67 | 237 | * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices. |
Jonathan Austin |
1:8aa5cdb4ab67 | 238 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 239 | void MicroBitBLEManager::advertise() |
Jonathan Austin |
1:8aa5cdb4ab67 | 240 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 241 | if(ble) |
Jonathan Austin |
1:8aa5cdb4ab67 | 242 | ble->gap().startAdvertising(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 243 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 244 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 245 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 246 | * Post constructor initialisation method as the BLE stack cannot be brought |
Jonathan Austin |
1:8aa5cdb4ab67 | 247 | * up in a static context. |
Jonathan Austin |
1:8aa5cdb4ab67 | 248 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 249 | * @param deviceName The name used when advertising |
Jonathan Austin |
1:8aa5cdb4ab67 | 250 | * @param serialNumber The serial number exposed by the device information service |
Jonathan Austin |
1:8aa5cdb4ab67 | 251 | * @param messageBus An instance of an EventModel, used during pairing. |
Jonathan Austin |
1:8aa5cdb4ab67 | 252 | * @param enableBonding If true, the security manager enabled bonding. |
Jonathan Austin |
1:8aa5cdb4ab67 | 253 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 254 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 255 | * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true); |
Jonathan Austin |
1:8aa5cdb4ab67 | 256 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 257 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 258 | void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding) |
Jonathan Austin |
1:8aa5cdb4ab67 | 259 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 260 | ManagedString BLEName("BBC micro:bit"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 261 | this->deviceName = deviceName; |
Jonathan Austin |
1:8aa5cdb4ab67 | 262 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 263 | #if !(CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 264 | ManagedString namePrefix(" ["); |
Jonathan Austin |
1:8aa5cdb4ab67 | 265 | ManagedString namePostfix("]"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 266 | BLEName = BLEName + namePrefix + deviceName + namePostfix; |
Jonathan Austin |
1:8aa5cdb4ab67 | 267 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 268 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 269 | // Start the BLE stack. |
Jonathan Austin |
1:8aa5cdb4ab67 | 270 | #if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD) |
Jonathan Austin |
1:8aa5cdb4ab67 | 271 | btle_set_gatt_table_size(MICROBIT_SD_GATT_TABLE_SIZE); |
Jonathan Austin |
1:8aa5cdb4ab67 | 272 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 273 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 274 | ble = new BLEDevice(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 275 | ble->init(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 276 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 277 | // automatically restart advertising after a device disconnects. |
Jonathan Austin |
1:8aa5cdb4ab67 | 278 | ble->gap().onDisconnection(bleDisconnectionCallback); |
Jonathan Austin |
1:8aa5cdb4ab67 | 279 | ble->gattServer().onSysAttrMissing(bleSysAttrMissingCallback); |
LancasterUniversity | 26:493daf8966fd | 280 | |
LancasterUniversity | 24:3373f1fb0353 | 281 | // generate an event when a Bluetooth connection is established |
LancasterUniversity | 23:6055f6c19fa6 | 282 | ble->gap().onConnection(bleConnectionCallback); |
Jonathan Austin |
1:8aa5cdb4ab67 | 283 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 284 | // Configure the stack to hold onto the CPU during critical timing events. |
Jonathan Austin |
1:8aa5cdb4ab67 | 285 | // mbed-classic performs __disable_irq() calls in its timers that can cause |
Jonathan Austin |
1:8aa5cdb4ab67 | 286 | // MIC failures on secure BLE channels... |
Jonathan Austin |
1:8aa5cdb4ab67 | 287 | ble_common_opt_radio_cpu_mutex_t opt; |
Jonathan Austin |
1:8aa5cdb4ab67 | 288 | opt.enable = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 289 | sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt); |
Jonathan Austin |
1:8aa5cdb4ab67 | 290 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 291 | #if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES) |
Jonathan Austin |
1:8aa5cdb4ab67 | 292 | // Configure for private addresses, so kids' behaviour can't be easily tracked. |
Jonathan Austin |
1:8aa5cdb4ab67 | 293 | ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0}); |
Jonathan Austin |
1:8aa5cdb4ab67 | 294 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 295 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 296 | // Setup our security requirements. |
Jonathan Austin |
1:8aa5cdb4ab67 | 297 | ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback); |
Jonathan Austin |
1:8aa5cdb4ab67 | 298 | ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); |
Jonathan Austin |
1:8aa5cdb4ab67 | 299 | ble->securityManager().init(enableBonding, (SecurityManager::MICROBIT_BLE_SECURITY_LEVEL == SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM), SecurityManager::IO_CAPS_DISPLAY_ONLY); |
Jonathan Austin |
1:8aa5cdb4ab67 | 300 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 301 | if (enableBonding) |
Jonathan Austin |
1:8aa5cdb4ab67 | 302 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 303 | // If we're in pairing mode, review the size of the bond table. |
Jonathan Austin |
1:8aa5cdb4ab67 | 304 | int bonds = getBondCount(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 305 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 306 | // TODO: It would be much better to implement some sort of LRU/NFU policy here, |
Jonathan Austin |
1:8aa5cdb4ab67 | 307 | // but this isn't currently supported in mbed, so we'd need to layer break... |
Jonathan Austin |
1:8aa5cdb4ab67 | 308 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 309 | // If we're full, empty the bond table. |
Jonathan Austin |
1:8aa5cdb4ab67 | 310 | if (bonds >= MICROBIT_BLE_MAXIMUM_BONDS) |
Jonathan Austin |
1:8aa5cdb4ab67 | 311 | ble->securityManager().purgeAllBondingState(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 312 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 313 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 314 | #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) |
Jonathan Austin |
1:8aa5cdb4ab67 | 315 | // Configure a whitelist to filter all connection requetss from unbonded devices. |
Jonathan Austin |
1:8aa5cdb4ab67 | 316 | // Most BLE stacks only permit one connection at a time, so this prevents denial of service attacks. |
Jonathan Austin |
1:8aa5cdb4ab67 | 317 | BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 318 | Gap::Whitelist_t whitelist; |
Jonathan Austin |
1:8aa5cdb4ab67 | 319 | whitelist.addresses = bondedAddresses; |
Jonathan Austin |
1:8aa5cdb4ab67 | 320 | whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS; |
Jonathan Austin |
1:8aa5cdb4ab67 | 321 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 322 | ble->securityManager().getAddressesFromBondTable(whitelist); |
Jonathan Austin |
1:8aa5cdb4ab67 | 323 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 324 | ble->gap().setWhitelist(whitelist); |
Jonathan Austin |
1:8aa5cdb4ab67 | 325 | ble->gap().setScanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST); |
Jonathan Austin |
1:8aa5cdb4ab67 | 326 | ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS); |
Jonathan Austin |
1:8aa5cdb4ab67 | 327 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 328 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 329 | // Configure the radio at our default power level |
Jonathan Austin |
1:8aa5cdb4ab67 | 330 | setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER); |
Jonathan Austin |
1:8aa5cdb4ab67 | 331 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 332 | // Bring up core BLE services. |
LancasterUniversity | 29:62f8b007debf | 333 | #if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE) |
Jonathan Austin |
1:8aa5cdb4ab67 | 334 | new MicroBitDFUService(*ble); |
LancasterUniversity | 29:62f8b007debf | 335 | #endif |
LancasterUniversity | 29:62f8b007debf | 336 | |
LancasterUniversity | 29:62f8b007debf | 337 | #if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE) |
Jonathan Austin |
1:8aa5cdb4ab67 | 338 | DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, serialNumber.toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION); |
LancasterUniversity | 29:62f8b007debf | 339 | #endif |
LancasterUniversity | 29:62f8b007debf | 340 | |
LancasterUniversity | 29:62f8b007debf | 341 | #if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE) |
Jonathan Austin |
1:8aa5cdb4ab67 | 342 | new MicroBitEventService(*ble, messageBus); |
LancasterUniversity | 29:62f8b007debf | 343 | #else |
LancasterUniversity | 29:62f8b007debf | 344 | (void)messageBus; |
LancasterUniversity | 29:62f8b007debf | 345 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 346 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 347 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 348 | // Configure for high speed mode where possible. |
Jonathan Austin |
1:8aa5cdb4ab67 | 349 | Gap::ConnectionParams_t fast; |
Jonathan Austin |
1:8aa5cdb4ab67 | 350 | ble->getPreferredConnectionParams(&fast); |
Jonathan Austin |
1:8aa5cdb4ab67 | 351 | fast.minConnectionInterval = 8; // 10 ms |
Jonathan Austin |
1:8aa5cdb4ab67 | 352 | fast.maxConnectionInterval = 16; // 20 ms |
Jonathan Austin |
1:8aa5cdb4ab67 | 353 | fast.slaveLatency = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 354 | ble->setPreferredConnectionParams(&fast); |
Jonathan Austin |
1:8aa5cdb4ab67 | 355 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 356 | // Setup advertising. |
Jonathan Austin |
1:8aa5cdb4ab67 | 357 | #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) |
Jonathan Austin |
1:8aa5cdb4ab67 | 358 | ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED); |
Jonathan Austin |
1:8aa5cdb4ab67 | 359 | #else |
Jonathan Austin |
1:8aa5cdb4ab67 | 360 | ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
Jonathan Austin |
1:8aa5cdb4ab67 | 361 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 362 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 363 | ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length()); |
Jonathan Austin |
1:8aa5cdb4ab67 | 364 | ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
Jonathan Austin |
1:8aa5cdb4ab67 | 365 | ble->setAdvertisingInterval(200); |
Jonathan Austin |
1:8aa5cdb4ab67 | 366 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 367 | #if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 368 | ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT); |
Jonathan Austin |
1:8aa5cdb4ab67 | 369 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 370 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 371 | // If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices... |
Jonathan Austin |
1:8aa5cdb4ab67 | 372 | // This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable. |
Jonathan Austin |
1:8aa5cdb4ab67 | 373 | // If whiltelisting is disabled, then we always advertise. |
Jonathan Austin |
1:8aa5cdb4ab67 | 374 | #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) |
Jonathan Austin |
1:8aa5cdb4ab67 | 375 | if (whitelist.size > 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 376 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 377 | ble->startAdvertising(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 378 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 379 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 380 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 381 | * Change the output power level of the transmitter to the given value. |
Jonathan Austin |
1:8aa5cdb4ab67 | 382 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 383 | * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. |
Jonathan Austin |
1:8aa5cdb4ab67 | 384 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 385 | * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range. |
Jonathan Austin |
1:8aa5cdb4ab67 | 386 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 387 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 388 | * // maximum transmission power. |
Jonathan Austin |
1:8aa5cdb4ab67 | 389 | * bleManager.setTransmitPower(7); |
Jonathan Austin |
1:8aa5cdb4ab67 | 390 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 391 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 392 | int MicroBitBLEManager::setTransmitPower(int power) |
Jonathan Austin |
1:8aa5cdb4ab67 | 393 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 394 | if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS) |
Jonathan Austin |
1:8aa5cdb4ab67 | 395 | return MICROBIT_INVALID_PARAMETER; |
Jonathan Austin |
1:8aa5cdb4ab67 | 396 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 397 | if (ble->gap().setTxPower(MICROBIT_BLE_POWER_LEVEL[power]) != NRF_SUCCESS) |
Jonathan Austin |
1:8aa5cdb4ab67 | 398 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 399 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 400 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 401 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 402 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 403 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 404 | * Determines the number of devices currently bonded with this micro:bit. |
Jonathan Austin |
1:8aa5cdb4ab67 | 405 | * @return The number of active bonds. |
Jonathan Austin |
1:8aa5cdb4ab67 | 406 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 407 | int MicroBitBLEManager::getBondCount() |
Jonathan Austin |
1:8aa5cdb4ab67 | 408 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 409 | BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 410 | Gap::Whitelist_t whitelist; |
Jonathan Austin |
1:8aa5cdb4ab67 | 411 | whitelist.addresses = bondedAddresses; |
Jonathan Austin |
1:8aa5cdb4ab67 | 412 | whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS; |
Jonathan Austin |
1:8aa5cdb4ab67 | 413 | ble->securityManager().getAddressesFromBondTable(whitelist); |
Jonathan Austin |
1:8aa5cdb4ab67 | 414 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 415 | return whitelist.bonds; |
Jonathan Austin |
1:8aa5cdb4ab67 | 416 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 417 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 418 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 419 | * A request to pair has been received from a BLE device. |
Jonathan Austin |
1:8aa5cdb4ab67 | 420 | * If we're in pairing mode, display the passkey to the user. |
Jonathan Austin |
1:8aa5cdb4ab67 | 421 | * Also, purge the bonding table if it has reached capacity. |
Jonathan Austin |
1:8aa5cdb4ab67 | 422 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 423 | * @note for internal use only. |
Jonathan Austin |
1:8aa5cdb4ab67 | 424 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 425 | void MicroBitBLEManager::pairingRequested(ManagedString passKey) |
Jonathan Austin |
1:8aa5cdb4ab67 | 426 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 427 | // Update our mode to display the passkey. |
Jonathan Austin |
1:8aa5cdb4ab67 | 428 | this->passKey = passKey; |
Jonathan Austin |
1:8aa5cdb4ab67 | 429 | this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST; |
Jonathan Austin |
1:8aa5cdb4ab67 | 430 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 431 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 432 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 433 | * A pairing request has been sucessfully completed. |
Jonathan Austin |
1:8aa5cdb4ab67 | 434 | * If we're in pairing mode, display a success or failure message. |
Jonathan Austin |
1:8aa5cdb4ab67 | 435 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 436 | * @note for internal use only. |
Jonathan Austin |
1:8aa5cdb4ab67 | 437 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 438 | void MicroBitBLEManager::pairingComplete(bool success) |
Jonathan Austin |
1:8aa5cdb4ab67 | 439 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 440 | this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 441 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 442 | if(success) |
Jonathan Austin |
1:8aa5cdb4ab67 | 443 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 444 | this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 445 | fiber_add_idle_component(this); |
Jonathan Austin |
1:8aa5cdb4ab67 | 446 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 447 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 448 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 449 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 450 | * Periodic callback in thread context. |
Jonathan Austin |
1:8aa5cdb4ab67 | 451 | * We use this here purely to safely issue a disconnect operation after a pairing operation is complete. |
Jonathan Austin |
1:8aa5cdb4ab67 | 452 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 453 | void MicroBitBLEManager::idleTick() |
Jonathan Austin |
1:8aa5cdb4ab67 | 454 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 455 | if (ble) |
Jonathan Austin |
1:8aa5cdb4ab67 | 456 | ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF); |
Jonathan Austin |
1:8aa5cdb4ab67 | 457 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 458 | fiber_remove_idle_component(this); |
Jonathan Austin |
1:8aa5cdb4ab67 | 459 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 460 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 461 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 462 | * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming |
Jonathan Austin |
1:8aa5cdb4ab67 | 463 | * of the micro:bit in cases where BLE is disabled during normal operation. |
Jonathan Austin |
1:8aa5cdb4ab67 | 464 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 465 | * @param display An instance of MicroBitDisplay used when displaying pairing information. |
Jonathan Austin |
1:8aa5cdb4ab67 | 466 | * @param authorizationButton The button to use to authorise a pairing request. |
Jonathan Austin |
1:8aa5cdb4ab67 | 467 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 468 | * @code |
Jonathan Austin |
1:8aa5cdb4ab67 | 469 | * // initiate pairing mode |
Jonathan Austin |
1:8aa5cdb4ab67 | 470 | * bleManager.pairingMode(uBit.display, uBit.buttonA); |
Jonathan Austin |
1:8aa5cdb4ab67 | 471 | * @endcode |
Jonathan Austin |
1:8aa5cdb4ab67 | 472 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 473 | void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton) |
Jonathan Austin |
1:8aa5cdb4ab67 | 474 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 475 | ManagedString namePrefix("BBC micro:bit ["); |
Jonathan Austin |
1:8aa5cdb4ab67 | 476 | ManagedString namePostfix("]"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 477 | ManagedString BLEName = namePrefix + deviceName + namePostfix; |
Jonathan Austin |
1:8aa5cdb4ab67 | 478 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 479 | ManagedString msg("PAIRING MODE!"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 480 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 481 | int timeInPairingMode = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 482 | int brightness = 255; |
Jonathan Austin |
1:8aa5cdb4ab67 | 483 | int fadeDirection = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 484 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 485 | ble->gap().stopAdvertising(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 486 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 487 | // Clear the whitelist (if we have one), so that we're discoverable by all BLE devices. |
Jonathan Austin |
1:8aa5cdb4ab67 | 488 | #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) |
Jonathan Austin |
1:8aa5cdb4ab67 | 489 | BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 490 | Gap::Whitelist_t whitelist; |
Jonathan Austin |
1:8aa5cdb4ab67 | 491 | whitelist.addresses = addresses; |
Jonathan Austin |
1:8aa5cdb4ab67 | 492 | whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS; |
Jonathan Austin |
1:8aa5cdb4ab67 | 493 | whitelist.size = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 494 | ble->gap().setWhitelist(whitelist); |
Jonathan Austin |
1:8aa5cdb4ab67 | 495 | ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST); |
Jonathan Austin |
1:8aa5cdb4ab67 | 496 | #endif |
Jonathan Austin |
1:8aa5cdb4ab67 | 497 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 498 | // Update the advertised name of this micro:bit to include the device name |
Jonathan Austin |
1:8aa5cdb4ab67 | 499 | ble->clearAdvertisingPayload(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 500 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 501 | ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
Jonathan Austin |
1:8aa5cdb4ab67 | 502 | ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length()); |
Jonathan Austin |
1:8aa5cdb4ab67 | 503 | ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
Jonathan Austin |
1:8aa5cdb4ab67 | 504 | ble->setAdvertisingInterval(200); |
Jonathan Austin |
1:8aa5cdb4ab67 | 505 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 506 | ble->gap().setAdvertisingTimeout(0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 507 | ble->gap().startAdvertising(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 508 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 509 | // Stop any running animations on the display |
Jonathan Austin |
1:8aa5cdb4ab67 | 510 | display.stopAnimation(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 511 | display.scroll(msg); |
Jonathan Austin |
1:8aa5cdb4ab67 | 512 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 513 | // Display our name, visualised as a histogram in the display to aid identification. |
Jonathan Austin |
1:8aa5cdb4ab67 | 514 | showNameHistogram(display); |
Jonathan Austin |
1:8aa5cdb4ab67 | 515 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 516 | while(1) |
Jonathan Austin |
1:8aa5cdb4ab67 | 517 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 518 | if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST) |
Jonathan Austin |
1:8aa5cdb4ab67 | 519 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 520 | timeInPairingMode = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 521 | MicroBitImage arrow("0,0,255,0,0\n0,255,0,0,0\n255,255,255,255,255\n0,255,0,0,0\n0,0,255,0,0\n"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 522 | display.print(arrow,0,0,0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 523 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 524 | if (fadeDirection == 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 525 | brightness -= MICROBIT_PAIRING_FADE_SPEED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 526 | else |
Jonathan Austin |
1:8aa5cdb4ab67 | 527 | brightness += MICROBIT_PAIRING_FADE_SPEED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 528 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 529 | if (brightness <= 40) |
Jonathan Austin |
1:8aa5cdb4ab67 | 530 | display.clear(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 531 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 532 | if (brightness <= 0) |
Jonathan Austin |
1:8aa5cdb4ab67 | 533 | fadeDirection = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 534 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 535 | if (brightness >= 255) |
Jonathan Austin |
1:8aa5cdb4ab67 | 536 | fadeDirection = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 537 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 538 | if (authorisationButton.isPressed()) |
Jonathan Austin |
1:8aa5cdb4ab67 | 539 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 540 | pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST; |
Jonathan Austin |
1:8aa5cdb4ab67 | 541 | pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 542 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 543 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 544 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 545 | if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE) |
Jonathan Austin |
1:8aa5cdb4ab67 | 546 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 547 | timeInPairingMode = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 548 | display.setBrightness(255); |
Jonathan Austin |
1:8aa5cdb4ab67 | 549 | for (int i=0; i<passKey.length(); i++) |
Jonathan Austin |
1:8aa5cdb4ab67 | 550 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 551 | display.image.print(passKey.charAt(i),0,0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 552 | fiber_sleep(800); |
Jonathan Austin |
1:8aa5cdb4ab67 | 553 | display.clear(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 554 | fiber_sleep(200); |
Jonathan Austin |
1:8aa5cdb4ab67 | 555 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 556 | if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE) |
Jonathan Austin |
1:8aa5cdb4ab67 | 557 | break; |
Jonathan Austin |
1:8aa5cdb4ab67 | 558 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 559 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 560 | fiber_sleep(1000); |
Jonathan Austin |
1:8aa5cdb4ab67 | 561 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 562 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 563 | if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE) |
Jonathan Austin |
1:8aa5cdb4ab67 | 564 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 565 | if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 566 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 567 | MicroBitImage tick("0,0,0,0,0\n0,0,0,0,255\n0,0,0,255,0\n255,0,255,0,0\n0,255,0,0,0\n"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 568 | display.print(tick,0,0,0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 569 | fiber_sleep(15000); |
Jonathan Austin |
1:8aa5cdb4ab67 | 570 | timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30; |
Jonathan Austin |
1:8aa5cdb4ab67 | 571 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 572 | /* |
Jonathan Austin |
1:8aa5cdb4ab67 | 573 | * Disabled, as the API to return the number of active bonds is not reliable at present... |
Jonathan Austin |
1:8aa5cdb4ab67 | 574 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 575 | display.clear(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 576 | ManagedString c(getBondCount()); |
Jonathan Austin |
1:8aa5cdb4ab67 | 577 | ManagedString c2("/"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 578 | ManagedString c3(MICROBIT_BLE_MAXIMUM_BONDS); |
Jonathan Austin |
1:8aa5cdb4ab67 | 579 | ManagedString c4("USED"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 580 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 581 | display.scroll(c+c2+c3+c4); |
Jonathan Austin |
1:8aa5cdb4ab67 | 582 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 583 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 584 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 585 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 586 | else |
Jonathan Austin |
1:8aa5cdb4ab67 | 587 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 588 | MicroBitImage cross("255,0,0,0,255\n0,255,0,255,0\n0,0,255,0,0\n0,255,0,255,0\n255,0,0,0,255\n"); |
Jonathan Austin |
1:8aa5cdb4ab67 | 589 | display.print(cross,0,0,0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 590 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 591 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 592 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 593 | fiber_sleep(100); |
Jonathan Austin |
1:8aa5cdb4ab67 | 594 | timeInPairingMode++; |
Jonathan Austin |
1:8aa5cdb4ab67 | 595 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 596 | if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30) |
Jonathan Austin |
1:8aa5cdb4ab67 | 597 | microbit_reset(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 598 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 599 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 600 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 601 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 602 | * Displays the device's ID code as a histogram on the provided MicroBitDisplay instance. |
Jonathan Austin |
1:8aa5cdb4ab67 | 603 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 604 | * @param display The display instance used for displaying the histogram. |
Jonathan Austin |
1:8aa5cdb4ab67 | 605 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 606 | void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display) |
Jonathan Austin |
1:8aa5cdb4ab67 | 607 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 608 | uint32_t n = NRF_FICR->DEVICEID[1]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 609 | int ld = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 610 | int d = MICROBIT_DFU_HISTOGRAM_HEIGHT; |
Jonathan Austin |
1:8aa5cdb4ab67 | 611 | int h; |
Jonathan Austin |
1:8aa5cdb4ab67 | 612 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 613 | display.clear(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 614 | for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++) |
Jonathan Austin |
1:8aa5cdb4ab67 | 615 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 616 | h = (n % d) / ld; |
Jonathan Austin |
1:8aa5cdb4ab67 | 617 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 618 | n -= h; |
Jonathan Austin |
1:8aa5cdb4ab67 | 619 | d *= MICROBIT_DFU_HISTOGRAM_HEIGHT; |
Jonathan Austin |
1:8aa5cdb4ab67 | 620 | ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT; |
Jonathan Austin |
1:8aa5cdb4ab67 | 621 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 622 | for (int j=0; j<h+1; j++) |
Jonathan Austin |
1:8aa5cdb4ab67 | 623 | display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255); |
Jonathan Austin |
1:8aa5cdb4ab67 | 624 | } |
LancasterUniversity | 21:cab56b701601 | 625 | } |