Files
STM32F4-Base/App/algo/prot_set.h
T
wandering1 b7c0889cc7 refactor(编号·批次二): 代码与测试侧 215 处保护功能号改成功能名,零行为改动
用户裁定「不要用字母加数字的编号,语义标识是最好的」后的批次二代码半(道 ui-param 执行,逐文件站点数与
自证见其交付)。唯一口径 = 映射表 ci-artifacts/lprot_map.tsv 的功能名列原文,**零自造同义词**;L2.5 与
L-TEST 经实测各 0 处(不是本族),TC 族一字未动。

固件 22 文件 128 处(adc_task.c 21、phasor.c 22、phasor.h 13…),主机测试 13 文件 87 处(pha
sor_test.c
57…);设计文档指针新增 19 行,另 16 只文件本来就写着规划文档 ⇒ 不重复加。

**两条只有真改过 215 处才会踩到的坑,都写进注释规范实践**:
· 指针**不能接在原句尾部**——那会替原文一个未闭合的半括号封口,实测咬坏 App/algo/sample_ring.h 这类
  跨行句 ⇒ 指针一律**单独成行**;
· 号删掉会留下**叠词**(「自检失败闭锁 闭锁判定」「定值校验和 定值巡检」)⇒ 复扫并收口 4 处,措辞只用
  映射名本身;具体对象需要留住时写成「自检失败闭锁(采样故障闭锁)」。

自证(不靠嘴说):改前把 35 只文件原文备份到仓外 temp,逐文件比 `/*`、`*/` 计数、三类括号计数、行数增量
恰等于指针行数、全角括号增删相等、残留号 0 ⇒ **35/35 通过**;Lead 复核后跑权威 @build **0 错 0 警**,
Program Size `Code=233900 RO=26104 RW=1536 ZI=136808` —— **与三条道各自改前改后测的四数逐
字节同数**,
这就是「只动注释与文本」的机器证据;八套主机单测 exit 0,cppcheck 按钩子参数零发现,coding-standard 0。

文件头「修改记录」里的号**一并换名、不还原**(Lead 裁定):这些号是全仓退役的,留一个查无此号的引用比
留一条改过名的条目更坏——「冻结历史不回改」保护的是**别替历史改口**,不是保护一个再也查不到的字符串;
id-check 对变更记录行本就豁免,两种选择都不影响门禁。
2026-10-27 08:59:26 +08:00

183 lines
9.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称:保护定值模型(P1,定值校验和 载体)
* 模块功能:保护定值的 RAM 模型——编号 / 通讯地址 / 范围 / 默认值 / 校验和自检,
* 以及 B7 定值持久化的**纯逻辑层**(blob 序列化/解析 + 原子装载)。
* 文件读写胶水在 App/cfg/prot_set_store.c(MCU 端)。
*
* 设计口径(docs/算法/继电保护功能复现规划.md §5):
* - 定点存储:Q10(×1024),与参考系统定点系数 2^10 一致(§5.3);
* - 通讯地址:与参考 g_tCommSetParaTab(Comm/Pub/Const_CommSetPara.c)逐项对齐,
* 基址 0x8820(=34848);告警类沿用运行参数段 0x8027/0x8029;
* - 校验和(定值校验和):sum32 正码 + 反码成对封存(参考 tagPRS 的
* dwTagSum/dwTagSumN 模式),selfcheck 失配 → 置闭锁;
* - ⚠ 默认值/范围为**拟定值**:参考 EEPROM 出厂默认表未在本仓库,
* 待对照后逐项修订(规划 §10.3 待补项);范围先按 DTU 馈线典型量级。
*
* 线程约定(B7 定):装载(init/store_parse)在 defaultTask(存储 bring-up,
* STORAGE_READY 前);单项写在 iec104Task(C_SE/YK12,经 set_sealed 原子路径);
* 落盘在 defaultTask(配置引擎属主)。读在保护消费者任务(快照值原子)。
* 双缓冲交换 = 单字写,读侧永远看到一致快照;写者之间靠启动时序串行
* (装载先于 NET_READY,104 写在其后)。
*
* 创建日期:2026-10-11
*/
#ifndef PROT_SET_H
#define PROT_SET_H
#include <stdint.h>
/* Q10 定点:工程量 × 1024(与参考 2^10 口径一致)。
* 必须写成单精度:×/÷1024 只是 2^10 指数平移,float 与 double 的结果逐位相同
* (宏里 42 个字面量 + int32 全域往返均已穷举核对),而写成 double 会把
* MicroLIB 的软浮点拉进镜像——F407 只有单精度 FPU,本工程的保护判据每
* 20 ms 节拍每元件要读三次定值(见 prot_elm_run),软件双精度纯属白烧。 */
#define PROT_SET_Q10(v) ((int32_t)((float)(v) * 1024.0f))
#define PROT_SET_FROM_Q10(v) ((float)(v) / 1024.0f)
/* 定值项编号(枚举序 = RAM 数组序 = 校验和覆盖序,只增不删不改序) */
typedef enum {
/* --- 三段式相间过流(A 相):投退/跳闸投退/电流/延时 --- */
PS_OC1_EN = 0, /* 0x8856 Ⅰ段投退 */
PS_OC1_TRIP, /* 0x8857 Ⅰ段跳闸投退(0 告警 / 1 跳闸) */
PS_OC1_CUR, /* 0x8858 Ⅰ段电流定值(A,二次值) */
PS_OC1_DLY, /* 0x8859 Ⅰ段延时(ms) */
PS_OC2_EN, /* 0x885A */
PS_OC2_TRIP, /* 0x885B */
PS_OC2_CUR, /* 0x885C */
PS_OC2_DLY, /* 0x885D */
PS_OC3_EN, /* 0x885E */
PS_OC3_TRIP, /* 0x885F */
PS_OC3_CUR, /* 0x8860 */
PS_OC3_DLY, /* 0x8861 */
/* --- 过负荷(A 相) --- */
PS_OL_EN, /* 0x8871 */
PS_OL_TRIP, /* 0x8872 */
PS_OL_CUR, /* 0x8873 */
PS_OL_DLY, /* 0x8874 */
/* --- 过压 / 欠压(UA;沿用参考告警段 0x8029/0x8027) --- */
PS_OV_EN, /* 本地投退(参考告警类无独立投退,V0.1 补) */
PS_OV_VOL, /* 0x8029 过电压门限(V,二次值) */
PS_OV_DLY, /* 0x802A 过电压延时(ms) */
PS_UV_EN, /* 本地投退 */
PS_UV_VOL, /* 0x8027 低电压门限(V,二次值) */
PS_UV_DLY, /* 0x8028 低电压延时(ms) */
/* --- 零序过压(UN) --- */
PS_3U0_EN, /* 0x888E */
PS_3U0_VOL, /* 0x888F 3U0 定值(V,二次值) */
PS_3U0_DLY, /* 0x8890 延时(ms) */
/* --- 公共 --- */
PS_RET_OVER, /* 过量返回系数(返回门槛 = 定值 × 系数,<1) */
PS_RET_UNDER, /* 欠量返回系数(返回门槛 = 定值 × 系数,>1) */
PS_PT_PRI, /* 0x8820 PT 一次额定(V) */
PS_PT_SEC, /* 0x8821 PT 二次额定(V) */
PS_CT_PRI, /* 0x8825 CT 一次额定(A) */
PS_CT_SEC, /* 0x8826 CT 二次额定(A) */
/* --- 全局软压板(B7):104 YK12 两段式投退;0 = 保护退出服务 --- */
PS_GLOBAL_EN, /* 本地项(无通讯地址,经 YK12 写、C_RD 不可读) */
/* --- 过频 / 低频(B8):投退/动作频率/延时 + 各自返回系数 ---
* ⚠ 通讯地址:参考 g_tCommSetParaTab 的保护定值段(0x8820~0x8882)
* 含"低压/低频"类目(规划 §5.1),但 OF/UF 的**逐项地址不在本仓库**
* (参考 Comm 源文件未随仓库提供)→ 按"找不到对应即本地项"规则全部
* comm_addr=0 登记本地项(104 C_SE 不可寻址),待对照参考表后补。
* ⚠ 默认值/范围为**拟定**(同全表口径,规划 §5.4 落实进度注)。 */
PS_OF_EN, /* 过频投退(本地) */
PS_OF_HZ, /* 过频动作频率(Hz) */
PS_OF_DLY, /* 过频延时(ms) */
PS_UF_EN, /* 低频投退(本地) */
PS_UF_HZ, /* 低频动作频率(Hz) */
PS_UF_DLY, /* 低频延时(ms) */
PS_RET_OF, /* 过频返回系数(返回门槛 = 定值 × 系数,<1;本地) */
PS_RET_UF, /* 低频返回系数(返回门槛 = 定值 × 系数,>1;本地) */
PS_ID_COUNT
} prot_set_id_t;
/* 定值项元数据(ROM 常量表,校验和自检不覆盖它——只覆盖 RAM 值区) */
typedef struct {
uint16_t comm_addr; /* 通讯信息体地址(0 = 本地项,不上送) */
uint8_t is_ctl; /* 1 = 投退/枚举项(0/1),0 = 模拟量项 */
int32_t def; /* 默认值(Q10;投退项为 0/1 的 Q10) */
int32_t min; /* 下限(Q10) */
int32_t max; /* 上限(Q10) */
} prot_set_meta_t;
extern const prot_set_meta_t g_prot_set_meta[PS_ID_COUNT];
/*
* 函数功能:装载出厂默认值并封存校验和(幂等,内核启动前可调)
*/
void prot_set_init(void);
/*
* 函数功能:整表装载外部值(P4 起由 cfg_file 定值段调用),逐项范围校验
* 入口参数:vals - PS_ID_COUNT 个 Q10 值
* 返 回 值:0 全部合法(已装载并封存)/ -1 存在越界项(**整表不装载**,
* 返回前可经 prot_set_bad_mask() 取越界位图)
*/
int prot_set_load_raw(const int32_t *vals);
/* 越界位图(bit i = 第 i 项越界;load_raw 失败后有效。B8:项数 32→40,
* 位图随项数扩为 64 位——消费方仅主机单测,板端闭锁走 prot_set_locked()) */
uint64_t prot_set_bad_mask(void);
/*
* 函数功能:单项写入(范围校验;**不自动重封校验和**——批量改完必须
* 显式 prot_set_seal(),否则 selfcheck 判"定值被非法改写")
* 返 回 值:0 / -1 越界拒写
*/
int prot_set_set(prot_set_id_t id, int32_t q10);
int32_t prot_set_get(prot_set_id_t id); /* Q10 原值 */
float prot_set_get_f(prot_set_id_t id); /* 工程量浮点 */
uint8_t prot_set_get_ctl(prot_set_id_t id); /* 投退项:!=0 视为投入 */
/* 校验和(定值校验和):sum32 覆盖 RAM 值区;seal 封存正/反码对 */
uint32_t prot_set_checksum(void);
void prot_set_seal(void);
/* 自检:重算并与封存值比对,失配 → 置闭锁并返回 -1(已闭锁也返回 -1) */
int prot_set_selfcheck(void);
uint8_t prot_set_locked(void);
/*
* 函数功能:单项**原子**写入+封存(B7,收口 B5 竞态窗口)
* 入口参数:id - 定值项编号;q10 - Q10 定点值
* 返 回 值:0 / -1 越界或非法编号拒写(原值不动)
* 函数说明:影子缓冲拷贝 → 改影子 → 重封校验和 → 单字交换活跃区。
* selfcheck 永远看到"值区与封存一致"的完整快照,不存在
* "已改值未封存"中间态(区别于 prot_set_set+seal 的批处理路径,
* 两条路径不得在一次批处理中途交错)。置脏标志(待持久化)。
*/
int prot_set_set_sealed(prot_set_id_t id, int32_t q10);
/* 脏标志(存在未落盘的定值改动):set_sealed 置位;load/init 不置 */
uint8_t prot_set_dirty_peek(void); /* 非消费(生产者用它通知属主任务) */
uint8_t prot_set_dirty_take(void); /* 消费(属主任务落盘前取) */
void prot_set_dirty_mark(void); /* 写盘失败回置(等下轮重试) */
/* ---------------- 持久化 blob(B7;纯逻辑,主机可单测) ----------------
* 格式(小端):magic 'PSET'(4B) + version u16 + count u16
* + values u32×count + sum32 u32 + ~sum32 u32
* 版本 2(B8:定值表 32→40 项,OF/UF 尾追加);count 必须等于 PS_ID_COUNT
* (定值表增项 → 旧 blob 整体作废,编号不回收但格式换代,宁可用出厂默认
* 也不半装载)。ver 1 旧档在 parse 即被版本闸拒绝 → 出厂默认 + 日志
* (措辞 = "version change",非 CORRUPT,见 prot_set_store/default_task)。 */
#define PROT_SET_BLOB_MAGIC 0x50534554uL /* 字节序 P,S,E,T */
#define PROT_SET_BLOB_VER 2u
#define PROT_SET_BLOB_HDR_SZ 8u /* magic(4)+ver(2)+cnt(2) */
#define PROT_SET_BLOB_SZ (PROT_SET_BLOB_HDR_SZ + 4u * (uint32_t)PS_ID_COUNT + 8u)
/*
* 函数功能:把当前值区序列化为 blob(校验和按值区现算,不依赖封存值)
* 返 回 值:0 / -1 缓冲不足或参数非法;*p_len 输出实际长度
*/
int prot_set_store_serialize(uint8_t *p_buf, uint32_t cap, uint32_t *p_len);
/*
* 函数功能:解析 blob 并**整表原子**装载(all-or-nothing)
* 入口参数:p_buf/len - blob 字节流
* 返 回 值:0 已装载并封存 / -1 拒绝(magic/版本/长度/校验对不符或
* 任一项越界 → 值区一字不动;越界项经 prot_set_bad_mask() 指认)
*/
int prot_set_store_parse(const uint8_t *p_buf, uint32_t len);
#endif /* PROT_SET_H */