/* * 模块名称:运行参数段(全周傅氏相量/保护判据整定层,「数据可信」这一项) * 模块功能:遥测死区(9 点)与通道标定系数覆盖(k/b 各 8 路)的**单一真源**: * - 死区 = 本模块 int32 毫单位 RAM 副本(注册进 cfg 引擎 [run_par] 段, * 工厂默认 = 「数据可信」下游常数按工程量重定后的额定 0.5 % 档),104 消费侧 * (App/protocol/iec104/iec104_pts.c)每拍实时读取——无投递、无缓存 * 副本(104 改读快照曾在 pts 侧留运行时副本 s_yc_db,运行参数段落地后收编于此, * 双源必打架); * - 系数覆盖 = **直通 adc_cal_set()**([adc_cal]/[adc_cal_ofs] 是系数 * 唯一真源,标定落盘与整定入口已定;本模块只加 104 地址映射 + 落盘请求,不另存 * 一份系数——同 D1 裁"两处判断必打架"逻辑)。 * 104 地址映射(docs/算法/继电保护功能复现规划.md §5.1 运行参数类 * 0x8020H~0x8058H;逐项表原文"待补"(参考项目 CommPara_ConfigTable * 不在仓),本表即运行参数段的落实,送检点表若另给权威地址只改常量段: * 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 运行参数段) * 修改记录: * 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 #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 */