/* * 模块名称:保护定值模型(P1,L5-1 载体)——实现 * 模块功能:见 prot_set.h。纯逻辑,零平台依赖(仅 stdint.h + 自身头)。 * * ⚠ 默认值/范围为拟定值(参考 EEPROM 出厂默认表不在本仓库,规划 §10.3 待补); * 通讯地址逐项对照参考 Comm/Pub/Const_CommSetPara.c g_tCommSetParaTab。 * * 创建日期:2026-10-11 */ #include "prot_set.h" /* 元数据表:顺序必须与 prot_set_id_t 严格一致(逐行带地址注释,同 phasor * k_inst 的朴素行式风格) */ const prot_set_meta_t g_prot_set_meta[PS_ID_COUNT] = { /* addr ctl default min max 说明 */ { 0x8856, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* OC1 投退 */ { 0x8857, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* OC1 跳闸投退 */ { 0x8858, 0u, PROT_SET_Q10(10.0), 0, PROT_SET_Q10(100.0) }, /* OC1 电流 A */ { 0x8859, 0u, PROT_SET_Q10(0.0), 0, PROT_SET_Q10(60000) }, /* OC1 延时 ms */ { 0x885A, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, { 0x885B, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, { 0x885C, 0u, PROT_SET_Q10(5.0), 0, PROT_SET_Q10(100.0) }, { 0x885D, 0u, PROT_SET_Q10(500.0), 0, PROT_SET_Q10(60000) }, { 0x885E, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, { 0x885F, 1u, PROT_SET_Q10(0), 0, PROT_SET_Q10(1) }, /* OC3 默认告警 */ { 0x8860, 0u, PROT_SET_Q10(2.0), 0, PROT_SET_Q10(100.0) }, { 0x8861, 0u, PROT_SET_Q10(3000.0), 0, PROT_SET_Q10(60000) }, { 0x8871, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* 过负荷投退 */ { 0x8872, 1u, PROT_SET_Q10(0), 0, PROT_SET_Q10(1) }, /* 默认告警 */ { 0x8873, 0u, PROT_SET_Q10(1.0), 0, PROT_SET_Q10(100.0) }, { 0x8874, 0u, PROT_SET_Q10(10000.0),0, PROT_SET_Q10(60000) }, { 0x0000, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* OV 投退(本地) */ { 0x8029, 0u, PROT_SET_Q10(120.0), 0, PROT_SET_Q10(200.0) }, /* 过压 V */ { 0x802A, 0u, PROT_SET_Q10(10000.0),0, PROT_SET_Q10(60000) }, { 0x0000, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* UV 投退(本地) */ { 0x8027, 0u, PROT_SET_Q10(20.0), 0, PROT_SET_Q10(200.0) }, /* 欠压 V */ { 0x8028, 0u, PROT_SET_Q10(10000.0),0, PROT_SET_Q10(60000) }, { 0x888E, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* 3U0 投退 */ { 0x888F, 0u, PROT_SET_Q10(15.0), 0, PROT_SET_Q10(200.0) }, /* 3U0 V */ { 0x8890, 0u, PROT_SET_Q10(5000.0), 0, PROT_SET_Q10(60000) }, { 0x0000, 0u, PROT_SET_Q10(0.95), PROT_SET_Q10(0.5), PROT_SET_Q10(1.0) }, /* 过量返回系数 */ { 0x0000, 0u, PROT_SET_Q10(1.05), PROT_SET_Q10(1.0), PROT_SET_Q10(1.5) }, /* 欠量返回系数 */ { 0x8820, 0u, PROT_SET_Q10(10000.0),PROT_SET_Q10(100.0), PROT_SET_Q10(500000.0) }, { 0x8821, 0u, PROT_SET_Q10(100.0), PROT_SET_Q10(1.0), PROT_SET_Q10(200.0) }, { 0x8825, 0u, PROT_SET_Q10(100.0), PROT_SET_Q10(1.0), PROT_SET_Q10(10000.0) }, { 0x8826, 0u, PROT_SET_Q10(5.0), PROT_SET_Q10(1.0), PROT_SET_Q10(10.0) }, }; static uint32_t s_val[PS_ID_COUNT]; /* RAM 值区(uint32 承载 int32,校验和按字覆盖) */ static uint32_t s_sum; /* 封存的正码 */ static uint32_t s_sumn; /* 封存的反码 */ static uint32_t s_bad_mask; /* load_raw 越界位图 */ static uint8_t s_locked; /* 定值非法 → 闭锁(L5-1) */ /* * 函数功能:sum32 覆盖 RAM 值区(参考 Fun_CalSum32 同款:32 位字累加自然回绕) * 入口参数:无 * 返 回 值:校验和正码 */ static uint32_t prot_sum32(void) { uint32_t sum = 0u; uint32_t i; for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) { sum += s_val[i]; } return sum; } /* * 函数功能:把元数据表默认值刷进 RAM 值区 * 入口参数:无 * 返 回 值:无 */ static void prot_load_defaults(void) { uint32_t i; for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) { s_val[i] = (uint32_t)g_prot_set_meta[i].def; } } /* * 函数功能:装载出厂默认值并封存校验和(幂等) * 入口参数:无 * 返 回 值:无 */ void prot_set_init(void) { prot_load_defaults(); s_bad_mask = 0u; s_locked = 0u; prot_set_seal(); } /* * 函数功能:取最近一次 load_raw 的越界位图 * 入口参数:无 * 返 回 值:bit i = 第 i 项越界(load_raw 失败后有效) */ uint32_t prot_set_bad_mask(void) { return s_bad_mask; } /* * 函数功能:整表装载外部值(P4 起由 cfg_file 定值段调用),逐项范围校验 * 入口参数:vals - PS_ID_COUNT 个 Q10 值 * 返 回 值:0 全部合法(已装载并封存)/ -1 存在越界项或空指针(整表不装载) * 函数说明:all-or-nothing——宁可全旧不可半新(定值一致性优先); * 越界项经 prot_set_bad_mask() 指认。 */ int prot_set_load_raw(const int32_t *vals) { uint32_t mask = 0u; uint32_t i; if (vals == 0) { return -1; } for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) { if ((vals[i] < g_prot_set_meta[i].min) || (vals[i] > g_prot_set_meta[i].max)) { mask |= (1uL << i); } } s_bad_mask = mask; if (mask != 0u) { return -1; } for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) { s_val[i] = (uint32_t)vals[i]; } prot_set_seal(); return 0; } /* * 函数功能:单项写入(范围校验) * 入口参数:id - 定值项编号;q10 - Q10 定点值 * 返 回 值:0 / -1 越界或非法编号拒写(原值不动) * 函数说明:**不自动重封校验和**——批量改完必须显式 prot_set_seal(), * 否则 selfcheck 判"定值被非法改写"(参考系统改定值走重写整表)。 */ int prot_set_set(prot_set_id_t id, int32_t q10) { if (id >= PS_ID_COUNT) { return -1; } if ((q10 < g_prot_set_meta[id].min) || (q10 > g_prot_set_meta[id].max)) { return -1; } s_val[(uint32_t)id] = (uint32_t)q10; return 0; } /* * 函数功能:读定值 Q10 原值 * 入口参数:id - 定值项编号 * 返 回 值:Q10 值;非法编号返回 0 */ int32_t prot_set_get(prot_set_id_t id) { if (id >= PS_ID_COUNT) { return 0; } return (int32_t)s_val[(uint32_t)id]; } /* * 函数功能:读定值工程量浮点值 * 入口参数:id - 定值项编号 * 返 回 值:Q10 → float;非法编号返回 0.0 */ float prot_set_get_f(prot_set_id_t id) { return PROT_SET_FROM_Q10(prot_set_get(id)); } /* * 函数功能:读投退/枚举项 * 入口参数:id - 定值项编号 * 返 回 值:!=0 视为投入(1/0) */ uint8_t prot_set_get_ctl(prot_set_id_t id) { return (prot_set_get(id) != 0) ? 1u : 0u; } /* * 函数功能:实时计算校验和(不读封存值) * 入口参数:无 * 返 回 值:sum32 正码 */ uint32_t prot_set_checksum(void) { return prot_sum32(); } /* * 函数功能:封存当前值区的正/反码对(合法改定值闭环的最后一步) * 入口参数:无 * 返 回 值:无 * 函数说明:封存同时解除闭锁——selfcheck 失配后的唯一合法解锁路径。 */ void prot_set_seal(void) { s_sum = prot_sum32(); s_sumn = ~s_sum; s_locked = 0u; } /* * 函数功能:定值自检(L5-1)——重算 sum32 并与封存值比对 * 入口参数:无 * 返 回 值:0 通过 / -1 失配(已置闭锁) * 函数说明:失配 → s_locked 置位并保持,直到下一次 seal; * 元件层每拍读 prot_set_locked() 决定整体复位(联动闭锁)。 */ int prot_set_selfcheck(void) { if (prot_sum32() != s_sum) { s_locked = 1u; /* 值区与封存不符:定值被非法改写 → 闭锁 */ } if ((s_sum != (~s_sumn)) || (s_locked != 0u)) { s_locked = 1u; return -1; } return 0; } /* * 函数功能:读闭锁状态 * 入口参数:无 * 返 回 值:1 = 定值非法(保护应整体闭锁)/ 0 = 正常 */ uint8_t prot_set_locked(void) { return s_locked; }