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.master
parent
85b2b1e09e
commit
aca544677e
|
@ -41,7 +41,9 @@
|
|||
#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.
|
||||
|
||||
#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
|
||||
{
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
// MESSAGE_BUS_LISTENER_NONBLOCKING
|
||||
|
||||
#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
|
||||
|
||||
//
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* MessageBus Event Codes
|
||||
*/
|
||||
#define MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE 1
|
||||
#define MICROBIT_DISPLAY_EVT_FREE 2
|
||||
|
||||
/**
|
||||
* I/O configurations for common devices.
|
||||
|
@ -70,6 +71,7 @@
|
|||
|
||||
enum AnimationMode {
|
||||
ANIMATION_MODE_NONE,
|
||||
ANIMATION_MODE_STOPPED,
|
||||
ANIMATION_MODE_SCROLL_TEXT,
|
||||
ANIMATION_MODE_PRINT_TEXT,
|
||||
ANIMATION_MODE_SCROLL_IMAGE,
|
||||
|
@ -103,7 +105,6 @@ class MicroBitDisplay : public MicroBitComponent
|
|||
uint8_t mode;
|
||||
uint8_t greyscaleBitMsk;
|
||||
uint8_t timingCount;
|
||||
uint16_t nonce;
|
||||
Timeout renderTimer;
|
||||
|
||||
MicroBitFont font;
|
||||
|
@ -221,6 +222,11 @@ class MicroBitDisplay : public MicroBitComponent
|
|||
*/
|
||||
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:
|
||||
// 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);
|
||||
|
||||
/**
|
||||
* Resets the current given animation.
|
||||
* @param delay the delay after which the animation is reset.
|
||||
* Stops any currently running animation, and any that are waiting to be displayed.
|
||||
*/
|
||||
void resetAnimation(uint16_t delay);
|
||||
void stopAnimation();
|
||||
|
||||
/**
|
||||
* Frame update method, invoked periodically to strobe the display.
|
||||
*/
|
||||
virtual void systemTick();
|
||||
|
||||
/**
|
||||
* Prints the given character to the display, if it is not in use.
|
||||
*
|
||||
* @param c The character to display.
|
||||
* @param 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.
|
||||
* Uses the given delay between characters.
|
||||
|
@ -267,6 +286,24 @@ public:
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -307,7 +344,7 @@ public:
|
|||
* uBit.display.print(i,400);
|
||||
* @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.
|
||||
|
|
|
@ -203,11 +203,6 @@ 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:
|
||||
|
||||
/**
|
||||
|
|
|
@ -191,7 +191,7 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
|
|||
*/
|
||||
void MicroBitDFUService::showTick()
|
||||
{
|
||||
uBit.display.resetAnimation(0);
|
||||
uBit.display.stopAnimation();
|
||||
|
||||
uBit.display.image.setPixelValue(0,3, 255);
|
||||
uBit.display.image.setPixelValue(1,4, 255);
|
||||
|
@ -206,7 +206,7 @@ void MicroBitDFUService::showTick()
|
|||
*/
|
||||
void MicroBitDFUService::showNameHistogram()
|
||||
{
|
||||
uBit.display.resetAnimation(0);
|
||||
uBit.display.stopAnimation();
|
||||
|
||||
uint32_t n = NRF_FICR->DEVICEID[1];
|
||||
int ld = 1;
|
||||
|
|
|
@ -234,10 +234,10 @@ MicroBitDisplay::animationUpdate()
|
|||
void MicroBitDisplay::sendAnimationCompleteEvent()
|
||||
{
|
||||
// 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).
|
||||
MicroBitEvent evt2(MICROBIT_ID_ALERT, nonce);
|
||||
// Wake up a fiber that was blocked on the animation (if any).
|
||||
MicroBitEvent(MICROBIT_ID_NOTIFY_ONE, MICROBIT_DISPLAY_EVT_FREE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -304,7 +304,6 @@ void MicroBitDisplay::updateScrollImage()
|
|||
scrollingImageRendered = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal animateImage update method.
|
||||
* 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.
|
||||
* @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.
|
||||
if (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.
|
||||
this->image.clear();
|
||||
this->animationDelay = delay;
|
||||
this->animationTick = delay-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time.
|
||||
* Uses the given delay between characters.
|
||||
* Blocks the current fiber until the display is available (i.e. not effect is being displayed).
|
||||
* Animations are queued until their time to display.
|
||||
*
|
||||
*/
|
||||
void MicroBitDisplay::waitForFreeDisplay()
|
||||
{
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
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.
|
||||
*
|
||||
* @param s The string to display.
|
||||
|
@ -367,41 +408,77 @@ void MicroBitDisplay::resetAnimation(uint16_t delay)
|
|||
*/
|
||||
void MicroBitDisplay::printAsync(ManagedString s, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
this->resetAnimation(delay);
|
||||
|
||||
this->printingChar = 0;
|
||||
this->printingText = s;
|
||||
|
||||
animationMode = ANIMATION_MODE_PRINT_TEXT;
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
printingChar = 0;
|
||||
printingText = s;
|
||||
animationDelay = delay;
|
||||
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.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print('p');
|
||||
* uBit.display.print('p',100);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::print(char c, int delay)
|
||||
{
|
||||
image.print(c, 0, 0);
|
||||
|
||||
if(delay <= 0)
|
||||
return;
|
||||
|
||||
this->animationDelay = delay;
|
||||
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
// 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 someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
this->printAsync(c, delay);
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -423,12 +500,16 @@ void MicroBitDisplay::print(ManagedString s, int delay)
|
|||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
// Start the effect.
|
||||
this->printAsync(s, delay);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
// 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 someone called stopAnimation(), then we simply skip...
|
||||
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)
|
||||
{
|
||||
image.paste(i, x, y, alpha);
|
||||
|
||||
if(delay <= 0)
|
||||
return;
|
||||
|
||||
this->animationDelay = delay;
|
||||
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
// 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 someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
this->printAsync(i, x, y, alpha, delay);
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -474,17 +555,19 @@ void MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
|
|||
*/
|
||||
void MicroBitDisplay::scrollAsync(ManagedString s, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
this->resetAnimation(delay);
|
||||
|
||||
this->scrollingPosition = width-1;
|
||||
this->scrollingChar = 0;
|
||||
this->scrollingText = s;
|
||||
|
||||
animationMode = ANIMATION_MODE_SCROLL_TEXT;
|
||||
// If the display is free, it's our turn to display.
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
//sanitise the delay parameter
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
scrollingPosition = width-1;
|
||||
scrollingChar = 0;
|
||||
scrollingText = s;
|
||||
|
||||
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)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
this->resetAnimation(delay);
|
||||
// If the display is free, it's our turn to display.
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
this->scrollingImagePosition = stride < 0 ? width : -image.getWidth();
|
||||
this->scrollingImageStride = stride;
|
||||
this->scrollingImage = image;
|
||||
this->scrollingImageRendered = false;
|
||||
|
||||
animationMode = ANIMATION_MODE_SCROLL_IMAGE;
|
||||
this->scrollingImagePosition = stride < 0 ? width : -image.getWidth();
|
||||
this->scrollingImageStride = stride;
|
||||
this->scrollingImage = image;
|
||||
this->scrollingImageRendered = false;
|
||||
|
||||
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)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
// Start the effect.
|
||||
this->scrollAsync(s, delay);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
// 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 someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
// Start the effect.
|
||||
this->scrollAsync(s, delay);
|
||||
|
||||
// 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)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
// Start the effect.
|
||||
this->scrollAsync(image, delay, stride);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
// 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 someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
// Start the effect.
|
||||
this->scrollAsync(image, delay, stride);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Assume right to left functionality, to align with scrollString()
|
||||
stride = -stride;
|
||||
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
// Reset any ongoing animation.
|
||||
if (animationMode != ANIMATION_MODE_NONE)
|
||||
// If the display is free, it's our turn to display.
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
animationMode = ANIMATION_MODE_NONE;
|
||||
this->sendAnimationCompleteEvent();
|
||||
}
|
||||
|
||||
this->animationDelay = delay;
|
||||
this->animationTick = delay-1;
|
||||
// Assume right to left functionality, to align with scrollString()
|
||||
stride = -stride;
|
||||
|
||||
//calculate starting position which is offset by the stride
|
||||
this->scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS)?MICROBIT_DISPLAY_WIDTH + stride:startingPosition;
|
||||
this->scrollingImageStride = stride;
|
||||
this->scrollingImage = image;
|
||||
this->scrollingImageRendered = false;
|
||||
|
||||
animationMode = ANIMATION_MODE_ANIMATE_IMAGE;
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
animationDelay = delay;
|
||||
animationTick = delay-1;
|
||||
|
||||
//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)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
// Start the effect.
|
||||
this->animateAsync(image, delay, stride, startingPosition);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
// 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 someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
// Start the effect.
|
||||
this->animateAsync(image, delay, stride, startingPosition);
|
||||
|
||||
// Wait for completion.
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
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.
|
||||
Fiber *idleFiber = NULL; // IDLE task - performs a power efficient sleep, and system maintenance tasks.
|
||||
|
||||
/*
|
||||
* Scheduler state.
|
||||
|
@ -205,6 +205,7 @@ void scheduler_event(MicroBitEvent evt)
|
|||
{
|
||||
Fiber *f = waitQueue;
|
||||
Fiber *t;
|
||||
int notifyOneComplete = 0;
|
||||
|
||||
// Check the wait queue, and wake up any fibers as necessary.
|
||||
while (f != NULL)
|
||||
|
@ -214,7 +215,16 @@ void scheduler_event(MicroBitEvent evt)
|
|||
// extract the event data this fiber is blocked on.
|
||||
uint16_t id = f->context & 0xFFFF;
|
||||
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))
|
||||
{
|
||||
// Wakey wakey!
|
||||
|
|
|
@ -15,18 +15,6 @@ 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++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,6 +74,9 @@ void async_callback(void *param)
|
|||
listener->evt = item->evt;
|
||||
listener->evt_queue = listener->evt_queue->next;
|
||||
delete item;
|
||||
|
||||
// We spin the scheduler here, to preven any particular event handler from continuously holding onto resources.
|
||||
schedule();
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue