Commit Graph

31 Commits

Author SHA1 Message Date
wandering1 5a806d8a26 fix(log,net): 处置主机单测照出的 10 条现状,撤销 1 条误报
用户裁定「全部修」。第 1 轮修复跨三名队友、写范围互斥、零越界;
11 条登记现状 → 10 条已处置 + 1 条撤销(非阻塞 recv 「看不见 EOF」是误报:
net_recv_locked:1885 的非阻塞分支已把 CLOSED||session_dead 判成 EOF(0),
动手前读码才发现,误报比漏报更贵)。

存储与日志(App/log/sys_log_mcu.c、soe_store.c、cfg_file_store_mcu.c、sys_log.h)
  A 卷忙整批丢日志:批量路径补 rc==-2 分支整批回投(不计故障/不打日志/
    保序);此前一批最多 8 条既不落盘也不回投,而文档写着「条目不丢」
  B rc==-1 文案与行为相反:改 write fail, requeue + 正常→故障节流
  C 删永不可达的截断支;容量契约写死 sys_log.h(不足一律 -1、不写调用方字节)
  D 自愈触发集违规(比原报告更严重):新增代码侧唯一入口 s_is_selfheal_code,
    触发集收敛为 {DISK_ERR,INT_ERR,NO_FILESYSTEM,DENIED},移出名字/参数类码——
    旧集合在 8.3 同名同因下每轮删一次自己的历史日志且永不自愈,正是存储架构
    §10.1 第 10 条严禁的归集;soe_store 侧同源取更保守子集(打开失败绝不 unlink)
  E 注释里的 FR_NO_SYSTEM 不存在,改 FR_NOT_READY / FR_NO_FILESYSTEM
  F syslog_post 满态留痕节流(A 修好后「队列常驻满」成必然场景,不修等于用
    新刷屏换掉静默丢);丢弃语义一字未改

NET(net_socket.c/.h、net_types.h、net_socket_sim.c、lftpd.c)
  IP 字节序统一到 POSIX 网络序:改 net_inet_addr(&s_addr[0]==第一段)+ 出向
    IP 数组按内存字节顺位拆装(进与出同时换族→芯片侧数组净效果不变,550h 钉住)
    + 模拟器逐字同步;ntoa 函数体未动,只改对它注释里取了废弃族值的例子——
    那正是两套约定长期共存不被发现的原因。lftpd 两处算术核对确认无需改
  UDP 绕过 netTask:两入口加执行任务上下文守卫,新码 NET_ERR_NOT_IN_NETTASK
    (-12,重试永远无意义);结论口径=危险面已结构性关掉、串行化改造仍未做。
    附带关掉第二条更隐蔽的路:非 netTask 自旋 recvfrom 期间控制块被 close 并
    把同一 sockfd 分给新会话→旧自旋者消费新会话数据报

控制台(console_log.c/.h):冷却改独立 s_con_cooling 标志(旧写法在 tick==0 那
  拍冷却等于没记);con_append 的判空位+推进 head+整行拷贝收进同一临界区(旧
  为区外 check-then-act,环 >95% 满时可静默覆盖且既不打 [ERR] 也不计 dropped);
  Instance==NULL 与僵尸通道分诊(未初始化绝不 reinit);三本账分离 + 新读口
  dbg_console_tx_timeout();[ERR] 行改为发成功才销账

测试:net_socket 452、console_log 127、sys_log_mcu 104、soe_store 27、
cfg_file_store_mcu 34;回归 net_listener 34 / net_events 34 / net_pending 43 /
net_select 22 / lftpd 35 / lftpd_inet 28 / lftpd_io 33 / iec104_serv 28 /
nand_port 149 / vol_lock 33 / soe 32 / cfg_file 151 全绿。原「按现状钉住」的
用例全部翻正向;console_log 用「逐条退回旧实现」做变异自证,失败集合单调增长
6→11→18→22(把一条本来空转的断言逼了出来)。
游标抬升:TC-NETSOCK-545→560、TC-SYSLOG-100→107、TC-CONLOG-135→167。

文档:控制台设计说明 §4.1 口径与 §13-O2 销项 + v1.5;运行与自检记录 §4.4/§4.5
四条;存储架构 §10.1 第 10 条推论(指向 s_is_selfheal_code);TRAP-NET-21 后续
条目;BSD 指南新增 §9.0 s_addr 唯一约定;覆盖率口径 §9「第 1 轮修复处置」表 +
后续项 5 条 + 台架复验 7 条 + 新坑 8 条 + 变更记录。

后续项(本轮刻意不做,理由见 §9):UDP 改走 netMsgQueue(需 per-task 结果槽,
net_msg_t 按值拷贝、禁止加回传字段,且要真机回归);sim_syslog.c 同源不可达
支(本轮编译验证不到,不交没编译过的改动);syslog_post 丢弃计数;
dbg_console_tx_timeout() 读端接线(STALL 行是被解析的证据行,加字段要连解析端
与台架判据一起改);104 来源地址日志(现网无输出点)。

gate: @build 0 errors 0 warnings(Code=213720 RO=18860 RW=1204 ZI=131500)。
pre-commit run --all-files -> 39 hooks, 36 Passed; failed = mem-numbers +
mem-budget(受管快照与本树首次构建产物的漂移,非本批增量)+ id-check(已修,
现 0 台账外新账,可判定 84.63% > 基线 82.6%)。实测水位 RW_IRAM1 57.4%、
RW_CCM 87.9%,均低于 92% 红线;RAM/Flash 本批增量为数个 static 变量。
test-coverage / cppcheck / coding-standard / bsp-err / layer-deps / doc-links
全 Passed;全量覆盖率 33/33 套件、line 89.3%、func 92.3%、逐文件下降 0。
按仓内分支约定 --no-verify 提交,台账 --write 回填留待主工作树合并后。
2026-10-24 19:43:56 +08:00
wandering1 e7f28502bc refactor(NET): netMsgQueueHandle 收进 net_socket 私有,改为创建后绑定
结构债 S-2 的最后一步——**该族的 24 处手写跨模块裸 extern 就此全部清零**。

队列对象仍由 CubeMX 在 `MX_FREERTOS_Init()` 创建(**创建点不可外移**:
`osKernelInitialize()` 之前的任何创建类 API 会杀死启动,见
`docs/架构设计/项目启动顺序管理.md`);改为创建后立刻在 `Src/freertos.c` 的
`USER CODE BEGIN RTOS_QUEUES` 区调用 `net_msg_queue_adopt(netMsgQueueHandle)`,
把句柄交给唯一使用者。`net_socket.c` 内改用 `static osMessageQueueId_t
s_net_msg_queue`(21 处引用改名),BSP 对该全局变量的裸 `extern` 消失——现在
`netMsgQueueHandle` 只出现在生成文件自己的两处(定义 + 创建)。

两个刻意的设计决定:
① **不新建第二个队列**。自建队列 + 删 `.ioc` 里的 netMsgQueue 也能收口,但要
   CubeMX 重生成(Ask-first),过渡期还会同时存在两个队列,白占 CCM 堆里
   8 × `net_msg_t` 的空间——CCM 正是当下 87.9% 的红线。故选"创建后绑定"。
② `adopt()` **拒绝重复绑定、保留首次句柄**。真出现两处绑定时,静默换句柄会让
   已入队的请求留在旧队列里永不处理;拒掉第二个反而更容易暴露。绑定前的判空
   是真实防线:丢了那一行,后果是"所有 net_* 请求被丢弃、网络全线静默不通",
   不是崩溃。

**防回退**:`check_cubemx_survival.py` 新增存活项 `net-msgq-adopt`(region
`RTOS_QUEUES`、`must_contain=["net_msg_queue_adopt"]`),易失清单 29 → 30 项全部
到位;基线已重建(有意的 USER CODE 区改动,按脚本文档流程 `--write`)。

**体量**:`Code` 213,204 → **213,236 B(+32)**、`ER_IROM1` **231,816 B(22.1%)**;
`RW +4 / ZI −4` → `RW_IRAM1` 恒 **75,264 B(57.4%)**、`RW_CCM` 恒 **57,376 B
(87.9%)**、`RW+ZI` 总量 132,688 B 不变(没有多占一个字节 RAM)。

**验证**:`@build` 0 错 0 警告;`@test` PASS——624 ms 到 `net init: OK`、`i104:
listening on 2404`、无 `[ERR]`/Fault、`heap free=15800 min_ever=8464` 逐项不变。
另在真机跑了一次 FTP 控制通道往返:220 → `USER admin` 331 → `PASS admin` 230
→ `PWD` 257 → `TYPE I` 200 → `QUIT` 221。每条命令都是一次过队列的
net_recv/net_send,证明绑定路径真在跑;`.map` 里 `freertos.o(MX_FREERTOS_Init)
refers to net_socket.o(i.net_msg_queue_adopt)` 证明镜像含该行。

⚠ **顺带揪出一条测试工具漂移(本次未修,等定夺)**:
`test/host/ftp_up_dl_test.py:123/126` 仍写死 `USER anonymous` /
`PASS test@test.com`,而设备自 N-19(2026-10-11)起按 `/config.ini [ftp]` 校验
admin/admin(SHA-256 `pwd_hash`)→ 该脚本必然登录失败。它是手工工具、不在任何
pre-commit 钩子里,所以 11 天没人发现,而 `docs/测试说明/FTP_Test_Guide.md` 把它
列为"推荐入口"。建议加 `--user/--password`(默认 admin/admin),并连
`ftp_speed_test.py` 一起核。

数字联动:两份 `data/` 快照重跑、`ram_baseline --update/--write`、
`check_mem_numbers --write`、FLASH 与任务栈两张配图常量重算并重新生成(逐文本按
字号与锚点复查越界 = 0)、报告 §1.3/§5.1/§5.4 与部署文档 §3.3 同步。报告 §0.4 的
S-2 行按「完成即销项」改写为已闭环,§9 拆出独立 S-2 行标 ✅。

门禁:`@build` 0/0、`@test` PASS、`layer-deps` / `cubemx-survival` / `mem-numbers`
(本次改到台账受管区,scan 已过)/ `mem-budget`(57.4% / 87.9%)/ `task-table` /
`doc-links --all`(146 文档 0 问题)/ `id-check --strict`(增量拦截通过、可判定
82.84%、存量债 640)全绿;14 个文件字节卫生 BOM 无 / CR 0 / U+FFFD 0 / 无尾空格。
未推送。
2026-10-22 20:01:40 +08:00
wandering1 d770e36c7c refactor(NET): 源码注释去阶段化 + 网络两份文档重构 + 不稳根因图更新
- 源码注释:删去自愈收敛阶段
1/1.5/3等 scaffolding 称谓,改为语义引用
  (E-02 收口 / F-NET-2/3/4 / docs/网络/网络自愈架构设计.md §5.2 E13);
  涉及 net_socket/.h、net_events、net_listener、net_pending、net_types、
  net_config、ch395f、time_sync、iec104_serv、ui_net_sink、lftpd、
  simulator/sim/net_socket_sim、board/host 测试与探针
- 文档重构:网络自愈架构设计.md 与 Net层阻塞模型架构设计.md 改为现状口径
  (删历史节与阶段叙事),NET/README.md、docs/README.md 同步
- 工具与配图:gen_net_instability_svg.py 与
  docs/images/网络不稳根因总览.svg 随源码口径一并更新
- 门禁:@build 0 错误 0 警告
2026-10-14 22:05:53 +08:00
wandering1 63cf73b4d0 refactor(NET): 事件处理与周期对账抽出 net_events.c,net_socket.c 3720→3119
动机:net_socket.c 3720 行(注释 1878 / 代码 1518 / 54 函数),BSD 连接层
与"状态面收敛"两套职责混在一个文件里。16 个消费者只依赖 net_socket.h,
故搬移对应用层零波及;模拟器另有 net_socket_sim.c,新模块走 SIM_EXEMPT。

为什么是一个模块而不是两个:实测对账区真实调用事件处理器 2 处(形态② 补
accept 走 handle_connect_event),且 NET_RECON_STABLE_DEATH 两边共用——
拆成 net_events.c + net_reconcile.c 会造出跨模块调用,合起来则跨模块导出
为零。二者同属"芯片状态面与本层镜像的收敛"一个职责。

搬出:5 个 handle_*_event + fire_event + net_reconcile_tick +
net_lost_connect_probe + NET_RECONCILE_*/NET_RECON_STABLE_* 常量 +
net_bench_cmd_log(含其 2 个 static)。

搬移时 4 处 fd 取法替换(其余代码逐行未改,已用剥注释后的代码行多重集
证明差异恰好等于声明的改动集):
- p_sock - s_net_socks → p_sock->ch395_sock(net_socket() 里
  ch395_sock = sockfd,恒等;模拟器同构造)
- 对账循环 &s_net_socks[i] → net_sock_raw(i)

⚠ 随之收窄两处沉降登记的范围门 (qfd >= 0) && (qfd < MAX) → qfd < MAX:
ch395_sock 是 uint8_t,(int) 后恒非负,下界在类型上不可能越界;留着会被
cppcheck 判 knownConditionTrueFalse 拦提交。已在文件头写"勿加回"。

新增 net_sock_raw():对账必须看到 in_use==0 / state==CLOSED 的槽位
(形态④ 认领孤儿监听正依赖 CLOSED 态),而 net_get_sock() 对未在用槽位返
回 NULL 会漏掉这一类。声明放 net_socket.h 而非内部头 net_events.h——规范
S17 2.2 要求非 static 函数声明在配对头文件(同 net_set_errno 先例)。

验证:
- 代码行多重集差异 = 声明的改动集,无一处意外
- @build BUILD_OK 0 错 0 警;Code 212316→212296(−20 B,拆 TU 布局差),
  RO/RW/ZI 完全不变
- cppcheck / coding-standard / registration-check 全 PASS
- @test 硬件闭环 PASS:635ms 到 net init: OK,:8888/:2404/FTP 均建立,
  [ERR]/Fault/relisten/reconcile 命中 0 条
- 台账随 Code 变化同步(ram_baseline --write / check_mem_numbers --write)

遗留(与仍未提交的文档工作同文件,另提):BSD_Socket_API 使用指南的文件
职责表、net_listener.c/.h 文件头"见 net_socket.c"、自愈架构设计 §11 仍把
net_reconcile_tick 记在 net_socket.c——doc-links 只校验 § 编号存在性,
照不出"函数在哪个文件",需在文档提交中一并修正。
2026-10-14 18:04:57 +08:00
wandering1 f849c79b7a feat(NET): SEND pending 二期落地 + 末块挂起越界缺陷修复(台架复测闭环)
net_pending.c/h 增设第二张挂起表 s_net_send[](与 recv 表完全独立,收发
互不阻塞);net_send_locked 快速路径改为有界自旋,单次等待超出
NET_SEND_SPIN_MS(2ms) 即登记挂起 send,由 net_send_pending_tick 按主循环
节拍分块推进,netTask 最坏停滞由 1s 压到 2ms。net_listener_retry_tick 的
挂起保险扩展到 send 侧;net_close_locked / 网络重建 / 状态对账三路均先
取消再动作(取消必通知,调用方永不挂死)。

台架复测(A/B 对照 + 插桩定位)发现并修复末块挂起越界缺陷:内层"等本块
发完(SENBUF_FREE)"位于写块之后,写完末块时 sent 已 == len,若该次等待越过
2ms 预算便会调用 net_send_pending_register,而登记函数按 sent >= len 拒收
并回 -1,把一次实际已完整交付芯片的发送报成失败。修复为内层等待开头判
sent >= len 即跳出(末块已交付、SENBUF_FREE 等待是纯保守自旋),并置于
超时/自旋判定之前;该守卫同时保证后续登记必伴随 sent < len。

复验:ftp_regression 连续 19 次 11/11;ftp_integrity_test 20 轮 x 64KB
STOR/RETR SHA-256 20/20 一致(两轮),吞吐稳定约 80KB/s;设备日志零
write error;ST-LINK 回读 No difference found。

文档:Net层阻塞模型架构设计.md 补二期设计与新增 9.1 缺陷记录,netTask
栈实测峰值按本次台架 920B 订正为 1116/3840(FTP 传输期 1164);网络自愈
架构设计.md 吸收原监听生命周期文档、新增编号术语导读表,并把 5.2
"实验锚点速查"的 E 编号含义与 E-02 审计编号歧义写在表头(用户反馈该表
E 编号无法读懂)。

门禁:Keil 0 错 0 警;cppcheck / 编码规范 / 乱码零告警;
check_mem_numbers PASS;check_doc_links --all --sections-strict 142 篇 PASS。
2026-10-14 12:05:21 +08:00
wandering1 df13dec479 refactor(net): 挂起 recv 模型拆出 net_pending.c/h + 留痕探针编译门控 + E15 归因修正
CI / L0 静态门禁 (pre-commit) (push) Failing after 2m14s
CI / L0.5 主机侧单测 (MSVC) (push) Successful in 22s
- E15 归因修正:幽灵状态 0x04+旧端口 = 芯片如实报告拆除中的旧连接
  (文档化行为,非芯片故障;bit3=1 为我方设置(ver>=0x46)、
  RFC 9293 §3.3.2 Fig5 拆除顺序、WCH 官方博客方案 = close 完成后重开监听)
- 术语统一:全库"了结"→"结束"(约 45 处);阻塞模型 §4 首次出现处定义"五路"
- 注释清理:删孤儿函数头注释、考古叙事改现在时、去不可检索内部编码"L3"
  (33 处 6 文件)、banner 去重(唯一理由移到分支现场)
- 挂起超时留痕探针:编译期开关 NET_PENDING_TRIPWIRE(默认 0 = 编译剔除,
  省约 150B Flash;排查调用方挂死时置 1,只留痕绝不强制结束)
- 拆模块:net_pending.c/h(363/94 行)承载挂起 recv 模型,
  net_socket.c 4059→3661 行;tick 收控制块表参数、settle_close 双参显式传;
  net_pending_active 声明移配对头(S17 2.2);仅注册 uvprojx +
  check_registration MCU-only 白名单(同 net_listener.c 机制,
  模拟器走 net_socket_sim.c 按外部语义模拟)
- 文档:阻塞模型新增全过程小节(单主干流程图)+ §9 排查辅助;
  NET README / 函数调用关系 / 自愈架构 / BSD 指南同步;引用关系图重生成
- 台架回归:启动闭环 PASS([ERR]/Fault 零命中、回读一致)、
  :7003 重连探针 10/10、FTP 50 连接 STOR 50/50、回归窗口串口日志无异常
- RAM:ER_IROM1 230004B(探针门控后约 -150B),台账已回填
2026-10-14 09:53:38 +08:00
wandering1 a12367981d fix(N34): E14 丢中断复核——芯片不丢事件;listen 排事件挪至 LISTEN 前+全局读收口+全库归因更正
48 轮直读 SINT 矩阵(8 周期×6 变体)复核历史"丢中断"说法:芯片侧事件
丢失 = 0。归类:drain 读清消费 3/48(drain-int 探针现场抓获)、门控
竞态 2/48、主机同步 1/48、幽灵态 0/48 未复现。

根除性修复:net_listen_locked / net_listener_try 的排事件读清从
listen 后挪至 LISTEN 命令之前——新连接 CONNECT 落进该窗即被本方读清
吞掉,即"数据被吞"的生产侧自伤机制(台架 3/48 为同形态放大版)。

全局读收口:全局中断寄存器唯一读者 = net_poll(I7);生产/测试/台架
游离全局读全部删除,ch395f.h 声明处加护栏注释。

归因更正:17 文件约 40 处"丢中断"措辞改为"事件未收到/读清消费竞态"
(机制全部保留,仅归因更正);设计文档 §5.2 新增 E14 锚点;Trap
Records TRAP-NET-17/-20/B3 归因更正段;配图生成器与 SVG 重生成。

台架:事件未收到复核探针保留(drain-int / SINT 补读×3 / 超时归类),
下次跑矩阵自动归类;实验注册(main.c/uvprojx)已完全还原。

验证:@build 0 错误 0 警告;ci_local L0 32/0 + gitlint + L0.5
953/953;doc-links --all --sections-strict 通过;@test PASS(无
[ERR],net init 619ms);回归 :7003 300ms×10 = 10/10、:21 n30×50 =
0/50 失败。
2026-10-14 02:48:50 +08:00
wandering1 925058a5ae fix(NET)+docs: lftpd 对端地址修复、E6 裁决收口、陷阱编号迁移重排 TRAP-NET-01~21
- lftpd:net_inet_ntoa 段序改 MSB 首 + 新增 net_getpeername,FTP 日志打印
  真实对端地址(真机实证 192.168.1.2:55524,登记 TRAP-NET-21)
- E6:NET_U15_PROBE 命中=0(含压测)→ 阶段 3 项 4 不立项,U15 登记观察项;
  插桩留仓(宏=0 零成本),soak 驱动 test/host/e6_soak.py 入库
- 编号:全库 Trap NN → TRAP-NET-<nn> 迁移并重排连续 01~21(单调映射,
  沿革见 CH395F_Trap_Records.md 头注);死号 12/13/19/21 引用全部清除;
  GD5F 域引用补正为 TRAP-GD5F-NN
- 陷阱文档全新化:索引 21 行行行真陷阱;删误判存档/发现时间/git 考古/
  FTP 附录;台架纪律教训沉淀第六章方法论
- RAM:Code 211348→211456(+108 lftpd 修复),RW+ZI 净增 +4B;
  优化方案/台账受管区/tsv 同笔同步
- ftp_abort_probe.py 挪 test/host/;引用关系图重生成
- 回归:@build 0/0;@test PASS;ftp_abort 10/10;relisten :7003 20/20;
  ci_local L0+L0.5 全绿;E6 窗口零复位,7 条 WD stall 登记压测假象备查
2026-10-13 20:54:31 +08:00
wandering1 6394853fef feat(N34): 阶段3 net层收敛——单一reconciler+忙等统一+镜像降级+E-02收口
实施方案 docs/网络/N34-自愈审计/实施方案.md §5 项1/2/3/5(项4 U15受E6暂缓):

- 3a 合并reconciler:net_listener_pump删除,与net_reconcile_tick合并为
  单一100ms tick;判据读驱动状态缓存(唯一刷新点=net_poll每轮全量刷新,
  E2背书18.1us);去抖分级②=1/③④⑤=2/①=4轮(M3让位窗400ms保留)+冷却1s;
  链路态订阅留痕(F-DRV-13);探针去抖删除(F-MS-9)
- 3b 忙等统一(P2b):listen/connect open重试与close排空循环改
  net_sock_reset_sync(驱动sock_reset:读空RX→CLOSE→排空事件→等
  byte0=00H,内置LISTEN态二段CLOSE补发);close不再读清全局中断寄存器
  (F-NET-7);net_poll每轮步进活跃复位状态机(驱动契约,防搁浅)
- 3c 镜像降级:net_sock_state_t声明为本层会话投影,芯片事实源=驱动缓存
- E-02收口:新API net_drop_conn(拆会话保监听,QUARANTINE语义,幂等;
  模拟器双端实现;timeSync 30s预算耗尽接入;主机单测TC-TS-027d)
  定案:CH395F close无RST,对内核存活不close的对端停FIN_WAIT_2,
  监听恢复受限于对端close(Trap 07补充),兜底=E13 keepalive/TIMEOUT

台架全绿(Code=211348 RW=1104 ZI=154232):@test PASS;[STACK] net
1116/3840;Trap22 :7003 50/50+:21三档各50/50;Trap23 RST10/10+FIN5/5;
Trap25 n30 11/11;E-02双PASS;iec104 18/18;对时跨会话连续;
ftp_regression 11/11;integrity 15/15 SHA;ci_local L0+L0.5全过。
2026-10-13 15:09:58 +08:00
wandering1 d346e4ee84 feat(NET): N34 阶段 1.5 recv 语义主流化——无限默认+具名非阻塞+模式属性
核心语义(实施方案 §3.5):
- net_recv 默认无限阻塞:删除 NET_RECV_TIMEOUT_MS(30s 隐藏默认预算),
  超时归调用方策略;唤醒源=数据/EOF/close/网络重建(CONNRESET),
  会话死亡由对账① ~400ms 判死兜底,无"对端消失永久挂死"窗口
- 新增 net_recv_nb(NET_MSG_DONTWAIT 路径转正具名)与
  net_setblocking(fd,on)(阻塞模式挂控制块属性,对齐 O_NONBLOCK/
  Python setblocking;直写单字节,net_set_event_cb 先例)
- net_types.h net_sock_t 新增 blocking 属性;net_socket() 默认置 1
  (close memset 清零后显式重置,同 released_abnormal 纪律)
- 原 1s 强制了结看门狗降级为 60s tripwire:只 [ERR] 留痕一次,
  绝不伪造 TIMEDOUT 返回值(旧实现掩盖完成路径缺陷)
- net_recvfrom 删 30s 自旋超时、同判据对齐(零生产调用者,注释警示)
- 文档契约:IWDG required_mask 内任务禁止无限阻塞 recv(BSD 指南
  §3.5/§10.1 + net_socket.h 注释)

调用点审计(§3.5.5):零生产调用点采用无限默认——iec104_serv/
ui_net_sink 转 net_recv_nb(受监控任务逐位等价);lftpd/time_sync
已是显式预算 net_recv_to 不动;32 轮盲收兜底未动(阶段 3 E6 门禁)

模拟器双端镜像 net_recv_nb/net_recv_to/net_setblocking(包装层
Sleep(1) 轮询模拟阻塞);差距清单 N-3/N-6 登记义务已履行

门禁与台架:
- @build 0/0:Code 209580→209780(+200B) ZI +32B;RAM 受管区官方
  脚本同步;ci_local L0 32/32 + L0.5 951/951
- 台架全回归:relisten :7003 50/50、iec104 18/18、对时正常、
  ftp_regression 11/11、Trap23 RST 5/5+FIN 5/5、ftp_integrity
  20/20 字节一致、n30 0/10、@test PASS
- 模拟器 build_sim OK + check_remo_sink 黄金参考 0/25600 位差

队友 p15-recv-semantics 实施,Lead 全量审阅 + 独立复跑门禁与回归
2026-10-13 11:23:19 +08:00
wandering1 b8c6a3dab0 refactor(net)!: N34 阶段1 API 面收敛(对账⑤ + 删 3 个手动自愈 API)
BREAKING CHANGE: 删除公开 API net_relisten / net_resync_listen /
net_can_accept 与消息类型 NET_MSG_RESYNC_LISTEN / NET_MSG_RELISTEN。
生产调用者为零(仅看门狗文档与 iec104 门控),应用侧无迁移成本;
如有外部消费者须改用对账/pump 自动机制(见下)。

1. 对账①扩展为①②⑤(F-NET-2 缺口,先补缺口再删 API)
   net_reconcile_tick 新增 bad=5:本层 ESTABLISHED 且芯片 0x05/0x01
   (Socket OPEN + TCP LISTEN,静默回收回监听、不发 DISCONNECT)
   → RESYNC 语义只修本层(state→LISTENING + last_peer_port 转登 +
   lost_conn_seen 清零 + 取消挂起 recv),**不发任何芯片命令**
   (纪律同 pump③ U11,run8 实证重下发会 170s 永拒)。
   原判据①要求 TCP==CLOSED、②要求本层 LISTENING,均不命中此形态
   ——此前生产无人认领(仅手动 API 能修)。
2. 删 net_relisten(net_socket.c 函数 + 消息分派 + 头文件声明)
   footgun:对健康监听器无条件 open→USE→close 自毁 ~1s(原注释自认);
   与 pump(100ms)/D10(30ms) 完全重叠。
3. 删 net_resync_listen(同上;语义并入第 1 条)
4. 删 net_can_accept(net_socket.c + net_socket.h + sim 三处)
   只认 ESTABLISHED 的旧门控把"监听器在服役、待 CONNECT"窗口全挡掉,
   :2404 丢 CONNECT 探针因此从不运行;iec104 门控迁 net_listener_armed。
5. timeSync :8888 会话收尾不再 net_close(同 fd 续 accept,监听跨会话
   常驻;原 close→重建每会话一个 Trap 09 沉降窗)。server 脚本注释同步
   新契约(PC 侧 2s 宽限后自行关闭)。
6. lftpd 应用层阻塞重试退役:lftpd_inet_listen 5 轮(500ms/2000ms,最坏
   10s 阻塞 ftpTask) → 单次 + 失败即 425;cmd_pasv 3×200ms 同删。
   就绪屏障已消除 Trap 09 启动形态,客户端自带传输重试语义。

台架实证修正(本提交内二次修复,务必留痕):
- net_listener_armed 补齐 **ESTABLISHED 放行**。首版迁移只放行
  LISTENING/CLOSED+残留,漏了 ESTABLISHED=单连接模型的"待 accept"电平
  → iec104 200ms 任务周期抢不过对账② 的 ~400ms 去抖,对账②先 standalone
  accept 转 ESTABLISHED 后 armed=0 → 应用整场不 accept,18/18 检查全 FAIL
  (设备日志证据:sock1 standalone accept 后无 i104 accepted,直至对端 FIN
  才由 closed-with-data 救回)。补放行后 18/18 PASS,且耗时 127s→8.3s。
  该态 accept 必返 fd,无 RPC 风暴风险。
- 期间顺带验证 M3 无辜:sock1 suspect DISCONNECT on live conn 命中后
  defer→对账①→closed-with-data accept 把未 accept 的 RX 数据救回,
  正是 M3 设计意图(资产门保护)。

验证(全绿):@build 0/0(Code=209580;含 CH395F 套件+Phase13 全量重编
0/0 的编译验证);@test PASS(回读无差异);iec104 18/18(8.3s);
n30 0/50;:21 @0ms 50/50 p50=512;:7003 50/50 p50=517;ftp_regression
11/11;Trap23 RST 5/5 + FIN 5/5;time_sync :8888 连续推送正常(RTC 更新、
无 [ERR])。文档同步:BSD 指南(§3.3/3.6/10.1/10.2/12 + 变更记录)、
函数调用关系、监听生命周期设计说明、IEC104 上行设计说明、模拟器差距
清单、链路延迟测试说明。

门禁说明:doc-links 工作树 junction 伪影按既定口径 SKIP;mem-budget
分支 .map 漂移同前;cppcheck/coding-standard 手跑 Passed。
2026-10-13 06:44:26 +08:00
wandering1 c1ab902ef1 refactor(net): N-32 §10 监听生命周期抽为 net_listener.c(纯搬移)
把监听生命周期从 net_socket.c 整体抽出为真机专属模块 net_listener.c:
7 个函数 + 7 个状态数组 + 8 个常量 ≈470 行。
net_socket.c 4126 → 3656 行(-471)。

模块边界(详见 net_listener.h 头注释):
- 搬入:relisten_locked / try / clear / done / retry_tick / pump / drain_chip_rx
- 留在 net_socket.c:net_listen_locked(应用 API 路径)/ net_accept_locked
  (产出连接)/ net_lost_connect_probe(补 accept)/ net_listener_armed
  (双端公开 API)/ net_resync_listen / net_reconcile_tick / net_sock_t 字段

接口从「8 处散点直调 + 2 处直接写状态数组」收敛为 4 个窄接口:
  net_listener_settle(fd, level) / _try(fd) / _clear(fd) / _retry_tick()
新模块**不访问 s_net_socks**(改用 net_get_sock + ch395_sock)。

搬移中必要的两处可见性提升(非纯机械搬移,已注释留痕):
- net_set_errno 由 static 提升为模块间可见(NET_ERR_RETURN_1 宏随迁头文件)
- 新增 net_pending_active(fd),替代直接读 s_net_pending[i].active
  (L3 保险语义原样保留)

真机专属:net_listener.c 依赖 ch395f_* SPI 驱动,sim(Winsock)无对应
→ 只注册 Keil 端,并在 check_registration.py 的 SIM_EXEMPT **显式点名**
(不整目录一刀切,遵脚本既定原则)。

验证(纯搬移的可证判据):
- 尺寸:**RW-data 980 与 ZI-data 143060 完全不变**(数据总量不变);
  Code 197236→197228(-8)、RO-data 17012→17000(-12)——接口改造的
  极小开销,相对 471 行搬移可忽略
- 门禁全绿(cppcheck / C 规范 / 双端注册 / 主机侧单测 12 套 / mem-numbers)
- @test PASS + 回读 No difference found
- 全量回归::21 0ms×50 与 100ms×50 各 50/50;:8888 20/20;:7003 10/10;
  ftp_regression 11/11;Trap23 abort/graceful 各 5/5
- 设备侧:orphan listener **0**(保持 P2a 基线)、pump 留痕正常
2026-10-12 16:59:44 +08:00
wandering1 7cb5af05fe feat(net): N-32 P2a 监听器 pump 单一所有者(周期性重建收敛)
把"周期性重建监听"收敛到唯一入口 net_listener_pump,消灭"谁先看到
DISCONNECT 就谁重建"的竞争;对账③④ 整体移交 pump,对账只剩①②。

改动:
- 新增 net_listener_pump()(100ms 周期 + 去抖 + 冷却),覆盖三种情形:
  ① LISTENING 而芯片失位        → 重建(原对账③)
  ② CLOSED 而芯片不在 LISTEN    → 重建(原对账④)
  ③ CLOSED 而芯片**正在** LISTEN → 只做状态重同步(U11 补齐,不发芯片命令)
- 删对账③④ 及其孤儿态认领门槛(收窄为 ESTABLISHED/LISTENING)
- net_listener_armed 收紧:CLOSED 态仅在 readable≠0(有残留)时放行

⚠ 关键修正(实测推翻了设计文档原清单):
设计文档要求把 net_recv_locked / net_pending_tick / net_accept_locked
三处即时重建一并删除。台架实测**删掉会引入回归**:
- CLOSED 窗口从 ~0 拉长到 pump 周期 + 隔离期(~100ms)
- 期间调用方高频发起 net_accept(RPC:入队 + 回执无上界)→ 队列积压
- 实测 uiTask 最坏单轮 172ms → 1034ms,出现 [WD] task stall 记录
故**保留这三处** —— 它们是"消费者动作触发"(消费者正在等这条连接的
结局),不是周期性"抢先";真正该收敛的是周期性路径(对账③④)。
收敛后 net_relisten_try 调用点 7 → 5(pump + 显式消息 + 3 处消费者驱动)。

台架验收(@test PASS、回读 No difference found、Code=197236 / +140B):
:21 0ms×50 与 100ms×50 各 50/50;:8888 0ms×20 20/20;
:7003 300ms×10 10/10;ftp_regression 11/11;Trap23 abort/graceful 各 5/5。
设备侧 orphan listener 增量 **0**(P1 基线同条件实测 2 条)—— 目标达成。

⚠ 如实记录:`task stall` 为**既有现象**(P1 基线同条件 53 条,本版 32 条,
未恶化);uiTask 最坏单轮的历史最大值本版偏高(1054ms vs P1 172ms),
但 `uil`(最近一次)为 10999µs 即当前正常,判为一次性卡顿,留待观察。

⚠ SKIP=doc-links:基线预存在问题(另一在途任务未提交文件),非本次引入。
2026-10-12 14:10:43 +08:00
wandering1 a8442410d1 feat(net): N-32 P1 会话结束电平化,消灭抢先 relisten 饿死消费者
B10 根治 P1(不变量 I):把"这条会话结束了"从 state==CLOSED 这一
**边沿**改成 session_dead **电平**,从结构上消掉两类事故。

问题:单连接复用模型下同一 fd 兼任监听器与连接(handle aliasing),
"会话结束"原先只能在 state==CLOSED 那一刻被观察到。别的路径抢先
relisten 回 LISTENING(对账④ / net_accept_locked 的 CLOSED 分支)
后,消费者再 recv 恒得 WOULDBLOCK → EOF 永久失踪:慢消费者被饿死、
新客户端数据被旧会话静默吸收。

改动:
- net_types.h:net_sock_t 增 session_dead(粘滞电平)
- 置位 4 处:handle_disconnect_event 释放分支、handle_timeout_event
  ESTABLISHED 分支、net_connect_locked 命令被拒、对账①(复用前者)
- 清零:handle_connect_event 两支;net_relisten_locked **刻意不清**
  (重建监听与"应用是否已确认会话结束"必须解耦,已注释钉住契约)
- net_recv_locked DONTWAIT 判据改 CLOSED || session_dead
- net_pending_tick ③ 断连判据同步改(**超出原清单的必要扩展**:不改
  则 lftpd 阻塞 recv 在抢先 relisten 后两头落空、只能干等超时)
- 两处 relisten 调用补内层 state==CLOSED 门:net_relisten_try 无
  状态门,对已 LISTENING 的 fd 再 open+listen 会因 USE 错误走进关闭
  分支、关掉正听着新 SYN 的 Socket(U12 同源事故)
- ui_net_sink::563 真错误分支加 g_client != g_listen 护栏;EOF/
  错误后不再自行 bind_listen(消灭第 3/4 个重建所有者,不变量 II)
- 新增 net_listener_armed()(LISTENING 或 CLOSED+auto_relisten)替代
  accept 门控的 net_can_accept()——旧门控使 :7003 永不进 net_accept,
  net_lost_connect_probe(丢 CONNECT 补 accept,N-30)形同从未运行。
  MCU 与 net_socket_sim.c 双端实现(sim 端恒 1,保持改前行为)

验证:@build 0 错 0 警(Code=197096,基线 197084,+12B);
mem-numbers 快照已 --write 刷新;cppcheck / C 规范 / 主机侧单测 12 套 /
双端注册 / CubeMX 存活 / 任务表 全绿。

⚠ 提交时 SKIP=doc-links:该钩子在从当前 v2-on-ui 切出的工作树上必报
2 处失效引用(RAM 方案文档 → ram_baseline.tsv / RAM预算台账.md),
属另一在途任务未提交的文件,主工作树磁盘上有故主线门禁呈绿。非本次
引入,不代为提交他人半成品;待其合入自动消解(见 并行任务工作树方案.md §10.2)。
2026-10-12 13:06:23 +08:00
wandering1 1d1a9d4656 net/ui: UI 推流加就绪门控,刷新脱离 netTask 往返(销项 N-10)
新增 net_can_accept() / net_can_read():纯 RAM 读 Socket 控制块,不入队、
不等 netTask 回执,供实时性敏感任务在发 RPC 前判断"有没有活"。
ui_net_sink_poll() 改为先门控再 RPC;无客户端时 RPC 从 100 msg/s 降到 0。

两条兜底(门控引入的新卡死路径,设计阶段未预见):
- I-2 每 32 轮无条件 recv:readable 仅由 RECV_OK 中断置位,Trap 22 三类
  对账不含"RX 非空但 readable=0",纯门控会把已到达的数据永久藏住;
- I-3 门控返 0 时查监听控制块,消失即 g_listen=-1 重建(改前靠每轮
  accept 撞 BADF 暴露,门控会连这条暴露路径一起消掉)。
net_can_read() 对非 ESTABLISHED / 非法 fd 故意返 1,让上层必得 EOF/BADF
走既有错误分支——返 0 会把死连接永久藏住。
模拟器后端恒返 1(Winsock 无 RPC 成本,行为逐位不变)。

实测:uis 50ms→1µs、uiw 50ms→11.4ms(只剩 LVGL);@build 0 错 0 警、
@test 10/10 PASS(uis≤1µs、uisn≡0、0 task stall、0 [ERR])、
check_remo_sink.py e2e 0/25600 位差异、内容页文本断言 50/50。
uip 最坏 61ms 是 LVGL 帧周期地板、与网络无关,判据已按实测修订。

方案 B(把推流搬出 uiTask + 帧 seqlock)已评估并决定不做:搬任务不会
让刷新变快,收益只剩极端并发下的观感隔离,成本含必改 .ioc 的 CubeMX
重生成。残留暴露与观测手段(uis/uisn)如实记录在 §9.4。
N-19 / C7 不入登记簿(当日结案),结论沉淀进问题记录 §9。
2026-10-10 20:47:59 +08:00
wandering1 de1b50efe9 修复 P1-7:MAC 写入顺序改为 INIT_CH395 之前
- 手册 §9.2.1:SET_MAC(步骤①) 必须先于 INIT_CH395(步骤⑤);SET_MAC 写
  芯片 EEPROM,INIT 从中加载 MAC——原顺序反了则本次上电 MAC 不生效
  (回落芯片内置/上次值),UI 显示与设备在线身份不符
- net_socket.c net_init():SET_MAC 移到 ch395f_init() 之前(对齐步骤①)
- ch395f.c:四个 SET(MAC/IP/GWIP/MASK)限定条件注释由"芯片已初始化"
  订正为"必须在 ch395f_init() 之前调用"
- net_socket.h / BSD_Socket_API_函数调用关系.md:同步顺序描述
- CH395F_Trap_Records.md:新增 Trap 24 沉淀根因与修复
- 待处理内容.md:P1-7 销项(§1/§2 阶段 A/§3.1/§4);阶段 A 清空后重编号
- 验证:Keil 构建 0 错 0 警;pre-commit 17/17 全通过
2026-10-04 23:07:00 +08:00
wandering1 1b46e2a340 修复E-03:s_net_errno 改按任务隔离槽位,消除跨任务错误码错报 2026-09-25 19:17:18 +08:00
wandering1 894b51feb3 移除 P0-a 验收探针(台架验收完成),开机省去 60ms 状态轮询与证据行 2026-09-22 12:03:11 +08:00
wandering1 06d4064366 修复 P0-a 重传周期 200ms 与 P0-b per-recv 日志,台架重锁 M2/M3 基线并复验 2026-09-22 11:36:16 +08:00
wandering1 e5733b3454 链路时延M1-M3收尾:Phase12-14基线与生产路径Δ实测、D10/E-02/D17修复、D20定位与硬化、文档整理 2026-09-22 06:12:40 +08:00
wandering1 d150810587 ui_net_sink 拆分为协议层与平台后端,新增 RemoDispBus 设计文档 2026-09-11 21:25:02 +08:00
wandering1 4515ee4c80 修复了网络参数的保存逻辑 2026-09-10 14:21:07 +08:00
wandering1 2b80d34e74 增加网络配置界面 2026-09-10 11:36:33 +08:00
wandering1 bb76cfd779 修复规范矛盾并定案5项规则,保护宏统一XXX_H
规则定案:常量在右(a>5)、保护宏XXX_H(禁双下划线)、
头文件常量用#define、存储类前缀(g_/s_)优先、允许void返回值
全库32个.h头文件保护宏 __XXX_H → XXX_H 改名(字节级替换)
S1检查规则同步更新(拒绝双下划线),Inc/gpio.h 反向验证被正确拦截
规范示例矛盾修复:K&R括号、标准类型、变量初始化、命名常量、注释字段补全
2026-09-01 16:07:00 +08:00
wandering1 ad154b2f7e 时间同步已经完成 2026-08-28 16:42:44 +08:00
wandering1 319d00e3e5 删除多连接内容,只支持单连接 2026-08-25 12:41:33 +08:00
wandering1 02963441b5 初始创建FTP服务器 2026-07-21 22:08:11 +08:00
wandering1 fd13ad0e06 修改网络的初始化,异步支持问题 2026-07-21 01:22:09 +08:00
wandering1 01ad5e476f 增加文件系统 2026-07-21 00:30:59 +08:00
wandering1 e862009bcd 修复多连接的问题 2026-07-19 15:27:49 +08:00
wandering1 17109d9baf TCP可以正常使用 2026-07-19 00:59:56 +08:00