Eddystone test using modified DAL

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit-eddystone

Fork of microbit-dal by Lancaster University

Files at this revision

API Documentation at this revision

Comitter:
bluetooth_mdw
Date:
Wed Feb 08 07:49:17 2017 +0000
Parent:
73:eb91bba49623
Commit message:
Eddystone URL test using modified DAL

Changed in this revision

inc/bluetooth/MicroBitBLEManager.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitEddystone.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitConfig.h Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitBLEManager.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitEddystone.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/inc/bluetooth/MicroBitBLEManager.h	Wed Jul 13 14:32:54 2016 +0000
+++ b/inc/bluetooth/MicroBitBLEManager.h	Wed Feb 08 07:49:17 2017 +0000
@@ -35,7 +35,7 @@
  * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
  * as a compatability option, but does not support the options used...
  */
-#if !defined (__arm)
+#if !defined(__arm)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 #endif
@@ -44,7 +44,7 @@
 /*
  * Return to our predefined compiler settings.
  */
-#if !defined (__arm)
+#if !defined(__arm)
 #pragma GCC diagnostic pop
 #endif
 
@@ -61,21 +61,24 @@
 #include "MicroBitButton.h"
 #include "MicroBitStorage.h"
 
-#define MICROBIT_BLE_PAIR_REQUEST               0x01
-#define MICROBIT_BLE_PAIR_COMPLETE              0x02
-#define MICROBIT_BLE_PAIR_PASSCODE              0x04
-#define MICROBIT_BLE_PAIR_SUCCESSFUL            0x08
+#define MICROBIT_BLE_PAIR_REQUEST 0x01
+#define MICROBIT_BLE_PAIR_COMPLETE 0x02
+#define MICROBIT_BLE_PAIR_PASSCODE 0x04
+#define MICROBIT_BLE_PAIR_SUCCESSFUL 0x08
 
-#define MICROBIT_BLE_PAIRING_TIMEOUT	        90
-#define MICROBIT_BLE_POWER_LEVELS               8
-#define MICROBIT_BLE_MAXIMUM_BONDS              4
-#define MICROBIT_BLE_ENABLE_BONDING 	        true
+#define MICROBIT_BLE_PAIRING_TIMEOUT 90
+#define MICROBIT_BLE_POWER_LEVELS 8
+#define MICROBIT_BLE_MAXIMUM_BONDS 4
+#define MICROBIT_BLE_ENABLE_BONDING true
+
+#define MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL     400
+#define MICROBIT_BLE_EDDYSTONE_DEFAULT_POWER    0xF0
 
 extern const int8_t MICROBIT_BLE_POWER_LEVEL[];
 
 struct BLESysAttribute
 {
-    uint8_t         sys_attr[8];
+    uint8_t sys_attr[8];
 };
 
 struct BLESysAttributeStore
@@ -89,13 +92,14 @@
   */
 class MicroBitBLEManager : MicroBitComponent
 {
-    public:
+  public:
+    static MicroBitBLEManager *manager;
 
-	// The mbed abstraction of the BlueTooth Low Energy (BLE) hardware
-    BLEDevice                       *ble;
+    // The mbed abstraction of the BlueTooth Low Energy (BLE) hardware
+    BLEDevice *ble;
 
     //an instance of MicroBitStorage used to store sysAttrs from softdevice
-    MicroBitStorage* storage;
+    MicroBitStorage *storage;
 
     /**
      * Constructor.
@@ -107,7 +111,7 @@
      * @note The BLE stack *cannot*  be brought up in a static context (the software simply hangs or corrupts itself).
      * Hence, the init() member function should be used to initialise the BLE stack.
      */
-    MicroBitBLEManager(MicroBitStorage& _storage);
+    MicroBitBLEManager(MicroBitStorage &_storage);
 
     /**
      * Constructor.
@@ -120,6 +124,15 @@
     MicroBitBLEManager();
 
     /**
+     * getInstance
+     *
+     * Allows other objects to easily obtain a pointer to the single instance of this object. By rights the constructor should be made
+     * private to properly implement the singleton pattern.
+     *
+     */
+    static MicroBitBLEManager *getInstance();
+
+    /**
       * Post constructor initialisation method as the BLE stack cannot be brought
       * up in a static context.
       *
@@ -132,7 +145,7 @@
       * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true);
       * @endcode
       */
-    void init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding);
+    void init(ManagedString deviceName, ManagedString serialNumber, EventModel &messageBus, bool enableBonding);
 
     /**
      * Change the output power level of the transmitter to the given value.
@@ -174,42 +187,102 @@
      */
     int getBondCount();
 
-	/**
+    /**
 	 * A request to pair has been received from a BLE device.
      * If we're in pairing mode, display the passkey to the user.
      * Also, purge the bonding table if it has reached capacity.
      *
      * @note for internal use only.
 	 */
-	void pairingRequested(ManagedString passKey);
+    void pairingRequested(ManagedString passKey);
 
-	/**
+    /**
 	 * A pairing request has been sucessfully completed.
 	 * If we're in pairing mode, display a success or failure message.
      *
      * @note for internal use only.
 	 */
-	void pairingComplete(bool success);
+    void pairingComplete(bool success);
 
-	/**
+    /**
      * Periodic callback in thread context.
      * We use this here purely to safely issue a disconnect operation after a pairing operation is complete.
 	 */
-	void idleTick();
+    void idleTick();
+
+    /**
+	* Stops any currently running BLE advertisements
+	*/
+    void stopAdvertising();
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL)
 
-    private:
+    /**
+      * Set the content of Eddystone URL frames
+      *
+      * @param url The url to broadcast
+      *
+      * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+      *
+      * @param connectable true to keep bluetooth connectable for other services, false otherwise. (Defaults to true)
+      *
+      * @param interval the rate at which the micro:bit will advertise url frames. (Defaults to MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL)
+      *
+      * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+      * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+      */
+    int advertiseEddystoneUrl(const char *url, int8_t calibratedPower = MICROBIT_BLE_EDDYSTONE_DEFAULT_POWER, bool connectable = true, uint16_t interval = MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL);
 
-	/**
-	 * Displays the device's ID code as a histogram on the provided MicroBitDisplay instance.
-     *
-     * @param display The display instance used for displaying the histogram.
-	 */
-	void showNameHistogram(MicroBitDisplay &display);
+    /**
+      * Set the content of Eddystone URL frames, but accepts a ManagedString as a url.
+      *
+      * @param url The url to broadcast
+      *
+      * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+      *
+      * @param connectable true to keep bluetooth connectable for other services, false otherwise. (Defaults to true)
+      *
+      * @param interval the rate at which the micro:bit will advertise url frames. (Defaults to MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL)
+      *
+      * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+      * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+      */
+    int advertiseEddystoneUrl(ManagedString url, int8_t calibratedPower = MICROBIT_BLE_EDDYSTONE_DEFAULT_POWER, bool connectable = true, uint16_t interval = MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL);
+#endif
 
-	int				pairingStatus;
-	ManagedString	passKey;
-	ManagedString	deviceName;
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID)
+    /**
+      * Set the content of Eddystone UID frames
+      *
+      * @param uid_namespace: the uid namespace. Must 10 bytes long.
+      *
+      * @param uid_instance:  the uid instance value. Must 6 bytes long.
+      *
+      * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+      *
+      * @param connectable true to keep bluetooth connectable for other services, false otherwise. (Defaults to true)
+      *
+      * @param interval the rate at which the micro:bit will advertise url frames. (Defaults to MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL)
+      *
+      * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+      * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+      */
+    int advertiseEddystoneUid(const char* uid_namespace, const char* uid_instance, int8_t calibratedPower = MICROBIT_BLE_EDDYSTONE_DEFAULT_POWER, bool connectable = true, uint16_t interval = MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL);
+#endif
 
+  private:
+    /**
+	* Displays the device's ID code as a histogram on the provided MicroBitDisplay instance.
+    *
+    * @param display The display instance used for displaying the histogram.
+	*/
+    void showNameHistogram(MicroBitDisplay &display);
+
+    #define MICROBIT_BLE_DISCONNECT_AFTER_PAIRING_DELAY  500
+    unsigned long pairing_completed_at_time;   
+
+    int pairingStatus;
+    ManagedString passKey;
+    ManagedString deviceName;
 };
 
-#endif
\ No newline at end of file
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitEddystone.h	Wed Feb 08 07:49:17 2017 +0000
@@ -0,0 +1,104 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2016 British Broadcasting Corporation.
+This software is provided by Lancaster University by arrangement with the BBC.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef MICROBIT_EDDYSTONE_H
+#define MICROBIT_EDDYSTONE_H
+
+#include "MicroBitConfig.h"
+
+/*
+ * Return to our predefined compiler settings.
+ */
+#if !defined(__arm)
+#pragma GCC diagnostic pop
+#endif
+
+#include "MicroBitBLEManager.h"
+
+/**
+  * Class definition for the MicroBitEddystone.
+  *
+  */
+class MicroBitEddystone
+{
+  public:
+
+    static MicroBitEddystone* getInstance();
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL)
+
+    /**
+      * Set the content of Eddystone URL frames
+      *
+      * @param url The url to broadcast
+      *
+      * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+      *
+      * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+      * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+      */
+    int setURL(BLEDevice* ble, const char *url, int8_t calibratedPower = 0xF0);
+
+    /**
+      * Set the content of Eddystone URL frames, but accepts a ManagedString as a url.
+      *
+      * @param url The url to broadcast
+      *
+      * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+      *
+      * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+      * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+      */
+    int setURL(BLEDevice* ble, ManagedString url, int8_t calibratedPower = 0xF0);
+
+#endif
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID)
+    /**
+      * Set the content of Eddystone UID frames
+      *
+      * @param uid_namespace the uid namespace. Must 10 bytes long.
+      *
+      * @param uid_instance  the uid instance value. Must 6 bytes long.
+      *
+      * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+      *
+      * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+      * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+      */
+    int setUID(BLEDevice* ble, const char* uid_namespace, const char* uid_instance, int8_t calibratedPower = 0xF0);
+#endif
+
+  private:
+
+    /**
+      * Private constructor.
+      */
+    MicroBitEddystone();
+
+    static MicroBitEddystone *_instance;
+};
+
+#endif
--- a/inc/core/MicroBitConfig.h	Wed Jul 13 14:32:54 2016 +0000
+++ b/inc/core/MicroBitConfig.h	Wed Feb 08 07:49:17 2017 +0000
@@ -72,6 +72,35 @@
 #define MICROBIT_HEAP_END                       (CORTEX_M0_STACK_BASE - MICROBIT_STACK_SIZE)
 #endif
 
+// Defines the size of a physical FLASH page in RAM.
+#ifndef PAGE_SIZE
+#define PAGE_SIZE                               1024
+#endif
+
+// Defines where in memory persistent data is stored.
+#ifndef KEY_VALUE_STORE_PAGE
+#define KEY_VALUE_STORE_PAGE                    (PAGE_SIZE * (NRF_FICR->CODESIZE - 17)) 
+#endif
+
+#ifndef BLE_BOND_DATA_PAGE 
+#define BLE_BOND_DATA_PAGE                      (PAGE_SIZE * (NRF_FICR->CODESIZE - 18))
+#endif
+
+#ifndef DEFAULT_SCRATCH_PAGE
+#define DEFAULT_SCRATCH_PAGE                    (PAGE_SIZE * (NRF_FICR->CODESIZE - 19))
+#endif
+
+// Address of the end of the current program in FLASH memory.
+// This is recorded by the C/C++ linker, but the symbol name varies depending on which compiler is used.
+#if defined(__arm)
+extern uint32_t Image$$ER_IROM1$$RO$$Limit;
+#define FLASH_PROGRAM_END (uint32_t) (&Image$$ER_IROM1$$RO$$Limit)
+#else
+extern uint32_t __etext;
+#define FLASH_PROGRAM_END (uint32_t) (&__etext)
+#endif
+
+
 // Enables or disables the MicroBitHeapllocator. Note that if disabled, no reuse of the SRAM normally
 // reserved for SoftDevice is possible, and out of memory condition will no longer be trapped...
 // i.e. panic() will no longer be triggered on memory full conditions.
@@ -237,6 +266,18 @@
 #define MICROBIT_BLE_DFU_SERVICE                1
 #endif
 
+// Enable/Disable availability of Eddystone URL APIs
+// Set '1' to enable.
+#ifndef MICROBIT_BLE_EDDYSTONE_URL
+#define MICROBIT_BLE_EDDYSTONE_URL               1
+#endif
+
+// Enable/Disable availability of Eddystone UID APIs
+// Set '1' to enable.
+#ifndef MICROBIT_BLE_EDDYSTONE_UID
+#define MICROBIT_BLE_EDDYSTONE_UID               0
+#endif
+
 // Enable/Disable BLE Service: MicroBitEventService
 // This allows routing of events from the micro:bit message bus over BLE.
 // Set '1' to enable.
@@ -318,6 +359,26 @@
 #define MICROBIT_DEFAULT_SERIAL_MODE            SYNC_SLEEP
 #endif
 
+//
+// File System configuration defaults
+//
+
+//
+// Defines the logical block size for the file system.
+// Must be a factor of the physical PAGE_SIZE (ideally a power of two less).
+//
+#ifndef MBFS_BLOCK_SIZE     
+#define MBFS_BLOCK_SIZE     256
+#endif
+
+//
+// FileSystem writeback cache size, in bytes. Defines how many bytes will be stored
+// in RAM before being written back to FLASH. Set to zero to disable this feature.
+// Should be <= MBFS_BLOCK_SIZE.
+//
+#ifndef MBFS_CACHE_SIZE
+#define MBFS_CACHE_SIZE     16
+#endif
 
 //
 // I/O Options
@@ -384,4 +445,4 @@
 extern RawSerial* SERIAL_DEBUG;
 #endif
 
-#endif
\ No newline at end of file
+#endif
--- a/source/bluetooth/MicroBitBLEManager.cpp	Wed Jul 13 14:32:54 2016 +0000
+++ b/source/bluetooth/MicroBitBLEManager.cpp	Wed Feb 08 07:49:17 2017 +0000
@@ -25,9 +25,10 @@
 
 #include "MicroBitConfig.h"
 #include "MicroBitBLEManager.h"
+#include "MicroBitEddystone.h"
 #include "MicroBitStorage.h"
 #include "MicroBitFiber.h"
-
+#include "MicroBitSystemTimer.h"
 
 /* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ.
  * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
@@ -42,8 +43,7 @@
 
 #include "ble.h"
 
-extern "C"
-{
+extern "C" {
 #include "device_manager.h"
 uint32_t btle_set_gatt_table_size(uint32_t size);
 }
@@ -55,13 +55,28 @@
 #pragma GCC diagnostic pop
 #endif
 
-#define MICROBIT_PAIRING_FADE_SPEED		4
+#define MICROBIT_PAIRING_FADE_SPEED 4
 
-const char* MICROBIT_BLE_MANUFACTURER = NULL;
-const char* MICROBIT_BLE_MODEL = "BBC micro:bit";
-const char* MICROBIT_BLE_HARDWARE_VERSION = NULL;
-const char* MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION;
-const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL;
+//
+// Local enumeration of valid security modes. Used only to optimise pre‐processor comparisons.
+//
+#define __SECURITY_MODE_ENCRYPTION_OPEN_LINK 0
+#define __SECURITY_MODE_ENCRYPTION_NO_MITM 1
+#define __SECURITY_MODE_ENCRYPTION_WITH_MITM 2
+//
+// Some Black Magic to compare the definition of our security mode in MicroBitConfig with a given parameter.
+// Required as the MicroBitConfig option is actually an mbed enum, that is not normally comparable at compile time.
+//
+
+#define __CAT(a, ...) a##__VA_ARGS__
+#define SECURITY_MODE(x) __CAT(__, x)
+#define SECURITY_MODE_IS(x) (SECURITY_MODE(MICROBIT_BLE_SECURITY_LEVEL) == SECURITY_MODE(x))
+
+const char *MICROBIT_BLE_MANUFACTURER = NULL;
+const char *MICROBIT_BLE_MODEL = "BBC micro:bit";
+const char *MICROBIT_BLE_HARDWARE_VERSION = NULL;
+const char *MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION;
+const char *MICROBIT_BLE_SOFTWARE_VERSION = NULL;
 const int8_t MICROBIT_BLE_POWER_LEVEL[] = {-30, -20, -16, -12, -8, -4, 0, 4};
 
 /*
@@ -69,17 +84,18 @@
  * So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit
  * whilst keeping the code modular.
  */
-static MicroBitBLEManager *manager = NULL;                      // Singleton reference to the BLE manager. many mbed BLE API callbacks still do not support member funcions yet. :-(
-static uint8_t deviceID = 255;                                  // Unique ID for the peer that has connected to us.
-static Gap::Handle_t pairingHandle = 0;                         // The connection handle used during a pairing process. Used to ensure that connections are dropped elegantly.
+MicroBitBLEManager *MicroBitBLEManager::manager = NULL; // Singleton reference to the BLE manager. many mbed BLE API callbacks still do not support member funcions yet. :-(
+
+static uint8_t deviceID = 255;          // Unique ID for the peer that has connected to us.
+static Gap::Handle_t pairingHandle = 0; // The connection handle used during a pairing process. Used to ensure that connections are dropped elegantly.
 
 static void storeSystemAttributes(Gap::Handle_t handle)
 {
-    if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
+    if (MicroBitBLEManager::manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
     {
         ManagedString key("bleSysAttrs");
 
-        KeyValuePair* bleSysAttrs = manager->storage->get(key);
+        KeyValuePair *bleSysAttrs = MicroBitBLEManager::manager->storage->get(key);
 
         BLESysAttribute attrib;
         BLESysAttributeStore attribStore;
@@ -89,17 +105,17 @@
         sd_ble_gatts_sys_attr_get(handle, attrib.sys_attr, &len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
 
         //copy our stored sysAttrs
-        if(bleSysAttrs != NULL)
+        if (bleSysAttrs != NULL)
         {
             memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore));
             delete bleSysAttrs;
         }
 
         //check if we need to update
-        if(memcmp(attribStore.sys_attrs[deviceID].sys_attr, attrib.sys_attr, len) != 0)
+        if (memcmp(attribStore.sys_attrs[deviceID].sys_attr, attrib.sys_attr, len) != 0)
         {
             attribStore.sys_attrs[deviceID] = attrib;
-            manager->storage->put(key, (uint8_t *)&attribStore, sizeof(attribStore));
+            MicroBitBLEManager::manager->storage->put(key, (uint8_t *)&attribStore, sizeof(attribStore));
         }
     }
 }
@@ -109,20 +125,20 @@
   */
 static void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *reason)
 {
-    MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_DISCONNECTED);
+    MicroBitEvent(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED);
 
     storeSystemAttributes(reason->handle);
 
-    if (manager)
-	    manager->advertise();
+    if (MicroBitBLEManager::manager)
+        MicroBitBLEManager::manager->advertise();
 }
 
 /**
   * Callback when a BLE connection is established.
   */
-static void bleConnectionCallback(const Gap::ConnectionCallbackParams_t*)
+static void bleConnectionCallback(const Gap::ConnectionCallbackParams_t *)
 {
-    MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_CONNECTED);
+    MicroBitEvent(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_CONNECTED);
 }
 
 /**
@@ -133,23 +149,23 @@
     int complete = 0;
     deviceID = 255;
 
-    dm_handle_t dm_handle = {0,0,0,0};
+    dm_handle_t dm_handle = {0, 0, 0, 0};
 
     int ret = dm_handle_get(params->connHandle, &dm_handle);
 
     if (ret == 0)
         deviceID = dm_handle.device_id;
 
-    if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
+    if (MicroBitBLEManager::manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
     {
         ManagedString key("bleSysAttrs");
 
-        KeyValuePair* bleSysAttrs = manager->storage->get(key);
+        KeyValuePair *bleSysAttrs = MicroBitBLEManager::manager->storage->get(key);
 
         BLESysAttributeStore attribStore;
         BLESysAttribute attrib;
 
-        if(bleSysAttrs != NULL)
+        if (bleSysAttrs != NULL)
         {
             //restore our sysAttrStore
             memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore));
@@ -161,40 +177,39 @@
 
             complete = 1;
 
-            if(ret == 0)
+            if (ret == 0)
                 ret = sd_ble_gatts_service_changed(params->connHandle, 0x000c, 0xffff);
         }
     }
 
     if (!complete)
         sd_ble_gatts_sys_attr_set(params->connHandle, NULL, 0, 0);
-
 }
 
 static void passkeyDisplayCallback(Gap::Handle_t handle, const SecurityManager::Passkey_t passkey)
 {
-    (void) handle; /* -Wunused-param */
+    (void)handle; /* -Wunused-param */
 
-	ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN);
+    ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN);
 
-    if (manager)
-	    manager->pairingRequested(passKey);
+    if (MicroBitBLEManager::manager)
+        MicroBitBLEManager::manager->pairingRequested(passKey);
 }
 
 static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
 {
-    (void) handle; /* -Wunused-param */
+    (void)handle; /* -Wunused-param */
 
-    dm_handle_t dm_handle = {0,0,0,0};
+    dm_handle_t dm_handle = {0, 0, 0, 0};
     int ret = dm_handle_get(handle, &dm_handle);
 
     if (ret == 0)
         deviceID = dm_handle.device_id;
 
-    if (manager)
+    if (MicroBitBLEManager::manager)
     {
         pairingHandle = handle;
-	    manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS);
+        MicroBitBLEManager::manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS);
     }
 }
 
@@ -208,12 +223,11 @@
  * @note The BLE stack *cannot*  be brought up in a static context (the software simply hangs or corrupts itself).
  * Hence, the init() member function should be used to initialise the BLE stack.
  */
-MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage& _storage) :
-    storage(&_storage)
+MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage &_storage) : storage(&_storage)
 {
     manager = this;
-	this->ble = NULL;
-	this->pairingStatus = 0;
+    this->ble = NULL;
+    this->pairingStatus = 0;
 }
 
 /**
@@ -224,12 +238,24 @@
  * @note The BLE stack *cannot*  be brought up in a static context (the software simply hangs or corrupts itself).
  * Hence, the init() member function should be used to initialise the BLE stack.
  */
-MicroBitBLEManager::MicroBitBLEManager() :
-    storage(NULL)
+MicroBitBLEManager::MicroBitBLEManager() : storage(NULL)
 {
     manager = this;
-	this->ble = NULL;
-	this->pairingStatus = 0;
+    this->ble = NULL;
+    this->pairingStatus = 0;
+}
+
+/**
+ * When called, the micro:bit will begin advertising for a predefined period,
+ * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices.
+ */
+MicroBitBLEManager *MicroBitBLEManager::getInstance()
+{
+    if (manager == 0)
+    {
+        manager = new MicroBitBLEManager;
+    }
+    return manager;
 }
 
 /**
@@ -238,7 +264,7 @@
  */
 void MicroBitBLEManager::advertise()
 {
-    if(ble)
+    if (ble)
         ble->gap().startAdvertising();
 }
 
@@ -255,18 +281,18 @@
   * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true);
   * @endcode
   */
-void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding)
+void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel &messageBus, bool enableBonding)
 {
-	ManagedString BLEName("BBC micro:bit");
-	this->deviceName = deviceName;
+    ManagedString BLEName("BBC micro:bit");
+    this->deviceName = deviceName;
 
 #if !(CONFIG_ENABLED(MICROBIT_BLE_WHITELIST))
-	ManagedString namePrefix(" [");
-	ManagedString namePostfix("]");
-	BLEName = BLEName + namePrefix + deviceName + namePostfix;
+    ManagedString namePrefix(" [");
+    ManagedString namePostfix("]");
+    BLEName = BLEName + namePrefix + deviceName + namePostfix;
 #endif
 
-    // Start the BLE stack.
+// Start the BLE stack.
 #if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD)
     btle_set_gatt_table_size(MICROBIT_SD_GATT_TABLE_SIZE);
 #endif
@@ -289,14 +315,26 @@
     sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);
 
 #if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES)
-	// Configure for private addresses, so kids' behaviour can't be easily tracked.
-	ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0});
+    // Configure for private addresses, so kids' behaviour can't be easily tracked.
+    ble->gap().setAddress(BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE, {0});
 #endif
 
     // Setup our security requirements.
     ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback);
     ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
-    ble->securityManager().init(enableBonding, (SecurityManager::MICROBIT_BLE_SECURITY_LEVEL == SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM), SecurityManager::IO_CAPS_DISPLAY_ONLY);
+// @bluetooth_mdw: select either passkey pairing (more secure), "just works" pairing (less secure but nice and simple for the user)
+// or no security
+// Default to passkey pairing with MITM protection
+#if (SECURITY_MODE_IS(SECURITY_MODE_ENCRYPTION_NO_MITM))
+    // Just Works
+    ble->securityManager().init(enableBonding, false, SecurityManager::IO_CAPS_NONE);
+#elif (SECURITY_MODE_IS(SECURITY_MODE_ENCRYPTION_OPEN_LINK))
+    // no security
+    ble->securityManager().init(false, false, SecurityManager::IO_CAPS_DISPLAY_ONLY);
+#else
+    // passkey
+    ble->securityManager().init(enableBonding, true, SecurityManager::IO_CAPS_DISPLAY_ONLY);
+#endif
 
     if (enableBonding)
     {
@@ -329,13 +367,13 @@
     // Configure the radio at our default power level
     setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER);
 
-    // Bring up core BLE services.
+// Bring up core BLE services.
 #if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE)
     new MicroBitDFUService(*ble);
 #endif
 
 #if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE)
-    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);
+    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);
 #else
     (void)serialNumber;
 #endif
@@ -346,16 +384,15 @@
     (void)messageBus;
 #endif
 
-
     // Configure for high speed mode where possible.
     Gap::ConnectionParams_t fast;
     ble->getPreferredConnectionParams(&fast);
-    fast.minConnectionInterval = 8; // 10 ms
+    fast.minConnectionInterval = 8;  // 10 ms
     fast.maxConnectionInterval = 16; // 20 ms
     fast.slaveLatency = 0;
     ble->setPreferredConnectionParams(&fast);
 
-    // Setup advertising.
+// Setup advertising.
 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
     ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
 #else
@@ -370,9 +407,9 @@
     ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT);
 #endif
 
-    // If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices...
-    // This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable.
-    // If whiltelisting is disabled, then we always advertise.
+// If we have whitelisting enabled, then prevent only enable advertising of we have any binded devices...
+// This is to further protect kids' privacy. If no-one initiates BLE, then the device is unreachable.
+// If whiltelisting is disabled, then we always advertise.
 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
     if (whitelist.size > 0)
 #endif
@@ -427,8 +464,8 @@
 void MicroBitBLEManager::pairingRequested(ManagedString passKey)
 {
     // Update our mode to display the passkey.
-	this->passKey = passKey;
-	this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST;
+    this->passKey = passKey;
+    this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST;
 }
 
 /**
@@ -439,11 +476,13 @@
  */
 void MicroBitBLEManager::pairingComplete(bool success)
 {
-	this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE;
+    this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE;
+
+    pairing_completed_at_time = system_timer_current_time();
 
-	if(success)
+    if (success)
     {
-		this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
+        this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
         fiber_add_idle_component(this);
     }
 }
@@ -454,11 +493,115 @@
  */
 void MicroBitBLEManager::idleTick()
 {
-    if (ble)
-        ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
+    if((system_timer_current_time() - pairing_completed_at_time) >= MICROBIT_BLE_DISCONNECT_AFTER_PAIRING_DELAY) {
+        if (ble)
+            ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
+        fiber_remove_idle_component(this);
+    }
+
+}
+
+
+/**
+* Stops any currently running BLE advertisements
+*/
+void MicroBitBLEManager::stopAdvertising()
+{
+    ble->gap().stopAdvertising();
+}
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL)
+/**
+  * Set the content of Eddystone URL frames
+  *
+  * @param url The url to broadcast
+  *
+  * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+  *
+  * @param connectable true to keep bluetooth connectable for other services, false otherwise. (Defaults to true)
+  *
+  * @param interval the rate at which the micro:bit will advertise url frames. (Defaults to MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL)
+  *
+  * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+  * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+  */
+int MicroBitBLEManager::advertiseEddystoneUrl(const char* url, int8_t calibratedPower, bool connectable, uint16_t interval)
+{
+    ble->gap().stopAdvertising();
+    ble->clearAdvertisingPayload();
+
+    ble->setAdvertisingType(connectable ? GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED : GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
+    ble->setAdvertisingInterval(interval);
+
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+
+    int ret = MicroBitEddystone::getInstance()->setURL(ble, url, calibratedPower);
+
+#if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0)
+    ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT);
+#endif
+    ble->gap().startAdvertising();
+
+    return ret;
+}
 
-    fiber_remove_idle_component(this);
+/**
+  * Set the content of Eddystone URL frames, but accepts a ManagedString as a url.
+  *
+  * @param url The url to broadcast
+  *
+  * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+  *
+  * @param connectable true to keep bluetooth connectable for other services, false otherwise. (Defaults to true)
+  *
+  * @param interval the rate at which the micro:bit will advertise url frames. (Defaults to MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL)
+  *
+  * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+  * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+  */
+int MicroBitBLEManager::advertiseEddystoneUrl(ManagedString url, int8_t calibratedPower, bool connectable, uint16_t interval)
+{
+    return advertiseEddystoneUrl((char *)url.toCharArray(), calibratedPower, connectable, interval);
 }
+#endif
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID)
+/**
+  * Set the content of Eddystone UID frames
+  *
+  * @param uid_namespace: the uid namespace. Must 10 bytes long.
+  *
+  * @param uid_instance:  the uid instance value. Must 6 bytes long.
+  *
+  * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+  *
+  * @param connectable true to keep bluetooth connectable for other services, false otherwise. (Defaults to true)
+  *
+  * @param interval the rate at which the micro:bit will advertise url frames. (Defaults to MICROBIT_BLE_EDDYSTONE_ADV_INTERVAL)
+  *
+  * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+  * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+  */
+int MicroBitBLEManager::advertiseEddystoneUid(const char* uid_namespace, const char* uid_instance, int8_t calibratedPower, bool connectable, uint16_t interval)
+{
+    ble->gap().stopAdvertising();
+    ble->clearAdvertisingPayload();
+
+    ble->setAdvertisingType(connectable ? GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED : GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
+    ble->setAdvertisingInterval(interval);
+
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+
+    int ret = MicroBitEddystone::getInstance()->setUID(ble, uid_namespace, uid_instance, calibratedPower);
+
+#if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0)
+    ble->gap().setAdvertisingTimeout(MICROBIT_BLE_ADVERTISING_TIMEOUT);
+#endif
+    ble->gap().startAdvertising();
+
+    return ret;
+}
+#endif
 
 /**
  * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
@@ -472,21 +615,21 @@
  * bleManager.pairingMode(uBit.display, uBit.buttonA);
  * @endcode
  */
-void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton)
+void MicroBitBLEManager::pairingMode(MicroBitDisplay &display, MicroBitButton &authorisationButton)
 {
-	ManagedString namePrefix("BBC micro:bit [");
-	ManagedString namePostfix("]");
-	ManagedString BLEName = namePrefix + deviceName + namePostfix;
+    ManagedString namePrefix("BBC micro:bit [");
+    ManagedString namePostfix("]");
+    ManagedString BLEName = namePrefix + deviceName + namePostfix;
 
-	ManagedString msg("PAIRING MODE!");
+    ManagedString msg("PAIRING MODE!");
 
-	int timeInPairingMode = 0;
-	int brightness = 255;
-	int fadeDirection = 0;
+    int timeInPairingMode = 0;
+    int brightness = 255;
+    int fadeDirection = 0;
 
     ble->gap().stopAdvertising();
 
-    // Clear the whitelist (if we have one), so that we're discoverable by all BLE devices.
+// Clear the whitelist (if we have one), so that we're discoverable by all BLE devices.
 #if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
     BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS];
     Gap::Whitelist_t whitelist;
@@ -497,7 +640,7 @@
     ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
 #endif
 
-	// Update the advertised name of this micro:bit to include the device name
+    // Update the advertised name of this micro:bit to include the device name
     ble->clearAdvertisingPayload();
 
     ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
@@ -508,68 +651,68 @@
     ble->gap().setAdvertisingTimeout(0);
     ble->gap().startAdvertising();
 
-	// Stop any running animations on the display
-	display.stopAnimation();
-	display.scroll(msg);
+    // Stop any running animations on the display
+    display.stopAnimation();
+    display.scroll(msg);
 
-	// Display our name, visualised as a histogram in the display to aid identification.
-	showNameHistogram(display);
+    // Display our name, visualised as a histogram in the display to aid identification.
+    showNameHistogram(display);
 
-	while(1)
-	{
-		if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
-		{
-			timeInPairingMode = 0;
-			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");
-			display.print(arrow,0,0,0);
+    while (1)
+    {
+        if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
+        {
+            timeInPairingMode = 0;
+            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");
+            display.print(arrow, 0, 0, 0);
 
-			if (fadeDirection == 0)
-				brightness -= MICROBIT_PAIRING_FADE_SPEED;
-			else
-				brightness += MICROBIT_PAIRING_FADE_SPEED;
+            if (fadeDirection == 0)
+                brightness -= MICROBIT_PAIRING_FADE_SPEED;
+            else
+                brightness += MICROBIT_PAIRING_FADE_SPEED;
 
-			if (brightness <= 40)
-				display.clear();
+            if (brightness <= 40)
+                display.clear();
 
-			if (brightness <= 0)
-				fadeDirection = 1;
+            if (brightness <= 0)
+                fadeDirection = 1;
 
-			if (brightness >= 255)
-				fadeDirection = 0;
+            if (brightness >= 255)
+                fadeDirection = 0;
 
-			if (authorisationButton.isPressed())
-			{
-				pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
-				pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
-			}
-		}
+            if (authorisationButton.isPressed())
+            {
+                pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
+                pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
+            }
+        }
 
-		if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE)
-		{
-			timeInPairingMode = 0;
-			display.setBrightness(255);
-			for (int i=0; i<passKey.length(); i++)
-			{
-				display.image.print(passKey.charAt(i),0,0);
-				fiber_sleep(800);
-				display.clear();
-				fiber_sleep(200);
+        if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE)
+        {
+            timeInPairingMode = 0;
+            display.setBrightness(255);
+            for (int i = 0; i < passKey.length(); i++)
+            {
+                display.image.print(passKey.charAt(i), 0, 0);
+                fiber_sleep(800);
+                display.clear();
+                fiber_sleep(200);
 
-				if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
-					break;
-			}
+                if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
+                    break;
+            }
 
-			fiber_sleep(1000);
-		}
+            fiber_sleep(1000);
+        }
 
-		if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
-		{
-			if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL)
-			{
-				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");
-				display.print(tick,0,0,0);
+        if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
+        {
+            if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL)
+            {
+                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");
+                display.print(tick, 0, 0, 0);
                 fiber_sleep(15000);
-		        timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30;
+                timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30;
 
                 /*
                  * Disabled, as the API to return the number of active bonds is not reliable at present...
@@ -584,20 +727,20 @@
                 *
                 *
                 */
-			}
-			else
-			{
-				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");
-				display.print(cross,0,0,0);
-			}
-		}
+            }
+            else
+            {
+                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");
+                display.print(cross, 0, 0, 0);
+            }
+        }
 
-		fiber_sleep(100);
-		timeInPairingMode++;
+        fiber_sleep(100);
+        timeInPairingMode++;
 
-		if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
-			microbit_reset();
-	}
+        if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
+            microbit_reset();
+    }
 }
 
 /**
@@ -613,7 +756,7 @@
     int h;
 
     display.clear();
-    for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++)
+    for (int i = 0; i < MICROBIT_DFU_HISTOGRAM_WIDTH; i++)
     {
         h = (n % d) / ld;
 
@@ -621,7 +764,7 @@
         d *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
         ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
 
-        for (int j=0; j<h+1; j++)
-            display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255);
+        for (int j = 0; j < h + 1; j++)
+            display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH - i - 1, MICROBIT_DFU_HISTOGRAM_HEIGHT - j - 1, 255);
     }
-}
\ No newline at end of file
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitEddystone.cpp	Wed Feb 08 07:49:17 2017 +0000
@@ -0,0 +1,215 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2016 British Broadcasting Corporation.
+This software is provided by Lancaster University by arrangement with the BBC.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#include "MicroBitConfig.h"
+#include "MicroBitEddystone.h"
+
+MicroBitEddystone *MicroBitEddystone::_instance = NULL;
+
+/* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ.
+ * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
+ * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
+ * as a compatability option, but does not support the options used...
+ */
+#if !defined(__arm)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+/*
+ * Return to our predefined compiler settings.
+ */
+#if !defined(__arm)
+#pragma GCC diagnostic pop
+#endif
+
+const uint8_t EDDYSTONE_UUID[] = {0xAA, 0xFE};
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL)
+const char *EDDYSTONE_URL_PREFIXES[] = {"http://www.", "https://www.", "http://", "https://"};
+const size_t EDDYSTONE_URL_PREFIXES_LENGTH = sizeof(EDDYSTONE_URL_PREFIXES) / sizeof(char *);
+const char *EDDYSTONE_URL_SUFFIXES[] = {".com/", ".org/", ".edu/", ".net/", ".info/", ".biz/", ".gov/", ".com", ".org", ".edu", ".net", ".info", ".biz", ".gov"};
+const size_t EDDYSTONE_URL_SUFFIXES_LENGTH = sizeof(EDDYSTONE_URL_SUFFIXES) / sizeof(char *);
+const int EDDYSTONE_URL_MAX_LENGTH = 18;
+const uint8_t EDDYSTONE_URL_FRAME_TYPE = 0x10;
+#endif
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID)
+const int EDDYSTONE_UID_NAMESPACE_MAX_LENGTH = 10;
+const int EDDYSTONE_UID_INSTANCE_MAX_LENGTH = 6;
+const uint8_t EDDYSTONE_UID_FRAME_TYPE = 0x00;
+#endif
+
+/**
+ * Constructor.
+ *
+ * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
+ *
+ * @param _storage an instance of MicroBitStorage used to persist sys attribute information. (This is required for compatability with iOS).
+ *
+ * @note The BLE stack *cannot*  be brought up in a static context (the software simply hangs or corrupts itself).
+ * Hence, the init() member function should be used to initialise the BLE stack.
+ */
+MicroBitEddystone::MicroBitEddystone()
+{
+}
+
+MicroBitEddystone* MicroBitEddystone::getInstance()
+{
+    if (_instance == 0)
+        _instance = new MicroBitEddystone;
+
+    return _instance;
+}
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL)
+
+/**
+  * Set the content of Eddystone URL frames
+  *
+  * @param url The url to broadcast
+  *
+  * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+  *
+  * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+  * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+  */
+int MicroBitEddystone::setURL(BLEDevice* ble, const char* url, int8_t calibratedPower)
+{
+    int urlDataLength = 0;
+    char urlData[EDDYSTONE_URL_MAX_LENGTH];
+    memset(urlData, 0, EDDYSTONE_URL_MAX_LENGTH);
+
+    if (url == NULL || strlen(url) == 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Prefix
+    for (size_t i = 0; i < EDDYSTONE_URL_PREFIXES_LENGTH; i++)
+    {
+        size_t prefixLen = strlen(EDDYSTONE_URL_PREFIXES[i]);
+        if (strncmp(url, EDDYSTONE_URL_PREFIXES[i], prefixLen) == 0)
+        {
+            urlData[urlDataLength++] = i;
+            url += prefixLen;
+            break;
+        }
+    }
+
+    // Suffix
+    while (*url && (urlDataLength < EDDYSTONE_URL_MAX_LENGTH))
+    {
+        size_t i;
+        for (i = 0; i < EDDYSTONE_URL_SUFFIXES_LENGTH; i++)
+        {
+            size_t suffixLen = strlen(EDDYSTONE_URL_SUFFIXES[i]);
+            if (strncmp(url, EDDYSTONE_URL_SUFFIXES[i], suffixLen) == 0)
+            {
+                urlData[urlDataLength++] = i;
+                url += suffixLen;
+                break;
+            }
+        }
+
+        // Catch the default case where the suffix doesn't match a preset ones
+        if (i == EDDYSTONE_URL_SUFFIXES_LENGTH)
+        {
+            urlData[urlDataLength++] = *url;
+            ++url;
+        }
+    }
+
+    uint8_t rawFrame[EDDYSTONE_URL_MAX_LENGTH + 4];
+    size_t index = 0;
+    rawFrame[index++] = EDDYSTONE_UUID[0];
+    rawFrame[index++] = EDDYSTONE_UUID[1];
+    rawFrame[index++] = EDDYSTONE_URL_FRAME_TYPE;
+    rawFrame[index++] = calibratedPower;
+    memcpy(rawFrame + index, urlData, urlDataLength);
+
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, EDDYSTONE_UUID, sizeof(EDDYSTONE_UUID));
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, rawFrame, index + urlDataLength);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Set the content of Eddystone URL frames, but accepts a ManagedString as a url.
+  *
+  * @param url The url to broadcast
+  *
+  * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+  *
+  * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+  * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+  */
+int MicroBitEddystone::setURL(BLEDevice* ble, ManagedString url, int8_t calibratedPower)
+{
+    return setURL(ble, (char *)url.toCharArray(), calibratedPower);
+}
+#endif
+
+#if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID)
+
+/**
+  * Set the content of Eddystone UID frames
+  *
+  * @param uid_namespace the uid namespace. Must 10 bytes long.
+  *
+  * @param uid_instance  the uid instance value. Must 6 bytes long.
+  *
+  * @param calibratedPower the transmission range of the beacon (Defaults to: 0xF0 ~10m).
+  *
+  * @note The calibratedPower value ranges from -100 to +20 to a resolution of 1. The calibrated power should be binary encoded.
+  * More information can be found at https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power
+  */
+int MicroBitEddystone::setUID(BLEDevice* ble, const char* uid_namespace, const char* uid_instance, int8_t calibratedPower)
+{
+    if (uid_namespace == NULL || uid_instance == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    char uidData[EDDYSTONE_UID_NAMESPACE_MAX_LENGTH + EDDYSTONE_UID_INSTANCE_MAX_LENGTH];
+
+    // UID namespace
+    memcpy(uidData, uid_namespace, EDDYSTONE_UID_NAMESPACE_MAX_LENGTH);
+
+    // UID instance
+    memcpy(uidData + EDDYSTONE_UID_NAMESPACE_MAX_LENGTH, uid_instance, EDDYSTONE_UID_INSTANCE_MAX_LENGTH);
+
+    uint8_t rawFrame[EDDYSTONE_UID_NAMESPACE_MAX_LENGTH + EDDYSTONE_UID_INSTANCE_MAX_LENGTH + 4];
+    size_t index = 0;
+    rawFrame[index++] = EDDYSTONE_UUID[0];
+    rawFrame[index++] = EDDYSTONE_UUID[1];
+    rawFrame[index++] = EDDYSTONE_UID_FRAME_TYPE;
+    rawFrame[index++] = calibratedPower;
+    memcpy(rawFrame + index, uidData, EDDYSTONE_UID_NAMESPACE_MAX_LENGTH + EDDYSTONE_UID_INSTANCE_MAX_LENGTH);
+
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, EDDYSTONE_UUID, sizeof(EDDYSTONE_UUID));
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, rawFrame, index + EDDYSTONE_UID_NAMESPACE_MAX_LENGTH + EDDYSTONE_UID_INSTANCE_MAX_LENGTH);
+
+    return MICROBIT_OK;
+}
+
+#endif