From fea4cc7502d27f4a8fb9ad1eeec6ac6e78128f9a Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Fri, 30 Oct 2026 06:53:07 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E6=9E=B6=E6=9E=84):=20=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E6=80=BB=E8=A7=88=E5=85=A8=E5=B1=80=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E2=80=94=E2=80=94=E5=90=8C=E6=AD=A5=E5=BD=95=E6=B3=A2?= =?UTF-8?q?/SOE/=E5=B1=8F=E6=9D=BF=E5=B9=B6=E8=AE=A2=E6=AD=A3=E4=B8=B2?= =?UTF-8?q?=E5=8F=A3=E5=BD=92=E5=B1=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v1.1(2026-10-14)之后主干前进 59 笔,本总览积累系统性偏差,通读全文后 全局更新(含配图生成器数据同步): - 串口三分定态:USART1=屏板链路 700 kbaud、UART4=RS-485(B2 未接线)、 UART5=控制台日志 115200(console_log CON_UART=huart5 实证; 旧文把 USART1 标成调试口是屏板批 0 迁移前的口径) - 采集主线补齐:adc_cal 标定折算、meas 200ms 遥测快照(adcTask 唯一 发布者,104 与 UI 共用同一份上游)、录波环三任务交接(adcTask 写入 冻结 / defaultTask 游标落 /wave / uiTask 单通道回放 / FTP 取回) - SOE 事件记录链路入图:protectTask 动作/复归边沿投递(纯 RAM 队列) → defaultTask 经 syslog_drain 尾部落 /log/soe.log(64B 定长) - 配置从 [network] 单段改五段注册制(+ftp/adc_cal/run_par/comm), 另有 /prot_set.bin(B7 原子写) - UI 一节按注册表驱动重写:菜单树 61 行、16 个 #P 受保护叶、26 个 #page 绑定、ui_data 三帧契约(写侧唯一填充 ui_data_feed)、录波 两页、显存一份三出(屏板主出口/:7003 镜像/模拟器) - §2.1 任务表按 freertos.c 现值逐行核对;protectTask 如实标注 「未标定闭锁」现状(产品 required_mask 0x1F7) - 配图:gen_arch_svg.py 顶部数据(层芯片/串口/删悬空图脚注)重跑, 脚本与产物同一笔提交;check_generated_fresh.py 按「只减不增、 还清即删整条」把本次还清的 项目架构总览.svg 基线下架(留出处注) 验证:check_doc_links --all --sections-strict 通过;scripts/ci_local.py 全绿;generated-fresh 单跑 rc=0(无 DIFF/NEW);SVG 无头渲染回读目检 两轮(首轮揪出悬空图脚注);md 无 BOM/CR/U+FFFD;#P 计数剔注释行复核。 --- docs/images/项目架构总览.svg | 200 ++++++++++++++------------ docs/架构设计/项目架构总览.md | 218 ++++++++++++++++++----------- scripts/check_generated_fresh.py | 4 +- tools/arch_diagram/gen_arch_svg.py | 30 ++-- 4 files changed, 267 insertions(+), 185 deletions(-) diff --git a/docs/images/项目架构总览.svg b/docs/images/项目架构总览.svg index 752cf89c..002d4d7a 100644 --- a/docs/images/项目架构总览.svg +++ b/docs/images/项目架构总览.svg @@ -1,111 +1,131 @@ - - + + STM32F4-Base 项目分层架构 STM32F407ZGTx @168MHz · FreeRTOS V10.3.1 (CMSIS-RTOS2) · 上层只依赖相邻下层 ① 业务层 顶层共享配置 · 被 UI 与基础服务共用 - -net_cfg(网口配置:IP/掩码/网关/MAC + Flash 持久化) - + +net_cfg(网口配置:IP/掩码/网关/MAC · /config.ini [network] 段) + ② UI 层 -Drivers/BSP/UI · 与 PC 模拟器共用 +Drivers/BSP/UI · 一份显存三出(模拟器/屏板/远程) ui_port(显示端口) ui_menu / ui_menu_view(级联菜单) - -ui_menu_tab(菜单表) + +ui_menu_tab(菜单树生成物) ui_content_page(内容页框架) - -ui_page_*(5 页插件) - -ui_net_sink(远程显示 :7003) - -ui_font_cn_12(中文字体) - -ui_deco(浅 V 装饰) - + +ui_page_registry(页面注册表 · 生成物) + +ui_page_*(20+ 页插件) + +ui_data(数据供给契约) + +ui_net_sink(远程显示 :7003) + +ui_standby(待机屏) + +ui_font_cn_12(中文字体) + +ui_deco(浅 V 装饰) + ③ 基础服务层 应用侧服务 / 编排 app_main(启动编排) sys_events(就绪屏障) - -app_cfg(编译开关) - -task/(net · ui · adc* · rs485*) - -lftpd(FTP :21) - -time_sync(TCP 对时 :8888) - -④ 中间件层 -通用库 / 协议栈 - -net_socket / net_select(BSD API) - -FatFs(文件系统) - -nand_ftl(dhara FTL) - -LVGL v9.2(图形库) - -sys_clock(墙钟基准) - -util(crc · ringbuf) - -⑤ 驱动层 -Drivers/BSP · 芯片时序/中断 - -ch395f(SPI2 + DMA) - -gd5f2gq5ue(SPI1) - -tpafe5160(并行 16 位) - -sd2506(I2C1) - -rs485(UART5 + DE) - -⑥ 内核 / HAL -调度 · 外设抽象 - -FreeRTOS V10.3.1(CMSIS-RTOS2 · heap_4) - -STM32 HAL(时基 TIM7) - -CMSIS / 启动文件 - -⑦ 硬件 -STM32F407ZGTx @168MHz - -CH395F 以太网(SPI2) - -GD5F2GQ5UE NAND(SPI1) - -TPAFE5160 ADC(并行) - -SD2506 RTC(I2C1) - -RS-485(UART5) - -USART1 调试(115200) - -6x LED + +task/(9 任务) + +algo/(语义取数与有效性~保护判据 · 遥测快照 · 录波数据面) + +protocol/iec104(104 上行 :2404) + +ui_data_feed(App→UI 装配) + +sys_log · soe(记录引擎) + +console_log(UART5 控制台单写者) + +cfg_file · prot_set_store(配置引擎) + +lftpd(FTP :21) + +time_sync(TCP 对时 :8888) + +④ 中间件层 +通用库 / 协议栈 + +net_socket / net_select / net_events / net_listener / net_pending(BSD API + 阻塞模型) + +FatFs(文件系统) + +nand_ftl(dhara FTL) + +LVGL v9.2(图形库) + +sys_clock(墙钟基准) + +task_watchdog(IWDG 判定) + +⑤ 驱动层 +Drivers/BSP · 芯片时序/中断 + +ch395f(SPI2 + DMA) + +gd5f2gq5ue(SPI1) + +tpafe5160(并行 16 位) + +sd2506(I2C1) + +rs485(UART4 + DE) + +sb_link · sb_proto(屏板链路 · USART1 700 kbaud) + +⑥ 内核 / HAL +调度 · 外设抽象 + +FreeRTOS V10.3.1(CMSIS-RTOS2 · heap_4) + +STM32 HAL(时基 TIM7) + +CMSIS / 启动文件 + +⑦ 硬件 +STM32F407ZGTx @168MHz + +CH395F 以太网(SPI2) + +GD5F2GQ5UE NAND(SPI1) + +TPAFE5160 ADC(并行) + +SD2506 RTC(I2C1) + +RS-485(UART4 · 未接线) + +屏板(USART1 · 700 kbaud) + +RS232#1 日志(UART5 · 115200) + +6x LED - - - - - - - - - - -上层只依赖相邻下层(单向);UI 层与基础服务层同级并列,均使用顶层 net_cfg。跨层调用细节见 docs/项目架构总览.md §1.2 * 预留未接入调度 + + + + + + + + + + +上层只依赖相邻下层(单向);UI 层与基础服务层同级并列,均使用顶层 net_cfg。跨层调用细节见 docs/架构设计/项目架构总览.md §1.2 diff --git a/docs/架构设计/项目架构总览.md b/docs/架构设计/项目架构总览.md index 4d909dfd..01935760 100644 --- a/docs/架构设计/项目架构总览.md +++ b/docs/架构设计/项目架构总览.md @@ -1,8 +1,8 @@ # STM32F4-Base 项目架构总览 -> 版本:v1.1 日期:2026-10-14 +> 版本:v1.2 日期:2026-10-30 > 平台:STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2)+ FreeRTOS V10.3.1(CMSIS-RTOS2) -> 用途:一页看清项目的分层、任务、数据流与目录组织。细节以各模块专项文档为准(见 §9)。 +> 用途:一页看清项目的分层、任务、数据流与目录组织。现状能力与功能缺口的权威口径在 AGENTS.md「项目概况」,细节以各模块专项文档为准(见 §9)。 --- @@ -10,10 +10,10 @@ ![STM32F4-Base 项目分层架构](../images/项目架构总览.svg) -> 上图由 `tools/arch_diagram/gen_arch_svg.py` 生成(**手绘 SVG**,布局确定、零连线交叉);改架构后编辑脚本顶部 `ROWS` 数据重跑即可,源数据与 §1.1 表一致。 +> 上图由 `tools/arch_diagram/gen_arch_svg.py` 生成(**手绘 SVG**,布局确定、零连线交叉);改架构后编辑脚本顶部 `L_*` / `ROWS` 数据重跑即可,源数据与 §1.1 表一致(脚本与产物同一笔提交,`generated-fresh` 门禁逐字节幂等)。 > 需要 PNG 预览(PPT/聊天分享):用 Edge 无头渲染 `docs/images/项目架构总览.svg` 即可(PNG 不入库)。 -> 分层原则:**上层只依赖相邻下层(单向)**——2026-10-22 起这条方向已有机械检查(`layer-deps` 钩子 / `scripts/check_layer_deps.py`:`Drivers/BSP/**` 不得 include `App/**` 的头,存量 6 条反向边钉成基线、只减不增,三个横切叶子头 `console_log.h`/`sys_clock.h`/`sha256.h` 显式豁免);**① 业务层为顶层**(仅 `net_cfg`,被 UI 与基础服务共用),**② UI 层与 ③ 基础服务层同级并列**。跨层的具体调用关系见 §1.2 表。 +> 分层原则:**上层只依赖相邻下层(单向)**——这条方向已有机械检查(`layer-deps` 钩子 / `scripts/check_layer_deps.py`:`Drivers/BSP/**` 不得 include `App/**` 的头,存量 3 条反向边钉成基线、只减不增,三个横切叶子头 `console_log.h`/`sys_clock.h`/`sha256.h` 显式豁免);**① 业务层为顶层**(仅 `net_cfg`,被 UI 与基础服务共用),**② UI 层与 ③ 基础服务层同级并列**。跨层的具体调用关系见 §1.2 表。 ### 1.1 各层职责与关键模块 @@ -21,13 +21,13 @@ | 层 | 目录 | 职责 | 关键模块 | |---|---|---|---| -| ① 业务层 | `Drivers/BSP/NETCFG/` | 顶层共享配置(被 UI 与基础服务共用) | `net_cfg` | -| ② UI 层 | `Drivers/BSP/UI/` | LVGL 界面(与 PC 模拟器共用源码) | `ui_port` `ui_menu` `ui_menu_view` `ui_menu_tab` `ui_content_page` `ui_page_*` `ui_net_sink` `ui_font_cn_12` `ui_deco` | -| ③ 基础服务层 | `App/`、`Drivers/BSP/NET/lftpd/` | 应用侧服务与编排 | `app_main` `sys_events` `app_cfg` `task/*` `algo/*`(语义取数与有效性~保护判据) `lftpd` `time_sync` | -| ④ 中间件层 | `Drivers/BSP/NET/`、`Lib/`、`App/util/` | 通用库 / 协议栈 | `net_socket` `net_select` `net_events` `net_pending` `net_listener` `FatFs` `nand_ftl(dhara)` `LVGL` `sys_clock` | -| ⑤ 驱动层 | `Drivers/BSP/{CH395F,GD5F2GQ5UE,TPAFE5160,SD2506,RS485}/` | 芯片寄存器 / 时序 / 中断 | `ch395f` `gd5f2gq5ue` `tpafe5160` `sd2506` `rs485` | +| ① 业务层 | `Drivers/BSP/NETCFG/` | 顶层共享配置(被 UI 与基础服务共用) | `net_cfg`(`/config.ini` `[network]` 段) | +| ② UI 层 | `Drivers/BSP/UI/` | LVGL 160×160 单色界面(与 PC 模拟器、屏板、远程显示**共用同一份显存**) | `ui_port` `ui_menu` `ui_menu_view` `ui_menu_tab`(生成物) `ui_content_page` `ui_page_registry`(生成物) `ui_page_*`(20+ 页插件) `ui_data`(数据供给发布 API) `ui_net_sink` `ui_standby` `ui_font_cn_12` `ui_deco` | +| ③ 基础服务层 | `App/`、`Drivers/BSP/NET/lftpd/` | 应用侧服务与编排 | `app_main` `sys_events` `ui_data_feed` `task/*`(9 任务) `algo/*`(语义取数与有效性~保护判据 + 遥测快照 + 录波数据面 + 屏板灯位映射) `protocol/iec104` `sys_log`·`soe_*`·`console_log` `cfg_file`·`prot_set_store` `vol_lock` `time_sync` `lftpd` | +| ④ 中间件层 | `Drivers/BSP/NET/`、`Lib/`、`App/util/` | 通用库 / 协议栈 | `net_socket` `net_select` `net_events` `net_listener` `net_pending` `FatFs` `nand_ftl(dhara)` `LVGL v9.2` `sys_clock` `task_watchdog` | +| ⑤ 驱动层 | `Drivers/BSP/{CH395F,GD5F2GQ5UE,TPAFE5160,SD2506,RS485,ScreenLink}/` | 芯片寄存器 / 时序 / 中断 | `ch395f` `gd5f2gq5ue` `tpafe5160` `sd2506` `rs485` `sb_link`·`sb_proto` | | ⑥ 内核 / HAL | `Middlewares/`、`Drivers/STM32F4xx_HAL_Driver/`、`Drivers/CMSIS/` | 任务调度、外设 HAL、启动 | FreeRTOS V10.3.1 · STM32 HAL · CMSIS | -| ⑦ 硬件 | — | STM32F407ZGTx @168MHz | SPI1 / SPI2 / I2C1 / UART4 / USART1 / ADC1 / TIM3 / DMA / GPIO | +| ⑦ 硬件 | — | STM32F407ZGTx @168MHz | SPI1 / SPI2 / I2C1 / UART4 / UART5 / USART1 / ADC1 / TIM3 / DMA / GPIO | ### 1.2 关键跨层依赖(对应上图未画出的连线) @@ -36,14 +36,20 @@ | `ui_page_net_cfg` → `net_cfg` | 网口设置页显示/编辑 RAM 副本(不直接触 CH395F SPI) | | `netTask` → `net_cfg` → `net_socket` | 上电只读 RAM 副本(defaultTask 已在屏障前 `net_cfg_load`)→ `net_init(ip,mask,gw,mac)`;配置保存后经 `SYS_EVT_NET_RECONFIG` 按**网络代次号**重建(新 IP 免重启生效) | | `net_socket` → `net_events` / `net_listener` / `net_pending` | socket 宿主调三个内部模块:芯片边沿事件 + 100ms 周期对账 / 监听生命周期(重建请求登记 + 唯一执行)/ 阻塞 recv·send 挂起请求表 | -| `App/algo/*`(语义取数与有效性→全周傅氏相量→保护判据) → `adc_task` / `protect_task` | 采集与算法层为纯计算:adcTask 消费 语义取数与有效性/全周傅氏相量(TIM3 1kHz 节拍)、protectTask 消费 保护判据(20ms 判据节拍) | -| `lftpd` / `net_cfg` / 测试 → `FatFs` → `nand_ftl` → `gd5f2gq5ue` | 文件与配置落 NAND | -| `ui_net_sink` / `time_sync` → `net_socket` | 远程显示 :7003 / 对时 :8888 共用同一 TCP 栈 | -| `ui_menu` → `ui_content_page` → `ui_page_*` | 框架 + 页面插件(描述符解耦) | +| `App/algo/*` → `adc_task` / `protect_task` | 采集与算法层为纯计算:adcTask 消费 语义取数与有效性/标定折算/全周傅氏相量/测频/录波环(TIM3 1kHz 节拍)并发布遥测快照,protectTask 消费 保护判据(20ms 判据节拍) | +| `App/algo/meas`·`prot_elm` → `iec104_pts` | 104 遥测 = 遥测快照 `meas_get()`(双区无锁、带品质、频率点绑定),遥信 = `prot_elm` 元件状态位图;点表与 `[comm]`/`[run_par]` 配置(运行参数段的 104 地址映射为真源) | +| `App/app/ui_data_feed` → `Drivers/BSP/UI/ui_data` | UI 数据通道的写/读两侧:装配层按节拍从 采集/算法/保护/协议/时钟 取数组三帧(实时量 rt / 参数 par / 装置信息 info),经 `ui_data.h` 发布 API 供页面只读;`ui_data_feed` 是快照唯一填充者(装配层可同时 include 两侧头,方向仍是上层→下层,`check_layer_deps.py` 只拦反向) | +| `uiTask` → `ScreenLink`(`sb_link`) | uiTask 10ms 节拍驱动:`sb_link_frame_update()` 活显存 memcmp 判变组帧 B(4208 B)、`sb_link_key_take()` 出队屏板按键、`sb_link_poll()` 离线判定(≥10s 无召唤);灯位映射在 `App/algo/sb_led_map`(104 RUN 观测口)。⚠ HAL 三个 UART 回调(`RxEvent`/`Error`/`TxCplt`)的**唯一实现处在 `rs485.c`**、逐行转发 `sb_link`——改任一 UART 回调必须两边一起看 | +| 录波链路(三任务交接) | adcTask `wave_ring_push()/tick()`(与相量主线同拍**并行**、互不阻塞)→ 触发冻结、后触发计满封段 → defaultTask 见 `wave_ring_sealed()` 游标分次搬进 `/wave` → uiTask 单通道回放页;落盘回执才解冻。取回 = FTP :21 | +| SOE 链路 | protectTask 动作/复归边沿 `soe_store_post()`(纯 RAM:取时标 + 组 64B 记录 + 队列,**零文件系统**)→ defaultTask(`/log` 唯一写者,`syslog_drain` 尾部挂接)落 `/log/soe.log` | +| `lftpd` / `net_cfg` / 测试 → `FatFs` → `nand_ftl` → `gd5f2gq5ue` | 文件、配置、录波段与 SOE 落 NAND | +| `ui_net_sink` / `time_sync` → `net_socket` | 远程显示 :7003 / 对时 :8888 共用同一 TCP 栈;屏板链路走 USART1 串口(不经 TCP),与 :7003 是同一份显存的两个出口(**串口为主**) | +| `ui_menu` → `ui_content_page` → `ui_page_*` | 框架 + 页面插件(描述符解耦;节点→页面绑定由注册表 `ui_page_registry.c` 生成,见 §6) | | `time_sync` / `sys_clock` → `sd2506` | 墙钟基准与写回 RTC | -| `ui_port` / `ui_page_*` → `LVGL` | UI 全部绘制走 LVGL | +| `ui_port` / `ui_page_*` → `LVGL` | UI 全部绘制走 LVGL(1bpp 离屏渲染到内存帧缓冲) | > `*` `rs485_task.c` 任务体已实现,但**当前未在 `freertos.c` 创建**(B2 暂缓,见 `docs/任务规划/暂缓-RS485.md`);`adc_task.c` 已于 2026-10-10 接入创建(`adcTask`)。 +> 串口三分(2026-10-29 屏板批 0 后的定态):**USART1 = 屏板链路 700 kbaud**、**UART4 = RS-485(115200,未接线)**、**UART5 = 控制台日志 115200**——日志口原在 USART1,屏板占用后迁至 UART5(RS232#1 台架线改接日志口)。 --- @@ -53,20 +59,18 @@ | 任务 | 栈 (字节) | 优先级 | 职责 | 入口 | |---|---|---|---|---| -| `defaultTask` | 5120 | Normal | FatFS 挂载(无卷 `f_mkfs`)→ 卷健康探针/自愈 → `net_cfg_load`(配置引擎属主)→ 置 `STORAGE_READY`(= 存储+配置就绪)→ 日志落盘(唯一写者,`syslog_drain`)+ 配置保存执行/2s poll + LED 闪烁 + **栈水位观测**(`stack_probe_poll`:首次 5s 后报告,此后仅在出现更深峰值时打印) | `StartDefaultTask` | +| `defaultTask` | 5120 | Normal | FatFS 挂载(无卷 `f_mkfs`)→ 卷健康探针/自愈 → `net_cfg_load`(配置引擎属主)→ 置 `STORAGE_READY`(= 存储+配置就绪)→ **`/log` 唯一写者**(`syslog_drain` 尾部统一排空 syslog / SOE 两条队列 → run/selftest/soe 三本日志 + 控制台排空)+ **录波落盘道**(已封存段游标分次搬 `/wave`,轮转号启动扫盘重建)+ 配置保存执行/2s poll + LED 闪烁 + **栈水位观测**(`stack_probe_poll`) | `StartDefaultTask` | | `netTask` | 3840 | Normal | 等存储(配置已由 defaultTask 就绪,本任务只读 RAM 副本)→ `net_stack_bring_up()`(不触碰配置文件引擎)→ 置 `NET_READY` → 循环 `net_poll` + `net_process_messages`;消费 `SYS_EVT_NET_RECONFIG` → 按网络代次号重建监听(CH395F 硬件层测试模式下入口自挂起) | `StartNetTask` | -| `ftpTask` | 4096 | Normal | 等网络**且**存储(`WaitAll`)→ `lftpd_start("/", 21)` → 单客户端会话循环(断开后经 `net_listener` 重建监听) | `StartFtpTask` | +| `ftpTask` | 4096 | Normal | 等网络**且**存储(`WaitAll`)→ `lftpd_start("/", 21)` → 单客户端会话循环(断开后经 `net_listener` 重建监听);录波段文件的取回通道 | `StartFtpTask` | | `testTask` | 8192 | BelowNormal | 测试套件入口(`test/board/test_config.h` 选择)。**产品构建不创建**:CubeMX 生成区无条件建后,`MX_FREERTOS_Init()` 在未选套件时(`!TEST_SUITE_SELECTED`)立即 `vTaskDelete` 回收其 8KB CCM 栈(2026-10-04) | `start_test_task` | -| `uiTask` | 16384 | BelowNormal | 等网络 → `ui_port_init`/`ui_menu_init`/`ui_standby_init`(空闲 60s 切待机屏)/`ui_net_sink` → 10ms 刷新 | `ui_task_func` | +| `uiTask` | 16384 | BelowNormal | 等网络 → `ui_port_init`/`ui_menu_init`/`ui_standby_init`(空闲 60s 切待机屏)/`ui_net_sink` → 10ms 刷新:`ui_data_feed_tick()` 三帧装配 + 屏板链路驱动(组帧 B / 出键 / 离线判定 / 状态灯位)+ 录波回放页 | `ui_task_func` | | `timeSyncTask` | 2560 | Normal | 等网络 → TCP :8888 收 PC 推送时间 → 写 RTC | `time_sync_task` | -| `adcTask` | 2560 | AboveNormal | 纯消费者:`osThreadFlagsWait` 等 TIM3 1kHz 唤醒(ISR 内 `adc_tick_irq_notify` 置位)→ `adc_input_poll()`(TPAFE 原子快照 + STM32 ADC1 DMA 双缓冲)→ 语义取数与有效性/全周傅氏相量消费,不取数不做保护运算 | `adc_task_func` | -| `iec104Task` | 2560 | Normal | 等网络 → IEC 60870-5-104 上行(:2404 监听 + link 状态机,遥信/遥测/定值区,B4) | `iec104_serv_task` | -| `protectTask` | 2048 | Normal | 保护判据 20ms 节拍:`prot_elm_run()` + 「自检失败闭锁」采样故障闭锁 + 定值校验和巡检(B5);不依赖网络,纳入 IWDG `required_mask` | `protect_task` | +| `adcTask` | 2560 | AboveNormal | 纯消费者 + **唯一发布者**:`osThreadFlagsWait` 等 TIM3 1kHz 唤醒(ISR 内 `adc_tick_irq_notify` 置位)→ `adc_input_poll()`(TPAFE 原子快照 + STM32 ADC1 DMA 双缓冲)→ 标定折算 → 相量 → 测频;录波支路 `wave_ring_push()/tick()`;**每 200ms `meas_tick()` 发布遥测快照**(双区无锁,104 与 UI 共用同一份上游) | `adc_task_func` | +| `iec104Task` | 2560 | Normal | 等网络 → IEC 60870-5-104 上行(:2404 监听 + link 状态机;遥测读 meas 快照、遥信读 `prot_elm` 元件态,COV 死区/变位上送;`[comm]`/`[run_par]` 配置;B4/批 2)。任何构建都创建,纳入 IWDG `required_mask` | `iec104_serv_task` | +| `protectTask` | 2048 | Normal | 保护判据 20ms 节拍:`prot_elm_run()` + 「自检失败闭锁」采样故障闭锁 + 定值校验和巡检 + 动作/复归边沿 SOE 投递(B5);⚠ **当前处于「未标定闭锁」态**——`adc_cal_flags()` 无 VALID 时判据停走,两点标定写入 `[adc_cal]` 后自动解卡(用户裁定 2026-10-25:保持闭锁,不用万用表走捷径);纳入 IWDG `required_mask`(产品 `0x1F7`) | `protect_task` | -> `idle`(128 words)/ `timer`(256 words)由 FreeRTOS 内核创建。所有任务栈从 FreeRTOS `heap_4` 堆分配(**已迁 CCM**,2026-10-12 扩容至 56 KB,见 `docs/内存管理/RAM使用分析与优化方案.md` §4.1.2/§2.3)。 -> **栈实测与预算**(2026-10-10~14,工具 `scripts/stack_report.py` = Keil 静态调用图 + 串口 `[STACK]` 水位;详见 `docs/内存管理/RAM使用分析与优化方案.md` §4.0.6/§2.3): -> defaultTask 实测峰值 **2152B/5120B(余 41%)**、静态最坏链 3016B;netTask 实测峰 **1116~1164B/3840B**(开机~FTP 传输期,2026-10-14)、静态链 1912B;ftpTask 实测 740B/4096B、静态 1216B;timeSyncTask 实测 616B/2560B、静态 1264B;uiTask 实测 4016B/16384B;adcTask 实测 952B/2560B、静态 1320B;iec104Task 静态 1456B(未上板);protectTask 静态 872B(未上板);testTask 静态 496B(仅测试构建)。 -> ⚠ 改栈或加大栈内局部变量前后**必须**重跑该脚本——静态分析低估含递归/间接调用的链(优化前 ftpTask:静态 2528B vs 实测 3480B)。 +> `idle`(128 words)/ `timer`(256 words)由 FreeRTOS 内核创建。所有任务栈从 FreeRTOS `heap_4` 堆分配(**已迁 CCM**,2026-10-12 B5 由 48KB 扩容至 56KB,见 `docs/内存管理/RAM使用分析与优化方案.md` §4.1.2/§2.3)。 +> **栈台账**:权威逐任务数字在内存方案 §2.3;`stack_report.py` 9/9 PASS(2026-10-22 静态最坏链 + 同日真机 `[STACK]` 水位;defaultTask 最坏 3024B/5120B 余 40%、protectTask 静态 872B/2048B 余 57%)。⚠ 改栈或加大栈内局部变量前后**必须**重跑该脚本——静态分析低估含递归/间接调用的链(优化前 ftpTask:静态 2528B vs 实测 3480B)。 ### 2.2 就绪屏障(Event Flags,取代魔法延时) @@ -86,7 +90,7 @@ | **状态位**("环境已就绪") | `SYS_EVT_NET_READY` / `SYS_EVT_STORAGE_READY` | `osFlagsWaitAny\|osFlagsNoClear`、`osFlagsWaitAll\|osFlagsNoClear`——**任何消费者都不许消费它** | | **命令位**("请做一件事") | `SYS_EVT_CFG_SAVE` / `SYS_EVT_NET_RECONFIG` | 消费型等待(默认,不加 NoClear)——必须恰好被消费一次,否则会反复写盘/重建网络 | -本节图中 `ftpTask ← bit0 + bit1(All 汇合点)`依赖的正是"状态位常驻"这一前提。 +本节图中 `ftpTask ← bit0 + bit1(All 汇合点)`依赖的正是"状态位常驻"这一前提。录波、SOE、屏板链路**不新增事件位**:录波/SOE 靠"唯一写者轮询封存队列/封存环"衔接,屏板靠中断与 uiTask 节拍,均不进启动屏障。 ### 2.3 线程间通信 @@ -94,6 +98,11 @@ |---|---|---| | Event Flags | `sys_evtHandle` | 启动就绪屏障(§2.2) | | Message Queue | `netMsgQueue`(深度 8,`net_msg_t`) | 所有 CH395F 操作经队列**串行化**到 netTask 执行,保证 SPI 单线程访问 | +| Message Queue | syslog 条目队列 + SOE 投递队列(内核后**惰性创建**) | 各任务投递 → defaultTask 排空落 `/log/run.log`·`selftest.log`·`soe.log`(定长 64B) | +| 双区无锁快照 | `phasor` / `meas`(`App/algo`) | adcTask 唯一发布者,双区原子切换;protectTask(20ms)、iec104Task、uiTask 无锁读 | +| 冻结环交棒 | `wave_ring` | adcTask 写入;触发即冻结写指针、计满封段;defaultTask 只读已封存区游标搬运;落盘回执才解冻,冷却期再触发只加溢出计数 | +| 环形缓冲 + 行级单一所有权 | `console_log` | 各任务 append 日志行进环形缓冲,defaultTask 唯一发送者(UART5);裸发窗口用**非阻塞**所有权防半行交错(2026-10-26 O1 实证) | +| 按键环形队列 | `sb_link` | USART1 空闲中断入队(按键骑在帧 A 里上来)→ uiTask 出队映射 `UI_KEY_*` | --- @@ -114,21 +123,22 @@ sequenceDiagram participant P as protectTask participant C as adcTask - M->>M: HAL_Init + CubeMX 外设初始化
(SPI1/SPI2/I2C1/UART4/USART1/ADC1/TIM3/DMA/GPIO/IWDG) + M->>M: HAL_Init + CubeMX 外设初始化
(SPI1/SPI2/I2C1/UART4/UART5/USART1/ADC1/TIM3/DMA/GPIO/IWDG) M->>A: app_main_init() - Note over A: 时间子系统优先,使后续日志带时间戳 - A->>A: sd2506_init() → sys_clock_init()(墙钟基准) - A->>A: rs485_init() → gd5f2gq5ue_init()(BBT 扫描)→ tpafe5160_init() - A->>A: adc_input_init()(语义取数与有效性层的语义映射 + ADC1 DMA)→ phasor_init() → freq_init()
→ prot_set_init() + prot_elm_init()(保护判据内核前封存) + Note over A: fault_handler_enable() 第一行(四 Fault 全采集,否则被升级成 HardFault 看不出根因) + A->>A: syslog_mcu_init() → sd2506_init() → boot_stats_init() → sys_clock_init()(墙钟基准,时间优先使后续日志带时间戳) + A->>A: rs485_init(UART4) → sb_link_init(USART1 屏板:波特率交叉核对 + 挂首轮 IDLE 接收) + A->>A: gd5f2gq5ue_init()(BBT 扫描)→ tpafe5160_init() + A->>A: adc_input_init()(语义映射 + ADC1 DMA)→ phasor_init() → freq_init()
→ adc_cal_init()(标定折算 [adc_cal] 注册)→ run_par_init()([run_par] + 104 地址映射真源)
→ iec104_comm_init()([comm] ca/端口)→ prot_set_init() + prot_elm_init()(保护判据内核前封存) A->>A: SD2506 诊断(ID/时间/温度/电池)→ HAL_TIM_Base_Start_IT(&htim3)(1kHz 节拍) A-->>M: "App init OK" M->>K: osKernelStart() - Note over K: MX_FREERTOS_Init 已创建 9 任务 + 事件组 + 队列
(产品构建 testTask 创建即回收,实跑 8 任务) + Note over K: MX_FREERTOS_Init 已创建 9 任务 + 事件组 + netMsgQueue
(产品构建 testTask 创建即回收,实跑 8 任务) K->>D: 调度 D->>D: f_mount(无卷则 f_mkfs FAT32)→ 卷健康探针/自愈 → net_cfg_load()(配置引擎属主) D-->>N: set SYS_EVT_STORAGE_READY - D->>D: 进入 LED / syslog / 配置 poll 循环(含 stack_probe_poll 栈水位采样) + D->>D: 进入 LED / syslog·SOE 排空 / 录波落盘道 / 配置 poll 循环(含 stack_probe_poll 栈水位采样) N->>N: wait STORAGE_READY(Any|NoClear,≤10s,超时回退工厂默认) N->>N: 读 RAM 配置副本 → net_init(ip,mask,gw,mac)
→ PHY 强制 100M 全双工 → 等链路 ≤3s → MAC 回写影子 @@ -136,11 +146,11 @@ sequenceDiagram N->>N: 循环 net_poll() + net_process_messages()
(消费 NET_RECONFIG → 按代次号重建监听) F->>F: wait NET_READY|STORAGE_READY(All|NoClear)→ lftpd_start("/", 21)
→ 串口输出:waiting for connection... - U->>U: wait NET_READY(Any|NoClear)→ ui_port_init → ui_menu_init → ui_net_sink_start(7003) + U->>U: wait NET_READY(Any|NoClear)→ ui_port_init → ui_menu_init → ui_net_sink_start(7003)
→ 10ms 循环:ui_data_feed_tick + 屏板组帧/出键/灯位 T->>T: wait NET_READY(Any|NoClear)→ TCP listen :8888 - I->>I: wait NET_READY(Any|NoClear)→ IEC104 listen :2404 - P->>P: 20ms 判据节拍 prot_elm_run()(保护判据,不依赖网络) - C->>C: wait TIM3 1kHz 唤醒(ISR adc_tick_irq_notify)→ adc_input_poll() 纯消费 + I->>I: wait NET_READY(Any|NoClear)→ IEC104 listen :2404(遥测读 meas 快照 / 遥信读 prot_elm) + P->>P: 20ms 判据节拍 prot_elm_run()(不依赖网络;未标定即闭锁停走)+ SOE 边沿投递 + C->>C: wait TIM3 1kHz 唤醒(ISR adc_tick_irq_notify)→ adc_input_poll() 纯消费
→ 标定→相量→测频 → wave_ring_push/tick → 每 200ms meas_tick() 发布快照 Note over D,N,F,U,T,I: 就绪位一律 osFlagsNoClear(状态常驻、可被多任务重复读取);
仅命令位 CFG_SAVE / NET_RECONFIG 用消费型等待 ``` @@ -157,15 +167,19 @@ flowchart LR CHIP[("GD5F2GQ5UE
NAND 2Gbit")] subgraph USERS["使用方"] - NC["net_cfg
/config.ini(INI [network] 段)"] - SLG["sys_log
/log/run.log · selftest.log"] - LF["lftpd
FTP 文件读写"] + NC["net_cfg / cfg_file 引擎
/config.ini 多段 INI"] + SLG["sys_log + soe_store
/log/run.log · selftest.log · soe.log"] + LF["lftpd
FTP 文件读写(录波取回同通道)"] + WS["录波落盘道(defaultTask)
/wave 段文件(8.3 短名 WAVE 轮转)"] + PS["prot_set_store
/prot_set.bin(B7 原子写)"] ST["测试套件
STORAGE/GD5F"] end NC --> FS SLG --> FS LF --> FS + WS --> FS + PS --> FS ST --> FS FS --> DIO --> FTL --> NAND --> CHIP @@ -174,8 +188,10 @@ flowchart LR end ``` -- 掉电持久化:`net_cfg` 配置(通用配置文件 `/config.ini`,INI `[network]` 段,cfg_file 引擎),保存后下次上电生效、或立即生效(网络重建)、外部变更 4s 沉降后自动重载;旧版 NCFG 二进制(`/cfg/netcfg.bin`)**已不再读取**——存在则忽略(不读、不删、不迁移),配置回落工厂默认(自动迁移已于 2026-10-10 删除)。 -- 日志记录:`sys_log` 引擎写定长 64B 文本记录到 `/log/run.log`(运行记录)与 `/log/selftest.log`(自检记录),defaultTask 唯一写者,FTP 可直下(详见 `docs/子系统设计/运行与自检记录设计说明.md`);实时调试流 = 控制台单写者日志(USART1,4KB 环形缓冲 + defaultTask 唯一发送,详见 `docs/子系统设计/控制台单写者日志设计说明.md`)。 +- **配置文件**:通用 `/config.ini`(cfg_file 引擎,静态态单任务收敛于 defaultTask,外部变更 4s 沉降后自动重载),**多段注册制**:`[network]`(net_cfg)/ `[ftp]`(鉴权)/ `[adc_cal]`(标定系数与零点)/ `[run_par]`(运行参数 + 104 地址映射真源)/ `[comm]`(104 ca/端口);新模块加段=注册 `cfg_file` 段处理器,唯一落盘者不变。旧版 NCFG 二进制(`/cfg/netcfg.bin`)已不再读取(2026-10-10 删迁移),存在则忽略。→ `docs/子系统设计/配置文件设计说明.md` +- **记录三本**:`sys_log` 引擎写定长 64B 文本记录到 `/log/run.log` 与 `/log/selftest.log`;`soe_store` 同先例落 `/log/soe.log`(64B 定长二进制,容量满删除重建)。defaultTask 是 `/log` 唯一写者(两条队列在 `syslog_drain` 尾部统一排空),FTP 可直下。→ `docs/子系统设计/运行与自检记录设计说明.md` +- **录波段文件**:`/wave`(首 boot `mkdir`,8.3 短名 WAVE 前缀轮转、启动扫盘重建下标),段头 + 通道表 + 两处 CRC-16/MODBUS + 整段自检;defaultTask 游标**分次搬运**(每次 64B 批)不独占 FatFs,落盘成功回执才解冻录波环。→ `docs/子系统设计/故障录波设计说明.md` +- **实时调试流** = 控制台单写者日志(**UART5**/RS232#1,4KB 环形缓冲 + defaultTask 唯一发送;2026-10-29 因屏板占用 USART1 自 UART5 定态),详见 `docs/子系统设计/控制台单写者日志设计说明.md`。 - NAND 坏块表(BBT)持久化在保留块池,不交给 dhara 管理。 --- @@ -202,7 +218,7 @@ flowchart TB style NT fill:#efe,stroke:#484 ``` -**单连接约束**:CH395F 配置为 8 Socket(索引寻址)+ TCP Server 单连接(`set_fun_para(0x08)`,bit3 SOCKET_CLOSE;bit0 保留必须为 0),Socket 0 复用监听与数据通道;FTP / 对时 / 远程显示 / IEC104 四个 TCP 服务**串行**占用连接,连接断开后自动回到 LISTEN。 +**单连接约束**:CH395F 配置为 8 Socket(索引寻址)+ TCP Server 单连接(`set_fun_para(0x08)`,bit3 SOCKET_CLOSE;bit0 保留必须为 0),Socket 0 复用监听与数据通道;FTP / 对时 / 远程显示 / IEC104 四个 TCP 服务**串行**占用连接,连接断开后自动回到 LISTEN。人机显存的另一路出口(屏板)走 USART1 串口、不经 TCP——显存**一份三出**:屏板(主)/ :7003(网络镜像)/ 模拟器(同源像素)。 > **FTP 启动门(2026-09-21 修复)**:`ftpTask` 必须等 `NET_READY` **且** `STORAGE_READY`(两位均 `NoClear`)才 `lftpd_start`——此前就绪位被其它等待者消费,FTP **静默不监听**(详见 §2.2 与 `docs/测试说明/FTP_Test_Guide.md` §8.6)。 > **单客户端实测注意**:同一时刻只服务 1 个会话,旧会话异常断开后经 `net_listener` 重建监听(实测恢复窗 p50 **208 ms**,n=30;口径见 `docs/网络/网络自愈架构设计.md`)。测试脚本必须内置连接重试(`test/host/ftp_up_dl_test.py`、`test/host/ftp_regression.py` 已内置),且**不要用裸 TCP 工具探测 21 端口**(探测会占掉唯一会话,见 `docs/测试说明/FTP_Test_Guide.md` §8.7)。 @@ -211,13 +227,14 @@ flowchart TB --- -## 6. UI 层架构(框架 + 页面插件) +## 6. UI 层架构(框架 + 注册表驱动的页面插件) ```mermaid flowchart TB subgraph LOGIC["逻辑层"] UM["ui_menu.c
级联框状态机 + 按键分发"] MT["ui_menu_tab.c
菜单树生成物(ui_menu_tree.txt)"] + RG["ui_page_registry.c
节点→页面注册表(生成物)"] end subgraph VIEW["显示层"] MV["ui_menu_view.c
框体/行/装饰自绘"] @@ -226,35 +243,50 @@ flowchart TB subgraph FRAME["内容页框架"] CP["ui_content_page.c
屏生命周期 + 描述符驱动绘制/按键"] end - subgraph PLUGIN["页面插件(每页一文件)"] - P1["ui_page_device_info"] - P2["ui_page_ac"] - P3["ui_page_dc"] - P4["ui_page_password"] - P5["ui_page_net_cfg"] - P6["ui_page_runlog
运行记录(动态列表)"] - P7["ui_page_selftest
自检记录(动态列表)"] + subgraph DATA["数据供给(写读分离)"] + FDR["App/app/ui_data_feed.c
唯一填充者(uiTask 节拍)"] + DSC["ui_data.h
发布 API:rt/par/info 三帧快照"] + end + subgraph PLUGIN["页面插件(20+ 页,每页一文件)"] + G1["实时量:ac / dc / yx / device_info"] + G2["参数定值:view_param / view_set /
view_word / view_plate(整定·查看双入口复用)"] + G3["三遥设置:deadband / calib …"] + G4["装置维护:clock / reset / wave_manual / clear"] + G5["通讯参数:comm / net_cfg"] + G6["记录查询 ×10:soe / accident / oper / alarm /
start / yk / selftest / runlog / runreport / wave_play"] end subgraph PORT["显示端口"] - UP["ui_port.c
160x160 1bpp 缓冲"] - SINK["ui_net_sink.c
远程推流"] + UP["ui_port.c
160x160 1bpp 内存帧缓冲"] + SINK["ui_net_sink.c
远程推流 :7003(显存镜像)"] + STBY["ui_standby.c
待机屏(空闲 60s 切入)"] end + SB["屏板链路 ScreenLink(USART1 700 kbaud)
帧 B 上屏(主出口)· 按键 → ui_port_queue_key"] + WR["录波数据
wave_ring 封存区 / 搬运快照"] UM --> MT UM --> MV UM --> CP - UM --> STBY["ui_standby.c
待机屏(空闲超时切入)"] + UM --> STBY MV --> DECO - CP --> P1 & P2 & P3 & P4 & P5 & P6 & P7 + RG --> CP + CP --> G1 & G2 & G3 & G4 & G5 & G6 + FDR --> DSC + DSC -.->|"页面只读快照"| G1 & G2 & G6 + G6 -.->|"回放取数"| WR MV --> UP SINK --> UP - P5 -.->|"net_cfg RAM 副本"| CFG["net_cfg"] - P4 -.->|"ui_pwd_def.h 编译期密码"| PWD["查看 000 / 修改 123"] - P6 & P7 -.->|"/log/run.log · selftest.log"| SLG["App/log/sys_log
定长 64B 记录引擎(defaultTask 落盘)"] + UP --> SB + SB -.->|"召唤帧带按键"| UM + G5 -.->|"net_cfg RAM 副本"| CFG["net_cfg"] + PASSWORD["password 页(#P 叶子统一入口)
ui_pwd_def.h 编译期:查看 000 / 修改 123"] -.-> UM ``` +- **单一事实源 = 仓根 `ui_menu_tree.txt`**(61 行,16 个受保护叶 ` #P`):缩进即层级,`#page=<模块>` 把叶子绑到 `ui_page_<模块>.c` 的描述符;重跑 `tools/menu_gen/gen_menu.py` 生成 `ui_menu_tab.*` 与 `ui_page_registry.*`,并**自动把新页写进双端注册文件**(`uvprojx` + `CMakeLists.txt`)。写了却不绑定的 `ui_page_*.c` 生成器直接报错(不留死代码)。 - 内容页为**独立全屏屏**,由框架一次性自绘(**零 LVGL 子对象**),ESC 返回菜单屏。 -- 菜单受保护叶子(`ui_menu_tree.txt` 行尾 ` #P`):先弹密码页,授权后 `menu_password_ok` **先关页再续进入动作**。 +- 菜单受保护叶子(行尾 ` #P`):先弹密码页,授权后 `menu_password_ok` **先关页再续进入动作**。 +- **数据供给**:页面不直接伸手进业务模块,一律读 `ui_data.h` 三帧快照(实时量/参数/装置信息);写侧唯一填充者 `ui_data_feed`(装配层,可双向 include 不违分层)。契约属主 `docs/UI设计/UI_数据供给设计说明.md`。 +- **显存一份三出**(§5):屏板串口为主出口(4208 B 帧 B 点阵,memcmp 判变才组帧),:7003 为网络镜像,模拟器与固件同一份 UI 源码;屏板按键经 uiTask 映射 `UI_KEY_*` 回注。→ `docs/子系统设计/屏板链路设计说明.md` +- 录波两页:`wave_manual`(装置上手动触发录波)与 `wave_play`(现场单通道回放)——判据与显示契约见 `docs/子系统设计/故障录波设计说明.md` §8。 - 待机屏:空闲超时(默认 60s)自动切入,仅确认键回菜单;数据源同实时量页。 - 字体 `ui_font_cn_12.c` 由 `tools/font_gen/` 生成(宋体 12px 1bpp 子集,**224 字/319 字形**,2026-10-29 实测;字形数 = 字符数 + ASCII 95 个)。 @@ -268,35 +300,48 @@ STM32F4-Base/ │ ├── freertos.c 9 任务 + netMsgQueue + sys_evt 创建(CubeMX 接线 + 崩溃钩子;任务体在 App/task/) │ └── main.c 入口 → app_main_init → osKernelStart ├── App/ 应用层(业务编排,非 CubeMX) -│ ├── app/ 启动编排与全局契约:app_main.c(时间子系统优先)、app_cfg.h、sys_events.h -│ ├── algo/ 采集与算法层 语义取数与有效性~保护判据:adc_input / phasor / freq / prot_set / prot_elm -│ ├── task/ default_task / net_task / ui_task / adc_task / iec104_serv / protect_task / rs485_task*(*未创建,B2 暂缓) -│ ├── log/ sys_log 记录引擎(定长 64B;MCU 后端落盘 /log/*.log) -│ ├── cfg/ 配置引擎:cfg_file(静态态单任务收敛于 defaultTask)、store(MCU=FreeRTOS 堆) -│ ├── fs/ 卷锁 vol_lock(syslog / cfg / lftpd 三条路径 try 语义) +│ ├── app/ 启动编排与全局契约:app_main.c(时间子系统优先)、app_cfg.h、sys_events.h、 +│ │ ui_data_feed(App→UI 数据装配,快照唯一填充者) +│ ├── algo/ 采集与算法层(除 adc_input.c 外零平台依赖 → 主机单测免桩): +│ │ adc_input / adc_health / adc_cal / sample_ring / phasor / freq / meas / +│ │ prot_set / prot_elm / run_par / wave_ring / wave_store / sb_led_map +│ ├── task/ default_task / net_task / ui_task / adc_task / iec104_serv / protect_task / +│ │ rs485_task*(*未创建,B2 暂缓)+ task_handles.h +│ ├── protocol/iec104/ IEC 60870-5-104:iec104_asdu / iec104_link / iec104_pts(点表:遥测读 meas、遥信读 prot_elm)/ iec104_comm([comm] 段) +│ ├── log/ sys_log 记录引擎(定长 64B,/log 唯一写者=defaultTask)、 +│ │ console_log(UART5 控制台单写者)、soe_rec(64B SOE 纯编解码)+ soe_store(投递/落盘胶水) +│ ├── cfg/ 配置引擎:cfg_file(静态态单任务收敛于 defaultTask)、store(MCU=FreeRTOS 堆)、 +│ │ prot_set_store(/prot_set.bin 原子写,B7) +│ ├── fs/ 卷锁 vol_lock(syslog / cfg / lftpd 三条路径 try 语义)、vol_idle_sync │ ├── sync/ time_sync(TCP 对时服务) -│ ├── protocol/ 协议编解码(MODBUS 等)与帧解析 -│ └── util/ sys_clock(墙钟)、task_watchdog(IWDG 判定状态机) +│ └── util/ sys_clock(墙钟)、task_watchdog(IWDG 判定状态机)、boot_stats、sha256、task_prof ├── Drivers/BSP/ 纯手工驱动/服务(不受 CubeMX 保护) -│ ├── CH395F/ 以太网 MAC+PHY +│ ├── CH395F/ 以太网 MAC+PHY(SPI2 + DMA) │ ├── GD5F2GQ5UE/ NAND + dhara FTL -│ ├── TPAFE5160/ ADC +│ ├── TPAFE5160/ ADC(并行 16 位) │ ├── SD2506/ RTC -│ ├── RS485/ 半双工串口 +│ ├── RS485/ 半双工串口(UART4 + DE;兼全局 UART 回调唯一实现处) +│ ├── ScreenLink/ 屏板链路(USART1 700 kbaud):sb_proto(纯协议,主机单测)+ sb_link(HAL/中断传输层) │ ├── NET/ net_socket / net_select / net_events / net_listener / net_pending / lftpd │ ├── NETCFG/ 网口配置(INI [network] 段) -│ ├── UI/ LVGL UI(与模拟器共用) -│ └── dbg_log.h/dbg_cfg.h 分级日志 -├── Lib/ 第三方:LVGL v9.2、FatFs、FreeRTOS、CMSIS -├── Middlewares/ ST 官方中间件 +│ ├── UI/ LVGL UI(与模拟器共用):ui_port / ui_menu* / ui_content_page / ui_page_*(20+ 页)/ +│ │ ui_page_registry(生成)/ ui_data / ui_net_sink / ui_standby / ui_font_cn_12 / ui_pwd_def.h +│ └── dbg_log.h/dbg_cfg.h/app_assert.h/bsp_err.h 分级日志与 BSP 契约 +├── Lib/ 第三方:LVGL v9.2、FatFs、dhara + lv_conf.h(MCU 端) +├── Middlewares/ FreeRTOS V10.3.1(ST 官方中间件) +├── Drivers/STM32F4xx_HAL_Driver/ + Drivers/CMSIS/ ST HAL / CMSIS(裁剪版) ├── MDK-ARM/ Keil 工程(uvprojx + scatter + build/download 脚本) -├── simulator/ PC 模拟器(CMake + SDL2,共用 UI 源码 + 无头回归测试) +├── simulator/ PC 模拟器(CMake + SDL2,共用 UI 源码 + tests/ref 像素黄金参考回归) ├── test/ 测试套件(test_config.h 互斥选择,产品构建空转) │ ├── board/ 板端套件(.c/.h:CH395F / 存储 / RTC / ADC / RS485 / UI) -│ └── host/ 主机侧脚本(.py:烧录闭环、日志校验、UI 回归) -├── tools/ font_gen(字体生成)/ menu_gen(菜单表生成) -├── scripts/ 代码规范/乱码检查、RAM 报告(ram_report.py)、栈报告(stack_report.py) -└── docs/ 设计/测试/问题记录文档 +│ └── host/ 主机侧单测与脚本(44 套带 run_unit_test.py,覆盖率总闸全量真跑) +├── ui_menu_tree.txt 菜单树声明源(生成器输入,仓根) +├── ui_cn_chars.txt 中文字库输入(生成器输入,仓根) +├── tools/ font_gen / menu_gen / arch_diagram(文档配图生成器)/ refgraph(引用图)/ +│ setview_check / netlist_semantics(网表语义) +├── scripts/ 门禁与报告(check_* / gen_* / ci_local.py / stack_report / ram_report / +│ rename_ref / rename_ids / bom…) +└── docs/ 设计/测试/规范文档(人类索引 docs/README.md) ``` --- @@ -317,6 +362,8 @@ flowchart LR | MCU 固件 | Keil MDK-ARM v5(`@build` = `keil-build` skill) | `@build` 0 错 0 警 → `@test` 串口闭环 | | PC 模拟器 | CMake + SDL2 + MSVC(`simulator/build/`) | `check_menu_rows.py` + `check_content_pages.py`(文本断言 + 像素黄金参考) | +**纯逻辑模块第三端**:录波(`wave_ring`/`wave_store`)、保护判据(`prot_set`/`prot_elm`)、遥测快照(`meas`)、SOE 编解码(`soe_rec`)、屏板协议层(`sb_proto`)等零平台依赖,被 `test/host/` 原样 `#include` 免桩直跑(覆盖率总闸全量真跑)——主机侧就是它们的"第三端"。 + **功能编译开关**:当前**不存在**——`App/app/app_cfg.h` 自 2026-10-22 起不含任何宏(原 `APP_NET/ADC/RS485_ENABLE` 三个零消费点占位宏已删,接回方法记在该文件 v1.2),各模块一律编译进产品;裁剪测试套件的唯一开关是 `test/board/test_config.h` 互斥选择(产品构建全注释)。 --- @@ -331,14 +378,23 @@ flowchart LR | 网络自愈(监听重建 / 沉降隔离 / 周期对账) | `docs/网络/网络自愈架构设计.md` | | 采集与算法层 语义取数与有效性~保护判据(**设计与判据**) | `docs/算法/采集与算法层设计说明.md` | | 采集与算法层目录索引(文件清单 / 构建测试) | `App/algo/README.md` | +| 保护功能复现规划(分层归属 / 功能项状态) | `docs/算法/继电保护功能复现规划.md` | | ADC 采样节拍(TIM3 1kHz 同源驱动) | `docs/子系统设计/ADC采样节拍设计说明.md` | +| ADC 通道映射(网名/板级/通道号 13 路置换) | `docs/硬件平台/ADC通道映射说明.md` | +| 故障录波(数据面/段格式/回放契约) | `docs/子系统设计/故障录波设计说明.md` | +| 屏板链路(USART1 主出口 / 帧 A 帧 B / 实测证据) | `docs/子系统设计/屏板链路设计说明.md` | | IEC 60870-5-104 上行(:2404) | `docs/子系统设计/IEC104上行设计说明.md` | +| 配置文件引擎(/config.ini 多段注册制) | `docs/子系统设计/配置文件设计说明.md` | +| 运行与自检记录(64B 记录 + SOE) | `docs/子系统设计/运行与自检记录设计说明.md` | | 墙钟时间维护 | `docs/子系统设计/系统墙钟时间维护说明.md` | -| 控制台单写者日志(USART1 调试流) | `docs/子系统设计/控制台单写者日志设计说明.md` | +| 控制台单写者日志(UART5 调试流) | `docs/子系统设计/控制台单写者日志设计说明.md` | +| 看门狗 / CubeMX 重生成存活方法论 | `docs/子系统设计/看门狗设计说明.md` §10 | | RAM 预算与优化 | `docs/内存管理/RAM使用分析与优化方案.md` | | 栈/内存观测工具 | `scripts/stack_report.py`(Keil 静态调用图 × 串口 `[STACK]` 水位,判定取两者更坏者)· `scripts/ram_report.py`(.map 静态占用)—— 用法与基线见内存方案 §4.0.6 | | FTP 功能与陷阱 | `docs/测试说明/FTP_Test_Guide.md` §8.6(启动门)/ §8.7(单客户端)· 脚本 `test/host/ftp_up_dl_test.py`、`test/host/ftp_regression.py`、`test/host/ftp_integrity_test.py` | | UI 设计架构 / 内容页 / 菜单 | `docs/UI设计/UI_设计架构.md` · `内容页架构.md` · `菜单页面设计.md` | +| UI 数据供给契约(rt/par/info 三帧) | `docs/UI设计/UI_数据供给设计说明.md` | +| RemoDispBus 远程显示协议(:7003) | `docs/UI设计/RemoDispBus协议与接收设计说明.md` | | UI 自动化测试 | `docs/UI设计/UI_自动化测试流程.md` | | 驱动已知陷阱 | `docs/问题记录/{CH395F,GD5F2GQ5UE,SD2506}_Trap_Records.md` | | 各模块测试指南 | `docs/测试说明/` | diff --git a/scripts/check_generated_fresh.py b/scripts/check_generated_fresh.py index eae9cf2b..e76fea24 100644 --- a/scripts/check_generated_fresh.py +++ b/scripts/check_generated_fresh.py @@ -99,8 +99,8 @@ RUN_PY = [sys.executable] # 存量基线:接线当天实测已漂的产物,**只减不增**(还清即删整条,--prune 打印出处) BASELINE = ( - ("docs/images/项目架构总览.svg", "tools/arch_diagram/gen_arch_svg.py", - "脚注写 docs/项目架构总览.md,生成器已改成 docs/架构设计/(文档挪目录,产物没重跑)"), + # 2026-10-30 还清下架 1 条:docs/images/项目架构总览.svg <- tools/arch_diagram/gen_arch_svg.py + # (分层图数据补录波/SOE/屏板后重跑,脚本与产物同批逐字节一致;见该文件提交说明) ("docs/images/配置文件分层架构.svg", "tools/arch_diagram/gen_cfg_arch_svg.py", "图内写 App/cfg_file.c,生成器已改成 App/cfg/cfg_file.c(配置引擎挪目录,产物没重跑)"), ("docs/images/RemoDispBus帧格式.svg", "tools/arch_diagram/gen_frame_svg.py", diff --git a/tools/arch_diagram/gen_arch_svg.py b/tools/arch_diagram/gen_arch_svg.py index eb721962..b69e1efb 100644 --- a/tools/arch_diagram/gen_arch_svg.py +++ b/tools/arch_diagram/gen_arch_svg.py @@ -43,30 +43,35 @@ FONT = "Microsoft YaHei, Segoe UI, PingFang SC, sans-serif" # ----------------------------- 架构数据(改这里) ----------------------------- L_BIZ = dict( title="① 业务层", sub="顶层共享配置 · 被 UI 与基础服务共用", color="#2563eb", bg="#eff6ff", - chips=["net_cfg(网口配置:IP/掩码/网关/MAC + Flash 持久化)"], + chips=["net_cfg(网口配置:IP/掩码/网关/MAC · /config.ini [network] 段)"], ) L_UI = dict( - title="② UI 层", sub="Drivers/BSP/UI · 与 PC 模拟器共用", color="#7c3aed", bg="#f5f3ff", - chips=["ui_port(显示端口)", "ui_menu / ui_menu_view(级联菜单)", "ui_menu_tab(菜单表)", - "ui_content_page(内容页框架)", "ui_page_*(5 页插件)", - "ui_net_sink(远程显示 :7003)", "ui_font_cn_12(中文字体)", "ui_deco(浅 V 装饰)"], + title="② UI 层", sub="Drivers/BSP/UI · 一份显存三出(模拟器/屏板/远程)", color="#7c3aed", bg="#f5f3ff", + chips=["ui_port(显示端口)", "ui_menu / ui_menu_view(级联菜单)", "ui_menu_tab(菜单树生成物)", + "ui_content_page(内容页框架)", "ui_page_registry(页面注册表 · 生成物)", "ui_page_*(20+ 页插件)", + "ui_data(数据供给契约)", "ui_net_sink(远程显示 :7003)", "ui_standby(待机屏)", + "ui_font_cn_12(中文字体)", "ui_deco(浅 V 装饰)"], ) L_SVC = dict( title="③ 基础服务层", sub="应用侧服务 / 编排", color="#0d9488", bg="#f0fdfa", - chips=["app_main(启动编排)", "sys_events(就绪屏障)", - "app_cfg(编译开关)", "task/(net · ui · adc* · rs485*)", + chips=["app_main(启动编排)", "sys_events(就绪屏障)", "task/(9 任务)", + "algo/(语义取数与有效性~保护判据 · 遥测快照 · 录波数据面)", + "protocol/iec104(104 上行 :2404)", "ui_data_feed(App→UI 装配)", + "sys_log · soe(记录引擎)", "console_log(UART5 控制台单写者)", + "cfg_file · prot_set_store(配置引擎)", "lftpd(FTP :21)", "time_sync(TCP 对时 :8888)"], ) L_MW = dict( title="④ 中间件层", sub="通用库 / 协议栈", color="#16a34a", bg="#f0fdf4", - chips=["net_socket / net_select(BSD API)", + chips=["net_socket / net_select / net_events / net_listener / net_pending(BSD API + 阻塞模型)", "FatFs(文件系统)", "nand_ftl(dhara FTL)", "LVGL v9.2(图形库)", - "sys_clock(墙钟基准)", "util(crc · ringbuf)"], + "sys_clock(墙钟基准)", "task_watchdog(IWDG 判定)"], ) L_DRV = dict( title="⑤ 驱动层", sub="Drivers/BSP · 芯片时序/中断", color="#d97706", bg="#fffbeb", chips=["ch395f(SPI2 + DMA)", "gd5f2gq5ue(SPI1)", "tpafe5160(并行 16 位)", - "sd2506(I2C1)", "rs485(UART5 + DE)"], + "sd2506(I2C1)", "rs485(UART4 + DE)", + "sb_link · sb_proto(屏板链路 · USART1 700 kbaud)"], ) L_KERN = dict( title="⑥ 内核 / HAL", sub="调度 · 外设抽象", color="#475569", bg="#f1f5f9", @@ -76,7 +81,8 @@ L_KERN = dict( L_HW = dict( title="⑦ 硬件", sub="STM32F407ZGTx @168MHz", color="#e11d48", bg="#fff1f2", chips=["CH395F 以太网(SPI2)", "GD5F2GQ5UE NAND(SPI1)", "TPAFE5160 ADC(并行)", - "SD2506 RTC(I2C1)", "RS-485(UART5)", "USART1 调试(115200)", "6x LED"], + "SD2506 RTC(I2C1)", "RS-485(UART4 · 未接线)", "屏板(USART1 · 700 kbaud)", + "RS232#1 日志(UART5 · 115200)", "6x LED"], ) # 每一行可放多个"同级并列"的层(上层只依赖下方各层) @@ -89,7 +95,7 @@ ROWS = [ [L_HW], ] -FOOT = "上层只依赖相邻下层(单向);UI 层与基础服务层同级并列,均使用顶层 net_cfg。跨层调用细节见 docs/架构设计/项目架构总览.md §1.2 * 预留未接入调度" +FOOT = "上层只依赖相邻下层(单向);UI 层与基础服务层同级并列,均使用顶层 net_cfg。跨层调用细节见 docs/架构设计/项目架构总览.md §1.2" # ----------------------------- 工具函数 -----------------------------