Cooperating Sequential Tasks

  1. Introduction
    1. Arduino
    2. Interrupts
  2. Simple Tasks
  3. Multiple Tasks
  4. Communicating Tasks
  5. Communicating Values
  6. Synchronising Tasks
  7. Buffered Communication
  8. Multiple Senders
  9. Conditional Tasks
  10. Transput
  11. Implementation
    1. Common Data
    2. Tasks
    3. task_builder
    4. task
    5. channel
    6. virtual_machine
    7. set
    8. queue
    9. clock
    10. standard
    11. Adjusting Limits


Function type definitions

using action_routine  = void(*)();
using action_routine1 = void(*)(int);
using wait_condition  = bool(*)();
using wait_condition1 = bool(*)(int);
using data_source     = int(*)();
using data_sink       = void(*)(int);

These function types are used to describe simple actions to be performed by tasks, with or without a parameter, wait conditions which return boolean results, with or without a parameter, and the data source and data sink functions used by the send_to, receive_from and transput actions.

Library Initialisation and System Execution

void init_tasks();

Must be called before any other library functions.

void run_system();

Each time run_system is called, it will execute an active task until it becomes inactive. An active task is one that is not paused, waiting for some condition to become true or waiting for communication to take place. If called repeatedly, e.g. in the standard Arduino loop function, it will keep executing tasks forever or until they all become inactive or execute terminate actions.

Channel and Task Creation

byte new_channel();

Creates a new channel and returns a byte value used to identify it.

byte new_task();

byte new_task(action_routine initial_action);

byte new_task(action_routine1 initial_action, int data);

int  end_task();

There are three variants of the new_task function for creating tasks with or without initial action routines. A call to any of these functions must be followed by a sequence of calls to any of the action functions defined below, and followed by a call of the end_task function. Note: the new_task function returns a byte value which represents the identifier the new task, but this is not used outside the library by the current set of facilities.

The end of a task definition is marked by calling end_task. This adds an action to the code array which will cause the task to loop back to its first action after it has executed the final one. It also adds the task to the active_tasks queue so that it will be executed when the system runs.

void set_task_data(int data);

int  get_task_data();

A data value can be associated with any task by calling set_task_data after a call of one of the new_task functions and before the final call of end_task. The data value can be retrieved while the task is running by calling get_task_data in any action routine, wait condition, data source or data sink function.

Action Functions

The following functions are used to specify the actions tasks are to perform. They have all been described in previous sections and are implemented as described in the task_builder section.

void action(action_routine routine);

void action(action_routine1 routine, int data);

void wait(wait_condition condition);

void wait(wait_condition1 condition, int data);

void pause(int interval);

void send_on(byte receiver_id);

void send_on(byte receiver_id, data_source source);

void receive_from(byte sender_id);

void receive_from(byte sender_id, data_sink sink);

void transput(byte input, data_sink sink, byte output, data_source source);

void transput(byte input, byte output, data_source source);

void transput(byte input, data_sink sink, byte output);

void transput(byte input, byte output);

void when(wait_condition condition);

void repeat(wait_condition condition);

void terminate();


These functions allow tasks to independently request that a serial connection is opened or closed. If a baud_rate is specified, the default serial port is opened at that rate. If more than one call is made, the baud_rate specified in the first one takes precedence, but otherwise no problems result. This is contrary to the behaviour of the standard Arduino Serial class where multiple initialisations can cause problems.

Calling init_serial without a baud_rate parameter, flushes the serial buffer and closes the port.

void init_serial(int baud_rate);

void init_serial();

When called with an integer parameter, the init_serial function allows a task to set-up the serial port without having to be aware of whether or not other tasks are using it. Serial output from a number of tasks will simply be interleaved when viewed on a serial monitor. The baud_rate used will be established by the first task to call init_serial. In general, it is a good idea to pass the required baud_rate as a parameter to the task definition function of any task that generates serial output. This allows pre-existing tasks which generate serial output to be composed together in a modular fashion.