4c21cff753
现象:抓自检台账基线那次 FTP 会话一结束,设备就打 `[ERR] [FTP] error reading next command`, 本次 `@test` 直接 FAIL(Forbidden 含 `[ERR]`)。查下去发现 lftpd 把**全部**异常路径一律按 error 级打,其中九处其实由外部输入决定:客户端关窗口、连上就走、PASV 后不建数据连接、 运维改 IP 触发监听重建。两条代价:① 任何人"连 21 端口一下就断开"就能把一次启动测试打成 FAIL;② 同样的动作可以**无限制造固件级 ERROR 日志**——日志面与门禁面都可被外部驱动, 工业现场过不了审。 **做法**:`private/lftpd_log.h` 新增 `lftpd_log_peer()`(info 级,带 `[FTP]` 前缀),而不是 就地改成 `DBG_INFO`——让"谁才算真故障"在读代码时一目了然,也防止后来者顺手把对端行为升回 error。降级的九处:控制通道被对端关闭(原 `error reading next command`,改为 `control channel closed by peer (ret=%d)`,措辞原先把正常收尾写成故障、误导过排查方向)、 发送 220 前对端已走、`listener rebuilt`(网络重建,原因由 accept 层自己记)、四处 `data accept failed`(PASV 后没来数据连接)、`accept timeout`。 **刻意留在 error 的**:create/bind/listen/取端口失败、写通道失败、文件打开失败、 `DOWNLOAD/UPLOAD FAILED`(对端中途退出确实让一次传输没走完 = 数据完整性事件, `../问题记录/CH395F_Trap_Records.md` 的中止家族要靠这些锚点定位)、 `data listener disarmed`(控制连接还活着而我方数据监听已不在服役 = 本侧异常,就地注明)。 **实测划清的边界**:客户端**干净收尾**(发 `QUIT` 或 FIN 半关)现在整条链路没有任何 `[ERR]`; 但 **RST 硬拆**(`SO_LINGER` 清零 / 进程被杀 / 拔线)仍会留一条 `[ERR][NET] sockN TIMEOUT`—— 那是 net 层的套接字超时锚点,网络自愈架构判据要读它,不在本次降级范围。所以"采集窗口内别跑 `data listener disarmed`(控制连接还活着而我方数据监听已不在服役 = 本侧异常,就地注明)。 **真机验证**:`@build` 0 错 0 警告;`@test --require-selftest-pass --device-ip` → **PASS** (基线 29 条 → 本次无新增;`net init: OK` 726 ms);专门写了 RST 复现脚本(登录后 `SO_LINGER` 清零直接关)→ 串口得到 `[FTP] control channel closed by peer (ret=-1)`,**不再是 `[ERR]` 行**; 同一份日志里 QUIT 收尾的那次会话完全没有错误行。 体量:`Code` 213,236 → **213,264 B(+28)**、`RO` 18,580 → **18,652 B(+72)**(措辞变长), 同一份日志里 QUIT 收尾的那次会话完全没有错误行。 `ZI` 131,500、`RW_IRAM1` 75,264 B 57.4% / `RW_CCM` 57,376 B 87.9% 全不变)。数字联动照做: 两份 `data/` 快照、`ram_baseline --update/--write`、`check_mem_numbers --write`、FLASH 配图 常量重算重生成(桶合计 = 231,916 与 `Code+RO` 相符;越界复查 0)、报告 §1.3/§5.1/§5.4 与 部署文档 §3.3 同步。 口径落文:新增 `docs/架构设计/STM32F4-Base存储架构说明.md` §10.3「FTP 日志级别划分:对端行为 vs 固件故障」(含两类的判据表与边界),并更新 `docs/测试说明/自动化测试流程.md` 的采集窗口警示。 顺手把 `private/lftpd_log.h` 工作区的 CRLF 混用归一回 LF(仓库里 blob 本来就是 LF,diff 无影响)。 门禁:`doc-links --all --sections-strict` 146 文档 0 问题、`id-check --strict` 增量拦截通过 (可判定 82.82%)、`mem-numbers` / `mem-budget` / `layer-deps` 全绿;改动文件字节卫生 BOM 无 / CR 0 / U+FFFD 0 / 无行尾空格。未推送。
Drivers/BSP/ — 板级支持包(纯手工自研代码)
本目录全部为手工编写的板级驱动与中间层(非 CubeMX 生成、非第三方库、非 ST HAL)。 每个芯片/子模块一个子目录。改驱动前必读对应模块的 Trap Records(见下)。
子模块一览
| 目录 | 芯片/模块 | 接口 | 职责 | 关键文档 |
|---|---|---|---|---|
CH395F/ |
CH395F 以太网控制器 | SPI2 | 以太网 MAC/PHY 控制器底层驱动 | docs/问题记录/CH395F_Trap_Records.md |
GD5F2GQ5UE/ |
GD5F2GQ5UE SPI NAND | SPI1 | NAND 驱动 + FTL(nand_ftl.c) |
docs/问题记录/GD5F2GQ5UE_Trap_Records.md |
TPAFE5160/ |
TPAFE5160 高精度 ADC | 并行 16 位 | ADC 采样驱动(CONVST/BUSY 时序) | — |
SD2506/ |
SD2506 RTC | I2C | 实时时钟驱动 | docs/问题记录/SD2506_Trap_Records.md |
RS485/ |
RS-485 半双工 | UART5 | 收发方向控制(DE 引脚)+ 时序 | — |
NET/ |
BSD Socket 网络抽象层 | — | Socket API + select + 轻量 FTP 服务器 | docs/网络/(含 Net层阻塞模型架构设计.md) |
NETCFG/ |
网络配置 | — | /config.ini 网络段的加载/保存(旧 NCFG 档已删除,2026-10-10) |
docs/子系统设计/网络配置说明.md |
UI/ |
LVGL UI 组件 | — | 菜单/内容页/组件/中文字体 | docs/UI设计/ |
根级文件
| 文件 | 作用 |
|---|---|
dbg_log.h |
调试日志宏(DBG_INFO 等),编译期开关 |
dbg_cfg.h |
调试配置项 |
子模块 README
NET/README.md— 网络抽象层(Socket / select / FTP)UI/README.md— LVGL UI 组件
⚠️ 改驱动前必读(踩坑速查)
| 模块 | 陷阱 |
|---|---|
| CH395F | SPI 事务须 ch395f_spi_begin()/end() 包裹;分频系数必须为 8(PCB 约束,勿"优化");快速复连会因事件被读清消费致监听死亡(TRAP-NET-17 已修,E14 复核:非芯片丢事件);上传中止后首笔复连截断(TRAP-NET-18 已修) |
| GD5F2GQ5UE | FatFs 移植版打开模式陷阱(FA_OPEN_APPEND 不含写位);文件名严格 8.3 短名、不得以点开头;f_write 簇分配失败返 FR_OK + 短写,须校验字节数 |
| NET | 就绪屏障位必须 osFlagsNoClear;s_net_errno 已按任务隔离(勿改回全局) |
| 通用 | 自研代码禁用 C 库堆分配(MicroLIB 堆仅 512 B),动态内存只用 pvPortMalloc/vPortFree |
完整平台约束见根
AGENTS.md「平台约束」章,以及各模块的 Trap Records。
相关文档
- 架构全景:
docs/架构设计/项目架构总览.md - 存储栈:
docs/架构设计/STM32F4-Base存储架构说明.md - 测试指南:
docs/测试说明/*_Test_Guide.md