Add back task features in a simplified way

This commit is contained in:
Steins7 2024-07-09 11:53:05 +02:00
parent b7951f2211
commit 173e16eb2e
2 changed files with 132 additions and 36 deletions

View File

@ -10,36 +10,50 @@
#include "task.h" #include "task.h"
#include "error.h" #include "error.h"
#include "../drv/stk.h"
//--local definitions----------------------------------------------------------- //--local definitions-----------------------------------------------------------
#define MAX_TASK_NB 10 #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------------------------------------------------------------- //--local variables-------------------------------------------------------------
static struct Task task_list[MAX_TASK_NB]; static struct Task task_list[MAX_TASK_NB];
static uint8_t task_nb; static uint8_t task_nb;
static volatile bool stk_irq;
static volatile bool rtc_irq;
static volatile uint32_t timestamp;
//--public functions------------------------------------------------------------ //--public functions------------------------------------------------------------
void task_schedule(uint32_t elapsed_ms) 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) { for (uint8_t i = 0; i < task_nb; ++i) {
if (task_list[i].function != nullptr) { stk_needed |= execute_task(&task_list[i], triggers);
if (task_list[i].state.is_active
|| task_list[i].state.delay <= 0) {
task_list[i].function(&task_list[i].state);
if (task_list[i].state.count == _TASK_COUNT_EXIT) {
task_list[i].function = nullptr;
} }
if (stk_needed) {
stk_start();
__asm("wfi");
} else { } else {
task_list[i].state.delay -= elapsed_ms; stk_stop();
} //TODO: enter deep sleep
} }
} }
} }
@ -50,9 +64,8 @@ void task_start(TaskFunction function)
if (task_list[i].function == nullptr) { if (task_list[i].function == nullptr) {
task_list[i].function = function; task_list[i].function = function;
task_list[i].state.delay = 0; task_list[i].state.timestamp = 0;
task_list[i].state.count = 0; task_list[i].state.count = 0;
task_list[i].state.is_active = false;
++task_nb; ++task_nb;
return; return;
@ -66,8 +79,8 @@ void task_stop(TaskFunction function)
{ {
for (uint8_t i = 0; i < task_nb; ++i) { for (uint8_t i = 0; i < task_nb; ++i) {
if (task_list[i].function == function) { if (task_list[i].function == function) {
task_list[i].state.count = _TASK_COUNT_CLEANUP & 0x7F; task_list[i].state.count = _TASK_COUNT_CLEANUP & 0x1F;
task_list[i].function(&task_list[i].state); task_list[i].function(&task_list[i].state, timestamp);
task_list[i].function = nullptr; task_list[i].function = nullptr;
return; return;
@ -88,3 +101,42 @@ bool task_is_running(TaskFunction function)
return false; 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;
}

View File

@ -17,13 +17,21 @@
//--type definitions------------------------------------------------------------ //--type definitions------------------------------------------------------------
struct TaskState { enum TaskTrigger {
int32_t delay; TASK_TRIGGER_ANY,
uint8_t count:7; TASK_TRIGGER_STK,
uint8_t is_active:1; TASK_TRIGGER_RTC,
TASK_TRIGGER_BOTH,
}; };
typedef void(*TaskFunction)(struct TaskState*); 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 { struct Task {
TaskFunction function; TaskFunction function;
@ -33,10 +41,12 @@ struct Task {
//--functions------------------------------------------------------------------- //--functions-------------------------------------------------------------------
#define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state) #define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state, \
uint32_t __task_time)
#define TASK_ENTRY \ #define TASK_ENTRY \
_TASK_COUNT_INIT; \ _TASK_COUNT_INIT; \
(void*) __task_time; \
switch (__task_state->count) { switch (__task_state->count) {
#define TASK_CLEANUP \ #define TASK_CLEANUP \
@ -45,19 +55,22 @@ struct Task {
#define TASK_EXIT \ #define TASK_EXIT \
} \ } \
__task_state->count = _TASK_COUNT_EXIT; \ __task_state->count = _TASK_COUNT_EXIT & 0x1F; \
return; return;
#define TASK_TIMEOUT #define TASK_TIMEOUT (__task_state->timeout == 0)
#define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR) #define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR)
#define TASK_SLEEP(delay_ms) _TASK_SLEEP(delay_ms, _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_YIELD_UNTIL(cond) _TASK_YIELD_UNTIL(cond, _TASK_COUNT_INCR)
#define TASK_SLEEP_UNTIL(cond, delay_ms) \ #define TASK_PAUSE_UNTIL(cond, delay_ms) \
_TASK_SLEEP_UNTIL(cond, delay_ms, _TASK_COUNT_INCR) _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) #define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR)
void task_schedule(uint32_t elapsed_ms); void task_start_scheduler(void);
void task_declare(); void task_declare();
@ -70,19 +83,30 @@ bool task_is_running(TaskFunction task);
#define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ } #define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ }
#define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1) #define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1)
#define _TASK_COUNT_EXIT (UINT8_MAX & 0x7F) #define _TASK_COUNT_EXIT (UINT8_MAX & 0x3F)
#define _TASK_COUNT_CLEANUP (UINT8_MAX - 1) #define _TASK_COUNT_CLEANUP (UINT8_MAX - 1)
#define _TASK_YIELD(count_val) do { \ #define _TASK_YIELD(count_val) do { \
__task_state->count = count_val; \ __task_state->count = count_val; \
__task_state->trigger = TASK_TRIGGER_ANY; \
return; \ return; \
case (count_val): \ case (count_val): \
/* fall through */ \ /* fall through */ \
} while (0) } while (0)
#define _TASK_SLEEP(delay_ms, count_val) do { \ #define _TASK_PAUSE(delay_ms, count_val) do { \
__task_state->count = count_val; \ __task_state->count = count_val; \
__task_state->delay = delay_ms; \ __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; \ return; \
case (count_val): \ case (count_val): \
/* fall through */ \ /* fall through */ \
@ -90,6 +114,7 @@ bool task_is_running(TaskFunction task);
#define _TASK_YIELD_UNTIL(cond, count_val) do { \ #define _TASK_YIELD_UNTIL(cond, count_val) do { \
__task_state->count = count_val; \ __task_state->count = count_val; \
__task_state->trigger = TASK_TRIGGER_ANY; \
case (count_val): \ case (count_val): \
if (!(cond)) { \ if (!(cond)) { \
return; \ return; \
@ -97,20 +122,39 @@ bool task_is_running(TaskFunction task);
/* fall through */ \ /* fall through */ \
} while (0) } while (0)
#define _TASK_SLEEP_UNTIL(cond, delay_ms, count_val) do { \ #define _TASK_PAUSE_UNTIL(cond, delay_ms, count_val) do { \
__task_state->count = count_val; \ __task_state->count = count_val; \
__task_state->delay = delay_ms; \ __task_state->timestamp = __task_time + delay_ms; \
__task_state->is_active = true; \ __task_state->trigger = TASK_TRIGGER_STK; \
case (count_val): \ __task_state->timeout_mode = true; \
if (!(cond) && __task_state->delay >= 0) { \ } \
return; \ 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; \
} \ } \
__task_state->is_active = false; \
/* fall through */ \ /* fall through */ \
} while (0) } while (0)
#define _TASK_EXECUTE(task, count_val) do { \ #define _TASK_EXECUTE(task, count_val) do { \
__task_state->count = count_val; \ __task_state->count = count_val; \
__task_state->trigger = TASK_TRIGGER_ANY; \
task_start(Task task); \ task_start(Task task); \
return; \ return; \
case (count_val): \ case (count_val): \