Skip to content

API Task Scheduler

Anatoli Arkhipenko edited this page Sep 24, 2021 · 30 revisions

TASK SCHEDULER:


CREATION:

  • Scheduler()
Scheduler();

Default constructor. Takes no parameters. Creates task scheduler with default parameters and an empty task queue.

  • void init()
void init();

Initializes the task queue and scheduler parameters, Executed as part of constructor, so don't need to be explicitly called after creation.
Note: be default (if compiled with _TASK_TIMECRITICAL enabled) scheduler is allowed to put processor to IDLE sleep mode. If this behavior was changed via allowSleep() method, init() will NOT reset allow sleep particular parameter.

  • void addTask(Task& aTask)
void addTask(Task& aTask);

Adds task aTask to the execution queue (or chain) of tasks by appending it to the end of the chain. If two tasks are scheduled for execution, the sequence will match the order in which tasks were appended to the chain. However, in reality, due to different timing of task execution, the actual order may be different.
Note: Currently, changing the execution sequence in a chain dynamically is not supported.
If you need to reorder the chain sequence – initialize the scheduler and re-add the tasks in a different order.

  • void deleteTask(Task& aTask)
void deleteTask(Task& aTask);

Deletes task aTask from the execution chain. The chain of remaining tasks is linked together (i.e if original task chain is 1 → 2 → 3 → 4, deleting 3 will result in 1 → 2 → 4).
Note: it is not required to delete a task from the chain. A disabled task will not be executed anyway, but you save a few microseconds per scheduling pass by deleting it, since it is not even considered for execution.
An example of proper use of this method would be running some sort of initialize task in the chain, and then deleting it from the chain since it only needs to run once.

  • void allowSleep(bool aState)
void allowSleep(bool aState);

Available in the API only if compiled with _TASK_SLEEP_ON_IDLE_RUN enabled.

Controls whether scheduler is allowed (aState = true), or not (aState = false) to put processor into IDLE sleep mode in case not tasks are scheduled to run.
The default behavior of scheduler upon creation is to allow sleep mode.

  • void setSleepMethod(SleepCallback aCallback)
void setSleepMethod(SleepCallback aCallback);

Available in the API only if compiled with _TASK_SLEEP_ON_IDLE_RUN enabled.

Allows control over how the microcontroller invokes IDLE SLEEP function. As a reminder: IDLE SLEEP is considered by Task Scheduler if after checking all the tasks in the execution chain none were found ready to invoke their callback methods. Such run is considered to be an "idle" run. Since Task Scheduler default scheduling resolution is 1 millisecond, such situation means none of the tasks are scheduled as 'immediate', and it is safe to assume nothing will change for the next 1 millisecond.

Under such conditions, Task Scheduler calls a custom supplied method which implements IDLE sleep function specific to a particular microcontroller and/or a use case.

Functional prototype for the callback method is as follows:

SleepCallback customCallback (unsigned long aDeltaTime);

The aDeltaTime variable is set to the number of microseconds TaskScheduler was active in the execution pass. This time interval could be evaluated by the callback method to perform a more precise scheduling.

Please refer to example 23 for details.

  • void enableAll(bool aRecursive = true)
  • void disableAll(bool aRecursive = true)
void enableAll(bool aRecursive = true);
void disableAll(bool aRecursive = true);

enables and disables (respectively) all tasks in the chain. Convenient if your need to enable/disable majority of the tasks (i.e. disable all and then enable one).
If support for layered task priority is enabled, supplying aRecursive parameter will enable/disable higher priority tasks as well (true, default), or tasks only on this priority layer (false).

  • Task* getCurrentTask()
Task* getCurrentTask();

Returns a pointer to the task, currently executing via execute() loop OR for OnEnable and OnDisable methods, reference to the task being enabled or disabled.
This distinction is important because one task can activate the other, and OnEnable should be referring to the task being enabled, not being executed.
Could be used by callback methods to identify which Task actually invoked this callback method.

Please NOTE: The use of the previous form Task& currentTask() is deprecated (but still supported for backward compatibility)

  • Task* getFirstTask()
Task* getFirstTask();

If compiled with _TASK_EXPOSE_CHAINoption, returns pointer to the first task in the execution chain of the current scheduler.

  • Task* getLastTask()
Task* getLastTask();

If compiled with _TASK_EXPOSE_CHAINoption, returns pointer to the last task in the execution chain of the current scheduler.

  • void* currentLts()
void* currentLts();

Returns pointer to Local Task Storage of the task, currently executing via execute() loop OR for OnEnable and OnDisable methods, task being enabled or disabled.

  • void startNow (bool aRecursive = true)
void startNow (bool aRecursive = true);

Sets ALL active tasks in the execution chain to start execution immediately. Should be placed at the end of setup() method to prevent task execution race due to long running setup tasks (hardware initialization, etc.) following task activation.
If support for layered task priority is enabled, supplying aRecursive parameter will set immediate execution for higher priority tasks as well (true, default), or tasks only on this priority layer (false).
NOTE: if setup() method does not contain long running tasks, use of startNow() method is not necessary. Alternatively, all tasks could be enabled after long-running setup() processes, thus eliminating the need to use startNow() method.
NOTE: Any tasks which should execute after a delay, should be explicitly delayed after call to startNow() method.

  • long timeUntilNextIteration (Task& aTask)
long timeUntilNextIteration (Task& aTask);

Inquire when a particular Task is scheduled to run next time.
Returns time in millis (or micros) until the next scheduled iteration of a task.
Returns 0 if next iteration is already due (or overdue).
Returns -1 if a Task is not active or waiting on an event, and next iteration runtime cannot be determined.

  • bool execute()
bool execute();

Executes one scheduling pass, including (in case of the base priority scheduler) end-of-pass sleep. This method should be placed inside the loop() method of the sketch. Since execute exits after every pass, you can put additional statements after execute inside the loop().

If layered task prioritization is enabled, all higher priority tasks will be evaluated and invoked by the base execute() method. There is no need to call execute() of the higher priority schedulers explicitly.

Generally, base priority execute will perform the following steps:

  1. Call higher priority scheduler's execute method, if provided.
  2. Ignore task completely if it is disabled.
  3. Disable task if it ran out of iterations (calling OnDisable, if necessary).
  4. Check if task is waiting on a StatusRequest object, and make appropriate scheduling arrangements
  5. Perform necessary timing calculations
  6. Invoke task's callback method, if it is time to do so, and one is provided.
  7. Put microcontroller to sleep (if requested and supported) if none of the tasks were invoked.

Please NOTE: schedule-related calculations are performed prior to task's callback method invocation. This allows tasks to manipulate their runtime parameters (like execution interval) directly.

  • bool isOverrun()
bool isOverrun();

If library is compiled with _TASK_TIMECRITICAL enabled, this method returns true if currently invoked task has overrun its scheduled start time when it was invoked. Returns false if task has been invoked according to schedule.


CONTROL:

  • void enable()
void enable();

Starts scheduling (following the previous disable directive).

** NOTE: enable/disable completely stops scheduling of the tasks on this priority level and immediately returns from execute method without evaluating idle sleep conditions.

  • void disable()
void disable();

Stops scheduling (following the previous enable directive).

** NOTE: enable/disable completely stops scheduling of the tasks on this priority level and immediately returns from execute method without evaluating idle sleep conditions.

** NOTE: Upon creation, a scheduler object is enabled.

  • void resume()
void resume();

Resumes scheduling (following the previous pause directive).

** NOTE: pause/resume stop the execution of callback methods (and StatusRequest objects), but still evaluate sleep conditions and put microcontroller to sleep if this feature is enabled.

  • void pause()
void pause();

Pauses scheduling (following the previous resume directive).

** NOTE: pause/resume stop the execution of callback methods (and StatusRequest objects), but still evaluate sleep conditions and put microcontroller to sleep if this feature is enabled.


TASK PRIORITY:

  • void setHighPriorityScheduler(Scheduler* aScheduler)
void setHighPriorityScheduler(Scheduler* aScheduler);

If library is compiled with _TASK_PRIORITY enabled, this method associates current scheduler with a higher priority scheduler.

**NOTE: **Only one execute() method needs to be explicitly called in the main loop(). That is the execute method of base priority scheduler. All higher priority schedulers are called by the base priority scheduler.

  • static Scheduler& currentScheduler()
static Scheduler& currentScheduler();

If library is compiled with _TASK_PRIORITY enabled, this method returns reference to a scheduler, which invoked current task.

NOTE: Please refer to examples 11 and 12 for illustration of Task Priority functionality


CPU LOAD MONITORING:

CPU load monitoring methods are available only when the library is compiled with _TASK_PRIORITY option. It allows assessing how much CPU time is spent scheduling the tasks and how much time is spent in IDLE sleep mode. Compared to a total CPU time since the last reset of the statistics engine, you can assess how much processing power you still have available (or not) for your tasks.

Generally CPU Load Total = CPU Load Cycle + CPU Load Idle + Other productive work

Other productive work includes time spent in call back methods and other OS related tasks (WiFi stack, Serial communications, etc.)

  • void cpuLoadReset()
void cpuLoadReset();

This method resets the CPU monitoring variables to their initial values and restarts CPU load monitoring.

NOTE: All statistics are presented in microseconds using micros() method. Because micros() is unsigned long, it rolls over (resets to 0) approximately every 72 minutes. It is necessary to call cpuLoadReset() once every hour or so to reset statistics collection. Otherwise, after 72 minutes, the statistics will change drastically and will present incorrect information.

  • void getCpuLoadCycle()
void getCpuLoadCycle();

This method returns a number of microseconds spent in scheduling overhead since the last reset of CPU load statistics. This number does not include the runtime of the callback methods - just the time spent by a scheduler in preparation and post-processing of the task scheduling.

  • void getCpuLoadIdle()
void getCpuLoadIdle();

This method returns a number of microseconds spent in IDLE Sleep mode since the last reset of CPU load statistics. If IDLE sleep is not supported (i.e., esp8266 or esp32) then a number of microseconds in the delay method is used (delay while yielding to the WiFi stack processing).

  • void getCpuLoadTotal()
void getCpuLoadTotal();

This method returns a total number of microseconds since the last reset of CPU load statistics. This number is important for detemination of relative time spent in idle vs. processing mode.


  • CONSTANTS

TASK_SECOND (1.000 millis or 1.000.000 micros) Task interval of 1 second
TASK_MINUTE (60.000 millis or 60.000.000 micros) Task interval of 1 minute
TASK_HOUR (3.600.000 millis or 3.600.000.000 micros) Task interval of 1 hour
TASK_FOREVER (-1) Task number of iterations for the infinite number of iterations
TASK_ONCE (1) Task single iteration
TASK_IMMEDIATE (0) Task interval for immediate execution
_TASK_ESP8266_DLY_THRESHOLD (200L)
_TASK_ESP32_DLY_THRESHOLD (200L) idle sleep threshold value for ESP chips. If one pass through the scheduler takes less than a threshold value, a one millisecond delay (and yield to the OS) is invoked.