Solution for Bluetooth SIG hands-on training course

Dependencies:   BLE_API mbed-dev-bin nRF51822-bluetooth-mdw

Dependents:   microbit

Fork of microbit-dal-bluetooth-mdw_starter by Martin Woolley

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:17:54 2016 +0100
Revision:
22:23d7b9a4b082
Parent:
21:cab56b701601
Child:
23:6055f6c19fa6
Synchronized with git rev 7cf98c22
Author: James Devine
microbit-dal: patch for fiber_wake_on_event

fiber_wake_on_event used to crash after forking a FOB fiber.

It would attempt to obtain a new fiber context, and would place it on the wait queue.
Then when that fiber was paged in, the context of that fiber would not have been
initialised, as the function presumed schedule would be called immediately after
fiber initialisation.

This patch catches that edge case.

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;
Jonathan Austin 1:8aa5cdb4ab67 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 {
Jonathan Austin 1:8aa5cdb4ab67 112 storeSystemAttributes(reason->handle);
Jonathan Austin 1:8aa5cdb4ab67 113
Jonathan Austin 1:8aa5cdb4ab67 114 if (manager)
Jonathan Austin 1:8aa5cdb4ab67 115 manager->advertise();
Jonathan Austin 1:8aa5cdb4ab67 116 }
Jonathan Austin 1:8aa5cdb4ab67 117
Jonathan Austin 1:8aa5cdb4ab67 118 /**
Jonathan Austin 1:8aa5cdb4ab67 119 * Callback when a BLE SYS_ATTR_MISSING.
Jonathan Austin 1:8aa5cdb4ab67 120 */
Jonathan Austin 1:8aa5cdb4ab67 121 static void bleSysAttrMissingCallback(const GattSysAttrMissingCallbackParams *params)
Jonathan Austin 1:8aa5cdb4ab67 122 {
Jonathan Austin 1:8aa5cdb4ab67 123 int complete = 0;
Jonathan Austin 1:8aa5cdb4ab67 124 deviceID = 255;
Jonathan Austin 1:8aa5cdb4ab67 125
Jonathan Austin 1:8aa5cdb4ab67 126 dm_handle_t dm_handle = {0,0,0,0};
Jonathan Austin 1:8aa5cdb4ab67 127
Jonathan Austin 1:8aa5cdb4ab67 128 int ret = dm_handle_get(params->connHandle, &dm_handle);
Jonathan Austin 1:8aa5cdb4ab67 129
Jonathan Austin 1:8aa5cdb4ab67 130 if (ret == 0)
Jonathan Austin 1:8aa5cdb4ab67 131 deviceID = dm_handle.device_id;
Jonathan Austin 1:8aa5cdb4ab67 132
Jonathan Austin 1:8aa5cdb4ab67 133 if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
Jonathan Austin 1:8aa5cdb4ab67 134 {
Jonathan Austin 1:8aa5cdb4ab67 135 ManagedString key("bleSysAttrs");
Jonathan Austin 1:8aa5cdb4ab67 136
Jonathan Austin 1:8aa5cdb4ab67 137 KeyValuePair* bleSysAttrs = manager->storage->get(key);
Jonathan Austin 1:8aa5cdb4ab67 138
Jonathan Austin 1:8aa5cdb4ab67 139 BLESysAttributeStore attribStore;
Jonathan Austin 1:8aa5cdb4ab67 140 BLESysAttribute attrib;
Jonathan Austin 1:8aa5cdb4ab67 141
Jonathan Austin 1:8aa5cdb4ab67 142 if(bleSysAttrs != NULL)
Jonathan Austin 1:8aa5cdb4ab67 143 {
Jonathan Austin 1:8aa5cdb4ab67 144 //restore our sysAttrStore
Jonathan Austin 1:8aa5cdb4ab67 145 memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore));
Jonathan Austin 1:8aa5cdb4ab67 146 delete bleSysAttrs;
Jonathan Austin 1:8aa5cdb4ab67 147
Jonathan Austin 1:8aa5cdb4ab67 148 attrib = attribStore.sys_attrs[deviceID];
Jonathan Austin 1:8aa5cdb4ab67 149
Jonathan Austin 1:8aa5cdb4ab67 150 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 151
Jonathan Austin 1:8aa5cdb4ab67 152 complete = 1;
Jonathan Austin 1:8aa5cdb4ab67 153
Jonathan Austin 1:8aa5cdb4ab67 154 if(ret == 0)
Jonathan Austin 1:8aa5cdb4ab67 155 ret = sd_ble_gatts_service_changed(params->connHandle, 0x000c, 0xffff);
Jonathan Austin 1:8aa5cdb4ab67 156 }
Jonathan Austin 1:8aa5cdb4ab67 157 }
Jonathan Austin 1:8aa5cdb4ab67 158
Jonathan Austin 1:8aa5cdb4ab67 159 if (!complete)
Jonathan Austin 1:8aa5cdb4ab67 160 sd_ble_gatts_sys_attr_set(params->connHandle, NULL, 0, 0);
Jonathan Austin 1:8aa5cdb4ab67 161
Jonathan Austin 1:8aa5cdb4ab67 162 }
Jonathan Austin 1:8aa5cdb4ab67 163
Jonathan Austin 1:8aa5cdb4ab67 164 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
Jonathan Austin 1:8aa5cdb4ab67 165 {
Jonathan Austin 1:8aa5cdb4ab67 166 (void) handle; /* -Wunused-param */
Jonathan Austin 1:8aa5cdb4ab67 167
Jonathan Austin 1:8aa5cdb4ab67 168 ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN);
Jonathan Austin 1:8aa5cdb4ab67 169
Jonathan Austin 1:8aa5cdb4ab67 170 if (manager)
Jonathan Austin 1:8aa5cdb4ab67 171 manager->pairingRequested(passKey);
Jonathan Austin 1:8aa5cdb4ab67 172 }
Jonathan Austin 1:8aa5cdb4ab67 173
Jonathan Austin 1:8aa5cdb4ab67 174 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
Jonathan Austin 1:8aa5cdb4ab67 175 {
Jonathan Austin 1:8aa5cdb4ab67 176 (void) handle; /* -Wunused-param */
Jonathan Austin 1:8aa5cdb4ab67 177
Jonathan Austin 1:8aa5cdb4ab67 178 dm_handle_t dm_handle = {0,0,0,0};
Jonathan Austin 1:8aa5cdb4ab67 179 int ret = dm_handle_get(handle, &dm_handle);
Jonathan Austin 1:8aa5cdb4ab67 180
Jonathan Austin 1:8aa5cdb4ab67 181 if (ret == 0)
Jonathan Austin 1:8aa5cdb4ab67 182 deviceID = dm_handle.device_id;
Jonathan Austin 1:8aa5cdb4ab67 183
Jonathan Austin 1:8aa5cdb4ab67 184 if (manager)
Jonathan Austin 1:8aa5cdb4ab67 185 {
Jonathan Austin 1:8aa5cdb4ab67 186 pairingHandle = handle;
Jonathan Austin 1:8aa5cdb4ab67 187 manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS);
Jonathan Austin 1:8aa5cdb4ab67 188 }
Jonathan Austin 1:8aa5cdb4ab67 189 }
Jonathan Austin 1:8aa5cdb4ab67 190
Jonathan Austin 1:8aa5cdb4ab67 191 /**
Jonathan Austin 1:8aa5cdb4ab67 192 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 193 *
Jonathan Austin 1:8aa5cdb4ab67 194 * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
Jonathan Austin 1:8aa5cdb4ab67 195 *
Jonathan Austin 1:8aa5cdb4ab67 196 * @param _storage an instance of MicroBitStorage used to persist sys attribute information. (This is required for compatability with iOS).
Jonathan Austin 1:8aa5cdb4ab67 197 *
Jonathan Austin 1:8aa5cdb4ab67 198 * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself).
Jonathan Austin 1:8aa5cdb4ab67 199 * Hence, the init() member function should be used to initialise the BLE stack.
Jonathan Austin 1:8aa5cdb4ab67 200 */
Jonathan Austin 1:8aa5cdb4ab67 201 MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage& _storage) :
Jonathan Austin 1:8aa5cdb4ab67 202 storage(&_storage)
Jonathan Austin 1:8aa5cdb4ab67 203 {
Jonathan Austin 1:8aa5cdb4ab67 204 manager = this;
Jonathan Austin 1:8aa5cdb4ab67 205 this->ble = NULL;
Jonathan Austin 1:8aa5cdb4ab67 206 this->pairingStatus = 0;
Jonathan Austin 1:8aa5cdb4ab67 207 }
Jonathan Austin 1:8aa5cdb4ab67 208
Jonathan Austin 1:8aa5cdb4ab67 209 /**
Jonathan Austin 1:8aa5cdb4ab67 210 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 211 *
Jonathan Austin 1:8aa5cdb4ab67 212 * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
Jonathan Austin 1:8aa5cdb4ab67 213 *
Jonathan Austin 1:8aa5cdb4ab67 214 * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself).
Jonathan Austin 1:8aa5cdb4ab67 215 * Hence, the init() member function should be used to initialise the BLE stack.
Jonathan Austin 1:8aa5cdb4ab67 216 */
Jonathan Austin 1:8aa5cdb4ab67 217 MicroBitBLEManager::MicroBitBLEManager() :
Jonathan Austin 1:8aa5cdb4ab67 218 storage(NULL)
Jonathan Austin 1:8aa5cdb4ab67 219 {
Jonathan Austin 1:8aa5cdb4ab67 220 manager = this;
Jonathan Austin 1:8aa5cdb4ab67 221 this->ble = NULL;
Jonathan Austin 1:8aa5cdb4ab67 222 this->pairingStatus = 0;
Jonathan Austin 1:8aa5cdb4ab67 223 }
Jonathan Austin 1:8aa5cdb4ab67 224
Jonathan Austin 1:8aa5cdb4ab67 225 /**
Jonathan Austin 1:8aa5cdb4ab67 226 * When called, the micro:bit will begin advertising for a predefined period,
Jonathan Austin 1:8aa5cdb4ab67 227 * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices.
Jonathan Austin 1:8aa5cdb4ab67 228 */
Jonathan Austin 1:8aa5cdb4ab67 229 void MicroBitBLEManager::advertise()
Jonathan Austin 1:8aa5cdb4ab67 230 {
Jonathan Austin 1:8aa5cdb4ab67 231 if(ble)
Jonathan Austin 1:8aa5cdb4ab67 232 ble->gap().startAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 233 }
Jonathan Austin 1:8aa5cdb4ab67 234
Jonathan Austin 1:8aa5cdb4ab67 235 /**
Jonathan Austin 1:8aa5cdb4ab67 236 * Post constructor initialisation method as the BLE stack cannot be brought
Jonathan Austin 1:8aa5cdb4ab67 237 * up in a static context.
Jonathan Austin 1:8aa5cdb4ab67 238 *
Jonathan Austin 1:8aa5cdb4ab67 239 * @param deviceName The name used when advertising
Jonathan Austin 1:8aa5cdb4ab67 240 * @param serialNumber The serial number exposed by the device information service
Jonathan Austin 1:8aa5cdb4ab67 241 * @param messageBus An instance of an EventModel, used during pairing.
Jonathan Austin 1:8aa5cdb4ab67 242 * @param enableBonding If true, the security manager enabled bonding.
Jonathan Austin 1:8aa5cdb4ab67 243 *
Jonathan Austin 1:8aa5cdb4ab67 244 * @code
Jonathan Austin 1:8aa5cdb4ab67 245 * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true);
Jonathan Austin 1:8aa5cdb4ab67 246 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 247 */
Jonathan Austin 1:8aa5cdb4ab67 248 void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding)
Jonathan Austin 1:8aa5cdb4ab67 249 {
Jonathan Austin 1:8aa5cdb4ab67 250 ManagedString BLEName("BBC micro:bit");
Jonathan Austin 1:8aa5cdb4ab67 251 this->deviceName = deviceName;
Jonathan Austin 1:8aa5cdb4ab67 252
Jonathan Austin 1:8aa5cdb4ab67 253 #if !(CONFIG_ENABLED(MICROBIT_BLE_WHITELIST))
Jonathan Austin 1:8aa5cdb4ab67 254 ManagedString namePrefix(" [");
Jonathan Austin 1:8aa5cdb4ab67 255 ManagedString namePostfix("]");
Jonathan Austin 1:8aa5cdb4ab67 256 BLEName = BLEName + namePrefix + deviceName + namePostfix;
Jonathan Austin 1:8aa5cdb4ab67 257 #endif
Jonathan Austin 1:8aa5cdb4ab67 258
Jonathan Austin 1:8aa5cdb4ab67 259 // Start the BLE stack.
Jonathan Austin 1:8aa5cdb4ab67 260 #if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD)
Jonathan Austin 1:8aa5cdb4ab67 261 btle_set_gatt_table_size(MICROBIT_SD_GATT_TABLE_SIZE);
Jonathan Austin 1:8aa5cdb4ab67 262 #endif
Jonathan Austin 1:8aa5cdb4ab67 263
Jonathan Austin 1:8aa5cdb4ab67 264 ble = new BLEDevice();
Jonathan Austin 1:8aa5cdb4ab67 265 ble->init();
Jonathan Austin 1:8aa5cdb4ab67 266
Jonathan Austin 1:8aa5cdb4ab67 267 // automatically restart advertising after a device disconnects.
Jonathan Austin 1:8aa5cdb4ab67 268 ble->gap().onDisconnection(bleDisconnectionCallback);
Jonathan Austin 1:8aa5cdb4ab67 269 ble->gattServer().onSysAttrMissing(bleSysAttrMissingCallback);
Jonathan Austin 1:8aa5cdb4ab67 270
Jonathan Austin 1:8aa5cdb4ab67 271 // Configure the stack to hold onto the CPU during critical timing events.
Jonathan Austin 1:8aa5cdb4ab67 272 // mbed-classic performs __disable_irq() calls in its timers that can cause
Jonathan Austin 1:8aa5cdb4ab67 273 // MIC failures on secure BLE channels...
Jonathan Austin 1:8aa5cdb4ab67 274 ble_common_opt_radio_cpu_mutex_t opt;
Jonathan Austin 1:8aa5cdb4ab67 275 opt.enable = 1;
Jonathan Austin 1:8aa5cdb4ab67 276 sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);
Jonathan Austin 1:8aa5cdb4ab67 277
Jonathan Austin 1:8aa5cdb4ab67 278 #if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES)
Jonathan Austin 1:8aa5cdb4ab67 279 // Configure for private addresses, so kids' behaviour can't be easily tracked.
Jonathan Austin 1:8aa5cdb4ab67 280 ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0});
Jonathan Austin 1:8aa5cdb4ab67 281 #endif
Jonathan Austin 1:8aa5cdb4ab67 282
Jonathan Austin 1:8aa5cdb4ab67 283 // Setup our security requirements.
Jonathan Austin 1:8aa5cdb4ab67 284 ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback);
Jonathan Austin 1:8aa5cdb4ab67 285 ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
Jonathan Austin 1:8aa5cdb4ab67 286 ble->securityManager().init(enableBonding, (SecurityManager::MICROBIT_BLE_SECURITY_LEVEL == SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM), SecurityManager::IO_CAPS_DISPLAY_ONLY);
Jonathan Austin 1:8aa5cdb4ab67 287
Jonathan Austin 1:8aa5cdb4ab67 288 if (enableBonding)
Jonathan Austin 1:8aa5cdb4ab67 289 {
Jonathan Austin 1:8aa5cdb4ab67 290 // If we're in pairing mode, review the size of the bond table.
Jonathan Austin 1:8aa5cdb4ab67 291 int bonds = getBondCount();
Jonathan Austin 1:8aa5cdb4ab67 292
Jonathan Austin 1:8aa5cdb4ab67 293 // TODO: It would be much better to implement some sort of LRU/NFU policy here,
Jonathan Austin 1:8aa5cdb4ab67 294 // but this isn't currently supported in mbed, so we'd need to layer break...
Jonathan Austin 1:8aa5cdb4ab67 295
Jonathan Austin 1:8aa5cdb4ab67 296 // If we're full, empty the bond table.
Jonathan Austin 1:8aa5cdb4ab67 297 if (bonds >= MICROBIT_BLE_MAXIMUM_BONDS)
Jonathan Austin 1:8aa5cdb4ab67 298 ble->securityManager().purgeAllBondingState();
Jonathan Austin 1:8aa5cdb4ab67 299 }
Jonathan Austin 1:8aa5cdb4ab67 300
Jonathan Austin 1:8aa5cdb4ab67 301 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 302 // Configure a whitelist to filter all connection requetss from unbonded devices.
Jonathan Austin 1:8aa5cdb4ab67 303 // Most BLE stacks only permit one connection at a time, so this prevents denial of service attacks.
Jonathan Austin 1:8aa5cdb4ab67 304 BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
Jonathan Austin 1:8aa5cdb4ab67 305 Gap::Whitelist_t whitelist;
Jonathan Austin 1:8aa5cdb4ab67 306 whitelist.addresses = bondedAddresses;
Jonathan Austin 1:8aa5cdb4ab67 307 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
Jonathan Austin 1:8aa5cdb4ab67 308
Jonathan Austin 1:8aa5cdb4ab67 309 ble->securityManager().getAddressesFromBondTable(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 310
Jonathan Austin 1:8aa5cdb4ab67 311 ble->gap().setWhitelist(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 312 ble->gap().setScanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST);
Jonathan Austin 1:8aa5cdb4ab67 313 ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS);
Jonathan Austin 1:8aa5cdb4ab67 314 #endif
Jonathan Austin 1:8aa5cdb4ab67 315
Jonathan Austin 1:8aa5cdb4ab67 316 // Configure the radio at our default power level
Jonathan Austin 1:8aa5cdb4ab67 317 setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER);
Jonathan Austin 1:8aa5cdb4ab67 318
Jonathan Austin 1:8aa5cdb4ab67 319 // Bring up core BLE services.
Jonathan Austin 1:8aa5cdb4ab67 320 new MicroBitDFUService(*ble);
Jonathan Austin 1:8aa5cdb4ab67 321 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);
Jonathan Austin 1:8aa5cdb4ab67 322 new MicroBitEventService(*ble, messageBus);
Jonathan Austin 1:8aa5cdb4ab67 323
Jonathan Austin 1:8aa5cdb4ab67 324
Jonathan Austin 1:8aa5cdb4ab67 325 // Configure for high speed mode where possible.
Jonathan Austin 1:8aa5cdb4ab67 326 Gap::ConnectionParams_t fast;
Jonathan Austin 1:8aa5cdb4ab67 327 ble->getPreferredConnectionParams(&fast);
Jonathan Austin 1:8aa5cdb4ab67 328 fast.minConnectionInterval = 8; // 10 ms
Jonathan Austin 1:8aa5cdb4ab67 329 fast.maxConnectionInterval = 16; // 20 ms
Jonathan Austin 1:8aa5cdb4ab67 330 fast.slaveLatency = 0;
Jonathan Austin 1:8aa5cdb4ab67 331 ble->setPreferredConnectionParams(&fast);
Jonathan Austin 1:8aa5cdb4ab67 332
Jonathan Austin 1:8aa5cdb4ab67 333 // Setup advertising.
Jonathan Austin 1:8aa5cdb4ab67 334 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 335 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
Jonathan Austin 1:8aa5cdb4ab67 336 #else
Jonathan Austin 1:8aa5cdb4ab67 337 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Jonathan Austin 1:8aa5cdb4ab67 338 #endif
Jonathan Austin 1:8aa5cdb4ab67 339
Jonathan Austin 1:8aa5cdb4ab67 340 ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
Jonathan Austin 1:8aa5cdb4ab67 341 ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Jonathan Austin 1:8aa5cdb4ab67 342 ble->setAdvertisingInterval(200);
Jonathan Austin 1:8aa5cdb4ab67 343
Jonathan Austin 1:8aa5cdb4ab67 344 #if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0)
Jonathan Austin 1:8aa5cdb4ab67 345 ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT);
Jonathan Austin 1:8aa5cdb4ab67 346 #endif
Jonathan Austin 1:8aa5cdb4ab67 347
Jonathan Austin 1:8aa5cdb4ab67 348 // If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices...
Jonathan Austin 1:8aa5cdb4ab67 349 // This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable.
Jonathan Austin 1:8aa5cdb4ab67 350 // If whiltelisting is disabled, then we always advertise.
Jonathan Austin 1:8aa5cdb4ab67 351 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 352 if (whitelist.size > 0)
Jonathan Austin 1:8aa5cdb4ab67 353 #endif
Jonathan Austin 1:8aa5cdb4ab67 354 ble->startAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 355 }
Jonathan Austin 1:8aa5cdb4ab67 356
Jonathan Austin 1:8aa5cdb4ab67 357 /**
Jonathan Austin 1:8aa5cdb4ab67 358 * Change the output power level of the transmitter to the given value.
Jonathan Austin 1:8aa5cdb4ab67 359 *
Jonathan Austin 1:8aa5cdb4ab67 360 * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest.
Jonathan Austin 1:8aa5cdb4ab67 361 *
Jonathan Austin 1:8aa5cdb4ab67 362 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range.
Jonathan Austin 1:8aa5cdb4ab67 363 *
Jonathan Austin 1:8aa5cdb4ab67 364 * @code
Jonathan Austin 1:8aa5cdb4ab67 365 * // maximum transmission power.
Jonathan Austin 1:8aa5cdb4ab67 366 * bleManager.setTransmitPower(7);
Jonathan Austin 1:8aa5cdb4ab67 367 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 368 */
Jonathan Austin 1:8aa5cdb4ab67 369 int MicroBitBLEManager::setTransmitPower(int power)
Jonathan Austin 1:8aa5cdb4ab67 370 {
Jonathan Austin 1:8aa5cdb4ab67 371 if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS)
Jonathan Austin 1:8aa5cdb4ab67 372 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 373
Jonathan Austin 1:8aa5cdb4ab67 374 if (ble->gap().setTxPower(MICROBIT_BLE_POWER_LEVEL[power]) != NRF_SUCCESS)
Jonathan Austin 1:8aa5cdb4ab67 375 return MICROBIT_NOT_SUPPORTED;
Jonathan Austin 1:8aa5cdb4ab67 376
Jonathan Austin 1:8aa5cdb4ab67 377 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 378 }
Jonathan Austin 1:8aa5cdb4ab67 379
Jonathan Austin 1:8aa5cdb4ab67 380 /**
Jonathan Austin 1:8aa5cdb4ab67 381 * Determines the number of devices currently bonded with this micro:bit.
Jonathan Austin 1:8aa5cdb4ab67 382 * @return The number of active bonds.
Jonathan Austin 1:8aa5cdb4ab67 383 */
Jonathan Austin 1:8aa5cdb4ab67 384 int MicroBitBLEManager::getBondCount()
Jonathan Austin 1:8aa5cdb4ab67 385 {
Jonathan Austin 1:8aa5cdb4ab67 386 BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
Jonathan Austin 1:8aa5cdb4ab67 387 Gap::Whitelist_t whitelist;
Jonathan Austin 1:8aa5cdb4ab67 388 whitelist.addresses = bondedAddresses;
Jonathan Austin 1:8aa5cdb4ab67 389 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
Jonathan Austin 1:8aa5cdb4ab67 390 ble->securityManager().getAddressesFromBondTable(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 391
Jonathan Austin 1:8aa5cdb4ab67 392 return whitelist.bonds;
Jonathan Austin 1:8aa5cdb4ab67 393 }
Jonathan Austin 1:8aa5cdb4ab67 394
Jonathan Austin 1:8aa5cdb4ab67 395 /**
Jonathan Austin 1:8aa5cdb4ab67 396 * A request to pair has been received from a BLE device.
Jonathan Austin 1:8aa5cdb4ab67 397 * If we're in pairing mode, display the passkey to the user.
Jonathan Austin 1:8aa5cdb4ab67 398 * Also, purge the bonding table if it has reached capacity.
Jonathan Austin 1:8aa5cdb4ab67 399 *
Jonathan Austin 1:8aa5cdb4ab67 400 * @note for internal use only.
Jonathan Austin 1:8aa5cdb4ab67 401 */
Jonathan Austin 1:8aa5cdb4ab67 402 void MicroBitBLEManager::pairingRequested(ManagedString passKey)
Jonathan Austin 1:8aa5cdb4ab67 403 {
Jonathan Austin 1:8aa5cdb4ab67 404 // Update our mode to display the passkey.
Jonathan Austin 1:8aa5cdb4ab67 405 this->passKey = passKey;
Jonathan Austin 1:8aa5cdb4ab67 406 this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST;
Jonathan Austin 1:8aa5cdb4ab67 407 }
Jonathan Austin 1:8aa5cdb4ab67 408
Jonathan Austin 1:8aa5cdb4ab67 409 /**
Jonathan Austin 1:8aa5cdb4ab67 410 * A pairing request has been sucessfully completed.
Jonathan Austin 1:8aa5cdb4ab67 411 * If we're in pairing mode, display a success or failure message.
Jonathan Austin 1:8aa5cdb4ab67 412 *
Jonathan Austin 1:8aa5cdb4ab67 413 * @note for internal use only.
Jonathan Austin 1:8aa5cdb4ab67 414 */
Jonathan Austin 1:8aa5cdb4ab67 415 void MicroBitBLEManager::pairingComplete(bool success)
Jonathan Austin 1:8aa5cdb4ab67 416 {
Jonathan Austin 1:8aa5cdb4ab67 417 this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE;
Jonathan Austin 1:8aa5cdb4ab67 418
Jonathan Austin 1:8aa5cdb4ab67 419 if(success)
Jonathan Austin 1:8aa5cdb4ab67 420 {
Jonathan Austin 1:8aa5cdb4ab67 421 this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
Jonathan Austin 1:8aa5cdb4ab67 422 fiber_add_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 423 }
Jonathan Austin 1:8aa5cdb4ab67 424 }
Jonathan Austin 1:8aa5cdb4ab67 425
Jonathan Austin 1:8aa5cdb4ab67 426 /**
Jonathan Austin 1:8aa5cdb4ab67 427 * Periodic callback in thread context.
Jonathan Austin 1:8aa5cdb4ab67 428 * We use this here purely to safely issue a disconnect operation after a pairing operation is complete.
Jonathan Austin 1:8aa5cdb4ab67 429 */
Jonathan Austin 1:8aa5cdb4ab67 430 void MicroBitBLEManager::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 431 {
Jonathan Austin 1:8aa5cdb4ab67 432 if (ble)
Jonathan Austin 1:8aa5cdb4ab67 433 ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
Jonathan Austin 1:8aa5cdb4ab67 434
Jonathan Austin 1:8aa5cdb4ab67 435 fiber_remove_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 436 }
Jonathan Austin 1:8aa5cdb4ab67 437
Jonathan Austin 1:8aa5cdb4ab67 438 /**
Jonathan Austin 1:8aa5cdb4ab67 439 * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
Jonathan Austin 1:8aa5cdb4ab67 440 * of the micro:bit in cases where BLE is disabled during normal operation.
Jonathan Austin 1:8aa5cdb4ab67 441 *
Jonathan Austin 1:8aa5cdb4ab67 442 * @param display An instance of MicroBitDisplay used when displaying pairing information.
Jonathan Austin 1:8aa5cdb4ab67 443 * @param authorizationButton The button to use to authorise a pairing request.
Jonathan Austin 1:8aa5cdb4ab67 444 *
Jonathan Austin 1:8aa5cdb4ab67 445 * @code
Jonathan Austin 1:8aa5cdb4ab67 446 * // initiate pairing mode
Jonathan Austin 1:8aa5cdb4ab67 447 * bleManager.pairingMode(uBit.display, uBit.buttonA);
Jonathan Austin 1:8aa5cdb4ab67 448 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 449 */
Jonathan Austin 1:8aa5cdb4ab67 450 void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton)
Jonathan Austin 1:8aa5cdb4ab67 451 {
Jonathan Austin 1:8aa5cdb4ab67 452 ManagedString namePrefix("BBC micro:bit [");
Jonathan Austin 1:8aa5cdb4ab67 453 ManagedString namePostfix("]");
Jonathan Austin 1:8aa5cdb4ab67 454 ManagedString BLEName = namePrefix + deviceName + namePostfix;
Jonathan Austin 1:8aa5cdb4ab67 455
Jonathan Austin 1:8aa5cdb4ab67 456 ManagedString msg("PAIRING MODE!");
Jonathan Austin 1:8aa5cdb4ab67 457
Jonathan Austin 1:8aa5cdb4ab67 458 int timeInPairingMode = 0;
Jonathan Austin 1:8aa5cdb4ab67 459 int brightness = 255;
Jonathan Austin 1:8aa5cdb4ab67 460 int fadeDirection = 0;
Jonathan Austin 1:8aa5cdb4ab67 461
Jonathan Austin 1:8aa5cdb4ab67 462 ble->gap().stopAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 463
Jonathan Austin 1:8aa5cdb4ab67 464 // Clear the whitelist (if we have one), so that we're discoverable by all BLE devices.
Jonathan Austin 1:8aa5cdb4ab67 465 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
Jonathan Austin 1:8aa5cdb4ab67 466 BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS];
Jonathan Austin 1:8aa5cdb4ab67 467 Gap::Whitelist_t whitelist;
Jonathan Austin 1:8aa5cdb4ab67 468 whitelist.addresses = addresses;
Jonathan Austin 1:8aa5cdb4ab67 469 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
Jonathan Austin 1:8aa5cdb4ab67 470 whitelist.size = 0;
Jonathan Austin 1:8aa5cdb4ab67 471 ble->gap().setWhitelist(whitelist);
Jonathan Austin 1:8aa5cdb4ab67 472 ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
Jonathan Austin 1:8aa5cdb4ab67 473 #endif
Jonathan Austin 1:8aa5cdb4ab67 474
Jonathan Austin 1:8aa5cdb4ab67 475 // Update the advertised name of this micro:bit to include the device name
Jonathan Austin 1:8aa5cdb4ab67 476 ble->clearAdvertisingPayload();
Jonathan Austin 1:8aa5cdb4ab67 477
Jonathan Austin 1:8aa5cdb4ab67 478 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Jonathan Austin 1:8aa5cdb4ab67 479 ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
Jonathan Austin 1:8aa5cdb4ab67 480 ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Jonathan Austin 1:8aa5cdb4ab67 481 ble->setAdvertisingInterval(200);
Jonathan Austin 1:8aa5cdb4ab67 482
Jonathan Austin 1:8aa5cdb4ab67 483 ble->gap().setAdvertisingTimeout(0);
Jonathan Austin 1:8aa5cdb4ab67 484 ble->gap().startAdvertising();
Jonathan Austin 1:8aa5cdb4ab67 485
Jonathan Austin 1:8aa5cdb4ab67 486 // Stop any running animations on the display
Jonathan Austin 1:8aa5cdb4ab67 487 display.stopAnimation();
Jonathan Austin 1:8aa5cdb4ab67 488 display.scroll(msg);
Jonathan Austin 1:8aa5cdb4ab67 489
Jonathan Austin 1:8aa5cdb4ab67 490 // Display our name, visualised as a histogram in the display to aid identification.
Jonathan Austin 1:8aa5cdb4ab67 491 showNameHistogram(display);
Jonathan Austin 1:8aa5cdb4ab67 492
Jonathan Austin 1:8aa5cdb4ab67 493 while(1)
Jonathan Austin 1:8aa5cdb4ab67 494 {
Jonathan Austin 1:8aa5cdb4ab67 495 if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
Jonathan Austin 1:8aa5cdb4ab67 496 {
Jonathan Austin 1:8aa5cdb4ab67 497 timeInPairingMode = 0;
Jonathan Austin 1:8aa5cdb4ab67 498 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 499 display.print(arrow,0,0,0);
Jonathan Austin 1:8aa5cdb4ab67 500
Jonathan Austin 1:8aa5cdb4ab67 501 if (fadeDirection == 0)
Jonathan Austin 1:8aa5cdb4ab67 502 brightness -= MICROBIT_PAIRING_FADE_SPEED;
Jonathan Austin 1:8aa5cdb4ab67 503 else
Jonathan Austin 1:8aa5cdb4ab67 504 brightness += MICROBIT_PAIRING_FADE_SPEED;
Jonathan Austin 1:8aa5cdb4ab67 505
Jonathan Austin 1:8aa5cdb4ab67 506 if (brightness <= 40)
Jonathan Austin 1:8aa5cdb4ab67 507 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 508
Jonathan Austin 1:8aa5cdb4ab67 509 if (brightness <= 0)
Jonathan Austin 1:8aa5cdb4ab67 510 fadeDirection = 1;
Jonathan Austin 1:8aa5cdb4ab67 511
Jonathan Austin 1:8aa5cdb4ab67 512 if (brightness >= 255)
Jonathan Austin 1:8aa5cdb4ab67 513 fadeDirection = 0;
Jonathan Austin 1:8aa5cdb4ab67 514
Jonathan Austin 1:8aa5cdb4ab67 515 if (authorisationButton.isPressed())
Jonathan Austin 1:8aa5cdb4ab67 516 {
Jonathan Austin 1:8aa5cdb4ab67 517 pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
Jonathan Austin 1:8aa5cdb4ab67 518 pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
Jonathan Austin 1:8aa5cdb4ab67 519 }
Jonathan Austin 1:8aa5cdb4ab67 520 }
Jonathan Austin 1:8aa5cdb4ab67 521
Jonathan Austin 1:8aa5cdb4ab67 522 if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE)
Jonathan Austin 1:8aa5cdb4ab67 523 {
Jonathan Austin 1:8aa5cdb4ab67 524 timeInPairingMode = 0;
Jonathan Austin 1:8aa5cdb4ab67 525 display.setBrightness(255);
Jonathan Austin 1:8aa5cdb4ab67 526 for (int i=0; i<passKey.length(); i++)
Jonathan Austin 1:8aa5cdb4ab67 527 {
Jonathan Austin 1:8aa5cdb4ab67 528 display.image.print(passKey.charAt(i),0,0);
Jonathan Austin 1:8aa5cdb4ab67 529 fiber_sleep(800);
Jonathan Austin 1:8aa5cdb4ab67 530 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 531 fiber_sleep(200);
Jonathan Austin 1:8aa5cdb4ab67 532
Jonathan Austin 1:8aa5cdb4ab67 533 if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
Jonathan Austin 1:8aa5cdb4ab67 534 break;
Jonathan Austin 1:8aa5cdb4ab67 535 }
Jonathan Austin 1:8aa5cdb4ab67 536
Jonathan Austin 1:8aa5cdb4ab67 537 fiber_sleep(1000);
Jonathan Austin 1:8aa5cdb4ab67 538 }
Jonathan Austin 1:8aa5cdb4ab67 539
Jonathan Austin 1:8aa5cdb4ab67 540 if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
Jonathan Austin 1:8aa5cdb4ab67 541 {
Jonathan Austin 1:8aa5cdb4ab67 542 if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL)
Jonathan Austin 1:8aa5cdb4ab67 543 {
Jonathan Austin 1:8aa5cdb4ab67 544 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 545 display.print(tick,0,0,0);
Jonathan Austin 1:8aa5cdb4ab67 546 fiber_sleep(15000);
Jonathan Austin 1:8aa5cdb4ab67 547 timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30;
Jonathan Austin 1:8aa5cdb4ab67 548
Jonathan Austin 1:8aa5cdb4ab67 549 /*
Jonathan Austin 1:8aa5cdb4ab67 550 * Disabled, as the API to return the number of active bonds is not reliable at present...
Jonathan Austin 1:8aa5cdb4ab67 551 *
Jonathan Austin 1:8aa5cdb4ab67 552 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 553 ManagedString c(getBondCount());
Jonathan Austin 1:8aa5cdb4ab67 554 ManagedString c2("/");
Jonathan Austin 1:8aa5cdb4ab67 555 ManagedString c3(MICROBIT_BLE_MAXIMUM_BONDS);
Jonathan Austin 1:8aa5cdb4ab67 556 ManagedString c4("USED");
Jonathan Austin 1:8aa5cdb4ab67 557
Jonathan Austin 1:8aa5cdb4ab67 558 display.scroll(c+c2+c3+c4);
Jonathan Austin 1:8aa5cdb4ab67 559 *
Jonathan Austin 1:8aa5cdb4ab67 560 *
Jonathan Austin 1:8aa5cdb4ab67 561 */
Jonathan Austin 1:8aa5cdb4ab67 562 }
Jonathan Austin 1:8aa5cdb4ab67 563 else
Jonathan Austin 1:8aa5cdb4ab67 564 {
Jonathan Austin 1:8aa5cdb4ab67 565 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 566 display.print(cross,0,0,0);
Jonathan Austin 1:8aa5cdb4ab67 567 }
Jonathan Austin 1:8aa5cdb4ab67 568 }
Jonathan Austin 1:8aa5cdb4ab67 569
Jonathan Austin 1:8aa5cdb4ab67 570 fiber_sleep(100);
Jonathan Austin 1:8aa5cdb4ab67 571 timeInPairingMode++;
Jonathan Austin 1:8aa5cdb4ab67 572
Jonathan Austin 1:8aa5cdb4ab67 573 if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
Jonathan Austin 1:8aa5cdb4ab67 574 microbit_reset();
Jonathan Austin 1:8aa5cdb4ab67 575 }
Jonathan Austin 1:8aa5cdb4ab67 576 }
Jonathan Austin 1:8aa5cdb4ab67 577
Jonathan Austin 1:8aa5cdb4ab67 578 /**
Jonathan Austin 1:8aa5cdb4ab67 579 * Displays the device's ID code as a histogram on the provided MicroBitDisplay instance.
Jonathan Austin 1:8aa5cdb4ab67 580 *
Jonathan Austin 1:8aa5cdb4ab67 581 * @param display The display instance used for displaying the histogram.
Jonathan Austin 1:8aa5cdb4ab67 582 */
Jonathan Austin 1:8aa5cdb4ab67 583 void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display)
Jonathan Austin 1:8aa5cdb4ab67 584 {
Jonathan Austin 1:8aa5cdb4ab67 585 uint32_t n = NRF_FICR->DEVICEID[1];
Jonathan Austin 1:8aa5cdb4ab67 586 int ld = 1;
Jonathan Austin 1:8aa5cdb4ab67 587 int d = MICROBIT_DFU_HISTOGRAM_HEIGHT;
Jonathan Austin 1:8aa5cdb4ab67 588 int h;
Jonathan Austin 1:8aa5cdb4ab67 589
Jonathan Austin 1:8aa5cdb4ab67 590 display.clear();
Jonathan Austin 1:8aa5cdb4ab67 591 for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++)
Jonathan Austin 1:8aa5cdb4ab67 592 {
Jonathan Austin 1:8aa5cdb4ab67 593 h = (n % d) / ld;
Jonathan Austin 1:8aa5cdb4ab67 594
Jonathan Austin 1:8aa5cdb4ab67 595 n -= h;
Jonathan Austin 1:8aa5cdb4ab67 596 d *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
Jonathan Austin 1:8aa5cdb4ab67 597 ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
Jonathan Austin 1:8aa5cdb4ab67 598
Jonathan Austin 1:8aa5cdb4ab67 599 for (int j=0; j<h+1; j++)
Jonathan Austin 1:8aa5cdb4ab67 600 display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255);
Jonathan Austin 1:8aa5cdb4ab67 601 }
LancasterUniversity 21:cab56b701601 602 }