feat(vd960DBN): 硬件 IWDG 看门狗 + 平台响应超时重启

设计:
  1. 硬件 IWDG: LSI≈40kHz, Prescaler=256, Reload=625 → ~4s 超时
     主循环 iot_mqtt_poll() 每轮喂狗, 防死循环/硬故障

  2. 平台响应看门狗: 3×心跳周期(180s)内无平台回复 → NVIC_SystemReset
     _iot_last_recv_ms 刷新点:
     - iot_handle_publish() — 收到平台任意 PUBLISH 命令
     - iot_evt_handle_ack() — event_report 的 ACK
     - iot_handle_suback() — 刚连上 READY 时初始化计时

  3. 仅在 IOT_STATE_READY 时检查 (未连上不触发)
This commit is contained in:
wangfq
2026-07-23 14:49:07 +08:00
parent 199cb5d23f
commit 127fed4b07
2 changed files with 50 additions and 0 deletions
@@ -21,6 +21,7 @@
#define IOT_MQTT_RECONNECT_MIN_MS 5000 // 最小重连间隔
#define IOT_MQTT_RECONNECT_MAX_MS 60000 // 最大重连间隔 (指数退避上限)
#define IOT_MQTT_HEARTBEAT_MS 60000 // 心跳上报周期 (60s)
#define IOT_MQTT_WDT_TIMEOUT_MS 180000 // 平台响应看门狗: 3×心跳=180s 无回复→重启
#define IOT_MQTT_RECV_BUF_LEN 1024 // 接收缓冲区 (单次交互 ≤1024)
#define IOT_MQTT_SEND_BUF_LEN 1024 // 发送缓冲区 (单次交互 ≤1024)
#define IOT_MQTT_TOPIC_MAX_LEN 128 // Topic 最大长度
@@ -52,5 +53,7 @@ void iot_mqtt_poll(void); // 主循环轮询 (状态机 + 心跳 +
void iot_mqtt_handle_sock_int(uint8_t socketid, uint8_t intstat); // Socket 中断处理
void iot_mqtt_publish_sensor(void); // 推送传感器数据到 MQTT
void iot_evt_handle_ack(uint32_t msg_id, int code); // event_report 平台应答入口 (V1.04)
void iot_watchdog_kick(void); // 喂硬件 IWDG (主循环调用)
void iot_watchdog_check(void); // 平台响应超时检查 (180s无回复→重启)
#endif /* __IOT_MQTT_SRV_H__ */
@@ -23,6 +23,7 @@
#include "simple_json.h"
#include "tcp_json_srv.h"
#include "storage.h"
#include "ch32v20x_iwdg.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -41,6 +42,7 @@ static uint32_t _iot_last_heartbeat = 0; // 上次心跳时刻 (ms)
static uint32_t _iot_reconnect_deadline = 0;
static uint32_t _iot_reconnect_backoff = 0;
static uint32_t _iot_connect_start = 0; // TCP connect 开始时刻
static uint32_t _iot_last_recv_ms = 0; // 上次收到平台回复时刻 (看门狗追踪)
/*===========================================================================
* 传感器数据缓存 & 上报间隔控制
@@ -207,6 +209,7 @@ void iot_evt_handle_ack(uint32_t msg_id, int code) {
return;
}
/* 确认成功 → 弹出本包事件 */
_iot_last_recv_ms = mstick(); // 看门狗: 平台对 event_report 的 ACK 也算响应
_evt_head = (_evt_head + _evt_pend_n) % IOT_EVT_QUEUE_DEPTH;
_evt_count -= _evt_pend_n;
PRINT("EVT: ack ok, %d events dequeued (left=%d)\n", _evt_pend_n, _evt_count);
@@ -395,6 +398,8 @@ static void iot_handle_publish(const char *topic, uint8_t *payload, int payload_
PRINT("IOT: PUBLISH topic=%s payload=%s\n", topic, json);
_iot_last_recv_ms = mstick(); // 看门狗: 收到平台任意消息即刷新
/* 提取 msg_id 和 cmd */
char tmp[256];
uint32_t msg_id = 0;
@@ -550,6 +555,7 @@ static void iot_handle_suback(void) {
PRINT("IOT: ← SUBACK, topics subscribed\n");
g_iot_state = IOT_STATE_READY;
_iot_reconnect_backoff = 0; // 连接成功, 重置退避
_iot_last_recv_ms = mstick(); // 看门狗: 刚连上, 重置平台响应计时
// V1.03: 订阅成功后发布 initialize 告知服务器上线 (IoT 路径)
iot_send_initialize();
@@ -898,10 +904,48 @@ void iot_mqtt_handle_sock_int(uint8_t socketid, uint8_t intstat) {
}
}
/*===========================================================================
* 看门狗 — 硬件 IWDG + 平台响应超时
* IWDG: ~4s LSI超时, 主循环喂狗, 防死循环/硬故障
* 平台狗: 3×心跳周期(180s)无平台回复 → NVIC_SystemReset
*===========================================================================*/
/* IWDG 初始化: LSI≈40kHz, Prescaler=256 → 156Hz tick, Reload=625 → 4s 超时 */
void iot_watchdog_init(void) {
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_256);
IWDG_SetReload(625); // 625 × (256/40000) ≈ 4.0s
IWDG_ReloadCounter();
IWDG_Enable();
PRINT("IOT: IWDG init ok, timeout≈4s\n");
}
/* 喂狗 — 主循环每轮调用 */
void iot_watchdog_kick(void) {
IWDG_ReloadCounter();
}
/* 平台响应超时检查 — iot_mqtt_poll 中调用 */
void iot_watchdog_check(void) {
if (g_iot_state != IOT_STATE_READY) return;
uint32_t now = mstick();
if (now - _iot_last_recv_ms > IOT_MQTT_WDT_TIMEOUT_MS) {
PRINT("IOT: WATCHDOG no platform reply for %lu ms (>%u ms), resetting...\n",
(unsigned long)(now - _iot_last_recv_ms), IOT_MQTT_WDT_TIMEOUT_MS);
/* 不再喂狗, IWDG 4s 后自动复位; 或直接 NVIC_SystemReset */
NVIC_SystemReset();
}
}
/*===========================================================================
* 主循环轮询
*===========================================================================*/
void iot_mqtt_poll(void) {
iot_watchdog_kick(); // 喂硬件 IWDG
/* 平台响应超时检查 */
iot_watchdog_check();
/* 断线重连 */
if (g_iot_state == IOT_STATE_DISCONNECTED && g_iot_socket == 0xFF) {
if (_iot_reconnect_deadline == 0 || mstick() > _iot_reconnect_deadline) {
@@ -974,4 +1018,7 @@ void iot_mqtt_init(void) {
_iot_reconnect_backoff = 0;
_iot_reconnect_deadline = mstick() + 2000; // 启动后 2s 开始首次连接
g_iot_state = IOT_STATE_DISCONNECTED;
/* 初始化硬件看门狗 IWDG (LSI≈40kHz, 4s 超时, 主循环喂狗) */
iot_watchdog_init();
}