test(net/udp): 阶段 16 台架加固 + 真机首跑证据回填(#73)
CI / 静态门禁 (pre-commit) (push) Failing after 5m39s
CI / 主机侧单测 (MSVC) (push) Successful in 30s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 4m15s
CI / 主机侧单测 (MSVC) (pull_request) Successful in 47s

第一次上真机把台架的两处软肋照出来了,都不是被测代码的问题:

- peer 死在 Windows 的 ICMP 10054:板子还没 bind 时那一下端口不可达会被记在套接句上,
  下一次 recvfrom 才抛出来。本机 CPython 3.14.7 既没有 socket.SIO_UDP_CONNRESET 也不接受
  它的数值形式,所以主力防线改成把 10054 当「这一轮没收到」继续重试,并在回路自检里加
  冷端口探针——探针走脚本真正在用的 _recv_maybe,另拿裸套接句证明这台机器确实会回 ICMP,
  否则那条判定就没有牙。
- 单步预算错位:板端每步等 25 s,peer 每步只等 8 s,一步超时后整条梯子全灭。现在 peer
  每步都重发、单步预算 --step-budget 默认 35 s(小于 26 s 打警告);板端 udp_bench_expect
  按载荷第 0 字节的步号自愈,比本步小的旧包丢掉继续等(上限 UDP_BENCH_STALE_MAX = 8),
  比本步大的直接报出来。DBG_WARN 在本工程不存在、字符串字面量必须纯 ASCII,两处已改。

真机已拿到的证据:TC-NET-1601a/b/c(建 socket、bind :6001、net_udp_get_mode 回 SERVER)与
TC-NET-1602(服务端形态收到 20 B、addrlen/sin_family/源端口全对、逐字节回显、形态翻成
CLIENT)全绿——剥 8 字节信息头与源地址回填在真芯片上成立;②③④⑤ 因板子当晚两次失电
(19:19、21:0x,SWD No target connected + ping 不通)未测,指南 §12.6 与覆盖率口径第 4 轮
的状态条据此改写。产品态(宏回默认)重新构建 0 Error 0 Warning,Code 249,124 / RO 29,836 /
RW 2,052 / ZI 149,996 与本阶段之前逐字节一致,阶段 16 在产品里被预处理干净。
This commit is contained in:
2026-11-03 21:28:36 +08:00
parent b0a6394aa1
commit fc0d3e4b5c
5 changed files with 189 additions and 42 deletions
@@ -1181,11 +1181,30 @@ WAIT_CLOSE 阶段已内置二段补发(只补一次),生产 net 层则靠
它只证明**对端脚本**可用,不证明板端行为——真机那一趟仍然一条都不能省。
- TC-NET-1607 用 30 s 预算版的挂起等待,不用无限版:同一套 park/唤醒机制,但无人值守的台架不该留一个
能把任务钉死的等待。无限版(`timeout_ms = 0` → deadline = 0)的语义由主机单测 UDP-6 钉住。
- 本阶段构建实测(2026-11-03,`MDK-ARM/STM32F407-Demo/STM32F407-Demo.map`):Code 257,176 /
RO 33,900 / RW 2,060 / ZI 151,596;RW_IRAM1 **96,232 B = 73.4%**(距 92% 红线余 24,354 B),
RW_CCM 57,376 B / 87.9% 与产品一致。台账数字以 `test/board/ch395f_test.h` 那段为准。
- **本阶段尚未在真机上跑过**:本轮台架的板子 19:19 起断电(SWD 报 `No target connected`、
ping 不通、串口静默),而 PR #74 的合并前提就是这条回归跑完拿到证据。
- 本阶段构建实测(2026-11-03 加固后,`MDK-ARM/STM32F407-Demo/STM32F407-Demo.map`):Code 257,388 /
RO 34,136 / RW 2,060 / ZI 151,596;RW_IRAM1 **96,232 B = 73.4%**(距 92% 红线余 24,354 B),
RW_CCM 57,376 B / 87.9% 与产品一致。产品态(宏回默认后重新构建)Code 249,124 / RW 2,052 /
ZI 149,996,与本阶段之前逐字节一致——阶段 16 的代码在产品里被预处理干净。台账数字以
`test/board/ch395f_test.h` 那段为准。
- **真机进度(2026-11-03 夜)**:第一次上台架已跑通**前半段**——板端
`TC-NET-1601a/b/c`(建 socket、bind :6001、`net_udp_get_mode` 回 SERVER)与
`TC-NET-1602`(服务端形态收到 20 B、`addrlen`/`sin_family`/源端口都对、逐字节一致,回显后模式
翻成 CLIENT)**全绿**,PC peer 侧同样收到那 20 B 回显;这就是队列化后的 UDP 收包路径在真芯片上
的第一份证据(剥 8 字节信息头 + 源地址回填 + 回显发送全部正确)。**1603 之后仍未测**:板子在
21:0x 再次失电(SWD `No target connected`、ping 不通、ST-LINK 探针仍在),与 19:19 那次同一现象。
- 首跑抓到两处**台架**缺陷(都不是被测代码的问题,已改掉并各自有守卫):
1. peer 死在 `WinError 10054`——板子还没 bind 时那一下 ICMP 端口不可达会被 Windows 记在套接句上,
下一次 `recvfrom` 才抛出来;本机 CPython 3.14.7 既没有 `socket.SIO_UDP_CONNRESET` 也不接受它的
数值,所以主力防线改成把 10054 当「这一轮没收到」继续重试(`udp_queue_bench.py` 的
`new_peer_socket` / `_recv_after` / `_recv_maybe`),并由
`test/host/udp_queue_bench_loopback.py` 的冷端口探针守着(用脚本真正在用的那条路判定,
同时拿裸套接句证明这台机器确实会回 ICMP,否则探针没有牙)。
2. **一步超时→整条梯子错位**:板端每步等 25 s,peer 每步只等 8 s,于是 1602 之后每一步都踩在板子
的上一步预算里,日志看起来像"全灭"。现在两侧各自加固:peer 每步都重发且单步预算 `--step-budget`
默认 35 s(小于 26 s 会打警告);板端 `udp_bench_expect` 认载荷第 0 字节的步号,比本步小的旧包
丢掉继续等(上限 `UDP_BENCH_STALE_MAX = 8`),比本步大的直接报出来。
3. 顺带一条纪律:跑台架期间**不要用 serial-assistant 守护进程取证**——它重启后不会重开 COM3
(`status` 里 `ready:false`、`rx_bytes:0`),会把整段板端日志丢光;直接 `pyserial` 落盘更稳。
---