From fa4cde36f6d5dc19ee8e9db4f64b63ec37e59180 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Fri, 23 Oct 2026 20:47:22 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E8=A6=86=E7=9B=96=E7=8E=87):=20=C2=A79=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E"=E5=81=87=20CH395F=20=E8=8A=AF=E7=89=87"?= =?UTF-8?q?=E5=AE=9E=E6=96=BD=E8=A7=84=E6=A0=BC=EF=BC=8C=E5=B9=B6=E6=9B=B4?= =?UTF-8?q?=E6=AD=A3=E4=B8=80=E9=A1=B9=E8=A2=AB=E6=88=91=E9=AB=98=E4=BC=B0?= =?UTF-8?q?=E7=9A=84=E5=89=8D=E7=BD=AE=E6=88=90=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 立项假 CH395F:NET 域剩下三块(net_pending 287 / net_events 263 / net_listener 191 = 741 行)都把芯片当真理读,这些语义真机上只在总线上一闪而过、台架不可复现;做完它 连 P2 的 net_socket.c(1,251 行,全仓最大逻辑块)一起解锁。 **一处更正**:我上一轮(提交 8bf4273 的正文与对话汇报)说这三块"还调 net_socket.c 的 内部函数(net_drain_chip_rx / net_relisten_done / net_relisten_locked),要一并给假件"。 实测这三个名字全是 **net_listener.c 文件内的 static**(net_listener.c:86 / :114 / :273), 不存在跨 TU 引用 → 该项前置成本**不成立**,工作量比我说的小。三块之间只走公开 API (net_listener_request/settle、net_pending_*、net_get_sock/net_sock_raw 等)。 规格内容(全部从真实头逐条核出,不凭记忆): - 15 个芯片函数的真实原型,假件必须一字不改照抄;特别标出三种形态: ch395f_get_socket_status / ch395f_get_remot_ipp 是**出参**、 ch395f_sock_state_cached 返回 **ch395f_sock_state_t 枚举**(不是 uint8_t,虽然底层 整型兼容,照抄才会在原型漂移时编译期报错)。 - 假芯片必须复刻的两条芯片怪癖:① get_sock_int_status **整体读即清**、芯片无按位 清除手段 —— 假件要按"返回该 socket 挂起位图并同步清空、可逐 socket 预置"实现, 否则照不出 AGENTS 模块约定里 B3 的实证坑("顺手全量清一遍"把别的在用 Socket 的 门焊死);② sock_state_cached / link_up_cached 是**缓存值**而非现场值,要把"缓存 在第几次调用后更新"做成可脚本化,才能测对账循环读到陈旧状态的路径。 - 脚本化模型沿用本仓既有假件风格(nand_port 的真头+假 diskio、lftpd_io 的可注入假 堆):读函数一条按调用序号取的返回队列、写函数一条调用记录、外加每函数调用计数 以断言"这一轮不该碰芯片"。 - 桩放置点需要拍板,已给推荐:test/host/common/ch395f_fake.h/.c 三模块共享,理由是 三份各自漂移会让"假件与被测代码同时错"这类问题再也报不出来;代价是不进 MCU 构建、 要靠 test-cppcheck 覆盖。若沿用每模块自带桩的惯例,则三份必须 include 同一份头锁签名。 - 实施顺序 net_listener → net_pending → net_events,逐个写明各自要桩什么、判据抄哪份 文档(网络自愈架构设计 §4.10 的读清点与三条准入判据),以及每步的验收动作 (@build 0/0、套件全绿、--update-baseline、先补 TC-HOST-* 族再往文档里引号)。 本轮**只动这一篇文档**(零代码改动,故不跑 @build);check_doc_links --all = 35 处 (= 存量基线,本分支贡献 0);文件 BOM/CR/行尾与 HEAD 一致。 另:本会话上下文见底,故把这块以规格形式交付而不是留下编译不过的半成品 —— 规格里的 原型、static 归属、怪癖与顺序都已核实,下一会话可直接从"写 test/host/common/ ch395f_fake.h"开始。 --- docs/测试说明/主机单测覆盖率口径.md | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/docs/测试说明/主机单测覆盖率口径.md b/docs/测试说明/主机单测覆盖率口径.md index a38e92a1..df99e751 100644 --- a/docs/测试说明/主机单测覆盖率口径.md +++ b/docs/测试说明/主机单测覆盖率口径.md @@ -289,6 +289,71 @@ 被门禁判了一次 `REGRESS`——那是台账在如实反映"代码少了一行",不是覆盖退化, 已按 `--update-baseline` 重登(这条恰好反证门禁有效:删代码想悄悄过去,它会拦)。 两处"现状桩"翻成正向契约,另新增 `TC-NETSEL-012c`;全量 22 套件仍然全绿。 +### 假 CH395F 芯片:实施规格(2026-10-23 立项,交给下一会话执行) + +**为什么要它**:@@NET@@ 域剩下的三块(@@net_pending.c@@ 287、@@net_events.c@@ 263、@@net_listener.c@@ 191 = 741 行) +全都把芯片当真理读,真机上这些语义只在总线上一闪而过、台架不可复现。做完它,P2 的 +@@net_socket.c@@(1,251 行,全仓最大逻辑块)也一起解锁。 + +**真实原型(@@Drivers/BSP/CH395F/ch395f.h@@ 逐条核出,假件必须一字不改地照抄签名)**: + +```cpp +uint8_t ch395f_sock_state_cached(uint8_t sn); /* 返回 ch395f_sock_state_t 枚举值 */ +void ch395f_get_socket_status(uint8_t sock, uint8_t *status); /* 出参形态 */ +uint8_t ch395f_get_sock_int_status(uint8_t sock); /* ⚠ 整体读即清,见下 */ +uint16_t ch395f_get_recv_len(uint8_t sock); +void ch395f_read_recv_buf(uint8_t sock, uint8_t *p_data, uint16_t len); +void ch395f_write_send_buf(uint8_t sock, uint8_t *p_data, uint16_t len); +uint8_t ch395f_open_socket(uint8_t sock); +uint8_t ch395f_close_socket(uint8_t sock); +uint8_t ch395f_tcp_listen(uint8_t sock); +void ch395f_set_proto_type(uint8_t sock, uint8_t proto); +void ch395f_set_sour_port(uint8_t sock, uint16_t port); +void ch395f_get_remot_ipp(uint8_t sock, uint8_t *p_buf); /* 出参形态 */ +void ch395f_set_keepalive_enable(uint8_t sock, uint8_t enable); +uint8_t ch395f_link_up_cached(void); +uint16_t ch395f_link_change_count(void); +``` + +**假芯片必须复刻的两条芯片怪癖**(不复刻就等于把被测代码的坑假件掉): +1. @@get_sock_int_status@@ 是**整体读即清**、芯片没有按位清除手段。假件要按"每次调用 + 返回该 socket 的挂起位图并**同时清空**"实现,并允许逐 socket 独立预置——否则 + 照不出 AGENTS「模块约定」里 B3 那条实证坑:*"顺手全量清一遍"等于把别的在用 + Socket 的门焊死*。 +2. 状态是**缓存值**而非现场值(@@sock_state_cached@@/@@link_up_cached@@):假件要把 + "缓存更新发生在哪一次调用之后"做成可脚本化,才能测出对账循环读到陈旧状态的路径。 + +**脚本化模型**(沿用本仓既有假件风格:@@nand_port@@ 的真头+假 diskio、@@lftpd_io@@ 的可注入假堆): +每个读函数一条**按调用序号取的返回队列**(耗尽后回落到最后一值),每个写函数一条 +**调用记录**(次数 + 最近一次入参),另给 @@g_chip_call_count[函数名]@@ 让"这一轮不该碰芯片" +的契约可断言;@@reset@@ 一次全清。所有假件写在测试单元 @@.c@@ 里,**不建共享 @@.so@@/库**。 + +**桩放哪里(一个需要拍板的点,先给推荐)**:三个模块都要用同一份假芯片,@@test/host/*/stub/@@ +每模块一份会漂移(三处签名各改一半 = 假件与被测代码同时错还不报错)。推荐 +@@test/host/common/ch395f_fake.h + .c@@(与 @@unit_test_harness.py@@ 同级,三模块的 +@@include_dirs@@ 各加这一条),代价是它不进 MCU 构建、要靠 @@test-cppcheck@@ 覆盖。 +若沿用"每模块自带桩"的现有惯例,则必须让三份桩都 @@#include@@ 同一份头以锁死签名。 + +**三个文件的真实依赖面(逐个核出,别按猜的排工作量)**: +- @@net_listener.c@@(191 行)—— **最便宜,先做它**:@@net_drain_chip_rx@@/@@net_relisten_locked@@/ + @@net_relisten_done@@ 全是**本文件内的 static**(2026-10-23 实测确认),所以它只需要 + 芯片假件 + @@net_get_sock@@ + @@net_pending_active@@ + @@HAL_GetTick@@ + @@dbg_log@@, + 外加 @@test_config.h@@/@@net_latency_test.h@@ 两个可空壳的头。**不需要假造 net_socket.c 内部函数** + (我上一轮把它当成前置成本,是错的,特此更正)。判据现成:单连接 socket 复用、 + 按网络代次重建监听、@@net_listener_armed@@ 门控(@@docs/网络/网络自愈架构设计.md@@ §4.10)。 +- @@net_pending.c@@(287 行)—— 要 @@net_listener_request@@(可用一个只记录调用的假件), + 契约是挂起 recv 的注册/超时/取消与"写失败回置"那族;@@tick@@ 收 @@net_sock_t *@@ 表参数 + (@@net_get_sock@@ 对未用槽位返 NULL,tick 需读 @@in_use == 0@@ 兜底 —— AGENTS 已记)。 +- @@net_events.c@@(263 行)—— 依赖最多(@@net_sock_raw@@/@@net_listener_settle@@/ + @@net_pending_cancel@@/@@net_send_pending_cancel@@/@@xTaskGetTickCount@@),**放最后**。 + 注意 @@net_sock_raw@@ 是刻意不给应用层用的现场指针(头注释写明"仅供 net_events.c 的 + 对账循环使用"),假件要保留"对未在用槽位也能拿到项"的行为,否则对账兜底路径测不到。 + +**验收顺序**:@@net_listener@@ 绿 → 立刻登记基线(哪怕只有它一个)→ @@net_pending@@ → @@net_events@@; +每步都要 ```build 0/0 + 21+ 套件全绿 + --update-baseline + 补建 @@TC-HOST-*@@ 族@@(族数现在 16, +三块做完应为 19),并且**先补族再往文档里引这些号**,否则 @@id-check@@ 会按台账外新账卡提交 +(本会话已被 @@TC-NETCFG-028@@ 实测拦过一次)。 + ### P2|值得但工程量大(5 个 `.c` = 2,226 行) 1. **`net_socket.c`(1,251 行 / 51 个函数,全仓最大的逻辑块)** —— 必须**分片**,别一次吞。