microbit: Updates to enable queing of display animation calls

Updates to change the behaviour of the scroll/print/animate faily of function away
from being pre-emtive and instead prroviding queing behaviour.

Minor updates to provide complete sets of async equivalent operations

Updates to the scheduler to provide wait/notify/waitone semantics.
This commit is contained in:
Joe Finney 2015-10-17 20:35:16 +01:00
parent 85b2b1e09e
commit aca544677e
8 changed files with 281 additions and 155 deletions

View File

@ -41,7 +41,9 @@
#define MICROBIT_ID_IO_P20 25 //SDA #define MICROBIT_ID_IO_P20 25 //SDA
#define MICROBIT_ID_BUTTON_AB 26 // Button A+B multibutton #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.
#define MICROBIT_ID_NOTIFY 1023 // Notfication channel, for general purpose synchronisation
#define MICROBIT_ID_NOTIFY_ONE 1022 // Notfication channel, for general purpose synchronisation
class MicroBitComponent class MicroBitComponent
{ {

View File

@ -88,7 +88,7 @@
// MESSAGE_BUS_LISTENER_NONBLOCKING // MESSAGE_BUS_LISTENER_NONBLOCKING
#ifndef MESSAGE_BUS_LISTENER_DEFAULT_FLAGS #ifndef MESSAGE_BUS_LISTENER_DEFAULT_FLAGS
#define MESSAGE_BUS_LISTENER_DEFAULT_FLAGS MESSAGE_BUS_LISTENER_REENTRANT #define MESSAGE_BUS_LISTENER_DEFAULT_FLAGS MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY
#endif #endif
// //

View File

@ -19,6 +19,7 @@
* MessageBus Event Codes * MessageBus Event Codes
*/ */
#define MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE 1 #define MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE 1
#define MICROBIT_DISPLAY_EVT_FREE 2
/** /**
* I/O configurations for common devices. * I/O configurations for common devices.
@ -70,6 +71,7 @@
enum AnimationMode { enum AnimationMode {
ANIMATION_MODE_NONE, ANIMATION_MODE_NONE,
ANIMATION_MODE_STOPPED,
ANIMATION_MODE_SCROLL_TEXT, ANIMATION_MODE_SCROLL_TEXT,
ANIMATION_MODE_PRINT_TEXT, ANIMATION_MODE_PRINT_TEXT,
ANIMATION_MODE_SCROLL_IMAGE, ANIMATION_MODE_SCROLL_IMAGE,
@ -103,7 +105,6 @@ class MicroBitDisplay : public MicroBitComponent
uint8_t mode; uint8_t mode;
uint8_t greyscaleBitMsk; uint8_t greyscaleBitMsk;
uint8_t timingCount; uint8_t timingCount;
uint16_t nonce;
Timeout renderTimer; Timeout renderTimer;
MicroBitFont font; MicroBitFont font;
@ -221,6 +222,11 @@ class MicroBitDisplay : public MicroBitComponent
*/ */
void sendAnimationCompleteEvent(); void sendAnimationCompleteEvent();
/**
* Blocks the current fiber until the display is available (i.e. not effect is being displayed).
* Animations are queued until their time to display.
*/
void waitForFreeDisplay();
public: public:
// The mutable bitmap buffer being rendered to the LED matrix. // The mutable bitmap buffer being rendered to the LED matrix.
@ -242,16 +248,29 @@ public:
MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y); MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y);
/** /**
* Resets the current given animation. * Stops any currently running animation, and any that are waiting to be displayed.
* @param delay the delay after which the animation is reset.
*/ */
void resetAnimation(uint16_t delay); void stopAnimation();
/** /**
* Frame update method, invoked periodically to strobe the display. * Frame update method, invoked periodically to strobe the display.
*/ */
virtual void systemTick(); virtual void systemTick();
/**
* Prints the given character to the display, if it is not in use.
*
* @param c The character to display.
* @param d Optional parameter - the time for which to show the character. Zero displays the character forever.
*
* Example:
* @code
* uBit.display.printAsync('p');
* uBit.display.printAsync('p',100);
* @endcode
*/
void printAsync(char c, int delay = 0);
/** /**
* Prints the given string to the display, one character at a time. * Prints the given string to the display, one character at a time.
* Uses the given delay between characters. * Uses the given delay between characters.
@ -267,6 +286,24 @@ public:
*/ */
void printAsync(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED); void printAsync(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
/**
* Prints the given image to the display, if the display is not in use.
* Returns immediately, and executes the animation asynchronously.
*
* @param i The image to display.
* @param x The horizontal position on the screen to display the image (default 0)
* @param y The vertical position on the screen to display the image (default 0)
* @param alpha Treats the brightness level '0' as transparent (default 0)
* @param delay The time to delay between characters, in timer ticks.
*
* Example:
* @code
* MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
* uBit.display.print(i,400);
* @endcode
*/
void printAsync(MicroBitImage i, int x, int y, int alpha, int delay = 0);
/** /**
* Prints the given character to the display. * Prints the given character to the display.
* *
@ -307,7 +344,7 @@ public:
* uBit.display.print(i,400); * uBit.display.print(i,400);
* @endcode * @endcode
*/ */
void print(MicroBitImage i, int x, int y, int alpha, int delay = MICROBIT_DEFAULT_PRINT_SPEED); void print(MicroBitImage i, int x, int y, int alpha, int delay = 0);
/** /**
* Scrolls the given string to the display, from right to left. * Scrolls the given string to the display, from right to left.

View File

@ -203,11 +203,6 @@ class MicroBitMessageBus : public MicroBitComponent
template <typename T> template <typename T>
void ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent)); 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: private:
/** /**

View File

@ -191,7 +191,7 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
*/ */
void MicroBitDFUService::showTick() void MicroBitDFUService::showTick()
{ {
uBit.display.resetAnimation(0); uBit.display.stopAnimation();
uBit.display.image.setPixelValue(0,3, 255); uBit.display.image.setPixelValue(0,3, 255);
uBit.display.image.setPixelValue(1,4, 255); uBit.display.image.setPixelValue(1,4, 255);
@ -206,7 +206,7 @@ void MicroBitDFUService::showTick()
*/ */
void MicroBitDFUService::showNameHistogram() void MicroBitDFUService::showNameHistogram()
{ {
uBit.display.resetAnimation(0); uBit.display.stopAnimation();
uint32_t n = NRF_FICR->DEVICEID[1]; uint32_t n = NRF_FICR->DEVICEID[1];
int ld = 1; int ld = 1;

View File

@ -234,10 +234,10 @@ MicroBitDisplay::animationUpdate()
void MicroBitDisplay::sendAnimationCompleteEvent() void MicroBitDisplay::sendAnimationCompleteEvent()
{ {
// Signal that we've completed an animation. // Signal that we've completed an animation.
MicroBitEvent evt1(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE); MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
// Wake up any fibers that were blocked on the animation (if any). // Wake up a fiber that was blocked on the animation (if any).
MicroBitEvent evt2(MICROBIT_ID_ALERT, nonce); MicroBitEvent(MICROBIT_ID_NOTIFY_ONE, MICROBIT_DISPLAY_EVT_FREE);
} }
/** /**
@ -304,7 +304,6 @@ void MicroBitDisplay::updateScrollImage()
scrollingImageRendered = true; scrollingImageRendered = true;
} }
/** /**
* Internal animateImage update method. * Internal animateImage update method.
* Paste the stored bitmap at the appropriate point and stop on the last frame. * Paste the stored bitmap at the appropriate point and stop on the last frame.
@ -333,28 +332,70 @@ void MicroBitDisplay::updateAnimateImage()
* Resets the current given animation. * Resets the current given animation.
* @param delay the delay after which the animation is reset. * @param delay the delay after which the animation is reset.
*/ */
void MicroBitDisplay::resetAnimation(uint16_t delay) void MicroBitDisplay::stopAnimation()
{ {
//sanitise this value
if(delay <= 0 )
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
// Reset any ongoing animation. // Reset any ongoing animation.
if (animationMode != ANIMATION_MODE_NONE) if (animationMode != ANIMATION_MODE_NONE)
{ {
animationMode = ANIMATION_MODE_NONE; animationMode = ANIMATION_MODE_NONE;
this->sendAnimationCompleteEvent();
// Indicate that we've completed an animation.
MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
// Wake up aall fibers that may blocked on the animation (if any).
MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE);
} }
// Clear the display and setup the animation timers. // Clear the display and setup the animation timers.
this->image.clear(); this->image.clear();
this->animationDelay = delay;
this->animationTick = delay-1;
} }
/** /**
* Prints the given string to the display, one character at a time. * Blocks the current fiber until the display is available (i.e. not effect is being displayed).
* Uses the given delay between characters. * Animations are queued until their time to display.
*
*/
void MicroBitDisplay::waitForFreeDisplay()
{
// If there's an ongoing animation, wait for our turn to display.
if (animationMode != ANIMATION_MODE_NONE && animationMode != ANIMATION_MODE_STOPPED)
fiber_wait_for_event(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE);
}
/**
* Prints the given character to the display, if it is not in use.
*
* @param c The character to display.
* @param d Optional parameter - the time for which to show the character. Zero displays the character forever.
*
* Example:
* @code
* uBit.display.printAsync('p');
* uBit.display.printAsync('p',100);
* @endcode
*/
void MicroBitDisplay::printAsync(char c, int delay)
{
// If there's an ongoing animation, wait for our turn to display.
this->waitForFreeDisplay();
// If the display is free, it's our turn to display.
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
{
image.print(c, 0, 0);
if(delay <= 0)
return;
animationDelay = delay;
animationTick = 0;
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
}
}
/**
* Prints the given string to the display, one character at a time, if the display is not in use.
* Returns immediately, and executes the animation asynchronously. * Returns immediately, and executes the animation asynchronously.
* *
* @param s The string to display. * @param s The string to display.
@ -367,41 +408,77 @@ void MicroBitDisplay::resetAnimation(uint16_t delay)
*/ */
void MicroBitDisplay::printAsync(ManagedString s, int delay) void MicroBitDisplay::printAsync(ManagedString s, int delay)
{ {
//sanitise this value if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
if(delay <= 0 ) {
delay = MICROBIT_DEFAULT_SCROLL_SPEED; //sanitise this value
if(delay <= 0 )
this->resetAnimation(delay); delay = MICROBIT_DEFAULT_SCROLL_SPEED;
this->printingChar = 0; printingChar = 0;
this->printingText = s; printingText = s;
animationDelay = delay;
animationMode = ANIMATION_MODE_PRINT_TEXT; animationTick = 0;
animationMode = ANIMATION_MODE_PRINT_TEXT;
}
} }
/** /**
* Prints the given character to the display. * Prints the given image to the display, if the display is not in use.
* Returns immediately, and executes the animation asynchronously.
*
* @param i The image to display.
* @param x The horizontal position on the screen to display the image (default 0)
* @param y The vertical position on the screen to display the image (default 0)
* @param alpha Treats the brightness level '0' as transparent (default 0)
* @param delay The time to delay between characters, in timer ticks.
*
* Example:
* @code
* MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
* uBit.display.print(i,400);
* @endcode
*/
void MicroBitDisplay::printAsync(MicroBitImage i, int x, int y, int alpha, int delay)
{
// If the display is free, it's our turn to display.
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
{
image.paste(i, x, y, alpha);
if(delay <= 0)
return;
animationDelay = delay;
animationTick = 0;
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
}
}
/**
* Prints the given character to the display, and wait for it to complete.
* *
* @param c The character to display. * @param c The character to display.
* *
* Example: * Example:
* @code * @code
* uBit.display.print('p'); * uBit.display.print('p');
* uBit.display.print('p',100);
* @endcode * @endcode
*/ */
void MicroBitDisplay::print(char c, int delay) void MicroBitDisplay::print(char c, int delay)
{ {
image.print(c, 0, 0); // If there's an ongoing animation, wait for our turn to display.
this->waitForFreeDisplay();
if(delay <= 0)
return; // If the display is free, it's our turn to display.
// If someone called stopAnimation(), then we simply skip...
this->animationDelay = delay; if (animationMode == ANIMATION_MODE_NONE)
animationMode = ANIMATION_MODE_PRINT_CHARACTER; {
this->printAsync(c, 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);
} }
/** /**
@ -423,12 +500,16 @@ void MicroBitDisplay::print(ManagedString s, int delay)
if(delay <= 0 ) if(delay <= 0 )
delay = MICROBIT_DEFAULT_SCROLL_SPEED; delay = MICROBIT_DEFAULT_SCROLL_SPEED;
// Start the effect. // If there's an ongoing animation, wait for our turn to display.
this->printAsync(s, delay); this->waitForFreeDisplay();
// Wait for completion. // If the display is free, it's our turn to display.
nonce = uBit.MessageBus.nonce(); // If someone called stopAnimation(), then we simply skip...
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce); if (animationMode == ANIMATION_MODE_NONE)
{
this->printAsync(s, delay);
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
}
} }
/** /**
@ -446,17 +527,17 @@ void MicroBitDisplay::print(ManagedString s, int delay)
*/ */
void MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay) void MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
{ {
image.paste(i, x, y, alpha); // If there's an ongoing animation, wait for our turn to display.
// If there's an ongoing animation, wait for our turn to display.
if(delay <= 0) this->waitForFreeDisplay();
return;
// If the display is free, it's our turn to display.
this->animationDelay = delay; // If someone called stopAnimation(), then we simply skip...
animationMode = ANIMATION_MODE_PRINT_CHARACTER; if (animationMode == ANIMATION_MODE_NONE)
{
// Wait for completion. this->printAsync(i, x, y, alpha, delay);
nonce = uBit.MessageBus.nonce(); fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce); }
} }
/** /**
@ -474,17 +555,19 @@ void MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
*/ */
void MicroBitDisplay::scrollAsync(ManagedString s, int delay) void MicroBitDisplay::scrollAsync(ManagedString s, int delay)
{ {
//sanitise this value // If the display is free, it's our turn to display.
if(delay <= 0 ) if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
delay = MICROBIT_DEFAULT_SCROLL_SPEED; {
//sanitise the delay parameter
this->resetAnimation(delay); if(delay <= 0 )
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
this->scrollingPosition = width-1;
this->scrollingChar = 0; scrollingPosition = width-1;
this->scrollingText = s; scrollingChar = 0;
scrollingText = s;
animationMode = ANIMATION_MODE_SCROLL_TEXT;
animationMode = ANIMATION_MODE_SCROLL_TEXT;
}
} }
/** /**
@ -502,18 +585,20 @@ void MicroBitDisplay::scrollAsync(ManagedString s, int delay)
*/ */
void MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride) void MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride)
{ {
//sanitise the delay value // If the display is free, it's our turn to display.
if(delay <= 0 ) if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
delay = MICROBIT_DEFAULT_SCROLL_SPEED; {
//sanitise the delay value
this->resetAnimation(delay); if(delay <= 0 )
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
this->scrollingImagePosition = stride < 0 ? width : -image.getWidth(); this->scrollingImagePosition = stride < 0 ? width : -image.getWidth();
this->scrollingImageStride = stride; this->scrollingImageStride = stride;
this->scrollingImage = image; this->scrollingImage = image;
this->scrollingImageRendered = false; this->scrollingImageRendered = false;
animationMode = ANIMATION_MODE_SCROLL_IMAGE; animationMode = ANIMATION_MODE_SCROLL_IMAGE;
}
} }
/** /**
@ -531,16 +616,19 @@ void MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride)
*/ */
void MicroBitDisplay::scroll(ManagedString s, int delay) void MicroBitDisplay::scroll(ManagedString s, int delay)
{ {
//sanitise this value // If there's an ongoing animation, wait for our turn to display.
if(delay <= 0 ) this->waitForFreeDisplay();
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
// If the display is free, it's our turn to display.
// Start the effect. // If someone called stopAnimation(), then we simply skip...
this->scrollAsync(s, delay); if (animationMode == ANIMATION_MODE_NONE)
{
// Wait for completion. // Start the effect.
nonce = uBit.MessageBus.nonce(); this->scrollAsync(s, delay);
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
}
} }
/** /**
@ -559,16 +647,19 @@ void MicroBitDisplay::scroll(ManagedString s, int delay)
*/ */
void MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride) void MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
{ {
//sanitise the delay value // If there's an ongoing animation, wait for our turn to display.
if(delay <= 0 ) this->waitForFreeDisplay();
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
// If the display is free, it's our turn to display.
// Start the effect. // If someone called stopAnimation(), then we simply skip...
this->scrollAsync(image, delay, stride); if (animationMode == ANIMATION_MODE_NONE)
{
// Wait for completion. // Start the effect.
nonce = uBit.MessageBus.nonce(); this->scrollAsync(image, delay, stride);
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
}
} }
/** /**
@ -591,30 +682,27 @@ void MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
*/ */
void MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, int startingPosition) void MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, int startingPosition)
{ {
// Assume right to left functionality, to align with scrollString() // If the display is free, it's our turn to display.
stride = -stride; if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
//sanitise the delay value
if(delay <= 0 )
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
// Reset any ongoing animation.
if (animationMode != ANIMATION_MODE_NONE)
{ {
animationMode = ANIMATION_MODE_NONE; // Assume right to left functionality, to align with scrollString()
this->sendAnimationCompleteEvent(); stride = -stride;
}
this->animationDelay = delay;
this->animationTick = delay-1;
//calculate starting position which is offset by the stride //sanitise the delay value
this->scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS)?MICROBIT_DISPLAY_WIDTH + stride:startingPosition; if(delay <= 0 )
this->scrollingImageStride = stride; delay = MICROBIT_DEFAULT_SCROLL_SPEED;
this->scrollingImage = image;
this->scrollingImageRendered = false; animationDelay = delay;
animationTick = delay-1;
animationMode = ANIMATION_MODE_ANIMATE_IMAGE;
//calculate starting position which is offset by the stride
scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS) ? MICROBIT_DISPLAY_WIDTH + stride : startingPosition;
scrollingImageStride = stride;
scrollingImage = image;
scrollingImageRendered = false;
animationMode = ANIMATION_MODE_ANIMATE_IMAGE;
}
} }
/** /**
@ -637,16 +725,19 @@ void MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, i
*/ */
void MicroBitDisplay::animate(MicroBitImage image, int delay, int stride, int startingPosition) void MicroBitDisplay::animate(MicroBitImage image, int delay, int stride, int startingPosition)
{ {
//sanitise the delay value // If there's an ongoing animation, wait for our turn to display.
if(delay <= 0 ) this->waitForFreeDisplay();
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
// If the display is free, it's our turn to display.
// Start the effect. // If someone called stopAnimation(), then we simply skip...
this->animateAsync(image, delay, stride, startingPosition); if (animationMode == ANIMATION_MODE_NONE)
{
// Wait for completion. // Start the effect.
nonce = uBit.MessageBus.nonce(); this->animateAsync(image, delay, stride, startingPosition);
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
// Wait for completion.
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
}
} }

View File

@ -15,7 +15,7 @@
*/ */
Fiber *currentFiber = NULL; // The context in which the current fiber is executing. 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 *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. Fiber *idleFiber = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks.
/* /*
* Scheduler state. * Scheduler state.
@ -205,6 +205,7 @@ void scheduler_event(MicroBitEvent evt)
{ {
Fiber *f = waitQueue; Fiber *f = waitQueue;
Fiber *t; Fiber *t;
int notifyOneComplete = 0;
// Check the wait queue, and wake up any fibers as necessary. // Check the wait queue, and wake up any fibers as necessary.
while (f != NULL) while (f != NULL)
@ -214,7 +215,16 @@ void scheduler_event(MicroBitEvent evt)
// extract the event data this fiber is blocked on. // extract the event data this fiber is blocked on.
uint16_t id = f->context & 0xFFFF; uint16_t id = f->context & 0xFFFF;
uint16_t value = (f->context & 0xFFFF0000) >> 16; uint16_t value = (f->context & 0xFFFF0000) >> 16;
// Special case for the NOTIFY_ONE channel...
if ((notifyOneComplete == 0) && (id == MICROBIT_ID_NOTIFY && evt.source == MICROBIT_ID_NOTIFY_ONE) && (value == MICROBIT_EVT_ANY || value == evt.value))
{
// Wakey wakey!
dequeue_fiber(f);
queue_fiber(f,&runQueue);
notifyOneComplete = 1;
}
if ((id == MICROBIT_ID_ANY || id == evt.source) && (value == MICROBIT_EVT_ANY || value == evt.value)) if ((id == MICROBIT_ID_ANY || id == evt.source) && (value == MICROBIT_EVT_ANY || value == evt.value))
{ {
// Wakey wakey! // Wakey wakey!

View File

@ -15,18 +15,6 @@ MicroBitMessageBus::MicroBitMessageBus()
this->listeners = NULL; this->listeners = NULL;
this->evt_queue_head = NULL; this->evt_queue_head = NULL;
this->evt_queue_tail = 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++;
} }
/** /**
@ -86,6 +74,9 @@ void async_callback(void *param)
listener->evt = item->evt; listener->evt = item->evt;
listener->evt_queue = listener->evt_queue->next; listener->evt_queue = listener->evt_queue->next;
delete item; delete item;
// We spin the scheduler here, to preven any particular event handler from continuously holding onto resources.
schedule();
} }
else else
break; break;