#include <SFBQLED.h>
Data Structures | |
struct | qentry |
Public Member Functions | |
u32 | available () |
Return the number of events that can currently be added to the SFBQLED before it will be completely full. | |
u32 | size () |
Return the total number of events that can fit in the queue. | |
void | begin () |
Initialize the SFBQLED for use using the default size of 32 and a private internal buffer for event storage. | |
void | begin (u16 *buffer, u32 size) |
Initialize the SFBQLED for use, using the given buffer and size. | |
void | end () |
Inverts the effect of the most recent begin() or begin(u16 * buffer, u32 size) call. | |
void | forget (u32 sfbPin) |
Cancel any pending events for sfbPin. | |
void | whenIdle (u32 sfbPin, u32 mode) |
Specify the desired state of sfbPin when there are no events queued for it. | |
u32 | time (u32 sfbPin) |
Compute and return the (approximate) total amount of time in all events currently queued for sfbPin. | |
void | on (u32 sfbPin, u32 ms) |
Schedule an 'on' event for sfbPin lasting approximately ms, to begin after any other events currently on sfbPin. | |
void | off (u32 sfbPin, u32 ms) |
Schedule an 'off' event for sfbPin lasting approximately ms, to begin after any other events currently on sfbPin. | |
void | set (u32 sfbPin, u32 ms, bool turnOn) |
Schedule an 'on' or 'off' event depending on turnOn. |
The system, if used, consumes one alarm out of the Alarms pool.
The traditional easy way to blink an LED is to do it from the loop() method:
void loop() { ledOn(BODY_RGB_RED_PIN); delay(2000); // 2seconds of red on ledOff(BODY_RGB_RED_PIN); delay(1000); // 1second of red off }
but that style of code doesn't transfer well when you want to blink an LED from inside a packet handler, because of the mantra: delay()ing A Handler Is A Bad Idea. As long as you are inside one packet (or alarm) handler, no other handler will run until you return, and calling delay() greatly, well, delays, the packet handler's return:
// Calling delay() inside a packet handler is a bad idea! void showPacketBADWAY(u8 *) { // While inside one packet handler, NO OTHER packet handler WILL RUN! ledOn(BODY_RGB_RED_PIN); delay(2000); // BAD IDEA! Delays handling any other packet for 2 seconds ledOff(BODY_RGB_RED_PIN); delay(1000); // BAD IDEA! Delays handling any other packet for another 1 second after that } void setup() { Body.reflex('p',showPacketBADWAY); } void loop() { }
The QLED, an object of class SFBQLED, provides a better solution:
// Blinking LEDs from packet handlers without delay(), using QLED void showPacket(u8 *) { QLED.on(BODY_RGB_RED_PIN,2000); // Add an 'on' event for RED lasting (about) 2 seconds QLED.off(BODY_RGB_RED_PIN,1000); // Add an 'off' event for RED lasting (about) 1 second } void setup() { QLED.begin(); // Start up the queue for LEDs! Body.reflex('p',showPacket); } void loop() { }
We would like to satisfy these incompatible goals:
The SFBQLED design favors goal (1) at the expense of (2) because individual and asynchronous can, with some overhead, simulate joint and synchronous, while the reverse is more expensive or impossible depending on the approach. To support (1), SFBQLED provides a separate event queue for each built-in LED, using (compact) linked lists to store all the event queues in a single buffer.
A single event involves turning on or off a single built-in LED for some multiple of 16ms from 16ms to 2032ms; to schedule an event for, say two, LEDs simultaneously, the programmer must schedule a copy of the event on each LED -- but before that, the programmer should first ensure that both LEDs have the same amount of time currently scheduled on them, or else there is no guarantee the events will start at the same time. Ensuring two LEDs are 'schedule-matched' can be done:
The SFBQLED design is aimed most naturally at non-repeating display patterns -- something that you want to display once in response to an event, and then move on. But since there is support for detecting how full (or empty) the queue is, one iteration of a repeating pattern can be scheduled, and then the queue can be polled from time to time and reloaded with the same pattern, once there is enough room available().
u32 SFBQLED::available | ( | ) | [inline] |
Initialize the SFBQLED for use, using the given buffer and size.
buffer must be non-null and pointing to space big enough for at least size u16's
, for event storage. Inverted by end(). See also begin().
buffer | non-null pointer to array of u16's to use for event storage | |
size | size of buffer (number of u16s); a value from 1 to 255 (note limits!) |
void SFBQLED::begin | ( | ) |
Initialize the SFBQLED for use using the default size of 32 and a private internal buffer for event storage.
Inverted by end(). See also begin(u16 * buffer, u32 size).
void SFBQLED::end | ( | ) |
Inverts the effect of the most recent begin() or begin(u16 * buffer, u32 size) call.
In the latter case, in particular, buffer
may be reused for other purposes after calling end(). Each built-in LED pin returns to its idle mode as specified by whenIdle() (or to reflex mode if whenIdle() was not called for it).
Note that because Alarms once created cannot be freed, the alarm used by SFBQLED will remain allocated even if end() is called. However, if begin() is subsequently called again, that alarm will be reused; at most one alarm will ever be allocated by SFBQLED.
void SFBQLED::forget | ( | u32 | sfbPin | ) |
Cancel any pending events for sfbPin.
The pin enters its idle state (see whenIdle()).
sfbPin | the pin number of a built-in LED. |
Schedule an 'off' event for sfbPin lasting approximately ms, to begin after any other events currently on sfbPin.
See on() for details.
sfbPin | the pin number of a built-in LED. | |
ms | the approximate number of milliseconds this event should last. |
Schedule an 'on' event for sfbPin lasting approximately ms, to begin after any other events currently on sfbPin.
The duration is only approximate because all events are measured in 16ms units, with a minimum duration of 16ms. (This is billed ripoff-style like cellphone airtime: 0..15ms is one unit, 16ms..31ms is two units, etc.)
Note that the maximum duration that can fit in a single event is 2032ms, but it is not an error for ms to exceed that value. Instead, if ms exceeds 2032ms, then multiple events will be scheduled (as long as room is available()) until the requested number of ms have been scheduled.
sfbPin | the pin number of a built-in LED. | |
ms | the approximate number of milliseconds this event should last. |
Schedule an 'on' or 'off' event depending on turnOn.
See on() for details.
sfbPin | the pin number of a built-in LED. | |
ms | the approximate number of milliseconds this event should last. | |
turnOn | whether to turn on or off |
u32 SFBQLED::size | ( | ) | [inline] |
Return the total number of events that can fit in the queue.
If SFBQLED was most recently started with begin(), this method will return the default size of SFBQLED, which is 32. If SFBQLED was most recently started with begin(u16 * buffer, u32 size), this method will return the size specified there.
Compute and return the (approximate) total amount of time in all events currently queued for sfbPin.
The returned time is only approximate because (1) All events are measured in 16ms units, and (2) it doesn't include the amount of time remaining until SFBQLED's alarm next tick.
sfbPin | the pin number of a built-in LED. |
Specify the desired state of sfbPin when there are no events queued for it.
When there are no events queued for a pin, mode
specifies how the pin should be handled. It can be left on or off or be returned to reflex mode. The default behavior is QLED_IDLE_REFLEX if this method is not used.
sfbPin | the pin number of a built-in LED. | |
mode | idle behavior of sfbPin: QLED_IDLE_ON, QLED_IDLE_OFF, or QLED_IDLE_REFLEX. |