为自建代码目录补齐 README,建立目录级导航体系

- 新增 26 份目录 README:App/(+log,task,util,protocol)、Drivers/BSP/(+8子系统)、
  Src/、Inc/、scripts/、tools/(+6子工具)、test/、MDK-ARM/、simulator/(+sim,tests)
- 每份含:定位、文件清单表、关键约束/陷阱、指向 docs 权威文档
- 第三方库与生成代码目录排除(CMSIS/HAL/Middlewares/Lib/SDL2)
- docs/文档规范.md 新增 §1.1b 代码目录 README 约定;根 README 目录结构加入说明
This commit is contained in:
2026-09-26 12:25:36 +08:00
parent 8d86fb1149
commit 39bd06adea
31 changed files with 1149 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
# App/ — 应用层
> **自研代码**(非 CubeMX 生成、非第三方库)。本目录是项目的**应用层**:任务编排、业务逻辑、
> 日志与配置引擎、工具函数。所有文件遵循 `docs/代码规范/嵌入式C语言代码规范_V1.0.md`。
## 职责
`Src/main.c`(CubeMX 初始化)→ `app_main_init`(本目录 `app_main.c`)→ `osKernelStart` →
6 个 FreeRTOS 任务(见 `task/`)。**`osKernelStart` 之前全是内核启动前代码,禁止调用任何
FreeRTOS/CMSIS-RTOS API**(见 `AGENTS.md`「平台约束」)。
## 文件一览
| 文件 | 作用 |
|---|---|
| `app_main.c/h` | 应用初始化入口 `app_main_init`:时间子系统优先 → RS485 → NAND → ADC → 诊断 |
| `app_cfg.h` | **功能模块编译开关**(裁剪测试套件/模块用) |
| `sys_events.h` | 系统就绪事件定义(Event Flags:`SYS_EVT_NET_READY` 等就绪屏障) |
| `time_sync.c/h` | 时间同步任务(等待网络就绪后与时间源同步) |
| `cfg_file.c/h` | **配置引擎**(`/config.ini` 解析 + 持久化 + 旧档迁移),属主为 defaultTask |
| `cfg_file_store.h` | 配置存储后端抽象接口(MCU=FreeRTOS 堆 / 模拟器=宿主堆,共享核心零分配) |
| `cfg_file_store_mcu.c` | 配置存储的 MCU 端后端实现(`cfg_store_alloc/free` → FreeRTOS 堆) |
| `log/` | 日志子系统(见下) |
| `task/` | FreeRTOS 任务实现(见下) |
| `util/` | 工具函数(见下) |
| `protocol/` | 通信协议(预留,当前为空) |
## 子目录
| 目录 | 内容 | README |
|---|---|---|
| `log/` | syslog(`/log/run.log`·`selftest.log` 定长记录)+ 控制台单写者日志 | [`log/README.md`](log/README.md) |
| `task/` | 6 个 FreeRTOS 任务实现 | [`task/README.md`](task/README.md) |
| `util/` | CRC / 环形缓冲 / 墙钟时间 | [`util/README.md`](util/README.md) |
| `protocol/` | 通信协议(预留) | — |
## 关键约束
- **配置引擎单任务收敛**:`cfg_file` 为静态态、属主是 defaultTask;UI 保存请求经
`SYS_EVT_CFG_SAVE` 事件唤醒,netTask/uiTask **不得直接触碰**配置引擎
- **syslog 唯一写者**:`/log/*` 只由 defaultTask 写入
- 新增任务/缓冲/栈前**必须先核算 RAM 余量**(`docs/内存管理/`)
## 相关文档
- 架构全景:`docs/架构设计/项目架构总览.md`
- 启动顺序:`docs/架构设计/项目启动顺序管理.md`
- 配置引擎:`docs/子系统设计/配置文件设计说明.md`
- 日志:`docs/子系统设计/控制台单写者日志设计说明.md`、`docs/子系统设计/运行与自检记录设计说明.md`
+34
View File
@@ -0,0 +1,34 @@
# App/log/ — 日志子系统
> 两类日志:**持久化运行日志**(`sys_log`,落 NAND)与**控制台日志**(`console_log`,走串口)。
> 两者都遵循**单写者**模型,避免多任务交错输出。
## 文件一览
| 文件 | 作用 |
|---|---|
| `sys_log.h` | **日志接口(平台无关)**:定长 64B 记录写入 `/log/run.log`·`selftest.log` |
| `sys_log_mcu.c` | `sys_log` 的 MCU 端后端实现(NAND + FatFs) |
| `console_log.c/h` | **控制台单写者日志**:多任务日志经队列汇入唯一写者,避免串口输出交错 |
## 关键机制
### syslog(运行/自检记录)
- **唯一写者 = defaultTask**;其它任务只投递,不直接写盘
- **单记录定长 64 B**,循环写;待机页可显示记录
- **内核启动前的日志**走**无锁静态缓冲** `s_preboot[8]` 暂存(因为内核启动前不能建队列),
内核启动后由 `syslog_drain` 惰性创建真队列并排空
- ⚠️ 写盘必须校验 `f_write` 返回的**字节数**(该 FatFs 移植在簇分配失败时返回 `FR_OK` + 短写,
不报错误码);追加写必须 `FA_WRITE|FA_OPEN_APPEND`(`FA_OPEN_APPEND` 单独用**不含写位**)
### console_log(控制台单写者)
- 多任务的生产者 → **单写者消费者**,消除任务间日志行交错
- 设计详见 `docs/子系统设计/控制台单写者日志设计说明.md`
## 相关文档
- `docs/子系统设计/控制台单写者日志设计说明.md`
- `docs/子系统设计/运行与自检记录设计说明.md`
- FatFs 陷阱:`AGENTS.md`「平台约束」
+12
View File
@@ -0,0 +1,12 @@
# App/protocol/ — 通信协议(预留)
> **占位目录**:规划用于存放自定义通信协议实现(解析 / 组帧 / 状态机)。
> 当前为空(仅 `.gitkeep`),协议相关实现暂分散在:
> - RS-485 侧:`App/task/rs485_task.c` + `App/util/crc.c` + `App/util/ringbuf.c`
> - 网络侧:`Drivers/BSP/NET/`
> - 远端显示:`docs/UI设计/RemoDispBus协议与接收设计说明.md`
## 何时使用本目录
当出现**跨接口复用的协议逻辑**(如统一的帧编解码器、协议状态机)时,落到此处,
避免散落到各 task 里。新增后请在本 README 补一行说明。
+39
View File
@@ -0,0 +1,39 @@
# App/task/ — FreeRTOS 任务实现
> 6 个任务的入口函数与任务体。任务创建在 `Src/freertos.c`(`MX_FREERTOS_Init`),
> **栈大小/优先级的唯一事实源也是 `Src/freertos.c`**;本目录只放任务**实现**。
## 任务清单
| 文件 | 任务 | 优先级 | 职责 |
|---|---|---|---|
| `default_task.c/h` | defaultTask | Normal | FTL + FatFS 挂载、配置引擎属主、syslog 唯一写者、LED 指示 |
| `net_task.c/h` | netTask | Normal | `net_stack_bring_up` → 置 NET_READY → 循环 `net_poll` + `net_process_messages` |
| `ui_task.c/h` | uiTask | BelowNormal | LVGL 界面(菜单 / 内容页 / 待机)+ 推流 |
| `adc_task.c/h` | (ADC 任务) | — | 高精度 ADC(TPAFE5160)数据采集 |
| `rs485_task.c/h` | (RS-485 任务) | — | 半双工 RS-485 协议通信 |
| `time_sync.c`(在 `App/` 根) | timeSyncTask | Normal | 墙钟时间同步(实现不在本目录) |
> 上表栈大小/优先级以 `Src/freertos.c` 为准(`README.md`/`AGENTS.md` 的任务表由
> `scripts/gen_task_table.py` 生成,勿手抄)。
## 就绪屏障(重要)
任务间**不用魔法延时**,改用 `App/sys_events.h` 的 Event Flags:
- `SYS_EVT_NET_READY` / `SYS_EVT_STORAGE_READY` 等是**状态位**——等待时必须
`osFlagsWaitAny|osFlagsNoClear`,**不能用默认消费型等待**(否则先到的消费者会清掉位,
导致 `ftpTask` 的 `WaitAll(两位)` 永不成立 → FTP 静默不监听)
- `SYS_EVT_CFG_SAVE` / `SYS_EVT_NET_RECONFIG` 等**命令位**保持消费型等待
## 平台约束(改本目录前必读)
- **内核启动前禁止任何 FreeRTOS/CMSIS-RTOS API 调用**(`osMessageQueueNew` 等会杀死启动)
- 就绪屏障位一律用 `osFlagsNoClear`
- 内存预算紧张,改栈/缓冲前先核算(`docs/内存管理/`)
## 相关文档
- 启动顺序与屏障:`docs/架构设计/项目启动顺序管理.md`
- 内存与定栈规则:`docs/内存管理/RAM使用分析与优化方案.md`
- 栈水位实测:`scripts/stack_report.py`
+29
View File
@@ -0,0 +1,29 @@
# App/util/ — 通用工具函数
> 平台无关的纯工具模块(无 FreeRTOS 依赖、无硬件依赖),可在 MCU 与 PC 模拟器中共用。
## 文件一览
| 文件 | 作用 |
|---|---|
| `crc.c/h` | 校验算法(CRC16/CRC32 等,供 RS-485 协议与数据校验使用) |
| `ringbuf.c/h` | 环形缓冲(SPSC 无锁环形队列,用于串口/数据流收发) |
| `sys_clock.c/h` | **墙钟时间管理**:RTC 基准、tick 回绕防护、每 30 天惰性再基准化 |
## 设计要点
### sys_clock
- 以 SD2506 RTC 为基准,HAL tick 计数补齐亚秒精度
- **49.7 天 tick 回绕防护**:每 30 天惰性再基准化(`sys_clock_get` 内部触发)
- RTC 故障时降级到默认时间基准并返回 -1,触发"时钟芯片异常"自检上报
- 设计详见 `docs/子系统设计/系统墙钟时间维护说明.md`
### ringbuf
- 单生产者单消费者(SPSC)无锁设计,配合 DMA/中断收发
- 容量为 2 的幂,用掩码取模(避免除法开销)
## 相关文档
- `docs/子系统设计/系统墙钟时间维护说明.md`
+34
View File
@@ -0,0 +1,34 @@
# Drivers/BSP/CH395F/ — CH395F 以太网控制器驱动
> CH395F 是 SPI 接口的 10/100M 以太网 MAC+PHY 控制器。本目录是其**底层寄存器级驱动**,
> 上层的 BSD Socket 抽象见 `../NET/`。
## 文件一览
| 文件 | 作用 |
|---|---|
| `ch395f.c/h` | SPI 命令收发、寄存器读写、芯片初始化、通道/中断管理 |
## 关键点
- **SPI 接口**:SPI2(PB12 CS / PB13 SCK / PB14 MISO / PB15 MOSI)
- **每次 SPI 事务必须 `ch395f_spi_begin()` / `ch395f_spi_end()` 包裹**
- **SPI 分频系数必须为 8**(PCB 信号完整性约束,**勿"优化"改快**)
- 芯片最多 8 个 socket,本层用**事件中断 + 周期轮询**驱动
- PHY 强制 **100M 全双工**(`net_task` 中配置)
## ⚠️ 改本驱动前必读陷阱(Trap Records)
| Trap | 问题 | 状态 |
|---|---|---|
| Trap 21 | TC-NET-604 "RX 窗口冻结" 判定为**非缺陷**(原报告系测试程序自吞数据 + 判读工具误判) | ✅ 结案 |
| Trap 22 | **快速复连丢 CONNECT/DISCONNECT 中断 → 监听静默死亡**;修复 = `net_reconcile_tick()` 周期对账自愈 | ✅ 已修 |
| Trap 23 | **上传中止后首笔复连被静默截断(≤2048B)并误报成功**;修复 = 异常释放后复监听隔离排空 | ✅ 已修 |
> 完整台账与复现配方见 `docs/问题记录/CH395F_Trap_Records.md`(**改驱动前必读**)。
## 相关文档
- 测试指南:`docs/测试说明/CH395F_Test_Guide.md`
- 上层抽象:`../NET/README.md`
- 台架探针:`MDK-ARM/tcp_reconnect_probe.py`、`MDK-ARM/ftp_abort_probe.py`
+46
View File
@@ -0,0 +1,46 @@
# Drivers/BSP/GD5F2GQ5UE/ — GD5F2GQ5UE SPI NAND 驱动 + FTL
> 256MB SPI NAND Flash 驱动,以及之上的 **FTL(Flash 转换层,`nand_ftl.c`)**——
> 提供逻辑块映射、坏块管理、磨损均衡。再上层是 dhara(坏块/磨损算法)与 FatFs。
## 文件一览
| 文件 | 作用 |
|---|---|
| `gd5f2gq5ue.c/h` | NAND 芯片底层驱动:读/写/擦除、页/块管理、ID 与状态查询 |
| `nand_ftl.c/h` | **FTL 层**:逻辑地址 → 物理地址映射、坏块表、磨损均衡 |
## 硬件接口
- **SPI1**:PE0 CS / PB3 SCK / PB4 MISO / PB5 MOSI / PB8 WP / PE1 HOLD
## 三层存储栈
```
FatFs(文件系统)
↓
dhara(坏块管理 + 磨损均衡算法,Lib/dhara/)
↓
nand_ftl.c(本目录,FTL 适配)
↓
gd5f2gq5ue.c(本目录,芯片驱动)
↓
GD5F2GQ5UE 芯片
```
## ⚠️ 改本驱动前必读陷阱
| 陷阱 | 说明 |
|---|---|
| **FatFs 打开模式** | `FA_OPEN_APPEND`(0x30) **不含 `FA_WRITE`(0x02)**——追加写必须 `FA_WRITE\|FA_OPEN_APPEND`,否则 `f_write` 恒返 `FR_DENIED`(7) |
| **FatFs 文件名** | 严格 8.3 短名、**不得以点开头**(`.fschk` 会 `FR_INVALID_NAME`,纯 RAM 判定不碰盘);自愈逻辑**严禁**把名字类错误归入"卷损坏"触发集 |
| **`f_write` 簇分配失败返回 `FR_OK` + 短写** | 判失败必须**校验写回字节数**(无错误码) |
| **禁用 C 库堆分配** | MicroLIB 堆仅 512B,`malloc` 必返回 NULL;用 `pvPortMalloc/vPortFree` |
> 完整台账见 `docs/问题记录/GD5F2GQ5UE_Trap_Records.md`。
## 相关文档
- 存储架构:`docs/架构设计/STM32F4-Base存储架构说明.md`
- 测试指南:`docs/测试说明/GD5F2GQ5UE_Test_Guide.md`
- 容量恢复:`docs/测试说明/存储维护与容量恢复.md`
+64
View File
@@ -0,0 +1,64 @@
# Drivers/BSP/NET/ — 网络抽象层(BSD Socket API)
> 在 CH395F 硬件驱动之上提供 **BSD Socket 风格 API**,使上层(FTP 服务、时间同步、UI 推流)
> 以标准 socket 语义编程,无需关心芯片细节。核心是**阻塞模型 + 事件驱动 + 周期对账自愈**。
## 文件一览
| 文件 | 作用 |
|---|---|
| `net_socket.c/h` | **BSD Socket API 实现**:`net_socket` / `net_connect` / `net_send` / `net_recv` / `net_close` / `net_listen` / `net_accept`,含 L3 挂起(pending)与错误码 |
| `net_select.c/h` | `select`/`poll` 多路复用(基于芯片中断事件 + 周期轮询) |
| `net_types.h` | 网络层公共类型定义 |
| `net_config.h` | 网络层编译期配置(缓冲区大小、超时、对账周期等) |
| `lftpd/` | **轻量 FTP 服务器**(第三方移植,见其子目录) |
## 核心机制
### 阻塞模型(L3 pending)
- 一期(RECV)已落地:`net_recv` 等支持带超时的阻塞(`pending` 挂起 + tick 唤醒)
- 二期(ACCEPT + SEND)待做 → `docs/待处理内容.md` N-4
### 周期对账自愈(Trap 22 修复)
- `net_reconcile_tick()`(200ms)回读芯片状态修正三类失同步:
本层 ESTABLISHED 而芯片已断 → 断开;本层 LISTENING 而芯片已握手 → 补 accept;
本层 LISTENING 而芯片监听消失 → 重建
- **去抖(连续 2 次)+ 冷却(1s)**——单次状态读的重建动作**必须去抖**,
否则"刚 listen 未生效"瞬态会反复重建直至 `relisten give up`(三监听口全死)
### 异常复监听隔离(Trap 23 修复)
- 异常释放(TIMEOUT)的 socket 复监听前隔离:排空 RX 残渣 + 主动 close + 等 CLOSED
- 400ms 起、800ms 上限强制放行(上限须 < 重试放弃时限 2000ms)
- 仅异常路径生效,正常 FIN 路径零改动
### 错误码(E-03 修复)
- **按任务隔离**:`s_net_errno_slots[8]`(每槽 `{任务句柄, err}`),替代原全局 `s_net_errno`
- `net_get_errno()` 只读本任务槽位,**对外语义不变**(成功不清零)
## 依赖关系
```
上层(FTP / timeSync / UI 推流)
↓ BSD Socket API
net_socket.c ←→ net_select.c
↓ ch395f_* 接口
Drivers/BSP/CH395F/
```
## ⚠️ 改本模块前必读
- 就绪屏障位(`SYS_EVT_NET_READY` 等)等待必须 `osFlagsNoClear`,**不能用默认消费型**
- 每次 CH395F SPI 事务须 `ch395f_spi_begin()/end()` 包裹
- **改任何自愈/重建逻辑必须去抖**,否则会引发重建风暴
- 相关陷阱:`docs/问题记录/CH395F_Trap_Records.md` Trap 21/22/23
## 相关文档
- 上层用法:`docs/网络/BSD_Socket_API_使用指南.md`
- 内部调用关系:`docs/网络/BSD_Socket_API_函数调用关系.md`
- 演进方案:`docs/问题记录/Net层阻塞模型业界对照与演进方案.md`
- 测试:`docs/测试说明/CH395F_Test_Guide.md`、`docs/测试说明/FTP_Test_Guide.md`
+41
View File
@@ -0,0 +1,41 @@
# Drivers/BSP/NET/lftpd/ — 轻量 FTP 服务器(第三方移植)
> ⚠️ **第三方开源库移植**(lftpd,许可证见 [`LICENSE.txt`](LICENSE.txt)),**非自研代码**。
> 本目录 README 仅说明其在本项目中的**定位与对接方式**;库内部逻辑请参考上游。
## 文件一览
| 文件 | 作用 |
|---|---|
| `lftpd.c/h` | FTP 服务器主体(命令解析、状态机、数据通道) |
| `lftpd_io.c` | I/O 适配层(**本项目对接 FatFs 的关键所在**) |
| `lftpd_inet.c` | 网络适配(对接本项目的 BSD Socket API) |
| `lftpd_log.c` | 日志输出适配 |
| `lftpd_string.c` | 字符串工具 |
| `private/*.h` | 内部头文件 |
| `LICENSE.txt` | 上游许可证 |
## 在本项目中的对接
```
ftpTask(App/ 侧创建)
↓ 等待 SYS_EVT_NET_READY + SYS_EVT_STORAGE_READY(osFlagsNoClear!)
lftpd(本目录)
├── lftpd_inet.c → Drivers/BSP/NET/net_socket.c(BSD Socket API)
└── lftpd_io.c → Lib/FatFs(文件读写)
```
## ⚠️ 项目相关注意
- **ftpTask 就绪屏障**:`osEventFlagsWait` 等两位就绪必须加 `osFlagsNoClear`,
否则位被先到的消费者清掉 → FTP 21 端口静默不监听(无日志无报错)
- **lftpd 大局部缓冲**:已按 `docs/内存管理/RAM使用分析与优化方案.md` §1.4 静态化 9 处
大局部缓冲(BSS +4.6KB),使 ftpTask 栈峰值从 3480B 降到 1184B——**勿改回局部变量**
- **上传中止截断**:FTP STOR 中途断开后首笔复连被截断(Trap 23)已在 `net_socket.c` 侧修复
- 本目录受 pre-commit 的**部分排除**(第三方代码)
## 相关文档
- 测试指南:`docs/测试说明/FTP_Test_Guide.md`
- 台架探针:`MDK-ARM/ftp_abort_probe.py`、`MDK-ARM/ftp_freeze_probe.py`
- 内存优化:`docs/内存管理/RAM使用分析与优化方案.md` §1.4
+36
View File
@@ -0,0 +1,36 @@
# Drivers/BSP/NETCFG/ — 网络配置
> 网络参数的**加载 / 保存 / 旧档迁移**(IP、掩码、网关等)。
> 本模块是**网络配置的持久化层**,与 `App/cfg_file.c`(配置引擎)配合工作。
## 文件一览
| 文件 | 作用 |
|---|---|
| `net_cfg.c/h` | 网络配置加载(`net_cfg_load`)/ 保存(`net_cfg_save_run`)+ RAM 副本管理 |
| `net_cfg_legacy.c/h` | **旧版配置档迁移**(首启时把旧格式转换为当前格式) |
## 工作流
```
defaultTask:net_cfg_load(含旧档迁移)→ 置 STORAGE_READY
↓ (网络配置在屏障前已加载)
netTask:只读 RAM 副本 → net_stack_bring_up(不在 netTask 里读盘)
↓
UI 改配置 → SYS_EVT_CFG_SAVE 事件 → defaultTask 执行 net_cfg_save_run + cfg_file_poll
↓
netTask 消费 SYS_EVT_NET_RECONFIG → 立即重建网络(新 IP 免重启生效)
```
## ⚠️ 约束
- **网络配置在 `STORAGE_READY` 屏障之前由 defaultTask 加载完毕**,netTask 只读 RAM 副本
- UI 保存请求经 `SYS_EVT_CFG_SAVE` 事件交由 **defaultTask**(配置引擎属主)执行,
**netTask/uiTask 不得直接触碰配置引擎**(`cfg_file` 是静态态、单任务收敛)
- 网络代次号(generation)用于各 TCP 服务判断是否需重建监听
## 相关文档
- `docs/子系统设计/网络配置说明.md` — 网口设置页与即时生效机制
- `docs/子系统设计/配置文件设计说明.md` — 配置引擎
- `docs/架构设计/项目启动顺序管理.md` — 就绪屏障
+46
View File
@@ -0,0 +1,46 @@
# 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/网络/`、`docs/问题记录/Net层阻塞模型业界对照与演进方案.md` |
| `NETCFG/` | 网络配置 | — | `/config.ini` 网络段的加载/保存 + 旧档迁移 | `docs/子系统设计/网络配置说明.md` |
| `UI/` | LVGL UI 组件 | — | 菜单/内容页/组件/中文字体 | `docs/UI设计/` |
## 根级文件
| 文件 | 作用 |
|---|---|
| `dbg_log.h` | **调试日志宏**(`DBG_INFO` 等),编译期开关 |
| `dbg_cfg.h` | 调试配置项 |
## 子模块 README
- [`NET/README.md`](NET/README.md) — 网络抽象层(Socket / select / FTP)
- [`UI/README.md`](UI/README.md) — LVGL UI 组件
## ⚠️ 改驱动前必读(踩坑速查)
| 模块 | 陷阱 |
|---|---|
| CH395F | SPI 事务须 `ch395f_spi_begin()/end()` 包裹;分频系数**必须为 8**(PCB 约束,勿"优化");快速复连会丢中断致监听死亡(Trap 22 已修);上传中止后首笔复连截断(Trap 23 已修) |
| 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`
+26
View File
@@ -0,0 +1,26 @@
# Drivers/BSP/RS485/ — RS-485 半双工通信驱动
> RS-485 半双工收发驱动:DE(发送使能)方向控制 + 收发时序管理。
> 配合 `App/task/rs485_task.c` 与 `App/util/crc.c`、`App/util/ringbuf.c` 组成完整协议栈。
## 文件一览
| 文件 | 作用 |
|---|---|
| `rs485.c/h` | 驱动初始化、DE 引脚方向切换、收发缓冲管理 |
## 硬件接口
- **UART5**:PC12 TX / PD2 RX / **PD0 DE**(发送使能,低=接收、高=发送)
## 关键点
- **半双工**:发送前拉高 DE 并等待发送完成,发送后立即拉低 DE 切回接收
- 方向切换时序与波特率相关——切换过快会截断末字节,过慢会阻塞总线
- 接收经 `ringbuf`(SPSC 无锁环形缓冲)缓冲,供协议层解析
## 相关文档
- 协议工具:`App/util/crc.c`、`App/util/ringbuf.c`
- 任务实现:`App/task/rs485_task.c`
- 硬件引脚:根 `README.md`「外设接口」
+28
View File
@@ -0,0 +1,28 @@
# Drivers/BSP/SD2506/ — SD2506 RTC 驱动
> SD2506 实时时钟芯片驱动(I2C 接口):时间读写、温度、电池状态、诊断。
> 是 `sys_clock`(墙钟)的**硬件时间基准**。
## 文件一览
| 文件 | 作用 |
|---|---|
| `sd2506.c/h` | RTC 初始化、时间读写、ID/温度/电池读取、诊断 |
## 硬件接口
- **I2C**(具体引脚见根 `README.md` 与 `Inc/main.h`)
## 关键点
- **时间子系统优先初始化**:`app_main_init` 中最先调用 `sd2506_init` +
`sys_clock_init`,使后续日志都带时间戳
- 开机执行 **SD2506 诊断**(ID / 时间 / 温度 / 电池),失败触发"时钟芯片异常"自检上报
- RTC 故障时 `sys_clock_init` **降级到默认时间基准并返回 -1**
- 时间源同步由 `App/time_sync.c`(timeSyncTask)负责
## 相关文档
- 墙钟维护:`docs/子系统设计/系统墙钟时间维护说明.md`
- 测试指南:`docs/测试说明/SD2506_Test_Guide.md`
- 陷阱台账:`docs/问题记录/SD2506_Trap_Records.md`
+32
View File
@@ -0,0 +1,32 @@
# Drivers/BSP/TPAFE5160/ — TPAFE5160 高精度 ADC 驱动
> TPAFE5160 是**并行 16 位**接口的高精度 ADC。本目录为寄存器级驱动:
> 转换启动(CONVST)、忙信号(BUSY)、数据读取(RD)时序管理。
## 文件一览
| 文件 | 作用 |
|---|---|
| `tpafe5160.c/h` | ADC 初始化、转换启动(轮询 + 中断)、16 位并行数据读取 |
## 硬件接口
- **并行 16 位**:PG0–PG15 数据总线 / **PD3 RD**(读选通)/ **PD4 CONVST**(转换启动)/ **PD7 BUSY**(转换中)
- 部分引脚为 GPIO 模拟时序(非硬件 SPI/FSMC)
## 关键点
- **首次转换在 `app_main_init` 末尾由 `tpafe5160_start_conv_irq` 启动**(中断驱动)
- 采样数据由 `App/task/adc_task.c` 消费处理
- CONVST→BUSY→RD 三段时序对**建立/保持时间敏感**,改动需对照芯片手册
- ⚠️ 本项目 ADC 相关功能**新增任务/缓冲前须核算 RAM**(见 `docs/内存管理/`)
## 已知问题
- `docs/问题记录/TPAFE5160.md` 有 **16 张图片断链**(文档引用了但图从未入库)——已登记,暂缓处理
## 相关文档
- 芯片手册转录:`docs/芯片手册/TPAFE5160.md`(注:其配图有断链)
- 任务实现:`App/task/adc_task.c`
- 硬件引脚:根 `README.md`「外设接口」
+57
View File
@@ -0,0 +1,57 @@
# Drivers/BSP/UI/ — LVGL UI 组件
> 基于 LVGL 的界面实现:菜单树、内容页、通用组件、中文字库、待机页。
> **与 PC 模拟器共用同一套 UI 源码**(`simulator/` 只提供平台层)。
## 结构
### 核心 / 框架
| 文件 | 作用 |
|---|---|
| `ui_port.c/h` | **LVGL 移植层**:显示驱动、输入设备、tick 注册 |
| `ui_menu.c/h` | 菜单框架(树结构与导航) |
| `ui_menu_view.c/h` | 菜单视图渲染 |
| `ui_menu_tab.c/h` | 页签组件 |
| `ui_deco.c/h` | 界面装饰元素(图标、边框等) |
| `ui_standby.c/h` | 待机页 |
| `ui_pwd_def.h` | 密码页默认值定义 |
| `ui_font_cn_12.c` | **中文字库**(由 `tools/font_gen/` 生成,勿手改) |
### 内容页
| 文件 | 作用 |
|---|---|
| `ui_content_page.c/h` | 内容页框架 |
| `ui_page_ac.c/h` | 交流量页 |
| `ui_page_dc.c/h` | 直流量页 |
| `ui_page_device_info.c/h` | 设备信息页 |
| `ui_page_net_cfg.c/h` | 网口设置页 |
| `ui_page_password.c/h` | 密码页 |
| `ui_page_runlog.c/h` | 运行日志页 |
| `ui_page_selftest.c/h` | 自检页 |
### 数据汇入(推流)
| 文件 | 作用 |
|---|---|
| `ui_net_sink.c/h` | 远端显示总线(RemoDispBus)数据汇入口 |
| `ui_net_sink_backend.h` | 后端抽象接口(MCU / 模拟器分别实现) |
| `ui_net_sink_backend_mcu.c` | MCU 端后端实现 |
## ⚠️ 编码注意(本目录含中文字符串)
- 本目录文件**带 UTF-8 BOM**(`.c` 内含中文字符串字面量,BOM 使 ARMCC 按 UTF-8 解码)
- **Edit 工具会剥掉 BOM**:改完必须核对并按原样补回 3 字节 `EF BB BF`,
否则 ARMCC 改按 CP936 解读 → `#870-D: invalid multibyte character sequence`
- UI 改动一律走 **`ui-verify` skill 五步门禁**
- 含新汉字的文案提交前先跑 **`font-regen` skill** 重生成 `ui_font_cn_12.c`
## 相关文档
- UI 架构:`docs/UI设计/UI_设计架构.md`
- 菜单设计:`docs/UI设计/菜单页面设计.md`、`docs/UI设计/内容页架构.md`
- 字体:`docs/UI设计/UI_中文字体生成与配置.md`
- 模拟器:`docs/UI设计/LVGL模拟器部署与使用说明.md`
- 自动化测试:`docs/UI设计/UI_自动化测试流程.md`
- 协议:`docs/UI设计/RemoDispBus协议与接收设计说明.md`
+33
View File
@@ -0,0 +1,33 @@
# Inc/ — CubeMX 生成的头文件
> ⚠️ **本目录文件由 STM32CubeMX 生成**(`.ioc` 重生成会覆盖),**不是自研代码**。
> 允许在 `USER CODE BEGIN/END` 标记区之间写自定义内容。
## 文件一览
| 文件 | 生成 | 作用 |
|---|---|---|
| `main.h` | CubeMX | 主头文件:引脚宏定义(`xxx_Pin` / `xxx_GPIO_Port`) |
| `FreeRTOSConfig.h` | CubeMX | **FreeRTOS 内核配置**(堆大小、tick、优先级位数等) |
| `stm32f4xx_hal_conf.h` | CubeMX | HAL 模块裁剪开关(启用/禁用各外设 HAL 模块) |
| `stm32f4xx_it.h` | CubeMX | 中断服务函数声明 |
| `gpio.h` / `dma.h` / `spi.h` / `i2c.h` / `usart.h` | CubeMX | 各外设初始化函数声明 |
## ⚠️ 修改约定
- 自定义内容只写 `USER CODE BEGIN xxx` / `USER CODE END xxx` 标记区之间
- 引脚宏(如 `CH395F_CS_Pin`)在 `main.h` 中定义,**改引脚须在 CubeMX 中改后重新生成**
## 关键配置速查
| 配置 | 值 | 位置 |
|---|---|---|
| FreeRTOS 堆 | `configTOTAL_HEAP_SIZE`(已迁 CCM) | `FreeRTOSConfig.h` |
| 栈溢出检查 | `configCHECK_FOR_STACK_OVERFLOW = 2` | `FreeRTOSConfig.h` |
| HAL 时基 | TIM7(`HAL_TIMEBASE` 覆盖) | `stm32f4xx_hal_conf.h` + `Src/` |
| NVIC 分组 | 4 位优先级 | CubeMX 配置 |
## 相关文档
- 内存/堆预算:`docs/内存管理/RAM使用分析与优化方案.md`
- 硬件引脚:根 `README.md`「外设接口」表
+69
View File
@@ -0,0 +1,69 @@
# MDK-ARM/ — Keil MDK-ARM v5 工程与构建/烧录/探针脚本
> **唯一工具链**:Keil MDK-ARM v5(ARMCC,C99)。本目录含工程文件、启动文件、
> 命令行构建/烧录脚本,以及**台架探针与判读脚本**。
## 关键文件
| 文件/目录 | 作用 |
|---|---|
| `STM32F407-Demo.uvprojx` | **Keil 工程文件**(源文件清单、编译选项、目标配置) |
| `STM32F407-Demo.uvoptx` | Keil 用户选项(调试器、断点等) |
| `startup_stm32f407xx.s` | 启动文件(**`Heap_Size EQU 0x200`(512B)在此限定**) |
| `build.bat` | **`@build` 命令行编译**(退出码 0=0 错 0 警;日志 `build_log.txt`) |
| `download.bat` | 烧录(UV4 路径) |
| `reset.bat` | **复位/烧录**(`ST-LINK_CLI`,见下) |
## 构建与烧录
```bash
# 编译(相对路径,勿用绝对路径)
& "MDK-ARM\build.bat" # 退出码 0 = 0 errors, 0 warnings
# 烧录 + 复位运行(推荐路径)
& "MDK-ARM\reset.bat" flash <文件.hex|.bin>
# 仅复位
& "MDK-ARM\reset.bat"
```
### ⚠️ 烧录铁律
- `reset.bat flash` = `ST-LINK_CLI -c SWD -P <文件> -Rst -Run`——**`-Rst -Run` 不可省略**!
裸 `-P` 会报 `Programming Complete`,但目标核处于异常状态时写入并不落地(芯片内容不变)
- 烧录后**必须回读校验**:`ST-LINK_CLI -c SWD -CmpFile <文件> 0x08000000`(`No difference found` 才算真写入)
- 本机 3 线接线(nRST 未接),**只重启不烧录**用 `reset.bat` 无参
## 台架探针与判读脚本
| 脚本 | 作用 |
|---|---|
| `bench_verdict.py` | 台架判读(把运行结果判为 PASS/FAIL) |
| `ftp_freeze_probe.py` | FTP 上传+回读哈希(真实路径冻结探针) |
| `ftp_abort_probe.py` | FTP 中止场景探针(Trap 23) |
| `ftp_retr_abort_probe.py` | FTP RETR 中止探针 |
| `tcp_reconnect_probe.py` | TCP 快速复连探针(Trap 22) |
| `audit_runs.py` / `audit_tcpclient.py` | 运行记录审计 / TCP 客户端审计 |
| `check_crecipe_content.py` | 检查创建配方内容 |
## 子目录
| 目录 | 内容 |
|---|---|
| `RTE/` | Keil Run-Time Environment 配置 |
| `DebugConfig/` | 调试会话配置 |
| `STM32F407-Demo/` | 构建输出(`.o`/`.axf`/`.map` 等,**产物不提交**) |
| `bench_diag/` | 台架诊断数据 |
| `retracted_bench_20260922/` | 已撤回的台架数据(存证) |
## ⚠️ 注意
- `build.bat` **硬编码本机 Keil 路径** `C:\Keil_v5\UV4\UV4.exe`(换机需改)
- 本目录被 pre-commit 门禁**排除**
- 启动文件的 `Heap_Size = 512B` 是**自研代码禁用 `malloc` 的根因**(见 `AGENTS.md`)
## 相关文档
- 烧录/复位:`docs/测试说明/ST-LINK_CLI_复位使用说明.md`
- 构建与验证:根 `AGENTS.md`「构建与验证」章
- 测试流程:`docs/测试说明/自动化测试流程.md`
+3
View File
@@ -93,6 +93,9 @@ main.c
## 目录结构
> **每个自建代码目录都有 `README.md`**(说明目录职责、文件清单与改前须知)——
> 下表是全局地图,各目录 README 是局部细节。约定见 [`docs/文档规范.md`](docs/文档规范.md) §1.1b。
```
STM32F4-Base/
├── Src/ # CubeMX 生成的源文件(USER CODE 区域可编辑)
+35
View File
@@ -0,0 +1,35 @@
# Src/ — CubeMX 生成的源文件
> ⚠️ **本目录文件由 STM32CubeMX 生成**(`.ioc` 重生成会覆盖),**不是自研代码**。
> 但允许在 `USER CODE BEGIN/END` 标记区之间写自定义代码。
## 文件一览
| 文件 | 生成 | 作用 |
|---|---|---|
| `main.c` | CubeMX | 程序入口:`HAL_Init` → `SystemClock_Config` → 外设初始化 → `app_main_init` → `osKernelStart` |
| `freertos.c` | CubeMX | **FreeRTOS 任务创建**(`MX_FREERTOS_Init`)+ 任务栈/优先级定义 |
| `gpio.c` / `dma.c` / `spi.c` / `i2c.c` / `usart.c` | CubeMX | 各外设 `MX_xxx_Init` |
| `stm32f4xx_hal_msp.c` | CubeMX | HAL 外设底层初始化(时钟使能、NVIC、引脚复用) |
| `stm32f4xx_hal_timebase_tim.c` | 自研覆盖 | **HAL 时基改用 TIM7**(非 SysTick),tick = 1ms |
| `stm32f4xx_it.c` | CubeMX | 中断服务函数(ISR) |
| `system_stm32f4xx.c` | CMSIS | 系统时钟初始化(`SystemInit`) |
## ⚠️ 修改约定(铁律)
- **自定义代码只写 `USER CODE BEGIN xxx` / `USER CODE END xxx` 标记区之间**——
标记区外的内容在 CubeMX 重新生成时会被**无条件覆盖丢失**
- 本目录被 pre-commit 的 C 代码规范检查**排除**(因是生成代码,风格不受控)
- `Drivers/BSP/` 才是纯手工代码区;应用逻辑放 `App/`
## 关键点
- **HAL 时基 = TIM7**,不是 SysTick;FreeRTOS 用 SysTick 之外的方式,tick = 1ms
- NVIC 4 位优先级分组;**外设中断优先级 ≥ 5**(0~4 预留给 FreeRTOS)
- 时钟:HSE 8MHz → PLL M=4/N=168/P=2 → 168MHz
## 相关文档
- 架构全景:`docs/架构设计/项目架构总览.md`
- 启动顺序:`docs/架构设计/项目启动顺序管理.md`
- 任务表(唯一事实源 = `freertos.c`):根 `README.md`
+17
View File
@@ -16,6 +16,23 @@
| **按领域归入子目录** | 顶层不放散落 `.md`;新领域先建无空格子目录,再在 [`README.md`](README.md) 登记 |
| 现有目录 | `架构设计/` `子系统设计/` `网络/` `测试说明/` `代码规范/` `内存管理/` `问题记录/` `审查记录/` `环境与部署/` `UI设计/` `硬件平台/` `芯片手册/` `images/` |
### 1.1b 代码目录的 README.md
**每个自建代码目录**(非第三方库、非 HAL/CMSIS 生成)**必须有一份 `README.md`**,
说明该目录的职责、文件清单与关键约束,让新接手者不必读遍代码即可建立认知。
| 规则 | 说明 |
|---|---|
| **覆盖范围** | `App/`(含 `log/` `task/` `util/`)、`Drivers/BSP/`(含各芯片子目录)、`Src/`、`Inc/`、`scripts/`、`tools/`(含各子工具)、`test/`、`MDK-ARM/`、`simulator/`(含 `sim/` `tests/`)、`docs/` |
| **排除** | 第三方库与生成代码:`Drivers/CMSIS/`、`Drivers/STM32F4xx_HAL_Driver/`、`Middlewares/Third_Party/`、`Lib/`(FatFs/dhara/lvgl)、`simulator/SDL2/`、构建产物目录 |
| **必备内容** | ① 一句话定位 + 是否自研 ② 文件/子目录清单表(每个一句话作用)③ 关键约束或陷阱(改前须知)④ 指向 `docs/` 权威文档的链接 |
| **命名** | 一律 `README.md`(大写),放该目录根部 |
| **链接** | 目录间互链用**同级相对路径**(如 `../NET/README.md`);指向 `docs/` 用**仓库根相对路径** |
| **门禁** | README 内所有链接受 `doc-links` 钩子检查;新增/改名目录或文件后须同步更新对应 README |
> 目的:**目录即文档的入口**。根 `README.md` 给全局地图,各目录 `README.md` 给局部细节,
> 二者构成"地图 + 地标"的导航体系(避免所有信息堆在单一 README)。
### 1.2 文件名
| 规则 | 说明 |
+51
View File
@@ -0,0 +1,51 @@
# scripts/ — 开发脚本(提交门禁 + 报告生成)
> 本目录是 **pre-commit 门禁脚本**与**报告生成脚本**的存放处。
> 与 `tools/`(面向开发者的功能工具)区别:本目录服务于**质量门禁与工程度量**。
## 文件一览
### 提交门禁(接入 `.pre-commit-config.yaml`)
| 脚本 | 钩子名 | 作用 |
|---|---|---|
| `check_coding_standard.py` | `C coding standard` | C 代码规范机械检查(命名前缀/常量右置/头文件保护宏等) |
| `check_mojibake.py` | `Forbid U+FFFD mojibake` | 扫描 `U+FFFD` 乱码(`EF BF BD` 字节) |
| `check_doc_links.py` | `doc-links` | **文档链接存在性** + 命名规范(D-3/D-7) |
| `gen_task_table.py` | `task-table` | FreeRTOS 任务表以 `Src/freertos.c` 为**唯一事实源**生成/校验(D-2/D-7) |
| `check_mem_numbers.py` | `mem-numbers` | 内存/Flash 数字以 `.map` 为唯一事实源校验(D-7 体积档) |
### 报告生成(非门禁)
| 脚本 | 作用 |
|---|---|
| `ram_report.py` | 从 `.map` 生成**静态 RAM/Flash 占用**报告(→ `docs/内存管理/data/`) |
| `stack_report.py` | 从 Keil 静态调用图 + 串口 `[STACK]` 水位生成**每任务最坏链**报告 |
## 使用方式
```bash
# 全库跑门禁
& 'C:\ProgramData\anaconda3\python.exe' -m pre_commit run --all-files
# 单个脚本
& '.venv\Scripts\python.exe' scripts/check_doc_links.py --all
& '.venv\Scripts\python.exe' scripts/gen_task_table.py --check # 或 --write / --diff
& '.venv\Scripts\python.exe' scripts/check_mem_numbers.py --check
& '.venv\Scripts\python.exe' scripts/ram_report.py
& '.venv\Scripts\python.exe' scripts/stack_report.py -s tools\serial_tool\state\serial.log
```
## ⚠️ 脚本编写约定
- **保真回写**:改文件前先探测原换行符(LF/CRLF)与 BOM,按原样回写(本仓库各文件换行混杂)
- **受管区锚点**:改文档中的数值/表格时用 `<!-- XXX:BEGIN/END -->` 锚点,只替换锚点内内容
- 脚本**输出文件绝不能落在自身扫描范围内**(否则会"自我污染",见 `docs-tree-reorg` skill)
- 生成器与校验器**共用同一套正则/口径**,避免两处数字打架
## 相关文档
- `docs/代码规范/pre-commit使用说明.md` — 门禁完整说明与排除项
- `docs/代码规范/cppcheck使用说明.md`
- `docs/文档规范.md` — 文档门禁三档
- `docs/内存管理/RAM使用分析与优化方案.md` — RAM/栈报告口径
+36
View File
@@ -0,0 +1,36 @@
# simulator/sim/ — 模拟器平台层
> PC 端 LVGL 模拟器的**平台适配层**:把 MCU 侧的硬件/RTOS 接口替换成 PC 实现,
> 使 **UI 源码(`Drivers/BSP/UI/`)与固件共用同一套代码**。
## 文件一览
| 文件 | 替换的 MCU 侧实现 | 作用 |
|---|---|---|
| `sim_port.c/h` | `ui_port.c` | **显示/输入移植层**:SDL 窗口 → LVGL 显示驱动 + 键鼠/触摸输入 |
| `net_socket_sim.c` | `net_socket.c` | 网络 Socket 的 PC 实现(宿主 BSD socket) |
| `cfg_file_store_sim.c` | `cfg_file_store_mcu.c` | 配置存储的 PC 后端(宿主堆) |
| `sim_syslog.c` | `sys_log_mcu.c` | 日志的 PC 实现(写文件而非 NAND) |
| `ui_net_sink_backend_sim.c` | `ui_net_sink_backend_mcu.c` | 推流后端的 PC 实现 |
| `sim_latency_stub.c` | — | 时延打桩(模拟链路延迟,供测试) |
## 设计模式
MCU 与模拟器**共用核心逻辑,仅后端不同**:
```
共享核心(无分配符号)
├── cfg_file.c(配置引擎)
└── ui_*(LVGL UI)
↓ 后端抽象接口
┌─────────┴─────────┐
MCU 后端(本工程 *_mcu.c) PC 后端(本目录 *_sim.c)
```
> 配置引擎后端:MCU = FreeRTOS 堆、模拟器 = 宿主堆,**共享核心零分配符号**。
## 相关文档
- 模拟器总说明:`../README.md`
- UI 架构与移植要点:`docs/UI设计/UI_设计架构.md`
- 模拟器部署:`docs/UI设计/LVGL模拟器部署与使用说明.md`
+36
View File
@@ -0,0 +1,36 @@
# simulator/tests/ — UI 模拟器无头回归测试
> PC 端**无头**(headless)UI 像素回归测试:在模拟器中渲染各页面,与**黄金参考图**比对,
> 检测 UI 改动是否引入像素级回归。属于 `ui-verify` skill 五步门禁的一部分。
## 文件一览
| 文件 | 作用 |
|---|---|
| `check_menu_rows.py` | **菜单像素回归**:渲染菜单行 → 与黄金参考比对 |
| `check_content_pages.py` | **内容页回归**:各内容页渲染比对 |
| `check_remo_sink.py` | **推流(RemoDispBus)回归**:接收端渲染比对 |
| `regen_ref_png.py` | **重建黄金参考**:UI 有意变更后,重新生成基准图 |
| `ref/` | 黄金参考图(基准 PNG) |
## 使用方式
```bash
# 跑回归(按 ui-verify skill 流程)
& '.venv\Scripts\python.exe' simulator/tests/check_menu_rows.py
& '.venv\Scripts\python.exe' simulator/tests/check_content_pages.py
# UI 有意变更、确认无误后重建基准
& '.venv\Scripts\python.exe' simulator/tests/regen_ref_png.py
```
## ⚠️ 注意
- **重建黄金参考前必须确认变更是有意的**——否则会把 bug 固化成"基准"
- UI 改动一律走 **`ui-verify` skill 五步门禁**(regression 是其中一步)
- 依赖模拟器已构建(`simulator/build_sim.bat`)
## 相关文档
- `docs/UI设计/UI_自动化测试流程.md` — ui-verify 五步门禁
- `docs/UI设计/LVGL模拟器部署与使用说明.md`
+54
View File
@@ -0,0 +1,54 @@
# test/ — 测试代码与主机端脚本
> 测试分两部分:**板端测试套件**(`.c/.h`,编入固件由 testTask 执行)与
> **主机端脚本**(`.py`,PC 侧驱动板子并判读结果)。
## 板端测试套件(编入固件)
| 文件 | 测试对象 |
|---|---|
| `test_config.c/h` | 测试任务配置(启用哪些套件) |
| `ch395f_test_task.c/h` + `ch395f_test.h` | CH395F 以太网(硬件层 + NET 层) |
| `gd5f_test_task.c/h` + `gd5f_test.h` | GD5F2GQ5UE SPI NAND 存储 |
| `sd2506_test_task.c/h` + `sd2506_test.h` | SD2506 RTC |
| `storage_test_task.c/h` + `storage_test.h` | 存储性能 |
| `net_test_task.c/h` + `net_latency_test.c/h` | 网络层 / 链路时延 |
| `nand_ftl_test.c`(如有) | FTL 层 |
## 主机端脚本(PC 侧)
| 脚本 | 作用 |
|---|---|
| `run_boot_test.py` | **`@test` 一键闭环**:开串口+清日志 → 烧录 → wait-idle → 校验(退出码 0=PASS) |
| `verify_log.py` | 日志标记校验(Required/Forbidden 标记) |
| `ch395f_socket_test.py` | Socket 通信测试 |
| `ftp_test.py` / `ftp_up_dl_test.py` / `ftp_speed_test.py` | FTP 功能 / 上传下载 / 速度 |
| `ftp_capture.py` / `ftp_regression.py` | FTP 抓包 / 回归 |
| `e02_probe.py` | E-02 专项探针 |
| `latency_peer.py` | 链路时延对端(PC peer) |
| `time_sync_server.py` | 时间同步推送服务 |
## 运行方式
```bash
# @test 一键闭环(推荐)
& '.venv\Scripts\python.exe' test/run_boot_test.py
# 单独校验日志
& '.venv\Scripts\python.exe' test/verify_log.py <日志文件>
```
退出码约定:`0`=PASS / `1`=FAIL / `2`=采集或烧录错误 / `3`=用法或预检错误。
## ⚠️ 注意
- 本目录**被 pre-commit 门禁排除**(测试代码不受 C 规范约束)
- 板端套件占用 RAM,启用前先核算预算(见 `docs/内存管理/`)
- 测试缓冲用**分 Phase 复用静态缓冲**(避免 `L6406E` 溢出)
## 相关文档
- `docs/测试说明/测试开发标准流程.md` — L0~L3 分层与门禁决策表
- `docs/测试说明/自动化测试流程.md` — `@test` 细节与失败模式
- 各模块测试指南:`docs/测试说明/*_Test_Guide.md`
- `docs/测试说明/链路延迟测试说明.md`
+44
View File
@@ -0,0 +1,44 @@
# tools/ — 开发工具
> 面向开发者的**功能性工具**(生成器 / 转换器 / 交互工具)。
> 与 `scripts/`(质量门禁与度量)分工不同:本目录产出**资产**(图、字体、代码、知识库)。
## 工具一览
| 目录 | 工具 | 产物 | 文档 |
|---|---|---|---|
| `arch_diagram/` | 架构图 SVG 生成器 | `docs/images/*.svg` | `docs/架构设计/图形绘制流程.md` |
| `font_gen/` | 中文字库生成 | `Drivers/BSP/UI/ui_font_cn_12.c` | `docs/UI设计/UI_中文字体生成与配置.md` |
| `menu_gen/` | 菜单树代码生成 | UI 菜单代码 | `docs/UI设计/菜单页面设计.md` |
| `netlist_semantics/` | 网表语义分析 | 引脚知识库 JSON + 网表报告 | `docs/硬件平台/` |
| `refgraph/` | 文件引用关系图 | `docs/images/引用关系图.*` | `docs/架构设计/引用关系图说明.md` |
| `serial_tool/` | Python 串口助手 | 日志状态(`state/`) | `docs/测试说明/串口助手使用指南.md` |
## 使用方式
```bash
# 架构图(精确布局)
& '.venv\Scripts\python.exe' tools/arch_diagram/gen_memory_svg.py
# 中文字体(含新汉字文案后必须重跑)
& '.venv\Scripts\python.exe' tools/font_gen/make_font.py
# 引用关系图
& 'tools\refgraph\gen_refgraph.bat'
# 串口助手(常驻 daemon)
& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py
```
## ⚠️ 约定
- **生成器的产物与脚本一并提交**(如 SVG);本地预览产物(如 PNG)不提交
- 图表选型:精确布局图用 `arch_diagram/` 生成器;拓扑图(流程/时序/状态机)用 Mermaid;
**勿手绘 ASCII 框图**(见 `docs/架构设计/图形绘制流程.md`)
- 涉及 UI 改动:走 `ui-verify` skill 五步门禁;涉及字体:走 `font-regen` skill
## 相关文档
- `docs/架构设计/图形绘制流程.md` — 配图规范与选型
- `docs/架构设计/引用关系图说明.md`
- `docs/测试说明/串口助手使用指南.md`、`docs/测试说明/串口助手设计说明.md`
+35
View File
@@ -0,0 +1,35 @@
# tools/arch_diagram/ — 架构图 SVG 生成器
> 用 Python 脚本**精确生成**架构类 SVG 图(分层、内存布局、协议帧、屏障等),
> 产物放 `docs/images/`。用于"必须精确布局"的图;拓扑图(流程/时序/状态机)改用 Mermaid。
## 脚本一览
| 脚本 | 产物 | 用途 |
|---|---|---|
| `gen_arch_svg.py` | 架构分层图 | 六层分层结构 |
| `gen_memory_svg.py` | 内存布局图 | RAM / Flash 分区 |
| `gen_storage_stack_svg.py` | 存储栈图 | FTL / dhara / FatFs 三层栈 |
| `gen_net_stack_svg.py` | 网络栈图 | BSD 网络栈分层 |
| `gen_barrier_svg.py` | 就绪屏障图 | Event Flags 屏障模型 |
| `gen_frame_svg.py` | 协议帧格式图 | RemoDispBus 帧结构 |
| `gen_cfg_arch_svg.py` | 配置引擎架构图 | 配置分层与持久化 |
| `gen_partition_svg.py` | 分区图 | 存储分区 |
## 使用方式
```bash
& '.venv\Scripts\python.exe' tools/arch_diagram/gen_memory_svg.py
```
产物统一输出到 `docs/images/`;**脚本与生成的 `.svg` 一并提交**。
## ⚠️ 约定
- 颜色/字体遵循 `docs/架构设计/图形绘制流程.md` 的规范
- 中文用 SVG `<text>` 直接写(需注意字体族声明)
- 改图**改脚本再重跑**,不手改 SVG(保证可复现)
## 相关文档
- `docs/架构设计/图形绘制流程.md` — 配图规范、选型与检查清单
+30
View File
@@ -0,0 +1,30 @@
# tools/font_gen/ — 中文字库生成
> 从**字符集清单**生成 LVGL 用的中文字库 C 文件(子集化,只嵌入用到的汉字以节省 Flash)。
## 脚本一览
| 脚本 | 作用 |
|---|---|
| `extract_cn.py` | **提取汉字**:扫描 UI 源码的字符串字面量,输出字符集清单 `ui_cn_chars.txt` |
| `make_font.py` | **生成字库**:按字符集从 TTF 生成 `Drivers/BSP/UI/ui_font_cn_12.c` |
## 使用方式
```bash
# 新增含汉字的 UI 文案后:先提取字符集,再生成字库
& '.venv\Scripts\python.exe' tools/font_gen/extract_cn.py
& '.venv\Scripts\python.exe' tools/font_gen/make_font.py
```
## ⚠️ 注意
- **含新汉字的 UI 文案提交前必须重跑**(走 `font-regen` skill)——否则新字显示为空白/方块
- 产物 `ui_font_cn_12.c` **带 UTF-8 BOM**,勿手改(由脚本生成)
- 字库大小直接影响 Flash 占用,只嵌入实际使用的字符
- 依赖 `fontTools` / `Pillow`(已装在 `.venv`)
## 相关文档
- `docs/UI设计/UI_中文字体生成与配置.md`
- `docs/UI设计/UI_设计架构.md`
+28
View File
@@ -0,0 +1,28 @@
# tools/menu_gen/ — 菜单代码生成
> 从**菜单树定义**生成 UI 菜单的 C 代码,保证菜单结构与页面注册一致、避免手写遗漏。
## 脚本一览
| 脚本 | 作用 |
|---|---|
| `gen_menu.py` | 读取菜单树定义(见 `ui_menu_tree.txt`)→ 生成菜单代码 |
## 使用方式
```bash
& '.venv\Scripts\python.exe' tools/menu_gen/gen_menu.py
```
菜单树输入的权威副本:仓库根 `ui_menu_tree.txt`。
## ⚠️ 注意
- 生成产物**勿手改**(会被下次生成覆盖);要改菜单结构改**定义源**后重跑
- 中文字符串字面量须为**纯 ASCII 安全**(见 `AGENTS.md` 编码铁律)——生成后的文案
如需汉字,须配套重跑字体生成(`tools/font_gen/`)
## 相关文档
- `docs/UI设计/菜单页面设计.md`
- `docs/UI设计/内容页架构.md`
+29
View File
@@ -0,0 +1,29 @@
# tools/netlist_semantics/ — 网表语义分析
> 把电路**网表文件**(`.tel`)解析成"有语义的引脚知识库",供生成引脚表与网表分析报告。
## 脚本一览
| 脚本 | 作用 |
|---|---|
| `netlist_sem.py` | 网表解析核心(把 `.tel` 网表 → 结构化的网络/引脚连接) |
| `gen_kb.py` | 生成**引脚知识库** `pinout_kb.json` |
| `pinout_kb.json` | 引脚知识库产物(MCU 引脚 ↔ 网络 ↔ 外设的映射) |
## 使用方式
```bash
& '.venv\Scripts\python.exe' tools/netlist_semantics/netlist_sem.py <网表.tel>
& '.venv\Scripts\python.exe' tools/netlist_semantics/gen_kb.py
```
## 输入 / 产物
- **输入**:硬件网表 `.tel`(位于 `docs/硬件平台/`,如 `V0.0.tel`、`V0.1.tel`)
- **产物**:`pinout_kb.json` + `docs/硬件平台/V0.0_网表详细分析报告.md`、`docs/硬件平台/V0.0_网表语义图.md`
## 相关文档
- `docs/硬件平台/V0.0_网表详细分析报告.md`
- `docs/硬件平台/V0.0_网表语义图.md`
- 硬件引脚表:根 `README.md`「外设接口」
+35
View File
@@ -0,0 +1,35 @@
# tools/refgraph/ — 文件引用关系图
> 扫描全仓库 `.c/.h` 的 `#include` 关系,生成**文件级 + 模块级引用关系图**(Graphviz)。
## 文件一览
| 文件 | 作用 |
|---|---|
| `gen_refgraph.bat` | 一键入口(调用 `gen_refgraph.py` + Graphviz 渲染) |
| `gen_refgraph.py` | 扫描 `#include` → 生成 `.dot` → 渲染 `.svg` / `.json` |
## 使用方式
```bash
& 'tools\refgraph\gen_refgraph.bat'
```
## 产物(放 `docs/images/`)
| 产物 | 内容 |
|---|---|
| `引用关系图.dot` | Graphviz 源 |
| `引用关系图.svg` / `.png` | 渲染图(`.svg` 提交,`.png` 本地预览不提交) |
| `引用关系图.json` | 结构化引用数据 |
## ⚠️ 注意
- **项目文件变化后重跑**更新(新增/删除源文件、改 include 关系)
- 渲染依赖 **Graphviz**(`winget install graphviz` 可装)
- 脚本与 `.dot`/`.svg`/`.json` **一并提交**
## 相关文档
- `docs/架构设计/引用关系图说明.md`
- `docs/架构设计/项目架构总览.md`
+41
View File
@@ -0,0 +1,41 @@
# tools/serial_tool/ — Python 串口助手
> **常驻 daemon + CLI** 架构的串口工具:后台持续收串口日志,CLI 按需查询/发送,
> 避免反复开关串口导致日志丢失(台架与测试的主力观测工具)。
## 文件一览
| 文件/目录 | 作用 |
|---|---|
| `serial_tool.py` | 串口助手主程序(daemon 与 CLI 合一) |
| `state/` | **运行时状态目录** |
| `state/serial.log` | 串口原始日志(`stack_report.py -s` 的输入之一) |
| `state/daemon.log` | daemon 自身运行日志 |
| `state/meta.json` | daemon 元数据(端口、状态等) |
## 使用方式
```bash
# 启动 daemon / 打开串口
& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py open COM6
# 查询日志 / 发送命令
& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py tail
& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py send "<命令>"
# 关闭
& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py close
```
> 具体子命令以 `--help` 为准。
## ⚠️ 注意
- **单写者**:串口同一时刻只能被一个进程占用——别同时用本工具和其它串口程序
- `state/serial.log` 是 `[STACK]` 运行时水位的来源,`scripts/stack_report.py -s` 直接读它
- `state/` 是运行时数据,**不入库**
## 相关文档
- `docs/测试说明/串口助手使用指南.md` — 命令用法 / 工作流 / 排障
- `docs/测试说明/串口助手设计说明.md` — 契约 / daemon 行为 / 陷阱