fork

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
Jonathan Austin
Date:
Thu Apr 07 01:33:22 2016 +0100
Revision:
1:8aa5cdb4ab67
Child:
21:cab56b701601
Synchronized with git rev 55cb9199

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 }
Jonathan Austin 1:8aa5cdb4ab67 602 }