Attempting to publish a tree
Dependencies: BLE_API mbed-dev-bin nRF51822
Fork of microbit-dal by
MicroBitBLEManager.cpp
00001 /* 00002 The MIT License (MIT) 00003 00004 Copyright (c) 2016 British Broadcasting Corporation. 00005 This software is provided by Lancaster University by arrangement with the BBC. 00006 00007 Permission is hereby granted, free of charge, to any person obtaining a 00008 copy of this software and associated documentation files (the "Software"), 00009 to deal in the Software without restriction, including without limitation 00010 the rights to use, copy, modify, merge, publish, distribute, sublicense, 00011 and/or sell copies of the Software, and to permit persons to whom the 00012 Software is furnished to do so, subject to the following conditions: 00013 00014 The above copyright notice and this permission notice shall be included in 00015 all copies or substantial portions of the Software. 00016 00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00023 DEALINGS IN THE SOFTWARE. 00024 */ 00025 00026 #include "MicroBitConfig.h" 00027 #include "MicroBitBLEManager.h" 00028 #include "MicroBitStorage.h" 00029 #include "MicroBitFiber.h" 00030 00031 00032 /* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ. 00033 * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL) 00034 * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this 00035 * as a compatability option, but does not support the options used... 00036 */ 00037 #if !defined(__arm) 00038 #pragma GCC diagnostic ignored "-Wunused-function" 00039 #pragma GCC diagnostic push 00040 #pragma GCC diagnostic ignored "-Wunused-parameter" 00041 #endif 00042 00043 #include "ble.h" 00044 00045 extern "C" 00046 { 00047 #include "device_manager.h" 00048 uint32_t btle_set_gatt_table_size(uint32_t size); 00049 } 00050 00051 /* 00052 * Return to our predefined compiler settings. 00053 */ 00054 #if !defined(__arm) 00055 #pragma GCC diagnostic pop 00056 #endif 00057 00058 #define MICROBIT_PAIRING_FADE_SPEED 4 00059 00060 const char* MICROBIT_BLE_MANUFACTURER = NULL; 00061 const char* MICROBIT_BLE_MODEL = "BBC micro:bit"; 00062 const char* MICROBIT_BLE_HARDWARE_VERSION = NULL; 00063 const char* MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION; 00064 const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL; 00065 const int8_t MICROBIT_BLE_POWER_LEVEL[] = {-30, -20, -16, -12, -8, -4, 0, 4}; 00066 00067 /* 00068 * Many of the mbed interfaces we need to use only support callbacks to plain C functions, rather than C++ methods. 00069 * So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit 00070 * whilst keeping the code modular. 00071 */ 00072 static MicroBitBLEManager *manager = NULL; // Singleton reference to the BLE manager. many mbed BLE API callbacks still do not support member funcions yet. :-( 00073 static uint8_t deviceID = 255; // Unique ID for the peer that has connected to us. 00074 static Gap::Handle_t pairingHandle = 0; // The connection handle used during a pairing process. Used to ensure that connections are dropped elegantly. 00075 00076 static void storeSystemAttributes(Gap::Handle_t handle) 00077 { 00078 if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS) 00079 { 00080 ManagedString key("bleSysAttrs"); 00081 00082 KeyValuePair* bleSysAttrs = manager->storage->get(key); 00083 00084 BLESysAttribute attrib; 00085 BLESysAttributeStore attribStore; 00086 00087 uint16_t len = sizeof(attrib.sys_attr); 00088 00089 sd_ble_gatts_sys_attr_get(handle, attrib.sys_attr, &len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); 00090 00091 //copy our stored sysAttrs 00092 if(bleSysAttrs != NULL) 00093 { 00094 memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore)); 00095 delete bleSysAttrs; 00096 } 00097 00098 //check if we need to update 00099 if(memcmp(attribStore.sys_attrs[deviceID].sys_attr, attrib.sys_attr, len) != 0) 00100 { 00101 attribStore.sys_attrs[deviceID] = attrib; 00102 manager->storage->put(key, (uint8_t *)&attribStore); 00103 } 00104 } 00105 } 00106 00107 /** 00108 * Callback when a BLE GATT disconnect occurs. 00109 */ 00110 static void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *reason) 00111 { 00112 storeSystemAttributes(reason->handle); 00113 00114 if (manager) 00115 manager->advertise(); 00116 } 00117 00118 /** 00119 * Callback when a BLE SYS_ATTR_MISSING. 00120 */ 00121 static void bleSysAttrMissingCallback(const GattSysAttrMissingCallbackParams *params) 00122 { 00123 int complete = 0; 00124 deviceID = 255; 00125 00126 dm_handle_t dm_handle = {0,0,0,0}; 00127 00128 int ret = dm_handle_get(params->connHandle, &dm_handle); 00129 00130 if (ret == 0) 00131 deviceID = dm_handle.device_id; 00132 00133 if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS) 00134 { 00135 ManagedString key("bleSysAttrs"); 00136 00137 KeyValuePair* bleSysAttrs = manager->storage->get(key); 00138 00139 BLESysAttributeStore attribStore; 00140 BLESysAttribute attrib; 00141 00142 if(bleSysAttrs != NULL) 00143 { 00144 //restore our sysAttrStore 00145 memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore)); 00146 delete bleSysAttrs; 00147 00148 attrib = attribStore.sys_attrs[deviceID]; 00149 00150 ret = sd_ble_gatts_sys_attr_set(params->connHandle, attrib.sys_attr, sizeof(attrib.sys_attr), BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); 00151 00152 complete = 1; 00153 00154 if(ret == 0) 00155 ret = sd_ble_gatts_service_changed(params->connHandle, 0x000c, 0xffff); 00156 } 00157 } 00158 00159 if (!complete) 00160 sd_ble_gatts_sys_attr_set(params->connHandle, NULL, 0, 0); 00161 00162 } 00163 00164 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey) 00165 { 00166 (void) handle; /* -Wunused-param */ 00167 00168 ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN); 00169 00170 if (manager) 00171 manager->pairingRequested(passKey); 00172 } 00173 00174 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status) 00175 { 00176 (void) handle; /* -Wunused-param */ 00177 00178 dm_handle_t dm_handle = {0,0,0,0}; 00179 int ret = dm_handle_get(handle, &dm_handle); 00180 00181 if (ret == 0) 00182 deviceID = dm_handle.device_id; 00183 00184 if (manager) 00185 { 00186 pairingHandle = handle; 00187 manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS); 00188 } 00189 } 00190 00191 /** 00192 * Constructor. 00193 * 00194 * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack. 00195 * 00196 * @param _storage an instance of MicroBitStorage used to persist sys attribute information. (This is required for compatability with iOS). 00197 * 00198 * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself). 00199 * Hence, the init() member function should be used to initialise the BLE stack. 00200 */ 00201 MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage& _storage) : 00202 storage(&_storage) 00203 { 00204 manager = this; 00205 this->ble = NULL; 00206 this->pairingStatus = 0; 00207 } 00208 00209 /** 00210 * Constructor. 00211 * 00212 * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack. 00213 * 00214 * @note The BLE stack *cannot* be brought up in a static context (the software simply hangs or corrupts itself). 00215 * Hence, the init() member function should be used to initialise the BLE stack. 00216 */ 00217 MicroBitBLEManager::MicroBitBLEManager() : 00218 storage(NULL) 00219 { 00220 manager = this; 00221 this->ble = NULL; 00222 this->pairingStatus = 0; 00223 } 00224 00225 /** 00226 * When called, the micro:bit will begin advertising for a predefined period, 00227 * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices. 00228 */ 00229 void MicroBitBLEManager::advertise() 00230 { 00231 if(ble) 00232 ble->gap().startAdvertising(); 00233 } 00234 00235 /** 00236 * Post constructor initialisation method as the BLE stack cannot be brought 00237 * up in a static context. 00238 * 00239 * @param deviceName The name used when advertising 00240 * @param serialNumber The serial number exposed by the device information service 00241 * @param messageBus An instance of an EventModel, used during pairing. 00242 * @param enableBonding If true, the security manager enabled bonding. 00243 * 00244 * @code 00245 * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true); 00246 * @endcode 00247 */ 00248 void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding) 00249 { 00250 ManagedString BLEName("BBC micro:bit"); 00251 this->deviceName = deviceName; 00252 00253 #if !(CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)) 00254 ManagedString namePrefix(" ["); 00255 ManagedString namePostfix("]"); 00256 BLEName = BLEName + namePrefix + deviceName + namePostfix; 00257 #endif 00258 00259 // Start the BLE stack. 00260 #if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD) 00261 btle_set_gatt_table_size(MICROBIT_SD_GATT_TABLE_SIZE); 00262 #endif 00263 00264 ble = new BLEDevice(); 00265 ble->init(); 00266 00267 // automatically restart advertising after a device disconnects. 00268 ble->gap().onDisconnection(bleDisconnectionCallback); 00269 ble->gattServer().onSysAttrMissing(bleSysAttrMissingCallback); 00270 00271 // Configure the stack to hold onto the CPU during critical timing events. 00272 // mbed-classic performs __disable_irq() calls in its timers that can cause 00273 // MIC failures on secure BLE channels... 00274 ble_common_opt_radio_cpu_mutex_t opt; 00275 opt.enable = 1; 00276 sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt); 00277 00278 #if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES) 00279 // Configure for private addresses, so kids' behaviour can't be easily tracked. 00280 ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0}); 00281 #endif 00282 00283 // Setup our security requirements. 00284 ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback); 00285 ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); 00286 ble->securityManager().init(enableBonding, (SecurityManager::MICROBIT_BLE_SECURITY_LEVEL == SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM), SecurityManager::IO_CAPS_DISPLAY_ONLY); 00287 00288 if (enableBonding) 00289 { 00290 // If we're in pairing mode, review the size of the bond table. 00291 int bonds = getBondCount(); 00292 00293 // TODO: It would be much better to implement some sort of LRU/NFU policy here, 00294 // but this isn't currently supported in mbed, so we'd need to layer break... 00295 00296 // If we're full, empty the bond table. 00297 if (bonds >= MICROBIT_BLE_MAXIMUM_BONDS) 00298 ble->securityManager().purgeAllBondingState(); 00299 } 00300 00301 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) 00302 // Configure a whitelist to filter all connection requetss from unbonded devices. 00303 // Most BLE stacks only permit one connection at a time, so this prevents denial of service attacks. 00304 BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS]; 00305 Gap::Whitelist_t whitelist; 00306 whitelist.addresses = bondedAddresses; 00307 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS; 00308 00309 ble->securityManager().getAddressesFromBondTable(whitelist); 00310 00311 ble->gap().setWhitelist(whitelist); 00312 ble->gap().setScanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST); 00313 ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS); 00314 #endif 00315 00316 // Configure the radio at our default power level 00317 setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER); 00318 00319 // Bring up core BLE services. 00320 new MicroBitDFUService(*ble); 00321 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); 00322 new MicroBitEventService(*ble, messageBus); 00323 00324 00325 // Configure for high speed mode where possible. 00326 Gap::ConnectionParams_t fast; 00327 ble->getPreferredConnectionParams(&fast); 00328 fast.minConnectionInterval = 8; // 10 ms 00329 fast.maxConnectionInterval = 16; // 20 ms 00330 fast.slaveLatency = 0; 00331 ble->setPreferredConnectionParams(&fast); 00332 00333 // Setup advertising. 00334 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) 00335 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED); 00336 #else 00337 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00338 #endif 00339 00340 ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length()); 00341 ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00342 ble->setAdvertisingInterval(200); 00343 00344 #if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0) 00345 ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT); 00346 #endif 00347 00348 // If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices... 00349 // This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable. 00350 // If whiltelisting is disabled, then we always advertise. 00351 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) 00352 if (whitelist.size > 0) 00353 #endif 00354 ble->startAdvertising(); 00355 } 00356 00357 /** 00358 * Change the output power level of the transmitter to the given value. 00359 * 00360 * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. 00361 * 00362 * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range. 00363 * 00364 * @code 00365 * // maximum transmission power. 00366 * bleManager.setTransmitPower(7); 00367 * @endcode 00368 */ 00369 int MicroBitBLEManager::setTransmitPower(int power) 00370 { 00371 if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS) 00372 return MICROBIT_INVALID_PARAMETER; 00373 00374 if (ble->gap().setTxPower(MICROBIT_BLE_POWER_LEVEL[power]) != NRF_SUCCESS) 00375 return MICROBIT_NOT_SUPPORTED; 00376 00377 return MICROBIT_OK; 00378 } 00379 00380 /** 00381 * Determines the number of devices currently bonded with this micro:bit. 00382 * @return The number of active bonds. 00383 */ 00384 int MicroBitBLEManager::getBondCount() 00385 { 00386 BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS]; 00387 Gap::Whitelist_t whitelist; 00388 whitelist.addresses = bondedAddresses; 00389 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS; 00390 ble->securityManager().getAddressesFromBondTable(whitelist); 00391 00392 return whitelist.bonds; 00393 } 00394 00395 /** 00396 * A request to pair has been received from a BLE device. 00397 * If we're in pairing mode, display the passkey to the user. 00398 * Also, purge the bonding table if it has reached capacity. 00399 * 00400 * @note for internal use only. 00401 */ 00402 void MicroBitBLEManager::pairingRequested(ManagedString passKey) 00403 { 00404 // Update our mode to display the passkey. 00405 this->passKey = passKey; 00406 this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST; 00407 } 00408 00409 /** 00410 * A pairing request has been sucessfully completed. 00411 * If we're in pairing mode, display a success or failure message. 00412 * 00413 * @note for internal use only. 00414 */ 00415 void MicroBitBLEManager::pairingComplete(bool success) 00416 { 00417 this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE; 00418 00419 if(success) 00420 { 00421 this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL; 00422 fiber_add_idle_component(this); 00423 } 00424 } 00425 00426 /** 00427 * Periodic callback in thread context. 00428 * We use this here purely to safely issue a disconnect operation after a pairing operation is complete. 00429 */ 00430 void MicroBitBLEManager::idleTick() 00431 { 00432 if (ble) 00433 ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF); 00434 00435 fiber_remove_idle_component(this); 00436 } 00437 00438 /** 00439 * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming 00440 * of the micro:bit in cases where BLE is disabled during normal operation. 00441 * 00442 * @param display An instance of MicroBitDisplay used when displaying pairing information. 00443 * @param authorizationButton The button to use to authorise a pairing request. 00444 * 00445 * @code 00446 * // initiate pairing mode 00447 * bleManager.pairingMode(uBit.display, uBit.buttonA); 00448 * @endcode 00449 */ 00450 void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton) 00451 { 00452 ManagedString namePrefix("BBC micro:bit ["); 00453 ManagedString namePostfix("]"); 00454 ManagedString BLEName = namePrefix + deviceName + namePostfix; 00455 00456 ManagedString msg("PAIRING MODE!"); 00457 00458 int timeInPairingMode = 0; 00459 int brightness = 255; 00460 int fadeDirection = 0; 00461 00462 ble->gap().stopAdvertising(); 00463 00464 // Clear the whitelist (if we have one), so that we're discoverable by all BLE devices. 00465 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST) 00466 BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS]; 00467 Gap::Whitelist_t whitelist; 00468 whitelist.addresses = addresses; 00469 whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS; 00470 whitelist.size = 0; 00471 ble->gap().setWhitelist(whitelist); 00472 ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST); 00473 #endif 00474 00475 // Update the advertised name of this micro:bit to include the device name 00476 ble->clearAdvertisingPayload(); 00477 00478 ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00479 ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length()); 00480 ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00481 ble->setAdvertisingInterval(200); 00482 00483 ble->gap().setAdvertisingTimeout(0); 00484 ble->gap().startAdvertising(); 00485 00486 // Stop any running animations on the display 00487 display.stopAnimation(); 00488 display.scroll(msg); 00489 00490 // Display our name, visualised as a histogram in the display to aid identification. 00491 showNameHistogram(display); 00492 00493 while(1) 00494 { 00495 if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST) 00496 { 00497 timeInPairingMode = 0; 00498 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"); 00499 display.print(arrow,0,0,0); 00500 00501 if (fadeDirection == 0) 00502 brightness -= MICROBIT_PAIRING_FADE_SPEED; 00503 else 00504 brightness += MICROBIT_PAIRING_FADE_SPEED; 00505 00506 if (brightness <= 40) 00507 display.clear(); 00508 00509 if (brightness <= 0) 00510 fadeDirection = 1; 00511 00512 if (brightness >= 255) 00513 fadeDirection = 0; 00514 00515 if (authorisationButton.isPressed()) 00516 { 00517 pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST; 00518 pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE; 00519 } 00520 } 00521 00522 if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE) 00523 { 00524 timeInPairingMode = 0; 00525 display.setBrightness(255); 00526 for (int i=0; i<passKey.length(); i++) 00527 { 00528 display.image.print(passKey.charAt(i),0,0); 00529 fiber_sleep(800); 00530 display.clear(); 00531 fiber_sleep(200); 00532 00533 if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE) 00534 break; 00535 } 00536 00537 fiber_sleep(1000); 00538 } 00539 00540 if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE) 00541 { 00542 if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL) 00543 { 00544 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"); 00545 display.print(tick,0,0,0); 00546 fiber_sleep(15000); 00547 timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30; 00548 00549 /* 00550 * Disabled, as the API to return the number of active bonds is not reliable at present... 00551 * 00552 display.clear(); 00553 ManagedString c(getBondCount()); 00554 ManagedString c2("/"); 00555 ManagedString c3(MICROBIT_BLE_MAXIMUM_BONDS); 00556 ManagedString c4("USED"); 00557 00558 display.scroll(c+c2+c3+c4); 00559 * 00560 * 00561 */ 00562 } 00563 else 00564 { 00565 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"); 00566 display.print(cross,0,0,0); 00567 } 00568 } 00569 00570 fiber_sleep(100); 00571 timeInPairingMode++; 00572 00573 if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30) 00574 microbit_reset(); 00575 } 00576 } 00577 00578 /** 00579 * Displays the device's ID code as a histogram on the provided MicroBitDisplay instance. 00580 * 00581 * @param display The display instance used for displaying the histogram. 00582 */ 00583 void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display) 00584 { 00585 uint32_t n = NRF_FICR->DEVICEID[1]; 00586 int ld = 1; 00587 int d = MICROBIT_DFU_HISTOGRAM_HEIGHT; 00588 int h; 00589 00590 display.clear(); 00591 for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++) 00592 { 00593 h = (n % d) / ld; 00594 00595 n -= h; 00596 d *= MICROBIT_DFU_HISTOGRAM_HEIGHT; 00597 ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT; 00598 00599 for (int j=0; j<h+1; j++) 00600 display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255); 00601 } 00602 }
Generated on Tue Jul 12 2022 19:58:09 by 1.7.2