No Changes

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:16 2016 +0100
Revision:
37:b624ae5e94a5
Parent:
35:8ce23bc1af38
Child:
56:1311cac15dda
Synchronized with git rev 7443b783
Author: Joe Finney
Fix typos

Who changed what in which revision?

UserRevisionLine numberNew 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 37:b624ae5e94a5 102 manager->storage->put(key, (uint8_t *)&attribStore, sizeof(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 }