# SFBQLED Class Reference

A simple queuing system to allow displaying various 'blink patterns' on the SFB built-in LEDs without having to block. More...

`#include <SFBQLED.h>`

Collaboration diagram for SFBQLED:

[legend]

## 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.

## Detailed Description

A simple queuing system to allow displaying various 'blink patterns' on the SFB built-in LEDs without having to block.

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() { }

## SFBQLED theory of operation

We would like to satisfy these incompatible goals:

1. Schedule events on LEDs individually and asynchronously, so we can, say, decide to blink the NORTH_LED_PIN for two seconds, and while that's in progress, we can later decide we also want to blink SOUTH_LED_PIN for two seconds, and the south blink can start without waiting for the north blink to finish.
2. Schedule events on LEDs jointly and simultaneously, so we can, say, schedule both RED and GREEN to be on for a second together to make yellow.
3. Keep the API code reasonably simple and non-threatening. Don't require bit masks or '|'s in API calls, and reuse existing constants and symbols as much as possible.

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:

1. By design, always scheduling equal times on the LEDs, making it impossible for them to get out of sync, or
2. By calling forget() on each, thus canceling any pending events on them, or
3. By calling time() on each to determine their current scheduling depth, and then adding an (on or off) event to the LED with the shorter schedule to line them up.

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().

Since:
  0.9.12

## Member Function Documentation

u32 SFBQLED::available | ( |  | ) | `[inline]`

Return the number of events that can currently be added to the SFBQLED before it will be completely full.

Maximum return value is size() when the queue is completely empty; minimum return value is 0 with the queue is completely full.

void SFBQLED::begin | ( | u16 * | buffer,
|  | u32 | size |
| ) |  |  |

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().

Parameters:

  | 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!)

Blinks:
  E_API_NULL_POINTER if buffer is null

Blinks:
  E_API_NONZERO if size is zero

Blinks:
  E_API_LESS_EQUAL if size is greater than 255

Blinks:
  E_API_NO_MORE_ALARMS if the needed alarm could not be created

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).

Examples:
  qled1.cpp.

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()).

Parameters:

  | sfbPin | the pin number of a built-in LED.

Blinks:
  E_API_ARGUMENT if sfbPin is not the pin number of a built-in LED.

void SFBQLED::off | ( | u32 | sfbPin,
|  | u32 | ms |
| ) |  |  |

Schedule an 'off' event for sfbPin lasting approximately ms, to begin after any other events currently on sfbPin.

See on() for details.

Parameters:

  | sfbPin | the pin number of a built-in LED.
  | ms | the approximate number of milliseconds this event should last.

Blinks:
  E_API_ARGUMENT if sfbPin is not the pin number of a built-in LED.

Examples:
  qled1.cpp.

void SFBQLED::on | ( | u32 | sfbPin,
|  | u32 | ms |
| ) |  |  |

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.

Parameters:

  | sfbPin | the pin number of a built-in LED.
  | ms | the approximate number of milliseconds this event should last.

Blinks:
  E_API_ARGUMENT if sfbPin is not the pin number of a built-in LED.

Examples:
  qled1.cpp.

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.

u32 SFBQLED::time | ( | u32 | sfbPin | ) |

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.

Parameters:

  | sfbPin | the pin number of a built-in LED.

Blinks:
  E_API_ARGUMENT if sfbPin is not the pin number of a built-in LED.

void SFBQLED::whenIdle | ( | u32 | sfbPin,
|  | u32 | mode |
| ) |  |  |

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.

Parameters:

  | sfbPin | the pin number of a built-in LED.
  | mode | idle behavior of sfbPin: QLED_IDLE_ON, QLED_IDLE_OFF, or QLED_IDLE_REFLEX.

Blinks:
  E_API_ARGUMENT if sfbPin is not the pin number of a built-in LED.

The documentation for this class was generated from the following files:

- src/include/SFBQLED.h
- src/components/library/SFBQLED.cpp