ffd462ef3c
卡 5(protect_task.c 第⑤闭锁源,「数据可信」§4.3 决策 1=闭锁): - UA/UN/IA 的 adc_cal VALID 未全置位 → prot_elm_init + 本拍不 eval;每拍现查 flags、无自有状态(卡 12 标定写入后自动解锁);判据链优先级 = 采样可信在前、 标定可用在后(数据都是旧的谈不上标定) - 边沿日志用 DBG_INFO 而非 [ERR]:未标定是出厂常态、非故障,且 @test 禁用 [ERR](「默认构建保护不动作 = 期望」的台架判据同步项已在 MR 报 lead); SOE 分型 SOE_T_CAL_BLOCK/RESUME(soe_rec.h 枚举尾追加,值 6/7——reader 侧 显示标签映射归道B reader,MR 已报) - 台架旁路 = 编译期宏 DTU_BENCH(§4.3:不进 cfg 不进 104;本仓所有提交目标 都不定义它 = 产品恒强制闭锁) 卡 6(下游三常数按工程量重定,依据同源 docs/任务规划/数据可信.md §2.3): - FREQ_AMP_MIN(freq.h):语义从拟定码值域重定为二次值 V——50 V = 0.5×Un (标称 100 V),断保险/PT 空载/浮空必低于之;数值沿用 50.0f 属巧合并在 注释明写;eng=0 过渡期本门恒失效 → OF/UF 按必不启动填充,与卡 5 同向安全 - k_yc[].deadband(iec104_pts.c):9 点按「额定 0.5 %」规则重定:电压类 0.5 %×100 V=0.5、电流类 0.5 %×1 A=0.005、频率维持 0.5 Hz 绝对值(非额定 比,卡 10 运行参数化);标称基准与 prot_set 头部同源,防两处真相 - g_prot_set_meta[](prot_set.c):数值/范围复核结论=不动(0~4×标称自洽), 文件头补量纲口径块:A/V = 二次值、标称 100 V/1 A、OV120=1.2Un/UV20=.2Un/ 3U0 15=.15Un、OC1/2/3=10/5/2×Ir、OL=1.0×Ir;PS_ID_COUNT/blob VER 未动 - iec104 套件 TC-008 死区用例同步重定标(100.4 带内 / 101.25 越带),97/97 卡 7(test/host/prot_dim 新套件,真实链 adc_cal→ring→phasor→prot_elm): - 用例从 ADC 码值出发、显式写出 code↔二次值互逆换算(dim_code vs apply), 折算点被旁路或量纲再错位断言立刻翻转(M4 判据⑥「不该动作时不动作」) - 合成 ROM 覆写(#undef K_Q16 宏)模拟卡 12 标定后板级口径,走 adc_cal_set 正规路径置 VALID;b=-30 码全链对消进 rms 断言 - 38/38:基线静默(含 OL 低定值陷阱)、反错配对照(raw 码值灌环复现历史事故 必假动作 vs 经折算必静默)、OC1/2/3+OL+OV+UV+3U0 七类逐一:越限定值→ 受控启动拍→dly-2 不动作/+5 动作→返回系数带内保持→跌破释放、双件聚合位图 独立性(撤 IA 只回 OC1) 测试与注册:prot-dim-unit-test 钩子 + TC-HOST-PROTDIM 族(游标 010,B 层口径 同 ADCHEALTH/ADCCAL 先例);无新 MCU 源文件(uvprojx/SIM_EXEMPT 零改动) gate:@build 0 错 0 警(Code=215640 RO=21388 RW=1220 ZI=131980 vs 基线 215440/19780/1220/131980 → Flash +1808 B、RAM 零增量);protectTask 静态最坏 链 872 B/margin 1176 B(57%)PASS,adcTask 不变;staged 门禁除 mem-numbers/ mem-budget(台账漂移,回填归 lead)外全绿: gate: only mem-budget/mem-numbers pending lead ledger backfill BOM/CR/U+FFFD/字面量 ASCII 已逐文件自查(本轮未触碰带 BOM 文件)
451 lines
15 KiB
C
451 lines
15 KiB
C
/*
|
||
* 模块名称:IEC 60870-5-104 点表与数据源适配(实现)
|
||
* 模块功能:实现 iec104_pts.h——YC/YX/YK/定值点表(ROM)、板端默认源
|
||
* (phasor / prot_elm / prot_set)、COV 快照比对(遥信变位 +
|
||
* 遥测死区)。点表口径见 iec104_pts.h 文件头与设计文档 §3。
|
||
* 线程约定:init/bind 建服务前;其余仅 104 服务任务上下文(快照非原子)。
|
||
* 创建日期:2026-10-12(B4)
|
||
* 修改记录:
|
||
* 2026-10-25 DTU 项目组 卡 6(「数据可信」):YC 死区由拟定码值域重定为
|
||
* 二次值工程量域(额定 0.5 % 规则),判据依据见
|
||
* k_yc 表头注释;数值随卡 9 迁运行参数,本表将退化为
|
||
* ROM 默认载体。
|
||
*/
|
||
#include "iec104_pts.h"
|
||
|
||
#include <string.h>
|
||
|
||
#include "iec104_asdu.h" /* QDS/DIQ 品质位常量 */
|
||
#include "phasor.h" /* 板端源:遥测 = 基波有效值 */
|
||
#include "prot_elm.h" /* 板端源:遥信 = 元件状态 */
|
||
#include "prot_set.h" /* 板端源:定值 + 闭锁 */
|
||
#include "adc_input.h" /* adc_semantic_t(phasor 实例按语义绑定) */
|
||
|
||
/* ---------------- YC 表(§1.5 点号 4011+;死区 = 二次值工程量域) --------- */
|
||
typedef struct {
|
||
uint32_t ioa;
|
||
int8_t sem; /* 绑定的 phasor 语义通道(-1 = 无 phasor 源,恒无效) */
|
||
float deadband; /* 死区(二次值工程量绝对值,「数据可信」卡 6 重定) */
|
||
} pts_yc_def_t;
|
||
|
||
/* 死区规则 = 额定二次值的 0.5 %(「数据可信」§2.3 表第 2 行建议规则,卡 6 采纳;
|
||
* 额定基准 100 V / 1 A 与 App/algo/prot_set.c 头部同源,勿在此另立口径):
|
||
* 电压类 0.5 % × 100 V = 0.5 V 电流类 0.5 % × 1 A = 0.005 A
|
||
* 频率点不适用"额定百分比"(额定附近 0.5 Hz 与旧值同量级,维持 0.5 并随
|
||
* 卡 10 运行参数段可调)。IV 品质点(sem=-1)数值仅为将来启用预留同型。
|
||
* ⚠ 过渡期(eng=0 引脚电压域,卡 12 标定前):上送值本身非二次值,死区
|
||
* 按本域判定无意义但也不会漏报——104 侧 IV/数据可信度语义由 M5 快照层
|
||
* (卡 8/9)统一处理,本卡只把"量纲错位"这一处常量债还掉。 */
|
||
static const pts_yc_def_t k_yc[] = {
|
||
{ 0x4011u, (int8_t)ADC_SEM_UA, 0.5f }, /* 1Ua:0.5 % × 100 V */
|
||
{ 0x4012u, -1, 0.5f }, /* 1Ub:V0.1 削顶 → IV */
|
||
{ 0x4013u, -1, 0.5f }, /* 1Uc:同上 */
|
||
{ 0x4014u, (int8_t)ADC_SEM_UN, 0.5f }, /* 1U0(外部零序专用通道) */
|
||
{ 0x4015u, (int8_t)ADC_SEM_IA, 0.005f }, /* 1Ia:0.5 % × 1 A */
|
||
{ 0x4016u, -1, 0.005f }, /* 1Ib */
|
||
{ 0x4017u, -1, 0.005f }, /* 1Ic */
|
||
{ 0x4018u, -1, 0.005f }, /* 1I0 */
|
||
{ 0x401Du, -1, 0.5f }, /* 1f:Hz 绝对死区(非额定比)→ IV */
|
||
};
|
||
#define YC_N ((uint8_t)(sizeof(k_yc) / sizeof(k_yc[0])))
|
||
|
||
/* phasor 实例下标缓存(init 时按 sem+harm==1 查表;-1 = 未找到) */
|
||
static int8_t s_yc_phasor_idx[YC_N];
|
||
|
||
/* ---------------- YX 表(IOA = 1..33;双点 = 开关位置类) ------------------ */
|
||
#define YX_N 33u
|
||
#define YX_DP_N 4u /* idx 0..3 = 双点(开关位置,V0.1 无硬件 → IV) */
|
||
|
||
/* 有效位图:YX15~18(idx14~17)+ YX23(idx22)+ YX31(idx30) */
|
||
#define YX_VALID_MASK (((1uLL << 14u) | (1uLL << 15u) | (1uLL << 16u) \
|
||
| (1uLL << 17u) | (1uLL << 22u) | (1uLL << 30u)))
|
||
|
||
/* ---------------- 数据源(默认 = 板端;bind_src 可整体替换) -------------- */
|
||
static int s_src_yc_read(uint8_t idx, float *out);
|
||
static uint64_t s_src_yx_bits(void);
|
||
static uint64_t s_src_yx_valid(void);
|
||
static int s_src_yk_exec(uint32_t ioa, uint8_t dpc, uint8_t select);
|
||
static int s_src_set_read(uint32_t addr, float *out);
|
||
static int s_src_set_write(uint32_t addr, float v, uint8_t select);
|
||
|
||
static const iec104_pts_src_t k_default_src = {
|
||
s_src_yc_read, s_src_yx_bits, s_src_yx_valid,
|
||
s_src_yk_exec, s_src_set_read, s_src_set_write
|
||
};
|
||
static const iec104_pts_src_t *s_src;
|
||
|
||
/* ---------------- COV 快照 ---------------- */
|
||
static float s_yc_last[YC_N];
|
||
static uint16_t s_yc_have; /* bit i = 已有上次快照 */
|
||
static uint64_t s_yx_last;
|
||
static uint8_t s_yx_snap_ok;
|
||
|
||
/* ============================ 公开接口 ================================== */
|
||
|
||
/*
|
||
* 函数功能:初始化点表模块(扫 phasor 基波实例映射、恢复默认源、清快照)
|
||
*/
|
||
void iec104_pts_init(void) {
|
||
uint8_t i;
|
||
uint8_t n;
|
||
|
||
(void)memset(s_yc_phasor_idx, -1, sizeof(s_yc_phasor_idx));
|
||
n = phasor_inst_count();
|
||
for (i = 0u; i < YC_N; i++) {
|
||
uint8_t j;
|
||
|
||
if (k_yc[i].sem < 0) {
|
||
continue;
|
||
}
|
||
for (j = 0u; j < n; j++) {
|
||
const phasor_inst_t *inst = phasor_inst(j);
|
||
|
||
if ((inst != NULL) && ((uint8_t)inst->sem == (uint8_t)k_yc[i].sem)
|
||
&& (inst->harm == 1u)) {
|
||
s_yc_phasor_idx[i] = (int8_t)j;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
s_src = &k_default_src;
|
||
s_yc_have = 0u;
|
||
s_yx_snap_ok = 0u;
|
||
s_yx_last = 0u;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:替换数据源(NULL = 恢复板端默认源;单测注入假源)
|
||
*/
|
||
void iec104_pts_bind_src(const iec104_pts_src_t *src) {
|
||
s_src = (src != NULL) ? src : &k_default_src;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:遥测点数
|
||
*/
|
||
uint8_t iec104_pts_yc_count(void) {
|
||
return YC_N;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:遥测点 IOA(按下标;越界 → 0)
|
||
*/
|
||
uint32_t iec104_pts_yc_ioa(uint8_t idx) {
|
||
return (idx < YC_N) ? k_yc[idx].ioa : 0u;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:读遥测(值 + 品质 descriptor;源 -2 → NT,其余失败 → IV)
|
||
* 返 回 值:0 有效 / -1 无效
|
||
*/
|
||
int iec104_pts_yc_read(uint8_t idx, float *v, uint8_t *qds) {
|
||
int rc;
|
||
|
||
if (v != NULL) {
|
||
*v = 0.0f;
|
||
}
|
||
if ((idx >= YC_N) || (s_src == NULL) || (s_src->yc_read == NULL)) {
|
||
if (qds != NULL) {
|
||
*qds = IEC104_QDS_IV;
|
||
}
|
||
return -1;
|
||
}
|
||
rc = s_src->yc_read(idx, v);
|
||
if (rc == 0) {
|
||
if (qds != NULL) {
|
||
*qds = 0u;
|
||
}
|
||
return 0;
|
||
}
|
||
if (v != NULL) {
|
||
*v = 0.0f;
|
||
}
|
||
if (qds != NULL) {
|
||
*qds = (rc == -2) ? IEC104_QDS_NT : IEC104_QDS_IV;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:遥信点数
|
||
*/
|
||
uint8_t iec104_pts_yx_count(void) {
|
||
return (uint8_t)YX_N;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:遥信点 IOA(idx + 1;越界 → 0)
|
||
*/
|
||
uint32_t iec104_pts_yx_ioa(uint8_t idx) {
|
||
return ((uint8_t)idx < YX_N) ? ((uint32_t)idx + 1u) : 0u;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:该遥信是否双点型(idx < 4 = 开关位置类)
|
||
*/
|
||
uint8_t iec104_pts_yx_is_dp(uint8_t idx) {
|
||
return ((uint8_t)idx < YX_DP_N) ? 1u : 0u;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:读遥信(无效通道 → DIQ_IV;双点 → DPC 编码)
|
||
*/
|
||
void iec104_pts_yx_read(uint8_t idx, uint8_t *out) {
|
||
uint64_t bits;
|
||
uint64_t valid;
|
||
uint8_t on;
|
||
|
||
if (out == NULL) {
|
||
return;
|
||
}
|
||
if ((idx >= YX_N) || (s_src == NULL) || (s_src->yx_bits == NULL)
|
||
|| (s_src->yx_valid == NULL)) {
|
||
*out = IEC104_DIQ_IV;
|
||
return;
|
||
}
|
||
valid = s_src->yx_valid();
|
||
if (((valid >> idx) & 1u) == 0u) {
|
||
*out = IEC104_DIQ_IV;
|
||
return;
|
||
}
|
||
bits = s_src->yx_bits();
|
||
on = (uint8_t)((bits >> idx) & 1u);
|
||
if (iec104_pts_yx_is_dp(idx) != 0u) {
|
||
*out = (on != 0u) ? (uint8_t)IEC104_DPC_ON : (uint8_t)IEC104_DPC_OFF;
|
||
} else {
|
||
*out = on;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 函数功能:COV 快照比对(遥信 = 有效位翻转;遥测 = 死区)
|
||
* 入口参数:cov = 输出变位位图(NULL = 只刷快照)
|
||
*/
|
||
void iec104_pts_cov_check(iec104_pts_cov_t *cov) {
|
||
iec104_pts_cov_t local;
|
||
|
||
(void)memset(&local, 0, sizeof(local));
|
||
|
||
/* YX:变位 = 有效位上的位翻转(无效位不参与,避免 IV 通道抖动成"变位") */
|
||
if ((s_src != NULL) && (s_src->yx_bits != NULL)
|
||
&& (s_src->yx_valid != NULL)) {
|
||
uint64_t bits = s_src->yx_bits() & s_src->yx_valid();
|
||
|
||
if (s_yx_snap_ok != 0u) {
|
||
local.yx_changed = bits ^ s_yx_last;
|
||
}
|
||
s_yx_last = bits;
|
||
s_yx_snap_ok = 1u;
|
||
}
|
||
|
||
/* YC:死区比对(仅对"本次有效 且 上次有快照"的点判定) */
|
||
if ((s_src != NULL) && (s_src->yc_read != NULL)) {
|
||
uint8_t i;
|
||
|
||
for (i = 0u; i < YC_N; i++) {
|
||
float v;
|
||
|
||
if (s_src->yc_read(i, &v) != 0) {
|
||
continue;
|
||
}
|
||
if (((s_yc_have >> i) & 1u) != 0u) {
|
||
float d = v - s_yc_last[i];
|
||
|
||
if (d < 0.0f) {
|
||
d = -d;
|
||
}
|
||
if (d > k_yc[i].deadband) {
|
||
local.yc_changed |= (uint16_t)(1u << i);
|
||
}
|
||
}
|
||
s_yc_last[i] = v;
|
||
s_yc_have |= (uint16_t)(1u << i);
|
||
}
|
||
}
|
||
|
||
if (cov != NULL) {
|
||
*cov = local;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 函数功能:遥控两段式(转发数据源;select=1 选择段 / 0 执行段)
|
||
* 返 回 值:0 接受 / -1 拒绝(调用方回 PN)
|
||
*/
|
||
int iec104_pts_yk_exec(uint32_t ioa, uint8_t dpc, uint8_t select) {
|
||
if ((s_src == NULL) || (s_src->yk_exec == NULL)) {
|
||
return -1;
|
||
}
|
||
return s_src->yk_exec(ioa, dpc, select);
|
||
}
|
||
|
||
/*
|
||
* 函数功能:按通讯地址读定值(工程量浮点)
|
||
* 返 回 值:0 / -1 未知地址
|
||
*/
|
||
int iec104_pts_set_read(uint32_t addr, float *out) {
|
||
if ((s_src == NULL) || (s_src->set_read == NULL)) {
|
||
return -1;
|
||
}
|
||
return s_src->set_read(addr, out);
|
||
}
|
||
|
||
/*
|
||
* 函数功能:按通讯地址写定值(select=1 只校验;0 执行写入)
|
||
* 返 回 值:0 / -1 越界或未知地址
|
||
*/
|
||
int iec104_pts_set_write(uint32_t addr, float v, uint8_t select) {
|
||
if ((s_src == NULL) || (s_src->set_write == NULL)) {
|
||
return -1;
|
||
}
|
||
return s_src->set_write(addr, v, select);
|
||
}
|
||
|
||
/* ============================ 板端默认源 ================================= */
|
||
|
||
/*
|
||
* 函数功能:板端默认源 - 遥测 = 基波相量有效值(fAmSQ)
|
||
* 返 回 值:0 / -1 无 phasor 源(削顶通道/频率未实现)/ -2 未满一周波(NT)
|
||
*/
|
||
static int s_src_yc_read(uint8_t idx, float *out) {
|
||
phasor_t p;
|
||
int8_t pi;
|
||
|
||
if ((idx >= YC_N) || (out == NULL)) {
|
||
return -1;
|
||
}
|
||
pi = s_yc_phasor_idx[idx];
|
||
if (pi < 0) {
|
||
return -1; /* 无 phasor 源(削顶通道/频率未实现) */
|
||
}
|
||
if (phasor_get((uint8_t)pi, &p) != 0) {
|
||
return -2; /* 未满一周波:未就绪(NT) */
|
||
}
|
||
*out = p.fAmSQ; /* 有效值口径(系数已折算) */
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:板端默认源 - 遥信位图(保护元件动作态 + 定值闭锁)
|
||
*/
|
||
static uint64_t s_src_yx_bits(void) {
|
||
prot_elm_state_t oc1;
|
||
prot_elm_state_t oc2;
|
||
prot_elm_state_t oc3;
|
||
prot_elm_state_t ol;
|
||
prot_elm_state_t u0;
|
||
uint64_t bits = 0u;
|
||
|
||
prot_elm_state(PE_OC1, &oc1);
|
||
prot_elm_state(PE_OC2, &oc2);
|
||
prot_elm_state(PE_OC3, &oc3);
|
||
prot_elm_state(PE_OL, &ol);
|
||
prot_elm_state(PE_3U0, &u0);
|
||
if ((oc1.asserted != 0u) || (oc2.asserted != 0u) || (oc3.asserted != 0u)
|
||
|| (u0.asserted != 0u)) {
|
||
bits |= (1uLL << 14u); /* YX15 故障总 */
|
||
}
|
||
if (oc1.asserted != 0u) {
|
||
bits |= (1uLL << 15u); /* YX16 过流 I 段 */
|
||
}
|
||
if (oc2.asserted != 0u) {
|
||
bits |= (1uLL << 16u); /* YX17 过流 II 段 */
|
||
}
|
||
if (oc3.asserted != 0u) {
|
||
bits |= (1uLL << 17u); /* YX18 过流 III 段 */
|
||
}
|
||
if (ol.asserted != 0u) {
|
||
bits |= (1uLL << 22u); /* YX23 过载 */
|
||
}
|
||
if (prot_set_locked() != 0u) {
|
||
bits |= (1uLL << 30u); /* YX31 保护闭锁 */
|
||
}
|
||
return bits;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:板端默认源 - 遥信有效位图(V0.1 = YX15~18/23/31)
|
||
*/
|
||
static uint64_t s_src_yx_valid(void) {
|
||
return YX_VALID_MASK;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:板端默认源 - 遥控(YK11 复归 → prot_elm_request_reset;
|
||
* YK12 全局软压板 → PS_GLOBAL_EN 两段式转真,B7)
|
||
* 返 回 值:0 / -1 无出口硬件或未知 IOA(YK1~4/13/14 负向确认)
|
||
* 函数说明:本回调跑在 iec104Task 上下文,**不得**直接 prot_elm_init()
|
||
* (与 protectTask 的 eval 竞态)→ 落请求,下一拍 eval 头部消费(B5)。
|
||
* YK12 走 prot_set_set_sealed(原子写+封存,B7);protectTask 下一拍
|
||
* 读到压板态即复位元件并停判据(protect_task.c)。
|
||
*/
|
||
static int s_src_yk_exec(uint32_t ioa, uint8_t dpc, uint8_t select) {
|
||
switch (ioa) {
|
||
case 0x600Au: /* YK11 信号复归 → 元件状态复位(异步一拍) */
|
||
(void)dpc; /* 复归与双点值无关 */
|
||
if (select == 0u) {
|
||
prot_elm_request_reset();
|
||
}
|
||
return 0;
|
||
case 0x600Bu: /* YK12 全局软压板(PS_GLOBAL_EN)两段式 */
|
||
if ((dpc != (uint8_t)IEC104_DPC_ON) && (dpc != (uint8_t)IEC104_DPC_OFF)) {
|
||
return -1; /* 非法双点命令:选择段即拒 */
|
||
}
|
||
if (select != 0u) {
|
||
return 0; /* 选择段 = 只校验 */
|
||
}
|
||
return prot_set_set_sealed(PS_GLOBAL_EN,
|
||
(dpc == (uint8_t)IEC104_DPC_ON)
|
||
? PROT_SET_Q10(1) : PROT_SET_Q10(0));
|
||
default:
|
||
return -1; /* 其余 YK:无出口硬件/无对应能力 → 拒绝 */
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 函数功能:板端默认源 - 定值读(扫 g_prot_set_meta 通讯地址映射)
|
||
* 返 回 值:0 / -1 未知地址(本地项 comm_addr=0 不可寻址,B7 起显式排除)
|
||
*/
|
||
static int s_src_set_read(uint32_t addr, float *out) {
|
||
uint32_t i;
|
||
|
||
if (out == NULL) {
|
||
return -1;
|
||
}
|
||
for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) {
|
||
if ((g_prot_set_meta[i].comm_addr != 0u)
|
||
&& (g_prot_set_meta[i].comm_addr == (uint16_t)addr)) {
|
||
*out = prot_set_get_f((prot_set_id_t)i);
|
||
return 0;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:板端默认源 - 定值写(Q10 范围校验;执行段 prot_set_set_sealed
|
||
* 原子写+封存,B7 收口 B5 竞态窗口;置脏 → 104 任务通知落盘)
|
||
* 返 回 值:0 / -1 越界或未知地址(本地项 comm_addr=0 不可寻址)
|
||
*/
|
||
static int s_src_set_write(uint32_t addr, float v, uint8_t select) {
|
||
uint32_t i;
|
||
int32_t q10;
|
||
|
||
for (i = 0u; i < (uint32_t)PS_ID_COUNT; i++) {
|
||
const prot_set_meta_t *meta = &g_prot_set_meta[i];
|
||
|
||
if ((meta->comm_addr == 0u) || (meta->comm_addr != (uint16_t)addr)) {
|
||
continue;
|
||
}
|
||
q10 = PROT_SET_Q10(v);
|
||
if ((q10 < meta->min) || (q10 > meta->max)) {
|
||
return -1; /* 越界:选择段即拒(执行段同样拒) */
|
||
}
|
||
if (select != 0u) {
|
||
return 0; /* 选择段 = 只做范围校验 */
|
||
}
|
||
return prot_set_set_sealed((prot_set_id_t)i, q10);
|
||
}
|
||
return -1; /* 未知地址 */
|
||
}
|