diff --git a/inc/MicroBit.h b/inc/MicroBit.h index 53bff1c..184a3a0 100644 --- a/inc/MicroBit.h +++ b/inc/MicroBit.h @@ -3,7 +3,7 @@ #include "mbed.h" -#include "MicroBitConfig.h" +#include "MicroBitConfig.h" #include "MicroBitHeapAllocator.h" #include "MicroBitPanic.h" #include "ErrorNo.h" @@ -12,7 +12,7 @@ #include "MicroBitComponent.h" #include "ManagedType.h" #include "ManagedString.h" -#include "MicroBitImage.h" +#include "MicroBitImage.h" #include "MicroBitFont.h" #include "MicroBitEvent.h" #include "DynamicPwm.h" @@ -59,16 +59,16 @@ * Represents the device as a whole, and includes member variables to that reflect the components of the system. */ class MicroBit -{ +{ private: - + void seedRandom(); void compassCalibrator(MicroBitEvent e); uint32_t randomValue; - + public: - + // Map of device state. uint32_t flags; @@ -76,43 +76,43 @@ class MicroBit Ticker systemTicker; // I2C Interface - MicroBitI2C i2c; - + MicroBitI2C i2c; + // Serial Interface - MicroBitSerial serial; + 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; MicroBitButton buttonA; MicroBitButton buttonB; - MicroBitMultiButton buttonAB; + MicroBitMultiButton buttonAB; MicroBitAccelerometer accelerometer; MicroBitCompass compass; MicroBitThermometer thermometer; //An object of available IO pins on the device MicroBitIO io; - + // Bluetooth related member variables. MicroBitBLEManager bleManager; BLEDevice *ble; - + /** - * Constructor. + * Constructor. * Create a representation of a MicroBit device as a global singleton. * @param messageBus callback function to receive MicroBitMessageBus events. * * Exposed objects: - * @code + * @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. @@ -124,16 +124,16 @@ class MicroBit * uBit.io.P*; //Where P* is P0 to P16, P19 & P20 on the edge connector * @endcode */ - MicroBit(); + MicroBit(); /** * Post constructor initialisation method. - * After *MUCH* pain, it's noted that the BLE stack can't be brought up in a + * After *MUCH* pain, it's noted that the BLE stack can't be brought up in a * static context, so we bring it up here rather than in the constructor. * n.b. This method *must* be called in main() or later, not before. * * Example: - * @code + * @code * uBit.init(); * @endcode */ @@ -157,7 +157,7 @@ class MicroBit * Will reset the micro:bit when called. * * Example: - * @code + * @code * uBit.reset(); * @endcode */ @@ -168,15 +168,15 @@ class MicroBit * If the scheduler is running, this will deschedule the current fiber and perform * a power efficent, concurrent sleep operation. * If the scheduler is disabled or we're running in an interrupt context, this - * will revert to a busy wait. - * + * will revert to a busy wait. + * * @note Values of 6 and below tend to lose resolution - do you really need to sleep for this short amount of time? * * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative. - * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero. + * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero. * * Example: - * @code + * @code * uBit.sleep(20); //sleep for 20ms * @endcode */ @@ -191,7 +191,7 @@ class MicroBit * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_PARAMETER if max is <= 0. * * Example: - * @code + * @code * uBit.random(200); //a number between 0 and 199 * @endcode */ @@ -202,27 +202,27 @@ class MicroBit * 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 + * 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 @@ -230,7 +230,7 @@ class MicroBit * @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. @@ -245,7 +245,7 @@ class MicroBit * TODO: handle overflow case. */ unsigned long systemTime(); - + /** * Determine the version of the micro:bit runtime currently in use. * @@ -256,7 +256,7 @@ 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); @@ -274,4 +274,3 @@ extern "C" void app_main(); #endif - diff --git a/inc/MicroBitAccelerometer.h b/inc/MicroBitAccelerometer.h index 1a26398..6d7b00b 100644 --- a/inc/MicroBitAccelerometer.h +++ b/inc/MicroBitAccelerometer.h @@ -57,7 +57,7 @@ #define MICROBIT_ACCELEROMETER_EVT_FACE_UP 5 #define MICROBIT_ACCELEROMETER_EVT_FACE_DOWN 6 #define MICROBIT_ACCELEROMETER_EVT_FREEFALL 7 -#define MICROBIT_ACCELEROMETER_EVT_3G 8 +#define MICROBIT_ACCELEROMETER_EVT_3G 8 #define MICROBIT_ACCELEROMETER_EVT_6G 9 #define MICROBIT_ACCELEROMETER_EVT_8G 10 #define MICROBIT_ACCELEROMETER_EVT_SHAKE 11 @@ -140,10 +140,10 @@ struct ShakeHistory class MicroBitAccelerometer : public MicroBitComponent { /** - * Unique, enumerated ID for this component. + * Unique, enumerated ID for this component. * Used to track asynchronous events in the event bus. */ - + uint16_t address; // I2C address of this accelerometer. uint16_t samplePeriod; // The time between samples, in milliseconds. uint8_t sampleRange; // The sample range of the accelerometer in g. @@ -152,20 +152,20 @@ class MicroBitAccelerometer : public MicroBitComponent float pitch; // Pitch of the device, in radians. float roll; // Roll of the device, in radians. uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable. - BasicGesture lastGesture; // the last, stable gesture recorded. + BasicGesture lastGesture; // the last, stable gesture recorded. BasicGesture currentGesture; // the instantaneous, unfiltered gesture detected. ShakeHistory shake; // State information needed to detect shake events. - + public: /** - * Constructor. + * Constructor. * Create an accelerometer representation with the given ID. * @param id the ID of the new object. - * @param address the default base address of the accelerometer. + * @param address the default base address of the accelerometer. * * Example: - * @code + * @code * accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR) * @endcode */ @@ -199,7 +199,7 @@ class MicroBitAccelerometer : public MicroBitComponent int setPeriod(int period); /** - * Reads the currently configured sample rate of the accelerometer. + * Reads the currently configured sample rate of the accelerometer. * @return The time between samples, in milliseconds. */ int getPeriod(); @@ -214,17 +214,17 @@ class MicroBitAccelerometer : public MicroBitComponent int setRange(int range); /** - * Reads the currently configured sample range of the accelerometer. + * Reads the currently configured sample range of the accelerometer. * @return The sample range, in g. */ int getRange(); /** - * Attempts to determine the 8 bit ID from the accelerometer. + * Attempts to determine the 8 bit ID from the accelerometer. * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails. * * Example: - * @code + * @code * uBit.accelerometer.whoAmI(); * @endcode */ @@ -236,32 +236,32 @@ class MicroBitAccelerometer : public MicroBitComponent * @return The force measured in the X axis, in milli-g. * * Example: - * @code + * @code * uBit.accelerometer.getX(); * @endcode */ int getX(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN); - + /** * Reads the Y axis value of the latest update from the accelerometer. * @return The force measured in the Y axis, in milli-g. * * Example: - * @code + * @code * uBit.accelerometer.getY(); * @endcode - */ + */ int getY(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN); - + /** * Reads the Z axis value of the latest update from the accelerometer. * @return The force measured in the Z axis, in milli-g. * * Example: - * @code + * @code * uBit.accelerometer.getZ(); * @endcode - */ + */ int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN); /** @@ -269,10 +269,10 @@ class MicroBitAccelerometer : public MicroBitComponent * @return The pitch of the device, in degrees. * * Example: - * @code + * @code * uBit.accelerometer.getPitch(); * @endcode - */ + */ int getPitch(); float getPitchRadians(); @@ -281,10 +281,10 @@ class MicroBitAccelerometer : public MicroBitComponent * @return The roll of the device, in degrees. * * Example: - * @code + * @code * uBit.accelerometer.getRoll(); * @endcode - */ + */ int getRoll(); float getRollRadians(); @@ -293,16 +293,16 @@ class MicroBitAccelerometer : public MicroBitComponent * @return The last gesture detected. * * Example: - * @code + * @code * if (uBit.accelerometer.getGesture() == SHAKE) * @endcode - */ + */ BasicGesture getGesture(); /** * periodic callback from MicroBit idle thread. * Check if any data is ready for reading by checking the interrupt flag on the accelerometer - */ + */ virtual void idleTick(); /** @@ -310,6 +310,11 @@ class MicroBitAccelerometer : public MicroBitComponent */ virtual int isIdleCallbackNeeded(); + /** + * Destructor for MicroBitButton, so that we deregister ourselves as an idleComponent + */ + ~MicroBitAccelerometer(); + private: /** * Issues a standard, 2 byte I2C command write to the accelerometer. @@ -341,7 +346,7 @@ class MicroBitAccelerometer : public MicroBitComponent /** * - * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote + * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote * stability. */ void updateGesture(); diff --git a/inc/MicroBitButton.h b/inc/MicroBitButton.h index 59370d4..abc50df 100644 --- a/inc/MicroBitButton.h +++ b/inc/MicroBitButton.h @@ -17,8 +17,8 @@ #define MICROBIT_BUTTON_EVT_HOLD 5 #define MICROBIT_BUTTON_EVT_DOUBLE_CLICK 6 -#define MICROBIT_BUTTON_LONG_CLICK_TIME 1000 -#define MICROBIT_BUTTON_HOLD_TIME 1500 +#define MICROBIT_BUTTON_LONG_CLICK_TIME 1000 +#define MICROBIT_BUTTON_HOLD_TIME 1500 #define MICROBIT_BUTTON_STATE 1 #define MICROBIT_BUTTON_STATE_HOLD_TRIGGERED 2 @@ -47,27 +47,27 @@ class MicroBitButton : public MicroBitComponent { PinName name; // mbed pin name of this pin. DigitalIn pin; // The mbed object looking after this pin at any point in time (may change!). - + unsigned long downStartTime; // used to store the current system clock when a button down event occurs uint8_t sigma; // integration of samples over time. We use this for debouncing, and noise tolerance for touch sensing MicroBitButtonEventConfiguration eventConfiguration; // Do we want to generate high level event (clicks), or defer this to another service. - + public: /** - * Constructor. + * Constructor. * Create a pin representation with the given ID. * @param id the ID of the new MicroBitButton object. * @param name the physical pin on the processor that this butotn is connected to. * @param mode the configuration of internal pullups/pulldowns, as define in the mbed PinMode class. PullNone by default. * * Example: - * @code + * @code * buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A); //a number between 0 and 200 inclusive * @endcode * * Possible Events: - * @code + * @code * MICROBIT_BUTTON_EVT_DOWN * MICROBIT_BUTTON_EVT_UP * MICROBIT_BUTTON_EVT_CLICK @@ -77,25 +77,29 @@ class MicroBitButton : public MicroBitComponent * @endcode */ MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventConfiguration eventConfiguration = MICROBIT_BUTTON_ALL_EVENTS, PinMode mode = PullNone); - + /** * Tests if this Button is currently pressed. * @return 1 if this button is pressed, 0 otherwise. * * Example: - * @code + * @code * if(uBit.buttonA.isPressed()) * print("Pressed!"); * @endcode */ int isPressed(); - + /** * periodic callback from MicroBit clock. * Check for state change for this button, and fires a hold event if button is pressed. - */ + */ virtual void systemTick(); - + + /** + * Destructor for MicroBitButton, so that we deregister ourselves as a systemComponent + */ + ~MicroBitButton(); }; #endif diff --git a/inc/MicroBitCompass.h b/inc/MicroBitCompass.h index a294c65..37b96ce 100644 --- a/inc/MicroBitCompass.h +++ b/inc/MicroBitCompass.h @@ -48,7 +48,7 @@ struct MAG3110SampleRateConfig extern const MAG3110SampleRateConfig MAG3110SampleRate[]; -#define MAG3110_SAMPLE_RATES 11 +#define MAG3110_SAMPLE_RATES 11 /* * Compass events @@ -66,7 +66,7 @@ extern const MAG3110SampleRateConfig MAG3110SampleRate[]; */ #define MICROBIT_COMPASS_STATUS_CALIBRATED 1 #define MICROBIT_COMPASS_STATUS_CALIBRATING 2 - + /* * Term to convert sample data into SI units */ @@ -83,19 +83,19 @@ struct CompassSample int x; int y; int z; - + CompassSample() { this->x = 0; this->y = 0; - this->z = 0; + this->z = 0; } CompassSample(int x, int y, int z) { this->x = x; this->y = y; - this->z = z; + this->z = z; } }; @@ -108,11 +108,11 @@ struct CompassSample class MicroBitCompass : public MicroBitComponent { /** - * Unique, enumerated ID for this component. + * Unique, enumerated ID for this component. * Used to track asynchronous events in the event bus. */ - - uint16_t address; // I2C address of the magnetmometer. + + uint16_t address; // I2C address of the magnetmometer. uint16_t samplePeriod; // The time between samples, in millseconds. CompassSample average; // Centre point of sample data. @@ -120,9 +120,9 @@ class MicroBitCompass : public MicroBitComponent DigitalIn int1; // Data ready interrupt. public: - + /** - * Constructor. + * Constructor. * Create a compass representation with the given ID. * @param id the event ID of the compass object. * @param address the default address for the compass register @@ -140,7 +140,7 @@ class MicroBitCompass : public MicroBitComponent * @endcode */ MicroBitCompass(uint16_t id, uint16_t address); - + /** * Configures the compass for the sample rate defined * in this object. The nearest values are chosen to those defined @@ -160,7 +160,7 @@ class MicroBitCompass : public MicroBitComponent int setPeriod(int period); /** - * Reads the currently configured sample rate of the compass. + * Reads the currently configured sample rate of the compass. * @return The time between samples, in milliseconds. */ int getPeriod(); @@ -169,10 +169,10 @@ class MicroBitCompass : public MicroBitComponent * Gets the current heading of the device, relative to magnetic north. * If the compass is not calibrated, it will raise the MICROBIT_COMPASS_EVT_CALIBRATE event. * Users wishing to implement their own calibration algorithms should listen for this event, - * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before - * the user program continues. - * - * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating. + * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before + * the user program continues. + * + * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating. * * Example: * @code @@ -182,7 +182,7 @@ class MicroBitCompass : public MicroBitComponent int heading(); /** - * Attempts to determine the 8 bit ID from the magnetometer. + * Attempts to determine the 8 bit ID from the magnetometer. * @return the id of the compass (magnetometer), or MICROBIT_I2C_ERROR if the magnetometer could not be updated. * * Example: @@ -202,7 +202,7 @@ class MicroBitCompass : public MicroBitComponent * @endcode */ int getX(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN); - + /** * Reads the Y axis value of the latest update from the compass. * @return The magnetic force measured in the Y axis, in nano teslas. @@ -211,9 +211,9 @@ class MicroBitCompass : public MicroBitComponent * @code * uBit.compass.getY(); * @endcode - */ + */ int getY(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN); - + /** * Reads the Z axis value of the latest update from the compass. * @return The magnetic force measured in the Z axis, in nano teslas. @@ -222,8 +222,8 @@ class MicroBitCompass : public MicroBitComponent * @code * uBit.compass.getZ(); * @endcode - */ - int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN); + */ + int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN); /** * Determines the overall magnetic field strength based on the latest update from the compass. @@ -233,21 +233,21 @@ class MicroBitCompass : public MicroBitComponent * @code * uBit.compass.getFieldStrength(); * @endcode - */ + */ int getFieldStrength(); /** - * Reads the current die temperature of the compass. + * Reads the current die temperature of the compass. * @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the magnetometer could not be updated. */ int readTemperature(); /** * Perform a calibration of the compass. - * + * * This method will be called automatically if a user attempts to read a compass value when * the compass is uncalibrated. It can also be called at any time by the user. - * + * * Any old calibration data is deleted. * The method will only return once the compass has been calibrated. * @@ -265,7 +265,7 @@ class MicroBitCompass : public MicroBitComponent * @note *** THIS FUNCITON IS NOW DEPRECATED AND WILL BE REMOVED IN THE NEXT MAJOR RELEASE *** * @note *** PLEASE USE THE calibrate() FUNCTION INSTEAD *** */ - void calibrateAsync(); + void calibrateAsync(); /** * Perform a calibration of the compass. @@ -274,62 +274,67 @@ class MicroBitCompass : public MicroBitComponent * @note *** THIS FUNCITON IS NOW DEPRECATED AND WILL BE REMOVED IN THE NEXT MAJOR RELEASE *** * @note *** PLEASE USE THE calibrate() FUNCTION INSTEAD *** */ - int calibrateStart(); + int calibrateStart(); /** * Complete the calibration of the compass. * This will fire MICROBIT_COMPASS_EVT_CAL_END. * * @note *** THIS FUNCITON IS NOW DEPRECATED AND WILL BE REMOVED IN THE NEXT MAJOR RELEASE *** - */ - void calibrateEnd(); + */ + void calibrateEnd(); /** * Configure the compass to use the given calibration data. * Calibration data is comprised of the perceived zero offset of each axis of the compass. - * After calibration this should now take into account trimming errors in the magnetometer, + * After calibration this should now take into account trimming errors in the magnetometer, * and any "hard iron" offsets on the device. * * @param The x, y and z zero offsets to use as calibration data. - */ + */ void setCalibration(CompassSample calibration); /** * Provides the calibration data currently in use by the compass. * More specifically, the x, y and z zero offsets of the compass. * - * @return The x, y and z xero offsets of the compass. - */ + * @return The x, y and z xero offsets of the compass. + */ CompassSample getCalibration(); /** * Periodic callback from MicroBit idle thread. * Check if any data is ready for reading by checking the interrupt. - */ + */ virtual void idleTick(); - + /** * Returns 0 or 1. 1 indicates that the compass is calibrated, zero means the compass requires calibration. */ int isCalibrated(); - + /** * Returns 0 or 1. 1 indicates that the compass is calibrating, zero means the compass is not currently calibrating. */ int isCalibrating(); - + /** * Clears the calibration held in persistent storage, and sets the calibrated flag to zero. */ void clearCalibration(); - + /** * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read. */ virtual int isIdleCallbackNeeded(); - + + /** + * Destructor for MicroBitCompass, so that we deregister ourselves as an idleComponent + */ + ~MicroBitCompass(); + private: - + /** * Issues a standard, 2 byte I2C command write to the magnetometer. * Blocks the calling thread until complete. @@ -339,7 +344,7 @@ class MicroBitCompass : public MicroBitComponent * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the magnetometer could not be accessed. */ int writeCommand(uint8_t reg, uint8_t value); - + /** * Issues a read command into the specified buffer. * Blocks the calling thread until complete. @@ -350,7 +355,7 @@ class MicroBitCompass : public MicroBitComponent * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the magnetometer could not be accessed. */ int readCommand(uint8_t reg, uint8_t* buffer, int length); - + /** * Issues a read of a given address, and returns the value. * Blocks the calling thread until complete. @@ -359,8 +364,8 @@ class MicroBitCompass : public MicroBitComponent * @return The register value, interpreted as a 16 but signed value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed. */ int read16(uint8_t reg); - - + + /** * Issues a read of a given address, and returns the value. * Blocks the calling thread until complete. diff --git a/inc/MicroBitDisplay.h b/inc/MicroBitDisplay.h index 86e6dd3..539569b 100644 --- a/inc/MicroBitDisplay.h +++ b/inc/MicroBitDisplay.h @@ -73,7 +73,7 @@ enum AnimationMode { enum DisplayMode { DISPLAY_MODE_BLACK_AND_WHITE, - DISPLAY_MODE_GREYSCALE + DISPLAY_MODE_GREYSCALE }; enum DisplayRotation { @@ -172,24 +172,24 @@ class MicroBitDisplay : public MicroBitComponent * Periodic callback, that we use to perform any animations we have running. */ void animationUpdate(); - + /** * Called by the display in an interval determined by the brightness of the display, to give an impression * of brightness. */ void renderFinish(); - + /** * Translates a bit mask to a bit mask suitable for the nrf PORT0 and PORT1. * Brightness has two levels on, or off. */ void render(); - + /** * Translates a bit mask into a timer interrupt that gives the appearence of greyscale. */ void renderGreyscale(); - + /** * Internal scrollText update method. * Shift the screen image by one pixel to the left. If necessary, paste in the next char. @@ -224,7 +224,7 @@ class MicroBitDisplay : public MicroBitComponent /** * Blocks the current fiber until the display is available (i.e. not effect is being displayed). * Animations are queued until their time to display. - */ + */ void waitForFreeDisplay(); public: @@ -255,16 +255,16 @@ public: * Frame update method, invoked periodically to strobe the display. */ virtual void systemTick(); - + /** * Prints the given character to the display, if it is not in use. * * @param c The character to display. * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever. * @return MICROBIT_OK, MICROBIT_BUSY is the screen is in use, or MICROBIT_INVALID_PARAMETER. - * + * * Example: - * @code + * @code * uBit.display.printAsync('p'); * uBit.display.printAsync('p',100); * @endcode @@ -294,7 +294,7 @@ public: * @param i The image to display. * @param x The horizontal position on the screen to display the image (default 0) * @param y The vertical position on the screen to display the image (default 0) - * @param alpha Treats the brightness level '0' as transparent (default 0) + * @param alpha Treats the brightness level '0' as transparent (default 0) * @param delay The time to delay between characters, in milliseconds. set to 0 to display forever. (default 0). * * Example: @@ -334,7 +334,7 @@ public: * @endcode */ int print(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED); - + /** * Prints the given image to the display. * Blocks the calling thread until all the text has been displayed. @@ -350,7 +350,7 @@ public: * @endcode */ int print(MicroBitImage i, int x, int y, int alpha, int delay = 0); - + /** * Scrolls the given string to the display, from right to left. * Uses the given delay between characters. @@ -474,14 +474,14 @@ public: /** * Sets the mode of the display. * @param mode The mode to swap the display into. (can be either DISPLAY_MODE_GREYSCALE, or DISPLAY_MODE_NORMAL) - * + * * Example: - * @code + * @code * uBit.display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness * @endcode - */ + */ void setDisplayMode(DisplayMode mode); - + /** * Fetches the current brightness of this display. * @return the brightness of this display, in the range 0..255. @@ -557,12 +557,16 @@ public: * Retreives the font object used for rendering characters on the display. */ MicroBitFont getFont(); - + /** * Captures the bitmap currently being rendered on the display. */ MicroBitImage screenShot(); + + /** + * Destructor for MicroBitDisplay, so that we deregister ourselves as a systemComponent + */ + ~MicroBitDisplay(); }; #endif - diff --git a/inc/MicroBitMessageBus.h b/inc/MicroBitMessageBus.h index abd38f7..8cf63c3 100644 --- a/inc/MicroBitMessageBus.h +++ b/inc/MicroBitMessageBus.h @@ -18,7 +18,7 @@ * MicroBit platform. It serves a number of purposes: * * 1) It provides an eventing abstraction that is independent of the underlying substrate. - * 2) It provides a mechanism to decouple user code from trusted system code + * 2) It provides a mechanism to decouple user code from trusted system code * i.e. the basis of a message passing nano kernel. * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE... * 4) It provides a mechanims for extensibility - new devices added via I/O pins can have OO based @@ -34,23 +34,23 @@ class MicroBitMessageBus : public MicroBitComponent public: /** - * Default constructor. + * Default constructor. * Anticipating only one MessageBus per device, as filtering is handled within the class. */ - MicroBitMessageBus(); + MicroBitMessageBus(); /** * Queues the given event to be sent to all registered recipients. * - * @param The event to send. + * @param The event to send. * * n.b. THIS IS NOW WRAPPED BY THE MicroBitEvent CLASS FOR CONVENIENCE... * * Example: - * @code + * @code * MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN,ticks,false); * evt.fire(); - * //OR YOU CAN DO THIS... + * //OR YOU CAN DO THIS... * MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN); * @endcode */ @@ -63,7 +63,7 @@ class MicroBitMessageBus : public MicroBitComponent * IT IS RECOMMENDED THAT ALL EXTERNAL CODE USE THE send() FUNCTIONS INSTEAD OF THIS FUNCTION, * or the constructors provided by MicroBitEvent. * - * @param evt The event to send. + * @param evt The event to send. * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed * otherwise, all other (standard) listeners will be processed. * @return 1 if all matching listeners were processed, 0 if further processing is required. @@ -72,19 +72,19 @@ class MicroBitMessageBus : public MicroBitComponent /** * Register a listener function. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. * Use MICROBIT_ID_ANY to receive events from all components. * - * @param value The value of messages to listen for. Events with any other values will be filtered. + * @param value The value of messages to listen for. Events with any other values will be filtered. * Use MICROBIT_EVT_ANY to receive events of any value. * * @param handler The function to call when an event is received. * * @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER - * + * * Example: - * @code + * @code * void onButtonBClick() * { * //do something @@ -93,22 +93,22 @@ class MicroBitMessageBus : public MicroBitComponent * @endcode */ int listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS); - + /** * Register a listener function. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. * Use MICROBIT_ID_ANY to receive events from all components. * - * @param value The value of messages to listen for. Events with any other values will be filtered. + * @param value The value of messages to listen for. Events with any other values will be filtered. * Use MICROBIT_EVT_ANY to receive events of any value. * * @param hander The function to call when an event is received. * * @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER - * + * * Example: - * @code + * @code * void onButtonBClick(void *arg) * { * //do something @@ -120,26 +120,26 @@ class MicroBitMessageBus : public MicroBitComponent /** * Register a listener function. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. * Use MICROBIT_ID_ANY to receive events from all components. * - * @param value The value of messages to listen for. Events with any other values will be filtered. + * @param value The value of messages to listen for. Events with any other values will be filtered. * Use MICROBIT_EVT_ANY to receive events of any value. * * @param hander The function to call when an event is received. * * @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER - * + * * Example: - * @code + * @code * void SomeClass::onButtonBClick() * { * //do something * } * * SomeClass s = new SomeClass(); - * uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); * @endcode */ template @@ -149,7 +149,7 @@ class MicroBitMessageBus : public MicroBitComponent /** * Unregister a listener function. * Listners are identified by the Event ID, Event VALUE and handler registered using listen(). - * + * * @param id The Event ID used to register the listener. * @param value The Event VALUE used to register the listener. * @param handler The function used to register the listener. @@ -158,21 +158,21 @@ class MicroBitMessageBus : public MicroBitComponent * * * Example: - * @code + * @code * void onButtonBClick() * { * //do something * } * - * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); + * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); * @endcode */ int ignore(int id, int value, void (*handler)(MicroBitEvent)); - + /** * Unregister a listener function. * Listners are identified by the Event ID, Event VALUE and handler registered using listen(). - * + * * @param id The Event ID used to register the listener. * @param value The Event VALUE used to register the listener. * @param handler The function used to register the listener. @@ -180,13 +180,13 @@ class MicroBitMessageBus : public MicroBitComponent * @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER * * Example: - * @code + * @code * void onButtonBClick(void *arg) * { * //do something * } * - * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); + * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); * @endcode */ int ignore(int id, int value, void (*handler)(MicroBitEvent, void*)); @@ -194,7 +194,7 @@ class MicroBitMessageBus : public MicroBitComponent /** * Unregister a listener function. * Listners are identified by the Event ID, Event VALUE and handler registered using listen(). - * + * * @param id The Event ID used to register the listener. * @param value The Event VALUE used to register the listener. * @param handler The function used to register the listener. @@ -202,15 +202,15 @@ class MicroBitMessageBus : public MicroBitComponent * @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER * * Example: - * @code - * + * @code + * * void SomeClass::onButtonBClick() * { * //do something * } * * SomeClass s = new SomeClass(); - * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); * @endcode */ template @@ -223,6 +223,11 @@ class MicroBitMessageBus : public MicroBitComponent */ MicroBitListener *elementAt(int n); + /** + * Destructor for MicroBitMessageBus, so that we deregister ourselves as an idleComponent + */ + ~MicroBitMessageBus(); + private: /** @@ -250,7 +255,7 @@ class MicroBitMessageBus : public MicroBitComponent MicroBitEventQueueItem *evt_queue_tail; // Tail of queued events to be processed. uint16_t nonce_val; // The last nonce issued. uint16_t queueLength; // The number of events currently waiting to be processed. - + void queueEvent(MicroBitEvent &evt); MicroBitEventQueueItem* dequeueEvent(); @@ -262,10 +267,10 @@ class MicroBitMessageBus : public MicroBitComponent * A registration function to allow C++ member funcitons (methods) to be registered as an event * listener. * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. * Use MICROBIT_ID_ANY to receive events from all components. * - * @param value The value of messages to listen for. Events with any other values will be filtered. + * @param value The value of messages to listen for. Events with any other values will be filtered. * Use MICROBIT_EVT_ANY to receive events of any value. * * @param object The object on which the method should be invoked. @@ -291,7 +296,7 @@ int MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T:: /** * Unregister a listener function. * Listners are identified by the Event ID, Event VALUE and handler registered using listen(). - * + * * @param id The Event ID used to register the listener. * @param value The Event VALUE used to register the listener. * @param handler The function used to register the listener. @@ -299,13 +304,13 @@ int MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T:: * @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER * * Example: - * @code + * @code * void onButtonBClick(void *arg) * { * //do something * } * - * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); + * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); * @endcode */ template @@ -322,5 +327,3 @@ int MicroBitMessageBus::ignore(uint16_t id, uint16_t value, T* object, void (T:: #endif - - diff --git a/module.json b/module.json index 13254ee..0d4e6a9 100644 --- a/module.json +++ b/module.json @@ -1,6 +1,6 @@ { "name": "microbit-dal", - "version": "1.4.4", + "version": "1.4.6", "license": "Apache2", "description": "The runtime library for the BBC micro:bit, developed by Lancaster University", "keywords": [ @@ -21,4 +21,4 @@ "extraIncludes": [ "inc" ] -} +} \ No newline at end of file diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index b0a25dd..ccc0fb7 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -5,7 +5,7 @@ */ void panic(int statusCode) { - uBit.panic(statusCode); + uBit.panic(statusCode); } /** @@ -43,30 +43,30 @@ void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *reason) { (void) reason; /* -Wunused-param */ - uBit.ble->startAdvertising(); + uBit.ble->startAdvertising(); } /** - * Constructor. + * Constructor. * Create a representation of a MicroBit device as a global singleton. * @param messageBus callback function to receive MicroBitMessageBus events. * * Exposed objects: - * @code + * @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. * uBit.buttonB; //The buttonB object for button b. - * uBit.buttonAB; //The buttonAB object for button a+b multi press. + * uBit.buttonAB; //The buttonAB object for button a+b multi press. * uBit.resetButton; //The resetButton used for soft resets. * uBit.accelerometer; //The object that represents the inbuilt accelerometer * uBit.compass; //The object that represents the inbuilt compass(magnetometer) * uBit.io.P*; //Where P* is P0 to P16, P19 & P20 on the edge connector * @endcode */ -MicroBit::MicroBit() : +MicroBit::MicroBit() : flags(0x00), i2c(MICROBIT_PIN_SDA, MICROBIT_PIN_SCL), serial(USBTX, USBRX), @@ -74,7 +74,7 @@ MicroBit::MicroBit() : display(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_WIDTH, MICROBIT_DISPLAY_HEIGHT), buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A, MICROBIT_BUTTON_SIMPLE_EVENTS), buttonB(MICROBIT_ID_BUTTON_B,MICROBIT_PIN_BUTTON_B, MICROBIT_BUTTON_SIMPLE_EVENTS), - buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B), + 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), thermometer(MICROBIT_ID_THERMOMETER), @@ -86,25 +86,25 @@ MicroBit::MicroBit() : MICROBIT_ID_IO_P15,MICROBIT_ID_IO_P16,MICROBIT_ID_IO_P19, MICROBIT_ID_IO_P20), bleManager() -{ +{ } /** * Post constructor initialisation method. - * After *MUCH* pain, it's noted that the BLE stack can't be brought up in a + * After *MUCH* pain, it's noted that the BLE stack can't be brought up in a * static context, so we bring it up here rather than in the constructor. * n.b. This method *must* be called in main() or later, not before. * * Example: - * @code + * @code * uBit.init(); * @endcode */ void MicroBit::init() -{ +{ //add the display to the systemComponent array addSystemComponent(&uBit.display); - + //add the compass and accelerometer to the idle array addIdleComponent(&uBit.accelerometer); addIdleComponent(&uBit.compass); @@ -114,14 +114,14 @@ void MicroBit::init() seedRandom(); #if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) - // Start the BLE stack. + // Start the BLE stack. bleManager.init(this->getName(), this->getSerial()); - + ble = bleManager.ble; #endif // Start refreshing the Matrix Display - systemTicker.attach(this, &MicroBit::systemTick, MICROBIT_DISPLAY_REFRESH_PERIOD); + systemTicker.attach(this, &MicroBit::systemTick, MICROBIT_DISPLAY_REFRESH_PERIOD); // Register our compass calibration algorithm. MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CALIBRATE, this, &MicroBit::compassCalibrator, MESSAGE_BUS_LISTENER_IMMEDIATE); @@ -146,7 +146,7 @@ void MicroBit::compassCalibrator(MicroBitEvent) const int PIXEL2_THRESHOLD = 800; Matrix4 X(PERIMETER_POINTS, 4); - Point perimeter[PERIMETER_POINTS] = {{1,0,0}, {2,0,0}, {3,0,0}, {4,1,0}, {4,2,0}, {4,3,0}, {3,4,0}, {2,4,0}, {1,4,0}, {0,3,0}, {0,2,0}, {0,1,0}}; + Point perimeter[PERIMETER_POINTS] = {{1,0,0}, {2,0,0}, {3,0,0}, {4,1,0}, {4,2,0}, {4,3,0}, {3,4,0}, {2,4,0}, {1,4,0}, {0,3,0}, {0,2,0}, {0,1,0}}; Point cursor = {2,2,0}; MicroBitImage img(5,5); @@ -186,7 +186,7 @@ void MicroBit::compassCalibrator(MicroBitEvent) cursor.x = 4; else if (x > PIXEL1_THRESHOLD) cursor.x = 3; - else + else cursor.x = 2; if (y < -PIXEL2_THRESHOLD) @@ -244,13 +244,13 @@ void MicroBit::compassCalibrator(MicroBitEvent) Y.set(i, 0, v); } - // Now perform a Least Squares Approximation. + // Now perform a Least Squares Approximation. Matrix4 XT = X.transpose(); Matrix4 Beta = XT.multiply(X).invert().multiply(XT).multiply(Y); // The result contains the approximate zero point of each axis, but doubled. // Halve each sample, and record this as the compass calibration data. - CompassSample cal = {(int)(Beta.get(0,0) / 2), (int)(Beta.get(1,0) / 2), (int)(Beta.get(2,0) / 2)}; + CompassSample cal ((int)(Beta.get(0,0) / 2), (int)(Beta.get(1,0) / 2), (int)(Beta.get(2,0) / 2)); compass.setCalibration(cal); // Show a smiley to indicate that we're done, and continue on with the user program. @@ -267,11 +267,11 @@ void MicroBit::compassCalibrator(MicroBitEvent) ManagedString MicroBit::getName() { char nameBuffer[MICROBIT_NAME_LENGTH]; - const uint8_t codebook[MICROBIT_NAME_LENGTH][MICROBIT_NAME_CODE_LETTERS] = + const uint8_t codebook[MICROBIT_NAME_LENGTH][MICROBIT_NAME_CODE_LETTERS] = { - {'z', 'v', 'g', 'p', 't'}, + {'z', 'v', 'g', 'p', 't'}, {'u', 'o', 'i', 'e', 'a'}, - {'z', 'v', 'g', 'p', 't'}, + {'z', 'v', 'g', 'p', 't'}, {'u', 'o', 'i', 'e', 'a'}, {'z', 'v', 'g', 'p', 't'} }; @@ -309,7 +309,7 @@ ManagedString MicroBit::getSerial() int n1 = NRF_FICR->DEVICEID[1] & 0xffff; int n2 = (NRF_FICR->DEVICEID[1] >> 16) & 0xffff; - // Simply concat the two numbers. + // Simply concat the two numbers. ManagedString s1 = ManagedString(n1); ManagedString s2 = ManagedString(n2); @@ -320,7 +320,7 @@ ManagedString MicroBit::getSerial() * Will reset the micro:bit when called. * * Example: - * @code + * @code * uBit.reset(); * @endcode */ @@ -334,15 +334,15 @@ void MicroBit::reset() * If the scheduler is running, this will deschedule the current fiber and perform * a power efficent, concurrent sleep operation. * If the scheduler is disabled or we're running in an interrupt context, this - * will revert to a busy wait. + * will revert to a busy wait. * * @note Values of below below the scheduling period (typical 6ms) tend to lose resolution. - * + * * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative. - * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero. + * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero. * * Example: - * @code + * @code * uBit.sleep(20); //sleep for 20ms * @endcode */ @@ -351,7 +351,7 @@ int MicroBit::sleep(int milliseconds) //sanity check, we can't time travel... (yet?) if(milliseconds < 0) return MICROBIT_INVALID_PARAMETER; - + if (flags & MICROBIT_FLAG_SCHEDULER_RUNNING) fiber_sleep(milliseconds); else @@ -368,14 +368,14 @@ int MicroBit::sleep(int milliseconds) * than the hardware random number generator built int the processor, which takes * a long time and uses a lot of energy. * - * KIDS: You shouldn't use this is the real world to generte cryptographic keys though... + * KIDS: You shouldn't use this is the real world to generte cryptographic keys though... * have a think why not. :-) * * @param max the upper range to generate a number for. This number cannot be negative * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE (defined in ErrorNo.h) if max is <= 0. * * Example: - * @code + * @code * uBit.random(200); //a number between 0 and 199 * @endcode */ @@ -395,7 +395,7 @@ int MicroBit::random(int max) result = 0; do { // Cycle the LFSR (Linear Feedback Shift Register). - // We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneier here (a true legend in the field!), + // We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneier here (a true legend in the field!), // For those interested, it's documented in his paper: // "Pseudo-Random Sequence Generator for 32-Bit CPUs: A fast, machine-independent generator for 32-bit Microprocessors" // https://www.schneier.com/paper-pseudorandom-sequence.html @@ -414,7 +414,7 @@ int MicroBit::random(int max) randomValue = rnd; result = ((result << 1) | (rnd & 0x00000001)); - } while(m >>= 1); + } while(m >>= 1); } while (result > (uint32_t)max); @@ -432,21 +432,21 @@ int MicroBit::random(int max) void MicroBit::seedRandom() { randomValue = 0; - + // Start the Random number generator. No need to leave it running... I hope. :-) NRF_RNG->TASKS_START = 1; - + for(int i = 0; i < 4 ;i++) { // Clear the VALRDY EVENT NRF_RNG->EVENTS_VALRDY = 0; - + // Wait for a number ot be generated. while ( NRF_RNG->EVENTS_VALRDY == 0); - + randomValue = (randomValue << 8) | ((int) NRF_RNG->VALUE); } - + // Disable the generator to save power. NRF_RNG->TASKS_STOP = 1; } @@ -456,11 +456,11 @@ void MicroBit::seedRandom() * 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(); - + 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()) @@ -468,7 +468,7 @@ void MicroBit::systemTick() 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) @@ -479,17 +479,17 @@ void MicroBit::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 +{ + //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 + * 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 @@ -497,14 +497,14 @@ void MicroBit::systemTasks() int MicroBit::addSystemComponent(MicroBitComponent *component) { int i = 0; - - while(systemTickComponents[i] != NULL && i < MICROBIT_SYSTEM_COMPONENTS) + + while(systemTickComponents[i] != NULL && i < MICROBIT_SYSTEM_COMPONENTS) i++; - + if(i == MICROBIT_SYSTEM_COMPONENTS) return MICROBIT_NO_RESOURCES; - - systemTickComponents[i] = component; + + systemTickComponents[i] = component; return MICROBIT_OK; } @@ -517,10 +517,10 @@ int MicroBit::addSystemComponent(MicroBitComponent *component) int MicroBit::removeSystemComponent(MicroBitComponent *component) { int i = 0; - - while(systemTickComponents[i] != component && i < MICROBIT_SYSTEM_COMPONENTS) + + while(systemTickComponents[i] != component && i < MICROBIT_SYSTEM_COMPONENTS) i++; - + if(i == MICROBIT_SYSTEM_COMPONENTS) return MICROBIT_INVALID_PARAMETER; @@ -530,7 +530,7 @@ int MicroBit::removeSystemComponent(MicroBitComponent *component) } /** - * add a component to the array of components which invocate the systemTick member function during a systemTick + * 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 @@ -538,14 +538,14 @@ int MicroBit::removeSystemComponent(MicroBitComponent *component) int MicroBit::addIdleComponent(MicroBitComponent *component) { int i = 0; - - while(idleThreadComponents[i] != NULL && i < MICROBIT_IDLE_COMPONENTS) + + while(idleThreadComponents[i] != NULL && i < MICROBIT_IDLE_COMPONENTS) i++; - + if(i == MICROBIT_IDLE_COMPONENTS) return MICROBIT_NO_RESOURCES; - - idleThreadComponents[i] = component; + + idleThreadComponents[i] = component; return MICROBIT_OK; } @@ -559,10 +559,10 @@ int MicroBit::addIdleComponent(MicroBitComponent *component) int MicroBit::removeIdleComponent(MicroBitComponent *component) { int i = 0; - - while(idleThreadComponents[i] != component && i < MICROBIT_IDLE_COMPONENTS) + + while(idleThreadComponents[i] != component && i < MICROBIT_IDLE_COMPONENTS) i++; - + if(i == MICROBIT_IDLE_COMPONENTS) return MICROBIT_INVALID_PARAMETER; @@ -596,7 +596,7 @@ const char *MicroBit::systemVersion() /** * 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 MicroBit::panic(int statusCode) @@ -604,4 +604,3 @@ void MicroBit::panic(int statusCode) //show error and enter infinite while uBit.display.error(statusCode); } - diff --git a/source/MicroBitAccelerometer.cpp b/source/MicroBitAccelerometer.cpp index 4574766..f06fae2 100644 --- a/source/MicroBitAccelerometer.cpp +++ b/source/MicroBitAccelerometer.cpp @@ -48,32 +48,32 @@ int MicroBitAccelerometer::configure() // Now configure the accelerometer accordingly. // First place the device into standby mode, so it can be configured. result = writeCommand(MMA8653_CTRL_REG1, 0x00); - if (result != 0) + if (result != 0) return MICROBIT_I2C_ERROR; // Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA! result = writeCommand(MMA8653_CTRL_REG2, 0x10); - if (result != 0) + if (result != 0) return MICROBIT_I2C_ERROR; // Enable the INT1 interrupt pin. result = writeCommand(MMA8653_CTRL_REG4, 0x01); - if (result != 0) + if (result != 0) return MICROBIT_I2C_ERROR; // Select the DATA_READY event source to be routed to INT1 result = writeCommand(MMA8653_CTRL_REG5, 0x01); - if (result != 0) + if (result != 0) return MICROBIT_I2C_ERROR; // Configure for the selected g range. result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg); - if (result != 0) + if (result != 0) return MICROBIT_I2C_ERROR; // Bring the device back online, with 10bit wide samples at the requested frequency. result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01); - if (result != 0) + if (result != 0) return MICROBIT_I2C_ERROR; return MICROBIT_OK; @@ -124,13 +124,13 @@ int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length) } /** - * Constructor. + * Constructor. * Create an accelerometer representation with the given ID. * @param id the ID of the new object. - * @param address the default base address of the accelerometer. + * @param address the default base address of the accelerometer. * * Example: - * @code + * @code * accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR) * @endcode */ @@ -161,11 +161,11 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa } /** - * Attempts to determine the 8 bit ID from the accelerometer. + * Attempts to determine the 8 bit ID from the accelerometer. * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails. * * Example: - * @code + * @code * uBit.accelerometer.whoAmI(); * @endcode */ @@ -174,7 +174,7 @@ int MicroBitAccelerometer::whoAmI() uint8_t data; int result; - result = readCommand(MMA8653_WHOAMI, &data, 1); + result = readCommand(MMA8653_WHOAMI, &data, 1); if (result !=0) return MICROBIT_I2C_ERROR; @@ -197,7 +197,7 @@ int MicroBitAccelerometer::update() return MICROBIT_I2C_ERROR; // read MSB values... - sample.x = data[0]; + sample.x = data[0]; sample.y = data[2]; sample.z = data[4]; @@ -221,7 +221,7 @@ int MicroBitAccelerometer::update() // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed. status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID; - // Update gesture tracking + // Update gesture tracking updateGesture(); // Indicate that a new sample is available @@ -257,9 +257,9 @@ BasicGesture MicroBitAccelerometer::instantaneousPosture() // Test for shake events. // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to the left followed by // a string acceleration to the right, then we can infer a shake. Similarly, we can do this for each acxis (left/right, up/down, in/out). - // + // // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device - // has been shaken. + // has been shaken. if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x)) { shakeDetected = true; @@ -289,7 +289,7 @@ BasicGesture MicroBitAccelerometer::instantaneousPosture() if(--shake.count == 0) shake.shaken = 0; } - } + } if (shake.shaken) return GESTURE_SHAKE; @@ -334,10 +334,10 @@ void MicroBitAccelerometer::updateGesture() BasicGesture g = instantaneousPosture(); // Perform some low pass filtering to reduce jitter from any detected effects - if (g == currentGesture) + if (g == currentGesture) { if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING) - sigma++; + sigma++; } else { @@ -350,7 +350,7 @@ void MicroBitAccelerometer::updateGesture() { lastGesture = currentGesture; MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture); - } + } } /** @@ -367,7 +367,7 @@ int MicroBitAccelerometer::setPeriod(int period) } /** - * Reads the currently configured sample rate of the accelerometer. + * Reads the currently configured sample rate of the accelerometer. * @return The time between samples, in milliseconds. */ int MicroBitAccelerometer::getPeriod() @@ -389,7 +389,7 @@ int MicroBitAccelerometer::setRange(int range) } /** - * Reads the currently configured sample range of the accelerometer. + * Reads the currently configured sample range of the accelerometer. * @return The sample range, in g. */ int MicroBitAccelerometer::getRange() @@ -403,7 +403,7 @@ int MicroBitAccelerometer::getRange() * @return The force measured in the X axis, in milli-g. * * Example: - * @code + * @code * uBit.accelerometer.getX(); * uBit.accelerometer.getX(RAW); * @endcode @@ -414,7 +414,7 @@ int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system) { case SIMPLE_CARTESIAN: return -sample.x; - + case NORTH_EAST_DOWN: return sample.y; @@ -430,18 +430,18 @@ int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system) * @return The force measured in the Y axis, in milli-g. * * Example: - * @code + * @code * uBit.accelerometer.getY(); * uBit.accelerometer.getY(RAW); * @endcode - */ + */ int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system) { switch (system) { case SIMPLE_CARTESIAN: return -sample.y; - + case NORTH_EAST_DOWN: return -sample.x; @@ -457,11 +457,11 @@ int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system) * @return The force measured in the Z axis, in milli-g. * * Example: - * @code + * @code * uBit.accelerometer.getZ(); * uBit.accelerometer.getZ(RAW); * @endcode - */ + */ int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system) { switch (system) @@ -475,16 +475,16 @@ int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system) return sample.z; } } - + /** * Provides a rotation compensated pitch of the device, based on the latest update from the accelerometer. * @return The pitch of the device, in degrees. * * Example: - * @code + * @code * uBit.accelerometer.getPitch(); * @endcode - */ + */ int MicroBitAccelerometer::getPitch() { return (int) ((360*getPitchRadians()) / (2*PI)); @@ -503,10 +503,10 @@ float MicroBitAccelerometer::getPitchRadians() * @return The roll of the device, in degrees. * * Example: - * @code + * @code * uBit.accelerometer.getRoll(); * @endcode - */ + */ int MicroBitAccelerometer::getRoll() { return (int) ((360*getRollRadians()) / (2*PI)); @@ -541,10 +541,10 @@ void MicroBitAccelerometer::recalculatePitchRoll() * @return The last gesture detected. * * Example: - * @code + * @code * if (uBit.accelerometer.getGesture() == SHAKE) * @endcode - */ + */ BasicGesture MicroBitAccelerometer::getGesture() { return lastGesture; @@ -553,7 +553,7 @@ BasicGesture MicroBitAccelerometer::getGesture() /** * periodic callback from MicroBit clock. * Check if any data is ready for reading by checking the interrupt flag on the accelerometer - */ + */ void MicroBitAccelerometer::idleTick() { // Poll interrupt line from accelerometer. @@ -571,19 +571,27 @@ int MicroBitAccelerometer::isIdleCallbackNeeded() return !int1; } +/** + * Destructor for MicroBitAccelerometer, so that we deregister ourselves as an idleComponent + */ +MicroBitAccelerometer::~MicroBitAccelerometer() +{ + uBit.removeIdleComponent(this); +} + const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = { - {2, 0}, - {4, 1}, + {2, 0}, + {4, 1}, {8, 2} }; const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = { - {1250, 0x00}, - {2500, 0x08}, - {5000, 0x10}, - {10000, 0x18}, - {20000, 0x20}, - {80000, 0x28}, + {1250, 0x00}, + {2500, 0x08}, + {5000, 0x10}, + {10000, 0x18}, + {20000, 0x20}, + {80000, 0x28}, {160000, 0x30}, {640000, 0x38} }; diff --git a/source/MicroBitButton.cpp b/source/MicroBitButton.cpp index 1311447..64c211e 100644 --- a/source/MicroBitButton.cpp +++ b/source/MicroBitButton.cpp @@ -1,19 +1,19 @@ #include "MicroBit.h" /** - * Constructor. + * Constructor. * Create a pin representation with the given ID. * @param id the ID of the new MicroBitButton object. * @param name the physical pin on the processor that this butotn is connected to. * @param mode the configuration of internal pullups/pulldowns, as define in the mbed PinMode class. PullNone by default. * * Example: - * @code + * @code * buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A); //a number between 0 and 200 inclusive * @endcode * * Possible Events: - * @code + * @code * MICROBIT_BUTTON_EVT_DOWN * MICROBIT_BUTTON_EVT_UP * MICROBIT_BUTTON_EVT_CLICK @@ -34,9 +34,9 @@ MicroBitButton::MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventCon /** * periodic callback from MicroBit clock. * Check for state change for this button, and fires a hold event if button is pressed. - */ + */ void MicroBitButton::systemTick() -{ +{ // // If the pin is pulled low (touched), increment our culumative counter. // otherwise, decrement it. We're essentially building a lazy follower here. @@ -45,37 +45,37 @@ void MicroBitButton::systemTick() // if(!pin) { - if (sigma < MICROBIT_BUTTON_SIGMA_MAX) - sigma++; + if (sigma < MICROBIT_BUTTON_SIGMA_MAX) + sigma++; } else { - if (sigma > MICROBIT_BUTTON_SIGMA_MIN) + if (sigma > MICROBIT_BUTTON_SIGMA_MIN) sigma--; } - + // Check to see if we have off->on state change. if(sigma > MICROBIT_BUTTON_SIGMA_THRESH_HI && !(status & MICROBIT_BUTTON_STATE)) { // Record we have a state change, and raise an event. status |= MICROBIT_BUTTON_STATE; MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN); - + //Record the time the button was pressed. - downStartTime=ticks; + downStartTime=ticks; } - - // Check to see if we have on->off state change. + + // Check to see if we have on->off state change. if(sigma < MICROBIT_BUTTON_SIGMA_THRESH_LO && (status & MICROBIT_BUTTON_STATE)) { status = 0; MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_UP); - + if (eventConfiguration == MICROBIT_BUTTON_ALL_EVENTS) - { + { //determine if this is a long click or a normal click and send event if((ticks - downStartTime) >= MICROBIT_BUTTON_LONG_CLICK_TIME) - MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_LONG_CLICK); + MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_LONG_CLICK); else MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK); } @@ -86,7 +86,7 @@ void MicroBitButton::systemTick() { //set the hold triggered event flag status |= MICROBIT_BUTTON_STATE_HOLD_TRIGGERED; - + //fire hold event MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_HOLD); } @@ -100,3 +100,11 @@ int MicroBitButton::isPressed() { return status & MICROBIT_BUTTON_STATE ? 1 : 0; } + +/** + * Destructor for MicroBitButton, so that we deregister ourselves as a systemComponent + */ +MicroBitButton::~MicroBitButton() +{ + uBit.removeSystemComponent(this); +} diff --git a/source/MicroBitCompass.cpp b/source/MicroBitCompass.cpp index e3610da..d89b6a5 100644 --- a/source/MicroBitCompass.cpp +++ b/source/MicroBitCompass.cpp @@ -1,7 +1,7 @@ #include "MicroBit.h" /** - * Constructor. + * Constructor. * Create a compass representation with the given ID. * @param id the event ID of the compass object. * @param address the default address for the compass register @@ -22,17 +22,17 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam { this->id = id; this->address = address; - + // We presume the device calibrated until the average values are read. this->status = 0x01; // Select 10Hz update rate, with oversampling, and enable the device. this->samplePeriod = 100; this->configure(); - - // Assume that we have no calibraiton information. + + // Assume that we have no calibraiton information. status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED; - + // Indicate that we're up and running. uBit.flags |= MICROBIT_FLAG_COMPASS_RUNNING; } @@ -50,7 +50,7 @@ int MicroBitCompass::writeCommand(uint8_t reg, uint8_t value) uint8_t command[2]; command[0] = reg; command[1] = value; - + return uBit.i2c.write(address, (const char *)command, 2); } @@ -100,7 +100,7 @@ int MicroBitCompass::read16(uint8_t reg) cmd[0] = 0x00; cmd[1] = 0x00; - + result = uBit.i2c.read(address, (char *)cmd, 2); if (result !=0) return MICROBIT_I2C_ERROR; @@ -132,10 +132,10 @@ int MicroBitCompass::read8(uint8_t reg) * Gets the current heading of the device, relative to magnetic north. * If the compass is not calibrated, it will raise the MICROBIT_COMPASS_EVT_CALIBRATE event. * Users wishing to implement their own calibration algorithms should listen for this event, - * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before - * the user program continues. - * - * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating. + * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before + * the user program continues. + * + * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating. * * Example: * @code @@ -147,7 +147,7 @@ int MicroBitCompass::heading() float bearing; if(status & MICROBIT_COMPASS_STATUS_CALIBRATING) - return MICROBIT_CALIBRATION_IN_PROGRESS; + return MICROBIT_CALIBRATION_IN_PROGRESS; if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED)) calibrate(); @@ -165,11 +165,11 @@ int MicroBitCompass::heading() float sinTheta = sin(theta); float cosTheta = cos(theta); - bearing = (360*atan2(z*sinPhi - y*cosPhi, x*cosTheta + y*sinTheta*sinPhi + z*sinTheta*cosPhi)) / (2*PI); + bearing = (360*atan2(z*sinPhi - y*cosPhi, x*cosTheta + y*sinTheta*sinPhi + z*sinTheta*cosPhi)) / (2*PI); if (bearing < 0) bearing += 360.0; - + return (int) bearing; } @@ -179,7 +179,7 @@ int MicroBitCompass::heading() */ void MicroBitCompass::idleTick() { - // Poll interrupt line from accelerometer (Active HI). + // Poll interrupt line from accelerometer (Active HI). // Interrupt is cleared on data read of MAG_OUT_X_MSB. if(int1) { @@ -225,7 +225,7 @@ int MicroBitCompass::getX(MicroBitCoordinateSystem system) * @code * uBit.compass.getY(); * @endcode - */ + */ int MicroBitCompass::getY(MicroBitCoordinateSystem system) { switch (system) @@ -235,7 +235,7 @@ int MicroBitCompass::getY(MicroBitCoordinateSystem system) case NORTH_EAST_DOWN: return (sample.x - average.x); - + case RAW: default: return sample.y; @@ -250,7 +250,7 @@ int MicroBitCompass::getY(MicroBitCoordinateSystem system) * @code * uBit.compass.getZ(); * @endcode - */ + */ int MicroBitCompass::getZ(MicroBitCoordinateSystem system) { switch (system) @@ -273,7 +273,7 @@ int MicroBitCompass::getZ(MicroBitCoordinateSystem system) * @code * uBit.compass.getFieldStrength(); * @endcode - */ + */ int MicroBitCompass::getFieldStrength() { double x = getX(); @@ -300,7 +300,7 @@ int MicroBitCompass::configure() if (result != MICROBIT_OK) return MICROBIT_I2C_ERROR; - // Wait for the part to enter standby mode... + // Wait for the part to enter standby mode... while(1) { // Read the status of the part... @@ -335,7 +335,7 @@ int MicroBitCompass::configure() if (result != MICROBIT_OK) return MICROBIT_I2C_ERROR; - + // Bring the device online, with the requested sample frequency. result = writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01); if (result != MICROBIT_OK) @@ -358,7 +358,7 @@ int MicroBitCompass::setPeriod(int period) } /** - * Reads the currently configured sample rate of the compass. + * Reads the currently configured sample rate of the compass. * @return The time between samples, in milliseconds. */ int MicroBitCompass::getPeriod() @@ -368,7 +368,7 @@ int MicroBitCompass::getPeriod() /** - * Attempts to determine the 8 bit ID from the magnetometer. + * Attempts to determine the 8 bit ID from the magnetometer. * @return the id of the compass (magnetometer), or MICROBIT_I2C_ERROR if the magnetometer could not be updated. * * Example: @@ -381,7 +381,7 @@ int MicroBitCompass::whoAmI() uint8_t data; int result; - result = readCommand(MAG_WHOAMI, &data, 1); + result = readCommand(MAG_WHOAMI, &data, 1); if (result != MICROBIT_OK) return MICROBIT_I2C_ERROR; @@ -389,7 +389,7 @@ int MicroBitCompass::whoAmI() } /** - * Reads the current die temperature of the compass. + * Reads the current die temperature of the compass. * @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the magnetometer could not be updated. */ int MicroBitCompass::readTemperature() @@ -406,10 +406,10 @@ int MicroBitCompass::readTemperature() /** * Perform a calibration of the compass. - * + * * This method will be called automatically if a user attempts to read a compass value when * the compass is uncalibrated. It can also be called at any time by the user. - * + * * Any old calibration data is deleted. * The method will only return once the compass has been calibrated. * @@ -453,7 +453,7 @@ int MicroBitCompass::calibrate() int MicroBitCompass::calibrateStart() { return calibrate(); -} +} /** * Perform the asynchronous calibration of the compass. @@ -463,7 +463,7 @@ int MicroBitCompass::calibrateStart() * @note *** PLEASE USE THE calibrate() FUNCTION INSTEAD *** */ void MicroBitCompass::calibrateAsync() -{ +{ calibrate(); } @@ -472,20 +472,20 @@ void MicroBitCompass::calibrateAsync() * This will fire MICROBIT_COMPASS_EVT_CAL_END. * * @note *** THIS FUNCTION IS NOW DEPRECATED AND WILL BE REMOVED IN THE NEXT MAJOR RELEASE *** - */ + */ void MicroBitCompass::calibrateEnd() { -} +} /** * Configure the compass to use the given calibration data. * Calibration data is comprised of the perceived zero offset of each axis of the compass. - * After calibration this should now take into account trimming errors in the magnetometer, + * After calibration this should now take into account trimming errors in the magnetometer, * and any "hard iron" offsets on the device. * * @param The x, y and z zero offsets to use as calibration data. - */ + */ void MicroBitCompass::setCalibration(CompassSample calibration) { average = calibration; @@ -496,8 +496,8 @@ void MicroBitCompass::setCalibration(CompassSample calibration) * Provides the calibration data currently in use by the compass. * More specifically, the x, y and z zero offsets of the compass. * - * @return The x, y and z xero offsets of the compass. - */ + * @return The x, y and z xero offsets of the compass. + */ CompassSample MicroBitCompass::getCalibration() { return average; @@ -508,7 +508,7 @@ CompassSample MicroBitCompass::getCalibration() */ int MicroBitCompass::isCalibrated() { - return status & MICROBIT_COMPASS_STATUS_CALIBRATED; + return status & MICROBIT_COMPASS_STATUS_CALIBRATED; } /** @@ -516,7 +516,7 @@ int MicroBitCompass::isCalibrated() */ int MicroBitCompass::isCalibrating() { - return status & MICROBIT_COMPASS_STATUS_CALIBRATING; + return status & MICROBIT_COMPASS_STATUS_CALIBRATING; } /** @@ -524,7 +524,7 @@ int MicroBitCompass::isCalibrating() */ void MicroBitCompass::clearCalibration() { - status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED; + status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED; } /** @@ -537,16 +537,24 @@ int MicroBitCompass::isIdleCallbackNeeded() return int1; } +/** + * Destructor for MicroBitMessageBus, so that we deregister ourselves as an idleComponent + */ +MicroBitCompass::~MicroBitCompass() +{ + uBit.removeIdleComponent(this); +} + const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = { {12500, 0x00}, // 80 Hz {25000, 0x20}, // 40 Hz - {50000, 0x40}, // 20 Hz - {100000, 0x60}, // 10 hz - {200000, 0x80}, // 5 hz - {400000, 0x88}, // 2.5 hz - {800000, 0x90}, // 1.25 hz - {1600000, 0xb0}, // 0.63 hz - {3200000, 0xd0}, // 0.31 hz - {6400000, 0xf0}, // 0.16 hz - {12800000, 0xf8} // 0.08 hz + {50000, 0x40}, // 20 Hz + {100000, 0x60}, // 10 hz + {200000, 0x80}, // 5 hz + {400000, 0x88}, // 2.5 hz + {800000, 0x90}, // 1.25 hz + {1600000, 0xb0}, // 0.63 hz + {3200000, 0xd0}, // 0.31 hz + {6400000, 0xf0}, // 0.16 hz + {12800000, 0xf8} // 0.08 hz }; diff --git a/source/MicroBitDisplay.cpp b/source/MicroBitDisplay.cpp index 1513c10..1ad22d2 100644 --- a/source/MicroBitDisplay.cpp +++ b/source/MicroBitDisplay.cpp @@ -17,19 +17,19 @@ const float timings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {0.000010, 0.000047, * * @param x the width of the display in pixels. * @param y the height of the display in pixels. - * + * * Example: - * @code + * @code * MicroBitDisplay display(MICROBIT_ID_DISPLAY, 5, 5), * @endcode */ -MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) : +MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) : font(), image(x*2,y) { //set pins as output nrf_gpio_range_cfg_output(MICROBIT_DISPLAY_COLUMN_START,MICROBIT_DISPLAY_COLUMN_START + MICROBIT_DISPLAY_COLUMN_COUNT + MICROBIT_DISPLAY_ROW_COUNT); - + this->id = id; this->width = x; this->height = y; @@ -38,46 +38,46 @@ MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) : this->rotation = MICROBIT_DISPLAY_ROTATION_0; this->greyscaleBitMsk = 0x01; this->timingCount = 0; - + this->setBrightness(MICROBIT_DISPLAY_DEFAULT_BRIGHTNESS); this->mode = DISPLAY_MODE_BLACK_AND_WHITE; this->animationMode = ANIMATION_MODE_NONE; - + uBit.flags |= MICROBIT_FLAG_DISPLAY_RUNNING; } /** * Internal frame update method, used to strobe the display. * - * TODO: Write a more efficient, complementary variation of this method for the case where + * TODO: Write a more efficient, complementary variation of this method for the case where * MICROBIT_DISPLAY_ROW_COUNT > MICROBIT_DISPLAY_COLUMN_COUNT. - */ + */ void MicroBitDisplay::systemTick() -{ +{ if(!(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING)) return; - - // Move on to the next row. + + // Move on to the next row. strobeBitMsk <<= 1; strobeRow++; - + //reset the row counts and bit mask when we have hit the max. if(strobeRow == MICROBIT_DISPLAY_ROW_COUNT){ strobeRow = 0; - strobeBitMsk = 0x20; + strobeBitMsk = 0x20; } - + if(mode == DISPLAY_MODE_BLACK_AND_WHITE) render(); - + if(mode == DISPLAY_MODE_GREYSCALE) { greyscaleBitMsk = 0x01; timingCount = 0; renderGreyscale(); } - + // Update text and image animations if we need to. this->animationUpdate(); } @@ -87,60 +87,60 @@ void MicroBitDisplay::renderFinish() //kept inline to reduce overhead //clear the old bit pattern for this row. //clear port 0 4-7 and retain lower 4 bits - nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, 0xF0 | (nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F)); - + nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, 0xF0 | (nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F)); + // clear port 1 8-12 for the current row - nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | 0x1F); + nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | 0x1F); } void MicroBitDisplay::render() -{ +{ // Simple optimisation. If display is at zero brightness, there's nothign to do. if(brightness == 0) return; int coldata = 0; - + // Calculate the bitpattern to write. for (int i = 0; i>4 & 0x1F)); + nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F)); //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(this, &MicroBitDisplay::renderFinish, (((float)brightness) / ((float)MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS)) * (float)MICROBIT_DISPLAY_REFRESH_PERIOD); - + //this will take around 23us to execute if(brightness <= MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS) renderFinish(); @@ -149,47 +149,47 @@ void MicroBitDisplay::render() void MicroBitDisplay::renderGreyscale() { int coldata = 0; - + // Calculate the bitpattern to write. for (int i = 0; i>4 & 0x1F)); + nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F)); if(timingCount > MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH-1) return; greyscaleBitMsk <<= 1; - + renderTimer.attach(this,&MicroBitDisplay::renderGreyscale, timings[timingCount++]); } @@ -198,29 +198,29 @@ void MicroBitDisplay::renderGreyscale() */ void MicroBitDisplay::animationUpdate() -{ +{ // If there's no ongoing animation, then nothing to do. if (animationMode == ANIMATION_MODE_NONE) return; - - animationTick += FIBER_TICK_PERIOD_MS; - + + animationTick += FIBER_TICK_PERIOD_MS; + if(animationTick >= animationDelay) { animationTick = 0; - + if (animationMode == ANIMATION_MODE_SCROLL_TEXT) this->updateScrollText(); - + if (animationMode == ANIMATION_MODE_PRINT_TEXT) this->updatePrintText(); if (animationMode == ANIMATION_MODE_SCROLL_IMAGE) this->updateScrollImage(); - + if (animationMode == ANIMATION_MODE_ANIMATE_IMAGE) this->updateAnimateImage(); - + if(animationMode == ANIMATION_MODE_PRINT_CHARACTER) { animationMode = ANIMATION_MODE_NONE; @@ -243,18 +243,18 @@ void MicroBitDisplay::sendAnimationCompleteEvent() } /** - * Internal scrollText update method. + * Internal scrollText update method. * Shift the screen image by one pixel to the left. If necessary, paste in the next char. - */ + */ void MicroBitDisplay::updateScrollText() -{ +{ image.shiftLeft(1); scrollingPosition++; - + if (scrollingPosition == width + MICROBIT_DISPLAY_SPACING) - { + { scrollingPosition = 0; - + image.print(scrollingChar < scrollingText.length() ? scrollingText.charAt(scrollingChar) : ' ',width,0); if (scrollingChar > scrollingText.length()) @@ -268,36 +268,36 @@ void MicroBitDisplay::updateScrollText() } /** - * Internal printText update method. + * Internal printText update method. * Paste in the next char in the string. - */ + */ void MicroBitDisplay::updatePrintText() -{ +{ image.print(printingChar < printingText.length() ? printingText.charAt(printingChar) : ' ',0,0); if (printingChar > printingText.length()) { - animationMode = ANIMATION_MODE_NONE; + animationMode = ANIMATION_MODE_NONE; this->sendAnimationCompleteEvent(); return; } - + printingChar++; } /** - * Internal scrollImage update method. + * Internal scrollImage update method. * Paste the stored bitmap at the appropriate point. - */ + */ void MicroBitDisplay::updateScrollImage() -{ - image.clear(); +{ + image.clear(); - if ((image.paste(scrollingImage, scrollingImagePosition, 0, 0) == 0) && scrollingImageRendered) + if (((image.paste(scrollingImage, scrollingImagePosition, 0, 0) == 0) && scrollingImageRendered) || scrollingImageStride == 0) { - animationMode = ANIMATION_MODE_NONE; - this->sendAnimationCompleteEvent(); + animationMode = ANIMATION_MODE_NONE; + this->sendAnimationCompleteEvent(); return; } @@ -307,27 +307,33 @@ void MicroBitDisplay::updateScrollImage() } /** - * Internal animateImage update method. + * Internal animateImage update method. * Paste the stored bitmap at the appropriate point and stop on the last frame. - */ + */ void MicroBitDisplay::updateAnimateImage() -{ +{ //wait until we have rendered the last position to give a continuous animation. if (scrollingImagePosition <= -scrollingImage.getWidth() + (MICROBIT_DISPLAY_WIDTH + scrollingImageStride) && scrollingImageRendered) { - animationMode = ANIMATION_MODE_NONE; + animationMode = ANIMATION_MODE_NONE; this->clear(); - this->sendAnimationCompleteEvent(); + this->sendAnimationCompleteEvent(); return; } - + if(scrollingImagePosition > 0) image.shiftLeft(-scrollingImageStride); - + image.paste(scrollingImage, scrollingImagePosition, 0, 0); - + + if(scrollingImageStride == 0) + { + animationMode = ANIMATION_MODE_NONE; + this->sendAnimationCompleteEvent(); + } + scrollingImageRendered = true; - + scrollingImagePosition += scrollingImageStride; } @@ -347,7 +353,7 @@ void MicroBitDisplay::stopAnimation() // Wake up aall fibers that may blocked on the animation (if any). MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE); } - + // Clear the display and setup the animation timers. this->image.clear(); } @@ -356,7 +362,7 @@ void MicroBitDisplay::stopAnimation() * Blocks the current fiber until the display is available (i.e. not effect is being displayed). * Animations are queued until their time to display. * - */ + */ void MicroBitDisplay::waitForFreeDisplay() { // If there's an ongoing animation, wait for our turn to display. @@ -371,9 +377,9 @@ void MicroBitDisplay::waitForFreeDisplay() * @param c The character to display. * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever. * @return MICROBIT_OK, MICROBIT_BUSY is the screen is in use, or MICROBIT_INVALID_PARAMETER. - * + * * Example: - * @code + * @code * uBit.display.printAsync('p'); * uBit.display.printAsync('p',100); * @endcode @@ -422,7 +428,7 @@ int MicroBitDisplay::printAsync(ManagedString s, int delay) //sanitise this value if(delay <= 0 ) return MICROBIT_INVALID_PARAMETER; - + if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { printingChar = 0; @@ -431,7 +437,7 @@ int MicroBitDisplay::printAsync(ManagedString s, int delay) animationTick = 0; animationMode = ANIMATION_MODE_PRINT_TEXT; - } + } else { return MICROBIT_BUSY; @@ -448,7 +454,7 @@ int MicroBitDisplay::printAsync(ManagedString s, int delay) * @param i The image to display. * @param x The horizontal position on the screen to display the image (default 0) * @param y The vertical position on the screen to display the image (default 0) - * @param alpha Treats the brightness level '0' as transparent (default 0) + * @param alpha Treats the brightness level '0' as transparent (default 0) * @param delay The time to delay between characters, in milliseconds. set to 0 to display forever. (default 0). * * Example: @@ -487,9 +493,9 @@ int MicroBitDisplay::printAsync(MicroBitImage i, int x, int y, int alpha, int de * @param c The character to display. * @param delay The time to delay between characters, in milliseconds. Must be > 0. * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER. - * + * * Example: - * @code + * @code * uBit.display.print('p'); * uBit.display.print('p',100); * @endcode @@ -537,7 +543,7 @@ int MicroBitDisplay::print(ManagedString s, int delay) //sanitise this value if(delay <= 0 ) return MICROBIT_INVALID_PARAMETER; - + // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); @@ -613,7 +619,7 @@ int MicroBitDisplay::scrollAsync(ManagedString s, int delay) //sanitise this value if(delay <= 0) return MICROBIT_INVALID_PARAMETER; - + // If the display is free, it's our turn to display. if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { @@ -649,7 +655,7 @@ int MicroBitDisplay::scrollAsync(ManagedString s, int delay) * @endcode */ int MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride) -{ +{ //sanitise the delay value if(delay <= 0) return MICROBIT_INVALID_PARAMETER; @@ -662,7 +668,7 @@ int MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride) scrollingImage = image; scrollingImageRendered = false; - animationDelay = delay; + animationDelay = stride == 0 ? 0 : delay; animationTick = 0; animationMode = ANIMATION_MODE_SCROLL_IMAGE; } @@ -682,9 +688,9 @@ int MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride) * @param s The string to display. * @param delay The time to delay between each update to the display, in milliseconds. Must be > 0. * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER. - * + * * Example: - * @code + * @code * uBit.display.scrollString("abc123",100); * @endcode */ @@ -706,12 +712,12 @@ int MicroBitDisplay::scroll(ManagedString s, int delay) // Wait for completion. fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE); - } + } else { return MICROBIT_CANCELLED; } - + return MICROBIT_OK; } @@ -731,11 +737,11 @@ int MicroBitDisplay::scroll(ManagedString s, int delay) * @endcode */ int MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride) -{ +{ //sanitise the delay value if(delay <= 0) return MICROBIT_INVALID_PARAMETER; - + // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); @@ -789,12 +795,12 @@ int MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, in stride = -stride; //calculate starting position which is offset by the stride - scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS) ? MICROBIT_DISPLAY_WIDTH + stride : startingPosition; + scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS) ? MICROBIT_DISPLAY_WIDTH + stride : startingPosition; scrollingImageStride = stride; scrollingImage = image; scrollingImageRendered = false; - animationDelay = delay; + animationDelay = stride == 0 ? 0 : delay; animationTick = delay-1; animationMode = ANIMATION_MODE_ANIMATE_IMAGE; } @@ -858,14 +864,14 @@ int MicroBitDisplay::animate(MicroBitImage image, int delay, int stride, int sta * Sets the display brightness to the specified level. * @param b The brightness to set the brightness to, in the range 0..255. * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER - * + * * Example: - * @code + * @code * uBit.display.setBrightness(255); //max brightness * @endcode - */ + */ int MicroBitDisplay::setBrightness(int b) -{ +{ //sanitise the brightness level if(b < 0 || b > 255) return MICROBIT_INVALID_PARAMETER; @@ -878,26 +884,26 @@ int MicroBitDisplay::setBrightness(int b) /** * Sets the mode of the display. * @param mode The mode to swap the display into. (can be either DISPLAY_MODE_GREYSCALE, or DISPLAY_MODE_NORMAL) - * + * * Example: - * @code + * @code * uBit.display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness * @endcode - */ + */ void MicroBitDisplay::setDisplayMode(DisplayMode mode) -{ +{ this->mode = mode; } /** * Fetches the current brightness of this display. * @return the brightness of this display, in the range 0..255. - * + * * Example: - * @code + * @code * uBit.display.getBrightness(); //the current brightness * @endcode - */ + */ int MicroBitDisplay::getBrightness() { return this->brightness; @@ -908,10 +914,10 @@ int MicroBitDisplay::getBrightness() * Axis aligned values only. * * Example: - * @code + * @code * uBit.display.rotateTo(MICROBIT_DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation * @endcode - */ + */ void MicroBitDisplay::rotateTo(DisplayRotation rotation) { this->rotation = rotation; @@ -921,7 +927,7 @@ void MicroBitDisplay::rotateTo(DisplayRotation rotation) * Enables the display, should only be called if the display is disabled. * * Example: - * @code + * @code * uBit.display.enable(); //reenables the display mechanics * @endcode */ @@ -933,13 +939,13 @@ void MicroBitDisplay::enable() uBit.flags |= MICROBIT_FLAG_DISPLAY_RUNNING; //set the display running flag } } - + /** * Disables the display, should only be called if the display is enabled. * Display must be disabled to avoid MUXing of edge connector pins. * * Example: - * @code + * @code * uBit.display.disable(); //disables the display * @endcode */ @@ -948,7 +954,7 @@ void MicroBitDisplay::disable() if(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING) { uBit.flags &= ~MICROBIT_FLAG_DISPLAY_RUNNING; //unset the display running flag - } + } } /** @@ -956,13 +962,13 @@ void MicroBitDisplay::disable() * Simplifies the process, you can also use uBit.display.image.clear * * Example: - * @code + * @code * uBit.display.clear(); //clears the display * @endcode - */ + */ void MicroBitDisplay::clear() { - image.clear(); + image.clear(); } /** @@ -970,12 +976,12 @@ void MicroBitDisplay::clear() * @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255. * * Example: - * @code + * @code * uBit.display.error(20); * @endcode */ void MicroBitDisplay::error(int statusCode) -{ +{ extern InterruptIn resetButton; __disable_irq(); //stop ALL interrupts @@ -984,16 +990,16 @@ void MicroBitDisplay::error(int statusCode) statusCode = 0; disable(); //relinquish PWMOut's control - + uint8_t strobeRow = 0; uint8_t strobeBitMsk = 0x20; - + //point to the font stored in Flash const unsigned char * fontLocation = MicroBitFont::defaultFont; - + //get individual digits of status code, and place it into a single array/ const uint8_t* chars[MICROBIT_DISPLAY_ERROR_CHARS] = { panicFace, fontLocation+((((statusCode/100 % 10)+48)-MICROBIT_FONT_ASCII_START) * 5), fontLocation+((((statusCode/10 % 10)+48)-MICROBIT_FONT_ASCII_START) * 5), fontLocation+((((statusCode % 10)+48)-MICROBIT_FONT_ASCII_START) * 5)}; - + //enter infinite loop. while(1) { @@ -1001,42 +1007,42 @@ void MicroBitDisplay::error(int statusCode) for(int characterCount = 0; characterCount < MICROBIT_DISPLAY_ERROR_CHARS; characterCount++) { int outerCount = 0; - + //display the current character while(outerCount < 500) { int coldata = 0; - + int i = 0; - + //if we have hit the row limit - reset both the bit mask and the row variable if(strobeRow == 3) { - strobeRow = 0; + strobeRow = 0; strobeBitMsk = 0x20; - } - + } + // Calculate the bitpattern to write. for (i = 0; i> matrixMap[i][strobeRow].x; //chars are right aligned but read left to right int y = matrixMap[i][strobeRow].y; - + if(chars[characterCount][y] & bitMsk) coldata |= (1 << i); } - + nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, 0xF0); //clear port 0 4-7 nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | 0x1F); // clear port 1 8-12 - + //write the new bit pattern 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 while(i>0) { @@ -1046,9 +1052,9 @@ void MicroBitDisplay::error(int statusCode) i--; } - + //update the bit mask and row count - strobeBitMsk <<= 1; + strobeBitMsk <<= 1; strobeRow++; outerCount++; } @@ -1080,3 +1086,11 @@ MicroBitImage MicroBitDisplay::screenShot() { return image.crop(0,0,MICROBIT_DISPLAY_WIDTH,MICROBIT_DISPLAY_HEIGHT); } + +/** + * Destructor for MicroBitDisplay, so that we deregister ourselves as a systemComponent + */ +MicroBitDisplay::~MicroBitDisplay() +{ + uBit.removeSystemComponent(this); +} diff --git a/source/MicroBitMessageBus.cpp b/source/MicroBitMessageBus.cpp index bf85e52..7fcd28d 100644 --- a/source/MicroBitMessageBus.cpp +++ b/source/MicroBitMessageBus.cpp @@ -7,7 +7,7 @@ #include "MicroBit.h" /** - * Constructor. + * Constructor. * Create a new Message Bus. */ MicroBitMessageBus::MicroBitMessageBus() @@ -30,7 +30,7 @@ void async_callback(void *param) // OK, now we need to decide how to behave depending on our configuration. // If this a fiber f already active within this listener then check our - // configuration to determine the correct course of action. + // configuration to determine the correct course of action. // if (listener->flags & MESSAGE_BUS_LISTENER_BUSY) @@ -47,7 +47,7 @@ void async_callback(void *param) } } - // Determine the calling convention for the callback, and invoke... + // Determine the calling convention for the callback, and invoke... // C++ is really bad at this! Especially as the ARM compiler is yet to support C++ 11 :-/ // Record that we have a fiber going into this listener... @@ -91,7 +91,7 @@ void async_callback(void *param) * Queue the given event for processing at a later time. * Add the given event at the tail of our queue. * - * @param The event to queue. + * @param The event to queue. */ void MicroBitMessageBus::queueEvent(MicroBitEvent &evt) { @@ -99,7 +99,7 @@ void MicroBitMessageBus::queueEvent(MicroBitEvent &evt) MicroBitEventQueueItem *prev = evt_queue_tail; - // Now process all handler regsitered as URGENT. + // Now process all handler regsitered as URGENT. // These pre-empt the queue, and are useful for fast, high priority services. processingComplete = this->process(evt, true); @@ -125,7 +125,7 @@ void MicroBitMessageBus::queueEvent(MicroBitEvent &evt) { item->next = evt_queue_head; evt_queue_head = item; - } + } else { item->next = prev->next; @@ -142,18 +142,18 @@ void MicroBitMessageBus::queueEvent(MicroBitEvent &evt) /** * Extract the next event from the front of the event queue (if present). - * @return + * @return * - * @param The event to queue. + * @param The event to queue. */ MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent() { MicroBitEventQueueItem *item = NULL; __disable_irq(); - + if (evt_queue_head != NULL) - { + { item = evt_queue_head; evt_queue_head = item->next; @@ -162,7 +162,7 @@ MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent() queueLength--; } - + __enable_irq(); @@ -188,7 +188,7 @@ int MicroBitMessageBus::deleteMarkedListeners() { if (p == NULL) listeners = l->next; - else + else p->next = l->next; // delete the listener. @@ -212,7 +212,7 @@ int MicroBitMessageBus::deleteMarkedListeners() * Periodic callback from MicroBit. * Process at least one event from the event queue, if it is not empty. * We then continue processing events until something appears on the runqueue. - */ + */ void MicroBitMessageBus::idleTick() { // Clear out any listeners marked for deletion @@ -231,7 +231,7 @@ void MicroBitMessageBus::idleTick() // If we have created some useful work to do, we stop processing. // This helps to minimise the number of blocked fibers we create at any point in time, therefore - // also reducing the RAM footprint. + // also reducing the RAM footprint. if(!scheduler_runqueue_empty()) break; @@ -242,26 +242,26 @@ void MicroBitMessageBus::idleTick() /** * Indicates whether or not we have any background work to do. - * @ return 1 if there are any events waitingto be processed, 0 otherwise. + * @ return 1 if there are any events waitingto be processed, 0 otherwise. */ int MicroBitMessageBus::isIdleCallbackNeeded() { - return !(evt_queue_head == NULL); + return !(evt_queue_head == NULL); } /** * Queues the given event to be sent to all registered recipients. * - * @param The event to send. + * @param The event to send. * * n.b. THIS IS NOW WRAPPED BY THE MicroBitEvent CLASS FOR CONVENIENCE... * * Example: - * @code + * @code * MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN,ticks,CREATE_ONLY); * evt.fire(); * - * //OR YOU CAN DO THIS... + * //OR YOU CAN DO THIS... * MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_DOWN); * @endcode */ @@ -299,7 +299,7 @@ int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent) { l->evt = evt; - // OK, if this handler has regisitered itself as non-blocking, we just execute it directly... + // OK, if this handler has regisitered itself as non-blocking, we just execute it directly... // This is normally only done for trusted system components. // Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber // should the event handler attempt a blocking operation, but doesn't have the overhead @@ -323,11 +323,11 @@ int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent) /** * Register a listener function. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. * Use MICROBIT_ID_ANY to receive events from all components. * - * @param value The value of messages to listen for. Events with any other values will be filtered. + * @param value The value of messages to listen for. Events with any other values will be filtered. * Use MICROBIT_VALUE_ANY to receive events of any value. * * @param handler The function to call when an event is received. @@ -335,7 +335,7 @@ int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent) * @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER * * Example: - * @code + * @code * void onButtonBClick(MicroBitEvent evt) * { * //do something @@ -344,7 +344,7 @@ int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent) * @endcode */ -int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags) +int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags) { if (handler == NULL) return MICROBIT_INVALID_PARAMETER; @@ -360,7 +360,7 @@ int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent) } -int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags) +int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags) { if (handler == NULL) return MICROBIT_INVALID_PARAMETER; @@ -378,20 +378,20 @@ int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, /** * Unregister a listener function. * Listners are identified by the Event ID, Event VALUE and handler registered using listen(). - * + * * @param id The Event ID used to register the listener. * @param value The Event VALUE used to register the listener. * @param handler The function used to register the listener. * * * Example: - * @code + * @code * void onButtonBClick() * { * //do something * } * - * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); + * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); * @endcode */ int MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent)) @@ -408,20 +408,20 @@ int MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent) /** * Unregister a listener function. * Listners are identified by the Event ID, Event VALUE and handler registered using listen(). - * + * * @param id The Event ID used to register the listener. * @param value The Event VALUE used to register the listener. * @param handler The function used to register the listener. * * * Example: - * @code + * @code * void onButtonBClick(void *arg) * { * //do something * } * - * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); + * uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); * @endcode */ int MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent, void*)) @@ -464,7 +464,7 @@ int MicroBitMessageBus::add(MicroBitListener *newListener) if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb)) { - // We have a perfect match for this event listener already registered. + // We have a perfect match for this event listener already registered. // If it's marked for deletion, we simply resurrect the listener, and we're done. // Either way, we return an error code, as the *new* listener should be released... if(l->flags & MESSAGE_BUS_LISTENER_DELETING) @@ -484,7 +484,7 @@ int MicroBitMessageBus::add(MicroBitListener *newListener) return MICROBIT_OK; } - // We maintain an ordered list of listeners. + // We maintain an ordered list of listeners. // The chain is held stictly in increasing order of ID (first level), then value code (second level). // Find the correct point in the chain for this event. // Adding a listener is a rare occurance, so we just walk the list... @@ -544,7 +544,7 @@ int MicroBitMessageBus::remove(MicroBitListener *listener) { if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD)) { - if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) || + if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) || ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb))) { if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value)) @@ -586,3 +586,10 @@ MicroBitListener* MicroBitMessageBus::elementAt(int n) return l; } +/** + * Destructor for MicroBitMessageBus, so that we deregister ourselves as an idleComponent + */ +MicroBitMessageBus::~MicroBitMessageBus() +{ + uBit.removeIdleComponent(this); +}