microbit: Added configurable concurrency modes for MicroBitMessageBus handlers.

MessageBus handlers can now have one of four concurrency modes for the eventuality
of an event being raised whilst a previous event is still being processed. An additional
(optional) parameter is provided to the listen() functions to allow this to be selected
on a per event handler basis. The permissable options are:

MESSAGE_BUS_LISTENER_REENTRANT:
The event handler is fired with the new event, regardless of whether or not
a previous event is still be processed by that handler.

MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY:
The new event is queued until such a time as the previous event has completed
execution. The new event is then processed. This option does not preclude the
processing of the new event by other event handlers.

MESSAGE_BUS_LISTENER_DROP_IF_BUSY:
The new event is dropped, and will never be processed the the event handler.
This option does not preclude the processing of the new event by other event handlers.

MESSAGE_BUS_LISTENER_NONBLOCKING:
The event handler is self-declaring that it never blocks. This flag is used purely
for optimisation, as it permits direct execution of the event hadnelr without inducing
any overhead from the scheduler.

In addition, the following minor revisions were made in this release:

* Cleanup of the #include dependencies contained in the microbit-dal .h files
* Bugfix to the scheduler block on event matching code.
* Introduced a MICROBIT_ID_ALERT MessageBus channel, for general purpose eventing using nonces.
This commit is contained in:
Joe Finney 2015-09-11 16:39:38 +01:00
parent 51493092ff
commit a875d5fccd
29 changed files with 315 additions and 204 deletions

View File

@ -2,31 +2,34 @@
#define MICROBIT_H
#include "mbed.h"
#include "MicroBitConfig.h"
#include "MicroBitHeapAllocator.h"
#include "MicroBitPanic.h"
#include "ErrorNo.h"
#include "MicroBitHeapAllocator.h"
#include "MicroBitCompat.h"
#include "MicroBitFiber.h"
#include "MicroBitComponent.h"
#include "ManagedType.h"
#include "ManagedString.h"
#include "MicroBitEvent.h"
#include "MicroBitFont.h"
#include "MicroBitImage.h"
#include "MicroBitMessageBus.h"
#include "MicroBitFont.h"
#include "MicroBitEvent.h"
#include "DynamicPwm.h"
#include "MicroBitComponent.h"
#include "MicroBitI2C.h"
#include "MicroBitSerial.h"
#include "MESEvents.h"
#include "MicroBitButton.h"
#include "MicroBitMultiButton.h"
#include "MicroBitDisplay.h"
#include "MicroBitPin.h"
#include "MicroBitIO.h"
#include "MicroBitCompass.h"
#include "MicroBitAccelerometer.h"
#include "MicroBitMultiButton.h"
#include "MicroBitSerial.h"
#include "MicroBitIO.h"
#include "MicroBitDisplay.h"
#include "MicroBitFiber.h"
#include "MicroBitMessageBus.h"
#include "ble/BLE.h"
#include "ble/services/DeviceInformationService.h"
@ -43,38 +46,6 @@
// Random number generator
#define NRF51822_RNG_ADDRESS 0x4000D000
#define MICROBIT_IO_PINS 20
// Enumeration of core components.
#define MICROBIT_ID_BUTTON_A 1
#define MICROBIT_ID_BUTTON_B 2
#define MICROBIT_ID_BUTTON_RESET 3
#define MICROBIT_ID_ACCELEROMETER 4
#define MICROBIT_ID_COMPASS 5
#define MICROBIT_ID_DISPLAY 6
//EDGE connector events
#define MICROBIT_ID_IO_P0 7 //P0 is the left most pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P1 8 //P1 is the middle pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P2 9 //P2 is the right most pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P3 10 //COL1 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P4 11 //BTN_A
#define MICROBIT_ID_IO_P5 12 //COL2 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P6 13 //ROW2
#define MICROBIT_ID_IO_P7 14 //ROW1
#define MICROBIT_ID_IO_P8 15 //PIN 18
#define MICROBIT_ID_IO_P9 16 //ROW3
#define MICROBIT_ID_IO_P10 17 //COL3 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P11 18 //BTN_B
#define MICROBIT_ID_IO_P12 19 //PIN 20
#define MICROBIT_ID_IO_P13 20 //SCK
#define MICROBIT_ID_IO_P14 21 //MISO
#define MICROBIT_ID_IO_P15 22 //MOSI
#define MICROBIT_ID_IO_P16 23 //PIN 16
#define MICROBIT_ID_IO_P19 24 //SCL
#define MICROBIT_ID_IO_P20 25 //SDA
#define MICROBIT_ID_BUTTON_AB 26 // Button A+B multibutton
// mBed pin assignments of core components.
#define MICROBIT_PIN_SDA P0_30

View File

@ -2,6 +2,7 @@
#define MICROBIT_ACCELEROMETER_H
#include "mbed.h"
#include "MicroBitComponent.h"
/**
* Relevant pin assignments

View File

@ -2,6 +2,8 @@
#define MICROBIT_BUTTON_H
#include "mbed.h"
#include "MicroBitComponent.h"
#include "MicroBitEvent.h"
//TODO: When platform is built for MB2 - pins will be defined by default, these will change...
#define MICROBIT_PIN_BUTTON_A P0_17

View File

@ -2,6 +2,7 @@
#define MICROBIT_COMPASS_H
#include "mbed.h"
#include "MicroBitComponent.h"
/**
* Relevant pin assignments

View File

@ -8,6 +8,41 @@
* If it's in the systemTick queue, you should override systemTick and implement the required functionality.
* Similarly if the component is in the idleTick queue, the idleTick member function should be overridden.
*/
// Enumeration of core components.
#define MICROBIT_ID_BUTTON_A 1
#define MICROBIT_ID_BUTTON_B 2
#define MICROBIT_ID_BUTTON_RESET 3
#define MICROBIT_ID_ACCELEROMETER 4
#define MICROBIT_ID_COMPASS 5
#define MICROBIT_ID_DISPLAY 6
//EDGE connector events
#define MICROBIT_IO_PINS 20
#define MICROBIT_ID_IO_P0 7 //P0 is the left most pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P1 8 //P1 is the middle pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P2 9 //P2 is the right most pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P3 10 //COL1 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P4 11 //BTN_A
#define MICROBIT_ID_IO_P5 12 //COL2 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P6 13 //ROW2
#define MICROBIT_ID_IO_P7 14 //ROW1
#define MICROBIT_ID_IO_P8 15 //PIN 18
#define MICROBIT_ID_IO_P9 16 //ROW3
#define MICROBIT_ID_IO_P10 17 //COL3 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P11 18 //BTN_B
#define MICROBIT_ID_IO_P12 19 //PIN 20
#define MICROBIT_ID_IO_P13 20 //SCK
#define MICROBIT_ID_IO_P14 21 //MISO
#define MICROBIT_ID_IO_P15 22 //MOSI
#define MICROBIT_ID_IO_P16 23 //PIN 16
#define MICROBIT_ID_IO_P19 24 //SCL
#define MICROBIT_ID_IO_P20 25 //SDA
#define MICROBIT_ID_BUTTON_AB 26 // Button A+B multibutton
#define MICROBIT_ID_ALERT 27 // Alert channel, used for general purpose condition synchronisation and alerting.
class MicroBitComponent
{
protected:

View File

@ -77,6 +77,19 @@
#define FIBER_TICK_PERIOD_MS 6
#endif
//
// Message Bus:
// Default behaviour for event handlers, if not specified in the listen() call
//
// Permissable values are:
// MESSAGE_BUS_LISTENER_REENTRANT
// MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY
// MESSAGE_BUS_LISTENER_DROP_IF_BUSY
// MESSAGE_BUS_LISTENER_NONBLOCKING
#ifndef MESSAGE_BUS_LISTENER_DEFAULT_FLAGS
#define MESSAGE_BUS_LISTENER_DEFAULT_FLAGS MESSAGE_BUS_LISTENER_REENTRANT
#endif
//
// Core micro:bit services

View File

@ -1,8 +1,8 @@
#ifndef MICROBIT_DFU_SERVICE_H
#define MICROBIT_DFU_SERVICE_H
#include "MicroBit.h"
#include "mbed.h"
#include "ble/BLE.h"
// MicroBit ControlPoint OpCodes
// Requests transfer to the Nordic DFU bootloader.

View File

@ -63,7 +63,10 @@
#define MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS -255
#include "mbed.h"
#include "MicroBit.h"
#include "ManagedString.h"
#include "MicroBitComponent.h"
#include "MicroBitImage.h"
#include "MicroBitFont.h"
enum AnimationMode {
ANIMATION_MODE_NONE,
@ -102,6 +105,7 @@ class MicroBitDisplay : public MicroBitComponent
uint8_t mode;
uint8_t greyscaleBitMsk;
uint8_t timingCount;
uint16_t nonce;
Timeout renderTimer;
MicroBitFont font;
@ -217,7 +221,7 @@ class MicroBitDisplay : public MicroBitComponent
* Broadcasts an event onto the shared MessageBus
* @param eventCode The ID of the event that has occurred.
*/
void sendEvent(uint16_t eventcode);
void sendAnimationCompleteEvent();
public:

View File

@ -1,7 +1,7 @@
#ifndef MICROBIT_EVENT_H
#define MICROBIT_EVENT_H
#include "MicroBit.h"
#include "mbed.h"
/**
* Class definition for a MicrobitEvent
@ -43,7 +43,21 @@ class MicroBitEvent
void fire();
};
/**
* Enclosing class to hold a chain of events.
*/
struct MicroBitEventQueueItem
{
MicroBitEvent evt;
MicroBitEventQueueItem *next;
/**
* Constructor.
* Creates a new MicroBitEventQueueItem.
* @param evt The event that is to be queued.
*/
MicroBitEventQueueItem(MicroBitEvent evt);
};
#endif

View File

@ -1,7 +1,7 @@
#ifndef MICROBIT_EVENT_SERVICE_H
#define MICROBIT_EVENT_SERVICE_H
#include "MicroBit.h"
#include "MicroBitEvent.h"
// UUIDs for our service and characteristics
extern const uint8_t MicroBitEventServiceUUID[];

View File

@ -12,7 +12,7 @@
#include "mbed.h"
#include "MicroBitConfig.h"
#include "MicroBitMessageBus.h"
#include "MicroBitEvent.h"
// TODO: Consider a split mode scheduler, that monitors used stack size, and maintains a dedicated, persistent
// stack for any long lived fibers with large stack

View File

@ -1,8 +1,6 @@
#include "MicroBit.h"
#ifndef MICROBIT_I2C_H
#define MICROBIT_I2C_H
#include "MicroBitComponent.h"
#include "mbed.h"
#define MICROBIT_I2C_MAX_RETRIES 9

View File

@ -2,6 +2,7 @@
#define MICROBIT_IO_H
#include "mbed.h"
#include "MicroBitComponent.h"
#include "MicroBitPin.h"
/**
@ -37,15 +38,13 @@ class MicroBitIO
* Constructor.
* Create a representation of all given I/O pins on the edge connector
*/
MicroBitIO(int MICROBIT_ID_IO_P0, int MICROBIT_ID_IO_P1, int MICROBIT_ID_IO_P2,
int MICROBIT_ID_IO_P3, int MICROBIT_ID_IO_P4, int MICROBIT_ID_IO_P5,
int MICROBIT_ID_IO_P6, int MICROBIT_ID_IO_P7, int MICROBIT_ID_IO_P8,
int MICROBIT_ID_IO_P9, int MICROBIT_ID_IO_P10,int MICROBIT_ID_IO_P11,
int MICROBIT_ID_IO_P12,int MICROBIT_ID_IO_P13,int MICROBIT_ID_IO_P14,
int MICROBIT_ID_IO_P15,int MICROBIT_ID_IO_P16,int MICROBIT_ID_IO_P19,
int MICROBIT_ID_IO_P20);
MicroBitIO(int ID_P0, int ID_P1, int ID_P2,
int ID_P3, int ID_P4, int ID_P5,
int ID_P6, int ID_P7, int ID_P8,
int ID_P9, int ID_P10,int ID_P11,
int ID_P12,int ID_P13,int ID_P14,
int ID_P15,int ID_P16,int ID_P19,
int ID_P20);
};
#endif

View File

@ -3,12 +3,16 @@
#include "mbed.h"
#include "MicroBitEvent.h"
#include "MemberFunctionCallback.h"
// MessageBusListener flags...
#define MESSAGE_BUS_LISTENER_PARAMETERISED 0x0001
#define MESSAGE_BUS_LISTENER_METHOD 0x0002
#define MESSAGE_BUS_LISTENER_REENTRANT 0x0004
#define MESSAGE_BUS_LISTENER_BUSY 0x0008
#define MESSAGE_BUS_LISTENER_BUSY 0x0004
#define MESSAGE_BUS_LISTENER_REENTRANT 0x0008
#define MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY 0x0010
#define MESSAGE_BUS_LISTENER_DROP_IF_BUSY 0x0020
#define MESSAGE_BUS_LISTENER_NONBLOCKING 0x0040
struct MicroBitListener
{
@ -25,7 +29,8 @@ struct MicroBitListener
void* cb_arg; // Optional argument to be passed to the caller.
MicroBitEvent evt;
MicroBitEvent evt;
MicroBitEventQueueItem *evt_queue;
MicroBitListener *next;
@ -36,13 +41,13 @@ struct MicroBitListener
* @param value The event ID you would like to listen to from that component
* @param handler A function pointer to call when the event is detected.
*/
MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent));
MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
/**
* Alternative constructor where we register a value to be passed to the
* callback.
*/
MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent, void *), void* arg);
MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent, void *), void* arg, uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
/**
* Constructor.
@ -53,12 +58,18 @@ struct MicroBitListener
* @param object The method within the C++ object to call.
*/
template <typename T>
MicroBitListener(uint16_t id, uint16_t value, T* object, void (T::*method)(MicroBitEvent));
MicroBitListener(uint16_t id, uint16_t value, T* object, void (T::*method)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
/**
* Destructor. Ensures all resources used by this listener are freed.
*/
~MicroBitListener();
/**
* Queues and event up to be processed.
* @param e The event to queue
*/
void queue(MicroBitEvent e);
};
/**
@ -71,13 +82,13 @@ struct MicroBitListener
*/
template <typename T>
MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, T* object, void (T::*method)(MicroBitEvent))
MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, T* object, void (T::*method)(MicroBitEvent), uint16_t flags)
{
this->id = id;
this->value = value;
this->cb_method = new MemberFunctionCallback(object, method);
this->cb_arg = NULL;
this->flags = MESSAGE_BUS_LISTENER_METHOD;
this->flags = flags | MESSAGE_BUS_LISTENER_METHOD;
this->next = NULL;
}

View File

@ -8,6 +8,8 @@
#ifndef MICROBIT_MATRIX_MAPS_H
#define MICROBIT_MATRIX_MAPS_H
#include "mbed.h"
#include "MicroBitDisplay.h"
/**
* Provides the mapping from Matrix ROW/COL to a linear X/Y buffer.
* It's arranged such that matrixMap[col, row] provides the [x,y] screen co-ord.

View File

@ -2,33 +2,15 @@
#define MICROBIT_MESSAGE_BUS_H
#include "mbed.h"
#include "MemberFunctionCallback.h"
#include "MicroBitListener.h"
#include "MicroBitComponent.h"
#include "MicroBitEvent.h"
#include "MicroBitListener.h"
// Enumeration of core components.
#define MICROBIT_CONTROL_BUS_ID 0
#define MICROBIT_ID_ANY 0
#define MICROBIT_EVT_ANY 0
/**
* Enclosing class to hold a chain of events.
*/
struct MicroBitEventQueueItem
{
MicroBitEvent evt;
MicroBitEventQueueItem *next;
/**
* Constructor.
* Creates a new MicroBitEventQueueItem.
* @param evt The event that is to be queued.
*/
MicroBitEventQueueItem(MicroBitEvent evt);
};
/**
* Class definition for the MicroBitMessageBus.
*
@ -105,7 +87,7 @@ class MicroBitMessageBus : public MicroBitComponent
* uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); // call function when ever a click event is detected.
* @endcode
*/
void listen(int id, int value, void (*handler)(MicroBitEvent));
void listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
/**
* Register a listener function.
@ -127,7 +109,7 @@ class MicroBitMessageBus : public MicroBitComponent
* uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); // call function when ever a click event is detected.
* @endcode
*/
void listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg);
void listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
/**
* Register a listener function.
@ -152,7 +134,7 @@ class MicroBitMessageBus : public MicroBitComponent
* @endcode
*/
template <typename T>
void listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
void listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
/**
@ -220,6 +202,12 @@ class MicroBitMessageBus : public MicroBitComponent
*/
template <typename T>
void ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
/**
* Returns a 'nonce' for use with the NONCE_ID channel of the message bus.
*/
uint16_t nonce();
private:
/**
@ -233,6 +221,7 @@ class MicroBitMessageBus : public MicroBitComponent
MicroBitListener *listeners; // Chain of active listeners.
MicroBitEventQueueItem *evt_queue_head; // Head of queued events to be processed.
MicroBitEventQueueItem *evt_queue_tail; // Tail of queued events to be processed.
uint16_t nonce_val; // The last nonce issued.
void queueEvent(MicroBitEvent &evt);
MicroBitEventQueueItem* dequeueEvent();
@ -255,12 +244,12 @@ class MicroBitMessageBus : public MicroBitComponent
* @param hander The method to call when an event is received.
*/
template <typename T>
void MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent))
void MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags)
{
if (object == NULL || handler == NULL)
return;
MicroBitListener *newListener = new MicroBitListener(id, value, object, handler);
MicroBitListener *newListener = new MicroBitListener(id, value, object, handler, flags);
if(!add(newListener))
delete newListener;

View File

@ -1,8 +1,8 @@
#ifndef MICROBIT_PIN_H
#define MICROBIT_PIN_H
#include "MicroBitComponent.h"
#include "mbed.h"
#include "MicroBitComponent.h"
// Status Field flags...
#define IO_STATUS_DIGITAL_IN 0x01 // Pin is configured as a digital input, with no pull up.
#define IO_STATUS_DIGITAL_OUT 0x02 // Pin is configured as a digital output

View File

@ -1,9 +1,9 @@
#include "MicroBit.h"
#ifndef MICROBIT_SERIAL_H
#define MICROBIT_SERIAL_H
#include "MicroBitComponent.h"
#include "mbed.h"
#include "ManagedString.h"
#include "MicroBitImage.h"
#define MICROBIT_SERIAL_DEFAULT_BAUD_RATE 115200
#define MICROBIT_SERIAL_BUFFER_SIZE 20

View File

@ -1,6 +1,4 @@
#include "MicroBitHeapAllocator.h"
#include "DynamicPwm.h"
#include "MicroBit.h"
DynamicPwm* DynamicPwm::pwms[NO_PWMS] = { NULL };

View File

@ -1,9 +1,7 @@
#include <string.h>
#include <stdlib.h>
#include "mbed.h"
#include "MicroBitHeapAllocator.h"
#include "MicroBitCompat.h"
#include "ManagedString.h"
#include "MicroBit.h"
/**

View File

@ -3,11 +3,10 @@
*
* A MicroBitDisplay represents the LED matrix array on the MicroBit device.
*/
#include "mbed.h"
#include "MicroBit.h"
#include "MicroBitMatrixMaps.h"
#include <new>
#include "nrf_gpio.h"
#include "mbed.h"
const float timings[MICROBIT_DISPLAY_GREYSCALE_BIT_DEPTH] = {0.000010, 0.000047, 0.000094, 0.000187, 0.000375, 0.000750, 0.001500, 0.003000};
@ -234,7 +233,7 @@ MicroBitDisplay::animationUpdate()
if(animationMode == ANIMATION_MODE_PRINT_CHARACTER)
{
animationMode = ANIMATION_MODE_NONE;
this->sendEvent(MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
this->sendAnimationCompleteEvent();
}
}
}
@ -243,9 +242,13 @@ MicroBitDisplay::animationUpdate()
* Broadcasts an event onto the shared MessageBus
* @param eventCode The ID of the event that has occurred.
*/
void MicroBitDisplay::sendEvent(uint16_t eventCode)
void MicroBitDisplay::sendAnimationCompleteEvent()
{
MicroBitEvent evt(id,eventCode);
// Signal that we've completed an animation.
MicroBitEvent evt1(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
// Wake up any fibers that were blocked on the animation (if any).
MicroBitEvent evt2(MICROBIT_ID_ALERT, nonce);
}
/**
@ -266,7 +269,7 @@ void MicroBitDisplay::updateScrollText()
if (scrollingChar > scrollingText.length())
{
animationMode = ANIMATION_MODE_NONE;
this->sendEvent(MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
this->sendAnimationCompleteEvent();
return;
}
scrollingChar++;
@ -284,7 +287,8 @@ void MicroBitDisplay::updatePrintText()
if (printingChar > printingText.length())
{
animationMode = ANIMATION_MODE_NONE;
this->sendEvent(MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
this->sendAnimationCompleteEvent();
return;
}
@ -302,7 +306,8 @@ void MicroBitDisplay::updateScrollImage()
if ((image.paste(scrollingImage, scrollingImagePosition, 0, 0) == 0) && scrollingImageRendered)
{
animationMode = ANIMATION_MODE_NONE;
this->sendEvent(MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
this->sendAnimationCompleteEvent();
return;
}
@ -321,7 +326,7 @@ void MicroBitDisplay::updateAnimateImage()
if (scrollingImagePosition <= -scrollingImage.getWidth() + (MICROBIT_DISPLAY_WIDTH + scrollingImageStride) && scrollingImageRendered)
{
animationMode = ANIMATION_MODE_NONE;
this->sendEvent(MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
this->sendAnimationCompleteEvent();
return;
}
@ -349,7 +354,7 @@ void MicroBitDisplay::resetAnimation(uint16_t delay)
if (animationMode != ANIMATION_MODE_NONE)
{
animationMode = ANIMATION_MODE_NONE;
this->sendEvent(MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
this->sendAnimationCompleteEvent();
}
// Clear the display and setup the animation timers.
@ -406,7 +411,8 @@ void MicroBitDisplay::print(char c, int delay)
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
nonce = uBit.MessageBus.nonce();
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
}
/**
@ -432,7 +438,8 @@ void MicroBitDisplay::print(ManagedString s, int delay)
this->printAsync(s, delay);
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
nonce = uBit.MessageBus.nonce();
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
}
/**
@ -459,7 +466,8 @@ void MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
nonce = uBit.MessageBus.nonce();
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
}
/**
@ -542,7 +550,8 @@ void MicroBitDisplay::scroll(ManagedString s, int delay)
this->scrollAsync(s, delay);
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
nonce = uBit.MessageBus.nonce();
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
}
/**
@ -569,7 +578,8 @@ void MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
this->scrollAsync(image, delay, stride);
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
nonce = uBit.MessageBus.nonce();
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
}
/**
@ -603,7 +613,7 @@ void MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, i
if (animationMode != ANIMATION_MODE_NONE)
{
animationMode = ANIMATION_MODE_NONE;
this->sendEvent(MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
this->sendAnimationCompleteEvent();
}
this->animationDelay = delay;
@ -646,7 +656,8 @@ void MicroBitDisplay::animate(MicroBitImage image, int delay, int stride, int st
this->animateAsync(image, delay, stride, startingPosition);
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
nonce = uBit.MessageBus.nonce();
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
}

View File

@ -44,3 +44,15 @@ void MicroBitEvent::fire()
{
uBit.MessageBus.send(*this);
}
/**
* Constructor.
* Create a new MicroBitEventQueueItem.
* @param evt The event to be queued.
*/
MicroBitEventQueueItem::MicroBitEventQueueItem(MicroBitEvent evt)
{
this->evt = evt;
this->next = NULL;
}

View File

@ -5,9 +5,7 @@
#include "MicroBit.h"
#include "ble/UUID.h"
#include "ExternalEvents.h"
#include "MicroBitEventService.h"
/**
* Constructor.

View File

@ -212,8 +212,8 @@ void scheduler_event(MicroBitEvent evt)
t = f->next;
// extract the event data this fiber is blocked on.
uint16_t id = f->context & 0xFF;
uint16_t value = (f->context & 0xFF00) >> 16;
uint16_t id = f->context & 0xFFFF;
uint16_t value = (f->context & 0xFFFF0000) >> 16;
if ((id == MICROBIT_ID_ANY || id == evt.source) && (value == MICROBIT_EVT_ANY || value == evt.value))
{

View File

@ -1,5 +1,5 @@
#include "MicroBit.h"
#include "mbed.h"
#include "MicroBit.h"
#include "twi_master.h"
#include "nrf_delay.h"

View File

@ -4,37 +4,37 @@
* Represents a single IO pin on the edge connector.
*/
#include "MicroBitIO.h"
#include "MicroBit.h"
/**
* Constructor.
* Create a representation of all given I/O pins on the edge connector
*/
MicroBitIO::MicroBitIO(int MICROBIT_ID_IO_P0, int MICROBIT_ID_IO_P1, int MICROBIT_ID_IO_P2,
int MICROBIT_ID_IO_P3, int MICROBIT_ID_IO_P4, int MICROBIT_ID_IO_P5,
int MICROBIT_ID_IO_P6, int MICROBIT_ID_IO_P7, int MICROBIT_ID_IO_P8,
int MICROBIT_ID_IO_P9, int MICROBIT_ID_IO_P10,int MICROBIT_ID_IO_P11,
int MICROBIT_ID_IO_P12,int MICROBIT_ID_IO_P13,int MICROBIT_ID_IO_P14,
int MICROBIT_ID_IO_P15,int MICROBIT_ID_IO_P16,int MICROBIT_ID_IO_P19,
int MICROBIT_ID_IO_P20) :
P0 (MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL), //P0 is the left most pad (ANALOG/DIGITAL/TOUCH)
P1 (MICROBIT_ID_IO_P1, MICROBIT_PIN_P1, PIN_CAPABILITY_ALL), //P1 is the middle pad (ANALOG/DIGITAL/TOUCH)
P2 (MICROBIT_ID_IO_P2, MICROBIT_PIN_P2, PIN_CAPABILITY_ALL), //P2 is the right most pad (ANALOG/DIGITAL/TOUCH)
P3 (MICROBIT_ID_IO_P3, MICROBIT_PIN_P3, PIN_CAPABILITY_AD), //COL1 (ANALOG/DIGITAL)
P4 (MICROBIT_ID_IO_P4, MICROBIT_PIN_P4, PIN_CAPABILITY_DIGITAL), //BTN_A
P5 (MICROBIT_ID_IO_P5, MICROBIT_PIN_P5, PIN_CAPABILITY_AD), //COL2 (ANALOG/DIGITAL)
P6 (MICROBIT_ID_IO_P6, MICROBIT_PIN_P6, PIN_CAPABILITY_DIGITAL), //ROW2
P7 (MICROBIT_ID_IO_P7, MICROBIT_PIN_P7, PIN_CAPABILITY_DIGITAL), //ROW1
P8 (MICROBIT_ID_IO_P8, MICROBIT_PIN_P8, PIN_CAPABILITY_DIGITAL), //PIN 18
P9 (MICROBIT_ID_IO_P9, MICROBIT_PIN_P9, PIN_CAPABILITY_DIGITAL), //ROW3
P10(MICROBIT_ID_IO_P10,MICROBIT_PIN_P10,PIN_CAPABILITY_AD), //COL3 (ANALOG/DIGITAL)
P11(MICROBIT_ID_IO_P11,MICROBIT_PIN_P11,PIN_CAPABILITY_DIGITAL), //BTN_B
P12(MICROBIT_ID_IO_P12,MICROBIT_PIN_P12,PIN_CAPABILITY_DIGITAL), //PIN 20
P13(MICROBIT_ID_IO_P13,MICROBIT_PIN_P13,PIN_CAPABILITY_DIGITAL), //SCK
P14(MICROBIT_ID_IO_P14,MICROBIT_PIN_P14,PIN_CAPABILITY_DIGITAL), //MISO
P15(MICROBIT_ID_IO_P15,MICROBIT_PIN_P15,PIN_CAPABILITY_DIGITAL), //MOSI
P16(MICROBIT_ID_IO_P16,MICROBIT_PIN_P16,PIN_CAPABILITY_DIGITAL), //PIN 16
P19(MICROBIT_ID_IO_P19,MICROBIT_PIN_P19,PIN_CAPABILITY_DIGITAL), //SCL
P20(MICROBIT_ID_IO_P20,MICROBIT_PIN_P20,PIN_CAPABILITY_DIGITAL) //SDA
MicroBitIO::MicroBitIO(int ID_P0, int ID_P1, int ID_P2,
int ID_P3, int ID_P4, int ID_P5,
int ID_P6, int ID_P7, int ID_P8,
int ID_P9, int ID_P10,int ID_P11,
int ID_P12,int ID_P13,int ID_P14,
int ID_P15,int ID_P16,int ID_P19,
int ID_P20) :
P0 (ID_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL), //P0 is the left most pad (ANALOG/DIGITAL/TOUCH)
P1 (ID_P1, MICROBIT_PIN_P1, PIN_CAPABILITY_ALL), //P1 is the middle pad (ANALOG/DIGITAL/TOUCH)
P2 (ID_P2, MICROBIT_PIN_P2, PIN_CAPABILITY_ALL), //P2 is the right most pad (ANALOG/DIGITAL/TOUCH)
P3 (ID_P3, MICROBIT_PIN_P3, PIN_CAPABILITY_AD), //COL1 (ANALOG/DIGITAL)
P4 (ID_P4, MICROBIT_PIN_P4, PIN_CAPABILITY_DIGITAL), //BTN_A
P5 (ID_P5, MICROBIT_PIN_P5, PIN_CAPABILITY_AD), //COL2 (ANALOG/DIGITAL)
P6 (ID_P6, MICROBIT_PIN_P6, PIN_CAPABILITY_DIGITAL), //ROW2
P7 (ID_P7, MICROBIT_PIN_P7, PIN_CAPABILITY_DIGITAL), //ROW1
P8 (ID_P8, MICROBIT_PIN_P8, PIN_CAPABILITY_DIGITAL), //PIN 18
P9 (ID_P9, MICROBIT_PIN_P9, PIN_CAPABILITY_DIGITAL), //ROW3
P10(ID_P10,MICROBIT_PIN_P10,PIN_CAPABILITY_AD), //COL3 (ANALOG/DIGITAL)
P11(ID_P11,MICROBIT_PIN_P11,PIN_CAPABILITY_DIGITAL), //BTN_B
P12(ID_P12,MICROBIT_PIN_P12,PIN_CAPABILITY_DIGITAL), //PIN 20
P13(ID_P13,MICROBIT_PIN_P13,PIN_CAPABILITY_DIGITAL), //SCK
P14(ID_P14,MICROBIT_PIN_P14,PIN_CAPABILITY_DIGITAL), //MISO
P15(ID_P15,MICROBIT_PIN_P15,PIN_CAPABILITY_DIGITAL), //MOSI
P16(ID_P16,MICROBIT_PIN_P16,PIN_CAPABILITY_DIGITAL), //PIN 16
P19(ID_P19,MICROBIT_PIN_P19,PIN_CAPABILITY_DIGITAL), //SCL
P20(ID_P20,MICROBIT_PIN_P20,PIN_CAPABILITY_DIGITAL) //SDA
{
}

View File

@ -15,13 +15,13 @@
* @param value The event ID you would like to listen to from that component
* @param handler A function pointer to call when the event is detected.
*/
MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent))
MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent), uint16_t flags)
{
this->id = id;
this->value = value;
this->cb = handler;
this->cb_arg = NULL;
this->flags = 0;
this->flags = flags;
this->next = NULL;
}
@ -33,13 +33,13 @@ MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(
* @param handler A function pointer to call when the event is detected.
* @param arg An additional argument to pass to the event handler function.
*/
MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent, void *), void* arg)
MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(MicroBitEvent, void *), void* arg, uint16_t flags)
{
this->id = id;
this->value = value;
this->cb_param = handler;
this->cb_arg = arg;
this->flags = MESSAGE_BUS_LISTENER_PARAMETERISED;
this->flags = flags | MESSAGE_BUS_LISTENER_PARAMETERISED;
this->next = NULL;
}
@ -51,3 +51,23 @@ MicroBitListener::~MicroBitListener()
if(this->flags & MESSAGE_BUS_LISTENER_METHOD)
delete cb_method;
}
/**
* Queues and event up to be processed.
* @param e The event to queue
*/
void MicroBitListener::queue(MicroBitEvent e)
{
MicroBitEventQueueItem *q = new MicroBitEventQueueItem(e);
MicroBitEventQueueItem *p = evt_queue;
if (evt_queue == NULL)
evt_queue = q;
else
{
while (p->next != NULL)
p = p->next;
p->next = q;
}
}

View File

@ -6,18 +6,6 @@
#include "MicroBit.h"
/**
* Constructor.
* Create a new MicroBitEventQueueItem.
* @param evt The event to be queued.
*/
MicroBitEventQueueItem::MicroBitEventQueueItem(MicroBitEvent evt)
{
this->evt = evt;
this->next = NULL;
}
/**
* Constructor.
* Create a new Message Bus.
@ -27,6 +15,18 @@ MicroBitMessageBus::MicroBitMessageBus()
this->listeners = NULL;
this->evt_queue_head = NULL;
this->evt_queue_tail = NULL;
this->nonce_val = 0;
}
/**
* Returns a 'nonce' for use with the NONCE_ID channel of the message bus.
*/
uint16_t MicroBitMessageBus::nonce()
{
// In the global scheme of things, a terrible nonce generator.
// However, for our purposes, this is simple and adequate for local use.
// This would be a bad idea if our events were networked though - can you think why?
return nonce_val++;
}
/**
@ -39,20 +39,60 @@ void async_callback(void *param)
{
MicroBitListener *listener = (MicroBitListener *)param;
// OK, now we need to decide how to behave depending on our configuration.
// If this a fiber f already active within this listener then check our
// configuration to determine the correct course of action.
//
if (listener->flags & MESSAGE_BUS_LISTENER_BUSY)
{
// Drop this event, if that's how we've been configured.
if (listener->flags & MESSAGE_BUS_LISTENER_DROP_IF_BUSY)
return;
// Queue this event up for later, if that's how we've been configured.
if (listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY)
{
listener->queue(listener->evt);
return;
}
}
// Determine the calling convention for the callback, and invoke...
// C++ is really bad at this! Especially as the ARM compiler is yet to support C++ 11 :-/
// Firstly, check for a method callback into an object.
if (listener->flags & MESSAGE_BUS_LISTENER_METHOD)
listener->cb_method->fire(listener->evt);
// Record that we have a fiber going into this listener...
listener->flags |= MESSAGE_BUS_LISTENER_BUSY;
// Now a parameterised C function
else if (listener->flags & MESSAGE_BUS_LISTENER_PARAMETERISED)
listener->cb_param(listener->evt, listener->cb_arg);
while (1)
{
// Firstly, check for a method callback into an object.
if (listener->flags & MESSAGE_BUS_LISTENER_METHOD)
listener->cb_method->fire(listener->evt);
// We must have a plain C function
else
listener->cb(listener->evt);
// Now a parameterised C function
else if (listener->flags & MESSAGE_BUS_LISTENER_PARAMETERISED)
listener->cb_param(listener->evt, listener->cb_arg);
// We must have a plain C function
else
listener->cb(listener->evt);
// If there are more events to process, dequeue te next one and process it.
if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue)
{
MicroBitEventQueueItem *item = listener->evt_queue;
listener->evt = item->evt;
listener->evt_queue = listener->evt_queue->next;
delete item;
}
else
break;
}
// The fiber of exiting... clear our state.
listener->flags &= ~MESSAGE_BUS_LISTENER_BUSY;
}
@ -176,33 +216,27 @@ void MicroBitMessageBus::process(MicroBitEvent evt)
{
MicroBitListener *l;
// Find the start of the sublist where we'll send this event.
l = listeners;
while (l != NULL && l->id != evt.source)
l = l->next;
// Now, send the event to all listeners registered for this event.
while (l != NULL && l->id == evt.source)
{
if(l->value == MICROBIT_EVT_ANY || l->value == evt.value)
{
while (l != NULL)
{
if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
{
l->evt = evt;
invoke(async_callback, (void *)l);
// OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
// This is normally only done for trusted system components.
// Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
// should the event handler attempt a blocking operation, but doesn't have the overhead
// of creating a fiber needlessly. (cool huh?)
if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING)
async_callback(l);
else
invoke(async_callback, l);
}
l = l->next;
}
// Next, send to any listeners registered for ALL event sources.
l = listeners;
while (l != NULL && l->id == MICROBIT_ID_ANY)
{
l->evt = evt;
invoke(async_callback, (void *)l);
l = l->next;
}
// Finally, forward the event to any other internal subsystems that may be interested.
// We *could* do this through the message bus of course, but this saves additional RAM,
// and procssor time (as we know these are non-blocking calls).
@ -237,23 +271,23 @@ void MicroBitMessageBus::process(MicroBitEvent evt)
* @endcode
*/
void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent))
void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags)
{
if (handler == NULL)
return;
MicroBitListener *newListener = new MicroBitListener(id, value, handler);
MicroBitListener *newListener = new MicroBitListener(id, value, handler, flags);
if(!add(newListener))
delete newListener;
}
void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg)
void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags)
{
if (handler == NULL)
return;
MicroBitListener *newListener = new MicroBitListener(id, value, handler, arg);
MicroBitListener *newListener = new MicroBitListener(id, value, handler, arg, flags);
if(!add(newListener))
delete newListener;

View File

@ -1,5 +1,5 @@
#include "MicroBit.h"
#include "mbed.h"
#include "MicroBit.h"
/**
* Constructor.