Rule of Thumb: Don't call delay() inside packet or alarm handlers.

The most common reason people are tempted to violate that rule is to blink an LED to indicate that some packet or time of interest has arrived.

The QLED object, illustrated in this example, provides a way to do that sort of blinking, without violating that rule.

Here's the reason that rule exists:

The traditional easy way to blink an LED is to do it from loop():

     void loop() {
       delay(2000);             // 2seconds of red on
       delay(1000);             // 1second of red off

That 'delay()-based' programming style works well in the loop() function, because loop() is a special case: When you call delay() from inside the loop() function, a process called 'dispatching' takes place. Dispatching is calling packet handlers for whom matching patckets have arrived, and alarm handlers whose time has arrived.

When delay(u32 ms) is called from inside loop(), dispatching is performed (repeatedly), until the ms delay time you specified has been used up. Dispatching is also performed briefly in between successive calls to loop().

So why should you care? Because of the 'Dispatching Rule': No Dispatching While Dispatching. When are packet handlers called? During dispatching. When are alarm handlers called? During dispatching. That means dispatching is already in progress when a packet or alarm handler is running. So if a packet or alarm handler calls delay(), no other packet or alarm handlers can be called during that delay, because dispatching is already going and calling another handler would violate the Dispatching Rule.

So, if delay(u32) is called from a packet or alarm handler, that delay time is basically wasted. Although low-level I/O and timer interrupts still occur, until that current handler returns, allowing dispatching to continue, any arrived packets will be buffered or discarded, depending on whether room is available, and any alarm handlers that should have been triggered will be delayed. And that's the reason for the:

Rule of Thumb: Don't call delay() inside packet or alarm handlers.

If you were calling delay(u32) just to blink a built-in LED, the QLED object provides an alternative. It's pretty easy to use: To get started, just call QLED.begin() in your setup() method, and then you can call QLED.on(ledPin, msOn) and QLED.off(ledPin,msOff) to schedule 'on' and 'off' events (lasting msOn and msOff milliseconds, respectively) for the given ledPin (which must be one of the built-in LEDs: You cannot use QLED to blink external data pins.)

In this sketch, when a 'p' packet arrives, the packet handler blinks the face LED corresponding to the source of the packet. In addition, the handler either tries to send the packet on to a neighbor, or 'eats' the packet itself, with a long red blink when that happens.

// qled sketch 1: Demo blinking LEDs without blocking packet handling

void doIt(u8 *packet) {
  // Get the face led where the packet came from.
  u32 led = pinInFace(FACE_LED_PIN, packetSource(packet)); 

  for (u32 i = 0; i < 3; ++i) { // Blink source face three times fast
    QLED.on(led, 100);          // Schedule about 100ms on..
    QLED.off(led, 100);         // and then about 100ms off.

  if (random(10)!=0)            // 9 times out of 10
    facePrintln(random(NORTH,WEST+1),packet,packetLength(packet)); // pass it on
  else {                        // 1 time out of 10
    QLED.off(BODY_RGB_RED_PIN, 400); // Red off for about 400ms, then
    QLED.on(BODY_RGB_RED_PIN, 200);  // Red on for about 200ms, then
    QLED.off(BODY_RGB_RED_PIN, 0);   // Leave red turned off

void setup() {
  QLED.begin();                // Init the LED queueing system!
  Body.reflex('p',doIt);       // Create a reflex

void loop() { 
  delay(100);                  // loop about 10 times per second
  if (random(30)==0)           // about 1 in 30 loops (about 3 seconds)
    facePrintln(random(NORTH,WEST+1),"p"); // send a 'p' to a random neighbor
}                                          // (who might or might not exist..)

Generated on Fri Apr 22 06:54:11 2011 for SFB by doxygen 1.5.9