/** @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 "../drv/stk.h" #include "error.h" //--local definitions----------------------------------------------------------- #define MAX_TASK_NB 10 struct TaskContext { Task function; uint32_t delay_ms; uint8_t state; uint8_t priority; }; void task_callback(void); //--local variables------------------------------------------------------------- static struct TaskContext task_list[MAX_TASK_NB]; static uint8_t task_nb; //--public functions------------------------------------------------------------ void task_start_scheduler(void) { while (1) { uint32_t delay = UINT32_MAX; for (uint8_t priority = 0; priority < UINT8_MAX; ++priority) { bool task_runned = false; for (uint8_t i = 0; i < task_nb; ++i) { if (task_list[i].function != nullptr) { if (task_list[i].priority == priority) { if (task_list[i].delay_ms == 0) { task_runned = true; struct TaskReturn ret = task_list[i].function(task_list[i].state); if (ret.state == _TASK_COUNT_EXIT) { task_list[i].function = nullptr; } else { task_list[i].delay_ms = ret.delay_ms; task_list[i].state = ret.state; } } if (delay > task_list[i].delay_ms) { delay = task_list[i].delay_ms; } } } } if (task_runned) { break; } } if (delay > 0) { stk_configure(delay * 1000, task_callback); stk_start(); __asm("wfi"); stk_stop(); uint32_t stk_delay = stk_read_us(); if (stk_delay != 0) { delay = stk_delay; } for (uint8_t i = 0; i < task_nb; ++i) { if (task_list[i].function != nullptr) { task_list[i].delay_ms -= delay; } } } } //never returns } void task_start(Task task, uint8_t priority) { for (uint8_t i = 0; i < MAX_TASK_NB; ++i) { if (task_list[i].function == nullptr) { task_list[i].function = task; task_list[i].delay_ms = 0; task_list[i].state = 0; task_list[i].priority = priority; ++task_nb; return; } } error_trigger("task list is full"); } void task_stop(Task task) { for (uint8_t i = 0; i < task_nb; ++i) { if (task_list[i].function == task) { task_list[i].function(_TASK_COUNT_CLEANUP); task_list[i].function = nullptr; return; } } error_trigger("task does not exist"); } bool task_is_running(Task task) { for (uint8_t i = 0; i < task_nb; ++i) { if (task_list[i].function == task) { return true; } } return false; } //--local functions------------------------------------------------------------- void task_callback(void) { stk_stop(); }