台架执行《实机测试实施指南》步骤 3~7 并闭环

步骤 3/4(IWDG V2/V4/V5 + 堆低水位 S11):
- V2 任务饿死 stall 后 ≤2.5s IWDG 复位;V4 关中断死循环 ~4.9s 稳定复位;
  V5 30min 120×FTP 全 PASS、零 IWDG 复位。堆告警全程未触发(min_ever=4728B)。
- task_watchdog.c:stall 证据写盘会经 nand_ftl_wd_feed 喂狗 → 增 s_stall_evidenced
  每次 stall 仅取一次证据,避免"取证据"本身阻止复位。
- default_task.c:堆低水位告警(HEAP_LOW_WATER_B=3072)。

步骤 5(GD5F 错误通道 S9):gd5f2gq5ue.c/.h + nand_ftl.c 错误码统一为 int32_t 并
全量检查返回值;套件回归 16/16 PASSED。
- test/run_all_suites.py:--forbidden 改为按套件覆盖(GD5F 用 "HardFault;assert")——
  TC-GD5F-704 故意触发 [ERR] 回落轮询,统一默认值会误判 FAIL。

步骤 6(网络稳定性):7.1 正常路径 ✅(V5 证据);7.2 N-2 丢弃可观测性代码已具备、
49s 静默在 V5 未复现(降级低风险观察项);7.3 N-3 待 PC peer。

步骤 7(工程卫生):
- S5:新增 test-cppcheck 钩子(仅 warning,排除模拟器桩)。
- S4:新增 scripts/check_test_traceability.py(默认仅告警)。
- 待核实项 TEST_SUITE_SELECTED 实机核实 = 死代码(无使用点);RTC 套件实际正常执行,
  真缺口 = 缺套件级汇总行 → sd2506_test_task.c 补 === RTC Tests: N/M PASSED === 并
  修正 Phase 级汇总累计问题;test_config.h 补齐 RTC 并注释"当前无引用"。

验证:产品 @build 0/0;pre-commit --all-files 17/17 Passed;
run_all_suites.py --suites RTC → PASS。
文档:实机测试实施指南 / SD2506_Test_Guide / 待处理内容 / 测试与架构改进建议 同步。
This commit is contained in:
2026-10-04 00:35:06 +08:00
parent aef1d92b3f
commit 029437be89
22 changed files with 631 additions and 151 deletions
+21
View File
@@ -57,6 +57,11 @@ extern const osThreadAttr_t timeSyncTask_attributes;
* 之后每周期只判定"是否出现更深峰值",无新峰值不打印(保持串口静默窗口) */
#define STACK_PROBE_FIRST_MS 5000u
#define STACK_PROBE_PERIOD_MS 2000u
/* S11(2026-10-03):堆低水位告警阈值(B)。
* 依据:2026-10-03 上板两次开机的 min_ever 实测下限 3,712 B(configTOTAL_HEAP_SIZE
* = 48KB)——低于此值说明堆余量 <8%,新增任务/缓冲随时可能分配失败(隐性风险)。
* 阈值取 3,072 B 留出运行间 ~600B 波动余量,避免把正常波动误报为故障。 */
#define HEAP_LOW_WATER_B 3072u
/* E-31 自愈策略(2026-09-21 审计 P0 修复):启动期存储挂载失败后,
* 主循环按 2s 周期重跑完整 bring-up 的次数上限;耗尽则维持无存储降级
* (自检已上报、卷保留、不重格式化),等下次上电重新 resume */
@@ -274,6 +279,22 @@ static void stack_probe_poll(void) {
}
s_last_tick = (uint32_t)now;
/* S11 堆低水位告警(2026-10-03):min_ever 跌破阈值 → 串口告警 + 自检留痕。
* 独立于下方"出现更深栈峰值才打印"的抑制:堆水位与栈峰值无关,须每 2s 采样。
* xPortGetMinimumEverFreeHeapSize() 单调不增 → 一旦跌破即持续成立,故只报一次
* (latch),既不刷屏,也不会漏(s_heap_alarm 置位后不再复报)。 */
{
static uint8_t s_heap_alarm;
const uint32_t min_ever = (uint32_t)xPortGetMinimumEverFreeHeapSize();
if ((s_heap_alarm == 0u) && (min_ever < HEAP_LOW_WATER_B)) {
s_heap_alarm = 1u;
DBG_ERROR("[HEAP] low water: %lu B (< %lu B)",
(unsigned long)min_ever, (unsigned long)HEAP_LOW_WATER_B);
(void)syslog_post(SYSLOG_SELFTEST, "heap low water");
}
}
for (i = 0u; i < (uint32_t)STACK_PROBE_COUNT; i++) {
const osThreadId_t th = *(s_stack_probe[i].p_id);
uint32_t free_now;
+16 -2
View File
@@ -106,6 +106,7 @@ static uint32_t s_miss_total; /* 累计未达标轮数(观测用) */
static uint32_t s_last_mask; /* 上次抽样到的位图(定位卡死任务用) */
static uint32_t s_started; /* 1 = IWDG 已启动 */
static uint32_t s_last_tick; /* 上次抽样时刻(100ms 节流基准) */
static uint32_t s_stall_evidenced; /* 1 = 本停摆 episode 已落盘证据(门闩;见 task_wd_poll) */
/* ==== round 7 纯取证状态(仅 MCU 构建;判定状态机逐字不变)====
* 设计背景见 docs/子系统设计/看门狗设计说明.md 2026-10-02 变更记录:误复位后 RAM 态随复位消失,
@@ -453,6 +454,7 @@ void task_wd_poll(void) {
if (snapshot == wd_required_mask()) {
s_miss_streak = 0u;
s_stall_evidenced = 0u; /* 恢复:允许下次停摆再落一次证据 */
wd_platform_feed(); /* 全员健康:喂狗 */
return;
}
@@ -487,8 +489,19 @@ void task_wd_poll(void) {
(unsigned long)s_miss_total);
#ifndef TASK_WATCHDOG_UNIT_TEST
/* round 7 取证:把现场落 /log/wdev.log(掉电不丢)。
* 串口 stall 行经僵尸通道可能丢失,故此处独立留盘上证据。 */
wd_stall_evidence(snapshot);
* 串口 stall 行经僵尸通道可能丢失,故此处独立留盘上证据。
* ⚠ 本 episode 只写**一次**(s_stall_evidenced 门闩;注意 s_miss_streak
* 达上限后会**饱和**在容忍值,不能用它判"首次"):证据落盘经
* sys_log_evidence() 走 NAND 写 → FTL 路径调 nand_ftl_wd_feed()
* **直接喂狗**。若每轮 100ms 都写,等于在"停喂"窗口里持续喂狗 →
* IWDG 永不溢出 → 停喂语义被证据机制自身抵消(2026-10-03 台架 V2
* 实测:stall 已声明、miss 累至 1157≈115s 仍不复位,见
* docs/测试说明/实机测试实施指南.md §4)。写一次即可留证,此后不再
* 触碰 NAND,恢复"停喂 → IWDG 溢出复位"(§5.3 的权威归因)。 */
if (s_stall_evidenced == 0u) {
s_stall_evidenced = 1u;
wd_stall_evidence(snapshot);
}
#endif
}
}
@@ -699,5 +712,6 @@ void task_wd_test_reset(void) {
s_last_mask = 0u;
s_started = 0u;
s_last_tick = 0u;
s_stall_evidenced = 0u;
}
#endif