728d60675f
三条道在同一棵树上交付,故合并成**一次权威构建**(@build 0 错 0 警,Code=235236 RO=26308 RW=1572
ZI=136924)后同笔入库;台账已按该构建回填(`ram_baseline.py --update` + `--write`、`chec
k_mem_numbers.py
--write`),凭证与实际 .map 同源。归属如下:
· **通讯设置页**(道G task-9):新增 `Drivers/BSP/UI/ui_page_comm.{c,h}`(通道六注入,与死
区页同骨架同纪
律),`#page=comm` 绑定使 bound **21 → 22**、内容页黄金 **47 → 53**(旧 47 页字节零变化,
新增六态含
WAIT/OK 两张);`iec104_comm` 脏位 + store_save(**无事件位**)挂 defaultTask 同点位
轮询;`port_104` 由
宏改走 getter、`IEC104_SERV_PORT` 删除;字体 +听/监(185 字全覆)。**实机链已闭环**:FTP 外改
[comm]
的 ca/port → 复位 → 串口出现 `section 'comm' (2 keys)` 与 `i104: listening o
n 9004` → 还原 2404,全程无
FAIL ⇒「重启即生效 + 端口真值」不是推断是实测。上限核对 6/8 段、2/16 键,超限现象由 TC-CONFIG-056/057
钉死(注册 -1 + `comm init: FAIL` 锚 + getter 回 ROM),**不抬宏**。
· **开机账本**(道F task-12):新增 `App/util/boot_stats.{c,h}`——上电次数落 SD2506 用户
SRAM(magic +
小端计数 + 版本 + 异或校验),一次上电 = 1 读 + ≤1 写,**零 NAND、零卷锁、零配置段**;四态互斥
UNKNOWN / FRESH / CONTINUED / RESTARTED(BLF=1 才算电池域掉过电),**读失败绝不回写**;
文案口径「自 RTC
电池周期起」,**禁写终身次数**。复位原因优先级链从 `app_main.c` 的 if-else 收进一份真源(串口与屏幕同
源);104 四个只增不清计数 + `iec104_serv_get_stats()` 留在 serv、未塞进 link(会被 open
/close 洗掉)。
运行时长按用户裁定 = **只报本次开机以来**,零新增代码。新套件 `test/host/boot_stats` 21/21,五处注入
**全部有牙**(含「漂一字节被校验和挡下而不是报 256 倍错账」)。
· **adc_cal 可诊断化**(道E task-43):三个 volatile 计数 + `adc_cal_get_stats()`
/ `adc_cal_note_persisted()`
(水位**盖写非自增**,因为一次 save 覆盖整档,数 save 会留假未落盘);「差额 × 脏位」三态语义唯一落在
`adc_cal.h`,其中「差额 > 0 且脏位恒 0」= 绕过语义 setter 的静默丢失;TC-ADCCAL-019~023。
三条**必须留档的自纠**(都是执行道自己报的,我不替他们润色):
① stdint 那条断链是**宿主套件抓到、通讯道先修**,采集道承认自己是重复添加者并删掉自己那份;
② 「exit 2 不是证据,断言变红才是」——采集道第一版反证注入了未声明标识符导致编译错,差点当成功;
③ 套件汇总行原写 `s_total/s_total`,失败时会打印「21/21 PASSED (failed=1)」这种自相矛盾的行,已改。
另修:`check_registration.py` 的 `SIM_EXEMPT` 加一行豁免 `App/util/boot_stats.c
`(依赖 I2C 与 RCC 位掩码,
MCU 专属;核过 `sys_clock.c`/`sha256.c` 同形态先例),注册反向校验 exit 1 → 0。发号 TC-IEC1
04-034、
TC-UIDATA-029 已实抬游标(`TC-IEC104-033→034`、`TC-UIDATA-026→029`)。
门禁:id-check --strict 与 plain 均 rc=0、doc-links --all rc=0、注册校验 0、cppche
ck / coding-standard /
bom-drift 0;iec104 179/179、ui_data 295/295、boot_stats 21/21、adc_cal 11
7/117、run_par 67/67;菜单 8 状态
池 5368 不变、内容页 53/53。**已知遗留**:内容页数 47 → 53 的全仓文本同步尚未做(另卡跟踪),本笔只保
证代码与黄金一致;面板注键真机那一腿缺 CLI,交台架道补。
200 lines
13 KiB
C
200 lines
13 KiB
C
/*
|
||
* 模块名称:运行参数段(L2/L3 整定层,「数据可信」卡 10)
|
||
* 模块功能:遥测死区(9 点)与通道标定系数覆盖(k/b 各 8 路)的**单一真源**:
|
||
* - 死区 = 本模块 int32 毫单位 RAM 副本(注册进 cfg 引擎 [run_par] 段,
|
||
* 工厂默认 = 「数据可信」卡 6 额定 0.5 % 档),104 消费侧
|
||
* (App/protocol/iec104/iec104_pts.c)每拍实时读取——无投递、无缓存
|
||
* 副本(卡 9 曾在 pts 侧留运行时副本 s_yc_db,卡 10 落地后收编于此,
|
||
* 双源必打架);
|
||
* - 系数覆盖 = **直通 adc_cal_set()**([adc_cal]/[adc_cal_ofs] 是系数
|
||
* 唯一真源,卡 4 已定;本模块只加 104 地址映射 + 落盘请求,不另存
|
||
* 一份系数——同 D1 裁"两处判断必打架"逻辑)。
|
||
* 104 地址映射(docs/算法/继电保护功能复现规划.md §5.1 运行参数类
|
||
* 0x8020H~0x8058H;逐项表原文"待补"(参考项目 CommPara_ConfigTable
|
||
* 不在仓),本表即卡 10 的落实,送检点表若另给权威地址只改常量段:
|
||
* 0x8030~0x8038 = 死区 UA/UB/UC/UN/IA/IB/IC/IN/FREQ(工程量 V/A/Hz);
|
||
* 0x8040~0x8047 = k 覆盖(µV/码);0x8048~0x804F = b 覆盖(码值,可负);
|
||
* 其余留白(未启用类别),**0x8027~0x802A 属 prot_set 告警段**,本表
|
||
* 永不让位(两表按精确地址分流,见 iec104_pts.c set 路由)。
|
||
* 持久化(B7 prot_set 先例同款):任一写成功 → 脏标志只置不清;
|
||
* iec104Task 主循环 peek → 置 SYS_EVT_RUN_PAR_SAVE → defaultTask
|
||
* (配置引擎属主)run_par_store_save() 调 cfg_file_save() 整档外科
|
||
* 保存(含 [run_par] 与刚被 adc_cal_set 改写的 [adc_cal]/[adc_cal_ofs]
|
||
* 副本)→ 成功清脏;失败留脏 = 下轮天然重试。本模块自身零文件 IO
|
||
* (属主纪律)。
|
||
* ⚠ 三份职责别混(道G task-43 第③项,此前只有意图式陈述):
|
||
* - **谁写 RAM**:系数/零点的唯一真源是 adc_cal 的引擎副本,而本模块那两支
|
||
* 语义 setter(run_par_cal_k_set / run_par_cal_b_set,task-7 落地)是**唯一
|
||
* "写值 + 置脏"成对发生**的入口;任何消费者绕过它们直调 adc_cal_set(),
|
||
* 值只进 RAM、脏标志不动 ⇒ 屏上"当前生效"是新的、盘上仍是旧的、重启即丢,
|
||
* 且该路径**没有错误返回**。这条形态现在可观测:adc_cal 侧
|
||
* set_ok 与落盘水位的差额 > 0,而 run_par_dirty_peek() 恒为 0。
|
||
* - **谁落盘 / 什么时机**:只有 defaultTask 的 run_par_store_save()(由
|
||
* iec104Task peek 后置的 SYS_EVT_RUN_PAR_SAVE 驱动);本模块零文件 IO。
|
||
* - **cfg_file_poll() 不是保存路径**:它的方向是**盘 → RAM 的重载**(外部
|
||
* 改档 → 沉降去抖 → 重载),拿它"兜住"未落盘的改值会把 FTP 侧的旧档倒灌
|
||
* 回 RAM,比不兜更坏。设计依据见 docs/算法/采集与算法层设计说明.md §10.1。
|
||
* 并发契约:引擎副本 int32 对齐字读写在 Cortex-M4 上原子;poll 重载 µs 级窗口
|
||
* 为「数据可信」§4.4 明载设计(adc_cal 同款)。写路径 = 104 执行段
|
||
* (iec104Task)与引擎读路径互不加锁,勿改成"读侧缓存"(缓存 = 新真源)。
|
||
* 纯算法:只用 stdint/stddef/math + cfg_file.h/adc_cal.h 头(注册/直通均为
|
||
* 接口级)→ 主机侧可单测(test/host/run_par,链真 cfg 引擎 + 真 adc_cal)。
|
||
* 适用平台:STM32F407ZGTx(Cortex-M4F,硬件 FPU)
|
||
* 作者:DTU 项目组
|
||
* 创建日期:2026-10-25(道D 卡 10)
|
||
* 修改记录:
|
||
* v1.0 2026-10-25 DTU 项目组 创建:[run_par] 段 + 104 地址映射 + 直通
|
||
* adc_cal + B7 式脏标志落盘请求
|
||
* v1.1 2026-10-27 DTU 项目组 道F task-7(遥测整定两页)配套:新增语义
|
||
* setter run_par_cal_k_set / run_par_cal_b_set
|
||
* (写值 + 置脏成对;104 的 k/b 两支同批改调它,
|
||
* 消除两份置脏逻辑)+ 合法域唯一出口
|
||
* run_par_db_range() + 系数粗守上限
|
||
* RUN_PAR_K_MAX_UV;毫→工程换算收进模块内单点
|
||
* s_milli_to_eng()(顺带把 task-43 第①项所需的
|
||
* "写值必置脏"这一半满足掉)
|
||
* v1.2 2026-10-27 DTU 项目组 道G task-43 第②③项:run_par_store_save() 成功路径
|
||
* 给标定层盖一次落盘水位(纯观测回执,不参与判定);
|
||
* 本头把"谁写 RAM / 谁落盘 / 什么时机 / poll 不是保存
|
||
* 路径"从意图式陈述改成逐条契约
|
||
*/
|
||
|
||
#ifndef RUN_PAR_H
|
||
#define RUN_PAR_H
|
||
|
||
#include <stdint.h>
|
||
|
||
#include "adc_cal.h" /* adc_semantic_t:公开语义 setter 的形参类型(同层 algo→algo,方向不逆)*/
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/* 死区/覆盖点数(死区 = YC 表行数:电气 8 + 频率;覆盖 = 语义电气 8 路) */
|
||
#define RUN_PAR_DB_N 9u
|
||
#define RUN_PAR_CH_N 8u
|
||
|
||
/* 系数 k 的**粗守**上限(µV/码):只为挡误写(如把 mV 当 µV 填),不是工况域;
|
||
* 真合法带在 adc_cal 执行段裁(µV/码 ×[0.5,2.0]),两层各说各的、互不掩盖。
|
||
* 公开它是因为 UI 整定页要给编辑器设上限——上限在这里,就不许页面再抄一份。*/
|
||
#define RUN_PAR_K_MAX_UV 1.0e9f
|
||
|
||
/*
|
||
* 函数功能:运行参数初始化——副本置工厂默认 + 注册 [run_par] 段进 cfg 引擎
|
||
* 入口参数:无
|
||
* 返 回 值:无
|
||
* 限定条件:**内核启动前**调用(app_main_init,adc_cal_init 之后);注册必须先
|
||
* 于 defaultTask 的 cfg_file_load(FTP 鉴权确立的契约,同 adc_cal 先例);幂等
|
||
* 函数说明:注册失败(段名重复/段数超限)打 [ERR] 后继续——工厂默认照常生效,
|
||
* 仅文件整定失效(adc_cal_init 同款降级)。
|
||
*/
|
||
void run_par_init(void);
|
||
|
||
/*
|
||
* 函数功能:读第 idx 路遥测死区(工程量)
|
||
* 入口参数:idx - 0..7 = 语义通道序(UA..IN),8 = 频率 uint8_t
|
||
* 返 回 值:死区 V / A / Hz;idx 越界返 0.0(调用方按"无死区"保守处理) float
|
||
* 限定条件:任意上下文(int32 单字读原子;104 COV 每拍调用)
|
||
* 函数说明:毫单位 → 浮点的换算在本模块内也只有一处(run_par.c 的
|
||
* s_milli_to_eng(),run_par_deadband 与 run_par_db_range 共用);
|
||
* 消费侧一律取本模块给的工程量,不要再各自除 1000。
|
||
*/
|
||
float run_par_deadband(uint8_t idx);
|
||
|
||
/*
|
||
* 函数功能:写第 idx 路死区(工程量,含范围守卫 + 脏置位)
|
||
* 入口参数:idx - 同上 uint8_t;db - 死区工程量(V/A/Hz,≥0) float
|
||
* 返 回 值:0 成功;-1 越界/越程/NaN(副本不动) int
|
||
* 限定条件:写者两门——**iec104Task**(104 C_SE 执行段)与 **uiTask**(遥测死区页
|
||
* 经 ui_data 通道五注入转达,道F task-7 起;ui_data.h 通道五表注:合法域
|
||
* 与"写值+置脏"必须原子发生在执行侧)。两门都只写 RAM 副本 + 置脏,
|
||
* 落盘统一收敛在 defaultTask(勿在 adcTask 调用;此句为 2026-10-27 措辞
|
||
* 收口——原写"UI 若整定需另行走属主路径"是 task-2 期遗留,task-7 已接线)
|
||
* 函数说明:合法域按点型分档——电压 0~50 V、电流 0~1 A、频率 0~5 Hz(上限 =
|
||
* 额定 × 二档裕量,守卫目的是挡误写不是限工况;见 .c 常量段)。
|
||
* 成功即置脏(落盘请求,见文件头持久化契约)。
|
||
*/
|
||
int run_par_deadband_set(uint8_t idx, float db);
|
||
|
||
/*
|
||
* 函数功能:104 运行参数地址读(C_RD 路由,先于 prot_set 扫描)
|
||
* 入口参数:addr - 通讯地址(0x8020~0x8058 段内) uint32_t;out - 工程量浮点
|
||
* (死区 V/A/Hz;k 覆盖 µV/码;b 覆盖 码值) float *
|
||
* 返 回 值:0 命中并写出;-1 地址不归本段(调用方继续走 prot_set) int
|
||
* 限定条件:iec104Task 上下文
|
||
* 函数说明:命中集 = 0x8030~0x8038 / 0x8040~0x8047 / 0x8048~0x804F 精确匹配;
|
||
* k/b 读回 = adc_cal **当前生效值**(与折算同视图:文件坏值被合法带
|
||
* 哨兵回退 ROM 时,回显的就是 ROM——主站看到的即下游实际吃到的)。
|
||
*/
|
||
int run_par_104_read(uint32_t addr, float *out);
|
||
|
||
/*
|
||
* 函数功能:104 运行参数地址写(C_SE 两段式路由,先于 prot_set 扫描)
|
||
* 入口参数:addr - 通讯地址 uint32_t;v - 工程量浮点 float;
|
||
* select - 1 = 选择段(只校验不落副本)/ 0 = 执行段 uint8_t
|
||
* 返 回 值:0 接受;-1 拒绝(越程/NaN/合法带外/非本段可写地址命中守卫);
|
||
* -2 地址不归本段(调用方继续走 prot_set) int
|
||
* 限定条件:iec104Task 上下文;执行段成功即置脏
|
||
* 函数说明:k/b 覆盖经 adc_cal_set() 合法带哨兵(µV/码 ×[0.5,2.0]、|b|≤8192,
|
||
* 越带 -1 → 104 侧 PN 否定确认,adc_cal 不留痕由**其自身**越带 [ERR]
|
||
* 机制负责——本模块直通不重复留痕);两段式与 prot_set 定值写同构。
|
||
*/
|
||
int run_par_104_write(uint32_t addr, float v, uint8_t select);
|
||
|
||
/*
|
||
* 函数功能:写某路系数 k(µV/码)**并在同一函数内置脏**——整定的语义写入口
|
||
* 入口参数:sem - 电气语义通道(adc_semantic_t 枚举序) adc_semantic_t;
|
||
* k_uv - 系数(µV/码,须 >0 且 <= RUN_PAR_K_MAX_UV) float
|
||
* 返回值:0 - RAM 副本已写且已置脏;-1 - 粗守或执行段拒(副本未动、不置脏) int
|
||
* 限定条件:整定路径上下文(iec104Task 的 C_SE 执行段;UI 侧由装配层
|
||
* App/app/ui_data_feed.c 经 ui_data_yt_ops_t 转进来)。勿在 adcTask 调用
|
||
* 函数说明:**写值与置脏成对,不许拆开**(lead 裁②):拆开就等于"屏上已改、
|
||
* 盘上永不落、且没有任何错误返回"。因此本模块**不提供**公开的
|
||
* mark_dirty——单独调它等于空承诺;零点 b 由本函数 RMW 取当前生效值。
|
||
*/
|
||
int run_par_cal_k_set(adc_semantic_t sem, float k_uv);
|
||
|
||
/*
|
||
* 函数功能:写某路零点偏移 b(码值)并置脏(与 k 同款语义,粗守 ±1e6 码)
|
||
* 入口参数:sem - 电气语义通道 adc_semantic_t;b_codes - 零点(码值) int32_t
|
||
* 返回值:0 - 已写并置脏;-1 - 粗守或执行段拒(副本未动、不置脏) int
|
||
* 限定条件:同 run_par_cal_k_set()
|
||
* 函数说明:k 侧 RMW 取当前生效值;±8192 真带由 adc_cal 执行段裁。消费者 =
|
||
* 104 的 0x8048~ 分支(改造后走这里),不是为将来预留的口
|
||
*/
|
||
int run_par_cal_b_set(adc_semantic_t sem, int32_t b_codes);
|
||
|
||
/*
|
||
* 函数功能:取第 idx 路死区的合法域(工程量)——**合法域的唯一出口**
|
||
* 入口参数:idx - 0..8 uint8_t;lo/hi - 输出下限/上限(V/A/Hz) float *
|
||
* 返回值:0 - 已写出;-1 - idx 越界或指针空(调用方不得回退成自造默认域) int
|
||
* 限定条件:任意上下文(纯常量读)
|
||
* 函数说明:存在的唯一理由:UI 整定页要给编辑器设 min/max,而这些上限的真源是
|
||
* 本模块的 RUN_PAR_DB_MAX_*;页面抄一份就是第二真源。给的是**粗守域**,
|
||
* 真提交仍由与 104 选择段同源的守卫裁,两条路不会漂移到两套数字。
|
||
*/
|
||
int run_par_db_range(uint8_t idx, float *lo, float *hi);
|
||
|
||
/*
|
||
* 函数功能:落盘脏标志探查(非消费)
|
||
* 入口参数:无
|
||
* 返 回 值:1 = 有已整定未落盘的改动;0 = 干净 uint8_t
|
||
* 限定条件:任意上下文(单字节);iec104_serv 主循环 peek 后投递事件(B7 同款)
|
||
*/
|
||
uint8_t run_par_dirty_peek(void);
|
||
|
||
/*
|
||
* 函数功能:执行落盘请求(cfg_file_save 整档外科保存 + 成功清脏)
|
||
* 入口参数:无
|
||
* 返 回 值:0 成功(或无脏可存);-1 写盘失败(脏保持,下轮重试) int
|
||
* 限定条件:**defaultTask(配置引擎属主)上下文**,由 SYS_EVT_RUN_PAR_SAVE 驱动
|
||
* 函数说明:save 走引擎唯一写闸(超长拒写/原子改名);本函数不清
|
||
* 引擎以外模块的脏语义([adc_cal] 副本值已由写路径就位)。
|
||
*/
|
||
int run_par_store_save(void);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* RUN_PAR_H */
|