7efa58d9a1
分两段(用户裁定 2026-11-02):先做地址迁移,再把同类字面量收敛成
单一真源,以后再改地址只动一处。
一、IP 迁移 192.168.1.100 → 192.168.31.100(gw 同步 → .31.1)
- 工厂默认:Drivers/BSP/NETCFG/net_cfg.c 的 NET_CFG_DEF_IP/_GW
- 注释/文档示例、主机与板级测试、台架 py 脚本、两份 sim_config.ini
- 字节序教学点同步换算 hex:0x6401A8C0 → 0x641FA8C0(内存
C0 A8 1F 64),旧版示例引文与历史 Trap 记录按冻结纪律不动
- UI 黄金基准:网口设置 4 态 + shot_info 共 5 张 .bin 由
check_content_pages.py --update 重刷(渲染值 IP 变了,属预期变更)
- 保留判定:客户点表引用(IEC104/继电保护规划)、芯片手册摘录、
日期冻结的变更记录行、已退役台架档案 MDK-ARM/retracted_bench_*
二、单一真源收口(A+B+C+D,用户批准全做)
- 新建 test/host/bench_defaults.py:台架 py 默认值唯一定义点
(DEVICE_IP/DEVICE_GW/PC_IP/NET_BCAST),22 个脚本改为引用;
MDK-ARM 两探针与 scripts/board_ui_nav.py 经 sys.path shim 引入
- test/board/net_test_task.h 新增 TEST_PC_PEER_IP,板测三处
PHASE*_REMOTE_IP 改引该宏(保留 -D 覆盖);Phase1 断言改
memcmp 数组比较,数组各只出现一次
- simulator/tests/check_content_pages.py 从 net_cfg.c 正则解析
NET_CFG_DEF_* 推导期望值(解析失败即报错、不静默兜底),
脚本内台架 IP 字面量清零
- 装饰性注释去具体值(net_cfg.h/net_socket.h/net_socket.c/
net_socket_sim.c);字节序教学 hex 对刻意保留为唯一写值点
- 刻意不动:主机单测夹具 IP(逐文件钉住的任意值是正确测试
实践)、文档正文 IP(那是文档内容本身)
顺带:scripts/gen_task_table.py 规范串清掉「,B5」——编号清退提交
72b4b094 改了受管区没重跑生成器,task-table 门禁因此一直红
验证:产品 @build 0/0;CH395F 套件开关构建 0/0 后还原产品态;
6 套主机单测 rc=0;content_pages(含宏推导路径)/菜单 8 态/
推流位比对全 PASS;bom-drift 99 无漂移;doc-links/coding-standard/
cppcheck 绿;py_compile 23 文件 + --help 冒烟(含 shim 绝对路径)
492 lines
36 KiB
Markdown
492 lines
36 KiB
Markdown
# 实机测试实施指南(On-Board Test Guide)
|
||
|
||
> **文档定位**:本文 = 上板(真机)测试的**执行流程**——按顺序执行。
|
||
> 每步给出「目的 → 判据(可观测、量化)→ 命令 → 状态(✅ 已闭环 / ⬜ 待执行)」。
|
||
> **已完成事项**(S7、A1~A4)的实施细节与证据**不在本文**,见对应模块文档(§10 状态与去向)。
|
||
> **前置铁律**:本文所有步骤**均在接上 MCU / 串口 / ST-LINK 之后**执行;
|
||
> 无实机时**只读本文,不执行任何烧录**。
|
||
> **上游**:`docs/任务规划/README.md`(统一登记簿:P-x / N·S·T-x /
|
||
> S1x·A-x / 阶段排序 / 诊断基线)·
|
||
> `子系统设计/看门狗设计说明.md`(§7 验证记录)。
|
||
> **约定**:本文事项完成后**先销上游登记**,再把结论写进正文对应小节(本文不再记流水,过程查 `git log`);
|
||
> 结论与证据沉淀进对应模块文档/问题记录(2026-10-02 台架窗口的完整取证链——
|
||
> IWDG PR/RLR 静默错配 / dhara resume 回滚 / ORE 僵尸通道——见 `看门狗设计说明.md` 2026-10-02 变更记录、
|
||
> `STM32F4-Base存储架构说明.md` §5.4.1、`控制台单写者日志设计说明.md` §12;修复已随 `930215f` 提交)。
|
||
|
||
---
|
||
|
||
## 1. 执行流程总览
|
||
|
||
台架窗口就绪后,**按下列顺序执行**(P0 → P1 → P2 → P3):
|
||
|
||
| 步骤 | 事项 | 状态 | 章节 |
|
||
|---|---|---|---|
|
||
| **步骤 1** | 环境预检(P0-A,每次上台架必跑) | 常设 | §2 |
|
||
| **步骤 2** | 产品 `/serial-boot-test` 闭环 + 自检结果判定(P0-B) | ✅ 已闭环 | §3 |
|
||
| **步骤 3** | IWDG 故障注入 V2/V4 + 长跑 V5(P1-A) | ✅ 已闭环 | §4 |
|
||
| **步骤 4** | 堆低水位告警实测(P1-B) | ✅ 已闭环 | §5 |
|
||
| **步骤 5** | GD5F 错误通道回归(P2-A) | ✅ 已闭环 | §6 |
|
||
| **步骤 6** | 网络稳定性与基线重锁(P2-B / 日志静默观察项 + 队列往返基线待重验) | ◐ 部分闭环(7.1/7.2 ✅;7.3 待 PC peer) | §7 |
|
||
| **步骤 7** | 工程卫生(P3 + 待核实项) | ✅ 已闭环 | §8 |
|
||
|
||
> **每步出口**:`/keil-build` 0/0 → 一轮 `/serial-boot-test` PASS → ST-LINK 全片回读 `No difference found` →
|
||
> 上游登记销项 + 把结论写进正文对应小节。
|
||
>
|
||
> **参考**(非执行步骤):§9 执行注意(实测陷阱)· §10 已完成事项与证据去向 · §11 引用闭环。
|
||
|
||
---
|
||
|
||
## 2. 步骤 1:环境预检(P0-A,每次上台架前必跑)
|
||
|
||
> **目的**:避免"改动没问题、台架有问题"的误判(历史上多次把接线/权限问题误判为代码缺陷)。
|
||
|
||
| # | 检查 | 命令 | 通过判据 |
|
||
|---|---|---|---|
|
||
| A1 | 工作区干净 | `git status --short` | 无输出(或有明确待提交项) |
|
||
| A2 | 产品构建 0/0 | `& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py` | 末行 `BUILD_OK: 0 errors, 0 warnings` |
|
||
| A3 | 构建产物为**产品态** | 检查 `test/board/test_config.h` L30-33 | 四个 `TEST_SUITE_*` **全部注释** |
|
||
| A4 | `.map` 非测试态 | 看 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map` 的 `ER_IROM1` | 产品态基线随已接受的修复增长:262,100(初版)→ 262,836 B(10-02 第 1~6 轮台架)→ 264,284 B(第 7~9 轮台架)→ **264,936 B(当前,含 A2/A3/A4 补码)**;明显阶跃 ≈3.7KB 及以上(10-02 实测产品 262,836 → 套件 266,540)= 停在套件态 → 重跑 A2 |
|
||
| A5 | 全量静态门禁 | `pre-commit run --all-files`(现只覆盖 `pre-commit` 阶段 47 根;manual 阶段三根另跑 `--hook-stage manual <id>`) | **当时 17/17 Passed**(2026-10-03 实测;含新增 `test-cppcheck`) |
|
||
| A6 | ST-LINK 探针可见 | `& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py list`(CLI 经 `DTU_STLINK_CLI` / PATH 解析) | 列出探针 SN `0B250D12A218303030303032` |
|
||
| A7 | 串口端口正确 | 检查 `.serialtest/config.json` 的 `portName` | 端口单一配置源 = 此文件(当前 COM6,2026-09-21 台架重插后由 COM7 变更);变更后先杀旧 daemon 再 `open` |
|
||
| A8 | 串口助手 daemon 可用 | `& '.venv\Scripts\python.exe' .dsh/skills/serial-assistant/scripts/serial_tool.py status` | 返回 JSON,`open: true/false` 可读 |
|
||
|
||
> ⚠️ **A4 的陷阱**(2026-10-02 实测):`/keil-build` 是**增量**构建,`run_all_suites.py` 跑完
|
||
> 套件后 `.map` 会停在**测试套件体积**;仅还原 `test_config.h` 不够,**必须再编一次产品固件**
|
||
> (`run_all_suites.py` 已在 `finally` 内自动补这一步)。
|
||
|
||
**预检失败处置**:任一项 FAIL → **不上台架**,先修到全绿(避免"带病测试"浪费台架窗口)。
|
||
|
||
---
|
||
|
||
## 3. 步骤 2:产品 /serial-boot-test 闭环 + 自检结果判定(P0-B) · ✅ 已闭环
|
||
|
||
> S7 判定已落地并投用;A1~A4 已闭环。**实施细节与真机验证证据见 §10 状态与去向**,本节只给复跑命令与判据。
|
||
|
||
### 3.1 执行
|
||
|
||
`/serial-boot-test` 闭环除串口标记外,还判定设备侧自检结论(v1 只记故障、不记通过):
|
||
`selftest.log` **缺失 / 0 字节 → 无故障 → PASS**;`filesize/64 > 0`(任一 64B 定长记录)
|
||
= 有故障 → FAIL,并打印故障条目(时间戳 + 描述)便于定位。
|
||
|
||
```bash
|
||
# 一键闭环(selftest.log 自动 FTP 抓取;无故障记录 = PASS)
|
||
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py --require-selftest-pass --device-ip 192.168.31.100
|
||
|
||
# 或手动联合判定(本轮串口日志 + selftest.log 本地副本)
|
||
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/verify_log.py \
|
||
--log-path <本轮串口日志> \
|
||
--require-selftest-pass \
|
||
--selftest-log <下载的 selftest.log 本地副本>
|
||
# 判据:退出码 0;输出含 "[OK] selftest: no fault record"
|
||
```
|
||
|
||
### 3.2 自检项清单(S7 判定覆盖面,20 处)
|
||
|
||
> 来源:全库 `syslog_post(SYSLOG_SELFTEST, ...)` 调用点。**这是 S7 的判定覆盖面基准**。
|
||
|
||
| 文件 | 自检描述串 |
|
||
|---|---|
|
||
| `App/app/app_main.c` | `watchdog reset` / `clock chip fault` / `NAND fault` / `ADC fault` |
|
||
| `App/cfg/cfg_file.c` | `cfg heap alloc fail`(×3) / `cfg template write fail` / `cfg load oversized` / `cfg load read fail` / `cfg save read fail` / `cfg save overflow` / `cfg save write fail` / `cfg poll oversized` |
|
||
| `App/task/default_task.c` | `filesystem fault`(×2) / `storage fault`(×2) |
|
||
| `App/task/net_task.c` | `comms fault` / `net init fail` / `net reinit fail` |
|
||
|
||
**联动**:`syslog_post` 的两级自愈(板端测试套件文件级重试 / 主机侧回归错误去重 `s_fault_reported[]`)
|
||
决定**持续故障只留第一条**——故 S7 判定"有记录即 FAIL"是**充分**的(不会被去重掩盖)。
|
||
|
||
---
|
||
|
||
## 4. 步骤 3:IWDG 故障注入与长跑(P1-A 收尾) · ✅ 已闭环
|
||
|
||
> **2026-10-03 台架结论**(实施细节与证据见 `子系统设计/看门狗设计说明.md` 变更记录):
|
||
> V2/V4/V5 三用例全部通过——V2(任务饿死)声明 stall 后 ≤2.5s `reset cause: IWDG`;V4(关中断死循环)每 ~4.9s 稳定 IWDG 复位(IWDG 独立于中断);V5(30 min 真实负载)**120/120 次 FTP 传输全 PASS、零 IWDG 复位**。
|
||
> **遗留观察**:V5 期间 44 次 stall 声明 100% 与 `e02_probe` 探针的 time_sync 30s 掉线+监听重建重合;隔离实验(仅 FTP 120s)**0 次 stall** → 探针场景专属,非一般负载误杀(已登记 `docs/任务规划/登记簿.md`)。
|
||
|
||
> 来源:`子系统设计/看门狗设计说明.md` §7 验证记录(原实施步骤已并入该文档文末变更记录)。
|
||
> 判定状态机与 IWDG 配置(PR/RLR 按设计值写入)已落地并经真机验证(2026-10-02,`930215f`,
|
||
> 见设计说明 2026-10-02 变更记录);故障注入 + 长跑验收结论见上文 2026-10-03 段落。
|
||
|
||
### 4.1 三个验收用例
|
||
|
||
| # | 用例 | 注入方法 | 通过判据 |
|
||
|---|---|---|---|
|
||
| **V2** | 任务饿死 | 临时在 `netTask` 循环插 `while(1);` | 800 ms 后串口 `[ERR] WATCHDOG: task stall mask=0x...`;≤2.5 s 复位;重启后 `[WD] reset cause=watchdog reset` |
|
||
| **V4** | 关中断死循环 | 临时插 `taskDISABLE_INTERRUPTS(); while(1);` | ≤2.5 s 复位(检验 IWDG **独立于中断**);`cause=watchdog reset` |
|
||
| **V5** | 长期不误杀(**核心验收项**) | FTP 大文件传输 + UI 菜单遍历 + 配置保存 + 网络重配 **≥30 min** | **零复位**(重点验证 `docs/子系统设计/看门狗设计说明.md` §4.3 白名单是否完备) |
|
||
|
||
> ⚠️ **V5 是核心验收项**:误杀比不杀更有害。必须在**真实业务负载**下跑足时长。
|
||
|
||
### 4.2 执行步骤
|
||
|
||
```bash
|
||
# --- V2/V4(故障注入,需临时改码)---
|
||
# 1) 基线:跑一轮产品 /serial-boot-test 确认无复位
|
||
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py
|
||
|
||
# 2) 注入:按 `docs/子系统设计/看门狗设计说明.md` §7 在 netTask 循环插 while(1);(或 taskDISABLE_INTERRUPTS(); while(1);)
|
||
# —— 改完 /keil-build,然后烧录
|
||
& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py
|
||
& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py flash MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex
|
||
|
||
# 3) 抓串口日志,确认 [ERR] WATCHDOG task stall + 复位原因
|
||
# 4) 回读校验复位后镜像(ST-LINK_CLI 经 DTU_STLINK_CLI 解析,未设时回退 PATH,不写死路径)
|
||
$cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-LINK_CLI.exe).Source }
|
||
& $cli -c SWD -CmpFile MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex 0x08000000
|
||
# 判据:No difference found
|
||
|
||
# 5) 撤销注入,/keil-build 回产品态,再跑一轮 /serial-boot-test 确认正常
|
||
|
||
# --- V5(长跑,需真实负载)---
|
||
# 1) 用 test/host/ftp_speed_test.py / ftp_up_dl_test.py 持续传输大文件
|
||
& '.venv\Scripts\python.exe' test/host/ftp_speed_test.py
|
||
# 2) 同时人工/脚本遍历 UI 菜单 + 反复保存配置 + 触发网络重配
|
||
# 3) 持续 ≥30 min,全程串口记录
|
||
# 判据:零复位(日志无 "reset cause=watchdog reset");业务不中断
|
||
```
|
||
|
||
**风险/回滚**:
|
||
- 故障注入用例**会复位设备多次**——确认设备非在用/非已部署。
|
||
- 长跑涉及 NAND 写入(FTP 上传)**消耗 NAND 块**——若设备已接近容量上限,改用只读传输。
|
||
- ⚠️ **R5 风险**(`docs/子系统设计/看门狗设计说明.md` §9):NAND 擦写偶发超 800 ms 可能误复位——若 V5 出现偶发复位,
|
||
先按设计说明增大容忍次数或把存储操作改分段置位,**不要盲目放宽全局超时**。
|
||
|
||
---
|
||
|
||
## 5. 步骤 4:堆低水位告警实测(P1-B,S11) · ✅ 已闭环
|
||
|
||
> **2026-10-03 台架结论**:告警代码(`default_task.c` 的 `HEAP_LOW_WATER_B=3072` 门闩 + `[HEAP]` 告警 + syslog 自检)已落地;复用 §4.2 V5 窗口 30 min 长跑,**全程未触发**(`min_ever=4728 B` > 3072 B)→ 记录"当前负载下 min_ever 仍高于阈值"为基线,已更新 `内存管理/RAM使用分析与优化方案.md`。
|
||
|
||
**现状证据**:2026-10-03 上板复测 `free=8,688 / min_ever=3,712~4,728 B`
|
||
(两次开机,运行间波动 ≈1KB;初始 `configTOTAL_HEAP_SIZE` 48KB)——
|
||
**min_ever 下限已跌破 4KB**,余量不到 8%,新增任务/缓冲可能触发分配失败。
|
||
现有代码仅有周期性 `[STACK]` 报告(每周期打印 `heap free/min_ever`),**无阈值告警、不写自检记录**。
|
||
|
||
**待补代码**(约 15 行 + 1 个编译期常量,在 `defaultTask` 低频循环(LED 闪烁节拍)内):
|
||
检查 `xPortGetMinimumEverFreeHeapSize()`,低于阈值(建议 **3072 B**,低于 10-03 实测下限 3,712 B,防运行间波动误报)时
|
||
`DBG_ERROR("[HEAP] low water: %u B")` + 写 syslog selftest。
|
||
|
||
**判据**:台架长跑(复用 §4.2 V5 窗口)下,若发生低水位 → 串口出现告警行 + `selftest.log` 有记录;
|
||
若全程未触发 → 记录"当前负载下 min_ever 仍高于阈值"作为基线。
|
||
|
||
**执行步骤**:
|
||
```bash
|
||
# 1) 代码改动(约 15 行 + 1 个编译期常量)在 defaultTask 低频循环内
|
||
# 2) /keil-build 0/0 后,与 §4.2 V5 长跑合并执行
|
||
# 3) 长跑结束读取 min_ever:
|
||
# - 串口 [HEAP] 告警行(若有)
|
||
# - 或 FTP 取 /log/selftest.log
|
||
# 4) 更新 docs/内存管理/RAM使用分析与优化方案.md 的 min_ever 基线
|
||
```
|
||
|
||
**成本/回滚**:约 15 行 + 零额外缓冲;阈值设编译期常量便于按新基线调整。
|
||
若长跑中频繁触发但系统正常 → 说明阈值偏紧,据实测值调整(不是缺陷)。
|
||
|
||
---
|
||
|
||
## 6. 步骤 5:GD5F 错误通道统一(P2-A,S9 = 上游 C2) · ✅ 已闭环
|
||
|
||
> **2026-10-03 台架结论**:四要素(分类/透传/分级/留痕)+ 返回类型统一 `int32_t` 已落地。
|
||
> 套件回归:`test/run_all_suites.py --suites gd5f` → **`=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===`**(只读模式,4 个破坏性用例按设计跳过);编排器 `[GD5F] -> PASS`。
|
||
> **顺带修复(编排器缺陷,非本次代码引入)**:`run_all_suites.py` 原对所有套件统一 `--forbidden "HardFault;assert;[ERR]"`,而 GD5F 的 `TC-GD5F-704`(CCM 非 DMA 可达缓冲)会**预期**打出 `[ERR][NAND] RX DMA buffer not DMA-reachable ... fallback poll`(用例 PASS)→ GD5F 套件**永远被判 FAIL**(自 `2055de0` 起)。按 `verify_log.py` 的说明改为**按套件覆盖 `--forbidden`**(GD5F = `HardFault;assert`),修复后 PASS。
|
||
|
||
> **来源**:第二档 #1;
|
||
> `docs/产品需求/产品需求设计文档.md` §7.1(错误码通道四要素骨架,设计基线)。
|
||
|
||
**现状证据**:`ch395f.c`(1330 行) 与 `gd5f2gq5ue.c`(1496 行) 是同代驱动,但**只有 CH395F**
|
||
形成了"分类 + 传播 + 审计"完整体系;GD5F 错误处理散落各函数,`Trap_Records` 仅 198 行。
|
||
|
||
**统一错误通道四要素**(以 CH395F 为范式):
|
||
|
||
| 要素 | 内容 |
|
||
|---|---|
|
||
| ① **分类** | `wait_busy` 区分「超时 / 真故障 / 参数错」——不得混为一个返回码 |
|
||
| ② **透传** | 底层错误码逐层上报,不吞不猜(禁 `(void)ret`) |
|
||
| ③ **分级** | 可恢复(重试)/ 不可恢复(上报自检 + 降级)显式判定 |
|
||
| ④ **留痕** | 不可恢复项写 syslog selftest;可恢复项计数并在 UI/日志可见 |
|
||
| — | 返回类型统一 `int32_t` |
|
||
|
||
**实施顺序**(数据安全优先):
|
||
1. 先建**分类函数**(`gd5f_wait_busy` 内检查三次 HAL 调用)——所有下游判断的基础;
|
||
2. 再修**最危险的**:`gd5f_bbt_scan` 失败**放弃持久化**(保护好副本)——**数据安全优先**;
|
||
3. 补 **init 全链路检查 + 重试 1~2 次**;
|
||
4. 回读 **B0h 校验 ECC 使能**(bit4);
|
||
5. `gd5f2gq5ue_read` 的 raw 契约文档化或加 ECCS 检查;
|
||
6. 全程在 `GD5F2GQ5UE_Trap_Records.md` 留痕,同步 `GD5F2GQ5UE_Test_Guide.md`。
|
||
7. **RAM 预算**:新增错误分支**不得引入新的大缓冲**(先跑 `ram_report.py` 核算)。
|
||
|
||
**判据**:
|
||
- **错误通道审计项全部销项**;
|
||
- **GD5F 套件回归 PASS**:
|
||
```bash
|
||
# 套件回归(需实机)
|
||
& '.venv\Scripts\python.exe' test/run_all_suites.py --suite gd5f
|
||
# 判据:=== GD5F Tests: N/M PASSED (failed=0) === 且 N>0
|
||
|
||
# 只编译验证(离机,改动后随手跑)
|
||
& '.venv\Scripts\python.exe' test/run_all_suites.py --check-build
|
||
```
|
||
|
||
> ⚠️ **纪律**(呼应 `AGENTS.md` 铁律):自愈逻辑**严禁**把"名字/参数类错误码"
|
||
> (如 `FR_INVALID_NAME`)归入"卷损坏触发集"——`.fschk` 无限重格式化事故即此类(2026-09-20)。
|
||
> ⚠️ **破坏性用例**:GD5F 套件默认只跑只读;`ENABLE_DESTRUCTIVE_TESTS` 跑一次消耗一个 NAND 块
|
||
> (实测 95248→95200),**仅在产线首启或明确需要时打开**。
|
||
|
||
---
|
||
|
||
## 7. 步骤 6:网络稳定性与基线重锁(P2-B) · ◐ 部分闭环(7.1/7.2 已闭环;7.3 待 PC peer)
|
||
|
||
### 7.1 网络重建失败恢复(A2;实施细节见 `网络/Net层阻塞模型架构设计.md`,状态见 §10) · ✅ 正常路径已闭环
|
||
|
||
**判据**:拔插网线/改 IP 触发重建后——
|
||
- 失败路径**写 syslog 自检**(不再零日志);
|
||
- **30s 周期重试**,不自驻留死循环;
|
||
- 恢复后各 TCP 服务(FTP 21 等)**据代次号重建监听**,功能正常。
|
||
|
||
**验证手段**:`test/host/e02_probe.py`(网络探针)+ UI 网口设置页改 IP。
|
||
|
||
**2026-10-03 台架结论**:
|
||
- **正常路径 ✅**:V5 长跑(30 min,FTP 512 KB 上/下传)**120/120 PASS、零 IWDG 复位**,
|
||
网络重建后的 FTP/time_sync 服务据代次号重建监听、功能正常(证据 `/tmp/v5_soak_serial_20261003.log`)。
|
||
- **负向路径(拔线/芯片级 `net_init` 失败)**受**台架拓扑**限制(CH395↔交换机,
|
||
拔交换机侧线缆链路仍 UP;芯片级失败需 SPI 故障注入)→ 已登记 `docs/任务规划/登记簿.md` 条目「网络负向场景台架验证」
|
||
(① PHY 拔线负向 ② A2 `net_init` 失败分支 ③ A4 短写压测),需专项窗口。
|
||
|
||
### 7.2 日志静默观察项:49s 全系统日志静默复现与定位 · ✅ 判据②已满足 / 判据①未复现
|
||
|
||
**现状证据**(登记簿条目「日志静默观察项」):2026-09-22 台架实测,串口日志 **49s 无行**
|
||
(testTask/netTask/[STACK] 行全缺),期间 net 栈照常处理外部连接 → **日志管线停滞**,
|
||
队列满后各任务日志行被丢;系统功能不受损。
|
||
|
||
**判据与核实(2026-10-03)**:
|
||
- **判据②(队列满丢弃计数/告警)→ ✅ 代码已满足**:日志管线**已有**显式丢弃可观测性——
|
||
`App/log/console_log.c` 的 `s_con_drop` 计数 + 排空末尾 `[ERR] CONSOLE dropped %lu lines`
|
||
提示 + `dbg_console_dropped()` 访问器;`App/log/sys_log_mcu.c` 的队列满/preboot 满分别
|
||
打 `DBG_ERROR("queue full, drop: …")` / `("preboot full, drop: …")`。另 UART TX 卡滞
|
||
已由**僵尸通道自愈**覆盖(`con_uart_reinit()` + `[WARN] CONSOLE tx fault: UART reinit`,
|
||
`s_con_tx_fault` 计数)。**"现静默丢行、排障不可见"已不成立**。
|
||
- **判据①(复现 49s 并定位卡点)→ 未复现**:对 V5 30 min 长跑日志(6031 条带时间戳行)
|
||
做间隔分析,**最大静默 41s**(发生在**开机/烧录边界**,非运行期),**运行期无 49s 静默**。
|
||
运行期 >10s 的静默共 24 处,**全部**为 ~28s,且**均落在 `e02_probe` 的 time_sync 30s
|
||
挂起客户端窗口内**——与「探针窗口心跳缺口」同源(探针场景专属,非通用负载)。
|
||
- **结论**:49s 静默在当前固件 + V5 负载下**不复现**;可观测性缺口已由既有代码补齐。
|
||
日志静默观察项降级为**低风险**(保留登记,若再现则借 `[ERR] CONSOLE dropped` 计数定位)。
|
||
- **后续(2026-10-25,道F 第二轮 合并评估)**:窗内静默的同源阻塞机制
|
||
(`drop_conn` 同步占用 netTask 400-600ms)已随「登记式拆链」修复
|
||
(`../../网络/网络自愈架构设计.md` §4.6);日志静默观察项与日志单写者化的合并评估已完成,结论与「无源 vs
|
||
真停滞」判别口径落 `../../子系统设计/控制台单写者日志设计说明.md` 文末附录——
|
||
再现静默先按三本账(`dbg_console_dropped/_tx_fault/_tx_timeout`)+ syslog 丢弃
|
||
账对照定性,再决定是否开卡;销项条件 = 探针窗口心跳缺口修复版 V5 复跑(e02_probe + FTP
|
||
≥30 min)运行期 `task stall` 与真停滞嫌疑静默段双零(2026-10-25 v1.1 起
|
||
`MISS start` 降级为诊断行不计销项——见下方判读工具与
|
||
`../../子系统设计/看门狗设计说明.md` §6.1)。
|
||
- **判读工具 v1.1(2026-10-25 大窗判读 F1 起)**:
|
||
`'.venv/Scripts/python.exe' scripts/v5_log_gap_report.py <serial-assistant 日志路径>`
|
||
——自动列 `>10s` 静默段(`--gap-threshold-s` 可调),每段带判定(NO-SOURCE /
|
||
PROBE-WINDOW / BOOT-WINDOW / TRUE-STALL-SUSPECT)与贴边证据行。违规口径 =
|
||
`task stall` 行 >0 **或** 真停滞嫌疑段 >0;退出码 0=达标 / 1=违规 /
|
||
2=日志无有效时戳;`--json` 机读、`--report-only` 只出报告、`--selftest`
|
||
内嵌合成样例自检(无台架可跑)。**v1.1 变更(判读口径,先文档后脚本)**:
|
||
① `MISS start` 降级为**诊断行**(看门狗 v1.5 按位分账后它只是复合缺席边沿,
|
||
不代表停喂,`../../子系统设计/看门狗设计说明.md` §6.1)——报告改出归因诊断:
|
||
开机良性 / 探针窗内 / 窗外运行期 + 窗外每分钟速率 top;v1.0 把运行期 MISS
|
||
计违规属收紧过头(2026-10-25 台架 70min 窗 1262 条经逐窗归因实为风暴复合边沿
|
||
与传输窗抖动),予以纠正;② `task stall` 行语义 = v1.5 起「同一任务 800ms
|
||
单串真停摆」(行文本不变,`../../子系统设计/看门狗设计说明.md` §5.3),每行都是
|
||
真猎物;开机豁免口径(§9 第 8 条)保留、仅作用于 MISS 诊断分类。口径唯一
|
||
来源 = `../../子系统设计/控制台单写者日志设计说明.md` 文末附录 + §9 第 8 条 +
|
||
看门狗设计说明——改口径先改文档再改脚本(自检断言会拦漂移)。
|
||
|
||
**执行步骤**:长跑(§4.2 V5)期间周期性打点 + 对照 `CH395F` 无关的 SD2506 侧日志判别卡点。
|
||
|
||
### 7.3 队列往返基线待重验 · ⬜ 待 PC peer
|
||
|
||
**现状**:L5 基线(1223/988µs)属**分片时代**;人工目检对该路径逐位不变 → 机制上无影响,
|
||
但严格重锁需跑一轮 Phase 13(**需 PC peer**)。
|
||
|
||
**判据**:Phase 13 窗口跑一轮,基线数值与阈值余量(>8×)对照,重锁数值。
|
||
|
||
**2026-10-03 台架**:本窗口**无 PC peer**,Phase 13 无法执行 → 保留待办(低风险:
|
||
阈值余量 >8×,机制上 人工目检对该路径逐位不变)。
|
||
|
||
---
|
||
|
||
## 8. 步骤 7:工程卫生(P3) · ✅ 已闭环
|
||
|
||
> S5 / S4 落地(离机可做),待核实项已实机核实并修复。本节留复跑命令与判据。
|
||
|
||
### 8.1 S5:`test/` 代码宽松静态检查
|
||
|
||
**现状证据**:`test/` 完全豁免 pre-commit("自律"要求),而 `test/board/` 下 **6300+ 行 C 代码**
|
||
(实测 `.c`+`.h` 合计 6,313 行)**且编入固件**。曾出现 `s_rx_buf` 使用先于声明。
|
||
|
||
**目标**:抓 `test/board/` 固件测试代码的**真实缺陷**(未初始化/越界/空指针),
|
||
但不引入存量 style 噪音。
|
||
|
||
**执行步骤(先跑基线,离机可做)**:
|
||
```bash
|
||
# 1) 基线统计(不需实机)
|
||
cppcheck --enable=warning --error-exitcode=1 test/ 2>&1 | tee test_cppcheck_baseline.txt
|
||
|
||
# 2) 若存量可控(建议 <20 条)→ 加 test-cppcheck 钩子,只开 warning
|
||
# 3) 若存量较多 → 先建 suppress 清单(明确每条豁免理由),再挂钩子
|
||
# 4) 务必排除模拟器桩/第三方头(test/host/watchdog/stub/ 等)
|
||
```
|
||
**判据**:`test-cppcheck` 在 CI PASS;新增测试代码越界/未初始化被自动拦截。
|
||
> **注意**:若基线告警过多,**保持现状亦可接受**——此时应把该决策写明确("理由:存量 N 条")。
|
||
|
||
**结论(✅ 已闭环,2026-10-03)**:已加 `test-cppcheck` 钩子(`.pre-commit-config.yaml`
|
||
`id: test-cppcheck`,**仅开 `warning`、排除模拟器桩/第三方头**)。基线可控,
|
||
`pre-commit run test-cppcheck --all-files` **PASS**。新增 `test/board/` 代码的
|
||
未初始化/越界/空指针问题现由钩子自动拦截。
|
||
|
||
### 8.2 S4:用例追溯脚本
|
||
|
||
**现状**:文档声称 91 个 TC、代码有 222 个 `TEST_CHECK`(断言点数 > 用例数是正常的),
|
||
但**双向是否一一对应无人校验**。
|
||
|
||
**目标**:新增 `[计划] scripts/check_test_traceability.py`——
|
||
输入 `test/board/*_test_task.c` 的 TC 注释 + `docs/测试说明/板级测试/*Test_Guide.md` 的 TC 编号;
|
||
输出 ① 文档有、代码无(未实现)② 代码有、文档无(未登记)。
|
||
**默认仅告警(warning),不阻断提交**(与 `doc-links` 演进路径一致)。
|
||
|
||
**判据**:一键列出双向差异清单;差异收敛后再考虑升为门禁。
|
||
|
||
**结论(✅ 已闭环,2026-10-03)**:`scripts/check_test_traceability.py` 已落地并跑通,
|
||
**默认仅告警(exit 0)、不阻断提交**。2026-10-26 重打:当前差异 **25 处**(文档有代码无 + 代码有文档无两向),
|
||
另有约 1,486 处属"代码有该号、号旁写着人话意图",按「代码即属主登记处」放过——**弱于文档的保证**,
|
||
对外举证仍需模块级说明。当年列出的孤儿号(GD5F 那三个 11xx、存储 06 号)已在 2026-10-26 清号批次
|
||
里从代码侧删号收口。差异清单可追踪,后续按需补登记;**暂不升门禁**(与 §8.2 目标一致)。
|
||
|
||
### 8.3 待核实项:`TEST_SUITE_SELECTED` 未含 `TEST_SUITE_RTC` · ✅ 已核实(非缺陷)
|
||
|
||
**原疑点**(`test/board/test_config.h`):派生标记 `TEST_SUITE_SELECTED` 只含
|
||
CH395F / STORAGE / GD5F,未含 RTC;怀疑 RTC 构建下 `testTask` 不被创建 → 套件不执行。
|
||
|
||
**2026-10-03 实机核实结论**:
|
||
- **`TEST_SUITE_SELECTED` 是死代码**:`grep -rn TEST_SUITE_SELECTED` 全仓**仅本文件有定义、
|
||
无任何使用点**。`Src/freertos.c` **无条件创建 `testTask`**;`test/board/test_config.c`
|
||
的 `start_test_task()` **直接按 `TEST_SUITE_RTC` 等宏分支**(不经 `TEST_SUITE_SELECTED`)。
|
||
→ "testTask 不被创建 → RTC 不执行"的推断**不成立**。
|
||
- **RTC 套件确实执行**:选 `TEST_SUITE_RTC` 构建烧录后,串口出现完整 RTC 输出
|
||
(`SD2506 test suite started` … `Phase 1 basic: 3/3 PASSED` … `Phase 2 API: 6/6 PASSED`)。
|
||
- **真正的缺口 = 缺套件级汇总行**:原 `sd2506_test_run()` 只打 Phase 级汇总,**没有**
|
||
`=== RTC Tests: N/M PASSED (failed=0) ===` → `run_all_suites.py --require-suite-summary "RTC Tests"`
|
||
判 **FAIL**(设备实际 12/12 全过)。属**判据缺口**,非设备缺陷。
|
||
|
||
**修复(2026-10-03)**:
|
||
1. `test/board/sd2506_test_task.c`:各 Phase 进入前**自清零**,末尾输出套件级
|
||
`=== RTC Tests: N/M PASSED (failed=0) ===`(复用 `SD2506_TEST_REPORT` 宏,格式与
|
||
`test_common.h` 统一)。顺带修正 Phase 级汇总行**累计**问题——原 Phase 2 显示的是
|
||
含 Phase 1 的累计值(9/9),现各阶段独立:Phase 1 = 3/3、Phase 2 = 6/6、套件级 = 9/9。
|
||
2. `test/board/test_config.h`:`TEST_SUITE_SELECTED` **补齐 RTC** 并注释其"当前无引用",
|
||
防止将来真有分支复用时重演"漏 RTC"。
|
||
|
||
**复跑命令**:`& '.venv\Scripts\python.exe' test/run_all_suites.py --suites RTC`
|
||
**判据**:`[RTC] -> PASS`、`VERDICT: PASS`,日志含 `=== RTC Tests: 9/9 PASSED (failed=0) ===`。
|
||
|
||
---
|
||
|
||
## 9. 执行注意:实测陷阱(2026-10-02 台架窗口,照做可少绕一天)
|
||
|
||
1. **写入"复位后消失"的两层原因**(窗口最大坑,根因均已修复,详见模块文档):
|
||
- **板端测试套件 dhara checkpoint 回滚**(`架构设计/STM32F4-Base存储架构说明.md` §5.4.1):环回绕后
|
||
`dhara_journal_resume()` 恢复旧 checkpoint,**之后写的一切整段丢弃**
|
||
(已修:epoch 锚点改比较两候选的新旧)。
|
||
- **主机侧回归 FTL 单页写回缓存**:一次 `disk_write` 里不满整页(2048 B)的写,在**写到另一个 LPN /
|
||
整页写 / `CTRL_SYNC`** 之前只存在于 RAM(`nand_ftl.c` 的 `s_cache_buf/s_cache_dirty`)。
|
||
但正常 `f_close` 就会走到 `CTRL_SYNC`(FatFs `sync_fs` → `disk_ioctl` → `ftl_flush_cache`),
|
||
所以**"写完即关"的路径(日志、配置保存)关文件即落盘,不必再"写另一个文件逼刷"**;会丢的
|
||
只有**写事务进行中**掉电/硬复位(含 IWDG 误复位)里最后那笔未跨页的写(≤512 B)——
|
||
FTP STOR 传输途中掉电就落在这一档(已登记观察;「写回缓存空闲 flush」于 2026-10-22 裁定暂不做,
|
||
缺的是"空闲/掉电前周期 flush",且本机无掉电检测硬件,掉电时点无法补救)。
|
||
→ 排查写入丢失时**先看开机日志的 head/tail/epoch**(`Map head=… tail=… epoch=…`,
|
||
纯内存字段、零 I/O):head 复位后倒退 = 板端测试套件(resume 错);head 正常 = 主机侧回归(缓存未刷)。
|
||
(旧口径"清台账/写证据后写另一个文件"的 flush 诱导属 板端测试套件时代的产物:现码 `f_close` 自带
|
||
`CTRL_SYNC`,正常写完即关就不需要它;这条诱导只在 `f_close` 失败时才还有兜底意义。)
|
||
2. **FTP 路径**:lftpd 相对路径基准是**根目录**(`SIZE selftest.log` → 550),一律用
|
||
绝对路径 `/log/xxx`;`LIST /log` 实测列的是**根目录**内容(lftpd 怪癖)——查状态只用
|
||
`SIZE` / `RETR`。
|
||
3. **0 字节 STOR 的数据连接**存活期仅 ~10~50ms,短于芯片/网络层轮询粒度 → 芯片只见
|
||
`DISCONNECTED (chip tcp=0x00)` → accept 失败(425 或控制连接被重置);2026-10-02 实测客户端
|
||
`PASV→STOR` 间隔达 **11 s**(数据口 LISTEN 半开)。这是**与看门狗误复位不同的另一类
|
||
问题**(CH395F 数据通道);若修复后仍复现 425,转 §7.1 专项。
|
||
4. **串口采集铁律**:`open` → `clear` → 烧录/复位 → `wait-idle --timeout 90 --settle-ms 8000
|
||
--max-ms 45000` → **直接 Read/Grep `.dsh/skills/serial-assistant/scripts/state/serial.log`**
|
||
(`log --grep` 子命令不可信);daemon 残留 → `taskkill /F /PID <旧>` 后重新 `open`。
|
||
5. **只用 `.venv\Scripts\python.exe`**(PATH 里的 `python` 是 msys64);每次烧录后**必须**
|
||
ST-LINK 全片回读 `No difference found`。
|
||
6. **误复位会使台账 +1 条** `watchdog reset`:取证/修复期间台账只会增长,
|
||
属预期(清台账留到最后一次修复后的出口闭环)。
|
||
7. **ST-LINK_CLI 取证三硬知识**(完整用法见 `ST-LINK_CLI_复位使用说明.md`):
|
||
- `-R32` **不会 halt 内核**(`-CoreReg` 才 halt,实测约 30ms/次且可重复)→ 用 `-R32` 做
|
||
**无扰动**存活性采样,只在需要 PC 时用 `-CoreReg`(halt 期间 TIM7 ISR 不执行,
|
||
会让中断计数出现"假停顿",须用非 halt 读法甄别)。
|
||
- `-R32 <addr> <count>` 的 `count` 单位是**字节**(`-R32 0x1000FF00 16` 得 4 个字);
|
||
按字理解会把读取**静默截断**。
|
||
- `-W32 <addr> <data>` 的 `data` 按**十六进制**解析(写 `1249` 会变成 `0x1249`,
|
||
被 12 位 RLR 截断成 `0x249`=585);要写十进制 1249 得传 `0x4E1`。另 `IWDG->KR` 是
|
||
**只写**寄存器(读回恒 0),`-W32` 写 KR 必报 `Error!`——那是 ST-LINK 的写-回读
|
||
校验失败,**写入其实成功**。
|
||
- 现场改寄存器(如 IWDG PR/RLR 验证手段)须在**一次调用**内完成整段键序列
|
||
(解锁→参数→键锁)——分多次调用会超过看门狗超时、中途被复位;寄存器随复位丢失,
|
||
只能用于验证,不是修复。
|
||
8. **开机良性 `MISS start` 行**(2026-10-03 上板):看门狗抽样在**开机屏障等待期**偶见
|
||
UI 位单抽样缺席,每 episode 记一条裸 UART `MISS start snap=0x… req=0x… t=…`
|
||
(`task_watchdog.c` 的停摆起点标记,round-7 取证件)。实测每次开机 2 条
|
||
(t≈0.6s / t≈2.8s,snap 仅缺 UI 位),NET_READY 解除后立即恢复——**未达 800ms 停喂
|
||
阈值、不触发复位**,属分片心跳与 100ms 抽样边界的固有交错,非回归;
|
||
处置:见到该行不必恐慌,**连续**出现 `task stall` 行/复位才是真停摆。
|
||
9. **导航类自动化脚本默认零 ENTER**(2026-10-26 台架实证,task-41 收口;口径也见
|
||
`启动日志原子性复验流程.md`):装置维护的 **强制复归 / 清除记录 是两段式确认**——
|
||
第一次 ENTER 只把该行标成「确认?」,**第二次 ENTER 才真执行**(复归保护位并写 SOE /
|
||
清 SOE·运行·操作记录)。因此任何"认不出屏就按 ENTER 试一下"的回收逻辑,落到这两页上
|
||
等于**替操作员按下执行键**;更隐蔽的是它只在画面异常时才发作(新字库缺字、白框、状态行
|
||
变化——恰恰是回归最想抓的那几帧),平时零流量、改动时无声。 `scripts/board_ui_nav.py`
|
||
的两条硬闸与 `--selftest-quick` 里的 **7 条常驻用例**(假设备 + 内存空白帧 + 按键只记账,
|
||
**不连 7003、不开串口、不碰台架**,提交钩子 `uinav-selftest` 就跑这档)把它钉成回归:
|
||
① UNKNOWN 退避的 ENTER 上限 `BACKOFF_MAX_E`(政策钉死 ≤1,需要第二次就当场停机并 dump 帧,
|
||
报错文案点名执行类风险);② `EXEC_PAGE_IDS`(clear / reset)**默认拒绝下钻**且拒绝发生在
|
||
**任何键投出去之前**(真机实测:连轨迹文件都不生成),显式 `--allow-exec-pages` 才放行并打警告。
|
||
用例还钉住**两个常量本身**:上限被调到 2 以上、清单被清空、或默认值被翻成"允许"——
|
||
都必须在 `--selftest-quick` 里报红(这三条都用"故意改坏再跑"逐条证过能红,不是空跑)。
|
||
通用要求:**导航 = 移光标 + 取帧;ENTER 只能出现在明确、非执行类的用例步骤里**;
|
||
要看执行类页面的显示正确性,去模拟器黄金参考(那里没有真机后果)。
|
||
|
||
---
|
||
|
||
## 10. 已完成事项与证据去向
|
||
|
||
> 已完成事项的**实施细节与真机证据不在本文**,按下列去向查阅;本文只保留其复跑命令与判据。
|
||
|
||
| 事项 | 状态 | 实施细节 / 证据所在 |
|
||
|---|---|---|
|
||
| **S7** 自检结果判定 | ✅ 已落地并投用 | `docs/测试说明/流程与规范/自动化测试流程.md`;提交 `4a4cd29` |
|
||
| **A1** `cfg_file` 堆分配改造 | ✅ 已闭环(含真机持久化) | `子系统设计/配置文件设计说明.md`(实施 v1.11 + 2026-10-03 真机验证记录 + 2026-10-04 独立复跑记录) |
|
||
| **A2** 网络重建失败恢复 | ✅ 已闭环(正常路径零回归;故障分支见「网络负向场景台架验证」) | `网络/Net层阻塞模型架构设计.md` |
|
||
| **A3** CH395F 字节命令超时 | ✅ 已闭环(正常路径零回归;故障分支待专项窗口) | — |
|
||
| **A4** `remo_send` 返回值 | ✅ 已闭环(正常路径零回归;推流压测待专项窗口) | — |
|
||
| 2026-10-02 台架取证链(IWDG PR/RLR 错配 / dhara resume 回滚 / ORE 僵尸通道) | ✅ 已修 | `子系统设计/看门狗设计说明.md` 2026-10-02 变更记录 · `架构设计/STM32F4-Base存储架构说明.md` §5.4.1 · `子系统设计/控制台单写者日志设计说明.md` §12;提交 `930215f` |
|
||
|
||
> **真机判定汇总**(2026-10-03,本机 MCU,新固件全闭环 `@test` PASS 7/7):A1 ✅ PASS(含配置持久化);
|
||
> A2/A3/A4 正常路径零回归;芯片级失败分支 / 短写 / 拔线负向场景记 `docs/任务规划/登记簿.md` 条目「网络负向场景台架验证」,待专项台架窗口。
|
||
|
||
---
|
||
|
||
## 11. 与既有文档的引用闭环
|
||
|
||
| 本文项 | 上游文档 | 下游落地文档 |
|
||
|---|---|---|
|
||
| S7 自检判定 | —(原复审项,已闭环 2026-10-02) | `docs/测试说明/流程与规范/自动化测试流程.md`(参数已落地,`4a4cd29`) |
|
||
| V2/V4/V5 | `子系统设计/看门狗设计说明.md` §7 验证记录 | `子系统设计/看门狗设计说明.md` 变更记录(2026-10-03) |
|
||
| S11 堆告警 | —(原复审项,已闭环 2026-10-03) | `内存管理/RAM使用分析与优化方案.md`(基线更新) |
|
||
| S9 GD5F | —(第二档 #1) | `问题记录/GD5F2GQ5UE_Trap_Records.md`、`docs/测试说明/板级测试/GD5F2GQ5UE_Test_Guide.md` |
|
||
| 日志静默观察项 | `docs/任务规划/登记簿.md` | `网络/Net层阻塞模型架构设计.md`(头阻塞,历史编号) |
|
||
| 网络重建 | —(原台账项,已闭环 2026-10-02) | `网络/Net层阻塞模型架构设计.md` |
|
||
| S5/S4 | —(原复审项,已闭环 2026-10-03) | `docs/测试说明/流程与规范/测试开发标准流程.md` |
|
||
| 模拟器差距 | `docs/测试说明/专项验证/模拟器差距清单.md` §3 决策规则 | 本文为"需回真机"项的执行面 |
|
||
|
||
> **模拟器差距清单 §3 的六条"必须回真机"规则**决定"哪些改动**必须在本规划内验证——
|
||
> 改动触及 `Drivers/BSP/` 寄存器时序 / 模拟器差距清单的硬件专属项 / 配置变更检测与回调 / 网络重建并发 / 启动段 / 内存预算,
|
||
> 一律在本文件找到对应批次。
|