First cut at a build without a global MicroBit singleton

This commit is contained in:
Joe Finney 2015-11-23 19:46:20 +00:00
parent fdbc41d6b6
commit 5231b5f526
54 changed files with 768 additions and 583 deletions

View File

@ -56,8 +56,6 @@
#define MICROBIT_PIN_SDA P0_30
#define MICROBIT_PIN_SCL P0_0
#define MICROBIT_DEFAULT_TICK_PERIOD FIBER_TICK_PERIOD_MS
/**
* Class definition for a MicroBit device.
*
@ -71,16 +69,10 @@ class MicroBit
void onABListenerRegisteredEvent(MicroBitEvent evt);
uint32_t randomValue;
//the current tick period in MS
int tickPeriod;
public:
// Map of device state.
uint32_t flags;
// Periodic callback
Ticker systemTicker;
// Reset Button
InterruptIn resetButton;
// I2C Interface
MicroBitI2C i2c;
@ -88,14 +80,8 @@ class MicroBit
// Serial Interface
MicroBitSerial serial;
// Array of components which are iterated during a system tick
MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS];
// Array of components which are iterated during idle thread execution, isIdleCallbackNeeded is polled during a systemTick.
MicroBitComponent* idleThreadComponents[MICROBIT_IDLE_COMPONENTS];
// Device level Message Bus abstraction
MicroBitMessageBus MessageBus;
MicroBitMessageBus messageBus;
// Member variables to represent each of the core components on the device.
MicroBitDisplay display;
@ -121,7 +107,6 @@ class MicroBit
*
* Exposed objects:
* @code
* uBit.systemTicker; //the Ticker callback that performs routines like updating the display.
* uBit.MessageBus; //The message bus where events are fired.
* uBit.display; //The display object for the LED matrix.
* uBit.buttonA; //The buttonA object for button a.
@ -152,14 +137,14 @@ class MicroBit
*
* @return A string representing the friendly name of this device.
*/
ManagedString getName();
static ManagedString getName();
/**
* Return the serial number of this device.
*
* @return A string representing the serial number of this device.
*/
ManagedString getSerial();
static ManagedString getSerial();
/**
* Will reset the micro:bit when called.
@ -185,10 +170,10 @@ class MicroBit
*
* Example:
* @code
* uBit.sleep(20); //sleep for 20ms
* MicroBit::sleep(20); //sleep for 20ms
* @endcode
*/
int sleep(int milliseconds);
static int sleep(int milliseconds);
/**
* Seed the pseudo random number generator using the hardware generator.
@ -227,62 +212,6 @@ class MicroBit
*/
int random(int max);
/**
* Period callback. Used by MicroBitDisplay, FiberScheduler and I2C sensors to
* provide a power efficient sense of time.
*/
void systemTick();
/**
* System tasks to be executed by the idle thread when the Micro:Bit isn't busy or when data needs to be read.
*/
void systemTasks();
/**
* add a component to the array of system components which invocate the systemTick member function during a systemTick
*
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
*/
int addSystemComponent(MicroBitComponent *component);
/**
* remove a component from the array of system components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added.
*/
int removeSystemComponent(MicroBitComponent *component);
/**
* add a component to the array of of idle thread components.
* isIdleCallbackNeeded is polled during a systemTick to determine if the idle thread should jump to the front of the queue
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
*/
int addIdleComponent(MicroBitComponent *component);
/**
* remove a component from the array of idle thread components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added.
*/
int removeIdleComponent(MicroBitComponent *component);
/*
* Reconfigures the ticker to the given speed in milliseconds.
* @param speedMs the speed in milliseconds
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedUs < 1
*
* @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick()
*/
int setTickPeriod(int speedMs);
/*
* Returns the currently used tick speed in milliseconds
*/
int getTickPeriod();
/**
* Determine the time since this MicroBit was last reset.
*
@ -306,12 +235,38 @@ class MicroBit
*/
void panic(int statusCode = 0);
};
/**
* add a component to the array of components which invocate the systemTick member function during a systemTick
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
* @note This interface is now deprecated. See fiber_add_system_component().
*/
int addSystemComponent(MicroBitComponent *component);
// Definition of the global instance of the MicroBit class.
// Using this as a variation on the singleton pattern, just to make
// code integration a little bit easier for third parties.
extern MicroBit uBit;
/**
* remove a component from the array of components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added.
* @note This interface is now deprecated. See fiber_remove_system_component().
*/
int removeSystemComponent(MicroBitComponent *component);
/**
* add a component to the array of components which invocate the systemTick member function during a systemTick
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
* @note This interface is now deprecated. See fiber_add_idle_component().
*/
int addIdleComponent(MicroBitComponent *component);
/**
* remove a component from the array of components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added.
* @note This interface is now deprecated. See fiber_remove_idle_component().
*/
int removeIdleComponent(MicroBitComponent *component);
};
// Entry point for application programs. Called after the super-main function
// has initialized the device and runtime environment.
@ -319,3 +274,4 @@ extern "C" void app_main();
#endif

View File

@ -150,6 +150,7 @@ class MicroBitAccelerometer : public MicroBitComponent
MMA8653Sample sample; // The last sample read.
DigitalIn int1; // Data ready interrupt.
float pitch; // Pitch of the device, in radians.
MicroBitI2C& i2c; // The I2C interface to use.
float roll; // Roll of the device, in radians.
uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable.
BasicGesture lastGesture; // the last, stable gesture recorded.
@ -169,7 +170,7 @@ class MicroBitAccelerometer : public MicroBitComponent
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
* @endcode
*/
MicroBitAccelerometer(uint16_t id, uint16_t address);
MicroBitAccelerometer(uint16_t id, uint16_t address, MicroBitI2C &_i2c);
/**
* Configures the accelerometer for G range and sample rate defined

View File

@ -22,7 +22,7 @@ class MicroBitAccelerometerService
* Create a representation of the AccelerometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitAccelerometerService(BLEDevice &_ble);
MicroBitAccelerometerService(BLEDevice &_ble, MicroBitAccelerometer &_acclerometer, MicroBitMessageBus &messageBus);
private:
@ -39,6 +39,7 @@ class MicroBitAccelerometerService
// Bluetooth stack we're running on.
BLEDevice &ble;
MicroBitAccelerometer &accelerometer;
// memory for our 8 bit control characteristics.
uint16_t accelerometerDataCharacteristicBuffer[3];

View File

@ -76,7 +76,7 @@ class MicroBitBLEManager : MicroBitComponent
* uBit.init();
* @endcode
*/
void init(ManagedString deviceName, ManagedString serialNumber, bool enableBonding);
void init(ManagedString deviceName, ManagedString serialNumber, MicroBitMessageBus& messageBus, bool enableBonding);
/**
* Change the output power level of the transmitter to the given value.
@ -92,8 +92,9 @@ class MicroBitBLEManager : MicroBitComponent
* of the micro:bit in cases where BLE is disabled during normal operation.
*
* @param display a MicroBitDisplay to use when displaying pairing information.
* @prarm authorizationButton The button to use to authorise a pairing request.
*/
void pairingMode(MicroBitDisplay &display);
void pairingMode(MicroBitDisplay &display, MicroBitButton &authorisationButton);
/**
* Makes the micro:bit discoverable via BLE, such that bonded devices can connect

View File

@ -22,7 +22,7 @@ class MicroBitButtonService
* Create a representation of the ButtonService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitButtonService(BLEDevice &_ble);
MicroBitButtonService(BLEDevice &_ble, MicroBitMessageBus &messageBus);
private:

View File

@ -4,6 +4,7 @@
#include "mbed.h"
#include "MicroBitComponent.h"
#include "MicroBitCoordinateSystem.h"
#include "MicroBitAccelerometer.h"
/**
* Relevant pin assignments
@ -128,6 +129,8 @@ class MicroBitCompass : public MicroBitComponent
CompassSample average; // Centre point of sample data.
CompassSample sample; // The latest sample data recorded.
DigitalIn int1; // Data ready interrupt.
MicroBitI2C& i2c; // The I2C interface the sensor is connected to.
MicroBitAccelerometer& accelerometer; // The accelerometer to use for tilt compensation.
public:
@ -149,7 +152,7 @@ class MicroBitCompass : public MicroBitComponent
* MICROBIT_COMPASS_EVT_CAL_END // triggered when calibration has finished.
* @endcode
*/
MicroBitCompass(uint16_t id, uint16_t address);
MicroBitCompass(uint16_t id, uint16_t address, MicroBitI2C& _i2c, MicroBitAccelerometer &_accelerometer);
/**
* Configures the compass for the sample rate defined

View File

@ -6,6 +6,7 @@
#define MICROBIT_COMPAT_H
#include "ErrorNo.h"
#include "MicroBitDevice.h"
#define PI 3.14159265359
@ -67,5 +68,4 @@ int string_reverse(char *s);
*/
void itoa(int n, char *s);
#endif

View File

@ -52,6 +52,10 @@
#define MICROBIT_ID_NOTIFY_ONE 1022 // Notfication channel, for general purpose synchronisation
#define MICROBIT_ID_NOTIFY 1023 // Notfication channel, for general purpose synchronisation
// Universal flags used as part of the status field
#define MICROBIT_COMPONENT_RUNNING 0x01
class MicroBitComponent
{
protected:

View File

@ -274,6 +274,7 @@
#ifndef MICROBIT_BLE_MAXIMUM_SCROLLTEXT
#define MICROBIT_BLE_MAXIMUM_SCROLLTEXT 20
#endif
//
// Accelerometer options
//

View File

@ -106,7 +106,9 @@ class MicroBitDisplay : public MicroBitComponent
uint8_t errorTimeout;
Timeout renderTimer;
MicroBitFont font;
//
// Reference to the first display created. Used as a defaut output channel, such as panic().
static MicroBitDisplay *defaultDisplay;
//
// State used by all animation routines.
@ -551,6 +553,17 @@ public:
*/
void clear();
/**
* Displays "=(" and an accompanying status code on the default display.
* @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
*
* Example:
* @code
* uBit.display.error(20);
* @endcode
*/
static void panic(int statusCode);
/**
* Displays "=(" and an accompanying status code infinitely.
* @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
@ -574,13 +587,16 @@ public:
void setErrorTimeout(int iterations);
/**
* Updates the font property of this object with the new font.
* @param font the new font that will be used to render characters..
* Updates the font that will be used for display operations.
* DEPRECATED: Please use MicroBitFont::setSystemFont() instead.
*
* @param font the new font that will be used to render characters.
*/
void setFont(MicroBitFont font);
/**
* Retreives the font object used for rendering characters on the display.
* DEPRECATED: Please use MicroBitFont::getSystemFont() instead.
*/
MicroBitFont getFont();

View File

@ -30,7 +30,7 @@ class MicroBitEventService : public MicroBitComponent
* Create a representation of the EventService
* @param BLE The instance of a BLE device that we're running on.
*/
MicroBitEventService(BLEDevice &_ble);
MicroBitEventService(BLEDevice &_ble, MicroBitMessageBus &_messageBus);
/**
* Periodic callback from MicroBit scheduler.
@ -58,6 +58,7 @@ class MicroBitEventService : public MicroBitComponent
// Bluetooth stack we're running on.
BLEDevice &ble;
MicroBitMessageBus &messageBus;
// memory for our event characteristics.
EventServiceEvent clientEventBuffer;

View File

@ -18,7 +18,7 @@
// stack for any long lived fibers with large stack
// Fiber Scheduler Flags
#define MICROBIT_FLAG_DATA_READY 0x01
#define MICROBIT_SCHEDULER_RUNNING 0x01
// Fiber Flags
#define MICROBIT_FIBER_FLAG_FOB 0x01
@ -70,13 +70,35 @@ struct Fiber
extern Fiber *currentFiber;
/**
* Initialises the Fiber scheduler.
* Creates a Fiber context around the calling thread, and adds it to the run queue as the current thread.
*
* This function must be called once only from the main thread, and before any other Fiber operation.
*/
void scheduler_init();
void scheduler_init(MicroBitMessageBus *_messageBus);
/*
* Reconfigures the system wide timer to the given period in milliseconds.
*
* @param speedMs the new period of the timer in milliseconds
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedMs < 1
*
* @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick()
*/
int scheduler_set_tick_period(int speedMs);
/*
* Returns the currently used tick speed in milliseconds
*/
int scheduler_get_tick_period();
/**
* Determines if the fiber scheduler is operational.
* @return 1 if the fber scheduler is running, 0 otherwise.
*/
int fiber_scheduler_running();
/**
* Exit point for all fibers.
@ -157,8 +179,9 @@ void scheduler_tick();
*
* @param id The ID field of the event to listen for (e.g. MICROBIT_ID_BUTTON_A)
* @param value The VALUE of the event to listen for (e.g. MICROBIT_BUTTON_EVT_CLICK)
* @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not associated with a MicroBitMessageBus.
*/
void fiber_wait_for_event(uint16_t id, uint16_t value);
int fiber_wait_for_event(uint16_t id, uint16_t value);
/**
* Executes the given function asynchronously if necessary.
@ -242,6 +265,36 @@ void idle();
*/
void idle_task();
/**
* add a component to the array of system components which invocate the systemTick member function during a systemTick
*
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
*/
int fiber_add_system_component(MicroBitComponent *component);
/**
* remove a component from the array of system components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added.
*/
int fiber_remove_system_component(MicroBitComponent *component);
/**
* add a component to the array of of idle thread components.
* isIdleCallbackNeeded is polled during a systemTick to determine if the idle thread should jump to the front of the queue
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
*/
int fiber_add_idle_component(MicroBitComponent *component);
/**
* remove a component from the array of idle thread components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added.
*/
int fiber_remove_idle_component(MicroBitComponent *component);
/**
* Determines if the processor is executing in interrupt context.
* @return true if any the processor is currently executing any interrupt service routine. False otherwise.
@ -266,9 +319,4 @@ extern "C" void restore_register_context(Cortex_M0_TCB *tcb);
*/
extern unsigned long ticks;
/**
* This variable is used to prioritise the systems' idle fibre to execute essential tasks.
*/
extern uint8_t fiber_flags;
#endif

View File

@ -17,6 +17,7 @@ class MicroBitFont
public:
static const unsigned char* defaultFont;
static MicroBitFont systemFont;
const unsigned char* characters;
@ -37,6 +38,18 @@ class MicroBitFont
* Sets the characters to defaultFont characters and asciiEnd to MICROBIT_FONT_ASCII_END.
*/
MicroBitFont();
/**
* Changes the current system font to the one specified.
* @param font the new font that will be used to render characters..
*/
static void setSystemFont(MicroBitFont font);
/**
* Retreives the font object used for rendering characters on the display.
*/
static MicroBitFont getSystemFont();
};
#endif

View File

@ -14,6 +14,7 @@ class MicroBitIO
{
public:
MicroBitPin pin[0];
MicroBitPin P0;
MicroBitPin P1;
MicroBitPin P2;

View File

@ -35,7 +35,7 @@ class MicroBitIOPinService : public MicroBitComponent
* Create a representation of the IOPinService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitIOPinService(BLEDevice &_ble);
MicroBitIOPinService(BLEDevice &_ble, MicroBitIO &_io);
/**
* periodic callback from MicroBit scheduler.
@ -91,6 +91,7 @@ class MicroBitIOPinService : public MicroBitComponent
// Bluetooth stack we're running on.
BLEDevice &ble;
MicroBitIO &io;
// memory for our 8 bit control characteristics.
uint32_t ioPinServiceADCharacteristicBuffer;

View File

@ -22,8 +22,9 @@ class MicroBitLEDService
* Constructor.
* Create a representation of the LEDService
* @param BLE The instance of a BLE device that we're running on.
* @param display The instance of a MicroBitDisplay to interface with.
*/
MicroBitLEDService(BLEDevice &_ble);
MicroBitLEDService(BLEDevice &_ble, MicroBitDisplay &_display);
/**
* Callback. Invoked when any of our attributes are written via BLE.
@ -39,6 +40,7 @@ class MicroBitLEDService
// Bluetooth stack we're running on.
BLEDevice &ble;
MicroBitDisplay &display;
// memory for our 8 bit control characteristics.
uint8_t matrixCharacteristicBuffer[5];

View File

@ -3,6 +3,7 @@
#include "mbed.h"
#include "MicroBitComponent.h"
#include "MicroBitMessageBus.h"
#define MICROBIT_LIGHT_SENSOR_CHAN_NUM 3
#define MICROBIT_LIGHT_SENSOR_AN_SET_TIME 4000

View File

@ -23,7 +23,7 @@ class MicroBitMagnetometerService
* Create a representation of the MagnetometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitMagnetometerService(BLEDevice &_ble);
MicroBitMagnetometerService(BLEDevice &_ble, MicroBitCompass &_compass, MicroBitMessageBus &messageBus);
private:
@ -47,6 +47,7 @@ class MicroBitMagnetometerService
// Bluetooth stack we're running on.
BLEDevice &ble;
MicroBitCompass &compass;
// memory for our 8 bit control characteristics.
int16_t magnetometerDataCharacteristicBuffer[3];

View File

@ -33,6 +33,8 @@ class MicroBitMessageBus : public MicroBitComponent
{
public:
static MicroBitMessageBus *defaultMessageBus;
/**
* Default constructor.
* Anticipating only one MessageBus per device, as filtering is handled within the class.

View File

@ -1,7 +1,9 @@
#ifndef MICROBIT_MULTI_BUTTON_H
#define MICROBIT_MULTI_BUTTON_H
#include "MicroBit.h"
#include "mbed.h"
#include "MicroBitButton.h"
#include "MicroBitMessageBus.h"
#define MICROBIT_MULTI_BUTTON_STATE_1 0x01
#define MICROBIT_MULTI_BUTTON_STATE_2 0x02
@ -57,7 +59,7 @@ class MicroBitMultiButton : public MicroBitComponent
* MICROBIT_BUTTON_EVT_HOLD
* @endcode
*/
MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2);
MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2, MicroBitMessageBus &messageBus);
/**
* Tests if this MultiButton is currently pressed.

View File

@ -1,8 +1,13 @@
#ifndef MICROBIT_RADIO_H
#define MICROBIT_RADIO_H
class MicroBitRadio;
struct FrameBuffer;
#include "mbed.h"
#include "PacketBuffer.h"
#include "MicroBitRadioDatagram.h"
#include "MicroBitRadioEvent.h"
/**
* Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module.
@ -46,6 +51,7 @@
// Events
#define MICROBIT_RADIO_EVT_DATAGRAM 1 // Event to signal that a new datagram has been received.
struct FrameBuffer
{
uint8_t length; // The length of the remaining bytes in the packet. includes protocol/version/group fields, excluding the length field itself.
@ -58,8 +64,6 @@ struct FrameBuffer
uint8_t rssi; // Received signal strength of this frame.
};
#include "MicroBitRadioDatagram.h"
#include "MicroBitRadioEvent.h"
class MicroBitRadio : MicroBitComponent
{

View File

@ -18,14 +18,17 @@
class MicroBitRadioDatagram
{
MicroBitRadio &radio; // The underlying radio module used to send and receive data.
FrameBuffer *rxQueue; // A linear list of incoming packets, queued awaiting processing.
public:
/**
* Constructor.
*
* @param radio The underlying radio module used to send and receive data.
*/
MicroBitRadioDatagram();
MicroBitRadioDatagram(MicroBitRadio &r);
/**
* Retreives packet payload data into the given buffer.

View File

@ -20,25 +20,39 @@
class MicroBitRadioEvent
{
bool suppressForwarding; // A private flag used to prevent event forwarding loops.
MicroBitRadio &radio; // A reference to the underlying radio module to use.
public:
/**
* Constructor.
*/
MicroBitRadioEvent();
MicroBitRadioEvent(MicroBitRadio &r);
/**
* Associates the given MessageBus events with the radio channel.
* Once registered, all events matching the given registration sent to this micro:bit's
* MessageBus will be automatically retrasmitted on the radio.
* default MessageBus will be automaticlaly retrasmitted on the radio.
*
* @param id The ID of the events to register.
* @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given ID.
* @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given id.
*
* @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if no defult MessageBus is available.
*/
int listen(uint16_t id, uint16_t value);
/**
* Associates the given MessageBus events with the radio channel.
* Once registered, all events matching the given registration sent to the given
* MessageBus will be automaticlaly retrasmitted on the radio.
*
* @param id The ID of the events to register.
* @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given id.
* @param The message bus to listen for events on.
*
* @return MICROBIT_OK on success.
*/
int listen(uint16_t id, uint16_t value);
int listen(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus);
/**
* Disassociates the given MessageBus events with the radio channel.
@ -46,10 +60,21 @@ class MicroBitRadioEvent
* @param id The ID of the events to deregister.
* @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given ID.
*
* @return MICROBIT_OK on success.
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the default message bus does not exist.
*/
int ignore(uint16_t id, uint16_t value);
/**
* Disassociates the given MessageBus events with the radio channel.
*
* @param id The ID of the events to deregister.
* @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given ID.
* @param The message bus to deregister on.
*
* @return MICROBIT_OK on success.
*/
int ignore(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus);
/**
* Protocol handler callback. This is called when the radio receives a packet marked as using the event protocol.
* This function process this packet, and fires the event contained inside onto the local MessageBus.

View File

@ -22,7 +22,7 @@ class MicroBitTemperatureService
* Create a representation of the TempertureService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitTemperatureService(BLEDevice &_ble);
MicroBitTemperatureService(BLEDevice &_ble, MicroBitThermometer &_thermometer, MicroBitMessageBus &messageBus);
/**
* Callback. Invoked when any of our attributes are written via BLE.
@ -38,6 +38,7 @@ class MicroBitTemperatureService
// Bluetooth stack we're running on.
BLEDevice &ble;
MicroBitThermometer &thermometer;
// memory for our 8 bit temperature characteristic.
int8_t temperatureDataCharacteristicBuffer;

View File

@ -22,6 +22,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
"MicroBitThermometer.cpp"
"MicroBitIO.cpp"
"MicroBitCompat.cpp"
"MicroBitDevice.cpp"
"MicroBitImage.cpp"
"MicroBitDisplay.cpp"
"DynamicPwm.cpp"

View File

@ -21,24 +21,6 @@
#pragma GCC diagnostic pop
#endif
/**
* custom function for panic for malloc & new due to scoping issue.
*/
void panic(int statusCode)
{
uBit.panic(statusCode);
}
/**
* Callback that performs a hard reset when a BLE GAP disconnect occurs.
* Only used when an explicit reset is invoked locally whilst a BLE connection is in progress.
* This allows for a clean diconnect of the BLE connection before resetting.
*/
void bleDisconnectionResetCallback(const Gap::DisconnectionCallbackParams_t *)
{
NVIC_SystemReset();
}
/**
* Perform a hard reset of the micro:bit.
* If BLE connected, then try to signal a disconnect first
@ -46,25 +28,9 @@ void bleDisconnectionResetCallback(const Gap::DisconnectionCallbackParams_t *)
void
microbit_reset()
{
if(uBit.ble && uBit.ble->getGapState().connected) {
uBit.ble->onDisconnection(bleDisconnectionResetCallback);
uBit.ble->gap().disconnect(Gap::REMOTE_USER_TERMINATED_CONNECTION);
// We should be reset by the disconnection callback, so we wait to
// allow that to happen. If it doesn't happen, then we fall through to the
// hard rest here. (For example there is a race condition where
// the remote device disconnects between us testing the connection
// state and re-setting the disconnection callback).
uBit.sleep(1000);
}
NVIC_SystemReset();
}
void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
{
uBit.ble->startAdvertising();
}
void MicroBit::onABListenerRegisteredEvent(MicroBitEvent evt)
{
(void) evt; // Unused parameter
@ -103,16 +69,16 @@ void MicroBit::onABListenerRegisteredEvent(MicroBitEvent evt)
* @endcode
*/
MicroBit::MicroBit() :
flags(0x00),
resetButton(MICROBIT_PIN_BUTTON_RESET),
i2c(MICROBIT_PIN_SDA, MICROBIT_PIN_SCL),
serial(USBTX, USBRX),
MessageBus(),
messageBus(),
display(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_WIDTH, MICROBIT_DISPLAY_HEIGHT),
buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A, MICROBIT_BUTTON_ALL_EVENTS),
buttonB(MICROBIT_ID_BUTTON_B,MICROBIT_PIN_BUTTON_B, MICROBIT_BUTTON_ALL_EVENTS),
buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B),
accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR),
compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR),
buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B, messageBus),
accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR, i2c),
compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR,i2c,accelerometer),
thermometer(MICROBIT_ID_THERMOMETER),
io(MICROBIT_ID_IO_P0,MICROBIT_ID_IO_P1,MICROBIT_ID_IO_P2,
MICROBIT_ID_IO_P3,MICROBIT_ID_IO_P4,MICROBIT_ID_IO_P5,
@ -125,6 +91,9 @@ MicroBit::MicroBit() :
radio(MICROBIT_ID_RADIO),
ble(NULL)
{
// Bring up soft reset functionality as soon as possible.
resetButton.mode(PullUp);
resetButton.fall(this, &MicroBit::reset);
}
/**
@ -140,25 +109,74 @@ MicroBit::MicroBit() :
*/
void MicroBit::init()
{
// Bring up our nested heap allocator.
microbit_heap_init();
// Bring up fiber scheduler
scheduler_init(&messageBus);
sleep(10);
// Load any stored calibration data from persistent storage.
MicroBitStorage s = MicroBitStorage();
MicroBitConfigurationBlock *b = s.getConfigurationBlock();
//if we have some calibrated data, calibrate the compass!
if(b->magic == MICROBIT_STORAGE_CONFIG_MAGIC)
{
if(b->compassCalibrationData != CompassSample(0,0,0))
compass.setCalibration(b->compassCalibrationData);
}
delete b;
// TODO: YUCK!!! MOVE THESE INTO THE RELEVANT COMPONENTS!!
//add the display to the systemComponent array
addSystemComponent(&uBit.display);
addSystemComponent(&display);
//add the compass and accelerometer to the idle array
addIdleComponent(&uBit.accelerometer);
addIdleComponent(&uBit.compass);
addIdleComponent(&uBit.MessageBus);
addIdleComponent(&accelerometer);
addIdleComponent(&compass);
addIdleComponent(&messageBus);
// Seed our random number generator
seedRandom();
tickPeriod = MICROBIT_DEFAULT_TICK_PERIOD;
// Start refreshing the Matrix Display
systemTicker.attach_us(this, &MicroBit::systemTick, tickPeriod * 1000);
// Register our compass calibration algorithm.
MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CALIBRATE, this, &MicroBit::compassCalibrator, MESSAGE_BUS_LISTENER_IMMEDIATE);
MessageBus.listen(MICROBIT_ID_MESSAGE_BUS_LISTENER, MICROBIT_ID_BUTTON_AB, this, &MicroBit::onABListenerRegisteredEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CALIBRATE, this, &MicroBit::compassCalibrator, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(MICROBIT_ID_MESSAGE_BUS_LISTENER, MICROBIT_ID_BUTTON_AB, this, &MicroBit::onABListenerRegisteredEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
#if CONFIG_ENABLED(MICROBIT_BLE_PAIRING_MODE)
// Test if we need to enter BLE pairing mode...
int i=0;
while (buttonA.isPressed() && buttonB.isPressed() && i<10)
{
sleep(100);
i++;
if (i == 10)
{
// Start the BLE stack, if it isn't already running.
if (!ble)
{
bleManager.init(getName(), getSerial(), messageBus, true);
ble = bleManager.ble;
}
// Enter pairing mode, using the LED matrix for any necessary pairing operations
bleManager.pairingMode(display, buttonA);
}
}
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED)
// Start the BLE stack, if it isn't already running.
if (!ble)
{
bleManager.init(getName(), getSerial(), messageBus, false);
ble = bleManager.ble;
}
#endif
}
/**
@ -208,8 +226,8 @@ void MicroBit::compassCalibrator(MicroBitEvent)
cursor.on = (cursor.on + 1) % 4;
// take a snapshot of the current accelerometer data.
int x = uBit.accelerometer.getX();
int y = uBit.accelerometer.getY();
int x = accelerometer.getX();
int y = accelerometer.getY();
// Deterine the position of the user controlled pixel on the screen.
if (x < -PIXEL2_THRESHOLD)
@ -245,7 +263,7 @@ void MicroBit::compassCalibrator(MicroBitEvent)
img.setPixelValue(cursor.x, cursor.y, 255);
// Update the buffer to the screen.
uBit.display.image.paste(img,0,0,0);
display.image.paste(img,0,0,0);
// test if we need to update the state at the users position.
for (int i=0; i<PERIMETER_POINTS; i++)
@ -264,7 +282,7 @@ void MicroBit::compassCalibrator(MicroBitEvent)
}
}
uBit.sleep(100);
sleep(100);
}
// We have enough sample data to make a fairly accurate calibration.
@ -361,6 +379,15 @@ ManagedString MicroBit::getSerial()
*/
void MicroBit::reset()
{
if(ble && ble->getGapState().connected) {
// We have a connected BLE peer. Disconnect the BLE session.
ble->gap().disconnect(Gap::REMOTE_USER_TERMINATED_CONNECTION);
// Wait a little while for the connection to drop.
sleep(100);
}
microbit_reset();
}
@ -387,7 +414,7 @@ int MicroBit::sleep(int milliseconds)
if(milliseconds < 0)
return MICROBIT_INVALID_PARAMETER;
if (flags & MICROBIT_FLAG_SCHEDULER_RUNNING)
if (fiber_scheduler_running())
fiber_sleep(milliseconds);
else
wait_ms(milliseconds);
@ -418,7 +445,6 @@ int MicroBit::random(int max)
{
uint32_t m, result;
//return MICROBIT_INVALID_VALUE if max is <= 0...
if(max <= 0)
return MICROBIT_INVALID_PARAMETER;
@ -468,7 +494,7 @@ void MicroBit::seedRandom()
{
randomValue = 0;
if(uBit.ble)
if(ble)
{
// If Bluetooth is enabled, we need to go through the Nordic software to safely do this.
uint32_t result = sd_rand_application_vector_get((uint8_t*)&randomValue, sizeof(randomValue));
@ -510,42 +536,6 @@ void MicroBit::seedRandom(uint32_t seed)
}
/**
* Periodic callback. Used by MicroBitDisplay, FiberScheduler and buttons.
*/
void MicroBit::systemTick()
{
// Scheduler callback. We do this here just as a single timer is more efficient. :-)
if (uBit.flags & MICROBIT_FLAG_SCHEDULER_RUNNING)
scheduler_tick();
//work out if any idle components need processing, if so prioritise the idle thread
for(int i = 0; i < MICROBIT_IDLE_COMPONENTS; i++)
if(idleThreadComponents[i] != NULL && idleThreadComponents[i]->isIdleCallbackNeeded())
{
fiber_flags |= MICROBIT_FLAG_DATA_READY;
break;
}
//update any components in the systemComponents array
for(int i = 0; i < MICROBIT_SYSTEM_COMPONENTS; i++)
if(systemTickComponents[i] != NULL)
systemTickComponents[i]->systemTick();
}
/**
* System tasks to be executed by the idle thread when the Micro:Bit isn't busy or when data needs to be read.
*/
void MicroBit::systemTasks()
{
//call the idleTick member function indiscriminately
for(int i = 0; i < MICROBIT_IDLE_COMPONENTS; i++)
if(idleThreadComponents[i] != NULL)
idleThreadComponents[i]->idleTick();
fiber_flags &= ~MICROBIT_FLAG_DATA_READY;
}
/**
* add a component to the array of components which invocate the systemTick member function during a systemTick
* @param component The component to add.
@ -554,16 +544,7 @@ void MicroBit::systemTasks()
*/
int MicroBit::addSystemComponent(MicroBitComponent *component)
{
int i = 0;
while(systemTickComponents[i] != NULL && i < MICROBIT_SYSTEM_COMPONENTS)
i++;
if(i == MICROBIT_SYSTEM_COMPONENTS)
return MICROBIT_NO_RESOURCES;
systemTickComponents[i] = component;
return MICROBIT_OK;
return fiber_add_system_component(component);
}
/**
@ -574,17 +555,7 @@ int MicroBit::addSystemComponent(MicroBitComponent *component)
*/
int MicroBit::removeSystemComponent(MicroBitComponent *component)
{
int i = 0;
while(systemTickComponents[i] != component && i < MICROBIT_SYSTEM_COMPONENTS)
i++;
if(i == MICROBIT_SYSTEM_COMPONENTS)
return MICROBIT_INVALID_PARAMETER;
systemTickComponents[i] = NULL;
return MICROBIT_OK;
return fiber_remove_system_component(component);
}
/**
@ -595,17 +566,7 @@ int MicroBit::removeSystemComponent(MicroBitComponent *component)
*/
int MicroBit::addIdleComponent(MicroBitComponent *component)
{
int i = 0;
while(idleThreadComponents[i] != NULL && i < MICROBIT_IDLE_COMPONENTS)
i++;
if(i == MICROBIT_IDLE_COMPONENTS)
return MICROBIT_NO_RESOURCES;
idleThreadComponents[i] = component;
return MICROBIT_OK;
return fiber_add_idle_component(component);
}
/**
@ -616,47 +577,9 @@ int MicroBit::addIdleComponent(MicroBitComponent *component)
*/
int MicroBit::removeIdleComponent(MicroBitComponent *component)
{
int i = 0;
while(idleThreadComponents[i] != component && i < MICROBIT_IDLE_COMPONENTS)
i++;
if(i == MICROBIT_IDLE_COMPONENTS)
return MICROBIT_INVALID_PARAMETER;
idleThreadComponents[i] = NULL;
return MICROBIT_OK;
return fiber_remove_idle_component(component);
}
/*
* Reconfigures the ticker to the given speed in milliseconds.
* @param speedMs the speed in milliseconds
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedUs < 1
*
* @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick()
*/
int MicroBit::setTickPeriod(int speedMs)
{
if(speedMs < 1)
return MICROBIT_INVALID_PARAMETER;
uBit.systemTicker.detach();
uBit.systemTicker.attach_us(this, &MicroBit::systemTick, speedMs * 1000);
tickPeriod = speedMs;
return MICROBIT_OK;
}
/*
* Returns the currently used tick speed in milliseconds
*/
int MicroBit::getTickPeriod()
{
return tickPeriod;
}
/**
* Determine the time since this MicroBit was last reset.
@ -682,12 +605,11 @@ const char *MicroBit::systemVersion()
}
/**
* Triggers a microbit panic where an infinite loop will occur swapping between the panicFace and statusCode if provided.
*
* Triggers a microbit panic. All functionality will cease, and a sad face displayed along with an error code.
* @param statusCode the status code of the associated error. Status codes must be in the range 0-255.
*/
void MicroBit::panic(int statusCode)
{
//show error and enter infinite while
uBit.display.error(statusCode);
display.error(statusCode);
}

View File

@ -93,7 +93,7 @@ int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
command[0] = reg;
command[1] = value;
return uBit.i2c.write(address, (const char *)command, 2);
return i2c.write(address, (const char *)command, 2);
}
/**
@ -112,11 +112,11 @@ int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
if (buffer == NULL || length <= 0 )
return MICROBIT_INVALID_PARAMETER;
result = uBit.i2c.write(address, (const char *)&reg, 1, true);
result = i2c.write(address, (const char *)&reg, 1, true);
if (result !=0)
return MICROBIT_I2C_ERROR;
result = uBit.i2c.read(address, (char *)buffer, length);
result = i2c.read(address, (char *)buffer, length);
if (result !=0)
return MICROBIT_I2C_ERROR;
@ -134,7 +134,7 @@ int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
* @endcode
*/
MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY)
MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address, MicroBitI2C& _i2c) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY), i2c(_i2c)
{
// Store our identifiers.
this->id = id;
@ -157,7 +157,7 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa
// Configure and enable the accelerometer.
if (this->configure() == MICROBIT_OK)
uBit.flags |= MICROBIT_FLAG_ACCELEROMETER_RUNNING;
status |= MICROBIT_COMPONENT_RUNNING;
}
/**
@ -576,7 +576,7 @@ int MicroBitAccelerometer::isIdleCallbackNeeded()
*/
MicroBitAccelerometer::~MicroBitAccelerometer()
{
uBit.removeIdleComponent(this);
fiber_remove_idle_component(this);
}
const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {

View File

@ -28,7 +28,7 @@ MicroBitButton::MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventCon
this->eventConfiguration = eventConfiguration;
this->downStartTime = 0;
this->sigma = 0;
uBit.addSystemComponent(this);
fiber_add_system_component(this);
}
/**
@ -128,5 +128,5 @@ int MicroBitButton::isPressed()
*/
MicroBitButton::~MicroBitButton()
{
uBit.removeSystemComponent(this);
fiber_remove_system_component(this);
}

View File

@ -18,7 +18,7 @@
* MICROBIT_COMPASS_EVT_CAL_END // triggered when calibration has finished.
* @endcode
*/
MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sample(), int1(MICROBIT_PIN_COMPASS_DATA_READY)
MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address, MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer) : average(), sample(), int1(MICROBIT_PIN_COMPASS_DATA_READY), i2c(_i2c), accelerometer(_accelerometer)
{
this->id = id;
this->address = address;
@ -34,7 +34,7 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
// Indicate that we're up and running.
uBit.flags |= MICROBIT_FLAG_COMPASS_RUNNING;
status |= MICROBIT_COMPONENT_RUNNING;
}
/**
@ -51,7 +51,7 @@ int MicroBitCompass::writeCommand(uint8_t reg, uint8_t value)
command[0] = reg;
command[1] = value;
return uBit.i2c.write(address, (const char *)command, 2);
return i2c.write(address, (const char *)command, 2);
}
/**
@ -69,11 +69,11 @@ int MicroBitCompass::readCommand(uint8_t reg, uint8_t* buffer, int length)
if (buffer == NULL || length <= 0)
return MICROBIT_INVALID_PARAMETER;
result = uBit.i2c.write(address, (const char *)&reg, 1, true);
result = i2c.write(address, (const char *)&reg, 1, true);
if (result !=0)
return MICROBIT_I2C_ERROR;
result = uBit.i2c.read(address, (char *)buffer, length);
result = i2c.read(address, (char *)buffer, length);
if (result !=0)
return MICROBIT_I2C_ERROR;
@ -94,14 +94,14 @@ int MicroBitCompass::read16(uint8_t reg)
int result;
cmd[0] = reg;
result = uBit.i2c.write(address, (const char *)cmd, 1);
result = i2c.write(address, (const char *)cmd, 1);
if (result !=0)
return MICROBIT_I2C_ERROR;
cmd[0] = 0x00;
cmd[1] = 0x00;
result = uBit.i2c.read(address, (char *)cmd, 2);
result = i2c.read(address, (char *)cmd, 2);
if (result !=0)
return MICROBIT_I2C_ERROR;
@ -153,8 +153,8 @@ int MicroBitCompass::heading()
calibrate();
// Precompute the tilt compensation parameters to improve readability.
float phi = uBit.accelerometer.getRollRadians();
float theta = uBit.accelerometer.getPitchRadians();
float phi = accelerometer.getRollRadians();
float theta = accelerometer.getPitchRadians();
float x = (float) getX(NORTH_EAST_DOWN);
float y = (float) getY(NORTH_EAST_DOWN);
float z = (float) getZ(NORTH_EAST_DOWN);
@ -314,7 +314,7 @@ int MicroBitCompass::configure()
break;
// Perform a power efficient sleep...
uBit.sleep(100);
MicroBit::sleep(100);
}
// Find the nearest sample rate to that specified.
@ -560,7 +560,7 @@ int MicroBitCompass::isIdleCallbackNeeded()
*/
MicroBitCompass::~MicroBitCompass()
{
uBit.removeIdleComponent(this);
fiber_remove_idle_component(this);
}
const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = {

View File

@ -9,6 +9,7 @@
#include "nrf_gpio.h"
const int timings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {1, 23, 70, 163, 351, 726, 1476, 2976};
MicroBitDisplay *MicroBitDisplay::defaultDisplay = NULL;
/**
* Constructor.
@ -24,7 +25,6 @@ const int timings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {1, 23, 70, 163, 351,
* @endcode
*/
MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) :
font(),
image(x*2,y)
{
//set pins as output
@ -47,7 +47,10 @@ MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) :
this->lightSensor = NULL;
uBit.flags |= MICROBIT_FLAG_DISPLAY_RUNNING;
if (!this->defaultDisplay)
this->defaultDisplay = this;
status |= MICROBIT_COMPONENT_RUNNING;
}
/**
@ -58,7 +61,7 @@ MicroBitDisplay::MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y) :
*/
void MicroBitDisplay::systemTick()
{
if(!(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING))
if(!(status & MICROBIT_COMPONENT_RUNNING))
return;
if(mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
@ -148,7 +151,7 @@ void MicroBitDisplay::render()
//timer does not have enough resolution for brightness of 1. 23.53 us
if(brightness != MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS && brightness > MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS)
renderTimer.attach_us(this, &MicroBitDisplay::renderFinish, (((brightness * 950) / (MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS)) * uBit.getTickPeriod()));
renderTimer.attach_us(this, &MicroBitDisplay::renderFinish, (((brightness * 950) / (MICROBIT_DISPLAY_MAXIMUM_BRIGHTNESS)) * scheduler_get_tick_period()));
//this will take around 23us to execute
if(brightness <= MICROBIT_DISPLAY_MINIMUM_BRIGHTNESS)
@ -934,16 +937,16 @@ void MicroBitDisplay::setDisplayMode(DisplayMode mode)
if(mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
{
//to reduce the artifacts on the display - increase the tick
if(uBit.getTickPeriod() != MICROBIT_LIGHT_SENSOR_TICK_PERIOD)
uBit.setTickPeriod(MICROBIT_LIGHT_SENSOR_TICK_PERIOD);
if(scheduler_get_tick_period() != MICROBIT_LIGHT_SENSOR_TICK_PERIOD)
scheduler_set_tick_period(MICROBIT_LIGHT_SENSOR_TICK_PERIOD);
}
if(this->mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE && mode != DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE)
{
//if we previously were in light sense mode - return to our default.
if(uBit.getTickPeriod() != MICROBIT_DEFAULT_TICK_PERIOD)
uBit.setTickPeriod(MICROBIT_DEFAULT_TICK_PERIOD);
if(scheduler_get_tick_period() != FIBER_TICK_PERIOD_MS)
scheduler_set_tick_period(FIBER_TICK_PERIOD_MS);
delete this->lightSensor;
@ -1000,10 +1003,10 @@ void MicroBitDisplay::rotateTo(DisplayRotation rotation)
*/
void MicroBitDisplay::enable()
{
if(!(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING))
if(!(status & MICROBIT_COMPONENT_RUNNING))
{
setBrightness(brightness);
uBit.flags |= MICROBIT_FLAG_DISPLAY_RUNNING; //set the display running flag
status |= MICROBIT_COMPONENT_RUNNING;
}
}
@ -1018,10 +1021,8 @@ void MicroBitDisplay::enable()
*/
void MicroBitDisplay::disable()
{
if(uBit.flags & MICROBIT_FLAG_DISPLAY_RUNNING)
{
uBit.flags &= ~MICROBIT_FLAG_DISPLAY_RUNNING; //unset the display running flag
}
if(status & MICROBIT_COMPONENT_RUNNING)
status &= ~MICROBIT_COMPONENT_RUNNING; //unset the display running flag
}
/**
@ -1053,7 +1054,22 @@ void MicroBitDisplay::setErrorTimeout(int iterations)
}
/**
* Displays "=(" and an accompanying status code infinitely.
* Displays "=(" and an accompanying status code on the default display.
* @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
*
* Example:
* @code
* uBit.display.error(20);
* @endcode
*/
void MicroBitDisplay::panic(int statusCode)
{
if(MicroBitDisplay::defaultDisplay)
defaultDisplay->error(statusCode);
}
/**
* Displays "=(" and an accompanying status code on the default display.
* @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
*
* Example:
@ -1063,15 +1079,14 @@ void MicroBitDisplay::setErrorTimeout(int iterations)
*/
void MicroBitDisplay::error(int statusCode)
{
extern InterruptIn resetButton;
DigitalIn resetButton(MICROBIT_PIN_BUTTON_RESET);
resetButton.mode(PullUp);
__disable_irq(); //stop ALL interrupts
if(statusCode < 0 || statusCode > 255)
statusCode = 0;
disable(); //relinquish PWMOut's control
uint8_t strobeRow = 0;
uint8_t strobeBitMsk = MICROBIT_DISPLAY_ROW_RESET;
uint8_t count = errorTimeout ? errorTimeout : 1;
@ -1122,10 +1137,8 @@ void MicroBitDisplay::error(int statusCode)
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, ~coldata<<4 & 0xF0); //set port 0 4-7
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F)); //set port 1 8-12
//set i to an obscene number.
i = 1000;
//burn cycles
i = 1000;
while(i>0)
{
// Check if the reset button has been pressed. Interrupts are disabled, so the normal method can't be relied upon...
@ -1155,7 +1168,7 @@ void MicroBitDisplay::error(int statusCode)
*/
void MicroBitDisplay::setFont(MicroBitFont font)
{
this->font = font;
MicroBitFont::setSystemFont(font);
}
/**
@ -1163,7 +1176,7 @@ void MicroBitDisplay::setFont(MicroBitFont font)
*/
MicroBitFont MicroBitDisplay::getFont()
{
return this->font;
return MicroBitFont::getSystemFont();
}
/**
@ -1201,5 +1214,5 @@ int MicroBitDisplay::readLightLevel()
*/
MicroBitDisplay::~MicroBitDisplay()
{
uBit.removeSystemComponent(this);
fiber_remove_system_component(this);
}

View File

@ -38,15 +38,15 @@ MicroBitEvent::MicroBitEvent()
}
/**
* Fires the represented event onto the message bus.
* Fires the represented event onto the default message bus.
*/
void MicroBitEvent::fire(MicroBitEventLaunchMode mode)
{
if (mode == CREATE_AND_QUEUE)
uBit.MessageBus.send(*this);
MicroBitMessageBus::defaultMessageBus->send(*this);
else if (mode == CREATE_AND_FIRE)
uBit.MessageBus.process(*this);
MicroBitMessageBus::defaultMessageBus->process(*this);
}
/**

View File

@ -14,27 +14,43 @@
* required to be defined here to allow persistence during context switches.
*/
Fiber *currentFiber = NULL; // The context in which the current fiber is executing.
Fiber *forkedFiber = NULL; // The context in which a newly created child fiber is executing.
Fiber *idleFiber = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks.
static Fiber *forkedFiber = NULL; // The context in which a newly created child fiber is executing.
static Fiber *idleFiber = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks.
/*
* Scheduler state.
*/
Fiber *runQueue = NULL; // The list of runnable fibers.
Fiber *sleepQueue = NULL; // The list of blocked fibers waiting on a fiber_sleep() operation.
Fiber *waitQueue = NULL; // The list of blocked fibers waiting on an event.
Fiber *fiberPool = NULL; // Pool of unused fibers, just waiting for a job to do.
static Fiber *runQueue = NULL; // The list of runnable fibers.
static Fiber *sleepQueue = NULL; // The list of blocked fibers waiting on a fiber_sleep() operation.
static Fiber *waitQueue = NULL; // The list of blocked fibers waiting on an event.
static Fiber *fiberPool = NULL; // Pool of unused fibers, just waiting for a job to do.
/*
* Time since power on. Measured in milliseconds.
* When stored as an unsigned long, this gives us approx 50 days between rollover, which is ample. :-)
*/
unsigned long ticks = 0;
static unsigned int tickPeriod = FIBER_TICK_PERIOD_MS;
/*
* Scheduler wide flags
*/
uint8_t fiber_flags = 0;
static uint8_t fiber_flags = 0;
/*
* Fibers may perform wait/notify semantics on events. If set, these operations will be permitted on this MicroBitMessageBus.
*/
static MicroBitMessageBus *messageBus = NULL;
// Array of components which are iterated during a system tick
static MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS];
// Array of components which are iterated during idle thread execution, isIdleCallbackNeeded is polled during a systemTick.
static MicroBitComponent* idleThreadComponents[MICROBIT_IDLE_COMPONENTS];
// Periodic callback interrupt
static Ticker fiberSchedulerTicker;
/**
* Utility function to add the currenty running fiber to the given queue.
@ -148,8 +164,12 @@ Fiber *getFiberContext()
*
* This function must be called once only from the main thread, and before any other Fiber operation.
*/
void scheduler_init()
void scheduler_init(MicroBitMessageBus *_messageBus)
{
// Store a reference to the messageBus provided.
// This parameter will be NULL if we're being run without a message bus.
messageBus = _messageBus;
// Create a new fiber context
currentFiber = getFiberContext();
@ -162,16 +182,61 @@ void scheduler_init()
idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04;
idleFiber->tcb.LR = (uint32_t) &idle_task;
if (messageBus)
{
// Register to receive events in the NOTIFY channel - this is used to implement wait-notify semantics
uBit.MessageBus.listen(MICROBIT_ID_NOTIFY, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
uBit.MessageBus.listen(MICROBIT_ID_NOTIFY_ONE, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus->listen(MICROBIT_ID_NOTIFY, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus->listen(MICROBIT_ID_NOTIFY_ONE, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
// Flag that we now have a scheduler running
uBit.flags |= MICROBIT_FLAG_SCHEDULER_RUNNING;
// register a period callback to drive the scheduler and any other registered components.
fiberSchedulerTicker.attach_us(scheduler_tick, tickPeriod * 1000);
fiber_flags |= MICROBIT_SCHEDULER_RUNNING;
}
/*
* Reconfigures the system wide timer to the given period in milliseconds.
*
* @param speedMs the new period of the timer in milliseconds
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if speedMs < 1
*
* @note this will also modify the value that is added to ticks in MiroBitFiber:scheduler_tick()
*/
int scheduler_set_tick_period(int speedMs)
{
if(speedMs < 1)
return MICROBIT_INVALID_PARAMETER;
tickPeriod = speedMs;
fiberSchedulerTicker.detach();
fiberSchedulerTicker.attach_us(scheduler_tick, tickPeriod * 1000);
return MICROBIT_OK;
}
/*
* Returns the currently used tick speed in milliseconds
*/
int scheduler_get_tick_period()
{
return tickPeriod;
}
/**
* Timer callback. Called from interrupt context, once every FIBER_TICK_PERIOD_MS milliseconds.
* Determines if the fiber scheduler is operational.
* @return 1 if the fber scheduler is running, 0 otherwise.
*/
int fiber_scheduler_running()
{
if (fiber_flags & MICROBIT_SCHEDULER_RUNNING)
return 1;
return 0;
}
/**
* Timer callback. Called from interrupt context, once every FIBER_TICK_PERIOD_MS milliseconds, by default.
* Simply checks to determine if any fibers blocked on the sleep queue need to be woken up
* and made runnable.
*/
@ -181,7 +246,7 @@ void scheduler_tick()
Fiber *t;
// increment our real-time counter.
ticks += uBit.getTickPeriod();
ticks += scheduler_get_tick_period();
// Check the sleep queue, and wake up any fibers as necessary.
while (f != NULL)
@ -197,12 +262,19 @@ void scheduler_tick()
f = t;
}
// Update any components registered for a callback
for(int i = 0; i < MICROBIT_SYSTEM_COMPONENTS; i++)
if(systemTickComponents[i] != NULL)
systemTickComponents[i]->systemTick();
}
/**
* Event callback. Called from the message bus whenever an event is raised.
* Checks to determine if any fibers blocked on the wait queue need to be woken up
* and made runnable due to the event.
* @param evt The event to be processed.
* @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not associated with a MicroBitMessageBus.
*/
void scheduler_event(MicroBitEvent evt)
{
@ -210,6 +282,12 @@ void scheduler_event(MicroBitEvent evt)
Fiber *t;
int notifyOneComplete = 0;
// This should never happen.
// It is however, safe to simply ignore any events provided, ans if no messageBus if recorded,
// no fibers are permitted to block on events.
if (messageBus == NULL)
return;
// Check the wait queue, and wake up any fibers as necessary.
while (f != NULL)
{
@ -244,7 +322,7 @@ void scheduler_event(MicroBitEvent evt)
// Unregister this event, as we've woken up all the fibers with this match.
if (evt.source != MICROBIT_ID_NOTIFY && evt.source != MICROBIT_ID_NOTIFY_ONE)
uBit.MessageBus.ignore(evt.source, evt.value, scheduler_event);
messageBus->ignore(evt.source, evt.value, scheduler_event);
}
@ -291,7 +369,7 @@ void fiber_sleep(unsigned long t)
/**
* Blocks the calling thread until the specified event is raised.
* The calling thread will be immediatley descheduled, and placed onto a
* The calling thread will be immediately descheduled, and placed onto a
* wait queue until the requested event is received.
*
* n.b. the fiber will not be be made runnable until after the event is raised, but there
@ -299,11 +377,15 @@ void fiber_sleep(unsigned long t)
*
* @param id The ID field of the event to listen for (e.g. MICROBIT_ID_BUTTON_A)
* @param value The VALUE of the event to listen for (e.g. MICROBIT_BUTTON_EVT_CLICK)
* @return MICROBIT_OK, or MICROBIT_NOT_SUPPORTED if the fiber scheduler is not associated with a MicroBitMessageBus.
*/
void fiber_wait_for_event(uint16_t id, uint16_t value)
int fiber_wait_for_event(uint16_t id, uint16_t value)
{
Fiber *f = currentFiber;
if (messageBus == NULL)
return MICROBIT_NOT_SUPPORTED;
// Sleep is a blocking call, so if we'r ein a fork on block context,
// it's time to spawn a new fiber...
if (currentFiber->flags & MICROBIT_FIBER_FLAG_FOB)
@ -330,10 +412,12 @@ void fiber_wait_for_event(uint16_t id, uint16_t value)
// Register to receive this event, so we can wake up the fiber when it happens.
// Special case for teh notify channel, as we always stay registered for that.
if (id != MICROBIT_ID_NOTIFY && id != MICROBIT_ID_NOTIFY_ONE)
uBit.MessageBus.listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus->listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
// Finally, enter the scheduler.
schedule();
return MICROBIT_OK;
}
/**
@ -643,7 +727,7 @@ void schedule()
// We're in a normal scheduling context, so perform a round robin algorithm across runnable fibers.
// OK - if we've nothing to do, then run the IDLE task (power saving sleep)
if (runQueue == NULL || fiber_flags & MICROBIT_FLAG_DATA_READY)
if (runQueue == NULL)
currentFiber = idleFiber;
else if (currentFiber->queue == &runQueue)
@ -667,7 +751,7 @@ void schedule()
{
idle();
}
while (runQueue == NULL || fiber_flags & MICROBIT_FLAG_DATA_READY);
while (runQueue == NULL);
// Switch to a non-idle fiber.
// If this fiber is the same as the old one then there'll be no switching at all.
@ -702,6 +786,91 @@ void schedule()
}
/**
* Add a component to to the collection of those invoked when the scheduler's periodic timer is triggered.
* The given component is called on each interrupt, within interrupt context.
*
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
* @note this will be converted into a dynamic list of components
*/
int fiber_add_system_component(MicroBitComponent *component)
{
int i = 0;
while(systemTickComponents[i] != NULL && i < MICROBIT_SYSTEM_COMPONENTS)
i++;
if(i == MICROBIT_SYSTEM_COMPONENTS)
return MICROBIT_NO_RESOURCES;
systemTickComponents[i] = component;
return MICROBIT_OK;
}
/**
* remove a component from the array of components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added.
* @note this will be converted into a dynamic list of components
*/
int fiber_remove_system_component(MicroBitComponent *component)
{
int i = 0;
while(systemTickComponents[i] != component && i < MICROBIT_SYSTEM_COMPONENTS)
i++;
if(i == MICROBIT_SYSTEM_COMPONENTS)
return MICROBIT_INVALID_PARAMETER;
systemTickComponents[i] = NULL;
return MICROBIT_OK;
}
/**
* add a component to the array of components which invocate the systemTick member function during a systemTick
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
* @note this will be converted into a dynamic list of components
*/
int fiber_add_idle_component(MicroBitComponent *component)
{
int i = 0;
while(idleThreadComponents[i] != NULL && i < MICROBIT_IDLE_COMPONENTS)
i++;
if(i == MICROBIT_IDLE_COMPONENTS)
return MICROBIT_NO_RESOURCES;
idleThreadComponents[i] = component;
return MICROBIT_OK;
}
/**
* remove a component from the array of components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added.
* @note this will be converted into a dynamic list of components
*/
int fiber_remove_idle_component(MicroBitComponent *component)
{
int i = 0;
while(idleThreadComponents[i] != component && i < MICROBIT_IDLE_COMPONENTS)
i++;
if(i == MICROBIT_IDLE_COMPONENTS)
return MICROBIT_INVALID_PARAMETER;
idleThreadComponents[i] = NULL;
return MICROBIT_OK;
}
/**
* Set of tasks to perform when idle.
* Service any background tasks that are required, and attmept power efficient sleep.
@ -709,17 +878,14 @@ void schedule()
void idle()
{
// Service background tasks
uBit.systemTasks();
for(int i = 0; i < MICROBIT_IDLE_COMPONENTS; i++)
if(idleThreadComponents[i] != NULL)
idleThreadComponents[i]->idleTick();
// If the above did create any useful work, enter power efficient sleep.
if(scheduler_runqueue_empty())
{
if (uBit.ble)
uBit.ble->waitForEvent();
else
__WFI();
}
}
/**
* IDLE task.
* Only scheduled for execution when the runqueue is empty.

View File

@ -29,6 +29,7 @@ const unsigned char pendolino3[475] = {
const unsigned char* MicroBitFont::defaultFont = pendolino3;
MicroBitFont MicroBitFont::systemFont = MicroBitFont(defaultFont, MICROBIT_FONT_ASCII_END);
/**
* Constructor.
@ -53,3 +54,21 @@ MicroBitFont::MicroBitFont()
this->characters = defaultFont;
this->asciiEnd = MICROBIT_FONT_ASCII_END;
}
/**
* Changes the current system font to the one specified.
* @param font the new font that will be used to render characters..
*/
void MicroBitFont::setSystemFont(MicroBitFont font)
{
MicroBitFont::systemFont = font;
}
/**
* Retreives the font object used for rendering characters on the display.
*/
MicroBitFont MicroBitFont::getSystemFont()
{
return MicroBitFont::systemFont;
}

View File

@ -362,7 +362,7 @@ void *microbit_malloc(size_t size)
#endif
#if CONFIG_ENABLED(MICROBIT_PANIC_HEAP_FULL)
panic(MICROBIT_OOM);
MicroBitDisplay::panic(MICROBIT_OOM);
#endif
return NULL;

View File

@ -519,7 +519,7 @@ int MicroBitImage::print(char c, int16_t x, int16_t y)
unsigned char v;
int x1, y1;
MicroBitFont font = uBit.display.getFont();
MicroBitFont font = MicroBitFont::getSystemFont();
// Sanity check. Silently ignore anything out of bounds.
if (x >= getWidth() || y >= getHeight() || c < MICROBIT_FONT_ASCII_START || c > font.asciiEnd)

View File

@ -82,7 +82,8 @@ MicroBitLightSensor::MicroBitLightSensor() : analogTrigger()
{
this->chan = 0;
uBit.MessageBus.listen(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing, MESSAGE_BUS_LISTENER_IMMEDIATE);
if (MicroBitMessageBus::defaultMessageBus)
MicroBitMessageBus::defaultMessageBus->listen(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing, MESSAGE_BUS_LISTENER_IMMEDIATE);
this->sensePin = NULL;
}
@ -143,5 +144,6 @@ int MicroBitLightSensor::read()
*/
MicroBitLightSensor::~MicroBitLightSensor()
{
uBit.MessageBus.ignore(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing);
if (MicroBitMessageBus::defaultMessageBus)
MicroBitMessageBus::defaultMessageBus->ignore(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing);
}

View File

@ -6,6 +6,8 @@
#include "MicroBit.h"
MicroBitMessageBus* MicroBitMessageBus::defaultMessageBus = NULL;
/**
* Constructor.
* Create a new Message Bus.
@ -16,6 +18,9 @@ MicroBitMessageBus::MicroBitMessageBus()
this->evt_queue_head = NULL;
this->evt_queue_tail = NULL;
this->queueLength = 0;
if(MicroBitMessageBus::defaultMessageBus == NULL)
MicroBitMessageBus::defaultMessageBus = this;
}
/**
@ -594,5 +599,5 @@ MicroBitListener* MicroBitMessageBus::elementAt(int n)
*/
MicroBitMessageBus::~MicroBitMessageBus()
{
uBit.removeIdleComponent(this);
fiber_remove_idle_component(this);
}

View File

@ -23,15 +23,15 @@
* MICROBIT_BUTTON_EVT_HOLD
* @endcode
*/
MicroBitMultiButton::MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2)
MicroBitMultiButton::MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t button2, MicroBitMessageBus &messageBus)
{
this->id = id;
this->button1 = button1;
this->button2 = button2;
this->eventConfiguration = MICROBIT_BUTTON_SIMPLE_EVENTS;
uBit.MessageBus.listen(button1, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
uBit.MessageBus.listen(button2, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(button1, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(button2, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
uint16_t MicroBitMultiButton::otherSubButton(uint16_t b)
@ -150,7 +150,6 @@ void MicroBitMultiButton::setEventConfiguration(MicroBitButtonEventConfiguration
{
this->eventConfiguration = config;
}
void MicroBitMultiButton::onButtonEvent(MicroBitEvent evt)
{
int button = evt.source;

View File

@ -138,9 +138,13 @@ MicroBitImage MicroBitSerial::readImage(int width, int height)
*/
void MicroBitSerial::sendDisplayState()
{
return;
/*
for(int i = 0; i < MICROBIT_DISPLAY_HEIGHT; i++)
for(int j = 0; j < MICROBIT_DISPLAY_WIDTH; j++)
_putc(uBit.display.image.getPixelValue(j,i));
*/
}
/**
@ -153,12 +157,14 @@ void MicroBitSerial::sendDisplayState()
*/
void MicroBitSerial::readDisplayState()
{
/*
for(int i = 0; i < MICROBIT_DISPLAY_HEIGHT; i++)
for(int j = 0; j < MICROBIT_DISPLAY_WIDTH; j++)
{
int c = _getc();
uBit.display.image.setPixelValue(j,i,c);
}
*/
}
ssize_t MicroBitSerial::readChars(void* buffer, size_t length, char eof) {

View File

@ -1,86 +1,18 @@
#include "MicroBit.h"
#ifdef UBIT_SUPERMAIN
MicroBit uBit;
InterruptIn resetButton(MICROBIT_PIN_BUTTON_RESET);
extern char* MICROBIT_BLE_DEVICE_NAME;
int main()
{
// Bring up soft reset button.
resetButton.mode(PullUp);
resetButton.fall(microbit_reset);
#if CONFIG_ENABLED(MICROBIT_DBG)
// For diagnostics. Gives time to open the console window. :-)
for (int i=3; i>0; i--)
{
uBit.serial.printf("=== SUPERMAIN: Starting in %d ===\n", i);
wait(1.0);
}
uBit.serial.printf("micro:bit runtime DAL version %s\n", MICROBIT_DAL_VERSION);
uBit.serial.printf("micro:bit runtime version %s\n", MICROBIT_DAL_VERSION);
#endif
// Bring up our nested heap allocator.
microbit_heap_init();
// Bring up fiber scheduler
scheduler_init();
// Bring up random number generator, BLE, display and system timers.
uBit.init();
// Provide time for all threaded initialisers to complete.
uBit.sleep(100);
//check our persistent storage for compassCalibrationData
MicroBitStorage s = MicroBitStorage();
MicroBitConfigurationBlock *b = s.getConfigurationBlock();
//if we have some calibrated data, calibrate the compass!
if(b->magic == MICROBIT_STORAGE_CONFIG_MAGIC)
{
if(b->compassCalibrationData != CompassSample(0,0,0))
uBit.compass.setCalibration(b->compassCalibrationData);
}
delete b;
#if CONFIG_ENABLED(MICROBIT_BLE_PAIRING_MODE)
// Test if we need to enter BLE pairing mode...
int i=0;
while (uBit.buttonA.isPressed() && uBit.buttonB.isPressed() && i<10)
{
uBit.sleep(100);
i++;
if (i == 10)
{
// Start the BLE stack, if it isn't already running.
if (!uBit.ble)
{
uBit.bleManager.init(uBit.getName(), uBit.getSerial(), true);
uBit.ble = uBit.bleManager.ble;
}
// Enter pairing mode, using the LED matrix for any necessary pairing operations
uBit.bleManager.pairingMode(uBit.display);
}
}
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED)
// Start the BLE stack, if it isn't already running.
if (!uBit.ble)
{
uBit.bleManager.init(uBit.getName(), uBit.getSerial(), false);
uBit.ble = uBit.bleManager.ble;
}
#endif
// Start the user application
app_main();
// If app_main exits, there may still be other fibers running, registered event handlers etc.
@ -91,3 +23,5 @@ int main()
// We should never get here, but just in case.
while(1);
}
#endif

View File

@ -27,6 +27,7 @@
#endif
#include "nrf_soc.h"
#include "nrf_sdm.h"
/*
* Return to our predefined compiler settings.
@ -56,7 +57,9 @@ MicroBitThermometer::MicroBitThermometer(uint16_t id)
this->samplePeriod = MICROBIT_THERMOMETER_PERIOD;
this->sampleTime = 0;
uBit.addIdleComponent(this);
// If we're running under a fiber scheduer, register ourselves for a periodic callback to keep our data up to date.
// Otherwise, we do just do this on demand, when polled through our read() interface.
fiber_add_idle_component(this);
}
/**
@ -130,12 +133,15 @@ int MicroBitThermometer::getPeriod()
void MicroBitThermometer::updateTemperature()
{
int32_t processorTemperature;
uint8_t sd_enabled;
// For now, we just rely on the nrf senesor to be the most accurate.
// The compass module also has a temperature sensor, and has the lowest power consumption, so will run the cooler...
// ...however it isn't trimmed for accuracy during manufacture, so requires calibration.
if (uBit.ble)
sd_softdevice_is_enabled(&sd_enabled);
if (sd_enabled)
{
// If Bluetooth is enabled, we need to go through the Nordic software to safely do this
sd_temp_get(&processorTemperature);

View File

@ -17,7 +17,7 @@ static inline bool isReadOnlyInline(RefCounted *t)
// Do some sanity checking while we're here
if (refCount == 1 || // object should have been deleted
(refCount & 1) == 0) // refCount doesn't look right
uBit.panic(MICROBIT_HEAP_ERROR);
MicroBitDisplay::panic(MICROBIT_HEAP_ERROR);
// Not read only
return false;

View File

@ -13,8 +13,8 @@
* Create a representation of the AccelerometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) :
ble(_ble)
MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble, MicroBitAccelerometer &_accelerometer, MicroBitMessageBus &messageBus) :
ble(_ble), accelerometer(_accelerometer)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic accelerometerDataCharacteristic(MicroBitAccelerometerServiceDataUUID, (uint8_t *)accelerometerDataCharacteristicBuffer, 0,
@ -28,7 +28,7 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) :
accelerometerDataCharacteristicBuffer[0] = 0;
accelerometerDataCharacteristicBuffer[1] = 0;
accelerometerDataCharacteristicBuffer[2] = 0;
accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod();
accelerometerPeriodCharacteristicBuffer = accelerometer.getPeriod();
// Set default security requirements
accelerometerDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
@ -46,7 +46,7 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) :
ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitAccelerometerService::onDataWritten);
uBit.MessageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
/**
@ -57,11 +57,11 @@ void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams *
if (params->handle == accelerometerPeriodCharacteristicHandle && params->len >= sizeof(accelerometerPeriodCharacteristicBuffer))
{
accelerometerPeriodCharacteristicBuffer = *((uint16_t *)params->data);
uBit.accelerometer.setPeriod(accelerometerPeriodCharacteristicBuffer);
accelerometer.setPeriod(accelerometerPeriodCharacteristicBuffer);
// The accelerometer will choose the nearest period to that requested that it can support
// Read back the ACTUAL period it is using, and report this back.
accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod();
accelerometerPeriodCharacteristicBuffer = accelerometer.getPeriod();
ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer));
}
}
@ -73,9 +73,9 @@ void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent)
{
if (ble.getGapState().connected)
{
accelerometerDataCharacteristicBuffer[0] = uBit.accelerometer.getX();
accelerometerDataCharacteristicBuffer[1] = uBit.accelerometer.getY();
accelerometerDataCharacteristicBuffer[2] = uBit.accelerometer.getZ();
accelerometerDataCharacteristicBuffer[0] = accelerometer.getX();
accelerometerDataCharacteristicBuffer[1] = accelerometer.getY();
accelerometerDataCharacteristicBuffer[2] = accelerometer.getZ();
ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer));
}

View File

@ -1,7 +1,7 @@
#include "MicroBit.h"
/* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ
/* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ.
* If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
* The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
* as a compatability option, but does not support the options used...
@ -180,10 +180,10 @@ void MicroBitBLEManager::advertise()
*
* Example:
* @code
* uBit.init();
* bleManager.init("zevug");
* @endcode
*/
void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, bool enableBonding)
void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber, MicroBitMessageBus& messageBus, bool enableBonding)
{
ManagedString BLEName("BBC micro:bit");
this->deviceName = deviceName;
@ -254,42 +254,11 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
// Configure the radio at our default power level
setTransmitPower(MICROBIT_BLE_DEFAULT_TX_POWER);
// Bring up any configured auxiliary services.
#if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE)
// Bring up core BLE services.
new MicroBitDFUService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE)
DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, serialNumber.toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION);
#endif
new MicroBitEventService(*ble, messageBus);
#if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE)
new MicroBitEventService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_LED_SERVICE)
new MicroBitLEDService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE)
new MicroBitAccelerometerService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_MAGNETOMETER_SERVICE)
new MicroBitMagnetometerService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_BUTTON_SERVICE)
new MicroBitButtonService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_IO_PIN_SERVICE)
new MicroBitIOPinService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_TEMPERATURE_SERVICE)
new MicroBitTemperatureService(*ble);
#endif
// Configure for high speed mode where possible.
Gap::ConnectionParams_t fast;
@ -379,7 +348,7 @@ void MicroBitBLEManager::pairingComplete(bool success)
if(success)
{
this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
uBit.addIdleComponent(this);
fiber_add_idle_component(this);
}
}
@ -392,14 +361,17 @@ void MicroBitBLEManager::idleTick()
if (ble)
ble->disconnect(pairingHandle, Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF);
uBit.removeIdleComponent(this);
fiber_remove_idle_component(this);
}
/**
* Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
* of the micro:bit in cases where BLE is disabled during normal operation.
*
* @param display A reference to the display on which to show usage notes and pass code information.
* @prarm authorizationButton The button to use to authorise a pairing request.
*/
void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
void MicroBitBLEManager::pairingMode(MicroBitDisplay& display, MicroBitButton& authorisationButton)
{
ManagedString namePrefix("BBC micro:bit [");
ManagedString namePostfix("]");
@ -464,7 +436,7 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
if (brightness >= 255)
fadeDirection = 0;
if (uBit.buttonA.isPressed())
if (authorisationButton.isPressed())
{
pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
@ -478,15 +450,15 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
for (int i=0; i<passKey.length(); i++)
{
display.image.print(passKey.charAt(i),0,0);
uBit.sleep(800);
fiber_sleep(800);
display.clear();
uBit.sleep(200);
fiber_sleep(200);
if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
break;
}
uBit.sleep(1000);
fiber_sleep(1000);
}
if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
@ -495,7 +467,7 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
{
MicroBitImage tick("0,0,0,0,0\n0,0,0,0,255\n0,0,0,255,0\n255,0,255,0,0\n0,255,0,0,0\n");
display.print(tick,0,0,0);
uBit.sleep(15000);
fiber_sleep(15000);
timeInPairingMode = MICROBIT_BLE_PAIRING_TIMEOUT * 30;
/*
@ -519,7 +491,7 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
}
}
uBit.sleep(30);
MicroBit::sleep(100);
timeInPairingMode++;
if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)

View File

@ -13,7 +13,7 @@
* Create a representation of the ButtonService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) :
MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble, MicroBitMessageBus &messageBus) :
ble(_ble)
{
// Create the data structures that represent each of our characteristics in Soft Device.
@ -43,8 +43,8 @@ MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) :
ble.gattServer().write(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
ble.gattServer().write(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
uBit.MessageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonAUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonBUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonAUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonBUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
}

View File

@ -72,11 +72,12 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
{
if(params->len > 0 && params->data[0] == MICROBIT_DFU_OPCODE_START_DFU)
{
uBit.display.stopAnimation();
uBit.display.clear();
// TODO: Raise a SYSTEM event here.
//uBit.display.stopAnimation();
//uBit.display.clear();
#if CONFIG_ENABLED(MICROBIT_DBG)
uBit.serial.printf(" ACTIVATING BOOTLOADER.\n");
printf(" ACTIVATING BOOTLOADER.\n");
#endif
// Perform an explicit disconnection to assist our peer to reconnect to the DFU service

View File

@ -12,8 +12,8 @@
* Create a representation of the EventService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitEventService::MicroBitEventService(BLEDevice &_ble) :
ble(_ble)
MicroBitEventService::MicroBitEventService(BLEDevice &_ble, MicroBitMessageBus &_messageBus) :
ble(_ble),messageBus(_messageBus)
{
GattCharacteristic microBitEventCharacteristic(MicroBitEventServiceMicroBitEventCharacteristicUUID, (uint8_t *)&microBitEventBuffer, 0, sizeof(EventServiceEvent),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
@ -51,7 +51,7 @@ MicroBitEventService::MicroBitEventService(BLEDevice &_ble) :
ble.onDataWritten(this, &MicroBitEventService::onDataWritten);
uBit.addIdleComponent(this);
fiber_add_idle_component(this);
}
@ -79,7 +79,7 @@ void MicroBitEventService::onDataWritten(const GattWriteCallbackParams *params)
// Read and register for all the events given...
while (len >= 4)
{
uBit.MessageBus.listen(e->type, e->reason, this, &MicroBitEventService::onMicroBitEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(e->type, e->reason, this, &MicroBitEventService::onMicroBitEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
len-=4;
e++;
@ -111,7 +111,7 @@ void MicroBitEventService::idleTick()
{
if (!ble.getGapState().connected && messageBusListenerOffset >0) {
messageBusListenerOffset = 0;
uBit.MessageBus.ignore(MICROBIT_ID_ANY, MICROBIT_EVT_ANY, this, &MicroBitEventService::onMicroBitEvent);
messageBus.ignore(MICROBIT_ID_ANY, MICROBIT_EVT_ANY, this, &MicroBitEventService::onMicroBitEvent);
}
}
@ -125,7 +125,7 @@ void MicroBitEventService::onRequirementsRead(GattReadAuthCallbackParams *params
{
// Walk through the lsit of message bus listeners.
// We send one at a time, and our client can keep reading from this characterisitic until we return an emtpy value.
MicroBitListener *l = uBit.MessageBus.elementAt(messageBusListenerOffset++);
MicroBitListener *l = messageBus.elementAt(messageBusListenerOffset++);
if (l != NULL)
{

View File

@ -13,8 +13,8 @@
* Create a representation of the IOPinService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) :
ble(_ble)
MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble, MicroBitIO &_io) :
ble(_ble), io(_io)
{
// Create the AD characteristic, that defines whether each pin is treated as analogue or digital
GattCharacteristic ioPinServiceADCharacteristic(MicroBitIOPinServiceADConfigurationUUID, (uint8_t *)&ioPinServiceADCharacteristicBuffer, 0, sizeof(ioPinServiceADCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
@ -48,7 +48,7 @@ MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) :
ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitIOPinService::onDataWritten);
uBit.addIdleComponent(this);
fiber_add_idle_component(this);
}
/**
@ -113,10 +113,12 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
{
if(isDigital(i) && isInput(i))
MicroBitIOPins[i]->getDigitalValue();
io.pin[i].getDigitalValue();
//MicroBitIOPins[i]->getDigitalValue();
if(isAnalog(i) && isInput(i))
MicroBitIOPins[i]->getAnalogValue();
io.pin[i].getAnalogValue();
//MicroBitIOPins[i]->getAnalogValue();
}
}
@ -133,10 +135,12 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
{
if(isDigital(i) && isInput(i))
MicroBitIOPins[i]->getDigitalValue();
io.pin[i].getDigitalValue();
//MicroBitIOPins[i]->getDigitalValue();
if(isAnalog(i) && isInput(i))
MicroBitIOPins[i]->getAnalogValue();
io.pin[i].getAnalogValue();
//MicroBitIOPins[i]->getAnalogValue();
}
}
@ -152,9 +156,11 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
if (isOutput(data->pin))
{
if (isDigital(data->pin))
MicroBitIOPins[data->pin]->setDigitalValue(data->value);
io.pin[data->pin].setDigitalValue(data->value);
//MicroBitIOPins[data->pin]->setDigitalValue(data->value);
else
MicroBitIOPins[data->pin]->setAnalogValue(data->value*4);
io.pin[data->pin].setAnalogValue(data->value*4);
//MicroBitIOPins[data->pin]->setAnalogValue(data->value*4);
}
data++;
@ -182,9 +188,11 @@ void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params)
uint8_t value;
if (isDigital(i))
value = MicroBitIOPins[i]->getDigitalValue();
value = io.pin[i].getDigitalValue();
//value = MicroBitIOPins[i]->getDigitalValue();
else
value = MicroBitIOPins[i]->getAnalogValue();
value = io.pin[i].getAnalogValue();
//value = MicroBitIOPins[i]->getAnalogValue();
ioPinServiceIOData[i] = value;
ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
@ -224,9 +232,11 @@ void MicroBitIOPinService::idleTick()
uint8_t value;
if (isDigital(i))
value = MicroBitIOPins[i]->getDigitalValue();
value = io.pin[i].getDigitalValue();
//value = MicroBitIOPins[i]->getDigitalValue();
else
value = MicroBitIOPins[i]->getAnalogValue();
value = io.pin[i].getAnalogValue();
//value = MicroBitIOPins[i]->getAnalogValue();
// If the data has changed, send an update.
if (value != ioPinServiceIOData[i])
@ -265,6 +275,7 @@ const uint8_t MicroBitIOPinServiceDataUUID[] = {
0xe9,0x5d,0x8d,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
/*
MicroBitPin * const MicroBitIOPins[] = {
&uBit.io.P0,
&uBit.io.P1,
@ -286,5 +297,5 @@ MicroBitPin * const MicroBitIOPins[] = {
&uBit.io.P19,
&uBit.io.P20
};
*/

View File

@ -13,8 +13,8 @@
* Create a representation of the LEDService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble) :
ble(_ble),
MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble, MicroBitDisplay &_display) :
ble(_ble), display(_display),
matrixCharacteristic(MicroBitLEDServiceMatrixUUID, (uint8_t *)&matrixCharacteristicBuffer, 0, sizeof(matrixCharacteristicBuffer),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)
{
@ -64,7 +64,7 @@ void MicroBitLEDService::onDataWritten(const GattWriteCallbackParams *params)
{
for (int y=0; y<params->len; y++)
for (int x=0; x<5; x++)
uBit.display.image.setPixelValue(x, y, (data[y] & (0x01 << (4-x))) ? 255 : 0);
display.image.setPixelValue(x, y, (data[y] & (0x01 << (4-x))) ? 255 : 0);
}
else if (params->handle == textCharacteristicHandle)
@ -74,7 +74,7 @@ void MicroBitLEDService::onDataWritten(const GattWriteCallbackParams *params)
ManagedString s((char *)params->data, params->len);
// Start the string scrolling and we're done.
uBit.display.scrollAsync(s, (int) scrollingSpeedCharacteristicBuffer);
display.scrollAsync(s, (int) scrollingSpeedCharacteristicBuffer);
}
else if (params->handle == scrollingSpeedCharacteristicHandle && params->len >= sizeof(scrollingSpeedCharacteristicBuffer))
@ -98,7 +98,7 @@ void MicroBitLEDService::onDataRead(GattReadAuthCallbackParams *params)
for (int x=0; x<5; x++)
{
if (uBit.display.image.getPixelValue(x, y))
if (display.image.getPixelValue(x, y))
matrixCharacteristicBuffer[y] |= 0x01 << (4-x);
}
}

View File

@ -13,8 +13,8 @@
* Create a representation of the MagnetometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) :
ble(_ble)
MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble, MicroBitCompass &_compass, MicroBitMessageBus &messageBus) :
ble(_ble), compass(_compass)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic magnetometerDataCharacteristic(MicroBitMagnetometerServiceDataUUID, (uint8_t *)magnetometerDataCharacteristicBuffer, 0,
@ -32,7 +32,7 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) :
magnetometerDataCharacteristicBuffer[1] = 0;
magnetometerDataCharacteristicBuffer[2] = 0;
magnetometerBearingCharacteristicBuffer = 0;
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
magnetometerPeriodCharacteristicBuffer = compass.getPeriod();
// Set default security requirements
magnetometerDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
@ -53,8 +53,8 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) :
ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitMagnetometerService::onDataWritten);
uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded);
messageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded);
}
/**
@ -76,17 +76,18 @@ void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent)
{
if (ble.getGapState().connected)
{
magnetometerDataCharacteristicBuffer[0] = uBit.compass.getX();
magnetometerDataCharacteristicBuffer[1] = uBit.compass.getY();
magnetometerDataCharacteristicBuffer[2] = uBit.compass.getZ();
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
magnetometerDataCharacteristicBuffer[0] = compass.getX();
magnetometerDataCharacteristicBuffer[1] = compass.getY();
magnetometerDataCharacteristicBuffer[2] = compass.getZ();
magnetometerBearingCharacteristicBuffer = (uint16_t) compass.heading();
magnetometerPeriodCharacteristicBuffer = compass.getPeriod();
ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer));
if (uBit.compass.isCalibrated())
if (compass.isCalibrated())
{
magnetometerBearingCharacteristicBuffer = (uint16_t) uBit.compass.heading();
magnetometerBearingCharacteristicBuffer = (uint16_t) compass.heading();
ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerBearingCharacteristicBuffer));
}
}
@ -100,11 +101,11 @@ void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent)
void MicroBitMagnetometerService::samplePeriodUpdateNeeded(MicroBitEvent)
{
// Reconfigure the compass. This might take a while...
uBit.compass.setPeriod(magnetometerPeriodCharacteristicBuffer);
compass.setPeriod(magnetometerPeriodCharacteristicBuffer);
// The compass will choose the nearest sample period to that we've specified.
// Read the ACTUAL sample period back.
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
magnetometerPeriodCharacteristicBuffer = compass.getPeriod();
// Ensure this is reflected in our BLE connection.
ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));

View File

@ -47,7 +47,7 @@ extern "C" void RADIO_IRQHandler(void)
{
uint8_t sample = NRF_RADIO->RSSISAMPLE;
uBit.radio.setRSSI(sample);
MicroBitRadio::instance->setRSSI(sample);
}
// Start listening and wait for the END event
@ -61,7 +61,7 @@ extern "C" void RADIO_IRQHandler(void)
* Initialise the MicroBitRadio. Note that this class is demand activated, so most resources are only committed
* if send/recv or event registrations calls are made.
*/
MicroBitRadio::MicroBitRadio(uint16_t id) : datagram()
MicroBitRadio::MicroBitRadio(uint16_t id) : datagram(*this), event (*this)
{
this->id = id;
this->status = 0;
@ -101,7 +101,7 @@ int MicroBitRadio::setTransmitPower(int power)
*/
int MicroBitRadio::setFrequencyBand(int band)
{
if (uBit.ble)
if (ble_running())
return MICROBIT_NOT_SUPPORTED;
if (band < 0 || band > 100)
@ -212,7 +212,7 @@ int MicroBitRadio::enable()
return MICROBIT_OK;
// Only attempt to enable this radio mode if BLE is disabled.
if (uBit.ble)
if (ble_running())
return MICROBIT_NOT_SUPPORTED;
// If this is the first time we've been enable, allocate out receive buffers.
@ -289,7 +289,7 @@ int MicroBitRadio::enable()
NRF_RADIO->TASKS_START = 1;
// register ourselves for a callback event, in order to empty the receive queue.
uBit.addIdleComponent(this);
fiber_add_idle_component(this);
// Done. Record that our RADIO is configured.
status |= MICROBIT_RADIO_STATUS_INITIALISED;
@ -304,7 +304,7 @@ int MicroBitRadio::enable()
int MicroBitRadio::disable()
{
// Only attempt to enable.disable the radio if the protocol is alreayd running.
if (uBit.ble)
if (ble_running())
return MICROBIT_NOT_SUPPORTED;
if (!(status & MICROBIT_RADIO_STATUS_INITIALISED))
@ -318,7 +318,7 @@ int MicroBitRadio::disable()
while(NRF_RADIO->EVENTS_DISABLED == 0);
// deregister ourselves from the callback event used to empty the receive queue.
uBit.removeIdleComponent(this);
fiber_remove_idle_component(this);
return MICROBIT_OK;
}
@ -331,7 +331,7 @@ int MicroBitRadio::disable()
*/
int MicroBitRadio::setGroup(uint8_t group)
{
if (uBit.ble)
if (ble_running())
return MICROBIT_NOT_SUPPORTED;
// Record our group id locally
@ -422,7 +422,7 @@ FrameBuffer* MicroBitRadio::recv()
*/
int MicroBitRadio::send(FrameBuffer *buffer)
{
if (uBit.ble)
if (ble_running())
return MICROBIT_NOT_SUPPORTED;
if (buffer == NULL)

View File

@ -14,10 +14,12 @@
/**
* Constructor.
*
* @param radio The underlying radio module used to send and receive data.
*/
MicroBitRadioDatagram::MicroBitRadioDatagram()
MicroBitRadioDatagram::MicroBitRadioDatagram(MicroBitRadio &r) : radio(r)
{
rxQueue = NULL;
this->rxQueue = NULL;
}
/**
@ -90,7 +92,7 @@ int MicroBitRadioDatagram::send(uint8_t *buffer, int len)
buf.protocol = MICROBIT_RADIO_PROTOCOL_DATAGRAM;
memcpy(buf.payload, buffer, len);
return uBit.radio.send(&buf);
return radio.send(&buf);
}
/**
@ -111,7 +113,7 @@ int MicroBitRadioDatagram::send(PacketBuffer data)
*/
void MicroBitRadioDatagram::packetReceived()
{
FrameBuffer *packet = uBit.radio.recv();
FrameBuffer *packet = radio.recv();
int queueDepth = 0;
// We add to the tail of the queue to preserve causal ordering.

View File

@ -15,15 +15,34 @@
/**
* Constructor.
* @param radio The underlying radio module that this service will use.
*/
MicroBitRadioEvent::MicroBitRadioEvent()
MicroBitRadioEvent::MicroBitRadioEvent(MicroBitRadio &r) : radio(r)
{
suppressForwarding = false;
this->suppressForwarding = false;
}
/**
* Associates the given MessageBus events with the radio channel.
* Once registered, all events matching the given registration sent to this micro:bit's
* default MessageBus will be automaticlaly retrasmitted on the radio.
*
* @param id The ID of the events to register.
* @param value the VALUE of the event to register. use MICROBIT_EVT_ANY for all event values matching the given id.
*
* @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if no defult MessageBus is available.
*/
int MicroBitRadioEvent::listen(uint16_t id, uint16_t value)
{
if (MicroBitMessageBus::defaultMessageBus)
return listen(id, value, *MicroBitMessageBus::defaultMessageBus);
return MICROBIT_NO_RESOURCES;
}
/**
* Associates the given MessageBus events with the radio channel.
* Once registered, all events matching the given registration sent to the given
* MessageBus will be automaticlaly retrasmitted on the radio.
*
* @param id The ID of the events to register.
@ -31,9 +50,9 @@ MicroBitRadioEvent::MicroBitRadioEvent()
*
* @return MICROBIT_OK on success.
*/
int MicroBitRadioEvent::listen(uint16_t id, uint16_t value)
int MicroBitRadioEvent::listen(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus)
{
return uBit.MessageBus.listen(id, value, this, &MicroBitRadioEvent::eventReceived, MESSAGE_BUS_LISTENER_IMMEDIATE);
return messageBus.listen(id, value, this, &MicroBitRadioEvent::eventReceived, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
/**
@ -42,20 +61,38 @@ int MicroBitRadioEvent::listen(uint16_t id, uint16_t value)
* @param id The ID of the events to deregister.
* @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given id.
*
* @return MICROBIT_OK on success.
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if no default MessageBus is available.
*/
int MicroBitRadioEvent::ignore(uint16_t id, uint16_t value)
{
return uBit.MessageBus.ignore(id, value, this, &MicroBitRadioEvent::eventReceived);
if (MicroBitMessageBus::defaultMessageBus)
return ignore(id, value, *MicroBitMessageBus::defaultMessageBus);
return MICROBIT_INVALID_PARAMETER;
}
/**
* Disassociates the given MessageBus events with the radio channel.
*
* @param id The ID of the events to deregister.
* @param value the VALUE of the event to deregister. use MICROBIT_EVT_ANY for all event values matching the given id.
* @param The message bus to deregister on.
*
* @return MICROBIT_OK on success.
*/
int MicroBitRadioEvent::ignore(uint16_t id, uint16_t value, MicroBitMessageBus &messageBus)
{
return messageBus.ignore(id, value, this, &MicroBitRadioEvent::eventReceived);
}
/**
* Protocol handler callback. This is called when the radio receives a packet marked as an event
* This function process this packet, and fires the event contained inside onto the local MessageBus.
*/
void MicroBitRadioEvent::packetReceived()
{
FrameBuffer *p = uBit.radio.recv();
FrameBuffer *p = radio.recv();
MicroBitEvent *e = (MicroBitEvent *) p->payload;
suppressForwarding = true;
@ -83,6 +120,6 @@ void MicroBitRadioEvent::eventReceived(MicroBitEvent e)
buf.protocol = MICROBIT_RADIO_PROTOCOL_EVENTBUS;
memcpy(buf.payload, (const uint8_t *)&e, sizeof(MicroBitEvent));
uBit.radio.send(&buf);
radio.send(&buf);
}

View File

@ -13,8 +13,8 @@
* Create a representation of the TemperatureService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) :
ble(_ble)
MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble, MicroBitThermometer &_thermometer, MicroBitMessageBus &messageBus) :
ble(_ble), thermometer(_thermometer)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic temperatureDataCharacteristic(MicroBitTemperatureServiceDataUUID, (uint8_t *)&temperatureDataCharacteristicBuffer, 0,
@ -25,7 +25,7 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) :
// Initialise our characteristic values.
temperatureDataCharacteristicBuffer = 0;
temperaturePeriodCharacteristicBuffer = uBit.thermometer.getPeriod();
temperaturePeriodCharacteristicBuffer = thermometer.getPeriod();
// Set default security requirements
temperatureDataCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
@ -43,7 +43,7 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) :
ble.gattServer().write(temperaturePeriodCharacteristicHandle,(uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitTemperatureService::onDataWritten);
uBit.MessageBus.listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
messageBus.listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
/**
@ -53,7 +53,7 @@ void MicroBitTemperatureService::temperatureUpdate(MicroBitEvent)
{
if (ble.getGapState().connected)
{
temperatureDataCharacteristicBuffer = uBit.thermometer.getTemperature();
temperatureDataCharacteristicBuffer = thermometer.getTemperature();
ble.gattServer().notify(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer));
}
}
@ -66,11 +66,11 @@ void MicroBitTemperatureService::onDataWritten(const GattWriteCallbackParams *pa
if (params->handle == temperaturePeriodCharacteristicHandle && params->len >= sizeof(temperaturePeriodCharacteristicBuffer))
{
temperaturePeriodCharacteristicBuffer = *((uint16_t *)params->data);
uBit.thermometer.setPeriod(temperaturePeriodCharacteristicBuffer);
thermometer.setPeriod(temperaturePeriodCharacteristicBuffer);
// The accelerometer will choose the nearest period to that requested that it can support
// Read back the ACTUAL period it is using, and report this back.
temperaturePeriodCharacteristicBuffer = uBit.accelerometer.getPeriod();
temperaturePeriodCharacteristicBuffer = thermometer.getPeriod();
ble.gattServer().write(temperaturePeriodCharacteristicHandle, (const uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer));
}
}