task #5
82
srv/task.c
82
srv/task.c
@ -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;
|
||||||
|
}
|
||||||
|
|||||||
88
srv/task.h
88
srv/task.h
@ -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): \
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user