73941da6b1
为 task_watchdog.c 的判定逻辑(位图取走清零 / 必需掩码 0x37 判定 / miss_streak 连续 8 次停喂 / 100ms 抽样节流 / tick 回绕安全)补一层 主机侧纯逻辑单元测试,弥补此前只能靠真机或模拟器才能发现回归的空白。 架构(沿用项目既有"共享核心 + 平台后端"做法,参照 cfg_file_store): - task_watchdog.h 末段新增"平台后端(内部)"声明 3 个钩子 (wd_platform_feed / _start / _tick_ms),MCU 端以 __weak 提供默认实现, 行为与重构前逐字一致(@build 0 错误 0 警告,Flash +20B)。 - 主机侧单测以同名强符号覆盖三钩子,即可离线注入/观测,无需碰 MCU 代码。 - 测试文件 #include 生产源文件本身,保证测的是真代码而非副本。 - 测试专用复位 task_wd_test_reset() 仅 TASK_WATCHDOG_UNIT_TEST 下编入, MCU 构建零代码零符号。 测试(test/host/watchdog/,MSVC 离线编译,纯标准库驱动): - 39 项断言全过(退出码 0);注入故障可复现退出码 1。 - run_unit_test.py 直接拼 INCLUDE/LIB 调 cl.exe,绕开本机被禁的 reg.exe。 - stub/ 三桩头覆盖 main.h / iwdg.h / dbg_log.h。 门禁:pre-commit 新增 watchdog-unit-test 本地钩子(L0.5 层),仅被测文件 或其测试变动时触发;测试开发标准流程.md 新增 L0.5 层说明。 顺带改善:task_watchdog.c 的节流基线 s_last_tick 由函数内 static 提为文件 static(可测性 + 模块状态归一)。
126 lines
4.5 KiB
C
126 lines
4.5 KiB
C
/*
|
||
* 模块名称:Task Watchdog(IWDG + 任务心跳位图)
|
||
* 模块功能:独立看门狗与"全部任务存活"绑定的对外接口
|
||
* 适用平台:STM32F407ZGTx + FreeRTOS(CMSIS-RTOS V2)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-09-29
|
||
* 修改记录:
|
||
* v1.0 2026-09-29 王建锋 创建
|
||
*
|
||
* 设计依据:docs/子系统设计/看门狗设计说明.md
|
||
*/
|
||
|
||
#ifndef TASK_WATCHDOG_H
|
||
#define TASK_WATCHDOG_H
|
||
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/*
|
||
* 任务 ID(位序号 = 心跳位图上的位置,与必需掩码一一对应)
|
||
* 顺序一旦确定不要插空/改动,掩码是编译期常量
|
||
*/
|
||
typedef enum {
|
||
TASK_WD_DEFAULT = 0,
|
||
TASK_WD_NET = 1,
|
||
TASK_WD_FTP = 2,
|
||
TASK_WD_TEST = 3,
|
||
TASK_WD_UI = 4,
|
||
TASK_WD_TIMESYNC = 5,
|
||
TASK_WD_ID_MAX
|
||
} task_wd_id_t;
|
||
|
||
/*
|
||
* 函数功能:任务心跳置位(各任务在自己主循环里调用)
|
||
* 入口参数:id - 任务 ID
|
||
* 返回值:无
|
||
* 限定条件:任意上下文可调(单字原子写、无内核对象依赖)
|
||
* 函数说明:仅 1~2 条指令,无锁、无阻塞,可放在中断外任意位置。
|
||
*/
|
||
void task_wd_beat(task_wd_id_t id);
|
||
|
||
/*
|
||
* 函数功能:启动 IWDG(**延后启动**)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:仅 defaultTask 在存储 bring-up 完成后调用一次
|
||
* 函数说明:MX_IWDG_Init() 只填参数不启动(原因见 Src/iwdg.c 的
|
||
* IWDG_DEFER_START 注释:HAL_IWDG_Init 内部会立即启动,而它被
|
||
* CubeMX 插在 app_main_init 之前,那段无喂狗点且耗时可达数秒)。
|
||
* 本函数才真正启动,使"启动段不喂狗、主循环段才喂"成立。
|
||
*/
|
||
void task_wd_start(void);
|
||
|
||
/*
|
||
* 函数功能:心跳抽样与喂狗判定
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:仅 defaultTask 主循环调用(唯一喂狗者)
|
||
* 函数说明:内部节流至 100ms 一次。全员到位才喂狗;连续 800ms 有任务
|
||
* 缺席则停止喂狗,由 IWDG 自然溢出复位(保留 IWDGRSTF 权威归因)。
|
||
*/
|
||
void task_wd_poll(void);
|
||
|
||
/* 观测接口(自检 / 串口报告用) */
|
||
uint32_t task_wd_last_mask(void); /* 上次抽样到的位图(0 位 = 缺席任务) */
|
||
uint32_t task_wd_miss_count(void); /* 累计未达标轮数 */
|
||
uint32_t task_wd_is_armed(void); /* 1 = IWDG 已启动 */
|
||
|
||
/*
|
||
* ============================ 平台后端(内部) ============================
|
||
* 把判定状态机中的硬件访问收敛到三个薄钩子,使"取走清零 / 掩码判定 / 缺失
|
||
* 累计 / 节流"成为纯逻辑,可在主机侧用桩替换后离线穷举验证
|
||
* (见 test/host/watchdog/ 与 docs/测试说明/看门狗单元测试说明.md)。
|
||
*
|
||
* 与 App/cfg/cfg_file_store.h 的"共享核心 + 平台后端"同款做法:
|
||
* - 三者由 task_watchdog.c 以 __weak 提供 MCU 默认实现(读写 IWDG 寄存器 /
|
||
* 调 HAL_GetTick),**行为与不抽钩子时逐字一致**;
|
||
* - 主机侧单测提供同名**强符号**覆盖 → 不碰 MCU 代码即可观测/注入;
|
||
* - MCU 构建零行为变化。
|
||
*
|
||
* ⚠ 非模块对外接口,业务代码**不要**直接调用(由 task_wd_* 间接使用)。
|
||
* ========================================================================
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:重装 IWDG 计数器(喂狗)
|
||
* 返回值:无
|
||
* 函数说明:MCU 默认实现 = `IWDG->KR = 0x0000AAAAu;`
|
||
* 主机侧单测覆盖此符号以记录"何时被喂"。
|
||
*/
|
||
void wd_platform_feed(void);
|
||
|
||
/*
|
||
* 函数功能:启动 IWDG(不可逆,启动后只能靠复位停止)
|
||
* 返回值:无
|
||
* 函数说明:MCU 默认实现 = `IWDG->KR = 0x0000CCCCu;`
|
||
*/
|
||
void wd_platform_start(void);
|
||
|
||
/*
|
||
* 函数功能:读单调毫秒时基(用于 100ms 抽样节流)
|
||
* 返回值:自启动以来的毫秒计数(32 位回绕安全,用无符号差比较)
|
||
* 函数说明:MCU 默认实现 = `HAL_GetTick()`
|
||
* 主机侧单测覆盖此符号以驱动时间推进。
|
||
*/
|
||
uint32_t wd_platform_tick_ms(void);
|
||
|
||
/*
|
||
* 函数功能:复位判定状态机(**仅主机侧单元测试使用**)
|
||
* 返回值:无
|
||
* 函数说明:仅当定义 TASK_WATCHDOG_UNIT_TEST 时编入(MCU 构建无此符号)。
|
||
* 用于在用例之间清空位图/计数/节流基线,保证用例互不污染。
|
||
*/
|
||
#ifdef TASK_WATCHDOG_UNIT_TEST
|
||
void task_wd_test_reset(void);
|
||
#endif
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* TASK_WATCHDOG_H */
|