/* 五个任务的那张表(需求 §10.3)。 §10.3 定了五个任务、各自的周期与优先级,还有一句最容易被写丢的话: **`t_safety` 越界时直接操作 `EFUSE_EN` / `VBUS_EN`,不经任何队列或抽象层。** 这张表在这里的意义不是「方便建任务」,而是让那五行**有一个能被自检查的形状** —— 优先级顺序写反了不会报错,只会让巡检在总线忙的时候被挤到几十毫秒之后。 ---- 为什么周期与优先级要合在一张表里 ------------------------------------ 因为它们是同一个判断的两半:`t_safety` 之所以是最高优先级,正是因为它有一个 20 ms 的硬节拍;`t_link` 之所以最低,正是因为它没有节拍(§10.2:失联不断电, 上位机慢一点没有任何后果)。分成两处写,改了一半的那天没人看得出来。 ⚠️ 事件驱动的三个任务(actuator / link / log)在本表里 `period_ms == 0`。 它们的队列与消息定义在 A9(执行器)/ A12(命令)/ A11(日志)里,本包只搭骨架。 */ #ifndef TASKS_H #define TASKS_H #include #include #ifdef __cplusplus extern "C" { #endif typedef enum { TASK_SAFETY = 0, /* 20 ms,最高:SW-2 / SW-8 判据 + 直接操作 EN 引脚 */ TASK_THERMAL, /* 1 s,中:两路 NTC + 载板 LM75 → 风扇 PWM 闭环 */ TASK_ACTUATOR, /* 事件驱动,中:断电重启 / 按键序列 / EDL 序列 */ TASK_LINK, /* 事件驱动,低:上位机命令与遥测 */ TASK_LOG, /* 空闲,最低:事件环形缓冲落盘 */ TASK_COUNT, } task_id_t; typedef struct { const char *name; uint32_t period_ms; /* 0 = 事件驱动 */ int prio; /* FreeRTOS 优先级,越大越高 */ uint32_t stack_bytes; /* ESP-IDF 的 xTaskCreate 收的是**字节**,不是字 */ } task_desc_t; /* id 越界直接 abort。 */ const task_desc_t *task_desc(task_id_t id); /* 启动自检的一部分(和 `rail_selftest()` 一样:不过就 abort,不降级)。 查的是**表本身的形状**,不碰硬件: · 名字非空且不重复; · `t_safety` 是**唯一**的最高优先级,`t_log` 是**唯一**的最低; · thermal 与 actuator 同级(§10.3 都是「中」),link 严格低于它们、高于 log; · 周期与 §10.3 逐格相符(20 ms / 1 s / 三个 0); · `t_safety` 的周期必须长于 INA226 的一帧转换时间,否则每次读到的是同一帧 —— 现象是「电流看起来非常稳」,而不是任何一种错误。 */ bool task_table_ok(void); #ifdef __cplusplus } #endif #endif /* TASKS_H */