mbed.org local branch of microbit-dal. The real version lives in git at https://github.com/lancaster-university/microbit-dal

Dependencies:   BLE_API nRF51822 mbed-dev-bin

Dependents:   microbit Microbit IoTChallenge1 microbit ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBitBLEManager.cpp Source File

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, sizeof(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     MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_DISCONNECTED);
00113 
00114     storeSystemAttributes(reason->handle);
00115 
00116     if (manager)
00117         manager->advertise();
00118 }
00119 
00120 /**
00121   * Callback when a BLE connection is established.
00122   */
00123 static void bleConnectionCallback(const Gap::ConnectionCallbackParams_t*)
00124 {
00125     MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_CONNECTED);
00126 }
00127 
00128 /**
00129   * Callback when a BLE SYS_ATTR_MISSING.
00130   */
00131 static void bleSysAttrMissingCallback(const GattSysAttrMissingCallbackParams *params)
00132 {
00133     int complete = 0;
00134     deviceID = 255;
00135 
00136     dm_handle_t dm_handle = {0,0,0,0};
00137 
00138     int ret = dm_handle_get(params->connHandle, &dm_handle);
00139 
00140     if (ret == 0)
00141         deviceID = dm_handle.device_id;
00142 
00143     if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
00144     {
00145         ManagedString key("bleSysAttrs");
00146 
00147         KeyValuePair* bleSysAttrs = manager->storage->get(key);
00148 
00149         BLESysAttributeStore attribStore;
00150         BLESysAttribute attrib;
00151 
00152         if(bleSysAttrs != NULL)
00153         {
00154             //restore our sysAttrStore
00155             memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore));
00156             delete bleSysAttrs;
00157 
00158             attrib = attribStore.sys_attrs[deviceID];
00159 
00160             ret = sd_ble_gatts_sys_attr_set(params->connHandle, attrib.sys_attr, sizeof(attrib.sys_attr), BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
00161 
00162             complete = 1;
00163 
00164             if(ret == 0)
00165                 ret = sd_ble_gatts_service_changed(params->connHandle, 0x000c, 0xffff);
00166         }
00167     }
00168 
00169     if (!complete)
00170         sd_ble_gatts_sys_attr_set(params->connHandle, NULL, 0, 0);
00171 
00172 }
00173 
00174 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
00175 {
00176     (void) handle; /* -Wunused-param */
00177 
00178     ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN);
00179 
00180     if (manager)
00181         manager->pairingRequested(passKey);
00182 }
00183 
00184 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
00185 {
00186     (void) handle; /* -Wunused-param */
00187 
00188     dm_handle_t dm_handle = {0,0,0,0};
00189     int ret = dm_handle_get(handle, &dm_handle);
00190 
00191     if (ret == 0)
00192         deviceID = dm_handle.device_id;
00193 
00194     if (manager)
00195     {
00196         pairingHandle = handle;
00197         manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS);
00198     }
00199 }
00200 
00201 /**
00202  * Constructor.
00203  *
00204  * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
00205  *
00206  * @param _storage an instance of MicroBitStorage used to persist sys attribute information. (This is required for compatability with iOS).
00207  *
00208  * @note The BLE stack *cannot*  be brought up in a static context (the software simply hangs or corrupts itself).
00209  * Hence, the init() member function should be used to initialise the BLE stack.
00210  */
00211 MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage& _storage) :
00212     storage(&_storage)
00213 {
00214     manager = this;
00215     this->ble = NULL;
00216     this->pairingStatus = 0;
00217 }
00218 
00219 /**
00220  * Constructor.
00221  *
00222  * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
00223  *
00224  * @note The BLE stack *cannot*  be brought up in a static context (the software simply hangs or corrupts itself).
00225  * Hence, the init() member function should be used to initialise the BLE stack.
00226  */
00227 MicroBitBLEManager::MicroBitBLEManager() :
00228     storage(NULL)
00229 {
00230     manager = this;
00231     this->ble = NULL;
00232     this->pairingStatus = 0;
00233 }
00234 
00235 /**
00236  * When called, the micro:bit will begin advertising for a predefined period,
00237  * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices.
00238  */
00239 void MicroBitBLEManager::advertise()
00240 {
00241     if(ble)
00242         ble->gap().startAdvertising();
00243 }
00244 
00245 /**
00246   * Post constructor initialisation method as the BLE stack cannot be brought
00247   * up in a static context.
00248   *
00249   * @param deviceName The name used when advertising
00250   * @param serialNumber The serial number exposed by the device information service
00251   * @param messageBus An instance of an EventModel, used during pairing.
00252   * @param enableBonding If true, the security manager enabled bonding.
00253   *
00254   * @code
00255   * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true);
00256   * @endcode
00257   */
00258 void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding)
00259 {
00260     ManagedString BLEName("BBC micro:bit");
00261     this->deviceName = deviceName;
00262 
00263 #if !(CONFIG_ENABLED(MICROBIT_BLE_WHITELIST))
00264     ManagedString namePrefix(" [");
00265     ManagedString namePostfix("]");
00266     BLEName = BLEName + namePrefix + deviceName + namePostfix;
00267 #endif
00268 
00269     // Start the BLE stack.
00270 #if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD)
00271     btle_set_gatt_table_size(MICROBIT_SD_GATT_TABLE_SIZE);
00272 #endif
00273 
00274     ble = new BLEDevice();
00275     ble->init();
00276 
00277     // automatically restart advertising after a device disconnects.
00278     ble->gap().onDisconnection(bleDisconnectionCallback);
00279     ble->gattServer().onSysAttrMissing(bleSysAttrMissingCallback);
00280 
00281     // generate an event when a Bluetooth connection is established
00282     ble->gap().onConnection(bleConnectionCallback);
00283 
00284     // Configure the stack to hold onto the CPU during critical timing events.
00285     // mbed-classic performs __disable_irq() calls in its timers that can cause
00286     // MIC failures on secure BLE channels...
00287     ble_common_opt_radio_cpu_mutex_t opt;
00288     opt.enable = 1;
00289     sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);
00290 
00291 #if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES)
00292     // Configure for private addresses, so kids' behaviour can't be easily tracked.
00293     ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0});
00294 #endif
00295 
00296     // Setup our security requirements.
00297     ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback);
00298     ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
00299     ble->securityManager().init(enableBonding, (SecurityManager::MICROBIT_BLE_SECURITY_LEVEL == SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM), SecurityManager::IO_CAPS_DISPLAY_ONLY);
00300 
00301     if (enableBonding)
00302     {
00303         // If we're in pairing mode, review the size of the bond table.
00304         int bonds = getBondCount();
00305 
00306         // TODO: It would be much better to implement some sort of LRU/NFU policy here,
00307         // but this isn't currently supported in mbed, so we'd need to layer break...
00308 
00309         // If we're full, empty the bond table.
00310         if (bonds >= MICROBIT_BLE_MAXIMUM_BONDS)
00311             ble->securityManager().purgeAllBondingState();
00312     }
00313 
00314 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
00315     // Configure a whitelist to filter all connection requetss from unbonded devices.
00316     // Most BLE stacks only permit one connection at a time, so this prevents denial of service attacks.
00317     BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
00318     Gap::Whitelist_t whitelist;
00319     whitelist.addresses = bondedAddresses;
00320     whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
00321 
00322     ble->securityManager().getAddressesFromBondTable(whitelist);
00323 
00324     ble->gap().setWhitelist(whitelist);
00325     ble->gap().setScanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST);
00326     ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS);
00327 #endif
00328 
00329     // Configure the radio at our default power level
00330     setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER);
00331 
00332     // Bring up core BLE services.
00333 #if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE)
00334     new MicroBitDFUService(*ble);
00335 #endif
00336 
00337 #if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE)
00338     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);
00339 #else
00340     (void)serialNumber;
00341 #endif
00342 
00343 #if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE)
00344     new MicroBitEventService(*ble, messageBus);
00345 #else
00346     (void)messageBus;
00347 #endif
00348 
00349 
00350     // Configure for high speed mode where possible.
00351     Gap::ConnectionParams_t fast;
00352     ble->getPreferredConnectionParams(&fast);
00353     fast.minConnectionInterval = 8; // 10 ms
00354     fast.maxConnectionInterval = 16; // 20 ms
00355     fast.slaveLatency = 0;
00356     ble->setPreferredConnectionParams(&fast);
00357 
00358     // Setup advertising.
00359 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
00360     ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
00361 #else
00362     ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00363 #endif
00364 
00365     ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
00366     ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00367     ble->setAdvertisingInterval(200);
00368 
00369 #if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0)
00370     ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT);
00371 #endif
00372 
00373     // If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices...
00374     // This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable.
00375     // If whiltelisting is disabled, then we always advertise.
00376 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
00377     if (whitelist.size > 0)
00378 #endif
00379         ble->startAdvertising();
00380 }
00381 
00382 /**
00383  * Change the output power level of the transmitter to the given value.
00384  *
00385  * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest.
00386  *
00387  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range.
00388  *
00389  * @code
00390  * // maximum transmission power.
00391  * bleManager.setTransmitPower(7);
00392  * @endcode
00393  */
00394 int MicroBitBLEManager::setTransmitPower(int power)
00395 {
00396     if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS)
00397         return MICROBIT_INVALID_PARAMETER;
00398 
00399     if (ble->gap().setTxPower(MICROBIT_BLE_POWER_LEVEL[power]) != NRF_SUCCESS)
00400         return MICROBIT_NOT_SUPPORTED;
00401 
00402     return MICROBIT_OK;
00403 }
00404 
00405 /**
00406  * Determines the number of devices currently bonded with this micro:bit.
00407  * @return The number of active bonds.
00408  */
00409 int MicroBitBLEManager::getBondCount()
00410 {
00411     BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
00412     Gap::Whitelist_t whitelist;
00413     whitelist.addresses = bondedAddresses;
00414     whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
00415     ble->securityManager().getAddressesFromBondTable(whitelist);
00416 
00417     return whitelist.bonds;
00418 }
00419 
00420 /**
00421  * A request to pair has been received from a BLE device.
00422  * If we're in pairing mode, display the passkey to the user.
00423  * Also, purge the bonding table if it has reached capacity.
00424  *
00425  * @note for internal use only.
00426  */
00427 void MicroBitBLEManager::pairingRequested(ManagedString passKey)
00428 {
00429     // Update our mode to display the passkey.
00430     this->passKey = passKey;
00431     this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST;
00432 }
00433 
00434 /**
00435  * A pairing request has been sucessfully completed.
00436  * If we're in pairing mode, display a success or failure message.
00437  *
00438  * @note for internal use only.
00439  */
00440 void MicroBitBLEManager::pairingComplete(bool success)
00441 {
00442     this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE;
00443 
00444     if(success)
00445     {
00446         this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
00447         fiber_add_idle_component(this);
00448     }
00449 }
00450 
00451 /**
00452  * Periodic callback in thread context.
00453  * We use this here purely to safely issue a disconnect operation after a pairing operation is complete.
00454  */
00455 void MicroBitBLEManager::idleTick()
00456 {
00457     if (ble)
00458         ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
00459 
00460     fiber_remove_idle_component(this);
00461 }
00462 
00463 /**
00464  * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
00465  * of the micro:bit in cases where BLE is disabled during normal operation.
00466  *
00467  * @param display An instance of MicroBitDisplay used when displaying pairing information.
00468  * @param authorizationButton The button to use to authorise a pairing request.
00469  *
00470  * @code
00471  * // initiate pairing mode
00472  * bleManager.pairingMode(uBit.display, uBit.buttonA);
00473  * @endcode
00474  */
00475 void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton)
00476 {
00477     ManagedString namePrefix("BBC micro:bit [");
00478     ManagedString namePostfix("]");
00479     ManagedString BLEName = namePrefix + deviceName + namePostfix;
00480 
00481     ManagedString msg("PAIRING MODE!");
00482 
00483     int timeInPairingMode = 0;
00484     int brightness = 255;
00485     int fadeDirection = 0;
00486 
00487     ble->gap().stopAdvertising();
00488 
00489     // Clear the whitelist (if we have one), so that we're discoverable by all BLE devices.
00490 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
00491     BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS];
00492     Gap::Whitelist_t whitelist;
00493     whitelist.addresses = addresses;
00494     whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
00495     whitelist.size = 0;
00496     ble->gap().setWhitelist(whitelist);
00497     ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
00498 #endif
00499 
00500     // Update the advertised name of this micro:bit to include the device name
00501     ble->clearAdvertisingPayload();
00502 
00503     ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00504     ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
00505     ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00506     ble->setAdvertisingInterval(200);
00507 
00508     ble->gap().setAdvertisingTimeout(0);
00509     ble->gap().startAdvertising();
00510 
00511     // Stop any running animations on the display
00512     display.stopAnimation();
00513     display.scroll(msg);
00514 
00515     // Display our name, visualised as a histogram in the display to aid identification.
00516     showNameHistogram(display);
00517 
00518     while(1)
00519     {
00520         if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
00521         {
00522             timeInPairingMode = 0;
00523             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");
00524             display.print(arrow,0,0,0);
00525 
00526             if (fadeDirection == 0)
00527                 brightness -= MICROBIT_PAIRING_FADE_SPEED;
00528             else
00529                 brightness += MICROBIT_PAIRING_FADE_SPEED;
00530 
00531             if (brightness <= 40)
00532                 display.clear();
00533 
00534             if (brightness <= 0)
00535                 fadeDirection = 1;
00536 
00537             if (brightness >= 255)
00538                 fadeDirection = 0;
00539 
00540             if (authorisationButton.isPressed())
00541             {
00542                 pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
00543                 pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
00544             }
00545         }
00546 
00547         if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE)
00548         {
00549             timeInPairingMode = 0;
00550             display.setBrightness(255);
00551             for (int i=0; i<passKey.length(); i++)
00552             {
00553                 display.image.print(passKey.charAt(i),0,0);
00554                 fiber_sleep(800);
00555                 display.clear();
00556                 fiber_sleep(200);
00557 
00558                 if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
00559                     break;
00560             }
00561 
00562             fiber_sleep(1000);
00563         }
00564 
00565         if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
00566         {
00567             if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL)
00568             {
00569                 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");
00570                 display.print(tick,0,0,0);
00571                 fiber_sleep(15000);
00572                 timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30;
00573 
00574                 /*
00575                  * Disabled, as the API to return the number of active bonds is not reliable at present...
00576                  *
00577                 display.clear();
00578                 ManagedString c(getBondCount());
00579                 ManagedString c2("/");
00580                 ManagedString c3(MICROBIT_BLE_MAXIMUM_BONDS);
00581                 ManagedString c4("USED");
00582 
00583                 display.scroll(c+c2+c3+c4);
00584                 *
00585                 *
00586                 */
00587             }
00588             else
00589             {
00590                 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");
00591                 display.print(cross,0,0,0);
00592             }
00593         }
00594 
00595         fiber_sleep(100);
00596         timeInPairingMode++;
00597 
00598         if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
00599             microbit_reset();
00600     }
00601 }
00602 
00603 /**
00604  * Displays the device's ID code as a histogram on the provided MicroBitDisplay instance.
00605  *
00606  * @param display The display instance used for displaying the histogram.
00607  */
00608 void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display)
00609 {
00610     uint32_t n = NRF_FICR->DEVICEID[1];
00611     int ld = 1;
00612     int d = MICROBIT_DFU_HISTOGRAM_HEIGHT;
00613     int h;
00614 
00615     display.clear();
00616     for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++)
00617     {
00618         h = (n % d) / ld;
00619 
00620         n -= h;
00621         d *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
00622         ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
00623 
00624         for (int j=0; j<h+1; j++)
00625             display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255);
00626     }
00627 }