From 5231b5f526fece6c2062f481ee3a26685f6a1204 Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Mon, 23 Nov 2015 19:46:20 +0000 Subject: [PATCH] First cut at a build without a global MicroBit singleton --- inc/MicroBit.h | 124 +++------ inc/MicroBitAccelerometer.h | 3 +- inc/MicroBitAccelerometerService.h | 5 +- inc/MicroBitBLEManager.h | 5 +- inc/MicroBitButtonService.h | 2 +- inc/MicroBitCompass.h | 15 +- inc/MicroBitCompat.h | 2 +- inc/MicroBitComponent.h | 4 + inc/MicroBitConfig.h | 1 + inc/MicroBitDisplay.h | 24 +- inc/MicroBitEventService.h | 3 +- inc/MicroBitFiber.h | 64 ++++- inc/MicroBitFont.h | 13 + inc/MicroBitIO.h | 5 +- inc/MicroBitIOPinService.h | 3 +- inc/MicroBitLEDService.h | 4 +- inc/MicroBitLightSensor.h | 1 + inc/MicroBitMagnetometerService.h | 3 +- inc/MicroBitMessageBus.h | 2 + inc/MicroBitMultiButton.h | 6 +- inc/MicroBitRadio.h | 10 +- inc/MicroBitRadioDatagram.h | 7 +- inc/MicroBitRadioEvent.h | 37 ++- inc/MicroBitTemperatureService.h | 5 +- source/CMakeLists.txt | 1 + source/MicroBit.cpp | 256 ++++++------------ source/MicroBitAccelerometer.cpp | 12 +- source/MicroBitButton.cpp | 4 +- source/MicroBitCompass.cpp | 22 +- source/MicroBitDisplay.cpp | 61 +++-- source/MicroBitEvent.cpp | 6 +- source/MicroBitFiber.cpp | 224 +++++++++++++-- source/MicroBitFont.cpp | 19 ++ source/MicroBitHeapAllocator.cpp | 2 +- source/MicroBitImage.cpp | 2 +- source/MicroBitLightSensor.cpp | 6 +- source/MicroBitMessageBus.cpp | 7 +- source/MicroBitMultiButton.cpp | 7 +- source/MicroBitSerial.cpp | 6 + source/MicroBitSuperMain.cpp | 76 +----- source/MicroBitThermometer.cpp | 10 +- source/RefCounted.cpp | 2 +- .../MicroBitAccelerometerService.cpp | 22 +- source/ble-services/MicroBitBLEManager.cpp | 62 ++--- source/ble-services/MicroBitButtonService.cpp | 6 +- source/ble-services/MicroBitDFUService.cpp | 7 +- source/ble-services/MicroBitEventService.cpp | 12 +- source/ble-services/MicroBitIOPinService.cpp | 39 ++- source/ble-services/MicroBitLEDService.cpp | 10 +- .../MicroBitMagnetometerService.cpp | 27 +- source/ble-services/MicroBitRadio.cpp | 18 +- source/ble-services/MicroBitRadioDatagram.cpp | 10 +- source/ble-services/MicroBitRadioEvent.cpp | 53 +++- .../MicroBitTemperatureService.cpp | 14 +- 54 files changed, 768 insertions(+), 583 deletions(-) diff --git a/inc/MicroBit.h b/inc/MicroBit.h index b80b561..d4f3a57 100644 --- a/inc/MicroBit.h +++ b/inc/MicroBit.h @@ -56,8 +56,6 @@ #define MICROBIT_PIN_SDA P0_30 #define MICROBIT_PIN_SCL P0_0 -#define MICROBIT_DEFAULT_TICK_PERIOD FIBER_TICK_PERIOD_MS - /** * Class definition for a MicroBit device. * @@ -71,16 +69,10 @@ class MicroBit void onABListenerRegisteredEvent(MicroBitEvent evt); uint32_t randomValue; - //the current tick period in MS - int tickPeriod; - public: - // Map of device state. - uint32_t flags; - - // Periodic callback - Ticker systemTicker; + // Reset Button + InterruptIn resetButton; // I2C Interface MicroBitI2C i2c; @@ -88,14 +80,8 @@ class MicroBit // Serial Interface MicroBitSerial serial; - // Array of components which are iterated during a system tick - MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS]; - - // Array of components which are iterated during idle thread execution, isIdleCallbackNeeded is polled during a systemTick. - MicroBitComponent* idleThreadComponents[MICROBIT_IDLE_COMPONENTS]; - // Device level Message Bus abstraction - MicroBitMessageBus MessageBus; + MicroBitMessageBus messageBus; // Member variables to represent each of the core components on the device. MicroBitDisplay display; @@ -121,7 +107,6 @@ class MicroBit * * Exposed objects: * @code - * uBit.systemTicker; //the Ticker callback that performs routines like updating the display. * uBit.MessageBus; //The message bus where events are fired. * uBit.display; //The display object for the LED matrix. * uBit.buttonA; //The buttonA object for button a. @@ -152,14 +137,14 @@ class MicroBit * * @return A string representing the friendly name of this device. */ - ManagedString getName(); + static ManagedString getName(); /** * Return the serial number of this device. * * @return A string representing the serial number of this device. */ - ManagedString getSerial(); + static ManagedString getSerial(); /** * Will reset the micro:bit when called. @@ -185,10 +170,10 @@ class MicroBit * * Example: * @code - * uBit.sleep(20); //sleep for 20ms + * MicroBit::sleep(20); //sleep for 20ms * @endcode */ - int sleep(int milliseconds); + static int sleep(int milliseconds); /** * Seed the pseudo random number generator using the hardware generator. @@ -227,62 +212,6 @@ class MicroBit */ int random(int max); - /** - * Period callback. Used by MicroBitDisplay, FiberScheduler and I2C sensors to - * provide a power efficient sense of time. - */ - void systemTick(); - - /** - * System tasks to be executed by the idle thread when the Micro:Bit isn't busy or when data needs to be read. - */ - void systemTasks(); - - /** - * add a component to the array of system components which invocate the systemTick member function during a systemTick - * - * @param component The component to add. - * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. - */ - int addSystemComponent(MicroBitComponent *component); - - /** - * remove a component from the array of system components - * @param component The component to remove. - * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added. - */ - int removeSystemComponent(MicroBitComponent *component); - - /** - * add a component to the array of of idle thread components. - * isIdleCallbackNeeded is polled during a systemTick to determine if the idle thread should jump to the front of the queue - * @param component The component to add. - * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. - */ - int addIdleComponent(MicroBitComponent *component); - - /** - * remove a component from the array of idle thread components - * @param component The component to remove. - * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added. - */ - int removeIdleComponent(MicroBitComponent *component); - - - /* - * Reconfigures the ticker to the given speed in milliseconds. - * @param speedMs the speed in milliseconds - * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedUs < 1 - * - * @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick() - */ - int setTickPeriod(int speedMs); - - /* - * Returns the currently used tick speed in milliseconds - */ - int getTickPeriod(); - /** * Determine the time since this MicroBit was last reset. * @@ -301,17 +230,43 @@ class MicroBit /** * Triggers a microbit panic where an infinite loop will occur swapping between the panicFace and statusCode if provided. - * + * * @param statusCode the status code of the associated error. Status codes must be in the range 0-255. */ void panic(int statusCode = 0); -}; + /** + * add a component to the array of components which invocate the systemTick member function during a systemTick + * @param component The component to add. + * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. + * @note This interface is now deprecated. See fiber_add_system_component(). + */ + int addSystemComponent(MicroBitComponent *component); -// Definition of the global instance of the MicroBit class. -// Using this as a variation on the singleton pattern, just to make -// code integration a little bit easier for third parties. -extern MicroBit uBit; + /** + * remove a component from the array of components + * @param component The component to remove. + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added. + * @note This interface is now deprecated. See fiber_remove_system_component(). + */ + int removeSystemComponent(MicroBitComponent *component); + + /** + * add a component to the array of components which invocate the systemTick member function during a systemTick + * @param component The component to add. + * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. + * @note This interface is now deprecated. See fiber_add_idle_component(). + */ + int addIdleComponent(MicroBitComponent *component); + + /** + * remove a component from the array of components + * @param component The component to remove. + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added. + * @note This interface is now deprecated. See fiber_remove_idle_component(). + */ + int removeIdleComponent(MicroBitComponent *component); +}; // Entry point for application programs. Called after the super-main function // has initialized the device and runtime environment. @@ -319,3 +274,4 @@ extern "C" void app_main(); #endif + diff --git a/inc/MicroBitAccelerometer.h b/inc/MicroBitAccelerometer.h index 6d7b00b..d93c4ef 100644 --- a/inc/MicroBitAccelerometer.h +++ b/inc/MicroBitAccelerometer.h @@ -150,6 +150,7 @@ class MicroBitAccelerometer : public MicroBitComponent 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. @@ -169,7 +170,7 @@ class MicroBitAccelerometer : public MicroBitComponent * accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR) * @endcode */ - MicroBitAccelerometer(uint16_t id, uint16_t address); + MicroBitAccelerometer(uint16_t id, uint16_t address, MicroBitI2C &_i2c); /** * Configures the accelerometer for G range and sample rate defined diff --git a/inc/MicroBitAccelerometerService.h b/inc/MicroBitAccelerometerService.h index 00976af..743e463 100644 --- a/inc/MicroBitAccelerometerService.h +++ b/inc/MicroBitAccelerometerService.h @@ -22,7 +22,7 @@ class MicroBitAccelerometerService * Create a representation of the AccelerometerService * @param _ble The instance of a BLE device that we're running on. */ - MicroBitAccelerometerService(BLEDevice &_ble); + MicroBitAccelerometerService(BLEDevice &_ble, MicroBitAccelerometer &_acclerometer, MicroBitMessageBus &messageBus); private: @@ -38,7 +38,8 @@ class MicroBitAccelerometerService void accelerometerUpdate(MicroBitEvent e); // Bluetooth stack we're running on. - BLEDevice &ble; + BLEDevice &ble; + MicroBitAccelerometer &accelerometer; // memory for our 8 bit control characteristics. uint16_t accelerometerDataCharacteristicBuffer[3]; diff --git a/inc/MicroBitBLEManager.h b/inc/MicroBitBLEManager.h index 63eb14f..4bd78ad 100644 --- a/inc/MicroBitBLEManager.h +++ b/inc/MicroBitBLEManager.h @@ -76,7 +76,7 @@ class MicroBitBLEManager : MicroBitComponent * uBit.init(); * @endcode */ - void init(ManagedString deviceName, ManagedString serialNumber, bool enableBonding); + void init(ManagedString deviceName, ManagedString serialNumber, MicroBitMessageBus& messageBus, bool enableBonding); /** * Change the output power level of the transmitter to the given value. @@ -92,8 +92,9 @@ class MicroBitBLEManager : MicroBitComponent * of the micro:bit in cases where BLE is disabled during normal operation. * * @param display a MicroBitDisplay to use when displaying pairing information. + * @prarm authorizationButton The button to use to authorise a pairing request. */ - void pairingMode(MicroBitDisplay &display); + void pairingMode(MicroBitDisplay &display, MicroBitButton &authorisationButton); /** * Makes the micro:bit discoverable via BLE, such that bonded devices can connect diff --git a/inc/MicroBitButtonService.h b/inc/MicroBitButtonService.h index 6e908f0..ec8aa62 100644 --- a/inc/MicroBitButtonService.h +++ b/inc/MicroBitButtonService.h @@ -22,7 +22,7 @@ class MicroBitButtonService * Create a representation of the ButtonService * @param _ble The instance of a BLE device that we're running on. */ - MicroBitButtonService(BLEDevice &_ble); + MicroBitButtonService(BLEDevice &_ble, MicroBitMessageBus &messageBus); private: diff --git a/inc/MicroBitCompass.h b/inc/MicroBitCompass.h index 0ddab7c..af6333f 100644 --- a/inc/MicroBitCompass.h +++ b/inc/MicroBitCompass.h @@ -4,6 +4,7 @@ #include "mbed.h" #include "MicroBitComponent.h" #include "MicroBitCoordinateSystem.h" +#include "MicroBitAccelerometer.h" /** * Relevant pin assignments @@ -122,12 +123,14 @@ class MicroBitCompass : public MicroBitComponent * Used to track asynchronous events in the event bus. */ - uint16_t address; // I2C address of the magnetmometer. - uint16_t samplePeriod; // The time between samples, in millseconds. + 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. + 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. public: @@ -149,7 +152,7 @@ class MicroBitCompass : public MicroBitComponent * MICROBIT_COMPASS_EVT_CAL_END // triggered when calibration has finished. * @endcode */ - MicroBitCompass(uint16_t id, uint16_t address); + MicroBitCompass(uint16_t id, uint16_t address, MicroBitI2C& _i2c, MicroBitAccelerometer &_accelerometer); /** * Configures the compass for the sample rate defined diff --git a/inc/MicroBitCompat.h b/inc/MicroBitCompat.h index 45233df..be957fd 100644 --- a/inc/MicroBitCompat.h +++ b/inc/MicroBitCompat.h @@ -6,6 +6,7 @@ #define MICROBIT_COMPAT_H #include "ErrorNo.h" +#include "MicroBitDevice.h" #define PI 3.14159265359 @@ -67,5 +68,4 @@ int string_reverse(char *s); */ void itoa(int n, char *s); - #endif diff --git a/inc/MicroBitComponent.h b/inc/MicroBitComponent.h index afafc78..51c1abe 100644 --- a/inc/MicroBitComponent.h +++ b/inc/MicroBitComponent.h @@ -52,6 +52,10 @@ #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 MicroBitComponent { protected: diff --git a/inc/MicroBitConfig.h b/inc/MicroBitConfig.h index 6e5f1f5..cc9afd4 100644 --- a/inc/MicroBitConfig.h +++ b/inc/MicroBitConfig.h @@ -274,6 +274,7 @@ #ifndef MICROBIT_BLE_MAXIMUM_SCROLLTEXT #define MICROBIT_BLE_MAXIMUM_SCROLLTEXT 20 #endif + // // Accelerometer options // diff --git a/inc/MicroBitDisplay.h b/inc/MicroBitDisplay.h index 9b18097..86fcc9d 100644 --- a/inc/MicroBitDisplay.h +++ b/inc/MicroBitDisplay.h @@ -106,7 +106,9 @@ class MicroBitDisplay : public MicroBitComponent uint8_t errorTimeout; Timeout renderTimer; - MicroBitFont font; + // + // Reference to the first display created. Used as a defaut output channel, such as panic(). + static MicroBitDisplay *defaultDisplay; // // State used by all animation routines. @@ -551,6 +553,17 @@ public: */ void clear(); + /** + * 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. + * + * Example: + * @code + * uBit.display.error(20); + * @endcode + */ + static void panic(int statusCode); + /** * Displays "=(" and an accompanying status code infinitely. * @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255. @@ -562,7 +575,7 @@ public: */ void error(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. * @@ -574,13 +587,16 @@ public: void setErrorTimeout(int iterations); /** - * Updates the font property of this object with the new font. - * @param font the new font that will be used to render characters.. + * Updates the font that will be used for display operations. + * DEPRECATED: Please use MicroBitFont::setSystemFont() instead. + * + * @param font the new font that will be used to render characters. */ void setFont(MicroBitFont font); /** * Retreives the font object used for rendering characters on the display. + * DEPRECATED: Please use MicroBitFont::getSystemFont() instead. */ MicroBitFont getFont(); diff --git a/inc/MicroBitEventService.h b/inc/MicroBitEventService.h index 3ce1aa6..df4dab5 100644 --- a/inc/MicroBitEventService.h +++ b/inc/MicroBitEventService.h @@ -30,7 +30,7 @@ class MicroBitEventService : public MicroBitComponent * Create a representation of the EventService * @param BLE The instance of a BLE device that we're running on. */ - MicroBitEventService(BLEDevice &_ble); + MicroBitEventService(BLEDevice &_ble, MicroBitMessageBus &_messageBus); /** * Periodic callback from MicroBit scheduler. @@ -58,6 +58,7 @@ class MicroBitEventService : public MicroBitComponent // Bluetooth stack we're running on. BLEDevice &ble; + MicroBitMessageBus &messageBus; // memory for our event characteristics. EventServiceEvent clientEventBuffer; diff --git a/inc/MicroBitFiber.h b/inc/MicroBitFiber.h index bc9ea3e..a8c0432 100644 --- a/inc/MicroBitFiber.h +++ b/inc/MicroBitFiber.h @@ -18,7 +18,7 @@ // stack for any long lived fibers with large stack // Fiber Scheduler Flags -#define MICROBIT_FLAG_DATA_READY 0x01 +#define MICROBIT_SCHEDULER_RUNNING 0x01 // Fiber Flags #define MICROBIT_FIBER_FLAG_FOB 0x01 @@ -70,13 +70,35 @@ struct Fiber 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. */ -void scheduler_init(); +void scheduler_init(MicroBitMessageBus *_messageBus); + +/* + * Reconfigures the system wide timer to the given period in milliseconds. + * + * @param speedMs the new period of the timer in milliseconds + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedMs < 1 + * + * @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick() + */ +int scheduler_set_tick_period(int speedMs); + +/* + * Returns the currently used tick speed in milliseconds + */ +int scheduler_get_tick_period(); + +/** + * 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. @@ -157,8 +179,9 @@ void scheduler_tick(); * * @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 associated with a MicroBitMessageBus. */ -void fiber_wait_for_event(uint16_t id, uint16_t value); +int fiber_wait_for_event(uint16_t id, uint16_t value); /** * Executes the given function asynchronously if necessary. @@ -242,6 +265,36 @@ void idle(); */ void idle_task(); +/** + * add a component to the array of system components which invocate the systemTick member function during a systemTick + * + * @param component The component to add. + * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. + */ +int fiber_add_system_component(MicroBitComponent *component); + +/** + * remove a component from the array of system components + * @param component The component to remove. + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added. + */ +int fiber_remove_system_component(MicroBitComponent *component); + +/** + * add a component to the array of of idle thread components. + * isIdleCallbackNeeded is polled during a systemTick to determine if the idle thread should jump to the front of the queue + * @param component The component to add. + * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. + */ +int fiber_add_idle_component(MicroBitComponent *component); + +/** + * remove a component from the array of idle thread components + * @param component The component to remove. + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added. + */ +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. @@ -266,9 +319,4 @@ extern "C" void restore_register_context(Cortex_M0_TCB *tcb); */ extern unsigned long ticks; -/** - * This variable is used to prioritise the systems' idle fibre to execute essential tasks. - */ -extern uint8_t fiber_flags; - #endif diff --git a/inc/MicroBitFont.h b/inc/MicroBitFont.h index 00ec058..fef2839 100644 --- a/inc/MicroBitFont.h +++ b/inc/MicroBitFont.h @@ -17,6 +17,7 @@ class MicroBitFont public: static const unsigned char* defaultFont; + static MicroBitFont systemFont; const unsigned char* characters; @@ -37,6 +38,18 @@ class MicroBitFont * Sets the characters to defaultFont characters and asciiEnd to MICROBIT_FONT_ASCII_END. */ MicroBitFont(); + +/** + * Changes the current system font to the one specified. + * @param font the new font that will be used to render characters.. + */ +static void setSystemFont(MicroBitFont font); + +/** + * Retreives the font object used for rendering characters on the display. + */ +static MicroBitFont getSystemFont(); + }; #endif diff --git a/inc/MicroBitIO.h b/inc/MicroBitIO.h index ac3cc4a..4ffc42b 100644 --- a/inc/MicroBitIO.h +++ b/inc/MicroBitIO.h @@ -13,8 +13,9 @@ class MicroBitIO { public: - - MicroBitPin P0; + + MicroBitPin pin[0]; + MicroBitPin P0; MicroBitPin P1; MicroBitPin P2; MicroBitPin P3; diff --git a/inc/MicroBitIOPinService.h b/inc/MicroBitIOPinService.h index f4bf4af..c4ace5e 100644 --- a/inc/MicroBitIOPinService.h +++ b/inc/MicroBitIOPinService.h @@ -35,7 +35,7 @@ class MicroBitIOPinService : public MicroBitComponent * Create a representation of the IOPinService * @param _ble The instance of a BLE device that we're running on. */ - MicroBitIOPinService(BLEDevice &_ble); + MicroBitIOPinService(BLEDevice &_ble, MicroBitIO &_io); /** * periodic callback from MicroBit scheduler. @@ -91,6 +91,7 @@ class MicroBitIOPinService : public MicroBitComponent // Bluetooth stack we're running on. BLEDevice &ble; + MicroBitIO &io; // memory for our 8 bit control characteristics. uint32_t ioPinServiceADCharacteristicBuffer; diff --git a/inc/MicroBitLEDService.h b/inc/MicroBitLEDService.h index e4c7ea8..6486fb1 100644 --- a/inc/MicroBitLEDService.h +++ b/inc/MicroBitLEDService.h @@ -22,8 +22,9 @@ class MicroBitLEDService * Constructor. * Create a representation of the LEDService * @param BLE The instance of a BLE device that we're running on. + * @param display The instance of a MicroBitDisplay to interface with. */ - MicroBitLEDService(BLEDevice &_ble); + MicroBitLEDService(BLEDevice &_ble, MicroBitDisplay &_display); /** * Callback. Invoked when any of our attributes are written via BLE. @@ -39,6 +40,7 @@ class MicroBitLEDService // Bluetooth stack we're running on. BLEDevice &ble; + MicroBitDisplay &display; // memory for our 8 bit control characteristics. uint8_t matrixCharacteristicBuffer[5]; diff --git a/inc/MicroBitLightSensor.h b/inc/MicroBitLightSensor.h index ee85219..043b531 100644 --- a/inc/MicroBitLightSensor.h +++ b/inc/MicroBitLightSensor.h @@ -3,6 +3,7 @@ #include "mbed.h" #include "MicroBitComponent.h" +#include "MicroBitMessageBus.h" #define MICROBIT_LIGHT_SENSOR_CHAN_NUM 3 #define MICROBIT_LIGHT_SENSOR_AN_SET_TIME 4000 diff --git a/inc/MicroBitMagnetometerService.h b/inc/MicroBitMagnetometerService.h index ee9595a..ff7a00f 100644 --- a/inc/MicroBitMagnetometerService.h +++ b/inc/MicroBitMagnetometerService.h @@ -23,7 +23,7 @@ class MicroBitMagnetometerService * Create a representation of the MagnetometerService * @param _ble The instance of a BLE device that we're running on. */ - MicroBitMagnetometerService(BLEDevice &_ble); + MicroBitMagnetometerService(BLEDevice &_ble, MicroBitCompass &_compass, MicroBitMessageBus &messageBus); private: @@ -47,6 +47,7 @@ class MicroBitMagnetometerService // Bluetooth stack we're running on. BLEDevice &ble; + MicroBitCompass &compass; // memory for our 8 bit control characteristics. int16_t magnetometerDataCharacteristicBuffer[3]; diff --git a/inc/MicroBitMessageBus.h b/inc/MicroBitMessageBus.h index 8cf63c3..a03ff91 100644 --- a/inc/MicroBitMessageBus.h +++ b/inc/MicroBitMessageBus.h @@ -33,6 +33,8 @@ class MicroBitMessageBus : public MicroBitComponent { public: + static MicroBitMessageBus *defaultMessageBus; + /** * Default constructor. * Anticipating only one MessageBus per device, as filtering is handled within the class. diff --git a/inc/MicroBitMultiButton.h b/inc/MicroBitMultiButton.h index 5596fec..b8e9f42 100644 --- a/inc/MicroBitMultiButton.h +++ b/inc/MicroBitMultiButton.h @@ -1,7 +1,9 @@ #ifndef MICROBIT_MULTI_BUTTON_H #define MICROBIT_MULTI_BUTTON_H -#include "MicroBit.h" +#include "mbed.h" +#include "MicroBitButton.h" +#include "MicroBitMessageBus.h" #define MICROBIT_MULTI_BUTTON_STATE_1 0x01 #define MICROBIT_MULTI_BUTTON_STATE_2 0x02 @@ -57,7 +59,7 @@ class MicroBitMultiButton : public MicroBitComponent * MICROBIT_BUTTON_EVT_HOLD * @endcode */ - MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2); + MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2, MicroBitMessageBus &messageBus); /** * Tests if this MultiButton is currently pressed. diff --git a/inc/MicroBitRadio.h b/inc/MicroBitRadio.h index 825332d..3ecacd6 100644 --- a/inc/MicroBitRadio.h +++ b/inc/MicroBitRadio.h @@ -1,8 +1,13 @@ #ifndef MICROBIT_RADIO_H #define MICROBIT_RADIO_H +class MicroBitRadio; +struct FrameBuffer; + #include "mbed.h" #include "PacketBuffer.h" +#include "MicroBitRadioDatagram.h" +#include "MicroBitRadioEvent.h" /** * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module. @@ -46,6 +51,7 @@ // 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. @@ -58,8 +64,6 @@ struct FrameBuffer uint8_t rssi; // Received signal strength of this frame. }; -#include "MicroBitRadioDatagram.h" -#include "MicroBitRadioEvent.h" class MicroBitRadio : MicroBitComponent { @@ -72,7 +76,7 @@ class MicroBitRadio : MicroBitComponent 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. + static MicroBitRadio *instance; // A singleton reference, used purely by the interrupt service routine. /** * Constructor. diff --git a/inc/MicroBitRadioDatagram.h b/inc/MicroBitRadioDatagram.h index 71b60d9..0f29e23 100644 --- a/inc/MicroBitRadioDatagram.h +++ b/inc/MicroBitRadioDatagram.h @@ -18,14 +18,17 @@ class MicroBitRadioDatagram { - FrameBuffer *rxQueue; // A linear list of incoming packets, queued awaiting processing. + 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. + * + * @param radio The underlying radio module used to send and receive data. */ - MicroBitRadioDatagram(); + MicroBitRadioDatagram(MicroBitRadio &r); /** * Retreives packet payload data into the given buffer. diff --git a/inc/MicroBitRadioEvent.h b/inc/MicroBitRadioEvent.h index 48d0259..f2347d7 100644 --- a/inc/MicroBitRadioEvent.h +++ b/inc/MicroBitRadioEvent.h @@ -19,26 +19,40 @@ class MicroBitRadioEvent { - bool suppressForwarding; // A private flag used to prevent event forwarding loops. + bool suppressForwarding; // A private flag used to prevent event forwarding loops. + MicroBitRadio &radio; // A reference to the underlying radio module to use. public: /** * Constructor. */ - MicroBitRadioEvent(); + MicroBitRadioEvent(MicroBitRadio &r); /** * Associates the given MessageBus events with the radio channel. * Once registered, all events matching the given registration sent to this micro:bit's - * MessageBus will be automatically retrasmitted on the radio. + * default MessageBus will be automaticlaly retrasmitted on the radio. * * @param id The ID of the events to register. - * @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given ID. + * @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given id. + * + * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if no defult MessageBus is available. + */ + int listen(uint16_t id, uint16_t value); + + /** + * Associates the given MessageBus events with the radio channel. + * Once registered, all events matching the given registration sent to the given + * MessageBus will be automaticlaly retrasmitted on the radio. + * + * @param id The ID of the events to register. + * @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given id. + * @param The message bus to listen for events on. * * @return MICROBIT_OK on success. */ - int listen(uint16_t id, uint16_t value); + int listen(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus); /** * Disassociates the given MessageBus events with the radio channel. @@ -46,10 +60,21 @@ class MicroBitRadioEvent * @param id The ID of the events to deregister. * @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given ID. * - * @return MICROBIT_OK on success. + * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the default message bus does not exist. */ int ignore(uint16_t id, uint16_t value); + /** + * Disassociates the given MessageBus events with the radio channel. + * + * @param id The ID of the events to deregister. + * @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given ID. + * @param The message bus to deregister on. + * + * @return MICROBIT_OK on success. + */ + int ignore(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus); + /** * 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 local MessageBus. diff --git a/inc/MicroBitTemperatureService.h b/inc/MicroBitTemperatureService.h index eec9eab..5393498 100644 --- a/inc/MicroBitTemperatureService.h +++ b/inc/MicroBitTemperatureService.h @@ -22,7 +22,7 @@ class MicroBitTemperatureService * Create a representation of the TempertureService * @param _ble The instance of a BLE device that we're running on. */ - MicroBitTemperatureService(BLEDevice &_ble); + MicroBitTemperatureService(BLEDevice &_ble, MicroBitThermometer &_thermometer, MicroBitMessageBus &messageBus); /** * Callback. Invoked when any of our attributes are written via BLE. @@ -37,7 +37,8 @@ class MicroBitTemperatureService private: // Bluetooth stack we're running on. - BLEDevice &ble; + BLEDevice &ble; + MicroBitThermometer &thermometer; // memory for our 8 bit temperature characteristic. int8_t temperatureDataCharacteristicBuffer; diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 59ece8e..3084b16 100755 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -22,6 +22,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES "MicroBitThermometer.cpp" "MicroBitIO.cpp" "MicroBitCompat.cpp" + "MicroBitDevice.cpp" "MicroBitImage.cpp" "MicroBitDisplay.cpp" "DynamicPwm.cpp" diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index 09290f2..ebc42b0 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -21,24 +21,6 @@ #pragma GCC diagnostic pop #endif -/** - * custom function for panic for malloc & new due to scoping issue. - */ -void panic(int statusCode) -{ - uBit.panic(statusCode); -} - -/** - * Callback that performs a hard reset when a BLE GAP disconnect occurs. - * Only used when an explicit reset is invoked locally whilst a BLE connection is in progress. - * This allows for a clean diconnect of the BLE connection before resetting. - */ -void bleDisconnectionResetCallback(const Gap::DisconnectionCallbackParams_t *) -{ - NVIC_SystemReset(); -} - /** * Perform a hard reset of the micro:bit. * If BLE connected, then try to signal a disconnect first @@ -46,25 +28,9 @@ void bleDisconnectionResetCallback(const Gap::DisconnectionCallbackParams_t *) void microbit_reset() { - if(uBit.ble && uBit.ble->getGapState().connected) { - uBit.ble->onDisconnection(bleDisconnectionResetCallback); - - uBit.ble->gap().disconnect(Gap::REMOTE_USER_TERMINATED_CONNECTION); - // We should be reset by the disconnection callback, so we wait to - // allow that to happen. If it doesn't happen, then we fall through to the - // hard rest here. (For example there is a race condition where - // the remote device disconnects between us testing the connection - // state and re-setting the disconnection callback). - uBit.sleep(1000); - } NVIC_SystemReset(); } -void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *) -{ - uBit.ble->startAdvertising(); -} - void MicroBit::onABListenerRegisteredEvent(MicroBitEvent evt) { (void) evt; // Unused parameter @@ -103,16 +69,16 @@ void MicroBit::onABListenerRegisteredEvent(MicroBitEvent evt) * @endcode */ MicroBit::MicroBit() : - flags(0x00), + resetButton(MICROBIT_PIN_BUTTON_RESET), i2c(MICROBIT_PIN_SDA, MICROBIT_PIN_SCL), serial(USBTX, USBRX), - MessageBus(), + messageBus(), display(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_WIDTH, MICROBIT_DISPLAY_HEIGHT), buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A, MICROBIT_BUTTON_ALL_EVENTS), buttonB(MICROBIT_ID_BUTTON_B,MICROBIT_PIN_BUTTON_B, MICROBIT_BUTTON_ALL_EVENTS), - buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B), - accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR), - compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR), + buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B, messageBus), + accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR, i2c), + compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR,i2c,accelerometer), thermometer(MICROBIT_ID_THERMOMETER), 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, @@ -125,6 +91,9 @@ MicroBit::MicroBit() : radio(MICROBIT_ID_RADIO), ble(NULL) { + // Bring up soft reset functionality as soon as possible. + resetButton.mode(PullUp); + resetButton.fall(this, &MicroBit::reset); } /** @@ -140,25 +109,74 @@ MicroBit::MicroBit() : */ void MicroBit::init() { + // Bring up our nested heap allocator. + microbit_heap_init(); + + // Bring up fiber scheduler + scheduler_init(&messageBus); + sleep(10); + + // Load any stored calibration data from persistent storage. + MicroBitStorage s = MicroBitStorage(); + MicroBitConfigurationBlock *b = s.getConfigurationBlock(); + + //if we have some calibrated data, calibrate the compass! + if(b->magic == MICROBIT_STORAGE_CONFIG_MAGIC) + { + if(b->compassCalibrationData != CompassSample(0,0,0)) + compass.setCalibration(b->compassCalibrationData); + } + + delete b; + + // TODO: YUCK!!! MOVE THESE INTO THE RELEVANT COMPONENTS!! + //add the display to the systemComponent array - addSystemComponent(&uBit.display); + addSystemComponent(&display); //add the compass and accelerometer to the idle array - addIdleComponent(&uBit.accelerometer); - addIdleComponent(&uBit.compass); - addIdleComponent(&uBit.MessageBus); + addIdleComponent(&accelerometer); + addIdleComponent(&compass); + addIdleComponent(&messageBus); // Seed our random number generator seedRandom(); - tickPeriod = MICROBIT_DEFAULT_TICK_PERIOD; - - // Start refreshing the Matrix Display - systemTicker.attach_us(this, &MicroBit::systemTick, tickPeriod * 1000); - // Register our compass calibration algorithm. - MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CALIBRATE, this, &MicroBit::compassCalibrator, MESSAGE_BUS_LISTENER_IMMEDIATE); - MessageBus.listen(MICROBIT_ID_MESSAGE_BUS_LISTENER, MICROBIT_ID_BUTTON_AB, this, &MicroBit::onABListenerRegisteredEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CALIBRATE, this, &MicroBit::compassCalibrator, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(MICROBIT_ID_MESSAGE_BUS_LISTENER, MICROBIT_ID_BUTTON_AB, this, &MicroBit::onABListenerRegisteredEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + +#if CONFIG_ENABLED(MICROBIT_BLE_PAIRING_MODE) + // Test if we need to enter BLE pairing mode... + int i=0; + while (buttonA.isPressed() && buttonB.isPressed() && i<10) + { + sleep(100); + i++; + + if (i == 10) + { + // 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 + +#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 } /** @@ -208,8 +226,8 @@ void MicroBit::compassCalibrator(MicroBitEvent) cursor.on = (cursor.on + 1) % 4; // take a snapshot of the current accelerometer data. - int x = uBit.accelerometer.getX(); - int y = uBit.accelerometer.getY(); + int x = accelerometer.getX(); + int y = accelerometer.getY(); // Deterine the position of the user controlled pixel on the screen. if (x < -PIXEL2_THRESHOLD) @@ -245,7 +263,7 @@ void MicroBit::compassCalibrator(MicroBitEvent) img.setPixelValue(cursor.x, cursor.y, 255); // Update the buffer to the screen. - uBit.display.image.paste(img,0,0,0); + display.image.paste(img,0,0,0); // test if we need to update the state at the users position. for (int i=0; igetGapState().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. + sleep(100); + } + microbit_reset(); } @@ -387,7 +414,7 @@ int MicroBit::sleep(int milliseconds) if(milliseconds < 0) return MICROBIT_INVALID_PARAMETER; - if (flags & MICROBIT_FLAG_SCHEDULER_RUNNING) + if (fiber_scheduler_running()) fiber_sleep(milliseconds); else wait_ms(milliseconds); @@ -418,7 +445,6 @@ int MicroBit::random(int max) { uint32_t m, result; - //return MICROBIT_INVALID_VALUE if max is <= 0... if(max <= 0) return MICROBIT_INVALID_PARAMETER; @@ -468,7 +494,7 @@ void MicroBit::seedRandom() { randomValue = 0; - if(uBit.ble) + if(ble) { // 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*)&randomValue, sizeof(randomValue)); @@ -510,42 +536,6 @@ void MicroBit::seedRandom(uint32_t seed) } -/** - * Periodic callback. Used by MicroBitDisplay, FiberScheduler and buttons. - */ -void MicroBit::systemTick() -{ - // Scheduler callback. We do this here just as a single timer is more efficient. :-) - if (uBit.flags & MICROBIT_FLAG_SCHEDULER_RUNNING) - scheduler_tick(); - - //work out if any idle components need processing, if so prioritise the idle thread - for(int i = 0; i < MICROBIT_IDLE_COMPONENTS; i++) - if(idleThreadComponents[i] != NULL && idleThreadComponents[i]->isIdleCallbackNeeded()) - { - fiber_flags |= MICROBIT_FLAG_DATA_READY; - break; - } - - //update any components in the systemComponents array - for(int i = 0; i < MICROBIT_SYSTEM_COMPONENTS; i++) - if(systemTickComponents[i] != NULL) - systemTickComponents[i]->systemTick(); -} - -/** - * System tasks to be executed by the idle thread when the Micro:Bit isn't busy or when data needs to be read. - */ -void MicroBit::systemTasks() -{ - //call the idleTick member function indiscriminately - for(int i = 0; i < MICROBIT_IDLE_COMPONENTS; i++) - if(idleThreadComponents[i] != NULL) - idleThreadComponents[i]->idleTick(); - - fiber_flags &= ~MICROBIT_FLAG_DATA_READY; -} - /** * add a component to the array of components which invocate the systemTick member function during a systemTick * @param component The component to add. @@ -554,16 +544,7 @@ void MicroBit::systemTasks() */ int MicroBit::addSystemComponent(MicroBitComponent *component) { - int i = 0; - - while(systemTickComponents[i] != NULL && i < MICROBIT_SYSTEM_COMPONENTS) - i++; - - if(i == MICROBIT_SYSTEM_COMPONENTS) - return MICROBIT_NO_RESOURCES; - - systemTickComponents[i] = component; - return MICROBIT_OK; + return fiber_add_system_component(component); } /** @@ -574,17 +555,7 @@ int MicroBit::addSystemComponent(MicroBitComponent *component) */ int MicroBit::removeSystemComponent(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; + return fiber_remove_system_component(component); } /** @@ -595,17 +566,7 @@ int MicroBit::removeSystemComponent(MicroBitComponent *component) */ int MicroBit::addIdleComponent(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; + return fiber_add_idle_component(component); } /** @@ -616,47 +577,9 @@ int MicroBit::addIdleComponent(MicroBitComponent *component) */ int MicroBit::removeIdleComponent(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; + return fiber_remove_idle_component(component); } -/* - * Reconfigures the ticker to the given speed in milliseconds. - * @param speedMs the speed in milliseconds - * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedUs < 1 - * - * @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick() - */ -int MicroBit::setTickPeriod(int speedMs) -{ - if(speedMs < 1) - return MICROBIT_INVALID_PARAMETER; - - uBit.systemTicker.detach(); - - uBit.systemTicker.attach_us(this, &MicroBit::systemTick, speedMs * 1000); - - tickPeriod = speedMs; - - return MICROBIT_OK; -} - -/* - * Returns the currently used tick speed in milliseconds - */ -int MicroBit::getTickPeriod() -{ - return tickPeriod; -} /** * Determine the time since this MicroBit was last reset. @@ -682,12 +605,11 @@ const char *MicroBit::systemVersion() } /** - * Triggers a microbit panic where an infinite loop will occur swapping between the panicFace and statusCode if provided. - * + * Triggers a microbit panic. All functionality will cease, and a sad face displayed along with an error code. * @param statusCode the status code of the associated error. Status codes must be in the range 0-255. */ void MicroBit::panic(int statusCode) { //show error and enter infinite while - uBit.display.error(statusCode); + display.error(statusCode); } diff --git a/source/MicroBitAccelerometer.cpp b/source/MicroBitAccelerometer.cpp index f06fae2..bf2fde9 100644 --- a/source/MicroBitAccelerometer.cpp +++ b/source/MicroBitAccelerometer.cpp @@ -93,7 +93,7 @@ int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value) command[0] = reg; command[1] = value; - return uBit.i2c.write(address, (const char *)command, 2); + return i2c.write(address, (const char *)command, 2); } /** @@ -112,11 +112,11 @@ int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length) if (buffer == NULL || length <= 0 ) return MICROBIT_INVALID_PARAMETER; - result = uBit.i2c.write(address, (const char *)®, 1, true); + result = i2c.write(address, (const char *)®, 1, true); if (result !=0) return MICROBIT_I2C_ERROR; - result = uBit.i2c.read(address, (char *)buffer, length); + result = i2c.read(address, (char *)buffer, length); if (result !=0) return MICROBIT_I2C_ERROR; @@ -134,7 +134,7 @@ int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length) * accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR) * @endcode */ -MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY) +MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address, MicroBitI2C& _i2c) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY), i2c(_i2c) { // Store our identifiers. this->id = id; @@ -157,7 +157,7 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa // Configure and enable the accelerometer. if (this->configure() == MICROBIT_OK) - uBit.flags |= MICROBIT_FLAG_ACCELEROMETER_RUNNING; + status |= MICROBIT_COMPONENT_RUNNING; } /** @@ -576,7 +576,7 @@ int MicroBitAccelerometer::isIdleCallbackNeeded() */ MicroBitAccelerometer::~MicroBitAccelerometer() { - uBit.removeIdleComponent(this); + fiber_remove_idle_component(this); } const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = { diff --git a/source/MicroBitButton.cpp b/source/MicroBitButton.cpp index f158125..4fc137c 100644 --- a/source/MicroBitButton.cpp +++ b/source/MicroBitButton.cpp @@ -28,7 +28,7 @@ MicroBitButton::MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventCon this->eventConfiguration = eventConfiguration; this->downStartTime = 0; this->sigma = 0; - uBit.addSystemComponent(this); + fiber_add_system_component(this); } /** @@ -128,5 +128,5 @@ int MicroBitButton::isPressed() */ MicroBitButton::~MicroBitButton() { - uBit.removeSystemComponent(this); + fiber_remove_system_component(this); } diff --git a/source/MicroBitCompass.cpp b/source/MicroBitCompass.cpp index 5d15c1f..49bcf60 100644 --- a/source/MicroBitCompass.cpp +++ b/source/MicroBitCompass.cpp @@ -18,7 +18,7 @@ * MICROBIT_COMPASS_EVT_CAL_END // triggered when calibration has finished. * @endcode */ -MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sample(), int1(MICROBIT_PIN_COMPASS_DATA_READY) +MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address, MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer) : average(), sample(), int1(MICROBIT_PIN_COMPASS_DATA_READY), i2c(_i2c), accelerometer(_accelerometer) { this->id = id; this->address = address; @@ -34,7 +34,7 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED; // Indicate that we're up and running. - uBit.flags |= MICROBIT_FLAG_COMPASS_RUNNING; + status |= MICROBIT_COMPONENT_RUNNING; } /** @@ -51,7 +51,7 @@ int MicroBitCompass::writeCommand(uint8_t reg, uint8_t value) command[0] = reg; command[1] = value; - return uBit.i2c.write(address, (const char *)command, 2); + return i2c.write(address, (const char *)command, 2); } /** @@ -69,11 +69,11 @@ int MicroBitCompass::readCommand(uint8_t reg, uint8_t* buffer, int length) if (buffer == NULL || length <= 0) return MICROBIT_INVALID_PARAMETER; - result = uBit.i2c.write(address, (const char *)®, 1, true); + result = i2c.write(address, (const char *)®, 1, true); if (result !=0) return MICROBIT_I2C_ERROR; - result = uBit.i2c.read(address, (char *)buffer, length); + result = i2c.read(address, (char *)buffer, length); if (result !=0) return MICROBIT_I2C_ERROR; @@ -94,14 +94,14 @@ int MicroBitCompass::read16(uint8_t reg) int result; cmd[0] = reg; - result = uBit.i2c.write(address, (const char *)cmd, 1); + result = i2c.write(address, (const char *)cmd, 1); if (result !=0) return MICROBIT_I2C_ERROR; cmd[0] = 0x00; cmd[1] = 0x00; - result = uBit.i2c.read(address, (char *)cmd, 2); + result = i2c.read(address, (char *)cmd, 2); if (result !=0) return MICROBIT_I2C_ERROR; @@ -153,8 +153,8 @@ int MicroBitCompass::heading() calibrate(); // Precompute the tilt compensation parameters to improve readability. - float phi = uBit.accelerometer.getRollRadians(); - float theta = uBit.accelerometer.getPitchRadians(); + 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); @@ -314,7 +314,7 @@ int MicroBitCompass::configure() break; // Perform a power efficient sleep... - uBit.sleep(100); + MicroBit::sleep(100); } // Find the nearest sample rate to that specified. @@ -560,7 +560,7 @@ int MicroBitCompass::isIdleCallbackNeeded() */ MicroBitCompass::~MicroBitCompass() { - uBit.removeIdleComponent(this); + fiber_remove_idle_component(this); } const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = { diff --git a/source/MicroBitDisplay.cpp b/source/MicroBitDisplay.cpp index 591015f..707f85d 100644 --- a/source/MicroBitDisplay.cpp +++ b/source/MicroBitDisplay.cpp @@ -9,6 +9,7 @@ #include "nrf_gpio.h" const int timings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {1, 23, 70, 163, 351, 726, 1476, 2976}; +MicroBitDisplay *MicroBitDisplay::defaultDisplay = NULL; /** * Constructor. @@ -24,7 +25,6 @@ const int timings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {1, 23, 70, 163, 351, * @endcode */ MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) : - font(), image(x*2,y) { //set pins as output @@ -47,7 +47,10 @@ MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) : this->lightSensor = NULL; - uBit.flags |= MICROBIT_FLAG_DISPLAY_RUNNING; + if (!this->defaultDisplay) + this->defaultDisplay = this; + + status |= MICROBIT_COMPONENT_RUNNING; } /** @@ -58,7 +61,7 @@ MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) : */ void MicroBitDisplay::systemTick() { - if(!(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING)) + if(!(status & MICROBIT_COMPONENT_RUNNING)) return; if(mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE) @@ -148,7 +151,7 @@ void MicroBitDisplay::render() //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)) * uBit.getTickPeriod())); + renderTimer.attach_us(this, &MicroBitDisplay::renderFinish, (((brightness * 950) / (MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS)) * scheduler_get_tick_period())); //this will take around 23us to execute if(brightness <= MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS) @@ -934,16 +937,16 @@ 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(uBit.getTickPeriod() != MICROBIT_LIGHT_SENSOR_TICK_PERIOD) - uBit.setTickPeriod(MICROBIT_LIGHT_SENSOR_TICK_PERIOD); + if(scheduler_get_tick_period() != MICROBIT_LIGHT_SENSOR_TICK_PERIOD) + scheduler_set_tick_period(MICROBIT_LIGHT_SENSOR_TICK_PERIOD); } if(this->mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE && mode != DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE) { //if we previously were in light sense mode - return to our default. - if(uBit.getTickPeriod() != MICROBIT_DEFAULT_TICK_PERIOD) - uBit.setTickPeriod(MICROBIT_DEFAULT_TICK_PERIOD); + if(scheduler_get_tick_period() != FIBER_TICK_PERIOD_MS) + scheduler_set_tick_period(FIBER_TICK_PERIOD_MS); delete this->lightSensor; @@ -1000,10 +1003,10 @@ void MicroBitDisplay::rotateTo(DisplayRotation rotation) */ void MicroBitDisplay::enable() { - if(!(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING)) + if(!(status & MICROBIT_COMPONENT_RUNNING)) { setBrightness(brightness); - uBit.flags |= MICROBIT_FLAG_DISPLAY_RUNNING; //set the display running flag + status |= MICROBIT_COMPONENT_RUNNING; } } @@ -1018,10 +1021,8 @@ void MicroBitDisplay::enable() */ void MicroBitDisplay::disable() { - if(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING) - { - uBit.flags &= ~MICROBIT_FLAG_DISPLAY_RUNNING; //unset the display running flag - } + if(status & MICROBIT_COMPONENT_RUNNING) + status &= ~MICROBIT_COMPONENT_RUNNING; //unset the display running flag } /** @@ -1053,7 +1054,22 @@ void MicroBitDisplay::setErrorTimeout(int iterations) } /** - * Displays "=(" and an accompanying status code infinitely. + * 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. + * + * Example: + * @code + * uBit.display.error(20); + * @endcode + */ +void MicroBitDisplay::panic(int statusCode) +{ + if(MicroBitDisplay::defaultDisplay) + defaultDisplay->error(statusCode); + +} +/** + * 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. * * Example: @@ -1063,15 +1079,14 @@ void MicroBitDisplay::setErrorTimeout(int iterations) */ void MicroBitDisplay::error(int statusCode) { - extern InterruptIn resetButton; + DigitalIn resetButton(MICROBIT_PIN_BUTTON_RESET); + resetButton.mode(PullUp); __disable_irq(); //stop ALL interrupts if(statusCode < 0 || statusCode > 255) statusCode = 0; - disable(); //relinquish PWMOut's control - uint8_t strobeRow = 0; uint8_t strobeBitMsk = MICROBIT_DISPLAY_ROW_RESET; uint8_t count = errorTimeout ? errorTimeout : 1; @@ -1122,10 +1137,8 @@ void MicroBitDisplay::error(int statusCode) nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, ~coldata<<4 & 0xF0); //set port 0 4-7 nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F)); //set port 1 8-12 - //set i to an obscene number. - i = 1000; - //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... @@ -1155,7 +1168,7 @@ void MicroBitDisplay::error(int statusCode) */ void MicroBitDisplay::setFont(MicroBitFont font) { - this->font = font; + MicroBitFont::setSystemFont(font); } /** @@ -1163,7 +1176,7 @@ void MicroBitDisplay::setFont(MicroBitFont font) */ MicroBitFont MicroBitDisplay::getFont() { - return this->font; + return MicroBitFont::getSystemFont(); } /** @@ -1201,5 +1214,5 @@ int MicroBitDisplay::readLightLevel() */ MicroBitDisplay::~MicroBitDisplay() { - uBit.removeSystemComponent(this); + fiber_remove_system_component(this); } diff --git a/source/MicroBitEvent.cpp b/source/MicroBitEvent.cpp index 330048a..b6294a9 100644 --- a/source/MicroBitEvent.cpp +++ b/source/MicroBitEvent.cpp @@ -38,15 +38,15 @@ MicroBitEvent::MicroBitEvent() } /** - * Fires the represented event onto the message bus. + * Fires the represented event onto the default message bus. */ void MicroBitEvent::fire(MicroBitEventLaunchMode mode) { if (mode == CREATE_AND_QUEUE) - uBit.MessageBus.send(*this); + MicroBitMessageBus::defaultMessageBus->send(*this); else if (mode == CREATE_AND_FIRE) - uBit.MessageBus.process(*this); + MicroBitMessageBus::defaultMessageBus->process(*this); } /** diff --git a/source/MicroBitFiber.cpp b/source/MicroBitFiber.cpp index bebe05a..0aef7a0 100644 --- a/source/MicroBitFiber.cpp +++ b/source/MicroBitFiber.cpp @@ -14,27 +14,43 @@ * required to be defined here to allow persistence during context switches. */ Fiber *currentFiber = NULL; // The context in which the current fiber is executing. -Fiber *forkedFiber = NULL; // The context in which a newly created child fiber is executing. -Fiber *idleFiber = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks. +static Fiber *forkedFiber = NULL; // The context in which a newly created child fiber is executing. +static Fiber *idleFiber = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks. /* * Scheduler state. */ -Fiber *runQueue = NULL; // The list of runnable fibers. -Fiber *sleepQueue = NULL; // The list of blocked fibers waiting on a fiber_sleep() operation. -Fiber *waitQueue = NULL; // The list of blocked fibers waiting on an event. -Fiber *fiberPool = NULL; // Pool of unused fibers, just waiting for a job to do. +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. /* * Time since power on. Measured in milliseconds. * When stored as an unsigned long, this gives us approx 50 days between rollover, which is ample. :-) */ unsigned long ticks = 0; +static unsigned int tickPeriod = FIBER_TICK_PERIOD_MS; /* * Scheduler wide flags */ -uint8_t fiber_flags = 0; +static uint8_t fiber_flags = 0; + + +/* + * Fibers may perform wait/notify semantics on events. If set, these operations will be permitted on this MicroBitMessageBus. + */ +static MicroBitMessageBus *messageBus = NULL; + +// Array of components which are iterated during a system tick +static MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS]; + +// Array of components which are iterated during idle thread execution, isIdleCallbackNeeded is polled during a systemTick. +static MicroBitComponent* idleThreadComponents[MICROBIT_IDLE_COMPONENTS]; + +// Periodic callback interrupt +static Ticker fiberSchedulerTicker; /** * Utility function to add the currenty running fiber to the given queue. @@ -148,8 +164,12 @@ Fiber *getFiberContext() * * This function must be called once only from the main thread, and before any other Fiber operation. */ -void scheduler_init() +void scheduler_init(MicroBitMessageBus *_messageBus) { + // 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(); @@ -162,16 +182,61 @@ void scheduler_init() idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04; idleFiber->tcb.LR = (uint32_t) &idle_task; - // Register to receive events in the NOTIFY channel - this is used to implement wait-notify semantics - uBit.MessageBus.listen(MICROBIT_ID_NOTIFY, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE); - uBit.MessageBus.listen(MICROBIT_ID_NOTIFY_ONE, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE); + 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); + } - // Flag that we now have a scheduler running - uBit.flags |= MICROBIT_FLAG_SCHEDULER_RUNNING; + // register a period callback to drive the scheduler and any other registered components. + fiberSchedulerTicker.attach_us(scheduler_tick, tickPeriod * 1000); + + fiber_flags |= MICROBIT_SCHEDULER_RUNNING; +} + +/* + * Reconfigures the system wide timer to the given period in milliseconds. + * + * @param speedMs the new period of the timer in milliseconds + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedMs < 1 + * + * @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick() + */ +int scheduler_set_tick_period(int speedMs) +{ + if(speedMs < 1) + return MICROBIT_INVALID_PARAMETER; + + tickPeriod = speedMs; + fiberSchedulerTicker.detach(); + fiberSchedulerTicker.attach_us(scheduler_tick, tickPeriod * 1000); + + return MICROBIT_OK; +} + +/* + * Returns the currently used tick speed in milliseconds + */ +int scheduler_get_tick_period() +{ + return tickPeriod; } /** - * Timer callback. Called from interrupt context, once every FIBER_TICK_PERIOD_MS milliseconds. + * 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; +} + +/** + * Timer callback. Called from interrupt context, once every FIBER_TICK_PERIOD_MS milliseconds, by default. * Simply checks to determine if any fibers blocked on the sleep queue need to be woken up * and made runnable. */ @@ -181,7 +246,7 @@ void scheduler_tick() Fiber *t; // increment our real-time counter. - ticks += uBit.getTickPeriod(); + ticks += scheduler_get_tick_period(); // Check the sleep queue, and wake up any fibers as necessary. while (f != NULL) @@ -197,12 +262,19 @@ void scheduler_tick() f = t; } + + // Update any components registered for a callback + for(int i = 0; i < MICROBIT_SYSTEM_COMPONENTS; i++) + if(systemTickComponents[i] != NULL) + systemTickComponents[i]->systemTick(); } /** * Event callback. Called from the message bus whenever an event is raised. * 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 to be processed. + * @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not associated with a MicroBitMessageBus. */ void scheduler_event(MicroBitEvent evt) { @@ -210,6 +282,12 @@ void scheduler_event(MicroBitEvent evt) Fiber *t; int notifyOneComplete = 0; + // This should never happen. + // It is however, safe to simply ignore any events provided, ans 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) { @@ -244,7 +322,7 @@ void scheduler_event(MicroBitEvent evt) // 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) - uBit.MessageBus.ignore(evt.source, evt.value, scheduler_event); + messageBus->ignore(evt.source, evt.value, scheduler_event); } @@ -291,7 +369,7 @@ void fiber_sleep(unsigned long t) /** * Blocks the calling thread until the specified event is raised. - * The calling thread will be immediatley descheduled, and placed onto a + * The calling thread will be immediately descheduled, and placed onto a * wait queue until the requested event is received. * * n.b. the fiber will not be be made runnable until after the event is raised, but there @@ -299,11 +377,15 @@ void fiber_sleep(unsigned long t) * * @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 associated with a MicroBitMessageBus. */ -void fiber_wait_for_event(uint16_t id, uint16_t value) +int fiber_wait_for_event(uint16_t id, uint16_t value) { Fiber *f = currentFiber; + if (messageBus == NULL) + 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) @@ -330,10 +412,12 @@ void fiber_wait_for_event(uint16_t id, uint16_t value) // 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) - uBit.MessageBus.listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus->listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE); // Finally, enter the scheduler. schedule(); + + return MICROBIT_OK; } /** @@ -643,7 +727,7 @@ void schedule() // 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 || fiber_flags & MICROBIT_FLAG_DATA_READY) + if (runQueue == NULL) currentFiber = idleFiber; else if (currentFiber->queue == &runQueue) @@ -667,7 +751,7 @@ void schedule() { idle(); } - while (runQueue == NULL || fiber_flags & MICROBIT_FLAG_DATA_READY); + 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. @@ -702,6 +786,91 @@ void schedule() } +/** + * Add a component to to the collection of those invoked when the scheduler's periodic timer is triggered. + * The given component is called on each interrupt, within interrupt context. + * + * @param component The component to add. + * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. + * @note this will be converted into a dynamic list of components + */ +int fiber_add_system_component(MicroBitComponent *component) +{ + int i = 0; + + 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 components + * @param component The component to remove. + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added. + * @note this will be converted into a dynamic list of components + */ +int fiber_remove_system_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; +} + +/** + * add a component to the array of components which invocate the systemTick member function during a systemTick + * @param component The component to add. + * @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported. + * @note this will be converted into a dynamic list of components + */ +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 components + * @param component The component to remove. + * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added. + * @note this will be converted into a dynamic list of components + */ +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 attmept power efficient sleep. @@ -709,16 +878,13 @@ void schedule() void idle() { // Service background tasks - uBit.systemTasks(); - + 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()) - { - if (uBit.ble) - uBit.ble->waitForEvent(); - else - __WFI(); - } + __WFI(); } /** * IDLE task. diff --git a/source/MicroBitFont.cpp b/source/MicroBitFont.cpp index d48fadb..6713c11 100644 --- a/source/MicroBitFont.cpp +++ b/source/MicroBitFont.cpp @@ -29,6 +29,7 @@ const unsigned char pendolino3[475] = { const unsigned char* MicroBitFont::defaultFont = pendolino3; +MicroBitFont MicroBitFont::systemFont = MicroBitFont(defaultFont, MICROBIT_FONT_ASCII_END); /** * Constructor. @@ -53,3 +54,21 @@ MicroBitFont::MicroBitFont() this->characters = defaultFont; this->asciiEnd = MICROBIT_FONT_ASCII_END; } + +/** + * Changes the current system font to the one specified. + * @param font the new font that will be used to render characters.. + */ +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; +} + diff --git a/source/MicroBitHeapAllocator.cpp b/source/MicroBitHeapAllocator.cpp index 3fac0c0..5c49d82 100644 --- a/source/MicroBitHeapAllocator.cpp +++ b/source/MicroBitHeapAllocator.cpp @@ -362,7 +362,7 @@ void *microbit_malloc(size_t size) #endif #if CONFIG_ENABLED(MICROBIT_PANIC_HEAP_FULL) - panic(MICROBIT_OOM); + MicroBitDisplay::panic(MICROBIT_OOM); #endif return NULL; diff --git a/source/MicroBitImage.cpp b/source/MicroBitImage.cpp index d2e9684..a8dcfbc 100644 --- a/source/MicroBitImage.cpp +++ b/source/MicroBitImage.cpp @@ -519,7 +519,7 @@ int MicroBitImage::print(char c, int16_t x, int16_t y) unsigned char v; int x1, y1; - MicroBitFont font = uBit.display.getFont(); + 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) diff --git a/source/MicroBitLightSensor.cpp b/source/MicroBitLightSensor.cpp index 8777107..f1c6eda 100644 --- a/source/MicroBitLightSensor.cpp +++ b/source/MicroBitLightSensor.cpp @@ -82,7 +82,8 @@ MicroBitLightSensor::MicroBitLightSensor() : analogTrigger() { this->chan = 0; - uBit.MessageBus.listen(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing, MESSAGE_BUS_LISTENER_IMMEDIATE); + if (MicroBitMessageBus::defaultMessageBus) + MicroBitMessageBus::defaultMessageBus->listen(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing, MESSAGE_BUS_LISTENER_IMMEDIATE); this->sensePin = NULL; } @@ -143,5 +144,6 @@ int MicroBitLightSensor::read() */ MicroBitLightSensor::~MicroBitLightSensor() { - uBit.MessageBus.ignore(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing); + if (MicroBitMessageBus::defaultMessageBus) + MicroBitMessageBus::defaultMessageBus->ignore(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing); } diff --git a/source/MicroBitMessageBus.cpp b/source/MicroBitMessageBus.cpp index bb76802..6492a13 100644 --- a/source/MicroBitMessageBus.cpp +++ b/source/MicroBitMessageBus.cpp @@ -6,6 +6,8 @@ #include "MicroBit.h" +MicroBitMessageBus* MicroBitMessageBus::defaultMessageBus = NULL; + /** * Constructor. * Create a new Message Bus. @@ -16,6 +18,9 @@ MicroBitMessageBus::MicroBitMessageBus() this->evt_queue_head = NULL; this->evt_queue_tail = NULL; this->queueLength = 0; + + if(MicroBitMessageBus::defaultMessageBus == NULL) + MicroBitMessageBus::defaultMessageBus = this; } /** @@ -594,5 +599,5 @@ MicroBitListener* MicroBitMessageBus::elementAt(int n) */ MicroBitMessageBus::~MicroBitMessageBus() { - uBit.removeIdleComponent(this); + fiber_remove_idle_component(this); } diff --git a/source/MicroBitMultiButton.cpp b/source/MicroBitMultiButton.cpp index 20d93b7..c570403 100644 --- a/source/MicroBitMultiButton.cpp +++ b/source/MicroBitMultiButton.cpp @@ -23,15 +23,15 @@ * MICROBIT_BUTTON_EVT_HOLD * @endcode */ -MicroBitMultiButton::MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2) +MicroBitMultiButton::MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2, MicroBitMessageBus &messageBus) { this->id = id; this->button1 = button1; this->button2 = button2; this->eventConfiguration = MICROBIT_BUTTON_SIMPLE_EVENTS; - uBit.MessageBus.listen(button1, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); - uBit.MessageBus.listen(button2, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(button1, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(button2, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); } uint16_t MicroBitMultiButton::otherSubButton(uint16_t b) @@ -150,7 +150,6 @@ void MicroBitMultiButton::setEventConfiguration(MicroBitButtonEventConfiguration { this->eventConfiguration = config; } - void MicroBitMultiButton::onButtonEvent(MicroBitEvent evt) { int button = evt.source; diff --git a/source/MicroBitSerial.cpp b/source/MicroBitSerial.cpp index 9d54c51..aac8b07 100644 --- a/source/MicroBitSerial.cpp +++ b/source/MicroBitSerial.cpp @@ -138,9 +138,13 @@ MicroBitImage MicroBitSerial::readImage(int width, int height) */ void MicroBitSerial::sendDisplayState() { + return; + + /* for(int i = 0; i < MICROBIT_DISPLAY_HEIGHT; i++) for(int j = 0; j < MICROBIT_DISPLAY_WIDTH; j++) _putc(uBit.display.image.getPixelValue(j,i)); + */ } /** @@ -153,12 +157,14 @@ void MicroBitSerial::sendDisplayState() */ void MicroBitSerial::readDisplayState() { + /* for(int i = 0; i < MICROBIT_DISPLAY_HEIGHT; i++) for(int j = 0; j < MICROBIT_DISPLAY_WIDTH; j++) { int c = _getc(); uBit.display.image.setPixelValue(j,i,c); } + */ } ssize_t MicroBitSerial::readChars(void* buffer, size_t length, char eof) { diff --git a/source/MicroBitSuperMain.cpp b/source/MicroBitSuperMain.cpp index b6a4e8a..b7c0dff 100644 --- a/source/MicroBitSuperMain.cpp +++ b/source/MicroBitSuperMain.cpp @@ -1,86 +1,18 @@ #include "MicroBit.h" +#ifdef UBIT_SUPERMAIN MicroBit uBit; -InterruptIn resetButton(MICROBIT_PIN_BUTTON_RESET); - -extern char* MICROBIT_BLE_DEVICE_NAME; int main() { - // Bring up soft reset button. - resetButton.mode(PullUp); - resetButton.fall(microbit_reset); - #if CONFIG_ENABLED(MICROBIT_DBG) - - // For diagnostics. Gives time to open the console window. :-) - for (int i=3; i>0; i--) - { - uBit.serial.printf("=== SUPERMAIN: Starting in %d ===\n", i); - wait(1.0); - } - - uBit.serial.printf("micro:bit runtime DAL version %s\n", MICROBIT_DAL_VERSION); - + uBit.serial.printf("micro:bit runtime version %s\n", MICROBIT_DAL_VERSION); #endif - // Bring up our nested heap allocator. - microbit_heap_init(); - - // Bring up fiber scheduler - scheduler_init(); - // Bring up random number generator, BLE, display and system timers. uBit.init(); - // Provide time for all threaded initialisers to complete. - uBit.sleep(100); - - //check our persistent storage for compassCalibrationData - MicroBitStorage s = MicroBitStorage(); - MicroBitConfigurationBlock *b = s.getConfigurationBlock(); - - //if we have some calibrated data, calibrate the compass! - if(b->magic == MICROBIT_STORAGE_CONFIG_MAGIC) - { - if(b->compassCalibrationData != CompassSample(0,0,0)) - uBit.compass.setCalibration(b->compassCalibrationData); - } - - delete b; - -#if CONFIG_ENABLED(MICROBIT_BLE_PAIRING_MODE) - // Test if we need to enter BLE pairing mode... - int i=0; - while (uBit.buttonA.isPressed() && uBit.buttonB.isPressed() && i<10) - { - uBit.sleep(100); - i++; - - if (i == 10) - { - // Start the BLE stack, if it isn't already running. - if (!uBit.ble) - { - uBit.bleManager.init(uBit.getName(), uBit.getSerial(), true); - uBit.ble = uBit.bleManager.ble; - } - - // Enter pairing mode, using the LED matrix for any necessary pairing operations - uBit.bleManager.pairingMode(uBit.display); - } - } -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) - // Start the BLE stack, if it isn't already running. - if (!uBit.ble) - { - uBit.bleManager.init(uBit.getName(), uBit.getSerial(), false); - uBit.ble = uBit.bleManager.ble; - } -#endif - + // Start the user application app_main(); // If app_main exits, there may still be other fibers running, registered event handlers etc. @@ -91,3 +23,5 @@ int main() // We should never get here, but just in case. while(1); } + +#endif diff --git a/source/MicroBitThermometer.cpp b/source/MicroBitThermometer.cpp index e730289..e5db65d 100644 --- a/source/MicroBitThermometer.cpp +++ b/source/MicroBitThermometer.cpp @@ -27,6 +27,7 @@ #endif #include "nrf_soc.h" +#include "nrf_sdm.h" /* * Return to our predefined compiler settings. @@ -56,7 +57,9 @@ MicroBitThermometer::MicroBitThermometer(uint16_t id) this->samplePeriod = MICROBIT_THERMOMETER_PERIOD; this->sampleTime = 0; - uBit.addIdleComponent(this); + // 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); } /** @@ -130,12 +133,15 @@ int MicroBitThermometer::getPeriod() void MicroBitThermometer::updateTemperature() { 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. - if (uBit.ble) + 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); diff --git a/source/RefCounted.cpp b/source/RefCounted.cpp index 3d4105e..36c43b6 100644 --- a/source/RefCounted.cpp +++ b/source/RefCounted.cpp @@ -17,7 +17,7 @@ static inline bool isReadOnlyInline(RefCounted *t) // Do some sanity checking while we're here if (refCount == 1 || // object should have been deleted (refCount & 1) == 0) // refCount doesn't look right - uBit.panic(MICROBIT_HEAP_ERROR); + MicroBitDisplay::panic(MICROBIT_HEAP_ERROR); // Not read only return false; diff --git a/source/ble-services/MicroBitAccelerometerService.cpp b/source/ble-services/MicroBitAccelerometerService.cpp index ac4d48a..8f31273 100644 --- a/source/ble-services/MicroBitAccelerometerService.cpp +++ b/source/ble-services/MicroBitAccelerometerService.cpp @@ -13,8 +13,8 @@ * Create a representation of the AccelerometerService * @param _ble The instance of a BLE device that we're running on. */ -MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) : - ble(_ble) +MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble, MicroBitAccelerometer &_accelerometer, MicroBitMessageBus &messageBus) : + ble(_ble), accelerometer(_accelerometer) { // Create the data structures that represent each of our characteristics in Soft Device. GattCharacteristic accelerometerDataCharacteristic(MicroBitAccelerometerServiceDataUUID, (uint8_t *)accelerometerDataCharacteristicBuffer, 0, @@ -28,7 +28,7 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) : accelerometerDataCharacteristicBuffer[0] = 0; accelerometerDataCharacteristicBuffer[1] = 0; accelerometerDataCharacteristicBuffer[2] = 0; - accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod(); + accelerometerPeriodCharacteristicBuffer = accelerometer.getPeriod(); // Set default security requirements accelerometerDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL); @@ -46,7 +46,7 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) : ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitAccelerometerService::onDataWritten); - uBit.MessageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); } /** @@ -57,11 +57,11 @@ void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams * if (params->handle == accelerometerPeriodCharacteristicHandle && params->len >= sizeof(accelerometerPeriodCharacteristicBuffer)) { accelerometerPeriodCharacteristicBuffer = *((uint16_t *)params->data); - uBit.accelerometer.setPeriod(accelerometerPeriodCharacteristicBuffer); + 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 = uBit.accelerometer.getPeriod(); + accelerometerPeriodCharacteristicBuffer = accelerometer.getPeriod(); ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer)); } } @@ -73,12 +73,12 @@ void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent) { if (ble.getGapState().connected) { - accelerometerDataCharacteristicBuffer[0] = uBit.accelerometer.getX(); - accelerometerDataCharacteristicBuffer[1] = uBit.accelerometer.getY(); - accelerometerDataCharacteristicBuffer[2] = uBit.accelerometer.getZ(); + accelerometerDataCharacteristicBuffer[0] = accelerometer.getX(); + accelerometerDataCharacteristicBuffer[1] = accelerometer.getY(); + accelerometerDataCharacteristicBuffer[2] = accelerometer.getZ(); - ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer)); - } + ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer)); + } } const uint8_t MicroBitAccelerometerServiceUUID[] = { diff --git a/source/ble-services/MicroBitBLEManager.cpp b/source/ble-services/MicroBitBLEManager.cpp index 206610f..c7ed50a 100644 --- a/source/ble-services/MicroBitBLEManager.cpp +++ b/source/ble-services/MicroBitBLEManager.cpp @@ -1,7 +1,7 @@ #include "MicroBit.h" -/* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ +/* 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... @@ -180,10 +180,10 @@ void MicroBitBLEManager::advertise() * * Example: * @code - * uBit.init(); + * bleManager.init("zevug"); * @endcode */ -void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, bool enableBonding) +void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, MicroBitMessageBus& messageBus, bool enableBonding) { ManagedString BLEName("BBC micro:bit"); this->deviceName = deviceName; @@ -254,42 +254,11 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb // Configure the radio at our default power level setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER); - // Bring up any configured auxiliary services. -#if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE) + // Bring up core BLE services. new MicroBitDFUService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE) DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, serialNumber.toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION); -#endif + new MicroBitEventService(*ble, messageBus); -#if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE) - new MicroBitEventService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_LED_SERVICE) - new MicroBitLEDService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE) - new MicroBitAccelerometerService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_MAGNETOMETER_SERVICE) - new MicroBitMagnetometerService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_BUTTON_SERVICE) - new MicroBitButtonService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_IO_PIN_SERVICE) - new MicroBitIOPinService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_TEMPERATURE_SERVICE) - new MicroBitTemperatureService(*ble); -#endif // Configure for high speed mode where possible. Gap::ConnectionParams_t fast; @@ -379,7 +348,7 @@ void MicroBitBLEManager::pairingComplete(bool success) if(success) { this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL; - uBit.addIdleComponent(this); + fiber_add_idle_component(this); } } @@ -392,14 +361,17 @@ void MicroBitBLEManager::idleTick() if (ble) ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF); - uBit.removeIdleComponent(this); + 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 A reference to the display on which to show usage notes and pass code information. + * @prarm authorizationButton The button to use to authorise a pairing request. */ -void MicroBitBLEManager::pairingMode(MicroBitDisplay &display) +void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton) { ManagedString namePrefix("BBC micro:bit ["); ManagedString namePostfix("]"); @@ -464,7 +436,7 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display) if (brightness >= 255) fadeDirection = 0; - if (uBit.buttonA.isPressed()) + if (authorisationButton.isPressed()) { pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST; pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE; @@ -478,15 +450,15 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display) for (int i=0; i= MICROBIT_BLE_PAIRING_TIMEOUT * 30) diff --git a/source/ble-services/MicroBitButtonService.cpp b/source/ble-services/MicroBitButtonService.cpp index 082c108..61b8fae 100644 --- a/source/ble-services/MicroBitButtonService.cpp +++ b/source/ble-services/MicroBitButtonService.cpp @@ -13,7 +13,7 @@ * Create a representation of the ButtonService * @param _ble The instance of a BLE device that we're running on. */ -MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) : +MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble, MicroBitMessageBus &messageBus) : ble(_ble) { // Create the data structures that represent each of our characteristics in Soft Device. @@ -43,8 +43,8 @@ MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) : ble.gattServer().write(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); ble.gattServer().write(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); - uBit.MessageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonAUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); - uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonBUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonAUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonBUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); } diff --git a/source/ble-services/MicroBitDFUService.cpp b/source/ble-services/MicroBitDFUService.cpp index e8b982d..d91d23d 100644 --- a/source/ble-services/MicroBitDFUService.cpp +++ b/source/ble-services/MicroBitDFUService.cpp @@ -72,11 +72,12 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params) { if(params->len > 0 && params->data[0] == MICROBIT_DFU_OPCODE_START_DFU) { - uBit.display.stopAnimation(); - uBit.display.clear(); + // TODO: Raise a SYSTEM event here. + //uBit.display.stopAnimation(); + //uBit.display.clear(); #if CONFIG_ENABLED(MICROBIT_DBG) - uBit.serial.printf(" ACTIVATING BOOTLOADER.\n"); + printf(" ACTIVATING BOOTLOADER.\n"); #endif // Perform an explicit disconnection to assist our peer to reconnect to the DFU service diff --git a/source/ble-services/MicroBitEventService.cpp b/source/ble-services/MicroBitEventService.cpp index 182ddfd..bc63c64 100644 --- a/source/ble-services/MicroBitEventService.cpp +++ b/source/ble-services/MicroBitEventService.cpp @@ -12,8 +12,8 @@ * Create a representation of the EventService * @param _ble The instance of a BLE device that we're running on. */ -MicroBitEventService::MicroBitEventService(BLEDevice &_ble) : - ble(_ble) +MicroBitEventService::MicroBitEventService(BLEDevice &_ble, MicroBitMessageBus &_messageBus) : + ble(_ble),messageBus(_messageBus) { GattCharacteristic microBitEventCharacteristic(MicroBitEventServiceMicroBitEventCharacteristicUUID, (uint8_t *)µBitEventBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); @@ -51,7 +51,7 @@ MicroBitEventService::MicroBitEventService(BLEDevice &_ble) : ble.onDataWritten(this, &MicroBitEventService::onDataWritten); - uBit.addIdleComponent(this); + fiber_add_idle_component(this); } @@ -79,7 +79,7 @@ void MicroBitEventService::onDataWritten(const GattWriteCallbackParams *params) // Read and register for all the events given... while (len >= 4) { - uBit.MessageBus.listen(e->type, e->reason, this, &MicroBitEventService::onMicroBitEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(e->type, e->reason, this, &MicroBitEventService::onMicroBitEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); len-=4; e++; @@ -111,7 +111,7 @@ void MicroBitEventService::idleTick() { if (!ble.getGapState().connected && messageBusListenerOffset >0) { messageBusListenerOffset = 0; - uBit.MessageBus.ignore(MICROBIT_ID_ANY, MICROBIT_EVT_ANY, this, &MicroBitEventService::onMicroBitEvent); + messageBus.ignore(MICROBIT_ID_ANY, MICROBIT_EVT_ANY, this, &MicroBitEventService::onMicroBitEvent); } } @@ -125,7 +125,7 @@ void MicroBitEventService::onRequirementsRead(GattReadAuthCallbackParams *params { // 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 = uBit.MessageBus.elementAt(messageBusListenerOffset++); + MicroBitListener *l = messageBus.elementAt(messageBusListenerOffset++); if (l != NULL) { diff --git a/source/ble-services/MicroBitIOPinService.cpp b/source/ble-services/MicroBitIOPinService.cpp index 3ba5ae8..4fcb8c8 100644 --- a/source/ble-services/MicroBitIOPinService.cpp +++ b/source/ble-services/MicroBitIOPinService.cpp @@ -13,8 +13,8 @@ * Create a representation of the IOPinService * @param _ble The instance of a BLE device that we're running on. */ -MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) : - ble(_ble) +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); @@ -48,7 +48,7 @@ MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) : ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitIOPinService::onDataWritten); - uBit.addIdleComponent(this); + fiber_add_idle_component(this); } /** @@ -113,10 +113,12 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params) for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++) { if(isDigital(i) && isInput(i)) - MicroBitIOPins[i]->getDigitalValue(); + io.pin[i].getDigitalValue(); + //MicroBitIOPins[i]->getDigitalValue(); if(isAnalog(i) && isInput(i)) - MicroBitIOPins[i]->getAnalogValue(); + io.pin[i].getAnalogValue(); + //MicroBitIOPins[i]->getAnalogValue(); } } @@ -133,10 +135,12 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params) for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++) { if(isDigital(i) && isInput(i)) - MicroBitIOPins[i]->getDigitalValue(); + io.pin[i].getDigitalValue(); + //MicroBitIOPins[i]->getDigitalValue(); if(isAnalog(i) && isInput(i)) - MicroBitIOPins[i]->getAnalogValue(); + io.pin[i].getAnalogValue(); + //MicroBitIOPins[i]->getAnalogValue(); } } @@ -152,9 +156,11 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params) if (isOutput(data->pin)) { if (isDigital(data->pin)) - MicroBitIOPins[data->pin]->setDigitalValue(data->value); + io.pin[data->pin].setDigitalValue(data->value); + //MicroBitIOPins[data->pin]->setDigitalValue(data->value); else - MicroBitIOPins[data->pin]->setAnalogValue(data->value*4); + io.pin[data->pin].setAnalogValue(data->value*4); + //MicroBitIOPins[data->pin]->setAnalogValue(data->value*4); } data++; @@ -182,9 +188,11 @@ void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params) uint8_t value; if (isDigital(i)) - value = MicroBitIOPins[i]->getDigitalValue(); + value = io.pin[i].getDigitalValue(); + //value = MicroBitIOPins[i]->getDigitalValue(); else - value = MicroBitIOPins[i]->getAnalogValue(); + value = io.pin[i].getAnalogValue(); + //value = MicroBitIOPins[i]->getAnalogValue(); ioPinServiceIOData[i] = value; ioPinServiceDataCharacteristicBuffer[pairs].pin = i; @@ -224,9 +232,11 @@ void MicroBitIOPinService::idleTick() uint8_t value; if (isDigital(i)) - value = MicroBitIOPins[i]->getDigitalValue(); + value = io.pin[i].getDigitalValue(); + //value = MicroBitIOPins[i]->getDigitalValue(); else - value = MicroBitIOPins[i]->getAnalogValue(); + value = io.pin[i].getAnalogValue(); + //value = MicroBitIOPins[i]->getAnalogValue(); // If the data has changed, send an update. if (value != ioPinServiceIOData[i]) @@ -265,6 +275,7 @@ 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, @@ -286,5 +297,5 @@ MicroBitPin * const MicroBitIOPins[] = { &uBit.io.P19, &uBit.io.P20 }; - +*/ diff --git a/source/ble-services/MicroBitLEDService.cpp b/source/ble-services/MicroBitLEDService.cpp index 5bccb55..86cb953 100644 --- a/source/ble-services/MicroBitLEDService.cpp +++ b/source/ble-services/MicroBitLEDService.cpp @@ -13,8 +13,8 @@ * Create a representation of the LEDService * @param _ble The instance of a BLE device that we're running on. */ -MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble) : - ble(_ble), +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) { @@ -64,7 +64,7 @@ void MicroBitLEDService::onDataWritten(const GattWriteCallbackParams *params) { for (int y=0; ylen; y++) for (int x=0; x<5; x++) - uBit.display.image.setPixelValue(x, y, (data[y] & (0x01 << (4-x))) ? 255 : 0); + display.image.setPixelValue(x, y, (data[y] & (0x01 << (4-x))) ? 255 : 0); } else if (params->handle == textCharacteristicHandle) @@ -74,7 +74,7 @@ void MicroBitLEDService::onDataWritten(const GattWriteCallbackParams *params) ManagedString s((char *)params->data, params->len); // Start the string scrolling and we're done. - uBit.display.scrollAsync(s, (int) scrollingSpeedCharacteristicBuffer); + display.scrollAsync(s, (int) scrollingSpeedCharacteristicBuffer); } else if (params->handle == scrollingSpeedCharacteristicHandle && params->len >= sizeof(scrollingSpeedCharacteristicBuffer)) @@ -98,7 +98,7 @@ void MicroBitLEDService::onDataRead(GattReadAuthCallbackParams *params) for (int x=0; x<5; x++) { - if (uBit.display.image.getPixelValue(x, y)) + if (display.image.getPixelValue(x, y)) matrixCharacteristicBuffer[y] |= 0x01 << (4-x); } } diff --git a/source/ble-services/MicroBitMagnetometerService.cpp b/source/ble-services/MicroBitMagnetometerService.cpp index ad24a44..7ba11af 100644 --- a/source/ble-services/MicroBitMagnetometerService.cpp +++ b/source/ble-services/MicroBitMagnetometerService.cpp @@ -13,8 +13,8 @@ * Create a representation of the MagnetometerService * @param _ble The instance of a BLE device that we're running on. */ -MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) : - ble(_ble) +MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble, MicroBitCompass &_compass, MicroBitMessageBus &messageBus) : + ble(_ble), compass(_compass) { // Create the data structures that represent each of our characteristics in Soft Device. GattCharacteristic magnetometerDataCharacteristic(MicroBitMagnetometerServiceDataUUID, (uint8_t *)magnetometerDataCharacteristicBuffer, 0, @@ -32,7 +32,7 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) : magnetometerDataCharacteristicBuffer[1] = 0; magnetometerDataCharacteristicBuffer[2] = 0; magnetometerBearingCharacteristicBuffer = 0; - magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod(); + magnetometerPeriodCharacteristicBuffer = compass.getPeriod(); // Set default security requirements magnetometerDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL); @@ -53,8 +53,8 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) : ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitMagnetometerService::onDataWritten); - uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); - uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded); + messageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded); } /** @@ -76,17 +76,18 @@ void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent) { if (ble.getGapState().connected) { - magnetometerDataCharacteristicBuffer[0] = uBit.compass.getX(); - magnetometerDataCharacteristicBuffer[1] = uBit.compass.getY(); - magnetometerDataCharacteristicBuffer[2] = uBit.compass.getZ(); - magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod(); + magnetometerDataCharacteristicBuffer[0] = compass.getX(); + magnetometerDataCharacteristicBuffer[1] = compass.getY(); + magnetometerDataCharacteristicBuffer[2] = compass.getZ(); + magnetometerBearingCharacteristicBuffer = (uint16_t) compass.heading(); + magnetometerPeriodCharacteristicBuffer = compass.getPeriod(); ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer)); ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); - if (uBit.compass.isCalibrated()) + if (compass.isCalibrated()) { - magnetometerBearingCharacteristicBuffer = (uint16_t) uBit.compass.heading(); + magnetometerBearingCharacteristicBuffer = (uint16_t) compass.heading(); ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerBearingCharacteristicBuffer)); } } @@ -100,11 +101,11 @@ void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent) void MicroBitMagnetometerService::samplePeriodUpdateNeeded(MicroBitEvent) { // Reconfigure the compass. This might take a while... - uBit.compass.setPeriod(magnetometerPeriodCharacteristicBuffer); + compass.setPeriod(magnetometerPeriodCharacteristicBuffer); // The compass will choose the nearest sample period to that we've specified. // Read the ACTUAL sample period back. - magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod(); + magnetometerPeriodCharacteristicBuffer = compass.getPeriod(); // Ensure this is reflected in our BLE connection. ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer)); diff --git a/source/ble-services/MicroBitRadio.cpp b/source/ble-services/MicroBitRadio.cpp index 01269e4..959d61a 100644 --- a/source/ble-services/MicroBitRadio.cpp +++ b/source/ble-services/MicroBitRadio.cpp @@ -47,7 +47,7 @@ extern "C" void RADIO_IRQHandler(void) { uint8_t sample = NRF_RADIO->RSSISAMPLE; - uBit.radio.setRSSI(sample); + MicroBitRadio::instance->setRSSI(sample); } // Start listening and wait for the END event @@ -61,7 +61,7 @@ extern "C" void RADIO_IRQHandler(void) * Initialise the MicroBitRadio. Note that this class is demand activated, so most resources are only committed * if send/recv or event registrations calls are made. */ -MicroBitRadio::MicroBitRadio(uint16_t id) : datagram() +MicroBitRadio::MicroBitRadio(uint16_t id) : datagram(*this), event (*this) { this->id = id; this->status = 0; @@ -101,7 +101,7 @@ int MicroBitRadio::setTransmitPower(int power) */ int MicroBitRadio::setFrequencyBand(int band) { - if (uBit.ble) + if (ble_running()) return MICROBIT_NOT_SUPPORTED; if (band < 0 || band > 100) @@ -212,7 +212,7 @@ int MicroBitRadio::enable() return MICROBIT_OK; // Only attempt to enable this radio mode if BLE is disabled. - if (uBit.ble) + if (ble_running()) return MICROBIT_NOT_SUPPORTED; // If this is the first time we've been enable, allocate out receive buffers. @@ -289,7 +289,7 @@ int MicroBitRadio::enable() NRF_RADIO->TASKS_START = 1; // register ourselves for a callback event, in order to empty the receive queue. - uBit.addIdleComponent(this); + fiber_add_idle_component(this); // Done. Record that our RADIO is configured. status |= MICROBIT_RADIO_STATUS_INITIALISED; @@ -304,7 +304,7 @@ int MicroBitRadio::enable() int MicroBitRadio::disable() { // Only attempt to enable.disable the radio if the protocol is alreayd running. - if (uBit.ble) + if (ble_running()) return MICROBIT_NOT_SUPPORTED; if (!(status & MICROBIT_RADIO_STATUS_INITIALISED)) @@ -318,7 +318,7 @@ int MicroBitRadio::disable() while(NRF_RADIO->EVENTS_DISABLED == 0); // deregister ourselves from the callback event used to empty the receive queue. - uBit.removeIdleComponent(this); + fiber_remove_idle_component(this); return MICROBIT_OK; } @@ -331,7 +331,7 @@ int MicroBitRadio::disable() */ int MicroBitRadio::setGroup(uint8_t group) { - if (uBit.ble) + if (ble_running()) return MICROBIT_NOT_SUPPORTED; // Record our group id locally @@ -422,7 +422,7 @@ FrameBuffer* MicroBitRadio::recv() */ int MicroBitRadio::send(FrameBuffer *buffer) { - if (uBit.ble) + if (ble_running()) return MICROBIT_NOT_SUPPORTED; if (buffer == NULL) diff --git a/source/ble-services/MicroBitRadioDatagram.cpp b/source/ble-services/MicroBitRadioDatagram.cpp index 8f96a73..d177a68 100644 --- a/source/ble-services/MicroBitRadioDatagram.cpp +++ b/source/ble-services/MicroBitRadioDatagram.cpp @@ -14,10 +14,12 @@ /** * Constructor. + * + * @param radio The underlying radio module used to send and receive data. */ -MicroBitRadioDatagram::MicroBitRadioDatagram() +MicroBitRadioDatagram::MicroBitRadioDatagram(MicroBitRadio &r) : radio(r) { - rxQueue = NULL; + this->rxQueue = NULL; } /** @@ -90,7 +92,7 @@ int MicroBitRadioDatagram::send(uint8_t *buffer, int len) buf.protocol = MICROBIT_RADIO_PROTOCOL_DATAGRAM; memcpy(buf.payload, buffer, len); - return uBit.radio.send(&buf); + return radio.send(&buf); } /** @@ -111,7 +113,7 @@ int MicroBitRadioDatagram::send(PacketBuffer data) */ void MicroBitRadioDatagram::packetReceived() { - FrameBuffer *packet = uBit.radio.recv(); + FrameBuffer *packet = radio.recv(); int queueDepth = 0; // We add to the tail of the queue to preserve causal ordering. diff --git a/source/ble-services/MicroBitRadioEvent.cpp b/source/ble-services/MicroBitRadioEvent.cpp index 4a9d445..2ac5b73 100644 --- a/source/ble-services/MicroBitRadioEvent.cpp +++ b/source/ble-services/MicroBitRadioEvent.cpp @@ -15,15 +15,34 @@ /** * Constructor. + * @param radio The underlying radio module that this service will use. */ -MicroBitRadioEvent::MicroBitRadioEvent() +MicroBitRadioEvent::MicroBitRadioEvent(MicroBitRadio &r) : radio(r) { - suppressForwarding = false; + this->suppressForwarding = false; } /** * Associates the given MessageBus events with the radio channel. * Once registered, all events matching the given registration sent to this micro:bit's + * default MessageBus will be automaticlaly retrasmitted on the radio. + * + * @param id The ID of the events to register. + * @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given id. + * + * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if no defult MessageBus is available. + */ +int MicroBitRadioEvent::listen(uint16_t id, uint16_t value) +{ + if (MicroBitMessageBus::defaultMessageBus) + return listen(id, value, *MicroBitMessageBus::defaultMessageBus); + + return MICROBIT_NO_RESOURCES; +} + +/** + * Associates the given MessageBus events with the radio channel. + * Once registered, all events matching the given registration sent to the given * MessageBus will be automaticlaly retrasmitted on the radio. * * @param id The ID of the events to register. @@ -31,9 +50,9 @@ MicroBitRadioEvent::MicroBitRadioEvent() * * @return MICROBIT_OK on success. */ -int MicroBitRadioEvent::listen(uint16_t id, uint16_t value) +int MicroBitRadioEvent::listen(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus) { - return uBit.MessageBus.listen(id, value, this, &MicroBitRadioEvent::eventReceived, MESSAGE_BUS_LISTENER_IMMEDIATE); + return messageBus.listen(id, value, this, &MicroBitRadioEvent::eventReceived, MESSAGE_BUS_LISTENER_IMMEDIATE); } /** @@ -42,20 +61,38 @@ int MicroBitRadioEvent::listen(uint16_t id, uint16_t value) * @param id The ID of the events to deregister. * @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given id. * - * @return MICROBIT_OK on success. + * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if no default MessageBus is available. */ int MicroBitRadioEvent::ignore(uint16_t id, uint16_t value) { - return uBit.MessageBus.ignore(id, value, this, &MicroBitRadioEvent::eventReceived); + if (MicroBitMessageBus::defaultMessageBus) + return ignore(id, value, *MicroBitMessageBus::defaultMessageBus); + + return MICROBIT_INVALID_PARAMETER; } +/** + * Disassociates the given MessageBus events with the radio channel. + * + * @param id The ID of the events to deregister. + * @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given id. + * @param The message bus to deregister on. + * + * @return MICROBIT_OK on success. + */ +int MicroBitRadioEvent::ignore(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus) +{ + return messageBus.ignore(id, value, this, &MicroBitRadioEvent::eventReceived); +} + + /** * Protocol handler callback. This is called when the radio receives a packet marked as an event * This function process this packet, and fires the event contained inside onto the local MessageBus. */ void MicroBitRadioEvent::packetReceived() { - FrameBuffer *p = uBit.radio.recv(); + FrameBuffer *p = radio.recv(); MicroBitEvent *e = (MicroBitEvent *) p->payload; suppressForwarding = true; @@ -83,6 +120,6 @@ void MicroBitRadioEvent::eventReceived(MicroBitEvent e) buf.protocol = MICROBIT_RADIO_PROTOCOL_EVENTBUS; memcpy(buf.payload, (const uint8_t *)&e, sizeof(MicroBitEvent)); - uBit.radio.send(&buf); + radio.send(&buf); } diff --git a/source/ble-services/MicroBitTemperatureService.cpp b/source/ble-services/MicroBitTemperatureService.cpp index 5d2fe86..bfadef7 100644 --- a/source/ble-services/MicroBitTemperatureService.cpp +++ b/source/ble-services/MicroBitTemperatureService.cpp @@ -13,8 +13,8 @@ * Create a representation of the TemperatureService * @param _ble The instance of a BLE device that we're running on. */ -MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) : - ble(_ble) +MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble, MicroBitThermometer &_thermometer, MicroBitMessageBus &messageBus) : + ble(_ble), thermometer(_thermometer) { // Create the data structures that represent each of our characteristics in Soft Device. GattCharacteristic temperatureDataCharacteristic(MicroBitTemperatureServiceDataUUID, (uint8_t *)&temperatureDataCharacteristicBuffer, 0, @@ -25,7 +25,7 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) : // Initialise our characteristic values. temperatureDataCharacteristicBuffer = 0; - temperaturePeriodCharacteristicBuffer = uBit.thermometer.getPeriod(); + temperaturePeriodCharacteristicBuffer = thermometer.getPeriod(); // Set default security requirements temperatureDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL); @@ -43,7 +43,7 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) : ble.gattServer().write(temperaturePeriodCharacteristicHandle,(uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitTemperatureService::onDataWritten); - uBit.MessageBus.listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus.listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE); } /** @@ -53,7 +53,7 @@ void MicroBitTemperatureService::temperatureUpdate(MicroBitEvent) { if (ble.getGapState().connected) { - temperatureDataCharacteristicBuffer = uBit.thermometer.getTemperature(); + temperatureDataCharacteristicBuffer = thermometer.getTemperature(); ble.gattServer().notify(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer)); } } @@ -66,11 +66,11 @@ void MicroBitTemperatureService::onDataWritten(const GattWriteCallbackParams *pa if (params->handle == temperaturePeriodCharacteristicHandle && params->len >= sizeof(temperaturePeriodCharacteristicBuffer)) { temperaturePeriodCharacteristicBuffer = *((uint16_t *)params->data); - uBit.thermometer.setPeriod(temperaturePeriodCharacteristicBuffer); + 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 = uBit.accelerometer.getPeriod(); + temperaturePeriodCharacteristicBuffer = thermometer.getPeriod(); ble.gattServer().write(temperaturePeriodCharacteristicHandle, (const uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer)); } }