The PQRST library: Priority Queue for Running Simple Tasks

This is a library, initially targeted at the Arduino, to provide simple ‘thread’ support (very much in scare-quotes). This is version 1.1, 2018 December 2 (rev b51a74b878dd).

The software is Copyright 2017–18, Norman Gray, and is available under the terms of the 2-clause BSD licence. It is therefore perfectly happy to disappear into your source tree.

The code is available at bitbucket (downloads). The code is now reasonably stable, and is used in production. See also the release notes.

Principles

This module implements a Priority Queue for Running Simple Tasks. It is intended to support a simple but very flexible threading framework for Arduino tasks.

When code uses this module, it should declare one or more subclasses of the Task class, and in each of those declare and implement at least the run method (overriding Task::run. These can then be queued using the Task::start method. There is a pre-existing subclass called LoopTask, which is a task which automatically re-queues itself at a specified cadence.

The main loop of the program should then call TaskQueue::run_ready when it has nothing else to do, which will run any task which has become due.

Although the module is currently targeted at the Arduino, it has only a rather loose dependence on the Arduino framework (it uses the Serial object for some non-essential debugging and the PROGMEM type for a version string in Flash). It could therefore be ported to a different framework without much difficulty. In particular, the library does not depend on the Arduino millis() function.

Example

For example, here is the Arduino ‘blink’ program, implemented with a task loop:


#include "pqrst.h"

class BlinkTask : public LoopTask {
private:
    int my_pin_;
    bool light_on_p_;
public:
    BlinkTask(int pin, ms_t cadence);
    void run(ms_t) override;
};

BlinkTask::BlinkTask(int pin, ms_t cadence)
    : LoopTask(cadence),
      my_pin_(pin),
      light_on_p_(false)
{
    // empty
}
void BlinkTask::run(ms_t t)
{
    // toggle the LED state every time we are called
    light_on_p_ = !light_on_p_;
    digitalWrite(my_pin_, light_on_p_);
}

// flash the built-in LED at a 500ms cadence
BlinkTask flasher(LED_BUILTIN, 500);

void setup()
{
    pinMode(LED_BUILTIN, OUTPUT);
    flasher.start(2000);  // start after 2000ms (=2s)
}

void loop()
{
    Queue.run_ready(millis());
}

The code has compile-time options for

Use and documentation

To use, drop the files pqrst.cpp and pqrst.h into your source tree.

To run the unit tests, run make check in the distribution directory.

The main documentation, currently, is the class and function documentation, generated by Doxygen.

Norman Gray
2018 December 2