updates

Dependencies:   BLE_API mbed-dev-bin nRF51822

Fork of microbit-dal-eddystone by Martin Woolley

Files at this revision

API Documentation at this revision

Comitter:
Jonathan Austin
Date:
Thu Apr 07 01:33:22 2016 +0100
Parent:
0:fb15f7887843
Child:
2:557d9ac9e959
Commit message:
Synchronized with git rev 55cb9199

Changed in this revision

AUTHORS Show annotated file Show diff for this revision Revisions of this file
LICENSE Show annotated file Show diff for this revision Revisions of this file
README.md Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/ExternalEvents.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MESEvents.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitAccelerometerService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitBLEManager.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitButtonService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitDFUService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitEventService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitIOPinService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitLEDService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitMagnetometerService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitTemperatureService.h Show annotated file Show diff for this revision Revisions of this file
inc/bluetooth/MicroBitUARTService.h Show annotated file Show diff for this revision Revisions of this file
inc/core/ErrorNo.h Show annotated file Show diff for this revision Revisions of this file
inc/core/EventModel.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MemberFunctionCallback.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitCompat.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitComponent.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
inc/core/MicroBitDevice.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitFiber.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitFont.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitHeapAllocator.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitListener.h Show annotated file Show diff for this revision Revisions of this file
inc/core/MicroBitSystemTimer.h Show annotated file Show diff for this revision Revisions of this file
inc/core/NotifyEvents.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/DynamicPwm.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitAccelerometer.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitButton.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitCompass.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitCompassCalibrator.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitDisplay.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitI2C.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitIO.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitLightSensor.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitMatrixMaps.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitMessageBus.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitMultiButton.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitPin.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitRadio.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitRadioDatagram.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitRadioEvent.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitSerial.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitStorage.h Show annotated file Show diff for this revision Revisions of this file
inc/drivers/MicroBitThermometer.h Show annotated file Show diff for this revision Revisions of this file
inc/types/ManagedString.h Show annotated file Show diff for this revision Revisions of this file
inc/types/ManagedType.h Show annotated file Show diff for this revision Revisions of this file
inc/types/Matrix4.h Show annotated file Show diff for this revision Revisions of this file
inc/types/MicroBitCoordinateSystem.h Show annotated file Show diff for this revision Revisions of this file
inc/types/MicroBitEvent.h Show annotated file Show diff for this revision Revisions of this file
inc/types/MicroBitImage.h Show annotated file Show diff for this revision Revisions of this file
inc/types/PacketBuffer.h Show annotated file Show diff for this revision Revisions of this file
inc/types/RefCounted.h Show annotated file Show diff for this revision Revisions of this file
module.json Show annotated file Show diff for this revision Revisions of this file
source/CMakeLists.txt Show annotated file Show diff for this revision Revisions of this file
source/asm/CortexContextSwitch.s.armcc Show annotated file Show diff for this revision Revisions of this file
source/asm/CortexContextSwitch.s.gcc Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitAccelerometerService.cpp 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/MicroBitButtonService.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitDFUService.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitEventService.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitIOPinService.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitLEDService.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitMagnetometerService.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitTemperatureService.cpp Show annotated file Show diff for this revision Revisions of this file
source/bluetooth/MicroBitUARTService.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MemberFunctionCallback.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MicroBitCompat.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MicroBitDevice.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MicroBitFiber.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MicroBitFont.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MicroBitHeapAllocator.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MicroBitListener.cpp Show annotated file Show diff for this revision Revisions of this file
source/core/MicroBitSystemTimer.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/DynamicPwm.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitAccelerometer.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitButton.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitCompass.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitCompassCalibrator.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitI2C.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitIO.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitLightSensor.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitMessageBus.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitMultiButton.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitPin.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitRadio.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitRadioDatagram.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitRadioEvent.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitSerial.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitStorage.cpp Show annotated file Show diff for this revision Revisions of this file
source/drivers/MicroBitThermometer.cpp Show annotated file Show diff for this revision Revisions of this file
source/types/ManagedString.cpp Show annotated file Show diff for this revision Revisions of this file
source/types/Matrix4.cpp Show annotated file Show diff for this revision Revisions of this file
source/types/MicroBitEvent.cpp Show annotated file Show diff for this revision Revisions of this file
source/types/MicroBitImage.cpp Show annotated file Show diff for this revision Revisions of this file
source/types/PacketBuffer.cpp Show annotated file Show diff for this revision Revisions of this file
source/types/RefCounted.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AUTHORS	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,9 @@
+Joe Finney (@finneyj)
+James Devine (@jamesadevine)
+Martin Woolley (@bluetooth-mdw)
+Michał Moskal (@mmoskal)
+Robert May (@remay)
+Jonathan Protzenko (@msprotz)
+James Sheppard (@jamessheppard)
+Damien George (@dpgeorge)
+Mathew Else (@matthewelse)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,22 @@
+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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.md	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,39 @@
+# microbit-dal
+
+The core set of drivers, mechanisms and types that make up the micro:bit runtime.
+
+## Overview
+
+The micro:bit runtime provides an easy to use environment for programming the BBC micro:bit in the C/C++ language, written by Lancaster University. It contains device drivers for all the hardware capabilities of the micro:bit, and also a suite of runtime mechanisms to make programming the micro:bit easier and more flexible. These range from control of the LED matrix display to peer-to-peer radio communication and secure Bluetooth Low Energy services. The micro:bit runtime is proudly built on the ARM mbed and Nordic nrf51 platforms.
+
+In addition to supporting development in C/C++, the runtime is also designed specifically to support higher level languages provided by our partners that target the micro:bit. It is currently used as a support library for all the languages on the BBC www.microbit.co.uk website, including Microsoft Block, Microsoft TouchDevelop, Code Kingdoms JavaScript and Micropython languages.
+
+## Links
+
+[micro:bit runtime docs](http://lancaster-university.github.io/microbit-docs/) | [uBit](https://github.com/lancaster-university/microbit) |  [samples](https://github.com/lancaster-university/microbit-samples)
+
+## Build Environments
+
+| Build Environment | Documentation |
+| ------------- |-------------|
+| ARM mbed online | http://lancaster-university.github.io/microbit-docs/online-toolchains/#mbed |
+| yotta  | http://lancaster-university.github.io/microbit-docs/offline-toolchains/#yotta |
+
+
+
+## Hello World!
+
+```cpp
+#include "MicroBitDisplay.h"
+
+MicroBitDisplay display;
+
+int main()
+{
+    display.scroll("Hello world!");
+}
+```
+
+## BBC Community Guidelines
+
+[BBC Community Guidelines](https://www.microbit.co.uk/help#sect_cg)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/ExternalEvents.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,38 @@
+/*
+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 EXTERNAL_EVENTS_H
+#define EXTERNAL_EVENTS_H
+
+/**
+  * This header file contains IDs and event codes use for Bluetooth communication.
+  */
+
+#define MICROBIT_ID_BLE             1000
+#define MICROBIT_ID_BLE_UART        1001
+
+#include "MESEvents.h"
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MESEvents.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,117 @@
+/*
+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 MES_EVENTS_H
+#define MES_EVENTS_H
+
+//
+// MicroBit Event Service Event ID's and values
+//
+
+//
+// Events that master devices respond to:
+//
+#define MES_REMOTE_CONTROL_ID               1001
+#define MES_REMOTE_CONTROL_EVT_PLAY         1
+#define MES_REMOTE_CONTROL_EVT_PAUSE        2
+#define MES_REMOTE_CONTROL_EVT_STOP         3
+#define MES_REMOTE_CONTROL_EVT_NEXTTRACK    4
+#define MES_REMOTE_CONTROL_EVT_PREVTRACK    5
+#define MES_REMOTE_CONTROL_EVT_FORWARD      6
+#define MES_REMOTE_CONTROL_EVT_REWIND       7
+#define MES_REMOTE_CONTROL_EVT_VOLUMEUP     8
+#define MES_REMOTE_CONTROL_EVT_VOLUMEDOWN   9
+
+
+#define MES_CAMERA_ID                       1002
+#define MES_CAMERA_EVT_LAUNCH_PHOTO_MODE    1
+#define MES_CAMERA_EVT_LAUNCH_VIDEO_MODE    2
+#define MES_CAMERA_EVT_TAKE_PHOTO           3
+#define MES_CAMERA_EVT_START_VIDEO_CAPTURE  4
+#define MES_CAMERA_EVT_STOP_VIDEO_CAPTURE   5
+#define MES_CAMERA_EVT_STOP_PHOTO_MODE      6
+#define MES_CAMERA_EVT_STOP_VIDEO_MODE      7
+#define MES_CAMERA_EVT_TOGGLE_FRONT_REAR    8
+
+
+#define MES_ALERTS_ID                       1004
+#define MES_ALERT_EVT_DISPLAY_TOAST         1
+#define MES_ALERT_EVT_VIBRATE               2
+#define MES_ALERT_EVT_PLAY_SOUND            3
+#define MES_ALERT_EVT_PLAY_RINGTONE         4
+#define MES_ALERT_EVT_FIND_MY_PHONE         5
+#define MES_ALERT_EVT_ALARM1                6
+#define MES_ALERT_EVT_ALARM2                7
+#define MES_ALERT_EVT_ALARM3                8
+#define MES_ALERT_EVT_ALARM4                9
+#define MES_ALERT_EVT_ALARM5                10
+#define MES_ALERT_EVT_ALARM6                11
+
+//
+// Events that master devices generate:
+//
+#define MES_SIGNAL_STRENGTH_ID              1101
+#define MES_SIGNAL_STRENGTH_EVT_NO_BAR      1
+#define MES_SIGNAL_STRENGTH_EVT_ONE_BAR     2
+#define MES_SIGNAL_STRENGTH_EVT_TWO_BAR     3
+#define MES_SIGNAL_STRENGTH_EVT_THREE_BAR   4
+#define MES_SIGNAL_STRENGTH_EVT_FOUR_BAR    5
+
+
+#define MES_DEVICE_INFO_ID                  1103
+#define MES_DEVICE_ORIENTATION_LANDSCAPE    1
+#define MES_DEVICE_ORIENTATION_PORTRAIT     2
+#define MES_DEVICE_GESTURE_NONE             3
+#define MES_DEVICE_GESTURE_DEVICE_SHAKEN    4
+#define MES_DEVICE_DISPLAY_OFF              5
+#define MES_DEVICE_DISPLAY_ON               6
+#define MES_DEVICE_INCOMING_CALL            7
+#define MES_DEVICE_INCOMING_MESSAGE         8
+
+
+#define MES_DPAD_CONTROLLER_ID              1104
+#define MES_DPAD_BUTTON_A_DOWN              1
+#define MES_DPAD_BUTTON_A_UP                2
+#define MES_DPAD_BUTTON_B_DOWN              3
+#define MES_DPAD_BUTTON_B_UP                4
+#define MES_DPAD_BUTTON_C_DOWN              5
+#define MES_DPAD_BUTTON_C_UP                6
+#define MES_DPAD_BUTTON_D_DOWN              7
+#define MES_DPAD_BUTTON_D_UP                8
+#define MES_DPAD_BUTTON_1_DOWN              9
+#define MES_DPAD_BUTTON_1_UP                10
+#define MES_DPAD_BUTTON_2_DOWN              11
+#define MES_DPAD_BUTTON_2_UP                12
+#define MES_DPAD_BUTTON_3_DOWN              13
+#define MES_DPAD_BUTTON_3_UP                14
+#define MES_DPAD_BUTTON_4_DOWN              15
+#define MES_DPAD_BUTTON_4_UP                16
+
+//
+// Events that typically use radio broadcast:
+//
+#define MES_BROADCAST_GENERAL_ID            2000
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitAccelerometerService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,83 @@
+/*
+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_ACCELEROMETER_SERVICE_H
+#define MICROBIT_ACCELEROMETER_SERVICE_H
+
+#include "MicroBitConfig.h"
+#include "ble/BLE.h"
+#include "MicroBitAccelerometer.h"
+#include "EventModel.h"
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitAccelerometerServiceUUID[];
+extern const uint8_t  MicroBitAccelerometerServiceDataUUID[];
+extern const uint8_t  MicroBitAccelerometerServicePeriodUUID[];
+
+
+/**
+  * Class definition for a MicroBit BLE Accelerometer Service.
+  * Provides access to live accelerometer data via Bluetooth, and provides basic configuration options.
+  */
+class MicroBitAccelerometerService
+{
+    public:
+
+    /**
+      * Constructor.
+      * Create a representation of the AccelerometerService
+      * @param _ble The instance of a BLE device that we're running on.
+      * @param _accelerometer An instance of MicroBitAccelerometer.
+      */
+    MicroBitAccelerometerService(BLEDevice &_ble, MicroBitAccelerometer &_acclerometer);
+
+
+    private:
+
+    /**
+      * Callback. Invoked when any of our attributes are written via BLE.
+      */
+    void onDataWritten(const GattWriteCallbackParams *params);
+
+    /**
+     * Accelerometer update callback
+     */
+    void accelerometerUpdate(MicroBitEvent e);
+
+    // Bluetooth stack we're running on.
+    BLEDevice           	&ble;
+	MicroBitAccelerometer	&accelerometer;
+
+    // memory for our 8 bit control characteristics.
+    uint16_t            accelerometerDataCharacteristicBuffer[3];
+    uint16_t            accelerometerPeriodCharacteristicBuffer;
+
+    // Handles to access each characteristic when they are held by Soft Device.
+    GattAttribute::Handle_t accelerometerDataCharacteristicHandle;
+    GattAttribute::Handle_t accelerometerPeriodCharacteristicHandle;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitBLEManager.h	Thu Apr 07 01:33:22 2016 +0100
@@ -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.
+*/
+
+#ifndef MICROBIT_BLE_MANAGER_H
+#define MICROBIT_BLE_MANAGER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.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)
+ * 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 push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+#include "ble/BLE.h"
+
+/*
+ * Return to our predefined compiler settings.
+ */
+#if !defined (__arm)
+#pragma GCC diagnostic pop
+#endif
+
+#include "ble/services/DeviceInformationService.h"
+#include "MicroBitDFUService.h"
+#include "MicroBitEventService.h"
+#include "MicroBitLEDService.h"
+#include "MicroBitAccelerometerService.h"
+#include "MicroBitMagnetometerService.h"
+#include "MicroBitButtonService.h"
+#include "MicroBitIOPinService.h"
+#include "MicroBitTemperatureService.h"
+#include "ExternalEvents.h"
+#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_PAIRING_TIMEOUT	        90
+#define MICROBIT_BLE_POWER_LEVELS               8
+#define MICROBIT_BLE_MAXIMUM_BONDS              4
+#define MICROBIT_BLE_ENABLE_BONDING 	        true
+
+extern const int8_t MICROBIT_BLE_POWER_LEVEL[];
+
+struct BLESysAttribute
+{
+    uint8_t         sys_attr[8] = { 0 };
+};
+
+struct BLESysAttributeStore
+{
+    BLESysAttribute sys_attrs[MICROBIT_BLE_MAXIMUM_BONDS];
+};
+
+/**
+  * Class definition for the MicroBitBLEManager.
+  *
+  */
+class MicroBitBLEManager : MicroBitComponent
+{
+    public:
+
+	// The mbed abstraction of the BlueTooth Low Energy (BLE) hardware
+    BLEDevice                       *ble;
+
+    //an instance of MicroBitStorage used to store sysAttrs from softdevice
+    MicroBitStorage* storage;
+
+    /**
+     * 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.
+     */
+    MicroBitBLEManager(MicroBitStorage& _storage);
+
+    /**
+     * Constructor.
+     *
+     * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
+     *
+     * @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();
+
+    /**
+      * Post constructor initialisation method as the BLE stack cannot be brought
+      * up in a static context.
+      *
+      * @param deviceName The name used when advertising
+      * @param serialNumber The serial number exposed by the device information service
+      * @param messageBus An instance of an EventModel, used during pairing.
+      * @param enableBonding If true, the security manager enabled bonding.
+      *
+      * @code
+      * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true);
+      * @endcode
+      */
+    void init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding);
+
+    /**
+     * Change the output power level of the transmitter to the given value.
+     *
+     * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest.
+     *
+     * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range.
+     *
+     * @code
+     * // maximum transmission power.
+     * bleManager.setTransmitPower(7);
+     * @endcode
+     */
+    int setTransmitPower(int power);
+
+    /**
+     * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
+     * of the micro:bit in cases where BLE is disabled during normal operation.
+     *
+     * @param display An instance of MicroBitDisplay used when displaying pairing information.
+     * @param authorizationButton The button to use to authorise a pairing request.
+     *
+     * @code
+     * // initiate pairing mode
+     * bleManager.pairingMode(uBit.display, uBit.buttonA);
+     * @endcode
+     */
+    void pairingMode(MicroBitDisplay &display, MicroBitButton &authorisationButton);
+
+    /**
+     * When called, the micro:bit will begin advertising for a predefined period,
+     * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices.
+     */
+    void advertise();
+
+    /**
+     * Determines the number of devices currently bonded with this micro:bit.
+     * @return The number of active bonds.
+     */
+    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);
+
+	/**
+	 * 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);
+
+	/**
+     * Periodic callback in thread context.
+     * We use this here purely to safely issue a disconnect operation after a pairing operation is complete.
+	 */
+	void idleTick();
+
+    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);
+
+	int				pairingStatus;
+	ManagedString	passKey;
+	ManagedString	deviceName;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitButtonService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,80 @@
+/*
+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_BUTTON_SERVICE_H
+#define MICROBIT_BUTTON_SERVICE_H
+
+#include "MicroBitConfig.h"
+#include "ble/BLE.h"
+#include "EventModel.h"
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitButtonServiceUUID[];
+extern const uint8_t  MicroBitButtonAServiceDataUUID[];
+extern const uint8_t  MicroBitButtonBServiceDataUUID[];
+
+
+/**
+  * Class definition for a MicroBit BLE Button Service.
+  * Provides access to live button data via BLE, and provides basic configuration options.
+  */
+class MicroBitButtonService
+{
+    public:
+
+    /**
+      * Constructor.
+      * Create a representation of the ButtonService
+      * @param _ble The instance of a BLE device that we're running on.
+      */
+    MicroBitButtonService(BLEDevice &_ble);
+
+
+    private:
+
+    /**
+     * Button A update callback
+     */
+    void buttonAUpdate(MicroBitEvent e);
+
+    /**
+     * Button B update callback
+     */
+    void buttonBUpdate(MicroBitEvent e);
+
+    // Bluetooth stack we're running on.
+    BLEDevice           &ble;
+
+    // memory for our 8 bit control characteristics.
+    uint8_t            buttonADataCharacteristicBuffer;
+    uint8_t            buttonBDataCharacteristicBuffer;
+
+    // Handles to access each characteristic when they are held by Soft Device.
+    GattAttribute::Handle_t buttonADataCharacteristicHandle;
+    GattAttribute::Handle_t buttonBDataCharacteristicHandle;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitDFUService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,103 @@
+/*
+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_DFU_SERVICE_H
+#define MICROBIT_DFU_SERVICE_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "ble/BLE.h"
+#include "MicroBitEvent.h"
+
+// MicroBit ControlPoint OpCodes
+// Requests transfer to the Nordic DFU bootloader.
+#define MICROBIT_DFU_OPCODE_START_DFU       1
+
+// visual ID code constants
+#define MICROBIT_DFU_HISTOGRAM_WIDTH        5
+#define MICROBIT_DFU_HISTOGRAM_HEIGHT       5
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitDFUServiceUUID[];
+extern const uint8_t  MicroBitDFUServiceControlCharacteristicUUID[];
+extern const uint8_t  MicroBitDFUServiceFlashCodeCharacteristicUUID[];
+
+// Handle on the memory resident Nordic bootloader.
+extern "C" void bootloader_start(void);
+
+/**
+  * Class definition for a MicroBit Device Firmware Update loader.
+  * This service allows hexes to be flashed remotely from another Bluetooth
+  * device.
+  */
+class MicroBitDFUService
+{
+    public:
+
+    /**
+      * Constructor.
+      * Initialise the Device Firmware Update service.
+      * @param _ble The instance of a BLE device that we're running on.
+      */
+    MicroBitDFUService(BLEDevice &_ble);
+
+    /**
+      * Callback. Invoked when any of our attributes are written via BLE.
+      */
+    virtual void onDataWritten(const GattWriteCallbackParams *params);
+
+    private:
+
+    // State of paiting process.
+    bool authenticated;
+    bool flashCodeRequested;
+
+    // Bluetooth stack we're running on.
+    BLEDevice           &ble;
+
+    // memory for our 8 bit control characteristic.
+    uint8_t             controlByte;
+
+    // BLE pairing name of this device, encoded as an integer.
+    uint32_t            flashCode;
+
+    GattAttribute::Handle_t microBitDFUServiceControlCharacteristicHandle;
+    GattAttribute::Handle_t microBitDFUServiceFlashCodeCharacteristicHandle;
+
+    // Displays the device's ID code as a histogram on the LED matrix display.
+    void showNameHistogram();
+
+    // Displays an acknowledgement on the LED matrix display.
+    void showTick();
+
+    // Update BLE characteristic to release our flash code.
+    void releaseFlashCode();
+
+    // Event handlers for button clicks.
+    void onButtonA(MicroBitEvent e);
+    void onButtonB(MicroBitEvent e);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitEventService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,111 @@
+/*
+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_EVENT_SERVICE_H
+#define MICROBIT_EVENT_SERVICE_H
+
+#include "MicroBitConfig.h"
+#include "ble/BLE.h"
+#include "MicroBitEvent.h"
+#include "EventModel.h"
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitEventServiceUUID[];
+extern const uint8_t  MicroBitEventServiceMicroBitEventCharacteristicUUID[];
+extern const uint8_t  MicroBitEventServiceClientEventCharacteristicUUID[];
+extern const uint8_t  MicroBitEventServiceMicroBitRequirementsCharacteristicUUID[];
+extern const uint8_t  MicroBitEventServiceClientRequirementsCharacteristicUUID[];
+
+struct EventServiceEvent
+{
+    uint16_t    type;
+    uint16_t    reason;
+};
+
+
+/**
+  * Class definition for a MicroBit BLE Event Service.
+  * Provides a BLE gateway onto an Event Model.
+  */
+class MicroBitEventService : public MicroBitComponent
+{
+    public:
+
+    /**
+      * Constructor.
+      * Create a representation of the EventService
+      * @param _ble The instance of a BLE device that we're running on.
+      * @param _messageBus An instance of an EventModel which events will be mirrored from.
+      */
+    MicroBitEventService(BLEDevice &_ble, EventModel &_messageBus);
+
+    /**
+     * Periodic callback from MicroBit scheduler.
+     * If we're no longer connected, remove any registered Message Bus listeners.
+     */
+    virtual void idleTick();
+
+    /**
+      * Callback. Invoked when any of our attributes are written via BLE.
+      */
+    void onDataWritten(const GattWriteCallbackParams *params);
+
+    /**
+      * Callback. Invoked when any events are sent on the microBit message bus.
+      */
+    void onMicroBitEvent(MicroBitEvent evt);
+
+    /**
+      * Read callback on microBitRequirements characteristic.
+      *
+      * Used to iterate through the events that the code on this micro:bit is interested in.
+      */
+    void onRequirementsRead(GattReadAuthCallbackParams *params);
+
+    private:
+
+    // Bluetooth stack we're running on.
+    BLEDevice           &ble;
+	EventModel	        &messageBus;
+
+    // memory for our event characteristics.
+    EventServiceEvent   clientEventBuffer;
+    EventServiceEvent   microBitEventBuffer;
+    EventServiceEvent   microBitRequirementsBuffer;
+    EventServiceEvent   clientRequirementsBuffer;
+
+    // handles on this service's characterisitics.
+    GattAttribute::Handle_t microBitEventCharacteristicHandle;
+    GattAttribute::Handle_t clientRequirementsCharacteristicHandle;
+    GattAttribute::Handle_t clientEventCharacteristicHandle;
+    GattCharacteristic *microBitRequirementsCharacteristic;
+
+    // Message bus offset last sent to the client...
+    uint16_t messageBusListenerOffset;
+
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitIOPinService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,143 @@
+/*
+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_IO_PIN_SERVICE_H
+#define MICROBIT_IO_PIN_SERVICE_H
+
+#include "MicroBitConfig.h"
+#include "ble/BLE.h"
+#include "MicroBitIO.h"
+
+#define MICROBIT_IO_PIN_SERVICE_PINCOUNT       20
+#define MICROBIT_IO_PIN_SERVICE_DATA_SIZE      10
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitIOPinServiceUUID[];
+extern const uint8_t  MicroBitIOPinServiceADConfigurationUUID[];
+extern const uint8_t  MicroBitIOPinServiceIOConfigurationUUID[];
+extern const uint8_t  MicroBitIOPinServiceDataUUID[];
+extern MicroBitPin * const MicroBitIOPins[];
+
+/**
+  * Name value pair definition, as used to read and write pin values over BLE.
+  */
+struct IOData
+{
+    uint8_t     pin;
+    uint8_t     value;
+};
+
+/**
+  * Class definition for the custom MicroBit IOPin Service.
+  * Provides a BLE service to remotely read the state of the I/O Pin, and configure its behaviour.
+  */
+class MicroBitIOPinService : public MicroBitComponent
+{
+    public:
+
+    /**
+      * Constructor.
+      * Create a representation of the IOPinService
+      * @param _ble The instance of a BLE device that we're running on.
+      * @param _io An instance of MicroBitIO that this service will use to perform
+      *            I/O operations.
+      */
+    MicroBitIOPinService(BLEDevice &_ble, MicroBitIO &_io);
+
+    /**
+     * Periodic callback from MicroBit scheduler.
+     *
+     * Check if any of the pins we're watching need updating. Notify any connected
+     * device with any changes.
+     */
+    virtual void idleTick();
+
+    private:
+
+    /**
+      * Callback. Invoked when any of our attributes are written via BLE.
+      */
+    void onDataWritten(const GattWriteCallbackParams *params);
+
+    /**
+     * Callback. invoked when the BLE data characteristic is read.
+     *
+     * Reads all the pins marked as inputs, and updates the data stored in the characteristic.
+     */
+    void onDataRead(GattReadAuthCallbackParams *params);
+
+    /**
+      * Determines if the given pin was configured as a digital pin by the BLE ADPinConfigurationCharacterisitic.
+      *
+      * @param i the enumeration of the pin to test
+      * @return 1 if this pin is configured as digital, 0 otherwise
+      */
+    int isDigital(int i);
+
+    /**
+      * Determines if the given pin was configured as an analog pin by the BLE ADPinConfigurationCharacterisitic.
+      *
+      * @param i the enumeration of the pin to test
+      * @return 1 if this pin is configured as analog, 0 otherwise
+      */
+    int isAnalog(int i);
+
+    /**
+      * Determines if the given pin was configured as an input by the BLE IOPinConfigurationCharacterisitic.
+      *
+      * @param i the enumeration of the pin to test
+      * @return 1 if this pin is configured as an input, 0 otherwise
+      */
+    int isInput(int i);
+
+    /**
+      * Determines if the given pin was configured as output by the BLE IOPinConfigurationCharacterisitic.
+      *
+      * @param i the enumeration of the pin to test
+      * @return 1 if this pin is configured as an output, 0 otherwise
+      */
+    int isOutput(int i);
+
+
+    // Bluetooth stack we're running on.
+    BLEDevice           &ble;
+    MicroBitIO          &io;
+
+    // memory for our 8 bit control characteristics.
+    uint32_t            ioPinServiceADCharacteristicBuffer;
+    uint32_t            ioPinServiceIOCharacteristicBuffer;
+    IOData              ioPinServiceDataCharacteristicBuffer[MICROBIT_IO_PIN_SERVICE_DATA_SIZE];
+
+    // Historic information about our pin data data.
+    uint8_t             ioPinServiceIOData[MICROBIT_IO_PIN_SERVICE_PINCOUNT];
+
+    // Handles to access each characteristic when they are held by Soft Device.
+    GattAttribute::Handle_t ioPinServiceADCharacteristicHandle;
+    GattAttribute::Handle_t ioPinServiceIOCharacteristicHandle;
+    GattCharacteristic *ioPinServiceDataCharacteristic;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitLEDService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,91 @@
+/*
+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_LED_SERVICE_H
+#define MICROBIT_LED_SERVICE_H
+
+#include "MicroBitConfig.h"
+#include "ble/BLE.h"
+#include "MicroBitDisplay.h"
+
+// Defines the buffer size for scrolling text over BLE, hence also defines
+// the maximum string length that can be scrolled via the BLE service.
+#define MICROBIT_BLE_MAXIMUM_SCROLLTEXT         20
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitLEDServiceUUID[];
+extern const uint8_t  MicroBitLEDServiceMatrixUUID[];
+extern const uint8_t  MicroBitLEDServiceTextUUID[];
+extern const uint8_t  MicroBitLEDServiceScrollingSpeedUUID[];
+
+
+/**
+  * Class definition for the custom MicroBit LED Service.
+  * Provides a BLE service to remotely read and write the state of the LED display.
+  */
+class MicroBitLEDService
+{
+    public:
+
+    /**
+      * Constructor.
+      * Create a representation of the LEDService
+      * @param _ble The instance of a BLE device that we're running on.
+      * @param _display An instance of MicroBitDisplay to interface with.
+      */
+    MicroBitLEDService(BLEDevice &_ble, MicroBitDisplay &_display);
+
+    /**
+      * Callback. Invoked when any of our attributes are written via BLE.
+      */
+    void onDataWritten(const GattWriteCallbackParams *params);
+
+    /**
+      * Callback. Invoked when any of our attributes are read via BLE.
+      */
+    void onDataRead(GattReadAuthCallbackParams *params);
+
+    private:
+
+    // Bluetooth stack we're running on.
+    BLEDevice           &ble;
+    MicroBitDisplay     &display;
+
+    // memory for our 8 bit control characteristics.
+    uint8_t             matrixCharacteristicBuffer[5];
+    uint16_t            scrollingSpeedCharacteristicBuffer;
+    uint8_t             textCharacteristicBuffer[MICROBIT_BLE_MAXIMUM_SCROLLTEXT];
+
+    // Handles to access each characteristic when they are held by Soft Device.
+    GattAttribute::Handle_t matrixCharacteristicHandle;
+    GattAttribute::Handle_t textCharacteristicHandle;
+    GattAttribute::Handle_t scrollingSpeedCharacteristicHandle;
+
+    // We hold a copy of the GattCharacteristic, as mbed's BLE API requires this to provide read callbacks (pity!).
+    GattCharacteristic  matrixCharacteristic;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitMagnetometerService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,91 @@
+/*
+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_MAGNETOMETER_SERVICE_H
+#define MICROBIT_MAGNETOMETER_SERVICE_H
+
+#include "ble/BLE.h"
+#include "MicroBitConfig.h"
+#include "MicroBitCompass.h"
+#include "EventModel.h"
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitMagnetometerServiceUUID[];
+extern const uint8_t  MicroBitMagnetometerServiceDataUUID[];
+extern const uint8_t  MicroBitMagnetometerServiceBearingUUID[];
+extern const uint8_t  MicroBitMagnetometerServicePeriodUUID[];
+
+
+/**
+  * Class definition for the MicroBit BLE Magnetometer Service.
+  * Provides access to live magnetometer data via BLE, and provides basic configuration options.
+  */
+class MicroBitMagnetometerService
+{
+    public:
+
+    /**
+      * Constructor.
+      * Create a representation of the MagnetometerService.
+      * @param _ble The instance of a BLE device that we're running on.
+      * @param _compass An instance of MicroBitCompass to use as our Magnetometer source.
+      */
+    MicroBitMagnetometerService(BLEDevice &_ble, MicroBitCompass &_compass);
+
+    private:
+
+    /**
+      * Callback. Invoked when any of our attributes are written via BLE.
+      */
+    void onDataWritten(const GattWriteCallbackParams *params);
+
+    /**
+     * Magnetometer update callback
+     */
+    void magnetometerUpdate(MicroBitEvent e);
+
+    /**
+     * Sample Period Change Needed callback.
+     * Reconfiguring the magnetometer can to a REALLY long time (sometimes even seconds to complete)
+     * So we do this in the background when necessary, through this event handler.
+     */
+    void samplePeriodUpdateNeeded(MicroBitEvent e);
+
+    // Bluetooth stack we're running on.
+    BLEDevice           &ble;
+    MicroBitCompass     &compass;
+
+    // memory for our 8 bit control characteristics.
+    int16_t             magnetometerDataCharacteristicBuffer[3];
+    uint16_t            magnetometerBearingCharacteristicBuffer;
+    uint16_t            magnetometerPeriodCharacteristicBuffer;
+
+    // Handles to access each characteristic when they are held by Soft Device.
+    GattAttribute::Handle_t magnetometerDataCharacteristicHandle;
+    GattAttribute::Handle_t magnetometerBearingCharacteristicHandle;
+    GattAttribute::Handle_t magnetometerPeriodCharacteristicHandle;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitTemperatureService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,82 @@
+/*
+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_TEMPERATURE_SERVICE_H
+#define MICROBIT_TEMPERATURE_SERVICE_H
+
+#include "MicroBitConfig.h"
+#include "ble/BLE.h"
+#include "MicroBitThermometer.h"
+#include "EventModel.h"
+
+// UUIDs for our service and characteristics
+extern const uint8_t  MicroBitTemperatureServiceUUID[];
+extern const uint8_t  MicroBitTemperatureServiceDataUUID[];
+extern const uint8_t  MicroBitTemperatureServicePeriodUUID[];
+
+
+/**
+  * Class definition for the custom MicroBit Temperature Service.
+  * Provides a BLE service to remotely read the silicon temperature of the nRF51822.
+  */
+class MicroBitTemperatureService
+{
+    public:
+
+    /**
+      * Constructor.
+      * Create a representation of the TemperatureService
+      * @param _ble The instance of a BLE device that we're running on.
+      * @param _thermometer An instance of MicroBitThermometer to use as our temperature source.
+      */
+    MicroBitTemperatureService(BLEDevice &_ble, MicroBitThermometer &_thermometer);
+
+    /**
+      * Callback. Invoked when any of our attributes are written via BLE.
+      */
+    void onDataWritten(const GattWriteCallbackParams *params);
+
+    /**
+     * Temperature update callback
+     */
+    void temperatureUpdate(MicroBitEvent e);
+
+    private:
+
+    // Bluetooth stack we're running on.
+    BLEDevice           	&ble;
+    MicroBitThermometer     &thermometer;
+
+    // memory for our 8 bit temperature characteristic.
+    int8_t             temperatureDataCharacteristicBuffer;
+    uint16_t           temperaturePeriodCharacteristicBuffer;
+
+    // Handles to access each characteristic when they are held by Soft Device.
+    GattAttribute::Handle_t temperatureDataCharacteristicHandle;
+    GattAttribute::Handle_t temperaturePeriodCharacteristicHandle;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/bluetooth/MicroBitUARTService.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,277 @@
+/*
+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_UART_SERVICE_H
+#define MICROBIT_UART_SERVICE_H
+
+#include "mbed.h"
+#include "ble/UUID.h"
+#include "ble/BLE.h"
+#include "MicroBitConfig.h"
+#include "MicroBitSerial.h"
+
+#define MICROBIT_UART_S_DEFAULT_BUF_SIZE    20
+
+#define MICROBIT_UART_S_EVT_DELIM_MATCH     1
+#define MICROBIT_UART_S_EVT_HEAD_MATCH      2
+#define MICROBIT_UART_S_EVT_RX_FULL         3
+
+/**
+  * Class definition for the custom MicroBit UART Service.
+  * Provides a BLE service that acts as a UART port, enabling the reception and transmission
+  * of an arbitrary number of bytes.
+  */
+class MicroBitUARTService
+{
+    uint8_t* rxBuffer;
+
+    uint8_t* txBuffer;
+
+    uint8_t rxBufferHead;
+    uint8_t rxBufferTail;
+    uint8_t rxBufferSize;
+
+    uint8_t txBufferSize;
+
+    uint32_t txCharacteristicHandle;
+
+    // Bluetooth stack we're running on.
+    BLEDevice           &ble;
+
+    //delimeters used for matching on receive.
+    ManagedString delimeters;
+
+    //a variable used when a user calls the eventAfter() method.
+    int rxBuffHeadMatch;
+
+    /**
+      * A callback function for whenever a Bluetooth device writes to our TX characteristic.
+      */
+    void onDataWritten(const GattWriteCallbackParams *params);
+
+    /**
+      * An internal method that copies values from a circular buffer to a linear buffer.
+      *
+      * @param circularBuff a pointer to the source circular buffer
+      * @param circularBuffSize the size of the circular buffer
+      * @param linearBuff a pointer to the destination linear buffer
+      * @param tailPosition the tail position in the circular buffer you want to copy from
+      * @param headPosition the head position in the circular buffer you want to copy to
+      *
+      * @note this method assumes that the linear buffer has the appropriate amount of
+      *       memory to contain the copy operation
+      */
+    void circularCopy(uint8_t *circularBuff, uint8_t circularBuffSize, uint8_t *linearBuff, uint16_t tailPosition, uint16_t headPosition);
+
+    public:
+
+    /**
+     * Constructor for the UARTService.
+     * @param _ble an instance of BLEDevice
+     * @param rxBufferSize the size of the rxBuffer
+     * @param txBufferSize the size of the txBuffer
+     *
+     * @note The default size is MICROBIT_UART_S_DEFAULT_BUF_SIZE (20 bytes).
+     */
+    MicroBitUARTService(BLEDevice &_ble, uint8_t rxBufferSize = MICROBIT_UART_S_DEFAULT_BUF_SIZE, uint8_t txBufferSize = MICROBIT_UART_S_DEFAULT_BUF_SIZE);
+
+    /**
+      * Retreives a single character from our RxBuffer.
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will attempt to read a single character, and return immediately
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+      *                         event is received.
+      *
+      * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, a character or MICROBIT_NO_DATA
+      */
+    int getc(MicroBitSerialMode mode = SYNC_SLEEP);
+
+    /**
+      * places a single character into our transmission buffer,
+      *
+      * @param c the character to transmit
+      *
+      * @return the number of characters written (0, or 1).
+      */
+    int putc(char c);
+
+    /**
+      * Copies characters into the buffer used for Transmitting to the central device.
+      *
+      * @param buf a buffer containing length number of bytes.
+      * @param length the size of the buffer.
+      *
+      * @return the number of characters copied into the buffer
+      *
+      * @note no modes for sending are available at the moment, due to interrupt overhead.
+      */
+    int send(const uint8_t *buf, int length);
+
+    /**
+      * Copies characters into the buffer used for Transmitting to the central device.
+      *
+      * @param s the string to transmit
+      *
+      * @return the number of characters copied into the buffer
+      *
+      * @note no modes for sending are available at the moment, due to interrupt overhead.
+      */
+    int send(ManagedString s);
+
+    /**
+      * Reads a number of characters from the rxBuffer and fills user given buffer.
+      *
+      * @param buf a pointer to a buffer of len bytes.
+      * @param len the size of the user allocated buffer
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will attempt to read all available characters, and return immediately
+      *                    until the buffer limit is reached
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will first of all determine whether the given number of characters
+      *                         are available in our buffer, if not, it will set an event and sleep
+      *                         until the number of characters are avaialable.
+      *
+      * @return the number of characters digested
+      */
+    int read(uint8_t *buf, int len, MicroBitSerialMode mode = SYNC_SLEEP);
+
+    /**
+      * Reads a number of characters from the rxBuffer and returns them as a ManagedString
+      *
+      * @param len the number of characters to read.
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will attempt to read all available characters, and return immediately
+      *                    until the buffer limit is reached
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will first of all determine whether the given number of characters
+      *                         are available in our buffer, if not, it will set an event and sleep
+      *                         until the number of characters are avaialable.
+      *
+      * @return an empty ManagedString on error, or a ManagedString containing characters
+      */
+    ManagedString read(int len, MicroBitSerialMode mode = SYNC_SLEEP);
+
+    /**
+      * Reads characters until a character matches one of the given delimeters
+      *
+      * @param delimeters the number of characters to match against
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will attempt read the immediate buffer, and look for a match.
+      *                    If there isn't, an empty ManagedString will be returned.
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will first of all consider the characters in the immediate buffer,
+      *                         if a match is not found, it will block on an event, fired when a
+      *                         character is matched.
+      *
+      * @return an empty ManagedString on error, or a ManagedString containing characters
+      */
+    ManagedString readUntil(ManagedString delimeters, MicroBitSerialMode mode = SYNC_SLEEP);
+
+    /**
+      * Configures an event to be fired on a match with one of the delimeters.
+      *
+      * @param delimeters the characters to match received characters against e.g. ManagedString("\r\n")
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will configure the event and return immediately.
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+      *                         event is received.
+      *
+      * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+      *
+      * @note delimeters are matched on a per byte basis.
+      */
+    int eventOn(ManagedString delimeters, MicroBitSerialMode mode = ASYNC);
+
+    /**
+      * Configures an event to be fired after "len" characters.
+      *
+      * @param len the number of characters to wait before triggering the event
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will configure the event and return immediately.
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+      *                         event is received.
+      *
+      * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+      */
+    int eventAfter(int len, MicroBitSerialMode mode = ASYNC);
+
+    /**
+      * Determines if we have space in our rxBuff.
+      *
+      * @return 1 if we have space, 0 if we do not.
+      */
+    int isReadable();
+
+    /**
+      * @return The currently buffered number of bytes in our rxBuff.
+      */
+    int rxBufferedSize();
+
+    /**
+      * @return The currently buffered number of bytes in our txBuff.
+      */
+    int txBufferedSize();
+};
+
+extern const uint8_t  UARTServiceBaseUUID[UUID::LENGTH_OF_LONG_UUID];
+extern const uint16_t UARTServiceShortUUID;
+extern const uint16_t UARTServiceTXCharacteristicShortUUID;
+extern const uint16_t UARTServiceRXCharacteristicShortUUID;
+
+extern const uint8_t  UARTServiceUUID[UUID::LENGTH_OF_LONG_UUID];
+extern const uint8_t  UARTServiceUUID_reversed[UUID::LENGTH_OF_LONG_UUID];
+
+extern const uint8_t  UARTServiceTXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID];
+extern const uint8_t  UARTServiceRXCharacteristicUUID[UUID::LENGTH_OF_LONG_UUID];
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/ErrorNo.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,86 @@
+/*
+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 ERROR_NO_H
+#define ERROR_NO_H
+
+#include "MicroBitConfig.h"
+
+/**
+  * Error codes used in the micro:bit runtime.
+  * These may be returned from functions implemented in the micro:bit runtime.
+  */
+enum ErrorCode{
+
+    // No error occurred.
+    MICROBIT_OK = 0,
+
+    // Invalid parameter given.
+    MICROBIT_INVALID_PARAMETER = -1001,
+
+    // Requested operation is unsupported.
+    MICROBIT_NOT_SUPPORTED = -1002,
+
+    // Device calibration errors
+    MICROBIT_CALIBRATION_IN_PROGRESS = -1003,
+    MICROBIT_CALIBRATION_REQUIRED = -1004,
+
+    // The requested operation could not be performed as the device has run out of some essential resource (e.g. allocated memory)
+    MICROBIT_NO_RESOURCES = -1005,
+
+    // The requested operation could not be performed as some essential resource is busy (e.g. the display)
+    MICROBIT_BUSY = -1006,
+
+    // The requested operation was cancelled before it completed.
+    MICROBIT_CANCELLED = -1007,
+
+    // I2C Communication error occured (typically I2C module on processor has locked up.)
+    MICROBIT_I2C_ERROR = -1010,
+
+    // The serial bus is currently in use by another fiber.
+    MICROBIT_SERIAL_IN_USE = -1011,
+
+    // The requested operation had no data to return.
+    MICROBIT_NO_DATA = -1012
+};
+
+/**
+  * Error codes used in the micro:bit runtime.
+  */
+enum PanicCode{
+    // PANIC Codes. These are not return codes, but are terminal conditions.
+    // These induce a panic operation, where all code stops executing, and a panic state is
+    // entered where the panic code is diplayed.
+
+    // Out out memory error. Heap storage was requested, but is not available.
+    MICROBIT_OOM = 20,
+
+    // Corruption detected in the micro:bit heap space
+    MICROBIT_HEAP_ERROR = 30,
+
+    // Dereference of a NULL pointer through the ManagedType class,
+    MICROBIT_NULL_DEREFERENCE = 40,
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/EventModel.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,430 @@
+/*
+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 EVENT_MODEL_H
+#define EVENT_MODEL_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitEvent.h"
+#include "MicroBitListener.h"
+#include "ErrorNo.h"
+
+/**
+  * Class definition for the micro:bit EventModel.
+  *
+  * It is common to need to send events from one part of a program (or system) to another.
+  * The way that these events are stored and delivered is known as an Event Model...
+  *
+  * The micro:bit can be programmed in a number of languages, and it not be good to
+  * constrain those languages to any particular event model (e.g. they may have their own already).
+  *
+  * This class defines the functionality an event model needs to have to be able to interact
+  * with events generated and/or used by the micro:bit runtime. Programmer may choose to implement
+  * such funcitonality to integrate their own event models.
+  *
+  * This is an example of a key principle in computing - ABSTRACTION. This is now part of the
+  * UK's Computing curriculum in schools... so ask your teacher about it. :-)
+  *
+  * An EventModel implementation is provided in the MicroBitMessageBus class.
+  */
+class EventModel
+{
+    public:
+
+    static EventModel *defaultEventBus;
+
+	/**
+	  * Queues the given event to be sent to all registered recipients.
+      * The method of delivery will vary depending on the underlying implementation.
+	  *
+	  * @param The event to send.
+      *
+      * @return This default implementation simply returns MICROBIT_NOT_SUPPORTED.
+	  */
+	virtual int send(MicroBitEvent evt)
+    {
+        (void) evt;
+        return MICROBIT_NOT_SUPPORTED;
+    }
+
+    /**
+     * Add the given MicroBitListener to the list of event handlers, unconditionally.
+     *
+     * @param listener The MicroBitListener to validate.
+     *
+     * @return This default implementation simply returns MICROBIT_NOT_SUPPORTED.
+     */
+    virtual int add(MicroBitListener *listener)
+    {
+        (void) listener;
+        return MICROBIT_NOT_SUPPORTED;
+    }
+
+    /**
+     * Remove the given MicroBitListener from the list of event handlers.
+     *
+     * @param listener The MicroBitListener to remove.
+     *
+     * @return This default implementation simply returns MICROBIT_NOT_SUPPORTED.
+     */
+    virtual int remove(MicroBitListener *listener)
+    {
+        (void) listener;
+        return MICROBIT_NOT_SUPPORTED;
+    }
+
+    /**
+      * Returns the MicroBitListener at the given position in the list.
+      *
+      * @param n The index of the desired MicroBitListener.
+      *
+      * @return This default implementation simply returns NULL.
+      */
+    MicroBitListener *elementAt(int n)
+    {
+        (void) n;
+        return NULL;
+    }
+
+	/**
+	  * Define the default EventModel to use for events raised and consumed by the microbit-dal runtime.
+      * The default EventModel may be changed at any time.
+      *
+	  * @param model A new instance of an EventModel to use as the default.
+      *
+      * @return MICROBIT_OK on success.
+	  *
+      * Example:
+      * @code
+      * MicroBitMessageBus b();
+      * EventModel:setDefaultEventModel(b);
+      * @endcode
+	  */
+	static int setDefaultEventModel(EventModel &model)
+    {
+        EventModel::defaultEventBus = &model;
+        return MICROBIT_OK;
+    }
+
+	/**
+	  * Register a listener function.
+      *
+      * An EventModel implementing this interface may optionally choose to override this method,
+      * if that EventModel supports asynchronous callbacks to user code, but there is no
+      * requirement to do so.
+      *
+	  * @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
+	  * Use MICROBIT_ID_ANY to receive events from all components.
+	  *
+	  * @param value The value of messages to listen for. Events with any other values will be filtered.
+	  * Use MICROBIT_EVT_ANY to receive events of any value.
+	  *
+	  * @param handler The function to call when an event is received.
+      *
+      * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+      * to be tuned.
+      *
+      * @return MICROBIT_OK on success, or any valid error code defined in "ErrNo.h". The default implementation
+      * simply returns MICROBIT_NOT_SUPPORTED.
+	  *
+      * @code
+      * void onButtonBClicked(MicroBitEvent)
+      * {
+      * 	//do something
+      * }
+      *
+      * // call onButtonBClicked when ever a click event from buttonB is detected.
+      * uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
+      * @endcode
+	  */
+	int listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS)
+    {
+        if (handler == NULL)
+            return MICROBIT_INVALID_PARAMETER;
+
+        MicroBitListener *newListener = new MicroBitListener(id, value, handler, flags);
+
+        if(add(newListener) == MICROBIT_OK)
+            return MICROBIT_OK;
+
+        delete newListener;
+
+        return MICROBIT_NOT_SUPPORTED;
+    }
+
+    /**
+	  * Register a listener function.
+      *
+      * An EventModel implementing this interface may optionally choose to override this method,
+      * if that EventModel supports asynchronous callbacks to user code, but there is no
+      * requirement to do so.
+      *
+	  * @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
+	  * Use MICROBIT_ID_ANY to receive events from all components.
+	  *
+	  * @param value The value of messages to listen for. Events with any other values will be filtered.
+	  * Use MICROBIT_EVT_ANY to receive events of any value.
+	  *
+	  * @param handler The function to call when an event is received.
+      *
+      * @param arg Provide the callback with in an additional argument.
+      *
+      * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+      * to be tuned.
+      *
+      * @return MICROBIT_OK on success, or any valid error code defined in "ErrNo.h". The default implementation
+      * simply returns MICROBIT_NOT_SUPPORTED.
+	  *
+      * @code
+      * void onButtonBClicked(MicroBitEvent, void* data)
+      * {
+      * 	//do something
+      * }
+      *
+      * // call onButtonBClicked when ever a click event from buttonB is detected.
+      * uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
+      * @endcode
+	  */
+    int listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS)
+    {
+        if (handler == NULL)
+            return MICROBIT_INVALID_PARAMETER;
+
+        MicroBitListener *newListener = new MicroBitListener(id, value, handler, arg, flags);
+
+        if(add(newListener) == MICROBIT_OK)
+            return MICROBIT_OK;
+
+        delete newListener;
+
+        return MICROBIT_NOT_SUPPORTED;
+    }
+
+	/**
+	  * Register a listener function.
+	  *
+	  * @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
+	  * Use MICROBIT_ID_ANY to receive events from all components.
+	  *
+	  * @param value The value of messages to listen for. Events with any other values will be filtered.
+	  * Use MICROBIT_EVT_ANY to receive events of any value.
+	  *
+	  * @param hander The function to call when an event is received.
+      *
+      * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+      * to be tuned.
+      *
+      * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER if the handler or object
+      *         pointers are NULL.
+      *
+      * @code
+      * void SomeClass::onButtonBClicked(MicroBitEvent)
+      * {
+      * 	//do something
+      * }
+      *
+      * SomeClass s = new SomeClass();
+      *
+      * uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick);
+      * @endcode
+	  */
+    template <typename T>
+	int listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS);
+
+
+	/**
+	  * Unregister a listener function.
+      * Listeners are identified by the Event ID, Event value and handler registered using listen().
+	  *
+	  * @param id The Event ID used to register the listener.
+	  * @param value The Event value used to register the listener.
+	  * @param handler The function used to register the listener.
+      *
+      * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER if the handler
+      *         given is NULL.
+	  *
+      * Example:
+      * @code
+      * void onButtonBClick(MicroBitEvent)
+      * {
+      * 	//do something
+      * }
+      *
+      * uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
+      *
+      * // the previously created listener is now ignored.
+      * uBit.messageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
+      * @endcode
+	  */
+	int ignore(int id, int value, void (*handler)(MicroBitEvent))
+    {
+        if (handler == NULL)
+            return MICROBIT_INVALID_PARAMETER;
+
+        MicroBitListener listener(id, value, handler);
+        remove(&listener);
+
+        return MICROBIT_OK;
+    }
+
+    /**
+	  * Unregister a listener function.
+      * Listeners are identified by the Event ID, Event value and handler registered using listen().
+	  *
+	  * @param id The Event ID used to register the listener.
+	  * @param value The Event value used to register the listener.
+	  * @param handler The function used to register the listener.
+      *
+      * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER if the handler
+      *         given is NULL.
+	  *
+      * Example:
+      * @code
+      * void onButtonBClick(MicroBitEvent, void* data)
+      * {
+      * 	//do something
+      * }
+      *
+      * uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
+      *
+      * // the previously created listener is now ignored.
+      * uBit.messageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
+      * @endcode
+	  */
+	int ignore(int id, int value, void (*handler)(MicroBitEvent, void*))
+    {
+        if (handler == NULL)
+            return MICROBIT_INVALID_PARAMETER;
+
+        MicroBitListener listener(id, value, handler, NULL);
+        remove(&listener);
+
+        return MICROBIT_OK;
+    }
+
+	/**
+	  * Unregister a listener function.
+      * Listners are identified by the Event ID, Event value and handler registered using listen().
+	  *
+	  * @param id The Event ID used to register the listener.
+	  * @param value The Event value used to register the listener.
+	  * @param handler The function used to register the listener.
+      *
+      * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER if the handler or object
+      *         pointers are NULL.
+	  *
+      * Example:
+      * @code
+      *
+      * void SomeClass::onButtonBClick()
+      * {
+      * 	//do something
+      * }
+      *
+      * SomeClass s = new SomeClass();
+      * uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick);
+      *
+      * // the previously created listener is now ignored.
+      * uBit.messageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick);
+      * @endcode
+	  */
+    template <typename T>
+	int ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
+
+};
+
+/**
+  * A registration function to allow C++ member functions (methods) to be registered as an event
+  * listener.
+  *
+  * @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
+  * Use MICROBIT_ID_ANY to receive events from all components.
+  *
+  * @param value The value of messages to listen for. Events with any other values will be filtered.
+  * Use MICROBIT_EVT_ANY to receive events of any value.
+  *
+  * @param object The object on which the method should be invoked.
+  *
+  * @param handler The method to call when an event is received.
+  *
+  * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER if the handler or object
+  *         pointers are NULL.
+  */
+template <typename T>
+int EventModel::listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags)
+{
+	if (object == NULL || handler == NULL)
+		return MICROBIT_INVALID_PARAMETER;
+
+	MicroBitListener *newListener = new MicroBitListener(id, value, object, handler, flags);
+
+    if(add(newListener) == MICROBIT_OK)
+        return MICROBIT_OK;
+
+    delete newListener;
+    return MICROBIT_NOT_SUPPORTED;
+}
+
+/**
+  * Unregister a listener function.
+  * Listners are identified by the Event ID, Event value and handler registered using listen().
+  *
+  * @param id The Event ID used to register the listener.
+  * @param value The Event value used to register the listener.
+  * @param handler The function used to register the listener.
+  *
+  * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER if the handler or object
+  *         pointers are NULL.
+  *
+  * Example:
+  * @code
+  *
+  * void SomeClass::onButtonBClick()
+  * {
+  * 	//do something
+  * }
+  *
+  * SomeClass s = new SomeClass();
+  * uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick);
+  *
+  * // the previously created listener is now ignored.
+  * uBit.messageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick);
+  * @endcode
+  */
+template <typename T>
+int EventModel::ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent))
+{
+	if (handler == NULL)
+		return MICROBIT_INVALID_PARAMETER;
+
+	MicroBitListener listener(id, value, object, handler);
+    remove(&listener);
+
+    return MICROBIT_OK;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MemberFunctionCallback.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,114 @@
+/*
+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 MEMBER_FUNCTION_CALLBACK_H
+#define MEMBER_FUNCTION_CALLBACK_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitEvent.h"
+#include "MicroBitCompat.h"
+
+/**
+  * Class definition for a MemberFunctionCallback.
+  *
+  * C++ member functions (also known as methods) have a more complex
+  * representation than normal C functions. This class allows a reference to
+  * a C++ member function to be stored then called at a later date.
+  *
+  * This class is used extensively by the MicroBitMessageBus to deliver
+  * events to C++ methods.
+  */
+class MemberFunctionCallback
+{
+    private:
+    void* object;
+    uint32_t method[4];
+    void (*invoke)(void *object, uint32_t *method, MicroBitEvent e);
+    template <typename T> static void methodCall(void* object, uint32_t*method, MicroBitEvent e);
+
+    public:
+
+    /**
+      * Constructor. Creates a MemberFunctionCallback based on a pointer to given method.
+      *
+      * @param object The object the callback method should be invooked on.
+      *
+      * @param method The method to invoke.
+      */
+    template <typename T> MemberFunctionCallback(T* object, void (T::*method)(MicroBitEvent e));
+
+    /**
+      * A comparison of two MemberFunctionCallback objects.
+      *
+      * @return true if the given MemberFunctionCallback is equivalent to this one, false otherwise.
+      */
+    bool operator==(const MemberFunctionCallback &mfc);
+
+    /**
+      * Calls the method reference held by this MemberFunctionCallback.
+      *
+      * @param e The event to deliver to the method
+      */
+    void fire(MicroBitEvent e);
+};
+
+/**
+  * Constructor. Creates a MemberFunctionCallback based on a pointer to given method.
+  *
+  * @param object The object the callback method should be invooked on.
+  *
+  * @param method The method to invoke.
+  */
+template <typename T>
+MemberFunctionCallback::MemberFunctionCallback(T* object, void (T::*method)(MicroBitEvent e))
+{
+    this->object = object;
+    memclr(this->method, sizeof(this->method));
+    memcpy(this->method, &method, sizeof(method));
+    invoke = &MemberFunctionCallback::methodCall<T>;
+}
+
+/**
+  * A template used to create a static method capable of invoking a C++ member function (method)
+  * based on the given parameters.
+  *
+  * @param object The object the callback method should be invooked on.
+  *
+  * @param method The method to invoke.
+  *
+  * @param method The MicroBitEvent to supply to the given member function.
+  */
+template <typename T>
+void MemberFunctionCallback::methodCall(void *object, uint32_t *method, MicroBitEvent e)
+{
+    T* o = (T*)object;
+    void (T::*m)(MicroBitEvent);
+    memcpy(&m, method, sizeof(m));
+
+    (o->*m)(e);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitCompat.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,111 @@
+/*
+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.
+*/
+
+/**
+  * This file contains functions used to maintain compatability and portability.
+  * It also contains constants that are used elsewhere in the DAL.
+  */
+
+#ifndef MICROBIT_COMPAT_H
+#define MICROBIT_COMPAT_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+
+#define PI 3.14159265359
+
+/**
+  * Determines the smallest of the two numbers
+  *
+  * @param a the first number
+  *
+  * @param b the second number
+  *
+  * @return The smallest of the two given values.
+  */
+inline int min(int a, int b)
+{
+    return (a < b ? a : b);
+}
+
+/**
+  * Determines the largest of the two numbers
+  *
+  * @param a the first number
+  *
+  * @param b the second number
+  *
+  * @return The larger of the two given values.
+  */
+inline int max(int a, int b)
+{
+    return (a > b ? a : b);
+}
+
+/**
+  * Sets a given area of memory to zero.
+  *
+  * @param a the pointer to the beginning of the memory to clear
+  *
+  * @param b the number of bytes to clear.
+  */
+inline void *memclr(void *a, size_t b)
+{
+    return memset(a,0,b);
+}
+
+/**
+  * Determines if the given character is a printable ASCII/UTF8 decimal digit (0..9).
+  *
+  * @param c the character to check
+  *
+  * @return true if the character is a digit, false otherwise.
+  */
+inline bool isdigit(char c)
+{
+    return (c > 47 && c < 58);
+}
+
+/**
+  * Performs an in buffer reverse of a given char array.
+  *
+  * @param s the string to reverse.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int string_reverse(char *s);
+
+/**
+  * Converts a given integer into a string representation.
+  *
+  * @param n The number to convert.
+  *
+  * @param s A pointer to the buffer where the resulting string will be stored.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int itoa(int n, char *s);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitComponent.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,152 @@
+/*
+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_COMPONENT_H
+#define MICROBIT_COMPONENT_H
+
+#include "MicroBitConfig.h"
+
+// Enumeration of core components.
+#define MICROBIT_ID_BUTTON_A            1
+#define MICROBIT_ID_BUTTON_B            2
+#define MICROBIT_ID_BUTTON_RESET        3
+#define MICROBIT_ID_ACCELEROMETER       4
+#define MICROBIT_ID_COMPASS             5
+#define MICROBIT_ID_DISPLAY             6
+
+//EDGE connector events
+#define MICROBIT_IO_PINS                20
+
+#define MICROBIT_ID_IO_P0               7           //P0 is the left most pad (ANALOG/DIGITAL)
+#define MICROBIT_ID_IO_P1               8           //P1 is the middle pad (ANALOG/DIGITAL)
+#define MICROBIT_ID_IO_P2               9           //P2 is the right most pad (ANALOG/DIGITAL)
+#define MICROBIT_ID_IO_P3               10          //COL1 (ANALOG/DIGITAL)
+#define MICROBIT_ID_IO_P4               11          //BTN_A
+#define MICROBIT_ID_IO_P5               12          //COL2 (ANALOG/DIGITAL)
+#define MICROBIT_ID_IO_P6               13          //ROW2
+#define MICROBIT_ID_IO_P7               14          //ROW1
+#define MICROBIT_ID_IO_P8               15          //PIN 18
+#define MICROBIT_ID_IO_P9               16          //ROW3
+#define MICROBIT_ID_IO_P10              17          //COL3 (ANALOG/DIGITAL)
+#define MICROBIT_ID_IO_P11              18          //BTN_B
+#define MICROBIT_ID_IO_P12              19          //PIN 20
+#define MICROBIT_ID_IO_P13              20          //SCK
+#define MICROBIT_ID_IO_P14              21          //MISO
+#define MICROBIT_ID_IO_P15              22          //MOSI
+#define MICROBIT_ID_IO_P16              23          //PIN 16
+#define MICROBIT_ID_IO_P19              24          //SCL
+#define MICROBIT_ID_IO_P20              25          //SDA
+
+#define MICROBIT_ID_BUTTON_AB           26          // Button A+B multibutton
+#define MICROBIT_ID_GESTURE             27          // Gesture events
+
+#define MICROBIT_ID_THERMOMETER         28
+#define MICROBIT_ID_RADIO               29
+#define MICROBIT_ID_RADIO_DATA_READY    30
+#define MICROBIT_ID_MULTIBUTTON_ATTACH  31
+#define MICROBIT_ID_SERIAL              32
+
+#define MICROBIT_ID_MESSAGE_BUS_LISTENER            1021          // Message bus indication that a handler for a given ID has been registered.
+#define MICROBIT_ID_NOTIFY_ONE                      1022          // Notfication channel, for general purpose synchronisation
+#define MICROBIT_ID_NOTIFY                          1023          // Notfication channel, for general purpose synchronisation
+
+// Universal flags used as part of the status field
+#define MICROBIT_COMPONENT_RUNNING		0x01
+
+
+/**
+  * Class definition for MicroBitComponent.
+  *
+  * All components should inherit from this class.
+  *
+  * If a component requires regular updates, then you should add the component
+  * to the systemTick and idleTick queues.
+  *
+  * The system timer will call systemTick() once the component has been added to
+  * the array of system components using system_timer_add_component. This callback
+  * will be in interrupt context.
+  *
+  * The idle thread will call idleTick() once the component has been added to the array
+  * of idle components using fiber_add_idle_component. Updates are determined by
+  * the isIdleCallbackNeeded() member function.
+  */
+class MicroBitComponent
+{
+    protected:
+
+    uint16_t id;                    // Event Bus ID
+    uint8_t status;                 // keeps track of various component state, and also indicates if data is ready.
+
+    public:
+
+    /**
+      * The default constructor of a MicroBitComponent
+      */
+    MicroBitComponent()
+    {
+        this->id = 0;
+        this->status = 0;
+    }
+
+    /**
+      * The system timer will call this member function once the component has been added to
+      * the array of system components using system_timer_add_component. This callback
+      * will be in interrupt context.
+      */
+    virtual void systemTick(){
+
+    }
+
+    /**
+      * The idle thread will call this member function once the component has been added to the array
+      * of idle components using fiber_add_idle_component. Updates are determined by
+      * the isIdleCallbackNeeded() member function.
+      */
+    virtual void idleTick()
+    {
+
+    }
+
+    /**
+      * When added to the idleThreadComponents array, this function will be called to determine
+      * if and when data is ready.
+      *
+      * @note override this if you want to request to be scheduled as soon as possible.
+      */
+    virtual int isIdleCallbackNeeded()
+    {
+        return 0;
+    }
+
+    /**
+      * If you have added your component to the idle or system tick component arrays,
+      * you must remember to remove your component from them if your component is destructed.
+      */
+    virtual ~MicroBitComponent()
+    {
+    }
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitConfig.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,373 @@
+/*
+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.
+*/
+
+/**
+  * Compile time configuration options for the micro:bit runtime.
+  */
+
+#ifndef MICROBIT_CONFIG_H
+#define MICROBIT_CONFIG_H
+
+#include "mbed.h"
+
+//
+// Memory configuration
+//
+
+// The start address of usable RAM memory.
+#ifndef MICROBIT_SRAM_BASE
+#define MICROBIT_SRAM_BASE                      0x20000008
+#endif
+
+// Physical address of the top of SRAM.
+#ifndef MICROBIT_SRAM_END
+#define MICROBIT_SRAM_END                       0x20004000
+#endif
+
+// The end address of memory normally reserved for Soft Device.
+#ifndef MICROBIT_SD_LIMIT
+#define MICROBIT_SD_LIMIT                       0x20002000
+#endif
+
+// The physical address in memory of the Soft Device GATT table.
+#ifndef MICROBIT_SD_GATT_TABLE_START
+#define MICROBIT_SD_GATT_TABLE_START            0x20001900
+#endif
+
+// Physical address of the top of the system stack (on mbed-classic this is the top of SRAM)
+#ifndef CORTEX_M0_STACK_BASE
+#define CORTEX_M0_STACK_BASE                    MICROBIT_SRAM_END
+#endif
+
+// Amount of memory reserved for the stack at the end of memory (bytes).
+#ifndef MICROBIT_STACK_SIZE
+#define MICROBIT_STACK_SIZE                     2048
+#endif
+
+// Physical address of the end of mbed heap space.
+#ifndef MICROBIT_HEAP_END
+#define MICROBIT_HEAP_END                       (CORTEX_M0_STACK_BASE - MICROBIT_STACK_SIZE)
+#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.
+#ifndef MICROBIT_HEAP_ALLOCATOR
+#define MICROBIT_HEAP_ALLOCATOR                 1
+#endif
+
+// Block size used by the allocator in bytes.
+// n.b. Currently only 32 bits (4 bytes) is supported.
+#ifndef MICROBIT_HEAP_BLOCK_SIZE
+#define MICROBIT_HEAP_BLOCK_SIZE                4
+#endif
+
+// The proportion of SRAM available on the mbed heap to reserve for the micro:bit heap.
+#ifndef MICROBIT_NESTED_HEAP_SIZE
+#define MICROBIT_NESTED_HEAP_SIZE               0.75
+#endif
+
+// If defined, reuse any unused SRAM normally reserved for SoftDevice (Nordic's memory resident BLE stack) as heap memory.
+// The amount of memory reused depends upon whether or not BLE is enabled using MICROBIT_BLE_ENABLED.
+// Set '1' to enable.
+#ifndef MICROBIT_HEAP_REUSE_SD
+#define MICROBIT_HEAP_REUSE_SD                  1
+#endif
+
+// The amount of memory allocated to Soft Device to hold its BLE GATT table.
+// For standard S110 builds, this should be word aligned and in the range 0x300 - 0x700.
+// Any unused memory will be automatically reclaimed as HEAP memory if both MICROBIT_HEAP_REUSE_SD and MICROBIT_HEAP_ALLOCATOR are enabled.
+#ifndef MICROBIT_SD_GATT_TABLE_SIZE
+#define MICROBIT_SD_GATT_TABLE_SIZE             0x300
+#endif
+
+//
+// Fiber scheduler configuration
+//
+
+// Scheduling quantum (milliseconds)
+// Also used to drive the micro:bit runtime system ticker.
+#ifndef SYSTEM_TICK_PERIOD_MS
+#define SYSTEM_TICK_PERIOD_MS                   6
+#endif
+
+//
+// Message Bus:
+// Default behaviour for event handlers, if not specified in the listen() call
+//
+// Permissable values are:
+//   MESSAGE_BUS_LISTENER_REENTRANT
+//   MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY
+//   MESSAGE_BUS_LISTENER_DROP_IF_BUSY
+//   MESSAGE_BUS_LISTENER_IMMEDIATE
+
+#ifndef EVENT_LISTENER_DEFAULT_FLAGS
+#define EVENT_LISTENER_DEFAULT_FLAGS            MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY
+#endif
+
+//
+// Maximum event queue depth. If a queue exceeds this depth, further events will be dropped.
+// Used to prevent message queues growing uncontrollably due to badly behaved user code and causing panic conditions.
+//
+#ifndef MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH
+#define MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH    10
+#endif
+
+//
+// Core micro:bit services
+//
+
+// To reduce memory cost and complexity, the micro:bit allows components to register for
+// periodic callback events during interrupt context, which occur every scheduling quantum (FIBER_TICK_PERIOD_MS)
+// This defines the maximum size of interrupt callback list.
+#ifndef MICROBIT_SYSTEM_COMPONENTS
+#define MICROBIT_SYSTEM_COMPONENTS              10
+#endif
+
+// To reduce memory cost and complexity, the micro:bit allows components to register for
+// periodic callback events when the processor is idle.
+// This defines the maximum size of the idle callback list.
+#ifndef MICROBIT_IDLE_COMPONENTS
+#define MICROBIT_IDLE_COMPONENTS                6
+#endif
+
+//
+// BLE options
+//
+// The BLE stack is very memory hungry. Each service can therefore be compiled in or out
+// by enabling/disabling the options below.
+//
+// n.b. The minimum set of services to enable over the air programming of the device will
+// still be brought up in pairing mode regardless of the settings below.
+//
+
+// Enable/Disable BLE during normal operation.
+// Set '1' to enable.
+#ifndef MICROBIT_BLE_ENABLED
+#define MICROBIT_BLE_ENABLED                    1
+#endif
+
+// Enable/Disable BLE pairing mode mode at power up.
+// Set '1' to enable.
+#ifndef MICROBIT_BLE_PAIRING_MODE
+#define MICROBIT_BLE_PAIRING_MODE               1
+#endif
+
+// Enable/Disable the use of private resolvable addresses.
+// Set '1' to enable.
+// n.b. This is known to be a feature that suffers compatibility issues with many BLE central devices.
+#ifndef MICROBIT_BLE_PRIVATE_ADDRESSES
+#define MICROBIT_BLE_PRIVATE_ADDRESSES          0
+#endif
+
+// Convenience option to enable / disable BLE security entirely
+// Open BLE links are not secure, but commonly used during the development of BLE services
+// Set '1' to disable all secuity
+#ifndef MICROBIT_BLE_OPEN
+#define MICROBIT_BLE_OPEN                       0
+#endif
+
+// Configure for open BLE operation if so configured
+#if (MICROBIT_BLE_OPEN == 1)
+#define MICROBIT_BLE_SECURITY_LEVEL             SECURITY_MODE_ENCRYPTION_OPEN_LINK
+#define MICROBIT_BLE_WHITELIST                  0
+#define MICROBIT_BLE_ADVERTISING_TIMEOUT        0
+#define MICROBIT_BLE_DEFAULT_TX_POWER           6
+#endif
+
+
+// Define the default, global BLE security requirements for MicroBit BLE services
+// May be one of the following options (see mbed's SecurityManager class implementaiton detail)
+// SECURITY_MODE_ENCRYPTION_OPEN_LINK:      No bonding, encryption, or whitelisting required.
+// SECURITY_MODE_ENCRYPTION_NO_MITM:        Bonding, encyption and whitelisting but no passkey.
+// SECURITY_MODE_ENCRYPTION_WITH_MITM:      Bonding, encrytion and whitelisting with passkey authentication.
+//
+#ifndef MICROBIT_BLE_SECURITY_LEVEL
+#define MICROBIT_BLE_SECURITY_LEVEL             SECURITY_MODE_ENCRYPTION_WITH_MITM
+#endif
+
+// Enable/Disable the use of BLE whitelisting.
+// If enabled, the micro:bit will only respond to connection requests from
+// known, bonded devices.
+#ifndef MICROBIT_BLE_WHITELIST
+#define MICROBIT_BLE_WHITELIST                  1
+#endif
+
+// Define the period of time for which the BLE stack will advertise (seconds)
+// Afer this period, advertising will cease. Set to '0' for no timeout (always advertise).
+#ifndef MICROBIT_BLE_ADVERTISING_TIMEOUT
+#define MICROBIT_BLE_ADVERTISING_TIMEOUT        0
+#endif
+
+// Defines default power level of the BLE radio transmitter.
+// Valid values are in the range 0..7 inclusive, with 0 being the lowest power and 7 the highest power.
+// Based on trials undertaken by the BBC, the radio is normally set to its lowest power level
+// to best protect children's privacy.
+#ifndef MICROBIT_BLE_DEFAULT_TX_POWER
+#define MICROBIT_BLE_DEFAULT_TX_POWER           0
+#endif
+
+// Enable/Disable BLE Service: MicroBitDFU
+// This allows over the air programming during normal operation.
+// Set '1' to enable.
+#ifndef MICROBIT_BLE_DFU_SERVICE
+#define MICROBIT_BLE_DFU_SERVICE                1
+#endif
+
+// Enable/Disable BLE Service: MicroBitEventService
+// This allows routing of events from the micro:bit message bus over BLE.
+// Set '1' to enable.
+#ifndef MICROBIT_BLE_EVENT_SERVICE
+#define MICROBIT_BLE_EVENT_SERVICE              1
+#endif
+
+// Enable/Disable BLE Service: MicroBitDeviceInformationService
+// This enables the standard BLE device information service.
+// Set '1' to enable.
+#ifndef MICROBIT_BLE_DEVICE_INFORMATION_SERVICE
+#define MICROBIT_BLE_DEVICE_INFORMATION_SERVICE 1
+#endif
+
+//
+// Accelerometer options
+//
+
+// Enable this to read 10 bits of data from the acclerometer.
+// Otherwise, 8 bits are used.
+// Set '1' to enable.
+#ifndef USE_ACCEL_LSB
+#define USE_ACCEL_LSB                           0
+#endif
+
+//
+// Display options
+//
+
+// Selects the matrix configuration for the display driver.
+// Known, acceptable options are:
+//
+#define MICROBUG_REFERENCE_DEVICE               1
+#define MICROBIT_3X9                            2
+#define MICROBIT_SB1                            3
+#define MICROBIT_SB2                            4
+
+#ifndef MICROBIT_DISPLAY_TYPE
+#define MICROBIT_DISPLAY_TYPE                   MICROBIT_SB2
+#endif
+
+// Selects the minimum permissable brightness level for the device
+// in the region of 0 (off) to 255 (full brightness)
+#ifndef MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS
+#define MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS     1
+#endif
+
+// Selects the maximum permissable brightness level for the device
+// in the region of 0 (off) to 255 (full brightness)
+#ifndef MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS
+#define MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS     255
+#endif
+
+// Selects the default brightness for the display
+// in the region of zero (off) to 255 (full brightness)
+#ifndef MICROBIT_DISPLAY_DEFAULT_BRIGHTNESS
+#define MICROBIT_DISPLAY_DEFAULT_BRIGHTNESS     MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS
+#endif
+
+// Selects the default scroll speed for the display.
+// The time taken to move a single pixel (ms).
+#ifndef MICROBIT_DEFAULT_SCROLL_SPEED
+#define MICROBIT_DEFAULT_SCROLL_SPEED           120
+#endif
+
+// Selects the number of pixels a scroll will move in each quantum.
+#ifndef MICROBIT_DEFAULT_SCROLL_STRIDE
+#define MICROBIT_DEFAULT_SCROLL_STRIDE          -1
+#endif
+
+// Selects the time each character will be shown on the display during print operations.
+// The time each character is shown on the screen  (ms).
+#ifndef MICROBIT_DEFAULT_PRINT_SPEED
+#define MICROBIT_DEFAULT_PRINT_SPEED            400
+#endif
+
+//Configures the default serial mode used by serial read and send calls.
+#ifndef MICROBIT_DEFAULT_SERIAL_MODE
+#define MICROBIT_DEFAULT_SERIAL_MODE            SYNC_SLEEP
+#endif
+
+
+//
+// Panic options
+//
+
+// Enable this to invoke a panic on out of memory conditions.
+// Set '1' to enable.
+#ifndef MICROBIT_PANIC_HEAP_FULL
+#define MICROBIT_PANIC_HEAP_FULL                1
+#endif
+
+//
+// Debug options
+//
+
+// Enable this to route debug messages through the USB serial interface.
+// n.b. This also disables the user serial port 'uBit.serial'.
+// Set '1' to enable.
+#ifndef MICROBIT_DBG
+#define MICROBIT_DBG                            0
+#endif
+
+// Enable this to receive diagnostic messages from the heap allocator via the USB serial interface.
+// n.b. This requires MICROBIT_DBG to be defined.
+// Set '1' to enable.
+#ifndef MICROBIT_HEAP_DBG
+#define MICROBIT_HEAP_DBG                       0
+#endif
+
+// Versioning options.
+// We use semantic versioning (http://semver.org/) to identify differnet versions of the micro:bit runtime.
+// Where possible we use yotta (an ARM mbed build tool) to help us track versions.
+// if this isn't available, it can be defined manually as a configuration option.
+//
+#ifndef MICROBIT_DAL_VERSION
+#define MICROBIT_DAL_VERSION                    "unknown"
+#endif
+
+
+//
+// Helper macro used by the micro:bit runtime to determine if a boolean configuration option is set.
+//
+#define CONFIG_ENABLED(X) (X == 1)
+#define CONFIG_DISABLED(X) (X != 1)
+
+#if CONFIG_ENABLED(MICROBIT_HEAP_ALLOCATOR)
+#include "MicroBitHeapAllocator.h"
+#endif
+
+#if CONFIG_ENABLED(MICROBIT_DBG)
+extern RawSerial* SERIAL_DEBUG;
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitDevice.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,136 @@
+/*
+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.
+*/
+
+/**
+ * Device specific funcitons for the nrf51822 device.
+ *
+ * Provides a degree of platform independence for microbit-dal functionality.
+ *
+ * TODO: Determine if any of this belongs in an mbed target definition.
+ * TODO: Review microbit-dal to place all such functions here.
+ */
+#ifndef MICROBIT_DEVICE_H
+#define MICROBIT_DEVICE_H
+
+#define MICROBIT_NAME_LENGTH                    5
+#define MICROBIT_NAME_CODE_LETTERS              5
+#define MICROBIT_PANIC_ERROR_CHARS              4
+
+#include "MicroBitConfig.h"
+#include "MicroBitMatrixMaps.h"
+
+/**
+  * Determines if a BLE stack is currently running.
+  *
+  * @return true is a bluetooth stack is operational, false otherwise.
+  */
+bool ble_running();
+
+/**
+ * Derive a unique, consistent serial number of this device from internal data.
+ *
+ * @return the serial number of this device.
+ */
+uint32_t microbit_serial_number();
+
+/**
+ * Derive the friendly name for this device, based on its serial number.
+ *
+ * @return the serial number of this device.
+ */
+char* microbit_friendly_name();
+
+/**
+  * Perform a hard reset of the micro:bit.
+  */
+void microbit_reset();
+
+/**
+  * Determine the version of microbit-dal currently running.
+  * @return a pointer to a character buffer containing a representation of the semantic version number.
+  */
+const char * microbit_dal_version();
+
+/**
+  * Disables all interrupts and user processing.
+  * Displays "=(" and an accompanying status code on the default display.
+  * @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
+  *
+  * @code
+  * microbit_panic(20);
+  * @endcode
+  */
+void microbit_panic(int statusCode);
+
+/**
+ * Defines the length of time that the device will remain in a error state before resetting.
+ *
+ * @param iteration The number of times the error code will be displayed before resetting. Set to zero to remain in error state forever.
+ *
+ * @code
+ * microbit_panic_timeout(4);
+ * @endcode
+ */
+void microbit_panic_timeout(int iterations);
+
+/**
+  * Generate a random number in the given range.
+  * We use a simple Galois LFSR random number generator here,
+  * as a Galois LFSR is sufficient for our applications, and much more lightweight
+  * than the hardware random number generator built int the processor, which takes
+  * a long time and uses a lot of energy.
+  *
+  * KIDS: You shouldn't use this is the real world to generte cryptographic keys though...
+  * have a think why not. :-)
+  *
+  * @param max the upper range to generate a number for. This number cannot be negative.
+  *
+  * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE if max is <= 0.
+  *
+  * @code
+  * microbit_random(200); //a number between 0 and 199
+  * @endcode
+  */
+int microbit_random(int max);
+
+/**
+  * Seed the random number generator (RNG).
+  *
+  * This function uses the NRF51822's in built cryptographic random number generator to seed a Galois LFSR.
+  * We do this as the hardware RNG is relatively high power, and is locked out by the BLE stack internally,
+  * with a less than optimal application interface. A Galois LFSR is sufficient for our
+  * applications, and much more lightweight.
+  */
+void microbit_seed_random();
+
+/**
+  * Seed the pseudo random number generator (RNG) using the given 32-bit value.
+  * This function does not use the NRF51822's in built cryptographic random number generator.
+  *
+  * @param seed The value to use as a seed.
+  */
+void microbit_seed_random(uint32_t seed);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitFiber.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,401 @@
+/*
+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.
+*/
+
+/**
+  * Functionality definitions for the MicroBit Fiber scheduler.
+  *
+  * This lightweight, non-preemptive scheduler provides a simple threading mechanism for two main purposes:
+  *
+  * 1) To provide a clean abstraction for application languages to use when building async behaviour (callbacks).
+  * 2) To provide ISR decoupling for EventModel events generated in an ISR context.
+  *
+  * TODO: Consider a split mode scheduler, that monitors used stack size, and maintains a dedicated, persistent
+  * stack for any long lived fibers with large stack
+  */
+#ifndef MICROBIT_FIBER_H
+#define MICROBIT_FIBER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitEvent.h"
+#include "EventModel.h"
+
+// Fiber Scheduler Flags
+#define MICROBIT_SCHEDULER_RUNNING	     	0x01
+
+// Fiber Flags
+#define MICROBIT_FIBER_FLAG_FOB             0x01
+#define MICROBIT_FIBER_FLAG_PARENT          0x02
+#define MICROBIT_FIBER_FLAG_CHILD           0x04
+#define MICROBIT_FIBER_FLAG_DO_NOT_PAGE     0x08
+
+/**
+  *  Thread Context for an ARM Cortex M0 core.
+  *
+  * This is probably overkill, but the ARMCC compiler uses a lot register optimisation
+  * in its calling conventions, so better safe than sorry!
+  */
+struct Cortex_M0_TCB
+{
+    uint32_t R0;
+    uint32_t R1;
+    uint32_t R2;
+    uint32_t R3;
+    uint32_t R4;
+    uint32_t R5;
+    uint32_t R6;
+    uint32_t R7;
+    uint32_t R8;
+    uint32_t R9;
+    uint32_t R10;
+    uint32_t R11;
+    uint32_t R12;
+    uint32_t SP;
+    uint32_t LR;
+    uint32_t stack_base;
+};
+
+/**
+  * Representation of a single Fiber
+  */
+struct Fiber
+{
+    Cortex_M0_TCB tcb;                  // Thread context when last scheduled out.
+    uint32_t stack_bottom;              // The start address of this Fiber's stack. The stack is heap allocated, and full descending.
+    uint32_t stack_top;                 // The end address of this Fiber's stack.
+    uint32_t context;                   // Context specific information.
+    uint32_t flags;                     // Information about this fiber.
+    Fiber **queue;                      // The queue this fiber is stored on.
+    Fiber *next, *prev;                 // Position of this Fiber on the run queue.
+};
+
+extern Fiber *currentFiber;
+
+
+/**
+  * Initialises the Fiber scheduler.
+  * Creates a Fiber context around the calling thread, and adds it to the run queue as the current thread.
+  *
+  * This function must be called once only from the main thread, and before any other Fiber operation.
+  *
+  * @param _messageBus An event model, used to direct the priorities of the scheduler.
+  */
+void scheduler_init(EventModel &_messageBus);
+
+/**
+  * Determines if the fiber scheduler is operational.
+  *
+  * @return 1 if the fber scheduler is running, 0 otherwise.
+  */
+int fiber_scheduler_running();
+
+/**
+  * Exit point for all fibers.
+  *
+  * Any fiber reaching the end of its entry function will return here  for recycling.
+  */
+void release_fiber(void);
+void release_fiber(void *param);
+
+/**
+ * Launches a fiber.
+ *
+ * @param ep the entry point for the fiber.
+ *
+ * @param cp the completion routine after ep has finished execution
+ */
+void launch_new_fiber(void (*ep)(void), void (*cp)(void))
+#ifdef __GCC__
+    __attribute__((naked))
+#endif
+;
+
+/**
+ * Launches a fiber with a parameter
+ *
+ * @param ep the entry point for the fiber.
+ *
+ * @param cp the completion routine after ep has finished execution
+ *
+ * @param pm the parameter to provide to ep and cp.
+ */
+void launch_new_fiber_param(void (*ep)(void *), void (*cp)(void *), void *pm)
+#ifdef __GCC__
+    __attribute__((naked))
+#endif
+;
+
+/**
+  * Creates a new Fiber, and launches it.
+  *
+  * @param entry_fn The function the new Fiber will begin execution in.
+  *
+  * @param completion_fn The function called when the thread completes execution of entry_fn.
+  *                      Defaults to release_fiber.
+  *
+  * @return The new Fiber, or NULL if the operation could not be completed.
+  */
+Fiber *create_fiber(void (*entry_fn)(void), void (*completion_fn)(void) = release_fiber);
+
+
+/**
+  * Creates a new parameterised Fiber, and launches it.
+  *
+  * @param entry_fn The function the new Fiber will begin execution in.
+  *
+  * @param param an untyped parameter passed into the entry_fn and completion_fn.
+  *
+  * @param completion_fn The function called when the thread completes execution of entry_fn.
+  *                      Defaults to release_fiber.
+  *
+  * @return The new Fiber, or NULL if the operation could not be completed.
+  */
+Fiber *create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)(void *) = release_fiber);
+
+
+/**
+  * Calls the Fiber scheduler.
+  * The calling Fiber will likely be blocked, and control given to another waiting fiber.
+  * Call this function to yield control of the processor when you have nothing more to do.
+  */
+void schedule();
+
+/**
+  * Blocks the calling thread for the given period of time.
+  * The calling thread will be immediateley descheduled, and placed onto a
+  * wait queue until the requested amount of time has elapsed.
+  *
+  * @param t The period of time to sleep, in milliseconds.
+  *
+  * @note the fiber will not be be made runnable until after the elapsed time, but there
+  * are no guarantees precisely when the fiber will next be scheduled.
+  */
+void fiber_sleep(unsigned long t);
+
+/**
+  * The timer callback, called from interrupt context once every SYSTEM_TICK_PERIOD_MS milliseconds.
+  * This function checks to determine if any fibers blocked on the sleep queue need to be woken up
+  * and made runnable.
+  */
+void scheduler_tick();
+
+/**
+  * Blocks the calling thread until the specified event is raised.
+  * The calling thread will be immediateley descheduled, and placed onto a
+  * wait queue until the requested event is received.
+  *
+  * @param id The ID field of the event to listen for (e.g. MICROBIT_ID_BUTTON_A)
+  *
+  * @param value The value of the event to listen for (e.g. MICROBIT_BUTTON_EVT_CLICK)
+  *
+  * @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel.
+  *
+  * @code
+  * fiber_wait_for_event(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
+  * @endcode
+  *
+  * @note the fiber will not be be made runnable until after the event is raised, but there
+  * are no guarantees precisely when the fiber will next be scheduled.
+  */
+int fiber_wait_for_event(uint16_t id, uint16_t value);
+
+/**
+  * Configures the fiber context for the current fiber to block on an event ID
+  * and value, but does not deschedule the fiber.
+  *
+  * @param id The ID field of the event to listen for (e.g. MICROBIT_ID_BUTTON_A)
+  *
+  * @param value The value of the event to listen for (e.g. MICROBIT_BUTTON_EVT_CLICK)
+  *
+  * @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel.
+  *
+  * @code
+  * fiber_wake_on_event(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
+  *
+  * //perform some time critical operation.
+  *
+  * //deschedule the current fiber manually, waiting for the previously configured event.
+  * schedule();
+  * @endcode
+  */
+int fiber_wake_on_event(uint16_t id, uint16_t value);
+
+/**
+  * Executes the given function asynchronously if necessary.
+  *
+  * Fibers are often used to run event handlers, however many of these event handlers are very simple functions
+  * that complete very quickly, bringing unecessary RAM overhead.
+  *
+  * This function takes a snapshot of the current processor context, then attempts to optimistically call the given function directly.
+  * We only create an additional fiber if that function performs a block operation.
+  *
+  * @param entry_fn The function to execute.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int invoke(void (*entry_fn)(void));
+
+/**
+  * Executes the given function asynchronously if necessary, and offers the ability to provide a parameter.
+  *
+  * Fibers are often used to run event handlers, however many of these event handlers are very simple functions
+  * that complete very quickly, bringing unecessary RAM. overhead
+  *
+  * This function takes a snapshot of the current fiber context, then attempt to optimistically call the given function directly.
+  * We only create an additional fiber if that function performs a block operation.
+  *
+  * @param entry_fn The function to execute.
+  *
+  * @param param an untyped parameter passed into the entry_fn and completion_fn.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int invoke(void (*entry_fn)(void *), void *param);
+
+/**
+  * Resizes the stack allocation of the current fiber if necessary to hold the system stack.
+  *
+  * If the stack allocation is large enough to hold the current system stack, then this function does nothing.
+  * Otherwise, the the current allocation of the fiber is freed, and a larger block is allocated.
+  *
+  * @param f The fiber context to verify.
+  *
+  * @return The stack depth of the given fiber.
+  */
+inline void verify_stack_size(Fiber *f);
+
+/**
+  * Event callback. Called from an instance of MicroBitMessageBus whenever an event is raised.
+  *
+  * This function checks to determine if any fibers blocked on the wait queue need to be woken up
+  * and made runnable due to the event.
+  *
+  * @param evt the event that has just been raised on an instance of MicroBitMessageBus.
+  */
+void scheduler_event(MicroBitEvent evt);
+
+/**
+  * Determines if any fibers are waiting to be scheduled.
+  *
+  * @return The number of fibers currently on the run queue
+  */
+int scheduler_runqueue_empty();
+
+/**
+  * Utility function to add the currenty running fiber to the given queue.
+  *
+  * Perform a simple add at the head, to avoid complexity,
+  *
+  * Queues are normally very short, so maintaining a doubly linked, sorted list typically outweighs the cost of
+  * brute force searching.
+  *
+  * @param f The fiber to add to the queue
+  *
+  * @param queue The run queue to add the fiber to.
+  */
+void queue_fiber(Fiber *f, Fiber **queue);
+
+/**
+  * Utility function to the given fiber from whichever queue it is currently stored on.
+  *
+  * @param f the fiber to remove.
+  */
+void dequeue_fiber(Fiber *f);
+
+/**
+  * Set of tasks to perform when idle.
+  * Service any background tasks that are required, and attempt a power efficient sleep.
+  */
+void idle();
+
+/**
+  * The idle task, which is called when the runtime has no fibers that require execution.
+  *
+  * This function typically calls idle().
+  */
+void idle_task();
+
+/**
+  * Adds a component to the array of idle thread components, which are processed
+  * when the run queue is empty.
+  *
+  * The system timer will poll isIdleCallbackNeeded on each component to determine
+  * if the scheduler should schedule the idle_task imminently.
+  *
+  * @param component The component to add to the array.
+  *
+  * @return MICROBIT_OK on success or MICROBIT_NO_RESOURCES if the fiber components array is full.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * // heap allocated - otherwise it will be paged out!
+  * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
+  *
+  * fiber_add_idle_component(accelerometer);
+  * @endcode
+  */
+int fiber_add_idle_component(MicroBitComponent *component);
+
+/**
+  * Remove a component from the array of idle thread components
+  *
+  * @param component The component to remove from the idle component array.
+  *
+  * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * // heap allocated - otherwise it will be paged out!
+  * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
+  *
+  * fiber_add_idle_component(accelerometer);
+  *
+  * fiber_remove_idle_component(accelerometer);
+  * @endcode
+  */
+int fiber_remove_idle_component(MicroBitComponent *component);
+
+/**
+  * Determines if the processor is executing in interrupt context.
+  *
+  * @return true if any the processor is currently executing any interrupt service routine. False otherwise.
+  */
+inline int inInterruptContext()
+{
+    return (((int)__get_IPSR()) & 0x003F) > 0;
+}
+
+/**
+  * Assembler Context switch routing.
+  * Defined in CortexContextSwitch.s.
+  */
+extern "C" void swap_context(Cortex_M0_TCB *from, Cortex_M0_TCB *to, uint32_t from_stack, uint32_t to_stack);
+extern "C" void save_context(Cortex_M0_TCB *tcb, uint32_t stack);
+extern "C" void save_register_context(Cortex_M0_TCB *tcb);
+extern "C" void restore_register_context(Cortex_M0_TCB *tcb);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitFont.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,100 @@
+/*
+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_FONT_H
+#define MICROBIT_FONT_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+
+#define MICROBIT_FONT_WIDTH 5
+#define MICROBIT_FONT_HEIGHT 5
+#define MICROBIT_FONT_ASCII_START 32
+#define MICROBIT_FONT_ASCII_END 126
+
+/**
+  * Class definition for a MicrobitFont
+  * This class represents a font that can be used by the display to render text.
+  *
+  * A MicroBitFont is 5x5.
+  * Each Row is represented by a byte in the array.
+  *
+  * Row Format:
+  *            ================================================================
+  *            | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
+  *            ================================================================
+  *            |  N/A  |  N/A  |  N/A  | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 |
+  *            |  0x80 |  0x40 |  0x20 | 0x10  | 0x08  | 0x04  | 0x02  | 0x01  |
+  *
+  * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 }
+  *
+  * The above will produce an exclaimation mark on the second column in form the left.
+  *
+  * We could compress further, but the complexity of decode would likely outweigh the gains.
+  */
+class MicroBitFont
+{
+    public:
+
+    static const unsigned char* defaultFont;
+    static MicroBitFont systemFont;
+
+    const unsigned char* characters;
+
+    int asciiEnd;
+
+    /**
+      * Constructor.
+      *
+      * Sets the font represented by this font object.
+      *
+      * @param font A pointer to the beginning of the new font.
+      *
+      * @param asciiEnd the char value at which this font finishes.
+      */
+    MicroBitFont(const unsigned char* font, int asciiEnd = MICROBIT_FONT_ASCII_END);
+
+    /**
+      * Default Constructor.
+      *
+      * Configures the default font for the display to use.
+      */
+    MicroBitFont();
+
+    /**
+      * Modifies the current system font to the given instance of MicroBitFont.
+      *
+      * @param font the new font that will be used to render characters on the display.
+      */
+    static void setSystemFont(MicroBitFont font);
+
+    /**
+      * Retreives the font object used for rendering characters on the display.
+      */
+    static MicroBitFont getSystemFont();
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitHeapAllocator.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,167 @@
+/*
+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.
+*/
+
+/**
+  * A simple 32 bit block based memory allocator. This allows one or more memory segments to
+  * be designated as heap storage, and is designed to run in a static memory area or inside the standard C
+  * heap for use by the micro:bit runtime. This is required for several reasons:
+  *
+  * 1) It reduces memory fragmentation due to the high churn sometime placed on the heap
+  * by ManagedTypes, fibers and user code. Underlying heap implentations are often have very simplistic
+  * allocation pilicies and suffer from fragmentation in prolonged use - which can cause programs to
+  * stop working after a period of time. The algorithm implemented here is simple, but highly tolerant to
+  * large amounts of churn.
+  *
+  * 2) It allows us to reuse the 8K of SRAM set aside for SoftDevice as additional heap storage
+  * when BLE is not in use.
+  *
+  * 3) It gives a simple example of how memory allocation works! :-)
+  *
+  * P.S. This is a very simple allocator, therefore not without its weaknesses. Why don't you consider
+  * what these are, and consider the tradeoffs against simplicity...
+  *
+  * @note The need for this should be reviewed in the future, if a different memory allocator is
+  * made availiable in the mbed platform.
+  *
+  * TODO: Consider caching recently freed blocks to improve allocation time.
+  */
+
+#ifndef MICROBIT_HEAP_ALLOCTOR_H
+#define MICROBIT_HEAP_ALLOCTOR_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include <new>
+
+// The maximum number of heap segments that can be created.
+#define MICROBIT_MAXIMUM_HEAPS          2
+
+// Flag to indicate that a given block is FREE/USED
+#define MICROBIT_HEAP_BLOCK_FREE		0x80000000
+
+/**
+  * Create and initialise a given memory region as for heap storage.
+  * After this is called, any future calls to malloc, new, free or delete may use the new heap.
+  * The heap allocator will attempt to allocate memory from heaps in the order that they are created.
+  * i.e. memory will be allocated from first heap created until it is full, then the second heap, and so on.
+  *
+  * @param start The start address of memory to use as a heap region.
+  *
+  * @param end The end address of memory to use as a heap region.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the heap could not be allocated.
+  *
+  * @note Only code that #includes MicroBitHeapAllocator.h will use this heap. This includes all micro:bit runtime
+  * code, and user code targetting the runtime. External code can choose to include this file, or
+  * simply use the standard heap.
+  */
+int microbit_create_heap(uint32_t start, uint32_t end);
+
+/**
+  * Create and initialise a heap region within the current the heap region specified
+  * by the linker script.
+  *
+  * If the requested amount is not available, then the amount requested will be reduced
+  * automatically to fit the space available.
+  *
+  * @param ratio The proportion of the underlying heap to allocate.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the heap could not be allocated.
+  */
+int microbit_create_nested_heap(float ratio);
+
+/**
+  * Attempt to allocate a given amount of memory from any of our configured heap areas.
+  *
+  * @param size The amount of memory, in bytes, to allocate.
+  *
+  * @return A pointer to the allocated memory, or NULL if insufficient memory is available.
+  */
+void *microbit_malloc(size_t size);
+
+
+/**
+  * Release a given area of memory from the heap.
+  *
+  * @param mem The memory area to release.
+  */
+void microbit_free(void *mem);
+
+/*
+ * Wrapper function to ensure we have an explicit handle on the heap allocator provided
+ * by our underlying platform.
+ *
+ * @param size The amount of memory, in bytes, to allocate.
+ *
+ * @return A pointer to the memory allocated. NULL if no memory is available.
+ */
+inline void *native_malloc(size_t size)
+{
+    return malloc(size);
+}
+
+/*
+ * Wrapper function to ensure we have an explicit handle on the heap allocator provided
+ * by our underlying platform.
+ *
+ * @param p Pointer to the memory to be freed.
+ */
+inline void native_free(void *p)
+{
+    free(p);
+}
+
+/**
+  * Overrides the 'new' operator globally, and redirects calls to the micro:bit heap allocator.
+  */
+inline void* operator new(size_t size) throw(std::bad_alloc)
+{
+    return microbit_malloc(size);
+}
+
+/**
+  * Overrides the 'new' operator globally, and redirects calls to the micro:bit theap allocator.
+  */
+inline void* operator new[](size_t size) throw(std::bad_alloc)
+{
+    return microbit_malloc(size);
+}
+
+/**
+  * Overrides the 'delete' operator globally, and redirects calls to the micro:bit theap allocator.
+  */
+inline void operator delete(void *ptr) throw()
+{
+    microbit_free(ptr);
+}
+
+
+// Macros to override overrides the 'malloc' and 'delete' functions globally, and redirects calls
+// to the micro:bit theap allocator.
+
+#define malloc(X) microbit_malloc( X )
+#define free(X) microbit_free( X )
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitListener.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,168 @@
+/*
+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_LISTENER_H
+#define MICROBIT_LISTENER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitEvent.h"
+#include "MemberFunctionCallback.h"
+#include "MicroBitConfig.h"
+
+// MicroBitListener flags...
+#define MESSAGE_BUS_LISTENER_PARAMETERISED          0x0001
+#define MESSAGE_BUS_LISTENER_METHOD                 0x0002
+#define MESSAGE_BUS_LISTENER_BUSY                   0x0004
+#define MESSAGE_BUS_LISTENER_REENTRANT              0x0008
+#define MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY          0x0010
+#define MESSAGE_BUS_LISTENER_DROP_IF_BUSY           0x0020
+#define MESSAGE_BUS_LISTENER_NONBLOCKING            0x0040
+#define MESSAGE_BUS_LISTENER_URGENT                 0x0080
+#define MESSAGE_BUS_LISTENER_DELETING               0x8000
+
+#define MESSAGE_BUS_LISTENER_IMMEDIATE              (MESSAGE_BUS_LISTENER_NONBLOCKING |  MESSAGE_BUS_LISTENER_URGENT)
+
+/**
+  *	This structure defines a MicroBitListener used to invoke functions, or member
+  * functions if an instance of EventModel receives an event whose id and value
+  * match this MicroBitListener's id and value.
+  */
+struct MicroBitListener
+{
+	uint16_t		id;				// The ID of the component that this listener is interested in.
+	uint16_t 		value;			// Value this listener is interested in receiving.
+    uint16_t        flags;          // Status and configuration options codes for this listener.
+
+    union
+    {
+        void (*cb)(MicroBitEvent);
+        void (*cb_param)(MicroBitEvent, void *);
+        MemberFunctionCallback *cb_method;
+    };
+
+	void*			cb_arg;			// Optional argument to be passed to the caller.
+
+	MicroBitEvent 	            evt;
+	MicroBitEventQueueItem 	    *evt_queue;
+
+	MicroBitListener *next;
+
+	/**
+	  * Constructor.
+	  *
+	  * Create a new Message Bus Listener.
+	  *
+	  * @param id The ID of the component you want to listen to.
+	  *
+	  * @param value The event value you would like to listen to from that component
+	  *
+	  * @param handler A function pointer to call when the event is detected.
+	  *
+	  * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+      * to be tuned.
+	  */
+	MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS);
+
+	/**
+	  * Constructor.
+	  *
+	  * Create a new Message Bus Listener, this constructor accepts an additional
+	  * parameter "arg", which is passed to the handler.
+	  *
+	  * @param id The ID of the component you want to listen to.
+	  *
+	  * @param value The event value you would like to listen to from that component
+	  *
+	  * @param handler A function pointer to call when the event is detected.
+	  *
+	  * @param arg A pointer to some data that will be given to the handler.
+	  *
+	  * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+      * to be tuned.
+	  */
+    MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent, void *), void* arg, uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS);
+
+
+	/**
+	  * Constructor.
+	  *
+	  * Create a new Message Bus Listener, with a callback to a C++ member function.
+	  *
+	  * @param id The ID of the component you want to listen to.
+	  *
+	  * @param value The event value you would like to listen to from that component
+	  *
+	  * @param object The C++ object on which to call the event handler.
+	  *
+      * @param method The method within the C++ object to call.
+	  *
+	  * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+      * to be tuned.
+	  */
+    template <typename T>
+    MicroBitListener(uint16_t id, uint16_t value, T* object, void (T::*method)(MicroBitEvent), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS);
+
+    /**
+      * Destructor. Ensures all resources used by this listener are freed.
+      */
+    ~MicroBitListener();
+
+    /**
+      * Queues and event up to be processed.
+	  *
+      * @param e The event to queue
+      */
+    void queue(MicroBitEvent e);
+};
+
+/**
+  * Constructor.
+  *
+  * Create a new Message Bus Listener, with a callback to a C++ member function.
+  *
+  * @param id The ID of the component you want to listen to.
+  *
+  * @param value The event value you would like to listen to from that component
+  *
+  * @param object The C++ object on which to call the event handler.
+  *
+  * @param method The method within the C++ object to call.
+  *
+  * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+  * to be tuned.
+  */
+template <typename T>
+MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, T* object, void (T::*method)(MicroBitEvent), uint16_t flags)
+{
+	this->id = id;
+	this->value = value;
+    this->cb_method = new MemberFunctionCallback(object, method);
+	this->cb_arg = NULL;
+    this->flags = flags | MESSAGE_BUS_LISTENER_METHOD;
+	this->next = NULL;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/MicroBitSystemTimer.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,149 @@
+/*
+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.
+*/
+
+/**
+  * Definitions for the MicroBit system timer.
+  *
+  * This module provides:
+  *
+  * 1) a concept of global system time since power up
+  * 2) a simple periodic multiplexing API for the underlying mbed implementation.
+  *
+  * The latter is useful to avoid costs associated with multiple mbed Ticker instances
+  * in microbit-dal components, as each incurs a significant additional RAM overhead (circa 80 bytes).
+  */
+
+#ifndef MICROBIT_SYSTEM_TIMER_H
+#define MICROBIT_SYSTEM_TIMER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+
+/**
+  * Initialises the system wide timer.
+  *
+  * This must be called before any components register to receive periodic periodic callbacks.
+  *
+  * @param timer_period The initial period between interrupts, in millseconds.
+  *
+  * @return MICROBIT_OK on success.
+  */
+int system_timer_init(int period);
+
+/**
+  * Reconfigures the system wide timer to the given period in milliseconds.
+  *
+  * @param period the new period of the timer in milliseconds
+  *
+  * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if period < 1
+  */
+int system_timer_set_period(int period);
+
+/**
+  * Accessor to obtain the current tick period in milliseconds
+  *
+  * @return the current tick period in milliseconds
+  */
+int system_timer_get_period();
+
+/**
+  * Determines the time since the device was powered on.
+  *
+  * @return the current time since power on in milliseconds
+  */
+unsigned long system_timer_current_time();
+
+/**
+  * Timer callback. Called from interrupt context, once per period.
+  *
+  * Simply checks to determine if any fibers blocked on the sleep queue need to be woken up
+  * and made runnable.
+  */
+void system_timer_tick();
+
+/**
+  * Add a component to the array of system components. This component will then receive
+  * periodic callbacks, once every tick period in interrupt context.
+  *
+  * @param component The component to add.
+  *
+  * @return MICROBIT_OK on success or MICROBIT_NO_RESOURCES if the component array is full.
+  *
+  * @code
+  * // heap allocated - otherwise it will be paged out!
+  * MicroBitDisplay* display = new MicroBitDisplay();
+  *
+  * system_timer_add_component(display);
+  * @endcode
+  */
+int system_timer_add_component(MicroBitComponent *component);
+
+/**
+  * Remove a component from the array of system components. This component will no longer receive
+  * periodic callbacks.
+  *
+  * @param component The component to remove.
+  *
+  * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
+  *
+  * @code
+  * // heap allocated - otherwise it will be paged out!
+  * MicroBitDisplay* display = new MicroBitDisplay();
+  *
+  * system_timer_add_component(display);
+  *
+  * system_timer_remove_component(display);
+  * @endcode
+  */
+int system_timer_remove_component(MicroBitComponent *component);
+
+/**
+  * A simple C/C++ wrapper to allow periodic callbacks to standard C functions transparently.
+  */
+class MicroBitSystemTimerCallback : MicroBitComponent
+{
+    void (*fn)(void);
+
+    /**
+     * Creates an object that receives periodic callbacks from the system timer,
+     * and, in turn, calls a plain C function as provided as a parameter.
+     *
+     * @param function the function to invoke upon a systemTick.
+     */
+    public:
+    MicroBitSystemTimerCallback(void (*function)(void))
+    {
+        fn = function;
+        system_timer_add_component(this);
+    }
+
+    void systemTick()
+    {
+        fn();
+    }
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/core/NotifyEvents.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,37 @@
+/*
+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 NOTIFY_EVENTS_H
+#define NOTIFY_EVENTS_H
+
+/**
+  * This file contains events used on the general purpose Eventing channel
+  * MICROBIT_ID_NOTIFY, new events should be added here, to prevent duplication.
+  */
+#define MICROBIT_DISPLAY_EVT_FREE           1
+#define MICROBIT_SERIAL_EVT_TX_EMPTY        2
+#define MICROBIT_UART_S_EVT_TX_EMPTY        3
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/DynamicPwm.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,216 @@
+/*
+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 "mbed.h"
+#include "MicroBitConfig.h"
+
+#ifndef MICROBIT_DYNAMIC_PWM_H
+#define MICROBIT_DYNAMIC_PWM_H
+
+#define NO_PWMS 3
+#define MICROBIT_DEFAULT_PWM_PERIOD 20000
+
+enum PwmPersistence
+{
+    PWM_PERSISTENCE_TRANSIENT = 1,
+    PWM_PERSISTENCE_PERSISTENT = 2,
+};
+
+/**
+  * Class definition for DynamicPwm.
+  *
+  * This class addresses a few issues found in the underlying libraries.
+  * This provides the ability for a neat, clean swap between PWM channels.
+  */
+class DynamicPwm : public PwmOut
+{
+    private:
+    static DynamicPwm* pwms[NO_PWMS];
+    static uint8_t lastUsed;
+    static uint16_t sharedPeriod;
+    uint8_t flags;
+    float lastValue;
+
+
+
+    /**
+      * An internal constructor used when allocating a new DynamicPwm instance.
+      *
+      * @param pin the name of the pin for the pwm to target
+      *
+      * @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
+      *                    or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
+      */
+    DynamicPwm(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
+
+    public:
+
+    /**
+      * Redirects the pwm channel to point at a different pin.
+      *
+      * @param pin the desired pin to output a PWM wave.
+      *
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      * pwm->redirect(p0); // pwm is now produced on p0
+      * @endcode
+      */
+    void redirect(PinName pin);
+
+
+    /**
+      * Creates a new DynamicPwm instance, or reuses an existing instance that
+      * has a persistence level of PWM_PERSISTENCE_TRANSIENT.
+      *
+      * @param pin the name of the pin for the pwm to target
+      *
+      * @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
+      *                    or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
+      *
+      * @return a pointer to the first available free pwm channel - or the first one that can be reallocated. If
+      *         no channels are available, NULL is returned.
+      *
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      * @endcode
+      */
+    static DynamicPwm* allocate(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
+
+    /**
+      * Frees this DynamicPwm instance for reuse.
+      *
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate();
+      * pwm->release();
+      * @endcode
+      */
+    void release();
+
+    /**
+      * A lightweight wrapper around the super class' write in order to capture the value
+      *
+      * @param value the duty cycle percentage in floating point format.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
+      *
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate();
+      * pwm->write(0.5);
+      * @endcode
+      */
+    int write(float value);
+
+    /**
+      * Retreives the PinName associated with this DynamicPwm instance.
+      *
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      *
+      * // returns the PinName n.
+      * pwm->getPinName();
+      * @endcode
+      *
+      * @note This should be used to check that the DynamicPwm instance has not
+      *       been reallocated for use in another part of a program.
+      */
+    PinName getPinName();
+
+    /**
+      * Retreives the last value that has been written to this DynamicPwm instance.
+      * in the range 0 - 1023 inclusive.
+      *
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      * pwm->write(0.5);
+      *
+      * // will return 512.
+      * pwm->getValue();
+      * @endcode
+      */
+    int getValue();
+
+    /**
+      * Retreives the current period in use by the entire PWM module in microseconds.
+      *
+      * Example:
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      * pwm->getPeriod();
+      * @endcode
+      */
+    int getPeriodUs();
+
+    /**
+      * Retreives the current period in use by the entire PWM module in milliseconds.
+      *
+      * Example:
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      * pwm->setPeriodUs(20000);
+      *
+      * // will return 20000
+      * pwm->getPeriod();
+      * @endcode
+      */
+    int getPeriod();
+
+    /**
+      * Sets the period used by the WHOLE PWM module.
+      *
+      * @param period the desired period in microseconds.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if period is out of range
+      *
+      * Example:
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      *
+      * // period now is 20ms
+      * pwm->setPeriodUs(20000);
+      * @endcode
+      *
+      * @note Any changes to the period will AFFECT ALL CHANNELS.
+      */
+    int setPeriodUs(int period);
+
+    /**
+      * Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
+      *
+      * @param period the desired period in milliseconds.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if period is out of range
+      *
+      * Example:
+      * @code
+      * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+      *
+      * // period now is 20ms
+      * pwm->setPeriod(20);
+      * @endcode
+      */
+      int setPeriod(int period);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitAccelerometer.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,467 @@
+/*
+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_ACCELEROMETER_H
+#define MICROBIT_ACCELEROMETER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitCoordinateSystem.h"
+#include "MicroBitI2C.h"
+
+/**
+  * Relevant pin assignments
+  */
+#define MICROBIT_PIN_ACCEL_DATA_READY          P0_28
+
+/**
+  * Status flags
+  */
+#define MICROBIT_ACCEL_PITCH_ROLL_VALID           0x02
+#define MICROBIT_ACCEL_ADDED_TO_IDLE              0x04
+
+/**
+  * I2C constants
+  */
+#define MMA8653_DEFAULT_ADDR    0x3A
+
+/**
+  * MMA8653 Register map (partial)
+  */
+#define MMA8653_STATUS          0x00
+#define MMA8653_OUT_X_MSB       0x01
+#define MMA8653_WHOAMI          0x0D
+#define MMA8653_XYZ_DATA_CFG    0x0E
+#define MMA8653_CTRL_REG1       0x2A
+#define MMA8653_CTRL_REG2       0x2B
+#define MMA8653_CTRL_REG3       0x2C
+#define MMA8653_CTRL_REG4       0x2D
+#define MMA8653_CTRL_REG5       0x2E
+
+
+/**
+  * MMA8653 constants
+  */
+#define MMA8653_WHOAMI_VAL      0x5A
+
+#define MMA8653_SAMPLE_RANGES   3
+#define MMA8653_SAMPLE_RATES    8
+
+/**
+  * Accelerometer events
+  */
+#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE              1
+
+/**
+  * Gesture events
+  */
+#define MICROBIT_ACCELEROMETER_EVT_TILT_UP                  1
+#define MICROBIT_ACCELEROMETER_EVT_TILT_DOWN                2
+#define MICROBIT_ACCELEROMETER_EVT_TILT_LEFT                3
+#define MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT               4
+#define MICROBIT_ACCELEROMETER_EVT_FACE_UP                  5
+#define MICROBIT_ACCELEROMETER_EVT_FACE_DOWN                6
+#define MICROBIT_ACCELEROMETER_EVT_FREEFALL                 7
+#define MICROBIT_ACCELEROMETER_EVT_3G                       8
+#define MICROBIT_ACCELEROMETER_EVT_6G                       9
+#define MICROBIT_ACCELEROMETER_EVT_8G                       10
+#define MICROBIT_ACCELEROMETER_EVT_SHAKE                    11
+
+/**
+  * Gesture recogniser constants
+  */
+#define MICROBIT_ACCELEROMETER_REST_TOLERANCE               200
+#define MICROBIT_ACCELEROMETER_TILT_TOLERANCE               200
+#define MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE           400
+#define MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE              1000
+#define MICROBIT_ACCELEROMETER_3G_TOLERANCE                 3072
+#define MICROBIT_ACCELEROMETER_6G_TOLERANCE                 6144
+#define MICROBIT_ACCELEROMETER_8G_TOLERANCE                 8192
+#define MICROBIT_ACCELEROMETER_GESTURE_DAMPING              10
+#define MICROBIT_ACCELEROMETER_SHAKE_DAMPING                10
+
+#define MICROBIT_ACCELEROMETER_REST_THRESHOLD               (MICROBIT_ACCELEROMETER_REST_TOLERANCE * MICROBIT_ACCELEROMETER_REST_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD           (MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE * MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_3G_THRESHOLD                 (MICROBIT_ACCELEROMETER_3G_TOLERANCE * MICROBIT_ACCELEROMETER_3G_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_6G_THRESHOLD                 (MICROBIT_ACCELEROMETER_6G_TOLERANCE * MICROBIT_ACCELEROMETER_6G_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_8G_THRESHOLD                 (MICROBIT_ACCELEROMETER_8G_TOLERANCE * MICROBIT_ACCELEROMETER_8G_TOLERANCE)
+#define MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD        4
+
+struct MMA8653Sample
+{
+    int16_t         x;
+    int16_t         y;
+    int16_t         z;
+};
+
+struct MMA8653SampleRateConfig
+{
+    uint32_t        sample_period;
+    uint8_t         ctrl_reg1;
+};
+
+struct MMA8653SampleRangeConfig
+{
+    uint8_t         sample_range;
+    uint8_t         xyz_data_cfg;
+};
+
+
+extern const MMA8653SampleRangeConfig MMA8653SampleRange[];
+extern const MMA8653SampleRateConfig MMA8653SampleRate[];
+
+enum BasicGesture
+{
+    GESTURE_NONE,
+    GESTURE_UP,
+    GESTURE_DOWN,
+    GESTURE_LEFT,
+    GESTURE_RIGHT,
+    GESTURE_FACE_UP,
+    GESTURE_FACE_DOWN,
+    GESTURE_FREEFALL,
+    GESTURE_3G,
+    GESTURE_6G,
+    GESTURE_8G,
+    GESTURE_SHAKE
+};
+
+struct ShakeHistory
+{
+    uint16_t    shaken:1,
+                x:1,
+                y:1,
+                z:1,
+                count:4,
+                timer:8;
+};
+
+/**
+ * Class definition for MicroBit Accelerometer.
+ *
+ * Represents an implementation of the Freescale MMA8653 3 axis accelerometer
+ * Also includes basic data caching and on demand activation.
+ */
+class MicroBitAccelerometer : public MicroBitComponent
+{
+    uint16_t        address;            // I2C address of this accelerometer.
+    uint16_t        samplePeriod;       // The time between samples, in milliseconds.
+    uint8_t         sampleRange;        // The sample range of the accelerometer in g.
+    MMA8653Sample   sample;             // The last sample read.
+    DigitalIn       int1;               // Data ready interrupt.
+    float           pitch;              // Pitch of the device, in radians.
+    MicroBitI2C&    i2c;                // The I2C interface to use.
+    float           roll;               // Roll of the device, in radians.
+    uint8_t         sigma;              // the number of ticks that the instantaneous gesture has been stable.
+    BasicGesture    lastGesture;        // the last, stable gesture recorded.
+    BasicGesture    currentGesture;     // the instantaneous, unfiltered gesture detected.
+    ShakeHistory    shake;              // State information needed to detect shake events.
+
+    public:
+
+    /**
+      * Constructor.
+      * Create a software abstraction of an accelerometer.
+      *
+      * @param _i2c an instance of MicroBitI2C used to communicate with the onboard accelerometer.
+      *
+      * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR.
+      *
+      * @param id the unique EventModel id of this component. Defaults to: MICROBIT_ID_ACCELEROMETER
+      *
+      * @code
+      * MicroBitI2C i2c = MicroBitI2C(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c);
+      * @endcode
+     */
+    MicroBitAccelerometer(MicroBitI2C &_i2c, uint16_t address = MMA8653_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_ACCELEROMETER);
+
+    /**
+      * Configures the accelerometer for G range and sample rate defined
+      * in this object. The nearest values are chosen to those defined
+      * that are supported by the hardware. The instance variables are then
+      * updated to reflect reality.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
+      */
+    int configure();
+
+    /**
+      * Reads the acceleration data from the accelerometer, and stores it in our buffer.
+      * This only happens if the accelerometer indicates that it has new data via int1.
+      *
+      * On first use, this member function will attempt to add this component to the
+      * list of fiber components in order to constantly update the values stored
+      * by this object.
+      *
+      * This technique is called lazy instantiation, and it means that we do not
+      * obtain the overhead from non-chalantly adding this component to fiber components.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails.
+      */
+    int updateSample();
+
+    /**
+      * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
+      *
+      * @param period the requested time between samples, in milliseconds.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
+      *
+      * @code
+      * // sample rate is now 20 ms.
+      * accelerometer.setPeriod(20);
+      * @endcode
+      *
+      * @note The requested rate may not be possible on the hardware. In this case, the
+      * nearest lower rate is chosen.
+      */
+    int setPeriod(int period);
+
+    /**
+      * Reads the currently configured sample rate of the accelerometer.
+      *
+      * @return The time between samples, in milliseconds.
+      */
+    int getPeriod();
+
+    /**
+      * Attempts to set the sample range of the accelerometer to the specified value (in g).
+      *
+      * @param range The requested sample range of samples, in g.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
+      *
+      * @code
+      * // the sample range of the accelerometer is now 8G.
+      * accelerometer.setRange(8);
+      * @endcode
+      *
+      * @note The requested range may not be possible on the hardware. In this case, the
+      * nearest lower range is chosen.
+      */
+    int setRange(int range);
+
+    /**
+      * Reads the currently configured sample range of the accelerometer.
+      *
+      * @return The sample range, in g.
+      */
+    int getRange();
+
+    /**
+      * Attempts to read the 8 bit ID from the accelerometer, this can be used for
+      * validation purposes.
+      *
+      * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
+      *
+      * @code
+      * accelerometer.whoAmI();
+      * @endcode
+      */
+    int whoAmI();
+
+    /**
+      * Reads the value of the X axis from the latest update retrieved from the accelerometer.
+      *
+      * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+      *
+      * @return The force measured in the X axis, in milli-g.
+      *
+      * @code
+      * accelerometer.getX();
+      * @endcode
+      */
+    int getX(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
+      *
+      * @return The force measured in the Y axis, in milli-g.
+      *
+      * @code
+      * accelerometer.getY();
+      * @endcode
+      */
+    int getY(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
+      *
+      * @return The force measured in the Z axis, in milli-g.
+      *
+      * @code
+      * accelerometer.getZ();
+      * @endcode
+      */
+    int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
+      *
+      * @return The pitch of the device, in degrees.
+      *
+      * @code
+      * accelerometer.getPitch();
+      * @endcode
+      */
+    int getPitch();
+
+    /**
+      * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
+      *
+      * @return The pitch of the device, in radians.
+      *
+      * @code
+      * accelerometer.getPitchRadians();
+      * @endcode
+      */
+    float getPitchRadians();
+
+    /**
+      * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
+      *
+      * @return The roll of the device, in degrees.
+      *
+      * @code
+      * accelerometer.getRoll();
+      * @endcode
+      */
+    int getRoll();
+
+    /**
+      * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
+      *
+      * @return The roll of the device, in radians.
+      *
+      * @code
+      * accelerometer.getRollRadians();
+      * @endcode
+      */
+    float getRollRadians();
+
+    /**
+      * Retrieves the last recorded gesture.
+      *
+      * @return The last gesture that was detected.
+      *
+      * Example:
+      * @code
+      * MicroBitDisplay display;
+      *
+      * if (accelerometer.getGesture() == SHAKE)
+      *     display.scroll("SHAKE!");
+      * @endcode
+      */
+    BasicGesture getGesture();
+
+    /**
+      * A periodic callback invoked by the fiber scheduler idle thread.
+      *
+      * Internally calls updateSample().
+      */
+    virtual void idleTick();
+
+    /**
+      * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
+      *
+      * We check if any data is ready for reading by checking the interrupt flag on the accelerometer.
+      */
+    virtual int isIdleCallbackNeeded();
+
+    /**
+      * Destructor for MicroBitButton, where we deregister this instance from the array of fiber components.
+      */
+    ~MicroBitAccelerometer();
+
+    private:
+
+    /**
+      * Issues a standard, 2 byte I2C command write to the accelerometer.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the register to write to.
+      *
+      * @param value The value to write.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
+      */
+    int writeCommand(uint8_t reg, uint8_t value);
+
+    /**
+      * Issues a read command, copying data into the specified buffer.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the register to access.
+      *
+      * @param buffer Memory area to read the data into.
+      *
+      * @param length The number of bytes to read.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
+      */
+    int readCommand(uint8_t reg, uint8_t* buffer, int length);
+
+    /**
+      * Recalculate roll and pitch values for the current sample.
+      *
+      * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
+      *       heavyweight for a CPU without a floating point unit.
+      */
+    void recalculatePitchRoll();
+
+    /**
+      * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
+      * stability.
+      */
+    void updateGesture();
+
+    /**
+      * A service function.
+      * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
+      * It does not, however, square root the result, as this is a relatively high cost operation.
+      *
+      * This is left to application code should it be needed.
+      *
+      * @return the sum of the square of the acceleration of the device across all axes.
+      */
+    int instantaneousAccelerationSquared();
+
+    /**
+     * Service function.
+     * Determines a 'best guess' posture of the device based on instantaneous data.
+     *
+     * This makes no use of historic data, and forms this input to the filter implemented in updateGesture().
+     *
+     * @return A 'best guess' of the current posture of the device, based on instanataneous data.
+     */
+    BasicGesture instantaneousPosture();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitButton.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,145 @@
+/*
+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_BUTTON_H
+#define MICROBIT_BUTTON_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitEvent.h"
+
+#define MICROBIT_PIN_BUTTON_A                   P0_17
+#define MICROBIT_PIN_BUTTON_B                   P0_26
+#define MICROBIT_PIN_BUTTON_RESET               P0_19
+
+#define MICROBIT_BUTTON_EVT_DOWN                1
+#define MICROBIT_BUTTON_EVT_UP                  2
+#define MICROBIT_BUTTON_EVT_CLICK               3
+#define MICROBIT_BUTTON_EVT_LONG_CLICK          4
+#define MICROBIT_BUTTON_EVT_HOLD                5
+#define MICROBIT_BUTTON_EVT_DOUBLE_CLICK        6
+
+#define MICROBIT_BUTTON_LONG_CLICK_TIME         1000
+#define MICROBIT_BUTTON_HOLD_TIME               1500
+
+#define MICROBIT_BUTTON_STATE                   1
+#define MICROBIT_BUTTON_STATE_HOLD_TRIGGERED    2
+#define MICROBIT_BUTTON_STATE_CLICK             4
+#define MICROBIT_BUTTON_STATE_LONG_CLICK        8
+
+#define MICROBIT_BUTTON_SIGMA_MIN               0
+#define MICROBIT_BUTTON_SIGMA_MAX               12
+#define MICROBIT_BUTTON_SIGMA_THRESH_HI         8
+#define MICROBIT_BUTTON_SIGMA_THRESH_LO         2
+#define MICROBIT_BUTTON_DOUBLE_CLICK_THRESH     50
+
+enum MicroBitButtonEventConfiguration
+{
+    MICROBIT_BUTTON_SIMPLE_EVENTS,
+    MICROBIT_BUTTON_ALL_EVENTS
+};
+
+
+/**
+  * Class definition for MicroBit Button.
+  *
+  * Represents a single, generic button on the device.
+  */
+class MicroBitButton : public MicroBitComponent
+{
+    PinName name;                                           // mbed pin name for this button.
+    DigitalIn pin;                                          // The mbed object looking after this pin at any point in time (may change!).
+
+    unsigned long downStartTime;                            // used to store the current system clock when a button down event occurs
+    uint8_t sigma;                                          // integration of samples over time. We use this for debouncing, and noise tolerance for touch sensing
+    MicroBitButtonEventConfiguration eventConfiguration;    // Do we want to generate high level event (clicks), or defer this to another service.
+
+    public:
+
+    /**
+      * Constructor.
+      *
+      * Create a software representation of a button.
+      *
+      * @param name the physical pin on the processor that should be used as input.
+      *
+      * @param id the ID of the new MicroBitButton object.
+      *
+      * @param eventConfiguration Configures the events that will be generated by this MicroBitButton instance.
+      *                           Defaults to MICROBIT_BUTTON_ALL_EVENTS.
+      *
+      * @param mode the configuration of internal pullups/pulldowns, as defined in the mbed PinMode class. PullNone by default.
+      *
+      * @code
+      * buttonA(MICROBIT_PIN_BUTTON_A, MICROBIT_ID_BUTTON_A);
+      * @endcode
+      */
+    MicroBitButton(PinName name, uint16_t id, MicroBitButtonEventConfiguration eventConfiguration = MICROBIT_BUTTON_ALL_EVENTS, PinMode mode = PullNone);
+
+    /**
+      * Tests if this Button is currently pressed.
+      *
+      * @code
+      * if(buttonA.isPressed())
+      *     display.scroll("Pressed!");
+      * @endcode
+      *
+      * @return 1 if this button is pressed, 0 otherwise.
+      */
+    int isPressed();
+
+    /**
+      * Changes the event configuration used by this button to the given MicroBitButtonEventConfiguration.
+      *
+      * All subsequent events generated by this button will then be informed by this configuraiton.
+      *
+      * @param config The new configuration for this button. Legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS.
+      *
+      * Example:
+      * @code
+      * // Configure a button to generate all possible events.
+      * buttonA.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS);
+      *
+      * // Configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events.
+      * buttonA.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS);
+      * @endcode
+      */
+    void setEventConfiguration(MicroBitButtonEventConfiguration config);
+
+    /**
+      * periodic callback from MicroBit system timer.
+      *
+      * Check for state change for this button, and fires various events on a state change.
+      */
+    virtual void systemTick();
+
+    /**
+      * Destructor for MicroBitButton, where we deregister this instance from the array of fiber components.
+      */
+    ~MicroBitButton();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitCompass.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,518 @@
+/*
+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_COMPASS_H
+#define MICROBIT_COMPASS_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitCoordinateSystem.h"
+#include "MicroBitAccelerometer.h"
+#include "MicroBitStorage.h"
+
+/**
+  * Relevant pin assignments
+  */
+#define MICROBIT_PIN_COMPASS_DATA_READY          P0_29
+
+/**
+  * I2C constants
+  */
+#define MAG3110_DEFAULT_ADDR    0x1D
+
+/**
+  * MAG3110 Register map
+  */
+#define MAG_DR_STATUS 0x00
+#define MAG_OUT_X_MSB 0x01
+#define MAG_OUT_X_LSB 0x02
+#define MAG_OUT_Y_MSB 0x03
+#define MAG_OUT_Y_LSB 0x04
+#define MAG_OUT_Z_MSB 0x05
+#define MAG_OUT_Z_LSB 0x06
+#define MAG_WHOAMI    0x07
+#define MAG_SYSMOD    0x08
+#define MAG_OFF_X_MSB 0x09
+#define MAG_OFF_X_LSB 0x0A
+#define MAG_OFF_Y_MSB 0x0B
+#define MAG_OFF_Y_LSB 0x0C
+#define MAG_OFF_Z_MSB 0x0D
+#define MAG_OFF_Z_LSB 0x0E
+#define MAG_DIE_TEMP  0x0F
+#define MAG_CTRL_REG1 0x10
+#define MAG_CTRL_REG2 0x11
+
+/**
+  * Configuration options
+  */
+struct MAG3110SampleRateConfig
+{
+    uint32_t        sample_period;
+    uint8_t         ctrl_reg1;
+};
+
+extern const MAG3110SampleRateConfig MAG3110SampleRate[];
+
+#define MAG3110_SAMPLE_RATES                    11
+
+/**
+  * Compass events
+  */
+#define MICROBIT_COMPASS_EVT_CAL_REQUIRED       1               // DEPRECATED
+#define MICROBIT_COMPASS_EVT_CAL_START          2               // DEPRECATED
+#define MICROBIT_COMPASS_EVT_CAL_END            3               // DEPRECATED
+
+#define MICROBIT_COMPASS_EVT_DATA_UPDATE        4
+#define MICROBIT_COMPASS_EVT_CONFIG_NEEDED      5
+#define MICROBIT_COMPASS_EVT_CALIBRATE          6
+
+/**
+  * Status Bits
+  */
+#define MICROBIT_COMPASS_STATUS_CALIBRATED      2
+#define MICROBIT_COMPASS_STATUS_CALIBRATING     4
+#define MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE   8
+
+/**
+  * Term to convert sample data into SI units
+  */
+#define MAG3110_NORMALIZE_SAMPLE(x) (100*x)
+
+/**
+  * MAG3110 MAGIC ID value
+  * Returned from the MAG_WHO_AM_I register for ID purposes.
+  */
+#define MAG3110_WHOAMI_VAL 0xC4
+
+struct CompassSample
+{
+    int     x;
+    int     y;
+    int     z;
+
+    CompassSample()
+    {
+        this->x = 0;
+        this->y = 0;
+        this->z = 0;
+    }
+
+    CompassSample(int x, int y, int z)
+    {
+        this->x = x;
+        this->y = y;
+        this->z = z;
+    }
+
+    bool operator==(const CompassSample& other) const
+    {
+        return x == other.x && y == other.y && z == other.z;
+    }
+
+    bool operator!=(const CompassSample& other) const
+    {
+        return !(x == other.x && y == other.y && z == other.z);
+    }
+};
+
+/**
+  * Class definition for MicroBit Compass.
+  *
+  * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer.
+  * Also includes basic caching, calibration and on demand activation.
+  */
+class MicroBitCompass : public MicroBitComponent
+{
+    uint16_t                address;                  // I2C address of the magnetmometer.
+    uint16_t                samplePeriod;             // The time between samples, in millseconds.
+
+    CompassSample           average;                  // Centre point of sample data.
+    CompassSample           sample;                   // The latest sample data recorded.
+    DigitalIn               int1;                     // Data ready interrupt.
+    MicroBitI2C&		    i2c;                      // The I2C interface the sensor is connected to.
+    MicroBitAccelerometer*  accelerometer;            // The accelerometer to use for tilt compensation.
+    MicroBitStorage*        storage;                  // An instance of MicroBitStorage used for persistence.
+
+    public:
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
+      *
+      * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitAccelerometer accelerometer(i2c);
+      *
+      * MicroBitStorage storage;
+      *
+      * MicroBitCompass compass(i2c, accelerometer, storage);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, MicroBitStorage& _storage, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitAccelerometer accelerometer(i2c);
+      *
+      * MicroBitCompass compass(i2c, accelerometer, storage);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitStorage storage;
+      *
+      * MicroBitCompass compass(i2c, storage);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, MicroBitStorage& _storage, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitCompass compass(i2c);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Configures the compass for the sample rate defined in this object.
+      * The nearest values are chosen to those defined that are supported by the hardware.
+      * The instance variables are then updated to reflect reality.
+      *
+      * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be configured.
+      */
+    int configure();
+
+    /**
+      * Attempts to set the sample rate of the compass to the specified value (in ms).
+      *
+      * @param period the requested time between samples, in milliseconds.
+      *
+      * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
+      *
+      * @code
+      * // sample rate is now 20 ms.
+      * compass.setPeriod(20);
+      * @endcode
+      *
+      * @note The requested rate may not be possible on the hardware. In this case, the
+      * nearest lower rate is chosen.
+      */
+    int setPeriod(int period);
+
+    /**
+      * Reads the currently configured sample rate of the compass.
+      *
+      * @return The time between samples, in milliseconds.
+      */
+    int getPeriod();
+
+    /**
+      * Gets the current heading of the device, relative to magnetic north.
+      *
+      * If the compass is not calibrated, it will raise the MICROBIT_COMPASS_EVT_CALIBRATE event.
+      *
+      * Users wishing to implement their own calibration algorithms should listen for this event,
+      * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before
+      * the user program continues.
+      *
+      * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating.
+      *
+      * @code
+      * compass.heading();
+      * @endcode
+      */
+    int heading();
+
+    /**
+      * Attempts to read the 8 bit ID from the magnetometer, this can be used for
+      * validation purposes.
+      *
+      * @return the 8 bit ID returned by the magnetometer, or MICROBIT_I2C_ERROR if the request fails.
+      *
+      * @code
+      * compass.whoAmI();
+      * @endcode
+      */
+    int whoAmI();
+
+    /**
+      * Reads the value of the X axis from the latest update retrieved from the magnetometer.
+      *
+      * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+      *
+      * @return The magnetic force measured in the X axis, in nano teslas.
+      *
+      * @code
+      * compass.getX();
+      * @endcode
+      */
+    int getX(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Reads the value of the Y axis from the latest update retrieved from the magnetometer.
+      *
+      * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+      *
+      * @return The magnetic force measured in the Y axis, in nano teslas.
+      *
+      * @code
+      * compass.getY();
+      * @endcode
+      */
+    int getY(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Reads the value of the Z axis from the latest update retrieved from the magnetometer.
+      *
+      * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+      *
+      * @return The magnetic force measured in the Z axis, in nano teslas.
+      *
+      * @code
+      * compass.getZ();
+      * @endcode
+      */
+    int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Determines the overall magnetic field strength based on the latest update from the magnetometer.
+      *
+      * @return The magnetic force measured across all axis, in nano teslas.
+      *
+      * @code
+      * compass.getFieldStrength();
+      * @endcode
+      */
+    int getFieldStrength();
+
+    /**
+      * Reads the current die temperature of the compass.
+      *
+      * @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the temperature reading could not be retreived
+      *         from the accelerometer.
+      */
+    int readTemperature();
+
+    /**
+      * Perform a calibration of the compass.
+      *
+      * This method will be called automatically if a user attempts to read a compass value when
+      * the compass is uncalibrated. It can also be called at any time by the user.
+      *
+      * The method will only return once the compass has been calibrated.
+      *
+      * @return MICROBIT_OK, MICROBIT_I2C_ERROR if the magnetometer could not be accessed,
+      * or MICROBIT_CALIBRATION_REQUIRED if the calibration algorithm failed to complete successfully.
+      *
+      * @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
+      */
+    int calibrate();
+
+    /**
+      * Configure the compass to use the calibration data that is supplied to this call.
+      *
+      * Calibration data is comprised of the perceived zero offset of each axis of the compass.
+      *
+      * After calibration this should now take into account trimming errors in the magnetometer,
+      * and any "hard iron" offsets on the device.
+      *
+      * @param calibration A CompassSample containing the offsets for the x, y and z axis.
+      */
+    void setCalibration(CompassSample calibration);
+
+    /**
+      * Provides the calibration data currently in use by the compass.
+      *
+      * More specifically, the x, y and z zero offsets of the compass.
+      *
+      * @return calibration A CompassSample containing the offsets for the x, y and z axis.
+      */
+    CompassSample getCalibration();
+
+    /**
+      * Updates the local sample, only if the compass indicates that
+      * data is stale.
+      *
+      * @note Can be used to trigger manual updates, if the device is running without a scheduler.
+      *       Also called internally by all get[X,Y,Z]() member functions.
+      */
+    int updateSample();
+
+    /**
+      * Periodic callback from MicroBit idle thread.
+      *
+      * Calls updateSample().
+      */
+    virtual void idleTick();
+
+    /**
+      * Returns 0 or 1. 1 indicates that the compass is calibrated, zero means the compass requires calibration.
+      */
+    int isCalibrated();
+
+    /**
+      * Returns 0 or 1. 1 indicates that the compass is calibrating, zero means the compass is not currently calibrating.
+      */
+    int isCalibrating();
+
+    /**
+      * Clears the calibration held in persistent storage, and sets the calibrated flag to zero.
+      */
+    void clearCalibration();
+
+    /**
+      * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
+      */
+    virtual int isIdleCallbackNeeded();
+
+    /**
+      * Destructor for MicroBitCompass, where we deregister this instance from the array of fiber components.
+      */
+    ~MicroBitCompass();
+
+    private:
+
+    /**
+      * Issues a standard, 2 byte I2C command write to the accelerometer.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the register to write to.
+      *
+      * @param value The value to write.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
+      */
+    int writeCommand(uint8_t reg, uint8_t value);
+
+    /**
+      * Issues a read command, copying data into the specified buffer.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the register to access.
+      *
+      * @param buffer Memory area to read the data into.
+      *
+      * @param length The number of bytes to read.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
+      */
+    int readCommand(uint8_t reg, uint8_t* buffer, int length);
+
+    /**
+      * Issues a read of a given address, and returns the value.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the 16 bit register to access.
+      *
+      * @return The register value, interpreted as a 16 but signed value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
+      */
+    int read16(uint8_t reg);
+
+    /**
+      * Issues a read of a given address, and returns the value.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the 16 bit register to access.
+      *
+      * @return The register value, interpreted as a 8 bit unsigned value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
+      */
+    int read8(uint8_t reg);
+
+    /**
+      * Calculates a tilt compensated bearing of the device, using the accelerometer.
+      */
+    int tiltCompensatedBearing();
+
+    /**
+      * Calculates a non-tilt compensated bearing of the device.
+      */
+    int basicBearing();
+
+    /**
+      * An initialisation member function used by the many constructors of MicroBitCompass.
+      *
+      * @param id the unique identifier for this compass instance.
+      *
+      * @param address the base address of the magnetometer on the i2c bus.
+      */
+    void init(uint16_t id, uint16_t address);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitCompassCalibrator.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,84 @@
+/*
+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_COMPASS_CALIBRATOR_H
+#define MICROBIT_COMPASS_CALIBRATOR_H
+
+#include "MicroBitConfig.h"
+#include "MicroBitCompass.h"
+#include "MicroBitAccelerometer.h"
+#include "MicroBitDisplay.h"
+
+
+/**
+  * Class definition for an interactive compass calibration algorithm.
+  *
+  * The algorithm uses an accelerometer to ensure that a broad range of sample data has been gathered
+  * from the compass module, then performs a least mean squares optimisation of the
+  * results to determine the calibration data for the compass.
+  *
+  * The LED matrix display is used to provide feedback to the user on the gestures required.
+  *
+  * This class listens for calibration requests from the compass (on the default event model),
+  * and automatically initiates a calibration sequence as necessary.
+  */
+class MicroBitCompassCalibrator
+{
+    MicroBitCompass&        compass;
+    MicroBitAccelerometer&  accelerometer;
+    MicroBitDisplay&        display;
+
+    public:
+
+    /**
+      * Constructor.
+      *
+      * Create an object capable of calibrating the compass.
+      *
+      * The algorithm uses an accelerometer to ensure that a broad range of sample data has been gathered
+      * from the compass module, then performs a least mean squares optimisation of the
+      * results to determine the calibration data for the compass.
+      *
+      * The LED matrix display is used to provide feedback to the user on the gestures required.
+      *
+      * @param compass The compass instance to calibrate.
+      *
+      * @param accelerometer The accelerometer to gather contextual data from.
+      *
+      * @param display The LED matrix to display user feedback on.
+      */
+    MicroBitCompassCalibrator(MicroBitCompass& _compass, MicroBitAccelerometer& _accelerometer, MicroBitDisplay& _display);
+
+    /**
+      * Performs a simple game that in parallel, calibrates the compass.
+      *
+      * This function is executed automatically when the user requests a compass bearing, and compass calibration is required.
+      *
+      * This function is, by design, synchronous and only returns once calibration is complete.
+      */
+    void calibrate(MicroBitEvent);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitDisplay.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,639 @@
+/*
+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_DISPLAY_H
+#define MICROBIT_DISPLAY_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "ManagedString.h"
+#include "MicroBitComponent.h"
+#include "MicroBitImage.h"
+#include "MicroBitFont.h"
+#include "MicroBitMatrixMaps.h"
+#include "MicroBitLightSensor.h"
+
+/**
+  * Event codes raised by MicroBitDisplay
+  */
+#define MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE         1
+#define MICROBIT_DISPLAY_EVT_LIGHT_SENSE                2
+
+//
+// Internal constants
+//
+
+#define MICROBIT_DISPLAY_SPACING                1
+#define MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH    8
+#define MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS    -255
+
+enum AnimationMode {
+    ANIMATION_MODE_NONE,
+    ANIMATION_MODE_STOPPED,
+    ANIMATION_MODE_SCROLL_TEXT,
+    ANIMATION_MODE_PRINT_TEXT,
+    ANIMATION_MODE_SCROLL_IMAGE,
+    ANIMATION_MODE_ANIMATE_IMAGE,
+    ANIMATION_MODE_PRINT_CHARACTER
+};
+
+enum DisplayMode {
+    DISPLAY_MODE_BLACK_AND_WHITE,
+    DISPLAY_MODE_GREYSCALE,
+    DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE
+};
+
+enum DisplayRotation {
+    MICROBIT_DISPLAY_ROTATION_0,
+    MICROBIT_DISPLAY_ROTATION_90,
+    MICROBIT_DISPLAY_ROTATION_180,
+    MICROBIT_DISPLAY_ROTATION_270
+};
+
+/**
+  * Class definition for MicroBitDisplay.
+  *
+  * A MicroBitDisplay represents the LED matrix array on the micro:bit.
+  */
+class MicroBitDisplay : public MicroBitComponent
+{
+    uint8_t width;
+    uint8_t height;
+    uint8_t brightness;
+    uint8_t strobeRow;
+    uint8_t rotation;
+    uint8_t mode;
+    uint8_t greyscaleBitMsk;
+    uint8_t timingCount;
+    uint32_t col_mask;
+
+    Timeout renderTimer;
+    PortOut *LEDMatrix;
+
+    //
+    // State used by all animation routines.
+    //
+
+    // The animation mode that's currently running (if any)
+    volatile AnimationMode animationMode;
+
+    // The time in milliseconds between each frame update.
+    uint16_t animationDelay;
+
+    // The time in milliseconds since the frame update.
+    uint16_t animationTick;
+
+    // Stop playback of any animations
+    void stopAnimation(int delay);
+
+    //
+    // State for scrollString() method.
+    // This is a surprisingly intricate method.
+    //
+    // The text being displayed.
+    ManagedString scrollingText;
+
+    // The index of the character currently being displayed.
+    uint16_t scrollingChar;
+
+    // The number of pixels the current character has been shifted on the display.
+    uint8_t scrollingPosition;
+
+    //
+    // State for printString() method.
+    //
+    // The text being displayed. NULL if no message is scheduled for playback.
+    // We *could* get some reuse in here with the scroll* variables above,
+    // but best to keep it clean in case kids try concurrent operation (they will!),
+    // given the small RAM overhead needed to maintain orthogonality.
+    ManagedString printingText;
+
+    // The index of the character currently being displayed.
+    uint16_t printingChar;
+
+    //
+    // State for scrollImage() method.
+    //
+    // The image being displayed.
+    MicroBitImage scrollingImage;
+
+    // The number of pixels the image has been shifted on the display.
+    int16_t scrollingImagePosition;
+
+    // The number of pixels the image is shifted on the display in each quantum.
+    int8_t scrollingImageStride;
+
+    // A pointer to an instance of light sensor, if in use
+    MicroBitLightSensor* lightSensor;
+
+    // Flag to indicate if image has been rendered to screen yet (or not)
+    bool scrollingImageRendered;
+
+    const MatrixMap &matrixMap;
+
+    // Internal methods to handle animation.
+
+    /**
+      *  Periodic callback, that we use to perform any animations we have running.
+      */
+    void animationUpdate();
+
+    /**
+      *  Called by the display in an interval determined by the brightness of the display, to give an impression
+      *  of brightness.
+      */
+    void renderFinish();
+
+    /**
+      * Translates a bit mask to a bit mask suitable for the nrf PORT0 and PORT1.
+      * Brightness has two levels on, or off.
+      */
+    void render();
+
+    /**
+      * Renders the current image, and drops the fourth frame to allow for
+      * sensors that require the display to operate.
+      */
+    void renderWithLightSense();
+
+    /**
+      * Translates a bit mask into a timer interrupt that gives the appearence of greyscale.
+      */
+    void renderGreyscale();
+
+    /**
+      * Internal scrollText update method.
+      * Shift the screen image by one pixel to the left. If necessary, paste in the next char.
+      */
+    void updateScrollText();
+
+    /**
+      * Internal printText update method.
+      * Paste the next character in the string.
+      */
+    void updatePrintText();
+
+    /**
+      * Internal scrollImage update method.
+      * Paste the stored bitmap at the appropriate point.
+      */
+    void updateScrollImage();
+
+    /**
+      * Internal animateImage update method.
+      * Paste the stored bitmap at the appropriate point and stop on the last frame.
+      */
+    void updateAnimateImage();
+
+    /**
+     * Broadcasts an event onto the defult EventModel indicating that the
+     * current animation has completed.
+     */
+    void sendAnimationCompleteEvent();
+
+    /**
+      * Blocks the current fiber until the display is available (i.e. does not effect is being displayed).
+      * Animations are queued until their time to display.
+      */
+    void waitForFreeDisplay();
+
+    /**
+      * Blocks the current fiber until the current animation has finished.
+      * If the scheduler is not running, this call will essentially perform a spinning wait.
+      */
+    void fiberWait();
+
+    /**
+      * Enables or disables the display entirely, and releases the pins for other uses.
+      *
+      * @param enableDisplay true to enabled the display, or false to disable it.
+      */
+    void setEnable(bool enableDisplay);
+
+public:
+    // The mutable bitmap buffer being rendered to the LED matrix.
+    MicroBitImage image;
+
+    /**
+      * Constructor.
+      *
+      * Create a software representation the micro:bit's 5x5 LED matrix.
+      * The display is initially blank.
+      *
+      * @param id The id the display should use when sending events on the MessageBus. Defaults to MICROBIT_ID_DISPLAY.
+      *
+      * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates.
+      *            Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * @endcode
+      */
+    MicroBitDisplay(uint16_t id = MICROBIT_ID_DISPLAY, const MatrixMap &map = microbitMatrixMap);
+
+    /**
+      * Stops any currently running animation, and any that are waiting to be displayed.
+      */
+    void stopAnimation();
+
+    /**
+      * Frame update method, invoked periodically to strobe the display.
+      */
+    virtual void systemTick();
+
+    /**
+      * Prints the given character to the display, if it is not in use.
+      *
+      * @param c The character to display.
+      *
+      * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever,
+      *              or until the Displays next use.
+      *
+      * @return MICROBIT_OK, MICROBIT_BUSY is the screen is in use, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * display.printAsync('p');
+      * display.printAsync('p',100);
+      * @endcode
+      */
+    int printCharAsync(char c, int delay = 0);
+
+    /**
+      * Prints the given ManagedString to the display, one character at a time.
+      * Returns immediately, and executes the animation asynchronously.
+      *
+      * @param s The string to display.
+      *
+      * @param delay The time to delay between characters, in milliseconds. Must be > 0.
+      *              Defaults to: MICROBIT_DEFAULT_PRINT_SPEED.
+      *
+      * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * display.printAsync("abc123",400);
+      * @endcode
+      */
+    int printAsync(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
+
+    /**
+      * Prints the given image to the display, if the display is not in use.
+      * Returns immediately, and executes the animation asynchronously.
+      *
+      * @param i The image to display.
+      *
+      * @param x The horizontal position on the screen to display the image. Defaults to 0.
+      *
+      * @param y The vertical position on the screen to display the image. Defaults to 0.
+      *
+      * @param alpha Treats the brightness level '0' as transparent. Defaults to 0.
+      *
+      * @param delay The time to delay between characters, in milliseconds. Defaults to 0.
+      *
+      * @code
+      * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+      * display.print(i,400);
+      * @endcode
+      */
+    int printAsync(MicroBitImage i, int x = 0, int y = 0, int alpha = 0, int delay = 0);
+
+    /**
+      * Prints the given character to the display.
+      *
+      * @param c The character to display.
+      *
+      * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever,
+      *              or until the Displays next use.
+      *
+      * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * display.printAsync('p');
+      * display.printAsync('p',100);
+      * @endcode
+      */
+    int printChar(char c, int delay = 0);
+
+    /**
+      * Prints the given string to the display, one character at a time.
+      *
+      * Blocks the calling thread until all the text has been displayed.
+      *
+      * @param s The string to display.
+      *
+      * @param delay The time to delay between characters, in milliseconds. Defaults
+      *              to: MICROBIT_DEFAULT_PRINT_SPEED.
+      *
+      * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * display.print("abc123",400);
+      * @endcode
+      */
+    int print(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
+
+    /**
+      * Prints the given image to the display.
+      * Blocks the calling thread until all the image has been displayed.
+      *
+      * @param i The image to display.
+      *
+      * @param x The horizontal position on the screen to display the image. Defaults to 0.
+      *
+      * @param y The vertical position on the screen to display the image. Defaults to 0.
+      *
+      * @param alpha Treats the brightness level '0' as transparent. Defaults to 0.
+      *
+      * @param delay The time to display the image for, or zero to show the image forever. Defaults to 0.
+      *
+      * @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+      * display.print(i,400);
+      * @endcode
+      */
+    int print(MicroBitImage i, int x = 0, int y = 0, int alpha = 0, int delay = 0);
+
+    /**
+      * Scrolls the given string to the display, from right to left.
+      * Returns immediately, and executes the animation asynchronously.
+      *
+      * @param s The string to display.
+      *
+      * @param delay The time to delay between characters, in milliseconds. Defaults
+      *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+      *
+      * @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * display.scrollAsync("abc123",100);
+      * @endcode
+      */
+    int scrollAsync(ManagedString s, int delay = MICROBIT_DEFAULT_SCROLL_SPEED);
+
+    /**
+      * Scrolls the given image across the display, from right to left.
+      * Returns immediately, and executes the animation asynchronously.
+      *
+      * @param image The image to display.
+      *
+      * @param delay The time between updates, in milliseconds. Defaults
+      *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+      *
+      * @param stride The number of pixels to shift by in each update. Defaults to MICROBIT_DEFAULT_SCROLL_STRIDE.
+      *
+      * @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+      * display.scrollAsync(i,100,1);
+      * @endcode
+      */
+    int scrollAsync(MicroBitImage image, int delay = MICROBIT_DEFAULT_SCROLL_SPEED, int stride = MICROBIT_DEFAULT_SCROLL_STRIDE);
+
+    /**
+      * Scrolls the given string across the display, from right to left.
+      * Blocks the calling thread until all text has been displayed.
+      *
+      * @param s The string to display.
+      *
+      * @param delay The time to delay between characters, in milliseconds. Defaults
+      *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+      *
+      * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * display.scroll("abc123",100);
+      * @endcode
+      */
+    int scroll(ManagedString s, int delay = MICROBIT_DEFAULT_SCROLL_SPEED);
+
+    /**
+      * Scrolls the given image across the display, from right to left.
+      * Blocks the calling thread until all the text has been displayed.
+      *
+      * @param image The image to display.
+      *
+      * @param delay The time between updates, in milliseconds. Defaults
+      *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+      *
+      * @param stride The number of pixels to shift by in each update. Defaults to MICROBIT_DEFAULT_SCROLL_STRIDE.
+      *
+      * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+      * display.scroll(i,100,1);
+      * @endcode
+      */
+    int scroll(MicroBitImage image, int delay = MICROBIT_DEFAULT_SCROLL_SPEED, int stride = MICROBIT_DEFAULT_SCROLL_STRIDE);
+
+    /**
+      * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation.
+      * Returns immediately.
+      *
+      * @param image The image to display.
+      *
+      * @param delay The time to delay between each update of the display, in milliseconds.
+      *
+      * @param stride The number of pixels to shift by in each update.
+      *
+      * @param startingPosition the starting position on the display for the animation
+      *                         to begin at. Defaults to MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS.
+      *
+      * @return MICROBIT_OK, MICROBIT_BUSY if the screen is in use, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * const int heart_w = 10;
+      * const int heart_h = 5;
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, };
+      *
+      * MicroBitImage i(heart_w,heart_h,heart);
+      * display.animateAsync(i,100,5);
+      * @endcode
+      */
+    int animateAsync(MicroBitImage image, int delay, int stride, int startingPosition = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS);
+
+    /**
+      * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation.
+      * Blocks the calling thread until the animation is complete.
+      *
+      *
+      * @param delay The time to delay between each update of the display, in milliseconds.
+      *
+      * @param stride The number of pixels to shift by in each update.
+      *
+      * @param startingPosition the starting position on the display for the animation
+      *                         to begin at. Defaults to MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS.
+      *
+      * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * const int heart_w = 10;
+      * const int heart_h = 5;
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, };
+      *
+      * MicroBitImage i(heart_w,heart_h,heart);
+      * display.animate(i,100,5);
+      * @endcode
+      */
+    int animate(MicroBitImage image, int delay, int stride, int startingPosition = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS);
+
+    /**
+      * Configures the brightness of the display.
+      *
+      * @param b The brightness to set the brightness to, in the range 0 - 255.
+      *
+      * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER
+      *
+      * @code
+      * display.setBrightness(255); //max brightness
+      * @endcode
+      */
+    int setBrightness(int b);
+
+    /**
+      * Configures the mode of the display.
+      *
+      * @param mode The mode to swap the display into. One of: DISPLAY_MODE_GREYSCALE,
+      *             DISPLAY_MODE_BLACK_AND_WHITE, DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE
+      *
+      * @code
+      * display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness
+      * @endcode
+      */
+    void setDisplayMode(DisplayMode mode);
+
+    /**
+      * Retrieves the mode of the display.
+      *
+      * @return the current mode of the display
+      */
+    int getDisplayMode();
+
+    /**
+      * Fetches the current brightness of this display.
+      *
+      * @return the brightness of this display, in the range 0..255.
+      *
+      * @code
+      * display.getBrightness(); //the current brightness
+      * @endcode
+      */
+    int getBrightness();
+
+    /**
+      * Rotates the display to the given position.
+      *
+      * Axis aligned values only.
+      *
+      * @code
+      * display.rotateTo(MICROBIT_DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation
+      * @endcode
+      */
+    void rotateTo(DisplayRotation position);
+
+    /**
+      * Enables the display, should only be called if the display is disabled.
+      *
+      * @code
+      * display.enable(); //Enables the display mechanics
+      * @endcode
+      *
+      * @note Only enables the display if the display is currently disabled.
+      */
+    void enable();
+
+    /**
+      * Disables the display, which releases control of the GPIO pins used by the display,
+      * which are exposed on the edge connector.
+      *
+      * @code
+      * display.disable(); //disables the display
+      * @endcode
+      *
+      * @note Only disables the display if the display is currently enabled.
+      */
+    void disable();
+
+    /**
+      * Clears the display of any remaining pixels.
+      *
+      * `display.image.clear()` can also be used!
+      *
+      * @code
+      * display.clear(); //clears the display
+      * @endcode
+      */
+    void clear();
+
+    /**
+      * Updates the font that will be used for display operations.
+	  *
+      * @param font the new font that will be used to render characters.
+      *
+      * @note DEPRECATED! Please use MicroBitFont::setSystemFont() instead.
+      */
+    void setFont(MicroBitFont font);
+
+    /**
+      * Retrieves the font object used for rendering characters on the display.
+	  *
+      * @note DEPRECATED! Please use MicroBitFont::getSystemFont() instead.
+      */
+    MicroBitFont getFont();
+
+    /**
+      * Captures the bitmap currently being rendered on the display.
+      *
+      * @return a MicroBitImage containing the captured data.
+      */
+    MicroBitImage screenShot();
+
+    /**
+      * Gives a representative figure of the light level in the current environment
+      * where are micro:bit is situated.
+      *
+      * Internally, it constructs an instance of a MicroBitLightSensor if not already configured
+      * and sets the display mode to DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE.
+      *
+      * This also changes the tickPeriod to MICROBIT_LIGHT_SENSOR_TICK_SPEED so
+      * that the display does not suffer from artifacts.
+      *
+      * @return an indicative light level in the range 0 - 255.
+      *
+      * @note this will return 0 on the first call to this method, a light reading
+      * will be available after the display has activated the light sensor for the
+      * first time.
+      */
+    int readLightLevel();
+
+    /**
+      * Destructor for MicroBitDisplay, where we deregister this instance from the array of system components.
+      */
+    ~MicroBitDisplay();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitI2C.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,107 @@
+/*
+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_I2C_H
+#define MICROBIT_I2C_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+
+#define MICROBIT_I2C_MAX_RETRIES 9
+
+/**
+  * Class definition for MicroBitI2C.
+  *
+  * Presents a wrapped mbed call to capture failed I2C operations caused by a known silicon bug in the nrf51822.
+  * Attempts to automatically reset and restart the I2C hardware if this case is detected.
+  *
+  * For reference see PAN56 in:
+  *
+  * https://www.nordicsemi.com/eng/nordic/Products/nRF51822/PAN-nRF51822/24634
+  *
+  * v2.0 through to v2.4
+  */
+class MicroBitI2C : public I2C
+{
+    uint8_t retries;
+
+    public:
+
+    /**
+      * Constructor.
+      *
+      * Create an instance of MicroBitI2C for I2C communication.
+      *
+      * @param sda the Pin to be used for SDA
+      *
+      * @param scl the Pin to be used for SCL
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      * @endcode
+      *
+      * @note This class presents a wrapped mbed call to capture failed I2C operations caused by a known silicon bug in the nrf51822.
+      * Attempts to automatically reset and restart the I2C hardware if this case is detected.
+      *
+      * For reference see PAN56 in:
+      *
+      * https://www.nordicsemi.com/eng/nordic/Products/nRF51822/PAN-nRF51822/24634
+      *
+      * v2.0 through to v2.4
+      */
+    MicroBitI2C(PinName sda, PinName scl);
+
+    /**
+      * Performs a complete read transaction. The bottom bit of the address is forced to 1 to indicate a read.
+      *
+      * @param address 8-bit I2C slave address [ addr | 1 ]
+      *
+      * @param data A pointer to a byte buffer used for storing retrieved data.
+      *
+      * @param length Number of bytes to read.
+      *
+      * @param repeated if true, stop is not sent at the end. Defaults to false.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved read failure is detected.
+      */
+    int read(int address, char *data, int length, bool repeated = false);
+
+    /**
+      * Performs a complete write transaction. The bottom bit of the address is forced to 0 to indicate a write.
+      *
+      * @param address 8-bit I2C slave address [ addr | 0 ]
+      *
+      * @param data A pointer to a byte buffer containing the data to write.
+      *
+      * @param length Number of bytes to write
+      *
+      * @param repeated if true, stop is not sent at the end. Defaults to false.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved write failure is detected.
+      */
+    int write(int address, const char *data, int length, bool repeated = false);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitIO.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,81 @@
+/*
+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_IO_H
+#define MICROBIT_IO_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitPin.h"
+
+/**
+  * Class definition for MicroBit IO.
+  *
+  * Represents a collection of all I/O pins on the edge connector.
+  */
+class MicroBitIO
+{
+    public:
+
+	MicroBitPin			 pin[0];
+	MicroBitPin          P0;
+    MicroBitPin          P1;
+    MicroBitPin          P2;
+    MicroBitPin          P3;
+    MicroBitPin          P4;
+    MicroBitPin          P5;
+    MicroBitPin          P6;
+    MicroBitPin          P7;
+    MicroBitPin          P8;
+    MicroBitPin          P9;
+    MicroBitPin          P10;
+    MicroBitPin          P11;
+    MicroBitPin          P12;
+    MicroBitPin          P13;
+    MicroBitPin          P14;
+    MicroBitPin          P15;
+    MicroBitPin          P16;
+    MicroBitPin          P19;
+    MicroBitPin          P20;
+
+    /**
+      * Constructor.
+      *
+      * Create a representation of all given I/O pins on the edge connector
+      *
+      * Accepts a sequence of unique ID's used to distinguish events raised
+      * by MicroBitPin instances on the default EventModel.
+      */
+    MicroBitIO(int ID_P0, int ID_P1, int ID_P2,
+               int ID_P3, int ID_P4, int ID_P5,
+               int ID_P6, int ID_P7, int ID_P8,
+               int ID_P9, int ID_P10,int ID_P11,
+               int ID_P12,int ID_P13,int ID_P14,
+               int ID_P15,int ID_P16,int ID_P19,
+               int ID_P20);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitLightSensor.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,137 @@
+/*
+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_LIGHT_SENSOR_H
+#define MICROBIT_LIGHT_SENSOR_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "EventModel.h"
+#include "MicroBitMatrixMaps.h"
+
+#define MICROBIT_LIGHT_SENSOR_CHAN_NUM      3
+#define MICROBIT_LIGHT_SENSOR_AN_SET_TIME   4000
+#define MICROBIT_LIGHT_SENSOR_TICK_PERIOD   5
+
+#define MICROBIT_LIGHT_SENSOR_MAX_VALUE     338
+#define MICROBIT_LIGHT_SENSOR_MIN_VALUE     75
+
+/**
+  * Class definition for MicroBitLightSensor.
+  *
+  * This is an object that interleaves light sensing with MicroBitDisplay.
+  */
+class MicroBitLightSensor
+{
+
+    //contains the results from each section of the display
+    int results[MICROBIT_LIGHT_SENSOR_CHAN_NUM] = { 0 };
+
+    //holds the current channel (also used to index the results array)
+    uint8_t chan;
+
+    //a Timeout which triggers our analogReady() call
+    Timeout analogTrigger;
+
+    //a pointer the currently sensed pin, represented as an AnalogIn
+    AnalogIn* sensePin;
+
+    const MatrixMap &matrixMap;
+
+    /**
+      * After the startSensing method has been called, this method will be called
+      * MICROBIT_LIGHT_SENSOR_AN_SET_TIME after.
+      *
+      * It will then read from the currently selected channel using the AnalogIn
+      * that was configured in the startSensing method.
+      */
+    void analogReady();
+
+    /**
+      * Forcibly disables the AnalogIn, otherwise it will remain in possession
+      * of the GPIO channel it is using, meaning that the display will not be
+      * able to use a channel (COL).
+      *
+      * This is required as per PAN 3, details of which can be found here:
+      *
+      * https://www.nordicsemi.com/eng/nordic/download_resource/24634/5/88440387
+      */
+    void analogDisable();
+
+    public:
+
+    /**
+      * Constructor.
+      *
+      * Create a representation of the light sensor.
+      *
+      * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates.
+      *            Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h.
+      */
+    MicroBitLightSensor(const MatrixMap &map);
+
+    /**
+      * This method returns a summed average of the three sections of the display.
+      *
+      * A section is defined as:
+      *  ___________________
+      * | 1 |   | 2 |   | 3 |
+      * |___|___|___|___|___|
+      * |   |   |   |   |   |
+      * |___|___|___|___|___|
+      * | 2 |   | 3 |   | 1 |
+      * |___|___|___|___|___|
+      * |   |   |   |   |   |
+      * |___|___|___|___|___|
+      * | 3 |   | 1 |   | 2 |
+      * |___|___|___|___|___|
+      *
+      * Where each number represents a different section on the 5 x 5 matrix display.
+      *
+      * @return returns a value in the range 0 - 255 where 0 is dark, and 255
+      * is very bright
+      */
+    int read();
+
+    /**
+      * The method that is invoked by sending MICROBIT_DISPLAY_EVT_LIGHT_SENSE
+      * using the id MICROBIT_ID_DISPLAY.
+      *
+      * @note this can be manually driven by calling this member function, with
+      *       a MicroBitEvent using the CREATE_ONLY option of the MicroBitEvent
+      *       constructor.
+      */
+    void startSensing(MicroBitEvent);
+
+    /**
+      * A destructor for MicroBitLightSensor.
+      *
+      * The destructor removes the listener, used by MicroBitLightSensor from the default EventModel.
+      */
+    ~MicroBitLightSensor();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitMatrixMaps.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,157 @@
+/*
+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.
+*/
+
+/**
+  * Definition of the LED Matrix maps supported.
+  * Each map represents the layou of a different device.
+  *
+  * Ensure only one of these is selected.
+  */
+
+#ifndef MICROBIT_MATRIX_MAPS_H
+#define MICROBIT_MATRIX_MAPS_H
+
+#include "MicroBitConfig.h"
+#include "mbed.h"
+
+#define NO_CONN 0
+
+/**
+  * Provides the mapping from Matrix ROW/COL to a linear X/Y buffer.
+  * It's arranged such that matrixMap[col, row] provides the [x,y] screen co-ord.
+  */
+
+struct MatrixPoint
+{
+    uint8_t x;
+    uint8_t y;
+};
+
+/**
+  * This struct presumes rows and columns are arranged contiguously...
+  */
+struct MatrixMap
+{
+    int         width;                      // The physical width of the LED matrix, in pixels.
+    int         height;                     // The physical height of the LED matrix, in pixels.
+    int         rows;                       // The number of drive pins connected to LEDs.
+    int         columns;                    // The number of sink pins connected to the LEDs.
+
+    PinName     rowStart;                   // ID of the first drive pin.
+    PinName     columnStart;                // ID of the first sink pink.
+
+    const MatrixPoint *map;                 // Table mapping logical LED positions to physical positions.
+};
+
+/*
+ * Dimensions for well known micro:bit LED configurations
+ */
+#define MICROBIT_DISPLAY_WIDTH                  5
+#define MICROBIT_DISPLAY_HEIGHT                 5
+
+#if MICROBIT_DISPLAY_TYPE == MICROBUG_REFERENCE_DEVICE
+
+#define MICROBIT_DISPLAY_COLUMN_COUNT           5
+#define MICROBIT_DISPLAY_ROW_COUNT              5
+
+    const MatrixPoint microbitDisplayMap[MICROBIT_DISPLAY_ROW_COUNT * MICROBIT_DISPLAY_COLUMN_COUNT] =
+    {
+        {0,0},{0,1},{0,2},{0,3},{0,4},
+        {1,0},{1,1},{1,2},{1,3},{1,4},
+        {2,0},{2,1},{2,2},{2,3},{2,4},
+        {3,0},{3,1},{3,2},{3,3},{3,4},
+        {4,0},{4,1},{4,2},{4,3},{4,4}
+    };
+
+#endif
+
+#if MICROBIT_DISPLAY_TYPE == MICROBIT_3X9
+
+#define MICROBIT_DISPLAY_COLUMN_COUNT       9
+#define MICROBIT_DISPLAY_ROW_COUNT          3
+
+    const MatrixPoint microbitDisplayMap[MICROBIT_DISPLAY_ROW_COUNT * MICROBIT_DISPLAY_COLUMN_COUNT] =
+    {
+        {0,4},{0,3},{1,1},
+        {1,4},{4,2},{0,1},
+        {2,4},{3,2},{4,0},
+        {3,4},{2,2},{3,0},
+        {4,4},{1,2},{2,0},
+        {4,3},{0,2},{1,0},
+        {3,3},{4,1},{0,0},
+        {2,3},{3,1},{NO_CONN,NO_CONN},
+        {1,3},{2,1},{NO_CONN,NO_CONN}
+    };
+
+#endif
+
+#if MICROBIT_DISPLAY_TYPE == MICROBIT_SB1
+
+#define MICROBIT_DISPLAY_COLUMN_COUNT       3
+#define MICROBIT_DISPLAY_ROW_COUNT          9
+
+    const MatrixPoint microbitDisplayMap[MICROBIT_DISPLAY_ROW_COUNT * MICROBIT_DISPLAY_COLUMN_COUNT] =
+    {
+        {0,4},{1,4},{2,4},{3,4},{4,4},{4,3},{3,3},{2,3},{1,3},
+        {0,3},{4,2},{3,2},{2,2},{1,2},{0,2},{4,1},{3,1},{2,1},
+        {1,1},{0,1},{4,0},{3,0},{2,0},{1,0},{0,0},{NO_CONN,NO_CONN},{NO_CONN,NO_CONN}
+    };
+
+#endif
+
+#if MICROBIT_DISPLAY_TYPE == MICROBIT_SB2
+
+#define MICROBIT_DISPLAY_COLUMN_COUNT       9
+#define MICROBIT_DISPLAY_ROW_COUNT          3
+
+    const MatrixPoint microbitDisplayMap[MICROBIT_DISPLAY_ROW_COUNT * MICROBIT_DISPLAY_COLUMN_COUNT] =
+    {
+        {0,0},{4,2},{2,4},
+        {2,0},{0,2},{4,4},
+        {4,0},{2,2},{0,4},
+        {4,3},{1,0},{0,1},
+        {3,3},{3,0},{1,1},
+        {2,3},{3,4},{2,1},
+        {1,3},{1,4},{3,1},
+        {0,3},{NO_CONN,NO_CONN},{4,1},
+        {1,2},{NO_CONN,NO_CONN},{3,2}
+    };
+
+#endif
+
+//ROW1 and COL1 are defined in mbed classic:
+//https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/TARGET_NRF51_MICROBIT/PinNames.h
+const MatrixMap microbitMatrixMap =
+{
+    MICROBIT_DISPLAY_WIDTH,
+    MICROBIT_DISPLAY_HEIGHT,
+    MICROBIT_DISPLAY_ROW_COUNT,
+    MICROBIT_DISPLAY_COLUMN_COUNT,
+    ROW1,
+    COL1,
+    microbitDisplayMap
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitMessageBus.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,188 @@
+/*
+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_MESSAGE_BUS_H
+#define MICROBIT_MESSAGE_BUS_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitEvent.h"
+#include "MicroBitListener.h"
+#include "EventModel.h"
+
+/**
+  * Class definition for the MicroBitMessageBus.
+  *
+  * The MicroBitMessageBus is the common mechanism to deliver asynchronous events on the
+  * MicroBit platform. It serves a number of purposes:
+  *
+  * 1) It provides an eventing abstraction that is independent of the underlying substrate.
+  *
+  * 2) It provides a mechanism to decouple user code from trusted system code
+  *    i.e. the basis of a message passing nano kernel.
+  *
+  * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE...
+  *
+  * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based
+  *    drivers and communicate via the message bus with minima impact on user level languages.
+  *
+  * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy.
+  *
+  * It has the following design principles:
+  *
+  * 1) Maintain a low RAM footprint where possible
+  *
+  * 2) Make few assumptions about the underlying platform, but allow optimizations where possible.
+  */
+class MicroBitMessageBus : public EventModel, public MicroBitComponent
+{
+    public:
+
+	/**
+	  * Default constructor.
+      *
+      * Adds itself as a fiber component, and also configures itself to be the
+      * default EventModel if defaultEventBus is NULL.
+	  */
+    MicroBitMessageBus();
+
+	/**
+	  * Queues the given event to be sent to all registered recipients.
+	  *
+	  * @param evt The event to send.
+      *
+      * @code
+      * MicroBitMessageBus bus;
+      *
+      * // Creates and sends the MicroBitEvent using bus.
+	  * MicrobitEvent evt(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
+      *
+      * // Creates the MicrobitEvent, but delays the sending of that event.
+      * MicrobitEvent evt1(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, CREATE_ONLY);
+      *
+      * bus.send(evt1);
+      *
+      * // This has the same effect!
+      * evt1.fire()
+      * @endcode
+	  */
+	virtual int send(MicroBitEvent evt);
+
+	/**
+      * Internal function, used to deliver the given event to all relevant recipients.
+      * Normally, this is called once an event has been removed from the event queue.
+	  *
+	  * @param evt The event to send.
+      *
+      * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed
+      *               otherwise, all other (standard) listeners will be processed. Defaults to false.
+      *
+      * @return 1 if all matching listeners were processed, 0 if further processing is required.
+      *
+      * @note It is recommended that all external code uses the send() function instead of this function,
+      *       or the constructors provided by MicrobitEvent.
+      */
+	int process(MicroBitEvent &evt, bool urgent = false);
+
+    /**
+      * Returns the microBitListener with the given position in our list.
+      *
+      * @param n The position in the list to return.
+      *
+      * @return the MicroBitListener at postion n in the list, or NULL if the position is invalid.
+      */
+    virtual MicroBitListener *elementAt(int n);
+
+    /**
+      * Destructor for MicroBitMessageBus, where we deregister this instance from the array of fiber components.
+      */
+    ~MicroBitMessageBus();
+
+    /**
+      * Add the given MicroBitListener to the list of event handlers, unconditionally.
+      *
+      * @param listener The MicroBitListener to add.
+      *
+      * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
+      */
+    virtual int add(MicroBitListener *newListener);
+
+    /**
+      * Remove the given MicroBitListener from the list of event handlers.
+      *
+      * @param listener The MicroBitListener to remove.
+      *
+      * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
+      */
+    virtual int remove(MicroBitListener *newListener);
+
+	private:
+
+    MicroBitListener            *listeners;		    // Chain of active listeners.
+    MicroBitEventQueueItem      *evt_queue_head;    // Head of queued events to be processed.
+    MicroBitEventQueueItem      *evt_queue_tail;    // Tail of queued events to be processed.
+    uint16_t                    nonce_val;          // The last nonce issued.
+    uint16_t                    queueLength;        // The number of events currently waiting to be processed.
+
+    /**
+      * Cleanup any MicroBitListeners marked for deletion from the list.
+      *
+      * @return The number of listeners removed from the list.
+      */
+    int deleteMarkedListeners();
+
+    /**
+      * Queue the given event for processing at a later time.
+      * Add the given event at the tail of our queue.
+      *
+      * @param The event to queue.
+      */
+    void queueEvent(MicroBitEvent &evt);
+
+    /**
+      * Extract the next event from the front of the event queue (if present).
+      *
+      * @return a pointer to the MicroBitEventQueueItem that is at the head of the list.
+      */
+    MicroBitEventQueueItem* dequeueEvent();
+
+    /**
+      * Periodic callback from MicroBit.
+      *
+      * Process at least one event from the event queue, if it is not empty.
+      * We then continue processing events until something appears on the runqueue.
+      */
+    virtual void idleTick();
+
+    /**
+      * Indicates whether or not we have any background work to do.
+      *
+      * @return 1 if there are any events waitingto be processed, 0 otherwise.
+      */
+    virtual int isIdleCallbackNeeded();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitMultiButton.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,176 @@
+/*
+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_MULTI_BUTTON_H
+#define MICROBIT_MULTI_BUTTON_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitButton.h"
+#include "EventModel.h"
+
+#define MICROBIT_MULTI_BUTTON_STATE_1               0x01
+#define MICROBIT_MULTI_BUTTON_STATE_2               0x02
+#define MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1      0x04
+#define MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_2      0x08
+#define MICROBIT_MULTI_BUTTON_SUPRESSED_1           0X10
+#define MICROBIT_MULTI_BUTTON_SUPRESSED_2           0x20
+#define MICROBIT_MULTI_BUTTON_ATTACHED              0x40
+
+/**
+  * Class definition for MicroBitMultiButton.
+  *
+  * Represents a virtual button, capable of reacting to simultaneous presses of two
+  * other buttons.
+  */
+class MicroBitMultiButton : public MicroBitComponent
+{
+    uint16_t    button1;        // ID of the first button we're monitoring
+    uint16_t    button2;        // ID of the second button we're monitoring
+    MicroBitButtonEventConfiguration eventConfiguration;    // Do we want to generate high level event (clicks), or defer this to another service.
+
+    /**
+      * Retrieves the button id for the alternate button id given.
+      *
+      * @param b the id of the button whose state we would like to retrieve.
+      *
+      * @return the other sub button id.
+      */
+    uint16_t    otherSubButton(uint16_t b);
+
+    /**
+      * Determines if the given button id is marked as pressed.
+      *
+      * @param button the id of the button whose state we would like to retrieve.
+      *
+      * @return 1 if pressed, 0 if not.
+      */
+    int         isSubButtonPressed(uint16_t button);
+
+    /**
+      * Determines if the given button id is marked as held.
+      *
+      * @param button the id of the button whose state we would like to retrieve.
+      *
+      * @return 1 if held, 0 if not.
+      */
+    int         isSubButtonHeld(uint16_t button);
+
+    /**
+      * Determines if the given button id is marked as supressed.
+      *
+      * @param button the id of the button whose state we would like to retrieve.
+      *
+      * @return 1 if supressed, 0 if not.
+      */
+    int         isSubButtonSupressed(uint16_t button);
+
+    /**
+      * Configures the button pressed state for the given button id.
+      *
+      * @param button the id of the button whose state requires updating.
+      *
+      * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1).
+      */
+    void        setButtonState(uint16_t button, int value);
+
+    /**
+      * Configures the button held state for the given button id.
+      *
+      * @param button the id of the button whose state requires updating.
+      *
+      * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1).
+      */
+    void        setHoldState(uint16_t button, int value);
+
+    /**
+      * Configures the button suppressed state for the given button id.
+      *
+      * @param button the id of the button whose state requires updating.
+      *
+      * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1).
+      */
+    void        setSupressedState(uint16_t button, int value);
+
+    public:
+
+    /**
+      * Constructor.
+      *
+      * Create a representation of a virtual button, that generates events based upon the combination
+      * of two given buttons.
+      *
+      * @param button1 the unique ID of the first button to watch.
+      *
+      * @param button2 the unique ID of the second button to watch.
+      *
+      * @param id the unique EventModel id of this MicroBitMultiButton instance.
+      *
+      * @code
+      * multiButton(MICROBIT_ID_BUTTON_A, MICROBIT_ID_BUTTON_B, MICROBIT_ID_BUTTON_AB);
+      * @endcode
+      */
+    MicroBitMultiButton(uint16_t button1, uint16_t button2, uint16_t id);
+
+    /**
+      * Tests if this MicroBitMultiButton instance is virtually pressed.
+      *
+      * @return 1 if both physical buttons are pressed simultaneously.
+      *
+      * @code
+      * if(buttonAB.isPressed())
+      *     display.scroll("Pressed!");
+      * @endcode
+      */
+    int isPressed();
+
+    /**
+      * Changes the event configuration of this button to the given MicroBitButtonEventConfiguration.
+      * All subsequent events generated by this button will then be informed by this configuraiton.
+      *
+      * @param config The new configuration for this button. Legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS.
+      *
+      * @code
+      * // Configure a button to generate all possible events.
+      * buttonAB.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS);
+      *
+      * // Configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events.
+      * buttonAB.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS);
+      * @endcode
+      */
+    void setEventConfiguration(MicroBitButtonEventConfiguration config);
+
+    private:
+
+    /**
+      * A member function that is invoked when any event is detected from the two
+      * button IDs this MicrobitMultiButton instance was constructed with.
+      *
+      * @param evt the event received from the default EventModel.
+      */
+    void onButtonEvent(MicroBitEvent evt);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitPin.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,297 @@
+/*
+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_PIN_H
+#define MICROBIT_PIN_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+                                                        // Status Field flags...
+#define IO_STATUS_DIGITAL_IN                0x01        // Pin is configured as a digital input, with no pull up.
+#define IO_STATUS_DIGITAL_OUT               0x02        // Pin is configured as a digital output
+#define IO_STATUS_ANALOG_IN                 0x04        // Pin is Analog in
+#define IO_STATUS_ANALOG_OUT                0x08        // Pin is Analog out
+#define IO_STATUS_TOUCH_IN                  0x10        // Pin is a makey-makey style touch sensor
+#define IO_STATUS_EVENTBUS_ENABLED          0x80        // Pin is will generate events on change
+
+//#defines for each edge connector pin
+#define MICROBIT_PIN_P0                     P0_3        //P0 is the left most pad (ANALOG/DIGITAL) used to be P0_3 on green board
+#define MICROBIT_PIN_P1                     P0_2        //P1 is the middle pad (ANALOG/DIGITAL)
+#define MICROBIT_PIN_P2                     P0_1        //P2 is the right most pad (ANALOG/DIGITAL) used to be P0_1 on green board
+#define MICROBIT_PIN_P3                     P0_4        //COL1 (ANALOG/DIGITAL)
+#define MICROBIT_PIN_P4                     P0_5        //COL2 (ANALOG/DIGITAL)
+#define MICROBIT_PIN_P5                     P0_17       //BTN_A
+#define MICROBIT_PIN_P6                     P0_12       //COL9
+#define MICROBIT_PIN_P7                     P0_11       //COL8
+#define MICROBIT_PIN_P8                     P0_18       //PIN 18
+#define MICROBIT_PIN_P9                     P0_10       //COL7
+#define MICROBIT_PIN_P10                    P0_6        //COL3 (ANALOG/DIGITAL)
+#define MICROBIT_PIN_P11                    P0_26       //BTN_B
+#define MICROBIT_PIN_P12                    P0_20       //PIN 20
+#define MICROBIT_PIN_P13                    P0_23       //SCK
+#define MICROBIT_PIN_P14                    P0_22       //MISO
+#define MICROBIT_PIN_P15                    P0_21       //MOSI
+#define MICROBIT_PIN_P16                    P0_16       //PIN 16
+#define MICROBIT_PIN_P19                    P0_0        //SCL
+#define MICROBIT_PIN_P20                    P0_30       //SDA
+
+#define MICROBIT_PIN_MAX_OUTPUT             1023
+
+#define MICROBIT_PIN_MAX_SERVO_RANGE        180
+#define MICROBIT_PIN_DEFAULT_SERVO_RANGE    2000
+#define MICROBIT_PIN_DEFAULT_SERVO_CENTER   1500
+
+
+/**
+  * Pin capabilities enum.
+  * Used to determine the capabilities of each Pin as some can only be digital, or can be both digital and analogue.
+  */
+enum PinCapability{
+    PIN_CAPABILITY_DIGITAL = 0x01,
+    PIN_CAPABILITY_ANALOG = 0x02,
+    PIN_CAPABILITY_TOUCH = 0x04,
+    PIN_CAPABILITY_AD = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG,
+    PIN_CAPABILITY_ALL = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG | PIN_CAPABILITY_TOUCH
+
+};
+
+/**
+  * Class definition for MicroBitPin.
+  *
+  * Commonly represents an I/O pin on the edge connector.
+  */
+class MicroBitPin : public MicroBitComponent
+{
+    // The mbed object looking after this pin at any point in time (untyped due to dynamic behaviour).
+    void *pin;
+
+    PinCapability capability;
+
+    /**
+      * Disconnect any attached mBed IO from this pin.
+      *
+      * Used only when pin changes mode (i.e. Input/Output/Analog/Digital)
+      */
+    void disconnect();
+
+    /**
+      * Performs a check to ensure that the current Pin is in control of a
+      * DynamicPwm instance, and if it's not, allocates a new DynamicPwm instance.
+      */
+    int obtainAnalogChannel();
+
+    public:
+
+    // mbed PinName of this pin.
+    PinName name;
+
+    /**
+      * Constructor.
+      * Create a MicroBitPin instance, generally used to represent a pin on the edge connector.
+      *
+      * @param id the unique EventModel id of this component.
+      *
+      * @param name the mbed PinName for this MicroBitPin instance.
+      *
+      * @param capability the capabilities this MicroBitPin instance should have.
+      *                   (PIN_CAPABILITY_DIGITAL, PIN_CAPABILITY_ANALOG, PIN_CAPABILITY_TOUCH, PIN_CAPABILITY_AD, PIN_CAPABILITY_ALL)
+      *
+      * @code
+      * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL);
+      * @endcode
+      */
+    MicroBitPin(int id, PinName name, PinCapability capability);
+
+    /**
+      * Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'.
+      *
+      * @param value 0 (LO) or 1 (HI)
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+      *         if the given pin does not have digital capability.
+      *
+      * @code
+      * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
+      * P0.setDigitalValue(1); // P0 is now HI
+      * @endcode
+      */
+    int setDigitalValue(int value);
+
+    /**
+      * Configures this IO pin as a digital input (if necessary) and tests its current value.
+      *
+      * @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED
+      *         if the given pin does not have analog capability.
+      *
+      * @code
+      * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
+      * P0.getDigitalValue(); // P0 is either 0 or 1;
+      * @endcode
+      */
+    int getDigitalValue();
+
+    /**
+      * Configures this IO pin as an analog/pwm output, and change the output value to the given level.
+      *
+      * @param value the level to set on the output pin, in the range 0 - 1024
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+      *         if the given pin does not have analog capability.
+      */
+    int setAnalogValue(int value);
+
+    /**
+      * Configures this IO pin as an analog/pwm output (if necessary) and configures the period to be 20ms,
+      * with a duty cycle between 500 us and 2500 us.
+      *
+      * A value of 180 sets the duty cycle to be 2500us, and a value of 0 sets the duty cycle to be 500us by default.
+      *
+      * This range can be modified to fine tune, and also tolerate different servos.
+      *
+      * @param value the level to set on the output pin, in the range 0 - 180.
+      *
+      * @param range which gives the span of possible values the i.e. the lower and upper bounds (center +/- range/2). Defaults to MICROBIT_PIN_DEFAULT_SERVO_RANGE.
+      *
+      * @param center the center point from which to calculate the lower and upper bounds. Defaults to MICROBIT_PIN_DEFAULT_SERVO_CENTER
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+      *         if the given pin does not have analog capability.
+      */
+    int setServoValue(int value, int range = MICROBIT_PIN_DEFAULT_SERVO_RANGE, int center = MICROBIT_PIN_DEFAULT_SERVO_CENTER);
+
+    /**
+      * Configures this IO pin as an analogue input (if necessary), and samples the Pin for its analog value.
+      *
+      * @return the current analogue level on the pin, in the range 0 - 1024, or
+      *         MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
+      *
+      * @code
+      * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
+      * P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024
+      * @endcode
+      */
+    int getAnalogValue();
+
+    /**
+      * Determines if this IO pin is currently configured as an input.
+      *
+      * @return 1 if pin is an analog or digital input, 0 otherwise.
+      */
+    int isInput();
+
+    /**
+      * Determines if this IO pin is currently configured as an output.
+      *
+      * @return 1 if pin is an analog or digital output, 0 otherwise.
+      */
+    int isOutput();
+
+    /**
+      * Determines if this IO pin is currently configured for digital use.
+      *
+      * @return 1 if pin is digital, 0 otherwise.
+      */
+    int isDigital();
+
+    /**
+      * Determines if this IO pin is currently configured for analog use.
+      *
+      * @return 1 if pin is analog, 0 otherwise.
+      */
+    int isAnalog();
+
+    /**
+      * Configures this IO pin as a "makey makey" style touch sensor (if necessary)
+      * and tests its current debounced state.
+      *
+      * Users can also subscribe to MicroBitButton events generated from this pin.
+      *
+      * @return 1 if pin is touched, 0 if not, or MICROBIT_NOT_SUPPORTED if this pin does not support touch capability.
+      *
+      * @code
+      * MicroBitMessageBus bus;
+      *
+      * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL);
+      * if(P0.isTouched())
+      * {
+      *     //do something!
+      * }
+      *
+      * // subscribe to events generated by this pin!
+      * bus.listen(MICROBIT_ID_IO_P0, MICROBIT_BUTTON_EVT_CLICK, someFunction);
+      * @endcode
+      */
+    int isTouched();
+
+    /**
+      * Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms,
+      * and sets the pulse width, based on the value it is given.
+      *
+      * @param pulseWidth the desired pulse width in microseconds.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+      *         if the given pin does not have analog capability.
+      */
+    int setServoPulseUs(int pulseWidth);
+
+    /**
+      * Configures the PWM period of the analog output to the given value.
+      *
+      * @param period The new period for the analog output in milliseconds.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
+      *         given pin is not configured as an analog output.
+      */
+    int setAnalogPeriod(int period);
+
+    /**
+      * Configures the PWM period of the analog output to the given value.
+      *
+      * @param period The new period for the analog output in microseconds.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
+      *         given pin is not configured as an analog output.
+      */
+    int setAnalogPeriodUs(int period);
+
+    /**
+      * Obtains the PWM period of the analog output in microseconds.
+      *
+      * @return the period on success, or MICROBIT_NOT_SUPPORTED if the
+      *         given pin is not configured as an analog output.
+      */
+    int getAnalogPeriodUs();
+
+    /**
+      * Obtains the PWM period of the analog output in milliseconds.
+      *
+      * @return the period on success, or MICROBIT_NOT_SUPPORTED if the
+      *         given pin is not configured as an analog output.
+      */
+    int getAnalogPeriod();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitRadio.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,227 @@
+/*
+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_RADIO_H
+#define MICROBIT_RADIO_H
+
+class MicroBitRadio;
+struct FrameBuffer;
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "PacketBuffer.h"
+#include "MicroBitRadioDatagram.h"
+#include "MicroBitRadioEvent.h"
+
+/**
+ * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
+ *
+ * The nrf51822 RADIO module supports a number of proprietary modes of operation in addition to the typical BLE usage.
+ * This class uses one of these modes to enable simple, point to multipoint communication directly between micro:bits.
+ *
+ * TODO: The protocols implemented here do not currently perform any significant form of energy management,
+ * which means that they will consume far more energy than their BLE equivalent. Later versions of the protocol
+ * should look to address this through energy efficient broadcast techniques / sleep scheduling. In particular, the GLOSSY
+ * approach to efficienct rebroadcast and network synchronisation would likely provide an effective future step.
+ *
+ * TODO: Meshing should also be considered - again a GLOSSY approach may be effective here, and highly complementary to
+ * the master/slave arachitecture of BLE.
+ *
+ * TODO: This implementation only operates whilst the BLE stack is disabled. The nrf51822 provides a timeslot API to allow
+ * BLE to cohabit with other protocols. Future work to allow this colocation would be benefical, and would also allow for the
+ * creation of wireless BLE bridges.
+ *
+ * NOTE: This API does not contain any form of encryption, authentication or authorization. It's purpose is solely for use as a
+ * teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place.
+ * For serious applications, BLE should be considered a substantially more secure alternative.
+ */
+
+// Status Flags
+#define MICROBIT_RADIO_STATUS_INITIALISED       0x0001
+
+// Default configuration values
+#define MICROBIT_RADIO_BASE_ADDRESS             0x75626974
+#define MICROBIT_RADIO_DEFAULT_GROUP            0
+#define MICROBIT_RADIO_DEFAULT_TX_POWER         6
+#define MICROBIT_RADIO_DEFAULT_FREQUENCY        7
+#define MICROBIT_RADIO_MAX_PACKET_SIZE          32
+#define MICROBIT_RADIO_HEADER_SIZE              4
+#define MICROBIT_RADIO_MAXIMUM_RX_BUFFERS       4
+
+// Known Protocol Numbers
+#define MICROBIT_RADIO_PROTOCOL_DATAGRAM        1       // A simple, single frame datagram. a little like UDP but with smaller packets. :-)
+#define MICROBIT_RADIO_PROTOCOL_EVENTBUS        2       // Transparent propogation of events from one micro:bit to another.
+
+// Events
+#define MICROBIT_RADIO_EVT_DATAGRAM             1       // Event to signal that a new datagram has been received.
+
+
+struct FrameBuffer
+{
+    uint8_t         length;                             // The length of the remaining bytes in the packet. includes protocol/version/group fields, excluding the length field itself.
+    uint8_t         version;                            // Protocol version code.
+    uint8_t         group;                              // ID of the group to which this packet belongs.
+    uint8_t         protocol;                           // Inner protocol number c.f. those issued by IANA for IP protocols
+
+    uint8_t         payload[MICROBIT_RADIO_MAX_PACKET_SIZE];    // User / higher layer protocol data
+    FrameBuffer     *next;                              // Linkage, to allow this and other protocols to queue packets pending processing.
+    uint8_t         rssi;                               // Received signal strength of this frame.
+};
+
+
+class MicroBitRadio : MicroBitComponent
+{
+    uint8_t                 group;      // The radio group to which this micro:bit belongs.
+    uint8_t                 queueDepth; // The number of packets in the receiver queue.
+    uint8_t                 rssi;
+    FrameBuffer             *rxQueue;   // A linear list of incoming packets, queued awaiting processing.
+    FrameBuffer             *rxBuf;     // A pointer to the buffer being actively used by the RADIO hardware.
+
+    public:
+    MicroBitRadioDatagram   datagram;   // A simple datagram service.
+    MicroBitRadioEvent      event;      // A simple event handling service.
+    static MicroBitRadio    *instance;  // A singleton reference, used purely by the interrupt service routine.
+
+    /**
+      * Constructor.
+      *
+      * Initialise the MicroBitRadio.
+      *
+      * @note This class is demand activated, as a result most resources are only
+      *       committed if send/recv or event registrations calls are made.
+      */
+    MicroBitRadio(uint16_t id = MICROBIT_ID_RADIO);
+
+    /**
+      * Change the output power level of the transmitter to the given value.
+      *
+      * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range.
+      */
+    int setTransmitPower(int power);
+
+    /**
+      * Change the transmission and reception band of the radio to the given channel
+      *
+      * @param band a frequency band in the range 0 - 100. Each step is 1MHz wide, based at 2400MHz.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range,
+      *         or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+      */
+    int setFrequencyBand(int band);
+
+    /**
+      * Retrieve a pointer to the currently allocated receive buffer. This is the area of memory
+      * actively being used by the radio hardware to store incoming data.
+      *
+      * @return a pointer to the current receive buffer.
+      */
+    FrameBuffer * getRxBuf();
+
+    /**
+      * Attempt to queue a buffer received by the radio hardware, if sufficient space is available.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if a replacement receiver buffer
+      *         could not be allocated (either by policy or memory exhaustion).
+      */
+    int queueRxBuf();
+
+    /**
+      * Sets the RSSI for the most recent packet.
+      *
+      * @param rssi the new rssi value.
+      *
+      * @note should only be called from RADIO_IRQHandler...
+      */
+    int setRSSI(uint8_t rssi);
+
+    /**
+      * Retrieves the current RSSI for the most recent packet.
+      *
+      * @return the most recent RSSI value or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+      */
+    int getRSSI();
+
+    /**
+      * Initialises the radio for use as a multipoint sender/receiver
+      *
+      * @return MICROBIT_OK on success, MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+      */
+    int enable();
+
+    /**
+      * Disables the radio for use as a multipoint sender/receiver.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+      */
+    int disable();
+
+    /**
+      * Sets the radio to listen to packets sent with the given group id.
+      *
+      * @param group The group to join. A micro:bit can only listen to one group ID at any time.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+      */
+    int setGroup(uint8_t group);
+
+    /**
+      * A background, low priority callback that is triggered whenever the processor is idle.
+      * Here, we empty our queue of received packets, and pass them onto higher level protocol handlers.
+      */
+    virtual void idleTick();
+
+    /**
+      * Determines the number of packets ready to be processed.
+      *
+      * @return The number of packets in the receive buffer.
+      */
+    int dataReady();
+
+    /**
+      * Retrieves the next packet from the receive buffer.
+      * If a data packet is available, then it will be returned immediately to
+      * the caller. This call will also dequeue the buffer.
+      *
+      * @return The buffer containing the the packet. If no data is available, NULL is returned.
+      *
+      * @note Once recv() has been called, it is the callers resposibility to
+      *       delete the buffer when appropriate.
+      */
+    FrameBuffer* recv();
+
+    /**
+      * Transmits the given buffer onto the broadcast radio.
+      * The call will wait until the transmission of the packet has completed before returning.
+      *
+      * @param data The packet contents to transmit.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+      */
+    int send(FrameBuffer *buffer);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitRadioDatagram.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,135 @@
+/*
+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_RADIO_DATAGRAM_H
+#define MICROBIT_RADIO_DATAGRAM_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitRadio.h"
+#include "ManagedString.h"
+
+/**
+  * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
+  *
+  * This class provides the ability to broadcast simple text or binary messages to other micro:bits in the vicinity
+  * It is envisaged that this would provide the basis for children to experiment with building their own, simple,
+  * custom protocols.
+  *
+  * @note This API does not contain any form of encryption, authentication or authorisation. Its purpose is solely for use as a
+  * teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place.
+  * For serious applications, BLE should be considered a substantially more secure alternative.
+  */
+class MicroBitRadioDatagram
+{
+    MicroBitRadio   &radio;     // The underlying radio module used to send and receive data.
+    FrameBuffer     *rxQueue;   // A linear list of incoming packets, queued awaiting processing.
+
+    public:
+
+    /**
+      * Constructor.
+      *
+      * Creates an instance of a MicroBitRadioDatagram which offers the ability
+      * to broadcast simple text or binary messages to other micro:bits in the vicinity
+      *
+      * @param r The underlying radio module used to send and receive data.
+      */
+    MicroBitRadioDatagram(MicroBitRadio &r);
+
+    /**
+      * Retrieves packet payload data into the given buffer.
+      *
+      * If a data packet is already available, then it will be returned immediately to the caller.
+      * If no data is available then MICROBIT_INVALID_PARAMETER is returned.
+      *
+      * @param buf A pointer to a valid memory location where the received data is to be stored
+      *
+      * @param len The maximum amount of data that can safely be stored in 'buf'
+      *
+      * @return The length of the data stored, or MICROBIT_INVALID_PARAMETER if no data is available, or the memory regions provided are invalid.
+      */
+    int recv(uint8_t *buf, int len);
+
+    /**
+      * Retreives packet payload data into the given buffer.
+      *
+      * If a data packet is already available, then it will be returned immediately to the caller
+      * in the form of a PacketBuffer.
+      *
+      * @return the data received, or an empty PacketBuffer if no data is available.
+      */
+    PacketBuffer recv();
+
+    /**
+      * Transmits the given buffer onto the broadcast radio.
+      *
+      * This is a synchronous call that will wait until the transmission of the packet
+      * has completed before returning.
+      *
+      * @param buffer The packet contents to transmit.
+      *
+      * @param len The number of bytes to transmit.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the buffer is invalid,
+      *         or the number of bytes to transmit is greater than `MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE`.
+      */
+    int send(uint8_t *buffer, int len);
+
+    /**
+      * Transmits the given string onto the broadcast radio.
+      *
+      * This is a synchronous call that will wait until the transmission of the packet
+      * has completed before returning.
+      *
+      * @param data The packet contents to transmit.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the buffer is invalid,
+      *         or the number of bytes to transmit is greater than `MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE`.
+      */
+    int send(PacketBuffer data);
+
+    /**
+      * Transmits the given string onto the broadcast radio.
+      *
+      * This is a synchronous call that will wait until the transmission of the packet
+      * has completed before returning.
+      *
+      * @param data The packet contents to transmit.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the buffer is invalid,
+      *         or the number of bytes to transmit is greater than `MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE`.
+      */
+    int send(ManagedString data);
+
+    /**
+      * Protocol handler callback. This is called when the radio receives a packet marked as a datagram.
+      *
+      * This function process this packet, and queues it for user reception.
+      */
+    void packetReceived();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitRadioEvent.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,143 @@
+/*
+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_RADIO_EVENT_H
+#define MICROBIT_RADIO_EVENT_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitRadio.h"
+#include "EventModel.h"
+
+/**
+ * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
+ *
+ * This class provides the ability to extend the micro:bit's default EventModel to other micro:bits in the vicinity,
+ * in a very similar way to the MicroBitEventService for BLE interfaces.
+ *
+ * It is envisaged that this would provide the basis for children to experiment with building their own, simple,
+ * custom asynchronous events and actions.
+ *
+ * @note This API does not contain any form of encryption, authentication or authorisation. Its purpose is solely for use as a
+ * teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place.
+ * For serious applications, BLE should be considered a substantially more secure alternative.
+ */
+class MicroBitRadioEvent
+{
+    bool            suppressForwarding;     // A private flag used to prevent event forwarding loops.
+    MicroBitRadio   &radio;                 // A reference to the underlying radio module to use.
+
+    public:
+
+    /**
+      * Constructor.
+      *
+      * Creates an instance of MicroBitRadioEvent which offers the ability to extend
+      * the micro:bit's default EventModel to other micro:bits in the vicinity.
+      *
+      * @param r The underlying radio module used to send and receive data.
+      */
+    MicroBitRadioEvent(MicroBitRadio &r);
+
+    /**
+      * Associates the given event with the radio channel.
+      *
+      * Once registered, all events matching the given registration sent to this micro:bit's
+      * default EventModel will be automatically retransmitted on the radio.
+      *
+      * @param id The id of the event to register.
+      *
+      * @param value the value of the event to register.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if no default EventModel is available.
+      *
+      * @note The wildcards MICROBIT_ID_ANY and MICROBIT_EVT_ANY can also be in place of the
+      *       id and value fields.
+      */
+    int listen(uint16_t id, uint16_t value);
+
+    /**
+      * Associates the given event with the radio channel.
+      *
+      * Once registered, all events matching the given registration sent to the given
+      * EventModel will be automatically retransmitted on the radio.
+      *
+      * @param id The id of the events to register.
+      *
+      * @param value the value of the event to register.
+      *
+      * @param eventBus The EventModel to listen for events on.
+      *
+      * @return MICROBIT_OK on success.
+      *
+      * @note The wildcards MICROBIT_ID_ANY and MICROBIT_EVT_ANY can also be in place of the
+      *       id and value fields.
+      */
+    int listen(uint16_t id, uint16_t value, EventModel &eventBus);
+
+    /**
+      * Disassociates the given event with the radio channel.
+      *
+      * @param id The id of the events to deregister.
+      *
+      * @param value The value of the event to deregister.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the default message bus does not exist.
+      *
+      * @note MICROBIT_EVT_ANY can be used to deregister all event values matching the given id.
+      */
+    int ignore(uint16_t id, uint16_t value);
+
+    /**
+      * Disassociates the given events with the radio channel.
+      *
+      * @param id The id of the events to deregister.
+      *
+      * @param value The value of the event to deregister.
+      *
+      * @param eventBus The EventModel to deregister on.
+      *
+      * @return MICROBIT_OK on success.
+      *
+      * @note MICROBIT_EVT_ANY can be used to deregister all event values matching the given id.
+      */
+    int ignore(uint16_t id, uint16_t value, EventModel &eventBus);
+
+    /**
+      * Protocol handler callback. This is called when the radio receives a packet marked as using the event protocol.
+      *
+      * This function process this packet, and fires the event contained inside onto the default EventModel.
+      */
+    void packetReceived();
+
+    /**
+      * Event handler callback. This is called whenever an event is received matching one of those registered through
+      * the registerEvent() method described above. Upon receiving such an event, it is wrapped into
+      * a radio packet and transmitted to any other micro:bits in the same group.
+      */
+    void eventReceived(MicroBitEvent e);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitSerial.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,587 @@
+/*
+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_SERIAL_H
+#define MICROBIT_SERIAL_H
+
+#include "mbed.h"
+#include "ManagedString.h"
+
+#define MICROBIT_SERIAL_DEFAULT_BAUD_RATE   115200
+#define MICROBIT_SERIAL_DEFAULT_BUFFER_SIZE 20
+
+#define MICROBIT_SERIAL_EVT_DELIM_MATCH     1
+#define MICROBIT_SERIAL_EVT_HEAD_MATCH      2
+#define MICROBIT_SERIAL_EVT_RX_FULL         3
+
+#define MICROBIT_SERIAL_RX_IN_USE           1
+#define MICROBIT_SERIAL_TX_IN_USE           2
+#define MICROBIT_SERIAL_RX_BUFF_INIT        4
+#define MICROBIT_SERIAL_TX_BUFF_INIT        8
+
+
+enum MicroBitSerialMode
+{
+    ASYNC,
+	SYNC_SPINWAIT,
+	SYNC_SLEEP
+};
+
+/**
+  * Class definition for MicroBitSerial.
+  *
+  * Represents an instance of RawSerial which accepts micro:bit specific data types.
+  */
+class MicroBitSerial : public RawSerial
+{
+
+    //holds that state of the mutex locks for all MicroBitSerial instances.
+    static uint8_t status;
+
+    //holds the state of the baudrate for all MicroBitSerial instances.
+    static int baudrate;
+
+    //delimeters used for matching on receive.
+    ManagedString delimeters;
+
+    //a variable used when a user calls the eventAfter() method.
+    int rxBuffHeadMatch;
+
+    uint8_t *rxBuff;
+    uint8_t rxBuffSize;
+    volatile uint16_t rxBuffHead;
+    uint16_t rxBuffTail;
+
+
+    uint8_t *txBuff;
+    uint8_t txBuffSize;
+    uint16_t txBuffHead;
+    volatile uint16_t txBuffTail;
+
+    /**
+      * An internal interrupt callback for MicroBitSerial configured for when a
+      * character is received.
+      *
+      * Each time a character is received fill our circular buffer!
+      */
+    void dataReceived();
+
+    /**
+      * An internal interrupt callback for MicroBitSerial.
+      *
+      * Each time the Serial module's buffer is empty, write a character if we have
+      * characters to write.
+      */
+    void dataWritten();
+
+    /**
+      * An internal method to configure an interrupt on tx buffer and also
+      * a best effort copy operation to move bytes from a user buffer to our txBuff
+      *
+      * @param string a pointer to the first character of the users' buffer.
+      *
+      * @param len the length of the string, and ultimately the maximum number of bytes
+      *        that will be copied dependent on the state of txBuff
+      *
+      * @return the number of bytes copied into the buffer.
+      */
+    int setTxInterrupt(uint8_t *string, int len);
+
+    /**
+      * Locks the mutex so that others can't use this serial instance for reception
+      */
+    void lockRx();
+
+    /**
+      * Locks the mutex so that others can't use this serial instance for transmission
+      */
+    void lockTx();
+
+    /**
+      * Unlocks the mutex so that others can use this serial instance for reception
+      */
+    void unlockRx();
+
+    /**
+      * Unlocks the mutex so that others can use this serial instance for transmission
+      */
+    void unlockTx();
+
+    /**
+      * We do not want to always have our buffers initialised, especially if users to not
+      * use them. We only bring them up on demand.
+      */
+    int initialiseRx();
+
+    /**
+      * We do not want to always have our buffers initialised, especially if users to not
+      * use them. We only bring them up on demand.
+      */
+    int initialiseTx();
+
+    /**
+      * An internal method that either spin waits if mode is set to SYNC_SPINWAIT
+      * or puts the fiber to sleep if the mode is set to SYNC_SLEEP
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP
+      */
+    void send(MicroBitSerialMode mode);
+
+    /**
+      * Reads a single character from the rxBuff
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - A character is read from the rxBuff if available, if there
+      *                    are no characters to be read, a value of zero is returned immediately.
+      *
+      *            SYNC_SPINWAIT - A character is read from the rxBuff if available, if there
+      *                            are no characters to be read, this method will spin
+      *                            (lock up the processor) until a character is available.
+      *
+      *            SYNC_SLEEP - A character is read from the rxBuff if available, if there
+      *                         are no characters to be read, the calling fiber sleeps
+      *                         until there is a character available.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return a character from the circular buffer, or MICROBIT_NO_DATA is there
+      *         are no characters in the buffer.
+      */
+    int getChar(MicroBitSerialMode mode);
+
+    /**
+      * An internal method that copies values from a circular buffer to a linear buffer.
+      *
+      * @param circularBuff a pointer to the source circular buffer
+      *
+      * @param circularBuffSize the size of the circular buffer
+      *
+      * @param linearBuff a pointer to the destination linear buffer
+      *
+      * @param tailPosition the tail position in the circular buffer you want to copy from
+      *
+      * @param headPosition the head position in the circular buffer you want to copy to
+      *
+      * @note this method assumes that the linear buffer has the appropriate amount of
+      *       memory to contain the copy operation
+      */
+    void circularCopy(uint8_t *circularBuff, uint8_t circularBuffSize, uint8_t *linearBuff, uint16_t tailPosition, uint16_t headPosition);
+
+    public:
+
+    /**
+      * Constructor.
+      * Create an instance of MicroBitSerial
+      *
+      * @param tx the Pin to be used for transmission
+      *
+      * @param rx the Pin to be used for receiving data
+      *
+      * @param rxBufferSize the size of the buffer to be used for receiving bytes
+      *
+      * @param txBufferSize the size of the buffer to be used for transmitting bytes
+      *
+      * @code
+      * MicroBitSerial serial(USBTX, USBRX);
+      * @endcode
+      * @note the default baud rate is 115200. More API details can be found:
+      *       -https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/api/SerialBase.h
+      *       -https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/api/RawSerial.h
+      *
+      *       Buffers aren't allocated until the first send or receive respectively.
+      */
+    MicroBitSerial(PinName tx, PinName rx, uint8_t rxBufferSize = MICROBIT_SERIAL_DEFAULT_BUFFER_SIZE, uint8_t txBufferSize = MICROBIT_SERIAL_DEFAULT_BUFFER_SIZE);
+
+    /**
+      * Sends a single character over the serial line.
+      *
+      * @param c the character to send
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - the character is copied into the txBuff and returns immediately.
+      *
+      *            SYNC_SPINWAIT - the character is copied into the txBuff and this method
+      *                            will spin (lock up the processor) until the character has
+      *                            been sent.
+      *
+      *            SYNC_SLEEP - the character is copied into the txBuff and the fiber sleeps
+      *                         until the character has been sent. This allows other fibers
+      *                         to continue execution.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return the number of bytes written, or MICROBIT_SERIAL_IN_USE if another fiber
+      *         is using the serial instance for transmission.
+      */
+    int sendChar(char c, MicroBitSerialMode mode = MICROBIT_DEFAULT_SERIAL_MODE);
+
+    /**
+      * Sends a ManagedString over the serial line.
+      *
+      * @param s the string to send
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - bytes are copied into the txBuff and returns immediately.
+      *
+      *            SYNC_SPINWAIT - bytes are copied into the txBuff and this method
+      *                            will spin (lock up the processor) until all bytes
+      *                            have been sent.
+      *
+      *            SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps
+      *                         until all bytes have been sent. This allows other fibers
+      *                         to continue execution.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return the number of bytes written, or MICROBIT_SERIAL_IN_USE if another fiber
+      *         is using the serial instance for transmission.
+      */
+    int send(ManagedString s, MicroBitSerialMode mode = MICROBIT_DEFAULT_SERIAL_MODE);
+
+    /**
+      * Sends a buffer of known length over the serial line.
+      *
+      * @param buffer a pointer to the first character of the buffer
+      *
+      * @param len the number of bytes that are safely available to read.
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - bytes are copied into the txBuff and returns immediately.
+      *
+      *            SYNC_SPINWAIT - bytes are copied into the txBuff and this method
+      *                            will spin (lock up the processor) until all bytes
+      *                            have been sent.
+      *
+      *            SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps
+      *                         until all bytes have been sent. This allows other fibers
+      *                         to continue execution.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return the number of bytes written, or MICROBIT_SERIAL_IN_USE if another fiber
+      *         is using the serial instance for transmission.
+      */
+    int send(uint8_t *buffer, int bufferLen, MicroBitSerialMode mode = MICROBIT_DEFAULT_SERIAL_MODE);
+
+    /**
+      * Reads a single character from the rxBuff
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - A character is read from the rxBuff if available, if there
+      *                    are no characters to be read, a value of MICROBIT_NO_DATA is returned immediately.
+      *
+      *            SYNC_SPINWAIT - A character is read from the rxBuff if available, if there
+      *                            are no characters to be read, this method will spin
+      *                            (lock up the processor) until a character is available.
+      *
+      *            SYNC_SLEEP - A character is read from the rxBuff if available, if there
+      *                         are no characters to be read, the calling fiber sleeps
+      *                         until there is a character available.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return a character, MICROBIT_SERIAL_IN_USE if another fiber is using the serial instance for reception,
+      *         MICROBIT_NO_RESOURCES if buffer allocation did not complete successfully, or MICROBIT_NO_DATA if
+      *         the rx buffer is empty and the mode given is ASYNC.
+      */
+    int read(MicroBitSerialMode mode = MICROBIT_DEFAULT_SERIAL_MODE);
+
+    /**
+      * Reads multiple characters from the rxBuff and returns them as a ManagedString
+      *
+      * @param size the number of characters to read.
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - If the desired number of characters are available, this will return
+      *                    a ManagedString with the expected size. Otherwise, it will read however
+      *                    many characters there are available.
+      *
+      *            SYNC_SPINWAIT - If the desired number of characters are available, this will return
+      *                            a ManagedString with the expected size. Otherwise, this method will spin
+      *                            (lock up the processor) until the desired number of characters have been read.
+      *
+      *            SYNC_SLEEP - If the desired number of characters are available, this will return
+      *                         a ManagedString with the expected size. Otherwise, the calling fiber sleeps
+      *                         until the desired number of characters have been read.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return A ManagedString, or an empty ManagedString if an error was encountered during the read.
+      */
+    ManagedString read(int size, MicroBitSerialMode mode = MICROBIT_DEFAULT_SERIAL_MODE);
+
+    /**
+      * Reads multiple characters from the rxBuff and fills a user buffer.
+      *
+      * @param buffer a pointer to a user allocated buffer.
+      *
+      * @param bufferLen the amount of data that can be safely stored
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - If the desired number of characters are available, this will fill
+      *                    the given buffer. Otherwise, it will fill the buffer with however
+      *                    many characters there are available.
+      *
+      *            SYNC_SPINWAIT - If the desired number of characters are available, this will fill
+      *                            the given buffer. Otherwise, this method will spin (lock up the processor)
+      *                            and fill the buffer until the desired number of characters have been read.
+      *
+      *            SYNC_SLEEP - If the desired number of characters are available, this will fill
+      *                         the given buffer. Otherwise, the calling fiber sleeps
+      *                         until the desired number of characters have been read.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return the number of characters read, or MICROBIT_SERIAL_IN_USE if another fiber
+      *         is using the instance for receiving.
+      */
+    int read(uint8_t *buffer, int bufferLen, MicroBitSerialMode mode = MICROBIT_DEFAULT_SERIAL_MODE);
+
+    /**
+      * Reads until one of the delimeters matches a character in the rxBuff
+      *
+      * @param delimeters a ManagedString containing a sequence of delimeter characters e.g. ManagedString("\r\n")
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - If one of the delimeters matches a character already in the rxBuff
+      *                    this method will return a ManagedString up to the delimeter.
+      *                    Otherwise, it will return an Empty ManagedString.
+      *
+      *            SYNC_SPINWAIT - If one of the delimeters matches a character already in the rxBuff
+      *                            this method will return a ManagedString up to the delimeter.
+      *                            Otherwise, this method will spin (lock up the processor) until a
+      *                            received character matches one of the delimeters.
+      *
+      *            SYNC_SLEEP - If one of the delimeters matches a character already in the rxBuff
+      *                         this method will return a ManagedString up to the delimeter.
+      *                         Otherwise, the calling fiber sleeps until a character matching one
+      *                         of the delimeters is seen.
+      *
+      *         Defaults to SYNC_SLEEP.
+      *
+      * @return A ManagedString containing the characters up to a delimeter, or an Empty ManagedString,
+      *         if another fiber is currently using this instance for reception.
+      *
+      * @note delimeters are matched on a per byte basis.
+      */
+    ManagedString readUntil(ManagedString delimeters, MicroBitSerialMode mode = MICROBIT_DEFAULT_SERIAL_MODE);
+
+    /**
+      * A wrapper around the inherited method "baud" so we can trap the baud rate
+      * as it changes and restore it if redirect() is called.
+      *
+      * @param baudrate the new baudrate. See:
+      *         - https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/serial_api.c
+      *        for permitted baud rates.
+      *
+      * @return MICROBIT_INVALID_PARAMETER if baud rate is less than 0, otherwise MICROBIT_OK.
+      *
+      * @note the underlying implementation chooses the first allowable rate at or above that requested.
+      */
+    void baud(int baudrate);
+
+    /**
+      * A way of dynamically configuring the serial instance to use pins other than USBTX and USBRX.
+      *
+      * @param tx the new transmission pin.
+      *
+      * @param rx the new reception pin.
+      *
+      * @return MICROBIT_SERIAL_IN_USE if another fiber is currently transmitting or receiving, otherwise MICROBIT_OK.
+      */
+    int redirect(PinName tx, PinName rx);
+
+    /**
+      * Configures an event to be fired after "len" characters.
+      *
+      * @param len the number of characters to wait before triggering the event.
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will configure the event and return immediately.
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+      *                         event is received.
+      *
+      * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+      */
+    int eventAfter(int len, MicroBitSerialMode mode = ASYNC);
+
+    /**
+      * Configures an event to be fired on a match with one of the delimeters.
+      *
+      * @param delimeters the characters to match received characters against e.g. ManagedString("\r\n")
+      *
+      * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+      *        gives a different behaviour:
+      *
+      *            ASYNC - Will configure the event and return immediately.
+      *
+      *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+      *
+      *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+      *                         event is received.
+      *
+      * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+      *
+      * @note delimeters are matched on a per byte basis.
+      */
+    int eventOn(ManagedString delimeters, MicroBitSerialMode mode = ASYNC);
+
+    /**
+      * Determines whether there is any data waiting in our Rx buffer.
+      *
+      * @return 1 if we have space, 0 if we do not.
+      *
+      * @note We do not wrap the super's readable() method as we don't want to
+      *       interfere with communities that use manual calls to serial.readable().
+      */
+    int isReadable();
+
+    /**
+      * Determines if we have space in our txBuff.
+      *
+      * @return 1 if we have space, 0 if we do not.
+      *
+      * @note We do not wrap the super's writeable() method as we don't want to
+      *       interfere with communities that use manual calls to serial.writeable().
+      */
+    int isWriteable();
+
+    /**
+      * Reconfigures the size of our rxBuff
+      *
+      * @param size the new size for our rxBuff
+      *
+      * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+      *         for reception, otherwise MICROBIT_OK.
+      */
+    int setRxBufferSize(uint8_t size);
+
+    /**
+      * Reconfigures the size of our txBuff
+      *
+      * @param size the new size for our txBuff
+      *
+      * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+      *         for transmission, otherwise MICROBIT_OK.
+      */
+    int setTxBufferSize(uint8_t size);
+
+    /**
+      * The size of our rx buffer in bytes.
+      *
+      * @return the current size of rxBuff in bytes
+      */
+    int getRxBufferSize();
+
+    /**
+      * The size of our tx buffer in bytes.
+      *
+      * @return the current size of txBuff in bytes
+      */
+    int getTxBufferSize();
+
+    /**
+      * Sets the tail to match the head of our circular buffer for reception,
+      * effectively clearing the reception buffer.
+      *
+      * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+      *         for reception, otherwise MICROBIT_OK.
+      */
+    int clearRxBuffer();
+
+    /**
+      * Sets the tail to match the head of our circular buffer for transmission,
+      * effectively clearing the transmission buffer.
+      *
+      * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+      *         for transmission, otherwise MICROBIT_OK.
+      */
+    int clearTxBuffer();
+
+    /**
+      * The number of bytes currently stored in our rx buffer waiting to be digested,
+      * by the user.
+      *
+      * @return The currently buffered number of bytes in our rxBuff.
+      */
+    int rxBufferedSize();
+
+    /**
+      * The number of bytes currently stored in our tx buffer waiting to be transmitted
+      * by the hardware.
+      *
+      * @return The currently buffered number of bytes in our txBuff.
+      */
+    int txBufferedSize();
+
+    /**
+      * Determines if the serial bus is currently in use by another fiber for reception.
+      *
+      * @return The state of our mutex lock for reception.
+      *
+      * @note Only one fiber can call read at a time
+      */
+    int rxInUse();
+
+    /**
+      * Determines if the serial bus is currently in use by another fiber for transmission.
+      *
+      * @return The state of our mutex lock for transmition.
+      *
+      * @note Only one fiber can call send at a time
+      */
+    int txInUse();
+
+    /**
+      * Detaches a previously configured interrupt
+      *
+      * @param interruptType one of Serial::RxIrq or Serial::TxIrq
+      */
+    void detach(Serial::IrqType interuptType);
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitStorage.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,233 @@
+/*
+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_STORAGE_H
+#define MICROBIT_STORAGE_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "ManagedString.h"
+#include "ErrorNo.h"
+
+#define MICROBIT_STORAGE_MAGIC       0xCAFE
+
+#define MICROBIT_STORAGE_BLOCK_SIZE             48
+#define MICROBIT_STORAGE_KEY_SIZE               16
+#define MICROBIT_STORAGE_VALUE_SIZE             MICROBIT_STORAGE_BLOCK_SIZE - MICROBIT_STORAGE_KEY_SIZE
+
+#define MICROBIT_STORAGE_STORE_PAGE_OFFSET      17      //Use the page just above the BLE Bond Data.
+#define MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET    19      //Use the page just below the BLE Bond Data.
+
+struct KeyValuePair
+{
+    uint8_t key[MICROBIT_STORAGE_KEY_SIZE] = { 0 };
+    uint8_t value[MICROBIT_STORAGE_VALUE_SIZE] = { 0 };
+};
+
+struct KeyValueStore
+{
+    uint32_t magic;
+    uint32_t size;
+
+    KeyValueStore(uint32_t magic, uint32_t size)
+    {
+        this->magic = magic;
+        this->size = size;
+    }
+
+    KeyValueStore()
+    {
+        this->magic = 0;
+        this->size = 0;
+    }
+};
+
+
+/**
+  * Class definition for the MicroBitStorage class.
+  * This allows reading and writing of small blocks of data to FLASH memory.
+  *
+  * This class operates as a key value store, it allows the retrieval, addition
+  * and deletion of KeyValuePairs.
+  *
+  * The first 8 bytes are reserved for the KeyValueStore struct which gives core
+  * information such as the number of KeyValuePairs in the store, and whether the
+  * store has been initialised.
+  *
+  * After the KeyValueStore struct, KeyValuePairs are arranged contiguously until
+  * the end of the block used as persistent storage.
+  *
+  * |-------8-------|--------48-------|-----|---------48--------|
+  * | KeyValueStore | KeyValuePair[0] | ... | KeyValuePair[N-1] |
+  * |---------------|-----------------|-----|-------------------|
+  */
+class MicroBitStorage
+{
+    /**
+      * Function for copying words from one location to another.
+      *
+      * @param from the address to copy data from.
+      *
+      * @param to the address to copy the data to.
+      *
+      * @param sizeInWords the number of words to copy
+      */
+    void flashCopy(uint32_t* from, uint32_t* to, int sizeInWords);
+
+    /**
+      * Function for populating the scratch page with a KeyValueStore.
+      *
+      * @param store the KeyValueStore struct to write to the scratch page.
+      */
+    void scratchKeyValueStore(KeyValueStore store);
+
+    /**
+      * Function for populating the scratch page with a KeyValuePair.
+      *
+      * @param pair the KeyValuePair struct to write to the scratch page.
+      *
+      * @param flashPointer the pointer in flash where this KeyValuePair resides. This pointer
+      * is used to determine the offset into the scratch page, where the KeyValuePair should
+      * be written.
+      */
+    void scratchKeyValuePair(KeyValuePair pair, uint32_t* flashPointer);
+
+    public:
+
+    /**
+      * Default constructor.
+      *
+      * Creates an instance of MicroBitStorage which acts like a KeyValueStore
+      * that allows the retrieval, addition and deletion of KeyValuePairs.
+      */
+    MicroBitStorage();
+
+    /**
+      * Writes the given number of bytes to the address specified.
+      *
+      * @param buffer the data to write.
+      *
+      * @param address the location in memory to write to.
+      *
+      * @param length the number of bytes to write.
+      *
+      * @note currently not implemented.
+      */
+    int writeBytes(uint8_t *buffer, uint32_t address, int length);
+
+    /**
+      * Method for erasing a page in flash.
+      *
+      * @param page_address Address of the first word in the page to be erased.
+      */
+    void flashPageErase(uint32_t * page_address);
+
+    /**
+      * Method for writing a word of data in flash with a value.
+      *
+      * @param address Address of the word to change.
+      *
+      * @param value Value to be written to flash.
+      */
+    void flashWordWrite(uint32_t * address, uint32_t value);
+
+    /**
+      * Places a given key, and it's corresponding value into flash at the earliest
+      * available point.
+      *
+      * @param key the unique name that should be used as an identifier for the given data.
+      *            The key is presumed to be null terminated.
+      *
+      * @param data a pointer to the beginning of the data to be persisted.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the storage page is full
+      */
+    int put(const char* key, uint8_t* data);
+
+    /**
+      * Places a given key, and it's corresponding value into flash at the earliest
+      * available point.
+      *
+      * @param key the unique name that should be used as an identifier for the given data.
+      *
+      * @param data a pointer to the beginning of the data to be persisted.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the storage page is full
+      */
+    int put(ManagedString key, uint8_t* data);
+
+    /**
+      * Retreives a KeyValuePair identified by a given key.
+      *
+      * @param key the unique name used to identify a KeyValuePair in flash.
+      *
+      * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
+      *         NULL if the key was not found in storage.
+      *
+      * @note it is up to the user to free memory after use.
+      */
+    KeyValuePair* get(const char* key);
+
+    /**
+      * Retreives a KeyValuePair identified by a given key.
+      *
+      * @param key the unique name used to identify a KeyValuePair in flash.
+      *
+      * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
+      *         NULL if the key was not found in storage.
+      *
+      * @note it is up to the user to free memory after use.
+      */
+    KeyValuePair* get(ManagedString key);
+
+    /**
+      * Removes a KeyValuePair identified by a given key.
+      *
+      * @param key the unique name used to identify a KeyValuePair in flash.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
+      *         was not found in flash.
+      */
+    int remove(const char* key);
+
+    /**
+      * Removes a KeyValuePair identified by a given key.
+      *
+      * @param key the unique name used to identify a KeyValuePair in flash.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
+      *         was not found in flash.
+      */
+    int remove(ManagedString key);
+
+    /**
+      * The size of the flash based KeyValueStore.
+      *
+      * @return the number of entries in the key value store
+      */
+    int size();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitThermometer.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,180 @@
+/*
+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_THERMOMETER_H
+#define MICROBIT_THERMOMETER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitStorage.h"
+
+#define MICROBIT_THERMOMETER_PERIOD             1000
+
+
+#define MAG3110_SAMPLE_RATES                    11
+
+/*
+ * Temperature events
+ */
+#define MICROBIT_THERMOMETER_EVT_UPDATE         1
+
+#define MICROBIT_THERMOMETER_ADDED_TO_IDLE      2
+
+/**
+  * Class definition for MicroBit Thermometer.
+  *
+  * Infers and stores the ambient temoperature based on the surface temperature
+  * of the various chips on the micro:bit.
+  *
+  */
+class MicroBitThermometer : public MicroBitComponent
+{
+    unsigned long           sampleTime;
+    uint32_t                samplePeriod;
+    int16_t                 temperature;
+    int16_t                 offset;
+    MicroBitStorage*        storage;
+
+    public:
+
+    /**
+      * Constructor.
+      * Create new MicroBitThermometer that gives an indication of the current temperature.
+      *
+      * @param _storage an instance of MicroBitStorage used to persist temperature offset data
+      *
+      * @param id the unique EventModel id of this component. Defaults to MICROBIT_ID_THERMOMETER.
+      *
+      * @code
+      * MicroBitStorage storage;
+      * MicroBitThermometer thermometer(storage);
+      * @endcode
+      */
+    MicroBitThermometer(MicroBitStorage& _storage, uint16_t id = MICROBIT_ID_THERMOMETER);
+
+    /**
+      * Constructor.
+      * Create new MicroBitThermometer that gives an indication of the current temperature.
+      *
+      * @param id the unique EventModel id of this component. Defaults to MICROBIT_ID_THERMOMETER.
+      *
+      * @code
+      * MicroBitThermometer thermometer;
+      * @endcode
+      */
+    MicroBitThermometer(uint16_t id = MICROBIT_ID_THERMOMETER);
+
+    /**
+      * Set the sample rate at which the temperatureis read (in ms).
+      *
+      * The default sample period is 1 second.
+      *
+      * @param period the requested time between samples, in milliseconds.
+      *
+      * @note the temperature is always read in the background, and is only updated
+      * when the processor is idle, or when the temperature is explicitly read.
+      */
+    void setPeriod(int period);
+
+    /**
+      * Reads the currently configured sample rate of the thermometer.
+      *
+      * @return The time between samples, in milliseconds.
+      */
+    int getPeriod();
+
+    /**
+      * Set the value that is used to offset the raw silicon temperature.
+      *
+      * @param offset the offset for the silicon temperature
+      *
+      * @return MICROBIT_OK on success
+      */
+    int setOffset(int offset);
+
+    /**
+      * Retreive the value that is used to offset the raw silicon temperature.
+      *
+      * @return the current offset.
+      */
+    int getOffset();
+
+    /**
+      * This member function fetches the raw silicon temperature, and calculates
+      * the value used to offset the raw silicon temperature based on a given temperature.
+      *
+      * @param calibrationTemp the temperature used to calculate the raw silicon temperature
+      * offset.
+      *
+      * @return MICROBIT_OK on success
+      */
+    int setCalibration(int calibrationTemp);
+
+    /**
+      * Gets the current temperature of the microbit.
+      *
+      * @return the current temperature, in degrees celsius.
+      *
+      * @code
+      * thermometer.getTemperature();
+      * @endcode
+      */
+    int getTemperature();
+
+    /**
+      * Updates the temperature sample of this instance of MicroBitThermometer
+      * only if isSampleNeeded() indicates that an update is required.
+      *
+      * This call also will add the thermometer to fiber components to receive
+      * periodic callbacks.
+      *
+      * @return MICROBIT_OK on success.
+      */
+    int updateSample();
+
+    /**
+      * Periodic callback from MicroBit idle thread.
+      */
+    virtual void idleTick();
+
+    /**
+      * Indicates if we'd like some processor time to sense the temperature.
+      *
+      * @returns 1 if we'd like some processor time, 0 otherwise.
+      */
+    virtual int isIdleCallbackNeeded();
+
+    private:
+
+    /**
+      * Determines if we're due to take another temperature reading
+      *
+      * @return 1 if we're due to take a temperature reading, 0 otherwise.
+      */
+    int isSampleNeeded();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/ManagedString.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,399 @@
+/*
+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 MANAGED_STRING_H
+#define MANAGED_STRING_H
+
+#include "MicroBitConfig.h"
+#include "RefCounted.h"
+#include "PacketBuffer.h"
+
+struct StringData : RefCounted
+{
+    uint16_t len;
+    char data[0];
+};
+
+
+/**
+  * Class definition for a ManagedString.
+  *
+  * Uses basic reference counting to implement a copy-assignable, immutable string.
+  *
+  * This maps closely to the constructs found in many high level application languages,
+  * such as Touch Develop.
+  *
+  * Written from first principles here, for several reasons:
+  * 1) std::shared_ptr is not yet availiable on the ARMCC compiler
+  *
+  * 2) to reduce memory footprint - we don't need many of the other features in the std library
+  *
+  * 3) it makes an interesting case study for anyone interested in seeing how it works!
+  *
+  * 4) we need explicit reference counting to inter-op with low-level application langauge runtimes.
+  *
+  * 5) the reference counting needs to also work for read-only, flash-resident strings
+  */
+class ManagedString
+{
+    // StringData contains the reference count, the length, follwed by char[] data, all in one block.
+    // When referece count is 0xffff, then it's read only and should not be counted.
+    // Otherwise the block was malloc()ed.
+    // We control access to this to proide immutability and reference counting.
+    StringData *ptr;
+
+    public:
+
+    /**
+      * Constructor.
+      * Create a managed string from a specially prepared string literal.
+      *
+      * @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The literal has to be 4-byte aligned.
+      *
+      * @code
+      * static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello";
+      * ManagedString s((StringData*)(void*)hello);
+      * @endcode
+      */
+    ManagedString(StringData *ptr);
+
+    /**
+      * Get current ptr, do not decr() it, and set the current instance to empty string.
+      *
+      * This is to be used by specialized runtimes which pass StringData around.
+      */
+    StringData *leakData();
+
+    /**
+      * Constructor.
+      *
+      * Create a managed string from a pointer to an 8-bit character buffer.
+      *
+      * The buffer is copied to ensure safe memory management (the supplied
+      * character buffer may be declared on the stack for instance).
+      *
+      * @param str The character array on which to base the new ManagedString.
+      *
+      * @code
+      * ManagedString s("abcdefg");
+      * @endcode
+      */
+    ManagedString(const char *str);
+
+    /**
+      * Constructor.
+      *
+      * Create a managed string from a given integer.
+      *
+      * @param value The integer from which to create the ManagedString.
+      *
+      * @code
+      * ManagedString s(20);
+      * @endcode
+      */
+    ManagedString(const int value);
+
+
+    /**
+      * Constructor.
+      * Create a managed string from a given char.
+      *
+      * @param value The character from which to create the ManagedString.
+      *
+      * @code
+      * ManagedString s('a');
+      * @endcode
+      */
+    ManagedString(const char value);
+
+    /**
+      * Constructor.
+      * Create a ManagedString from a PacketBuffer. All bytes in the
+      * PacketBuffer are added to the ManagedString.
+      *
+      * @param buffer The PacktBuffer from which to create the ManagedString.
+      *
+      * @code
+      * ManagedString s = radio.datagram.recv();
+      * @endcode
+      */
+    ManagedString(PacketBuffer buffer);
+
+    /**
+      * Constructor.
+      * Create a ManagedString from a pointer to an 8-bit character buffer of a given length.
+      *
+      * The buffer is copied to ensure sane memory management (the supplied
+      * character buffer may be declared on the stack for instance).
+      *
+      * @param str The character array on which to base the new ManagedString.
+      *
+      * @param length The length of the character array
+      *
+      * @code
+      * ManagedString s("abcdefg",7);
+      * @endcode
+      */
+    ManagedString(const char *str, const int16_t length);
+
+    /**
+      * Copy constructor.
+      * Makes a new ManagedString identical to the one supplied.
+      *
+      * Shares the character buffer and reference count with the supplied ManagedString.
+      *
+      * @param s The ManagedString to copy.
+      *
+      * @code
+      * ManagedString s("abcdefg");
+      * ManagedString p(s);
+      * @endcode
+      */
+    ManagedString(const ManagedString &s);
+
+    /**
+      * Default constructor.
+      *
+      * Create an empty ManagedString.
+      *
+      * @code
+      * ManagedString s();
+      * @endcode
+      */
+    ManagedString();
+
+    /**
+      * Destructor.
+      *
+      * Free this ManagedString, and decrement the reference count to the
+      * internal character buffer.
+      *
+      * If we're holding the last reference, also free the character buffer.
+      */
+    ~ManagedString();
+
+    /**
+      * Copy assign operation.
+      *
+      * Called when one ManagedString is assigned the value of another.
+      *
+      * If the ManagedString being assigned is already refering to a character buffer,
+      * decrement the reference count and free up the buffer as necessary.
+      *
+      * Then, update our character buffer to refer to that of the supplied ManagedString,
+      * and increase its reference count.
+      *
+      * @param s The ManagedString to copy.
+      *
+      * @code
+      * ManagedString s("abcd");
+      * ManagedString p("efgh");
+      * p = s   // p now points to s, s' ref is incremented
+      * @endcode
+      */
+    ManagedString& operator = (const ManagedString& s);
+
+    /**
+      * Equality operation.
+      *
+      * Called when one ManagedString is tested to be equal to another using the '==' operator.
+      *
+      * @param s The ManagedString to test ourselves against.
+      *
+      * @return true if this ManagedString is identical to the one supplied, false otherwise.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * ManagedString s("abcd");
+      * ManagedString p("efgh");
+      *
+      * if(p == s)
+      *     display.scroll("We are the same!");
+      * else
+      *     display.scroll("We are different!"); //p is not equal to s - this will be called
+      * @endcode
+      */
+    bool operator== (const ManagedString& s);
+
+    /**
+      * Inequality operation.
+      *
+      * Called when one ManagedString is tested to be less than another using the '<' operator.
+      *
+      * @param s The ManagedString to test ourselves against.
+      *
+      * @return true if this ManagedString is alphabetically less than to the one supplied, false otherwise.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * ManagedString s("a");
+      * ManagedString p("b");
+      *
+      * if(s < p)
+      *     display.scroll("a is before b!"); //a is before b
+      * else
+      *     display.scroll("b is before a!");
+      * @endcode
+      */
+    bool operator< (const ManagedString& s);
+
+    /**
+      * Inequality operation.
+      *
+      * Called when one ManagedString is tested to be greater than another using the '>' operator.
+      *
+      * @param s The ManagedString to test ourselves against.
+      *
+      * @return true if this ManagedString is alphabetically greater than to the one supplied, false otherwise.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * ManagedString s("a");
+      * ManagedString p("b");
+      *
+      * if(p>a)
+      *     display.scroll("b is after a!"); //b is after a
+      * else
+      *     display.scroll("a is after b!");
+      * @endcode
+      */
+    bool operator> (const ManagedString& s);
+
+    /**
+      * Extracts a ManagedString from this string, at the position provided.
+      *
+      * @param start The index of the first character to extract, indexed from zero.
+      *
+      * @param length The number of characters to extract from the start position
+      *
+      * @return a ManagedString representing the requested substring.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * ManagedString s("abcdefg");
+      *
+      * display.scroll(s.substring(0,2)) // displays "ab"
+      * @endcode
+      */
+    ManagedString substring(int16_t start, int16_t length);
+
+    /**
+      * Concatenates this string with the one provided.
+      *
+      * @param s The ManagedString to concatenate.
+      *
+      * @return a new ManagedString representing the joined strings.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * ManagedString s("abcd");
+      * ManagedString p("efgh")
+      *
+      * display.scroll(s + p) // scrolls "abcdefgh"
+      * @endcode
+      */
+    ManagedString operator+ (ManagedString& s);
+
+    /**
+      * Provides a character value at a given position in the string, indexed from zero.
+      *
+      * @param index The position of the character to return.
+      *
+      * @return the character at posisiton index, zero if index is invalid.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * ManagedString s("abcd");
+      *
+      * display.scroll(s.charAt(1)) // scrolls "b"
+      * @endcode
+      */
+    char charAt(int16_t index);
+
+
+    /**
+      * Provides an immutable 8 bit wide character buffer representing this string.
+      *
+      * @return a pointer to the character buffer.
+      */
+    const char *toCharArray() const
+    {
+        return ptr->data;
+    }
+
+    /**
+      * Determines the length of this ManagedString in characters.
+      *
+      * @return the length of the string in characters.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * ManagedString s("abcd");
+      *
+      * display.scroll(s.length()) // scrolls "4"
+      * @endcode
+      */
+    int16_t length() const
+    {
+        return ptr->len;
+    }
+
+    /**
+      * Empty String constant
+      */
+    static ManagedString EmptyString;
+
+    private:
+
+    /**
+      * Internal constructor helper.
+      *
+      * Configures this ManagedString to refer to the static EmptyString
+      */
+    void initEmpty();
+
+    /**
+      * Internal constructor helper.
+      *
+      * Creates this ManagedString based on a given null terminated char array.
+      */
+    void initString(const char *str);
+
+    /**
+      * Private Constructor.
+      *
+      * Create a managed string based on a concat of two strings.
+      * The buffer is copied to ensure sane memory management (the supplied
+      * character buffer may be declared on the stack for instance).
+      *
+      * @param str1 The first string on which to base the new ManagedString.
+      *
+      * @param str2 The second string on which to base the new ManagedString.
+      */
+    ManagedString(const ManagedString &s1, const ManagedString &s2);
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/ManagedType.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,279 @@
+/*
+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_MANAGED_TYPE_H
+#define MICROBIT_MANAGED_TYPE_H
+
+#include "MicroBitConfig.h"
+
+/**
+  * Class definition for a Generic Managed Type.
+  *
+  * Represents a reference counted object.
+  *
+  * @note When the destructor is called, delete is called on the object - implicitly calling the given objects destructor.
+  */
+template <class T>
+class ManagedType
+{
+protected:
+
+    int *ref;
+
+public:
+
+    T *object;
+
+    /**
+      * Constructor for the managed type, given a class space T.
+      *
+      * @param object the object that you would like to be ref counted - of class T
+      *
+      * @code
+      * T object = new T();
+      * ManagedType<T> mt(t);
+      * @endcode
+      */
+    ManagedType(T* object);
+
+    /**
+      * Default constructor for the managed type, given a class space T.
+      */
+    ManagedType();
+
+    /**
+      * Copy constructor for the managed type, given a class space T.
+      *
+      * @param t another managed type instance of class type T.
+      *
+      * @code
+      * T* object = new T();
+      * ManagedType<T> mt(t);
+      * ManagedType<T> mt1(mt);
+      * @endcode
+      */
+    ManagedType(const ManagedType<T> &t);
+
+    /**
+      * Destructor for the managed type, given a class space T.
+      */
+    ~ManagedType();
+
+    /**
+      * Copy-assign member function for the managed type, given a class space.
+      *
+      * @code
+      * T* object = new T();
+      * ManagedType<T> mt(t);
+      * ManagedType<T> mt1 = mt;
+      * @endcode
+      */
+    ManagedType<T>& operator = (const ManagedType<T>&i);
+
+    /**
+      * Returns the references to this ManagedType.
+      *
+      * @code
+      * T* object = new T();
+      * ManagedType<T> mt(t);
+      * ManagedType<T> mt1(mt);
+      *
+      * mt.getReferences // this will be 2!
+      * @endcode
+      */
+    int getReferences();
+
+    /**
+      * De-reference operator overload. This makes modifying ref-counted POD
+      * easier.
+      *
+      * @code
+      * ManagedType<int> x = 0;
+      * *x = 1; // mutates the ref-counted integer
+      * @endcode
+      */
+    T& operator*() {
+        return *object;
+    }
+
+    /**
+      * Method call operator overload. This forwards the call to the underlying
+      * object.
+      *
+      * @code
+      * ManagedType<T> x = new T();
+      * x->m(); // resolves to T::m
+      */
+    T* operator->() {
+        if (object == NULL)
+            microbit_panic(MICROBIT_NULL_DEREFERENCE);
+        return object;
+    }
+
+    /**
+      * Shorthand for `x.operator->()`
+      */
+    T* get() {
+        return object;
+    }
+
+    /**
+      * A simple inequality overload to compare two ManagedType instances.
+      */
+    bool operator!=(const ManagedType<T>& x) {
+        return !(this == x);
+    }
+
+    /**
+      * A simple equality overload to compare two ManagedType instances.
+      */
+    bool operator==(const ManagedType<T>& x) {
+        return this->object == x.object;
+    }
+};
+
+/**
+  * Constructor for the managed type, given a class space T.
+  *
+  * @param object the object that you would like to be ref counted - of class T
+  *
+  * @code
+  * T object = new T();
+  * ManagedType<T> mt(t);
+  * @endcode
+  */
+template<typename T>
+ManagedType<T>::ManagedType(T* object)
+{
+    this->object = object;
+    ref = (int *)malloc(sizeof(int));
+    *ref = 1;
+}
+
+/**
+  * Default constructor for the managed type, given a class space T.
+  */
+template<typename T>
+ManagedType<T>::ManagedType()
+{
+    this->object = NULL;
+    ref = (int *)malloc(sizeof(int));
+    *ref = 0;
+}
+
+/**
+  * Copy constructor for the managed type, given a class space T.
+  *
+  * @param t another managed type instance of class type T.
+  *
+  * @code
+  * T* object = new T();
+  * ManagedType<T> mt(t);
+  * ManagedType<T> mt1(mt);
+  * @endcode
+  */
+template<typename T>
+ManagedType<T>::ManagedType(const ManagedType<T> &t)
+{
+    this->object = t.object;
+    this->ref = t.ref;
+    (*ref)++;
+}
+
+/**
+  * Destructor for the managed type, given a class space T.
+  */
+template<typename T>
+ManagedType<T>::~ManagedType()
+{
+    // Special case - we were created using a default constructor, and never assigned a value.
+    if (*ref == 0)
+    {
+        // Simply destroy our reference counter and we're done.
+        free(ref);
+    }
+
+    // Normal case - we have a valid piece of data.
+    // Decrement our reference counter and free all allocated memory if we're deleting the last reference.
+    else if (--(*ref) == 0)
+    {
+        delete object;
+        free(ref);
+    }
+}
+
+/**
+  * Copy-assign member function for the managed type, given a class space.
+  *
+  * @code
+  * T* object = new T();
+  * ManagedType<T> mt(t);
+  * ManagedType<T> mt1 = mt;
+  * @endcode
+  */
+template<typename T>
+ManagedType<T>& ManagedType<T>::operator = (const ManagedType<T>&t)
+{
+    if (this == &t)
+        return *this;
+
+    // Special case - we were created using a default constructor, and never assigned a value.
+    if (*ref == 0)
+    {
+        // Simply destroy our reference counter, as we're about to adopt another.
+        free(ref);
+    }
+
+    else if (--(*ref) == 0)
+    {
+        delete object;
+        free(ref);
+    }
+
+    object = t.object;
+    ref = t.ref;
+
+    (*ref)++;
+
+    return *this;
+}
+
+/**
+  * Returns the references to this ManagedType.
+  *
+  * @code
+  * T* object = new T();
+  * ManagedType<T> mt(t);
+  * ManagedType<T> mt1(mt);
+  *
+  * mt.getReferences // this will be 2!
+  * @endcode
+  */
+template<typename T>
+int ManagedType<T>::getReferences()
+{
+    return (*ref);
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/Matrix4.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,202 @@
+/*
+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_MATRIX4_H
+#define MICROBIT_MATRIX4_H
+
+#include "MicroBitConfig.h"
+
+/**
+* Class definition for a simple matrix, that is optimised for nx4 or 4xn matrices.
+*
+* This class is heavily optimised for these commonly used matrices as used in 3D geometry.
+* Whilst this class does support basic operations on matrices of any dimension, it is not intended as a
+* general purpose matrix class as inversion operations are only provided for 4x4 matrices.
+* For programmers needing more flexible Matrix support, the Matrix and MatrixMath classes from
+* Ernsesto Palacios provide a good basis:
+*
+* https://developer.mbed.org/cookbook/MatrixClass
+* https://developer.mbed.org/users/Yo_Robot/code/MatrixMath/
+*/
+class Matrix4
+{
+	float   *data;         // Linear buffer representing the matrix.
+	int     rows;           // The number of rows in the matrix.
+	int     cols;           // The number of columns in the matrix.
+
+public:
+
+	/**
+	  * Constructor.
+	  * Create a matrix of the given size.
+	  *
+	  * @param rows the number of rows in the matrix to be created.
+	  *
+	  * @param cols the number of columns in the matrix to be created.
+	  *
+	  * @code
+	  * Matrix4(10, 4);        // Creates a Matrix with 10 rows and 4 columns.
+	  * @endcode
+	  */
+	Matrix4(int rows, int cols);
+
+	/**
+	  * Constructor.
+	  * Create a matrix that is an identical copy of the given matrix.
+	  *
+	  * @param matrix The matrix to copy.
+	  *
+	  * @code
+	  * Matrix newMatrix(matrix);        .
+	  * @endcode
+	  */
+	Matrix4(const Matrix4 &matrix);
+
+	/**
+	  * Determines the number of columns in this matrix.
+	  *
+	  * @return The number of columns in the matrix.
+	  *
+	  * @code
+	  * int c = matrix.width();
+	  * @endcode
+	  */
+	int width();
+
+	/**
+	  * Determines the number of rows in this matrix.
+	  *
+	  * @return The number of rows in the matrix.
+	  *
+	  * @code
+	  * int r = matrix.height();
+	  * @endcode
+	  */
+	int height();
+
+	/**
+	  * Reads the matrix element at the given position.
+	  *
+	  * @param row The row of the element to read.
+	  *
+	  * @param col The column of the element to read.
+	  *
+	  * @return The value of the matrix element at the given position. 0 is returned if the given index is out of range.
+	  *
+	  * @code
+	  * float v = matrix.get(1,2);
+	  * @endcode
+	  */
+	float get(int row, int col);
+
+	/**
+	  * Writes the matrix element at the given position.
+	  *
+	  * @param row The row of the element to write.
+	  *
+	  * @param col The column of the element to write.
+	  *
+	  * @param v The new value of the element.
+	  *
+	  * @code
+	  * matrix.set(1,2,42.0);
+	  * @endcode
+	  */
+	void set(int row, int col, float v);
+
+	/**
+	  * Transposes this matrix.
+	  *
+	  * @return the resultant matrix.
+	  *
+	  * @code
+	  * matrix.transpose();
+	  * @endcode
+	  */
+	Matrix4 transpose();
+
+	/**
+	  * Multiplies this matrix with the given matrix (if possible).
+	  *
+	  * @param matrix the matrix to multiply this matrix's values against.
+	  *
+	  * @param transpose Transpose the matrices before multiplication. Defaults to false.
+	  *
+	  * @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
+	  *
+	  * @code
+	  * Matrix result = matrixA.multiply(matrixB);
+	  * @endcode
+	  */
+	Matrix4 multiply(Matrix4 &matrix, bool transpose = false);
+
+	/**
+	  * Multiplies the transpose of this matrix with the given matrix (if possible).
+      *
+	  * @param matrix the matrix to multiply this matrix's values against.
+	  *
+	  * @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
+	  *
+	  * @code
+	  * Matrix result = matrixA.multiplyT(matrixB);
+	  * @endcode
+	  */
+	Matrix4 multiplyT(Matrix4 &matrix);
+
+	/**
+	  * Performs an optimised inversion of a 4x4 matrix.
+	  * Only 4x4 matrices are supported by this operation.
+	  *
+	  * @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
+	  *
+	  * @code
+	  * Matrix result = matrixA.invert();
+	  * @endcode
+	  */
+	Matrix4 invert();
+
+	/**
+	  * Destructor.
+	  *
+	  * Frees any memory consumed by this Matrix4 instance.
+	  */
+	~Matrix4();
+};
+
+/**
+  * Multiplies the transpose of this matrix with the given matrix (if possible).
+  *
+  * @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
+  *
+  * @code
+  * Matrix result = matrixA.multiplyT(matrixB);
+  * @endcode
+  */
+inline Matrix4 Matrix4::multiplyT(Matrix4 &matrix)
+{
+    return multiply(matrix, true);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/MicroBitCoordinateSystem.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,67 @@
+/*
+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_COORDINATE_SYSTEM_H
+#define MICROBIT_COORDINATE_SYSTEM_H
+#include "MicroBitConfig.h"
+
+/**
+  * Co-ordinate systems that can be used.
+  * RAW: Unaltered data. Data will be returned directly from the accelerometer.
+  *
+  * SIMPLE_CARTESIAN: Data will be returned based on an easy to understand alignment, consistent with the cartesian system taught in schools.
+  * When held upright, facing the user:
+  *
+  *                            /
+  *    +--------------------+ z
+  *    |                    |
+  *    |       .....        |
+  *    | *     .....      * |
+  * ^  |       .....        |
+  * |  |                    |
+  * y  +--------------------+  x-->
+  *
+  *
+  * NORTH_EAST_DOWN: Data will be returned based on the industry convention of the North East Down (NED) system.
+  * When held upright, facing the user:
+  *
+  *                            z
+  *    +--------------------+ /
+  *    |                    |
+  *    |       .....        |
+  *    | *     .....      * |
+  * ^  |       .....        |
+  * |  |                    |
+  * x  +--------------------+  y-->
+  *
+  */
+enum MicroBitCoordinateSystem
+{
+    RAW,
+    SIMPLE_CARTESIAN,
+    NORTH_EAST_DOWN
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/MicroBitEvent.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,106 @@
+/*
+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_EVENT_H
+#define MICROBIT_EVENT_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+
+// Wildcard event codes
+#define MICROBIT_ID_ANY         0
+#define MICROBIT_EVT_ANY        0
+
+enum MicroBitEventLaunchMode
+{
+    CREATE_ONLY,
+    CREATE_AND_FIRE
+};
+
+#define MICROBIT_EVENT_DEFAULT_LAUNCH_MODE     CREATE_AND_FIRE
+
+/**
+  * Class definition for a MicroBitEvent
+  *
+  * It represents a common event that is generated by the various components on the micro:bit.
+  */
+class MicroBitEvent
+{
+    public:
+
+    uint16_t source;         // ID of the MicroBit Component that generated the event e.g. MICROBIT_ID_BUTTON_A.
+    uint16_t value;          // Component specific code indicating the cause of the event.
+    uint32_t timestamp;      // Time at which the event was generated. ms since power on.
+
+    /**
+      * Constructor.
+      *
+      * @param src The id of the MicroBit Component that generated the event e.g. MICROBIT_ID_BUTTON_A.
+      *
+      * @param value A component specific code indicating the cause of the event.
+      *
+      * @param mode Optional definition of how the event should be processed after construction (if at all):
+      *                 CREATE_ONLY: MicroBitEvent is initialised, and no further processing takes place.
+      *                 CREATE_AND_FIRE: MicroBitEvent is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!).
+      *
+      * @code
+      * // Create and launch an event using the default configuration
+      * MicrobitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK);
+      *
+      * // Create an event only, do not fire onto an EventModel.
+      * MicrobitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK,CREATE_AND_FIRE);
+      * @endcode
+      */
+    MicroBitEvent(uint16_t source, uint16_t value, MicroBitEventLaunchMode mode = MICROBIT_EVENT_DEFAULT_LAUNCH_MODE);
+
+    /**
+      * Default constructor - initialises all values, and sets timestamp to the current time.
+      */
+    MicroBitEvent();
+
+    /**
+      * Fires this MicroBitEvent onto the Default EventModel, or a custom one!
+      */
+    void fire();
+};
+
+/**
+  * Enclosing class to hold a chain of events.
+  */
+struct MicroBitEventQueueItem
+{
+    MicroBitEvent evt;
+    MicroBitEventQueueItem *next;
+
+    /**
+      * Constructor.
+      * Create a new MicroBitEventQueueItem.
+      *
+      * @param evt The event to be queued.
+      */
+    MicroBitEventQueueItem(MicroBitEvent evt);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/MicroBitImage.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,480 @@
+/*
+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_IMAGE_H
+#define MICROBIT_IMAGE_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "ManagedString.h"
+#include "RefCounted.h"
+
+struct ImageData : RefCounted
+{
+    uint16_t width;     // Width in pixels
+    uint16_t height;    // Height in pixels
+    uint8_t data[0];    // 2D array representing the bitmap image
+};
+
+/**
+  * Class definition for a MicroBitImage.
+  *
+  * An MicroBitImage is a simple bitmap representation of an image.
+  * n.b. This is a mutable, managed type.
+  */
+class MicroBitImage
+{
+    ImageData *ptr;     // Pointer to payload data
+
+
+    /**
+      * Internal constructor which provides sanity checking and initialises class properties.
+      *
+      * @param x the width of the image
+      *
+      * @param y the height of the image
+      *
+      * @param bitmap an array of integers that make up an image.
+      */
+    void init(const int16_t x, const int16_t y, const uint8_t *bitmap);
+
+    /**
+      * Internal constructor which defaults to the Empty Image instance variable
+      */
+    void init_empty();
+
+    public:
+    static MicroBitImage EmptyImage;    // Shared representation of a null image.
+
+    /**
+      * Get current ptr, do not decr() it, and set the current instance to empty image.
+      *
+      * This is to be used by specialized runtimes which pass ImageData around.
+      */
+    ImageData *leakData();
+
+    /**
+      * Return a 2D array representing the bitmap image.
+      */
+    uint8_t *getBitmap()
+    {
+        return ptr->data;
+    }
+
+    /**
+      * Constructor.
+      * Create an image from a specially prepared constant array, with no copying. Will call ptr->incr().
+      *
+      * @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height are 16 bit. The literal has to be 4-byte aligned.
+      *
+      * @code
+      * static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i((ImageData*)(void*)heart);
+      * @endcode
+      */
+    MicroBitImage(ImageData *ptr);
+
+    /**
+      * Default Constructor.
+      * Creates a new reference to the empty MicroBitImage bitmap
+      *
+      * @code
+      * MicroBitImage i(); //an empty image instance
+      * @endcode
+      */
+    MicroBitImage();
+
+
+    /**
+      * Copy Constructor.
+      * Add ourselves as a reference to an existing MicroBitImage.
+      *
+      * @param image The MicroBitImage to reference.
+      *
+      * @code
+      * MicroBitImage i("0,1,0,1,0\n");
+      * MicroBitImage i2(i); //points to i
+      * @endcode
+      */
+    MicroBitImage(const MicroBitImage &image);
+
+    /**
+      * Constructor.
+      * Create a blank bitmap representation of a given size.
+      *
+      * @param s A text based representation of the image given whitespace delimited numeric values.
+      *
+      * @code
+      * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+      * @endcode
+      */
+    explicit MicroBitImage(const char *s);
+
+    /**
+      * Constructor.
+      * Create a blank bitmap representation of a given size.
+      *
+      * @param x the width of the image.
+      *
+      * @param y the height of the image.
+      *
+      * Bitmap buffer is linear, with 8 bits per pixel, row by row,
+      * top to bottom with no word alignment. Stride is therefore the image width in pixels.
+      * in where w and h are width and height respectively, the layout is therefore:
+      *
+      * |[0,0]...[w,o][1,0]...[w,1]  ...  [[w,h]
+      *
+      * A copy of the image is made in RAM, as images are mutable.
+      */
+    MicroBitImage(const int16_t x, const int16_t y);
+
+    /**
+      * Constructor.
+      * Create a bitmap representation of a given size, based on a given buffer.
+      *
+      * @param x the width of the image.
+      *
+      * @param y the height of the image.
+      *
+      * @param bitmap a 2D array representing the image.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * @endcode
+      */
+    MicroBitImage(const int16_t x, const int16_t y, const uint8_t *bitmap);
+
+    /**
+      * Destructor.
+      *
+      * Removes buffer resources held by the instance.
+      */
+    ~MicroBitImage();
+
+    /**
+      * Copy assign operation.
+      *
+      * Called when one MicroBitImage is assigned the value of another using the '=' operator.
+      *
+      * Decrement our reference count and free up the buffer as necessary.
+      *
+      * Then, update our buffer to refer to that of the supplied MicroBitImage,
+      * and increase its reference count.
+      *
+      * @param s The MicroBitImage to reference.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * MicroBitImage i1();
+      * i1 = i; // i1 now references i
+      * @endcode
+      */
+    MicroBitImage& operator = (const MicroBitImage& i);
+
+
+    /**
+      * Equality operation.
+      *
+      * Called when one MicroBitImage is tested to be equal to another using the '==' operator.
+      *
+      * @param i The MicroBitImage to test ourselves against.
+      *
+      * @return true if this MicroBitImage is identical to the one supplied, false otherwise.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * MicroBitImage i();
+      * MicroBitImage i1();
+      *
+      * if(i == i1) //will be true
+      *     display.scroll("true");
+      * @endcode
+      */
+    bool operator== (const MicroBitImage& i);
+
+    /**
+      * Resets all pixels in this image to 0.
+      *
+      * @code
+      * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+      * i.clear();
+      * @endcode
+      */
+    void clear();
+
+    /**
+      * Sets the pixel at the given co-ordinates to a given value.
+      *
+      * @param x The co-ordinate of the pixel to change.
+      *
+      * @param y The co-ordinate of the pixel to change.
+      *
+      * @param value The new value of the pixel (the brightness level 0-255)
+      *
+      * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+      * i.setPixelValue(0,0,255);
+      * @endcode
+      *
+      * @note all coordinates originate from the top left of an image.
+      */
+    int setPixelValue(int16_t x , int16_t y, uint8_t value);
+
+    /**
+      * Retreives the value of a given pixel.
+      *
+      * @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image.
+      *
+      * @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image.
+      *
+      * @return The value assigned to the given pixel location (the brightness level 0-255), or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+      * i.getPixelValue(0,0); //should be 0;
+      * @endcode
+      */
+    int getPixelValue(int16_t x , int16_t y);
+
+    /**
+      * Replaces the content of this image with that of a given 2D array representing
+      * the image.
+      *
+      * @param x the width of the image. Must be within the dimensions of the image.
+      *
+      * @param y the width of the image. Must be within the dimensions of the image.
+      *
+      * @param bitmap a 2D array representing the image.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i();
+      * i.printImage(0,0,heart);
+      * @endcode
+      *
+      * @note all coordinates originate from the top left of an image.
+      */
+    int printImage(int16_t x, int16_t y, const uint8_t *bitmap);
+
+    /**
+      * Pastes a given bitmap at the given co-ordinates.
+      *
+      * Any pixels in the relvant area of this image are replaced.
+      *
+      * @param image The MicroBitImage to paste.
+      *
+      * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0.
+      *
+      * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0.
+      *
+      * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 otherwise.  Defaults to 0.
+      *
+      * @return The number of pixels written.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart); // a big heart
+      * i.paste(i, -5, 0); // a small heart
+      * @endcode
+      */
+    int paste(const MicroBitImage &image, int16_t x = 0, int16_t y = 0, uint8_t alpha = 0);
+
+     /**
+       * Prints a character to the display at the given location
+       *
+       * @param c The character to display.
+       *
+       * @param x The x co-ordinate of on the image to place the top left of the character. Defaults to 0.
+       *
+       * @param y The y co-ordinate of on the image to place the top left of the character. Defaults to 0.
+       *
+       * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+       *
+       * @code
+       * MicroBitImage i(5,5);
+       * i.print('a');
+       * @endcode
+       */
+    int print(char c, int16_t x = 0, int16_t y = 0);
+
+    /**
+      * Shifts the pixels in this Image a given number of pixels to the left.
+      *
+      * @param n The number of pixels to shift.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart); // a big heart
+      * i.shiftLeft(5); // a small heart
+      * @endcode
+      */
+    int shiftLeft(int16_t n);
+
+    /**
+      * Shifts the pixels in this Image a given number of pixels to the right.
+      *
+      * @param n The number of pixels to shift.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart); // a big heart
+      * i.shiftLeft(5); // a small heart
+      * i.shiftRight(5); // a big heart
+      * @endcode
+      */
+    int shiftRight(int16_t n);
+
+    /**
+      * Shifts the pixels in this Image a given number of pixels to upward.
+      *
+      * @param n The number of pixels to shift.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * i.shiftUp(1);
+      * @endcode
+      */
+    int shiftUp(int16_t n);
+
+    /**
+      * Shifts the pixels in this Image a given number of pixels to downward.
+      *
+      * @param n The number of pixels to shift.
+      *
+      * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * i.shiftDown(1);
+      * @endcode
+      */
+    int shiftDown(int16_t n);
+
+    /**
+      * Gets the width of this image.
+      *
+      * @return The width of this image.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * i.getWidth(); // equals 10...
+      * @endcode
+      */
+    int getWidth() const
+    {
+        return ptr->width;
+    }
+
+    /**
+      * Gets the height of this image.
+      *
+      * @return The height of this image.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * i.getHeight(); // equals 5...
+      * @endcode
+      */
+    int getHeight() const
+    {
+        return ptr->height;
+    }
+
+    /**
+      * Gets number of bytes in the bitmap, ie., width * height.
+      *
+      * @return The size of the bitmap.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * i.getSize(); // equals 50...
+      * @endcode
+      */
+    int getSize() const
+    {
+        return ptr->width * ptr->height;
+    }
+
+    /**
+      * Converts the bitmap to a csv ManagedString.
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * uBit.serial.printString(i.toString()); // "0,1,0,1,0,0,0,0,0,0\n..."
+      * @endcode
+      */
+    ManagedString toString();
+
+    /**
+      * Crops the image to the given dimensions.
+      *
+      * @param startx the location to start the crop in the x-axis
+      *
+      * @param starty the location to start the crop in the y-axis
+      *
+      * @param width the width of the desired cropped region
+      *
+      * @param height the height of the desired cropped region
+      *
+      * @code
+      * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+      * MicroBitImage i(10,5,heart);
+      * i.crop(0,0,2,2).toString() // "0,1\n1,1\n"
+      * @endcode
+      */
+    MicroBitImage crop(int startx, int starty, int finx, int finy);
+
+    /**
+      * Check if image is read-only (i.e., residing in flash).
+      */
+    bool isReadOnly();
+
+    /**
+      * Create a copy of the image bitmap. Used particularly, when isReadOnly() is true.
+      *
+      * @return an instance of MicroBitImage which can be modified independently of the current instance
+      */
+    MicroBitImage clone();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/PacketBuffer.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,269 @@
+/*
+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_PACKET_BUFFER_H
+#define MICROBIT_PACKET_BUFFER_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "RefCounted.h"
+
+struct PacketData : RefCounted
+{
+    uint16_t        rssi;               // The radio signal strength this packet was received.
+    uint8_t         length;             // The length of the payload in bytes
+    uint8_t         payload[0];         // User / higher layer protocol data
+};
+
+/**
+  * Class definition for a PacketBuffer.
+  * A PacketBuffer holds a series of bytes that can be sent or received from the MicroBitRadio channel.
+  *
+  * @note This is a mutable, managed type.
+  */
+class PacketBuffer
+{
+    PacketData      *ptr;     // Pointer to payload data
+
+    public:
+
+    /**
+      * Provide a pointer to a memory location containing the packet data.
+      *
+      * @return The contents of this packet, as an array of bytes.
+      */
+    uint8_t *getBytes();
+
+    /**
+      * Default Constructor.
+      * Creates an empty Packet Buffer.
+      *
+      * @code
+      * PacketBuffer p();
+      * @endcode
+      */
+    PacketBuffer();
+
+    /**
+      * Constructor.
+      * Creates a new PacketBuffer of the given size.
+      *
+      * @param length The length of the buffer to create.
+      *
+      * @code
+      * PacketBuffer p(16);         // Creates a PacketBuffer 16 bytes long.
+      * @endcode
+      */
+    PacketBuffer(int length);
+
+    /**
+      * Constructor.
+      * Creates an empty Packet Buffer of the given size,
+      * and fills it with the data provided.
+      *
+      * @param data The data with which to fill the buffer.
+      *
+      * @param length The length of the buffer to create.
+      *
+      * @param rssi The radio signal strength at the time this packet was recieved. Defaults to 0.
+      *
+      * @code
+      * uint8_t buf = {13,5,2};
+      * PacketBuffer p(buf, 3);         // Creates a PacketBuffer 3 bytes long.
+      * @endcode
+      */
+    PacketBuffer(uint8_t *data, int length, int rssi = 0);
+
+    /**
+      * Copy Constructor.
+      * Add ourselves as a reference to an existing PacketBuffer.
+      *
+      * @param buffer The PacketBuffer to reference.
+      *
+      * @code
+      * PacketBuffer p();
+      * PacketBuffer p2(p); // Refers to the same packet as p.
+      * @endcode
+      */
+    PacketBuffer(const PacketBuffer &buffer);
+
+    /**
+      * Internal constructor-initialiser.
+      *
+      * @param data The data with which to fill the buffer.
+      *
+      * @param length The length of the buffer to create.
+      *
+      * @param rssi The radio signal strength at the time this packet was recieved.
+      */
+    void init(uint8_t *data, int length, int rssi);
+
+    /**
+      * Destructor.
+      *
+      * Removes buffer resources held by the instance.
+      */
+    ~PacketBuffer();
+
+    /**
+      * Copy assign operation.
+      *
+      * Called when one PacketBuffer is assigned the value of another using the '=' operator.
+      *
+      * Decrements our reference count and free up the buffer as necessary.
+      *
+      * Then, update our buffer to refer to that of the supplied PacketBuffer,
+      * and increase its reference count.
+      *
+      * @param p The PacketBuffer to reference.
+      *
+      * @code
+      * uint8_t buf = {13,5,2};
+      * PacketBuffer p1(16);
+      * PacketBuffer p2(buf, 3);
+      *
+      * p1 = p2;
+      * @endcode
+      */
+    PacketBuffer& operator = (const PacketBuffer& p);
+
+    /**
+      * Array access operation (read).
+      *
+      * Called when a PacketBuffer is dereferenced with a [] operation.
+      *
+      * Transparently map this through to the underlying payload for elegance of programming.
+      *
+      * @code
+      * PacketBuffer p1(16);
+      * uint8_t data = p1[0];
+      * @endcode
+      */
+    uint8_t operator [] (int i) const;
+
+    /**
+      * Array access operation (modify).
+      *
+      * Called when a PacketBuffer is dereferenced with a [] operation.
+      *
+      * Transparently map this through to the underlying payload for elegance of programming.
+      *
+      * @code
+      * PacketBuffer p1(16);
+      * p1[0] = 42;
+      * @endcode
+      */
+    uint8_t& operator [] (int i);
+
+    /**
+      * Equality operation.
+      *
+      * Called when one PacketBuffer is tested to be equal to another using the '==' operator.
+      *
+      * @param p The PacketBuffer to test ourselves against.
+      *
+      * @return true if this PacketBuffer is identical to the one supplied, false otherwise.
+      *
+      * @code
+      * MicroBitDisplay display;
+      * uint8_t buf = {13,5,2};
+      * PacketBuffer p1();
+      * PacketBuffer p2();
+      *
+      * if(p1 == p2)                    // will be true
+      *     display.scroll("same!");
+      * @endcode
+      */
+    bool operator== (const PacketBuffer& p);
+
+    /**
+      * Sets the byte at the given index to value provided.
+      *
+      * @param position The index of the byte to change.
+      *
+      * @param value The new value of the byte (0-255).
+      *
+      * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * PacketBuffer p1(16);
+      * p1.setByte(0,255);              // Sets the first byte in the buffer to the value 255.
+      * @endcode
+      */
+    int setByte(int position, uint8_t value);
+
+    /**
+      * Determines the value of the given byte in the packet.
+      *
+      * @param position The index of the byte to read.
+      *
+      * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER.
+      *
+      * @code
+      * PacketBuffer p1(16);
+      * p1.setByte(0,255);              // Sets the first byte in the buffer to the value 255.
+      * p1.getByte(0);                  // Returns 255.
+      * @endcode
+      */
+    int getByte(int position);
+
+    /**
+      * Gets number of bytes in this buffer
+      *
+      * @return The size of the buffer in bytes.
+      *
+      * @code
+      * PacketBuffer p1(16);
+      * p1.length(); // Returns 16.
+      * @endcode
+      */
+    int length();
+
+    /**
+      * Retrieves the received signal strength of this packet.
+      *
+      * @return The signal strength of the radio when this packet was received, in -dbM.
+      *
+      * @code
+      * PacketBuffer p1(16);
+      * p1.getRSSI();                 // Returns the received signal strength.
+      * @endcode
+      */
+    int getRSSI();
+
+    /**
+      * Sets the received signal strength of this packet.
+      *
+      * @code
+      * PacketBuffer p1(16);
+      * p1.setRSSI(37);
+      * @endcode
+      */
+    void setRSSI(uint8_t rssi);
+
+    static PacketBuffer EmptyPacket;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/types/RefCounted.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,72 @@
+/*
+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 REF_COUNTED_H
+#define REF_COUNTED_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitDevice.h"
+
+/**
+  * Base class for payload for ref-counted objects. Used by ManagedString and MicroBitImage.
+  * There is no constructor, as this struct is typically malloc()ed.
+  */
+struct RefCounted
+{
+public:
+
+    /**
+      * The high 15 bits hold the number of outstanding references. The lowest bit is always 1
+      * to make sure it doesn't look like vtable.
+      * Should never be even or one (object should be deleted then).
+      * When it's set to 0xffff, it means the object sits in flash and should not be counted.
+      */
+    uint16_t refCount;
+
+    /**
+      * Increment reference count.
+      */
+    void incr();
+
+    /**
+      * Decrement reference count.
+      */
+    void decr();
+
+    /**
+      * Initializes for one outstanding reference.
+      */
+    void init();
+
+    /**
+      * Checks if the object resides in flash memory.
+      *
+      * @return true if the object resides in flash memory, false otherwise.
+      */
+    bool isReadOnly();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/module.json	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,28 @@
+{
+  "name": "microbit-dal",
+  "version": "2.0.0-rc1",
+  "license": "MIT",
+  "description": "The runtime library for the BBC micro:bit, developed by Lancaster University",
+  "keywords": [
+    "mbed-classic",
+    "microbit",
+    "runtime",
+    "library",
+    "lancaster",
+    "University"
+  ],
+  "author": "Joe Finney <j.finney@lancaster.ac.uk (mailto:j.finney@lancaster.ac.uk) >",
+  "homepage": "https://github.com/lancaster-university/microbit-dal/",
+  "dependencies": {
+    "mbed-classic": "lancaster-university/mbed-classic#microbit_hfclk+mb2",
+    "ble": "lancaster-university/BLE_API#v2.5.0+mb3",
+    "ble-nrf51822": "lancaster-university/nrf51822#v2.5.0+mb5",
+    "nrf51-sdk": "lancaster-university/nrf51-sdk#v2.2.0+mb3"
+  },
+  "extraIncludes": [
+    "inc/core",
+    "inc/types",
+    "inc/drivers",
+    "inc/bluetooth"
+  ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/CMakeLists.txt	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,104 @@
+# This file is no longer auto-generated to make the repository builds with GCC
+# and ARMCC no matter what.
+
+cmake_minimum_required(VERSION 2.8.12)
+
+enable_language(ASM)
+
+set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
+    "core/MemberFunctionCallback.cpp"
+    "core/MicroBitCompat.cpp"
+    "core/MicroBitDevice.cpp"
+    "core/MicroBitFiber.cpp"
+    "core/MicroBitFont.cpp"
+    "core/MicroBitHeapAllocator.cpp"
+    "core/MicroBitListener.cpp"
+    "core/MicroBitSystemTimer.cpp"
+
+    "types/ManagedString.cpp"
+    "types/Matrix4.cpp"
+    "types/MicroBitEvent.cpp"
+    "types/MicroBitImage.cpp"
+    "types/PacketBuffer.cpp"
+    "types/RefCounted.cpp"
+
+    "drivers/DynamicPwm.cpp"
+    "drivers/MicroBitAccelerometer.cpp"
+    "drivers/MicroBitButton.cpp"
+    "drivers/MicroBitCompass.cpp"
+    "drivers/MicroBitCompassCalibrator.cpp"
+    "drivers/MicroBitDisplay.cpp"
+    "drivers/MicroBitI2C.cpp"
+    "drivers/MicroBitIO.cpp"
+    "drivers/MicroBitLightSensor.cpp"
+    "drivers/MicroBitMessageBus.cpp"
+    "drivers/MicroBitMultiButton.cpp"
+    "drivers/MicroBitPin.cpp"
+    "drivers/MicroBitRadio.cpp"
+    "drivers/MicroBitRadioDatagram.cpp"
+    "drivers/MicroBitRadioEvent.cpp"
+    "drivers/MicroBitSerial.cpp"
+    "drivers/MicroBitStorage.cpp"
+    "drivers/MicroBitThermometer.cpp"
+
+    "bluetooth/MicroBitAccelerometerService.cpp"
+    "bluetooth/MicroBitBLEManager.cpp"
+    "bluetooth/MicroBitButtonService.cpp"
+    "bluetooth/MicroBitDFUService.cpp"
+    "bluetooth/MicroBitEventService.cpp"
+    "bluetooth/MicroBitIOPinService.cpp"
+    "bluetooth/MicroBitLEDService.cpp"
+    "bluetooth/MicroBitMagnetometerService.cpp"
+    "bluetooth/MicroBitTemperatureService.cpp"
+    "bluetooth/MicroBitUARTService.cpp"
+)
+
+execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "log" "--pretty=format:%h" "-n" "1" OUTPUT_VARIABLE git_hash)
+execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE git_branch OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if ("${git_branch}" STREQUAL "master")
+    set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}")
+else()
+    set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}-${git_branch}-g${git_hash}")
+endif()
+
+set(MICROBIT_DAL_VERSION_FLAGS "-DMICROBIT_DAL_VERSION=\\\"${MICROBIT_DAL_VERSION_STRING}\\\"")
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MICROBIT_DAL_VERSION_FLAGS}")
+
+if (YOTTA_CFG_MICROBIT_CONFIGFILE)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${YOTTA_FORCE_INCLUDE_FLAG} \"${YOTTA_CFG_MICROBIT_CONFIGFILE}\"")
+endif ()
+
+if(CMAKE_COMPILER_IS_GNUCC)
+  file(REMOVE "asm/CortexContextSwitch.s")
+  configure_file("asm/CortexContextSwitch.s.gcc" "asm/CortexContextSwitch.s" COPYONLY)
+else()
+  file(REMOVE "asm/CortexContextSwitch.s")
+  configure_file("asm/CortexContextSwitch.s.armcc" "asm/CortexContextSwitch.s" COPYONLY)
+endif()
+
+set(YOTTA_AUTO_MICROBIT-DAL_S_FILES
+    "asm/CortexContextSwitch.s"
+)
+
+add_library(microbit-dal
+    ${YOTTA_AUTO_MICROBIT-DAL_CPP_FILES}
+    ${YOTTA_AUTO_MICROBIT-DAL_S_FILES}
+)
+
+yotta_postprocess_target(LIBRARY microbit-dal)
+
+target_link_libraries(microbit-dal
+    mbed-classic
+    ble
+    ble-nrf51822
+)
+
+if(CMAKE_COMPILER_IS_GNUCC)
+    message("suppressing ALL warnings from mbed-classic, ble, ble-nrf51822 & nrf51-sdk")
+    target_compile_options(mbed-classic PRIVATE "-w")
+    target_compile_options(ble PRIVATE "-w")
+    target_compile_options(ble-nrf51822 PRIVATE "-w")
+    target_compile_options(nrf51-sdk PRIVATE "-w")
+endif()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/asm/CortexContextSwitch.s.armcc	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,293 @@
+; 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.
+
+   AREA asm_func, CODE, READONLY
+
+; Export our context switching subroutine as a C function for use in mbed
+    EXPORT swap_context
+    EXPORT save_context
+    EXPORT save_register_context
+    EXPORT restore_register_context
+
+    ALIGN
+
+; R0 Contains a pointer to the TCB of the fibre being scheduled out.
+; R1 Contains a pointer to the TCB of the fibre being scheduled in.
+; R2 Contains a pointer to the base of the stack of the fibre being scheduled out.
+; R3 Contains a pointer to the base of the stack of the fibre being scheduled in.
+
+swap_context
+
+    ; Write our core registers into the TCB
+    ; First, store the general registers
+
+    ; Skip this is we're given a NULL parameter for the TCB
+    CMP     R0, #0
+    BEQ     store_context_complete
+
+    STR     R0, [R0,#0]
+    STR     R1, [R0,#4]
+    STR     R2, [R0,#8]
+    STR     R3, [R0,#12]
+    STR     R4, [R0,#16]
+    STR     R5, [R0,#20]
+    STR     R6, [R0,#24]
+    STR     R7, [R0,#28]
+
+    ; Now the high general purpose registers
+    MOV     R4, R8
+    STR     R4, [R0,#32]
+    MOV     R4, R9
+    STR     R4, [R0,#36]
+    MOV     R4, R10
+    STR     R4, [R0,#40]
+    MOV     R4, R11
+    STR     R4, [R0,#44]
+    MOV     R4, R12
+    STR     R4, [R0,#48]
+
+    ; Now the Stack and Link Register.
+    ; As this context is only intended for use with a fiber scheduler,
+    ; we don't need the PC.
+    MOV     R6, SP
+    STR     R6, [R0,#52]
+    MOV     R4, LR
+    STR     R4, [R0,#56]
+
+store_context_complete
+    ; Finally, Copy the stack. We do this to reduce RAM footprint, as stack is usually very small at the point
+    ; of scheduling, but we need a lot of capacity for interrupt handling and other functions.
+
+    ; Skip this is we're given a NULL parameter for the stack.
+    CMP     R2, #0
+    BEQ     store_stack_complete
+
+    LDR     R4, [R0,#60]         ; Load R4 with the fiber's defined stack_base.
+store_stack
+    SUBS    R4, #4
+    SUBS    R2, #4
+
+    LDR     R5, [R4]
+    STR     R5, [R2]
+
+    CMP     R4, R6
+    BNE     store_stack
+
+store_stack_complete
+
+    ;
+    ; Now page in the new context.
+    ; Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler.
+    ;
+    LDR     R4, [R1, #56]
+    MOV     LR, R4
+    LDR     R6, [R1, #52]
+    MOV     SP, R6
+
+    ; Copy the stack in.
+    ; n.b. we do this after setting the SP to make comparisons easier.
+
+    ; Skip this is we're given a NULL parameter for the stack.
+    CMP     R3, #0
+    BEQ     restore_stack_complete
+
+    LDR     R4, [R1,#60]         ; Load R4 with the fiber's defined stack_base.
+
+restore_stack
+    SUBS    R4, #4
+    SUBS    R3, #4
+
+    LDR     R5, [R3]
+    STR     R5, [R4]
+
+    CMP     R4, R6
+    BNE     restore_stack
+
+restore_stack_complete
+    LDR     R4, [R1, #48]
+    MOV     R12, R4
+    LDR     R4, [R1, #44]
+    MOV     R11, R4
+    LDR     R4, [R1, #40]
+    MOV     R10, R4
+    LDR     R4, [R1, #36]
+    MOV     R9, R4
+    LDR     R4, [R1, #32]
+    MOV     R8, R4
+
+    LDR     R7, [R1, #28]
+    LDR     R6, [R1, #24]
+    LDR     R5, [R1, #20]
+    LDR     R4, [R1, #16]
+    LDR     R3, [R1, #12]
+    LDR     R2, [R1, #8]
+    LDR     R0, [R1, #0]
+    LDR     R1, [R1, #4]
+
+    ; Return to caller (scheduler).
+    BX      LR
+
+
+; R0 Contains a pointer to the TCB of the fibre to snapshot
+; R1 Contains a pointer to the base of the stack of the fibre being snapshotted
+
+save_context
+
+    ; Write our core registers into the TCB
+    ; First, store the general registers
+
+    STR     R0, [R0,#0]
+    STR     R1, [R0,#4]
+    STR     R2, [R0,#8]
+    STR     R3, [R0,#12]
+    STR     R4, [R0,#16]
+    STR     R5, [R0,#20]
+    STR     R6, [R0,#24]
+    STR     R7, [R0,#28]
+
+    ; Now the high general purpose registers
+    MOV     R4, R8
+    STR     R4, [R0,#32]
+    MOV     R4, R9
+    STR     R4, [R0,#36]
+    MOV     R4, R10
+    STR     R4, [R0,#40]
+    MOV     R4, R11
+    STR     R4, [R0,#44]
+    MOV     R4, R12
+    STR     R4, [R0,#48]
+
+    ; Now the Stack and Link Register.
+    ; As this context is only intended for use with a fiber scheduler,
+    ; we don't need the PC.
+    MOV     R6, SP
+    STR     R6, [R0,#52]
+    MOV     R4, LR
+    STR     R4, [R0,#56]
+
+    ; Finally, Copy the stack. We do this to reduce RAM footprint, as stackis usually very small at the point
+    ; of sceduling, but we need a lot of capacity for interrupt handling and other functions.
+
+    LDR     R4, [R0,#60]         ; Load R4 with the fiber's defined stack_base.
+
+store_stack1
+    SUBS    R4, #4
+    SUBS    R1, #4
+
+    LDR     R5, [R4]
+    STR     R5, [R1]
+
+    CMP     R4, R6
+    BNE     store_stack1
+
+    ; Restore scratch registers.
+
+    LDR     R7, [R0, #28]
+    LDR     R6, [R0, #24]
+    LDR     R5, [R0, #20]
+    LDR     R4, [R0, #16]
+
+    ; Return to caller (scheduler).
+    BX      LR
+
+
+; R0 Contains a pointer to the TCB of the fiber to snapshot
+save_register_context
+
+    ; Write our core registers into the TCB
+    ; First, store the general registers
+
+    STR     R0, [R0,#0]
+    STR     R1, [R0,#4]
+    STR     R2, [R0,#8]
+    STR     R3, [R0,#12]
+    STR     R4, [R0,#16]
+    STR     R5, [R0,#20]
+    STR     R6, [R0,#24]
+    STR     R7, [R0,#28]
+
+    ; Now the high general purpose registers
+    MOV     R4, R8
+    STR     R4, [R0,#32]
+    MOV     R4, R9
+    STR     R4, [R0,#36]
+    MOV     R4, R10
+    STR     R4, [R0,#40]
+    MOV     R4, R11
+    STR     R4, [R0,#44]
+    MOV     R4, R12
+    STR     R4, [R0,#48]
+
+    ; Now the Stack Pointer and Link Register.
+    ; As this context is only intended for use with a fiber scheduler,
+    ; we don't need the PC.
+    MOV     R4, SP
+    STR     R4, [R0,#52]
+    MOV     R4, LR
+    STR     R4, [R0,#56]
+
+    ; Restore scratch registers.
+    LDR     R4, [R0, #16]
+
+    ; Return to caller (scheduler).
+    BX      LR
+
+
+restore_register_context
+
+    ;
+    ; Now page in the new context.
+    ; Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler.
+    ;
+    LDR     R4, [R0, #56]
+    MOV     LR, R4
+    LDR     R4, [R0, #52]
+    MOV     SP, R4
+
+    ; High registers...
+    LDR     R4, [R0, #48]
+    MOV     R12, R4
+    LDR     R4, [R0, #44]
+    MOV     R11, R4
+    LDR     R4, [R0, #40]
+    MOV     R10, R4
+    LDR     R4, [R0, #36]
+    MOV     R9, R4
+    LDR     R4, [R0, #32]
+    MOV     R8, R4
+
+    ; Low registers...
+    LDR     R7, [R0, #28]
+    LDR     R6, [R0, #24]
+    LDR     R5, [R0, #20]
+    LDR     R4, [R0, #16]
+    LDR     R3, [R0, #12]
+    LDR     R2, [R0, #8]
+    LDR     R0, [R0, #0]
+    LDR     R1, [R0, #4]
+
+    ; Return to caller (normally the scheduler).
+    BX      LR
+
+    ALIGN
+    END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/asm/CortexContextSwitch.s.gcc	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,292 @@
+@ 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.
+
+    .syntax unified
+    .cpu cortex-m0
+    .thumb
+    .text
+    .align 2
+
+@ Export our context switching subroutine as a C function for use in mbed
+    .global swap_context
+    .global save_context
+    .global save_register_context
+    .global restore_register_context
+
+@ R0 Contains a pointer to the TCB of the fibre being scheduled out.
+@ R1 Contains a pointer to the TCB of the fibre being scheduled in.
+@ R2 Contains a pointer to the base of the stack of the fibre being scheduled out.
+@ R3 Contains a pointer to the base of the stack of the fibre being scheduled in.
+
+swap_context:
+
+    @ Write our core registers into the TCB
+    @ First, store the general registers
+
+    @ Skip this is we're given a NULL parameter for the TCB
+    CMP     R0, #0
+    BEQ     store_context_complete
+
+    STR     R0, [R0,#0]
+    STR     R1, [R0,#4]
+    STR     R2, [R0,#8]
+    STR     R3, [R0,#12]
+    STR     R4, [R0,#16]
+    STR     R5, [R0,#20]
+    STR     R6, [R0,#24]
+    STR     R7, [R0,#28]
+
+    @ Now the high general purpose registers
+    MOV     R4, R8
+    STR     R4, [R0,#32]
+    MOV     R4, R9
+    STR     R4, [R0,#36]
+    MOV     R4, R10
+    STR     R4, [R0,#40]
+    MOV     R4, R11
+    STR     R4, [R0,#44]
+    MOV     R4, R12
+    STR     R4, [R0,#48]
+
+    @ Now the Stack and Link Register.
+    @ As this context is only intended for use with a fiber scheduler,
+    @ we don't need the PC.
+    MOV     R6, SP
+    STR     R6, [R0,#52]
+    MOV     R4, LR
+    STR     R4, [R0,#56]
+
+store_context_complete:
+    @ Finally, Copy the stack. We do this to reduce RAM footprint, as stack is usually very small at the point
+    @ of scheduling, but we need a lot of capacity for interrupt handling and other functions.
+
+    @ Skip this is we're given a NULL parameter for the stack.
+    CMP     R2, #0
+    BEQ     store_stack_complete
+
+    LDR     R4, [R0,#60]         @ Load R4 with the fiber's defined stack_base.
+store_stack:
+    SUBS    R4, #4
+    SUBS    R2, #4
+
+    LDR     R5, [R4]
+    STR     R5, [R2]
+
+    CMP     R4, R6
+    BNE     store_stack
+
+store_stack_complete:
+
+    @
+    @ Now page in the new context.
+    @ Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler.
+    @
+    LDR     R4, [R1, #56]
+    MOV     LR, R4
+    LDR     R6, [R1, #52]
+    MOV     SP, R6
+
+    @ Copy the stack in.
+    @ n.b. we do this after setting the SP to make comparisons easier.
+
+    @ Skip this is we're given a NULL parameter for the stack.
+    CMP     R3, #0
+    BEQ     restore_stack_complete
+
+    LDR     R4, [R1,#60]         @ Load R4 with the fiber's defined stack_base.
+
+restore_stack:
+    SUBS    R4, #4
+    SUBS    R3, #4
+
+    LDR     R5, [R3]
+    STR     R5, [R4]
+
+    CMP     R4, R6
+    BNE     restore_stack
+
+restore_stack_complete:
+    LDR     R4, [R1, #48]
+    MOV     R12, R4
+    LDR     R4, [R1, #44]
+    MOV     R11, R4
+    LDR     R4, [R1, #40]
+    MOV     R10, R4
+    LDR     R4, [R1, #36]
+    MOV     R9, R4
+    LDR     R4, [R1, #32]
+    MOV     R8, R4
+
+    LDR     R7, [R1, #28]
+    LDR     R6, [R1, #24]
+    LDR     R5, [R1, #20]
+    LDR     R4, [R1, #16]
+    LDR     R3, [R1, #12]
+    LDR     R2, [R1, #8]
+    LDR     R0, [R1, #0]
+    LDR     R1, [R1, #4]
+
+    @ Return to caller (scheduler).
+    BX      LR
+
+
+@ R0 Contains a pointer to the TCB of the fibre to snapshot
+@ R1 Contains a pointer to the base of the stack of the fibre being snapshotted
+
+save_context:
+
+    @ Write our core registers into the TCB
+    @ First, store the general registers
+
+    STR     R0, [R0,#0]
+    STR     R1, [R0,#4]
+    STR     R2, [R0,#8]
+    STR     R3, [R0,#12]
+    STR     R4, [R0,#16]
+    STR     R5, [R0,#20]
+    STR     R6, [R0,#24]
+    STR     R7, [R0,#28]
+
+    @ Now the high general purpose registers
+    MOV     R4, R8
+    STR     R4, [R0,#32]
+    MOV     R4, R9
+    STR     R4, [R0,#36]
+    MOV     R4, R10
+    STR     R4, [R0,#40]
+    MOV     R4, R11
+    STR     R4, [R0,#44]
+    MOV     R4, R12
+    STR     R4, [R0,#48]
+
+    @ Now the Stack and Link Register.
+    @ As this context is only intended for use with a fiber scheduler,
+    @ we don't need the PC.
+    MOV     R6, SP
+    STR     R6, [R0,#52]
+    MOV     R4, LR
+    STR     R4, [R0,#56]
+
+    @ Finally, Copy the stack. We do this to reduce RAM footprint, as stackis usually very small at the point
+    @ of sceduling, but we need a lot of capacity for interrupt handling and other functions.
+
+    LDR     R4, [R0,#60]         @ Load R4 with the fiber's defined stack_base.
+
+store_stack1:
+    SUBS    R4, #4
+    SUBS    R1, #4
+
+    LDR     R5, [R4]
+    STR     R5, [R1]
+
+    CMP     R4, R6
+    BNE     store_stack1
+
+    @ Restore scratch registers.
+
+    LDR     R7, [R0, #28]
+    LDR     R6, [R0, #24]
+    LDR     R5, [R0, #20]
+    LDR     R4, [R0, #16]
+
+    @ Return to caller (scheduler).
+    BX      LR
+
+
+@ R0 Contains a pointer to the TCB of the fiber to snapshot
+save_register_context:
+
+    @ Write our core registers into the TCB
+    @ First, store the general registers
+
+    STR     R0, [R0,#0]
+    STR     R1, [R0,#4]
+    STR     R2, [R0,#8]
+    STR     R3, [R0,#12]
+    STR     R4, [R0,#16]
+    STR     R5, [R0,#20]
+    STR     R6, [R0,#24]
+    STR     R7, [R0,#28]
+
+    @ Now the high general purpose registers
+    MOV     R4, R8
+    STR     R4, [R0,#32]
+    MOV     R4, R9
+    STR     R4, [R0,#36]
+    MOV     R4, R10
+    STR     R4, [R0,#40]
+    MOV     R4, R11
+    STR     R4, [R0,#44]
+    MOV     R4, R12
+    STR     R4, [R0,#48]
+
+    @ Now the Stack Pointer and Link Register.
+    @ As this context is only intended for use with a fiber scheduler,
+    @ we don't need the PC.
+    MOV     R4, SP
+    STR     R4, [R0,#52]
+    MOV     R4, LR
+    STR     R4, [R0,#56]
+
+    @ Restore scratch registers.
+    LDR     R4, [R0, #16]
+
+    @ Return to caller (scheduler).
+    BX      LR
+
+
+restore_register_context:
+
+    @
+    @ Now page in the new context.
+    @ Update all registers except the PC. We can also safely ignore the STATUS register, as we're just a fiber scheduler.
+    @
+    LDR     R4, [R0, #56]
+    MOV     LR, R4
+    LDR     R4, [R0, #52]
+    MOV     SP, R4
+
+    @ High registers...
+    LDR     R4, [R0, #48]
+    MOV     R12, R4
+    LDR     R4, [R0, #44]
+    MOV     R11, R4
+    LDR     R4, [R0, #40]
+    MOV     R10, R4
+    LDR     R4, [R0, #36]
+    MOV     R9, R4
+    LDR     R4, [R0, #32]
+    MOV     R8, R4
+
+    @ Low registers...
+    LDR     R7, [R0, #28]
+    LDR     R6, [R0, #24]
+    LDR     R5, [R0, #20]
+    LDR     R4, [R0, #16]
+    LDR     R3, [R0, #12]
+    LDR     R2, [R0, #8]
+    LDR     R0, [R0, #0]
+    LDR     R1, [R0, #4]
+
+    @ Return to caller (normally the scheduler).
+    BX      LR
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitAccelerometerService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,121 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the custom MicroBit Accelerometer Service.
+  * Provides a BLE service to remotely read the state of the accelerometer, and configure its behaviour.
+  */
+#include "MicroBitConfig.h"
+#include "ble/UUID.h"
+
+#include "MicroBitAccelerometerService.h"
+
+/**
+  * Constructor.
+  * Create a representation of the AccelerometerService
+  * @param _ble The instance of a BLE device that we're running on.
+  * @param _accelerometer An instance of MicroBitAccelerometer.
+  */
+MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble, MicroBitAccelerometer &_accelerometer) :
+        ble(_ble), accelerometer(_accelerometer)
+{
+    // Create the data structures that represent each of our characteristics in Soft Device.
+    GattCharacteristic  accelerometerDataCharacteristic(MicroBitAccelerometerServiceDataUUID, (uint8_t *)accelerometerDataCharacteristicBuffer, 0,
+    sizeof(accelerometerDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    GattCharacteristic  accelerometerPeriodCharacteristic(MicroBitAccelerometerServicePeriodUUID, (uint8_t *)&accelerometerPeriodCharacteristicBuffer, 0,
+    sizeof(accelerometerPeriodCharacteristicBuffer),
+    GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    // Initialise our characteristic values.
+    accelerometerDataCharacteristicBuffer[0] = 0;
+    accelerometerDataCharacteristicBuffer[1] = 0;
+    accelerometerDataCharacteristicBuffer[2] = 0;
+    accelerometerPeriodCharacteristicBuffer = accelerometer.getPeriod();
+
+    // Set default security requirements
+    accelerometerDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    accelerometerPeriodCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&accelerometerDataCharacteristic, &accelerometerPeriodCharacteristic};
+    GattService         service(MicroBitAccelerometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    accelerometerDataCharacteristicHandle = accelerometerDataCharacteristic.getValueHandle();
+    accelerometerPeriodCharacteristicHandle = accelerometerPeriodCharacteristic.getValueHandle();
+
+    ble.gattServer().write(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer));
+    ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer));
+
+    ble.onDataWritten(this, &MicroBitAccelerometerService::onDataWritten);
+
+    if (EventModel::defaultEventBus)
+        EventModel::defaultEventBus->listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate,  MESSAGE_BUS_LISTENER_IMMEDIATE);
+}
+
+/**
+  * Callback. Invoked when any of our attributes are written via BLE.
+  */
+void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams *params)
+{
+    if (params->handle == accelerometerPeriodCharacteristicHandle && params->len >= sizeof(accelerometerPeriodCharacteristicBuffer))
+    {
+        accelerometerPeriodCharacteristicBuffer = *((uint16_t *)params->data);
+        accelerometer.setPeriod(accelerometerPeriodCharacteristicBuffer);
+
+        // The accelerometer will choose the nearest period to that requested that it can support
+        // Read back the ACTUAL period it is using, and report this back.
+        accelerometerPeriodCharacteristicBuffer = accelerometer.getPeriod();
+        ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer));
+    }
+}
+
+/**
+  * Accelerometer update callback
+  */
+void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent)
+{
+    if (ble.getGapState().connected)
+    {
+        accelerometerDataCharacteristicBuffer[0] = accelerometer.getX();
+        accelerometerDataCharacteristicBuffer[1] = accelerometer.getY();
+        accelerometerDataCharacteristicBuffer[2] = accelerometer.getZ();
+
+        ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer));
+    }
+}
+
+const uint8_t  MicroBitAccelerometerServiceUUID[] = {
+    0xe9,0x5d,0x07,0x53,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitAccelerometerServiceDataUUID[] = {
+    0xe9,0x5d,0xca,0x4b,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitAccelerometerServicePeriodUUID[] = {
+    0xe9,0x5d,0xfb,0x24,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitBLEManager.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,602 @@
+/*
+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 "MicroBitBLEManager.h"
+#include "MicroBitStorage.h"
+#include "MicroBitFiber.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)
+ * 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
+
+#include "ble.h"
+
+extern "C"
+{
+#include "device_manager.h"
+uint32_t btle_set_gatt_table_size(uint32_t size);
+}
+
+/*
+ * Return to our predefined compiler settings.
+ */
+#if !defined(__arm)
+#pragma GCC diagnostic pop
+#endif
+
+#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;
+const int8_t MICROBIT_BLE_POWER_LEVEL[] = {-30, -20, -16, -12, -8, -4, 0, 4};
+
+/*
+ * Many of the mbed interfaces we need to use only support callbacks to plain C functions, rather than C++ methods.
+ * 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.
+
+static void storeSystemAttributes(Gap::Handle_t handle)
+{
+    if(manager->storage != NULL && deviceID < MICROBIT_BLE_MAXIMUM_BONDS)
+    {
+        ManagedString key("bleSysAttrs");
+
+        KeyValuePair* bleSysAttrs = manager->storage->get(key);
+
+        BLESysAttribute attrib;
+        BLESysAttributeStore attribStore;
+
+        uint16_t len = sizeof(attrib.sys_attr);
+
+        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)
+        {
+            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)
+        {
+            attribStore.sys_attrs[deviceID] = attrib;
+            manager->storage->put(key, (uint8_t *)&attribStore);
+        }
+    }
+}
+
+/**
+  * Callback when a BLE GATT disconnect occurs.
+  */
+static void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *reason)
+{
+    storeSystemAttributes(reason->handle);
+
+    if (manager)
+	    manager->advertise();
+}
+
+/**
+  * Callback when a BLE SYS_ATTR_MISSING.
+  */
+static void bleSysAttrMissingCallback(const GattSysAttrMissingCallbackParams *params)
+{
+    int complete = 0;
+    deviceID = 255;
+
+    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)
+    {
+        ManagedString key("bleSysAttrs");
+
+        KeyValuePair* bleSysAttrs = manager->storage->get(key);
+
+        BLESysAttributeStore attribStore;
+        BLESysAttribute attrib;
+
+        if(bleSysAttrs != NULL)
+        {
+            //restore our sysAttrStore
+            memcpy(&attribStore, bleSysAttrs->value, sizeof(BLESysAttributeStore));
+            delete bleSysAttrs;
+
+            attrib = attribStore.sys_attrs[deviceID];
+
+            ret = sd_ble_gatts_sys_attr_set(params->connHandle, attrib.sys_attr, sizeof(attrib.sys_attr), BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
+
+            complete = 1;
+
+            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 */
+
+	ManagedString passKey((const char *)passkey, SecurityManager::PASSKEY_LEN);
+
+    if (manager)
+	    manager->pairingRequested(passKey);
+}
+
+static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager::SecurityCompletionStatus_t status)
+{
+    (void) handle; /* -Wunused-param */
+
+    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)
+    {
+        pairingHandle = handle;
+	    manager->pairingComplete(status == SecurityManager::SEC_STATUS_SUCCESS);
+    }
+}
+
+/**
+ * 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.
+ */
+MicroBitBLEManager::MicroBitBLEManager(MicroBitStorage& _storage) :
+    storage(&_storage)
+{
+    manager = this;
+	this->ble = NULL;
+	this->pairingStatus = 0;
+}
+
+/**
+ * Constructor.
+ *
+ * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
+ *
+ * @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)
+{
+    manager = this;
+	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.
+ */
+void MicroBitBLEManager::advertise()
+{
+    if(ble)
+        ble->gap().startAdvertising();
+}
+
+/**
+  * Post constructor initialisation method as the BLE stack cannot be brought
+  * up in a static context.
+  *
+  * @param deviceName The name used when advertising
+  * @param serialNumber The serial number exposed by the device information service
+  * @param messageBus An instance of an EventModel, used during pairing.
+  * @param enableBonding If true, the security manager enabled bonding.
+  *
+  * @code
+  * bleManager.init(uBit.getName(), uBit.getSerial(), uBit.messageBus, true);
+  * @endcode
+  */
+void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, EventModel& messageBus, bool enableBonding)
+{
+	ManagedString BLEName("BBC micro:bit");
+	this->deviceName = deviceName;
+
+#if !(CONFIG_ENABLED(MICROBIT_BLE_WHITELIST))
+	ManagedString namePrefix(" [");
+	ManagedString namePostfix("]");
+	BLEName = BLEName + namePrefix + deviceName + namePostfix;
+#endif
+
+    // Start the BLE stack.
+#if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD)
+    btle_set_gatt_table_size(MICROBIT_SD_GATT_TABLE_SIZE);
+#endif
+
+    ble = new BLEDevice();
+    ble->init();
+
+    // automatically restart advertising after a device disconnects.
+    ble->gap().onDisconnection(bleDisconnectionCallback);
+    ble->gattServer().onSysAttrMissing(bleSysAttrMissingCallback);
+
+    // Configure the stack to hold onto the CPU during critical timing events.
+    // mbed-classic performs __disable_irq() calls in its timers that can cause
+    // MIC failures on secure BLE channels...
+    ble_common_opt_radio_cpu_mutex_t opt;
+    opt.enable = 1;
+    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});
+#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);
+
+    if (enableBonding)
+    {
+        // If we're in pairing mode, review the size of the bond table.
+        int bonds = getBondCount();
+
+        // TODO: It would be much better to implement some sort of LRU/NFU policy here,
+        // but this isn't currently supported in mbed, so we'd need to layer break...
+
+        // If we're full, empty the bond table.
+        if (bonds >= MICROBIT_BLE_MAXIMUM_BONDS)
+            ble->securityManager().purgeAllBondingState();
+    }
+
+#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
+    // Configure a whitelist to filter all connection requetss from unbonded devices.
+    // Most BLE stacks only permit one connection at a time, so this prevents denial of service attacks.
+    BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
+    Gap::Whitelist_t whitelist;
+    whitelist.addresses = bondedAddresses;
+    whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
+
+    ble->securityManager().getAddressesFromBondTable(whitelist);
+
+    ble->gap().setWhitelist(whitelist);
+    ble->gap().setScanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST);
+    ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_FILTER_CONN_REQS);
+#endif
+
+    // Configure the radio at our default power level
+    setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER);
+
+    // Bring up core BLE services.
+    new MicroBitDFUService(*ble);
+    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);
+    new MicroBitEventService(*ble, messageBus);
+
+
+    // Configure for high speed mode where possible.
+    Gap::ConnectionParams_t fast;
+    ble->getPreferredConnectionParams(&fast);
+    fast.minConnectionInterval = 8; // 10 ms
+    fast.maxConnectionInterval = 16; // 20 ms
+    fast.slaveLatency = 0;
+    ble->setPreferredConnectionParams(&fast);
+
+    // Setup advertising.
+#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
+#else
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+#endif
+
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
+    ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble->setAdvertisingInterval(200);
+
+#if (MICROBIT_BLE_ADVERTISING_TIMEOUT > 0)
+    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 CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
+    if (whitelist.size > 0)
+#endif
+        ble->startAdvertising();
+}
+
+/**
+ * Change the output power level of the transmitter to the given value.
+ *
+ * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest.
+ *
+ * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range.
+ *
+ * @code
+ * // maximum transmission power.
+ * bleManager.setTransmitPower(7);
+ * @endcode
+ */
+int MicroBitBLEManager::setTransmitPower(int power)
+{
+    if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if (ble->gap().setTxPower(MICROBIT_BLE_POWER_LEVEL[power]) != NRF_SUCCESS)
+        return MICROBIT_NOT_SUPPORTED;
+
+    return MICROBIT_OK;
+}
+
+/**
+ * Determines the number of devices currently bonded with this micro:bit.
+ * @return The number of active bonds.
+ */
+int MicroBitBLEManager::getBondCount()
+{
+    BLEProtocol::Address_t bondedAddresses[MICROBIT_BLE_MAXIMUM_BONDS];
+    Gap::Whitelist_t whitelist;
+    whitelist.addresses = bondedAddresses;
+    whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
+    ble->securityManager().getAddressesFromBondTable(whitelist);
+
+    return whitelist.bonds;
+}
+
+/**
+ * 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 MicroBitBLEManager::pairingRequested(ManagedString passKey)
+{
+    // Update our mode to display the passkey.
+	this->passKey = passKey;
+	this->pairingStatus = MICROBIT_BLE_PAIR_REQUEST;
+}
+
+/**
+ * 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 MicroBitBLEManager::pairingComplete(bool success)
+{
+	this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE;
+
+	if(success)
+    {
+		this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
+        fiber_add_idle_component(this);
+    }
+}
+
+/**
+ * Periodic callback in thread context.
+ * We use this here purely to safely issue a disconnect operation after a pairing operation is complete.
+ */
+void MicroBitBLEManager::idleTick()
+{
+    if (ble)
+        ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
+
+    fiber_remove_idle_component(this);
+}
+
+/**
+ * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
+ * of the micro:bit in cases where BLE is disabled during normal operation.
+ *
+ * @param display An instance of MicroBitDisplay used when displaying pairing information.
+ * @param authorizationButton The button to use to authorise a pairing request.
+ *
+ * @code
+ * // initiate pairing mode
+ * bleManager.pairingMode(uBit.display, uBit.buttonA);
+ * @endcode
+ */
+void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton)
+{
+	ManagedString namePrefix("BBC micro:bit [");
+	ManagedString namePostfix("]");
+	ManagedString BLEName = namePrefix + deviceName + namePostfix;
+
+	ManagedString msg("PAIRING MODE!");
+
+	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.
+#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
+    BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS];
+    Gap::Whitelist_t whitelist;
+    whitelist.addresses = addresses;
+    whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
+    whitelist.size = 0;
+    ble->gap().setWhitelist(whitelist);
+    ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
+#endif
+
+	// 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);
+    ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
+    ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble->setAdvertisingInterval(200);
+
+    ble->gap().setAdvertisingTimeout(0);
+    ble->gap().startAdvertising();
+
+	// 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);
+
+	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 (brightness <= 40)
+				display.clear();
+
+			if (brightness <= 0)
+				fadeDirection = 1;
+
+			if (brightness >= 255)
+				fadeDirection = 0;
+
+			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_COMPLETE)
+					break;
+			}
+
+			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);
+                fiber_sleep(15000);
+		        timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30;
+
+                /*
+                 * Disabled, as the API to return the number of active bonds is not reliable at present...
+                 *
+                display.clear();
+                ManagedString c(getBondCount());
+                ManagedString c2("/");
+                ManagedString c3(MICROBIT_BLE_MAXIMUM_BONDS);
+                ManagedString c4("USED");
+
+                display.scroll(c+c2+c3+c4);
+                *
+                *
+                */
+			}
+			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++;
+
+		if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
+			microbit_reset();
+	}
+}
+
+/**
+ * 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 MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display)
+{
+    uint32_t n = NRF_FICR->DEVICEID[1];
+    int ld = 1;
+    int d = MICROBIT_DFU_HISTOGRAM_HEIGHT;
+    int h;
+
+    display.clear();
+    for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++)
+    {
+        h = (n % d) / ld;
+
+        n -= h;
+        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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitButtonService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,143 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the custom MicroBit Button Service.
+  * Provides a BLE service to remotely read the state of each button, and configure its behaviour.
+  */
+#include "MicroBitConfig.h"
+#include "ble/UUID.h"
+
+#include "MicroBitButtonService.h"
+#include "MicroBitButton.h"
+
+/**
+  * Constructor.
+  * Create a representation of the ButtonService
+  * @param _ble The instance of a BLE device that we're running on.
+  */
+MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) :
+        ble(_ble)
+{
+    // Create the data structures that represent each of our characteristics in Soft Device.
+    GattCharacteristic  buttonADataCharacteristic(MicroBitButtonAServiceDataUUID, (uint8_t *)&buttonADataCharacteristicBuffer, 0,
+    sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    GattCharacteristic  buttonBDataCharacteristic(MicroBitButtonBServiceDataUUID, (uint8_t *)&buttonADataCharacteristicBuffer, 0,
+    sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+
+    // Initialise our characteristic values.
+    buttonADataCharacteristicBuffer = 0;
+    buttonBDataCharacteristicBuffer = 0;
+
+    // Set default security requirements
+    buttonADataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    buttonBDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&buttonADataCharacteristic, &buttonBDataCharacteristic};
+    GattService         service(MicroBitButtonServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    buttonADataCharacteristicHandle = buttonADataCharacteristic.getValueHandle();
+    buttonBDataCharacteristicHandle = buttonBDataCharacteristic.getValueHandle();
+
+    ble.gattServer().write(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
+    ble.gattServer().write(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
+
+    if (EventModel::defaultEventBus)
+    {
+        EventModel::defaultEventBus->listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonAUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
+        EventModel::defaultEventBus->listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonBUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
+    }
+}
+
+
+/**
+  * Button B update callback
+  */
+void MicroBitButtonService::buttonAUpdate(MicroBitEvent e)
+{
+    if (ble.getGapState().connected)
+    {
+        if (e.value == MICROBIT_BUTTON_EVT_UP)
+        {
+            buttonADataCharacteristicBuffer = 0;
+            ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
+        }
+
+        if (e.value == MICROBIT_BUTTON_EVT_DOWN)
+        {
+            buttonADataCharacteristicBuffer = 1;
+            ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
+        }
+
+        if (e.value == MICROBIT_BUTTON_EVT_HOLD)
+        {
+            buttonADataCharacteristicBuffer = 2;
+            ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
+        }
+    }
+}
+
+/**
+  * Button A update callback
+  */
+void MicroBitButtonService::buttonBUpdate(MicroBitEvent e)
+{
+    if (ble.getGapState().connected)
+    {
+        if (e.value == MICROBIT_BUTTON_EVT_UP)
+        {
+            buttonBDataCharacteristicBuffer = 0;
+            ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
+        }
+
+        if (e.value == MICROBIT_BUTTON_EVT_DOWN)
+        {
+            buttonBDataCharacteristicBuffer = 1;
+            ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
+        }
+
+        if (e.value == MICROBIT_BUTTON_EVT_HOLD)
+        {
+            buttonBDataCharacteristicBuffer = 2;
+            ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
+        }
+    }
+}
+
+const uint8_t  MicroBitButtonServiceUUID[] = {
+    0xe9,0x5d,0x98,0x82,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitButtonAServiceDataUUID[] = {
+    0xe9,0x5d,0xda,0x90,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+}
+;
+const uint8_t  MicroBitButtonBServiceDataUUID[] = {
+    0xe9,0x5d,0xda,0x91,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitDFUService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,137 @@
+/*
+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.
+*/
+
+/**
+ * Class definition for a MicroBit Device Firmware Update loader.
+ *
+ * This is actually just a frontend to a memory resident nordic DFU loader.
+ *
+ * We rely on the BLE standard pairing processes to provide encryption and authentication.
+ * We assume any device that is paied with the micro:bit is authorized to reprogram the device.
+ *
+ */
+#include "MicroBitConfig.h"
+#include "MicroBitDFUService.h"
+#include "ble/UUID.h"
+#include "MicroBitConfig.h"
+
+#if !defined(__arm)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+/*
+ * 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...
+ */
+extern "C" {
+#include "dfu_app_handler.h"
+}
+
+/*
+ * Return to our predefined compiler settings.
+ */
+#if !defined(__arm)
+#pragma GCC diagnostic pop
+#endif
+
+
+/**
+  * Constructor.
+  * Initialise the Device Firmware Update service.
+  * @param _ble The instance of a BLE device that we're running on.
+  */
+MicroBitDFUService::MicroBitDFUService(BLEDevice &_ble) :
+    ble(_ble)
+{
+    // Opcodes can be issued here to control the MicroBitDFU Service, as defined above.
+    GattCharacteristic  microBitDFUServiceControlCharacteristic(MicroBitDFUServiceControlCharacteristicUUID, &controlByte, 0, sizeof(uint8_t),
+            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    controlByte = 0x00;
+
+    // Set default security requirements
+    microBitDFUServiceControlCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&microBitDFUServiceControlCharacteristic};
+    GattService         service(MicroBitDFUServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    microBitDFUServiceControlCharacteristicHandle = microBitDFUServiceControlCharacteristic.getValueHandle();
+
+    ble.gattServer().write(microBitDFUServiceControlCharacteristicHandle, &controlByte, sizeof(uint8_t));
+    ble.gattServer().onDataWritten(this, &MicroBitDFUService::onDataWritten);
+}
+
+/**
+  * Callback. Invoked when any of our attributes are written via BLE.
+  */
+void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
+{
+    if (params->handle == microBitDFUServiceControlCharacteristicHandle)
+    {
+        if(params->len > 0 && params->data[0] == MICROBIT_DFU_OPCODE_START_DFU)
+        {
+            // TODO: Raise a SYSTEM event here.
+            //uBit.display.stopAnimation();
+            //uBit.display.clear();
+
+#if CONFIG_ENABLED(MICROBIT_DBG)
+            printf("  ACTIVATING BOOTLOADER.\n");
+#endif
+
+            // Perform an explicit disconnection to assist our peer to reconnect to the DFU service
+            ble.disconnect(Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
+
+            wait_ms(1000);
+
+            // Call bootloader_start implicitly trough a event handler call
+            // it is a work around for bootloader_start not being public in sdk 8.1
+            ble_dfu_t p_dfu;
+            ble_dfu_evt_t p_evt;
+
+            p_dfu.conn_handle = params->connHandle;
+            p_evt.ble_dfu_evt_type = BLE_DFU_START;
+
+            dfu_app_on_dfu_evt(&p_dfu, &p_evt);
+        }
+    }
+}
+
+
+/**
+  * UUID definitions for BLE Services and Characteristics.
+  */
+const uint8_t              MicroBitDFUServiceUUID[] = {
+    0xe9,0x5d,0x93,0xb0,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t              MicroBitDFUServiceControlCharacteristicUUID[] = {
+    0xe9,0x5d,0x93,0xb1,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitEventService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,188 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for a MicroBit BLE Event Service.
+  * Provides a BLE gateway onto an Event Model.
+  */
+
+#include "MicroBitConfig.h"
+#include "MicroBitEventService.h"
+#include "ble/UUID.h"
+#include "ExternalEvents.h"
+#include "MicroBitFiber.h"
+
+/**
+  * Constructor.
+  * Create a representation of the EventService
+  * @param _ble The instance of a BLE device that we're running on.
+  * @param _messageBus An instance of an EventModel which events will be mirrored from.
+  */
+MicroBitEventService::MicroBitEventService(BLEDevice &_ble, EventModel &_messageBus) :
+        ble(_ble),messageBus(_messageBus)
+{
+    GattCharacteristic  microBitEventCharacteristic(MicroBitEventServiceMicroBitEventCharacteristicUUID, (uint8_t *)&microBitEventBuffer, 0, sizeof(EventServiceEvent),
+    GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    GattCharacteristic  clientEventCharacteristic(MicroBitEventServiceClientEventCharacteristicUUID, (uint8_t *)&clientEventBuffer, 0, sizeof(EventServiceEvent),
+    GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    GattCharacteristic  clientRequirementsCharacteristic(MicroBitEventServiceClientRequirementsCharacteristicUUID, (uint8_t *)&clientRequirementsBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    microBitRequirementsCharacteristic = new GattCharacteristic(MicroBitEventServiceMicroBitRequirementsCharacteristicUUID, (uint8_t *)&microBitRequirementsBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    microBitRequirementsCharacteristic->setReadAuthorizationCallback(this, &MicroBitEventService::onRequirementsRead);
+
+    clientEventBuffer.type = 0x00;
+    clientEventBuffer.reason = 0x00;
+
+    microBitEventBuffer = microBitRequirementsBuffer = clientRequirementsBuffer = clientEventBuffer;
+
+    messageBusListenerOffset = 0;
+
+    // Set default security requirements
+    microBitEventCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    clientEventCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    clientRequirementsCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    microBitRequirementsCharacteristic->requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&microBitEventCharacteristic, &clientEventCharacteristic, &clientRequirementsCharacteristic, microBitRequirementsCharacteristic};
+    GattService         service(MicroBitEventServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    microBitEventCharacteristicHandle = microBitEventCharacteristic.getValueHandle();
+    clientEventCharacteristicHandle = clientEventCharacteristic.getValueHandle();
+    clientRequirementsCharacteristicHandle = clientRequirementsCharacteristic.getValueHandle();
+
+    ble.onDataWritten(this, &MicroBitEventService::onDataWritten);
+
+    fiber_add_idle_component(this);
+}
+
+
+/**
+  * Callback. Invoked when any of our attributes are written via BLE.
+  */
+void MicroBitEventService::onDataWritten(const GattWriteCallbackParams *params)
+{
+    int len = params->len;
+    EventServiceEvent *e = (EventServiceEvent *)params->data;
+
+    if (params->handle == clientEventCharacteristicHandle) {
+
+        // Read and fire all events...
+        while (len >= 4)
+        {
+            MicroBitEvent evt(e->type, e->reason);
+            len-=4;
+            e++;
+        }
+        return;
+    }
+
+    if (params->handle == clientRequirementsCharacteristicHandle) {
+        // Read and register for all the events given...
+        while (len >= 4)
+        {
+            messageBus.listen(e->type, e->reason, this, &MicroBitEventService::onMicroBitEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
+
+            len-=4;
+            e++;
+        }
+        return;
+    }
+}
+
+/**
+  * Callback. Invoked when any events are sent on the microBit message bus.
+  */
+void MicroBitEventService::onMicroBitEvent(MicroBitEvent evt)
+{
+    EventServiceEvent *e = &microBitEventBuffer;
+
+    if (ble.getGapState().connected) {
+        e->type = evt.source;
+        e->reason = evt.value;
+
+        ble.gattServer().notify(microBitEventCharacteristicHandle, (const uint8_t *)e, sizeof(EventServiceEvent));
+    }
+}
+
+/**
+  * Periodic callback from MicroBit scheduler.
+  * If we're no longer connected, remove any registered Message Bus listeners.
+  */
+void MicroBitEventService::idleTick()
+{
+    if (!ble.getGapState().connected && messageBusListenerOffset >0) {
+        messageBusListenerOffset = 0;
+        messageBus.ignore(MICROBIT_ID_ANY, MICROBIT_EVT_ANY, this, &MicroBitEventService::onMicroBitEvent);
+    }
+}
+
+/**
+  * Read callback on microBitRequirements characteristic.
+  *
+  * Used to iterate through the events that the code on this micro:bit is interested in.
+  */
+void MicroBitEventService::onRequirementsRead(GattReadAuthCallbackParams *params)
+{
+    if (params->handle == microBitRequirementsCharacteristic->getValueHandle())
+    {
+        // Walk through the lsit of message bus listeners.
+        // We send one at a time, and our client can keep reading from this characterisitic until we return an emtpy value.
+        MicroBitListener *l = messageBus.elementAt(messageBusListenerOffset++);
+
+        if (l != NULL)
+        {
+            microBitRequirementsBuffer.type = l->id;
+            microBitRequirementsBuffer.reason = l->value;
+            ble.gattServer().write(microBitRequirementsCharacteristic->getValueHandle(), (uint8_t *)&microBitRequirementsBuffer, sizeof(EventServiceEvent));
+        } else {
+            ble.gattServer().write(microBitRequirementsCharacteristic->getValueHandle(), (uint8_t *)&microBitRequirementsBuffer, 0);
+        }
+    }
+}
+
+const uint8_t  MicroBitEventServiceUUID[] = {
+    0xe9,0x5d,0x93,0xaf,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitEventServiceMicroBitEventCharacteristicUUID[] = {
+    0xe9,0x5d,0x97,0x75,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitEventServiceClientEventCharacteristicUUID[] = {
+    0xe9,0x5d,0x54,0x04,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitEventServiceMicroBitRequirementsCharacteristicUUID[] = {
+    0xe9,0x5d,0xb8,0x4c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitEventServiceClientRequirementsCharacteristicUUID[] = {
+    0xe9,0x5d,0x23,0xc4,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitIOPinService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,330 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the custom MicroBit IOPin Service.
+  * Provides a BLE service to remotely read the state of the I/O Pin, and configure its behaviour.
+  */
+#include "MicroBitConfig.h"
+#include "ble/UUID.h"
+
+#include "MicroBitIOPinService.h"
+#include "MicroBitFiber.h"
+
+/**
+  * Constructor.
+  * Create a representation of the IOPinService
+  * @param _ble The instance of a BLE device that we're running on.
+  * @param _io An instance of MicroBitIO that this service will use to perform
+  *            I/O operations.
+  */
+MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble, MicroBitIO &_io) :
+        ble(_ble), io(_io)
+{
+    // Create the AD characteristic, that defines whether each pin is treated as analogue or digital
+    GattCharacteristic ioPinServiceADCharacteristic(MicroBitIOPinServiceADConfigurationUUID, (uint8_t *)&ioPinServiceADCharacteristicBuffer, 0, sizeof(ioPinServiceADCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    // Create the IO characteristic, that defines whether each pin is treated as input or output
+    GattCharacteristic ioPinServiceIOCharacteristic(MicroBitIOPinServiceIOConfigurationUUID, (uint8_t *)&ioPinServiceIOCharacteristicBuffer, 0, sizeof(ioPinServiceIOCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    // Create the Data characteristic, that allows the actual read and write operations.
+    ioPinServiceDataCharacteristic = new GattCharacteristic(MicroBitIOPinServiceDataUUID, (uint8_t *)ioPinServiceDataCharacteristicBuffer, 0, sizeof(ioPinServiceDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    ioPinServiceDataCharacteristic->setReadAuthorizationCallback(this, &MicroBitIOPinService::onDataRead);
+
+    ioPinServiceADCharacteristicBuffer = 0;
+    ioPinServiceIOCharacteristicBuffer = 0;
+    memset(ioPinServiceIOData, 0, sizeof(ioPinServiceIOData));
+
+    // Set default security requirements
+    ioPinServiceADCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    ioPinServiceIOCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    ioPinServiceDataCharacteristic->requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&ioPinServiceADCharacteristic, &ioPinServiceIOCharacteristic, ioPinServiceDataCharacteristic};
+    GattService         service(MicroBitIOPinServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    ioPinServiceADCharacteristicHandle = ioPinServiceADCharacteristic.getValueHandle();
+    ioPinServiceIOCharacteristicHandle = ioPinServiceIOCharacteristic.getValueHandle();
+
+    ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer));
+    ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
+
+    ble.onDataWritten(this, &MicroBitIOPinService::onDataWritten);
+    fiber_add_idle_component(this);
+}
+
+/**
+  * Determines if the given pin was configured as a digital pin by the BLE ADPinConfigurationCharacterisitic.
+  *
+  * @param i the enumeration of the pin to test
+  * @return 1 if this pin is configured as digital, 0 otherwise
+  */
+int MicroBitIOPinService::isDigital(int i)
+{
+    return ((ioPinServiceADCharacteristicBuffer & (1 << i)) == 0);
+}
+
+/**
+  * Determines if the given pin was configured as an analog pin by the BLE ADPinConfigurationCharacterisitic.
+  *
+  * @param i the enumeration of the pin to test
+  * @return 1 if this pin is configured as analog, 0 otherwise
+  */
+int MicroBitIOPinService::isAnalog(int i)
+{
+    return ((ioPinServiceADCharacteristicBuffer & (1 << i)) != 0);
+}
+
+/**
+  * Determines if the given pin was configured as an input by the BLE IOPinConfigurationCharacterisitic.
+  *
+  * @param i the enumeration of the pin to test
+  * @return 1 if this pin is configured as an input, 0 otherwise
+  */
+int MicroBitIOPinService::isInput(int i)
+{
+    return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) != 0);
+}
+
+/**
+  * Determines if the given pin was configured as output by the BLE IOPinConfigurationCharacterisitic.
+  *
+  * @param i the enumeration of the pin to test
+  * @return 1 if this pin is configured as an output, 0 otherwise
+  */
+int MicroBitIOPinService::isOutput(int i)
+{
+    return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) == 0);
+}
+
+/**
+  * Callback. Invoked when any of our attributes are written via BLE.
+  */
+void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
+{
+    // Check for writes to the IO configuration characteristic
+    if (params->handle == ioPinServiceIOCharacteristicHandle && params->len >= sizeof(ioPinServiceIOCharacteristicBuffer))
+    {
+        uint32_t *value = (uint32_t *)params->data;
+
+        // Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
+        ioPinServiceIOCharacteristicBuffer = *value;
+        ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
+
+        // Also, drop any selected pins into input mode, so we can pick up changes later
+        for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
+        {
+            if(isDigital(i) && isInput(i))
+               io.pin[i].getDigitalValue();
+               //MicroBitIOPins[i]->getDigitalValue();
+
+            if(isAnalog(i) && isInput(i))
+               io.pin[i].getAnalogValue();
+               //MicroBitIOPins[i]->getAnalogValue();
+        }
+    }
+
+    // Check for writes to the IO configuration characteristic
+    if (params->handle == ioPinServiceADCharacteristicHandle && params->len >= sizeof(ioPinServiceADCharacteristicBuffer))
+    {
+        uint32_t *value = (uint32_t *)params->data;
+
+        // Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
+        ioPinServiceADCharacteristicBuffer = *value;
+        ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer));
+
+        // Also, drop any selected pins into input mode, so we can pick up changes later
+        for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
+        {
+            if(isDigital(i) && isInput(i))
+               io.pin[i].getDigitalValue();
+               //MicroBitIOPins[i]->getDigitalValue();
+
+            if(isAnalog(i) && isInput(i))
+               io.pin[i].getAnalogValue();
+               //MicroBitIOPins[i]->getAnalogValue();
+        }
+    }
+
+    if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
+    {
+        // We have some pin data to change...
+        uint16_t len = params->len;
+        IOData *data = (IOData *)params->data;
+
+        // There may be multiple write operaitons... take each in turn and update the pin values
+        while (len >= sizeof(IOData))
+        {
+            if (isOutput(data->pin))
+            {
+                if (isDigital(data->pin))
+               		io.pin[data->pin].setDigitalValue(data->value);
+                    //MicroBitIOPins[data->pin]->setDigitalValue(data->value);
+                else
+               		io.pin[data->pin].setAnalogValue(data->value*4);
+                    //MicroBitIOPins[data->pin]->setAnalogValue(data->value*4);
+            }
+
+            data++;
+            len -= sizeof(IOData);
+        }
+    }
+}
+
+/**
+ * Callback. invoked when the BLE data characteristic is read.
+ *
+ * Reads all the pins marked as inputs, and updates the data stored in the characteristic.
+ */
+void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params)
+{
+    if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
+    {
+
+        // Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
+        int pairs = 0;
+
+        for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
+        {
+            if (isInput(i))
+            {
+                uint8_t value;
+
+                if (isDigital(i))
+               		value = io.pin[i].getDigitalValue();
+                    //value = MicroBitIOPins[i]->getDigitalValue();
+                else
+               		value = io.pin[i].getAnalogValue();
+                    //value = MicroBitIOPins[i]->getAnalogValue();
+
+                ioPinServiceIOData[i] = value;
+                ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
+                ioPinServiceDataCharacteristicBuffer[pairs].value = value;
+
+                pairs++;
+
+                if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
+                    break;
+            }
+        }
+
+        // If there's any data, issue a BLE notification.
+        if (pairs > 0)
+            ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
+    }
+}
+
+
+/**
+ * Periodic callback from MicroBit scheduler.
+ *
+ * Check if any of the pins we're watching need updating. Notify any connected
+ * device with any changes.
+ */
+void MicroBitIOPinService::idleTick()
+{
+    // If we're not we're connected, then there's nothing to do...
+    if (!ble.getGapState().connected)
+        return;
+
+    // Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
+    int pairs = 0;
+
+    for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
+    {
+        if (isInput(i))
+        {
+            uint8_t value;
+
+            if (isDigital(i))
+               	value = io.pin[i].getDigitalValue();
+                //value = MicroBitIOPins[i]->getDigitalValue();
+            else
+               	value = io.pin[i].getAnalogValue();
+                //value = MicroBitIOPins[i]->getAnalogValue();
+
+            // If the data has changed, send an update.
+            if (value != ioPinServiceIOData[i])
+            {
+                ioPinServiceIOData[i] = value;
+
+                ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
+                ioPinServiceDataCharacteristicBuffer[pairs].value = value;
+
+                pairs++;
+
+                if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
+                    break;
+            }
+        }
+    }
+
+    // If there were any changes, issue a BLE notification.
+    if (pairs > 0)
+        ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
+}
+
+const uint8_t  MicroBitIOPinServiceUUID[] = {
+    0xe9,0x5d,0x12,0x7b,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitIOPinServiceIOConfigurationUUID[] = {
+    0xe9,0x5d,0xb9,0xfe,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitIOPinServiceADConfigurationUUID[] = {
+    0xe9,0x5d,0x58,0x99,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t MicroBitIOPinServiceDataUUID[] = {
+    0xe9,0x5d,0x8d,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+/*
+MicroBitPin * const MicroBitIOPins[] = {
+    &uBit.io.P0,
+    &uBit.io.P1,
+    &uBit.io.P2,
+    &uBit.io.P3,
+    &uBit.io.P4,
+    &uBit.io.P5,
+    &uBit.io.P6,
+    &uBit.io.P7,
+    &uBit.io.P8,
+    &uBit.io.P9,
+    &uBit.io.P10,
+    &uBit.io.P11,
+    &uBit.io.P12,
+    &uBit.io.P13,
+    &uBit.io.P14,
+    &uBit.io.P15,
+    &uBit.io.P16,
+    &uBit.io.P19,
+    &uBit.io.P20
+};
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitLEDService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,150 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the custom MicroBit LED Service.
+  * Provides a BLE service to remotely read and write the state of the LED display.
+  */
+#include "MicroBitConfig.h"
+#include "ble/UUID.h"
+
+#include "MicroBitLEDService.h"
+
+/**
+  * Constructor.
+  * Create a representation of the LEDService
+  * @param _ble The instance of a BLE device that we're running on.
+  * @param _display An instance of MicroBitDisplay to interface with.
+  */
+MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble, MicroBitDisplay &_display) :
+        ble(_ble), display(_display),
+        matrixCharacteristic(MicroBitLEDServiceMatrixUUID, (uint8_t *)&matrixCharacteristicBuffer, 0, sizeof(matrixCharacteristicBuffer),
+    GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)
+{
+    // Create the data structures that represent each of our characteristics in Soft Device.
+    GattCharacteristic  textCharacteristic(MicroBitLEDServiceTextUUID, (uint8_t *)textCharacteristicBuffer, 0, MICROBIT_BLE_MAXIMUM_SCROLLTEXT,
+    GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    GattCharacteristic  scrollingSpeedCharacteristic(MicroBitLEDServiceScrollingSpeedUUID, (uint8_t *)&scrollingSpeedCharacteristicBuffer, 0,
+    sizeof(scrollingSpeedCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
+
+    // Initialise our characteristic values.
+    memclr(matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer));
+    textCharacteristicBuffer[0] = 0;
+    scrollingSpeedCharacteristicBuffer = MICROBIT_DEFAULT_SCROLL_SPEED;
+
+    matrixCharacteristic.setReadAuthorizationCallback(this, &MicroBitLEDService::onDataRead);
+
+    // Set default security requirements
+    matrixCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    textCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    scrollingSpeedCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&matrixCharacteristic, &textCharacteristic, &scrollingSpeedCharacteristic};
+    GattService         service(MicroBitLEDServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    matrixCharacteristicHandle = matrixCharacteristic.getValueHandle();
+    textCharacteristicHandle = textCharacteristic.getValueHandle();
+    scrollingSpeedCharacteristicHandle = scrollingSpeedCharacteristic.getValueHandle();
+
+    ble.gattServer().write(scrollingSpeedCharacteristicHandle, (const uint8_t *)&scrollingSpeedCharacteristicBuffer, sizeof(scrollingSpeedCharacteristicBuffer));
+    ble.gattServer().write(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer));
+
+    ble.onDataWritten(this, &MicroBitLEDService::onDataWritten);
+}
+
+
+/**
+  * Callback. Invoked when any of our attributes are written via BLE.
+  */
+void MicroBitLEDService::onDataWritten(const GattWriteCallbackParams *params)
+{
+    uint8_t *data = (uint8_t *)params->data;
+
+    if (params->handle == matrixCharacteristicHandle && params->len > 0 && params->len < 6)
+    {
+        for (int y=0; y<params->len; y++)
+            for (int x=0; x<5; x++)
+                display.image.setPixelValue(x, y, (data[y] & (0x01 << (4-x))) ? 255 : 0);
+    }
+
+    else if (params->handle == textCharacteristicHandle)
+    {
+        // Create a ManagedString representation from the UTF8 data.
+        // We do this explicitly to control the length (in case the string is not NULL terminated!)
+        ManagedString s((char *)params->data, params->len);
+
+        // Start the string scrolling and we're done.
+        display.scrollAsync(s, (int) scrollingSpeedCharacteristicBuffer);
+    }
+
+    else if (params->handle == scrollingSpeedCharacteristicHandle && params->len >= sizeof(scrollingSpeedCharacteristicBuffer))
+    {
+        // Read the speed requested, and store it locally.
+        // We use this as the speed for all scroll operations subsquently initiated from BLE.
+        scrollingSpeedCharacteristicBuffer = *((uint16_t *)params->data);
+    }
+}
+
+/**
+  * Callback. Invoked when any of our attributes are read via BLE.
+  */
+void MicroBitLEDService::onDataRead(GattReadAuthCallbackParams *params)
+{
+    if (params->handle == matrixCharacteristicHandle)
+    {
+        for (int y=0; y<5; y++)
+        {
+            matrixCharacteristicBuffer[y] = 0;
+
+            for (int x=0; x<5; x++)
+            {
+                if (display.image.getPixelValue(x, y))
+                    matrixCharacteristicBuffer[y] |= 0x01 << (4-x);
+            }
+        }
+
+        ble.gattServer().write(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer));
+    }
+}
+
+
+const uint8_t  MicroBitLEDServiceUUID[] = {
+    0xe9,0x5d,0xd9,0x1d,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitLEDServiceMatrixUUID[] = {
+    0xe9,0x5d,0x7b,0x77,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitLEDServiceTextUUID[] = {
+    0xe9,0x5d,0x93,0xee,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitLEDServiceScrollingSpeedUUID[] = {
+    0xe9,0x5d,0x0d,0x2d,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitMagnetometerService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,156 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the MicroBit BLE Magnetometer Service.
+  * Provides access to live magnetometer data via BLE, and provides basic configuration options.
+  */
+#include "MicroBitConfig.h"
+#include "ble/UUID.h"
+
+#include "MicroBitMagnetometerService.h"
+
+/**
+  * Constructor.
+  * Create a representation of the MagnetometerService.
+  * @param _ble The instance of a BLE device that we're running on.
+  * @param _compass An instance of MicroBitCompass to use as our Magnetometer source.
+  */
+MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble, MicroBitCompass &_compass) :
+        ble(_ble), compass(_compass)
+{
+    // Create the data structures that represent each of our characteristics in Soft Device.
+    GattCharacteristic  magnetometerDataCharacteristic(MicroBitMagnetometerServiceDataUUID, (uint8_t *)magnetometerDataCharacteristicBuffer, 0,
+    sizeof(magnetometerDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    GattCharacteristic  magnetometerBearingCharacteristic(MicroBitMagnetometerServiceBearingUUID, (uint8_t *)&magnetometerBearingCharacteristicBuffer, 0,
+    sizeof(magnetometerBearingCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    GattCharacteristic  magnetometerPeriodCharacteristic(MicroBitMagnetometerServicePeriodUUID, (uint8_t *)&magnetometerPeriodCharacteristicBuffer, 0,
+    sizeof(magnetometerPeriodCharacteristicBuffer),
+    GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    // Initialise our characteristic values.
+    magnetometerDataCharacteristicBuffer[0] = 0;
+    magnetometerDataCharacteristicBuffer[1] = 0;
+    magnetometerDataCharacteristicBuffer[2] = 0;
+    magnetometerBearingCharacteristicBuffer = 0;
+    magnetometerPeriodCharacteristicBuffer = compass.getPeriod();
+
+    // Set default security requirements
+    magnetometerDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    magnetometerBearingCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    magnetometerPeriodCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&magnetometerDataCharacteristic, &magnetometerBearingCharacteristic, &magnetometerPeriodCharacteristic};
+    GattService         service(MicroBitMagnetometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    magnetometerDataCharacteristicHandle = magnetometerDataCharacteristic.getValueHandle();
+    magnetometerBearingCharacteristicHandle = magnetometerBearingCharacteristic.getValueHandle();
+    magnetometerPeriodCharacteristicHandle = magnetometerPeriodCharacteristic.getValueHandle();
+
+    ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer));
+    ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer));
+    ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
+
+    ble.onDataWritten(this, &MicroBitMagnetometerService::onDataWritten);
+    if (EventModel::defaultEventBus)
+    {
+        EventModel::defaultEventBus->listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
+        EventModel::defaultEventBus->listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded);
+    }
+}
+
+/**
+  * Callback. Invoked when any of our attributes are written via BLE.
+  */
+void MicroBitMagnetometerService::onDataWritten(const GattWriteCallbackParams *params)
+{
+    if (params->handle == magnetometerPeriodCharacteristicHandle && params->len >= sizeof(magnetometerPeriodCharacteristicBuffer))
+    {
+        magnetometerPeriodCharacteristicBuffer = *((uint16_t *)params->data);
+        MicroBitEvent evt(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED);
+    }
+}
+
+/**
+  * Magnetometer update callback
+  */
+void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent)
+{
+    if (ble.getGapState().connected)
+    {
+        magnetometerDataCharacteristicBuffer[0] = compass.getX();
+        magnetometerDataCharacteristicBuffer[1] = compass.getY();
+        magnetometerDataCharacteristicBuffer[2] = compass.getZ();
+        magnetometerPeriodCharacteristicBuffer = compass.getPeriod();
+
+        ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
+        ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer));
+
+        if (compass.isCalibrated())
+        {
+            magnetometerBearingCharacteristicBuffer = (uint16_t) compass.heading();
+            ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerBearingCharacteristicBuffer));
+        }
+    }
+}
+
+/**
+ * Sample Period Change Needed callback.
+ * Reconfiguring the magnetometer can to a REALLY long time (sometimes even seconds to complete)
+ * So we do this in the background when necessary, through this event handler.
+ */
+void MicroBitMagnetometerService::samplePeriodUpdateNeeded(MicroBitEvent)
+{
+    // Reconfigure the compass. This might take a while...
+    compass.setPeriod(magnetometerPeriodCharacteristicBuffer);
+
+    // The compass will choose the nearest sample period to that we've specified.
+    // Read the ACTUAL sample period back.
+    magnetometerPeriodCharacteristicBuffer = compass.getPeriod();
+
+    // Ensure this is reflected in our BLE connection.
+    ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
+
+}
+
+const uint8_t  MicroBitMagnetometerServiceUUID[] = {
+    0xe9,0x5d,0xf2,0xd8,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitMagnetometerServiceDataUUID[] = {
+    0xe9,0x5d,0xfb,0x11,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitMagnetometerServicePeriodUUID[] = {
+    0xe9,0x5d,0x38,0x6c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitMagnetometerServiceBearingUUID[] = {
+    0xe9,0x5d,0x97,0x15,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitTemperatureService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,115 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the custom MicroBit Temperature Service.
+  * Provides a BLE service to remotely read the silicon temperature of the nRF51822.
+  */
+#include "MicroBitConfig.h"
+#include "ble/UUID.h"
+
+#include "MicroBitTemperatureService.h"
+
+/**
+  * Constructor.
+  * Create a representation of the TemperatureService
+  * @param _ble The instance of a BLE device that we're running on.
+  * @param _thermometer An instance of MicroBitThermometer to use as our temperature source.
+  */
+MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble, MicroBitThermometer &_thermometer) :
+        ble(_ble), thermometer(_thermometer)
+{
+    // Create the data structures that represent each of our characteristics in Soft Device.
+    GattCharacteristic  temperatureDataCharacteristic(MicroBitTemperatureServiceDataUUID, (uint8_t *)&temperatureDataCharacteristicBuffer, 0,
+    sizeof(temperatureDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
+
+    GattCharacteristic  temperaturePeriodCharacteristic(MicroBitTemperatureServicePeriodUUID, (uint8_t *)&temperaturePeriodCharacteristicBuffer, 0,
+    sizeof(temperaturePeriodCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+
+    // Initialise our characteristic values.
+    temperatureDataCharacteristicBuffer = 0;
+    temperaturePeriodCharacteristicBuffer = thermometer.getPeriod();
+
+    // Set default security requirements
+    temperatureDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+    temperaturePeriodCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
+
+    GattCharacteristic *characteristics[] = {&temperatureDataCharacteristic, &temperaturePeriodCharacteristic};
+    GattService         service(MicroBitTemperatureServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
+
+    ble.addService(service);
+
+    temperatureDataCharacteristicHandle = temperatureDataCharacteristic.getValueHandle();
+    temperaturePeriodCharacteristicHandle = temperaturePeriodCharacteristic.getValueHandle();
+
+    ble.gattServer().write(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer));
+    ble.gattServer().write(temperaturePeriodCharacteristicHandle,(uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer));
+
+    ble.onDataWritten(this, &MicroBitTemperatureService::onDataWritten);
+    if (EventModel::defaultEventBus)
+        EventModel::defaultEventBus->listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
+}
+
+/**
+  * Temperature update callback
+  */
+void MicroBitTemperatureService::temperatureUpdate(MicroBitEvent)
+{
+    if (ble.getGapState().connected)
+    {
+        temperatureDataCharacteristicBuffer = thermometer.getTemperature();
+        ble.gattServer().notify(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer));
+    }
+}
+
+/**
+  * Callback. Invoked when any of our attributes are written via BLE.
+  */
+void MicroBitTemperatureService::onDataWritten(const GattWriteCallbackParams *params)
+{
+    if (params->handle == temperaturePeriodCharacteristicHandle && params->len >= sizeof(temperaturePeriodCharacteristicBuffer))
+    {
+        temperaturePeriodCharacteristicBuffer = *((uint16_t *)params->data);
+        thermometer.setPeriod(temperaturePeriodCharacteristicBuffer);
+
+        // The accelerometer will choose the nearest period to that requested that it can support
+        // Read back the ACTUAL period it is using, and report this back.
+        temperaturePeriodCharacteristicBuffer = thermometer.getPeriod();
+        ble.gattServer().write(temperaturePeriodCharacteristicHandle, (const uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer));
+    }
+}
+
+
+const uint8_t  MicroBitTemperatureServiceUUID[] = {
+    0xe9,0x5d,0x61,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitTemperatureServiceDataUUID[] = {
+    0xe9,0x5d,0x92,0x50,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
+
+const uint8_t  MicroBitTemperatureServicePeriodUUID[] = {
+    0xe9,0x5d,0x1b,0x25,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/bluetooth/MicroBitUARTService.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,539 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the custom MicroBit UART Service.
+  * Provides a BLE service that acts as a UART port, enabling the reception and transmission
+  * of an arbitrary number of bytes.
+  */
+
+#include "ble/UUID.h"
+
+#include "ExternalEvents.h"
+#include "MicroBitUARTService.h"
+#include "MicroBitFiber.h"
+#include "ErrorNo.h"
+#include "NotifyEvents.h"
+
+static uint8_t txBufferHead = 0;
+static uint8_t txBufferTail = 0;
+
+static GattCharacteristic* rxCharacteristic = NULL;
+
+/**
+  * A callback function for whenever a Bluetooth device consumes our RX Buffer
+  */
+void on_confirmation_received_callback(uint16_t handle)
+{
+#if CONFIG_ENABLED(MICROBIT_DBG)
+    SERIAL_DEBUG->printf("RECEIVED!! %d \r\n",handle);
+#endif
+    if(handle == rxCharacteristic->getValueAttribute().getHandle())
+    {
+        txBufferTail = txBufferHead;
+        MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_UART_S_EVT_TX_EMPTY);
+    }
+}
+
+/**
+ * Constructor for the UARTService.
+ * @param _ble an instance of BLEDevice
+ * @param rxBufferSize the size of the rxBuffer
+ * @param txBufferSize the size of the txBuffer
+ *
+ * @note defaults to 20
+ */
+MicroBitUARTService::MicroBitUARTService(BLEDevice &_ble, uint8_t rxBufferSize, uint8_t txBufferSize) : ble(_ble)
+{
+
+    txBuffer = (uint8_t *)malloc(txBufferSize);
+    rxBuffer = (uint8_t *)malloc(rxBufferSize);
+
+    rxBufferHead = 0;
+    rxBufferTail = 0;
+    this->rxBufferSize = rxBufferSize;
+
+    txBufferHead = 0;
+    txBufferTail = 0;
+    this->txBufferSize = txBufferSize;
+
+    GattCharacteristic txCharacteristic(UARTServiceTXCharacteristicUUID, rxBuffer, 1, rxBufferSize, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
+
+    rxCharacteristic = new GattCharacteristic(UARTServiceRXCharacteristicUUID, txBuffer, 1, txBufferSize, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
+
+    GattCharacteristic *charTable[] = {&txCharacteristic, rxCharacteristic};
+
+    GattService uartService(UARTServiceUUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+
+    _ble.addService(uartService);
+
+    this->txCharacteristicHandle = txCharacteristic.getValueAttribute().getHandle();
+
+    _ble.gattServer().onDataWritten(this, &MicroBitUARTService::onDataWritten);
+    _ble.gattServer().onConfirmationReceived(on_confirmation_received_callback);
+}
+
+/**
+  * A callback function for whenever a Bluetooth device writes to our TX characteristic.
+  */
+void MicroBitUARTService::onDataWritten(const GattWriteCallbackParams *params) {
+    if (params->handle == this->txCharacteristicHandle)
+    {
+        uint16_t bytesWritten = params->len;
+
+        for(int byteIterator = 0; byteIterator <  bytesWritten; byteIterator++)
+        {
+            int newHead = (rxBufferHead + 1) % rxBufferSize;
+
+            if(newHead != rxBufferTail)
+            {
+                char c = params->data[byteIterator];
+
+                int delimeterOffset = 0;
+                int delimLength = this->delimeters.length();
+
+                //iterate through our delimeters (if any) to see if there is a match
+                while(delimeterOffset < delimLength)
+                {
+                    //fire an event if there is to block any waiting fibers
+                    if(this->delimeters.charAt(delimeterOffset) == c)
+                        MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH);
+
+                    delimeterOffset++;
+                }
+
+                rxBuffer[rxBufferHead] = c;
+
+                rxBufferHead = newHead;
+
+                if(rxBufferHead == rxBuffHeadMatch)
+                {
+                    rxBuffHeadMatch = -1;
+                    MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_HEAD_MATCH);
+                }
+            }
+            else
+                MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_RX_FULL);
+        }
+    }
+}
+
+/**
+  * An internal method that copies values from a circular buffer to a linear buffer.
+  *
+  * @param circularBuff a pointer to the source circular buffer
+  * @param circularBuffSize the size of the circular buffer
+  * @param linearBuff a pointer to the destination linear buffer
+  * @param tailPosition the tail position in the circular buffer you want to copy from
+  * @param headPosition the head position in the circular buffer you want to copy to
+  *
+  * @note this method assumes that the linear buffer has the appropriate amount of
+  *       memory to contain the copy operation
+  */
+void MicroBitUARTService::circularCopy(uint8_t *circularBuff, uint8_t circularBuffSize, uint8_t *linearBuff, uint16_t tailPosition, uint16_t headPosition)
+{
+    int toBuffIndex = 0;
+
+    while(tailPosition != headPosition)
+    {
+        linearBuff[toBuffIndex++] = circularBuff[tailPosition];
+
+        tailPosition = (tailPosition + 1) % circularBuffSize;
+    }
+}
+
+/**
+  * Retreives a single character from our RxBuffer.
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will attempt to read a single character, and return immediately
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+  *                         event is received.
+  *
+  * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, a character or MICROBIT_NO_DATA
+  */
+int MicroBitUARTService::getc(MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if(mode == ASYNC)
+    {
+        if(!isReadable())
+            return MICROBIT_NO_DATA;
+    }
+
+    if(mode == SYNC_SLEEP)
+    {
+        if(!isReadable())
+            eventAfter(1, mode);
+    }
+
+    char c = rxBuffer[rxBufferTail];
+
+    rxBufferTail = (rxBufferTail + 1) % rxBufferSize;
+
+    return c;
+}
+
+/**
+  * places a single character into our transmission buffer,
+  *
+  * @param c the character to transmit
+  *
+  * @return the number of characters written (0, or 1).
+  */
+int MicroBitUARTService::putc(char c)
+{
+    return (send((uint8_t *)&c, 1) == 1) ? 1 : EOF;
+}
+
+/**
+  * Copies characters into the buffer used for Transmitting to the central device.
+  *
+  * @param buf a buffer containing length number of bytes.
+  * @param length the size of the buffer.
+  *
+  * @return the number of characters copied into the buffer
+  *
+  * @note no modes for sending are available at the moment, due to interrupt overhead.
+  */
+int MicroBitUARTService::send(const uint8_t *buf, int length)
+{
+    if(length < 1)
+        return MICROBIT_INVALID_PARAMETER;
+
+    int bytesWritten = 0;
+
+    if (ble.getGapState().connected) {
+
+        for(int bufferIterator = 0; bufferIterator < length; bufferIterator++)
+        {
+            int nextHead = (txBufferHead + 1) % txBufferSize;
+
+            if(nextHead != txBufferTail)
+            {
+                txBuffer[txBufferHead] = buf[bufferIterator];
+
+                txBufferHead = nextHead;
+
+                bytesWritten++;
+            }
+        }
+
+        int size = txBufferedSize();
+
+#if CONFIG_ENABLED(MICROBIT_DBG)
+        SERIAL_DEBUG->printf("tx size: %d", size);
+#endif
+
+        uint8_t temp[size] = { 0 };
+
+        circularCopy(txBuffer, txBufferSize, temp, txBufferTail, txBufferHead);
+
+#if CONFIG_ENABLED(MICROBIT_DBG)
+        for(int i = 0; i < size; i++)
+            SERIAL_DEBUG->printf("%c",temp[i]);
+#endif
+
+        ble.gattServer().write(rxCharacteristic->getValueAttribute().getHandle(), temp, size);
+    }
+
+#if CONFIG_ENABLED(MICROBIT_DBG)
+    SERIAL_DEBUG->printf("written: %d \r\n",bytesWritten);
+#endif
+
+    return bytesWritten;
+}
+
+/**
+  * Copies characters into the buffer used for Transmitting to the central device.
+  *
+  * @param s the string to transmit
+  *
+  * @return the number of characters copied into the buffer
+  *
+  * @note no modes for sending are available at the moment, due to interrupt overhead.
+  */
+int MicroBitUARTService::send(ManagedString s)
+{
+    return send((uint8_t *)s.toCharArray(), s.length());
+}
+
+/**
+  * Reads a number of characters from the rxBuffer and fills user given buffer.
+  *
+  * @param buf a pointer to a buffer of len bytes.
+  * @param len the size of the user allocated buffer
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will attempt to read all available characters, and return immediately
+  *                    until the buffer limit is reached
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will first of all determine whether the given number of characters
+  *                         are available in our buffer, if not, it will set an event and sleep
+  *                         until the number of characters are avaialable.
+  *
+  * @return the number of characters digested
+  */
+int MicroBitUARTService::read(uint8_t *buf, int len, MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    int i = 0;
+
+    if(mode == ASYNC)
+    {
+        int c;
+
+        while((c = getc(mode)) > 0 && i < len)
+        {
+            buf[i] = c;
+            i++;
+        }
+    }
+
+    if(mode == SYNC_SLEEP)
+    {
+        if(len > rxBufferedSize())
+            eventAfter(len - rxBufferedSize(), mode);
+
+        while(i < len)
+        {
+            buf[i] = (char)getc(mode);
+            i++;
+        }
+    }
+
+    return i;
+}
+
+/**
+  * Reads a number of characters from the rxBuffer and returns them as a ManagedString
+  *
+  * @param len the number of characters to read.
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will attempt to read all available characters, and return immediately
+  *                    until the buffer limit is reached
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will first of all determine whether the given number of characters
+  *                         are available in our buffer, if not, it will set an event and sleep
+  *                         until the number of characters are avaialable.
+  *
+  * @return an empty ManagedString on error, or a ManagedString containing characters
+  */
+ManagedString MicroBitUARTService::read(int len, MicroBitSerialMode mode)
+{
+    uint8_t buf[len + 1] = { 0 };
+
+    int ret = read(buf, len, mode);
+
+    if(ret < 1)
+        return ManagedString();
+
+    return ManagedString((const char *)buf);
+}
+
+/**
+  * Reads characters until a character matches one of the given delimeters
+  *
+  * @param delimeters the number of characters to match against
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will attempt read the immediate buffer, and look for a match.
+  *                    If there isn't, an empty ManagedString will be returned.
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will first of all consider the characters in the immediate buffer,
+  *                         if a match is not found, it will block on an event, fired when a
+  *                         character is matched.
+  *
+  * @return an empty ManagedString on error, or a ManagedString containing characters
+  */
+ManagedString MicroBitUARTService::readUntil(ManagedString delimeters, MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    int localTail = rxBufferTail;
+    int preservedTail = rxBufferTail;
+
+    int foundIndex = -1;
+
+    //ASYNC mode just iterates through our stored characters checking for any matches.
+    while(localTail != rxBufferHead && foundIndex  == -1)
+    {
+        //we use localTail to prevent modification of the actual tail.
+        char c = rxBuffer[localTail];
+
+        for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++)
+            if(delimeters.charAt(delimeterIterator) == c)
+                foundIndex = localTail;
+
+        localTail = (localTail + 1) % rxBufferSize;
+    }
+
+    //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a
+    //matching character.
+    if(mode == SYNC_SLEEP && foundIndex == -1)
+    {
+        eventOn(delimeters, mode);
+
+        foundIndex = rxBufferHead - 1;
+
+        this->delimeters = ManagedString();
+    }
+
+    if(foundIndex >= 0)
+    {
+        //calculate our local buffer size
+        int localBuffSize = (preservedTail > foundIndex) ? (rxBufferSize - preservedTail) + foundIndex : foundIndex - preservedTail;
+
+        uint8_t localBuff[localBuffSize + 1] = { 0 };
+
+        circularCopy(rxBuffer, rxBufferSize, localBuff, preservedTail, foundIndex);
+
+        //plus one for the character we listened for...
+        rxBufferTail = (rxBufferTail + localBuffSize + 1) % rxBufferSize;
+
+        return ManagedString((char *)localBuff, localBuffSize);
+    }
+
+    return ManagedString();
+}
+
+/**
+  * Configures an event to be fired on a match with one of the delimeters.
+  *
+  * @param delimeters the characters to match received characters against e.g. ManagedString("\r\n")
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will configure the event and return immediately.
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+  *                         event is received.
+  *
+  * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+  *
+  * @note delimeters are matched on a per byte basis.
+  */
+int MicroBitUARTService::eventOn(ManagedString delimeters, MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    //configure our head match...
+    this->delimeters = delimeters;
+
+    //block!
+    if(mode == SYNC_SLEEP)
+        fiber_wait_for_event(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures an event to be fired after "len" characters.
+  *
+  * @param len the number of characters to wait before triggering the event
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will configure the event and return immediately.
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+  *                         event is received.
+  *
+  * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+  */
+int MicroBitUARTService::eventAfter(int len, MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    //configure our head match...
+    this->rxBuffHeadMatch = (rxBufferHead + len) % rxBufferSize;
+
+    //block!
+    if(mode == SYNC_SLEEP)
+        fiber_wait_for_event(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_HEAD_MATCH);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Determines if we have space in our rxBuff.
+  *
+  * @return 1 if we have space, 0 if we do not.
+  *
+  * @note the reason we do not wrap the super's readable() method is so that we
+  *       don't interfere with communities that use manual calls to uBit.serial.readable()
+  */
+int MicroBitUARTService::isReadable()
+{
+    return (rxBufferTail != rxBufferHead) ? 1 : 0;
+}
+
+/**
+  * @return The currently buffered number of bytes in our rxBuff.
+  */
+int MicroBitUARTService::rxBufferedSize()
+{
+    if(rxBufferTail > rxBufferHead)
+        return (rxBufferSize - rxBufferTail) + rxBufferHead;
+
+    return rxBufferHead - rxBufferTail;
+}
+
+/**
+  * @return The currently buffered number of bytes in our txBuff.
+  */
+int MicroBitUARTService::txBufferedSize()
+{
+    if(txBufferTail > txBufferHead)
+        return (txBufferSize - txBufferTail) + txBufferHead;
+
+    return txBufferHead - txBufferTail;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MemberFunctionCallback.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,58 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for a MemberFunctionCallback.
+  *
+  * C++ member functions (also known as methods) have a more complex
+  * representation than normal C functions. This class allows a reference to
+  * a C++ member function to be stored then called at a later date.
+  *
+  * This class is used extensively by the MicroBitMessageBus to deliver
+  * events to C++ methods.
+  */
+
+#include "MicroBitConfig.h"
+#include "MemberFunctionCallback.h"
+
+/**
+  * Calls the method reference held by this MemberFunctionCallback.
+  *
+  * @param e The event to deliver to the method
+  */
+void MemberFunctionCallback::fire(MicroBitEvent e)
+{
+    invoke(object, method, e);
+}
+
+/**
+  * A comparison of two MemberFunctionCallback objects.
+  *
+  * @return true if the given MemberFunctionCallback is equivalent to this one, false otherwise.
+  */
+bool MemberFunctionCallback::operator==(const MemberFunctionCallback &mfc)
+{
+    return (object == mfc.object && (memcmp(method,mfc.method,sizeof(method))==0));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MicroBitCompat.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,101 @@
+/*
+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.
+*/
+
+/**
+  * This file contains functions used to maintain compatability and portability.
+  * It also contains constants that are used elsewhere in the DAL.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitCompat.h"
+#include "ErrorNo.h"
+
+
+/**
+  * Performs an in buffer reverse of a given char array.
+  *
+  * @param s the string to reverse.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int string_reverse(char *s)
+{
+    //sanity check...
+    if(s == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    char *j;
+    int c;
+
+    j = s + strlen(s) - 1;
+
+    while(s < j)
+    {
+        c = *s;
+        *s++ = *j;
+        *j-- = c;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Converts a given integer into a string representation.
+  *
+  * @param n The number to convert.
+  *
+  * @param s A pointer to the buffer where the resulting string will be stored.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int itoa(int n, char *s)
+{
+    int i = 0;
+    int positive = (n >= 0);
+
+    if (s == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Record the sign of the number,
+    // Ensure our working value is positive.
+    if (positive)
+        n = -n;
+
+    // Calculate each character, starting with the LSB.
+    do {
+         s[i++] = abs(n % 10) + '0';
+    } while (abs(n /= 10) > 0);
+
+    // Add a negative sign as needed
+    if (!positive)
+        s[i++] = '-';
+
+    // Terminate the string.
+    s[i] = '\0';
+
+    // Flip the order.
+    string_reverse(s);
+
+    return MICROBIT_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MicroBitDevice.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,375 @@
+/*
+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.
+*/
+
+/**
+  * Compatibility / portability funcitons and constants for the MicroBit DAL.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitButton.h"
+#include "MicroBitDevice.h"
+#include "MicroBitFont.h"
+#include "mbed.h"
+#include "ErrorNo.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)
+ * 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
+
+#include "nrf_soc.h"
+#include "nrf_sdm.h"
+
+/*
+ * Return to our predefined compiler settings.
+ */
+#if !defined(__arm)
+#pragma GCC diagnostic pop
+#endif
+
+static char friendly_name[MICROBIT_NAME_LENGTH+1];
+static const uint8_t panicFace[5] = {0x1B, 0x1B,0x0,0x0E,0x11};
+static int panic_timeout = 0;
+static uint32_t random_value = 0;
+
+/**
+  * Determines if a BLE stack is currently running.
+  *
+  * @return true is a bluetooth stack is operational, false otherwise.
+  */
+bool ble_running()
+{
+    uint8_t t;
+    sd_softdevice_is_enabled(&t);
+    return t==1;
+}
+
+/**
+ * Derived a unique, consistent serial number of this device from internal data.
+ *
+ * @return the serial number of this device.
+ */
+uint32_t microbit_serial_number()
+{
+    return NRF_FICR->DEVICEID[1];
+}
+
+/**
+ * Derive the friendly name for this device, based on its serial number.
+ *
+ * @return the serial number of this device.
+ */
+char* microbit_friendly_name()
+{
+    const uint8_t codebook[MICROBIT_NAME_LENGTH][MICROBIT_NAME_CODE_LETTERS] =
+    {
+        {'z', 'v', 'g', 'p', 't'},
+        {'u', 'o', 'i', 'e', 'a'},
+        {'z', 'v', 'g', 'p', 't'},
+        {'u', 'o', 'i', 'e', 'a'},
+        {'z', 'v', 'g', 'p', 't'}
+    };
+
+    // We count right to left, so create a pointer to the end of the buffer.
+	char *name = friendly_name;
+    name += MICROBIT_NAME_LENGTH;
+
+    // Terminate the string.
+    *name = 0;
+
+	// Derive our name from the nrf51822's unique ID.
+    uint32_t n = microbit_serial_number();
+    int ld = 1;
+    int d = MICROBIT_NAME_CODE_LETTERS;
+    int h;
+
+    for (int i=0; i<MICROBIT_NAME_LENGTH; i++)
+    {
+        h = (n % d) / ld;
+        n -= h;
+        d *= MICROBIT_NAME_CODE_LETTERS;
+        ld *= MICROBIT_NAME_CODE_LETTERS;
+        *--name = codebook[i][h];
+    }
+
+    return friendly_name;
+}
+
+/**
+  * Perform a hard reset of the micro:bit.
+  */
+void
+microbit_reset()
+{
+    NVIC_SystemReset();
+}
+
+/**
+  * Determine the version of microbit-dal currently running.
+  * @return a pointer to a character buffer containing a representation of the semantic version number.
+  */
+const char *
+microbit_dal_version()
+{
+    return MICROBIT_DAL_VERSION;
+}
+
+/**
+ * Defines the length of time that the device will remain in a error state before resetting.
+ *
+ * @param iteration The number of times the error code will be displayed before resetting. Set to zero to remain in error state forever.
+ *
+ * @code
+ * microbit_panic_timeout(4);
+ * @endcode
+ */
+void microbit_panic_timeout(int iterations)
+{
+    panic_timeout = iterations;
+}
+
+/**
+  * Disables all interrupts and user processing.
+  * Displays "=(" and an accompanying status code on the default display.
+  * @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
+  *
+  * @code
+  * microbit_panic(20);
+  * @endcode
+  */
+void microbit_panic(int statusCode)
+{
+    DigitalIn resetButton(MICROBIT_PIN_BUTTON_RESET);
+    resetButton.mode(PullUp);
+
+    uint32_t    row_mask = 0;
+    uint32_t    col_mask = 0;
+    uint32_t    row_reset = 0x01 << microbitMatrixMap.rowStart;
+    uint32_t    row_data = row_reset;
+    uint8_t     count = panic_timeout ? panic_timeout : 1;
+    uint8_t     strobeRow = 0;
+
+    row_mask = 0;
+    for (int i = microbitMatrixMap.rowStart; i < microbitMatrixMap.rowStart + microbitMatrixMap.rows; i++)
+        row_mask |= 0x01 << i;
+
+    for (int i = microbitMatrixMap.columnStart; i < microbitMatrixMap.columnStart + microbitMatrixMap.columns; i++)
+        col_mask |= 0x01 << i;
+
+    PortOut LEDMatrix(Port0, row_mask | col_mask);
+
+    if(statusCode < 0 || statusCode > 255)
+        statusCode = 0;
+
+    __disable_irq(); //stop ALL interrupts
+
+
+    //point to the font stored in Flash
+    const unsigned char * fontLocation = MicroBitFont::defaultFont;
+
+    //get individual digits of status code, and place it into a single array/
+    const uint8_t* chars[MICROBIT_PANIC_ERROR_CHARS] = { panicFace, fontLocation+((((statusCode/100 % 10)+48)-MICROBIT_FONT_ASCII_START) * 5), fontLocation+((((statusCode/10 % 10)+48)-MICROBIT_FONT_ASCII_START) * 5), fontLocation+((((statusCode % 10)+48)-MICROBIT_FONT_ASCII_START) * 5)};
+
+    //enter infinite loop.
+    while(count)
+    {
+        //iterate through our chars :)
+        for(int characterCount = 0; characterCount < MICROBIT_PANIC_ERROR_CHARS; characterCount++)
+        {
+            int outerCount = 0;
+
+            //display the current character
+            while(outerCount < 500)
+            {
+                uint32_t col_data = 0;
+
+                int i = 0;
+
+                //if we have hit the row limit - reset both the bit mask and the row variable
+                if(strobeRow == microbitMatrixMap.rows)
+                {
+                    strobeRow = 0;
+                    row_data = row_reset;
+                }
+
+                // Calculate the bitpattern to write.
+                for (i = 0; i < microbitMatrixMap.columns; i++)
+                {
+                    int index = (i * microbitMatrixMap.rows) + strobeRow;
+
+                    int bitMsk = 0x10 >> microbitMatrixMap.map[index].x; //chars are right aligned but read left to right
+                    int y = microbitMatrixMap.map[index].y;
+
+                    if(chars[characterCount][y] & bitMsk)
+                        col_data |= (1 << i);
+                }
+
+                col_data = ~col_data << microbitMatrixMap.columnStart & col_mask;
+
+                LEDMatrix = col_data | row_data;
+
+                //burn cycles
+                i = 1000;
+                while(i>0)
+                {
+                    // Check if the reset button has been pressed. Interrupts are disabled, so the normal method can't be relied upon...
+                    if (resetButton == 0)
+                        microbit_reset();
+
+                    i--;
+                }
+
+                //update the bit mask and row count
+                row_data <<= 1;
+                strobeRow++;
+                outerCount++;
+            }
+        }
+
+        if (panic_timeout)
+            count--;
+    }
+
+    microbit_reset();
+}
+
+/**
+  * Generate a random number in the given range.
+  * We use a simple Galois LFSR random number generator here,
+  * as a Galois LFSR is sufficient for our applications, and much more lightweight
+  * than the hardware random number generator built int the processor, which takes
+  * a long time and uses a lot of energy.
+  *
+  * KIDS: You shouldn't use this is the real world to generte cryptographic keys though...
+  * have a think why not. :-)
+  *
+  * @param max the upper range to generate a number for. This number cannot be negative.
+  *
+  * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE if max is <= 0.
+  *
+  * @code
+  * microbit_random(200); //a number between 0 and 199
+  * @endcode
+  */
+int microbit_random(int max)
+{
+    uint32_t m, result;
+
+    if(max <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Our maximum return value is actually one less than passed
+    max--;
+
+    do {
+        m = (uint32_t)max;
+        result = 0;
+		do {
+            // Cycle the LFSR (Linear Feedback Shift Register).
+            // We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneier here (a true legend in the field!),
+            // For those interested, it's documented in his paper:
+            // "Pseudo-Random Sequence Generator for 32-Bit CPUs: A fast, machine-independent generator for 32-bit Microprocessors"
+            // https://www.schneier.com/paper-pseudorandom-sequence.html
+			uint32_t rnd = random_value;
+
+            rnd = ((((rnd >> 31)
+                          ^ (rnd >> 6)
+                          ^ (rnd >> 4)
+                          ^ (rnd >> 2)
+                          ^ (rnd >> 1)
+                          ^ rnd)
+                          & 0x0000001)
+                          << 31 )
+                          | (rnd >> 1);
+
+			random_value = rnd;
+
+            result = ((result << 1) | (rnd & 0x00000001));
+        } while(m >>= 1);
+    } while (result > (uint32_t)max);
+
+    return result;
+}
+
+/**
+  * Seed the random number generator (RNG).
+  *
+  * This function uses the NRF51822's in built cryptographic random number generator to seed a Galois LFSR.
+  * We do this as the hardware RNG is relatively high power, and is locked out by the BLE stack internally,
+  * with a less than optimal application interface. A Galois LFSR is sufficient for our
+  * applications, and much more lightweight.
+  */
+void microbit_seed_random()
+{
+    random_value = 0;
+
+    if(ble_running())
+    {
+        // If Bluetooth is enabled, we need to go through the Nordic software to safely do this.
+        uint32_t result = sd_rand_application_vector_get((uint8_t*)&random_value, sizeof(random_value));
+
+        // If we couldn't get the random bytes then at least make the seed non-zero.
+        if (result != NRF_SUCCESS)
+            random_value = 0xBBC5EED;
+    }
+    else
+    {
+        // Othwerwise we can access the hardware RNG directly.
+
+        // Start the Random number generator. No need to leave it running... I hope. :-)
+        NRF_RNG->TASKS_START = 1;
+
+        for(int i = 0; i < 4; i++)
+        {
+            // Clear the VALRDY EVENT
+            NRF_RNG->EVENTS_VALRDY = 0;
+
+            // Wait for a number ot be generated.
+            while(NRF_RNG->EVENTS_VALRDY == 0);
+
+            random_value = (random_value << 8) | ((int) NRF_RNG->VALUE);
+        }
+
+        // Disable the generator to save power.
+        NRF_RNG->TASKS_STOP = 1;
+    }
+}
+
+/**
+  * Seed the pseudo random number generator (RNG) using the given 32-bit value.
+  * This function does not use the NRF51822's in built cryptographic random number generator.
+  *
+  * @param seed The value to use as a seed.
+  */
+void microbit_seed_random(uint32_t seed)
+{
+    random_value = seed;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MicroBitFiber.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,964 @@
+/*
+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.
+*/
+
+/**
+  * Functionality definitions for the MicroBit Fiber scheduler.
+  *
+  * This lightweight, non-preemptive scheduler provides a simple threading mechanism for two main purposes:
+  *
+  * 1) To provide a clean abstraction for application languages to use when building async behaviour (callbacks).
+  * 2) To provide ISR decoupling for EventModel events generated in an ISR context.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitFiber.h"
+#include "MicroBitSystemTimer.h"
+
+/*
+ * Statically allocated values used to create and destroy Fibers.
+ * required to be defined here to allow persistence during context switches.
+ */
+Fiber *currentFiber = NULL;                        // The context in which the current fiber is executing.
+static Fiber *forkedFiber = NULL;                  // The context in which a newly created child fiber is executing.
+static Fiber *idleFiber = NULL;                    // the idle task - performs a power efficient sleep, and system maintenance tasks.
+
+/*
+ * Scheduler state.
+ */
+static Fiber *runQueue = NULL;                     // The list of runnable fibers.
+static Fiber *sleepQueue = NULL;                   // The list of blocked fibers waiting on a fiber_sleep() operation.
+static Fiber *waitQueue = NULL;                    // The list of blocked fibers waiting on an event.
+static Fiber *fiberPool = NULL;                    // Pool of unused fibers, just waiting for a job to do.
+
+/*
+ * Scheduler wide flags
+ */
+static uint8_t fiber_flags = 0;
+
+
+/*
+ * Fibers may perform wait/notify semantics on events. If set, these operations will be permitted on this EventModel.
+ */
+static EventModel *messageBus = NULL;
+
+// Array of components which are iterated during idle thread execution, isIdleCallbackNeeded is polled during a systemTick.
+static MicroBitComponent* idleThreadComponents[MICROBIT_IDLE_COMPONENTS];
+
+/**
+  * Utility function to add the currenty running fiber to the given queue.
+  *
+  * Perform a simple add at the head, to avoid complexity,
+  *
+  * Queues are normally very short, so maintaining a doubly linked, sorted list typically outweighs the cost of
+  * brute force searching.
+  *
+  * @param f The fiber to add to the queue
+  *
+  * @param queue The run queue to add the fiber to.
+  */
+void queue_fiber(Fiber *f, Fiber **queue)
+{
+    __disable_irq();
+
+    // Record which queue this fiber is on.
+    f->queue = queue;
+
+    // Add the fiber to the tail of the queue. Although this involves scanning the
+    // list, it results in fairer scheduling.
+    if (*queue == NULL)
+    {
+        f->next = NULL;
+        f->prev = NULL;
+        *queue = f;
+    }
+    else
+    {
+        // Scan to the end of the queue.
+        // We don't maintain a tail pointer to save RAM (queues are nrmally very short).
+        Fiber *last = *queue;
+
+        while (last->next != NULL)
+            last = last->next;
+
+        last->next = f;
+        f->prev = last;
+        f->next = NULL;
+    }
+
+    __enable_irq();
+}
+
+/**
+  * Utility function to the given fiber from whichever queue it is currently stored on.
+  *
+  * @param f the fiber to remove.
+  */
+void dequeue_fiber(Fiber *f)
+{
+    // If this fiber is already dequeued, nothing the there's nothing to do.
+    if (f->queue == NULL)
+        return;
+
+    // Remove this fiber fromm whichever queue it is on.
+    __disable_irq();
+
+    if (f->prev != NULL)
+        f->prev->next = f->next;
+    else
+        *(f->queue) = f->next;
+
+    if(f->next)
+        f->next->prev = f->prev;
+
+    f->next = NULL;
+    f->prev = NULL;
+    f->queue = NULL;
+
+    __enable_irq();
+
+}
+
+/**
+  * Allocates a fiber from the fiber pool if availiable. Otherwise, allocates a new one from the heap.
+  */
+Fiber *getFiberContext()
+{
+    Fiber *f;
+
+    __disable_irq();
+
+    if (fiberPool != NULL)
+    {
+        f = fiberPool;
+        dequeue_fiber(f);
+        // dequeue_fiber() exits with irqs enabled, so no need to do this again!
+    }
+    else
+    {
+        __enable_irq();
+
+        f = new Fiber();
+
+        if (f == NULL)
+            return NULL;
+
+        f->stack_bottom = 0;
+        f->stack_top = 0;
+    }
+
+    // Ensure this fiber is in suitable state for reuse.
+    f->flags = 0;
+    f->tcb.stack_base = CORTEX_M0_STACK_BASE;
+
+    return f;
+}
+
+
+/**
+  * Initialises the Fiber scheduler.
+  * Creates a Fiber context around the calling thread, and adds it to the run queue as the current thread.
+  *
+  * This function must be called once only from the main thread, and before any other Fiber operation.
+  *
+  * @param _messageBus An event model, used to direct the priorities of the scheduler.
+  */
+void scheduler_init(EventModel &_messageBus)
+{
+    // If we're already initialised, then nothing to do.
+    if (fiber_scheduler_running())
+        return;
+
+	// Store a reference to the messageBus provided.
+	// This parameter will be NULL if we're being run without a message bus.
+	messageBus = &_messageBus;
+
+    // Create a new fiber context
+    currentFiber = getFiberContext();
+
+    // Add ourselves to the run queue.
+    queue_fiber(currentFiber, &runQueue);
+
+    // Create the IDLE fiber.
+    // Configure the fiber to directly enter the idle task.
+    idleFiber = getFiberContext();
+    idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04;
+    idleFiber->tcb.LR = (uint32_t) &idle_task;
+
+	if (messageBus)
+	{
+		// Register to receive events in the NOTIFY channel - this is used to implement wait-notify semantics
+		messageBus->listen(MICROBIT_ID_NOTIFY, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
+		messageBus->listen(MICROBIT_ID_NOTIFY_ONE, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
+	}
+
+	// register a period callback to drive the scheduler and any other registered components.
+    new MicroBitSystemTimerCallback(scheduler_tick);
+
+	fiber_flags |= MICROBIT_SCHEDULER_RUNNING;
+}
+
+/**
+  * Determines if the fiber scheduler is operational.
+  *
+  * @return 1 if the fber scheduler is running, 0 otherwise.
+  */
+int fiber_scheduler_running()
+{
+	if (fiber_flags & MICROBIT_SCHEDULER_RUNNING)
+		return 1;
+
+	return 0;
+}
+
+/**
+  * The timer callback, called from interrupt context once every SYSTEM_TICK_PERIOD_MS milliseconds.
+  * This function checks to determine if any fibers blocked on the sleep queue need to be woken up
+  * and made runnable.
+  */
+void scheduler_tick()
+{
+    Fiber *f = sleepQueue;
+    Fiber *t;
+
+    // Check the sleep queue, and wake up any fibers as necessary.
+    while (f != NULL)
+    {
+        t = f->next;
+
+        if (system_timer_current_time() >= f->context)
+        {
+            // Wakey wakey!
+            dequeue_fiber(f);
+            queue_fiber(f,&runQueue);
+        }
+
+        f = t;
+    }
+}
+
+/**
+  * Event callback. Called from an instance of MicroBitMessageBus whenever an event is raised.
+  *
+  * This function checks to determine if any fibers blocked on the wait queue need to be woken up
+  * and made runnable due to the event.
+  *
+  * @param evt the event that has just been raised on an instance of MicroBitMessageBus.
+  */
+void scheduler_event(MicroBitEvent evt)
+{
+    Fiber *f = waitQueue;
+    Fiber *t;
+    int notifyOneComplete = 0;
+
+	// This should never happen.
+	// It is however, safe to simply ignore any events provided, as if no messageBus if recorded,
+	// no fibers are permitted to block on events.
+	if (messageBus == NULL)
+		return;
+
+    // Check the wait queue, and wake up any fibers as necessary.
+    while (f != NULL)
+    {
+        t = f->next;
+
+        // extract the event data this fiber is blocked on.
+        uint16_t id = f->context & 0xFFFF;
+        uint16_t value = (f->context & 0xFFFF0000) >> 16;
+
+        // Special case for the NOTIFY_ONE channel...
+        if ((evt.source == MICROBIT_ID_NOTIFY_ONE && id == MICROBIT_ID_NOTIFY) && (value == MICROBIT_EVT_ANY || value == evt.value))
+        {
+            if (!notifyOneComplete)
+            {
+                // Wakey wakey!
+                dequeue_fiber(f);
+                queue_fiber(f,&runQueue);
+                notifyOneComplete = 1;
+            }
+        }
+
+        // Normal case.
+        else if ((id == MICROBIT_ID_ANY || id == evt.source) && (value == MICROBIT_EVT_ANY || value == evt.value))
+        {
+            // Wakey wakey!
+            dequeue_fiber(f);
+            queue_fiber(f,&runQueue);
+        }
+
+        f = t;
+    }
+
+    // Unregister this event, as we've woken up all the fibers with this match.
+    if (evt.source != MICROBIT_ID_NOTIFY && evt.source != MICROBIT_ID_NOTIFY_ONE)
+        messageBus->ignore(evt.source, evt.value, scheduler_event);
+}
+
+
+/**
+  * Blocks the calling thread for the given period of time.
+  * The calling thread will be immediateley descheduled, and placed onto a
+  * wait queue until the requested amount of time has elapsed.
+  *
+  * @param t The period of time to sleep, in milliseconds.
+  *
+  * @note the fiber will not be be made runnable until after the elapsed time, but there
+  * are no guarantees precisely when the fiber will next be scheduled.
+  */
+void fiber_sleep(unsigned long t)
+{
+    Fiber *f = currentFiber;
+
+    // If the scheduler is not running, then simply perform a spin wait and exit.
+    if (!fiber_scheduler_running())
+    {
+        wait_ms(t);
+        return;
+    }
+
+    // Sleep is a blocking call, so if we're in a fork on block context,
+    // it's time to spawn a new fiber...
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_FOB)
+    {
+        // Allocate a new fiber. This will come from the fiber pool if availiable,
+        // else a new one will be allocated on the heap.
+        forkedFiber = getFiberContext();
+
+        // If we're out of memory, there's nothing we can do.
+        // keep running in the context of the current thread as a best effort.
+        if (forkedFiber != NULL)
+                f = forkedFiber;
+    }
+
+    // Calculate and store the time we want to wake up.
+    f->context = system_timer_current_time() + t;
+
+    // Remove fiber from the run queue
+    dequeue_fiber(f);
+
+    // Add fiber to the sleep queue. We maintain strict ordering here to reduce lookup times.
+    queue_fiber(f, &sleepQueue);
+
+    // Finally, enter the scheduler.
+    schedule();
+}
+
+/**
+  * Blocks the calling thread until the specified event is raised.
+  * The calling thread will be immediateley descheduled, and placed onto a
+  * wait queue until the requested event is received.
+  *
+  * @param id The ID field of the event to listen for (e.g. MICROBIT_ID_BUTTON_A)
+  *
+  * @param value The value of the event to listen for (e.g. MICROBIT_BUTTON_EVT_CLICK)
+  *
+  * @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel.
+  *
+  * @code
+  * fiber_wait_for_event(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
+  * @endcode
+  *
+  * @note the fiber will not be be made runnable until after the event is raised, but there
+  * are no guarantees precisely when the fiber will next be scheduled.
+  */
+int fiber_wait_for_event(uint16_t id, uint16_t value)
+{
+    int ret = fiber_wake_on_event(id, value);
+
+    if(ret == MICROBIT_OK)
+        schedule();
+
+	return ret;
+}
+
+/**
+  * Configures the fiber context for the current fiber to block on an event ID
+  * and value, but does not deschedule the fiber.
+  *
+  * @param id The ID field of the event to listen for (e.g. MICROBIT_ID_BUTTON_A)
+  *
+  * @param value The value of the event to listen for (e.g. MICROBIT_BUTTON_EVT_CLICK)
+  *
+  * @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel.
+  *
+  * @code
+  * fiber_wake_on_event(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
+  *
+  * //perform some time critical operation.
+  *
+  * //deschedule the current fiber manually, waiting for the previously configured event.
+  * schedule();
+  * @endcode
+  */
+int fiber_wake_on_event(uint16_t id, uint16_t value)
+{
+    Fiber *f = currentFiber;
+
+	if (messageBus == NULL || !fiber_scheduler_running())
+		return MICROBIT_NOT_SUPPORTED;
+
+    // Sleep is a blocking call, so if we'r ein a fork on block context,
+    // it's time to spawn a new fiber...
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_FOB)
+    {
+        // Allocate a TCB from the new fiber. This will come from the tread pool if availiable,
+        // else a new one will be allocated on the heap.
+        forkedFiber = getFiberContext();
+
+        // If we're out of memory, there's nothing we can do.
+        // keep running in the context of the current thread as a best effort.
+        if (forkedFiber != NULL)
+                f = forkedFiber;
+    }
+
+    // Encode the event data in the context field. It's handy having a 32 bit core. :-)
+    f->context = value << 16 | id;
+
+    // Remove ourselve from the run queue
+    dequeue_fiber(f);
+
+    // Add ourselves to the sleep queue. We maintain strict ordering here to reduce lookup times.
+    queue_fiber(f, &waitQueue);
+
+    // Register to receive this event, so we can wake up the fiber when it happens.
+    // Special case for teh notify channel, as we always stay registered for that.
+    if (id != MICROBIT_ID_NOTIFY && id != MICROBIT_ID_NOTIFY_ONE)
+        messageBus->listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Executes the given function asynchronously if necessary.
+  *
+  * Fibers are often used to run event handlers, however many of these event handlers are very simple functions
+  * that complete very quickly, bringing unecessary RAM overhead.
+  *
+  * This function takes a snapshot of the current processor context, then attempts to optimistically call the given function directly.
+  * We only create an additional fiber if that function performs a block operation.
+  *
+  * @param entry_fn The function to execute.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int invoke(void (*entry_fn)(void))
+{
+    // Validate our parameters.
+    if (entry_fn == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if (!fiber_scheduler_running())
+		return MICROBIT_NOT_SUPPORTED;
+
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_FOB)
+    {
+        // If we attempt a fork on block whilst already in  fork n block context,
+        // simply launch a fiber to deal with the request and we're done.
+        create_fiber(entry_fn);
+        return MICROBIT_OK;
+    }
+
+    // Snapshot current context, but also update the Link Register to
+    // refer to our calling function.
+    save_register_context(&currentFiber->tcb);
+
+    // If we're here, there are two possibilities:
+    // 1) We're about to attempt to execute the user code
+    // 2) We've already tried to execute the code, it blocked, and we've backtracked.
+
+    // If we're returning from the user function and we forked another fiber then cleanup and exit.
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_PARENT)
+    {
+        currentFiber->flags &= ~MICROBIT_FIBER_FLAG_FOB;
+        currentFiber->flags &= ~MICROBIT_FIBER_FLAG_PARENT;
+        return MICROBIT_OK;
+    }
+
+    // Otherwise, we're here for the first time. Enter FORK ON BLOCK mode, and
+    // execute the function directly. If the code tries to block, we detect this and
+    // spawn a thread to deal with it.
+    currentFiber->flags |= MICROBIT_FIBER_FLAG_FOB;
+    entry_fn();
+    currentFiber->flags &= ~MICROBIT_FIBER_FLAG_FOB;
+
+    // If this is is an exiting fiber that for spawned to handle a blocking call, recycle it.
+    // The fiber will then re-enter the scheduler, so no need for further cleanup.
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_CHILD)
+        release_fiber();
+
+     return MICROBIT_OK;
+}
+
+/**
+  * Executes the given function asynchronously if necessary, and offers the ability to provide a parameter.
+  *
+  * Fibers are often used to run event handlers, however many of these event handlers are very simple functions
+  * that complete very quickly, bringing unecessary RAM. overhead
+  *
+  * This function takes a snapshot of the current fiber context, then attempt to optimistically call the given function directly.
+  * We only create an additional fiber if that function performs a block operation.
+  *
+  * @param entry_fn The function to execute.
+  *
+  * @param param an untyped parameter passed into the entry_fn and completion_fn.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  */
+int invoke(void (*entry_fn)(void *), void *param)
+{
+    // Validate our parameters.
+    if (entry_fn == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if (!fiber_scheduler_running())
+		return MICROBIT_NOT_SUPPORTED;
+
+    if (currentFiber->flags & (MICROBIT_FIBER_FLAG_FOB | MICROBIT_FIBER_FLAG_PARENT | MICROBIT_FIBER_FLAG_CHILD))
+    {
+        // If we attempt a fork on block whilst already in a fork on block context,
+        // simply launch a fiber to deal with the request and we're done.
+        create_fiber(entry_fn, param);
+        return MICROBIT_OK;
+    }
+
+    // Snapshot current context, but also update the Link Register to
+    // refer to our calling function.
+    save_register_context(&currentFiber->tcb);
+
+    // If we're here, there are two possibilities:
+    // 1) We're about to attempt to execute the user code
+    // 2) We've already tried to execute the code, it blocked, and we've backtracked.
+
+    // If we're returning from the user function and we forked another fiber then cleanup and exit.
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_PARENT)
+    {
+        currentFiber->flags &= ~MICROBIT_FIBER_FLAG_FOB;
+        currentFiber->flags &= ~MICROBIT_FIBER_FLAG_PARENT;
+        return MICROBIT_OK;
+    }
+
+    // Otherwise, we're here for the first time. Enter FORK ON BLOCK mode, and
+    // execute the function directly. If the code tries to block, we detect this and
+    // spawn a thread to deal with it.
+    currentFiber->flags |= MICROBIT_FIBER_FLAG_FOB;
+    entry_fn(param);
+    currentFiber->flags &= ~MICROBIT_FIBER_FLAG_FOB;
+
+    // If this is is an exiting fiber that for spawned to handle a blocking call, recycle it.
+    // The fiber will then re-enter the scheduler, so no need for further cleanup.
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_CHILD)
+        release_fiber(param);
+
+    return MICROBIT_OK;
+}
+
+/**
+ * Launches a fiber.
+ *
+ * @param ep the entry point for the fiber.
+ *
+ * @param cp the completion routine after ep has finished execution
+ */
+void launch_new_fiber(void (*ep)(void), void (*cp)(void))
+{
+    // Execute the thread's entrypoint
+    ep();
+
+    // Execute the thread's completion routine;
+    cp();
+
+    // If we get here, then the completion routine didn't recycle the fiber... so do it anyway. :-)
+    release_fiber();
+}
+
+/**
+ * Launches a fiber with a parameter
+ *
+ * @param ep the entry point for the fiber.
+ *
+ * @param cp the completion routine after ep has finished execution
+ *
+ * @param pm the parameter to provide to ep and cp.
+ */
+void launch_new_fiber_param(void (*ep)(void *), void (*cp)(void *), void *pm)
+{
+    // Execute the thread's entrypoint.
+    ep(pm);
+
+    // Execute the thread's completion routine.
+    cp(pm);
+
+    // If we get here, then the completion routine didn't recycle the fiber... so do it anyway. :-)
+    release_fiber(pm);
+}
+
+Fiber *__create_fiber(uint32_t ep, uint32_t cp, uint32_t pm, int parameterised)
+{
+    // Validate our parameters.
+    if (ep == 0 || cp == 0)
+        return NULL;
+
+    // Allocate a TCB from the new fiber. This will come from the fiber pool if availiable,
+    // else a new one will be allocated on the heap.
+    Fiber *newFiber = getFiberContext();
+
+    // If we're out of memory, there's nothing we can do.
+    if (newFiber == NULL)
+        return NULL;
+
+    newFiber->tcb.R0 = (uint32_t) ep;
+    newFiber->tcb.R1 = (uint32_t) cp;
+    newFiber->tcb.R2 = (uint32_t) pm;
+
+    // Set the stack and assign the link register to refer to the appropriate entry point wrapper.
+    newFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04;
+    newFiber->tcb.LR = parameterised ? (uint32_t) &launch_new_fiber_param : (uint32_t) &launch_new_fiber;
+
+    // Add new fiber to the run queue.
+    queue_fiber(newFiber, &runQueue);
+
+    return newFiber;
+}
+
+/**
+  * Creates a new Fiber, and launches it.
+  *
+  * @param entry_fn The function the new Fiber will begin execution in.
+  *
+  * @param completion_fn The function called when the thread completes execution of entry_fn.
+  *                      Defaults to release_fiber.
+  *
+  * @return The new Fiber, or NULL if the operation could not be completed.
+  */
+Fiber *create_fiber(void (*entry_fn)(void), void (*completion_fn)(void))
+{
+    if (!fiber_scheduler_running())
+		return NULL;
+
+    return __create_fiber((uint32_t) entry_fn, (uint32_t)completion_fn, 0, 0);
+}
+
+
+/**
+  * Creates a new parameterised Fiber, and launches it.
+  *
+  * @param entry_fn The function the new Fiber will begin execution in.
+  *
+  * @param param an untyped parameter passed into the entry_fn and completion_fn.
+  *
+  * @param completion_fn The function called when the thread completes execution of entry_fn.
+  *                      Defaults to release_fiber.
+  *
+  * @return The new Fiber, or NULL if the operation could not be completed.
+  */
+Fiber *create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)(void *))
+{
+    if (!fiber_scheduler_running())
+		return NULL;
+
+    return __create_fiber((uint32_t) entry_fn, (uint32_t)completion_fn, (uint32_t) param, 1);
+}
+
+/**
+  * Exit point for all fibers.
+  *
+  * Any fiber reaching the end of its entry function will return here  for recycling.
+  */
+void release_fiber(void *)
+{
+    if (!fiber_scheduler_running())
+		return;
+
+    release_fiber();
+}
+
+/**
+  * Exit point for all fibers.
+  *
+  * Any fiber reaching the end of its entry function will return here  for recycling.
+  */
+void release_fiber(void)
+{
+    if (!fiber_scheduler_running())
+		return;
+
+    // Remove ourselves form the runqueue.
+    dequeue_fiber(currentFiber);
+
+    // Add ourselves to the list of free fibers
+    queue_fiber(currentFiber, &fiberPool);
+
+    // Find something else to do!
+    schedule();
+}
+
+/**
+  * Resizes the stack allocation of the current fiber if necessary to hold the system stack.
+  *
+  * If the stack allocation is large enough to hold the current system stack, then this function does nothing.
+  * Otherwise, the the current allocation of the fiber is freed, and a larger block is allocated.
+  *
+  * @param f The fiber context to verify.
+  *
+  * @return The stack depth of the given fiber.
+  */
+void verify_stack_size(Fiber *f)
+{
+    // Ensure the stack buffer is large enough to hold the stack Reallocate if necessary.
+    uint32_t stackDepth;
+    uint32_t bufferSize;
+
+    // Calculate the stack depth.
+    stackDepth = f->tcb.stack_base - ((uint32_t) __get_MSP());
+
+    // Calculate the size of our allocated stack buffer
+    bufferSize = f->stack_top - f->stack_bottom;
+
+    // If we're too small, increase our buffer size.
+    if (bufferSize < stackDepth)
+    {
+        // To ease heap churn, we choose the next largest multple of 32 bytes.
+        bufferSize = (stackDepth + 32) & 0xffffffe0;
+
+        // Release the old memory
+        if (f->stack_bottom != 0)
+            free((void *)f->stack_bottom);
+
+        // Allocate a new one of the appropriate size.
+        f->stack_bottom = (uint32_t) malloc(bufferSize);
+
+        // Recalculate where the top of the stack is and we're done.
+        f->stack_top = f->stack_bottom + bufferSize;
+    }
+}
+
+/**
+  * Determines if any fibers are waiting to be scheduled.
+  *
+  * @return The number of fibers currently on the run queue
+  */
+int scheduler_runqueue_empty()
+{
+    return (runQueue == NULL);
+}
+
+/**
+  * Calls the Fiber scheduler.
+  * The calling Fiber will likely be blocked, and control given to another waiting fiber.
+  * Call this function to yield control of the processor when you have nothing more to do.
+  */
+void schedule()
+{
+    if (!fiber_scheduler_running())
+		return;
+
+    // First, take a reference to the currently running fiber;
+    Fiber *oldFiber = currentFiber;
+
+    // First, see if we're in Fork on Block context. If so, we simply want to store the full context
+    // of the currently running thread in a newly created fiber, and restore the context of the
+    // currently running fiber, back to the point where it entered FOB.
+
+    if (currentFiber->flags & MICROBIT_FIBER_FLAG_FOB)
+    {
+        // Record that the fibers have a parent/child relationship
+        currentFiber->flags |= MICROBIT_FIBER_FLAG_PARENT;
+        forkedFiber->flags |= MICROBIT_FIBER_FLAG_CHILD;
+
+        // Define the stack base of the forked fiber to be align with the entry point of the parent fiber
+        forkedFiber->tcb.stack_base = currentFiber->tcb.SP;
+
+        // Ensure the stack allocation of the new fiber is large enough
+        verify_stack_size(forkedFiber);
+
+        // Store the full context of this fiber.
+        save_context(&forkedFiber->tcb, forkedFiber->stack_top);
+
+        // We may now be either the newly created thread, or the one that created it.
+        // if the MICROBIT_FIBER_FLAG_PARENT flag is still set, we're the old thread, so
+        // restore the current fiber to its stored context and we're done.
+        if (currentFiber->flags & MICROBIT_FIBER_FLAG_PARENT)
+            restore_register_context(&currentFiber->tcb);
+
+        // If we're the new thread, we must have been unblocked by the scheduler, so simply return
+        // and continue processing.
+        return;
+    }
+
+    // We're in a normal scheduling context, so perform a round robin algorithm across runnable fibers.
+    // OK - if we've nothing to do, then run the IDLE task (power saving sleep)
+    if (runQueue == NULL)
+        currentFiber = idleFiber;
+
+    else if (currentFiber->queue == &runQueue)
+        // If the current fiber is on the run queue, round robin.
+        currentFiber = currentFiber->next == NULL ? runQueue : currentFiber->next;
+
+    else
+        // Otherwise, just pick the head of the run queue.
+        currentFiber = runQueue;
+
+    if (currentFiber == idleFiber && oldFiber->flags & MICROBIT_FIBER_FLAG_DO_NOT_PAGE)
+    {
+        // Run the idle task right here using the old fiber's stack.
+        // Keep idling while the runqueue is empty, or there is data to process.
+
+        // Run in the context of the original fiber, to preserve state of flags...
+        // as we are running on top of this fiber's stack.
+        currentFiber = oldFiber;
+
+        do
+        {
+            idle();
+        }
+        while (runQueue == NULL);
+
+        // Switch to a non-idle fiber.
+        // If this fiber is the same as the old one then there'll be no switching at all.
+        currentFiber = runQueue;
+    }
+
+    // Swap to the context of the chosen fiber, and we're done.
+    // Don't bother with the overhead of switching if there's only one fiber on the runqueue!
+    if (currentFiber != oldFiber)
+    {
+        // Special case for the idle task, as we don't maintain a stack context (just to save memory).
+        if (currentFiber == idleFiber)
+        {
+            idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04;
+            idleFiber->tcb.LR = (uint32_t) &idle_task;
+        }
+
+        if (oldFiber == idleFiber)
+        {
+            // Just swap in the new fiber, and discard changes to stack and register context.
+            swap_context(NULL, &currentFiber->tcb, 0, currentFiber->stack_top);
+        }
+        else
+        {
+            // Ensure the stack allocation of the fiber being scheduled out is large enough
+            verify_stack_size(oldFiber);
+
+            // Schedule in the new fiber.
+            swap_context(&oldFiber->tcb, &currentFiber->tcb, oldFiber->stack_top, currentFiber->stack_top);
+        }
+    }
+}
+
+/**
+  * Adds a component to the array of idle thread components, which are processed
+  * when the run queue is empty.
+  *
+  * The system timer will poll isIdleCallbackNeeded on each component to determine
+  * if the scheduler should schedule the idle_task imminently.
+  *
+  * @param component The component to add to the array.
+  *
+  * @return MICROBIT_OK on success or MICROBIT_NO_RESOURCES if the fiber components array is full.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * // heap allocated - otherwise it will be paged out!
+  * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
+  *
+  * fiber_add_idle_component(accelerometer);
+  * @endcode
+  */
+int fiber_add_idle_component(MicroBitComponent *component)
+{
+    int i = 0;
+
+    while(idleThreadComponents[i] != NULL && i < MICROBIT_IDLE_COMPONENTS)
+        i++;
+
+    if(i == MICROBIT_IDLE_COMPONENTS)
+        return MICROBIT_NO_RESOURCES;
+
+    idleThreadComponents[i] = component;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Remove a component from the array of idle thread components
+  *
+  * @param component The component to remove from the idle component array.
+  *
+  * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * // heap allocated - otherwise it will be paged out!
+  * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
+  *
+  * fiber_add_idle_component(accelerometer);
+  *
+  * fiber_remove_idle_component(accelerometer);
+  * @endcode
+  */
+int fiber_remove_idle_component(MicroBitComponent *component)
+{
+    int i = 0;
+
+    while(idleThreadComponents[i] != component && i < MICROBIT_IDLE_COMPONENTS)
+        i++;
+
+    if(i == MICROBIT_IDLE_COMPONENTS)
+        return MICROBIT_INVALID_PARAMETER;
+
+    idleThreadComponents[i] = NULL;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Set of tasks to perform when idle.
+  * Service any background tasks that are required, and attempt a power efficient sleep.
+  */
+void idle()
+{
+    // Service background tasks
+    for(int i = 0; i < MICROBIT_IDLE_COMPONENTS; i++)
+        if(idleThreadComponents[i] != NULL)
+            idleThreadComponents[i]->idleTick();
+
+    // If the above did create any useful work, enter power efficient sleep.
+    if(scheduler_runqueue_empty())
+    	__WFE();
+}
+
+/**
+  * The idle task, which is called when the runtime has no fibers that require execution.
+  *
+  * This function typically calls idle().
+  */
+void idle_task()
+{
+    while(1)
+    {
+        idle();
+        schedule();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MicroBitFont.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,99 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for a MicrobitFont
+  * This class represents a font that can be used by the display to render text.
+  *
+  * A MicroBitFont is 5x5.
+  * Each Row is represented by a byte in the array.
+  *
+  * Row Format:
+  *            ================================================================
+  *            | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
+  *            ================================================================
+  *            |  N/A  |  N/A  |  N/A  | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 |
+  *            |  0x80 |  0x40 |  0x20 | 0x10  | 0x08  | 0x04  | 0x02  | 0x01  |
+  *
+  * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 }
+  *
+  * The above will produce an exclaimation mark on the second column in form the left.
+  *
+  * We could compress further, but the complexity of decode would likely outweigh the gains.
+  */
+
+#include "MicroBitConfig.h"
+#include "MicroBitFont.h"
+
+const unsigned char pendolino3[475] = {
+0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60};
+
+
+const unsigned char* MicroBitFont::defaultFont = pendolino3;
+MicroBitFont MicroBitFont::systemFont = MicroBitFont(defaultFont, MICROBIT_FONT_ASCII_END);
+
+/**
+  * Constructor.
+  *
+  * Sets the font represented by this font object.
+  *
+  * @param font A pointer to the beginning of the new font.
+  *
+  * @param asciiEnd the char value at which this font finishes.
+  */
+MicroBitFont::MicroBitFont(const unsigned char* characters, int asciiEnd)
+{
+    this->characters = characters;
+    this->asciiEnd = asciiEnd;
+}
+
+/**
+  * Default Constructor.
+  *
+  * Configures the default font for the display to use.
+  */
+MicroBitFont::MicroBitFont()
+{
+    this->characters = defaultFont;
+    this->asciiEnd = MICROBIT_FONT_ASCII_END;
+}
+
+/**
+  * Modifies the current system font to the given instance of MicroBitFont.
+  *
+  * @param font the new font that will be used to render characters on the display.
+  */
+void MicroBitFont::setSystemFont(MicroBitFont font)
+{
+	MicroBitFont::systemFont = font;
+}
+
+/**
+  * Retreives the font object used for rendering characters on the display.
+  */
+MicroBitFont MicroBitFont::getSystemFont()
+{
+    return MicroBitFont::systemFont;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MicroBitHeapAllocator.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,405 @@
+/*
+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.
+*/
+
+/**
+  * A simple 32 bit block based memory allocator. This allows one or more memory segments to
+  * be designated as heap storage, and is designed to run in a static memory area or inside the standard C
+  * heap for use by the micro:bit runtime. This is required for several reasons:
+  *
+  * 1) It reduces memory fragmentation due to the high churn sometime placed on the heap
+  * by ManagedTypes, fibers and user code. Underlying heap implentations are often have very simplistic
+  * allocation pilicies and suffer from fragmentation in prolonged use - which can cause programs to
+  * stop working after a period of time. The algorithm implemented here is simple, but highly tolerant to
+  * large amounts of churn.
+  *
+  * 2) It allows us to reuse the 8K of SRAM set aside for SoftDevice as additional heap storage
+  * when BLE is not in use.
+  *
+  * 3) It gives a simple example of how memory allocation works! :-)
+  *
+  * P.S. This is a very simple allocator, therefore not without its weaknesses. Why don't you consider
+  * what these are, and consider the tradeoffs against simplicity...
+  *
+  * @note The need for this should be reviewed in the future, if a different memory allocator is
+  * made availiable in the mbed platform.
+  *
+  * TODO: Consider caching recently freed blocks to improve allocation time.
+  */
+
+#include "MicroBitConfig.h"
+#include "MicroBitHeapAllocator.h"
+#include "MicroBitDevice.h"
+#include "ErrorNo.h"
+
+struct HeapDefinition
+{
+    uint32_t *heap_start;		// Physical address of the start of this heap.
+    uint32_t *heap_end;		    // Physical address of the end of this heap.
+};
+
+// A list of all active heap regions, and their dimensions in memory.
+HeapDefinition heap[MICROBIT_MAXIMUM_HEAPS] = { };
+uint8_t heap_count = 0;
+
+#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
+// Diplays a usage summary about a given heap...
+void microbit_heap_print(HeapDefinition &heap)
+{
+	uint32_t	blockSize;
+	uint32_t	*block;
+    int         totalFreeBlock = 0;
+    int         totalUsedBlock = 0;
+    int         cols = 0;
+
+    if (heap.heap_start == NULL)
+    {
+        if(SERIAL_DEBUG) SERIAL_DEBUG->printf("--- HEAP NOT INITIALISED ---\n");
+        return;
+    }
+
+    if(SERIAL_DEBUG) SERIAL_DEBUG->printf("heap_start : %p\n", heap.heap_start);
+    if(SERIAL_DEBUG) SERIAL_DEBUG->printf("heap_end   : %p\n", heap.heap_end);
+    if(SERIAL_DEBUG) SERIAL_DEBUG->printf("heap_size  : %d\n", (int)heap.heap_end - (int)heap.heap_start);
+
+	// Disable IRQ temporarily to ensure no race conditions!
+    __disable_irq();
+
+	block = heap.heap_start;
+	while (block < heap.heap_end)
+	{
+		blockSize = *block & ~MICROBIT_HEAP_BLOCK_FREE;
+        if(SERIAL_DEBUG) SERIAL_DEBUG->printf("[%c:%d] ", *block & MICROBIT_HEAP_BLOCK_FREE ? 'F' : 'U', blockSize*4);
+        if (cols++ == 20)
+        {
+            if(SERIAL_DEBUG) SERIAL_DEBUG->printf("\n");
+            cols = 0;
+        }
+
+        if (*block & MICROBIT_HEAP_BLOCK_FREE)
+            totalFreeBlock += blockSize;
+        else
+            totalUsedBlock += blockSize;
+
+		block += blockSize;
+    }
+
+	// Enable Interrupts
+    __enable_irq();
+
+    if(SERIAL_DEBUG) SERIAL_DEBUG->printf("\n");
+
+    if(SERIAL_DEBUG) SERIAL_DEBUG->printf("mb_total_free : %d\n", totalFreeBlock*4);
+    if(SERIAL_DEBUG) SERIAL_DEBUG->printf("mb_total_used : %d\n", totalUsedBlock*4);
+}
+
+
+// Diagnostics function. Displays a usage summary about all initialised heaps.
+void microbit_heap_print()
+{
+    for (int i=0; i < heap_count; i++)
+    {
+        if(SERIAL_DEBUG) SERIAL_DEBUG->printf("\nHEAP %d: \n", i);
+        microbit_heap_print(heap[i]);
+    }
+}
+#endif
+
+void microbit_initialise_heap(HeapDefinition &heap)
+{
+    // Simply mark the entire heap as free.
+    *heap.heap_start = ((uint32_t) heap.heap_end - (uint32_t) heap.heap_start) / MICROBIT_HEAP_BLOCK_SIZE;
+    *heap.heap_start |= MICROBIT_HEAP_BLOCK_FREE;
+}
+
+/**
+  * Create and initialise a given memory region as for heap storage.
+  * After this is called, any future calls to malloc, new, free or delete may use the new heap.
+  * The heap allocator will attempt to allocate memory from heaps in the order that they are created.
+  * i.e. memory will be allocated from first heap created until it is full, then the second heap, and so on.
+  *
+  * @param start The start address of memory to use as a heap region.
+  *
+  * @param end The end address of memory to use as a heap region.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the heap could not be allocated.
+  *
+  * @note Only code that #includes MicroBitHeapAllocator.h will use this heap. This includes all micro:bit runtime
+  * code, and user code targetting the runtime. External code can choose to include this file, or
+  * simply use the standard heap.
+  */
+int microbit_create_heap(uint32_t start, uint32_t end)
+{
+    // Ensure we don't exceed the maximum number of heap segments.
+    if (heap_count == MICROBIT_MAXIMUM_HEAPS)
+        return MICROBIT_NO_RESOURCES;
+
+    // Sanity check. Ensure range is valid, large enough and word aligned.
+    if (end <= start || end - start < MICROBIT_HEAP_BLOCK_SIZE*2 || end % 4 != 0 || start % 4 != 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+	// Disable IRQ temporarily to ensure no race conditions!
+    __disable_irq();
+
+    // Record the dimensions of this new heap
+    heap[heap_count].heap_start = (uint32_t *)start;
+    heap[heap_count].heap_end = (uint32_t *)end;
+
+    // Initialise the heap as being completely empty and available for use.
+    microbit_initialise_heap(heap[heap_count]);
+    heap_count++;
+
+	// Enable Interrupts
+    __enable_irq();
+
+#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
+    microbit_heap_print();
+#endif
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Create and initialise a heap region within the current the heap region specified
+  * by the linker script.
+  *
+  * If the requested amount is not available, then the amount requested will be reduced
+  * automatically to fit the space available.
+  *
+  * @param ratio The proportion of the underlying heap to allocate.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the heap could not be allocated.
+  */
+int microbit_create_nested_heap(float ratio)
+{
+    uint32_t length;
+    void *p;
+
+    if (ratio <= 0.0 || ratio > 1.0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Snapshot something at the top of the main heap.
+    p = native_malloc(sizeof(uint32_t));
+
+    // Estimate the size left in our heap, taking care to ensure it lands on a word boundary.
+    length = (uint32_t) (((float)(MICROBIT_HEAP_END - (uint32_t)p)) * ratio);
+    length &= 0xFFFFFFFC;
+
+    // Release our reference pointer.
+    native_free(p);
+    p = NULL;
+
+    // Allocate memory for our heap.
+    // We iteratively reduce the size of memory are allocate until it fits within available space.
+    while (p == NULL)
+    {
+        p = native_malloc(length);
+        if (p == NULL)
+        {
+            length -= 32;
+            if (length <= 0)
+                return MICROBIT_NO_RESOURCES;
+        }
+    }
+
+    uint32_t start = (uint32_t) p;
+    microbit_create_heap(start, start + length);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Attempt to allocate a given amount of memory from any of our configured heap areas.
+  *
+  * @param size The amount of memory, in bytes, to allocate.
+  *
+  * @return A pointer to the allocated memory, or NULL if insufficient memory is available.
+  */
+void *microbit_malloc(size_t size, HeapDefinition &heap)
+{
+	uint32_t	blockSize = 0;
+	uint32_t	blocksNeeded = size % MICROBIT_HEAP_BLOCK_SIZE == 0 ? size / MICROBIT_HEAP_BLOCK_SIZE : size / MICROBIT_HEAP_BLOCK_SIZE + 1;
+	uint32_t	*block;
+	uint32_t	*next;
+
+	if (size <= 0)
+		return NULL;
+
+	// Account for the index block;
+	blocksNeeded++;
+
+	// Disable IRQ temporarily to ensure no race conditions!
+    __disable_irq();
+
+	// We implement a first fit algorithm with cache to handle rapid churn...
+    // We also defragment free blocks as we search, to optimise this and future searches.
+	block = heap.heap_start;
+	while (block < heap.heap_end)
+	{
+		// If the block is used, then keep looking.
+		if(!(*block & MICROBIT_HEAP_BLOCK_FREE))
+		{
+			block += *block;
+			continue;
+		}
+
+		blockSize = *block & ~MICROBIT_HEAP_BLOCK_FREE;
+
+		// We have a free block. Let's see if the subsequent ones are too. If so, we can merge...
+		next = block + blockSize;
+
+		while (*next & MICROBIT_HEAP_BLOCK_FREE)
+		{
+			if (next >= heap.heap_end)
+				break;
+
+			// We can merge!
+			blockSize += (*next & ~MICROBIT_HEAP_BLOCK_FREE);
+			*block = blockSize | MICROBIT_HEAP_BLOCK_FREE;
+
+			next = block + blockSize;
+		}
+
+		// We have a free block. Let's see if it's big enough.
+        // If so, we have a winner.
+		if (blockSize >= blocksNeeded)
+			break;
+
+		// Otherwise, keep looking...
+		block += blockSize;
+	}
+
+	// We're full!
+	if (block >= heap.heap_end)
+    {
+        __enable_irq();
+        return NULL;
+    }
+
+	// If we're at the end of memory or have very near match then mark the whole segment as in use.
+	if (blockSize <= blocksNeeded+1 || block+blocksNeeded+1 >= heap.heap_end)
+	{
+		// Just mark the whole block as used.
+		*block &= ~MICROBIT_HEAP_BLOCK_FREE;
+	}
+	else
+	{
+		// We need to split the block.
+		uint32_t *splitBlock = block + blocksNeeded;
+		*splitBlock = blockSize - blocksNeeded;
+		*splitBlock |= MICROBIT_HEAP_BLOCK_FREE;
+
+		*block = blocksNeeded;
+	}
+
+	// Enable Interrupts
+    __enable_irq();
+
+	return block+1;
+}
+
+/**
+  * Release a given area of memory from the heap.
+  *
+  * @param mem The memory area to release.
+  */
+void *microbit_malloc(size_t size)
+{
+    void *p;
+
+    // Assign the memory from the first heap created that has space.
+    for (int i=0; i < heap_count; i++)
+    {
+        p = microbit_malloc(size, heap[i]);
+        if (p != NULL)
+        {
+#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
+            if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_malloc: ALLOCATED: %d [%p]\n", size, p);
+#endif
+            return p;
+        }
+    }
+
+    // If we reach here, then either we have no memory available, or our heap spaces
+    // haven't been initialised. Either way, we try the native allocator.
+
+    p = native_malloc(size);
+    if (p != NULL)
+    {
+#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
+        // Keep everything trasparent if we've not been initialised yet
+        if (heap_count > 0)
+            if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_malloc: NATIVE ALLOCATED: %d [%p]\n", size, p);
+#endif
+        return p;
+    }
+
+    // We're totally out of options (and memory!).
+#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
+    // Keep everything transparent if we've not been initialised yet
+    if (heap_count > 0)
+        if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_malloc: OUT OF MEMORY [%d]\n", size);
+#endif
+
+#if CONFIG_ENABLED(MICROBIT_PANIC_HEAP_FULL)
+	microbit_panic(MICROBIT_OOM);
+#endif
+
+    return NULL;
+}
+
+/**
+  * Release a given area of memory from the heap.
+  *
+  * @param mem The memory area to release.
+  */
+void microbit_free(void *mem)
+{
+	uint32_t	*memory = (uint32_t *)mem;
+	uint32_t	*cb = memory-1;
+
+#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
+    if (heap_count > 0)
+        if(SERIAL_DEBUG) SERIAL_DEBUG->printf("microbit_free:   %p\n", mem);
+#endif
+    // Sanity check.
+	if (memory == NULL)
+       return;
+
+    // If this memory was created from a heap registered with us, free it.
+    for (int i=0; i < heap_count; i++)
+    {
+        if(memory > heap[i].heap_start && memory < heap[i].heap_end)
+        {
+            // The memory block given is part of this heap, so we can simply
+	        // flag that this memory area is now free, and we're done.
+	        *cb |= MICROBIT_HEAP_BLOCK_FREE;
+            return;
+        }
+    }
+
+    // If we reach here, then the memory is not part of any registered heap.
+    // Forward it to the native heap allocator, and let nature take its course...
+    native_free(mem);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MicroBitListener.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,122 @@
+/*
+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.
+*/
+
+/**
+  *	This structure defines a MicroBitListener used to invoke functions, or member
+  * functions if an instance of EventModel receives an event whose id and value
+  * match this MicroBitListener's id and value.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitListener.h"
+
+/**
+  * Constructor.
+  *
+  * Create a new Message Bus Listener.
+  *
+  * @param id The ID of the component you want to listen to.
+  *
+  * @param value The event value you would like to listen to from that component
+  *
+  * @param handler A function pointer to call when the event is detected.
+  *
+  * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+  * to be tuned.
+  */
+MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent), uint16_t flags)
+{
+	this->id = id;
+	this->value = value;
+	this->cb = handler;
+	this->cb_arg = NULL;
+    this->flags = flags;
+	this->next = NULL;
+    this->evt_queue = NULL;
+}
+
+/**
+  * Constructor.
+  *
+  * Create a new Message Bus Listener, this constructor accepts an additional
+  * parameter "arg", which is passed to the handler.
+  *
+  * @param id The ID of the component you want to listen to.
+  *
+  * @param value The event value you would like to listen to from that component
+  *
+  * @param handler A function pointer to call when the event is detected.
+  *
+  * @param arg A pointer to some data that will be given to the handler.
+  *
+  * @param flags User specified, implementation specific flags, that allow behaviour of this events listener
+  * to be tuned.
+  */
+MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent, void *), void* arg, uint16_t flags)
+{
+	this->id = id;
+	this->value = value;
+	this->cb_param = handler;
+	this->cb_arg = arg;
+    this->flags = flags | MESSAGE_BUS_LISTENER_PARAMETERISED;
+	this->next = NULL;
+    this->evt_queue = NULL;
+}
+
+/**
+  * Destructor. Ensures all resources used by this listener are freed.
+  */
+MicroBitListener::~MicroBitListener()
+{
+    if(this->flags & MESSAGE_BUS_LISTENER_METHOD)
+        delete cb_method;
+}
+
+/**
+  * Queues and event up to be processed.
+  *
+  * @param e The event to queue
+  */
+void MicroBitListener::queue(MicroBitEvent e)
+{
+    int queueDepth;
+
+    MicroBitEventQueueItem *p = evt_queue;
+
+    if (evt_queue == NULL)
+        evt_queue = new MicroBitEventQueueItem(e);
+    else
+    {
+        queueDepth = 1;
+
+        while (p->next != NULL)
+        {
+            p = p->next;
+            queueDepth++;
+        }
+
+        if (queueDepth < MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH)
+            p->next = new MicroBitEventQueueItem(e);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/core/MicroBitSystemTimer.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,181 @@
+/*
+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.
+*/
+
+/**
+  * Definitions for the MicroBit system timer.
+  *
+  * This module provides:
+  *
+  * 1) a concept of global system time since power up
+  * 2) a simple periodic multiplexing API for the underlying mbed implementation.
+  *
+  * The latter is useful to avoid costs associated with multiple mbed Ticker instances
+  * in microbit-dal components, as each incurs a significant additional RAM overhead (circa 80 bytes).
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitSystemTimer.h"
+#include "ErrorNo.h"
+
+/*
+ * Time since power on. Measured in milliseconds.
+ * When stored as an unsigned long, this gives us approx 50 days between rollover, which is ample. :-)
+ */
+static unsigned long ticks = 0;
+static unsigned int tick_period = 0;
+
+// Array of components which are iterated during a system tick
+static MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS];
+
+// Periodic callback interrupt
+static Ticker *timer = NULL;
+
+
+/**
+  * Initialises the system wide timer.
+  *
+  * This must be called before any components register to receive periodic periodic callbacks.
+  *
+  * @param timer_period The initial period between interrupts, in millseconds.
+  *
+  * @return MICROBIT_OK on success.
+  */
+int system_timer_init(int period)
+{
+    if (timer == NULL)
+        timer = new Ticker();
+
+    return system_timer_set_period(period);
+}
+
+/**
+  * Reconfigures the system wide timer to the given period in milliseconds.
+  *
+  * @param period the new period of the timer in milliseconds
+  *
+  * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if period < 1
+  */
+int system_timer_set_period(int period)
+{
+    if (period < 1)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If a timer is already running, ensure it is disabled before reconfiguring.
+    if (tick_period)
+        timer->detach();
+
+	// register a period callback to drive the scheduler and any other registered components.
+    tick_period = period;
+    timer->attach_us(system_timer_tick, period * 1000);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Accessor to obtain the current tick period in milliseconds
+  *
+  * @return the current tick period in milliseconds
+  */
+int system_timer_get_period()
+{
+    return tick_period;
+}
+
+/**
+  * Determines the time since the device was powered on.
+  *
+  * @return the current time since power on in milliseconds
+  */
+unsigned long system_timer_current_time()
+{
+    return ticks;
+}
+
+/**
+  * Timer callback. Called from interrupt context, once per period.
+  *
+  * Simply checks to determine if any fibers blocked on the sleep queue need to be woken up
+  * and made runnable.
+  */
+void system_timer_tick()
+{
+    // increment our real-time counter.
+    ticks += system_timer_get_period();
+
+    // Update any components registered for a callback
+    for(int i = 0; i < MICROBIT_SYSTEM_COMPONENTS; i++)
+        if(systemTickComponents[i] != NULL)
+            systemTickComponents[i]->systemTick();
+}
+
+/**
+  * Add a component to the array of system components. This component will then receive
+  * periodic callbacks, once every tick period.
+  *
+  * @param component The component to add.
+  *
+  * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if the component array is full.
+  *
+  * @note The callback will be in interrupt context.
+  */
+int system_timer_add_component(MicroBitComponent *component)
+{
+    int i = 0;
+
+    // If we haven't been initialized, bring up the timer with the default period.
+    if (timer == NULL)
+        system_timer_init(SYSTEM_TICK_PERIOD_MS);
+
+    while(systemTickComponents[i] != NULL && i < MICROBIT_SYSTEM_COMPONENTS)
+        i++;
+
+    if(i == MICROBIT_SYSTEM_COMPONENTS)
+        return MICROBIT_NO_RESOURCES;
+
+    systemTickComponents[i] = component;
+    return MICROBIT_OK;
+}
+
+/**
+  * Remove a component from the array of system components. This component will no longer receive
+  * periodic callbacks.
+  *
+  * @param component The component to remove.
+  *
+  * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
+  */
+int system_timer_remove_component(MicroBitComponent *component)
+{
+    int i = 0;
+
+    while(systemTickComponents[i] != component && i < MICROBIT_SYSTEM_COMPONENTS)
+        i++;
+
+    if(i == MICROBIT_SYSTEM_COMPONENTS)
+        return MICROBIT_INVALID_PARAMETER;
+
+    systemTickComponents[i] = NULL;
+
+    return MICROBIT_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/DynamicPwm.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,331 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for DynamicPwm.
+  *
+  * This class addresses a few issues found in the underlying libraries.
+  * This provides the ability for a neat, clean swap between PWM channels.
+  */
+
+#include "MicroBitConfig.h"
+#include "DynamicPwm.h"
+#include "MicroBitPin.h"
+#include "ErrorNo.h"
+
+DynamicPwm* DynamicPwm::pwms[NO_PWMS] = { NULL };
+
+uint8_t DynamicPwm::lastUsed = NO_PWMS+1; //set it to out of range i.e. 4 so we know it hasn't been used yet.
+
+uint16_t DynamicPwm::sharedPeriod = 0; //set the shared period to an unknown state
+
+/**
+  * Reassigns an already operational PWM channel to the given pin.
+  *
+  * @param pin The desired pin to begin a PWM wave.
+  *
+  * @param oldPin The pin to stop running a PWM wave.
+  *
+  * @param channel_number The GPIOTE channel being used to drive this PWM channel
+  *
+  * TODO: Merge into mbed, at a later date.
+  */
+void gpiote_reinit(PinName pin, PinName oldPin, uint8_t channel_number)
+{
+    // Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as an output.
+    NRF_GPIO->PIN_CNF[pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
+                            | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+                            | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
+                            | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+                            | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
+
+    NRF_GPIO->OUTCLR = (1 << oldPin);
+    NRF_GPIO->OUTCLR = (1 << pin);
+
+    /* Finally configure the channel as the caller expects. If OUTINIT works, the channel is configured properly.
+       If it does not, the channel output inheritance sets the proper level. */
+
+    NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
+                                         ((uint32_t)pin << GPIOTE_CONFIG_PSEL_Pos) |
+                                         ((uint32_t)GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) |
+                                         ((uint32_t)GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos); // ((uint32_t)GPIOTE_CONFIG_OUTINIT_High <<
+                                                                                                             // GPIOTE_CONFIG_OUTINIT_Pos);//
+
+    /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */
+    __NOP();
+    __NOP();
+    __NOP();
+
+    NRF_TIMER2->CC[channel_number] = 0;
+}
+
+/**
+  * An internal constructor used when allocating a new DynamicPwm instance.
+  *
+  * @param pin the name of the pin for the pwm to target
+  *
+  * @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
+  *                    or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
+  */
+DynamicPwm::DynamicPwm(PinName pin, PwmPersistence persistence) : PwmOut(pin)
+{
+    this->flags = persistence;
+}
+
+/**
+  * Redirects the pwm channel to point at a different pin.
+  *
+  * @param pin the desired pin to output a PWM wave.
+  *
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  * pwm->redirect(p0); // pwm is now produced on p0
+  * @endcode
+  */
+void DynamicPwm::redirect(PinName pin)
+{
+    gpiote_reinit(pin, _pwm.pin, (uint8_t)_pwm.pwm);
+    this->_pwm.pin = pin;
+}
+
+/**
+  * Creates a new DynamicPwm instance, or reuses an existing instance that
+  * has a persistence level of PWM_PERSISTENCE_TRANSIENT.
+  *
+  * @param pin the name of the pin for the pwm to target
+  *
+  * @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
+  *                    or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
+  *
+  * @return a pointer to the first available free pwm channel - or the first one that can be reallocated. If
+  *         no channels are available, NULL is returned.
+  *
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  * @endcode
+  */
+DynamicPwm* DynamicPwm::allocate(PinName pin, PwmPersistence persistence)
+{
+    //try to find a blank spot first
+    for(int i = 0; i < NO_PWMS; i++)
+    {
+        if(pwms[i] == NULL)
+        {
+            lastUsed = i;
+            pwms[i] = new DynamicPwm(pin, persistence);
+            return pwms[i];
+        }
+    }
+
+    //no blank spot.. try to find a transient PWM
+    int channelIterator = (lastUsed + 1 > NO_PWMS - 1) ? 0 : lastUsed + 1;
+
+    while(channelIterator != lastUsed)
+    {
+        if(pwms[channelIterator]->flags & PWM_PERSISTENCE_TRANSIENT)
+        {
+            lastUsed = channelIterator;
+            pwms[channelIterator]->flags = persistence;
+            pwms[channelIterator]->redirect(pin);
+            return pwms[channelIterator];
+        }
+
+        channelIterator = (channelIterator + 1 > NO_PWMS - 1) ? 0 : channelIterator + 1;
+    }
+
+    //if we haven't found a free one, we must try to allocate the last used...
+    if(pwms[lastUsed]->flags & PWM_PERSISTENCE_TRANSIENT)
+    {
+        pwms[lastUsed]->flags = persistence;
+        pwms[lastUsed]->redirect(pin);
+        return pwms[lastUsed];
+    }
+
+    //well if we have no transient channels - we can't give any away! :( return null
+    return (DynamicPwm*)NULL;
+}
+
+/**
+  * Frees this DynamicPwm instance for reuse.
+  *
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate();
+  * pwm->release();
+  * @endcode
+  */
+void DynamicPwm::release()
+{
+    //free the pwm instance.
+    NRF_GPIOTE->CONFIG[(uint8_t) _pwm.pwm] = 0;
+    pwmout_free(&_pwm);
+    this->flags = PWM_PERSISTENCE_TRANSIENT;
+
+    //set the pointer to this object to null...
+    for(int i =0; i < NO_PWMS; i++)
+        if(pwms[i] == this)
+        {
+            delete pwms[i];
+            pwms[i] = NULL;
+        }
+}
+
+/**
+  * A lightweight wrapper around the super class' write in order to capture the value
+  *
+  * @param value the duty cycle percentage in floating point format.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
+  *
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate();
+  * pwm->write(0.5);
+  * @endcode
+  */
+int DynamicPwm::write(float value){
+
+    if(value < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    PwmOut::write(value);
+    lastValue = value;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Retreives the PinName associated with this DynamicPwm instance.
+  *
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  *
+  * // returns the PinName n.
+  * pwm->getPinName();
+  * @endcode
+  *
+  * @note This should be used to check that the DynamicPwm instance has not
+  *       been reallocated for use in another part of a program.
+  */
+PinName DynamicPwm::getPinName()
+{
+    return _pwm.pin;
+}
+
+/**
+  * Retreives the last value that has been written to this DynamicPwm instance.
+  * in the range 0 - 1023 inclusive.
+  *
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  * pwm->write(0.5);
+  *
+  * // will return 512.
+  * pwm->getValue();
+  * @endcode
+  */
+int DynamicPwm::getValue()
+{
+    return (float)lastValue * float(MICROBIT_PIN_MAX_OUTPUT);
+}
+
+/**
+  * Retreives the current period in use by the entire PWM module in microseconds.
+  *
+  * Example:
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  * pwm->getPeriod();
+  * @endcode
+  */
+int DynamicPwm::getPeriodUs()
+{
+    return sharedPeriod;
+}
+
+/**
+  * Retreives the current period in use by the entire PWM module in milliseconds.
+  *
+  * Example:
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  * pwm->setPeriodUs(20000);
+  *
+  * // will return 20000
+  * pwm->getPeriod();
+  * @endcode
+  */
+int DynamicPwm::getPeriod()
+{
+    return getPeriodUs() / 1000;
+}
+
+/**
+  * Sets the period used by the WHOLE PWM module.
+  *
+  * @param period the desired period in microseconds.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if period is out of range
+  *
+  * Example:
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  *
+  * // period now is 20ms
+  * pwm->setPeriodUs(20000);
+  * @endcode
+  *
+  * @note Any changes to the period will AFFECT ALL CHANNELS.
+  */
+int DynamicPwm::setPeriodUs(int period)
+{
+    if(period < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    //#HACK this forces mbed to update the pulse width calculation.
+    period_us(period);
+    write(lastValue);
+    sharedPeriod = period;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
+  *
+  * @param period the desired period in milliseconds.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if period is out of range
+  *
+  * Example:
+  * @code
+  * DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
+  *
+  * // period now is 20ms
+  * pwm->setPeriod(20);
+  * @endcode
+  */
+int DynamicPwm::setPeriod(int period)
+{
+    return setPeriodUs(period * 1000);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitAccelerometer.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,710 @@
+/*
+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.
+*/
+
+/**
+ * Class definition for MicroBit Accelerometer.
+ *
+ * Represents an implementation of the Freescale MMA8653 3 axis accelerometer
+ * Also includes basic data caching and on demand activation.
+ */
+#include "MicroBitConfig.h"
+#include "MicroBitAccelerometer.h"
+#include "ErrorNo.h"
+#include "MicroBitConfig.h"
+#include "MicroBitEvent.h"
+#include "MicroBitCompat.h"
+#include "MicroBitFiber.h"
+
+/**
+  * Configures the accelerometer for G range and sample rate defined
+  * in this object. The nearest values are chosen to those defined
+  * that are supported by the hardware. The instance variables are then
+  * updated to reflect reality.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
+  */
+int MicroBitAccelerometer::configure()
+{
+    const MMA8653SampleRangeConfig  *actualSampleRange;
+    const MMA8653SampleRateConfig  *actualSampleRate;
+    int result;
+
+    // First find the nearest sample rate to that specified.
+    actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1];
+    for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--)
+    {
+        if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000)
+            break;
+
+        actualSampleRate = &MMA8653SampleRate[i];
+    }
+
+    // Now find the nearest sample range to that specified.
+    actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1];
+    for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--)
+    {
+        if(MMA8653SampleRange[i].sample_range < this->sampleRange)
+            break;
+
+        actualSampleRange = &MMA8653SampleRange[i];
+    }
+
+    // OK, we have the correct data. Update our local state.
+    this->samplePeriod = actualSampleRate->sample_period / 1000;
+    this->sampleRange = actualSampleRange->sample_range;
+
+    // Now configure the accelerometer accordingly.
+    // First place the device into standby mode, so it can be configured.
+    result = writeCommand(MMA8653_CTRL_REG1, 0x00);
+    if (result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    // Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
+    result = writeCommand(MMA8653_CTRL_REG2, 0x10);
+    if (result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    // Enable the INT1 interrupt pin.
+    result = writeCommand(MMA8653_CTRL_REG4, 0x01);
+    if (result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    // Select the DATA_READY event source to be routed to INT1
+    result = writeCommand(MMA8653_CTRL_REG5, 0x01);
+    if (result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    // Configure for the selected g range.
+    result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
+    if (result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    // Bring the device back online, with 10bit wide samples at the requested frequency.
+    result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
+    if (result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Issues a standard, 2 byte I2C command write to the accelerometer.
+  *
+  * Blocks the calling thread until complete.
+  *
+  * @param reg The address of the register to write to.
+  *
+  * @param value The value to write.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
+  */
+int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
+{
+    uint8_t command[2];
+    command[0] = reg;
+    command[1] = value;
+
+    return i2c.write(address, (const char *)command, 2);
+}
+
+/**
+  * Issues a read command, copying data into the specified buffer.
+  *
+  * Blocks the calling thread until complete.
+  *
+  * @param reg The address of the register to access.
+  *
+  * @param buffer Memory area to read the data into.
+  *
+  * @param length The number of bytes to read.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
+  */
+int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
+{
+    int result;
+
+    if (buffer == NULL || length <= 0 )
+        return MICROBIT_INVALID_PARAMETER;
+
+    result = i2c.write(address, (const char *)&reg, 1, true);
+    if (result !=0)
+        return MICROBIT_I2C_ERROR;
+
+    result = i2c.read(address, (char *)buffer, length);
+    if (result !=0)
+        return MICROBIT_I2C_ERROR;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Constructor.
+  * Create a software abstraction of an accelerometer.
+  *
+  * @param _i2c an instance of MicroBitI2C used to communicate with the onboard accelerometer.
+  *
+  * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR.
+  *
+  * @param id the unique EventModel id of this component. Defaults to: MICROBIT_ID_ACCELEROMETER
+  *
+  * @code
+  * MicroBitI2C i2c = MicroBitI2C(I2C_SDA0, I2C_SCL0);
+  *
+  * MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c);
+  * @endcode
+ */
+MicroBitAccelerometer::MicroBitAccelerometer(MicroBitI2C& _i2c, uint16_t address, uint16_t id) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY), i2c(_i2c)
+{
+    // Store our identifiers.
+    this->id = id;
+    this->status = 0;
+    this->address = address;
+
+    // Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms).
+    this->samplePeriod = 20;
+    this->sampleRange = 2;
+
+    // Initialise gesture history
+    this->sigma = 0;
+    this->lastGesture = GESTURE_NONE;
+    this->currentGesture = GESTURE_NONE;
+    this->shake.x = 0;
+    this->shake.y = 0;
+    this->shake.z = 0;
+    this->shake.count = 0;
+    this->shake.timer = 0;
+
+    // Configure and enable the accelerometer.
+    if (this->configure() == MICROBIT_OK)
+        status |= MICROBIT_COMPONENT_RUNNING;
+}
+
+/**
+  * Attempts to read the 8 bit ID from the accelerometer, this can be used for
+  * validation purposes.
+  *
+  * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
+  *
+  * @code
+  * accelerometer.whoAmI();
+  * @endcode
+  */
+int MicroBitAccelerometer::whoAmI()
+{
+    uint8_t data;
+    int result;
+
+    result = readCommand(MMA8653_WHOAMI, &data, 1);
+    if (result !=0)
+        return MICROBIT_I2C_ERROR;
+
+    return (int)data;
+}
+
+/**
+  * Reads the acceleration data from the accelerometer, and stores it in our buffer.
+  * This only happens if the accelerometer indicates that it has new data via int1.
+  *
+  * On first use, this member function will attempt to add this component to the
+  * list of fiber components in order to constantly update the values stored
+  * by this object.
+  *
+  * This technique is called lazy instantiation, and it means that we do not
+  * obtain the overhead from non-chalantly adding this component to fiber components.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails.
+  */
+int MicroBitAccelerometer::updateSample()
+{
+    if(!(status & MICROBIT_ACCEL_ADDED_TO_IDLE))
+    {
+        fiber_add_idle_component(this);
+        status |= MICROBIT_ACCEL_ADDED_TO_IDLE;
+    }
+
+    // Poll interrupt line from accelerometer.
+    // n.b. Default is Active LO. Interrupt is cleared in data read.
+    if(!int1)
+    {
+        int8_t data[6];
+        int result;
+
+        result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
+        if (result !=0)
+            return MICROBIT_I2C_ERROR;
+
+        // read MSB values...
+        sample.x = data[0];
+        sample.y = data[2];
+        sample.z = data[4];
+
+        // Normalize the data in the 0..1024 range.
+        sample.x *= 8;
+        sample.y *= 8;
+        sample.z *= 8;
+
+#if CONFIG_ENABLED(USE_ACCEL_LSB)
+        // Add in LSB values.
+        sample.x += (data[1] / 64);
+        sample.y += (data[3] / 64);
+        sample.z += (data[5] / 64);
+#endif
+
+        // Scale into millig (approx!)
+        sample.x *= this->sampleRange;
+        sample.y *= this->sampleRange;
+        sample.z *= this->sampleRange;
+
+        // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed.
+        status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID;
+
+        // Update gesture tracking
+        updateGesture();
+
+        // Indicate that a new sample is available
+        MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
+    }
+
+    return MICROBIT_OK;
+};
+
+/**
+  * A service function.
+  * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
+  * It does not, however, square root the result, as this is a relatively high cost operation.
+  *
+  * This is left to application code should it be needed.
+  *
+  * @return the sum of the square of the acceleration of the device across all axes.
+  */
+int MicroBitAccelerometer::instantaneousAccelerationSquared()
+{
+    updateSample();
+
+    // Use pythagoras theorem to determine the combined force acting on the device.
+    return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z;
+}
+
+/**
+ * Service function.
+ * Determines a 'best guess' posture of the device based on instantaneous data.
+ *
+ * This makes no use of historic data, and forms this input to the filter implemented in updateGesture().
+ *
+ * @return A 'best guess' of the current posture of the device, based on instanataneous data.
+ */
+BasicGesture MicroBitAccelerometer::instantaneousPosture()
+{
+    int force = instantaneousAccelerationSquared();
+    bool shakeDetected = false;
+
+    // Test for shake events.
+    // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to the left followed by
+    // a string acceleration to the right, then we can infer a shake. Similarly, we can do this for each acxis (left/right, up/down, in/out).
+    //
+    // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device
+    // has been shaken.
+    if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x))
+    {
+        shakeDetected = true;
+        shake.x = !shake.x;
+    }
+
+    if ((getY() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (getY() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y))
+    {
+        shakeDetected = true;
+        shake.y = !shake.y;
+    }
+
+    if ((getZ() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (getZ() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z))
+    {
+        shakeDetected = true;
+        shake.z = !shake.z;
+    }
+
+    if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD && ++shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
+        shake.shaken = 1;
+
+    if (++shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
+    {
+        shake.timer = 0;
+        if (shake.count > 0)
+        {
+            if(--shake.count == 0)
+                shake.shaken = 0;
+        }
+    }
+
+    if (shake.shaken)
+        return GESTURE_SHAKE;
+
+    if (force < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
+        return GESTURE_FREEFALL;
+
+    if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD)
+        return GESTURE_3G;
+
+    if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD)
+        return GESTURE_6G;
+
+    if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD)
+        return GESTURE_8G;
+
+    // Determine our posture.
+    if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
+        return GESTURE_LEFT;
+
+    if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
+        return GESTURE_RIGHT;
+
+    if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
+        return GESTURE_DOWN;
+
+    if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
+        return GESTURE_UP;
+
+    if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
+        return GESTURE_FACE_UP;
+
+    if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
+        return GESTURE_FACE_DOWN;
+
+    return GESTURE_NONE;
+}
+
+/**
+  * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
+  * stability.
+  */
+void MicroBitAccelerometer::updateGesture()
+{
+    // Determine what it looks like we're doing based on the latest sample...
+    BasicGesture g = instantaneousPosture();
+
+    // Perform some low pass filtering to reduce jitter from any detected effects
+    if (g == currentGesture)
+    {
+        if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
+            sigma++;
+    }
+    else
+    {
+        currentGesture = g;
+        sigma = 0;
+    }
+
+    // If we've reached threshold, update our record and raise the relevant event...
+    if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
+    {
+        lastGesture = currentGesture;
+        MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture);
+    }
+}
+
+/**
+  * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
+  *
+  * @param period the requested time between samples, in milliseconds.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
+  *
+  * @code
+  * // sample rate is now 20 ms.
+  * accelerometer.setPeriod(20);
+  * @endcode
+  *
+  * @note The requested rate may not be possible on the hardware. In this case, the
+  * nearest lower rate is chosen.
+  */
+int MicroBitAccelerometer::setPeriod(int period)
+{
+    this->samplePeriod = period;
+    return this->configure();
+}
+
+/**
+  * Reads the currently configured sample rate of the accelerometer.
+  *
+  * @return The time between samples, in milliseconds.
+  */
+int MicroBitAccelerometer::getPeriod()
+{
+    return (int)samplePeriod;
+}
+
+/**
+  * Attempts to set the sample range of the accelerometer to the specified value (in g).
+  *
+  * @param range The requested sample range of samples, in g.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
+  *
+  * @code
+  * // the sample range of the accelerometer is now 8G.
+  * accelerometer.setRange(8);
+  * @endcode
+  *
+  * @note The requested range may not be possible on the hardware. In this case, the
+  * nearest lower range is chosen.
+  */
+int MicroBitAccelerometer::setRange(int range)
+{
+    this->sampleRange = range;
+    return this->configure();
+}
+
+/**
+  * Reads the currently configured sample range of the accelerometer.
+  *
+  * @return The sample range, in g.
+  */
+int MicroBitAccelerometer::getRange()
+{
+    return (int)sampleRange;
+}
+
+/**
+  * Reads the value of the X axis from the latest update retrieved from the accelerometer.
+  *
+  * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+  *
+  * @return The force measured in the X axis, in milli-g.
+  *
+  * @code
+  * accelerometer.getX();
+  * @endcode
+  */
+int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system)
+{
+    updateSample();
+
+    switch (system)
+    {
+        case SIMPLE_CARTESIAN:
+            return -sample.x;
+
+        case NORTH_EAST_DOWN:
+            return sample.y;
+
+        case RAW:
+        default:
+            return sample.x;
+    }
+}
+
+/**
+  * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
+  *
+  * @return The force measured in the Y axis, in milli-g.
+  *
+  * @code
+  * accelerometer.getY();
+  * @endcode
+  */
+int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system)
+{
+    updateSample();
+
+    switch (system)
+    {
+        case SIMPLE_CARTESIAN:
+            return -sample.y;
+
+        case NORTH_EAST_DOWN:
+            return -sample.x;
+
+        case RAW:
+        default:
+            return sample.y;
+    }
+}
+
+/**
+  * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
+  *
+  * @return The force measured in the Z axis, in milli-g.
+  *
+  * @code
+  * accelerometer.getZ();
+  * @endcode
+  */
+int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system)
+{
+    updateSample();
+
+    switch (system)
+    {
+        case NORTH_EAST_DOWN:
+            return -sample.z;
+
+        case SIMPLE_CARTESIAN:
+        case RAW:
+        default:
+            return sample.z;
+    }
+}
+
+/**
+  * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
+  *
+  * @return The pitch of the device, in degrees.
+  *
+  * @code
+  * accelerometer.getPitch();
+  * @endcode
+  */
+int MicroBitAccelerometer::getPitch()
+{
+    return (int) ((360*getPitchRadians()) / (2*PI));
+}
+
+/**
+  * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
+  *
+  * @return The pitch of the device, in radians.
+  *
+  * @code
+  * accelerometer.getPitchRadians();
+  * @endcode
+  */
+float MicroBitAccelerometer::getPitchRadians()
+{
+    if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
+        recalculatePitchRoll();
+
+    return pitch;
+}
+
+/**
+  * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
+  *
+  * @return The roll of the device, in degrees.
+  *
+  * @code
+  * accelerometer.getRoll();
+  * @endcode
+  */
+int MicroBitAccelerometer::getRoll()
+{
+    return (int) ((360*getRollRadians()) / (2*PI));
+}
+
+/**
+  * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
+  *
+  * @return The roll of the device, in radians.
+  *
+  * @code
+  * accelerometer.getRollRadians();
+  * @endcode
+  */
+float MicroBitAccelerometer::getRollRadians()
+{
+    if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
+        recalculatePitchRoll();
+
+    return roll;
+}
+
+/**
+  * Recalculate roll and pitch values for the current sample.
+  *
+  * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
+  *       heavyweight for a CPU without a floating point unit.
+  */
+void MicroBitAccelerometer::recalculatePitchRoll()
+{
+    float x = (float) getX(NORTH_EAST_DOWN);
+    float y = (float) getY(NORTH_EAST_DOWN);
+    float z = (float) getZ(NORTH_EAST_DOWN);
+
+    roll = atan2(getY(NORTH_EAST_DOWN), getZ(NORTH_EAST_DOWN));
+    pitch = atan(-x / (y*sin(roll) + z*cos(roll)));
+    status |= MICROBIT_ACCEL_PITCH_ROLL_VALID;
+}
+
+/**
+  * Retrieves the last recorded gesture.
+  *
+  * @return The last gesture that was detected.
+  *
+  * Example:
+  * @code
+  * MicroBitDisplay display;
+  *
+  * if (accelerometer.getGesture() == SHAKE)
+  *     display.scroll("SHAKE!");
+  * @endcode
+  */
+BasicGesture MicroBitAccelerometer::getGesture()
+{
+    return lastGesture;
+}
+
+/**
+  * A periodic callback invoked by the fiber scheduler idle thread.
+  *
+  * Internally calls updateSample().
+  */
+void MicroBitAccelerometer::idleTick()
+{
+    updateSample();
+}
+
+/**
+  * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
+  *
+  * We check if any data is ready for reading by checking the interrupt flag on the accelerometer.
+  */
+int MicroBitAccelerometer::isIdleCallbackNeeded()
+{
+    return !int1;
+}
+
+/**
+  * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components.
+  */
+MicroBitAccelerometer::~MicroBitAccelerometer()
+{
+    fiber_remove_idle_component(this);
+}
+
+const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
+    {2, 0},
+    {4, 1},
+    {8, 2}
+};
+
+const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
+    {1250,      0x00},
+    {2500,      0x08},
+    {5000,      0x10},
+    {10000,     0x18},
+    {20000,     0x20},
+    {80000,     0x28},
+    {160000,    0x30},
+    {640000,    0x38}
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitButton.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,162 @@
+/*
+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 "MicroBitButton.h"
+#include "MicroBitSystemTimer.h"
+
+/**
+  * Constructor.
+  *
+  * Create a software representation of a button.
+  *
+  * @param name the physical pin on the processor that should be used as input.
+  *
+  * @param id the ID of the new MicroBitButton object.
+  *
+  * @param eventConfiguration Configures the events that will be generated by this MicroBitButton instance.
+  *                           Defaults to MICROBIT_BUTTON_ALL_EVENTS.
+  *
+  * @param mode the configuration of internal pullups/pulldowns, as defined in the mbed PinMode class. PullNone by default.
+  *
+  * @code
+  * buttonA(MICROBIT_PIN_BUTTON_A, MICROBIT_ID_BUTTON_A);
+  * @endcode
+  */
+MicroBitButton::MicroBitButton(PinName name, uint16_t id, MicroBitButtonEventConfiguration eventConfiguration, PinMode mode) : pin(name, mode)
+{
+    this->id = id;
+    this->name = name;
+    this->eventConfiguration = eventConfiguration;
+    this->downStartTime = 0;
+    this->sigma = 0;
+    system_timer_add_component(this);
+}
+
+/**
+  * Changes the event configuration used by this button to the given MicroBitButtonEventConfiguration.
+  *
+  * All subsequent events generated by this button will then be informed by this configuraiton.
+  *
+  * @param config The new configuration for this button. Legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS.
+  *
+  * Example:
+  * @code
+  * // Configure a button to generate all possible events.
+  * buttonA.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS);
+  *
+  * // Configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events.
+  * buttonA.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS);
+  * @endcode
+  */
+void MicroBitButton::setEventConfiguration(MicroBitButtonEventConfiguration config)
+{
+    this->eventConfiguration = config;
+}
+
+/**
+  * periodic callback from MicroBit system timer.
+  *
+  * Check for state change for this button, and fires various events on a state change.
+  */
+void MicroBitButton::systemTick()
+{
+    //
+    // If the pin is pulled low (touched), increment our culumative counter.
+    // otherwise, decrement it. We're essentially building a lazy follower here.
+    // This makes the output debounced for buttons, and desensitizes touch sensors
+    // (particularly in environments where there is mains noise!)
+    //
+    if(!pin)
+    {
+        if (sigma < MICROBIT_BUTTON_SIGMA_MAX)
+            sigma++;
+    }
+    else
+    {
+        if (sigma > MICROBIT_BUTTON_SIGMA_MIN)
+            sigma--;
+    }
+
+    // Check to see if we have off->on state change.
+    if(sigma > MICROBIT_BUTTON_SIGMA_THRESH_HI && !(status & MICROBIT_BUTTON_STATE))
+    {
+        // Record we have a state change, and raise an event.
+        status |= MICROBIT_BUTTON_STATE;
+        MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN);
+
+        //Record the time the button was pressed.
+        downStartTime = system_timer_current_time();
+    }
+
+    // Check to see if we have on->off state change.
+    if(sigma < MICROBIT_BUTTON_SIGMA_THRESH_LO && (status & MICROBIT_BUTTON_STATE))
+    {
+        status = 0;
+        MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_UP);
+
+       if (eventConfiguration == MICROBIT_BUTTON_ALL_EVENTS)
+       {
+           //determine if this is a long click or a normal click and send event
+           if((system_timer_current_time() - downStartTime) >= MICROBIT_BUTTON_LONG_CLICK_TIME)
+               MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_LONG_CLICK);
+           else
+               MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK);
+       }
+    }
+
+    //if button is pressed and the hold triggered event state is not triggered AND we are greater than the button debounce value
+    if((status & MICROBIT_BUTTON_STATE) && !(status & MICROBIT_BUTTON_STATE_HOLD_TRIGGERED) && (system_timer_current_time() - downStartTime) >= MICROBIT_BUTTON_HOLD_TIME)
+    {
+        //set the hold triggered event flag
+        status |= MICROBIT_BUTTON_STATE_HOLD_TRIGGERED;
+
+        //fire hold event
+        MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_HOLD);
+    }
+}
+
+/**
+  * Tests if this Button is currently pressed.
+  *
+  * @code
+  * if(buttonA.isPressed())
+  *     display.scroll("Pressed!");
+  * @endcode
+  *
+  * @return 1 if this button is pressed, 0 otherwise.
+  */
+int MicroBitButton::isPressed()
+{
+    return status & MICROBIT_BUTTON_STATE ? 1 : 0;
+}
+
+/**
+  * Destructor for MicroBitButton, where we deregister this instance from the array of fiber components.
+  */
+MicroBitButton::~MicroBitButton()
+{
+    system_timer_remove_component(this);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitCompass.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,778 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for MicroBit Compass.
+  *
+  * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer.
+  * Also includes basic caching, calibration and on demand activation.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitCompass.h"
+#include "MicroBitFiber.h"
+#include "ErrorNo.h"
+
+/**
+  * An initialisation member function used by the many constructors of MicroBitCompass.
+  *
+  * @param id the unique identifier for this compass instance.
+  *
+  * @param address the base address of the magnetometer on the i2c bus.
+  */
+void MicroBitCompass::init(uint16_t id, uint16_t address)
+{
+    this->id = id;
+    this->address = address;
+
+    // Select 10Hz update rate, with oversampling, and enable the device.
+    this->samplePeriod = 100;
+    this->configure();
+
+    // Assume that we have no calibration information.
+    status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
+
+    if(this->storage != NULL)
+    {
+        KeyValuePair *calibrationData =  storage->get(ManagedString("compassCal"));
+
+        if(calibrationData != NULL)
+        {
+            CompassSample storedSample = CompassSample();
+
+            memcpy(&storedSample, calibrationData->value, sizeof(CompassSample));
+
+            setCalibration(storedSample);
+
+            delete calibrationData;
+        }
+    }
+
+    // Indicate that we're up and running.
+    status |= MICROBIT_COMPONENT_RUNNING;
+}
+
+/**
+  * Constructor.
+  * Create a software representation of an e-compass.
+  *
+  * @param _i2c an instance of i2c, which the compass is accessible from.
+  *
+  * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
+  *
+  * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
+  *
+  * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * MicroBitAccelerometer accelerometer(i2c);
+  *
+  * MicroBitStorage storage;
+  *
+  * MicroBitCompass compass(i2c, accelerometer, storage);
+  * @endcode
+  */
+MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, MicroBitStorage& _storage, uint16_t address,  uint16_t id) :
+    average(),
+    sample(),
+    int1(MICROBIT_PIN_COMPASS_DATA_READY),
+    i2c(_i2c),
+    accelerometer(&_accelerometer),
+    storage(&_storage)
+{
+    init(id, address);
+}
+
+/**
+  * Constructor.
+  * Create a software representation of an e-compass.
+  *
+  * @param _i2c an instance of i2c, which the compass is accessible from.
+  *
+  * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
+  *
+  * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * MicroBitAccelerometer accelerometer(i2c);
+  *
+  * MicroBitCompass compass(i2c, accelerometer, storage);
+  * @endcode
+  */
+MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, uint16_t address, uint16_t id) :
+    average(),
+    sample(),
+    int1(MICROBIT_PIN_COMPASS_DATA_READY),
+    i2c(_i2c),
+    accelerometer(&_accelerometer),
+    storage(NULL)
+{
+    init(id, address);
+}
+
+/**
+  * Constructor.
+  * Create a software representation of an e-compass.
+  *
+  * @param _i2c an instance of i2c, which the compass is accessible from.
+  *
+  * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
+  *
+  * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * MicroBitStorage storage;
+  *
+  * MicroBitCompass compass(i2c, storage);
+  * @endcode
+  */
+MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, MicroBitStorage& _storage, uint16_t address, uint16_t id) :
+    average(),
+    sample(),
+    int1(MICROBIT_PIN_COMPASS_DATA_READY),
+    i2c(_i2c),
+    accelerometer(NULL),
+    storage(&_storage)
+{
+    init(id, address);
+}
+
+/**
+  * Constructor.
+  * Create a software representation of an e-compass.
+  *
+  * @param _i2c an instance of i2c, which the compass is accessible from.
+  *
+  * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  *
+  * MicroBitCompass compass(i2c);
+  * @endcode
+  */
+MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, uint16_t address, uint16_t id) :
+    average(),
+    sample(),
+    int1(MICROBIT_PIN_COMPASS_DATA_READY),
+    i2c(_i2c),
+    accelerometer(NULL),
+    storage(NULL)
+{
+    init(id, address);
+}
+
+/**
+  * Issues a standard, 2 byte I2C command write to the accelerometer.
+  *
+  * Blocks the calling thread until complete.
+  *
+  * @param reg The address of the register to write to.
+  *
+  * @param value The value to write.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
+  */
+int MicroBitCompass::writeCommand(uint8_t reg, uint8_t value)
+{
+    uint8_t command[2];
+    command[0] = reg;
+    command[1] = value;
+
+    return i2c.write(address, (const char *)command, 2);
+}
+
+/**
+  * Issues a read command, copying data into the specified buffer.
+  *
+  * Blocks the calling thread until complete.
+  *
+  * @param reg The address of the register to access.
+  *
+  * @param buffer Memory area to read the data into.
+  *
+  * @param length The number of bytes to read.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
+  */
+int MicroBitCompass::readCommand(uint8_t reg, uint8_t* buffer, int length)
+{
+    int result;
+
+    if (buffer == NULL || length <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    result = i2c.write(address, (const char *)&reg, 1, true);
+    if (result !=0)
+        return MICROBIT_I2C_ERROR;
+
+    result = i2c.read(address, (char *)buffer, length);
+    if (result !=0)
+        return MICROBIT_I2C_ERROR;
+
+    return MICROBIT_OK;
+}
+
+
+/**
+  * Issues a read of a given address, and returns the value.
+  *
+  * Blocks the calling thread until complete.
+  *
+  * @param reg The address of the 16 bit register to access.
+  *
+  * @return The register value, interpreted as a 16 but signed value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
+  */
+int MicroBitCompass::read16(uint8_t reg)
+{
+    uint8_t cmd[2];
+    int result;
+
+    cmd[0] = reg;
+    result = i2c.write(address, (const char *)cmd, 1);
+    if (result !=0)
+        return MICROBIT_I2C_ERROR;
+
+    cmd[0] = 0x00;
+    cmd[1] = 0x00;
+
+    result = i2c.read(address, (char *)cmd, 2);
+    if (result !=0)
+        return MICROBIT_I2C_ERROR;
+
+    return (int16_t) ((cmd[1] | (cmd[0] << 8))); //concatenate the MSB and LSB
+}
+
+/**
+  * Issues a read of a given address, and returns the value.
+  *
+  * Blocks the calling thread until complete.
+  *
+  * @param reg The address of the 16 bit register to access.
+  *
+  * @return The register value, interpreted as a 8 bit unsigned value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
+  */
+int MicroBitCompass::read8(uint8_t reg)
+{
+    uint8_t data;
+    int result;
+
+    data = 0;
+    result = readCommand(reg, (uint8_t*) &data, 1);
+    if (result != MICROBIT_OK)
+        return MICROBIT_I2C_ERROR;
+
+    return data;
+}
+
+/**
+  * Calculates a tilt compensated bearing of the device, using the accelerometer.
+  */
+int MicroBitCompass::tiltCompensatedBearing()
+{
+    // Precompute the tilt compensation parameters to improve readability.
+    float phi = accelerometer->getRollRadians();
+    float theta = accelerometer->getPitchRadians();
+
+    float x = (float) getX(NORTH_EAST_DOWN);
+    float y = (float) getY(NORTH_EAST_DOWN);
+    float z = (float) getZ(NORTH_EAST_DOWN);
+
+    // Precompute cos and sin of pitch and roll angles to make the calculation a little more efficient.
+    float sinPhi = sin(phi);
+    float cosPhi = cos(phi);
+    float sinTheta = sin(theta);
+    float cosTheta = cos(theta);
+
+    float bearing = (360*atan2(z*sinPhi - y*cosPhi, x*cosTheta + y*sinTheta*sinPhi + z*sinTheta*cosPhi)) / (2*PI);
+
+    if (bearing < 0)
+        bearing += 360.0;
+
+    return (int) bearing;
+}
+
+/**
+  * Calculates a non-tilt compensated bearing of the device.
+  */
+int MicroBitCompass::basicBearing()
+{
+    updateSample();
+
+    float bearing = (atan2((double)(sample.y - average.y),(double)(sample.x - average.x)))*180/PI;
+
+    if (bearing < 0)
+        bearing += 360.0;
+
+    return (int)(360.0 - bearing);
+}
+
+/**
+  * Gets the current heading of the device, relative to magnetic north.
+  *
+  * If the compass is not calibrated, it will raise the MICROBIT_COMPASS_EVT_CALIBRATE event.
+  *
+  * Users wishing to implement their own calibration algorithms should listen for this event,
+  * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before
+  * the user program continues.
+  *
+  * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating.
+  *
+  * @code
+  * compass.heading();
+  * @endcode
+  */
+int MicroBitCompass::heading()
+{
+    if(status & MICROBIT_COMPASS_STATUS_CALIBRATING)
+        return MICROBIT_CALIBRATION_IN_PROGRESS;
+
+    if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
+        calibrate();
+
+    if(accelerometer != NULL)
+        return tiltCompensatedBearing();
+
+    return basicBearing();
+}
+
+/**
+  * Updates the local sample, only if the compass indicates that
+  * data is stale.
+  *
+  * @note Can be used to trigger manual updates, if the device is running without a scheduler.
+  *       Also called internally by all get[X,Y,Z]() member functions.
+  */
+int MicroBitCompass::updateSample()
+{
+    /**
+      * Adds the compass to idle, if it hasn't been added already.
+      * This is an optimisation so that the compass is only added on first 'use'.
+      */
+    if(!(status & MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE))
+    {
+        fiber_add_idle_component(this);
+        status |= MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE;
+    }
+
+    // Poll interrupt line from compass (Active HI).
+    // Interrupt is cleared on data read of MAG_OUT_X_MSB.
+    if(int1)
+    {
+        sample.x = MAG3110_NORMALIZE_SAMPLE((int) read16(MAG_OUT_X_MSB));
+        sample.y = MAG3110_NORMALIZE_SAMPLE((int) read16(MAG_OUT_Y_MSB));
+        sample.z = MAG3110_NORMALIZE_SAMPLE((int) read16(MAG_OUT_Z_MSB));
+
+        // Indicate that a new sample is available
+        MicroBitEvent e(id, MICROBIT_COMPASS_EVT_DATA_UPDATE);
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Periodic callback from MicroBit idle thread.
+  *
+  * Calls updateSample().
+  */
+void MicroBitCompass::idleTick()
+{
+    updateSample();
+}
+
+/**
+  * Reads the value of the X axis from the latest update retrieved from the magnetometer.
+  *
+  * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+  *
+  * @return The magnetic force measured in the X axis, in nano teslas.
+  *
+  * @code
+  * compass.getX();
+  * @endcode
+  */
+int MicroBitCompass::getX(MicroBitCoordinateSystem system)
+{
+    updateSample();
+
+    switch (system)
+    {
+        case SIMPLE_CARTESIAN:
+            return sample.x - average.x;
+
+        case NORTH_EAST_DOWN:
+            return -(sample.y - average.y);
+
+        case RAW:
+        default:
+            return sample.x;
+    }
+}
+
+/**
+  * Reads the value of the Y axis from the latest update retrieved from the magnetometer.
+  *
+  * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+  *
+  * @return The magnetic force measured in the Y axis, in nano teslas.
+  *
+  * @code
+  * compass.getY();
+  * @endcode
+  */
+int MicroBitCompass::getY(MicroBitCoordinateSystem system)
+{
+    updateSample();
+
+    switch (system)
+    {
+        case SIMPLE_CARTESIAN:
+            return -(sample.y - average.y);
+
+        case NORTH_EAST_DOWN:
+            return (sample.x - average.x);
+
+        case RAW:
+        default:
+            return sample.y;
+    }
+}
+
+/**
+  * Reads the value of the Z axis from the latest update retrieved from the magnetometer.
+  *
+  * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+  *
+  * @return The magnetic force measured in the Z axis, in nano teslas.
+  *
+  * @code
+  * compass.getZ();
+  * @endcode
+  */
+int MicroBitCompass::getZ(MicroBitCoordinateSystem system)
+{
+    updateSample();
+
+    switch (system)
+    {
+        case SIMPLE_CARTESIAN:
+        case NORTH_EAST_DOWN:
+            return -(sample.z - average.z);
+
+        case RAW:
+        default:
+            return sample.z;
+    }
+}
+
+/**
+  * Determines the overall magnetic field strength based on the latest update from the magnetometer.
+  *
+  * @return The magnetic force measured across all axis, in nano teslas.
+  *
+  * @code
+  * compass.getFieldStrength();
+  * @endcode
+  */
+int MicroBitCompass::getFieldStrength()
+{
+    double x = getX();
+    double y = getY();
+    double z = getZ();
+
+    return (int) sqrt(x*x + y*y + z*z);
+}
+
+/**
+  * Configures the compass for the sample rate defined in this object.
+  * The nearest values are chosen to those defined that are supported by the hardware.
+  * The instance variables are then updated to reflect reality.
+  *
+  * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be configured.
+  */
+int MicroBitCompass::configure()
+{
+    const MAG3110SampleRateConfig  *actualSampleRate;
+    int result;
+
+    // First, take the device offline, so it can be configured.
+    result = writeCommand(MAG_CTRL_REG1, 0x00);
+    if (result != MICROBIT_OK)
+        return MICROBIT_I2C_ERROR;
+
+    // Wait for the part to enter standby mode...
+    while(1)
+    {
+        // Read the status of the part...
+        // If we can't communicate with it over I2C, pass on the error.
+        result = this->read8(MAG_SYSMOD);
+        if (result == MICROBIT_I2C_ERROR)
+            return MICROBIT_I2C_ERROR;
+
+        // if the part in in standby, we're good to carry on.
+        if((result & 0x03) == 0)
+            break;
+
+        // Perform a power efficient sleep...
+		fiber_sleep(100);
+    }
+
+    // Find the nearest sample rate to that specified.
+    actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES-1];
+    for (int i=MAG3110_SAMPLE_RATES-1; i>=0; i--)
+    {
+        if(MAG3110SampleRate[i].sample_period < this->samplePeriod * 1000)
+            break;
+
+        actualSampleRate = &MAG3110SampleRate[i];
+    }
+
+    // OK, we have the correct data. Update our local state.
+    this->samplePeriod = actualSampleRate->sample_period / 1000;
+
+    // Enable automatic reset after each sample;
+    result = writeCommand(MAG_CTRL_REG2, 0xA0);
+    if (result != MICROBIT_OK)
+        return MICROBIT_I2C_ERROR;
+
+
+    // Bring the device online, with the requested sample frequency.
+    result = writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
+    if (result != MICROBIT_OK)
+        return MICROBIT_I2C_ERROR;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Attempts to set the sample rate of the compass to the specified value (in ms).
+  *
+  * @param period the requested time between samples, in milliseconds.
+  *
+  * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
+  *
+  * @code
+  * // sample rate is now 20 ms.
+  * compass.setPeriod(20);
+  * @endcode
+  *
+  * @note The requested rate may not be possible on the hardware. In this case, the
+  * nearest lower rate is chosen.
+  */
+int MicroBitCompass::setPeriod(int period)
+{
+    this->samplePeriod = period;
+    return this->configure();
+}
+
+/**
+  * Reads the currently configured sample rate of the compass.
+  *
+  * @return The time between samples, in milliseconds.
+  */
+int MicroBitCompass::getPeriod()
+{
+    return (int)samplePeriod;
+}
+
+/**
+  * Attempts to read the 8 bit ID from the magnetometer, this can be used for
+  * validation purposes.
+  *
+  * @return the 8 bit ID returned by the magnetometer, or MICROBIT_I2C_ERROR if the request fails.
+  *
+  * @code
+  * compass.whoAmI();
+  * @endcode
+  */
+int MicroBitCompass::whoAmI()
+{
+    uint8_t data;
+    int result;
+
+    result = readCommand(MAG_WHOAMI, &data, 1);
+    if (result != MICROBIT_OK)
+        return MICROBIT_I2C_ERROR;
+
+    return (int)data;
+}
+
+/**
+  * Reads the current die temperature of the compass.
+  *
+  * @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the temperature reading could not be retreived
+  *         from the accelerometer.
+  */
+int MicroBitCompass::readTemperature()
+{
+    int8_t temperature;
+    int result;
+
+    result = readCommand(MAG_DIE_TEMP, (uint8_t *)&temperature, 1);
+    if (result != MICROBIT_OK)
+        return MICROBIT_I2C_ERROR;
+
+    return temperature;
+}
+
+/**
+  * Perform a calibration of the compass.
+  *
+  * This method will be called automatically if a user attempts to read a compass value when
+  * the compass is uncalibrated. It can also be called at any time by the user.
+  *
+  * The method will only return once the compass has been calibrated.
+  *
+  * @return MICROBIT_OK, MICROBIT_I2C_ERROR if the magnetometer could not be accessed,
+  * or MICROBIT_CALIBRATION_REQUIRED if the calibration algorithm failed to complete successfully.
+  *
+  * @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
+  */
+int MicroBitCompass::calibrate()
+{
+    // Only perform one calibration process at a time.
+    if(isCalibrating())
+        return MICROBIT_CALIBRATION_IN_PROGRESS;
+
+    updateSample();
+
+    // Delete old calibration data
+    clearCalibration();
+
+    // Record that we've started calibrating.
+    status |= MICROBIT_COMPASS_STATUS_CALIBRATING;
+
+    // Launch any registred calibration alogrithm visialisation
+    MicroBitEvent(id, MICROBIT_COMPASS_EVT_CALIBRATE);
+
+    // Record that we've finished calibrating.
+    status &= ~MICROBIT_COMPASS_STATUS_CALIBRATING;
+
+    // If there are no changes to our sample data, we either have no calibration algorithm, or it couldn't complete succesfully.
+    if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
+        return MICROBIT_CALIBRATION_REQUIRED;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configure the compass to use the calibration data that is supplied to this call.
+  *
+  * Calibration data is comprised of the perceived zero offset of each axis of the compass.
+  *
+  * After calibration this should now take into account trimming errors in the magnetometer,
+  * and any "hard iron" offsets on the device.
+  *
+  * @param calibration A CompassSample containing the offsets for the x, y and z axis.
+  */
+void MicroBitCompass::setCalibration(CompassSample calibration)
+{
+    if(this->storage != NULL)
+        this->storage->put(ManagedString("compassCal"), (uint8_t *)&calibration);
+
+    average = calibration;
+    status |= MICROBIT_COMPASS_STATUS_CALIBRATED;
+}
+
+/**
+  * Provides the calibration data currently in use by the compass.
+  *
+  * More specifically, the x, y and z zero offsets of the compass.
+  *
+  * @return calibration A CompassSample containing the offsets for the x, y and z axis.
+  */
+CompassSample MicroBitCompass::getCalibration()
+{
+    return average;
+}
+
+/**
+  * Returns 0 or 1. 1 indicates that the compass is calibrated, zero means the compass requires calibration.
+  */
+int MicroBitCompass::isCalibrated()
+{
+    return status & MICROBIT_COMPASS_STATUS_CALIBRATED;
+}
+
+/**
+  * Returns 0 or 1. 1 indicates that the compass is calibrating, zero means the compass is not currently calibrating.
+  */
+int MicroBitCompass::isCalibrating()
+{
+    return status & MICROBIT_COMPASS_STATUS_CALIBRATING;
+}
+
+/**
+  * Clears the calibration held in persistent storage, and sets the calibrated flag to zero.
+  */
+void MicroBitCompass::clearCalibration()
+{
+    status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
+}
+
+/**
+  * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
+  */
+int MicroBitCompass::isIdleCallbackNeeded()
+{
+    // The MAG3110 raises an interrupt line when data is ready, which we sample here.
+    // The interrupt line is active HI, so simply return the state of the pin.
+    return int1;
+}
+
+/**
+  * Destructor for MicroBitCompass, where we deregister this instance from the array of fiber components.
+  */
+MicroBitCompass::~MicroBitCompass()
+{
+    fiber_remove_idle_component(this);
+}
+
+const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = {
+    {12500,      0x00},        // 80 Hz
+    {25000,      0x20},        // 40 Hz
+    {50000,      0x40},        // 20 Hz
+    {100000,     0x60},        // 10 hz
+    {200000,     0x80},        // 5 hz
+    {400000,     0x88},        // 2.5 hz
+    {800000,     0x90},        // 1.25 hz
+    {1600000,    0xb0},        // 0.63 hz
+    {3200000,    0xd0},        // 0.31 hz
+    {6400000,    0xf0},        // 0.16 hz
+    {12800000,   0xf8}         // 0.08 hz
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitCompassCalibrator.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,188 @@
+/*
+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 "MicroBitCompassCalibrator.h"
+#include "EventModel.h"
+#include "Matrix4.h"
+
+/**
+  * Constructor.
+  *
+  * Create an object capable of calibrating the compass.
+  *
+  * The algorithm uses an accelerometer to ensure that a broad range of sample data has been gathered
+  * from the compass module, then performs a least mean squares optimisation of the
+  * results to determine the calibration data for the compass.
+  *
+  * The LED matrix display is used to provide feedback to the user on the gestures required.
+  *
+  * @param compass The compass instance to calibrate.
+  *
+  * @param accelerometer The accelerometer to gather contextual data from.
+  *
+  * @param display The LED matrix to display user feedback on.
+  */
+MicroBitCompassCalibrator::MicroBitCompassCalibrator(MicroBitCompass& _compass, MicroBitAccelerometer& _accelerometer, MicroBitDisplay& _display) : compass(_compass), accelerometer(_accelerometer), display(_display)
+{
+    if (EventModel::defaultEventBus)
+        EventModel::defaultEventBus->listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CALIBRATE, this, &MicroBitCompassCalibrator::calibrate, MESSAGE_BUS_LISTENER_IMMEDIATE);
+}
+
+/**
+  * Performs a simple game that in parallel, calibrates the compass.
+  *
+  * This function is executed automatically when the user requests a compass bearing, and compass calibration is required.
+  *
+  * This function is, by design, synchronous and only returns once calibration is complete.
+  */
+void MicroBitCompassCalibrator::calibrate(MicroBitEvent)
+{
+    struct Point
+    {
+        uint8_t x;
+        uint8_t y;
+        uint8_t on;
+    };
+
+    const int PERIMETER_POINTS = 12;
+    const int PIXEL1_THRESHOLD = 200;
+    const int PIXEL2_THRESHOLD = 800;
+
+    wait_ms(100);
+
+	Matrix4 X(PERIMETER_POINTS, 4);
+    Point perimeter[PERIMETER_POINTS] = {{1,0,0}, {2,0,0}, {3,0,0}, {4,1,0}, {4,2,0}, {4,3,0}, {3,4,0}, {2,4,0}, {1,4,0}, {0,3,0}, {0,2,0}, {0,1,0}};
+    Point cursor = {2,2,0};
+
+    MicroBitImage img(5,5);
+    MicroBitImage smiley("0,255,0,255,0\n0,255,0,255,0\n0,0,0,0,0\n255,0,0,0,255\n0,255,255,255,0\n");
+    int samples = 0;
+
+    // Firstly, we need to take over the display. Ensure all active animations are paused.
+    display.stopAnimation();
+    display.scrollAsync("DRAW A CIRCLE");
+
+    for (int i=0; i<110; i++)
+        wait_ms(100);
+
+    display.stopAnimation();
+    display.clear();
+
+    while(samples < PERIMETER_POINTS)
+    {
+        // update our model of the flash status of the user controlled pixel.
+        cursor.on = (cursor.on + 1) % 4;
+
+        // take a snapshot of the current accelerometer data.
+        int x = accelerometer.getX();
+        int y = accelerometer.getY();
+
+        // Wait a little whie for the button state to stabilise (one scheduler tick).
+        wait_ms(10);
+
+        // Deterine the position of the user controlled pixel on the screen.
+        if (x < -PIXEL2_THRESHOLD)
+            cursor.x = 0;
+        else if (x < -PIXEL1_THRESHOLD)
+            cursor.x = 1;
+        else if (x > PIXEL2_THRESHOLD)
+            cursor.x = 4;
+        else if (x > PIXEL1_THRESHOLD)
+            cursor.x = 3;
+        else
+            cursor.x = 2;
+
+        if (y < -PIXEL2_THRESHOLD)
+            cursor.y = 0;
+        else if (y < -PIXEL1_THRESHOLD)
+            cursor.y = 1;
+        else if (y > PIXEL2_THRESHOLD)
+            cursor.y = 4;
+        else if (y > PIXEL1_THRESHOLD)
+            cursor.y = 3;
+        else
+            cursor.y = 2;
+
+        img.clear();
+
+        // Turn on any pixels that have been visited.
+        for (int i=0; i<PERIMETER_POINTS; i++)
+            if (perimeter[i].on)
+                img.setPixelValue(perimeter[i].x, perimeter[i].y, 255);
+
+        // Update the pixel at the users position.
+        img.setPixelValue(cursor.x, cursor.y, 255);
+
+        // Update the buffer to the screen.
+        display.image.paste(img,0,0,0);
+
+        // test if we need to update the state at the users position.
+        for (int i=0; i<PERIMETER_POINTS; i++)
+        {
+            if (cursor.x == perimeter[i].x && cursor.y == perimeter[i].y && !perimeter[i].on)
+            {
+                // Record the sample data for later processing...
+                X.set(samples, 0, compass.getX(RAW));
+                X.set(samples, 1, compass.getY(RAW));
+                X.set(samples, 2, compass.getZ(RAW));
+                X.set(samples, 3, 1);
+
+                // Record that this pixel has been visited.
+                perimeter[i].on = 1;
+                samples++;
+            }
+        }
+
+        wait_ms(100);
+    }
+
+    // We have enough sample data to make a fairly accurate calibration.
+    // We use a Least Mean Squares approximation, as detailed in Freescale application note AN2426.
+
+    // Firstly, calculate the square of each sample.
+	Matrix4 Y(X.height(), 1);
+	for (int i = 0; i < X.height(); i++)
+	{
+		float v = X.get(i, 0)*X.get(i, 0) + X.get(i, 1)*X.get(i, 1) + X.get(i, 2)*X.get(i, 2);
+		Y.set(i, 0, v);
+	}
+
+    // Now perform a Least Squares Approximation.
+	Matrix4 Alpha = X.multiplyT(X).invert();
+	Matrix4 Gamma = X.multiplyT(Y);
+	Matrix4 Beta = Alpha.multiply(Gamma);
+
+    // The result contains the approximate zero point of each axis, but doubled.
+    // Halve each sample, and record this as the compass calibration data.
+    CompassSample cal ((int)(Beta.get(0,0) / 2), (int)(Beta.get(1,0) / 2), (int)(Beta.get(2,0) / 2));
+    compass.setCalibration(cal);
+
+    // Show a smiley to indicate that we're done, and continue on with the user program.
+    display.clear();
+    display.printAsync(smiley, 0, 0, 0, 1500);
+    wait_ms(1000);
+    display.clear();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitDisplay.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,1218 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for MicroBitDisplay.
+  *
+  * A MicroBitDisplay represents the LED matrix array on the micro:bit.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitDisplay.h"
+#include "MicroBitSystemTimer.h"
+#include "MicroBitFiber.h"
+#include "ErrorNo.h"
+#include "NotifyEvents.h"
+
+const int greyScaleTimings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {1, 23, 70, 163, 351, 726, 1476, 2976};
+
+/**
+  * Constructor.
+  *
+  * Create a software representation the micro:bit's 5x5 LED matrix.
+  * The display is initially blank.
+  *
+  * @param id The id the display should use when sending events on the MessageBus. Defaults to MICROBIT_ID_DISPLAY.
+  *
+  * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates.
+  *            Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * @endcode
+  */
+MicroBitDisplay::MicroBitDisplay(uint16_t id, const MatrixMap &map) :
+    matrixMap(map),
+    image(map.width*2,map.height)
+{
+    uint32_t row_mask;
+
+    this->id = id;
+    this->width = map.width;
+    this->height = map.height;
+    this->rotation = MICROBIT_DISPLAY_ROTATION_0;
+
+    row_mask = 0;
+    col_mask = 0;
+    strobeRow = 0;
+    row_mask = 0;
+
+    for (int i = matrixMap.rowStart; i < matrixMap.rowStart + matrixMap.rows; i++)
+        row_mask |= 0x01 << i;
+
+    for (int i = matrixMap.columnStart; i < matrixMap.columnStart + matrixMap.columns; i++)
+        col_mask |= 0x01 << i;
+
+    LEDMatrix = new PortOut(Port0, row_mask | col_mask);
+
+    this->greyscaleBitMsk = 0x01;
+    this->timingCount = 0;
+    this->setBrightness(MICROBIT_DISPLAY_DEFAULT_BRIGHTNESS);
+    this->mode = DISPLAY_MODE_BLACK_AND_WHITE;
+    this->animationMode = ANIMATION_MODE_NONE;
+    this->lightSensor = NULL;
+
+	system_timer_add_component(this);
+
+    status |= MICROBIT_COMPONENT_RUNNING;
+}
+
+/**
+  * Internal frame update method, used to strobe the display.
+  *
+  * TODO: Write a more efficient, complementary variation of this method for the case where
+  * MICROBIT_DISPLAY_ROW_COUNT > MICROBIT_DISPLAY_COLUMN_COUNT.
+  */
+void MicroBitDisplay::systemTick()
+{
+    if(!(status & MICROBIT_COMPONENT_RUNNING))
+        return;
+
+    if(mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
+    {
+        renderWithLightSense();
+        return;
+    }
+
+    // Move on to the next row.
+    strobeRow++;
+
+    //reset the row counts and bit mask when we have hit the max.
+    if(strobeRow == matrixMap.rows)
+        strobeRow = 0;
+
+    if(mode == DISPLAY_MODE_BLACK_AND_WHITE)
+        render();
+
+    if(mode == DISPLAY_MODE_GREYSCALE)
+    {
+        greyscaleBitMsk = 0x01;
+        timingCount = 0;
+        renderGreyscale();
+    }
+
+    // Update text and image animations if we need to.
+    this->animationUpdate();
+}
+
+void MicroBitDisplay::renderFinish()
+{
+    *LEDMatrix = 0;
+}
+
+void MicroBitDisplay::render()
+{
+    // Simple optimisation.
+    // If display is at zero brightness, there's nothing to do.
+    if(brightness == 0)
+        return;
+
+    // Calculate the bitpattern to write.
+    uint32_t row_data = 0x01 << (microbitMatrixMap.rowStart + strobeRow);
+    uint32_t col_data = 0;
+
+    for (int i = 0; i < matrixMap.columns; i++)
+    {
+        int index = (i * matrixMap.rows) + strobeRow;
+
+        int x = matrixMap.map[index].x;
+        int y = matrixMap.map[index].y;
+        int t = x;
+
+        if(rotation == MICROBIT_DISPLAY_ROTATION_90)
+        {
+                x = width - 1 - y;
+                y = t;
+        }
+
+        if(rotation == MICROBIT_DISPLAY_ROTATION_180)
+        {
+                x = width - 1 - x;
+                y = height - 1 - y;
+        }
+
+        if(rotation == MICROBIT_DISPLAY_ROTATION_270)
+        {
+                x = y;
+                y = height - 1 - t;
+        }
+
+        if(image.getBitmap()[y*(width*2)+x])
+            col_data |= (1 << i);
+    }
+
+    // Invert column bits (as we're sinking not sourcing power), and mask off any unused bits.
+    col_data = ~col_data << matrixMap.columnStart & col_mask;
+
+    // Write the new bit pattern
+    *LEDMatrix = col_data | row_data;
+
+    //timer does not have enough resolution for brightness of 1. 23.53 us
+    if(brightness != MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS && brightness > MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS)
+        renderTimer.attach_us(this, &MicroBitDisplay::renderFinish, (((brightness * 950) / (MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS)) * system_timer_get_period()));
+
+    //this will take around 23us to execute
+    if(brightness <= MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS)
+        renderFinish();
+}
+
+void MicroBitDisplay::renderWithLightSense()
+{
+    //reset the row counts and bit mask when we have hit the max.
+    if(strobeRow == matrixMap.rows + 1)
+    {
+        MicroBitEvent(id, MICROBIT_DISPLAY_EVT_LIGHT_SENSE);
+        strobeRow = 0;
+    }
+    else
+    {
+        render();
+        this->animationUpdate();
+
+        // Move on to the next row.
+        strobeRow++;
+    }
+
+}
+
+void MicroBitDisplay::renderGreyscale()
+{
+    uint32_t row_data = 0x01 << (microbitMatrixMap.rowStart + strobeRow);
+    uint32_t col_data = 0;
+
+    // Calculate the bitpattern to write.
+    for (int i = 0; i < matrixMap.columns; i++)
+    {
+        int index = (i * matrixMap.rows) + strobeRow;
+
+        int x = matrixMap.map[index].x;
+        int y = matrixMap.map[index].y;
+        int t = x;
+
+        if(rotation == MICROBIT_DISPLAY_ROTATION_90)
+        {
+                x = width - 1 - y;
+                y = t;
+        }
+
+        if(rotation == MICROBIT_DISPLAY_ROTATION_180)
+        {
+                x = width - 1 - x;
+                y = height - 1 - y;
+        }
+
+        if(rotation == MICROBIT_DISPLAY_ROTATION_270)
+        {
+                x = y;
+                y = height - 1 - t;
+        }
+
+        if(min(image.getBitmap()[y * (width * 2) + x],brightness) & greyscaleBitMsk)
+            col_data |= (1 << i);
+    }
+
+    // Invert column bits (as we're sinking not sourcing power), and mask off any unused bits.
+    col_data = ~col_data << matrixMap.columnStart & col_mask;
+
+    // Write the new bit pattern
+    *LEDMatrix = col_data | row_data;
+
+    if(timingCount > MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH-1)
+        return;
+
+    greyscaleBitMsk <<= 1;
+
+    if(timingCount < 3)
+    {
+        wait_us(greyScaleTimings[timingCount++]);
+        renderGreyscale();
+        return;
+    }
+    renderTimer.attach_us(this,&MicroBitDisplay::renderGreyscale, greyScaleTimings[timingCount++]);
+}
+
+/**
+  * Periodic callback, that we use to perform any animations we have running.
+  */
+void
+MicroBitDisplay::animationUpdate()
+{
+    // If there's no ongoing animation, then nothing to do.
+    if (animationMode == ANIMATION_MODE_NONE)
+        return;
+
+    animationTick += system_timer_get_period();
+
+    if(animationTick >= animationDelay)
+    {
+        animationTick = 0;
+
+        if (animationMode == ANIMATION_MODE_SCROLL_TEXT)
+            this->updateScrollText();
+
+        if (animationMode == ANIMATION_MODE_PRINT_TEXT)
+            this->updatePrintText();
+
+        if (animationMode == ANIMATION_MODE_SCROLL_IMAGE)
+            this->updateScrollImage();
+
+        if (animationMode == ANIMATION_MODE_ANIMATE_IMAGE)
+            this->updateAnimateImage();
+
+        if(animationMode == ANIMATION_MODE_PRINT_CHARACTER)
+        {
+            animationMode = ANIMATION_MODE_NONE;
+            this->sendAnimationCompleteEvent();
+        }
+    }
+}
+
+/**
+  * Broadcasts an event onto the defult EventModel indicating that the
+  * current animation has completed.
+  */
+void MicroBitDisplay::sendAnimationCompleteEvent()
+{
+    // Signal that we've completed an animation.
+    MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
+
+    // Wake up a fiber that was blocked on the animation (if any).
+    MicroBitEvent(MICROBIT_ID_NOTIFY_ONE, MICROBIT_DISPLAY_EVT_FREE);
+}
+
+/**
+  * Internal scrollText update method.
+  * Shift the screen image by one pixel to the left. If necessary, paste in the next char.
+  */
+void MicroBitDisplay::updateScrollText()
+{
+    image.shiftLeft(1);
+    scrollingPosition++;
+
+    if (scrollingPosition == width + MICROBIT_DISPLAY_SPACING)
+    {
+        scrollingPosition = 0;
+
+        image.print(scrollingChar < scrollingText.length() ? scrollingText.charAt(scrollingChar) : ' ',width,0);
+
+        if (scrollingChar > scrollingText.length())
+        {
+            animationMode = ANIMATION_MODE_NONE;
+            this->sendAnimationCompleteEvent();
+            return;
+        }
+        scrollingChar++;
+   }
+}
+
+/**
+  * Internal printText update method.
+  * Paste the next character in the string.
+  */
+void MicroBitDisplay::updatePrintText()
+{
+    image.print(printingChar < printingText.length() ? printingText.charAt(printingChar) : ' ',0,0);
+
+    if (printingChar > printingText.length())
+    {
+        animationMode = ANIMATION_MODE_NONE;
+
+        this->sendAnimationCompleteEvent();
+        return;
+    }
+
+    printingChar++;
+}
+
+/**
+  * Internal scrollImage update method.
+  * Paste the stored bitmap at the appropriate point.
+  */
+void MicroBitDisplay::updateScrollImage()
+{
+    image.clear();
+
+    if (((image.paste(scrollingImage, scrollingImagePosition, 0, 0) == 0) && scrollingImageRendered) || scrollingImageStride == 0)
+    {
+        animationMode = ANIMATION_MODE_NONE;
+        this->sendAnimationCompleteEvent();
+
+        return;
+    }
+
+    scrollingImagePosition += scrollingImageStride;
+    scrollingImageRendered = true;
+}
+
+/**
+  * Internal animateImage update method.
+  * Paste the stored bitmap at the appropriate point and stop on the last frame.
+  */
+void MicroBitDisplay::updateAnimateImage()
+{
+    //wait until we have rendered the last position to give a continuous animation.
+    if (scrollingImagePosition <= -scrollingImage.getWidth() + (MICROBIT_DISPLAY_WIDTH + scrollingImageStride) && scrollingImageRendered)
+    {
+        animationMode = ANIMATION_MODE_NONE;
+        this->clear();
+        this->sendAnimationCompleteEvent();
+        return;
+    }
+
+    if(scrollingImagePosition > 0)
+        image.shiftLeft(-scrollingImageStride);
+
+    image.paste(scrollingImage, scrollingImagePosition, 0, 0);
+
+    if(scrollingImageStride == 0)
+    {
+        animationMode = ANIMATION_MODE_NONE;
+        this->sendAnimationCompleteEvent();
+    }
+
+    scrollingImageRendered = true;
+
+    scrollingImagePosition += scrollingImageStride;
+}
+
+/**
+  * Resets the current given animation.
+  */
+void MicroBitDisplay::stopAnimation()
+{
+    // Reset any ongoing animation.
+    if (animationMode != ANIMATION_MODE_NONE)
+    {
+        animationMode = ANIMATION_MODE_NONE;
+
+        // Indicate that we've completed an animation.
+        MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
+
+        // Wake up aall fibers that may blocked on the animation (if any).
+        MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE);
+    }
+
+    // Clear the display and setup the animation timers.
+    this->image.clear();
+}
+
+/**
+  * Blocks the current fiber until the display is available (i.e. does not effect is being displayed).
+  * Animations are queued until their time to display.
+  */
+void MicroBitDisplay::waitForFreeDisplay()
+{
+    // If there's an ongoing animation, wait for our turn to display.
+    if (animationMode != ANIMATION_MODE_NONE && animationMode != ANIMATION_MODE_STOPPED)
+        fiber_wait_for_event(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE);
+}
+
+/**
+  * Blocks the current fiber until the current animation has finished.
+  * If the scheduler is not running, this call will essentially perform a spinning wait.
+  */
+void MicroBitDisplay::fiberWait()
+{
+    if (fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE) == MICROBIT_NOT_SUPPORTED)
+        while(animationMode != ANIMATION_MODE_NONE && animationMode != ANIMATION_MODE_STOPPED)
+            __WFE();
+}
+
+/**
+  * Prints the given character to the display, if it is not in use.
+  *
+  * @param c The character to display.
+  *
+  * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever,
+  *              or until the Displays next use.
+  *
+  * @return MICROBIT_OK, MICROBIT_BUSY is the screen is in use, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * display.printAsync('p');
+  * display.printAsync('p',100);
+  * @endcode
+  */
+int MicroBitDisplay::printCharAsync(char c, int delay)
+{
+    //sanitise this value
+    if(delay < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If the display is free, it's our turn to display.
+    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
+    {
+        image.print(c, 0, 0);
+
+        if (delay > 0)
+        {
+            animationDelay = delay;
+            animationTick = 0;
+            animationMode = ANIMATION_MODE_PRINT_CHARACTER;
+        }
+    }
+    else
+    {
+        return MICROBIT_BUSY;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Prints the given ManagedString to the display, one character at a time.
+  * Returns immediately, and executes the animation asynchronously.
+  *
+  * @param s The string to display.
+  *
+  * @param delay The time to delay between characters, in milliseconds. Must be > 0.
+  *              Defaults to: MICROBIT_DEFAULT_PRINT_SPEED.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * display.printAsync("abc123",400);
+  * @endcode
+  */
+int MicroBitDisplay::printAsync(ManagedString s, int delay)
+{
+    if (s.length() == 1)
+        return printCharAsync(s.charAt(0));
+
+    //sanitise this value
+    if (delay <= 0 )
+        return MICROBIT_INVALID_PARAMETER;
+
+    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
+    {
+        printingChar = 0;
+        printingText = s;
+        animationDelay = delay;
+        animationTick = 0;
+
+        animationMode = ANIMATION_MODE_PRINT_TEXT;
+    }
+    else
+    {
+        return MICROBIT_BUSY;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Prints the given image to the display, if the display is not in use.
+  * Returns immediately, and executes the animation asynchronously.
+  *
+  * @param i The image to display.
+  *
+  * @param x The horizontal position on the screen to display the image. Defaults to 0.
+  *
+  * @param y The vertical position on the screen to display the image. Defaults to 0.
+  *
+  * @param alpha Treats the brightness level '0' as transparent. Defaults to 0.
+  *
+  * @param delay The time to delay between characters, in milliseconds. Defaults to 0.
+  *
+  * @code
+  * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+  * display.print(i,400);
+  * @endcode
+  */
+int MicroBitDisplay::printAsync(MicroBitImage i, int x, int y, int alpha, int delay)
+{
+    if(delay < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
+    {
+        image.paste(i, x, y, alpha);
+
+        if(delay > 0)
+        {
+            animationDelay = delay;
+            animationTick = 0;
+            animationMode = ANIMATION_MODE_PRINT_CHARACTER;
+        }
+    }
+    else
+    {
+        return MICROBIT_BUSY;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Prints the given character to the display.
+  *
+  * @param c The character to display.
+  *
+  * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever,
+  *              or until the Displays next use.
+  *
+  * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * display.printAsync('p');
+  * display.printAsync('p',100);
+  * @endcode
+  */
+int MicroBitDisplay::printChar(char c, int delay)
+{
+    if (delay < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If there's an ongoing animation, wait for our turn to display.
+    this->waitForFreeDisplay();
+
+    // If the display is free, it's our turn to display.
+    // If someone called stopAnimation(), then we simply skip...
+    if (animationMode == ANIMATION_MODE_NONE)
+    {
+        this->printCharAsync(c, delay);
+
+        if (delay > 0)
+            fiberWait();
+    }
+    else
+    {
+        return MICROBIT_CANCELLED;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Prints the given string to the display, one character at a time.
+  *
+  * Blocks the calling thread until all the text has been displayed.
+  *
+  * @param s The string to display.
+  *
+  * @param delay The time to delay between characters, in milliseconds. Defaults
+  *              to: MICROBIT_DEFAULT_PRINT_SPEED.
+  *
+  * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * display.print("abc123",400);
+  * @endcode
+  */
+int MicroBitDisplay::print(ManagedString s, int delay)
+{
+    //sanitise this value
+    if(delay <= 0 )
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If there's an ongoing animation, wait for our turn to display.
+    this->waitForFreeDisplay();
+
+    // If the display is free, it's our turn to display.
+    // If someone called stopAnimation(), then we simply skip...
+    if (animationMode == ANIMATION_MODE_NONE)
+    {
+        if (s.length() == 1)
+        {
+            return printCharAsync(s.charAt(0));
+        }
+        else
+        {
+            this->printAsync(s, delay);
+            fiberWait();
+        }
+    }
+    else
+    {
+        return MICROBIT_CANCELLED;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Prints the given image to the display.
+  * Blocks the calling thread until all the image has been displayed.
+  *
+  * @param i The image to display.
+  *
+  * @param x The horizontal position on the screen to display the image. Defaults to 0.
+  *
+  * @param y The vertical position on the screen to display the image. Defaults to 0.
+  *
+  * @param alpha Treats the brightness level '0' as transparent. Defaults to 0.
+  *
+  * @param delay The time to display the image for, or zero to show the image forever. Defaults to 0.
+  *
+  * @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+  * display.print(i,400);
+  * @endcode
+  */
+int MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
+{
+    if(delay < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If there's an ongoing animation, wait for our turn to display.
+    this->waitForFreeDisplay();
+
+    // If the display is free, it's our turn to display.
+    // If someone called stopAnimation(), then we simply skip...
+    if (animationMode == ANIMATION_MODE_NONE)
+    {
+        this->printAsync(i, x, y, alpha, delay);
+
+        if (delay > 0)
+            fiberWait();
+    }
+    else
+    {
+        return MICROBIT_CANCELLED;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Scrolls the given string to the display, from right to left.
+  * Returns immediately, and executes the animation asynchronously.
+  *
+  * @param s The string to display.
+  *
+  * @param delay The time to delay between characters, in milliseconds. Defaults
+  *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+  *
+  * @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * display.scrollAsync("abc123",100);
+  * @endcode
+  */
+int MicroBitDisplay::scrollAsync(ManagedString s, int delay)
+{
+    //sanitise this value
+    if(delay <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If the display is free, it's our turn to display.
+    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
+    {
+        scrollingPosition = width-1;
+        scrollingChar = 0;
+        scrollingText = s;
+
+        animationDelay = delay;
+        animationTick = 0;
+        animationMode = ANIMATION_MODE_SCROLL_TEXT;
+    }
+    else
+    {
+        return MICROBIT_BUSY;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Scrolls the given image across the display, from right to left.
+  * Returns immediately, and executes the animation asynchronously.
+  *
+  * @param image The image to display.
+  *
+  * @param delay The time between updates, in milliseconds. Defaults
+  *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+  *
+  * @param stride The number of pixels to shift by in each update. Defaults to MICROBIT_DEFAULT_SCROLL_STRIDE.
+  *
+  * @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+  * display.scrollAsync(i,100,1);
+  * @endcode
+  */
+int MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride)
+{
+    //sanitise the delay value
+    if(delay <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If the display is free, it's our turn to display.
+    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
+    {
+        scrollingImagePosition = stride < 0 ? width : -image.getWidth();
+        scrollingImageStride = stride;
+        scrollingImage = image;
+        scrollingImageRendered = false;
+
+        animationDelay = stride == 0 ? 0 : delay;
+        animationTick = 0;
+        animationMode = ANIMATION_MODE_SCROLL_IMAGE;
+    }
+    else
+    {
+        return MICROBIT_BUSY;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Scrolls the given string across the display, from right to left.
+  * Blocks the calling thread until all text has been displayed.
+  *
+  * @param s The string to display.
+  *
+  * @param delay The time to delay between characters, in milliseconds. Defaults
+  *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+  *
+  * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * display.scroll("abc123",100);
+  * @endcode
+  */
+int MicroBitDisplay::scroll(ManagedString s, int delay)
+{
+    //sanitise this value
+    if(delay <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If there's an ongoing animation, wait for our turn to display.
+    this->waitForFreeDisplay();
+
+    // If the display is free, it's our turn to display.
+    // If someone called stopAnimation(), then we simply skip...
+    if (animationMode == ANIMATION_MODE_NONE)
+    {
+        // Start the effect.
+        this->scrollAsync(s, delay);
+
+        // Wait for completion.
+        fiberWait();
+    }
+    else
+    {
+        return MICROBIT_CANCELLED;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Scrolls the given image across the display, from right to left.
+  * Blocks the calling thread until all the text has been displayed.
+  *
+  * @param image The image to display.
+  *
+  * @param delay The time between updates, in milliseconds. Defaults
+  *              to: MICROBIT_DEFAULT_SCROLL_SPEED.
+  *
+  * @param stride The number of pixels to shift by in each update. Defaults to MICROBIT_DEFAULT_SCROLL_STRIDE.
+  *
+  * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
+  * display.scroll(i,100,1);
+  * @endcode
+  */
+int MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
+{
+    //sanitise the delay value
+    if(delay <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If there's an ongoing animation, wait for our turn to display.
+    this->waitForFreeDisplay();
+
+    // If the display is free, it's our turn to display.
+    // If someone called stopAnimation(), then we simply skip...
+    if (animationMode == ANIMATION_MODE_NONE)
+    {
+        // Start the effect.
+        this->scrollAsync(image, delay, stride);
+
+        // Wait for completion.
+        fiberWait();
+    }
+    else
+    {
+        return MICROBIT_CANCELLED;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation.
+  * Returns immediately.
+  *
+  * @param image The image to display.
+  *
+  * @param delay The time to delay between each update of the display, in milliseconds.
+  *
+  * @param stride The number of pixels to shift by in each update.
+  *
+  * @param startingPosition the starting position on the display for the animation
+  *                         to begin at. Defaults to MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS.
+  *
+  * @return MICROBIT_OK, MICROBIT_BUSY if the screen is in use, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * const int heart_w = 10;
+  * const int heart_h = 5;
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, };
+  *
+  * MicroBitImage i(heart_w,heart_h,heart);
+  * display.animateAsync(i,100,5);
+  * @endcode
+  */
+int MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, int startingPosition)
+{
+    //sanitise the delay value
+    if(delay <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If the display is free, we can display.
+    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
+    {
+        // Assume right to left functionality, to align with scrollString()
+        stride = -stride;
+
+        //calculate starting position which is offset by the stride
+        scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS) ? MICROBIT_DISPLAY_WIDTH + stride : startingPosition;
+        scrollingImageStride = stride;
+        scrollingImage = image;
+        scrollingImageRendered = false;
+
+        animationDelay = stride == 0 ? 0 : delay;
+        animationTick = delay-1;
+        animationMode = ANIMATION_MODE_ANIMATE_IMAGE;
+    }
+    else
+    {
+        return MICROBIT_BUSY;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation.
+  * Blocks the calling thread until the animation is complete.
+  *
+  *
+  * @param delay The time to delay between each update of the display, in milliseconds.
+  *
+  * @param stride The number of pixels to shift by in each update.
+  *
+  * @param startingPosition the starting position on the display for the animation
+  *                         to begin at. Defaults to MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS.
+  *
+  * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * const int heart_w = 10;
+  * const int heart_h = 5;
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, };
+  *
+  * MicroBitImage i(heart_w,heart_h,heart);
+  * display.animate(i,100,5);
+  * @endcode
+  */
+int MicroBitDisplay::animate(MicroBitImage image, int delay, int stride, int startingPosition)
+{
+    //sanitise the delay value
+    if(delay <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // If there's an ongoing animation, wait for our turn to display.
+    this->waitForFreeDisplay();
+
+    // If the display is free, it's our turn to display.
+    // If someone called stopAnimation(), then we simply skip...
+    if (animationMode == ANIMATION_MODE_NONE)
+    {
+        // Start the effect.
+        this->animateAsync(image, delay, stride, startingPosition);
+
+        // Wait for completion.
+        //TODO: Put this in when we merge tight-validation
+        //if (delay > 0)
+            fiberWait();
+    }
+    else
+    {
+        return MICROBIT_CANCELLED;
+    }
+
+    return MICROBIT_OK;
+}
+
+
+/**
+  * Configures the brightness of the display.
+  *
+  * @param b The brightness to set the brightness to, in the range 0 - 255.
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER
+  *
+  * @code
+  * display.setBrightness(255); //max brightness
+  * @endcode
+  */
+int MicroBitDisplay::setBrightness(int b)
+{
+    //sanitise the brightness level
+    if(b < 0 || b > 255)
+        return MICROBIT_INVALID_PARAMETER;
+
+    this->brightness = b;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures the mode of the display.
+  *
+  * @param mode The mode to swap the display into. One of: DISPLAY_MODE_GREYSCALE,
+  *             DISPLAY_MODE_BLACK_AND_WHITE, DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE
+  *
+  * @code
+  * display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness
+  * @endcode
+  */
+void MicroBitDisplay::setDisplayMode(DisplayMode mode)
+{
+    if(mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
+    {
+        //to reduce the artifacts on the display - increase the tick
+        if(system_timer_get_period() != MICROBIT_LIGHT_SENSOR_TICK_PERIOD)
+            system_timer_set_period(MICROBIT_LIGHT_SENSOR_TICK_PERIOD);
+    }
+
+    if(this->mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE && mode != DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
+    {
+        delete this->lightSensor;
+
+        this->lightSensor = NULL;
+    }
+
+    this->mode = mode;
+}
+
+/**
+  * Retrieves the mode of the display.
+  *
+  * @return the current mode of the display
+  */
+int MicroBitDisplay::getDisplayMode()
+{
+    return this->mode;
+}
+
+/**
+  * Fetches the current brightness of this display.
+  *
+  * @return the brightness of this display, in the range 0..255.
+  *
+  * @code
+  * display.getBrightness(); //the current brightness
+  * @endcode
+  */
+int MicroBitDisplay::getBrightness()
+{
+    return this->brightness;
+}
+
+/**
+  * Rotates the display to the given position.
+  *
+  * Axis aligned values only.
+  *
+  * @code
+  * display.rotateTo(MICROBIT_DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation
+  * @endcode
+  */
+void MicroBitDisplay::rotateTo(DisplayRotation rotation)
+{
+    this->rotation = rotation;
+}
+
+/**
+ * Enables or disables the display entirely, and releases the pins for other uses.
+ *
+ * @param enableDisplay true to enabled the display, or false to disable it.
+ */
+void MicroBitDisplay::setEnable(bool enableDisplay)
+{
+    // If we're already in the correct state, then there's nothing to do.
+    if(((status & MICROBIT_COMPONENT_RUNNING) && enableDisplay) || (!(status & MICROBIT_COMPONENT_RUNNING) && !enableDisplay))
+        return;
+
+    uint32_t rmask = 0;
+    uint32_t cmask = 0;
+
+    for (int i = matrixMap.rowStart; i < matrixMap.rowStart + matrixMap.rows; i++)
+        rmask |= 0x01 << i;
+
+    for (int i = matrixMap.columnStart; i < matrixMap.columnStart + matrixMap.columns; i++)
+        cmask |= 0x01 << i;
+
+    if (enableDisplay)
+    {
+        PortOut p(Port0, rmask | cmask);
+        status |= MICROBIT_COMPONENT_RUNNING;
+    }
+    else
+    {
+        PortIn p(Port0, rmask | cmask);
+        p.mode(PullNone);
+        status &= ~MICROBIT_COMPONENT_RUNNING;
+    }
+}
+
+/**
+  * Enables the display, should only be called if the display is disabled.
+  *
+  * @code
+  * display.enable(); //Enables the display mechanics
+  * @endcode
+  *
+  * @note Only enables the display if the display is currently disabled.
+  */
+void MicroBitDisplay::enable()
+{
+    setEnable(true);
+}
+
+/**
+  * Disables the display, which releases control of the GPIO pins used by the display,
+  * which are exposed on the edge connector.
+  *
+  * @code
+  * display.disable(); //disables the display
+  * @endcode
+  *
+  * @note Only disables the display if the display is currently enabled.
+  */
+void MicroBitDisplay::disable()
+{
+    setEnable(false);
+}
+
+/**
+  * Clears the display of any remaining pixels.
+  *
+  * `display.image.clear()` can also be used!
+  *
+  * @code
+  * display.clear(); //clears the display
+  * @endcode
+  */
+void MicroBitDisplay::clear()
+{
+    image.clear();
+}
+
+/**
+  * Updates the font that will be used for display operations.
+  *
+  * @param font the new font that will be used to render characters.
+  *
+  * @note DEPRECATED! Please use MicroBitFont::setSystemFont() instead.
+  */
+void MicroBitDisplay::setFont(MicroBitFont font)
+{
+	MicroBitFont::setSystemFont(font);
+}
+
+/**
+  * Retrieves the font object used for rendering characters on the display.
+  *
+  * @note DEPRECATED! Please use MicroBitFont::getSystemFont() instead.
+  */
+MicroBitFont MicroBitDisplay::getFont()
+{
+	return MicroBitFont::getSystemFont();
+}
+
+/**
+  * Captures the bitmap currently being rendered on the display.
+  *
+  * @return a MicroBitImage containing the captured data.
+  */
+MicroBitImage MicroBitDisplay::screenShot()
+{
+    return image.crop(0,0,MICROBIT_DISPLAY_WIDTH,MICROBIT_DISPLAY_HEIGHT);
+}
+
+/**
+  * Gives a representative figure of the light level in the current environment
+  * where are micro:bit is situated.
+  *
+  * Internally, it constructs an instance of a MicroBitLightSensor if not already configured
+  * and sets the display mode to DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE.
+  *
+  * This also changes the tickPeriod to MICROBIT_LIGHT_SENSOR_TICK_SPEED so
+  * that the display does not suffer from artifacts.
+  *
+  * @return an indicative light level in the range 0 - 255.
+  *
+  * @note this will return 0 on the first call to this method, a light reading
+  * will be available after the display has activated the light sensor for the
+  * first time.
+  */
+int MicroBitDisplay::readLightLevel()
+{
+    if(mode != DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
+    {
+        setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE);
+        this->lightSensor = new MicroBitLightSensor(matrixMap);
+    }
+
+    return this->lightSensor->read();
+}
+
+/**
+  * Destructor for MicroBitDisplay, where we deregister this instance from the array of system components.
+  */
+MicroBitDisplay::~MicroBitDisplay()
+{
+    system_timer_remove_component(this);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitI2C.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,134 @@
+/*
+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 "MicroBitI2C.h"
+#include "ErrorNo.h"
+#include "twi_master.h"
+#include "nrf_delay.h"
+
+/**
+  * Constructor.
+  *
+  * Create an instance of MicroBitI2C for I2C communication.
+  *
+  * @param sda the Pin to be used for SDA
+  *
+  * @param scl the Pin to be used for SCL
+  *
+  * @code
+  * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+  * @endcode
+  *
+  * @note This class presents a wrapped mbed call to capture failed I2C operations caused by a known silicon bug in the nrf51822.
+  * Attempts to automatically reset and restart the I2C hardware if this case is detected.
+  *
+  * For reference see PAN56 in:
+  *
+  * https://www.nordicsemi.com/eng/nordic/Products/nRF51822/PAN-nRF51822/24634
+  *
+  * v2.0 through to v2.4
+  */
+MicroBitI2C::MicroBitI2C(PinName sda, PinName scl) : I2C(sda,scl)
+{
+    this->retries = 0;
+}
+
+/**
+  * Performs a complete read transaction. The bottom bit of the address is forced to 1 to indicate a read.
+  *
+  * @param address 8-bit I2C slave address [ addr | 1 ]
+  *
+  * @param data A pointer to a byte buffer used for storing retrieved data.
+  *
+  * @param length Number of bytes to read.
+  *
+  * @param repeated if true, stop is not sent at the end. Defaults to false.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved read failure is detected.
+  */
+int MicroBitI2C::read(int address, char *data, int length, bool repeated)
+{
+    int result = I2C::read(address,data,length,repeated);
+
+    //0 indicates a success, presume failure
+    while(result != 0 && retries < MICROBIT_I2C_MAX_RETRIES)
+    {
+        _i2c.i2c->EVENTS_ERROR = 0;
+        _i2c.i2c->ENABLE       = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
+        _i2c.i2c->POWER        = 0;
+        nrf_delay_us(5);
+        _i2c.i2c->POWER        = 1;
+        _i2c.i2c->ENABLE       = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
+        twi_master_init_and_clear();
+        result = I2C::read(address,data,length,repeated);
+        retries++;
+    }
+
+    if(result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    retries = 0;
+    return MICROBIT_OK;
+}
+
+/**
+  * Performs a complete write transaction. The bottom bit of the address is forced to 0 to indicate a write.
+  *
+  * @param address 8-bit I2C slave address [ addr | 0 ]
+  *
+  * @param data A pointer to a byte buffer containing the data to write.
+  *
+  * @param length Number of bytes to write
+  *
+  * @param repeated if true, stop is not sent at the end. Defaults to false.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved write failure is detected.
+  */
+int MicroBitI2C::write(int address, const char *data, int length, bool repeated)
+{
+    int result = I2C::write(address,data,length,repeated);
+
+    //0 indicates a success, presume failure
+    while(result != 0 && retries < MICROBIT_I2C_MAX_RETRIES)
+    {
+        _i2c.i2c->EVENTS_ERROR = 0;
+        _i2c.i2c->ENABLE       = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
+        _i2c.i2c->POWER        = 0;
+        nrf_delay_us(5);
+        _i2c.i2c->POWER        = 1;
+        _i2c.i2c->ENABLE       = TWI_ENABLE_ENABLE_Enabled << TWI_ENABLE_ENABLE_Pos;
+
+        twi_master_init_and_clear();
+        result = I2C::write(address,data,length,repeated);
+        retries++;
+    }
+
+    if(result != 0)
+        return MICROBIT_I2C_ERROR;
+
+    retries = 0;
+    return MICROBIT_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitIO.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,70 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for MicroBit IO.
+  *
+  * Represents a collection of all I/O pins on the edge connector.
+  */
+
+#include "MicroBitConfig.h"
+#include "MicroBitIO.h"
+
+/**
+  * Constructor.
+  *
+  * Create a representation of all given I/O pins on the edge connector
+  *
+  * Accepts a sequence of unique ID's used to distinguish events raised
+  * by MicroBitPin instances on the default EventModel.
+  */
+MicroBitIO::MicroBitIO(int ID_P0, int ID_P1, int ID_P2,
+                       int ID_P3, int ID_P4, int ID_P5,
+                       int ID_P6, int ID_P7, int ID_P8,
+                       int ID_P9, int ID_P10,int ID_P11,
+                       int ID_P12,int ID_P13,int ID_P14,
+                       int ID_P15,int ID_P16,int ID_P19,
+                       int ID_P20) :
+    P0 (ID_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL),            //P0 is the left most pad (ANALOG/DIGITAL/TOUCH)
+    P1 (ID_P1, MICROBIT_PIN_P1, PIN_CAPABILITY_ALL),            //P1 is the middle pad (ANALOG/DIGITAL/TOUCH)
+    P2 (ID_P2, MICROBIT_PIN_P2, PIN_CAPABILITY_ALL),            //P2 is the right most pad (ANALOG/DIGITAL/TOUCH)
+    P3 (ID_P3, MICROBIT_PIN_P3, PIN_CAPABILITY_AD),             //COL1 (ANALOG/DIGITAL)
+    P4 (ID_P4, MICROBIT_PIN_P4, PIN_CAPABILITY_AD),             //COL2 (ANALOG/DIGITAL)
+    P5 (ID_P5, MICROBIT_PIN_P5, PIN_CAPABILITY_DIGITAL),        //BTN_A
+    P6 (ID_P6, MICROBIT_PIN_P6, PIN_CAPABILITY_DIGITAL),        //ROW2
+    P7 (ID_P7, MICROBIT_PIN_P7, PIN_CAPABILITY_DIGITAL),        //ROW1
+    P8 (ID_P8, MICROBIT_PIN_P8, PIN_CAPABILITY_DIGITAL),        //PIN 18
+    P9 (ID_P9, MICROBIT_PIN_P9, PIN_CAPABILITY_DIGITAL),        //ROW3
+    P10(ID_P10,MICROBIT_PIN_P10,PIN_CAPABILITY_AD),             //COL3 (ANALOG/DIGITAL)
+    P11(ID_P11,MICROBIT_PIN_P11,PIN_CAPABILITY_DIGITAL),        //BTN_B
+    P12(ID_P12,MICROBIT_PIN_P12,PIN_CAPABILITY_DIGITAL),        //PIN 20
+    P13(ID_P13,MICROBIT_PIN_P13,PIN_CAPABILITY_DIGITAL),        //SCK
+    P14(ID_P14,MICROBIT_PIN_P14,PIN_CAPABILITY_DIGITAL),        //MISO
+    P15(ID_P15,MICROBIT_PIN_P15,PIN_CAPABILITY_DIGITAL),        //MOSI
+    P16(ID_P16,MICROBIT_PIN_P16,PIN_CAPABILITY_DIGITAL),        //PIN 16
+    P19(ID_P19,MICROBIT_PIN_P19,PIN_CAPABILITY_DIGITAL),        //SCL
+    P20(ID_P20,MICROBIT_PIN_P20,PIN_CAPABILITY_DIGITAL)         //SDA
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitLightSensor.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,177 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for MicroBitLightSensor.
+  *
+  * This is an object that interleaves light sensing with MicroBitDisplay.
+  */
+
+#include "MicroBitConfig.h"
+#include "MicroBitLightSensor.h"
+#include "MicroBitDisplay.h"
+
+/**
+  * After the startSensing method has been called, this method will be called
+  * MICROBIT_LIGHT_SENSOR_AN_SET_TIME after.
+  *
+  * It will then read from the currently selected channel using the AnalogIn
+  * that was configured in the startSensing method.
+  */
+void MicroBitLightSensor::analogReady()
+{
+    this->results[chan] = this->sensePin->read_u16();
+
+    analogDisable();
+
+    DigitalOut((PinName)(matrixMap.columnStart + chan)).write(1);
+
+    chan++;
+
+    chan = chan % MICROBIT_LIGHT_SENSOR_CHAN_NUM;
+}
+
+/**
+  * Forcibly disables the AnalogIn, otherwise it will remain in possession
+  * of the GPIO channel it is using, meaning that the display will not be
+  * able to use a channel (COL).
+  *
+  * This is required as per PAN 3, details of which can be found here:
+  *
+  * https://www.nordicsemi.com/eng/nordic/download_resource/24634/5/88440387
+  */
+void MicroBitLightSensor::analogDisable()
+{
+    NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled;
+
+    NRF_ADC->CONFIG = (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos) |
+                      (ADC_CONFIG_INPSEL_SupplyTwoThirdsPrescaling << ADC_CONFIG_INPSEL_Pos) |
+                      (ADC_CONFIG_REFSEL_VBG                       << ADC_CONFIG_REFSEL_Pos) |
+                      (ADC_CONFIG_PSEL_Disabled                    << ADC_CONFIG_PSEL_Pos) |
+                      (ADC_CONFIG_EXTREFSEL_None                   << ADC_CONFIG_EXTREFSEL_Pos);
+}
+
+/**
+  * Constructor.
+  *
+  * Create a representation of the light sensor.
+  *
+  * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates.
+  *            Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h.
+  */
+MicroBitLightSensor::MicroBitLightSensor(const MatrixMap &map) :
+    analogTrigger(),
+    matrixMap(map)
+{
+    this->chan = 0;
+
+    if (EventModel::defaultEventBus)
+        EventModel::defaultEventBus->listen(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing, MESSAGE_BUS_LISTENER_IMMEDIATE);
+
+    this->sensePin = NULL;
+}
+
+/**
+  * This method returns a summed average of the three sections of the display.
+  *
+  * A section is defined as:
+  *  ___________________
+  * | 1 |   | 2 |   | 3 |
+  * |___|___|___|___|___|
+  * |   |   |   |   |   |
+  * |___|___|___|___|___|
+  * | 2 |   | 3 |   | 1 |
+  * |___|___|___|___|___|
+  * |   |   |   |   |   |
+  * |___|___|___|___|___|
+  * | 3 |   | 1 |   | 2 |
+  * |___|___|___|___|___|
+  *
+  * Where each number represents a different section on the 5 x 5 matrix display.
+  *
+  * @return returns a value in the range 0 - 255 where 0 is dark, and 255
+  * is very bright
+  */
+int MicroBitLightSensor::read()
+{
+    int sum = 0;
+
+    for(int i = 0; i < MICROBIT_LIGHT_SENSOR_CHAN_NUM; i++)
+        sum += results[i];
+
+    int average = sum / MICROBIT_LIGHT_SENSOR_CHAN_NUM;
+
+    average = min(average, MICROBIT_LIGHT_SENSOR_MAX_VALUE);
+
+    average = max(average, MICROBIT_LIGHT_SENSOR_MIN_VALUE);
+
+    int inverted = (MICROBIT_LIGHT_SENSOR_MAX_VALUE - average) + MICROBIT_LIGHT_SENSOR_MIN_VALUE;
+
+    int a = 0;
+
+    int b = 255;
+
+    int normalised = a + ((((inverted - MICROBIT_LIGHT_SENSOR_MIN_VALUE)) * (b - a))/ (MICROBIT_LIGHT_SENSOR_MAX_VALUE - MICROBIT_LIGHT_SENSOR_MIN_VALUE));
+
+    return normalised;
+}
+
+/**
+  * The method that is invoked by sending MICROBIT_DISPLAY_EVT_LIGHT_SENSE
+  * using the id MICROBIT_ID_DISPLAY.
+  *
+  * @note this can be manually driven by calling this member function, with
+  *       a MicroBitEvent using the CREATE_ONLY option of the MicroBitEvent
+  *       constructor.
+  */
+void MicroBitLightSensor::startSensing(MicroBitEvent)
+{
+    for(int rowCount = 0; rowCount < matrixMap.rows; rowCount++)
+        DigitalOut((PinName)(matrixMap.rowStart + rowCount)).write(0);
+
+    PinName currentPin = (PinName)(matrixMap.columnStart + chan);
+
+    DigitalOut(currentPin).write(1);
+
+    DigitalIn(currentPin, PullNone).~DigitalIn();
+
+    if(this->sensePin != NULL)
+        delete this->sensePin;
+
+    this->sensePin = new AnalogIn(currentPin);
+
+    analogTrigger.attach_us(this, &MicroBitLightSensor::analogReady, MICROBIT_LIGHT_SENSOR_AN_SET_TIME);
+}
+
+/**
+  * A destructor for MicroBitLightSensor.
+  *
+  * The destructor removes the listener, used by MicroBitLightSensor from the default EventModel.
+  */
+MicroBitLightSensor::~MicroBitLightSensor()
+{
+    if (EventModel::defaultEventBus)
+        EventModel::defaultEventBus->ignore(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitMessageBus.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,552 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the MicroBitMessageBus.
+  *
+  * The MicroBitMessageBus is the common mechanism to deliver asynchronous events on the
+  * MicroBit platform. It serves a number of purposes:
+  *
+  * 1) It provides an eventing abstraction that is independent of the underlying substrate.
+  *
+  * 2) It provides a mechanism to decouple user code from trusted system code
+  *    i.e. the basis of a message passing nano kernel.
+  *
+  * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE...
+  *
+  * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based
+  *    drivers and communicate via the message bus with minima impact on user level languages.
+  *
+  * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy.
+  *
+  * It has the following design principles:
+  *
+  * 1) Maintain a low RAM footprint where possible
+  *
+  * 2) Make few assumptions about the underlying platform, but allow optimizations where possible.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitMessageBus.h"
+#include "MicroBitFiber.h"
+#include "ErrorNo.h"
+
+/**
+  * Default constructor.
+  *
+  * Adds itself as a fiber component, and also configures itself to be the
+  * default EventModel if defaultEventBus is NULL.
+  */
+MicroBitMessageBus::MicroBitMessageBus()
+{
+	this->listeners = NULL;
+    this->evt_queue_head = NULL;
+    this->evt_queue_tail = NULL;
+    this->queueLength = 0;
+
+	fiber_add_idle_component(this);
+
+	if(EventModel::defaultEventBus == NULL)
+		EventModel::defaultEventBus = this;
+}
+
+/**
+  * Invokes a callback on a given MicroBitListener
+  *
+  * Internal wrapper function, used to enable
+  * parameterised callbacks through the fiber scheduler.
+  */
+void async_callback(void *param)
+{
+	MicroBitListener *listener = (MicroBitListener *)param;
+
+    // OK, now we need to decide how to behave depending on our configuration.
+    // If this a fiber f already active within this listener then check our
+    // configuration to determine the correct course of action.
+    //
+
+    if (listener->flags & MESSAGE_BUS_LISTENER_BUSY)
+    {
+        // Drop this event, if that's how we've been configured.
+        if (listener->flags & MESSAGE_BUS_LISTENER_DROP_IF_BUSY)
+            return;
+
+        // Queue this event up for later, if that's how we've been configured.
+        if (listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY)
+        {
+            listener->queue(listener->evt);
+            return;
+        }
+    }
+
+    // Determine the calling convention for the callback, and invoke...
+    // C++ is really bad at this! Especially as the ARM compiler is yet to support C++ 11 :-/
+
+    // Record that we have a fiber going into this listener...
+    listener->flags |= MESSAGE_BUS_LISTENER_BUSY;
+
+    while (1)
+    {
+        // Firstly, check for a method callback into an object.
+        if (listener->flags & MESSAGE_BUS_LISTENER_METHOD)
+            listener->cb_method->fire(listener->evt);
+
+        // Now a parameterised C function
+        else if (listener->flags & MESSAGE_BUS_LISTENER_PARAMETERISED)
+            listener->cb_param(listener->evt, listener->cb_arg);
+
+        // We must have a plain C function
+        else
+            listener->cb(listener->evt);
+
+        // If there are more events to process, dequeue the next one and process it.
+        if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue)
+        {
+            MicroBitEventQueueItem *item = listener->evt_queue;
+
+            listener->evt = item->evt;
+            listener->evt_queue = listener->evt_queue->next;
+            delete item;
+
+            // We spin the scheduler here, to preven any particular event handler from continuously holding onto resources.
+            schedule();
+        }
+        else
+            break;
+    }
+
+    // The fiber of exiting... clear our state.
+    listener->flags &= ~MESSAGE_BUS_LISTENER_BUSY;
+}
+
+/**
+  * Queue the given event for processing at a later time.
+  * Add the given event at the tail of our queue.
+  *
+  * @param The event to queue.
+  */
+void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
+{
+    int processingComplete;
+
+    MicroBitEventQueueItem *prev = evt_queue_tail;
+
+    // Now process all handler regsitered as URGENT.
+    // These pre-empt the queue, and are useful for fast, high priority services.
+    processingComplete = this->process(evt, true);
+
+    // If we've already processed all event handlers, we're all done.
+    // No need to queue the event.
+    if (processingComplete)
+        return;
+
+    // If we need to queue, but there is no space, then there's nothg we can do.
+    if (queueLength >= MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH)
+        return;
+
+    // Otherwise, we need to queue this event for later processing...
+    // We queue this event at the tail of the queue at the point where we entered queueEvent()
+    // This is important as the processing above *may* have generated further events, and
+    // we want to maintain ordering of events.
+    MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
+
+    // The queue was empty when we entered this function, so queue our event at the start of the queue.
+    __disable_irq();
+
+    if (prev == NULL)
+    {
+        item->next = evt_queue_head;
+        evt_queue_head = item;
+    }
+    else
+    {
+        item->next = prev->next;
+        prev->next = item;
+    }
+
+    if (item->next == NULL)
+        evt_queue_tail = item;
+
+    queueLength++;
+
+    __enable_irq();
+}
+
+/**
+  * Extract the next event from the front of the event queue (if present).
+  *
+  * @return a pointer to the MicroBitEventQueueItem that is at the head of the list.
+  */
+MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent()
+{
+    MicroBitEventQueueItem *item = NULL;
+
+    __disable_irq();
+
+    if (evt_queue_head != NULL)
+    {
+        item = evt_queue_head;
+        evt_queue_head = item->next;
+
+        if (evt_queue_head == NULL)
+            evt_queue_tail = NULL;
+
+        queueLength--;
+    }
+
+    __enable_irq();
+
+
+    return item;
+}
+
+/**
+  * Cleanup any MicroBitListeners marked for deletion from the list.
+  *
+  * @return The number of listeners removed from the list.
+  */
+int MicroBitMessageBus::deleteMarkedListeners()
+{
+	MicroBitListener *l, *p;
+    int removed = 0;
+
+	l = listeners;
+	p = NULL;
+
+    // Walk this list of event handlers. Delete any that match the given listener.
+    while (l != NULL)
+    {
+        if (l->flags & MESSAGE_BUS_LISTENER_DELETING && !l->flags & MESSAGE_BUS_LISTENER_BUSY)
+        {
+            if (p == NULL)
+                listeners = l->next;
+            else
+                p->next = l->next;
+
+            // delete the listener.
+            MicroBitListener *t = l;
+            l = l->next;
+
+            delete t;
+            removed++;
+
+            continue;
+        }
+
+        p = l;
+        l = l->next;
+    }
+
+    return removed;
+}
+
+/**
+  * Periodic callback from MicroBit.
+  *
+  * Process at least one event from the event queue, if it is not empty.
+  * We then continue processing events until something appears on the runqueue.
+  */
+void MicroBitMessageBus::idleTick()
+{
+    // Clear out any listeners marked for deletion
+    this->deleteMarkedListeners();
+
+    MicroBitEventQueueItem *item = this->dequeueEvent();
+
+    // Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them.
+    while (item)
+    {
+        // send the event to all standard event listeners.
+        this->process(item->evt);
+
+        // Free the queue item.
+        delete item;
+
+        // If we have created some useful work to do, we stop processing.
+        // This helps to minimise the number of blocked fibers we create at any point in time, therefore
+        // also reducing the RAM footprint.
+        if(!scheduler_runqueue_empty())
+            break;
+
+        // Pull the next event to process, if there is one.
+        item = this->dequeueEvent();
+    }
+}
+
+/**
+  * Indicates whether or not we have any background work to do.
+  *
+  * @return 1 if there are any events waitingto be processed, 0 otherwise.
+  */
+int MicroBitMessageBus::isIdleCallbackNeeded()
+{
+    return !(evt_queue_head == NULL);
+}
+
+/**
+  * Queues the given event to be sent to all registered recipients.
+  *
+  * @param evt The event to send.
+  *
+  * @code
+  * MicroBitMessageBus bus;
+  *
+  * // Creates and sends the MicroBitEvent using bus.
+  * MicrobitEvent evt(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
+  *
+  * // Creates the MicrobitEvent, but delays the sending of that event.
+  * MicrobitEvent evt1(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, CREATE_ONLY);
+  *
+  * bus.send(evt1);
+  *
+  * // This has the same effect!
+  * evt1.fire()
+  * @endcode
+  */
+int MicroBitMessageBus::send(MicroBitEvent evt)
+{
+    // We simply queue processing of the event until we're scheduled in normal thread context.
+    // We do this to avoid the possibility of executing event handler code in IRQ context, which may bring
+    // hidden race conditions to kids code. Queuing all events ensures causal ordering (total ordering in fact).
+    this->queueEvent(evt);
+    return MICROBIT_OK;
+}
+
+/**
+  * Internal function, used to deliver the given event to all relevant recipients.
+  * Normally, this is called once an event has been removed from the event queue.
+  *
+  * @param evt The event to send.
+  *
+  * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed
+  *               otherwise, all other (standard) listeners will be processed. Defaults to false.
+  *
+  * @return 1 if all matching listeners were processed, 0 if further processing is required.
+  *
+  * @note It is recommended that all external code uses the send() function instead of this function,
+  *       or the constructors provided by MicrobitEvent.
+  */
+int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent)
+{
+	MicroBitListener *l;
+    int complete = 1;
+    bool listenerUrgent;
+
+    l = listeners;
+    while (l != NULL)
+    {
+	    if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
+        {
+            listenerUrgent = (l->flags & MESSAGE_BUS_LISTENER_IMMEDIATE) == MESSAGE_BUS_LISTENER_IMMEDIATE;
+            if(listenerUrgent == urgent && !(l->flags & MESSAGE_BUS_LISTENER_DELETING))
+            {
+                l->evt = evt;
+
+                // OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
+                // This is normally only done for trusted system components.
+                // Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
+                // should the event handler attempt a blocking operation, but doesn't have the overhead
+                // of creating a fiber needlessly. (cool huh?)
+                if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING || !fiber_scheduler_running())
+                    async_callback(l);
+                else
+                    invoke(async_callback, l);
+            }
+            else
+            {
+                complete = 0;
+            }
+		}
+
+		l = l->next;
+	}
+
+    return complete;
+}
+
+/**
+  * Add the given MicroBitListener to the list of event handlers, unconditionally.
+  *
+  * @param listener The MicroBitListener to add.
+  *
+  * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
+  */
+int MicroBitMessageBus::add(MicroBitListener *newListener)
+{
+	MicroBitListener *l, *p;
+    int methodCallback;
+
+	//handler can't be NULL!
+	if (newListener == NULL)
+		return MICROBIT_INVALID_PARAMETER;
+
+	l = listeners;
+
+	// Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler
+	// registered in a that will already capture these events. If we do, silently ignore.
+
+    // We always check the ID, VALUE and CB_METHOD fields.
+    // If we have a callback to a method, check the cb_method class. Otherwise, the cb function point is sufficient.
+    while (l != NULL)
+    {
+        methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD);
+
+        if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb))
+        {
+            // We have a perfect match for this event listener already registered.
+            // If it's marked for deletion, we simply resurrect the listener, and we're done.
+            // Either way, we return an error code, as the *new* listener should be released...
+            if(l->flags & MESSAGE_BUS_LISTENER_DELETING)
+                l->flags &= ~MESSAGE_BUS_LISTENER_DELETING;
+
+            return MICROBIT_NOT_SUPPORTED;
+        }
+
+        l = l->next;
+    }
+
+    // We have a valid, new event handler. Add it to the list.
+	// if listeners is null - we can automatically add this listener to the list at the beginning...
+	if (listeners == NULL)
+	{
+		listeners = newListener;
+        MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
+
+		return MICROBIT_OK;
+	}
+
+	// We maintain an ordered list of listeners.
+	// The chain is held stictly in increasing order of ID (first level), then value code (second level).
+	// Find the correct point in the chain for this event.
+	// Adding a listener is a rare occurance, so we just walk the list...
+
+	p = listeners;
+	l = listeners;
+
+	while (l != NULL && l->id < newListener->id)
+	{
+		p = l;
+		l = l->next;
+	}
+
+	while (l != NULL && l->id == newListener->id && l->value < newListener->value)
+	{
+		p = l;
+		l = l->next;
+	}
+
+	//add at front of list
+	if (p == listeners && (newListener->id < p->id || (p->id == newListener->id && p->value > newListener->value)))
+	{
+		newListener->next = p;
+
+		//this new listener is now the front!
+		listeners = newListener;
+	}
+
+	//add after p
+	else
+	{
+		newListener->next = p->next;
+		p->next = newListener;
+	}
+
+    MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
+    return MICROBIT_OK;
+}
+
+/**
+  * Remove the given MicroBitListener from the list of event handlers.
+  *
+  * @param listener The MicroBitListener to remove.
+  *
+  * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
+  */
+int MicroBitMessageBus::remove(MicroBitListener *listener)
+{
+	MicroBitListener *l;
+    int removed = 0;
+
+	//handler can't be NULL!
+	if (listener == NULL)
+		return MICROBIT_INVALID_PARAMETER;
+
+	l = listeners;
+
+    // Walk this list of event handlers. Delete any that match the given listener.
+    while (l != NULL)
+    {
+        if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD))
+        {
+            if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) ||
+              ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb)))
+            {
+                if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value))
+                {
+                    // Found a match. mark this to be removed from the list.
+                    l->flags |= MESSAGE_BUS_LISTENER_DELETING;
+                    removed++;
+                }
+            }
+        }
+
+        l = l->next;
+    }
+
+    if (removed > 0)
+        return MICROBIT_OK;
+    else
+        return MICROBIT_INVALID_PARAMETER;
+}
+
+/**
+  * Returns the microBitListener with the given position in our list.
+  *
+  * @param n The position in the list to return.
+  *
+  * @return the MicroBitListener at postion n in the list, or NULL if the position is invalid.
+  */
+MicroBitListener* MicroBitMessageBus::elementAt(int n)
+{
+    MicroBitListener *l = listeners;
+
+    while (n > 0)
+    {
+        if (l == NULL)
+            return NULL;
+
+        n--;
+        l = l->next;
+    }
+
+    return l;
+}
+
+/**
+  * Destructor for MicroBitMessageBus, where we deregister this instance from the array of fiber components.
+  */
+MicroBitMessageBus::~MicroBitMessageBus()
+{
+    fiber_remove_idle_component(this);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitMultiButton.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,298 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for MicroBitMultiButton.
+  *
+  * Represents a virtual button, capable of reacting to simultaneous presses of two
+  * other buttons.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitMultiButton.h"
+
+/**
+  * Constructor.
+  *
+  * Create a representation of a virtual button, that generates events based upon the combination
+  * of two given buttons.
+  *
+  * @param button1 the unique ID of the first button to watch.
+  *
+  * @param button2 the unique ID of the second button to watch.
+  *
+  * @param id the unique EventModel id of this MicroBitMultiButton instance.
+  *
+  * @code
+  * multiButton(MICROBIT_ID_BUTTON_A, MICROBIT_ID_BUTTON_B, MICROBIT_ID_BUTTON_AB);
+  * @endcode
+  */
+MicroBitMultiButton::MicroBitMultiButton(uint16_t button1, uint16_t button2, uint16_t id)
+{
+    this->id = id;
+    this->button1 = button1;
+    this->button2 = button2;
+    this->eventConfiguration = MICROBIT_BUTTON_SIMPLE_EVENTS;
+
+    if (EventModel::defaultEventBus)
+    {
+        EventModel::defaultEventBus->listen(button1, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent,  MESSAGE_BUS_LISTENER_IMMEDIATE);
+        EventModel::defaultEventBus->listen(button2, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent,  MESSAGE_BUS_LISTENER_IMMEDIATE);
+    }
+}
+
+/**
+  * Retrieves the button id for the alternate button id given.
+  *
+  * @param b the id of the button whose state we would like to retrieve.
+  *
+  * @return the other sub button id.
+  */
+uint16_t MicroBitMultiButton::otherSubButton(uint16_t b)
+{
+    return (b == button1 ? button2 : button1);
+}
+
+/**
+  * Determines if the given button id is marked as pressed.
+  *
+  * @param button the id of the button whose state we would like to retrieve.
+  *
+  * @return 1 if pressed, 0 if not.
+  */
+int MicroBitMultiButton::isSubButtonPressed(uint16_t button)
+{
+    if (button == button1)
+        return status & MICROBIT_MULTI_BUTTON_STATE_1;
+
+    if (button == button2)
+        return status & MICROBIT_MULTI_BUTTON_STATE_2;
+
+    return 0;
+}
+
+/**
+  * Determines if the given button id is marked as held.
+  *
+  * @param button the id of the button whose state we would like to retrieve.
+  *
+  * @return 1 if held, 0 if not.
+  */
+int MicroBitMultiButton::isSubButtonHeld(uint16_t button)
+{
+    if (button == button1)
+        return status & MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1;
+
+    if (button == button2)
+        return status & MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_2;
+
+    return 0;
+}
+
+/**
+  * Determines if the given button id is marked as supressed.
+  *
+  * @param button the id of the button whose state we would like to retrieve.
+  *
+  * @return 1 if supressed, 0 if not.
+  */
+int MicroBitMultiButton::isSubButtonSupressed(uint16_t button)
+{
+    if (button == button1)
+        return status & MICROBIT_MULTI_BUTTON_SUPRESSED_1;
+
+    if (button == button2)
+        return status & MICROBIT_MULTI_BUTTON_SUPRESSED_2;
+
+    return 0;
+}
+
+/**
+  * Configures the button pressed state for the given button id.
+  *
+  * @param button the id of the button whose state requires updating.
+  *
+  * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1).
+  */
+void MicroBitMultiButton::setButtonState(uint16_t button, int value)
+{
+    if (button == button1)
+    {
+        if (value)
+            status |= MICROBIT_MULTI_BUTTON_STATE_1;
+        else
+            status &= ~MICROBIT_MULTI_BUTTON_STATE_1;
+    }
+
+    if (button == button2)
+    {
+        if (value)
+            status |= MICROBIT_MULTI_BUTTON_STATE_2;
+        else
+            status &= ~MICROBIT_MULTI_BUTTON_STATE_2;
+    }
+}
+
+/**
+  * Configures the button held state for the given button id.
+  *
+  * @param button the id of the button whose state requires updating.
+  *
+  * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1).
+  */
+void MicroBitMultiButton::setHoldState(uint16_t button, int value)
+{
+    if (button == button1)
+    {
+        if (value)
+            status |= MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1;
+        else
+            status &= ~MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1;
+    }
+
+    if (button == button2)
+    {
+        if (value)
+            status |= MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_2;
+        else
+            status &= ~MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_2;
+    }
+}
+
+/**
+  * Configures the button suppressed state for the given button id.
+  *
+  * @param button the id of the button whose state requires updating.
+  *
+  * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1).
+  */
+void MicroBitMultiButton::setSupressedState(uint16_t button, int value)
+{
+    if (button == button1)
+    {
+        if (value)
+            status |= MICROBIT_MULTI_BUTTON_SUPRESSED_1;
+        else
+            status &= ~MICROBIT_MULTI_BUTTON_SUPRESSED_1;
+    }
+
+    if (button == button2)
+    {
+        if (value)
+            status |= MICROBIT_MULTI_BUTTON_SUPRESSED_2;
+        else
+            status &= ~MICROBIT_MULTI_BUTTON_SUPRESSED_2;
+    }
+}
+
+/**
+  * Changes the event configuration of this button to the given MicroBitButtonEventConfiguration.
+  * All subsequent events generated by this button will then be informed by this configuraiton.
+  *
+  * @param config The new configuration for this button. Legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS.
+  *
+  * @code
+  * // Configure a button to generate all possible events.
+  * buttonAB.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS);
+  *
+  * // Configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events.
+  * buttonAB.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS);
+  * @endcode
+  */
+void MicroBitMultiButton::setEventConfiguration(MicroBitButtonEventConfiguration config)
+{
+    this->eventConfiguration = config;
+}
+
+/**
+  * A member function that is invoked when any event is detected from the two
+  * button IDs this MicrobitMultiButton instance was constructed with.
+  *
+  * @param evt the event received from the default EventModel.
+  */
+void MicroBitMultiButton::onButtonEvent(MicroBitEvent evt)
+{
+    int button = evt.source;
+    int otherButton = otherSubButton(button);
+
+    switch(evt.value)
+    {
+        case MICROBIT_BUTTON_EVT_DOWN:
+            setButtonState(button, 1);
+            if(isSubButtonPressed(otherButton))
+                MicroBitEvent e(id, MICROBIT_BUTTON_EVT_DOWN);
+
+        break;
+
+        case MICROBIT_BUTTON_EVT_HOLD:
+            setHoldState(button, 1);
+            if(isSubButtonHeld(otherButton))
+                MicroBitEvent e(id, MICROBIT_BUTTON_EVT_HOLD);
+
+        break;
+
+        case MICROBIT_BUTTON_EVT_UP:
+            if(isSubButtonPressed(otherButton))
+            {
+                MicroBitEvent e(id, MICROBIT_BUTTON_EVT_UP);
+
+                if (isSubButtonHeld(button) && isSubButtonHeld(otherButton))
+                    MicroBitEvent e(id, MICROBIT_BUTTON_EVT_LONG_CLICK);
+                else
+                    MicroBitEvent e(id, MICROBIT_BUTTON_EVT_CLICK);
+
+                setSupressedState(otherButton, 1);
+            }
+            else if (!isSubButtonSupressed(button) && eventConfiguration == MICROBIT_BUTTON_ALL_EVENTS)
+            {
+                if (isSubButtonHeld(button))
+                    MicroBitEvent e(button, MICROBIT_BUTTON_EVT_LONG_CLICK);
+                else
+                    MicroBitEvent e(button, MICROBIT_BUTTON_EVT_CLICK);
+            }
+
+            setButtonState(button, 0);
+            setHoldState(button, 0);
+            setSupressedState(button, 0);
+
+        break;
+
+    }
+}
+
+
+/**
+  * Tests if this MicroBitMultiButton instance is virtually pressed.
+  *
+  * @return 1 if both physical buttons are pressed simultaneously.
+  *
+  * @code
+  * if(buttonAB.isPressed())
+  *     display.scroll("Pressed!");
+  * @endcode
+  */
+int MicroBitMultiButton::isPressed()
+{
+    return ((status & MICROBIT_MULTI_BUTTON_STATE_1) && (status & MICROBIT_MULTI_BUTTON_STATE_2));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitPin.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,432 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for MicroBitPin.
+  *
+  * Commonly represents an I/O pin on the edge connector.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitPin.h"
+#include "MicroBitButton.h"
+#include "DynamicPwm.h"
+#include "ErrorNo.h"
+
+/**
+  * Constructor.
+  * Create a MicroBitPin instance, generally used to represent a pin on the edge connector.
+  *
+  * @param id the unique EventModel id of this component.
+  *
+  * @param name the mbed PinName for this MicroBitPin instance.
+  *
+  * @param capability the capabilities this MicroBitPin instance should have.
+  *                   (PIN_CAPABILITY_DIGITAL, PIN_CAPABILITY_ANALOG, PIN_CAPABILITY_TOUCH, PIN_CAPABILITY_AD, PIN_CAPABILITY_ALL)
+  *
+  * @code
+  * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL);
+  * @endcode
+  */
+MicroBitPin::MicroBitPin(int id, PinName name, PinCapability capability)
+{
+    //set mandatory attributes
+    this->id = id;
+    this->name = name;
+    this->capability = capability;
+
+    // Power up in a disconnected, low power state.
+    // If we're unused, this is how it will stay...
+    this->status = 0x00;
+    this->pin = NULL;
+
+}
+
+/**
+  * Disconnect any attached mBed IO from this pin.
+  *
+  * Used only when pin changes mode (i.e. Input/Output/Analog/Digital)
+  */
+void MicroBitPin::disconnect()
+{
+    // This is a bit ugly, but rarely used code.
+    // It would be much better to use some polymorphism here, but the mBed I/O classes aren't arranged in an inheritance hierarchy... yet. :-)
+    if (status & IO_STATUS_DIGITAL_IN)
+        delete ((DigitalIn *)pin);
+
+    if (status & IO_STATUS_DIGITAL_OUT)
+        delete ((DigitalOut *)pin);
+
+    if (status & IO_STATUS_ANALOG_IN){
+        NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled; // forcibly disable the ADC - BUG in mbed....
+        delete ((AnalogIn *)pin);
+    }
+
+    if (status & IO_STATUS_ANALOG_OUT)
+    {
+        if(((DynamicPwm *)pin)->getPinName() == name)
+            ((DynamicPwm *)pin)->release();
+    }
+
+    if (status & IO_STATUS_TOUCH_IN)
+        delete ((MicroBitButton *)pin);
+
+    this->pin = NULL;
+    this->status = status & IO_STATUS_EVENTBUS_ENABLED; //retain event bus status
+}
+
+/**
+  * Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'.
+  *
+  * @param value 0 (LO) or 1 (HI)
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+  *         if the given pin does not have digital capability.
+  *
+  * @code
+  * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
+  * P0.setDigitalValue(1); // P0 is now HI
+  * @endcode
+  */
+int MicroBitPin::setDigitalValue(int value)
+{
+    // Check if this pin has a digital mode...
+    if(!(PIN_CAPABILITY_DIGITAL & capability))
+        return MICROBIT_NOT_SUPPORTED;
+
+    // Ensure we have a valid value.
+    if (value < 0 || value > 1)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Move into a Digital input state if necessary.
+    if (!(status & IO_STATUS_DIGITAL_OUT)){
+        disconnect();
+        pin = new DigitalOut(name);
+        status |= IO_STATUS_DIGITAL_OUT;
+    }
+
+    // Write the value.
+    ((DigitalOut *)pin)->write(value);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures this IO pin as a digital input (if necessary) and tests its current value.
+  *
+  * @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED
+  *         if the given pin does not have analog capability.
+  *
+  * @code
+  * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
+  * P0.getDigitalValue(); // P0 is either 0 or 1;
+  * @endcode
+  */
+int MicroBitPin::getDigitalValue()
+{
+    //check if this pin has a digital mode...
+    if(!(PIN_CAPABILITY_DIGITAL & capability))
+        return MICROBIT_NOT_SUPPORTED;
+
+    // Move into a Digital input state if necessary.
+    if (!(status & IO_STATUS_DIGITAL_IN)){
+        disconnect();
+        pin = new DigitalIn(name,PullDown);
+        status |= IO_STATUS_DIGITAL_IN;
+    }
+
+    return ((DigitalIn *)pin)->read();
+}
+
+int MicroBitPin::obtainAnalogChannel()
+{
+    // Move into an analogue input state if necessary, if we are no longer the focus of a DynamicPWM instance, allocate ourselves again!
+    if (!(status & IO_STATUS_ANALOG_OUT) || !(((DynamicPwm *)pin)->getPinName() == name)){
+        disconnect();
+        pin = (void *)DynamicPwm::allocate(name);
+        status |= IO_STATUS_ANALOG_OUT;
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures this IO pin as an analog/pwm output, and change the output value to the given level.
+  *
+  * @param value the level to set on the output pin, in the range 0 - 1024
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+  *         if the given pin does not have analog capability.
+  */
+int MicroBitPin::setAnalogValue(int value)
+{
+    //check if this pin has an analogue mode...
+    if(!(PIN_CAPABILITY_ANALOG & capability))
+        return MICROBIT_NOT_SUPPORTED;
+
+    //sanitise the level value
+    if(value < 0 || value > MICROBIT_PIN_MAX_OUTPUT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    float level = (float)value / float(MICROBIT_PIN_MAX_OUTPUT);
+
+    //obtain use of the DynamicPwm instance, if it has changed / configure if we do not have one
+    if(obtainAnalogChannel() == MICROBIT_OK)
+        return ((DynamicPwm *)pin)->write(level);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures this IO pin as an analog/pwm output (if necessary) and configures the period to be 20ms,
+  * with a duty cycle between 500 us and 2500 us.
+  *
+  * A value of 180 sets the duty cycle to be 2500us, and a value of 0 sets the duty cycle to be 500us by default.
+  *
+  * This range can be modified to fine tune, and also tolerate different servos.
+  *
+  * @param value the level to set on the output pin, in the range 0 - 180.
+  *
+  * @param range which gives the span of possible values the i.e. the lower and upper bounds (center +/- range/2). Defaults to MICROBIT_PIN_DEFAULT_SERVO_RANGE.
+  *
+  * @param center the center point from which to calculate the lower and upper bounds. Defaults to MICROBIT_PIN_DEFAULT_SERVO_CENTER
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+  *         if the given pin does not have analog capability.
+  */
+int MicroBitPin::setServoValue(int value, int range, int center)
+{
+    //check if this pin has an analogue mode...
+    if(!(PIN_CAPABILITY_ANALOG & capability))
+        return MICROBIT_NOT_SUPPORTED;
+
+    //sanitise the servo level
+    if(value < 0 || range < 1 || center < 1)
+        return MICROBIT_INVALID_PARAMETER;
+
+    //clip - just in case
+    if(value > MICROBIT_PIN_MAX_SERVO_RANGE)
+        value = MICROBIT_PIN_MAX_SERVO_RANGE;
+
+    //calculate the lower bound based on the midpoint
+    int lower = (center - (range / 2)) * 1000;
+
+    value = value * 1000;
+
+    //add the percentage of the range based on the value between 0 and 180
+    int scaled = lower + (range * (value / MICROBIT_PIN_MAX_SERVO_RANGE));
+
+    return setServoPulseUs(scaled / 1000);
+}
+
+/**
+  * Configures this IO pin as an analogue input (if necessary), and samples the Pin for its analog value.
+  *
+  * @return the current analogue level on the pin, in the range 0 - 1024, or
+  *         MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
+  *
+  * @code
+  * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
+  * P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024
+  * @endcode
+  */
+int MicroBitPin::getAnalogValue()
+{
+    //check if this pin has an analogue mode...
+    if(!(PIN_CAPABILITY_ANALOG & capability))
+        return MICROBIT_NOT_SUPPORTED;
+
+    // Move into an analogue input state if necessary.
+    if (!(status & IO_STATUS_ANALOG_IN)){
+        disconnect();
+        pin = new AnalogIn(name);
+        status |= IO_STATUS_ANALOG_IN;
+    }
+
+    //perform a read!
+    return ((AnalogIn *)pin)->read_u16();
+}
+
+/**
+  * Determines if this IO pin is currently configured as an input.
+  *
+  * @return 1 if pin is an analog or digital input, 0 otherwise.
+  */
+int MicroBitPin::isInput()
+{
+    return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_ANALOG_IN)) == 0 ? 0 : 1;
+}
+
+/**
+  * Determines if this IO pin is currently configured as an output.
+  *
+  * @return 1 if pin is an analog or digital output, 0 otherwise.
+  */
+int MicroBitPin::isOutput()
+{
+    return (status & (IO_STATUS_DIGITAL_OUT | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1;
+}
+
+/**
+  * Determines if this IO pin is currently configured for digital use.
+  *
+  * @return 1 if pin is digital, 0 otherwise.
+  */
+int MicroBitPin::isDigital()
+{
+    return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_DIGITAL_OUT)) == 0 ? 0 : 1;
+}
+
+/**
+  * Determines if this IO pin is currently configured for analog use.
+  *
+  * @return 1 if pin is analog, 0 otherwise.
+  */
+int MicroBitPin::isAnalog()
+{
+    return (status & (IO_STATUS_ANALOG_IN | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1;
+}
+
+/**
+  * Configures this IO pin as a "makey makey" style touch sensor (if necessary)
+  * and tests its current debounced state.
+  *
+  * Users can also subscribe to MicroBitButton events generated from this pin.
+  *
+  * @return 1 if pin is touched, 0 if not, or MICROBIT_NOT_SUPPORTED if this pin does not support touch capability.
+  *
+  * @code
+  * MicroBitMessageBus bus;
+  *
+  * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL);
+  * if(P0.isTouched())
+  * {
+  *     //do something!
+  * }
+  *
+  * // subscribe to events generated by this pin!
+  * bus.listen(MICROBIT_ID_IO_P0, MICROBIT_BUTTON_EVT_CLICK, someFunction);
+  * @endcode
+  */
+int MicroBitPin::isTouched()
+{
+    //check if this pin has a touch mode...
+    if(!(PIN_CAPABILITY_TOUCH & capability))
+        return MICROBIT_NOT_SUPPORTED;
+
+    // Move into a touch input state if necessary.
+    if (!(status & IO_STATUS_TOUCH_IN)){
+        disconnect();
+        pin = new MicroBitButton(name, id);
+        status |= IO_STATUS_TOUCH_IN;
+    }
+
+    return ((MicroBitButton *)pin)->isPressed();
+}
+
+/**
+  * Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms,
+  * and sets the pulse width, based on the value it is given.
+  *
+  * @param pulseWidth the desired pulse width in microseconds.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
+  *         if the given pin does not have analog capability.
+  */
+int MicroBitPin::setServoPulseUs(int pulseWidth)
+{
+    //check if this pin has an analogue mode...
+    if(!(PIN_CAPABILITY_ANALOG & capability))
+        return MICROBIT_NOT_SUPPORTED;
+
+    //sanitise the pulse width
+    if(pulseWidth < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    //Check we still have the control over the DynamicPwm instance
+    if(obtainAnalogChannel() == MICROBIT_OK)
+    {
+        //check if the period is set to 20ms
+        if(((DynamicPwm *)pin)->getPeriodUs() != MICROBIT_DEFAULT_PWM_PERIOD)
+            ((DynamicPwm *)pin)->setPeriodUs(MICROBIT_DEFAULT_PWM_PERIOD);
+
+        ((DynamicPwm *)pin)->pulsewidth_us(pulseWidth);
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures the PWM period of the analog output to the given value.
+  *
+  * @param period The new period for the analog output in microseconds.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
+  *         given pin is not configured as an analog output.
+  */
+int MicroBitPin::setAnalogPeriodUs(int period)
+{
+    if (!(status & IO_STATUS_ANALOG_OUT))
+        return MICROBIT_NOT_SUPPORTED;
+
+    return ((DynamicPwm *)pin)->setPeriodUs(period);
+}
+
+/**
+  * Configures the PWM period of the analog output to the given value.
+  *
+  * @param period The new period for the analog output in milliseconds.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
+  *         given pin is not configured as an analog output.
+  */
+int MicroBitPin::setAnalogPeriod(int period)
+{
+    return setAnalogPeriodUs(period*1000);
+}
+
+/**
+  * Obtains the PWM period of the analog output in microseconds.
+  *
+  * @return the period on success, or MICROBIT_NOT_SUPPORTED if the
+  *         given pin is not configured as an analog output.
+  */
+int MicroBitPin::getAnalogPeriodUs()
+{
+    if (!(status & IO_STATUS_ANALOG_OUT))
+        return MICROBIT_NOT_SUPPORTED;
+
+    return ((DynamicPwm *)pin)->getPeriodUs();
+}
+
+/**
+  * Obtains the PWM period of the analog output in milliseconds.
+  *
+  * @return the period on success, or MICROBIT_NOT_SUPPORTED if the
+  *         given pin is not configured as an analog output.
+  */
+int MicroBitPin::getAnalogPeriod()
+{
+    return getAnalogPeriodUs()/1000;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitRadio.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,512 @@
+/*
+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 "MicroBitRadio.h"
+#include "MicroBitComponent.h"
+#include "EventModel.h"
+#include "MicroBitDevice.h"
+#include "ErrorNo.h"
+#include "MicroBitFiber.h"
+#include "MicroBitBLEManager.h"
+
+/**
+  * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
+  *
+  * The nrf51822 RADIO module supports a number of proprietary modes of operation oher than the typical BLE usage.
+  * This class uses one of these modes to enable simple, point to multipoint communication directly between micro:bits.
+  *
+  * TODO: The protocols implemented here do not currently perform any significant form of energy management,
+  * which means that they will consume far more energy than their BLE equivalent. Later versions of the protocol
+  * should look to address this through energy efficient broadcast techbiques / sleep scheduling. In particular, the GLOSSY
+  * approach to efficient rebroadcast and network synchronisation would likely provide an effective future step.
+  *
+  * TODO: Meshing should also be considered - again a GLOSSY approach may be effective here, and highly complementary to
+  * the master/slave arachitecture of BLE.
+  *
+  * TODO: This implementation may only operated whilst the BLE stack is disabled. The nrf51822 provides a timeslot API to allow
+  * BLE to cohabit with other protocols. Future work to allow this colocation would be benefical, and would also allow for the
+  * creation of wireless BLE bridges.
+  *
+  * NOTE: This API does not contain any form of encryption, authentication or authorisation. Its purpose is solely for use as a
+  * teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place.
+  * For serious applications, BLE should be considered a substantially more secure alternative.
+  */
+
+MicroBitRadio* MicroBitRadio::instance = NULL;
+
+extern "C" void RADIO_IRQHandler(void)
+{
+    // Move on to the next buffer, if possible.
+    MicroBitRadio::instance->queueRxBuf();
+    NRF_RADIO->PACKETPTR = (uint32_t) MicroBitRadio::instance->getRxBuf();
+
+    if(NRF_RADIO->EVENTS_READY)
+    {
+        NRF_RADIO->EVENTS_READY = 0;
+
+        // Start listening and wait for the END event
+        NRF_RADIO->TASKS_START = 1;
+    }
+
+    if(NRF_RADIO->EVENTS_END)
+    {
+        NRF_RADIO->EVENTS_END = 0;
+
+        if(NRF_RADIO->CRCSTATUS == 1)
+        {
+            uint8_t sample = NRF_RADIO->RSSISAMPLE;
+
+            MicroBitRadio::instance->setRSSI(sample);
+        }
+
+        // Start listening and wait for the END event
+        NRF_RADIO->TASKS_START = 1;
+    }
+}
+
+/**
+  * Constructor.
+  *
+  * Initialise the MicroBitRadio.
+  *
+  * @note This class is demand activated, as a result most resources are only
+  *       committed if send/recv or event registrations calls are made.
+  */
+MicroBitRadio::MicroBitRadio(uint16_t id) : datagram(*this), event (*this)
+{
+    this->id = id;
+    this->status = 0;
+	this->group = 0;
+	this->queueDepth = 0;
+    this->rssi = 0;
+    this->rxQueue = NULL;
+    this->rxBuf = NULL;
+
+    instance = this;
+}
+
+/**
+  * Change the output power level of the transmitter to the given value.
+  *
+  * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range.
+  */
+int MicroBitRadio::setTransmitPower(int power)
+{
+    if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS)
+        return MICROBIT_INVALID_PARAMETER;
+
+    NRF_RADIO->TXPOWER = (uint32_t)MICROBIT_BLE_POWER_LEVEL[power];
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Change the transmission and reception band of the radio to the given channel
+  *
+  * @param band a frequency band in the range 0 - 100. Each step is 1MHz wide, based at 2400MHz.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range,
+  *         or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+  */
+int MicroBitRadio::setFrequencyBand(int band)
+{
+    if (ble_running())
+        return MICROBIT_NOT_SUPPORTED;
+
+    if (band < 0 || band > 100)
+        return MICROBIT_INVALID_PARAMETER;
+
+    NRF_RADIO->FREQUENCY = (uint32_t)band;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Retrieve a pointer to the currently allocated receive buffer. This is the area of memory
+  * actively being used by the radio hardware to store incoming data.
+  *
+  * @return a pointer to the current receive buffer.
+  */
+FrameBuffer* MicroBitRadio::getRxBuf()
+{
+    return rxBuf;
+}
+
+/**
+  * Attempt to queue a buffer received by the radio hardware, if sufficient space is available.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if a replacement receiver buffer
+  *         could not be allocated (either by policy or memory exhaustion).
+  */
+int MicroBitRadio::queueRxBuf()
+{
+    if (rxBuf == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if (queueDepth >= MICROBIT_RADIO_MAXIMUM_RX_BUFFERS)
+        return MICROBIT_NO_RESOURCES;
+
+    // Store the received RSSI value in the frame
+    rxBuf->rssi = getRSSI();
+
+    // Ensure that a replacement buffer is available before queuing.
+    FrameBuffer *newRxBuf = new FrameBuffer();
+
+    if (newRxBuf == NULL)
+        return MICROBIT_NO_RESOURCES;
+
+    // We add to the tail of the queue to preserve causal ordering.
+    rxBuf->next = NULL;
+
+    if (rxQueue == NULL)
+    {
+        rxQueue = rxBuf;
+    }
+    else
+    {
+        FrameBuffer *p = rxQueue;
+        while (p->next != NULL)
+            p = p->next;
+
+        p->next = rxBuf;
+    }
+
+    // Increase our received packet count
+    queueDepth++;
+
+    // Allocate a new buffer for the receiver hardware to use. the old on will be passed on to higher layer protocols/apps.
+    rxBuf = newRxBuf;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Sets the RSSI for the most recent packet.
+  *
+  * @param rssi the new rssi value.
+  *
+  * @note should only be called from RADIO_IRQHandler...
+  */
+int MicroBitRadio::setRSSI(uint8_t rssi)
+{
+    if (!(status & MICROBIT_RADIO_STATUS_INITIALISED))
+        return MICROBIT_NOT_SUPPORTED;
+
+    this->rssi = rssi;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Retrieves the current RSSI for the most recent packet.
+  *
+  * @return the most recent RSSI value or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+  */
+int MicroBitRadio::getRSSI()
+{
+    if (!(status & MICROBIT_RADIO_STATUS_INITIALISED))
+        return MICROBIT_NOT_SUPPORTED;
+
+    return this->rssi;
+}
+
+/**
+  * Initialises the radio for use as a multipoint sender/receiver
+  *
+  * @return MICROBIT_OK on success, MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+  */
+int MicroBitRadio::enable()
+{
+    // If the device is already initialised, then there's nothing to do.
+    if (status & MICROBIT_RADIO_STATUS_INITIALISED)
+        return MICROBIT_OK;
+
+    // Only attempt to enable this radio mode if BLE is disabled.
+    if (ble_running())
+        return MICROBIT_NOT_SUPPORTED;
+
+    // If this is the first time we've been enable, allocate out receive buffers.
+    if (rxBuf == NULL)
+        rxBuf = new FrameBuffer();
+
+    if (rxBuf == NULL)
+        return MICROBIT_NO_RESOURCES;
+
+    // Enable the High Frequency clock on the processor. This is a pre-requisite for
+    // the RADIO module. Without this clock, no communication is possible.
+    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
+    NRF_CLOCK->TASKS_HFCLKSTART = 1;
+    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
+
+    // Bring up the nrf51822 RADIO module in Nordic's proprietary 1MBps packet radio mode.
+    setTransmitPower(MICROBIT_RADIO_DEFAULT_TX_POWER);
+    setFrequencyBand(MICROBIT_RADIO_DEFAULT_FREQUENCY);
+
+    // Configure for 1Mbps throughput.
+    // This may sound excessive, but running a high data rates reduces the chances of collisions...
+    NRF_RADIO->MODE = RADIO_MODE_MODE_Nrf_1Mbit;
+
+    // Configure the addresses we use for this protocol. We run ANONYMOUSLY at the core.
+    // A 40 bit addresses is used. The first 32 bits match the ASCII character code for "uBit".
+    // Statistically, this provides assurance to avoid other similar 2.4GHz protocols that may be in the vicinity.
+    // We also map the assigned 8-bit GROUP id into the PREFIX field. This allows the RADIO hardware to perform
+    // address matching for us, and only generate an interrupt when a packet matching our group is received.
+    NRF_RADIO->BASE0 = MICROBIT_RADIO_BASE_ADDRESS;
+
+    // Join the default group. This will configure the remaining byte in the RADIO hardware module.
+    setGroup(MICROBIT_RADIO_DEFAULT_GROUP);
+
+    // The RADIO hardware module supports the use of multiple addresses, but as we're running anonymously, we only need one.
+    // Configure the RADIO module to use the default address (address 0) for both send and receive operations.
+    NRF_RADIO->TXADDRESS = 0;
+    NRF_RADIO->RXADDRESSES = 1;
+
+    // Packet layout configuration. The nrf51822 has a highly capable and flexible RADIO module that, in addition to transmission
+    // and reception of data, also contains a LENGTH field, two optional additional 1 byte fields (S0 and S1) and a CRC calculation.
+    // Configure the packet format for a simple 8 bit length field and no additional fields.
+    NRF_RADIO->PCNF0 = 0x00000008;
+    NRF_RADIO->PCNF1 = 0x02040000 | MICROBIT_RADIO_MAX_PACKET_SIZE;
+
+    // Most communication channels contain some form of checksum - a mathematical calculation taken based on all the data
+    // in a packet, that is also sent as part of the packet. When received, this calculation can be repeated, and the results
+    // from the sender and receiver compared. If they are different, then some corruption of the data ahas happened in transit,
+    // and we know we can't trust it. The nrf51822 RADIO uses a CRC for this - a very effective checksum calculation.
+    //
+    // Enable automatic 16bit CRC generation and checking, and configure how the CRC is calculated.
+    NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Two;
+    NRF_RADIO->CRCINIT = 0xFFFF;
+    NRF_RADIO->CRCPOLY = 0x11021;
+
+    // Set the start random value of the data whitening algorithm. This can be any non zero number.
+    NRF_RADIO->DATAWHITEIV = 0x18;
+
+    // Set up the RADIO module to read and write from our internal buffer.
+    NRF_RADIO->PACKETPTR = (uint32_t)rxBuf;
+
+    // Configure the hardware to issue an interrupt whenever a task is complete (e.g. send/receive).
+    NRF_RADIO->INTENSET = 0x00000008;
+    NVIC_ClearPendingIRQ(RADIO_IRQn);
+    NVIC_EnableIRQ(RADIO_IRQn);
+
+    NRF_RADIO->SHORTS |= RADIO_SHORTS_ADDRESS_RSSISTART_Msk;
+
+    // Start listening for the next packet
+    NRF_RADIO->EVENTS_READY = 0;
+    NRF_RADIO->TASKS_RXEN = 1;
+    while(NRF_RADIO->EVENTS_READY == 0);
+
+    NRF_RADIO->EVENTS_END = 0;
+    NRF_RADIO->TASKS_START = 1;
+
+    // register ourselves for a callback event, in order to empty the receive queue.
+    fiber_add_idle_component(this);
+
+    // Done. Record that our RADIO is configured.
+    status |= MICROBIT_RADIO_STATUS_INITIALISED;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Disables the radio for use as a multipoint sender/receiver.
+  *
+  * @return MICROBIT_OK on success, MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+  */
+int MicroBitRadio::disable()
+{
+    // Only attempt to enable.disable the radio if the protocol is alreayd running.
+    if (ble_running())
+        return MICROBIT_NOT_SUPPORTED;
+
+    if (!(status & MICROBIT_RADIO_STATUS_INITIALISED))
+        return MICROBIT_OK;
+
+    // Disable interrupts and STOP any ongoing packet reception.
+    NVIC_DisableIRQ(RADIO_IRQn);
+
+    NRF_RADIO->EVENTS_DISABLED = 0;
+    NRF_RADIO->TASKS_DISABLE = 1;
+    while(NRF_RADIO->EVENTS_DISABLED == 0);
+
+    // deregister ourselves from the callback event used to empty the receive queue.
+    fiber_remove_idle_component(this);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Sets the radio to listen to packets sent with the given group id.
+  *
+  * @param group The group to join. A micro:bit can only listen to one group ID at any time.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+  */
+int MicroBitRadio::setGroup(uint8_t group)
+{
+    if (ble_running())
+        return MICROBIT_NOT_SUPPORTED;
+
+    // Record our group id locally
+    this->group = group;
+
+    // Also append it to the address of this device, to allow the RADIO module to filter for us.
+    NRF_RADIO->PREFIX0 = (uint32_t)group;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * A background, low priority callback that is triggered whenever the processor is idle.
+  * Here, we empty our queue of received packets, and pass them onto higher level protocol handlers.
+  */
+void MicroBitRadio::idleTick()
+{
+    // Walk the list of packets and process each one.
+    while(rxQueue)
+    {
+        FrameBuffer *p = rxQueue;
+
+        switch (p->protocol)
+        {
+            case MICROBIT_RADIO_PROTOCOL_DATAGRAM:
+                datagram.packetReceived();
+                break;
+
+            case MICROBIT_RADIO_PROTOCOL_EVENTBUS:
+                event.packetReceived();
+                break;
+
+            default:
+                MicroBitEvent(MICROBIT_ID_RADIO_DATA_READY, p->protocol);
+        }
+
+        // If the packet was processed, it will have been recv'd, and taken from the queue.
+        // If this was a packet for an unknown protocol, it will still be there, so simply free it.
+        if (p == rxQueue)
+        {
+            recv();
+            delete p;
+        }
+    }
+}
+
+/**
+  * Determines the number of packets ready to be processed.
+  *
+  * @return The number of packets in the receive buffer.
+  */
+int MicroBitRadio::dataReady()
+{
+    return queueDepth;
+}
+
+/**
+  * Retrieves the next packet from the receive buffer.
+  * If a data packet is available, then it will be returned immediately to
+  * the caller. This call will also dequeue the buffer.
+  *
+  * @return The buffer containing the the packet. If no data is available, NULL is returned.
+  *
+  * @note Once recv() has been called, it is the callers resposibility to
+  *       delete the buffer when appropriate.
+  */
+FrameBuffer* MicroBitRadio::recv()
+{
+    FrameBuffer *p = rxQueue;
+
+    if (p)
+    {
+        rxQueue = rxQueue->next;
+        queueDepth--;
+    }
+
+    return p;
+}
+
+/**
+  * Transmits the given buffer onto the broadcast radio.
+  * The call will wait until the transmission of the packet has completed before returning.
+  *
+  * @param data The packet contents to transmit.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running.
+  */
+int MicroBitRadio::send(FrameBuffer *buffer)
+{
+    if (ble_running())
+        return MICROBIT_NOT_SUPPORTED;
+
+    if (buffer == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if (buffer->length > MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE - 1)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Firstly, disable the Radio interrupt. We want to wait until the trasmission completes.
+    NVIC_DisableIRQ(RADIO_IRQn);
+
+    // Turn off the transceiver.
+    NRF_RADIO->EVENTS_DISABLED = 0;
+    NRF_RADIO->TASKS_DISABLE = 1;
+    while(NRF_RADIO->EVENTS_DISABLED == 0);
+
+    // Configure the radio to send the buffer provided.
+    NRF_RADIO->PACKETPTR = (uint32_t) buffer;
+
+    // Turn on the transmitter, and wait for it to signal that it's ready to use.
+    NRF_RADIO->EVENTS_READY = 0;
+    NRF_RADIO->TASKS_TXEN = 1;
+    while (NRF_RADIO->EVENTS_READY == 0);
+
+    // Start transmission and wait for end of packet.
+    NRF_RADIO->TASKS_START = 1;
+    NRF_RADIO->EVENTS_END = 0;
+    while(NRF_RADIO->EVENTS_END == 0);
+
+    // Return the radio to using the default receive buffer
+    NRF_RADIO->PACKETPTR = (uint32_t) rxBuf;
+
+    // Turn off the transmitter.
+    NRF_RADIO->EVENTS_DISABLED = 0;
+    NRF_RADIO->TASKS_DISABLE = 1;
+    while(NRF_RADIO->EVENTS_DISABLED == 0);
+
+    // Start listening for the next packet
+    NRF_RADIO->EVENTS_READY = 0;
+    NRF_RADIO->TASKS_RXEN = 1;
+    while(NRF_RADIO->EVENTS_READY == 0);
+
+    NRF_RADIO->EVENTS_END = 0;
+    NRF_RADIO->TASKS_START = 1;
+
+    // Re-enable the Radio interrupt.
+    NVIC_ClearPendingIRQ(RADIO_IRQn);
+    NVIC_EnableIRQ(RADIO_IRQn);
+
+    return MICROBIT_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitRadioDatagram.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,203 @@
+/*
+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 "MicroBitRadio.h"
+
+/**
+  * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
+  *
+  * This class provides the ability to broadcast simple text or binary messages to other micro:bits in the vicinity
+  * It is envisaged that this would provide the basis for children to experiment with building their own, simple,
+  * custom protocols.
+  *
+  * @note This API does not contain any form of encryption, authentication or authorisation. Its purpose is solely for use as a
+  * teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place.
+  * For serious applications, BLE should be considered a substantially more secure alternative.
+  */
+
+/**
+* Constructor.
+*
+* Creates an instance of a MicroBitRadioDatagram which offers the ability
+* to broadcast simple text or binary messages to other micro:bits in the vicinity
+*
+* @param r The underlying radio module used to send and receive data.
+*/
+MicroBitRadioDatagram::MicroBitRadioDatagram(MicroBitRadio &r) : radio(r)
+{
+    this->rxQueue = NULL;
+}
+
+/**
+  * Retrieves packet payload data into the given buffer.
+  *
+  * If a data packet is already available, then it will be returned immediately to the caller.
+  * If no data is available then MICROBIT_INVALID_PARAMETER is returned.
+  *
+  * @param buf A pointer to a valid memory location where the received data is to be stored
+  *
+  * @param len The maximum amount of data that can safely be stored in 'buf'
+  *
+  * @return The length of the data stored, or MICROBIT_INVALID_PARAMETER if no data is available, or the memory regions provided are invalid.
+  */
+int MicroBitRadioDatagram::recv(uint8_t *buf, int len)
+{
+    if (buf == NULL || rxQueue == NULL || len < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Take the first buffer from the queue.
+    FrameBuffer *p = rxQueue;
+    rxQueue = rxQueue->next;
+
+    int l = min(len, p->length - (MICROBIT_RADIO_HEADER_SIZE - 1));
+
+    // Fill in the buffer provided, if possible.
+    memcpy(buf, p->payload, l);
+
+    delete p;
+    return l;
+}
+
+/**
+  * Retreives packet payload data into the given buffer.
+  *
+  * If a data packet is already available, then it will be returned immediately to the caller
+  * in the form of a PacketBuffer.
+  *
+  * @return the data received, or an empty PacketBuffer if no data is available.
+  */
+PacketBuffer MicroBitRadioDatagram::recv()
+{
+    if (rxQueue == NULL)
+        return PacketBuffer::EmptyPacket;
+
+    FrameBuffer *p = rxQueue;
+    rxQueue = rxQueue->next;
+
+    PacketBuffer packet(p->payload, p->length - (MICROBIT_RADIO_HEADER_SIZE - 1), p->rssi);
+
+    delete p;
+    return packet;
+}
+
+/**
+  * Transmits the given buffer onto the broadcast radio.
+  *
+  * This is a synchronous call that will wait until the transmission of the packet
+  * has completed before returning.
+  *
+  * @param buffer The packet contents to transmit.
+  *
+  * @param len The number of bytes to transmit.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the buffer is invalid,
+  *         or the number of bytes to transmit is greater than `MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE`.
+  */
+int MicroBitRadioDatagram::send(uint8_t *buffer, int len)
+{
+    if (buffer == NULL || len < 0 || len > MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE - 1)
+        return MICROBIT_INVALID_PARAMETER;
+
+    FrameBuffer buf;
+
+    buf.length = len + MICROBIT_RADIO_HEADER_SIZE - 1;
+    buf.version = 1;
+    buf.group = 0;
+    buf.protocol = MICROBIT_RADIO_PROTOCOL_DATAGRAM;
+    memcpy(buf.payload, buffer, len);
+
+    return radio.send(&buf);
+}
+
+/**
+  * Transmits the given string onto the broadcast radio.
+  *
+  * This is a synchronous call that will wait until the transmission of the packet
+  * has completed before returning.
+  *
+  * @param data The packet contents to transmit.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the buffer is invalid,
+  *         or the number of bytes to transmit is greater than `MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE`.
+  */
+int MicroBitRadioDatagram::send(PacketBuffer data)
+{
+    return send((uint8_t *)data.getBytes(), data.length());
+}
+
+/**
+  * Transmits the given string onto the broadcast radio.
+  *
+  * This is a synchronous call that will wait until the transmission of the packet
+  * has completed before returning.
+  *
+  * @param data The packet contents to transmit.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the buffer is invalid,
+  *         or the number of bytes to transmit is greater than `MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE`.
+  */
+int MicroBitRadioDatagram::send(ManagedString data)
+{
+    return send((uint8_t *)data.toCharArray(), data.length());
+}
+
+/**
+  * Protocol handler callback. This is called when the radio receives a packet marked as a datagram.
+  *
+  * This function process this packet, and queues it for user reception.
+  */
+void MicroBitRadioDatagram::packetReceived()
+{
+    FrameBuffer *packet = radio.recv();
+    int queueDepth = 0;
+
+    // We add to the tail of the queue to preserve causal ordering.
+    packet->next = NULL;
+
+    if (rxQueue == NULL)
+    {
+        rxQueue = packet;
+    }
+    else
+    {
+        FrameBuffer *p = rxQueue;
+        while (p->next != NULL)
+        {
+            p = p->next;
+            queueDepth++;
+        }
+
+        if (queueDepth >= MICROBIT_RADIO_MAXIMUM_RX_BUFFERS)
+        {
+            delete packet;
+            return;
+        }
+
+        p->next = packet;
+    }
+
+    MicroBitEvent(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitRadioEvent.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,175 @@
+/*
+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 "MicroBitRadio.h"
+
+/**
+ * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
+ *
+ * This class provides the ability to extend the micro:bit's default EventModel to other micro:bits in the vicinity,
+ * in a very similar way to the MicroBitEventService for BLE interfaces.
+ *
+ * It is envisaged that this would provide the basis for children to experiment with building their own, simple,
+ * custom asynchronous events and actions.
+ *
+ * @note This API does not contain any form of encryption, authentication or authorisation. Its purpose is solely for use as a
+ * teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place.
+ * For serious applications, BLE should be considered a substantially more secure alternative.
+ */
+
+/**
+  * Constructor.
+  *
+  * Creates an instance of MicroBitRadioEvent which offers the ability to extend
+  * the micro:bit's default EventModel to other micro:bits in the vicinity.
+  *
+  * @param r The underlying radio module used to send and receive data.
+  */
+MicroBitRadioEvent::MicroBitRadioEvent(MicroBitRadio &r) : radio(r)
+{
+    this->suppressForwarding = false;
+}
+
+/**
+  * Associates the given event with the radio channel.
+  *
+  * Once registered, all events matching the given registration sent to this micro:bit's
+  * default EventModel will be automatically retransmitted on the radio.
+  *
+  * @param id The id of the event to register.
+  *
+  * @param value the value of the event to register.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if no default EventModel is available.
+  *
+  * @note The wildcards MICROBIT_ID_ANY and MICROBIT_EVT_ANY can also be in place of the
+  *       id and value fields.
+  */
+int MicroBitRadioEvent::listen(uint16_t id, uint16_t value)
+{
+    if (EventModel::defaultEventBus)
+        return listen(id, value, *EventModel::defaultEventBus);
+
+    return MICROBIT_NO_RESOURCES;
+}
+
+/**
+  * Associates the given event with the radio channel.
+  *
+  * Once registered, all events matching the given registration sent to the given
+  * EventModel will be automatically retransmitted on the radio.
+  *
+  * @param id The id of the events to register.
+  *
+  * @param value the value of the event to register.
+  *
+  * @param eventBus The EventModel to listen for events on.
+  *
+  * @return MICROBIT_OK on success.
+  *
+  * @note The wildcards MICROBIT_ID_ANY and MICROBIT_EVT_ANY can also be in place of the
+  *       id and value fields.
+  */
+int MicroBitRadioEvent::listen(uint16_t id, uint16_t value, EventModel &eventBus)
+{
+    return eventBus.listen(id, value, this, &MicroBitRadioEvent::eventReceived, MESSAGE_BUS_LISTENER_IMMEDIATE);
+}
+
+/**
+  * Disassociates the given event with the radio channel.
+  *
+  * @param id The id of the events to deregister.
+  *
+  * @param value The value of the event to deregister.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the default message bus does not exist.
+  *
+  * @note MICROBIT_EVT_ANY can be used to deregister all event values matching the given id.
+  */
+int MicroBitRadioEvent::ignore(uint16_t id, uint16_t value)
+{
+    if (EventModel::defaultEventBus)
+        return ignore(id, value, *EventModel::defaultEventBus);
+
+    return MICROBIT_INVALID_PARAMETER;
+}
+
+/**
+  * Disassociates the given events with the radio channel.
+  *
+  * @param id The id of the events to deregister.
+  *
+  * @param value The value of the event to deregister.
+  *
+  * @param eventBus The EventModel to deregister on.
+  *
+  * @return MICROBIT_OK on success.
+  *
+  * @note MICROBIT_EVT_ANY can be used to deregister all event values matching the given id.
+  */
+int MicroBitRadioEvent::ignore(uint16_t id, uint16_t value, EventModel &eventBus)
+{
+    return eventBus.ignore(id, value, this, &MicroBitRadioEvent::eventReceived);
+}
+
+
+/**
+  * Protocol handler callback. This is called when the radio receives a packet marked as using the event protocol.
+  *
+  * This function process this packet, and fires the event contained inside onto the default EventModel.
+  */
+void MicroBitRadioEvent::packetReceived()
+{
+    FrameBuffer *p = radio.recv();
+    MicroBitEvent *e = (MicroBitEvent *) p->payload;
+
+    suppressForwarding = true;
+    e->fire();
+    suppressForwarding = false;
+
+    delete p;
+}
+
+/**
+  * Event handler callback. This is called whenever an event is received matching one of those registered through
+  * the registerEvent() method described above. Upon receiving such an event, it is wrapped into
+  * a radio packet and transmitted to any other micro:bits in the same group.
+  */
+void MicroBitRadioEvent::eventReceived(MicroBitEvent e)
+{
+    if(suppressForwarding)
+        return;
+
+    FrameBuffer buf;
+
+    buf.length = sizeof(MicroBitEvent) + MICROBIT_RADIO_HEADER_SIZE - 1;
+    buf.version = 1;
+    buf.group = 0;
+    buf.protocol = MICROBIT_RADIO_PROTOCOL_EVENTBUS;
+    memcpy(buf.payload, (const uint8_t *)&e, sizeof(MicroBitEvent));
+
+    radio.send(&buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitSerial.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,1099 @@
+/*
+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 "mbed.h"
+#include "MicroBitSerial.h"
+#include "ErrorNo.h"
+#include "MicroBitComponent.h"
+#include "MicroBitFiber.h"
+#include "NotifyEvents.h"
+
+uint8_t MicroBitSerial::status = 0;
+
+int MicroBitSerial::baudrate = 0;
+
+/**
+  * Constructor.
+  * Create an instance of MicroBitSerial
+  *
+  * @param tx the Pin to be used for transmission
+  *
+  * @param rx the Pin to be used for receiving data
+  *
+  * @param rxBufferSize the size of the buffer to be used for receiving bytes
+  *
+  * @param txBufferSize the size of the buffer to be used for transmitting bytes
+  *
+  * @code
+  * MicroBitSerial serial(USBTX, USBRX);
+  * @endcode
+  * @note the default baud rate is 115200. More API details can be found:
+  *       -https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/api/SerialBase.h
+  *       -https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/api/RawSerial.h
+  *
+  *       Buffers aren't allocated until the first send or receive respectively.
+  */
+MicroBitSerial::MicroBitSerial(PinName tx, PinName rx, uint8_t rxBufferSize, uint8_t txBufferSize) : RawSerial(tx,rx), delimeters()
+{
+    this->rxBuffSize = rxBufferSize;
+    this->txBuffSize = txBufferSize;
+
+    this->rxBuff = NULL;
+    this->txBuff = NULL;
+
+    this->rxBuffHead = 0;
+    this->rxBuffTail = 0;
+
+    this->txBuffHead = 0;
+    this->txBuffTail = 0;
+
+    this->rxBuffHeadMatch = -1;
+
+    this->baud(MICROBIT_SERIAL_DEFAULT_BAUD_RATE);
+
+#if CONFIG_ENABLED(MICROBIT_DBG)
+    SERIAL_DEBUG = this;
+#endif
+
+}
+
+/**
+  * An internal interrupt callback for MicroBitSerial configured for when a
+  * character is received.
+  *
+  * Each time a character is received fill our circular buffer!
+  */
+void MicroBitSerial::dataReceived()
+{
+    if(!(status & MICROBIT_SERIAL_RX_BUFF_INIT))
+        return;
+
+    //get the received character
+    char c = getc();
+
+    int delimeterOffset = 0;
+    int delimLength = this->delimeters.length();
+
+    //iterate through our delimeters (if any) to see if there is a match
+    while(delimeterOffset < delimLength)
+    {
+        //fire an event if there is to block any waiting fibers
+        if(this->delimeters.charAt(delimeterOffset) == c)
+            MicroBitEvent(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_DELIM_MATCH);
+
+        delimeterOffset++;
+    }
+
+    uint16_t newHead = (rxBuffHead + 1) % rxBuffSize;
+
+    //look ahead to our newHead value to see if we are about to collide with the tail
+    if(newHead != rxBuffTail)
+    {
+        //if we are not, store the character, and update our actual head.
+        this->rxBuff[rxBuffHead] = c;
+        rxBuffHead = newHead;
+
+        //if we have any fibers waiting for a specific number of characters, unblock them
+        if(rxBuffHeadMatch >= 0)
+            if(rxBuffHead == rxBuffHeadMatch)
+            {
+                rxBuffHeadMatch = -1;
+                MicroBitEvent(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_HEAD_MATCH);
+            }
+    }
+    else
+        //otherwise, our buffer is full, send an event to the user...
+        MicroBitEvent(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_RX_FULL);
+}
+
+/**
+  * An internal interrupt callback for MicroBitSerial.
+  *
+  * Each time the Serial module's buffer is empty, write a character if we have
+  * characters to write.
+  */
+void MicroBitSerial::dataWritten()
+{
+    if(txBuffTail == txBuffHead || !(status & MICROBIT_SERIAL_TX_BUFF_INIT))
+        return;
+
+    //send our current char
+    putc(txBuff[txBuffTail]);
+
+    uint16_t nextTail = (txBuffTail + 1) % txBuffSize;
+
+    //unblock any waiting fibers that are waiting for transmission to finish.
+    if(nextTail == txBuffHead)
+    {
+        MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_SERIAL_EVT_TX_EMPTY);
+        detach(Serial::IrqType::TxIrq);
+    }
+
+    //update our tail!
+    txBuffTail = nextTail;
+}
+
+/**
+  * An internal method to configure an interrupt on tx buffer and also
+  * a best effort copy operation to move bytes from a user buffer to our txBuff
+  *
+  * @param string a pointer to the first character of the users' buffer.
+  *
+  * @param len the length of the string, and ultimately the maximum number of bytes
+  *        that will be copied dependent on the state of txBuff
+  *
+  * @return the number of bytes copied into the buffer.
+  */
+int MicroBitSerial::setTxInterrupt(uint8_t *string, int len)
+{
+    int copiedBytes = 0;
+
+    for(copiedBytes = 0; copiedBytes < len; copiedBytes++)
+    {
+        uint16_t nextHead = (txBuffHead + 1) % txBuffSize;
+        if(nextHead != txBuffTail)
+        {
+            this->txBuff[txBuffHead] = string[copiedBytes];
+            txBuffHead = nextHead;
+        }
+        else
+            break;
+    }
+
+    fiber_wake_on_event(MICROBIT_ID_NOTIFY, MICROBIT_SERIAL_EVT_TX_EMPTY);
+
+    //set the TX interrupt
+    attach(this, &MicroBitSerial::dataWritten, Serial::IrqType::TxIrq);
+
+    return copiedBytes;
+}
+
+/**
+  * Locks the mutex so that others can't use this serial instance for reception
+  */
+void MicroBitSerial::lockRx()
+{
+    status |= MICROBIT_SERIAL_RX_IN_USE;
+}
+
+/**
+  * Locks the mutex so that others can't use this serial instance for transmission
+  */
+void MicroBitSerial::lockTx()
+{
+    status |= MICROBIT_SERIAL_TX_IN_USE;
+}
+
+/**
+  * Unlocks the mutex so that others can use this serial instance for reception
+  */
+void MicroBitSerial::unlockRx()
+{
+    status &= ~MICROBIT_SERIAL_RX_IN_USE;
+}
+
+/**
+  * Unlocks the mutex so that others can use this serial instance for transmission
+  */
+void MicroBitSerial::unlockTx()
+{
+    status &= ~MICROBIT_SERIAL_TX_IN_USE;
+}
+
+/**
+  * We do not want to always have our buffers initialised, especially if users to not
+  * use them. We only bring them up on demand.
+  */
+int MicroBitSerial::initialiseRx()
+{
+    if((status & MICROBIT_SERIAL_RX_BUFF_INIT))
+    {
+        //ensure that we receive no interrupts after freeing our buffer
+        detach(Serial::IrqType::RxIrq);
+        free(this->rxBuff);
+    }
+
+    status &= ~MICROBIT_SERIAL_RX_BUFF_INIT;
+
+    if((this->rxBuff = (uint8_t *)malloc(rxBuffSize)) == NULL)
+        return MICROBIT_NO_RESOURCES;
+
+    this->rxBuffHead = 0;
+    this->rxBuffTail = 0;
+
+    //set the receive interrupt
+    status |= MICROBIT_SERIAL_RX_BUFF_INIT;
+    attach(this, &MicroBitSerial::dataReceived, Serial::IrqType::RxIrq);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * We do not want to always have our buffers initialised, especially if users to not
+  * use them. We only bring them up on demand.
+  */
+int MicroBitSerial::initialiseTx()
+{
+    if((status & MICROBIT_SERIAL_TX_BUFF_INIT))
+    {
+        //ensure that we receive no interrupts after freeing our buffer
+        detach(Serial::IrqType::TxIrq);
+        free(this->txBuff);
+    }
+
+    status &= ~MICROBIT_SERIAL_TX_BUFF_INIT;
+
+    if((this->txBuff = (uint8_t *)malloc(txBuffSize)) == NULL)
+        return MICROBIT_NO_RESOURCES;
+
+    this->txBuffHead = 0;
+    this->txBuffTail = 0;
+
+    status |= MICROBIT_SERIAL_TX_BUFF_INIT;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * An internal method that either spin waits if mode is set to SYNC_SPINWAIT
+  * or puts the fiber to sleep if the mode is set to SYNC_SLEEP
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP
+  */
+void MicroBitSerial::send(MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        while(txBufferedSize() > 0);
+
+    if(mode == SYNC_SLEEP)
+        fiber_sleep(0);
+}
+
+/**
+  * Reads a single character from the rxBuff
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - A character is read from the rxBuff if available, if there
+  *                    are no characters to be read, a value of zero is returned immediately.
+  *
+  *            SYNC_SPINWAIT - A character is read from the rxBuff if available, if there
+  *                            are no characters to be read, this method will spin
+  *                            (lock up the processor) until a character is available.
+  *
+  *            SYNC_SLEEP - A character is read from the rxBuff if available, if there
+  *                         are no characters to be read, the calling fiber sleeps
+  *                         until there is a character available.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return a character from the circular buffer, or MICROBIT_NO_DATA is there
+  *         are no characters in the buffer.
+  */
+int MicroBitSerial::getChar(MicroBitSerialMode mode)
+{
+    if(mode == ASYNC)
+    {
+        if(!isReadable())
+            return MICROBIT_NO_DATA;
+    }
+
+    if(mode == SYNC_SPINWAIT)
+        while(!isReadable());
+
+    if(mode == SYNC_SLEEP)
+    {
+        if(!isReadable())
+            eventAfter(1, mode);
+    }
+
+    char c = rxBuff[rxBuffTail];
+
+    rxBuffTail = (rxBuffTail + 1) % rxBuffSize;
+
+    return c;
+}
+
+/**
+  * An internal method that copies values from a circular buffer to a linear buffer.
+  *
+  * @param circularBuff a pointer to the source circular buffer
+  *
+  * @param circularBuffSize the size of the circular buffer
+  *
+  * @param linearBuff a pointer to the destination linear buffer
+  *
+  * @param tailPosition the tail position in the circular buffer you want to copy from
+  *
+  * @param headPosition the head position in the circular buffer you want to copy to
+  *
+  * @note this method assumes that the linear buffer has the appropriate amount of
+  *       memory to contain the copy operation
+  */
+void MicroBitSerial::circularCopy(uint8_t *circularBuff, uint8_t circularBuffSize, uint8_t *linearBuff, uint16_t tailPosition, uint16_t headPosition)
+{
+    int toBuffIndex = 0;
+
+    while(tailPosition != headPosition)
+    {
+        linearBuff[toBuffIndex++] = circularBuff[tailPosition];
+
+        tailPosition = (tailPosition + 1) % circularBuffSize;
+    }
+}
+
+/**
+  * Sends a single character over the serial line.
+  *
+  * @param c the character to send
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - the character is copied into the txBuff and returns immediately.
+  *
+  *            SYNC_SPINWAIT - the character is copied into the txBuff and this method
+  *                            will spin (lock up the processor) until the character has
+  *                            been sent.
+  *
+  *            SYNC_SLEEP - the character is copied into the txBuff and the fiber sleeps
+  *                         until the character has been sent. This allows other fibers
+  *                         to continue execution.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return the number of bytes written, or MICROBIT_SERIAL_IN_USE if another fiber
+  *         is using the serial instance for transmission.
+  */
+int MicroBitSerial::sendChar(char c, MicroBitSerialMode mode)
+{
+    if(txInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockTx();
+
+    //lazy initialisation of our tx buffer
+    if(!(status & MICROBIT_SERIAL_TX_BUFF_INIT))
+    {
+        int result = initialiseTx();
+
+        if(result != MICROBIT_OK)
+            return result;
+    }
+
+    uint8_t toTransmit[2] =  { c, '\0'};
+
+    int bytesWritten = setTxInterrupt(toTransmit, 1);
+
+    send(mode);
+
+    unlockTx();
+
+    return bytesWritten;
+}
+
+/**
+  * Sends a ManagedString over the serial line.
+  *
+  * @param s the string to send
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - bytes are copied into the txBuff and returns immediately.
+  *
+  *            SYNC_SPINWAIT - bytes are copied into the txBuff and this method
+  *                            will spin (lock up the processor) until all bytes
+  *                            have been sent.
+  *
+  *            SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps
+  *                         until all bytes have been sent. This allows other fibers
+  *                         to continue execution.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return the number of bytes written, or MICROBIT_SERIAL_IN_USE if another fiber
+  *         is using the serial instance for transmission.
+  */
+int MicroBitSerial::send(ManagedString s, MicroBitSerialMode mode)
+{
+    return send((uint8_t *)s.toCharArray(), s.length(), mode);
+}
+
+/**
+  * Sends a buffer of known length over the serial line.
+  *
+  * @param buffer a pointer to the first character of the buffer
+  *
+  * @param len the number of bytes that are safely available to read.
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - bytes are copied into the txBuff and returns immediately.
+  *
+  *            SYNC_SPINWAIT - bytes are copied into the txBuff and this method
+  *                            will spin (lock up the processor) until all bytes
+  *                            have been sent.
+  *
+  *            SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps
+  *                         until all bytes have been sent. This allows other fibers
+  *                         to continue execution.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return the number of bytes written, or MICROBIT_SERIAL_IN_USE if another fiber
+  *         is using the serial instance for transmission.
+  */
+int MicroBitSerial::send(uint8_t *buffer, int bufferLen, MicroBitSerialMode mode)
+{
+    if(txInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockTx();
+
+    //lazy initialisation of our tx buffer
+    if(!(status & MICROBIT_SERIAL_TX_BUFF_INIT))
+    {
+        int result = initialiseTx();
+
+        if(result != MICROBIT_OK)
+            return result;
+    }
+
+    int bytesWritten = setTxInterrupt(buffer, bufferLen);
+
+    send(mode);
+
+    unlockTx();
+
+    return bytesWritten;
+}
+
+/**
+  * Reads a single character from the rxBuff
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - A character is read from the rxBuff if available, if there
+  *                    are no characters to be read, a value of MICROBIT_NO_DATA is returned immediately.
+  *
+  *            SYNC_SPINWAIT - A character is read from the rxBuff if available, if there
+  *                            are no characters to be read, this method will spin
+  *                            (lock up the processor) until a character is available.
+  *
+  *            SYNC_SLEEP - A character is read from the rxBuff if available, if there
+  *                         are no characters to be read, the calling fiber sleeps
+  *                         until there is a character available.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return a character, MICROBIT_SERIAL_IN_USE if another fiber is using the serial instance for reception,
+  *         MICROBIT_NO_RESOURCES if buffer allocation did not complete successfully, or MICROBIT_NO_DATA if
+  *         the rx buffer is empty and the mode given is ASYNC.
+  */
+int MicroBitSerial::read(MicroBitSerialMode mode)
+{
+    if(rxInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockRx();
+
+    //lazy initialisation of our buffers
+    if(!(status & MICROBIT_SERIAL_RX_BUFF_INIT))
+    {
+        int result = initialiseRx();
+
+        if(result != MICROBIT_OK)
+            return result;
+    }
+
+    char c = (char)getChar(mode);
+
+    unlockRx();
+
+    return c;
+}
+
+/**
+  * Reads multiple characters from the rxBuff and returns them as a ManagedString
+  *
+  * @param size the number of characters to read.
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - If the desired number of characters are available, this will return
+  *                    a ManagedString with the expected size. Otherwise, it will read however
+  *                    many characters there are available.
+  *
+  *            SYNC_SPINWAIT - If the desired number of characters are available, this will return
+  *                            a ManagedString with the expected size. Otherwise, this method will spin
+  *                            (lock up the processor) until the desired number of characters have been read.
+  *
+  *            SYNC_SLEEP - If the desired number of characters are available, this will return
+  *                         a ManagedString with the expected size. Otherwise, the calling fiber sleeps
+  *                         until the desired number of characters have been read.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return A ManagedString, or an empty ManagedString if an error was encountered during the read.
+  */
+ManagedString MicroBitSerial::read(int size, MicroBitSerialMode mode)
+{
+    uint8_t buff[size + 1] = { 0 };
+
+    int returnedSize = read((uint8_t *)buff, size, mode);
+
+    if(returnedSize <= 0)
+        return ManagedString();
+
+    return ManagedString((char *)buff, returnedSize);
+}
+
+/**
+  * Reads multiple characters from the rxBuff and fills a user buffer.
+  *
+  * @param buffer a pointer to a user allocated buffer.
+  *
+  * @param bufferLen the amount of data that can be safely stored
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - If the desired number of characters are available, this will fill
+  *                    the given buffer. Otherwise, it will fill the buffer with however
+  *                    many characters there are available.
+  *
+  *            SYNC_SPINWAIT - If the desired number of characters are available, this will fill
+  *                            the given buffer. Otherwise, this method will spin (lock up the processor)
+  *                            and fill the buffer until the desired number of characters have been read.
+  *
+  *            SYNC_SLEEP - If the desired number of characters are available, this will fill
+  *                         the given buffer. Otherwise, the calling fiber sleeps
+  *                         until the desired number of characters have been read.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return the number of characters read, or MICROBIT_SERIAL_IN_USE if another fiber
+  *         is using the instance for receiving.
+  */
+int MicroBitSerial::read(uint8_t *buffer, int bufferLen, MicroBitSerialMode mode)
+{
+    if(rxInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockRx();
+
+    //lazy initialisation of our rx buffer
+    if(!(status & MICROBIT_SERIAL_RX_BUFF_INIT))
+    {
+        int result = initialiseRx();
+
+        if(result != MICROBIT_OK)
+            return result;
+    }
+
+    int bufferIndex = 0;
+
+    int temp = 0;
+
+    if(mode == ASYNC)
+    {
+        while((temp = getChar(mode)) != MICROBIT_NO_DATA && bufferIndex < bufferLen)
+        {
+            buffer[bufferIndex] = (char)temp;
+            bufferIndex++;
+        }
+    }
+
+    if(mode == SYNC_SPINWAIT)
+    {
+        while(bufferIndex < bufferLen)
+        {
+            buffer[bufferIndex] = (char)getChar(mode);
+            bufferIndex++;
+        }
+    }
+
+    if(mode == SYNC_SLEEP)
+    {
+        if(bufferLen > rxBufferedSize())
+            eventAfter(bufferLen - rxBufferedSize(), mode);
+
+        while(bufferIndex < bufferLen)
+        {
+            buffer[bufferIndex] = (char)getChar(mode);
+            bufferIndex++;
+        }
+    }
+
+    unlockRx();
+
+    return bufferIndex;
+}
+
+
+/**
+  * Reads until one of the delimeters matches a character in the rxBuff
+  *
+  * @param delimeters a ManagedString containing a sequence of delimeter characters e.g. ManagedString("\r\n")
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - If one of the delimeters matches a character already in the rxBuff
+  *                    this method will return a ManagedString up to the delimeter.
+  *                    Otherwise, it will return an Empty ManagedString.
+  *
+  *            SYNC_SPINWAIT - If one of the delimeters matches a character already in the rxBuff
+  *                            this method will return a ManagedString up to the delimeter.
+  *                            Otherwise, this method will spin (lock up the processor) until a
+  *                            received character matches one of the delimeters.
+  *
+  *            SYNC_SLEEP - If one of the delimeters matches a character already in the rxBuff
+  *                         this method will return a ManagedString up to the delimeter.
+  *                         Otherwise, the calling fiber sleeps until a character matching one
+  *                         of the delimeters is seen.
+  *
+  *         Defaults to SYNC_SLEEP.
+  *
+  * @return A ManagedString containing the characters up to a delimeter, or an Empty ManagedString,
+  *         if another fiber is currently using this instance for reception.
+  *
+  * @note delimeters are matched on a per byte basis.
+  */
+ManagedString MicroBitSerial::readUntil(ManagedString delimeters, MicroBitSerialMode mode)
+{
+
+    if(rxInUse())
+        return ManagedString();
+
+    //lazy initialisation of our rx buffer
+    if(!(status & MICROBIT_SERIAL_RX_BUFF_INIT))
+    {
+        int result = initialiseRx();
+
+        if(result != MICROBIT_OK)
+            return result;
+    }
+
+    lockRx();
+
+    int localTail = rxBuffTail;
+    int preservedTail = rxBuffTail;
+
+    int foundIndex = -1;
+
+    //ASYNC mode just iterates through our stored characters checking for any matches.
+    while(localTail != rxBuffHead && foundIndex  == -1)
+    {
+        //we use localTail to prevent modification of the actual tail.
+        char c = rxBuff[localTail];
+
+        for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++)
+            if(delimeters.charAt(delimeterIterator) == c)
+                foundIndex = localTail;
+
+        localTail = (localTail + 1) % rxBuffSize;
+    }
+
+    //if our mode is SYNC_SPINWAIT and we didn't see any matching characters in our buffer
+    //spin until we find a match!
+    if(mode == SYNC_SPINWAIT)
+    {
+        while(foundIndex == -1)
+        {
+            while(localTail == rxBuffHead);
+
+            char c = rxBuff[localTail];
+
+            for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++)
+                if(delimeters.charAt(delimeterIterator) == c)
+                    foundIndex = localTail;
+
+            localTail = (localTail + 1) % rxBuffSize;
+        }
+    }
+
+    //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a
+    //matching character.
+    if(mode == SYNC_SLEEP && foundIndex == -1)
+    {
+        eventOn(delimeters, mode);
+
+        foundIndex = rxBuffHead - 1;
+
+        this->delimeters = ManagedString();
+    }
+
+    if(foundIndex >= 0)
+    {
+        //calculate our local buffer size
+        int localBuffSize = (preservedTail > foundIndex) ? (rxBuffSize - preservedTail) + foundIndex : foundIndex - preservedTail;
+
+        uint8_t localBuff[localBuffSize + 1] = { 0 };
+
+        circularCopy(rxBuff, rxBuffSize, localBuff, preservedTail, foundIndex);
+
+        //plus one for the character we listened for...
+        rxBuffTail = (rxBuffTail + localBuffSize + 1) % rxBuffSize;
+
+        unlockRx();
+
+        return ManagedString((char *)localBuff, localBuffSize);
+    }
+
+    unlockRx();
+
+    return ManagedString();
+}
+
+/**
+  * A wrapper around the inherited method "baud" so we can trap the baud rate
+  * as it changes and restore it if redirect() is called.
+  *
+  * @param baudrate the new baudrate. See:
+  *         - https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/serial_api.c
+  *        for permitted baud rates.
+  *
+  * @return MICROBIT_INVALID_PARAMETER if baud rate is less than 0, otherwise MICROBIT_OK.
+  *
+  * @note the underlying implementation chooses the first allowable rate at or above that requested.
+  */
+void MicroBitSerial::baud(int baudrate)
+{
+    if(baudrate < 0)
+        return;
+
+    this->baudrate = baudrate;
+
+    RawSerial::baud(baudrate);
+}
+
+/**
+  * A way of dynamically configuring the serial instance to use pins other than USBTX and USBRX.
+  *
+  * @param tx the new transmission pin.
+  *
+  * @param rx the new reception pin.
+  *
+  * @return MICROBIT_SERIAL_IN_USE if another fiber is currently transmitting or receiving, otherwise MICROBIT_OK.
+  */
+int MicroBitSerial::redirect(PinName tx, PinName rx)
+{
+    if(txInUse() || rxInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockTx();
+    lockRx();
+
+    if(txBufferedSize() > 0)
+        detach(Serial::IrqType::TxIrq);
+
+    detach(Serial::IrqType::RxIrq);
+
+    serial_free(&_serial);
+    serial_init(&_serial, tx, rx);
+
+    attach(this, &MicroBitSerial::dataReceived, Serial::IrqType::RxIrq);
+
+    if(txBufferedSize() > 0)
+        attach(this, &MicroBitSerial::dataWritten, Serial::IrqType::TxIrq);
+
+    this->baud(this->baudrate);
+
+    unlockRx();
+    unlockTx();
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures an event to be fired after "len" characters.
+  *
+  * @param len the number of characters to wait before triggering the event.
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will configure the event and return immediately.
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+  *                         event is received.
+  *
+  * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+  */
+int MicroBitSerial::eventAfter(int len, MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    //configure our head match...
+    this->rxBuffHeadMatch = (rxBuffHead + len) % rxBuffSize;
+
+    //block!
+    if(mode == SYNC_SLEEP)
+        fiber_wait_for_event(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_HEAD_MATCH);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Configures an event to be fired on a match with one of the delimeters.
+  *
+  * @param delimeters the characters to match received characters against e.g. ManagedString("\r\n")
+  *
+  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
+  *        gives a different behaviour:
+  *
+  *            ASYNC - Will configure the event and return immediately.
+  *
+  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
+  *
+  *            SYNC_SLEEP - Will configure the event and block the current fiber until the
+  *                         event is received.
+  *
+  * @return MICROBIT_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise MICROBIT_OK.
+  *
+  * @note delimeters are matched on a per byte basis.
+  */
+int MicroBitSerial::eventOn(ManagedString delimeters, MicroBitSerialMode mode)
+{
+    if(mode == SYNC_SPINWAIT)
+        return MICROBIT_INVALID_PARAMETER;
+
+    //configure our head match...
+    this->delimeters = delimeters;
+
+    //block!
+    if(mode == SYNC_SLEEP)
+        fiber_wait_for_event(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_DELIM_MATCH);
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Determines whether there is any data waiting in our Rx buffer.
+  *
+  * @return 1 if we have space, 0 if we do not.
+  *
+  * @note We do not wrap the super's readable() method as we don't want to
+  *       interfere with communities that use manual calls to serial.readable().
+  */
+int MicroBitSerial::isReadable()
+{
+    return (rxBuffTail != rxBuffHead) ? 1 : 0;
+}
+
+/**
+  * Determines if we have space in our txBuff.
+  *
+  * @return 1 if we have space, 0 if we do not.
+  *
+  * @note We do not wrap the super's writeable() method as we don't want to
+  *       interfere with communities that use manual calls to serial.writeable().
+  */
+int MicroBitSerial::isWriteable()
+{
+    return (txBuffHead != (txBuffTail - 1)) ? 1 : 0;
+}
+
+/**
+  * Reconfigures the size of our rxBuff
+  *
+  * @param size the new size for our rxBuff
+  *
+  * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+  *         for reception, otherwise MICROBIT_OK.
+  */
+int MicroBitSerial::setRxBufferSize(uint8_t size)
+{
+    if(rxInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockRx();
+
+    this->rxBuffSize = size;
+
+    int result = initialiseRx();
+
+    unlockRx();
+
+    return result;
+}
+
+/**
+  * Reconfigures the size of our txBuff
+  *
+  * @param size the new size for our txBuff
+  *
+  * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+  *         for transmission, otherwise MICROBIT_OK.
+  */
+int MicroBitSerial::setTxBufferSize(uint8_t size)
+{
+    if(txInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockTx();
+
+    this->txBuffSize = size;
+
+    int result = initialiseTx();
+
+    unlockTx();
+
+    return result;
+}
+
+/**
+  * The size of our rx buffer in bytes.
+  *
+  * @return the current size of rxBuff in bytes
+  */
+int MicroBitSerial::getRxBufferSize()
+{
+    return this->rxBuffSize;
+}
+
+/**
+  * The size of our tx buffer in bytes.
+  *
+  * @return the current size of txBuff in bytes
+  */
+int MicroBitSerial::getTxBufferSize()
+{
+    return this->txBuffSize;
+}
+
+/**
+  * Sets the tail to match the head of our circular buffer for reception,
+  * effectively clearing the reception buffer.
+  *
+  * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+  *         for reception, otherwise MICROBIT_OK.
+  */
+int MicroBitSerial::clearRxBuffer()
+{
+    if(rxInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockRx();
+
+    rxBuffTail = rxBuffHead;
+
+    unlockRx();
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Sets the tail to match the head of our circular buffer for transmission,
+  * effectively clearing the transmission buffer.
+  *
+  * @return MICROBIT_SERIAL_IN_USE if another fiber is currently using this instance
+  *         for transmission, otherwise MICROBIT_OK.
+  */
+int MicroBitSerial::clearTxBuffer()
+{
+    if(txInUse())
+        return MICROBIT_SERIAL_IN_USE;
+
+    lockTx();
+
+    txBuffTail = txBuffHead;
+
+    unlockTx();
+
+    return MICROBIT_OK;
+}
+
+/**
+  * The number of bytes currently stored in our rx buffer waiting to be digested,
+  * by the user.
+  *
+  * @return The currently buffered number of bytes in our rxBuff.
+  */
+int MicroBitSerial::rxBufferedSize()
+{
+    if(rxBuffTail > rxBuffHead)
+        return (rxBuffSize - rxBuffTail) + rxBuffHead;
+
+    return rxBuffHead - rxBuffTail;
+}
+
+/**
+  * The number of bytes currently stored in our tx buffer waiting to be transmitted
+  * by the hardware.
+  *
+  * @return The currently buffered number of bytes in our txBuff.
+  */
+int MicroBitSerial::txBufferedSize()
+{
+    if(txBuffTail > txBuffHead)
+        return (txBuffSize - txBuffTail) + txBuffHead;
+
+    return txBuffHead - txBuffTail;
+}
+
+/**
+  * Determines if the serial bus is currently in use by another fiber for reception.
+  *
+  * @return The state of our mutex lock for reception.
+  *
+  * @note Only one fiber can call read at a time
+  */
+int MicroBitSerial::rxInUse()
+{
+    return (status & MICROBIT_SERIAL_RX_IN_USE);
+}
+
+/**
+  * Determines if the serial bus is currently in use by another fiber for transmission.
+  *
+  * @return The state of our mutex lock for transmition.
+  *
+  * @note Only one fiber can call send at a time
+  */
+int MicroBitSerial::txInUse()
+{
+    return (status & MICROBIT_SERIAL_TX_IN_USE);
+}
+
+/**
+  * Detaches a previously configured interrupt
+  *
+  * @param interruptType one of Serial::RxIrq or Serial::TxIrq
+  */
+void MicroBitSerial::detach(Serial::IrqType interruptType)
+{
+    //we detach by sending a bad value to attach, for some weird reason...
+    attach((MicroBitSerial *)NULL, &MicroBitSerial::dataReceived, interruptType);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitStorage.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,485 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for the MicroBitStorage class.
+  * This allows reading and writing of FLASH memory.
+  */
+
+#include "MicroBitConfig.h"
+#include "MicroBitStorage.h"
+#include "MicroBitCompat.h"
+
+/**
+  * Default constructor.
+  *
+  * Creates an instance of MicroBitStorage which acts like a KeyValueStore
+  * that allows the retrieval, addition and deletion of KeyValuePairs.
+  */
+MicroBitStorage::MicroBitStorage()
+{
+    //initialise our magic block, if required.
+    size();
+}
+
+/**
+  * Writes the given number of bytes to the address specified.
+  *
+  * @param buffer the data to write.
+  *
+  * @param address the location in memory to write to.
+  *
+  * @param length the number of bytes to write.
+  *
+  * @note currently not implemented.
+  */
+int MicroBitStorage::writeBytes(uint8_t *buffer, uint32_t address, int length)
+{
+    (void) buffer;
+    (void) address;
+    (void) length;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Method for erasing a page in flash.
+  *
+  * @param page_address Address of the first word in the page to be erased.
+  */
+void MicroBitStorage::flashPageErase(uint32_t * page_address)
+{
+    // Turn on flash erase enable and wait until the NVMC is ready:
+    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);
+
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+
+    // Erase page:
+    NRF_NVMC->ERASEPAGE = (uint32_t)page_address;
+
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+
+    // Turn off flash erase enable and wait until the NVMC is ready:
+    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
+
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+}
+
+/**
+  * Function for copying words from one location to another.
+  *
+  * @param from the address to copy data from.
+  *
+  * @param to the address to copy the data to.
+  *
+  * @param sizeInWords the number of words to copy
+  */
+void MicroBitStorage::flashCopy(uint32_t* from, uint32_t* to, int sizeInWords)
+{
+    // Turn on flash write enable and wait until the NVMC is ready:
+    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
+
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {};
+
+    for(int i = 0; i < sizeInWords; i++)
+    {
+        *(to + i) = *(from + i);
+        while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {};
+    }
+
+    // Turn off flash write enable and wait until the NVMC is ready:
+    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {};
+}
+
+/**
+  * Method for writing a word of data in flash with a value.
+  *
+  * @param address Address of the word to change.
+  *
+  * @param value Value to be written to flash.
+  */
+void MicroBitStorage::flashWordWrite(uint32_t * address, uint32_t value)
+{
+    // Turn on flash write enable and wait until the NVMC is ready:
+    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
+
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+
+    *address = value;
+
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+
+    // Turn off flash write enable and wait until the NVMC is ready:
+    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
+
+    while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
+}
+
+/**
+  * Function for populating the scratch page with a KeyValueStore.
+  *
+  * @param store the KeyValueStore struct to write to the scratch page.
+  */
+void MicroBitStorage::scratchKeyValueStore(KeyValueStore store)
+{
+    //calculate our various offsets
+    uint32_t *s = (uint32_t *) &store;
+    uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
+
+    uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
+
+    //KeyValueStore is word aligned.
+    int wordsToWrite = sizeof(KeyValueStore) / 4;
+
+    //write the given KeyValueStore
+    for (int i = 0; i < wordsToWrite; i++)
+    {
+        flashWordWrite(scratchPointer, *s);
+        scratchPointer++;
+        s++;
+    }
+}
+
+/**
+  * Function for populating the scratch page with a KeyValuePair.
+  *
+  * @param pair the KeyValuePair struct to write to the scratch page.
+  *
+  * @param flashPointer the pointer in flash where this KeyValuePair resides. This pointer
+  * is used to determine the offset into the scratch page, where the KeyValuePair should
+  * be written.
+  */
+void MicroBitStorage::scratchKeyValuePair(KeyValuePair pair, uint32_t* flashPointer)
+{
+    //we can only write using words
+    uint32_t *p = (uint32_t *) &pair;
+
+    //calculate our various offsets
+    uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
+    uint32_t pg_num  = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
+
+    uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
+    uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
+
+    uint32_t flashPointerOffset = flashPointer - flashBlockPointer;
+
+    scratchPointer += flashPointerOffset;
+
+    //KeyValuePair is word aligned...
+    int wordsToWrite = sizeof(KeyValuePair) / 4;
+
+    //write
+    for (int i = 0; i < wordsToWrite; i++)
+    {
+        flashWordWrite(scratchPointer, *p);
+        scratchPointer++;
+        p++;
+    }
+}
+
+/**
+  * Places a given key, and it's corresponding value into flash at the earliest
+  * available point.
+  *
+  * @param key the unique name that should be used as an identifier for the given data.
+  *            The key is presumed to be null terminated.
+  *
+  * @param data a pointer to the beginning of the data to be persisted.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the storage page is full
+  */
+int MicroBitStorage::put(const char *key, uint8_t *data)
+{
+    KeyValuePair pair = KeyValuePair();
+
+    memcpy(pair.key, key, min(sizeof(pair.key), strlen(key)));
+    memcpy(pair.value, data, sizeof(pair.value));
+
+    //calculate our various offsets.
+    uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
+    uint32_t *flashPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET));
+    uint32_t *flashBlockPointer = flashPointer;
+    uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
+
+    uint32_t kvStoreSize = sizeof(KeyValueStore) / 4;
+    uint32_t kvPairSize = sizeof(KeyValuePair) / 4;
+
+    int storeSize = size();
+
+    //our KeyValueStore struct is always at 0
+    flashPointer += kvStoreSize;
+
+    KeyValuePair storedPair = KeyValuePair();
+
+    int found = 0;
+
+    //erase our scratch page
+    flashPageErase(scratchPointer);
+
+    //iterate through key value pairs in flash, writing them to the scratch page.
+    for(int i = 0; i < storeSize; i++)
+    {
+        memcpy(&storedPair, flashPointer, sizeof(KeyValuePair));
+
+        //check if the keys match...
+        if(strcmp((char *)storedPair.key, (char *)pair.key) == 0)
+        {
+            found = 1;
+            //scratch our KeyValueStore struct so that it is preserved.
+            scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
+            scratchKeyValuePair(pair, flashPointer);
+        }
+        else
+        {
+            scratchKeyValuePair(storedPair, flashPointer);
+        }
+
+        flashPointer += kvPairSize;
+    }
+
+    if(!found)
+    {
+        //if we haven't got a match for the key, check we can add a new KeyValuePair
+        if(storeSize == (int)((pg_size - kvStoreSize) / MICROBIT_STORAGE_BLOCK_SIZE))
+            return MICROBIT_NO_RESOURCES;
+
+        storeSize += 1;
+
+        //scratch our updated values.
+        scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
+        scratchKeyValuePair(pair, flashPointer);
+    }
+
+    //erase our storage page
+    flashPageErase((uint32_t *)flashBlockPointer);
+
+    //copy from scratch to storage.
+    flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, kvStoreSize + (storeSize * kvPairSize));
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Places a given key, and it's corresponding value into flash at the earliest
+  * available point.
+  *
+  * @param key the unique name that should be used as an identifier for the given data.
+  *
+  * @param data a pointer to the beginning of the data to be persisted.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the storage page is full
+  */
+int MicroBitStorage::put(ManagedString key, uint8_t* data)
+{
+    return put((char *)key.toCharArray(), data);
+}
+
+/**
+  * Retreives a KeyValuePair identified by a given key.
+  *
+  * @param key the unique name used to identify a KeyValuePair in flash.
+  *
+  * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
+  *         NULL if the key was not found in storage.
+  *
+  * @note it is up to the user to free memory after use.
+  */
+KeyValuePair* MicroBitStorage::get(const char* key)
+{
+    //calculate our offsets for our storage page
+    uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
+    uint32_t pg_num  = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
+
+    uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
+
+    int storeSize = size();
+
+    //we haven't got anything stored, so return...
+    if(storeSize == 0)
+        return NULL;
+
+    //our KeyValueStore struct is always at 0
+    flashBlockPointer += sizeof(KeyValueStore) / 4;
+
+    KeyValuePair *pair = new KeyValuePair();
+
+    int i;
+
+    //iterate through flash until we have a match, or drop out.
+    for(i = 0; i < storeSize; i++)
+    {
+        memcpy(pair, flashBlockPointer, sizeof(KeyValuePair));
+
+        if(strcmp(key,(char *)pair->key) == 0)
+            break;
+
+        flashBlockPointer += sizeof(KeyValuePair) / 4;
+    }
+
+    //clean up
+    if(i == storeSize)
+    {
+        delete pair;
+        return NULL;
+    }
+
+    return pair;
+}
+
+/**
+  * Retreives a KeyValuePair identified by a given key.
+  *
+  * @param key the unique name used to identify a KeyValuePair in flash.
+  *
+  * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
+  *         NULL if the key was not found in storage.
+  *
+  * @note it is up to the user to free memory after use.
+  */
+KeyValuePair* MicroBitStorage::get(ManagedString key)
+{
+    return get((char *)key.toCharArray());
+}
+
+/**
+  * Removes a KeyValuePair identified by a given key.
+  *
+  * @param key the unique name used to identify a KeyValuePair in flash.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
+  *         was not found in flash.
+  */
+int MicroBitStorage::remove(const char* key)
+{
+    //calculate our various offsets
+    uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
+    uint32_t *flashPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET));
+    uint32_t *flashBlockPointer = flashPointer;
+    uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
+
+    uint32_t kvStoreSize = sizeof(KeyValueStore) / 4;
+    uint32_t kvPairSize = sizeof(KeyValuePair) / 4;
+
+    int storeSize = size();
+
+    //if we have no data, we have nothing to do.
+    if(storeSize == 0)
+        return MICROBIT_NO_DATA;
+
+    //our KeyValueStore struct is always at 0
+    flashPointer += kvStoreSize;
+    scratchPointer += kvStoreSize;
+
+    KeyValuePair storedPair = KeyValuePair();
+
+    int found = 0;
+
+    //set up our scratch area
+    flashPageErase(scratchPointer);
+
+    //iterate through our flash copy pairs to scratch, unless there is a key patch
+    for(int i = 0; i < storeSize; i++)
+    {
+        memcpy(&storedPair, flashPointer, sizeof(KeyValuePair));
+
+        //if we have a match, don't increment our scratchPointer
+        if(strcmp((char *)storedPair.key, (char *)key) == 0)
+        {
+            found = 1;
+            //write our new KeyValueStore data
+            scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize - 1));
+        }
+        else
+        {
+            //otherwise copy the KeyValuePair from our storage page.
+            flashCopy(flashPointer, scratchPointer, sizeof(KeyValuePair) / 4);
+            scratchPointer += sizeof(KeyValuePair) / 4;
+        }
+
+        flashPointer += sizeof(KeyValuePair) / 4;
+    }
+
+    //if we haven't got a match, write our old KeyValueStore struct
+    if(!found)
+    {
+        scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
+        return MICROBIT_NO_DATA;
+    }
+
+    //copy scratch to our storage page
+    flashPageErase((uint32_t *)flashBlockPointer);
+    flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, kvStoreSize + (storeSize * kvPairSize));
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Removes a KeyValuePair identified by a given key.
+  *
+  * @param key the unique name used to identify a KeyValuePair in flash.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
+  *         was not found in flash.
+  */
+int MicroBitStorage::remove(ManagedString key)
+{
+    return remove((char *)key.toCharArray());
+}
+
+/**
+  * The size of the flash based KeyValueStore.
+  *
+  * @return the number of entries in the key value store
+  */
+int MicroBitStorage::size()
+{
+    uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
+    uint32_t pg_num  = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
+
+    uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
+
+    KeyValueStore store = KeyValueStore();
+
+    //read our data!
+    memcpy(&store, flashBlockPointer, sizeof(KeyValueStore));
+
+    //if we haven't used flash before, we need to configure it
+    if(store.magic != MICROBIT_STORAGE_MAGIC)
+    {
+        store.magic = MICROBIT_STORAGE_MAGIC;
+        store.size = 0;
+
+        //erase the scratch page and write our new KeyValueStore
+        flashPageErase((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)));
+        scratchKeyValueStore(store);
+
+        //erase flash, and copy the scratch page over
+        flashPageErase((uint32_t *)flashBlockPointer);
+        flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, pg_size/4);
+    }
+
+    return store.size;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/drivers/MicroBitThermometer.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,278 @@
+/*
+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 "MicroBitThermometer.h"
+#include "MicroBitSystemTimer.h"
+#include "MicroBitFiber.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)
+ * 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
+
+#include "nrf_soc.h"
+#include "nrf_sdm.h"
+
+/*
+ * Return to our predefined compiler settings.
+ */
+#if !defined(__arm)
+#pragma GCC diagnostic pop
+#endif
+
+/**
+  * Constructor.
+  * Create new MicroBitThermometer that gives an indication of the current temperature.
+  *
+  * @param _storage an instance of MicroBitStorage used to persist temperature offset data
+  *
+  * @param id the unique EventModel id of this component. Defaults to MICROBIT_ID_THERMOMETER.
+  *
+  * @code
+  * MicroBitStorage storage;
+  * MicroBitThermometer thermometer(storage);
+  * @endcode
+  */
+MicroBitThermometer::MicroBitThermometer(MicroBitStorage& _storage, uint16_t id) :
+    storage(&_storage)
+{
+    this->id = id;
+    this->samplePeriod = MICROBIT_THERMOMETER_PERIOD;
+    this->sampleTime = 0;
+    this->offset = 0;
+
+    KeyValuePair *tempCalibration =  storage->get(ManagedString("tempCal"));
+
+    if(tempCalibration != NULL)
+    {
+        memcpy(&offset, tempCalibration->value, sizeof(int16_t));
+        delete tempCalibration;
+    }
+}
+
+/**
+  * Constructor.
+  * Create new MicroBitThermometer that gives an indication of the current temperature.
+  *
+  * @param id the unique EventModel id of this component. Defaults to MICROBIT_ID_THERMOMETER.
+  *
+  * @code
+  * MicroBitThermometer thermometer;
+  * @endcode
+  */
+MicroBitThermometer::MicroBitThermometer(uint16_t id) :
+    storage(NULL)
+{
+    this->id = id;
+    this->samplePeriod = MICROBIT_THERMOMETER_PERIOD;
+    this->sampleTime = 0;
+    this->offset = 0;
+}
+
+/**
+  * Gets the current temperature of the microbit.
+  *
+  * @return the current temperature, in degrees celsius.
+  *
+  * @code
+  * thermometer.getTemperature();
+  * @endcode
+  */
+int MicroBitThermometer::getTemperature()
+{
+    updateSample();
+    return temperature - offset;
+}
+
+
+/**
+  * Updates the temperature sample of this instance of MicroBitThermometer
+  * only if isSampleNeeded() indicates that an update is required.
+  *
+  * This call also will add the thermometer to fiber components to receive
+  * periodic callbacks.
+  *
+  * @return MICROBIT_OK on success.
+  */
+int MicroBitThermometer::updateSample()
+{
+    if(!(status & MICROBIT_THERMOMETER_ADDED_TO_IDLE))
+    {
+        // If we're running under a fiber scheduer, register ourselves for a periodic callback to keep our data up to date.
+        // Otherwise, we do just do this on demand, when polled through our read() interface.
+        fiber_add_idle_component(this);
+        status |= MICROBIT_THERMOMETER_ADDED_TO_IDLE;
+    }
+
+    // check if we need to update our sample...
+    if(isSampleNeeded())
+    {
+        int32_t processorTemperature;
+        uint8_t sd_enabled;
+
+        // For now, we just rely on the nrf senesor to be the most accurate.
+        // The compass module also has a temperature sensor, and has the lowest power consumption, so will run the cooler...
+        // ...however it isn't trimmed for accuracy during manufacture, so requires calibration.
+
+        sd_softdevice_is_enabled(&sd_enabled);
+
+        if (sd_enabled)
+        {
+            // If Bluetooth is enabled, we need to go through the Nordic software to safely do this
+            sd_temp_get(&processorTemperature);
+        }
+        else
+        {
+            // Othwerwise, we access the information directly...
+            uint32_t *TEMP = (uint32_t *)0x4000C508;
+
+            NRF_TEMP->TASKS_START = 1;
+
+            while (NRF_TEMP->EVENTS_DATARDY == 0);
+
+            NRF_TEMP->EVENTS_DATARDY = 0;
+
+            processorTemperature = *TEMP;
+
+            NRF_TEMP->TASKS_STOP = 1;
+        }
+
+
+        // Record our reading...
+        temperature = processorTemperature / 4;
+
+        // Schedule our next sample.
+        sampleTime = system_timer_current_time() + samplePeriod;
+
+        // Send an event to indicate that we'e updated our temperature.
+        MicroBitEvent e(id, MICROBIT_THERMOMETER_EVT_UPDATE);
+    }
+
+    return MICROBIT_OK;
+};
+
+/**
+  * Indicates if we'd like some processor time to sense the temperature.
+  *
+  * @returns 1 if we'd like some processor time, 0 otherwise.
+  */
+int MicroBitThermometer::isIdleCallbackNeeded()
+{
+    return isSampleNeeded();
+}
+
+/**
+  * Periodic callback from MicroBit idle thread.
+  */
+void MicroBitThermometer::idleTick()
+{
+    updateSample();
+}
+
+/**
+  * Determines if we're due to take another temperature reading
+  *
+  * @return 1 if we're due to take a temperature reading, 0 otherwise.
+  */
+int MicroBitThermometer::isSampleNeeded()
+{
+    return  system_timer_current_time() >= sampleTime;
+}
+
+/**
+  * Set the sample rate at which the temperatureis read (in ms).
+  *
+  * The default sample period is 1 second.
+  *
+  * @param period the requested time between samples, in milliseconds.
+  *
+  * @note the temperature is always read in the background, and is only updated
+  * when the processor is idle, or when the temperature is explicitly read.
+  */
+void MicroBitThermometer::setPeriod(int period)
+{
+    updateSample();
+    samplePeriod = period;
+}
+
+/**
+  * Reads the currently configured sample rate of the thermometer.
+  *
+  * @return The time between samples, in milliseconds.
+  */
+int MicroBitThermometer::getPeriod()
+{
+    return samplePeriod;
+}
+
+/**
+  * Set the value that is used to offset the raw silicon temperature.
+  *
+  * @param offset the offset for the silicon temperature
+  *
+  * @return MICROBIT_OK on success
+  */
+int MicroBitThermometer::setOffset(int offset)
+{
+    if(this->storage != NULL)
+        this->storage->put(ManagedString("tempCal"), (uint8_t *)&offset);
+
+    this->offset = offset;
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Retreive the value that is used to offset the raw silicon temperature.
+  *
+  * @return the current offset.
+  */
+int MicroBitThermometer::getOffset()
+{
+    return offset;
+}
+
+/**
+  * This member function fetches the raw silicon temperature, and calculates
+  * the value used to offset the raw silicon temperature based on a given temperature.
+  *
+  * @param calibrationTemp the temperature used to calculate the raw silicon temperature
+  * offset.
+  *
+  * @return MICROBIT_OK on success
+  */
+int MicroBitThermometer::setCalibration(int calibrationTemp)
+{
+    updateSample();
+    return setOffset(temperature - calibrationTemp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/types/ManagedString.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,489 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for a ManagedString.
+  *
+  * Uses basic reference counting to implement a copy-assignable, immutable string.
+  *
+  * This maps closely to the constructs found in many high level application languages,
+  * such as Touch Develop.
+  *
+  * Written from first principles here, for several reasons:
+  * 1) std::shared_ptr is not yet availiable on the ARMCC compiler
+  *
+  * 2) to reduce memory footprint - we don't need many of the other features in the std library
+  *
+  * 3) it makes an interesting case study for anyone interested in seeing how it works!
+  *
+  * 4) we need explicit reference counting to inter-op with low-level application langauge runtimes.
+  *
+  * 5) the reference counting needs to also work for read-only, flash-resident strings
+  */
+#include <string.h>
+#include <stdlib.h>
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "ManagedString.h"
+#include "MicroBitCompat.h"
+
+static const char empty[] __attribute__ ((aligned (4))) = "\xff\xff\0\0\0";
+
+/**
+  * Internal constructor helper.
+  *
+  * Configures this ManagedString to refer to the static EmptyString
+  */
+void ManagedString::initEmpty()
+{
+    ptr = (StringData*)(void*)empty;
+}
+
+/**
+  * Internal constructor helper.
+  *
+  * Creates this ManagedString based on a given null terminated char array.
+  */
+void ManagedString::initString(const char *str)
+{
+    // Initialise this ManagedString as a new string, using the data provided.
+    // We assume the string is sane, and null terminated.
+    int len = strlen(str);
+    ptr = (StringData *) malloc(4+len+1);
+    ptr->init();
+    ptr->len = len;
+    memcpy(ptr->data, str, len+1);
+}
+
+/**
+  * Constructor.
+  * Create a managed string from a specially prepared string literal.
+  *
+  * @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The literal has to be 4-byte aligned.
+  *
+  * @code
+  * static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello";
+  * ManagedString s((StringData*)(void*)hello);
+  * @endcode
+  */
+ManagedString::ManagedString(StringData *p)
+{
+    ptr = p;
+    ptr->incr();
+}
+
+/**
+  * Get current ptr, do not decr() it, and set the current instance to empty string.
+  *
+  * This is to be used by specialized runtimes which pass StringData around.
+  */
+StringData* ManagedString::leakData()
+{
+    StringData *res = ptr;
+    initEmpty();
+    return res;
+}
+
+/**
+  * Constructor.
+  *
+  * Create a managed string from a given integer.
+  *
+  * @param value The integer from which to create the ManagedString.
+  *
+  * @code
+  * ManagedString s(20);
+  * @endcode
+  */
+ManagedString::ManagedString(const int value)
+{
+    char str[12];
+
+    itoa(value, str);
+    initString(str);
+}
+
+/**
+  * Constructor.
+  * Create a managed string from a given char.
+  *
+  * @param value The character from which to create the ManagedString.
+  *
+  * @code
+  * ManagedString s('a');
+  * @endcode
+  */
+ManagedString::ManagedString(const char value)
+{
+    char str[2] = {value, 0};
+    initString(str);
+}
+
+
+/**
+  * Constructor.
+  *
+  * Create a managed string from a pointer to an 8-bit character buffer.
+  *
+  * The buffer is copied to ensure safe memory management (the supplied
+  * character buffer may be declared on the stack for instance).
+  *
+  * @param str The character array on which to base the new ManagedString.
+  *
+  * @code
+  * ManagedString s("abcdefg");
+  * @endcode
+  */
+ManagedString::ManagedString(const char *str)
+{
+    // Sanity check. Return EmptyString for anything distasteful
+    if (str == NULL || *str == 0)
+    {
+        initEmpty();
+        return;
+    }
+
+    initString(str);
+}
+
+/**
+  * Private Constructor.
+  *
+  * Create a managed string based on a concat of two strings.
+  * The buffer is copied to ensure sane memory management (the supplied
+  * character buffer may be declared on the stack for instance).
+  *
+  * @param str1 The first string on which to base the new ManagedString.
+  *
+  * @param str2 The second string on which to base the new ManagedString.
+  */
+ManagedString::ManagedString(const ManagedString &s1, const ManagedString &s2)
+{
+    // Calculate length of new string.
+    int len = s1.length() + s2.length();
+
+    // Create a new buffer for holding the new string data.
+    ptr = (StringData*) malloc(4+len+1);
+    ptr->init();
+    ptr->len = len;
+
+    // Enter the data, and terminate the string.
+    memcpy(ptr->data, s1.toCharArray(), s1.length());
+    memcpy(ptr->data + s1.length(), s2.toCharArray(), s2.length());
+    ptr->data[len] = 0;
+}
+
+
+/**
+  * Constructor.
+  * Create a ManagedString from a PacketBuffer. All bytes in the
+  * PacketBuffer are added to the ManagedString.
+  *
+  * @param buffer The PacktBuffer from which to create the ManagedString.
+  *
+  * @code
+  * ManagedString s = radio.datagram.recv();
+  * @endcode
+  */
+ManagedString::ManagedString(PacketBuffer buffer)
+{
+    // Allocate a new buffer ( just in case the data is not NULL terminated).
+    ptr = (StringData*) malloc(4+buffer.length()+1);
+    ptr->init();
+
+    // Store the length of the new string
+    ptr->len = buffer.length();
+    memcpy(ptr->data, buffer.getBytes(), buffer.length());
+    ptr->data[buffer.length()] = 0;
+}
+
+/**
+  * Constructor.
+  * Create a ManagedString from a pointer to an 8-bit character buffer of a given length.
+  *
+  * The buffer is copied to ensure sane memory management (the supplied
+  * character buffer may be declared on the stack for instance).
+  *
+  * @param str The character array on which to base the new ManagedString.
+  *
+  * @param length The length of the character array
+  *
+  * @code
+  * ManagedString s("abcdefg",7);
+  * @endcode
+  */
+ManagedString::ManagedString(const char *str, const int16_t length)
+{
+    // Sanity check. Return EmptyString for anything distasteful
+    if (str == NULL || *str == 0 || (uint16_t)length > strlen(str)) // XXX length should be unsigned on the interface
+    {
+        initEmpty();
+        return;
+    }
+
+
+    // Allocate a new buffer, and create a NULL terminated string.
+    ptr = (StringData*) malloc(4+length+1);
+    ptr->init();
+    // Store the length of the new string
+    ptr->len = length;
+    memcpy(ptr->data, str, length);
+    ptr->data[length] = 0;
+}
+
+/**
+  * Copy constructor.
+  * Makes a new ManagedString identical to the one supplied.
+  *
+  * Shares the character buffer and reference count with the supplied ManagedString.
+  *
+  * @param s The ManagedString to copy.
+  *
+  * @code
+  * ManagedString s("abcdefg");
+  * ManagedString p(s);
+  * @endcode
+  */
+ManagedString::ManagedString(const ManagedString &s)
+{
+    ptr = s.ptr;
+    ptr->incr();
+}
+
+
+/**
+  * Default constructor.
+  *
+  * Create an empty ManagedString.
+  *
+  * @code
+  * ManagedString s();
+  * @endcode
+  */
+ManagedString::ManagedString()
+{
+    initEmpty();
+}
+
+/**
+  * Destructor.
+  *
+  * Free this ManagedString, and decrement the reference count to the
+  * internal character buffer.
+  *
+  * If we're holding the last reference, also free the character buffer.
+  */
+ManagedString::~ManagedString()
+{
+    ptr->decr();
+}
+
+/**
+  * Copy assign operation.
+  *
+  * Called when one ManagedString is assigned the value of another.
+  *
+  * If the ManagedString being assigned is already refering to a character buffer,
+  * decrement the reference count and free up the buffer as necessary.
+  *
+  * Then, update our character buffer to refer to that of the supplied ManagedString,
+  * and increase its reference count.
+  *
+  * @param s The ManagedString to copy.
+  *
+  * @code
+  * ManagedString s("abcd");
+  * ManagedString p("efgh");
+  * p = s   // p now points to s, s' ref is incremented
+  * @endcode
+  */
+ManagedString& ManagedString::operator = (const ManagedString& s)
+{
+    if (this->ptr == s.ptr)
+        return *this;
+
+    ptr->decr();
+    ptr = s.ptr;
+    ptr->incr();
+
+    return *this;
+}
+
+/**
+  * Equality operation.
+  *
+  * Called when one ManagedString is tested to be equal to another using the '==' operator.
+  *
+  * @param s The ManagedString to test ourselves against.
+  *
+  * @return true if this ManagedString is identical to the one supplied, false otherwise.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * ManagedString s("abcd");
+  * ManagedString p("efgh");
+  *
+  * if(p == s)
+  *     display.scroll("We are the same!");
+  * else
+  *     display.scroll("We are different!"); //p is not equal to s - this will be called
+  * @endcode
+  */
+bool ManagedString::operator== (const ManagedString& s)
+{
+    return ((length() == s.length()) && (strcmp(toCharArray(),s.toCharArray())==0));
+}
+
+/**
+  * Inequality operation.
+  *
+  * Called when one ManagedString is tested to be less than another using the '<' operator.
+  *
+  * @param s The ManagedString to test ourselves against.
+  *
+  * @return true if this ManagedString is alphabetically less than to the one supplied, false otherwise.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * ManagedString s("a");
+  * ManagedString p("b");
+  *
+  * if(s < p)
+  *     display.scroll("a is before b!"); //a is before b
+  * else
+  *     display.scroll("b is before a!");
+  * @endcode
+  */
+bool ManagedString::operator< (const ManagedString& s)
+{
+    return (strcmp(toCharArray(), s.toCharArray())<0);
+}
+
+/**
+  * Inequality operation.
+  *
+  * Called when one ManagedString is tested to be greater than another using the '>' operator.
+  *
+  * @param s The ManagedString to test ourselves against.
+  *
+  * @return true if this ManagedString is alphabetically greater than to the one supplied, false otherwise.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * ManagedString s("a");
+  * ManagedString p("b");
+  *
+  * if(p>a)
+  *     display.scroll("b is after a!"); //b is after a
+  * else
+  *     display.scroll("a is after b!");
+  * @endcode
+  */
+bool ManagedString::operator> (const ManagedString& s)
+{
+    return (strcmp(toCharArray(), s.toCharArray())>0);
+}
+
+/**
+  * Extracts a ManagedString from this string, at the position provided.
+  *
+  * @param start The index of the first character to extract, indexed from zero.
+  *
+  * @param length The number of characters to extract from the start position
+  *
+  * @return a ManagedString representing the requested substring.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * ManagedString s("abcdefg");
+  *
+  * display.scroll(s.substring(0,2)) // displays "ab"
+  * @endcode
+  */
+ManagedString ManagedString::substring(int16_t start, int16_t length)
+{
+    // If the parameters are illegal, just return a reference to the empty string.
+    if (start >= this->length())
+        return ManagedString(ManagedString::EmptyString);
+
+    // Compute a safe copy length;
+    length = min(this->length()-start, length);
+
+    // Build a ManagedString from this.
+    return ManagedString(toCharArray()+start, length);
+}
+
+/**
+  * Concatenates this string with the one provided.
+  *
+  * @param s The ManagedString to concatenate.
+  *
+  * @return a new ManagedString representing the joined strings.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * ManagedString s("abcd");
+  * ManagedString p("efgh")
+  *
+  * display.scroll(s + p) // scrolls "abcdefgh"
+  * @endcode
+  */
+ManagedString ManagedString::operator+ (ManagedString& s)
+{
+    // If the other string is empty, nothing to do!
+    if(s.length() == 0)
+        return *this;
+
+    if (length() == 0)
+        return s;
+
+    return ManagedString(*this, s);
+}
+
+
+/**
+  * Provides a character value at a given position in the string, indexed from zero.
+  *
+  * @param index The position of the character to return.
+  *
+  * @return the character at posisiton index, zero if index is invalid.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * ManagedString s("abcd");
+  *
+  * display.scroll(s.charAt(1)) // scrolls "b"
+  * @endcode
+  */
+char ManagedString::charAt(int16_t index)
+{
+    return (index >=0 && index < length()) ? ptr->data[index] : 0;
+}
+
+/**
+  * Empty string constant literal
+  */
+ManagedString ManagedString::EmptyString((StringData*)(void*)empty);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/types/Matrix4.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,285 @@
+/*
+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 "Matrix4.h"
+#include "mbed.h"
+
+/**
+* Class definition for a simple matrix, optimised for n x 4 or 4 x n matrices.
+*
+* This class is heavily optimised for these commonly used matrices as used in 3D geometry,
+* and is not intended as a general purpose matrix class. For programmers needing more flexible
+* Matrix support, the mbed Matrix and MatrixMath classes from Ernsesto Palacios provide a good basis:
+*
+* https://developer.mbed.org/cookbook/MatrixClass
+* https://developer.mbed.org/users/Yo_Robot/code/MatrixMath/
+*/
+
+/**
+  * Constructor.
+  * Create a matrix of the given size.
+  *
+  * @param rows the number of rows in the matrix to be created.
+  *
+  * @param cols the number of columns in the matrix to be created.
+  *
+  * @code
+  * Matrix4(10, 4);        // Creates a Matrix with 10 rows and 4 columns.
+  * @endcode
+  */
+Matrix4::Matrix4(int rows, int cols)
+{
+	this->rows = rows;
+	this->cols = cols;
+
+	int size = rows * cols;
+
+	if (size > 0)
+		data = new float[size];
+	else
+		data = NULL;
+}
+
+/**
+  * Constructor.
+  * Create a matrix that is an identical copy of the given matrix.
+  *
+  * @param matrix The matrix to copy.
+  *
+  * @code
+  * Matrix newMatrix(matrix);        .
+  * @endcode
+  */
+Matrix4::Matrix4(const Matrix4 &matrix)
+{
+	this->rows = matrix.rows;
+	this->cols = matrix.cols;
+
+	int size = rows * cols;
+
+	if (size > 0)
+	{
+		data = new float[size];
+		for (int i = 0; i < size; i++)
+			data[i] = matrix.data[i];
+	}
+	else
+	{
+		data = NULL;
+	}
+
+}
+
+/**
+  * Determines the number of columns in this matrix.
+  *
+  * @return The number of columns in the matrix.
+  *
+  * @code
+  * int c = matrix.width();
+  * @endcode
+  */
+int Matrix4::width()
+{
+	return cols;
+}
+
+/**
+  * Determines the number of rows in this matrix.
+  *
+  * @return The number of rows in the matrix.
+  *
+  * @code
+  * int r = matrix.height();
+  * @endcode
+  */
+int Matrix4::height()
+{
+	return rows;
+}
+
+/**
+  * Reads the matrix element at the given position.
+  *
+  * @param row The row of the element to read.
+  *
+  * @param col The column of the element to read.
+  *
+  * @return The value of the matrix element at the given position. 0 is returned if the given index is out of range.
+  *
+  * @code
+  * float v = matrix.get(1,2);
+  * @endcode
+  */
+float Matrix4::get(int row, int col)
+{
+	if (row < 0 || col < 0 || row >= rows || col >= cols)
+		return 0;
+
+	return data[width() * row + col];
+}
+
+/**
+  * Writes the matrix element at the given position.
+  *
+  * @param row The row of the element to write.
+  *
+  * @param col The column of the element to write.
+  *
+  * @param v The new value of the element.
+  *
+  * @code
+  * matrix.set(1,2,42.0);
+  * @endcode
+  */
+void Matrix4::set(int row, int col, float v)
+{
+	if (row < 0 || col < 0 || row >= rows || col >= cols)
+		return;
+
+	data[width() * row + col] = v;
+}
+
+/**
+  * Transposes this matrix.
+  *
+  * @return the resultant matrix.
+  *
+  * @code
+  * matrix.transpose();
+  * @endcode
+  */
+Matrix4 Matrix4::transpose()
+{
+	Matrix4 result = Matrix4(cols, rows);
+
+	for (int i = 0; i < width(); i++)
+		for (int j = 0; j < height(); j++)
+			result.set(i, j, get(j, i));
+
+	return result;
+}
+
+/**
+  * Multiplies this matrix with the given matrix (if possible).
+  *
+  * @param matrix the matrix to multiply this matrix's values against.
+  *
+  * @param transpose Transpose the matrices before multiplication. Defaults to false.
+  *
+  * @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
+  *
+  * @code
+  * Matrix result = matrixA.multiply(matrixB);
+  * @endcode
+  */
+Matrix4 Matrix4::multiply(Matrix4 &matrix, bool transpose)
+{
+    int w = transpose ? height() : width();
+    int h = transpose ? width() : height();
+
+	if (w != matrix.height())
+		return Matrix4(0, 0);
+
+	Matrix4 result(h, matrix.width());
+
+	for (int r = 0; r < result.height(); r++)
+	{
+		for (int c = 0; c < result.width(); c++)
+		{
+			float v = 0.0;
+
+			for (int i = 0; i < w; i++)
+				v += (transpose ? get(i, r) : get(r, i)) * matrix.get(i, c);
+
+			result.set(r, c, v);
+		}
+	}
+
+	return result;
+}
+
+/**
+  * Performs an optimised inversion of a 4x4 matrix.
+  * Only 4x4 matrices are supported by this operation.
+  *
+  * @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
+  *
+  * @code
+  * Matrix result = matrixA.invert();
+  * @endcode
+  */
+Matrix4 Matrix4::invert()
+{
+	// We only support square matrices of size 4...
+	if (width() != height() || width() != 4)
+		return Matrix4(0, 0);
+
+	Matrix4 result(width(), height());
+
+	result.data[0] = data[5] * data[10] * data[15] - data[5] * data[11] * data[14] - data[9] * data[6] * data[15] + data[9] * data[7] * data[14] + data[13] * data[6] * data[11] - data[13] * data[7] * data[10];
+	result.data[1] = -data[1] * data[10] * data[15] + data[1] * data[11] * data[14] + data[9] * data[2] * data[15] - data[9] * data[3] * data[14] - data[13] * data[2] * data[11] + data[13] * data[3] * data[10];
+	result.data[2] = data[1] * data[6] * data[15] - data[1] * data[7] * data[14] - data[5] * data[2] * data[15] + data[5] * data[3] * data[14] + data[13] * data[2] * data[7] - data[13] * data[3] * data[6];
+	result.data[3] = -data[1] * data[6] * data[11] + data[1] * data[7] * data[10] + data[5] * data[2] * data[11] - data[5] * data[3] * data[10] - data[9] * data[2] * data[7] + data[9] * data[3] * data[6];
+	result.data[4] = -data[4] * data[10] * data[15] + data[4] * data[11] * data[14] + data[8] * data[6] * data[15] - data[8] * data[7] * data[14] - data[12] * data[6] * data[11] + data[12] * data[7] * data[10];
+	result.data[5] = data[0] * data[10] * data[15] - data[0] * data[11] * data[14] - data[8] * data[2] * data[15] + data[8] * data[3] * data[14] + data[12] * data[2] * data[11] - data[12] * data[3] * data[10];
+	result.data[6] = -data[0] * data[6] * data[15] + data[0] * data[7] * data[14] + data[4] * data[2] * data[15] - data[4] * data[3] * data[14] - data[12] * data[2] * data[7] + data[12] * data[3] * data[6];
+	result.data[7] = data[0] * data[6] * data[11] - data[0] * data[7] * data[10] - data[4] * data[2] * data[11] + data[4] * data[3] * data[10] + data[8] * data[2] * data[7] - data[8] * data[3] * data[6];
+	result.data[8] = data[4] * data[9] * data[15] - data[4] * data[11] * data[13] - data[8] * data[5] * data[15] + data[8] * data[7] * data[13] + data[12] * data[5] * data[11] - data[12] * data[7] * data[9];
+	result.data[9] = -data[0] * data[9] * data[15] + data[0] * data[11] * data[13] + data[8] * data[1] * data[15] - data[8] * data[3] * data[13] - data[12] * data[1] * data[11] + data[12] * data[3] * data[9];
+	result.data[10] = data[0] * data[5] * data[15] - data[0] * data[7] * data[13] - data[4] * data[1] * data[15] + data[4] * data[3] * data[13] + data[12] * data[1] * data[7] - data[12] * data[3] * data[5];
+	result.data[11] = -data[0] * data[5] * data[11] + data[0] * data[7] * data[9] + data[4] * data[1] * data[11] - data[4] * data[3] * data[9] - data[8] * data[1] * data[7] + data[8] * data[3] * data[5];
+	result.data[12] = -data[4] * data[9] * data[14] + data[4] * data[10] * data[13] + data[8] * data[5] * data[14] - data[8] * data[6] * data[13] - data[12] * data[5] * data[10] + data[12] * data[6] * data[9];
+	result.data[13] = data[0] * data[9] * data[14] - data[0] * data[10] * data[13] - data[8] * data[1] * data[14] + data[8] * data[2] * data[13] + data[12] * data[1] * data[10] - data[12] * data[2] * data[9];
+	result.data[14] = -data[0] * data[5] * data[14] + data[0] * data[6] * data[13] + data[4] * data[1] * data[14] - data[4] * data[2] * data[13] - data[12] * data[1] * data[6] + data[12] * data[2] * data[5];
+	result.data[15] = data[0] * data[5] * data[10] - data[0] * data[6] * data[9] - data[4] * data[1] * data[10] + data[4] * data[2] * data[9] + data[8] * data[1] * data[6] - data[8] * data[2] * data[5];
+
+	float det = data[0] * result.data[0] + data[1] * result.data[4] + data[2] * result.data[8] + data[3] * result.data[12];
+
+	if (det == 0)
+		return Matrix4(0, 0);
+
+	det = 1.0f / det;
+
+	for (int i = 0; i < 16; i++)
+		result.data[i] *= det;
+
+	return result;
+}
+
+/**
+  * Destructor.
+  *
+  * Frees any memory consumed by this Matrix4 instance.
+  */
+Matrix4::~Matrix4()
+{
+	if (data != NULL)
+	{
+		delete data;
+		data = NULL;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/types/MicroBitEvent.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,97 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for a MicroBitEvent
+  *
+  * It represents a common event that is generated by the various components on the micro:bit.
+  */
+#include "MicroBitConfig.h"
+#include "MicroBitEvent.h"
+#include "MicroBitSystemTimer.h"
+#include "EventModel.h"
+
+EventModel* EventModel::defaultEventBus = NULL;
+
+/**
+  * Constructor.
+  *
+  * @param src The id of the MicroBit Component that generated the event e.g. MICROBIT_ID_BUTTON_A.
+  *
+  * @param value A component specific code indicating the cause of the event.
+  *
+  * @param mode Optional definition of how the event should be processed after construction (if at all):
+  *                 CREATE_ONLY: MicroBitEvent is initialised, and no further processing takes place.
+  *                 CREATE_AND_FIRE: MicroBitEvent is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!).
+  *
+  * @code
+  * // Create and launch an event using the default configuration
+  * MicrobitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK);
+  *
+  * // Create an event only, do not fire onto an EventModel.
+  * MicrobitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK,CREATE_AND_FIRE);
+  * @endcode
+  */
+MicroBitEvent::MicroBitEvent(uint16_t source, uint16_t value, MicroBitEventLaunchMode mode)
+{
+    this->source = source;
+    this->value = value;
+    this->timestamp = system_timer_current_time();
+
+    if(mode != CREATE_ONLY)
+        this->fire();
+}
+
+/**
+  * Default constructor - initialises all values, and sets timestamp to the current time.
+  */
+MicroBitEvent::MicroBitEvent()
+{
+    this->source = 0;
+    this->value = 0;
+    this->timestamp = system_timer_current_time();
+}
+
+/**
+  * Fires this MicroBitEvent onto the Default EventModel, or a custom one!
+  */
+void MicroBitEvent::fire()
+{
+	if(EventModel::defaultEventBus)
+		EventModel::defaultEventBus->send(*this);
+}
+
+
+/**
+  * Constructor.
+  * Create a new MicroBitEventQueueItem.
+  *
+  * @param evt The event to be queued.
+  */
+MicroBitEventQueueItem::MicroBitEventQueueItem(MicroBitEvent evt)
+{
+    this->evt = evt;
+	this->next = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/types/MicroBitImage.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,887 @@
+/*
+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.
+*/
+
+/**
+  * Class definition for a MicroBitImage.
+  *
+  * An MicroBitImage is a simple bitmap representation of an image.
+  * n.b. This is a mutable, managed type.
+  */
+
+#include "MicroBitConfig.h"
+#include "MicroBitImage.h"
+#include "MicroBitFont.h"
+#include "MicroBitCompat.h"
+#include "ManagedString.h"
+#include "ErrorNo.h"
+
+
+/**
+  * The null image. We actally create a small one byte buffer here, just to keep NULL pointers out of the equation.
+  */
+static const uint16_t empty[] __attribute__ ((aligned (4))) = { 0xffff, 1, 1, 0, };
+MicroBitImage MicroBitImage::EmptyImage((ImageData*)(void*)empty);
+
+/**
+  * Default Constructor.
+  * Creates a new reference to the empty MicroBitImage bitmap
+  *
+  * @code
+  * MicroBitImage i(); //an empty image instance
+  * @endcode
+  */
+MicroBitImage::MicroBitImage()
+{
+    // Create new reference to the EmptyImage and we're done.
+    init_empty();
+}
+
+
+/**
+  * Constructor.
+  * Create a blank bitmap representation of a given size.
+  *
+  * @param x the width of the image.
+  *
+  * @param y the height of the image.
+  *
+  * Bitmap buffer is linear, with 8 bits per pixel, row by row,
+  * top to bottom with no word alignment. Stride is therefore the image width in pixels.
+  * in where w and h are width and height respectively, the layout is therefore:
+  *
+  * |[0,0]...[w,o][1,0]...[w,1]  ...  [[w,h]
+  *
+  * A copy of the image is made in RAM, as images are mutable.
+  *
+  * TODO: Consider an immutable flavour, which might save us RAM for animation spritesheets...
+  * ...as these could be kept in FLASH.
+  */
+MicroBitImage::MicroBitImage(const int16_t x, const int16_t y)
+{
+    this->init(x,y,NULL);
+}
+
+/**
+  * Copy Constructor.
+  * Add ourselves as a reference to an existing MicroBitImage.
+  *
+  * @param image The MicroBitImage to reference.
+  *
+  * @code
+  * MicroBitImage i("0,1,0,1,0\n");
+  * MicroBitImage i2(i); //points to i
+  * @endcode
+  */
+MicroBitImage::MicroBitImage(const MicroBitImage &image)
+{
+    ptr = image.ptr;
+    ptr->incr();
+}
+
+/**
+  * Constructor.
+  * Create a blank bitmap representation of a given size.
+  *
+  * @param s A text based representation of the image given whitespace delimited numeric values.
+  *
+  * @code
+  * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+  * @endcode
+  */
+MicroBitImage::MicroBitImage(const char *s)
+{
+    int width = 0;
+    int height = 0;
+    int count = 0;
+    int digit = 0;
+
+    char parseBuf[10];
+
+    const char *parseReadPtr;
+    char *parseWritePtr;
+    uint8_t *bitmapPtr;
+
+    if (s == NULL)
+    {
+        init_empty();
+        return;
+    }
+
+    // First pass: Parse the string to determine the geometry of the image.
+    // We do this from first principles to avoid unecessary load of the strtok() libs etc.
+    parseReadPtr = s;
+
+    while (*parseReadPtr)
+    {
+        if (isdigit(*parseReadPtr))
+        {
+            // Ignore numbers.
+            digit = 1;
+        }
+        else if (*parseReadPtr =='\n')
+        {
+            if (digit)
+            {
+                count++;
+                digit = 0;
+            }
+
+            height++;
+
+            width = count > width ? count : width;
+            count = 0;
+        }
+        else
+        {
+            if (digit)
+            {
+                count++;
+                digit = 0;
+            }
+        }
+
+        parseReadPtr++;
+    }
+
+    this->init(width, height, NULL);
+
+    // Second pass: collect the data.
+    parseReadPtr = s;
+    parseWritePtr = parseBuf;
+    bitmapPtr = this->getBitmap();
+
+    while (*parseReadPtr)
+    {
+        if (isdigit(*parseReadPtr))
+        {
+            *parseWritePtr = *parseReadPtr;
+            parseWritePtr++;
+        }
+        else
+        {
+            *parseWritePtr = 0;
+            if (parseWritePtr > parseBuf)
+            {
+                *bitmapPtr = atoi(parseBuf);
+                bitmapPtr++;
+                parseWritePtr = parseBuf;
+            }
+        }
+
+        parseReadPtr++;
+    }
+}
+
+/**
+  * Constructor.
+  * Create an image from a specially prepared constant array, with no copying. Will call ptr->incr().
+  *
+  * @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height are 16 bit. The literal has to be 4-byte aligned.
+  *
+  * @code
+  * static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i((ImageData*)(void*)heart);
+  * @endcode
+  */
+MicroBitImage::MicroBitImage(ImageData *p)
+{
+    ptr = p;
+    ptr->incr();
+}
+
+/**
+  * Get current ptr, do not decr() it, and set the current instance to empty image.
+  *
+  * This is to be used by specialized runtimes which pass ImageData around.
+  */
+ImageData *MicroBitImage::leakData()
+{
+    ImageData* res = ptr;
+    init_empty();
+    return res;
+}
+
+
+/**
+  * Constructor.
+  * Create a bitmap representation of a given size, based on a given buffer.
+  *
+  * @param x the width of the image.
+  *
+  * @param y the height of the image.
+  *
+  * @param bitmap a 2D array representing the image.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart);
+  * @endcode
+  */
+MicroBitImage::MicroBitImage(const int16_t x, const int16_t y, const uint8_t *bitmap)
+{
+    this->init(x,y,bitmap);
+}
+
+/**
+  * Destructor.
+  *
+  * Removes buffer resources held by the instance.
+  */
+MicroBitImage::~MicroBitImage()
+{
+    ptr->decr();
+}
+
+/**
+  * Internal constructor which defaults to the EmptyImage instance variable
+  */
+void MicroBitImage::init_empty()
+{
+    ptr = (ImageData*)(void*)empty;
+}
+
+/**
+  * Internal constructor which provides sanity checking and initialises class properties.
+  *
+  * @param x the width of the image
+  *
+  * @param y the height of the image
+  *
+  * @param bitmap an array of integers that make up an image.
+  */
+void MicroBitImage::init(const int16_t x, const int16_t y, const uint8_t *bitmap)
+{
+    //sanity check size of image - you cannot have a negative sizes
+    if(x < 0 || y < 0)
+    {
+        init_empty();
+        return;
+    }
+
+
+    // Create a copy of the array
+    ptr = (ImageData*)malloc(sizeof(ImageData) + x * y);
+    ptr->init();
+    ptr->width = x;
+    ptr->height = y;
+
+    // create a linear buffer to represent the image. We could use a jagged/2D array here, but experimentation
+    // showed this had a negative effect on memory management (heap fragmentation etc).
+
+    if (bitmap)
+        this->printImage(x,y,bitmap);
+    else
+        this->clear();
+}
+
+/**
+  * Copy assign operation.
+  *
+  * Called when one MicroBitImage is assigned the value of another using the '=' operator.
+  *
+  * Decrement our reference count and free up the buffer as necessary.
+  *
+  * Then, update our buffer to refer to that of the supplied MicroBitImage,
+  * and increase its reference count.
+  *
+  * @param s The MicroBitImage to reference.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart);
+  * MicroBitImage i1();
+  * i1 = i; // i1 now references i
+  * @endcode
+  */
+MicroBitImage& MicroBitImage::operator = (const MicroBitImage& i)
+{
+    if(ptr == i.ptr)
+        return *this;
+
+    ptr->decr();
+    ptr = i.ptr;
+    ptr->incr();
+
+    return *this;
+}
+
+/**
+  * Equality operation.
+  *
+  * Called when one MicroBitImage is tested to be equal to another using the '==' operator.
+  *
+  * @param i The MicroBitImage to test ourselves against.
+  *
+  * @return true if this MicroBitImage is identical to the one supplied, false otherwise.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * MicroBitImage i();
+  * MicroBitImage i1();
+  *
+  * if(i == i1) //will be true
+  *     display.scroll("true");
+  * @endcode
+  */
+bool MicroBitImage::operator== (const MicroBitImage& i)
+{
+    if (ptr == i.ptr)
+        return true;
+    else
+        return (ptr->width == i.ptr->width && ptr->height == i.ptr->height && (memcmp(getBitmap(), i.ptr->data, getSize())==0));
+}
+
+
+/**
+  * Resets all pixels in this image to 0.
+  *
+  * @code
+  * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+  * i.clear();
+  * @endcode
+  */
+void MicroBitImage::clear()
+{
+    memclr(getBitmap(), getSize());
+}
+
+/**
+  * Sets the pixel at the given co-ordinates to a given value.
+  *
+  * @param x The co-ordinate of the pixel to change.
+  *
+  * @param y The co-ordinate of the pixel to change.
+  *
+  * @param value The new value of the pixel (the brightness level 0-255)
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+  * i.setPixelValue(0,0,255);
+  * @endcode
+  *
+  * @note all coordinates originate from the top left of an image.
+  */
+int MicroBitImage::setPixelValue(int16_t x , int16_t y, uint8_t value)
+{
+    //sanity check
+    if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    this->getBitmap()[y*getWidth()+x] = value;
+    return MICROBIT_OK;
+}
+
+/**
+  * Retreives the value of a given pixel.
+  *
+  * @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image.
+  *
+  * @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image.
+  *
+  * @return The value assigned to the given pixel location (the brightness level 0-255), or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * MicroBitImage i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image
+  * i.getPixelValue(0,0); //should be 0;
+  * @endcode
+  */
+int MicroBitImage::getPixelValue(int16_t x , int16_t y)
+{
+    //sanity check
+    if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    return this->getBitmap()[y*getWidth()+x];
+}
+
+/**
+  * Replaces the content of this image with that of a given 2D array representing
+  * the image.
+  *
+  * @param x the width of the image. Must be within the dimensions of the image.
+  *
+  * @param y the width of the image. Must be within the dimensions of the image.
+  *
+  * @param bitmap a 2D array representing the image.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i();
+  * i.printImage(0,0,heart);
+  * @endcode
+  *
+  * @note all coordinates originate from the top left of an image.
+  */
+int MicroBitImage::printImage(int16_t width, int16_t height, const uint8_t *bitmap)
+{
+    const uint8_t *pIn;
+    uint8_t *pOut;
+    int pixelsToCopyX, pixelsToCopyY;
+
+    // Sanity check.
+    if (width <= 0 || width <= 0 || bitmap == NULL)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Calcualte sane start pointer.
+    pixelsToCopyX = min(width,this->getWidth());
+    pixelsToCopyY = min(height,this->getHeight());
+
+    pIn = bitmap;
+    pOut = this->getBitmap();
+
+    // Copy the image, stride by stride.
+    for (int i=0; i<pixelsToCopyY; i++)
+    {
+        memcpy(pOut, pIn, pixelsToCopyX);
+        pIn += width;
+        pOut += this->getWidth();
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Pastes a given bitmap at the given co-ordinates.
+  *
+  * Any pixels in the relvant area of this image are replaced.
+  *
+  * @param image The MicroBitImage to paste.
+  *
+  * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0.
+  *
+  * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0.
+  *
+  * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 otherwise.  Defaults to 0.
+  *
+  * @return The number of pixels written.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart); // a big heart
+  * i.paste(i, -5, 0); // a small heart
+  * @endcode
+  */
+int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8_t alpha)
+{
+    uint8_t *pIn, *pOut;
+    int cx, cy;
+    int pxWritten = 0;
+
+    // Sanity check.
+    // We permit writes that overlap us, but ones that are clearly out of scope we can filter early.
+    if (x >= getWidth() || y >= getHeight() || x+image.getWidth() <= 0 || y+image.getHeight() <= 0)
+        return 0;
+
+    //Calculate the number of byte we need to copy in each dimension.
+    cx = x < 0 ? min(image.getWidth() + x, getWidth()) : min(image.getWidth(), getWidth() - x);
+    cy = y < 0 ? min(image.getHeight() + y, getHeight()) : min(image.getHeight(), getHeight() - y);
+
+    // Calculate sane start pointer.
+    pIn = image.ptr->data;
+    pIn += (x < 0) ? -x : 0;
+    pIn += (y < 0) ? -image.getWidth()*y : 0;
+
+    pOut = getBitmap();
+    pOut += (x > 0) ? x : 0;
+    pOut += (y > 0) ? getWidth()*y : 0;
+
+    // Copy the image, stride by stride
+    // If we want primitive transparecy, we do this byte by byte.
+    // If we don't, use a more efficient block memory copy instead. Every little helps!
+
+    if (alpha)
+    {
+        for (int i=0; i<cy; i++)
+        {
+            for (int j=0; j<cx; j++)
+            {
+                // Copy this byte if appropriate.
+                if (*(pIn+j) != 0){
+                    *(pOut+j) = *(pIn+j);
+                    pxWritten++;
+                }
+            }
+
+            pIn += image.getWidth();
+            pOut += getWidth();
+        }
+    }
+    else
+    {
+        for (int i=0; i<cy; i++)
+        {
+            memcpy(pOut, pIn, cx);
+
+            pxWritten += cx;
+            pIn += image.getWidth();
+            pOut += getWidth();
+        }
+    }
+
+    return pxWritten;
+}
+
+/**
+  * Prints a character to the display at the given location
+  *
+  * @param c The character to display.
+  *
+  * @param x The x co-ordinate of on the image to place the top left of the character. Defaults to 0.
+  *
+  * @param y The y co-ordinate of on the image to place the top left of the character. Defaults to 0.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * MicroBitImage i(5,5);
+  * i.print('a');
+  * @endcode
+  */
+int MicroBitImage::print(char c, int16_t x, int16_t y)
+{
+    unsigned char v;
+    int x1, y1;
+
+    MicroBitFont font = MicroBitFont::getSystemFont();
+
+    // Sanity check. Silently ignore anything out of bounds.
+    if (x >= getWidth() || y >= getHeight() || c < MICROBIT_FONT_ASCII_START || c > font.asciiEnd)
+        return MICROBIT_INVALID_PARAMETER;
+
+    // Paste.
+    int offset = (c-MICROBIT_FONT_ASCII_START) * 5;
+
+    for (int row=0; row<MICROBIT_FONT_HEIGHT; row++)
+    {
+        v = (char)*(font.characters + offset);
+
+        offset++;
+
+        // Update our Y co-ord write position
+        y1 = y+row;
+
+        for (int col = 0; col < MICROBIT_FONT_WIDTH; col++)
+        {
+            // Update our X co-ord write position
+            x1 = x+col;
+
+            if (x1 < getWidth() && y1 < getHeight())
+                this->getBitmap()[y1*getWidth()+x1] = (v & (0x10 >> col)) ? 255 : 0;
+        }
+    }
+
+    return MICROBIT_OK;
+}
+
+
+/**
+  * Shifts the pixels in this Image a given number of pixels to the left.
+  *
+  * @param n The number of pixels to shift.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart); // a big heart
+  * i.shiftLeft(5); // a small heart
+  * @endcode
+  */
+int MicroBitImage::shiftLeft(int16_t n)
+{
+    uint8_t *p = getBitmap();
+    int pixels = getWidth()-n;
+
+    if (n <= 0 )
+        return MICROBIT_INVALID_PARAMETER;
+
+    if(n >= getWidth())
+    {
+        clear();
+        return MICROBIT_OK;
+    }
+
+    for (int y = 0; y < getHeight(); y++)
+    {
+        // Copy, and blank fill the rightmost column.
+        memcpy(p, p+n, pixels);
+        memclr(p+pixels, n);
+        p += getWidth();
+    }
+
+    return MICROBIT_OK;
+}
+
+/**
+  * Shifts the pixels in this Image a given number of pixels to the right.
+  *
+  * @param n The number of pixels to shift.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart); // a big heart
+  * i.shiftLeft(5); // a small heart
+  * i.shiftRight(5); // a big heart
+  * @endcode
+  */
+int MicroBitImage::shiftRight(int16_t n)
+{
+    uint8_t *p = getBitmap();
+    int pixels = getWidth()-n;
+
+    if (n <= 0)
+        return MICROBIT_INVALID_PARAMETER;
+
+    if(n >= getWidth())
+    {
+        clear();
+        return MICROBIT_OK;
+    }
+
+    for (int y = 0; y < getHeight(); y++)
+    {
+        // Copy, and blank fill the leftmost column.
+        memmove(p+n, p, pixels);
+        memclr(p, n);
+        p += getWidth();
+    }
+
+    return MICROBIT_OK;
+}
+
+
+/**
+  * Shifts the pixels in this Image a given number of pixels to upward.
+  *
+  * @param n The number of pixels to shift.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart);
+  * i.shiftUp(1);
+  * @endcode
+  */
+int MicroBitImage::shiftUp(int16_t n)
+{
+    uint8_t *pOut, *pIn;
+
+    if (n <= 0 )
+        return MICROBIT_INVALID_PARAMETER;
+
+    if(n >= getHeight())
+    {
+        clear();
+        return MICROBIT_OK;
+    }
+
+    pOut = getBitmap();
+    pIn = getBitmap()+getWidth()*n;
+
+    for (int y = 0; y < getHeight(); y++)
+    {
+        // Copy, and blank fill the leftmost column.
+        if (y < getHeight()-n)
+            memcpy(pOut, pIn, getWidth());
+        else
+            memclr(pOut, getWidth());
+
+        pIn += getWidth();
+        pOut += getWidth();
+    }
+
+    return MICROBIT_OK;
+}
+
+
+/**
+  * Shifts the pixels in this Image a given number of pixels to downward.
+  *
+  * @param n The number of pixels to shift.
+  *
+  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart);
+  * i.shiftDown(1);
+  * @endcode
+  */
+int MicroBitImage::shiftDown(int16_t n)
+{
+    uint8_t *pOut, *pIn;
+
+    if (n <= 0 )
+        return MICROBIT_INVALID_PARAMETER;
+
+    if(n >= getHeight())
+    {
+        clear();
+        return MICROBIT_OK;
+    }
+
+    pOut = getBitmap() + getWidth()*(getHeight()-1);
+    pIn = pOut - getWidth()*n;
+
+    for (int y = 0; y < getHeight(); y++)
+    {
+        // Copy, and blank fill the leftmost column.
+        if (y < getHeight()-n)
+            memcpy(pOut, pIn, getWidth());
+        else
+            memclr(pOut, getWidth());
+
+        pIn -= getWidth();
+        pOut -= getWidth();
+    }
+
+    return MICROBIT_OK;
+}
+
+
+/**
+  * Converts the bitmap to a csv ManagedString.
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart);
+  * uBit.serial.printString(i.toString()); // "0,1,0,1,0,0,0,0,0,0\n..."
+  * @endcode
+  */
+ManagedString MicroBitImage::toString()
+{
+    //width including commans and \n * height
+    int stringSize = getSize() * 2;
+
+    //plus one for string terminator
+    char parseBuffer[stringSize + 1];
+
+    parseBuffer[stringSize] = '\0';
+
+    uint8_t *bitmapPtr = getBitmap();
+
+    int parseIndex = 0;
+    int widthCount = 0;
+
+    while (parseIndex < stringSize)
+    {
+        if(*bitmapPtr)
+            parseBuffer[parseIndex] = '1';
+        else
+            parseBuffer[parseIndex] = '0';
+
+        parseIndex++;
+
+        if(widthCount == getWidth()-1)
+        {
+            parseBuffer[parseIndex] = '\n';
+            widthCount = 0;
+        }
+        else
+        {
+            parseBuffer[parseIndex] = ',';
+            widthCount++;
+        }
+
+        parseIndex++;
+        bitmapPtr++;
+    }
+
+    return ManagedString(parseBuffer);
+}
+
+/**
+  * Crops the image to the given dimensions.
+  *
+  * @param startx the location to start the crop in the x-axis
+  *
+  * @param starty the location to start the crop in the y-axis
+  *
+  * @param width the width of the desired cropped region
+  *
+  * @param height the height of the desired cropped region
+  *
+  * @code
+  * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
+  * MicroBitImage i(10,5,heart);
+  * i.crop(0,0,2,2).toString() // "0,1\n1,1\n"
+  * @endcode
+  */
+MicroBitImage MicroBitImage::crop(int startx, int starty, int cropWidth, int cropHeight)
+{
+    int newWidth = startx + cropWidth;
+    int newHeight = starty + cropHeight;
+
+    if (newWidth >= getWidth() || newWidth <=0)
+        newWidth = getWidth();
+
+    if (newHeight >= getHeight() || newHeight <= 0)
+        newHeight = getHeight();
+
+    //allocate our storage.
+    uint8_t cropped[newWidth * newHeight];
+
+    //calculate the pointer to where we want to begin cropping
+    uint8_t *copyPointer = getBitmap() + (getWidth() * starty) + startx;
+
+    //get a reference to our storage
+    uint8_t *pastePointer = cropped;
+
+    //go through row by row and select our image.
+    for (int i = starty; i < newHeight; i++)
+    {
+        memcpy(pastePointer, copyPointer, newWidth);
+
+        copyPointer += getWidth();
+        pastePointer += newHeight;
+    }
+
+    return MicroBitImage(newWidth, newHeight, cropped);
+}
+
+/**
+  * Check if image is read-only (i.e., residing in flash).
+  */
+bool MicroBitImage::isReadOnly()
+{
+    return ptr->isReadOnly();
+}
+
+/**
+  * Create a copy of the image bitmap. Used particularly, when isReadOnly() is true.
+  *
+  * @return an instance of MicroBitImage which can be modified independently of the current instance
+  */
+MicroBitImage MicroBitImage::clone()
+{
+    return MicroBitImage(getWidth(), getHeight(), getBitmap());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/types/PacketBuffer.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,326 @@
+/*
+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 "PacketBuffer.h"
+#include "ErrorNo.h"
+
+// Create the EmptyPacket reference.
+PacketBuffer PacketBuffer::EmptyPacket = PacketBuffer(1);
+
+/**
+  * Default Constructor.
+  * Creates an empty Packet Buffer.
+  *
+  * @code
+  * PacketBuffer p();
+  * @endcode
+  */
+PacketBuffer::PacketBuffer()
+{
+    this->init(NULL, 0, 0);
+}
+
+/**
+  * Constructor.
+  * Creates a new PacketBuffer of the given size.
+  *
+  * @param length The length of the buffer to create.
+  *
+  * @code
+  * PacketBuffer p(16);         // Creates a PacketBuffer 16 bytes long.
+  * @endcode
+  */
+PacketBuffer::PacketBuffer(int length)
+{
+    this->init(NULL, length, 0);
+}
+
+/**
+  * Constructor.
+  * Creates an empty Packet Buffer of the given size,
+  * and fills it with the data provided.
+  *
+  * @param data The data with which to fill the buffer.
+  *
+  * @param length The length of the buffer to create.
+  *
+  * @param rssi The radio signal strength at the time this packet was recieved. Defaults to 0.
+  *
+  * @code
+  * uint8_t buf = {13,5,2};
+  * PacketBuffer p(buf, 3);         // Creates a PacketBuffer 3 bytes long.
+  * @endcode
+  */
+PacketBuffer::PacketBuffer(uint8_t *data, int length, int rssi)
+{
+    this->init(data, length, rssi);
+}
+
+/**
+  * Copy Constructor.
+  * Add ourselves as a reference to an existing PacketBuffer.
+  *
+  * @param buffer The PacketBuffer to reference.
+  *
+  * @code
+  * PacketBuffer p();
+  * PacketBuffer p2(p); // Refers to the same packet as p.
+  * @endcode
+  */
+PacketBuffer::PacketBuffer(const PacketBuffer &buffer)
+{
+    ptr = buffer.ptr;
+    ptr->incr();
+}
+
+/**
+  * Internal constructor-initialiser.
+  *
+  * @param data The data with which to fill the buffer.
+  *
+  * @param length The length of the buffer to create.
+  *
+  * @param rssi The radio signal strength at the time this packet was recieved.
+  */
+void PacketBuffer::init(uint8_t *data, int length, int rssi)
+{
+    if (length < 0)
+        length = 0;
+
+    ptr = (PacketData *) malloc(sizeof(PacketData) + length);
+    ptr->init();
+
+    ptr->length = length;
+    ptr->rssi = rssi;
+
+    // Copy in the data buffer, if provided.
+    if (data)
+        memcpy(ptr->payload, data, length);
+}
+
+/**
+  * Destructor.
+  *
+  * Removes buffer resources held by the instance.
+  */
+PacketBuffer::~PacketBuffer()
+{
+    ptr->decr();
+}
+
+/**
+  * Copy assign operation.
+  *
+  * Called when one PacketBuffer is assigned the value of another using the '=' operator.
+  *
+  * Decrements our reference count and free up the buffer as necessary.
+  *
+  * Then, update our buffer to refer to that of the supplied PacketBuffer,
+  * and increase its reference count.
+  *
+  * @param p The PacketBuffer to reference.
+  *
+  * @code
+  * uint8_t buf = {13,5,2};
+  * PacketBuffer p1(16);
+  * PacketBuffer p2(buf, 3);
+  *
+  * p1 = p2;
+  * @endcode
+  */
+PacketBuffer& PacketBuffer::operator = (const PacketBuffer &p)
+{
+    if(ptr == p.ptr)
+        return *this;
+
+    ptr->decr();
+    ptr = p.ptr;
+    ptr->incr();
+
+    return *this;
+}
+
+/**
+  * Array access operation (read).
+  *
+  * Called when a PacketBuffer is dereferenced with a [] operation.
+  *
+  * Transparently map this through to the underlying payload for elegance of programming.
+  *
+  * @code
+  * PacketBuffer p1(16);
+  * uint8_t data = p1[0];
+  * @endcode
+  */
+uint8_t PacketBuffer::operator [] (int i) const
+{
+    return ptr->payload[i];
+}
+
+/**
+  * Array access operation (modify).
+  *
+  * Called when a PacketBuffer is dereferenced with a [] operation.
+  *
+  * Transparently map this through to the underlying payload for elegance of programming.
+  *
+  * @code
+  * PacketBuffer p1(16);
+  * p1[0] = 42;
+  * @endcode
+  */
+uint8_t& PacketBuffer::operator [] (int i)
+{
+    return ptr->payload[i];
+}
+
+/**
+  * Equality operation.
+  *
+  * Called when one PacketBuffer is tested to be equal to another using the '==' operator.
+  *
+  * @param p The PacketBuffer to test ourselves against.
+  *
+  * @return true if this PacketBuffer is identical to the one supplied, false otherwise.
+  *
+  * @code
+  * MicroBitDisplay display;
+  * uint8_t buf = {13,5,2};
+  * PacketBuffer p1();
+  * PacketBuffer p2();
+  *
+  * if(p1 == p2)                    // will be true
+  *     display.scroll("same!");
+  * @endcode
+  */
+bool PacketBuffer::operator== (const PacketBuffer& p)
+{
+    if (ptr == p.ptr)
+        return true;
+    else
+        return (ptr->length == p.ptr->length && (memcmp(ptr->payload, p.ptr->payload, ptr->length)==0));
+}
+
+/**
+  * Sets the byte at the given index to value provided.
+  *
+  * @param position The index of the byte to change.
+  *
+  * @param value The new value of the byte (0-255).
+  *
+  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * PacketBuffer p1(16);
+  * p1.setByte(0,255);              // Sets the first byte in the buffer to the value 255.
+  * @endcode
+  */
+int PacketBuffer::setByte(int position, uint8_t value)
+{
+    if (position < ptr->length)
+    {
+        ptr->payload[position] = value;
+        return MICROBIT_OK;
+    }
+    else
+    {
+        return MICROBIT_INVALID_PARAMETER;
+    }
+}
+
+/**
+  * Determines the value of the given byte in the packet.
+  *
+  * @param position The index of the byte to read.
+  *
+  * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER.
+  *
+  * @code
+  * PacketBuffer p1(16);
+  * p1.setByte(0,255);              // Sets the first byte in the buffer to the value 255.
+  * p1.getByte(0);                  // Returns 255.
+  * @endcode
+  */
+int PacketBuffer::getByte(int position)
+{
+    if (position < ptr->length)
+        return ptr->payload[position];
+    else
+        return MICROBIT_INVALID_PARAMETER;
+}
+
+/**
+  * Provide a pointer to a memory location containing the packet data.
+  *
+  * @return The contents of this packet, as an array of bytes.
+  */
+uint8_t*PacketBuffer::getBytes()
+{
+    return ptr->payload;
+}
+
+/**
+  * Gets number of bytes in this buffer
+  *
+  * @return The size of the buffer in bytes.
+  *
+  * @code
+  * PacketBuffer p1(16);
+  * p1.length(); // Returns 16.
+  * @endcode
+  */
+int PacketBuffer::length()
+{
+    return ptr->length;
+}
+
+/**
+  * Retrieves the received signal strength of this packet.
+  *
+  * @return The signal strength of the radio when this packet was received, in -dbM.
+  *
+  * @code
+  * PacketBuffer p1(16);
+  * p1.getRSSI();                 // Returns the received signal strength.
+  * @endcode
+  */
+int PacketBuffer::getRSSI()
+{
+    return ptr->rssi;
+}
+
+/**
+  * Sets the received signal strength of this packet.
+  *
+  * @code
+  * PacketBuffer p1(16);
+  * p1.setRSSI(37);
+  * @endcode
+  */
+void PacketBuffer::setRSSI(uint8_t rssi)
+{
+    ptr->rssi = rssi;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/types/RefCounted.cpp	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,98 @@
+/*
+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.
+*/
+
+/**
+  * Base class for payload for ref-counted objects. Used by ManagedString and MicroBitImage.
+  * There is no constructor, as this struct is typically malloc()ed.
+  */
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "RefCounted.h"
+#include "MicroBitDisplay.h"
+
+/**
+  * Initializes for one outstanding reference.
+  */
+void RefCounted::init()
+{
+    // Initialize to one reference (lowest bit set to 1)
+    refCount = 3;
+}
+
+/**
+  * Checks if the object resides in flash memory.
+  *
+  * @param t the object to check.
+  *
+  * @return true if the object resides in flash memory, false otherwise.
+  */
+static inline bool isReadOnlyInline(RefCounted *t)
+{
+    uint32_t refCount = t->refCount;
+
+    if (refCount == 0xffff)
+        return true; // object in flash
+
+    // Do some sanity checking while we're here
+    if (refCount == 1 ||        // object should have been deleted
+        (refCount & 1) == 0)    // refCount doesn't look right
+        microbit_panic(MICROBIT_HEAP_ERROR);
+
+    // Not read only
+    return false;
+}
+
+/**
+  * Checks if the object resides in flash memory.
+  *
+  * @return true if the object resides in flash memory, false otherwise.
+  */
+bool RefCounted::isReadOnly()
+{
+    return isReadOnlyInline(this);
+}
+
+/**
+  * Increment reference count.
+  */
+void RefCounted::incr()
+{
+    if (!isReadOnlyInline(this))
+        refCount += 2;
+}
+
+/**
+  * Decrement reference count.
+  */
+void RefCounted::decr()
+{
+    if (isReadOnlyInline(this))
+        return;
+
+    refCount -= 2;
+    if (refCount == 1) {
+        free(this);
+    }
+}