Files

145 lines
4.4 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "wdt_task/wdt_task.h"
#if SYSTEM_TYPE == SYSTEM_TYPE_CCU601E_D
#include "iwdg.h" /* [CCU601E_D] STM32 IWDG 独立看门狗 */
#endif
#include "sys_drv_init.h"
#include "publicdata/public_define.h"
#include "mylog/mylog.h"
#include "publicdata/publicdata.h"
#define WDT_TASK_CNT ((uint8_t)MY_TASK_NUM)
#define WDT_TIMEOUT_SECONDS (300U)
#define WDT_RESET_ENABLE 0U /* 1: 超时后触发系统复位; 0: 仅钳位计数 */
static uint16_t g_wdt_evt_flag[WDT_TASK_CNT] = {0U};
#define WDT_LOG(fmt, ...) \
MYLOG_MSG(TASK_ID_WATCHDOG,fmt, ##__VA_ARGS__)
/**
* @brief 获取指定任务的看门狗计数值。
*
* 计数值含义:距离该任务最近一次调用 `v_wdt_setFlag()` 的秒数。
* 当任务ID非法时返回0。
*
* @param id 任务ID(对应 `TASK_ID` 枚举值)。
* @return uint16_t 对应任务当前计数值。
*/
uint16_t u16_get_wdt_cnt(uint8_t id)
{
if (id < WDT_TASK_CNT) {
return g_wdt_evt_flag[id];
}
return 0U;
}
/**
* @brief 清零指定任务的看门狗计数(任务喂狗)。
*
* 该函数通常由各业务任务在其主循环中周期调用,用于表明任务仍在正常运行。
* 传入ID越界时函数静默返回,不执行任何写操作。
*
* @param task_id 任务ID`TASK_ID` 枚举)。
*/
void v_wdt_setFlag(TASK_ID task_id)
{
uint8_t id = (uint8_t)task_id;
if (id < WDT_TASK_CNT) {
g_wdt_evt_flag[id] = 0U;
}
}
/**
* @brief 每秒对所有任务看门狗计数加1。
*
* 基于 `xTaskGetTickCount()` 做1秒节拍判断,避免依赖RTC/系统秒计时接口。
* 计数采用饱和累加,最大不超过 `0xFFFF`。
*/
static void v_wdt_add_timer(void)
{
static TickType_t last_tick = 0U;
TickType_t now_tick = xTaskGetTickCount();
if ((now_tick - last_tick) >= pdMS_TO_TICKS(1000U)) {
last_tick = now_tick;
for (uint8_t i = 0U; i < WDT_TASK_CNT; ++i) {
if (g_wdt_evt_flag[i] < 0xFFFFU) {
++g_wdt_evt_flag[i];
}
}
}
}
void v_wdt_dog_toggle()
{
WATCKDOG_TOGGLE(); //看门狗翻转
#if SYSTEM_TYPE == SYSTEM_TYPE_CCU601E_D
v_iwdg_refresh(); /* [CCU601E_D] STM32 内部看门狗喂狗 */
#endif
}
/**
* @brief 执行任务运行状态检查。
*
* 检查流程:
* 1. 先调用 `v_wdt_add_timer()` 更新各任务计数;
* 2. 跳过 lwIP 内部任务(`EthIf`、`TCPIP`);
* 3. 当 Shell 未使能时跳过 `MyShell`
* 4. 若任务计数超过超时阈值,当前阶段先钳位到阈值,不直接复位系统。
*/
static void v_wdt_task_runing_cheak(void)
{
v_wdt_add_timer();
/* EthIf/TCPIP 为 lwIP 内部线程创建,不参与本任务计数判断 */
for (uint8_t i = 0U; i < WDT_TASK_CNT; ++i) {
if ((i == (uint8_t)TASK_ID_EthIf) || (i == (uint8_t)TASK_ID_TCPIP)) {
continue;
}
if (g_wdt_evt_flag[i] > WDT_TIMEOUT_SECONDS) {
#if (WDT_RESET_ENABLE)
/* 超时触发系统复位:打印故障任务名后复位 */
const char *task_name = (i < (uint8_t)MY_TASK_NUM) ? my_task_data[i].task_name : "UNKNOWN";
printf("\r\n!!! WDT RESET: Task[%s](ID=%u) timeout > %us, system reset !!!\r\n",
task_name, (unsigned int)i, (unsigned int)WDT_TIMEOUT_SECONDS);
/* 短暂延时让串口数据发送完成 */
for (volatile uint32_t delay = 0U; delay < 100000U; delay++) {}
NVIC_SystemReset();
#else
/* 仅钳位计数,不复位(调试阶段使用) */
g_wdt_evt_flag[i] = WDT_TIMEOUT_SECONDS;
#endif
}
}
}
/**
* @brief 看门狗任务主循环。
*
* 任务职责:
* - 对自身任务喂狗;
* - 周期扫描其它任务运行计数;
* - 按半周期翻转外部看门狗引脚,维持硬件喂狗节奏。
*
* @param argument 任务参数,当前未使用。
*/
void v_wdt_task(void *argument)
{
(void)argument;
uint16_t sleep_ms = MY_GET_SLEEP_TIME(TASK_ID_WATCHDOG);
/* 将完整周期拆成两次半周期喂狗;当周期过小时兜底为1ms,避免出现0ms延时。 */
uint16_t half_sleep_ms = (sleep_ms > 1U) ? (sleep_ms / 2U) : 1U;
for (;;) {
v_wdt_setFlag(TASK_ID_WATCHDOG);
v_wdt_task_runing_cheak();
v_wdt_dog_toggle();
mSleep(half_sleep_ms);
v_wdt_dog_toggle();
mSleep(half_sleep_ms);
}
}