Files
STM32F4-Base/docs/产品需求/产品需求设计文档.md
T
wandering1 aed842e1f2 Merge branch 'v2-on-ui' into task/archsplit-sw-hw
# Conflicts:
#	docs/架构设计/软件架构与运行时规格.md
2026-10-30 13:32:52 +08:00

135 KiB
Raw Blame History

STM32F4-Base 产品需求设计文档

文档定位:本项目面向产品的需求基线——回答三个问题:产品是什么(§2 背景·用户·场景)、 要做到什么程度(§4~§8 需求与验收标准)、当前做到哪一步(§4 总览表 + §9 路线图)。 散落在架构、子系统、测试文档中的"产品做什么 / 做到什么程度 / 依据是什么"以本文为唯一收敛点。 版本:v2.0 日期:2026-10-30 状态:现状基线(含已实现项 + 待实现项) 范围口径:1:1 复刻——本产品是参考产品 CLS100(Scatter_P_HV03.01_SV01.01,OMAP-L138 ARM+DSP 双核 + VxWorks 配电保护测控装置)的逐模块复刻;差异只允许来自物理不可移植项 (§3.2)。能力基线与逐项明细已独立成档: 参考产品复刻明细.md(能力清单、点表/定值/元件/规约逐项差额)。 配套权威档:运行时架构(就绪位表、启动时序、线程通信)→ ../架构设计/软件架构与运行时规格.md;硬件规格与 能力边界(引脚表、H1~H5)→ ../架构设计/硬件规格与能力边界.md。 事实来源:本文所有数值与结论均取自仓库内受管事实源(代码、.ioc、.map、网表分析 报告与各模块设计文档),凡与其它文档冲突处,以本文标注的权威来源为准。 阅读前提:建议先读 docs/README.md(文档索引)。 产品定义的技术细化(保护功能复现)见 docs/算法/继电保护功能复现规划.md。

1. 文档说明

1.1 目的与范围

本文回答三个问题:

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

不含(各有权威档,本文不重复):

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/配置源码
/keil-build / /serial-boot-test 仓库约定的构建 / 自动化测试命令别名
语义取数与有效性 / 标定折算 / 全周傅氏相量 / 测频与遥测快照 / 保护判据 采集链路分层:语义取数与有效性(语义取数与有效性)→ 标定折算(标定折算)→ 全周傅氏相量(全周傅氏相量)→ 测频与遥测快照(测频与遥测快照)→ 保护判据(保护判据)
全周傅氏 单频 DFT 取基波相量,窗长 = 整周波(20 点);幅值即基波有效值
相量 {fRe, fIm, fAm, fAmSQ},实部 / 虚部 / 幅值 / 有效值
双区交换 相量(及遥测快照)计算区 / 使用区索引单字节翻转,读者无锁取整份快照
等周波采样 软件测频 + 调采样周期,使窗长恒等于实际周波(严格 20 点/周波)
标定 k / b 通道折算系数(µV/码,Q16 定点)与零点(码值);工程量 = (code + b) × k
QDS IEC 60870-5-104 的品质描述符字节(OV / NT / IV 等位)
SOE Sequence of Event,带时标的事件顺序记录(本产品落 /log/soe.log)
CP56Time2a 104 的 7 字节时标格式(毫秒 / 分 / 时 / 日 / 月 / 年 + 时标标志位)
点表 / IOA 104 上送对象表与信息体地址;本产品点表口径见 §6.8
固有 / 运行 / 保护定值 三类参数:只读身份信息、可整定的运行参数、可整定的保护定值(§5.13)
软压板 软件投退开关(全局软压板 = 保护总投入,可经 104 遥控投退)
遥测死区 遥测变化上送门槛;本产品按"连续 2 个新测量点越限才确认"
软件架构档 docs/架构设计/软件架构与运行时规格.md 的简称(本文与复刻明细档共用此简称)
硬件规格档 docs/架构设计/硬件规格与能力边界.md 的简称(本文与复刻明细档共用此简称)
复刻明细档 docs/产品需求/参考产品复刻明细.md 的简称
CLS100 参考产品(配电保护测控装置,ARM + DSP 双核 / VxWorks),仅作能力对照,非本产品代次

1.3 读者与相关文档

角色 建议读法
甲方 / 产品 §2 背景·用户·场景 → §4 需求总览 → §9 路线图 → §10 验收判据
开发 全文;深入时按 §11 指向各模块设计文档
测试 / 验证 §5、§6、§7、§10 + docs/测试说明/
评审 §2、§3、§7、§9

2. 背景、目标用户与产品目标

2.1 背景与产品定位

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

它的产品目标是 1:1 复刻参考产品 CLS100(配电保护测控装置)——按参考工程源码的 常量表与模块文件逐项对齐点表、定值、保护元件与规约栈(§3.1、复刻明细 §1)。在此过程中沉淀出的 分层底座(采集链 语义取数与有效性~出口与记录、配置引擎、就绪屏障、双端测试)同时是可复用的平台能力。

产品现状一句话:平台能力(网络 / 存储 / 时间 / UI / 日志 / 看门狗 / FTP / 配置) 已实现并台架验收;采集主线(语义取数与有效性采集 → 标定折算 → 全周傅氏相量 → 测频与遥测快照 → 保护判据 → 出口与记录 SOE → IEC 60870-5-104 上送)软件链路已全线贯通并台架闭环;与参考产品的差距 集中在三处:① 保护判据处于未标定闭锁态(等标准源两点标定)、② 点表规模远小于参考 (定值 40 vs 249 项、遥测 9 vs 31 点、开入开出 0 vs 138/31 点)、③ 独立子系统未立项 (故障录波、电度、多规约、SNTP)。即:"数"与"判据"已可信到引脚电压口径, 缺的是标定、点表铺开与一次设备接口(明细见 复刻明细 §1.2、§9)。

交付节奏与验收锚点见 §9、§10;本文对"为什么是这四点能力组合"不再另立论证—— 它是 DTU 数据接入类产品的工业现场最小完备集(通信、存储、采集、对外规约), 并以 1:1 复刻 CLS100 为纵深(§3)。

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→RS-232 适配器:RS232#1 @115200 调试日志" --> TGT
    TGT -- "以太网 CH395F<br/>FTP:21 / 对时:8888 / 远程显示:7003" --> RMT
环境 角色 必需性
① 开发机 编译/烧录、UI 模拟器、脚本工具链 开发/测试必需
② 目标板 运行固件的 DTU 硬件 上机必需
③ 远端客户端 远程看图/按键、对时推送、FTP 文件操作 现场使用必需

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

2.3 目标用户

角色 与产品的接触面 关心的事
主站操作员 / 调度 IEC 60870-5-104(:2404):总召、变位、遥控、定值、对时 数据可信(品质位如实)、动作可追溯(SOE 时标)、异常可自恢复
现场调试与运维 串口屏板(本地带屏运行)、UART5 日志口(:115200)、FTP(:21)、ST-LINK 烧录 上电即用的接线口径、看得见的状态灯与日志、改配置不重启、掉电不丢参数
工厂生产 / 出厂 /config.ini 工厂默认、UI 工厂菜单、自检记录 产线可批量预置网络与口令、自检留痕可查
远程看图 / 注键人员 TCP :7003(RemoDispBus)+ DTU-RemoteLCD 与本地屏板同源的画面与按键(两出口并发互不干扰)
送检 / 验收方 §10 验收判据、第三方 104 主站往返 每项要求都有可跑通的判据,"没做"与"接线错"可区分

2.4 典型使用场景

  1. 开关柜现场部署:设备上电 → 按 /config.ini 出厂 IP 组网 → 主站连 :2404 总召 → 现场用屏板看测量、按按键翻菜单;死机由看门狗自恢复(无需到场)。
  2. 远程运维:PC 经 :7003 看同一份 UI、注键操作;FTP 取 /log(运行/自检/SOE 记录) 与 /config.ini;改 IP 后 2~5 s 生效不重启;PC 推 :8888 对时。
  3. 脱离 PC 独立带屏运行:串口屏板直连 USART1(700 kbaud),主机 275 ms 召唤、 ≤200 ms 回 4208 B 帧(3200 B 显存 + 状态灯掩码 + info)——无 PC 也能看与按(§5.16)。
  4. 保护运行(等标定解锁):1 kHz 采样 → 全周傅氏相量 → 20 ms 判据节拍 → 动作只落 遥信 + SOE + 日志(V0.1 无出口硬件);未标定态判据整体停走且 YX31 如实置位—— 这是刻意的安全设计,不是缺陷。
  5. 复刻验收:按 参考产品复刻明细.md 逐项对照点表/定值/元件/规约, 差额即排期输入(§9)。

2.5 目标与成功指标

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

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

  1. 上层只依赖相邻下层(单向);禁止反向依赖(例外经登记)。
  2. 状态位常驻、命令位消费——Event Flags 就绪位必须 osFlagsNoClear。
  3. 能推导的就不存——持久化"不可推导"的状态(导航历史、配置、日志),其余现算。
  4. 单写者——配置文件属主 = defaultTask;syslog 唯一写者 = defaultTask;控制台唯一发送者 = defaultTask。
  5. 一切写入 = 临时文件 + rename(原子替换),半截窗口结构消除。
  6. 测量不可信就不判据——未标定(VALID 未置位)或采样故障时保护停走,品质位如实上送, 绝不用"看起来对"的数去动作(§5.12、§5.15)。
  7. 点表优先于实现——本期做不了的 104 点照常入表并置 IV;缺行比置 IV 更糟, 主站将无法区分"没做"与"接线错"(§6.8)。

成功指标(可判定):

指标 目标 当前状态
平台能力台架验收 网络/存储/时间/UI/日志/看门狗/FTP/配置 全部闭环 ✅ 已达成(§10.4)
采集主线到业务出口 采样→相量→测频→遥测快照→判据→104/UI 全链路数据同源 ✅ 软件链路闭环;判据等标定(§9.1.1)
屏板独立带屏 串口通道交付并台架验收 ✅ 主机侧交付(§5.16;尾巴见屏板链路设计说明 §9.2)
送检就绪 两点标定 → 保护解卡 → 第三方主站验收 ⬜ 等标准源与端子变比(§9.2 第 4/5 步)
复刻完成 复刻明细各项达"做完了"口径 🔶 见 参考产品复刻明细.md §1.2

3. 范围与产品级非目标

3.1 产品范围(1:1 复刻口径)

产品范围 = 参考产品 CLS100 的可移植能力全集。 本产品不是"在参考产品里挑一部分做", 而是按参考工程源码逐模块复刻:凡参考源码中存在的点表、定值单元、保护元件、记录类型、 规约栈,都属本产品目标范围;差异只允许来自物理不可移植项(§3.1.1)。

范围按复刻完成度分三档,判定口径见 参考产品复刻明细.md §1.1:

档 含义 处置
✅ 已对齐 参考源码能力在本产品上已实现,且有台架/单测证据 进 §10 验收判据
🔶 部分对齐 骨架、口径、地址编排已对齐,覆盖范围小于参考(通道数 / 元件数 / 点数) 差额逐条进 §9
⬜ 未开始 参考源码存在、本产品无对应实现 逐条进 §9,不等于"不做"

当前分布(20 项能力,明细见 参考产品复刻明细.md §1.2):✅ 2 项(采样节拍、自检类型)、🔶 10 项、 ⬜ 7 项、— 1 项(双核分工,不可移植)。

3.1.1 不可移植项(产品级非目标)(唯一允许落在范围外的部分)

# 不可移植项 参考实现 本产品 归因
X1 双核 ARM + DSP 分工 OMAP-L138(ARM 跑通信/HMI,DSP 跑保护) 单核 Cortex-M4F 按任务划分承担 芯片形态
X2 实时操作系统与工具链 VxWorks 5.x + CCS FreeRTOS V10.3.1 + Keil ARMCC 平台形态
X3 一次设备接口 KO / KI 板卡(出口、开入、硬压板) V0.1 无该硬件(硬件规格档 §5 H3) 硬件缺失
X4 独立计量通道 专用计量芯片(电度) 无(跨转换器无同刻,§4.6 H1) 硬件缺失

X1~X4 是范围外项的全部。 除此以外不存在"参考有、我们决定不做"的能力—

3.2 产品级非目标(本期不做,与"范围外"不同义)

非目标 边界 理由
屏板硬件本体固件 DTU-LCD 独立工程 不在本仓;主机侧以需求档 §5.16 契约为黑盒验收线
多定值区 / 定值文件下装 参考有 4 区 本产品只定义单定值区(§5.15 未实现项表)
主站 IP 白名单 — 单 socket 语义下"拒绝"= 断链重听,可被扫描打成 SPI 风暴(§5.15)
LOGO 下发 帧 info[4..5] 保留位恒 0 参考该功能无消费方,协议保留位存在但主机不提供操作(§5.16)
归一化 / 标度化遥测 点表要求短浮点(系数 1) 协议语义决定,非进度缺口

"非目标"是产品决策;复刻差额不是(那是进度,见 §9 与复刻明细档)。两者不混。


4. 需求总览(优先级与状态)

优先级是排期语义:P0 = 交付/送检主线;P1 = 复刻铺开项(可并行、依赖标定或硬件); P2 = 冻结或等立项。状态口径同 §5 章头(✅ / 🔶 / ⬜)。细节与验收判据在 §5 各节。

优先级 需求域 状态 一句话边界
P0 FR-NET 网络通信(§5.1) ✅ CH395F + BSD 抽象 + 单连接自愈
P0 FR-STO 存储(§5.2) ✅ SPI NAND→dhara→FatFs,卷自愈
P0 FR-TIME 时间(§5.3) ✅ SD2506 墙钟 + :8888 对时(2038 已知限)
P0 FR-CFG 配置引擎(§5.4) ✅ INI 段键表 + 外科保存 + 免重启生效
P0 FR-LOG 记录与日志(§5.5) ✅ 定长记录 + 控制台单写者
P0 FR-WD 看门狗(§5.7) ✅ 心跳位图 + 复位原因 + Fault 现场
P0 FR-ADC 采集与标定(§5.9) ✅ 1 kHz 同源节拍;两点标定后解卡
P0 FR-MEAS 遥测与相量(§5.11) ✅ 全周傅氏 + 测频 + 200 ms 快照单源
P0 FR-IEC104 上行(§5.15) ✅ 被控站;无效点入表置 IV
P0 FR-PROT 保护(§5.12) 🔶 软件就绪;未标定闭锁(用户裁定走标准源)
P0 FR-SET 定值(§5.13) ✅ 40 项;原子封存 + 掉电保持
P0 FR-SOE 事件记录(§5.14) ✅ 判据路径零 NAND I/O
P0 FR-HMI 屏板链路(§5.16) 🔶 串口主通道已交付;7003 报文口径 6 项未做
P0 FR-UI 远程显示(§5.6) ✅ 两出口同源推流
P1 FR-LED 状态指示(§5.8) ✅ 主板 6 路;屏板 20 路属 FR-HMI
P1 复刻铺开(定值/遥测/元件/规约/软压板) 🔶 明细见复刻明细档;顺序不可早于标定(§9.2)
P1 故障录波 🔶 最小闭环代码面已交付;4 kHz/多段/COMTRADE 二期
P2 FR-RS485 对下采集(§5.10) ⬜ 整簇冻结(用户决定),重启门禁见该节
P2 FR-PROT-5 出口(§5.12) ⬜ 等 V0.2 硬件

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)渲染到离屏显存, 经两个出口送出:串口屏板通道(主,§5.16.2)与 TCP :7003(镜像);两路的按键都回注 UI。
  • 实现:LVGL 160×160 1bpp 离屏渲染到 g_ui_fbuf(3200 B)→ ui_net_sink 经 RemoDispBus 推流; 远端按键经协议注入。串口屏板通道尚未实现(§5.16.9 第 11 条)。
  • 判据:DTU-RemoteLCD 连 7003 出图(160×160 1bpp)+ 远端菜单导航可用; 屏板实物接入后 280 ms 节拍出图 + 状态灯正确(§5.16.10 第 8~15 条)。

FR-UI-2 菜单与内容页

  • 需求:42 节点层级菜单(最大 4 级)+ 内容页(装置信息/交流量/直流量等)。
  • 实现:三层拆分(数据层 ui_menu_tab 生成物 / 逻辑层 ui_menu 17 B 导航状态 / 显示层 ui_menu_view 级联框);内容页框架 + 页面插件描述符。2026-10-29 实到 43 节点(新增「录波回放」叶,需求原文的 42 是 V0.1 立项数)。
  • 判据: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 随系统状态变化。

⚠ 本节只讲主板 LED。 屏板上另有 20 路状态指示灯(ID 0 电源常亮 + ID 1~19 位掩码), 由主机每帧下发 4 B 控制,属另一套输出,规格见 §5.16.3 ①。 两套 LED 的"位 → 业务状态"语义各自独立,不要混用同一个状态表。

5.9 ADC 采集与标定(FR-ADC)✅

FR-ADC-1 采样节拍与触发

  • 需求:8 路电气量(UA/UB/UC/UN、IA/IB/IC/IN)持续采集,1000 Hz(50 Hz 下 20 点/周波), 采集节拍与任务唤醒同源;不得用任务周期软定时冒充硬件节拍。
  • 实现:TIM3 更新事件(1 kHz)在 ISR 内触发 TPAFE CONVST,同一事件经 TRGO 触发 ADC1 一轮 9 通道并由 DMA2 循环搬入乒乓双缓冲;ISR 只置"消费者就绪"门并唤醒 adcTask(不做重运算)。
  • 判据:frame_seq 每 10 s 精确 +10000(1000.0 Hz)、frst_err=0、adc1_err=0、adc1_hw=0; 单拍消费耗时 ≤10 µs(DMA 搬运后实测 8 µs,软件轮询时为 122 µs)。

FR-ADC-2 语义通道映射

  • 需求:按语义取数(UA/UN/IA 等),不写死缓冲区下标——V0.2 换映射表即可切换硬件归属。
  • 实现:App/algo/adc_input.c 的语义表(TPAFE buf[6]/[5]/[2];ADC1 CH14/3/6/1/2/5)+ 开机 映射自检(STM32 映射通道必须落在扫描序列内,否则拒绝并自检留痕)。
  • 判据:ADC input layer init: OK;8 路 + 温度首帧全部读出、互异、非饱和。

FR-ADC-3 标定与量纲折算(标定折算)

  • 需求:把码值折算为工程量 (code + b) × k,系数与零点可落盘、掉电保持;未标定不得冒充二次值。
  • 实现:App/algo/adc_cal.c——k 以 Q16(µV/码 ×65536)、b 以码值存 [adc_cal] / [adc_cal_ofs] 段;ROM 默认 = 引脚侧 LSB(TPAFE 152.59 µV/码、STM32 805.66 µV/码); 三态可用性 ADC_CAL_F_VALID / ADC_CAL_F_CLIPPED 由 adc_cal_flags() 单点查询,104 / UI / 保护闭锁共用。
  • 判据:已知电压注入斜率与理论 LSB 偏差 ≤2%(2026-10-27 台架实测端子侧 6544.2 码/V,与引脚侧 理论 6553.6 差 −0.14%,零点 0~5 码、R²=0.9999997、极性对称 ≤0.34%);8 通道系数/零点往返一致。
  • 证据与现场步骤:docs/硬件平台/ADC通道映射说明.md §8.1、 docs/测试说明/专项验证/ADC前端注入验证流程.md。

FR-ADC-4 采样有效性校验

  • 需求:芯片静默、丢帧、序号倒退、转换错误必须被检出并可闭锁保护,且不误报。
  • 实现:App/algo/adc_health.c 纯逻辑判定层——静默 100 ms 门限(电平位、可自愈)、丢帧边沿计数、 序号倒退锁存、FRSTDATA/HAL 错误/STM32 停摆计数增量;严重事件与上升沿写自检记录(每类每次开机一次)。
  • 判据:主机侧 31 用例全绿;台架零 [ERR](健康不误报),人为制造丢帧时 tgap 与 adc1_gap 同步可见。

FR-ADC-5 前端物理口径(已实测盖章)

  • 1k 串联 + 1k 到地 是源阻抗匹配、不是分压:ADCn 节点只有 {串阻、滤波电容、转换器引脚}, 「1k 到地」接在差分负端(ADC7_GND → R32 → AGND),故 AINn↔引脚变比 1:1。
  • 芯片手册 ±10 V 档的 LSB(305.18 / 1611.3 µV/码)是另一回事,不可与本板变比混用。
  • 剩余未知量只有子板/端子板变比,因此系数只能推到"µV/码 @ 引脚"(硬件规格档 §5 量纲口径)。
  • 拓扑图 docs/images/ADC前端电路.svg。

5.10 RS-485 采集(FR-RS485)⬜ 冻结

  • 需求(已确认):半双工 RS-485 对下 ModBus RTU 采集(下行采集口;上行走以太网 104)。
  • 现状:rs485_init() 已调用;rs485_task.c 为空桩、未在 freertos.c 创建;App/protocol/ 为该 协议族预留(当前仅 104 在用)。整簇冻结(用户决定,2026-10-12)。
  • 重启门禁:先修「单缓冲包撕裂」「TX 超时拉 DE 未等 TC」两条,再谈接消费者;实现须满足 双缓冲 + 序号、DE 收尾超时路径、协议解析与硬件 I/O 分离。
  • 详见 docs/任务规划/暂缓-RS485.md。

5.11 遥测与相量(FR-MEAS)✅

FR-MEAS-1 全周傅氏相量

  • 需求:每 1 ms 产出基波/谐波相量,幅值直接是基波有效值,读者无锁取整份快照。
  • 实现:App/algo/phasor.c——N=20 全周 DFT,系数表离线预乘 √2/N;5 个实例 (IA/UA/UN 基波 + IA 二次/五次);每来新点整窗重算,算完单字节翻转计算区/使用区。
  • 判据:主机侧 57 用例全绿(系数表逐项复核、合成正弦幅值误差 ≤1%、双区交换);台架开机即产出 5 行 phasor(first),心跳持续刷新。
  • 双轨有效值:保护用基波有效值(抗衰减直流与谐波误动),计量/遥测要真有效值(谐波方和根) ——两者不可混用;本产品当前只实现基波轨,谐波方和根轨未做(§9)。

FR-MEAS-2 频率测量(测频与遥测快照)

  • 需求:45~55 Hz 内测频,精度优先于响应速度。
  • 实现:App/algo/freq.c——共轭乘积相位增量 + 解缠绕 + 自适应窗长(对齐纹波周期整数倍); 假值钳制带与系统合理带分离;幅值门 <50 码判无效;UA → IA 优先级。
  • 判据:45~55 Hz 扫频最坏误差 0.0101 Hz、1% 噪声 0.0160 Hz、启动收敛 ≤40 ms、阶跃 50→51 Hz ≤120 ms; 浮空(无信号)时 valid=0 不发散。

FR-MEAS-3 遥测快照(200 ms)

  • 需求:104 与 UI 共用同一份上游——"什么时候算新值、品质怎么判"只此一处决定;快照必须可无锁整体读。
  • 实现:App/algo/meas.c——每 200 ms(经过时间分频,非拍计数)取基波有效值 + 逐点品质,双区 + seq; 唯一发布者 = adcTask(meas_tick 全仓仅一处调用),其余任务只读。
  • 判据:主机侧布局用例钉死字段偏移(改字段 = 破协议);台架 104 与 UI 读数同源一致;快照未发布时 消费者得到 IV|NT 而不是 0。

FR-MEAS-4 品质与死区

  • 需求:品质必须如实反映"这一路能不能信";遥测变化上送不得被单点噪声触发。
  • 实现:品质位低字节与 104 QDS 同值直传;CLIPPED(削顶)由 104 侧映射为 IV; 死区 = 连续 2 个新测量点越限才确认(基准恒为上次上送值,防慢漂移吃掉基准),品质翻转当拍直报。
  • 判据:UB/UC/IB/IC/IN 五路恒 IV(品质驱动,V0.2 消除 H1 后零改动自动启用);死区两拍确认、 回摆撤销;TEMP 通道恒 NT。

5.12 保护功能(FR-PROT)🔶 软件就绪,判据现闭锁

FR-PROT-1 元件框架

  • 需求:统一"越限 + 返回系数滞回 + 定时限"元件核,判据为纯逻辑(吃测量值 + 定值),可离线单测; 新增元件只加实例表一行,不改核。
  • 实现:App/algo/prot_elm.c——数据驱动实例表 9 行;prot_elm_eval() 纯判据、prot_elm_run() 为 相量/频率到测量值的薄适配;延时用 now_ms 差值法(与节拍无关,精度不受 20 ms 节拍影响)。
  • 判据:主机侧 47 断言全绿(1.01× 启动 / 0.9× 返回 / 滞回保持 / 欠量方向 / 投退 / 闭锁联动 / 时基回绕)。

FR-PROT-2 元件清单(V0.1 有效子集)

元件 测量量 判据要点 104 遥信
过流 Ⅰ/Ⅱ/Ⅲ 段 IA 越定值经延时动作,返回系数滞回 YX16/17/18(并汇入 YX15 故障总)
过负荷 IA 越定值告警(默认不跳闸) YX23 过载
过压 / 欠压 UA 过量 / 欠量方向,各自延时 无遥信点(仅 SOE + 日志)
零序过压 UN(外部零序专用通道) 越定值经延时 汇入 YX15 故障总
过频 / 低频 测频结果 过量 / 欠量方向,默认 51.0 / 49.0 Hz 无遥信点(仅 SOE + 日志)

⚠ YX15 故障总的构成是 OC1∨OC2∨OC3∨3U0——电压类与频率类元件不在其中,其动作目前只能从 SOE、[PROT] 日志与 UI 记录看到。这是点表层面的已知缺口(送检点表要求独立分点时再补), 不要把它误读成"元件没动作"。

  • 未复刻的元件(建接口不使能,等条件):三相完整过流(B/C 相)、零序过流、方向/功率类、 PT/CT 断线、涌流制动、重合闸、故障隔离——原因见硬件规格档 §5 的 H1/H2,属需求档 §9.1.1「三相与同期」, 解除条件为 V0.2 硬件。
  • 判据:[PROT] elm 边沿日志与 104 变位一致;未使能元件不误动。

FR-PROT-3 判据节拍

  • 需求:判据独立于采集任务,周期稳定,且不得阻塞在存储 I/O 上。
  • 实现:protectTask 20 ms 节拍(元件吃 50 Hz 基波有效值,相量每工频周更新,20 ms 足够); 纳入 IWDG 必需位;动作只投递 SOE(SPSC 环),不做 NAND I/O。
  • 判据:静态最坏链 872 B / 配置 2048 B(余 57%);动作到 104 上送端到端 ≤120 ms。

FR-PROT-4 闭锁(四源,任一命中即停走判据)

闭锁源 判据 行为
未标定 UA/UN/IA 的 ADC_CAL_F_VALID 未全部置位 整条判据链停走(产品构建默认态,等两点标定)
采样故障 adc_health_flags() 电平位(TPAFE/STM32 静默、序号倒退) 元件全部复位 + 本拍不判据,自愈后自动恢复
定值非法 定值校验和(sum32 正/反码)复核失败 闭锁相关保护并告警,需重写定值解除
全局软压板退出 PS_GLOBAL_EN = OFF(104 遥控 YK12) 元件复位 + 停判据,压板恢复即重返联

FR-PROT-5 出口(⬜ 未实现)

  • 需求:判据满足驱动跳闸/告警出口继电器,带保持/脉冲与回读自检。
  • 现状:V0.1 无出口硬件 → 保护"动作"= 遥信 + SOE + 日志;104 遥控 YK1~4 为否定确认。
  • 判据(立项后):动作驱动对应出口;出口回路自检可检出断线;遥控执行有确认与回读。

5.13 定值与运行参数(FR-SET)✅

FR-SET-1 三类参数

类 地址范围 内容 属性 本产品状态
固有参数 8001H~800AH 终端类型 / 操作系统 / 制造商 / 硬件版本 / 软件版本 / 校验码 / 规约类型 / 型号 / ID / MAC 只读 ⬜ 未实现(字符串类无法短浮点上送,未知 IOA 应答)
运行参数 8020H~8058H 遥测死区、PT/CT 变比、负荷越限/重载/过载报警、录波投退与定值、功率置负 可整定 🔶 已落死区 9 点 + k/b 覆盖 16 点(0x8030~0x804F);其余类别无消费者,留白不预埋
保护定值 8820H~8882H 过流 Ⅰ/Ⅱ/Ⅲ 段、零序过流、重合闸、低压/低频、励磁涌流闭锁、小电流接地等 可整定 🔶 40 项(Q10 定点):过流三段、过负荷、过压/欠压、零序过压、过频/低频 + 本地项(投退/返回系数/全局软压板)

FR-SET-2 定值模型与封存

  • 需求:定值改动必须原子可见——保护巡检任何时刻都看到自洽快照;范围校验失败整笔拒绝。
  • 实现:App/algo/prot_set.c——影子区写好后重封 sum32 正/反码,再单字交换活跃区; prot_set_selfcheck() 用 seqlock 式复核(提交撞见则本轮跳过);范围校验 + 整表 all-or-nothing 装载。
  • 判据:主机侧 90 断言(含伪造自洽越界对抗样本);104 写定值与巡检并发无 µs 级误锁。

FR-SET-3 持久化

  • 需求:定值掉电保持;档案损坏与版本换代必须能区分,损坏不得静默使用。
  • 实现:/prot_set.bin(magic + 版本 + 计数 + 值区 + sum32 正/反码对),走临时文件 + rename 原子写; 写路径 = 脏标志 → 事件位 → defaultTask 落盘(失败保留脏位下轮重试); 装载在 STORAGE_READY 之前整表原子完成。
  • 判据:非默认定值跨复位保持(台架 7.5 A 往返读回一致);版本换代(旧档)记 INFO, 真损坏记 ERROR + 自检留痕并回落出厂默认。

FR-SET-4 运行参数段

  • 需求:死区与通道系数可由主站整定并持久化,且系数只有一份真源。
  • 实现:App/algo/run_par.c——[run_par] 段 9 键(死区,毫单位 int32)+ k/b 覆盖 16 点; k/b 写为 adc_cal_set 代理(合法带 ROM×[0.5,2.0] 由执行段裁决),run_par 不存系数。
  • 判据:0x8027~0x802A(过压/欠压告警段)永不被覆盖(路由 run_par 先、未命中落 prot_set); 越带写回否定确认;整档保存一趟覆盖 [run_par] 与被改写的 [adc_cal]。

FR-SET-5 主站读写

  • 需求:主站可读定值、两段式写定值,失配/越界必须明确否定。
  • 实现:C_RD 读 + C_SE_NC 两段写;地址 = prot_set comm_addr(点表不另立地址表); comm_addr = 0 的本地项显式不可寻址(防 IOA=0 误命中)。
  • 判据:读回值 = 写入值(COT 正确);本地项读回 COT=14 + EVI;执行段写失败不影响旧值。

5.14 SOE 与动作记录(FR-SOE)✅

FR-SOE-1 记录格式

  • 需求:动作与状态变化必须带时标留痕,且保护路径不得因写盘被拖慢。
  • 实现:App/log/soe_rec.c——64 B 定长记录 = 类型 + 元件号 + IV 位 + seq + CP56Time2a + epoch + 值 + 校验和; 六类边沿:元件动作 / 复归、软压板投 / 退、采样数据块 / 恢复。
  • 判据:/log/soe.log 经 FTP 下载后逐条解码通过(校验和、seq 严格 +1、CP56 与 epoch 交叉一致)。

FR-SOE-2 落盘与上送

  • 需求:写盘单写者;104 变位与落盘记录同源同时基。
  • 实现:protectTask 投递 SPSC 环(深度 8,禁 DBG)→ defaultTask 排空落盘; 104 自发单点换 M_SP_TB_1(带 CP56 时标),总召/周期保持 M_SP_NA_1。
  • 判据:动作路径零 NAND I/O(protectTask 静态链 872 B 改前后不变);104 时标 = 事件上送时刻, 与落盘记录(事件发生时刻)差 ≤ 一拍 + 排空延迟(≤50 ms)。

FR-SOE-3 记录体系(✅ 软件面已落地;真机判据待台架)

  • 现状:七类文本记录(运行 / 自检 / 事故 / 告警 / 启动 / 操作 / 遥控)+ 二进制 SOE 已落地, 「记录类型 = 日志 ID 本身」(一类记录一个文件,记录体内无类型字段位);UI 六页已绑 (记录 5 页 + 运行报告,2026-10-28)。运行报告的四个数取自 boot_stats(SD2506 用户 SRAM 上电次数 + 本次复位原因快照)与 iec104_serv 的四个只读观测计数,经 info 帧下发 (口径 docs/UI设计/UI_数据供给设计说明.md §4.4)。
  • 判据:五类记录各有写入点、可翻最近 20 条、空记录明确显示"无记录"、共用 reader——软件面已满足 (空态与四个范围标签由 66 张像素黄金钉住;模拟器侧这些文件没有写入方,只拍到空态)。 真记录翻页、掉电后保持、清除记录后归零、boot_count 自增与四态判定待台架复核 (docs/任务规划/登记簿.md §7)。

5.15 IEC 60870-5-104 上行(FR-IEC104)✅

本产品为被控站(受控端):104 TCP 服务器,端口 [comm] 段 port(工厂默认 2404),主站主动连入。 点表口径见 §6.8,设计细节见 docs/子系统设计/IEC104上行设计说明.md。

FR-IEC104-1 链路层

  • 需求:APCI U/S/I 帧、STARTDT/STOPDT/TESTFR、k/w 窗、t1/t2/t3;TCP 流重组与坏帧自恢复。
  • 实现:App/protocol/iec104/iec104_link.c(纯逻辑:收=喂流、发=回调、时基注入);参数 k=12 / w=8 / t1=15 s / t2=10 s / t3=20 s;序号 15 bit 回绕、超时一律差值法。
  • 判据:主机侧 174 断言全绿;台架主站往返 STARTDT → 总召四组 → actterm 全通过。

FR-IEC104-2 遥测上送

  • 需求:遥测短浮点、系数 1、点号落在 0x4001 起的遥测段(段基址见 复刻明细 §1);支持背景/总召、 周期(60 s)、死区与品质上送。
  • 实现:数据源 = 测频与遥测快照(§5.11);品质直传,CLIPPED 映射为 IV;死区运行时副本(运行参数段可读写)。
  • 判据:总召读回值与 UI 同源一致;死区两拍确认、品质翻转直报;削顶五路恒 IV。

FR-IEC104-3 遥信上送

  • 需求:双位置遥信上双点、其余单点;变位突发 + 背景扫描;无效点也入表并置 IV。
  • 实现:iec104_pts.c 点表(33 点)+ COV 判定;突发单点带 CP56 时标。
  • 判据:YX15~18/23/31 为活数据;YX1~14/19~22/24~30/32~33 恒 IV(缺行比置 IV 更糟)。

FR-IEC104-4 遥控

  • 需求:双点命令两段式(选择 82H / 执行 02H),失配或越界否定确认。
  • 实现:YK11 信号复归 → 跨上下文复归请求;YK12 全局软压板 → 定值原子写; YK1~4 开关、YK13 电池活化、YK14 解除闭锁 = 否定确认(无硬件)。
  • 判据:YK11/YK12 两段正答且行为可观测(压板退出态跨复位保持);否定确认带正确 COT + PN。

FR-IEC104-5 定值与运行参数读写

  • 需求:C_RD 读、C_SE_NC 两段写;地址即定值表 comm_addr;写成功即持久化。
  • 实现:见 §5.13;路由顺序 = run_par 表先、未命中落 prot_set。
  • 判据:读回一致、越界否定、断电重启保持。

FR-IEC104-6 对时

  • 需求:主站 C_CS 对时写入设备墙钟;时标无效如实置 IV。
  • 实现:CP56 → epoch ms → sys_clock(含 RTC 写回);epoch >2^32 显式拒绝回 PN。
  • 判据:对时后日志时间戳跟随主站;C_CS 后 SOE 时标同步。

FR-IEC104-7 响应时间(点表推荐值)

参数 要求 本产品实测 / 设计
终端启动时间 ≤100 s 开机到 net init: OK ≈0.6 s,到 104 监听 <2 s
104 连接 / 总召 ≤3 s / ≤8 s 连接 <1 s;总召分片 + 单轮 4 ASDU 预算,实测远小于 8 s
SOE 上送 ≤5 s 变位到上送 ≤120 ms
遥控选择 / 撤销 / 执行 ≤5 s 同轮应答(ms 级)
读定值 / 改定值预置 / 执行 ≤10 s / ≤5 s 同轮应答(ms 级)
读文件目录 / 文件 ≤30 s ⬜ 未实现(文件传输未立项)
录波文件存储 ≤15 s ⬜ 未验收(代码面 2026-10-29 已交付:/wave 段文件 + FTP 取回;本波按 1 kHz / 8 路 / 单段做;≤15 s 时限未测,80 点/周波属二期;卡片见 docs/任务规划/故障录波.md)

FR-IEC104-8 单连接与自愈

  • 需求:单连接语义(CH395F 单 socket);断链自动重听;网络重建(改 IP)后服务自愈;协议故障主动拆链。
  • 实现:监听与数据通道复用同一 socket(EOF 时 net 层 auto_relisten,应用层不关 fd); net_get_generation() 变化即重建;坏帧 / N(R) 倒退 / t1 超时 / 发送 3 连败 → 本端拆链促主站重连。
  • 判据:断链后自动恢复监听;改 IP 后重建;V0.1 为首到优先(后连优先需 net 层支持,未实现)。

FR-IEC104-9 本期未实现项(如实登记,均为 §9.1 复刻进度条目)

项 原因 归属
多主站 / 双链路冗余 单连接 socket 语义;后连优先需 net 层扩展 规模型
归一化值 / 标度化值上送 点表要求短浮点(系数 1),无需另做 不适用
双点遥信带时标 V0.1 双点恒 IV,无意义 随开入硬件(X3)
定值区切换 / 定值文件下装 产品未定义多定值区(参考有 4 区) 规模型
文件传输(目录 / 读文件 / 录波) 录波已立项,段文件取回走现成 FTP(21 端口);规约侧文件服务仍未做 规模型
固有参数 8001H~800AH 字符串类无法短浮点上送 规模型
主站 IP 白名单 单 socket 上"拒绝"= 断链重听,可被扫描打成 SPI 风暴且易锁死真主站 不适用

5.16 屏板链路:串口主通道 + 网络镜像(FR-HMI)🔶

口径(2026-10-28 定版):参考产品的屏与键不在主机板上。主机侧源码里 5 个"碰硬件"的函数 KeyGet() / WriteScreenByByte() / LCD_LED_Update() / getRs485Key() / anyNewKey() 全树只有声明、没有实现(由屏板 BSP 库提供);按键轮询函数名即 Key_Rs485_Process() (注释"轮询从485传来的按键值");屏板插槽号 CN_SLOT_DISP = 0(注释"显示板插槽号固定为0")。 结论:屏和键都在一块独立的屏板板件上,主机只负责"送帧 + 收键"。本产品与参考同构, 不在本仓实现的只剩那块屏板板件硬件本体(独立工程 DTU-LCD);主机侧"送帧 + 收键"链路是范围内待做(§5.16)。

两条通道,串口为主、网络为镜像:参考把同一份显存同时喂给两个出口——串口屏板通道 (LCD_LED_Update 变化驱动 + WriteScreenByByte 500 ms 兜底)和网络显示总线(TCP 7003)。 也就是说"显示信息不只走网络,还走串口"。本产品目前只有网络这一路,串口屏板通道整条缺失 (§5.16.9 第 11 条),这是本项复刻的最大缺口——没有它,产品无法脱离 PC 独立带屏运行。

屏板固件已到手(2026-10-28):屏板侧源码在 D:\Code\DTU Code\DTU-LCD(STM32F103ZE + UC1698U 160×160 单色 + 20 路状态指示灯 + 7 个物理按键),物理层与帧格式全部可从代码确定,见 §5.16.2、§5.16.3。 该链路不是可选项:屏板是主动召唤方,主机不应答则屏板无画面、无灯、无键。

5.16.1 一份显存、两个出口(串口为主,网络为镜像)

参考的 HMI 只有一份显存(g_tVsr[0].pwbyLCDMemory,物理基址 CN_VIDEO_ADDRESS_BASE = 0xC1F00000, 非 cache 区,3200 B),但有两个互不影响的出口——串口屏板通道是主通道,网络总线是镜像:

出口 归属任务 调用 下行载荷 节拍
串口屏板通道(主) tDisp(Dsp_Main) LCD_LED_Update(ptr, 3200, ledbuf, 4) 显存 3200 B + 面板 LED 4 B 变化驱动(anyNewKey() || LCD_UPDATE_FLAG)
串口屏板通道(周期兜底) tRemoDisp(RDisp_Main) WriteScreenByByte(byLcdMemory) 显存 3200 B 500 ms(tTimerLCD)
网络显示总线(镜像) tRemoDisp(RDisp_Main) RDisp_Proc / RDisp_Send 0xAA/0xBB 帧(INIT/KEY/LCDMEM) 客户端召唤驱动

上行(按键)同样是两条,最后在 Key_Read() 汇合:

上行通道 采集方式 载荷 与另一路的关系
串口屏板通道(主) getRs485Key() 轮询 + anyNewKey() / ClearNewKeyEvent() 事件 物理键号 1~9(实测 7 个物理键,§5.16.3 ②) 映射为逻辑键值写入 g_tKey
网络显示总线(镜像) RDisp_Proc_SaveKey → g_tRemoteKey 键值位掩码 1 B 写入 g_tRemoteKey
汇合点 Key_Read()(Key.c:199) — 先取远程、再被本地覆盖——两键同时挂起时本地(串口)优先

串口通道的物理层与协议以屏板源码为准(§5.16.2 / §5.16.3)。参考主机侧源码给不出物理层, 只能给出调用契约——能确定的只有这几项:

契约项 已确定的内容 依据
下行粒度 3200 B 整帧 + 4 B LED,一次调用一帧(无分片参数) LCD_LED_Update(ptr,len,ledbuf,ledbuflen) 签名
上行粒度 单字节物理键号,0 表示无键 getRs485Key() 返回 uint8_t,Key.c:176 判 key == 0 即返回
事件语义 有"新键事件"与"清除事件"两个动作 anyNewKey() / ClearNewKeyEvent()
屏板地址 板件槽号 0(CN_SLOT_DISP) Key.c:8 注释"显示板插槽号固定为0"
屏板初始化 Lcd_init_display(0xC1F00000) 由 LocalDisp_StartTask() 调用,不经过任何 UART 打开动作 Disp_Main.c:56

5.16.2 串口通道:物理层与帧格式(屏板源码实测)

屏板固件工程 DTU-LCD 已在手(STM32F103ZE / 512 KB Flash / 64 KB RAM / 72 MHz,UC1698U 160×160 单色), 链路协议逐字节可确定,本节即主机侧必须实现的契约。

⚠ 角色与直觉相反:屏板是 Modbus 主站,主机是从站。 屏板主动发请求,主机在请求后应答; 主机从不主动推送,也不允许主动推送(半双工总线,谁先说谁占用)。 这与 §5.16.4 的 TCP 7003 通道方向相反——网络通道是客户端召唤,串口通道是屏板召唤。

物理层

项 屏板侧实测值 依据
接口 RS-485 半双工 rs485.c
引脚 TX = PA2、RX = PA3、DE = PA1 rs485.h
DE 极性 低 = 发送,高 = 接收 RS485_SEND_ENABLE() 拉低、RS485_RECEIVE_ENABLE() 拉高
波特率 700000 bps #define BAUDRATE 700000
数据格式 8 数据位 / 无校验 / 1 停止位,无流控,16 倍过采样 rs485.c 初始化
接收 HAL_UARTEx_ReceiveToIdle_IT(空闲断帧),DMA 版本被注释掉 rs485.c:192-195
发送 HAL_UART_Transmit(..., 1000) 阻塞发完,随即切回接收 RS485_SendBuff()
缓冲 RX 4208 B、TX 8 B UART_RX_LEN / UART_TX_LEN

700 kbaud 在两种候选时钟下都零误差:16 倍过采样(OVER8 = 0)时 USARTDIV = fCK / (16 × 波特率),写入值 BRR = (整数部分 << 4) | (小数部分 × 16)。

  • 屏板链路的默认端口 USART1 挂 APB2 = 84 MHz:84 000 000 / (16 × 700 000) = 7.5 → 整数 7、小数 8 → BRR = 0x0078,误差 0 %。
  • 若改用 APB1 上的实例(UART4 / USART2 / USART3,42 MHz):42 000 000 / (16 × 700 000) = 3.75 → 整数 3、小数 12 → BRR = 0x003C,误差 0 %。

若改时钟树或改用 HSI,必须重算——700 kbaud 下 2 % 误差已足以丢帧。

屏板自己那侧不是零误差:它的串口挂 APB1 = 36 MHz,UART_BRR_SAMPLING16(36e6, 700000) → BRR = 0x33(USARTDIV = 3.1875)→ 实跑 705 882 bps,比标称高 0.84 %;它源码里「手动写精确 BRR」 那段注释后面没有对应代码。与主机侧的 0 % 合起来 0.84 %,8 位数据 / 1 停止位(10 bit/帧)下在容差内; 但位宽与整帧耗时的实测判据要按 705 882 算,不是按 700 000(1 字符 ≈14.17 µs、整帧 ≈59.6 ms)。

端口裁定(用户决定,2026-10-28):屏板走 USART1,日志口让位。 屏板链路改用 USART1(PA9/PA10)——这条通道是 MCU 引脚直出 TTL,不经过板上任何收发器, 因此收发器速率上限问题不复存在:本板 485 通道上的 U15 = TP8485E-SR 只有 250 kbps (docs/芯片手册/TP8485E-SR.md)这件事,对屏板链路不再构成约束。 作为交换,调试日志迁到 RS-232 通道(V0.1 板上 RS232#3 = USART2 PD5/PD6, 备选 RS232#1 = UART5 PC12/PD2,两者都经隔离器 → U13 TPT3232E → CN1), 迁移已实施——控制台现走 UART5/RS232#1,见下方"主机侧端口重排"。

PA10 一直是接线的(2026-10-28 用户确认)→ 屏板链路不需要额外飞线。

ORE 锁存的充分条件与接线无关——RX 使能了却从不读 DR:线上只要出现 任意一个字节或一个噪声沿,RXNE 置位后没人读,下一个事件就把 ORE 锁存;而 ORE 只能用 "先读 SR 再读 DR"清除,于是永不自愈。这条对本实现有一条硬要求: 屏板链路要用 RX,就必须真的消费 DR,并在 HAL_UART_ErrorCallback 里清 ORE 后重挂接收 (否则一次噪声就永久锁死,症状与"屏板不回帧"一模一样)。

帧 A:召唤 / 按键(屏板 → 主机,固定 6 B)

偏移 长度 字段 取值
0 1 从站地址 固定 0x01(主机的从站地址,不是屏板地址)
1 1 功能码 固定 0x03(读保持寄存器)
2 1 命令类型 0x00 = KEY_CMD(按键事件,立即召唤)
0x01 = RT_CMD(周期刷新,280 ms 一次:RT_count > 55,第 56 拍 × 5 ms)
3 1 按键值 KEY_CMD 时有效(见 §5.16.3 键值表);RT_CMD 时恒为 0(按键发完即清 key_bk,见 RS485_Process())
4 1 CRC-16 低字节 CRC-16/MODBUS
5 1 CRC-16 高字节 同上

CRC-16/MODBUS(多项式 0xA001 反转式、初值 0xFFFF、查表法), 只覆盖前 4 字节,低字节在前——这是标准 Modbus RTU 的线上顺序(教科书校验值:数据 123456789 → 0x4B37,线上写 37 4B)。

⚠ 屏板源码里的字节序注释是反的,别照抄:Calculate_CRC() 返回的不是标准 CRC 值,而是高低 互换后的「线上字」(123456789 它返回 0x374B)。于是 RS485_RefreshScreenCMD() 里那句 cmdbuf[4] = crc>>8(注释写"CRC校验高字节")实际写出去的是低字节——两处命名都反,线上字节是对的。 主机侧按「标准值 + 低字节在前」实现,两侧字节逐一相同;若照字面写成"高字节在前",屏板会把每一帧 都判成 CRC 错,而它的超时判定只看"收没收到一整包"、不看 CRC,现场只表现为画面不刷新, 极易误判成波特率或时序问题。实测向量与实现见 Drivers/BSP/ScreenLink/sb_proto.c 文件头。

帧 B:图像应答(主机 → 屏板,固定 4208 B)

偏移 长度 字段 说明
0 3200 Picture[] 显存位图:160 行 × 20 B/行,1 bpp,MSB 在前,bit=1 → 白
3200 4 info[0..3] 普通图:LED 状态,32 位位掩码,小端(info[0] = bit0~7)
LOGO 图:info[0..1] = 宽、info[2..3] = 高(均大端)
3204 1 info[4] LOGO 魔数高字节 0x89
3205 1 info[5] LOGO 魔数低字节 0x45
3206 2 info[6..7] 保留,屏板不读
3208 998 保留填充 屏板不读,但参与 CRC 计算,须固定填充(建议 0x00)
4206 2 CRC-16 覆盖 [0, 4205],低字节在前(与帧 A 同一口径,见上方的字节序说明)

⚠ 帧长以代码为准:4208 B(屏板 readme 与 BMP_LEN 写的"3208 字节"不作准):接收侧实参是 Check_CRC(DR, UART_RX_LEN),UART_RX_LEN = 4208 → CRC 取 DR[4206]/DR[4207]、覆盖 DR[0..4205]。 有效载荷只有前 3208 B,其后 998 B 为凑齐 CRC 窗口的填充;主机只发 3210 B 时屏板会在 DR[4206] 读到陈旧字节,CRC 必失败并静默丢弃。已台架与真屏板实测固化(屏板出图 = 端到端证据,docs/子系统设计/屏板链路设计说明.md §9.1)。

⚠ 应答帧不是合法 Modbus RTU 响应:没有地址、没有功能码、没有字节数域,是一段裸二进制块。 因此不能套用现成 Modbus 从站栈,只能按上表手工组帧。

⚠ 同一 4 字节双解释:info[0..3] 在普通图里是 LED 位掩码、在 LOGO 图里是宽高。 区分只靠 info[4..5] == 0x89 0x45。先判魔数再解释这 4 字节,顺序不能反。

时序与预算

参数 屏板侧常量 实际时间 含义
基准节拍 5 ms 定时器 — Process_Count() 每 5 ms 递增
周期召唤 RS485_RT_COUNT_MAX = 55,判据 RT_count > 55 280 ms(第 56 拍 × 5 ms) 无按键时每 280 ms 召唤一次;屏板 readme 与常见口径写的 275 ms 是按 55×5 算的
应答超时 RS485_ACK_COUNT_MAX = 40,判据 ACK_count > 40 205 ms(第 41 拍 × 5 ms) 到点只置「可以重发」标志 + 累计一次超时——不丢已收字节、不清缓冲、不重启串口;计时起点是召唤帧最后一位的 TC
迟到的应答 收帧处理与超时判定相互独立,帧里没有序号 — 超过 205 ms 才到的完整帧照样显示(当成下一轮的应答,无从区分);代价 = 多一轮画面滞后 + 一次超时计数
有按键待报时 收到帧或超时即打开发送闸门 最早 约 205 ms 就可能再来一帧 上一答还在总线上 → 双向对撞;且键只发一次不重试(发完立刻清备份)→ 错过那一轮 = 丢键
收到任意一包 无论 CRC 是否通过 — 超时阶梯全部清零(ACK_count / ACK_OverTimeCnt)→ 主机把帧发断,屏板也不报超时,只表现为画面不更新
连续超时 RS485_ACK_OVERTIME_MAX = 5 5 次 连续 5 次超时 → 强制允许重发(不重启串口,重初始化被注释)
屏板自复位 sysRunTime > 1 000 000 ≈5000 s(83 min) 屏板自己无条件 HAL_NVIC_SystemReset()

真正的硬约束不是 200 ms,是下面三条(按风险排序,均出自屏板源码):

  1. 整帧零间隙:屏板按「总线空闲 1 个字符时间」断帧,而它的串口 IP 没有接收超时寄存器可调 (该系列 USART 只有 SR / DR / BRR / CR1 / CR2 / CR3 / GTPR)。705 882 bps 下 1 字符 ≈14.17 µs, 间隙 ≥2 字符(约 28 µs)必把一帧切成两帧,两半都过不了 CRC——这条才是卡主机实现方式的约束。
  2. 必须正好 4208 B:CRC 固定取 DR[4206]/DR[4207]、覆盖 DR[0..4205],实收长度被丢弃 → 短帧永远通不过(998 B 填充是承重的);超过 4208 B 会让它把正在处理的那一帧撕裂(收满即回调、缓冲从头再填)。
  3. 绝不让它溢出:一旦 ORE 就永久收不到(它错误回调里的重启被注释掉),而屏幕上没有任何通信状态指示 (运行灯翻转被注释、故障显示函数无人调用)→ 唯一症状是「画面与状态灯一起冻死」,只能断电重上或等 83 min 自复位(自复位后是白屏,没有开机 LOGO)。此外它下发 LOGO 时要写 Flash + 4×500 ms 延时, 那段时间既不能处理也不能应答,是最容易撞上本条的窗口。

所以主机侧整帧必须一次性交给 DMA + 发送完成中断,不要逐块阻塞发:任务态轮询随时可能被几十 µs 的 ISR 抢占,一抢就撞第 1 条,而后果在屏板侧完全不可见。时间预算 4208 × 10 bit ÷ 705 882 ≈ 59.6 ms (按标称 700 000 算是 60.1 ms),占 280 ms 周期约 21 %;「≤200 ms 内发完」仍是我们对自己的要求—— 理由是不与下一轮召唤撞总线、不多一轮画面滞后,不是因为屏板会把迟到的帧判废。宿主与起发方式见 docs/子系统设计/屏板链路设计说明.md §1(uiTask 组帧 + USART1 空闲中断点 DMA 起发)。

主机侧端口重排(2026-10-28 用户裁定)

串口 引脚 V0.1 板上通道(docs/硬件平台/V0.1_网表详细分析报告.md §4.2) 重排后用途
USART1 PA9 / PA10 调试口 + U5 直连 TTL(ST_TX0/RX0),MCU 直出、不经任何收发器 ✅ 屏板链路(700 kbaud)
USART2 PD5 / PD6 RS232#3(U10 隔离 → U13 TPT3232E → CN1) 已初始化、固件未占用(日志最终选了 UART5)
UART5 PC12 / PD2 RS232#1(U9 隔离 → U13 → CN1) ✅ 调试日志(115200,已迁移、台架在用;端子见 docs/子系统设计/屏板链路设计说明.md §3.2)
UART4 PC10 / PC11,DE = PA15 RS485#4(U11 隔离 → U15 → A/B → CN1) 冻结簇,本项不碰
USART3 PB10 / PB11 U5 直连 TTL(ST_TX2/RX2) 空闲

为什么是 USART1:它是唯一一条不经收发器、MCU 引脚直出的通道,而 700 kbaud 恰好卡在收发器上 (U15 = TP8485E-SR 只有 250 kbps,docs/芯片手册/TP8485E-SR.md)。换到这条线上,速率问题从根上消失, 也不用改任何硬件。UART4 保持 RS-485 冻结簇不动——rs485_init(&g_rs485, &huart4, …) 与 V0.1 一致,无需摘除。

这次重排的落地形态(2026-10-29 已实施):控制台端口已收口成 App/log/console_log.c 的 CON_UART* 单点宏(句柄 / IRQn / 时钟 / 自愈 con_uart_reinit() 一体,现指向 UART5/RS232#1), 换口只改那一段——当初"日志口迁移不是一行改动、建议收口成一处可配置端口宏"的顾虑由此闭环。

⚠ TTL 直连没有方向控制:主机侧不再有半双工方向切换,建立时间、"等 TC 收尾"一类约束全部不适用。

⚠ 主机 RX 只需吃下 6 B 召唤帧(不像屏板要吃 4208 B):16 B 缓冲 + 空闲中断断帧就够——TX / RX 是两根独立线,无自发自收。

本节描述屏板固件实际做什么——决定主机侧要下发什么、以及哪些语义必须由产品自己定义。

① 状态指示灯(4 B 位掩码下行)

屏板有 20 路 LED,由主机每帧的 info[0..3] 控制。解码规则(LED_Printf):

leddata = (ledbuf[3]<<24) | (ledbuf[2]<<16) | (ledbuf[1]<<8) | ledbuf[0];  /* 32 位小端 */
LED_POW(LED_ON);                                                           /* ID 0 无条件常亮 */
for (i = 1; i < LED_COUNT; i++)                                            /* LED_COUNT = 20 */
    LED_Set(i, (leddata & (1UL << i)) ? LED_ON : LED_OFF);
  • ID 0 = 电源灯,硬件常亮,不受位掩码控制(leddata 的 bit0 被忽略)。
  • ID 119 一一对应 bit1bit19;bit20~bit31 未使用,填 0。
  • 全部低电平点亮(LED_ON = 低)、推挽输出、内部上拉、高速模式。
  • 只在普通图像帧到达时刷新;LOGO 帧走另一分支,不动 LED。

屏板侧 LED 引脚表(led_config[20],仅备查——主机不直接驱动):

ID 引脚 备注 ID 引脚 ID 引脚 ID 引脚
0 PC8 电源灯,常亮 5 PC11 10 PC7 15 PC12
1 PC9 运行灯 6 PD0 11 PA8 16 PD1
2 PA9 7 PD2 12 PA10 17 PD3
3 PA11 8 PD4 13 PA12 18 PD5
4 PA15 9 PD6 14 PC10 19 PD7

对本产品的含义:§5.8 的主板 6 路 LED(LED1~6)与屏板 20 路指示灯是两套独立输出, 语义不同——主板 LED 表"设备自身状态",屏板指示灯是"操作员面前的状态/告警灯组"。

⚠ 位掩码 → 业务状态的映射表,参考源码里没有。参考的 LCD_LED_Update(ptr, 3200, ledbuf, 4) 只证明"主机侧填这 4 B",填哪几位对应哪个业务状态在未实现的屏板 BSP 里。 因此"哪几号灯表哪个状态"必须由本产品定义(建议按 §5.8 的 6 路语义扩展到 19 路, 并保留 1~2 路作屏板自检/通信状态)。这是本项唯一需要"新设计"而非"照抄"的地方。

② 按键上行

项 屏板侧实测
库 MultiButton,只绑 BTN_SINGLE_CLICK(单击事件)
扫描 5 ms 定时器内 Button_Ticks()
电气 输入模式、无内部上拉/下拉(依赖外部)、低电平有效
引脚 KEY_ENTER=PD12、KEY_UP=PD11、KEY_DOWN=PD10、KEY_LEFT=PD13、KEY_RIGHT=PD8、KEY_ESC=PB15、KEY_RESET=PB3
JTAG PB3 需 __HAL_AFIO_REMAP_SWJ_NOJTAG() 才能当普通 GPIO
回调 任意键按下 → BackLight_ON() + 更新 keyStatus,主循环转交 RS485_Process()

键值枚举(KEY_TYPE,即帧 A 偏移 3 的 key 字节):

值 名称 值 名称
0 KEY_NONE(无键) 5 KEY_ADD
1 KEY_ENTER 6 KEY_DEC
2 KEY_UP 7 KEY_LEFT
3 KEY_DOWN 8 KEY_RIGHT
4 KEY_ESC 9 KEY_RESET
10 KEY_FACTORY

⚠ 两套键号只在 1~8 对齐,9/10 语义不同,必须显式建映射:

语义 屏板 KEY_TYPE(帧 A 的 key) 参考主机 getRs485Key() 物理键号
确认 ENT 1 1
上 UP 2 2
下 DOWN 3 3
取消 ESC 4 4
加 ADD 5 5
减 SUB 6 6
左 LEFT 7 7
右 RIGHT 8 8
9 KEY_RESET(复位键) F1
10 KEY_FACTORY(工厂模式键) F1|ENT 组合

帧 A 的 key 字节只能按屏板枚举解释。主机收到 9/10 时不得按 F1 / F1|ENT 处理。 若产品要求保留 F1/F2 语义,只有两条路:改屏板固件 或 在主机侧加语义映射表——二者选一,须先定。

⚠ key_configs[] 只有 7 项,且与枚举不自洽:表内第 7 项为 {PB3, KEY_RESET}(注释却写"加键"); 枚举有 KEY_ADD(5) / KEY_DEC(6) / KEY_FACTORY(10),但 key_configs[] 没有映射任何 ADD/DEC 物理键。 即实物只有 7 个物理键(上/下/左/右/确认/取消/复位),ADD/DEC/FACTORY 有枚举无入口。 屏板 readme 的按键表列了 8 个键,与代码不符——以 key_configs[] 的 7 项为准。 这直接影响 §5.16.9 第 8 条"补 F1/F2"是否成立:屏板上根本没有 F1/F2 物理键, 网络通道的 8 键表是给远程工具用的;串口通道只可能收到 1/2/3/4/7/8/9 这 7 个值 (5/6/10 有枚举无入口)。

③ 背光

  • 任意键按下 → BackLight_ON()(按键回调里,不在 5 ms 定时器内)。
  • 5 ms 定时器每拍调 BackLight_Close(),超时熄灭(时长在 160160D.C,屏板自管)。
  • LOGO 帧到达时也会 BackLight_ON()。
  • 主机侧不参与背光控制——参考主机的 Lcd_BackLight() / 空闲 120 s 熄灭在主机 BSP里, 而屏板固件自己就管背光,两条路径不能同时启用。本产品按"屏板自管"实现,主机不做(§5.16.9 第 14 条)。

④ LOGO 与 Flash

  • 魔数命中(info[4]==0x89 && info[5]==0x45)→ 按 LOGO 处理: Picture 存入屏板 Flash 0x0803F000(扇区 126),宽高取 info[0..1] / info[2..3](大端), 然后点背光、ClearScreen()、LOGO_Printf()、延时 2 s(4 × delay_ms(500))。
  • 上电时 BMP_Get() 从同一地址读回并显示。
  • LOGO 帧不刷新 LED、不进入常规画面;一帧 LOGO 会永久覆盖屏板上一次的 LOGO。
  • LOGO 下发已出局、不实现:主机侧不提供该操作,总线上不会出现 info[4..5] = 0x89 0x45 的帧。

⑤ 屏板自身的健壮性机制

机制 实现 对本产品的影响
CRC 错计数 连续 ≥3 次错 → 计数清零(重初始化串口被注释掉) 错帧静默丢弃,链路不会自愈,只能靠下一次召唤重试
应答超时 第 41 拍 = 205 ms;连续 5 次 → 只是打开重发闸门(重初始化被注释掉) 主机长时间不应答不会锁死屏板,恢复后自动续上。但两个坑:① 收到任意一包就清零计数、不看 CRC → 主机把帧发断时屏板也不报超时,只表现为画面不更新;② 真会永久锁死的是接收溢出(§5.16.2 硬约束 3),不是超时
系统自复位 sysRunTime > 1 000 000(≈5000 s)→ HAL_NVIC_SystemReset() 每 83 分钟屏板重启一次,约 1 s 空窗
看门狗 5 ms 定时器内 Clear_Watchdog() 主循环卡死 → 屏板复位
DMA 接收 屏板提交记录明写"DMA 接收的问题没有解决" 长帧接收可靠性未经充分验证,台架必须压测

⚠ 5000 s 周期性自复位必须被主机容忍:复位期间屏板约 1 s 不响应召唤。 主机的链路监视不能把这种周期性空窗判成"屏板掉线",更不能联动告警/保护。 判据建议:连续 ≥ 10 s 无任何应答才置"屏板离线"。

待与屏板固件方确认的 4 项(不影响本产品先开工,但验收前必须闭环):

  1. Check_CRC 用缓冲区容量而非实际接收长度,短帧会被误判;是否计划改为传 Size。
  2. 键值 9 / 10 是否要改成 F1 / F1|ENT(对齐参考),还是保持"复位 / 工厂"语义。
  3. key_configs[] 是否要补 ADD / DEC 物理键(当前 7 键,枚举 11 项)。
  4. 屏板 4208 B 接收缓冲与 700 kbaud 在长线(> 50 m)下的误码率实测数据。

5.16.4 链路 B 帧格式(逐字节)

项 规格
传输 TCP 7003;设备为 Server(TcpAddServer + TcpAddConnection(..., EN_NET_MODE_SERVER, RDisp_MsgRecv));目标 IP 填 255.255.255.255 = 接受任意客户端
连接参数 TcpSetConnPara(iTcpNo, 10240, 10240, 0, 30, 5);收发缓冲各 10240 B
建链条件 getnetport() != 1 才建 Server(该函数源码无注释,疑为单网口板件跳过本链路;未验证,勿照抄此条件)
帧结构 [TAG 1B][CMD 1B][LEN_H 1B][LEN_LO 1B][DATA nB][CRC 1B]
TAG 0xAA = 客户端→设备(CN_RDISP_C_TAG);0xBB = 设备→客户端(CN_RDISP_R_TAG)
LEN 数据段长度(不含 4 B 头与 CRC),大端
CRC 数据段逐字节异或(RDisp_CalCrc),不覆盖头与 CRC 自身
最长帧 CN_RDISP_FRAME_LEN_MAX = 9800(数据段上限)
接收定界 逐字节找 0xAA(最多 10240 次防死循环)→ 再收 3 B(CMD+LEN)→ LEN > 10237 视为噪声重新同步 → 再收 LEN+1 B(数据+CRC)→ 返回 LEN+4

接收侧不校验 CRC:RDisp_MsgRecv 只做定界;CRC 只在 RDisp_Proc_LcdMem / RDisp_Proc_SaveKey 内比对,且 INIT / KEEPLIVE 帧根本不校验。这是参考的既有行为, 本产品在全帧校验上更严(见 §5.16.9 第 10 行),不作退让。

5.16.5 命令集与数据段布局

CMD 名称 客户端请求 设备应答 备注
0 KEEPLIVE 空 不应答 源码 return,注释"无 keep alive 报文";仅重置 1 分钟通信计时
1 INIT 空 16 B(见下表) 工具召唤屏幕参数
2 KEY [键值 1B] 空(LEN=0) 键值写入 g_tRemoteKey,byKeyValid = EN_KEY_FLAG_NEW
3 LCDMEM [起始偏移 4B 大端] [起始偏移 4B][显存 nB] 支持断点续传;拒绝语义见 §5.16.6
4 ACK — — 参考 RDisp_Send 中为空分支,未使用
5 NCK — — 同上,未使用
0xFF IDLE — — 内部空闲码,不上线

INIT 应答数据段(16 B,即 RDisp_Form_InitInf 的单色子集):

偏移 长度 字段 取值
0 2 LCD 像素宽(大端) UI_SCREEN_W = 160
2 2 LCD 像素高(大端) UI_SCREEN_H = 160
4 4 显存字节数(大端) UI_FB_SIZE = (160*160)/8 = 3200
8 8 键值表 F1/F2/U/D/L/R/ENT/ESC 0x04/0x80/0x02/0x40/0x10/0x08/0x20/0x01

为什么是 16 B 而不是参考的 29 B:参考的 29 B 里有 13 B 颜色信息(1 B 颜色位 CN_RDISP_LCD_TYPE + 12 B RGB CN_RGB_RED/GREEN/BLUE),而这 13 B 在参考自己的构建里就是死字段: RemoDispBus.h:46 的 CN_RDISP_TYPE_MONO = TRUE → 链路显存本身就是 1 bpp;三个 RGB 值是编译期 常量(每次召唤发同样的 12 B);RDisp_LcdColor_To_Mono() 对 CN_MODE_GREY_MONO 直接 return TRUE, RGB565 分支永不进入(§3.1.1)。本产品屏板同为单色 1 bpp(DTU-LCD 的 ScreenPrintf() 只吃 1 bpp 点阵),这 13 B 既无接收方也无语义 → 整段删除,不对齐多色协议:29 − 13 = 16 B。

键值是位掩码,不是枚举——可组合下发:CN_KEY_F1|CN_KEY_ENT = 0x24(Key.c 物理键号 10 即此值)。 CN_KEY_ADD=0x82、CN_KEY_SUB=0x84 只在串口屏板通道使用,不进 7003 键值表。

5.16.6 显存上送的续传与拒绝语义

RDisp_Form_LcdMem / RDisp_Proc_LcdMem 的完整规则:

  1. 分片:dwSendBase + 9800 > 3200 成立 → 本帧发 3200 - dwSendBase 字节;否则发 9800 B。 因 MEMSIZE = 3200 < 9800,实际恒为单帧 3204 B(4 B 偏移 + 3200 B 位图); 分片逻辑为"显存变大"预留,当前不触发。
  2. 推进:发完后 dwSendBase += dwLen;若 >= MEMSIZE → bNeedFlash = TRUE、dwSendBase = 0。
  3. 拒绝:召唤时若 bNeedFlash 为真(上一帧刚发完、新图还没拷贝)→ 返回 -1,且把 dwSendBase 清 0,不应答。含义是"一帧图像只允许被完整上送一次",客户端要下一帧 必须等主机完成下一次刷新。
  4. 越界:dwSendBase >= MEMSIZE → 返回 -2,不应答。
  5. 成功:返回 1,置 wSendCode = LCDMEM,由 RDisp_Send 组帧发出。
  6. 刷新来源:RDisp_Main 每轮检查 bNeedFlash,为真则 memcpy(byLcdMemory, __Lcd_Pub_GetScreenAddr(0), 3200) → RDisp_LcdColor_To_Mono() 转单色 → 清 bNeedFlash、dwSendBase = 0。

RDisp_LcdColor_To_Mono() 这一步本产品不需要(参考自己也不走):该函数按 CN_LCD_TYPE 分派, 而本构建 CN_LCD_TYPE = CN_MODE_GREY_MONO → 命中第一分支直接 return TRUE,不做任何转换; 只有 CN_MODE_COLOR_16B 才调 RDisp_Lcd16B_To_Mono() 做 RGB565 → 单色,那条路是死代码。 本产品的 g_ui_fbuf 本来就是 1 bpp 单色(LVGL 单色渲染,UI_FB_SIZE = 3200),拷贝即可送, 没有"颜色 → 单色"的转换环节。这是"不对齐多色协议"带来的简化之一。

为什么必须有 bNeedFlash 握手:显存由显示任务异步改写,若允许客户端随时按偏移拉取, 跨两次刷新的位图会在客户端拼成撕裂帧。参考用"整帧一次性 + 拒绝重拉"消除这个窗口, 本产品当前无此保护(§5.16.9 第 4 行)。

5.16.7 按键注入与状态机

项 规格
存储 tagRKeyCtrl g_tRemoteKey { byUsrFlg, byKeyValid, byKeyValue, bUseRkey }
有效性 EN_KEY_FLAG_NULL=0(无新键)/ EN_KEY_FLAG_NEW=1(有新键)/ EN_KEY_FLAG_SAM=2(采样中)
注入 收 KEY 帧 → byKeyValue = DATA[0]、byKeyValid = EN_KEY_FLAG_NEW
消费 Key_Read() 读到 NEW 后立即清 NULL(边沿消费,不重复触发)
合并顺序 有本地键板时:先取远程 g_tRemoteKey,再被本地 g_tKey 覆盖——两键同时挂起时本地优先
连接联动 TCP 连上 → bUseRkey = TRUE;断开 → FALSE + wSendCode = IDLE + dwSendBase = 0
背光 Key_HaveNewKey() 每次调用都执行 MenuProc_Have_Key()(无新键也点背光),再返回是否有新键

5.16.8 时序、超时与重试

定时器 周期 作用
tTimerLCD 500 ms 参考主机侧串口屏板通道的周期兜底节拍(WriteScreenByByte)。
⚠ 本产品不照抄:屏板固件自己按 275 ms 主动召唤(§5.16.2),主机只需"来一帧答一帧",无需自带节拍
tTimerComBrk 1 分钟 通信中断判定;每收到任一帧、每次发送成功都重置
tTimerAbandon 200 ms 发送未完成时的放弃窗口

发送状态机(RDisp_Send):

  1. TcpGetSendState(iTcpNo) <= 0 → 直接返回(链路未建或芯片发送忙),不组帧。
  2. wSendFlag == CN_RDISP_SEND_BUSY → 重发上次缓冲;成功 → IDLE + 重置 tTimerComBrk; 失败且 tTimerAbandon 未到 → 返回;已到 → IDLE 后重新组帧(宁可丢帧不阻塞)。
  3. 组帧:byCRC = XOR(DATA);填 TAG=0xBB、CMD、LEN;CRC 写在 DATA 之后。
  4. TcpSend 返回值 必须等于 wMsgLen 才算成功(部分发送视为失败,进 BUSY 重试)。

显存刷新互斥:g_tShareSetBuf.dwReserSet[3] 三态——0xaa = 被其他模块占用(本轮跳过)、 0x55 = 显示已刷新(供远程工具判断)、0 = 空闲。取用前查 0xaa、用后清 0。

任务模型:taskSpawn("tRemoDisp%d", 111, 0x0008, 0x35000, RDisp_Main, ...) ——prio 111、栈 0x35000(212 KB,VxWorks 字节语义)、主循环 taskDelay(1), 每轮 DogTask_InfoUpdate(EN_TASK_DSP, ...) 喂狗,退出时 DogTask_InfoError 报异常。

5.16.9 与参考的差异(本产品当前实现)

# 项 参考 本产品 处置
1 INIT 应答长度 29 B(= 宽高 4 + 颜色位 1 + 显存 4 + RGB 三色 12 + 键值表 8) 8 B(宽 2 + 高 2 + 帧字节 4) 补 8 B 键值表 → 16 B;颜色 13 B 不对齐(单色屏无接收方,§5.16.5)
2 KEEPLIVE 应答 不应答 回显空 KEEPLIVE 帧 改为不应答(或留兼容开关)
3 LCDMEM 非 0 偏移 支持续传(从 dwSendBase 起) 仅支持偏移 0,非 0 静默忽略 补续传
4 召唤拒绝语义 bNeedFlash 为真 → -1 不发 无 补(防撕裂帧)
5 越界语义 >= 3200 → -2 不发 无 补
6 链路监视 tTimerComBrk 1 分钟 无 补(掉线判定 / 重连驱动)
7 发送重试 BUSY + 200 ms 放弃 依赖 net_send 阻塞模型 评估是否需独立实现
8 键值集(网络通道) 8 键(含 F1 / F2) 6 键(无 F1 / F2) 补 F1 / F2;仅网络通道——屏板无 F1/F2 物理键(§5.16.3 ②)
9 任务模型 独立任务 prio 111 / 栈 212 KB uiTask 10 ms 轮询(prio BelowNormal / 16 KB) 形态差异,不追平(X1 / X2)
10 接收侧 CRC 仅 LCDMEM / KEY 校验 全帧校验 本产品更严,保留
11 串口屏板通道 有:显存 3200 B + 状态灯 4 B 下行、键号上行,变化驱动 + 500 ms 兜底 已交付:700000 8N1、一召一答 4208 B、键号上行(docs/子系统设计/屏板链路设计说明.md) 验收尾巴见该设计说明 §9.2
12 双出口并发 同一份显存同时喂串口与网络,互不阻塞 两出口并存(7003 + 串口通道),60 s 并发台架无互扰 —(屏板链路设计说明 §9.1)
13 屏板状态指示灯 20 路(ID 0 电源常亮 + ID 1~19 位掩码),4 B 小端随每帧下发 已交付:5 位映射 App/algo/sb_led_map.h(屏板链路设计说明 §6);主板另有 6 路 GPIO LED(LED1~6) 逐位目视验收未闭环(设计说明 §9.2)
14 背光 / 对比度 主机 BSP 有 Lcd_BackLight / Lcd_SetContrast + 空闲 120 s 熄灭 无 不做——屏板固件自管背光,两条路径不能同时启用

来自屏板固件的新增约束(参考主机侧源码里看不出来,但对实现是硬约束):

  • 角色反转:屏板是 Modbus 主站(主动召唤),主机是从站 0x01;与网络通道"客户端召唤"方向相反。
  • 帧长 4208 B(3208 B 有效载荷 + 998 B 填充 + 2 B CRC,§5.16.2)。
  • 700000 8N1,主机侧走 USART1 TTL 直连(无方向控制)。
  • 屏板每 ≈5000 s 自复位一次,约 1 s 空窗;主机链路监视须容忍(建议连续 ≥10 s 无应答才判离线)。
  • 屏板只有 7 个物理键,键值 9/10 是"复位 / 工厂",与参考主机的 F1 / F1|ENT 语义不同。
  • 单色:屏板是 1 bpp 单色面板,参考的 13 B 颜色信息(颜色位 + RGB 三色)无接收方,不对齐。

第 1 / 3 / 4 / 5 / 8 条是客户端可见的报文口径差异——现有 DTU-RemoteLCD 按 8 B INIT 实现, 补到 16 B 后客户端必须同步改,否则会错位解析。这是本项复刻唯一的跨端风险点。 注意:16 B 与参考的 29 B 不是同一口径——客户端不得按 29 B 预留缓冲再截取前 16 B 使用 (从偏移 4 起含义即不同:参考偏移 4 是颜色位,本产品偏移 4 是显存大小的高字节)。

第 11 / 12 / 13 条(串口通道三件套)主机侧已交付(docs/子系统设计/屏板链路设计说明.md)——本产品已可脱离 PC 独立带屏运行;仍开放的是第 2~9 条(7003 网络通道报文口径)。

第 14 条已决定不做:屏板固件自管背光与超时熄灭,主机再插一手会打架。

5.16.10 复刻完成判据

  1. 任意 TCP 客户端连 7003 → 发 INIT → 收到 16 B(宽 2 + 高 2 + 显存 4 + 8 键值表), 字段值与 §5.16.5 逐字节一致;不得出现颜色位或 RGB 字段。
  2. 发 LCDMEM(0) → 收到 3204 B;再次发 LCDMEM(0)(新图未就绪)→ 无应答(对应参考 -1)。
  3. 发 LCDMEM(3200) → 无应答(对应参考 -2)。注:该分支在 bNeedFlash 为真时先被 -1 截住, 只能在"新图已拷贝、尚未上送"的窗口内触发,属边角路径,判据以"无应答且不越界读"为准。
  4. 发 KEEPLIVE → 无应答,且链路 1 分钟内不被本端主动断开。
  5. 发 KEY(0x24) → 收到空 KEY 应答,界面表现为 F1+ENT 组合键。
  6. 断开 TCP 60 s 以上 → 设备侧可观测到"通信中断"(日志 / 状态位),重连后自动恢复推流。
  7. 8 键逐个下发 → 界面动作与按键表一致;组合键 F1|ENT 生效。

串口屏板通道(与上面 7 条并列,待建后验收):

  1. 主机上电后,屏板按 280 ms 节拍发帧 A(6 B,形如 01 03 01 xx CRC_H CRC_L);主机每帧在 ≤200 ms 内发完帧 B(4208 B,整帧无 2 个字符时间以上的间隙,CRC 覆盖 [0, 4205]), 主机侧连续 10 分钟零超时、零 CRC 错帧(屏板不指示通信状态,计数只能在主机侧取)。
  2. 帧 B 前 3200 B 与主机 g_ui_fbuf 逐字节一致(160 行 × 20 B,1 bpp,MSB 在前,bit = 1 → 白)。
  3. 屏板 7 个物理键逐个按下 → 主机收到的 key 依次为 1/2/3/4/7/8/9 (ENTER / UP / DOWN / ESC / LEFT / RIGHT / RESET),界面动作与 §8.2 菜单树一致; 0 表示无键、不产生事件。
  4. 状态灯下行:主机把 19 路业务状态映射为位掩码 → 屏板 LED 1~19 的亮灭与掩码逐位一致; LED 0 恒亮、不受掩码控制(bit0 置位不改变任何灯)。
  5. 双通道并发:同一时刻 7003 客户端在拉帧、屏板在召唤,两侧画面一致,互不丢帧、不串帧; 串口侧 4208 B 发送阻塞不得导致 7003 侧超时(反之亦然)。
  6. 屏板自复位容忍:屏板跑满 ≈5000 s 触发自复位,主机不误判"屏板离线"(无告警、不触发保护), 约 1 s 后自动续上。
  7. 拔掉屏板 → 7003 侧不受影响;插回后自动恢复,无需复位主机。
  8. LOGO 下发(出局,不实现):主机不提供 LOGO 帧,本条不参与验收;本表串口侧判据按其余十四条计。

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 被控站接入:遥测/遥信上送、总召、遥控/定值下发(点表见 §6.8) 任意 104 主站连 2404,STARTDT+总召往返(→ docs/子系统设计/IEC104上行设计说明.md)

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

6.2 RemoDispBus 协议

RemoDispBus 帧格式

口径:本节按参考源码(HMI/RemoeDisp/RemoDispBus.c)给线上格式;本产品当前实现与该口径的 逐项差异、以及为什么会有差异,见 §5.16.9。以参考为准,差异项按 参考产品复刻明细.md §11 排期收敛。

本节只讲网络通道(TCP 7003)。串口屏板通道不走本协议——它是 RS-485 上的 Modbus RTU 风格裸二进制帧(6 B 召唤 + 4208 B 图像应答,CRC-16/MODBUS 低字节在前), 帧格式已按屏板源码逐字节定版,见 §5.16.2。 两条通道共用同一份显存,但帧格式、校验、时序、主从方向全都不同,不能共用组帧代码。

项目 内容
传输 TCP,端口 7003;设备为 Server,目标 IP 255.255.255.255 = 接受任意客户端
帧格式 [TAG(1)][CMD(1)][LEN_H(1)][LEN_LO(1)][DATA(n)][CRC(1)]
方向标识 TAG 0xAA = 客户端→服务端,0xBB = 服务端→客户端
校验 CRC = 数据段逐字节异或(低 8 位,不含 TAG/CMD/LEN,也不含 CRC 自身)
字节序 多字节字段大端(网络字节序)
最短帧 5 字节(LEN=0)
最长帧 数据段 ≤ 9800 B(CN_RDISP_FRAME_LEN_MAX)
缓冲 收发各 10240 B(CN_RDISP_BUF_RECV/SEND)
接收方式 逐字节有限状态机(TAG 定界 + 长度定长 + CRC 校验,自动重同步)

命令集:

CMD 名称 请求数据段 应答数据段
0 KEEPLIVE 无 无应答(仅重置 1 分钟通信计时)
1 INIT 无 [宽u16][高u16][显存u32][8 键值](16 B;参考的 29 B 含 13 B 颜色信息,本产品不对齐)
2 KEY [按键码u8] 无(空帧确认,LEN=0)
3 LCDMEM [起始偏移u32] [偏移u32][1bpp位图 3200B](3204 B);偏移非 0 时续传,bNeedFlash 期间不应答

INIT 字段明细与按键码表:见 §5.16.5(含 16 B 逐字段偏移)。

单色口径:本产品只实现单色分支。参考 INIT 里的颜色位 CN_RDISP_LCD_TYPE 与 CN_RGB_RED/GREEN/BLUE(共 13 B)整段删除,不做多色对齐——屏板是 1 bpp 单色面板, 没有彩色/灰度的接收方;参考侧 RDisp_LcdColor_To_Mono() 这道"彩色转单色"也因此不存在 (本产品显存本来就是单色)。

按键码:F1=0x04 / F2=0x80 / UP=0x02 / DOWN=0x40 / LEFT=0x10 / RIGHT=0x08 / ENTER=0x20 / ESC=0x01;位掩码可组合(如 F1|ENTER = 0x24)。

位图格式: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 (本产品侧常量;参考侧对应 CN_RDISP_TCP_PORT / CN_RDISP_FRAME_LEN_MAX / CN_RDISP_MEMSIZE)。

详见 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):口令登录([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 调试串口

项 值
端口 UART5(RS232#1:PC12 TX / PD2 RX,经 U9 隔离 → U13 → CN1 端子),115200 8N1;台架端子接法见 docs/子系统设计/屏板链路设计说明.md §3.2
用途 printf 日志 + /serial-boot-test 采集通道
配置源 .serialtest/config.json(单一配置源)
工具 仓库内置 Python 串口助手(.dsh/skills/serial-assistant/,常驻 daemon + CLI)

启动标记(/serial-boot-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 + 9 个事件位 启动屏障 + 落盘请求
adc_input adc_input_init/poll/raw/desc 语义取数与有效性语义取数(8 电气量 + 温度)
adc_health adc_health_init/report/flags 语义取数与有效性采样有效性判定(纯逻辑)
adc_cal adc_cal_init/apply/flags/set/b_codes/prot_blocked 标定折算 + 三态可用性
phasor phasor_init/run/read 全周傅氏相量(双区)
freq freq_run/get/valid 测频与遥测快照测频(自适应窗)
meas meas_tick/snap 测频与遥测快照(200 ms,双区)
prot_set prot_set_init/load/selfcheck/set_sealed/get/locked 保护判据定值模型(原子写 + 封存)
prot_elm prot_elm_init/run/eval/state/request_reset 保护判据元件框架(9 实例)
run_par run_par_init/get/set_104_write/dirty_peek 运行参数段(死区 + 系数代理)
soe_rec / soe_store soe_rec_encode/decode · soe_store_post/drain SOE 编解码 + 落盘投递
iec104 iec104_link_* / iec104_pts_* / iec104_serv_* 104 链路 / 点表 / 板端胶水

6.8 IEC 60870-5-104 点表摘要

权威口径:验收以《检测平台配电终端送检要求(点表)》为准;本表是 V0.1 实现摘要, 逐点细节与未实现项见 docs/子系统设计/IEC104上行设计说明.md §3。 段基址与参考产品逐字对齐(8 段全表见 复刻明细 §1):遥信 0x0001、保护 0x1001、遥测 0x4001、 参数 0x5001、遥控 0x6001、设定 0x6201、电能 0x6401、步位置 0x6601。 点表规模是当前最大差距:本产品 9 遥测 / 33 遥信 / 2 遥控,参考产品 31 遥测 / 138 开入 / 31 开出。

遥测(0x4001 段起,短浮点,系数 1)

IOA 点 来源 V0.1
4011 / 4014 / 4015 1Ua / 1U0 / 1Ia 遥测快照(TPAFE 侧,有效) ✅
4012 / 4013 / 4016~4018 1Ub/1Uc/1Ib/1Ic/1I0 快照(STM32 侧,削顶) ❌ 恒 IV
4019~401C 1P/1Q/1S/1Pf 需跨转换器同刻 ❌ 恒 IV(V0.2)
401D 1f 频率 测频结果 ✅(未收敛则 IV)
4010 / 401E / 401F UBA 后备电源 / V1/V2 直流 无硬件通道 ❌ 未入表(X3)

与参考的差额:参考 g_tYcIndexTab 共 31 点——双回线各三相电流/电压(12)、双回线各三组 线电压(6)、双回零序电流/电压(3)、频率(1)、直流 2 路(2)、有功/无功/视在/功率因数 单相 3 + 三相 1(4)、电度 8 种另列。本产品 9 点,缺的是第二回线、线电压、零序双回与 功率四量——前者等通道(X4),后两者等标定后的功率运算。

遥信(0x0001 段起,V0.1 定义 33 点):1~4 开关位置(双点,恒 IV)、5~14 预留(IV)、 15 故障总、16~18 过流 Ⅰ/Ⅱ/Ⅲ 段、19~20 零序过流 Ⅰ/Ⅱ(IV)、21~22 接地故障/重载(IV)、 23 过载、24~30 外部遥信(RS-485 冻结 → IV)、31 保护闭锁、32~33 预留(IV)。 有效位图 YX_VALID_MASK = YX15~18 / 23 / 31(6 点)。

与参考的差额:参考 g_tInputModelTab 共 138 点(开关合/分位、未储能、就地远方、接地位置、 隔离位置、停用重合闸、保护投入、检修压板、远方信号、手合手分、电源输入、活化状态、电池欠压…), 另 g_tOutputModelTab 31 点开出(保跳/保合/遥分/遥合/遥控备用/电池活化/电机保护/闭锁…)。 两者都需要一次设备接口硬件(X4),属 §9.1 阻塞型。

遥控(0x6001 段起,双点两段式):YK1~4 开关(否定确认)、YK11 信号复归、YK12 遥控软压板、 YK13 电池活化(否定)、YK14 解除闭锁(否定)。

定值与运行参数:保护定值地址 = prot_set.comm_addr(基址 0x8820,过压/欠压沿用告警段 0x8027~0x802A);运行参数段 0x8030~0x8038(死区 9 点)/ 0x8040~0x8047(k 覆盖 8 路)/ 0x8048~0x804F(b 覆盖 8 路),共 25 项。 逐项地址为本仓自定,送检点表到位后以送检为准替换常量段。

与参考的差额:参考 104 定值映射 107 项占 0x8820~0x8891(8 个空洞), 底层定值表 249 项 / 23 单元。本产品 40 项,缺的是重合闸(16)、电压时间型自愈(17)、 同期(13)、看门狗(63)、遥测越限(10)等整单元(复刻明细 §1)。

链路参数:k=12 / w=8 / t1=15 s / t2=10 s / t3=20 s;IOA 3 字节、公共地址 2 字节、传送原因 2 字节; 公共地址与端口可配([comm] 段,工厂默认 1 / 2404,改后需重启生效)。



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 设计
采样节拍 1000 Hz(每 10 s 帧号 +10000,零丢帧) 台架 /serial-boot-test
单拍采集消费 ≤10 µs(DMA 搬运后实测 8 µs) adc_task 实测
相量刷新 1 ms(每拍整窗重算 5 实例) phasor_run
遥测快照周期 200 ms(经过时间分频) meas_tick
测频精度 45~55 Hz 最坏 0.0101 Hz 主机侧扫频用例
保护判据节拍 20 ms(延时精度由 now_ms 差值保证) protectTask
动作到 104 上送 ≤120 ms(判据拍 + COV + 服务周期) 台架主站往返

7.3 内存与资源预算

权威来源:.map 受管快照(docs/内存管理/RAM使用分析与优化方案.md §2.1,由 scripts/check_mem_numbers.py --write 生成)+ 2026-10-22 栈预算快照 (docs/内存管理/data/stack_report_20261022.md)。本节数值随代码演进会过期,提交前以受管快照为准。

静态区(产品构建,2026-10-24 .map):

区域 用量 容量 占比
Flash ER_IROM1 261,928 B 1024 KB 25.0%
ROM 合计 263,500 B 1024 KB 25.1%
RW_IRAM1 81,072 B 131,072 B 61.9%
RW_CCM 57,376 B 65,280 B 87.9%

运行时栈预算(9 任务,静态最坏链 × 真机水位取更坏者):

任务 配置 静态最坏链 真机峰值 余量 判定
defaultTask 5120 B 3024 B 2152 B 40% ✅
netTask 3840 B 1912 B 1116 B 50% ✅
ftpTask 4096 B 1456 B 740 B 64% ✅
uiTask 16384 B 1336 B 4052 B 75% ✅
testTask 8192 B 736 B — 91% ✅
timeSyncTask 2560 B 1264 B 616 B 50% ✅
adcTask 2560 B 1320 B 952 B 48% ✅
iec104Task 2560 B 1456 B 580 B 43% ✅
protectTask 2048 B 872 B 828 B 57% ✅

定栈规则:改栈或加大栈内局部变量前后必须重跑 scripts/stack_report.py (Keil 静态调用图 × 串口 [STACK] 水位,判定取两者更坏者;余量须 ≥ max(1024 B ISR, 30%))。 LVGL 内存池 16 KB(静态占用,2026-10-15 由 40 KB 收缩);FreeRTOS 堆 56 KB(CCM,水位 87.9% < 92% 门禁)。 卡点已从主 SRAM 移到 CCM(余 ~7.9 KB)——再加任务或抬栈前先看 docs/内存管理/RAM使用分析与优化方案.md §4。

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

测试分层:

层 内容 运行位置
静态门禁 pre-commit 钩子族:格式 / 编码 / 静态分析 / 文档链接 / 体积 / 生成物新鲜度 / 编号 本地 / CI
主机侧纯逻辑单测 MSVC 离线编译真实源码 本地 / CI
板端测试套件 板端套件(testTask 串口 [PASS]/[FAIL] 汇总) 本地(需真机 + 串口)
主机侧回归 模拟器像素 / 池水位回归 + 真机 /serial-boot-test 闭环(含探针) 本地(模拟器免硬件;/serial-boot-test 需真机 + ST-LINK)

构建 / 测试命令:

# 构建(/keil-build):0 错 0 警
& '.venv\Scripts\python.exe' .dsh/skills/keil-build/scripts/keil_build.py   # 退出码 0=PASS / 1=构建失败 / 2=环境错误
# 自动化测试(/serial-boot-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 门禁族(钩子数量随套件增长,以 .pre-commit-config.yaml 为准):

族 代表钩子 作用
格式 / 仓库卫生 trailing-whitespace、end-of-file-fixer、check-added-large-files、check-merge-conflict、check-yaml、gitlint 行尾与空白、超大文件、冲突标记、提交信息规范
编码与源码纪律 no-mojibake、coding-standard、nested-comment、bom-guard、layer-deps、bsp-err 乱码、命名与常量位置、注释嵌套、BOM 漂移、分层依赖、BSP 错误码契约
静态分析 cppcheck、test-cppcheck 主机侧与测试代码静态检查
文档一致性 doc-links、id-check、task-table、mem-numbers、mem-budget、size-gate 链接与章节引用、编号、任务表、内存数字、体积门禁
生成物新鲜度 generated-fresh、font-charset、lv-conf-sync、ui-golden、setview-check、uinav-selftest 菜单/字体/像素黄金等生成物与源一致
主机侧单测 watchdog / sys-clock / cfg-file / phasor / adc-input / adc-health / adc-cal / meas / freq / prot-set / prot-elm / run-par / iec104 / soe / nand-port / ui-data 等 *-unit-test MSVC 离线编译真实源码跑断言
结构与注册 registration-check、test-suite-switch、cubemx-survival 双端注册、套件互斥、CubeMX 保护区审计

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

  • 任务表(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/宿主文件)
验证 /keil-build 0/0 → /serial-boot-test 串口闭环 check_menu_rows.py + check_content_pages.py(像素黄金参考)

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

7.6 安全与权限

项 现状
FTP 鉴权 已鉴权(2026-10-11):口令登录([ftp] 段存 SHA-256 摘要,不存明文)+ 连续 5 次失败锁 60 s + write=0 可选只读;出厂默认 admin/admin,默认口令在用有启动告警。边界:FTP 明文传口令,挡未授权访问、不挡网络嗅探(详见 docs/子系统设计/网络配置说明.md §3.4)
UI 菜单权限 受保护叶子(行尾 #P)先经密码页;密码仅编译期写入(查看 000 / 修改 123),不落 Flash、无运行期设置页
远程显示 无鉴权,单连接;现场同网段部署
104 上行 无应用层鉴权(标准 104 本身不带认证):安全边界 = 现场同网段部署 + 单连接语义 + 首到优先。主站 IP 白名单不实现(单 socket 上"拒绝"= close + 重听,可被端口扫描打成 SPI 风暴,且配错即锁死真主站;属协议语义决定,非范围裁剪,见 §9 卷首)→ 需冗余/白名单时随 net 层立项
配置面 配置与定值只能经 FTP(需口令)或 104(同网段)改写;UI 侧修改需修改密码。本地无串口配置命令通道


8. UI 规格

8.1 屏幕与渲染

项 值
屏幕尺寸 160 × 160 px
色深 1bpp 单色(MSB 优先),帧缓冲 3200 B;无灰度、无彩色——参考与本产品的链路都是单色,7003 INIT 的颜色字段已删(§5.16.5)
渲染 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 菜单树(43 节点)

菜单树总览(层级 · 绑页 · 密码门)

图里的节点数、绑页与密码门读数由 tools/arch_diagram/gen_menu_tree_svg.py 现算自真值 ui_menu_tree.txt(改菜单树 → 同步脚本内 NODE_SRC 重跑);级联框在屏上怎么摆(几何)→ docs/UI设计/菜单页面设计.md §4.1。

规模:菜单节点 9 个(含根)+ 叶子节点 34 个 = 43 节点;最大深度 4 级(主界面 / 一级 / 二级 / 三级菜单)。 绑定现状(2026-10-29 复扫):已绑内容页 30 叶 / 未绑 4 叶(页面注册表 UI_PAGE_MAP_COUNT = 30, 与已绑叶数一致);未绑 4 叶 = 无开入硬件 3 + SNTP 1(取舍与重开条件见 docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5 页 + 运行报告)已于 2026-10-28 落地绑页, 「手动录波」与「录波回放」两叶于 2026-10-29 随录波道绑页(判据见 docs/子系统设计/故障录波设计说明.md §4.1 与 §8.1)。

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

完整层级树:

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

三层代码架构:数据层 ui_menu_tab(生成物,g_menu_tab[43] 扁平父子索引表,≈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 内容页

已绑 30 页(按分组;逐页形态见 docs/UI设计/页面补齐规划.md):

分组 页面 形态
装置信息 装置信息 静态键值行 6 行不分页;副标题"馈线自动化终端"
实时数据 交流量 / 直流量 / 遥信量 数据列表(交流量 24 行 / 每页 8,共 3 页;直流量 3 行单页)
参数定值 查看 4 页(参数 / 定值 / 控制字 / 软压板) 只读列表
参数定值 整定 4 页(参数 / 定值 / 控制字 / 软压板) 可编辑(写值 + 置脏 + 保存反馈)
三遥设置 遥测死区 / 遥测系数 可编辑(运行参数段,0x8030~0x804F)
装置维护 时钟设置 / 强制复归 / 清除记录 / 手动录波 操作页(执行类必须出真反馈,不得"点了没效果";手动录波触发后回读同一份计数,判据见 docs/子系统设计/故障录波设计说明.md §8.2)
通讯参数 通讯设置 / 网口设置 可编辑([comm] / [network] 段,保存后按各自生效时机)
记录查询 SOE 记录 / 自检记录 / 运行记录 记录列表(共用 reader)
记录查询 事故记录 / 操作记录 / 保护告警 / 保护启动 / 遥控记录 记录列表(每记录 2 行、空态显「无记录」;写入点与判据见 App/log/README.md §五类记录)
记录查询 运行报告 只读列表 13 行分 2 页;四个数逐个挂范围标签(自电池周期 / 本次开机),跨开机累计按裁定不做
记录查询 录波回放 单通道波形页(阶梯线自绘、8 路切换、单位徽标、削顶标记、空态与不可读态显式文案);显示契约见 docs/子系统设计/故障录波设计说明.md §8.1

未绑 4 叶(2026-10-28:记录 5 页与运行报告页已落地绑页,原「当前执行 6 项」清零;2026-10-29: 录波道落地,「手动录波」叶子随之一并绑页): 遥信类型 / 遥信防抖 / 双点遥信 = 等开入硬件(§9.1.1「出口与开入」);SNTP 设置 = 等 SNTP 对时(§9.1.2「SNTP 对时」)。

  • 内容页为独立全屏屏,由框架一次性自绘(零 LVGL 子对象),ESC 返回菜单屏。
  • 菜单导航状态不压层,返回即原样还原;同一时刻至多一个内容页打开。
  • 节点→页映射在逻辑层 menu_content_page_for(node);未绑叶子进入空白终点框(不伪造数据)。
  • 数据供给走注入通道(rt / par / info / 遥测死区与系数第四表),页面不直接触算法层; 像素黄金用例当前 66 张(菜单 8 状态另计;2026-10-28 记录 5 页与运行报告 2 页落地 +7 张;2026-10-29 录波 UI 道 6 张:手动录波 3 态 + 录波回放 3 态)。

8.4 密码与权限

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

8.5 中文字体

  • 字体 ui_font_cn_12.c:宋体 12px 1bpp 子集(当前 224 唯一字 / 319 字形,2026-10-29 实测; 122/217、179/274、185/280 均为历史快照。字形数 = 汉字/符号数 + ASCII 0x20~0x7E 共 95 个)。
  • 生成流程:tools/font_gen/extract_cn.py(扫 UI 源码 → ui_cn_chars.txt)→ tools/font_gen/make_font.py。
  • 约束:任何 UI 文案新增汉字后必须走此流程,否则显示为空白方块。


9. 缺口清单与推进顺序

口径:本章条目全部来自 复刻明细 §1.2 的 🔶 / ⬜ 行——即"参考源码有、本产品还没做或只做了一部分"。 "不做"一词在本章不出现:1:1 复刻口径下没有主动放弃的能力,只有尚未排期的能力。 唯二例外是 复刻明细 §1.7 标为"不适用"的两条(归一化值上送、主站 IP 白名单),那是协议语义决定, 不是范围裁剪。

命名:本节条目一律用语义短语(编号规范 P-8 语义优先),不发字母+数字号—— 避免与其它文档的 S/A/P 编号族撞名。

9.1 复刻缺口总表

按缺口性质分两类:阻塞型(缺外部资源或硬件,排期无用)与规模型(无外部依赖,只等排期)。

本节是清单;逐项明细在 参考产品复刻明细.md §2~§10——参考源码到底有哪几项、本产品有哪几项、 差额具体落在哪个定值 / 哪个点 / 哪个模块上、以及"怎么算做完了"。排期与估算以明细为准。

9.1.1 阻塞型(等外部条件,排期不能解决)

条目 对应 复刻明细 §1.2 现状 缺的是 解除条件
标定闭锁 1~3 9 个元件、定值、闭锁链、SOE、104 上送全部就绪,但 ADC_CAL_F_VALID 未置位 → 判据整体停走 外部资源:子板/端子板变比 + 标准源 端子变比确认 → 8 通道两点标定 → VALID 置位(届时自动解卡,无需改代码)
出口与开入 7、8 无硬件;保护动作只体现为遥信 + SOE;遥控开关量否定确认 硬件 + 立项:出口继电器、开入回路、回读自检 开入开出作为独立模块立项(不可移植项 X3 解除)
三相与同期 4、12 建接口不使能(B/C 相与 IN 削顶、跨转换器无同刻) V0.2 硬件 8 路电气量全接 TPAFE + 中点偏置
电度计量 6 未实现(功率积分需跨转换器同刻) V0.2 硬件 同上(不可移植项 X4 解除)
对下采集 17(子站侧) rs485_task.c 空桩、未建任务、协议族未实现;整簇冻结 决策 + 门禁:用户已决定暂缓 先修「单缓冲包撕裂」「TX 超时拉 DE 未等 TC」→ 接消费者
第三方送检 17 自有主站工具往返已通过 标定 + 第三方环境 标定闭锁解除后送检

9.1.2 规模型(无外部依赖,只等排期)

条目 对应 复刻明细 §1.2 参考 现状 差额
定值铺开 1、2 249 项 / 23 单元 40 项(覆盖参考 35 + 本地 5)/ 5 组 +214 项 / +18 单元
映射铺开 3 107 项 0x8820~0x8891 40 项局部 +67 项
元件铺开 12 45 个模块 8 个模块 / 9 个实例 +37 个模块(过流类 6 / 电压类 5 / 重合闸 5 / 方向功率 4 / 涌流故障 5 / 自动控制 5 / 记录 5 / 录波采样 2)
遥测铺开 4、5 31 点 + 模型 35 行 9 点 +22 点 + 模型表
录波子系统 10、15 3 类型 / 6 段 / 65 通道 / RAM 16 个 / COMTRADE 64·64·16 最小闭环代码面已交付(2026-10-29):1 kHz / 8 路原始码值 / 单段 320 点 / 轮转段文件 / 手动与保护启动 / 单通道回放页;板级判据一轮未跑 仍差 4 kHz 全速与 80 点/周波、多段与 65 通道、COMTRADE、104 文件传输;口径偏离登记见 docs/子系统设计/故障录波设计说明.md §2
记录体系 9、13 13 类队列(128/256 条) 8 类 +5 类(越限 / 闭锁 / COS / 顺控 / 顺控执行)
UI 记录页 9、13 参考有完整记录页与运行报告 六页已绑并纳入像素黄金回归(2026-10-28) 只剩真机判据(docs/任务规划/登记簿.md §7)
多规约栈 17 12 种 1 种(104) +11 种(101 / 102 / 103 / CDT / ModBus / Whm_GB / 61850 / CAN + 子站侧 3 类)
国密算法 18 Comm/Ecc/ 全套 0 SM2 / SM3 / ECDSA
软压板铺开 11 9 面(表容量 32) 1 面 +8 面
SNTP 对时 17 参考对时走 SNTP 私有 TCP 8888 + 104 C_CS SNTP 客户端
固有参数 1 8001H~800AH 字符串类参数 未实现(无法短浮点上送) 随送检点表设计
遥测增强 4、5 k=1~9 谐波方和根 + 4 点平均 仅基波轨 谐波 / 等周波调频 / 零序自产外接切换 三条算法轨
屏板链路对齐 20 串口屏板通道(700000 8N1 / USART1 TTL 直连、无 DE,帧 A 6 B 召唤、帧 B 4208 B 应答:显存 3200 B + 状态灯 4 B 位掩码 + 4 B info)+ 7003 四命令(INIT 16 B,单色口径)+ 续传 / 拒绝握手 / 链路监视 / F1·F2 串口通道已交付(4208 B 应答 / 状态灯掩码 / 键上行 / 双出口并发,屏板链路设计说明 §9.1);7003 四命令(INIT 8 B);无续传、无 bNeedFlash 拒绝、无 1 分钟监视、键值 6 个 7003 报文口径 6 项(参考产品复刻明细.md §11 第 2~9 条);串口侧验收尾巴见屏板链路设计说明 §9.2

一句话:「标定闭锁」是唯一"再排期也没用"的缺口(等标准源);「出口与开入」「三相与同期」 「电度计量」等 V0.2 硬件;「对下采集」等用户决策;其余规模型条目全部可在现有硬件上推进, 只取决于排期。 这张表与 docs/任务规划/登记簿.md 一一对应;状态只在登记簿维护, 本节不另建状态。

9.2 推进顺序

顺序唯一权威 → docs/任务规划/README.md §2.0(本表只是产品视角摘要, 冲突时以该节为准)。

顺序 工作 类别 当前状态 开始条件
1 UI 补齐(记录 5 页 → 运行报告) 规模型 清单已清空(2026-10-28) 六页已落地;余 4 叶属不做项(手动录波与录波回放两叶已随录波道绑页),重开条件见 docs/任务规划/UI补齐.md §5
2 net 层跨上下文收口 平台 下一顺位(未开工) UI 清单已清空,切换条件已满足;开工待用户点头
3 其余结构与可靠性评估 平台 排队 net 收口后
4 端子/子板变比确认 → 两点标定 阻塞型 等外部资源 子板实物/原理图、标准源到位可插入
5 标准源送检与第三方 104 主站验收 阻塞型 等标定 保护 VALID 置位;送检窗口前 2 日冻结特性
6 定值铺开 / 映射铺开 / 遥测铺开 / 软压板铺开 规模型 等排期 标定后(工程量才有意义)
7 元件铺开与遥测增强 规模型 等标准源/硬件 先解除未标定闭锁;三相类等 V0.2
8 录波子系统 → 记录体系 → 多规约栈 规模型 录波最小闭环已提前插入并交付代码面(用户裁定 2026-10-29 录波先行,见 docs/任务规划/故障录波.md);本行剩下的参考机完整形态(多段 / 65 通道 / COMTRADE / 104 文件传输)仍不排 各自重启条件
9 验证窗口事项(CI 远端、PC peer、负向注入) 平台 逢条件顺带 条件到位即执行
10 出口与开入 / 三相与同期 / 电度计量 / 对下采集 阻塞型 不排 V0.2 硬件 / 用户决策

不可颠倒的顺序(一):变比确认 → 两点标定 → 保护解卡 → 送检。未完成标定就送检, 保护表现为不动作;保持该闭锁,不用非标准源走捷径(用户裁定,2026-10-25)。

不可颠倒的顺序(二):点表铺开必须晚于标定——否则铺出去的全是 IV 点, 主站无法区分"没做"与"接线错",比不铺更糟。

9.3 未接线开关说明

开关 位置 现状
功能裁剪开关 App/app/app_cfg.h(当前无宏) 没有任何生效的裁剪开关:原三个 APP_*_ENABLE 占位宏因全库零消费点已于 2026-10-22 删除,各模块一律编译进产品——ADC / RS-485 均为必需链路(ADC = 遥测/保护来源,RS-485 = 对下 ModBus RTU 采集)。将来确需裁剪时在真实初始化点接入门控,并同步登记回该文件
TEST_SUITE_* test/board/test_config.h 测试套件互斥,一次构建只开一个;全注释 = 正常产品固件
rs485_task.c App/task/(未建任务、白名单登记) 唯一的结构白名单缺口:RS-485 整簇冻结期间刻意不接线,随该簇一并出白名单
DTU_BENCH 构建宏(protect_task.c 等) 台架构建下允许保护判据在未标定时动作(仅测试用);产品构建(#ifndef DTU_BENCH)下保护闭锁

逐项明细(定值 249 / 遥测 31 / 开入开出 / 动作事件 / 元件 / 录波 / 记录 / 规约 / 完成判据 / 屏板规划)已独立成档 → 参考产品复刻明细.md §2~§11。


10. 验收判据

10.1 构建与静态门禁

项 判据
构建 /keil-build → BUILD_OK: 0 errors, 0 warnings(退出码 0)
静态门禁 pre-commit run --all-files 全部通过(钩子族见 §7.4)
主机侧单测 全部套件全绿(看门狗、时钟、配置、相量、采集层、标定、遥测、测频、定值、元件、运行参数、104、SOE 等;套件与断言数随代码演进,以 .pre-commit-config.yaml 与 test/host/ 为准)
栈门禁 scripts/stack_report.py 9/9 PASS(余量 ≥ max(1024 B, 30%))
体积门禁 check_size_gate.py --ci PASS(体积凭证与 git 索引一致)
双端构建 Keil 与 CMake 均 0 错 0 警
UI 回归 菜单行 + 内容页像素黄金 + 导航自检全 PASS

10.2 上电自检(/serial-boot-test)

层 判据
Required 标记(基础) App init OK / Network Init / net init: OK / PHY: 100M FULL
Required 标记(采集链,可选启用) ADC input layer init: OK / phasor(first) / freq(hb)(顺序锚点 App init OK>phasor(first)>phasor(hb))
Required 标记(保护链,可选启用) protect task start / set=40 elm=9 计数锚
Required 标记(104,可选启用) [I104] 监听/接入行
Forbidden 标记 无 FAIL / ERROR / HardFault / [ERR](四个 Fault 的崩溃日志都以 [ERR] 开头,出现即不通过)
自检记录 selftest: no fault record
固件身份 fw build 身份戳匹配 + 烧录后回读 No difference found
退出码 /serial-boot-test → 0(PASS)

10.3 现场验收清单

# 项目 方法 通过标准
1 上电自启动 断电上电 + 串口采集 /serial-boot-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、/prot_set.bin 按新值生效)
8 LED 状态 目检 6 路 LED 随系统状态变化(低电平点亮)
9 104 总召与变位 PC 主站连 :2404 → STARTDT → 总召 四组数据回全、actterm 正常;制造变位后 COT=3 上送
10 104 遥控与定值 YK12 软压板投退、C_SE 写定值 两段式正答、压板行为可观测、定值跨复位保持
11 保护闭锁态 未标定状态下观察 YX31 与日志 判据停走且明确可见(不得静默不动作)
12 记录可追溯 FTP 下载 /log/soe.log、/log/run.log、/log/selftest.log 记录连续、时标正确、解码校验通过
13 屏板链路一致性 串口屏板 + TCP 客户端同时接入,按 §5.16.10 十四条逐项验证(第 15 条 LOGO 出局) 串口侧:275 ms 召唤 / ≤200 ms 回 4208 B、显存 3200 B 逐字节一致、状态灯 4 B 掩码逐位一致、7 键动作正确、自复位不误判离线;网络侧:INIT 16 B、重复召唤 / 越界无应答、KEEPLIVE 静默、8 键(含组合)动作正确

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 复位
堆分配改造 配置引擎堆分配改造(真机) ✅ [CFG] load: OK(经 FreeRTOS 堆);FTP 改 IP 复位即生效
存储/网络套件 16/16 PASS ✅
采样节拍与相量 帧号 1000 Hz、5 实例产出、双区刷新 ✅ 2026-10-11
ADC 前端注入 已知电压注入:零点 / 线性 / 斜率 / 映射 / 极性 ✅ 2026-10-27 五项 PASS(斜率偏差 −0.14%,R²=0.9999997)
104 主站往返 STARTDT / 总召四组 / 变位 / 遥控 / 定值读回 ✅ 2026-10-12 18/18 PASS
定值与压板持久化 YK12 投退 + 非默认定值跨复位 ✅ 2026-10-12 21/21 + 13/13 + 4/4 + 4/4 PASS
SOE 落盘 自发 M_SP_TB_1 带时标 + FTP 下载解码 ✅ 2026-10-12 56 条记录全 PASS

11. 相关文档

主题 文档
文档索引 docs/README.md
软件架构与运行时规格(本文拆出的就绪位表/启动时序/线程通信权威) docs/架构设计/软件架构与运行时规格.md
硬件规格与能力边界(本文拆出的引脚表与 H1~H5/量纲权威) docs/架构设计/硬件规格与能力边界.md
参考产品复刻明细(能力基线与逐项差额) docs/产品需求/参考产品复刻明细.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/算法/继电保护功能复现规划.md
全周傅氏算法原理 docs/算法/傅氏算法详解.md
采样有效性校验 docs/算法/采样有效性校验设计说明.md
ADC 采样节拍与 DMA docs/子系统设计/ADC采样节拍设计说明.md
ADC 通道映射与实测 docs/硬件平台/ADC通道映射说明.md
ADC 前端注入验证流程 docs/测试说明/专项验证/ADC前端注入验证流程.md
IEC 60870-5-104 上行 docs/子系统设计/IEC104上行设计说明.md
数据可信(标定 / 快照 / 运行参数) docs/任务规划/数据可信.md
页面补齐规划 docs/UI设计/页面补齐规划.md
编号规范 docs/编号规范.md
部署环境 docs/环境与部署/项目部署环境要求.md
硬件网表 docs/硬件平台/V0.1_网表详细分析报告.md
待办登记簿 docs/任务规划/README.md
实机测试指南 docs/测试说明/板级测试/实机测试实施指南.md
测试标准流程 docs/测试说明/流程与规范/测试开发标准流程.md
RAM 预算与优化 docs/内存管理/RAM使用分析与优化方案.md
AI 开发规范 AGENTS.md(仓库根)
开发者入门 README.md(仓库根)