证据源 = 主树 ci-artifacts/archify/architecture-dtu-overview-20261030-095132/ evidence.md §11。该目录不入库,故把每条的判据与实测源抄进正文,别让证据只活在 一台机器上。处置口径:能改的改成与代码同源,核实后确认文档没问题的明确写「不改」。 判停点与就绪屏障(条 1、条 3) - AGENTS 原写 `protect_task.c:98` 直接停走判据:`:98` 是 `s_prev_cal_lock` 变量, 判停点是 `App/task/protect_task.c:268 if (adc_cal_prot_blocked() != 0u)`, 判定本体在标定层 `adc_cal_prot_blocked()`、protectTask 只是消费者 → 改引用, 同步 `ui_task.c:240` 页面注释与 `docs/任务规划/数据可信.md` 的同一处行号。 - `SYS_EVT_FTP_READY` 有生产者(`Src/freertos.c:490`,注释自陈预留)无消费者; `SYS_EVT_TIMESYNC_READY` 全仓无生产者也无消费者(只有定义与测试桩)。 AGENTS、`sys_events.h` 位注释、屏障配图(生成器 + 产物)三处从「四个就绪位 并列」改成「bit0/bit1 在用 + bit2/bit3 预留」,并指向 `docs/架构设计/项目启动顺序管理.md` §3.2 的逐位对照表。ftpTask 实际等的是 `NET|STORAGE`(`Src/freertos.c:477-479`,WaitAll|NoClear,100 ms 分片喂狗)。 /log 不是「三本」(条 5) - `App/log/sys_log_mcu.c` 的 `s_paths[]` = run / selftest / accid / alarm / start / oper / yk 七本 64B 定长文本 + `soe.log`(64B 定长二进制)+ `wdev.log` (变长取证行,`App/fs/vol_lock` 侧投,不走定长格式)。 → AGENTS 两处、总览 §2.1 与 §4 的「三本」改成「七本 + SOE(+ wdev 取证行)」。 主机单测 44 套 → 47 套(条 2,两把机器尺互证) - `scripts/check_test_coverage.py --list` 打印 47 行;`ls -d test/host/*/` = 48 个 一级目录,唯一没有 `run_unit_test.py` 的是 `common/` ⇒ 47 套。 - 差额三名 = 屏板链路套件:`sb_proto`、`sb_link`(2026-10-29 入库)、 `sb_led_map`(2026-10-30 入库)。专属钩子仍是 22 根 ⇒ 无专属钩子的从 22 套变 25 套。 - 同步面:AGENTS、`docs/门禁说明/README.md`、`host-unit-tests.md` §6 台账(名单补 三名)、`docs/代码规范/pre-commit使用说明.md`、`主机单测覆盖率口径.md`(含耗时句)、 `scripts/README.md`、总览目录树、`.pre-commit-config.yaml` 三处注释、 `test/host/sys_log_mcu/sys_log_mcu_test.c` 一处注释。 - 带日期戳的历史测量值按纪律冻结不动:28 套、41 套 ~105 s、40 套/18 套那三处。 本仓 LVGL 版本(条 6) - vendored 版本 = `Lib/lvgl/lv_version.h:9-11` 的 9.3.0;总览两处「LVGL v9.2」与 `gen_arch_svg.py` 图内文字改 v9.3 并重跑产物(脚本与产物同一笔,`generated-fresh` 逐字节核)。 - **刻意不动**:`docs/内存管理/RAM使用分析与优化方案.md` 两处「LVGL v9.2 文档」+ GitHub `release/v9.2` 分支 URL ——那是对外游某分支文档的引用,不是本仓版本声明。 触发口径与栈值(条 4、7、9、10) - ADC 映射 §1「ADC1 为软件触发」是旧口径:`Src/adc.c:53` 实为 `ADC_EXTERNALTRIGCONV_T3_TRGO` → 改成 TIM3 TRGO,并补一句「TIM3 与 TPAFE 的 CONVST 之间没有硬件耦合,仍不构成共同采样触发」,缺陷结论本身不变。 - 同文档 adcTask 栈 512 → 640 words(`Src/freertos.c:159 .stack_size = 640 * 4`)。 - `docs/UI设计/UI_设计架构.md` 的 uiTask 栈「16384 words」是单位错: 实为 4096 words = 16384 B(`Src/freertos.c:218`),顺手补上行号。 - `App/app/app_main.c:197` 注释「DE = PD0」陈旧:`:198` 实传 `ST_DIR4_*` (V0.1 实板 PA15,V0.0 才是 PD0)→ 注释改指 V0.1 网表报告的引脚迁移表。 - 两处已退役编号 `N-18`(ADC 映射、V0.1 网表报告)换成登记簿条目名 「双转换器无共同采样触发」。 核实后确认「文档没问题」的三条(条 8、12、13) - 黄金参考「菜单 8 状态 + 内容页 66 张」:`simulator/tests/ref/` 实测 66 个 `shot_*.bin`,与 `ui-golden` 钩子显示名一致 → 不改。 - `App/task/rs485_task.c` 存在但 `Src/freertos.c` 不创建它(grep 无 rs485): AGENTS 与总览都已写明「尚未接线 / 暂缓」,图侧画成「实现待接线」→ 不改。 - 104 端口 `:2404` 是工厂默认、可经 `/config.ini` `[comm]` 改 → 总览索引表补 「默认」二字;「uiTask 10 ms 节拍」核实 = `ui_tokens.h:65 UI_TASK_TICK_MS 10` ✓。 并行勘查会话的同族发现(它扫「文档声明数 vs 真值」,逐处独立复验后采纳 3 处) - `App/protocol/iec104/iec104_link.h` 头注释写「端口:TCP 2404(§1.5 B0 定义)」, 同文件下方已写「服务端口真源已迁 [comm] 段」= 自相矛盾 → 补「工厂默认」并指回 [comm] 与「下次重 bind 即生效」。 - `scripts/gen_task_table.py` 的 iec104Task 描述「:2404 监听」→「工厂默认 :2404 监听」,`--write` 重生成 README 任务表(AGENTS 表无描述列,实测未被改写)。 - `App/log/README.md` 五行写入点行号全漂:事故 181→188、告警 184→191、启动 176→183(`App/task/protect_task.c`);操作 `iec104_pts.c` 574/602→582/610、 `default_task.c` 242→266、`sys_log_mcu.c` 646→682;遥控 573/576/582/586/596/ 598/609 → 581/584/590/594/604/606/617(宿主 `sim_syslog.c:245` 原值正确、未动)。 - **撤销一条**:我早先记的「`docs/算法/继电保护功能复现规划.md:225` 声称记录本已 有消费者」与原文不符——:225 实为规划表里「动作/SOE 记录 | 复用 `sys_log`」一行, 属能力复用口径、不是当前态断言 → 不改。教训:**改引用前逐处读现文,别照自己 上一轮的笔记盲替**(这条比改中的每一处都值钱)。 - 同一批勘查还报了约 12 处「`2404` 缺『工厂默认』限定词」(AGENTS、`App/protocol/ README.md`、`Src/freertos.c` 注释、5 篇 docs、`test/host` 工具,含一张配图生成器 要连产物同批重跑)与 `测试开发标准流程.md`「像素层 60 内容页」、 `.pre-commit-config.yaml` uinav 注释「快检档 18 张黄金参考」(后者写时为真、 描述的却是钩子现有行为):**本笔刻意不做**,另开任务空间处理——那批要同时动 AGENTS.md 与 `.pre-commit-config.yaml` 两处单写者面,与并行会话撞车的代价更高。 - 端口生效语义(用户裁定 2026-10-30):产品基线写「公共地址与端口可配…改后需重启 生效」,代码 `App/task/iec104_serv.c` 是「ca 改后要重启;port 下次重 bind 才生效」 ——裁定**按代码语义要改**处理(改了端口应立刻重 bind),属固件行为变更,另开任务 且需真机验证;`.serialtest/config.json` 写死 `i104: listening on 2404` 必检锚点 是同题(现场改端口会让串口回归假失败),一并留给那条任务。 自查(任务树内) - `check_doc_links.py --sections-strict`:12 个改动 .md 逐个 rc=0; `check_mermaid.py` 改动 .md 全 rc=0;`check_generated_fresh.py` PASS (25 个生成器 / 21 一致 / 4 存量基线);`check_nested_comment.py --all` PASS (449 文件,新发 0、存量 2);`check_bom_drift.py --all` 99 个名单文件无漂移。 - 编译:`.dsh/skills/keil-build` 退出码 0(0 错误 0 警告), Program Size Code=246720 RO=29836 RW=2052 ZI=149708 —— 与本树凭证同码, 证明这批改的确实只有注释与文档。 - 字节体检:23 个文件无 CR / U+FFFD / 行尾空格 / 缺末行换行;`ui_task.c` 被编辑后 丢的 3 字节 BOM 已补回(bom-guard 复验通过);5 处「三连空行」逐文件与 HEAD 比对确认是存量(Python 生成器的 PEP8 双空行与个别 C 文件原有空行)。 - 一次性工具 `ci-artifacts/fix_docs2.py`:断言式规则表,按文件读一次、在演化文本上 逐条替换、一次写盘。第一版写成「每条规则各自从启动时快照起算」,同一文件后一条 把前一条整体覆盖,只有每文件最后一条活下来——靠「改完再全仓复扫旧形态」当场抓到, 这条判据本身已值得写进流程。 - 待办:`git add` 后需重跑 `ram_baseline.py --update`(体积凭证按 git 索引内容生成, 未 staged 的文件不在凭证里,`check_size_gate.py --local` 现在因此报红)。 - 未 commit、未 push(AGENTS.md 边界:提交属 Ask first)。
STM32F4-Base
基于 STM32F407ZGTx 的工业级嵌入式平台固件,集成以太网通信、NAND Flash 存储、ADC 采集、RS-485 通信及 FTP 文件服务。
硬件平台
- MCU: STM32F407ZGTx @ 168MHz (HSE 8MHz → PLL M=4/N=168/P=2)
- 封装: LQFP144
- RTOS: FreeRTOS V10.3.1 (CMSIS-RTOS V2)
外设接口(V0.1 硬件)
引脚口径 =
Inc/main.h(CubeMX 生成,已迁 V0.1)+docs/硬件平台/V0.1_网表详细分析报告.md。 V0.0 与本表的差异:TPAFE 控制组 7 线、LED1/LED2 驱动脚、RS-485 所在串口实例。
| 外设 | 接口 | 引脚 | 说明 |
|---|---|---|---|
| CH395F 以太网 | SPI2 | PB12 CS, PB13 SCK, PB14 MISO, PB15 MOSI | 10/100M 以太网控制器 |
| GD5F2GQ5UE NAND | SPI1 | PE0 CS, PB3 SCK, PB4 MISO, PB5 MOSI, PB8 WP, PE1 HOLD | 256MB SPI NAND Flash |
| TPAFE5160 ADC | 并行16位 | PG0-PG15 数据, PC6 FRSTDATA, PC7 BUSY(EXTI), PC8 RD, PC9 CONVST, PA8 OS2 / PA11 OS1 / PA12 OS0 | 高精度 ADC |
| USART1 | 串口 | PA9 TX, PA10 RX | 115200bps 调试串口 |
| SD2506 RTC | I2C1 | PB6 SCL, PB7 SDA | 墙钟基准与日志时间戳 |
| 6x LED | GPIO | PC5, PB0, PB1, PB2, PF11, PF12 | 低电平点亮 |
| RS-485 | UART4 | PC10 TX, PC11 RX, PA15 DE | 半双工通信(B2 暂缓,见 docs/任务规划/暂缓-RS485.md) |
| SWD | — | PA13 SWDIO, PA14 SWCLK | 调试口 CN2(XH-3A) |
项目架构
flowchart TB
subgraph APP["应用层 (App/)"]
direction LR
A1["app/app_main.c"] ~~~ A2["task/net_task.c"] ~~~ A3["task/ui_task.c"] ~~~ A4["sync/time_sync.c"] ~~~ A5["algo/(语义取数与有效性~保护判据)"]
end
subgraph BSP["驱动层 (Drivers/BSP/)"]
direction LR
B1["CH395F"] ~~~ B2["GD5F2GQ5UE"] ~~~ B3["TPAFE5160"] ~~~ B4["SD2506"] ~~~ B5["RS485"] ~~~ B6["UI"]
end
subgraph MW["中间件 (Middlewares/ & Lib/)"]
direction LR
C1["FreeRTOS"] ~~~ C2["FatFs"] ~~~ C3["dhara FTL"] ~~~ C4["LVGL"]
end
subgraph HAL["HAL 层 / CMSIS"]
direction LR
D1["STM32F4xx_HAL_Driver/"] ~~~ D2["CMSIS/"]
end
HW["硬件 (STM32F407ZGTx)"]
APP --> BSP --> MW --> HAL --> HW
更详细的全景架构(六层分层 + 任务与就绪屏障 + 启动时序 + 存储/网络/UI 栈 + 目录组织)见
docs/架构设计/项目架构总览.md。
启动流程
main.c
├─ HAL_Init()
├─ SystemClock_Config() // 168MHz 系统时钟
├─ MX_GPIO/DMA/UART/SPI/I2C/ADC/TIM/IWDG_Init() // CubeMX 外设初始化
├─ app_main_init() // 应用层初始化(时间→RS485→NAND→ADC→采集算法→诊断)
│ ├─ syslog_mcu_init() // 日志先进 RAM 暂存(内核前安全)
│ ├─ sd2506_init() + sys_clock_init() // 时间子系统优先(墙钟基准)
│ ├─ rs485_init()
│ ├─ gd5f2gq5ue_init() // 含 BBT 全片扫描
│ ├─ tpafe5160_init()
│ ├─ adc_input_init() // 语义取数与有效性层(语义映射 + STM32 ADC1 DMA)
│ ├─ phasor_init() / freq_init() / prot_set_init() + prot_elm_init() // 全周傅氏相量/保护判据内核前就绪
│ ├─ SD2506 诊断(ID/时间/温度/电池)
│ └─ HAL_TIM_Base_Start_IT(&htim3) // 启动 TIM3 1kHz 采样节拍
├─ osKernelInitialize()
├─ MX_FREERTOS_Init() // 创建 9 任务 + 事件组 + 消息队列
└─ osKernelStart() // 启动调度器
FreeRTOS 任务
| 任务 | 栈大小 | 优先级 | 职责 |
|---|---|---|---|
| defaultTask | 1280 words | Normal | FTL + FatFS 挂载、配置引擎属主、syslog 唯一写者 |
| netTask | 960 words | Normal | 网络初始化 + CH395F 轮询(消费 NET_RECONFIG 按代次重建监听) |
| ftpTask | 1024 words | Normal | FTP 服务(等待网络+存储就绪) |
| testTask | 2048 words | BelowNormal | 硬件测试入口 |
| uiTask | 4096 words | BelowNormal | LVGL UI 界面 |
| timeSyncTask | 640 words | Normal | 墙钟时间同步 |
| adcTask | 640 words | AboveNormal | TPAFE5160 采样(TIM3 1kHz 事件驱动 + 原子快照 + STM32 ADC DMA,纯消费者) |
| iec104Task | 640 words | Normal | IEC 60870-5-104 上行(工厂默认 :2404 监听,遥信/遥测/定值区) |
| protectTask | 512 words | Normal | 保护判据 20ms 节拍(保护判据元件 + 采样故障闭锁,B5) |
上表与
Src/freertos.c的osThreadAttr_t一致(2026-10-14 校准,9 任务);改动栈大小前先读docs/内存管理/RAM使用分析与优化方案.md的定栈规则与docs/内存管理/RAM预算台账.md的预算项。
任务启动顺序管理
使用 CMSIS-RTOS v2 Event Flags 实现就绪屏障(readiness barrier):
SYS_EVT_NET_READY(bit 0): netTask 置位SYS_EVT_STORAGE_READY(bit 1): defaultTask 置位SYS_EVT_FTP_READY(bit 2): ftpTask 置位(预留)SYS_EVT_TIMESYNC_READY(bit 3): timeSyncTask 置位(预留)
消费者通过 osEventFlagsWait() 阻塞等待,零占用,取代魔法延时和全局变量轮询。
目录结构
每个自建代码目录都有
README.md(说明目录职责、文件清单与改前须知)—— 下表是全局地图,各目录 README 是局部细节。约定见docs/文档规范.md§1.1b。
STM32F4-Base/
├── Src/ # CubeMX 生成的源文件(USER CODE 区域可编辑)
│ ├── main.c # 程序入口
│ ├── freertos.c # FreeRTOS 任务创建
│ ├── gpio.c / dma.c / spi.c / i2c.c / usart.c
│ └── stm32f4xx_hal_msp.c / stm32f4xx_it.c
├── Inc/ # CubeMX 生成的头文件
│ ├── main.h / FreeRTOSConfig.h / stm32f4xx_hal_conf.h
│ └── gpio.h / dma.h / spi.h / i2c.h / usart.h
├── App/ # 应用层代码
│ ├── app/ # 应用入口与全局(app_main / app_cfg / sys_events)
│ ├── algo/ # 采集与算法层(语义取数与有效性 adc_input / 全周傅氏相量 phasor+freq / 保护判据 prot_set+prot_elm)
│ ├── cfg/ # 配置引擎(cfg_file 解析/持久化/迁移 + 存储后端)
│ ├── fs/ # 卷锁(vol_lock,syslog/cfg/lftpd 三条路径 try 语义)
│ ├── sync/ # 时间同步(time_sync 任务)
│ ├── log/ # 日志(sys_log 运行/自检记录、console_log 控制台单写者)
│ ├── task/ # FreeRTOS 任务实现
│ │ ├── default_task.c/h # 存储挂载 + 配置引擎属主 + syslog 写者
│ │ ├── net_task.c/h # 网络任务
│ │ ├── ui_task.c/h # UI 任务
│ │ ├── adc_task.c/h # ADC 任务(语义取数与有效性/全周傅氏相量纯消费者,TIM3 1kHz 唤醒)
│ │ ├── iec104_serv.c/h # IEC 60870-5-104 上行服务
│ │ ├── protect_task.c/h # 保护判据任务(保护判据 20ms 节拍)
│ │ └── rs485_task.c/h # RS-485 任务(已实现,未创建,B2 暂缓)
│ ├── util/ # 工具函数(crc / ringbuf / sys_clock)
│ └── protocol/ # 通信协议(预留)
├── Drivers/
│ ├── BSP/ # 板级驱动(手工编写)
│ │ ├── CH395F/ # 以太网控制器驱动
│ │ ├── GD5F2GQ5UE/ # NAND Flash 驱动 + FTL
│ │ ├── TPAFE5160/ # ADC 驱动
│ │ ├── SD2506/ # RTC 驱动
│ │ ├── RS485/ # RS-485 通信驱动
│ │ ├── NET/ # BSD Socket API 网络抽象层
│ │ │ ├── net_socket.c/h # Socket API
│ │ │ ├── net_events.c/h # 芯片边沿事件处理 + 100ms 周期对账
│ │ │ ├── net_listener.c/h # 监听生命周期(请求登记 + 单一重建执行者)
│ │ │ ├── net_pending.c/h # 阻塞 recv/send 挂起请求表(SEND 二期已落地)
│ │ │ ├── net_select.c/h # select/poll 多路复用
│ │ │ └── lftpd/ # 轻量 FTP 服务器
│ │ ├── NETCFG/ # 网络配置(/config.ini [network] 段加载/保存)
│ │ ├── UI/ # LVGL UI 组件
│ │ └── dbg_log.h / dbg_cfg.h # 调试日志(DBG_INFO 等)
│ ├── STM32F4xx_HAL_Driver/ # ST HAL 库
│ └── CMSIS/ # ARM CMSIS
├── Lib/ # 第三方库
│ ├── dhara/ # NAND FTL 算法
│ ├── FatFs/ # FAT 文件系统
│ └── lvgl/ # 图形库
├── Middlewares/
│ └── Third_Party/FreeRTOS/ # FreeRTOS 内核
├── MDK-ARM/ # Keil 工程
│ ├── STM32F407-Demo.uvprojx # 工程文件
│ ├── *_probe.py # 台架探针(TCP 复连 / FTP 中止等)
│ └── startup_stm32f407xx.s # 启动文件
├── test/ # 测试代码与脚本
│ ├── board/ # 板端测试套件(编入固件)
│ │ ├── test_config.c/h # 套件选择开关(互斥)
│ │ ├── ch395f_test_task.c/h # CH395F 测试
│ │ ├── gd5f_test_task.c/h # NAND Flash 测试
│ │ ├── sd2506_test_task.c/h # RTC 测试
│ │ ├── storage_test_task.c/h # 存储性能测试
│ │ ├── net_test_task.c/h # 网络层测试
│ │ └── net_latency_test.c/h # 链路时延探针
│ └── host/ # 主机端脚本(PC 侧;串口回归入口在 .dsh/skills/serial-boot-test/)
│ ├── ch395f_socket_test.py # Socket 通信测试
│ ├── ftp_test.py / ftp_up_dl_test.py / ftp_regression.py / ftp_integrity_test.py / ftp_capture.py
│ ├── e02_probe.py # 队头阻塞专项探针
│ ├── latency_peer.py # 链路时延 PC 对端
│ └── time_sync_server.py # 时间同步推送服务
├── docs/ # 项目文档(全量索引见 docs/README.md)
│ ├── README.md # 文档索引:目录结构 + 推荐阅读顺序 + 全量清单
│ ├── 任务规划/ # 统一待办登记簿(README 排序权威 + 拆分文件)
│ ├── 架构设计/ # 项目架构总览 / 存储架构 / 启动顺序 / 配图流程 / 引用关系图
│ ├── 子系统设计/ # 配置 / 网络 / 墙钟 / 日志 / 运行自检记录 设计说明
│ ├── 网络/ # BSD Socket API 使用指南 + 内部函数调用关系
│ ├── 测试说明/ # 测试标准流程、各模块测试指南、串口助手、烧录复位
│ ├── 代码规范/ # C 代码规范、pre-commit / cppcheck 使用说明
│ ├── 内存管理/ # RAM 使用分析与优化方案 + 快照数据(data/)
│ ├── 问题记录/ # 各模块 Trap Records、专项审计与项目评审报告
│ ├── 环境与部署/ # 环境搭建与部署核对清单
│ ├── UI设计/ # LVGL UI:架构 / 菜单页面 / 制作流程 / 字体 / 模拟器 / 自动化测试 + mockups
│ ├── 硬件平台/ # 网表分析报告与语义图
│ ├── 芯片手册/ # 外部芯片数据手册(只读资料)
│ └── images/ # 文档技术配图(SVG 产物,脚本生成)
├── scripts/ # pre-commit 本地钩子脚本
│ ├── check_coding_standard.py # 代码规范机械检查
│ └── check_mojibake.py # U+FFFD 乱码检查
├── simulator/ # LVGL PC 模拟器(CMake + SDL2,与 MCU 共用 UI 源码)
│ ├── CMakeLists.txt # 模拟器构建脚本
│ ├── main.c # 模拟器入口(SDL → LVGL → 菜单 → 主循环)
│ ├── sim/ # 平台层(sim_port 显示/输入、net_socket_sim、推流/网口配置 backend)
│ ├── lv_conf.h # LVGL 配置(1bpp + SDL)
│ ├── i1_to_png.py # 截图 I1(1bpp) → PNG 转换工具
│ ├── tests/ # 无头回归脚本 + 黄金参考(菜单像素回归 / 内容页黄金参考)
│ └── SDL2/ # SDL2 2.32.10 预编译库
├── tools/ # 开发工具
│ └── font_gen/ # 中文字体生成工具
├── ui_cn_chars.txt # 中文字体字符集
├── requirements.txt # Python 依赖清单(统一 .venv 环境,见 AGENTS.md「Python 环境」)
├── STM32F407-Demo.ioc # CubeMX 工程文件
├── .pre-commit-config.yaml # pre-commit 钩子配置
├── .gitlint # commit message 检查规则
├── .dsh/skills/ # DSH 项目级 skill(编译/烧录/串口采集/闭环 + 流程类)
├── .serialtest/ # 串口测试档案(串口端口单一配置源 + 烧录/标记参数)
└── AGENTS.md # AI 开发规范
构建系统
环境要求
- Keil MDK-ARM v5 (ARMCC 编译器)
- Python 3(统一入口为仓库内
.venv,依赖见requirements.txt,重建方法见 AGENTS.md「Python 环境」) - ST-Link 或兼容调试器
编译
# 方式一:命令行编译(推荐;= keil-build skill)
& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py
# 方式二:Keil IDE
# 打开 MDK-ARM\STM32F407-Demo.uvprojx → Build (F7)
退出码:0 = 成功 | 1 = 有警告 | 2+ = 错误
编译日志:MDK-ARM/build_log.txt
烧录
& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py flash
LVGL PC 模拟器
PC 端 UI 开发调试(无需烧录 MCU,与 MCU 共用 Drivers/BSP/UI/ 源码),详见 docs/UI设计/LVGL模拟器部署与使用说明.md:
& "simulator\build_sim.bat" # 一键构建(自动探测本机 VS2019/2022/2026 生成器)
# 运行 simulator\build\Debug\lvgl_sim.exe
UI 改动回归门禁(菜单像素回归 + 内容页黄金参考 + 池水位校验):
.venv\Scripts\python.exe simulator/tests/check_menu_rows.py
.venv\Scripts\python.exe simulator/tests/check_content_pages.py
详见 docs/UI设计/UI_自动化测试流程.md。
驱动开发指南
CH395F 以太网
- 单连接模式:Socket 0 复用监听和数据通道
- 中断统一处理:所有中断在
net_poll()中通过GET_GLOB_INT_STATUS集中读取清除 - SPI 事务必须用
ch395f_spi_begin()/ch395f_spi_end()包裹 - SPI 分频系数必须为 8(PCB 设计限制)
GD5F2GQ5UE NAND Flash
- 三层软件栈:FatFS → dhara FTL → NAND 驱动
- FTL 提供 LBA 映射、磨损均衡、坏块管理、垃圾回收
- 物理分区:全部 2048 块用于 FTL + FatFS
网络层 (NET)
- BSD Socket API 抽象:
net_socket.h/c - 事件处理与周期对账:
net_events.c(芯片边沿事件 + 100ms 对账,net_poll()内分派) - 监听生命周期单一所有者:
net_listener.c(net_listener_request只登记意图、net_listener_tick唯一执行) - 阻塞挂起请求表:
net_pending.c(recv 一期 / SEND 二期已落地;调用方铁律sent < len) - select/poll I/O 多路复用:
net_select.h/c - 线程安全通过消息队列(
netMsgQueue)实现 - 所有 CH395F 操作在 netTask 中串行处理
- 网口配置保存后经
SYS_EVT_NET_RECONFIG按网络代次号重建监听(新 IP 免重启生效)
时间子系统
- SD2506 RTC 提供初始时间
- sys_clock 将 RTC 时间转为 Unix epoch 墙钟基准
- timeSyncTask 通过 TCP 同步墙钟时间
自动化测试
启动测试
# 一键测试:串口捕获 → 烧录 → 日志校验(2026-09-20 起为纯 Python 标准库实现)
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py
退出码:0 = PASS | 1 = FAIL | 2 = 错误
测试模块
| 模块 | 测试文件 | 说明 |
|---|---|---|
| CH395F 硬件 | ch395f_test_task.c |
SPI 通信、寄存器读写 |
| NAND Flash | gd5f_test_task.c |
页读写、块擦除、ECC |
| 网络层 | net_test_task.c |
BSD Socket、TCP/UDP |
| RTC | sd2506_test_task.c |
时间读写、温度、电池 |
| 存储性能 | storage_test_task.c |
FTL/FatFS 读写速度 |
主机端测试脚本(Python)
| 脚本 | 说明 |
|---|---|
ch395f_socket_test.py |
Socket 通信测试 |
ftp_test.py |
FTP 服务器基础测试 |
ftp_up_dl_test.py |
FTP 上传/下载测试 |
ftp_regression.py |
FTP 功能回归(会话流程全序列) |
ftp_integrity_test.py |
FTP 传输完整性压测(多轮 SHA-256 校验) |
ftp_capture.py |
FTP 流量抓取 |
time_sync_server.py |
时间同步推送服务(PC → 板子) |
串口调试
通过仓库内置 Python 串口助手(.dsh/skills/serial-assistant/)自主读取 USART1 串口打印:
- 端口配置:
.serialtest/config.json(单一配置源) - 用法详见
docs/测试说明/测试工具/串口助手使用指南.md,设计见docs/测试说明/测试工具/串口助手设计说明.md
开发规范
源码编辑安全
铁律:绝不用 Get-Content / Set-Content / cmd 重写含中文的源码文件,会导致不可逆乱码。
- 改代码只用 Edit 工具(精确子串替换)
- 发现乱码先评估能否用 Edit 修复,不要急着
git checkout
CubeMX 生成文件
Inc/和Src/中的文件带有USER CODE BEGIN/END标记- 自定义代码必须写在这些区域之间
Drivers/BSP/下的驱动文件为纯手工代码,不受 CubeMX 保护
编译验证
所有代码修改后必须编译通过(0 错误 0 警告)才能提交。
新增文件
新文件需手动添加到 Keil MDK 工程才能编译。
自动化代码审查(pre-commit)
每次 git commit 自动执行检查,任一失败即拦截提交:
- 行尾空格 / 文件尾换行(自动修复)
- 大文件 / 冲突标记 / YAML 语法(拦截)
- cppcheck 静态分析:warning / performance / portability / style 四类,发现问题即拦截
- 代码规范检查:头文件保护宏、命名(宏大写/
_t后缀)、函数注释、default 分支、禁用 strcpy/sprintf/goto/Tab 等(规范 V1.0 可机械校验项) - U+FFFD 乱码(拦截,不可逆损坏)
- commit message 格式(gitlint,拦截)
本地钩子脚本:scripts/check_coding_standard.py、scripts/check_mojibake.py(由 .pre-commit-config.yaml 引用)。
# 新机器启用钩子
pre-commit install
# 全库扫描(配置变更后验证)
pre-commit run --all-files
详见 docs/代码规范/pre-commit使用说明.md 与 docs/代码规范/cppcheck使用说明.md。
关键文件索引
| 文件 | 说明 |
|---|---|
Src/main.c |
程序入口,CubeMX 生成 + USER CODE 区域 |
Src/freertos.c |
FreeRTOS 任务创建 |
App/app/app_main.c |
应用初始化流程编排 |
App/task/net_task.c |
网络任务主循环 |
App/app/sys_events.h |
系统就绪事件定义 |
App/app/app_cfg.h |
功能裁剪的决策占位说明(当前无宏;原未接线占位开关 2026-10-22 已删) |
Drivers/BSP/CH395F/ch395f.c |
以太网控制器驱动 |
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c |
NAND Flash 驱动 |
Drivers/BSP/NET/net_socket.c |
BSD Socket API |
Drivers/BSP/NET/net_events.c |
芯片边沿事件处理 + 周期对账 |
Drivers/BSP/NET/net_listener.c |
监听生命周期(单一重建所有者) |
App/algo/prot_elm.h |
保护判据元件框架(判据消费入口) |
.dsh/skills/keil-build/scripts/keil_build.py |
编译脚本(/keil-build) |
.dsh/skills/serial-boot-test/scripts/run_boot_test.py |
自动化测试脚本 |
已知问题
详见 docs/问题记录/ 目录:
CH395F_Trap_Records.md— 以太网控制器已知陷阱GD5F2GQ5UE_Trap_Records.md— NAND Flash 已知陷阱SD2506_Trap_Records.md— RTC 已知陷阱
文档
📚 全量文档索引见
docs/README.md(目录结构 + 推荐阅读顺序 + 按角色导航)。
| 文档 | 说明 |
|---|---|
docs/README.md |
文档索引(全量清单 + 阅读顺序 + 新增文档约定) |
docs/架构设计/项目架构总览.md |
项目全景架构(六层分层 + 任务/就绪屏障 + 启动时序 + 存储/网络/UI 栈 + 目录组织) |
docs/环境与部署/项目部署环境要求.md |
部署环境要求(开发机 / 目标板 / 网络与现场 / 远端客户端)+ 分步安装命令 + 下载来源速查 + 验收清单 |
docs/架构设计/STM32F4-Base存储架构说明.md |
三层存储软件栈详解(FatFS → dhara FTL → NAND) |
docs/架构设计/项目启动顺序管理.md |
Event Flags 就绪屏障设计 |
docs/子系统设计/系统墙钟时间维护说明.md |
RTC + 墙钟时间子系统 |
docs/子系统设计/网络配置说明.md |
网口设置页配置(UI 可改的 IP/掩码/网关/MAC:持久化 + 立即生效 + 页面操作) |
docs/网络/BSD_Socket_API_使用指南.md |
BSD Socket API 使用指南(net_socket / net_select:线程安全 / 快速开始 / TCP / UDP / I/O 多路复用 / 事件回调 / API 参考 / 常见问题) |
docs/网络/Net层阻塞模型架构设计.md |
NET 阻塞模型(挂起请求表五路语义,recv 一期 / SEND 二期已落地) |
docs/网络/网络自愈架构设计.md |
网络自愈架构(监听重建 / 沉降隔离 / 周期对账) |
docs/子系统设计/IEC104上行设计说明.md |
IEC 60870-5-104 上行(:2404 监听,B4) |
docs/子系统设计/ADC采样节拍设计说明.md |
TIM3 1kHz 采样节拍(两片转换器同源硬件驱动) |
docs/UI设计/UI_设计架构.md |
LVGL UI 系统架构(菜单 / 内容页 / 内存预算) |
docs/UI设计/菜单页面设计.md |
菜单导航行为、数据流与内容页设计 |
docs/UI设计/UI_界面制作流程.md |
参考图 → 设计规格 → LVGL 代码管线(P0~P4 门禁) |
docs/UI设计/UI_中文字体生成与配置.md |
中文字体生成与配置 |
docs/UI设计/LVGL模拟器部署与使用说明.md |
LVGL PC 模拟器部署 |
docs/UI设计/UI_自动化测试流程.md |
UI 回归门禁(脚本 + 池水位常量 + 黄金参考更新) |
docs/代码规范/嵌入式C语言代码规范_V1.0.md |
C 语言代码规范 |
docs/代码规范/pre-commit使用说明.md |
自动化代码审查部署与使用 |
docs/代码规范/cppcheck使用说明.md |
cppcheck 规则、配置与误报抑制 |
docs/测试说明/流程与规范/自动化测试流程.md |
构建 → 烧录 → 串口校验闭环 |
docs/测试说明/ |
各模块测试指南(CH395F / NAND / FTP / RTC / 串口调试) |
docs/测试说明/流程与规范/测试开发标准流程.md / docs/测试说明/流程与规范/测试文档模板规范.md |
测试开发流程与文档模板 |
docs/问题记录/ |
已知陷阱与解决方案(CH395F / NAND / RTC) |
docs/芯片手册/ |
硬件数据手册 |
许可证
本项目为私有项目,未经授权不得分发。