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() { ledOn(BODY_RGB_RED_PIN); delay(2000); // 2seconds of red on ledOff(BODY_RGB_RED_PIN); 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..)