stm32f1xx_HBL/srv/task.c
Steins7 b893a0283f Reduce task's context size
Since RTC ans STK timestamps are now different, they don't need to be as big and
be can safely reduce their size to 24 bits to save space
2024-11-03 22:53:19 +01:00

169 lines
4.4 KiB
C

/** @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
*
* Task can be viewed as a lightweight, somewhat restricted, cooperative OS.
* Tasks are runned on every events. Since the RTC is enabled by the scheduler,
* every task should be run at least once per second. If at least one task is
* currently paused, the systick is enabled and all tasks are updated every
* millisecond
*
* State machine should mainly yield (see TASK_YIELD) while time sensitive
* applications should pause (see TASK_PAUSE) instead. This configuration allows
* state machines to be updated every time something changes in the system while
* allowing the cpu to enter low power mode when possible. When time sensitive
* applications are paused, they cause the systick to start which stops the cpu
* from entering low power but making sure that the task is polled quickly
* enough. Tasks requiring longer delay and less sensitive to timings can sleep
* (see TASK_SLEEP) instead, which relies on the RTC rather than the systick
*/
//--includes--------------------------------------------------------------------
#include "task.h"
#include "error.h"
#include "../drv/stk.h"
#include "../drv/pwr.h"
#include "../drv/rcc.h"
#include "../drv/bkp.h"
#include "../drv/exti.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;
//--public functions------------------------------------------------------------
void task_start_scheduler(void)
{
stk_configure(1000, callback_stk);
rcc_configure_lsi(true);
pwr_configure_bkp_write(true);
//may need to be looked into later: basically, the RTC only wakes up the
//system 1 tick too late when using pwr_stop(). To fix that, we can use a
//tick divided by 2, but I have no idea what the underlying problem is
bkp_configure_rtc(500, BKP_RTC_CLOCK_SRC_LSI, BKP_RTC_IRQ_NONE, nullptr);
pwr_configure_bkp_write(false);
exti_configure(EXTI_LINE_RTC, EXTI_CONFIG_RISING_EDGE, callback_rtc);
pwr_configure_bkp_write(true);
bkp_set_rtc_alam(1);
pwr_configure_bkp_write(false);
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();
pwr_sleep();
} else {
stk_stop();
pwr_stop(PWR_WAKEUP_SPEED_SLOW);
}
}
}
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);
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);
} else {
if ((task->state.trigger & triggers) != 0) {
--task->state.timestamp;
if ((task->state.timestamp == 0) ||
task->state.timeout_mode) {
task->function(&task->state);
}
}
}
return (task->state.trigger & TASK_TRIGGER_STK) != 0;
}
return false;
}
static void callback_stk(void)
{
stk_irq = true;
}
static void callback_rtc(void)
{
rtc_irq = true;
pwr_configure_bkp_write(true);
bkp_set_rtc_alam(1);
pwr_configure_bkp_write(false);
}