143 lines
2.9 KiB
C
143 lines
2.9 KiB
C
/** @file task.c
|
|
* Module handling the task creation and management
|
|
*
|
|
* The module provides an API to create, run and manage lightweight, stack-less
|
|
* threads (tasks). This system is based on protothreads,
|
|
* see https://dunkels.com/adam/pt/index.html
|
|
*/
|
|
|
|
//--includes--------------------------------------------------------------------
|
|
|
|
#include "task.h"
|
|
#include "error.h"
|
|
#include "../drv/stk.h"
|
|
|
|
|
|
//--local definitions-----------------------------------------------------------
|
|
|
|
#define MAX_TASK_NB 10
|
|
|
|
static bool execute_task(struct Task* restrict task, uint8_t triggers);
|
|
static void callback_stk(void);
|
|
static void callback_rtc(void);
|
|
|
|
|
|
//--local variables-------------------------------------------------------------
|
|
|
|
static struct Task task_list[MAX_TASK_NB];
|
|
static uint8_t task_nb;
|
|
static volatile bool stk_irq;
|
|
static volatile bool rtc_irq;
|
|
static volatile uint32_t timestamp;
|
|
|
|
|
|
//--public functions------------------------------------------------------------
|
|
|
|
void task_start_scheduler(void)
|
|
{
|
|
stk_configure(1000, callback_stk);
|
|
//TODO: configure RTC
|
|
|
|
while (true) {
|
|
uint8_t triggers = stk_irq << 0 | rtc_irq << 1;
|
|
stk_irq = false;
|
|
rtc_irq = false;
|
|
bool stk_needed = false;
|
|
|
|
for (uint8_t i = 0; i < task_nb; ++i) {
|
|
stk_needed |= execute_task(&task_list[i], triggers);
|
|
}
|
|
|
|
if (stk_needed) {
|
|
stk_start();
|
|
__asm("wfi");
|
|
} else {
|
|
stk_stop();
|
|
//TODO: enter deep sleep
|
|
}
|
|
}
|
|
}
|
|
|
|
void task_start(TaskFunction function)
|
|
{
|
|
for (uint8_t i = 0; i < MAX_TASK_NB; ++i) {
|
|
if (task_list[i].function == nullptr) {
|
|
|
|
task_list[i].function = function;
|
|
task_list[i].state.timestamp = 0;
|
|
task_list[i].state.count = 0;
|
|
|
|
++task_nb;
|
|
return;
|
|
}
|
|
}
|
|
|
|
error_trigger("task list is full");
|
|
}
|
|
|
|
void task_stop(TaskFunction function)
|
|
{
|
|
for (uint8_t i = 0; i < task_nb; ++i) {
|
|
if (task_list[i].function == function) {
|
|
task_list[i].state.count = _TASK_COUNT_CLEANUP & 0x1F;
|
|
task_list[i].function(&task_list[i].state, timestamp);
|
|
task_list[i].function = nullptr;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
error_trigger("task does not exist");
|
|
}
|
|
|
|
bool task_is_running(TaskFunction function)
|
|
{
|
|
for (uint8_t i = 0; i < task_nb; ++i) {
|
|
if (task_list[i].function == function) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//--local functions-------------------------------------------------------------
|
|
|
|
static bool execute_task(struct Task* restrict task, uint8_t triggers)
|
|
{
|
|
if (task->function != nullptr) {
|
|
if (task->state.trigger == TASK_TRIGGER_ANY) {
|
|
task->function(&task->state, timestamp);
|
|
} else {
|
|
if ((task->state.trigger & triggers) != 0) {
|
|
|
|
if (task->state.timestamp <= timestamp) {
|
|
task->state.timestamp = 0;
|
|
}
|
|
|
|
if ((task->state.timestamp == 0) ||
|
|
task->state.timeout_mode) {
|
|
task->function(&task->state,
|
|
timestamp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (task->state.trigger & TASK_TRIGGER_STK) != 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void callback_stk(void)
|
|
{
|
|
stk_irq = true;
|
|
++timestamp;
|
|
}
|
|
|
|
static void callback_rtc(void)
|
|
{
|
|
rtc_irq = true;
|
|
}
|