-
Notifications
You must be signed in to change notification settings - Fork 243
API Task Scheduler
- Scheduler()
- void init()
- void addTask(Task& aTask)
- void deleteTask(Task& aTask)
- void allowSleep(bool aState)
- void setSleepMethod(SleepCallback aCallback)
- void enableAll(bool aRecursive = true)
- void disableAll(bool aRecursive = true)
- Task& currentTask()
- void* currentLts()
- void startNow (bool aRecursive = true)
- long timeUntilNextIteration (Task& aTask)
- bool execute()
- bool isOverrun()
Scheduler();
Default constructor. Takes no parameters. Creates task scheduler with default parameters and an empty task queue.
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);
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);
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);
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);
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);
enables
and disable
s (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& currentTask();
Returns reference 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.
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);
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);
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();
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:
- Call higher priority scheduler's execute method, if provided.
- Ignore task completely if it is disabled.
- Disable task if it ran out of iterations (calling
OnDisable
, if necessary). - Check if task is waiting on a
StatusRequest
object, and make appropriate scheduling arrangements - Perform necessary timing calculations
- Invoke task's callback method, if it is time to do so, and one is provided.
- 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();
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.
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();
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 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();
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();
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();
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();
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.
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 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 1 millisend delay (and yield to the OS) is invoked.