developer.mbed.org branch of Lancaster University's microbit library. The real home for this is https://github.com/lancaster-university/microbit
Dependents: MB02 asteroid_shooting
Revision 0:ee31ccbe9919, committed 2019-12-23
- Comitter:
- ikkeje
- Date:
- Mon Dec 23 10:31:28 2019 +0000
- Commit message:
- 1.1
Changed in this revision
diff -r 000000000000 -r ee31ccbe9919 LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE Mon Dec 23 10:31:28 2019 +0000 @@ -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.
diff -r 000000000000 -r ee31ccbe9919 README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Mon Dec 23 10:31:28 2019 +0000 @@ -0,0 +1,42 @@ +# microbit + +A collection of the commonly used components of the micro:bit runtime with a +standard configuration, to provide an easy to use interface for programming the micro:bit in C/C++. + +## 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/) | [microbit-dal](https://github.com/lancaster-university/microbit-dal) | [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 "MicroBit.h" + +MicroBit uBit; + +int main() +{ + uBit.init(); + + uBit.display.scroll("Hello world!"); +} +``` + +## BBC Community Guidelines + +[BBC Community Guidelines](https://www.microbit.co.uk/help#sect_cg)
diff -r 000000000000 -r ee31ccbe9919 inc/MicroBit.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/inc/MicroBit.h Mon Dec 23 10:31:28 2019 +0000 @@ -0,0 +1,658 @@ +/* +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_H +#define MICROBIT_H + +#include "mbed.h" + +#include "MicroBitConfig.h" +#include "MicroBitHeapAllocator.h" +#include "MicroBitDevice.h" +#include "ErrorNo.h" +#include "MicroBitSystemTimer.h" +#include "Matrix4.h" +#include "MicroBitCompat.h" +#include "MicroBitComponent.h" +#include "ManagedType.h" +#include "ManagedString.h" +#include "MicroBitImage.h" +#include "MicroBitFont.h" +#include "MicroBitEvent.h" +#include "DynamicPwm.h" +#include "MicroBitI2C.h" +#include "NotifyEvents.h" + +#include "MicroBitButton.h" +#include "MicroBitPin.h" +#include "MicroBitCompass.h" +#include "MicroBitCompassCalibrator.h" +#include "MicroBitAccelerometer.h" +#include "MicroBitThermometer.h" +#include "MicroBitLightSensor.h" +#include "MicroBitMultiButton.h" + +#include "MicroBitSerial.h" +#include "MicroBitIO.h" +#include "MicroBitMatrixMaps.h" +#include "MicroBitDisplay.h" + +#include "MicroBitFiber.h" +#include "MicroBitMessageBus.h" + +#include "MicroBitBLEManager.h" +#include "MicroBitRadio.h" +#include "MicroBitStorage.h" + +// MicroBit::flags values +#define MICROBIT_INITIALIZED 0x01 + +/** + * Class definition for a MicroBit device. + * + * Represents the device as a whole, and includes member variables that represent various device drivers + * used to control aspects of the micro:bit. + */ +class MicroBit +{ + private: + + /** + * A listener to perform actions as a result of Message Bus reflection. + * + * In some cases we want to perform lazy instantiation of components, such as + * the compass and the accelerometer, where we only want to add them to the idle + * fiber when someone has the intention of using these components. + */ + void onListenerRegisteredEvent(MicroBitEvent evt); + + uint8_t status; + + public: + + // Serial Interface + MicroBitSerial serial; + + // Reset Button + InterruptIn resetButton; + + // Persistent key value store + MicroBitStorage storage; + + // I2C Interface + MicroBitI2C i2c; + + // Device level Message Bus abstraction + MicroBitMessageBus messageBus; + + // Member variables to represent each of the core components on the device. + MicroBitDisplay display; + MicroBitButton buttonA; + MicroBitButton buttonB; + MicroBitMultiButton buttonAB; + MicroBitAccelerometer accelerometer; + MicroBitCompass compass; + MicroBitCompassCalibrator compassCalibrator; + MicroBitThermometer thermometer; + + //An object of available IO pins on the device + MicroBitIO io; + + // Bluetooth related member variables. + MicroBitBLEManager bleManager; + MicroBitRadio radio; + BLEDevice *ble; + + /** + * Constructor. + * + * Create a representation of a MicroBit device, which includes member variables + * that represent various device drivers used to control aspects of the micro:bit. + */ + MicroBit(); + + /** + * Post constructor initialisation method. + * + * This call will initialised the scheduler, memory allocator and Bluetooth stack. + * + * This is required as the Bluetooth stack can't be brought up in a + * static context i.e. in a constructor. + * + * @code + * uBit.init(); + * @endcode + * + * @note This method must be called before user code utilises any functionality + * contained by uBit. + */ + void init(); + + /** + * Return the friendly name for this device. + * + * @return A ManagedString representing the friendly name of this device. + * + * @code + * ManagedString name = uBit.getName(); + * @endcode + */ + static ManagedString getName(); + + /** + * Return the serial number of this device. + * + * @return A ManagedString representing the serial number of this device. + * + * @code + * ManagedString serialNumber = uBit.getSerial(); + * @endcode + */ + static ManagedString getSerial(); + + /** + * Will reset the micro:bit when called. + * + * @code + * uBit.reset(); + * @endcode + */ + void reset(); + + /** + * Delay execution for the given amount of time. + * + * If the scheduler is running, this will deschedule the current fiber and perform + * a power efficient, concurrent sleep operation. + * + * If the scheduler is disabled or we're running in an interrupt context, this + * will revert to a busy wait. + * + * Alternatively: wait, wait_ms, wait_us can be used which will perform a blocking sleep + * operation. + * + * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative. + * + * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero. + * + * @code + * uBit.sleep(20); //sleep for 20ms + * @endcode + * + * @note This operation is currently limited by the rate of the system timer, therefore + * the granularity of the sleep operation is limited to 6 ms unless the rate of + * the system timer is modified. + */ + void sleep(uint32_t milliseconds); + + /** + * Seed the pseudo random number generator using the hardware random number generator. + * + * @code + * uBit.seedRandom(); + * @endcode + */ + void seedRandom(); + + /** + * Seed the pseudo random number generator using the given value. + * + * @param seed The 32-bit value to seed the generator with. + * + * @code + * uBit.seedRandom(0xBB5EED); + * @endcode + */ + void seedRandom(uint32_t seed); + + + /** + * 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 generate 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 + * uBit.random(200); //a number between 0 and 199 + * @endcode + */ + int random(int max); + + /** + * Determine the time since this MicroBit was last reset. + * + * @return The time since the last reset, in milliseconds. + * + * @note This will value overflow after 1.6 months. + */ + //TODO: handle overflow case. + unsigned long systemTime(); + + /** + * Determine the version of the micro:bit runtime currently in use. + * + * @return A textual description of the version of the micro:bit runtime that + * is currently running on this device. + */ + const char *systemVersion(); + + /** + * Triggers a microbit panic where an loop will display a panic face + * and the status code, if provided. + * + * This loop will continue for panic_timeout iterations, defaults to 0 (infinite). + * + * panic_timeout can be configured via a call to microbit_panic_timeout. + * + * @param statusCode the status code of the associated error. + * + * @code + * microbit_panic_timeout(4); + * + * // will display loop for 4 iterations. + * uBit.panic(10); + * @endcode + */ + void panic(int statusCode = 0); + + /** + * 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(); + * + * uBit.addSystemComponent(display); + * @endcode + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_add_component(). + */ + int addSystemComponent(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(); + * + * uBit.addSystemComponent(display); + * + * uBit.removeSystemComponent(display); + * @endcode + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_remove_component(). + */ + int removeSystemComponent(MicroBitComponent *component); + + /** + * 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 + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_add_idle_component(). + */ + int addIdleComponent(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); + * + * uBit.addIdleComponent(accelerometer); + * + * uBit.removeIdleComponent(accelerometer); + * @endcode + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_remove_idle_component(). + */ + int removeIdleComponent(MicroBitComponent *component); +}; + +/** + * Return the friendly name for this device. + * + * @return A ManagedString representing the friendly name of this device. + * + * @code + * ManagedString name = uBit.getName(); + * @endcode + */ +inline ManagedString MicroBit::getName() +{ + return ManagedString(microbit_friendly_name()); +} + +/** + * Return the serial number of this device. + * + * @return A ManagedString representing the serial number of this device. + * + * @code + * ManagedString serialNumber = uBit.getSerial(); + * @endcode + */ +inline ManagedString MicroBit::getSerial() +{ + // We take to 16 bit numbers here, as we want the full range of ID bits, but don't want negative numbers... + int n1 = microbit_serial_number() & 0xffff; + int n2 = (microbit_serial_number() >> 16) & 0xffff; + + // Simply concat the two numbers. + ManagedString s1(n1); + ManagedString s2(n2); + + return s1 + s2; +} + +/** + * Will reset the micro:bit when called. + * + * @code + * uBit.reset(); + * @endcode + */ +inline void MicroBit::reset() +{ + if(ble && ble->getGapState().connected) { + + // We have a connected BLE peer. Disconnect the BLE session. + ble->gap().disconnect(Gap::REMOTE_USER_TERMINATED_CONNECTION); + + // Wait a little while for the connection to drop. + wait_ms(100); + } + + microbit_reset(); +} + +/** + * Delay execution for the given amount of time. + * + * If the scheduler is running, this will deschedule the current fiber and perform + * a power efficient, concurrent sleep operation. + * + * If the scheduler is disabled or we're running in an interrupt context, this + * will revert to a busy wait. + * + * Alternatively: wait, wait_ms, wait_us can be used which will perform a blocking sleep + * operation. + * + * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative. + * + * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero. + * + * @code + * uBit.sleep(20); //sleep for 20ms + * @endcode + * + * @note This operation is currently limited by the rate of the system timer, therefore + * the granularity of the sleep operation is limited to 6 ms unless the rate of + * the system timer is modified. + */ +inline void MicroBit::sleep(uint32_t milliseconds) +{ + fiber_sleep(milliseconds); +} + +/** + * 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 generate 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 + * uBit.random(200); //a number between 0 and 199 + * @endcode + */ +inline int MicroBit::random(int max) +{ + return microbit_random(max); +} + +/** + * Seed the pseudo random number generator using the hardware random number generator. + * + * @code + * uBit.seedRandom(); + * @endcode + */ +inline void MicroBit::seedRandom() +{ + microbit_seed_random(); +} + + +/** + * Seed the pseudo random number generator using the given value. + * + * @param seed The 32-bit value to seed the generator with. + * + * @code + * uBit.seedRandom(0xBB5EED); + * @endcode + */ +inline void MicroBit::seedRandom(uint32_t seed) +{ + microbit_seed_random(seed); +} + + +/** + * 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(); + * + * uBit.addSystemComponent(display); + * @endcode + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_add_component(). + */ +inline int MicroBit::addSystemComponent(MicroBitComponent *component) +{ + return system_timer_add_component(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(); + * + * uBit.addSystemComponent(display); + * + * uBit.removeSystemComponent(display); + * @endcode + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_remove_component(). + */ +inline int MicroBit::removeSystemComponent(MicroBitComponent *component) +{ + return system_timer_remove_component(component); +} + +/** + * 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 + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_add_idle_component(). + */ +inline int MicroBit::addIdleComponent(MicroBitComponent *component) +{ + return fiber_add_idle_component(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); + * + * uBit.addIdleComponent(accelerometer); + * + * uBit.removeIdleComponent(accelerometer); + * @endcode + * + * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_remove_idle_component(). + */ +inline int MicroBit::removeIdleComponent(MicroBitComponent *component) +{ + return fiber_remove_idle_component(component); +} + + +/** + * Determine the time since this MicroBit was last reset. + * + * @return The time since the last reset, in milliseconds. + * + * @note This will value overflow after 1.6 months. + */ +inline unsigned long MicroBit::systemTime() +{ + return system_timer_current_time(); +} + + +/** + * Determine the version of the micro:bit runtime currently in use. + * + * @return A textual description of the version of the micro:bit runtime that + * is currently running on this device. + */ +inline const char *MicroBit::systemVersion() +{ + return microbit_dal_version(); +} + +/** + * Triggers a microbit panic where an loop will display a panic face + * and the status code, if provided. + * + * This loop will continue for panic_timeout iterations, defaults to 0 (infinite). + * + * panic_timeout can be configured via a call to microbit_panic_timeout. + * + * @param statusCode the status code of the associated error. + * + * @code + * microbit_panic_timeout(4); + * + * // will display loop for 4 iterations. + * uBit.panic(10); + * @endcode + */ +inline void MicroBit::panic(int statusCode) +{ + //show error and enter infinite while + microbit_panic(statusCode); +} + +#endif \ No newline at end of file
diff -r 000000000000 -r ee31ccbe9919 microbit-dal.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/microbit-dal.lib Mon Dec 23 10:31:28 2019 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/teams/Lancaster-University/code/microbit-dal/#eb91bba49623
diff -r 000000000000 -r ee31ccbe9919 module.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/module.json Mon Dec 23 10:31:28 2019 +0000 @@ -0,0 +1,13 @@ +{ + "name": "microbit", + "version": "2.0.0-rc4", + "description": "A simple to use collection of the most commonly used components in the micro:bit runtime", + "license": "MIT", + "dependencies": { + "microbit-dal": "lancaster-university/microbit-dal" + }, + "extraIncludes": [ + "inc" + ], + "targetDependencies": {} +} \ No newline at end of file
diff -r 000000000000 -r ee31ccbe9919 source/MicroBit.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/MicroBit.cpp Mon Dec 23 10:31:28 2019 +0000 @@ -0,0 +1,223 @@ +/* +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" +/* + * 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 "MicroBit.h" + +#include "nrf_soc.h" + +/* + * Return to our predefined compiler settings. + */ +#if !defined(__arm) +#pragma GCC diagnostic pop +#endif + +#if CONFIG_ENABLED(MICROBIT_DBG) +// We create and initialize to NULL here, but MicroBitSerial will automatically update this as needed in its constructor. +RawSerial* SERIAL_DEBUG = NULL; +#endif + +/** + * Constructor. + * + * Create a representation of a MicroBit device, which includes member variables + * that represent various device drivers used to control aspects of the micro:bit. + */ +MicroBit::MicroBit() : + serial(USBTX, USBRX), + resetButton(MICROBIT_PIN_BUTTON_RESET), + storage(), + i2c(I2C_SDA0, I2C_SCL0), + messageBus(), + display(), + buttonA(MICROBIT_PIN_BUTTON_A, MICROBIT_ID_BUTTON_A), + buttonB(MICROBIT_PIN_BUTTON_B, MICROBIT_ID_BUTTON_B), + buttonAB(MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B, MICROBIT_ID_BUTTON_AB), + accelerometer(i2c), + compass(i2c, accelerometer, storage), + compassCalibrator(compass, accelerometer, display), + thermometer(storage), + io(MICROBIT_ID_IO_P0,MICROBIT_ID_IO_P1,MICROBIT_ID_IO_P2, + MICROBIT_ID_IO_P3,MICROBIT_ID_IO_P4,MICROBIT_ID_IO_P5, + MICROBIT_ID_IO_P6,MICROBIT_ID_IO_P7,MICROBIT_ID_IO_P8, + MICROBIT_ID_IO_P9,MICROBIT_ID_IO_P10,MICROBIT_ID_IO_P11, + MICROBIT_ID_IO_P12,MICROBIT_ID_IO_P13,MICROBIT_ID_IO_P14, + MICROBIT_ID_IO_P15,MICROBIT_ID_IO_P16,MICROBIT_ID_IO_P19, + MICROBIT_ID_IO_P20), + bleManager(storage), + radio(), + ble(NULL) +{ + // Clear our status + status = 0; + + // Bring up soft reset functionality as soon as possible. + resetButton.mode(PullUp); + resetButton.fall(this, &MicroBit::reset); +} + +/** + * Post constructor initialisation method. + * + * This call will initialised the scheduler, memory allocator and Bluetooth stack. + * + * This is required as the Bluetooth stack can't be brought up in a + * static context i.e. in a constructor. + * + * @code + * uBit.init(); + * @endcode + * + * @note This method must be called before user code utilises any functionality + * contained by uBit. + */ +void MicroBit::init() +{ + if (status & MICROBIT_INITIALIZED) + return; + +#if CONFIG_ENABLED(MICROBIT_HEAP_ALLOCATOR) + // Bring up a nested heap allocator. + microbit_create_nested_heap(MICROBIT_NESTED_HEAP_SIZE); +#endif + + // Bring up fiber scheduler. + scheduler_init(messageBus); + + // Seed our random number generator + seedRandom(); + + // Create an event handler to trap any handlers being created for I2C services. + // We do this to enable initialisation of those services only when they're used, + // which saves processor time, memeory and battery life. + messageBus.listen(MICROBIT_ID_MESSAGE_BUS_LISTENER, MICROBIT_EVT_ANY, this, &MicroBit::onListenerRegisteredEvent); + + status |= MICROBIT_INITIALIZED; + +#if CONFIG_ENABLED(MICROBIT_BLE_PAIRING_MODE) + // Test if we need to enter BLE pairing mode... + int i=0; + sleep(100); + while (buttonA.isPressed() && buttonB.isPressed() && i<10) + { + sleep(100); + i++; + + if (i == 10) + { +#if CONFIG_ENABLED(MICROBIT_HEAP_ALLOCATOR) && CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD) + microbit_create_heap(MICROBIT_SD_GATT_TABLE_START + MICROBIT_SD_GATT_TABLE_SIZE, MICROBIT_SD_LIMIT); +#endif + // Start the BLE stack, if it isn't already running. + if (!ble) + { + bleManager.init(getName(), getSerial(), messageBus, true); + ble = bleManager.ble; + } + + // Enter pairing mode, using the LED matrix for any necessary pairing operations + bleManager.pairingMode(display, buttonA); + } + } +#endif + + // Attempt to bring up a second heap region, using unused memory normally reserved for Soft Device. +#if CONFIG_ENABLED(MICROBIT_HEAP_ALLOCATOR) && CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD) +#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) + microbit_create_heap(MICROBIT_SD_GATT_TABLE_START + MICROBIT_SD_GATT_TABLE_SIZE, MICROBIT_SD_LIMIT); +#else + microbit_create_heap(MICROBIT_SRAM_BASE, MICROBIT_SD_LIMIT); +#endif +#endif + +#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) + // Start the BLE stack, if it isn't already running. + if (!ble) + { + bleManager.init(getName(), getSerial(), messageBus, false); + ble = bleManager.ble; + } +#endif +} + +/** + * A listener to perform actions as a result of Message Bus reflection. + * + * In some cases we want to perform lazy instantiation of components, such as + * the compass and the accelerometer, where we only want to add them to the idle + * fiber when someone has the intention of using these components. + */ +void MicroBit::onListenerRegisteredEvent(MicroBitEvent evt) +{ + switch(evt.value) + { + case MICROBIT_ID_BUTTON_AB: + // A user has registered to receive events from the buttonAB multibutton. + // Disable click events from being generated by ButtonA and ButtonB, and defer the + // control of this to the multibutton handler. + // + // This way, buttons look independent unless a buttonAB is requested, at which + // point button A+B clicks can be correclty handled without breaking + // causal ordering. + buttonA.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + buttonB.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + buttonAB.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS); + break; + + case MICROBIT_ID_COMPASS: + // A listener has been registered for the compass. + // The compass uses lazy instantiation, we just need to read the data once to start it running. + // Touch the compass through the heading() function to ensure it is calibrated. if it isn't this will launch any associated calibration algorithms. + compass.heading(); + + break; + + case MICROBIT_ID_ACCELEROMETER: + case MICROBIT_ID_GESTURE: + // A listener has been registered for the accelerometer. + // The accelerometer uses lazy instantiation, we just need to read the data once to start it running. + accelerometer.updateSample(); + break; + + case MICROBIT_ID_THERMOMETER: + // A listener has been registered for the thermometer. + // The thermometer uses lazy instantiation, we just need to read the data once to start it running. + thermometer.updateSample(); + break; + } +} \ No newline at end of file