Files
STM32F4-Base/docs/产品需求/产品需求设计文档.md
T
wandering1 a7f526569a perf(mem): R-9 落地——LVGL 池 40→16 KB,SRAM1 74.9%→56.1%
取值依据是实测水位,不是预估:菜单根框 5,368 B、开页-关页往返
5,448 B、最重页面峰值 6,568 B(占 16 KB 的 40%)、真机开机
used=3,192 B。注意 16,384 B 建池后 lv_mem_monitor 报的 total 是
15,020 B(TLSF 控制块与对齐元数据 ≈1,364 B),核算余量用后者。

两端 lv_conf.h 同步改值(lv-conf-sync 生效值比对 163 项 PASS),
Lib/lv_conf.h 的 UTF-8 BOM 已按原样补回(Edit 会静默剥掉)。

验证:
- @build 0 错 0 警;ZI 154,456 → 129,880,精确 −24,576 B
- SRAM1 98,144/74.9% → 73,568/56.1%(余 57,504 B);CCM 不变 87.9%
- 模拟器菜单回归 PASS(8 状态像素 + 池基线 5,368 B 未变);11 页
  黄金参考逐字节 10/11 一致,往返池水位 5,448 B 分毫未变
- 唯一差异 netcfg_save 保存态:用 40 KB 旧池做 A/B 复测同样失败,
  确认与本改动无关(属 506eccc 的 cfg_file 行为变化),未刷黄金
  参考掩盖,留给该改动属主处置
- @test PASS:fw build Oct 15 2026 07:31:34,无 [ERR]/Fault,
  开机 622 ms 到 net init: OK,menu build done: used=3192
- 本地 CI 全绿(L0 + L0.5,15 runner / 955 断言)
- 台账受管区与内存快照区已 --write 回填,mem-budget / mem-numbers
  由红转绿

连带结论:R-2 后半待迁体量 54,146 → 29,570 B,瓶颈由 SRAM1 换到
CCM(只剩 7,904 B);解锁链第 ① 步完成,下一步只差缩堆 56→32 KB
(B5 是反向扩容,缩回前须重跑 stack_report.py + 上板 min_ever)。

文档同步 20 处:本报告按修复即销项删除 R-9 行,并改写 §0.2/§0.3/
§0.4/§5.1/§5.2/§5.3/§6.4 与变更记录、去处表;RAM使用分析 §2.6.2
新增实测水位表、阶段 1.1 标已执行;台账 §3 解锁链、登记簿 N-27、
任务规划 README W3 行与链路图;UI 四篇、产品需求、内存内容分配
策略、运行与自检记录、项目部署环境要求、测试开发标准流程、
simulator/README、ui-verify skill 常量。顺带订正三处与脚本不符的
旧值:池水位常量 4784/4864 → 5368/5448、FreeRTOS 堆 48 → 56 KB。
2026-10-15 09:56:15 +08:00

54 KiB
Raw Blame History

STM32F4-Base 产品需求设计文档

文档定位:本项目面向产品的需求基线——把散落在架构、子系统、测试、问题记录各文档中的 "产品做什么 / 做到什么程度 / 依据是什么"收敛成一份可评审、可追溯的需求说明,供甲方、产品、 开发、测试与评审者建立统一认知。 范围:硬件规格、系统架构、功能需求(FR)、接口规范、非功能需求(NFR)、UI 规格、平台约束、 待实现项与路线图、验收判据。 事实来源:本文所有数值与结论均取自仓库内受管事实源(代码、.ioc、.map、网表分析报告与 各模块设计文档),凡与其它文档冲突处,以本文标注的权威来源为准。 版本:v1.0 日期:2026-10-05 状态:现状基线(含已实现项 + 待实现项) 阅读前提:建议先读 docs/README.md(文档索引)与 docs/架构设计/项目架构总览.md(全景架构)。


1. 文档说明

1.1 目的与范围

本文回答三个问题:

  1. 产品是什么——一块工业级嵌入式 DTU 平台固件,做什么、面向谁、部署在哪;
  2. 产品要做到什么程度——每一项功能/接口/性能/可靠性的可验收要求;
  3. 产品当前做到哪一步——已实现、已验收、待实现的明确边界。

不含:具体代码实现细节(见各模块设计文档)、测试用例步骤(见 docs/测试说明/)、 未闭环事项的逐条跟踪(见 docs/任务规划/README.md)。

1.2 术语与缩写

术语 全称 / 含义
DTU Data Transfer Unit,数据传输单元;本产品的设备角色
MCU STM32F407ZGTx(Cortex-M4,LQFP144)
FTL Flash Translation Layer,闪存转换层(本项目用 dhara 实现)
BBT Bad Block Table,NAND 坏块表(持久化在保留块池)
FatFs 通用 FAT 文件系统模块(Lib/FatFs)
BSD Socket API 本项目在 CH395F 之上封装的 net_socket 接口(socket/bind/listen/accept/recv/send/close)
RemoDispBus 远程显示总线协议(MCU 无屏,UI 以 1bpp 帧经 TCP 推流到远端客户端)
cfg_file 通用配置引擎(INI 段键表,MCU/模拟器双端共享核心)
sys_clock 系统墙钟时间服务(RTC 基准 + tick 推进)
sys_log 定长 64B 记录引擎(运行/自检日志)
IWDG Independent Watchdog,独立看门狗(LSI 时钟源)
就绪屏障 用 CMSIS-RTOS2 Event Flags 表达"子系统就绪"的启动顺序机制
双端 MCU(Keil/ARMCC)与 PC 模拟器(CMake/MSVC)共用同一份 UI/配置源码
@build / @test 仓库约定的构建 / 自动化测试命令别名

1.3 读者与相关文档

角色 建议读法
甲方 / 产品 §2 产品概述 → §5 功能需求 → §9 待实现项与路线图 → §10 验收判据
开发 全文;深入时按 §11 指向各模块设计文档
测试 / 验证 §5、§6、§7、§10 + docs/测试说明/
评审 §2、§7、§8、§9 + docs/问题记录/项目审查与优化建议报告.md

2. 产品概述

2.1 产品定位

STM32F4-Base 是一块工业级嵌入式 DTU 平台固件,基于 STM32F407ZGTx,集成 以太网通信、SPI NAND 存储、ADC 采集、RS-485 通信与 FTP 文件服务,并自带 远程显示(UI 推流)、墙钟对时、看门狗自恢复、运行/自检记录等工业现场能力。

它既是一台可独立部署的现场设备(通过以太网与远端客户端交互),也是一套 可复用的平台底座——后续产品(保护测控、馈线自动化终端等)在此底座上补齐采集与协议。

产品现状一句话:平台能力(网络 / 存储 / 时间 / UI / 日志 / 看门狗 / FTP / 配置) 已实现并台架验收;DTU 的核心采集职责(ADC / RS-485)尚未接线,是当前最大功能缺口 (见 §9)。这不是缺陷难修,而是产品定义未落定。

2.2 产品形态与部署

flowchart LR
    subgraph DEV["开发机(Windows)"]
        K[Keil MDK-ARM v5<br/>编译/烧录]
        SIM[LVGL PC 模拟器<br/>CMake + SDL2]
        PY[Python .venv<br/>脚本/测试]
    end
    subgraph TGT["目标板(DTU 硬件)"]
        M[STM32F407ZGTx @168MHz]
        P[CH395F / GD5F2GQ5UE / TPAFE5160 / SD2506 / RS-485 / LED×6]
    end
    subgraph RMT["远端客户端(PC/浏览器)"]
        C[DTU-RemoteLCD 或任意 TCP 客户端]
    end
    DEV -- "USB:ST-Link 下载器" --> TGT
    DEV -- "USB 串口 USART1 @115200 调试日志" --> TGT
    TGT -- "以太网 CH395F<br/>FTP:21 / 对时:8888 / 远程显示:7003" --> RMT
环境 角色 必需性
① 开发机 编译/烧录、UI 模拟器、脚本工具链 开发/测试必需
② 目标板 运行固件的 DTU 硬件 上机必需
③ 远端客户端 远程看图/按键、对时推送、FTP 文件操作 现场使用必需

关键产品特征:MCU 端无物理屏幕——UI 画面以 160×160 单色位图(1bpp)经 TCP 推送到远端 客户端渲染,按键亦由远端下发(见 §5.6、§8)。

2.3 设计目标与原则

# 目标 落地手段
G1 可靠:现场死机可自恢复、掉电不丢配置、错误可追溯 IWDG + 任务心跳位图、原子写 + 迁移、错误码通道四要素
G2 可维护:分层解耦、单一事实源、双端复用、门禁强制 六层架构、就绪屏障、生成器(菜单/字体/任务表)、pre-commit 18 钩子
G3 可移植:UI/配置源码 MCU 与 PC 模拟器共用 平台后端抽象(*_mcu.c / *_sim.c),核心零平台依赖
G4 可扩展:新子系统/新配置段/新页面按模板接入 事件位扩展、段注册三步、页面插件描述符、App/protocol/ 预留
G5 可验收:每项能力有明确判据与自动化门禁 @build / @test / L0 静态 / L0.5 主机侧单测 / 台架验证

设计原则(贯穿全项目):

  1. 上层只依赖相邻下层(单向);禁止反向依赖(例外经登记)。
  2. 状态位常驻、命令位消费——Event Flags 就绪位必须 osFlagsNoClear。
  3. 能推导的就不存——持久化"不可推导"的状态(导航历史、配置、日志),其余现算。
  4. 单写者——配置文件属主 = defaultTask;syslog 唯一写者 = defaultTask;控制台唯一发送者 = defaultTask。
  5. 一切写入 = 临时文件 + rename(原子替换),半截窗口结构消除。

2.4 产品范围

本期(已实现):网络通信与配置、NAND 存储栈、时间子系统、运行/自检记录、UI 远程显示、 看门狗、FTP 服务、LED 指示、启动屏障与任务调度。

非本期(待实现 / 待定义):ADC 采集链路、RS-485 采集链路与协议状态机、DTU 核心转发职责 (MODBUS RTU / 上行 TCP 等,取决于产品定义)、UI 部分叶子内容页、SNTP 客户端等。


3. 系统总体架构

3.1 六层分层架构

STM32F4-Base 项目分层架构

上图由 tools/arch_diagram/gen_arch_svg.py 生成(手绘 SVG,零连线交叉);改架构后编辑脚本顶部 ROWS 数据重跑即可,源数据与下表一致。

分层原则:上层只依赖相邻下层(单向);① 业务层为顶层(仅 net_cfg,被 UI 与基础服务共用), ② UI 层与 ③ 基础服务层同级并列。

层 目录 职责 关键模块
① 业务层 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/* lftpd time_sync
④ 中间件层 Drivers/BSP/NET/、Lib/、App/util/ 通用库 / 协议栈 net_socket net_select FatFs nand_ftl(dhara) LVGL sys_clock
⑤ 驱动层 Drivers/BSP/{CH395F,GD5F2GQ5UE,TPAFE5160,SD2506,RS485}/ 芯片寄存器 / 时序 / 中断 ch395f gd5f2gq5ue tpafe5160 sd2506 rs485
⑥ 内核 / HAL Middlewares/、Drivers/STM32F4xx_HAL_Driver/、Drivers/CMSIS/ 任务调度、外设 HAL、启动 FreeRTOS V10.3.1 · STM32 HAL · CMSIS
⑦ 硬件 — STM32F407ZGTx @168MHz SPI1 / SPI2 / I2C1 / UART4 / USART1 / DMA / GPIO / TIM7

3.2 运行时任务模型

六个 FreeRTOS 任务(Src/freertos.c 创建,任务体在 App/task/、App/sync/):

任务 栈 优先级 职责
defaultTask 4096 B Normal FatFS 挂载(无卷 f_mkfs)→ 卷健康探针/自愈 → net_cfg_load(配置引擎属主)→ 置 STORAGE_READY → 日志落盘(唯一写者)+ 配置保存执行/2s poll + LED 闪烁 + 栈水位观测 + 看门狗唯一喂狗者
netTask 4096 B Normal 等存储 → net_stack_bring_up() → 置 NET_READY → net_poll 轮询(CH395F 操作串行化)
ftpTask 4096 B Normal 等网络且存储(WaitAll)→ lftpd_start("/", 21) → 单客户端会话循环
testTask 8192 B BelowNormal 测试套件入口(test/board/test_config.h 选择)。产品构建不创建(未选套件时立即 vTaskDelete 回收其 8 KB CCM 栈)
uiTask 16384 B BelowNormal 等网络 → ui_port_init/ui_menu_init/ui_standby_init(空闲 60s 切待机屏)/ui_net_sink → 10 ms 刷新
timeSyncTask 2048 B Normal 等网络 → TCP :8888 收 PC 推送时间 → 写 RTC

idle(128 words)/ timer(256 words)由 FreeRTOS 内核创建。所有任务栈从 48 KB heap_4 堆(CCM)分配。 任务表与 Src/freertos.c 的 osThreadAttr_t 一致,由 scripts/gen_task_table.py 生成并门禁校验。

3.3 就绪屏障(Event Flags)

就绪屏障(Event Flags)

用 CMSIS-RTOS2 Event Flags(sys_evtHandle)表达"子系统就绪",取代魔法延时与全局标志轮询。 生产者与消费者互不知晓,只经事件组解耦;新增子系统只需定义新 bit + 各自 wait/set。

位 名称 类型 语义
bit0 SYS_EVT_NET_READY 状态位 netTask:net_init + PHY 稳定完成
bit1 SYS_EVT_STORAGE_READY 状态位 defaultTask:FTL/FatFS 挂载 + 配置就绪
bit2 SYS_EVT_FTP_READY 状态位 ftpTask:lftpd_start 完成
bit3 SYS_EVT_TIMESYNC_READY 状态位 timeSyncTask:首次时间同步完成
bit4 SYS_EVT_NET_RECONFIG 命令位 UI:请求立即应用新网口配置
bit5 SYS_EVT_CFG_SAVE 命令位 UI:网口配置保存请求(defaultTask 消费并写盘)
bit6 SYS_EVT_CONSOLE_TX 命令位 控制台单写者:生产者入环形缓冲后置位

⚠️ 铁律:状态位(bit03)表达持久状态,任何消费者都不许消费——必须 osFlagsWaitAny|osFlagsNoClear。命令位(bit46)表达"请做一件事",必须恰好被消费一次(消费型等待)。 历史事故:就绪位被先到的等待者消费,导致 ftpTask 的 WaitAll(bit0|bit1) 永不成立、21 端口从未监听(静默)。

3.4 启动时序

sequenceDiagram
    autonumber
    participant M as main
    participant A as app_main_init
    participant K as osKernelStart
    participant D as defaultTask
    participant N as netTask
    participant F as ftpTask
    participant U as uiTask
    participant T as timeSyncTask

    M->>M: HAL_Init + CubeMX 外设初始化<br/>(SPI1/SPI2/I2C1/UART4/USART1/DMA/GPIO/TIM7)
    M->>A: app_main_init()
    Note over A: 时间子系统优先,使后续日志带时间戳
    A->>A: sd2506_init() → sys_clock_init()(墙钟基准)
    A->>A: rs485_init() → gd5f2gq5ue_init()(BBT 扫描)
    A->>A: tpafe5160_init() → SD2506 诊断 → start_conv_irq()
    A-->>M: "App init OK"
    M->>K: osKernelStart()
    K->>D: 调度
    D->>D: f_mount(无卷则 f_mkfs FAT32)→ 卷健康探针/自愈 → net_cfg_load()
    D-->>N: set SYS_EVT_STORAGE_READY
    N->>N: wait STORAGE_READY(Any|NoClear)→ net_init(ip,mask,gw,mac)<br/>→ PHY 强制 100M 全双工 → 等链路 ≤3s
    N-->>F: set SYS_EVT_NET_READY
    F->>F: wait NET_READY|STORAGE_READY(All|NoClear)→ lftpd_start("/", 21)
    U->>U: wait NET_READY(Any|NoClear)→ ui_port_init → ui_menu_init → ui_net_sink_start(7003)
    T->>T: wait NET_READY(Any|NoClear)→ TCP listen :8888

3.5 线程间通信

机制 对象 用途
Event Flags sys_evtHandle 启动就绪屏障 + 命令位(§3.3)
Message Queue netMsgQueue(深度 8,net_msg_t) 所有 CH395F 操作经队列串行化到 netTask 执行,保证 SPI 单线程访问

4. 硬件规格

4.1 主控与内存

项 值 说明
MCU STM32F407ZGTx Cortex-M4(FPU),LQFP144
主频 168 MHz HSE 8 MHz → PLL M=4 / N=168 / P=2
Flash 1 MB(0x08000000) 片内
SRAM 192 KB(128 KB 主 SRAM1+SRAM2 + 64 KB CCM) 链接器映射 128 KB 主 SRAM;CCM 用于 FreeRTOS 堆(任务栈)
RTOS FreeRTOS V10.3.1(CMSIS-RTOS2) HAL 时基 TIM7,tick = 1 ms;NVIC 4 位抢占,外设中断优先级 ≥5
工具链 Keil MDK-ARM v5(ARMCC v5) 工程锁 uAC6=0,不支持 armclang
CubeMX 6.17.0 + STM32Cube FW_F4 V1.28.3 与 .ioc 记录一致,再生成须用此组合

4.2 外设与引脚分配

权威来源:V0.1 网表分析报告 + Inc/main.h(代码已迁移至 V0.1)。下表为 V0.1 硬件的引脚。

外设 接口 引脚 说明
CH395F 以太网 SPI2 PB12 CS / PB13 SCK / PB14 SDO / PB15 SDI 10/100M 以太网控制器;PHY 强制 100M 全双工;SPI 分频系数必须为 8(PCB 设计约束)
GD5F2GQ5UE NAND SPI1 PE0 CS / PB3 SCK / PB4 MISO / PB5 MOSI / PB8 WP / PE1 HOLD 256 MB SPI NAND(2 Gbit)
TPAFE5160 ADC 并行 16 位 PG0~PG15 数据 / PC6 FRSTDATA / PC7 BUSY(EXTI) / PC8 RD / PC9 CONVST / PA8 OS2 / PA11 OS1 / PA12 OS0 高精度多通道 ADC
SD2506 RTC I2C1 PB6 SCL / PB7 SDA 提供墙钟基准与日志时间戳
USART1(调试串口) UART PA9 TX / PA10 RX 115200 8N1;printf 日志 + @test 采集通道
UART4(RS-485) UART PC10 TX / PC11 RX / PA15 DE 半双工通信
状态 LED ×6 GPIO PC5 / PB0 / PB1 / PB2 / PF11 / PF12 低电平点亮
SWD — PA13 SWDIO / PA14 SWCLK V0.1 已修复 V0.0 的 SWCLK 引脚缺陷
调试口 — CN2(XH-3A,1=SWDIO/2=SWCLK/3=GND) V0.1 由 H2 排针改为 XH 端子

⚠️ V0.0 / V0.1 差异:V0.1 相比 V0.0 做了接口裁剪(删 8080 LCD 与 8 键)+ U17 大面积引脚重排 + ADC 前端通道置换(17 路中 13 路变化)+ 调试口改型。固件 BSP 与 ADC 通道映射表必须按 V0.1 重映射; 详见 docs/硬件平台/V0.1_网表详细分析报告.md。

⚠️ 文档遗留:根 README.md 的"外设接口"表与 docs/环境与部署/项目部署环境要求.md §3.2 仍为 V0.0 口径(TPAFE 控制组、RS-485 实例、LED 序号),与 V0.1 不符——本文以 V0.1 为准。

4.3 存储器件

器件 容量 组织 软件栈
GD5F2GQ5UE 2 Gbit(256 MB) 2048 块 × 64 页 × 2048 B FatFS(FAT32)→ dhara FTL(磨损均衡 / 坏块管理 / GC)→ NAND 驱动
SD2506 — I2C1 RTC(时间/温度/电池诊断)
  • BBT 持久化:坏块表存于保留块池(顶部 4 块),不交给 dhara 管理。
  • 单写者纪律:defaultTask 拥有存储;netTask 只读 RAM 配置副本,不触卷。
  • FatFs 约束:FF_USE_LFN=0(严格 8.3 文件名);FF_FS_REENTRANT=1 + ffsystem.c 互斥钩子(超时 1 s);FF_FS_NORTC=0(get_fattime 直引用墙钟)。

4.4 硬件版本与兼容性

版本 状态 说明
V0.0 历史 含 8080 LCD、8 按键;存在 2 处设计缺陷(SWCLK 引脚错误致 SWD 不通、ADC17 落在非 ADC 引脚)
V0.1 当前 架构与 V0.0 一致;裁剪 LCD/按键、U17 引脚重排、修复上述 2 处缺陷;固件已迁移
V0.2 规划关注 新增关注项:VCAP 电容值未标注、PC13/14/15 子板 LED 3 mA 限流、SPI1 无法双落点

4.5 平台约束

约束 内容
CubeMX 生成文件 Inc/、Src/ 中带 USER CODE BEGIN/END 标记;自定义代码只能写标记区内
生成区外的定制 仅限 Src/iwdg.c 延后启动、4 个 Fault Handler 实体(scripts/check_cubemx_survival.py 审计兜底)
osKernelStart 前 禁止任何 FreeRTOS / CMSIS-RTOS API 调用
BOM / 编码 部分源文件带 BOM(Drivers/BSP/UI/*、App/task/ui_task.c、App/cfg/cfg_file.c、Lib/lv_conf.h),被工具改写丢 BOM 会导致 ARMCC 按 CP936 解码、中文字面量编译失败
SDIO V0.1 主板 SDIO 固定引脚组被 TPAFE/UART 全部占用 → 无 SDIO 能力(当前设计不受影响,FatFs 卷在 SPI NAND 上)
新源文件 必须双端注册(Keil .uvprojx + simulator/CMakeLists.txt),否则不参与编译

5. 功能需求

每项功能给出:需求描述 → 实现要点 → 验收判据。状态标注:✅ 已实现并验收 / ⚠️ 已实现待专项 / ⬜ 待实现。

5.1 网络通信子系统(FR-NET)✅

FR-NET-1 以太网组网

  • 需求:上电后按配置的 IP/掩码/网关/MAC 完成以太网初始化,PHY 强制 100M 全双工,等链路稳定后置就绪位。
  • 实现:netTask 等 STORAGE_READY → 读 RAM 配置副本 → net_init(ip,mask,gw,mac) → 等链路 ≤3 s → 置 NET_READY。
  • 判据:串口出现 Network Init / net init: OK / PHY: 100M FULL;PC 能 ping 通设备 IP。

FR-NET-2 网络抽象层(BSD Socket API)

  • 需求:为上层提供 socket/bind/listen/accept/recv/send/close 与 select/poll 多路复用;所有 CH395F 操作串行化。
  • 实现:net_socket.c(BSD API)→ netMsgQueue(深度 8)→ netTask 串行执行;net_select.c 提供 I/O 多路复用。
  • 判据:三个 TCP 服务(FTP / 对时 / 远程显示)均经同一 API 工作;单连接模型下连接断开自动回到 LISTEN。

FR-NET-3 单连接模型与自愈

  • 需求:CH395F 配置为 8 Socket(索引寻址)+ TCP Server 单连接(set_fun_para(0x08),bit3 SOCKET_CLOSE;bit0 为保留位必须为 0),Socket 0 复用监听与数据通道;网络重建后服务自动重连。
  • 实现:三个 TCP 服务串行占用连接,断开自动重听;代次号(net_get_generation())驱动服务自愈。
  • 判据:FTP 旧会话异常断开后约 30 s 恢复监听;网络重建(改 IP)后服务自动重建监听。

网络层是全项目最成熟子系统(pending 机制 + 四份 Trap 记录 + 量化基线 + 探针族)。

5.2 存储子系统(FR-STO)✅

存储栈分层

FR-STO-1 三层存储栈

  • 需求:在 SPI NAND 上提供 FAT32 文件系统;具备磨损均衡、坏块管理、垃圾回收;上电无卷自动格式化。
  • 实现:FatFS(FAT32)→ dhara FTL → gd5f2gq5ue 驱动;defaultTask 挂载(无卷 f_mkfs)+ 卷健康探针/自愈。
  • 判据:FTP 可列目录/读写卷根文件;掉电后数据仍在。

FR-STO-2 坏块管理与持久化 BBT

  • 需求:坏块表持久化,重启后不丢失;不交给 dhara 管理。
  • 判据:全片擦除后容量恢复流程可用(见 docs/测试说明/存储维护与容量恢复.md)。

FR-STO-3 卷并发一致性

  • 需求:FTP 传输(ftpTask)与配置读写(defaultTask)并发访问卷时不得损坏。
  • 实现:FF_FS_REENTRANT=1 + 逐次加锁/放锁(超时 1 s);三条一致性协议(写 tmp+rename / 沉降去抖 / 单写者)。
  • 判据:并发 FTP 下载 + UI 保存无卷损坏、无死锁。

5.3 时间子系统(FR-TIME)✅

FR-TIME-1 墙钟维护

  • 需求:以 SD2506 RTC 建立 Unix epoch 墙钟基准,运行期以 tick 推进(零 I2C 流量),提供字符串格式时间。
  • 实现:sys_clock_init() 读一次 RTC 建基准(无效时按默认值自动校时);base+delta 法;30 天惰性再基准化(防 49.7 天 tick 回绕);sys_clock_get_str() → "YYYY-MM-DD HH:MM:SS"。
  • 判据:日志时间戳真实正确;主机侧单测 100 断言点通过。

FR-TIME-2 网络对时

  • 需求:PC 主动通过 TCP :8888 推送时间到设备,设备写回 RTC。
  • 实现:timeSyncTask 等 NET_READY → TCP listen :8888 → 收 PC 推送 → 写 RTC;30 s 无包则掉线重建监听。
  • 判据:对时后设备墙钟更新、日志时间戳正确。

已知限制:uint32 epoch → 2038 年上限。

5.4 配置引擎(FR-CFG)✅

配置文件分层架构

FR-CFG-1 通用配置文件

  • 需求:网络参数(IP/掩码/网关/MAC)持久化到 /config.ini(INI [network] 段);文件可经 FTP 下载/上传;格式纯文本、带注释、可编辑器编辑。
  • 实现:cfg_file 段键表引擎(段 RAM 副本复用模块静态结构体,键表 const 映射键→偏移);工厂模板首启自动生成。
  • 判据:文件缺失/损坏回退工厂默认并重建模板;FTP 上传后 2~5 s 自动生效。

FR-CFG-2 外科手术式保存 + 原子写

  • 需求:保存时保留用户注释/未知段/未知键(降级安全);写入原子(并发读者只见旧完整或新完整文件)。
  • 实现:受管键行替换,其余原样保留;临时文件 + unlink 目标 + f_rename;输出 >4096 B 拒绝保存。
  • 判据:设备保存后下载文件,用户注释与未来版本段落原样保留。

FR-CFG-3 变更检测与立即应用

  • 需求:FTP 上传配置后无需重启即生效;网络段变化触发网络重建。
  • 实现:defaultTask 每 2 s f_stat 比对 (size, mtime),连续 2 次稳定才重载(沉降去抖);[network] 段变化 → SYS_EVT_NET_RECONFIG → 网络重建(代次 +1,服务自愈)。
  • 判据:FTP 改 IP 后 2~5 s 生效(网络重建含等链路 ≤3 s)。

FR-CFG-4 旧档迁移(已取消 · 2026-10-10)

  • 原需求:旧固件的 /cfg/netcfg.bin(NCFG 二进制)首启自动迁移为 INI 并删除旧文件——已取消,不再实现。
  • 现口径:旧档若存在则被忽略(不读、不删、不迁移),配置直接回落工厂默认(/config.ini [network] 段模板)。
  • 取消理由:该一次性路径把整条配置写链(net_cfg_save → cfg_file_save → cfg_store_write_atomic → f_rename → FatFS → dhara FTL)挂进启动期调用图,defaultTask 静态最坏栈链 +600 B;本仓库不存在携带旧档的设备。
  • 判据:卷上残留 /cfg/netcfg.bin 时开机不产生任何迁移日志、旧档不被改动,/config.ini 按工厂默认生成。

FR-CFG-5 扩展性

  • 需求:未来所有模块配置(ADC/RS-485/端口等)进同一文件、按段组织。
  • 实现:未来模块接入三步——① 定义段结构体(静态工厂默认)② 写键表 ③ cfg_file_register()。

5.5 运行 / 自检记录与日志(FR-LOG)✅

FR-LOG-1 定长记录引擎

  • 需求:运行记录与自检记录持久化到 NAND,FTP 可直下。
  • 实现:sys_log 定长 64 B 文本记录(一行一条);/log/run.log(1024 条 / 64 KB 上限)、/log/selftest.log(512 条 / 32 KB);defaultTask 唯一写者;ISO8601 时间戳 + epoch。
  • 判据:UI"运行记录/自检记录"页可显示;FTP 可下载。

FR-LOG-2 控制台单写者日志

  • 需求:多任务并发日志不得字符级交错;异常场景(HardFault)日志可控。
  • 实现:4 KB 环形缓冲 + defaultTask 唯一发送(行级原子);内核前/ISR/异常钩子有界直发回退。
  • 判据:日志无交错;崩溃时能输出归因日志。

FR-LOG-3 上电/重启分类与待机显示

  • 需求:区分上电与重启;空闲切待机屏。
  • 实现:run.log 末条 epoch 时间差推断;硬件复位原因(RCC_CSR)优先;ui_standby 空闲 60 s 切入。

5.6 UI 与远程显示(FR-UI)✅

FR-UI-1 离屏渲染 + 远程推流

  • 需求:MCU 无物理屏幕,UI 以 160×160 单色位图(1bpp,3200 B)经 TCP :7003 推送到远端客户端渲染;远端按键回注 UI。
  • 实现:LVGL 160×160 1bpp 离屏渲染到 g_ui_fbuf(3200 B)→ ui_net_sink 经 RemoDispBus 推流;远端按键经协议注入。
  • 判据:DTU-RemoteLCD 连 7003 出图(160×160 1bpp)+ 远端菜单导航可用。

FR-UI-2 菜单与内容页

  • 需求:42 节点层级菜单(最大 4 级)+ 内容页(装置信息/交流量/直流量等)。
  • 实现:三层拆分(数据层 ui_menu_tab 生成物 / 逻辑层 ui_menu 17 B 导航状态 / 显示层 ui_menu_view 级联框);内容页框架 + 页面插件描述符。
  • 判据:UI menu init: OK;菜单像素回归全 PASS。

FR-UI-3 待机屏

  • 需求:空闲超时(默认 60 s)自动切待机屏,仅确认键回菜单。
  • 判据:空闲后进入待机屏,按键返回菜单。

详见 §8 UI 规格。

5.7 看门狗与故障自恢复(FR-WD)✅

看门狗心跳模型

FR-WD-1 IWDG + 任务心跳位图

  • 需求:任务级死锁/饿死/断言死循环可自恢复(硬件复位),无需人工到场;不误杀正常长耗时窗口。
  • 实现:IWDG(LSI 独立时钟,PR=4 / RLR=1249 → 标称 2498 ms、最坏 ≈1701 ms);任务心跳位图(各自置位,无锁单字)+ defaultTask 单一喂狗者(task_wd_poll 每 100 ms 抽样);连续 8 次(800 ms)未达标 → 停喂 → 约 2.5 s 后复位;必需位掩码 0x37。
  • 判据:V2 任务饿死 ≤2.5 s 复位;V4 关中断死循环每 ~4.9 s 稳定复位;V5 30 min 真实负载零复位。

FR-WD-2 复位原因诊断

  • 需求:复位后可区分上电 / 看门狗 / 软件 / 引脚 / 欠压。
  • 实现:HAL_Init() 后一次性读 RCC_CSR 锁存并清标志;优先级 POR > PIN > IWDG > WWDG > SFT > LPWR > BOR。
  • 判据:串口 [APP] reset cause: <类型>;[WD] armed: 自检标记。

FR-WD-3 故障现场采集

  • 需求:HardFault / MemManage / BusFault / UsageFault 触发时输出完整现场。
  • 实现:4 个 Fault Handler 采集(PC/LR/xPSR/R0-R3/CFSR/HFSR/BFAR/MMFAR)+ fault_handler_enable() 使能 SHCSR 后三者。
  • 判据:日志形如 [ERR] MEMFAULT PC=... CFSR=... MMFAR=...。

已知边界:启动段(app_main_init + bring-up)无看门狗保护;ftpTask 首期不纳入监视(掩码剔除)。

5.8 LED 状态指示(FR-LED)✅

  • 需求:6 路 LED(低电平点亮)随系统状态变化。
  • 实现:defaultTask 循环驱动(闪烁指示系统活跃)。
  • 判据:目检 6 路 LED 随系统状态变化。

5.9 ADC 采集(FR-ADC)🔶 采集链路已实现(B1);保护/遥测算法与上行待实现

  • 需求(B0 已确认,2026-10-10):持续采集 8 路电气量(Ua/Ub/Uc/U0、Ia/Ib/Ic/I0,1000 Hz / 20 点/周波),经保护/遥测算法后上送 IEC 60870-5-104(以太网 TCP 2404;遥测上送短浮点、采集上传系数 = 1)。
  • 现状(采集链路 B1 + L1 已实现,2026-10-10):启动序列调用一次 tpafe5160_init();运行期周期 CONVST 重触发已由 TIM6 更新中断(1 kHz)接管(Src/main.c 的 HAL_TIM_PeriodElapsedCallback,2026-10-10)+ adcTask 经 L1 层 adc_input_poll() 消费(tpafe5160_snapshot() 8 通道 + STM32 ADC1 9 通道扫描)+ 帧统计,台架 @test 确认 frame_seq 严格 1000 Hz 递增、frst_err=0、adc1_rc=0 / adc1_err=0;STM32 侧 ADC1 消费者已落地(App/algo/adc_input.c 的 stm32_scan(),L1-3/L1-4,2026-10-10),按 N-18 仅逐通道独立监视。
  • 后果:上电后仅采集 1 个样本,此后数据永久陈旧。
  • B0 结论(2026-10-10,详见 docs/算法/继电保护功能复现规划.md §1.5):① 持续采集 ② 1000 Hz(20 点/周波),通道 = 4U+4I(点表 4011~4018)③ 上行 IEC 60870-5-104(2404,非 ModBus RTU 上行)④ APP_ADC_ENABLE 语义 = 门控 ADC 采集链路(ADC 为遥测/保护必需来源;是否接线或删除占位宏待定)。
  • 实现约束(见 §9):周期 CONVST 重触发 + adc_task 消费 tpafe5160_snapshot();原子快照 API 已就位(2026-10-10 修 E-44 / E-45 / E-58,旧的 get_buf / data_ready / clear_ready 已删 → 取数不再撕裂、重触发不再丢帧、芯片不驱动总线会被 init() 首帧自检抓到);栈预算核算;V0.1 通道映射已固化 → docs/硬件平台/ADC通道映射说明.md(13/17 路置换;语义 UA/UB/UC/UN、IA/IB/IC/IN、V_ZL2=温度,其余备用;网名 ADC17 = PC4 用 ADC_CHANNEL_14,不是 ADC_CHANNEL_12)。⚠ 8 路电气量分属 TPAFE / STM32 两片转换器属 V0.1 硬件缺陷(跨转换器无同一时刻性、精度与量程不一致,登记簿 N-18,V0.2 改版要求全部走 TPAFE)→ 在 V0.1 上主板侧只做逐通道独立监视,功率 / 功率因数 / 相角 / 矢量类量一律取子板计量模块结果,不得由主板混算。

5.10 RS-485 采集(FR-RS485)⬜ 待实现

  • 需求(B0 已确认,2026-10-10):半双工 RS-485 对下 ModBus RTU 采集(下行采集口,非上行口;上行走以太网 IEC 60870-5-104)。
  • 现状:rs485_init() 已调用;rs485_task.c 为空桩,未在 freertos.c 创建;App/protocol/ 预留(仅 README + .gitkeep)。
  • 实现约束:双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ 协议状态机;解析必须与硬件 I/O 分离(App/protocol/ 正为此预留)。B0 结论详见 docs/算法/继电保护功能复现规划.md §1.5。

6. 接口规范

6.1 网络服务端口

服务 协议 / 端口 用途 核对方法
FTP TCP 21 文件上传/下载(根目录 /,NAND 存储) 登录后任意 FTP 客户端列目录/读写(鉴权见 §7.6)
墙钟对时 TCP 8888 PC 主动推送时间到设备 对时后核对设备时间 / 日志时间戳
远程显示(RemoDispBus) TCP 7003 远端看图(160×160 1bpp)+ 远端导航按键 DTU-RemoteLCD 或任意 TCP 客户端连 7003 收帧
IEC 60870-5-104 上行 TCP 2404 被控站接入:遥测/遥信上送、总召、遥控/定值下发(B4) 任意 104 主站连 2404,STARTDT+总召往返(→ docs/子系统设计/IEC104上行设计说明.md)

现场组网要求:设备与客户端同网段(默认 .100/24、网关 .1);跨网段先改 IP 再上线。

6.2 RemoDispBus 协议

RemoDispBus 帧格式

项目 内容
传输 TCP,端口 7003;单连接(backlog=1)
帧格式 [TAG(1)][CMD(1)][LEN_H(1)][LEN_LO(1)][DATA(n)][CRC(1)]
方向标识 TAG 0xAA = 客户端→服务端,0xBB = 服务端→客户端
校验 CRC = 数据段逐字节异或(低 8 位,不含 TAG/CMD/LEN)
字节序 多字节字段大端(网络字节序)
最短帧 5 字节(LEN=0)
接收方式 逐字节有限状态机(TAG 定界 + 长度定长 + CRC 校验,自动重同步)

命令集:

CMD 名称 请求数据段 应答数据段
0 KEEPLIVE 无 无(原样回显)
1 INIT 无 [宽u16][高u16][帧字节数u32](8 B)
2 KEY [按键码u8] 无(确认)
3 LCDMEM [起始偏移u32] [偏移u32][1bpp位图 3200B](3204 B)

按键码:UP=0x02 / DOWN=0x40 / LEFT=0x10 / RIGHT=0x08 / ENTER=0x20 / ESC=0x01。

位图格式:1bpp 单色,MSB 优先(bit7 = 该字节第一个像素);像素 (x,y) → byte_i=(y*W+x)/8、bit_i=7-(x%8);位值 1=白、0=黑;160×160 → 3200 B。

关键常量:UI_NET_SINK_PORT=7003、RM_MAX_RX_PAYLOAD=256、RM_RX_BUF=64、帧重组缓冲 261 B。

详见 docs/UI设计/RemoDispBus协议与接收设计说明.md。MCU 与模拟器共用同一份 ui_net_sink.c。

6.3 对时协议

  • 载体:TCP :8888,PC 主动推送,设备接收并写 RTC。
  • 行为:timeSyncTask 监听 → 收包 → 写回 RTC;30 s 无包则掉线重建监听(约 4 s)。
  • 待补充:推送报文的具体帧格式(当前实现细节见 App/sync/time_sync.c 与 test/host/time_sync_server.py)。

6.4 FTP 服务

  • 实现:lftpd(轻量 FTP 服务器),root = /(FatFS 卷根),端口 21,单客户端。
  • 支持命令:登录 / TYPE I / PASV / STOR / RETR / LIST / DELE / QUIT。
  • 鉴权(已鉴权 · 2026-10-11,N-19):口令登录([ftp] 段 user / pwd_hash = SHA-256(user‖password) / write);未登录仅 USER/PASS/QUIT/FEAT/SYST/NOOP 放行,其余一律 530;write=0 可禁 STOR/DELE;连续 5 次失败锁 60 s;出厂默认 admin/admin,默认口令在用有启动告警。口径详见 docs/子系统设计/网络配置说明.md §3.4。
  • 启动门:ftpTask 必须等 NET_READY 且 STORAGE_READY(两位 NoClear)才 lftpd_start。
  • 注意:同一时刻只服务 1 个会话,旧会话异常断开后约 30 s 恢复监听;测试脚本须内置连接重试,不要用裸 TCP 工具探测 21 端口。
  • 实测:128 KB 上传下载逐字节一致(约 49/60 KB/s)。

6.5 配置文件格式

位置:MCU /config.ini(卷根);模拟器 sim_config.ini(工作目录)。

语法:key=value(key [a-z0-9_]+ 大小写敏感);[section];;/# 注释行;UTF-8(容忍 BOM);CRLF(设备写出)/ LF 均接受;行长 >127 字符该行无效;文件 >4096 B 视为损坏。

出厂模板(首启自动生成):

; DTU 通用配置文件
[network]
; IP 地址
ip=192.168.1.100
; 子网掩码
mask=255.255.255.0
; 默认网关
gateway=192.168.1.1
; MAC 地址 (全零 = 使用芯片内置 MAC)
mac=00:00:00:00:00:00

值类型:IP4(a.b.c.d)、MAC(aa:bb:cc:dd:ee:ff)、UINT(十进制,兼容 0x)、STR(≤31 字符)。

工厂默认:IP 192.168.1.100 / 掩码 255.255.255.0 / 网关 192.168.1.1 / MAC 全零(= 芯片内置)。

MAC 全零是"使用芯片内置 MAC"的哨兵,不是"MAC 为 0"。恢复出厂:FTP DELE /config.ini → 下次上电重新生成模板。

6.6 调试串口

项 值
端口 USART1(PA9 TX / PA10 RX),115200 8N1
用途 printf 日志 + @test 采集通道
配置源 .serialtest/config.json(单一配置源)
工具 仓库内置 Python 串口助手(.dsh/skills/serial-assistant/,常驻 daemon + CLI)

启动标记(@test 判据):

  • Required:App init OK / Network Init / net init: OK / PHY: 100M FULL
  • Forbidden:FAIL / ERROR / HardFault / [ERR]

6.7 对外 API 一览

模块 关键 API 说明
net_socket socket/bind/listen/accept/recv/send/close + select/poll BSD Socket 抽象
net_cfg net_cfg_load/save/get/set/get_mac/set_active_mac/fmt_ipv4/set_apply_cb/request_apply 网络配置(签名与语义稳定)
cfg_file cfg_file_register/load/save/poll/section_data 配置引擎核心(双端共享)
sys_clock sys_clock_init/get/get_str/get_time 墙钟时间服务
sys_log syslog_post(RUN / SELFTEST) 定长记录引擎
ui_net_sink ui_net_sink_start(port) / ui_net_sink_poll() 远程显示服务端
ui_content_page ui_content_page_open/close/invalidate/is_open 内容页框架
task_watchdog task_wd_beat/poll/start + 观测接口 看门狗判定状态机
sys_events sys_evtHandle + 7 个事件位 启动屏障

7. 非功能需求

7.1 可靠性

需求 要求 落地
自恢复 任务死锁/饿死/断言死循环 → 硬件复位 IWDG + 心跳位图(§5.7)
掉电不丢配置 配置原子写(旧档迁移已取消,2026-10-10) tmp+rename;旧 /cfg/netcfg.bin 不读、不删、不迁移
错误可追溯 错误码分级/透传/留痕,不吞不猜 错误码通道四要素(分类/透传/分级/留痕)
存储自愈 卷损坏可探针/自愈;丢弃可观测 卷健康探针 + 丢弃计数 + TX 僵尸通道自愈
不误杀 正常长耗时窗口不触发复位 启动段不喂狗 + 心跳切片 + 白名单

错误码通道四要素(CH395F 范式,后续任何驱动/子系统建立错误通道时应沿用): ① 分类(超时/真故障/参数错)② 透传(逐层上报,禁 (void)ret)③ 分级(可恢复重试/不可恢复上报) ④ 留痕(不可恢复写 syslog selftest,可恢复计数并 UI/日志可见)。 纪律:自愈逻辑严禁把"名字/参数类错误码"归入"卷损坏触发集"。

7.2 性能指标

指标 基线值 来源
M3 压力档帧周期 med 60.1 / p95 66.4 / max 69.3 ms(零尖峰) docs/测试说明/链路延迟测试说明.md
队列响应性(挂起客户端) 92.5 ms(pending 一期) test/host/e02_probe.py
FTP 传输速率 约 49 / 60 KB/s(上传/下载) 128 KB 实测
网络重建生效 2~5 s(含等链路 ≤3 s) 配置设计
UI 刷新 10 ms 循环 ui_task_func
IWDG 停喂到复位 ≤2.5 s IWDG 设计

7.3 内存与资源预算

权威来源:.map 受管快照 + V5 30 min 运行时水位(2026-10-04)。详见 docs/内存管理/RAM使用分析与优化方案.md。

静态区(产品构建):

区域 用量 容量 占比
Flash ER_IROM1 266,632 B 1024 KB 25.4%
ROM 合计 267,372 B — —
RW_IRAM1 84,960 B 131,072 B 64.8%
RW_CCM 49,184 B 65,280 B 75.3%

运行时(V5 30 min 真实负载):

项 值 判定
实测堆 free=8,664 / min_ever=4,728 B —
defaultTask 栈峰值 3664 / 4096 B(余量 432 B ≈ 10%) ⚠️ 低于 30% 判据,需处理
netTask 栈峰值 1228 / 4096 B(余量 70%) ✅
ftpTask 栈峰值 2516 / 4096 B(余量 38%) ✅
uiTask 栈峰值 4060 / 16384 B(余量 75%) ✅
timeSyncTask 栈峰值 792 / 2048 B(余量 61%) ✅
testTask 栈峰值(产品态空转) 496 / 8192 B(余量 93%) ✅

定栈规则:改栈或加大栈内局部变量前后必须重跑 scripts/stack_report.py (Keil 静态调用图 × 串口 [STACK] 水位,判定取两者更坏者)。 LVGL 内存池 16 KB(静态占用,2026-10-15 由 40 KB 收缩);FreeRTOS 堆 56 KB(CCM)。

7.4 可维护性(测试与门禁)

测试分层:

层 内容 运行位置
L0 静态门禁(pre-commit 18 钩子) 本地 / CI
L0.5 主机侧单元测试(MSVC 离线编译真实源码) 本地 / CI
L1 / L2 板端套件 / 模拟器回归 本地(需硬件 / 模拟器)
L3 真机台架(@test 闭环 + 探针) 本地(需真机 + ST-LINK)

构建 / 测试命令:

# 构建(@build):0 错 0 警
& '.venv\Scripts\python.exe' .dsh/skills/keil-build/scripts/keil_build.py   # 退出码 0=PASS / 1=构建失败 / 2=环境错误
# 自动化测试(@test):串口采集 → 烧录 → 日志校验
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py   # 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法错误
# 全库门禁
pre-commit run --all-files

pre-commit 18 钩子:trailing-whitespace、end-of-file-fixer、check-added-large-files、 check-merge-conflicts、check-yaml、cppcheck、test-cppcheck、no-mojibake、coding-standard、 doc-links、task-table、mem-numbers、cubemx-survival、watchdog-unit-test、sys-clock-unit-test、 cfg-file-unit-test、test-suite-switch、gitlint。

受管事实源(禁止手改,由脚本生成):

  • 任务表(README.md / AGENTS.md)← scripts/gen_task_table.py
  • 内存/Flash 快照 ← scripts/check_mem_numbers.py
  • 菜单表 ← tools/menu_gen/gen_menu.py
  • 中文字体 ← tools/font_gen/make_font.py

7.5 可移植性(双端)

项 MCU 模拟器
构建 Keil MDK-ARM v5(ARMCC) CMake + SDL2 + MSVC
共用源码 Drivers/BSP/UI/*、Drivers/BSP/NETCFG/net_cfg.c、App/cfg/cfg_file.c 同左
平台后端 *_mcu.c(CH395F/FatFS) *_sim.c(Winsock/宿主文件)
验证 @build 0/0 → @test 串口闭环 check_menu_rows.py + check_content_pages.py(像素黄金参考)

新源文件必须双端注册(Keil .uvprojx + simulator/CMakeLists.txt),否则不参与编译。

7.6 安全与权限

项 现状
FTP 鉴权 已鉴权(2026-10-11,N-19):口令登录([ftp] 段存 SHA-256 摘要,不存明文)+ 连续 5 次失败锁 60 s + write=0 可选只读;出厂默认 admin/admin,默认口令在用有启动告警。边界:FTP 明文传口令,挡未授权访问、不挡网络嗅探(详见 docs/子系统设计/网络配置说明.md §3.4)
UI 菜单权限 受保护叶子(行尾 #P)先经密码页;密码仅编译期写入(查看 000 / 修改 123),不落 Flash、无运行期设置页
远程显示 无鉴权,单连接;现场同网段部署

8. UI 规格

8.1 屏幕与渲染

项 值
屏幕尺寸 160 × 160 px
色深 1bpp 单色(MSB 优先),帧缓冲 3200 B
渲染 LVGL 离屏渲染到 g_ui_fbuf;MCU 无物理屏,经 TCP 7003 推流
内存池 LV_MEM_SIZE = 16 KB(2026-10-15 由 40 KB 收缩,实测峰值占 40%)
主题 dark mono(单色深色)
刷新 uiTask 10 ms 循环
绘制缓冲 I1 draw buffer 需 +8 B palette 头

8.2 菜单树(42 节点)

级联框总览

规模:菜单节点 9 个(含根)+ 叶子节点 33 个 = 42 节点;最大深度 4 级(L0~L3)。

根页(主界面)7 个一级条目:装置信息 / 实时数据 / 参数定值 / 三遥设置 / 装置维护 / 通讯参数 / 记录查询。

完整层级树:

主界面 (L0)
├─ 装置信息                          [叶子]
├─ 实时数据 ▶                        [菜单]
│   ├─ 交流量  ├─ 直流量  └─ 遥信量
├─ 参数定值 ▶
│   ├─ 整定 ▶(参数 / 定值 / 控制字 / 软压板)
│   └─ 查看 ▶(参数 / 定值 / 控制字 / 软压板)
├─ 三遥设置 ▶(遥测死区 / 遥测系数 / 遥信类型 / 遥信防抖 / 双点遥信)
├─ 装置维护 ▶(时钟设置 / 强制复归 / 手动录波 / 清除记录)
├─ 通讯参数 ▶(通讯设置 / 网口设置 / SNTP设置)
└─ 记录查询 ▶(SOE记录 / 事故记录 / 操作记录 / 保护告警 / 保护启动 /
              遥控记录 / 自检记录 / 运行记录 / 运行报告)

三层代码架构:数据层 ui_menu_tab(生成物,g_menu_tab[42] 扁平父子索引表,≈0.7 KB Flash)

  • 逻辑层 ui_menu(唯一 17 B 导航状态)+ 显示层 ui_menu_view(持全部 LVGL 对象,零导航状态)。

导航模型:树形逐级进入——ENTER/→ 进入子页,ESC/← 返回上一级;页面 = 对表的一次 parent == 节点 过滤(现算不落地)。

显示模型:横向级联子框——每级一个框,子框左缘 = 父框右缘(共享 1px 边框列);子框顶边对齐父框 "选中行"行顶,溢出时整框上移使底边对齐选中行行底;选中行整行反色(白带黑字),菜单行带 ▶。

改菜单流程:编辑 ui_menu_tree.txt(缩进即层级)→ 重跑 tools/menu_gen/gen_menu.py → 导航/渲染代码零改动。

8.3 内容页

页 节点 类型 规格
装置信息 node 1 静态键值行 6 行不分页;副标题"馈线自动化终端"
交流量 node 3 数据列表 24 行 / 每页 8(3 页)
直流量 node 4 数据列表 3 行单页
用户密钥 受保护叶子 表单/操作页 3 个 14×14 数字框 + 反显光标
  • 内容页为独立全屏屏,由框架一次性自绘(零 LVGL 子对象),ESC 返回菜单屏。
  • 菜单导航状态不压层,返回即原样还原;同一时刻至多一个内容页打开。
  • 节点→页映射在逻辑层 menu_content_page_for(node);其余叶子暂无内容页(进空白终点框)。

8.4 密码与权限

项 值
查看密码 000(授只读权限)
修改密码 123(授修改权限)
存储 ui_pwd_def.h 编译期写入,不落 Flash
流程 受保护叶子先 arm → 开密码页 → 确认一致后回调 → 先关页再续做进入动作(携授予权限)

8.5 中文字体

  • 字体 ui_font_cn_12.c:宋体 12px 1bpp 子集(当前 122 唯一字 / 217 字形)。
  • 生成流程:tools/font_gen/extract_cn.py(扫 UI 源码 → ui_cn_chars.txt)→ tools/font_gen/make_font.py。
  • 约束:任何 UI 文案新增汉字后必须走此流程,否则显示为空白方块。

9. 待实现项与路线图

9.1 功能缺口(当前最大产品空洞)

缺口 现状 影响
ADC 采集链路 ✅ 采集链路已实现(B1 + L1,2026-10-10):采样节拍由 TIM6 更新中断(1 kHz)硬件触发;adcTask 经 L1 层 adc_input_poll() 消费(TPAFE 8 通道快照 + STM32 ADC1 9 通道扫描),台架 @test 闭环(1000 Hz、adc1_rc=0);取数按语义(L1-3/L1-4,N-18 逐通道独立监视) 数据路径已通;剩余为上层保护/遥测算法与 104 上行
RS-485 采集链路 rs485_task.c 空桩;App/protocol/ 仅 README 无 RS-485 数据收发(B0 定:对下 ModBus RTU 采集)
DTU 核心转发职责 B0 已定(2026-10-10):上行 IEC 60870-5-104(以太网 TCP 2404,遥测短浮点系数 1);RS-485 对下 ModBus RTU 采集 转发目标已明确,待实现

根因不是"缺陷难修",而是"功能没接"——B1/B2 的规模取决于 B0 产品定义,B0 已于 2026-10-10 确认(见 docs/算法/继电保护功能复现规划.md §1.5)。

9.2 阶段路线图

顺序唯一权威 → ../任务规划/README.md §2(统一推进顺序,波次 W1~W7; RS-485/B2 整簇暂缓见其 §2.4,2026-10-12 用户决定)。 本节自 2026-10-11 起不再维护路线图(原阶段图删除,避免与登记簿漂移;原 C4"defaultTask 栈余量 10%" 已于 2026-10-10 削链闭环销项,见 ../内存管理/RAM使用分析与优化方案.md)。 功能缺口口径见 §9.1;B0 产品定义结论见 ../算法/继电保护功能复现规划.md §1.5。

9.3 未接线开关说明

开关 位置 现状
APP_NET_ENABLE / APP_ADC_ENABLE / APP_RS485_ENABLE App/app/app_cfg.h 未接线占位,不门控任何代码——三宏全库零消费点,各模块一律编译进产品;B0 已确认 ADC / RS-485 均为必需链路(ADC=遥测/保护来源,RS-485=对下 ModBus RTU 采集)→ 建议在后续落地时接线为真实门控(或删除占位宏)。在接线前不要把它们当开关用
TEST_SUITE_* test/board/test_config.h 测试套件互斥,一次构建只开一个;全注释 = 正常产品固件

10. 验收判据

10.1 构建与静态门禁

项 判据
构建 @build → BUILD_OK: 0 errors, 0 warnings(退出码 0)
静态门禁 pre-commit run --all-files 全部通过(18 钩子)
主机侧单测 看门狗 39 用例 / 系统时钟 100 断言 / 配置文件 149 断言 全 PASS
双端构建 Keil 与 CMake 均 0 错 0 警
UI 回归 check_menu_rows.py + check_content_pages.py PASS

10.2 上电自检(@test)

项 判据
Required 标记 App init OK / Network Init / net init: OK / PHY: 100M FULL
Forbidden 标记 无 FAIL / ERROR / HardFault / [ERR]
自检记录 selftest: no fault record
退出码 @test → 0(PASS)

10.3 现场验收清单

# 项目 方法 通过标准
1 上电自启动 断电上电 + 串口采集 @test PASS,无 Forbidden 标记
2 网络连通 PC ping 设备 IP 通(PHY 100M FULL)
3 远程显示 DTU-RemoteLCD 连 7003 出图(160×160 1bpp)+ 远端菜单导航可用
4 FTP FTP 客户端连 :21 列目录 / 读写 / 下文件
5 UI 功能 远端操作 菜单 7 项导航、内容页、密码(查看 000 / 修改 123)、网口设置保存后立即生效
6 对时 PC 推送 8888 设备墙钟更新、日志时间戳正确
7 掉电保持 写文件 / 改网口配置 → 重启 数据仍在(/config.ini 按新值生效)
8 LED 状态 目检 6 路 LED 随系统状态变化(低电平点亮)

10.4 台架验收(已闭环)

用例 内容 结论
V2 任务饿死 → IWDG 复位 ✅ 800 ms 声明 stall,≤2.5 s 复位(reset cause: IWDG)
V4 关中断死循环 → IWDG 复位 ✅ 每 ~4.9 s 稳定复位(IWDG 独立于中断)
V5 30 min 真实负载长跑 ✅ 120/120 FTP PASS,零 IWDG 复位
P0-1 配置引擎堆分配改造(真机) ✅ [CFG] load: OK(经 FreeRTOS 堆);FTP 改 IP 复位即生效
存储/网络套件 16/16 PASS ✅

11. 相关文档

主题 文档
文档索引 docs/README.md
项目全景架构 docs/架构设计/项目架构总览.md
存储架构 docs/架构设计/STM32F4-Base存储架构说明.md
启动顺序 / 就绪屏障 docs/架构设计/项目启动顺序管理.md
配置引擎 docs/子系统设计/配置文件设计说明.md
网络配置 docs/子系统设计/网络配置说明.md
墙钟时间 docs/子系统设计/系统墙钟时间维护说明.md
运行/自检记录 docs/子系统设计/运行与自检记录设计说明.md
控制台单写者日志 docs/子系统设计/控制台单写者日志设计说明.md
看门狗 docs/子系统设计/看门狗设计说明.md
BSD Socket API docs/网络/BSD_Socket_API_使用指南.md
Net 层阻塞模型 docs/网络/Net层阻塞模型架构设计.md
UI 架构 docs/UI设计/UI_设计架构.md
菜单页面 docs/UI设计/菜单页面设计.md
内容页 docs/UI设计/内容页架构.md
远程显示协议 docs/UI设计/RemoDispBus协议与接收设计说明.md
部署环境 docs/环境与部署/项目部署环境要求.md
硬件网表 docs/硬件平台/V0.1_网表详细分析报告.md
待办登记簿 docs/任务规划/README.md
体系层评审报告 docs/问题记录/项目审查与优化建议报告.md
实机测试指南 docs/测试说明/实机测试实施指南.md
测试标准流程 docs/测试说明/测试开发标准流程.md
RAM 预算与优化 docs/内存管理/RAM使用分析与优化方案.md
AI 开发规范 AGENTS.md(仓库根)
开发者入门 README.md(仓库根)

12. 变更记录

日期 变更 说明
2026-10-05 初版 基于项目全量内容(架构 / 子系统 / UI / 测试 / 硬件网表 / 待办)编写完整产品需求设计文档:产品定位、六层架构与任务模型、V0.1 硬件规格、10 类功能需求(含 2 项待实现)、接口规范、非功能需求、UI 规格、待实现项与路线图、验收判据
2026-10-10 FR-CFG-4 旧档迁移取消 删除旧固件 /cfg/netcfg.bin(NCFG 二进制)的首启自动迁移:旧档若存在则被忽略(不读、不删、不迁移),配置回落工厂默认。理由:该一次性路径把整条配置写链挂进启动期调用图,defaultTask 静态最坏栈链 +600 B,而本仓库不存在携带旧档的设备;net_cfg_legacy.c/h 与 cfg_store_legacy_path() 一并移除。§7.1「掉电不丢配置」同步