/** @file task.h * 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 */ #ifndef _task_h_ #define _task_h_ //--includes-------------------------------------------------------------------- #include #include //--type definitions------------------------------------------------------------ enum TaskTrigger { TASK_TRIGGER_ANY, TASK_TRIGGER_STK, TASK_TRIGGER_RTC, TASK_TRIGGER_BOTH, }; struct TaskState { uint32_t timestamp; uint8_t count:5; enum TaskTrigger trigger:2; uint8_t timeout_mode:1; }; typedef void(*TaskFunction)(struct TaskState*, uint32_t); struct Task { TaskFunction function; struct TaskState state; }; //--functions------------------------------------------------------------------- #define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state, \ uint32_t __task_time) #define TASK_ENTRY \ _TASK_COUNT_INIT; \ (void*) __task_time; \ switch (__task_state->count) { #define TASK_CLEANUP \ case (_TASK_COUNT_CLEANUP): \ /* fall through */ #define TASK_EXIT \ } \ __task_state->count = _TASK_COUNT_EXIT & 0x1F; \ return; #define TASK_TIMEOUT (__task_state->timeout == 0) #define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR) #define TASK_PAUSE(delay_ms) _TASK_PAUSE(delay_ms, _TASK_COUNT_INCR) #define TASK_SLEEP(delay_s) _TASK_SLEEP(delay_s, _TASK_COUNT_INCR) #define TASK_YIELD_UNTIL(cond) _TASK_YIELD_UNTIL(cond, _TASK_COUNT_INCR) #define TASK_PAUSE_UNTIL(cond, delay_ms) \ _TASK_PAUSE_UNTIL(cond, delay_ms, _TASK_COUNT_INCR) #define TASK_SLEEP_UNTIL(cond, delay_s) \ _TASK_SLEEP_UNTIL(cond, delay_s, _TASK_COUNT_INCR) #define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR) void task_start_scheduler(void); uint32_t task_current_time(void); void task_start(TaskFunction task); void task_stop(TaskFunction task); bool task_is_running(TaskFunction task); //--internal_functions---------------------------------------------------------- #define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ } #define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1) #define _TASK_COUNT_EXIT (UINT8_MAX & 0x3F) #define _TASK_COUNT_CLEANUP (UINT8_MAX - 1) #define _TASK_YIELD(count_val) do { \ __task_state->count = count_val; \ __task_state->trigger = TASK_TRIGGER_ANY; \ return; \ case (count_val): \ /* fall through */ \ } while (0) #define _TASK_PAUSE(delay_ms, count_val) do { \ __task_state->count = count_val; \ __task_state->timestamp = __task_time + delay_ms; \ __task_state->trigger = TASK_TRIGGER_STK; \ return; \ case (count_val): \ /* fall through */ \ } while (0) #define _TASK_SLEEP(delay_s, count_val) do { \ __task_state->count = count_val; \ __task_state->timestamp = __task_time + delay_s * 1000; \ __task_state->trigger = TASK_TRIGGER_RTC; \ return; \ case (count_val): \ /* fall through */ \ } while (0) #define _TASK_YIELD_UNTIL(cond, count_val) do { \ __task_state->count = count_val; \ __task_state->trigger = TASK_TRIGGER_ANY; \ case (count_val): \ if (!(cond)) { \ return; \ } \ /* fall through */ \ } while (0) #define _TASK_PAUSE_UNTIL(cond, delay_ms, count_val) do { \ __task_state->count = count_val; \ __task_state->timestamp = __task_time + delay_ms; \ __task_state->trigger = TASK_TRIGGER_STK; \ __task_state->timeout_mode = true; \ case (count_val): \ if (!(cond) && __task_state->timestamp != 0) { \ return; \ } else { \ __task_state->timeout_mode = false; \ } \ /* fall through */ \ } while (0) #define _TASK_SLEEP_UNTIL(cond, delay_s, count_val) do { \ __task_state->count = count_val; \ __task_state->timestamp = __taks_time + delay_s * 1000; \ __task_state->trigger = TASK_TRIGGER_RTC; \ __task_state->timeout_mode = true; \ case (count_val): \ if (!(cond) && __task_state->timestamp != 0) { \ return; \ } else { \ __task_state->timeout_mode = false; \ } \ /* fall through */ \ } while (0) #define _TASK_EXECUTE(task, count_val) do { \ __task_state->count = count_val; \ __task_state->trigger = TASK_TRIGGER_ANY; \ task_start(Task task); \ return; \ case (count_val): \ if (task_is_running(task)) { \ return; \ } \ /* fall through */ \ } while (0) #endif //_task_h_