fix(test/udp): peer 换源端口上报方式并补 PC 回路自检(#73)
CI / 静态门禁 (pre-commit) (push) Failing after 5m4s
CI / 主机侧单测 (MSVC) (push) Successful in 44s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 4m48s
CI / 主机侧单测 (MSVC) (pull_request) Failing after 44s

- test/host/udp_queue_bench.py:Windows 上未 connect 的 UDP socket 调 getsockname()
  直接抛 WinError 10022(请求一个未连接套接句的名称),脚本在第一条用例就崩。
  源端口改为首次收到回显时打印——它本来就是「板端剥头/源地址判定对不对」的直接读数。
- 新增 test/host/udp_queue_bench_loopback.py:不用板子的 peer 自检,在 127.0.0.1 上放
  一个按板端阶段 16 同样三条规矩说话的假板子(原样回显、tag 0x04 只回 64 B、>1KB 按
  1024 拆片),先把步骤表 / 模式函数 / 分片预期验掉。2026-11-03 首跑 27/27 绿,
  实测拆片形状 [1024, 1] 与 [1024, 448]。
- CH395F_Test_Guide.md §12.6:运行方法补「先跑自检」这一步;>1024 B 的 UDP 拆片从
  「多收到一片就 FAIL」改成「实测观测量」(拼接后逐字节一致才算绿),并说清这是既有
  NET_SEND_CHUNK_MAX 行为、不是本轮引入;脚本表补一行。
- 板子自 19:19 起未再上电(ping 不通、SWD No target、串口静默),阶段 16 真机那一趟
  仍未跑,PR #74 的合并前提不变。
This commit is contained in:
2026-11-03 20:46:15 +08:00
parent 8a81fa9e41
commit b0a6394aa1
3 changed files with 173 additions and 30 deletions
@@ -1155,24 +1155,30 @@ WAIT_CLOSE 阶段已内置二段补发(只补一次),生产 net 层则靠
**运行方法**:
1. `test/board/test_config.h` 开 `TEST_SUITE_CH395F`;`test/board/ch395f_test.h` **只**开
1. 先在 PC 上自检 peer 脚本(不用板子):`python test/host/udp_queue_bench_loopback.py`,绿了再往下走。
2. `test/board/test_config.h` 开 `TEST_SUITE_CH395F`;`test/board/ch395f_test.h` **只**开
`ENABLE_PHASE16_TESTS`,并把默认的 `ENABLE_PHASE11_TESTS` / `ENABLE_PHASE14_TESTS` 注掉——
它们会带进 `TEST_LATENCY_PROBE`,污染要证的 UDP 面。
2. `/keil-build` 后烧录(`.dsh/skills/stlink-flash/scripts/stlink_flash.py flash`,`-Rst -Run` 必带)。
3. PC 先起 peer:`python test/host/udp_queue_bench.py --board 192.168.31.100`,再给板子上电/复位;
3. `/keil-build` 后烧录(`.dsh/skills/stlink-flash/scripts/stlink_flash.py flash`,`-Rst -Run` 必带)。
4. PC 先起 peer:`python test/host/udp_queue_bench.py --board 192.168.31.100`,再给板子上电/复位;
peer 首步每 4 s 重发,能盖住板子启动那段时间。
4. 判据是**两侧都绿**:板端串口 `=== Phase 16: N/N PASSED (failed=0) ===`,PC 端
5. 判据是**两侧都绿**:板端串口 `=== Phase 16: N/N PASSED (failed=0) ===`,PC 端
`=== UDP Bench PC Peer: N/N PASSED (failed=0) ===`。PC 绿板红 = 板端断言没对上激励;
板端绿 PC 红 = 回显内容或分片不对。Windows 防火墙静默丢包会让首步一直"无回显"(§14 已记)。
5. 跑完把这四行宏恢复成产品态重新构建 + 烧录(`test-suite-switch` 钩子也会拦住带测试宏的提交)。
6. 跑完把这四行宏恢复成产品态重新构建 + 烧录(`test-suite-switch` 钩子也会拦住带测试宏的提交)。
**限度与观测点**:
- `net_send_locked` 的分块上限 `NET_SEND_CHUNK_MAX = 1024` 是为 TCP 流设计的;UDP 上它会把一条
超过 1024 B 的 `sendto` 拆成多次 `WRITE_SEND_BUF`,芯片就发成**多个数据报**(UDP 没有可拼的流语义)。
TC-NET-1609 的 1025 / 1472 两条会在 PC 侧把这件事直接量出来(多收到一片就记 [FAIL] 并打印各片长度)。
产品侧结论:**UDP 单包保持在 1024 B 以内**(#57 的 SNTP 是 48 B,碰不到这条)。这不是本轮引入的——
改造前的直调 `net_sendto` 就是同一个分块循环,只是那时 UDP 根本没有多任务调用者。
这是既有行为、不是本轮引入(改造前的直调 `net_sendto` 就是同一个分块循环,只是那时 UDP 根本没有多任务
调用者)。peer 把它当**观测量**而不是错误:TC-NET-1609 的 1025 / 1472 两条要求「所有片拼回来与发出的
载荷逐字节一致」,并打印实测分片形状;只有拼接后长度或内容不对才判 [FAIL]。
产品侧结论:**UDP 单包保持在 1024 B 以内**(#57 的 SNTP 是 48 B,碰不到这条)。
- peer 脚本自己有 PC 侧回路自检,不用板子:`python test/host/udp_queue_bench_loopback.py`——它在
127.0.0.1 上放一个按上面三条规矩说话的假板子(同样剥 tag 0x04 到 64 B、同样 1024 拆片),把步骤表、
模式函数、分片预期先验一遍。2026-11-03 首跑 `27/27 PASSED`(实测拆片形状 `[1024, 1]` / `[1024, 448]`)。
它只证明**对端脚本**可用,不证明板端行为——真机那一趟仍然一条都不能省。
- 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 /
@@ -1193,6 +1199,7 @@ WAIT_CLOSE 阶段已内置二段补发(只补一次),生产 net 层则靠
| `udp_client --ip ... --port 60000` | PC 作 UDP Client | 测试 UDP Echo(阶段 3) |
| `udp_server --port 8082` | PC 作 UDP Server | 接收 CH395F UDP 数据 |
| `python test/host/udp_queue_bench.py --board <板 IP>` | PC 作 UDP 对端(独立脚本,不在上面那个脚本的模式里) | 阶段 16 BSD UDP 数据面回归:逐步换源端口、切形态、截断、空窗、迟到包(§12.6) |
| `python test/host/udp_queue_bench_loopback.py` | 不用板子的 peer 回路自检(本机假板子) | 上阶段 16 台架前先验 peer 的步骤表与分片预期(§12.6 第 1 步) |
| `dhcp_server ...` | DHCP Server | 内置 DHCP(阶段 4,需管理员权限) |
### 通用参数