feat(104遥测): 卡9改读L2快照+死区运行化2点确认 + 卡11绑频0x401D(道D M5/M6)
卡 9(App/protocol/iec104/iec104_pts.*,「数据可信」,docs/子系统设计/ IEC104上行设计说明.md §3.1/§4 同步): - 数据源换轨:板端默认 YC 源从直读 phasor 改为**整体透传 L2 遥测快照** (meas_get 双区无锁;"新不新、能不能信"只在发布侧判一次,M5-② 落地); iec104_pts_src_t 表尾追加 yc_read_ex(带品质)——旧注入源走 legacy 退路, 品质由返回值推导,行为与卡 9 前**完全一致**(存量假源用例零改动) - 品质映射 s_q_map:MEAS_QDS_* 低字节=线上 QDS 同值直传;CLIPPED→IV (「削顶通道 104 恒 IV」口径不变、从点表绑死 -1 改品质驱动——UB/UC/IB/ IC/IN 五路现绑快照槽,V0.2/N-18 削顶消失后**零改动自动启用**);IV 优先 NT;快照从未发布(开机 <200ms)→ IV|NT;无效信息体清零(旧线上口径保持) - 死区运行化:运行时副本 s_yc_db(ROM 默认 = 点表列,卡 6 额定 0.5% 档不变) + iec104_pts_yc_set_deadband()/iec104_pts_yc_deadband()——卡 10 运行参数段 (8020H)的接线点已留;非法 idx/负值/NaN 拒绝、成功时清该点待确认计数 - COV 遥测腿升级(lead 裁②"卡 9 是消费者"):判定 = 相对**上次上送值**(非 上次读值,防慢漂移吃基准)连续 2 个新测量点越死区才确认上送;回摆入带即 撤销候选;品质翻转当拍直报(含 0x401D 的 IV 进出)。测量点推进:板端按 快照 seq 去重(100ms poll vs 200ms 快照——不去重则同一帧把单点噪声计满 2 点,抗噪语义失效);注入源=每次调用一测点(单测步进自持) 卡 11:YC 表加 src 类型(PTS_SRC_MEAS/FREQ);0x401D 绑快照 freq_hz(与 freq_get 同源);snap.freq_valid==0 → IV 清零(卡 11 DoD 原句) 测试与文档:test/host/iec104 97→127 断言——TC-008 语义更新为 2 点确认; 新 TC-IEC104-025~028(024 号被存量 B7 用例裸标签占用,让号并改用全家长 形态)板端默认源走**真实 L2 链**(ring→phasor→freq→meas,非桩):未发布 NT/值透传/CLIPPED→IV 清零/绑频收敛 ±0.02Hz/未新鲜 IV/死区运行档压旧档/ 回摆撤销/seq 去重同帧不计数/换帧只变品质按集合直报;id_registry 族游标 023→028;IEC104 上行设计说明 §3.1 表+注/§4/§7/§8 第 4 条/变更记录同步。 无新 .c(uvprojx 零改动);PC 主站读回一致与频率 ±0.01Hz 属网络对端验证 ——步骤清单已发 lead 排窗,本轮零台架动作。 gate:@build 0 错 0 警(Code=218128 RO=21624 RW=1272 ZI=132864);增量 vs adeef7d:Flash +348B、RAM(RW+ZI) +48B(低于 96B 预估,链接器并洞), IRAM1 58.5% 不变;iec104Task 栈 worst=1456B margin=1104B(43%) PASS 无抬栈 (stack_report);--all-files 全量实跑:其余钩子全绿(含修掉一处 cppcheck variableScope 后),仅 mem-budget + mem-numbers 两红 = 台账受管区 vs .map 漂移(回填属 lead 单写者区,批 1/道D-1 同口径): gate: only mem-budget/mem-numbers pending lead ledger backfill BOM/CR/U+FFFD/字面量 ASCII 逐文件自查通过(未触碰带 BOM 文件)。
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
/*
|
||||
* 模块名称:IEC 60870-5-104 点表与数据源适配(实现)
|
||||
* 模块功能:实现 iec104_pts.h——YC/YX/YK/定值点表(ROM)、板端默认源
|
||||
* (phasor / prot_elm / prot_set)、COV 快照比对(遥信变位 +
|
||||
* 遥测死区)。点表口径见 iec104_pts.h 文件头与设计文档 §3。
|
||||
* (**L2 遥测快照**(卡 9)/ prot_elm / prot_set)、COV 比对(遥信变位 +
|
||||
* 遥测死区 2 点确认 + 品质变化)。点表口径见 iec104_pts.h 文件头与
|
||||
* 设计文档 §3。
|
||||
* 线程约定:init/bind 建服务前;其余仅 104 服务任务上下文(快照非原子)。
|
||||
* 创建日期:2026-10-12(B4)
|
||||
* 修改记录:
|
||||
@@ -10,47 +11,71 @@
|
||||
* 二次值工程量域(额定 0.5 % 规则),判据依据见
|
||||
* k_yc 表头注释;数值随卡 9 迁运行参数,本表将退化为
|
||||
* ROM 默认载体。
|
||||
* 2026-10-25 DTU 项目组 卡 9/卡 11(「数据可信」,道D):YC 板端源改读
|
||||
* L2 遥测快照(App/algo/meas.h,meas_get 无锁双区);
|
||||
* 削顶五路由快照品质 CLIPPED 驱动线上 IV(不再绑死 -1,
|
||||
* V0.2/N-18 零改动自动启用);0x401d 绑频率源(卡 11);
|
||||
* 死区改运行时副本 + set/get 入口;COV 遥测腿 = 死区
|
||||
* 连续 2 点确认(板端按快照 seq 去重)+ 品质翻转即报。
|
||||
* 单测 = test/host/iec104 TC-IEC104-025~028。
|
||||
*/
|
||||
#include "iec104_pts.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "iec104_asdu.h" /* QDS/DIQ 品质位常量 */
|
||||
#include "phasor.h" /* 板端源:遥测 = 基波有效值 */
|
||||
#include "meas.h" /* 板端源:遥测 = L2 遥测快照(卡 9;品质域位同源) */
|
||||
#include "prot_elm.h" /* 板端源:遥信 = 元件状态 */
|
||||
#include "prot_set.h" /* 板端源:定值 + 闭锁 */
|
||||
#include "adc_input.h" /* adc_semantic_t(phasor 实例按语义绑定) */
|
||||
|
||||
/* ---------------- YC 表(§1.5 点号 4011+;死区 = 二次值工程量域) --------- */
|
||||
/* ---------------- YC 表(§1.5 点号 4011+;死区列 = ROM 默认值) ------------ */
|
||||
/* 源类型(「数据可信」卡 11:YC 表加 src 类型区分相量/频率) */
|
||||
#define PTS_SRC_MEAS 0u /* L2 快照槽 sem(电气量,yc/qds 直读) */
|
||||
#define PTS_SRC_FREQ 1u /* 快照频率(freq_valid 门 → IV) */
|
||||
|
||||
typedef struct {
|
||||
uint32_t ioa;
|
||||
int8_t sem; /* 绑定的 phasor 语义通道(-1 = 无 phasor 源,恒无效) */
|
||||
float deadband; /* 死区(二次值工程量绝对值,「数据可信」卡 6 重定) */
|
||||
int8_t sem; /* 快照 yc 槽 = 语义通道(-1 = 非测量量点,当前仅频率) */
|
||||
float db_default; /* 死区 ROM 默认(运行时生效值 = s_yc_db,卡 10 覆盖) */
|
||||
uint8_t src; /* PTS_SRC_* 源类型 */
|
||||
} 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)数值仅为将来启用预留同型。
|
||||
* 卡 10 运行参数段可调)。自卡 9 起本表**只作 ROM 默认载体**:运行时死区 =
|
||||
* s_yc_db 副本;削顶五路不再 sem=-1 绑死,而是绑快照槽、由品质 CLIPPED
|
||||
* 驱动线上 IV——V0.2(N-18)削顶消失后点位零改动自动启用(docs/任务规划/
|
||||
* 数据可信.md §10 的 N-18 行)。
|
||||
* ⚠ 过渡期(eng=0 引脚电压域,卡 12 标定前):上送值本身非二次值,死区
|
||||
* 按本域判定无意义但也不会漏报——104 侧 IV/数据可信度语义由 M5 快照层
|
||||
* (卡 8/9)统一处理,本卡只把"量纲错位"这一处常量债还掉。 */
|
||||
* 数字按本域偏保守(迟报不漏报);标定落地后复核(「数据可信」§2.3 表
|
||||
* 第 2 行)。判定 = 死区连续 2 点确认(卡 9),见 iec104_pts.h COV 说明。 */
|
||||
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 */
|
||||
{ 0x4011u, (int8_t)ADC_SEM_UA, 0.5f, PTS_SRC_MEAS }, /* 1Ua:0.5 % × 100 V */
|
||||
{ 0x4012u, (int8_t)ADC_SEM_UB, 0.5f, PTS_SRC_MEAS }, /* 1Ub:削顶 → 品质驱动 IV */
|
||||
{ 0x4013u, (int8_t)ADC_SEM_UC, 0.5f, PTS_SRC_MEAS }, /* 1Uc:同上 */
|
||||
{ 0x4014u, (int8_t)ADC_SEM_UN, 0.5f, PTS_SRC_MEAS }, /* 1U0(外部零序专用通道) */
|
||||
{ 0x4015u, (int8_t)ADC_SEM_IA, 0.005f, PTS_SRC_MEAS }, /* 1Ia:0.5 % × 1 A */
|
||||
{ 0x4016u, (int8_t)ADC_SEM_IB, 0.005f, PTS_SRC_MEAS }, /* 1Ib:削顶 → 品质驱动 IV */
|
||||
{ 0x4017u, (int8_t)ADC_SEM_IC, 0.005f, PTS_SRC_MEAS }, /* 1Ic:同上 */
|
||||
{ 0x4018u, (int8_t)ADC_SEM_IN, 0.005f, PTS_SRC_MEAS }, /* 1I0:同上 */
|
||||
{ 0x401Du, -1, 0.5f, PTS_SRC_FREQ }, /* 1f:卡 11 绑频率源,
|
||||
* freq_valid=0 → 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];
|
||||
/* ===== 遥测 COV 运行时状态(卡 9;仅 iec104Task 上下文访问,无并发) =====
|
||||
* 判据链:新测量点 → |v − 上次上送值| > 死区?→ 连续 2 点确认 → 置变化位。
|
||||
* 基准 = **上次上送值**(非上次读值——否则慢漂移永不出死区,参考系统同款);
|
||||
* 品质(线上 qds)翻转 = 事件:不参与 2 点计数、当拍直报。 */
|
||||
static float s_yc_db[YC_N]; /* 死区运行时副本(ROM 默认 = k_yc 列) */
|
||||
static float s_yc_rep[YC_N]; /* 上次上送值(建线/确认上送时更新) */
|
||||
static uint8_t s_yc_repq[YC_N]; /* 上次上送的线上 qds */
|
||||
static uint8_t s_yc_cnf[YC_N]; /* 越死区连续计数(1 = 待确认;2 = 确认) */
|
||||
static uint32_t s_yc_seq; /* COV 已消费到的快照 seq(板端源测点去重) */
|
||||
static uint8_t s_yc_seqmode; /* 1 = 板端默认源(测点 = meas 换帧) */
|
||||
|
||||
/* ---------------- YX 表(IOA = 1..33;双点 = 开关位置类) ------------------ */
|
||||
#define YX_N 33u
|
||||
@@ -61,63 +86,65 @@ static int8_t s_yc_phasor_idx[YC_N];
|
||||
| (1uLL << 17u) | (1uLL << 22u) | (1uLL << 30u)))
|
||||
|
||||
/* ---------------- 数据源(默认 = 板端;bind_src 可整体替换) -------------- */
|
||||
static int s_src_yc_read(uint8_t idx, float *out);
|
||||
static int s_src_yc_read_ex(uint8_t idx, float *out, uint16_t *qds);
|
||||
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);
|
||||
|
||||
/* 板端默认源:遥测走**带品质**的 ex 通道(legacy yc_read 槽置 NULL——
|
||||
* s_yc_point 优先 ex;注入源两种槽位均可,见 iec104_pts.h) */
|
||||
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
|
||||
NULL, s_src_yx_bits, s_src_yx_valid,
|
||||
s_src_yk_exec, s_src_set_read, s_src_set_write, s_src_yc_read_ex
|
||||
};
|
||||
static const iec104_pts_src_t *s_src;
|
||||
|
||||
/* ---------------- COV 快照 ---------------- */
|
||||
static float s_yc_last[YC_N];
|
||||
static uint16_t s_yc_have; /* bit i = 已有上次快照 */
|
||||
/* ---------------- COV 快照(遥信侧;遥测侧状态见上方 s_yc_* 块) --------- */
|
||||
static uint16_t s_yc_have; /* bit i = 已建立上送基线 */
|
||||
static uint64_t s_yx_last;
|
||||
static uint8_t s_yx_snap_ok;
|
||||
|
||||
/* ============================ 公开接口 ================================== */
|
||||
|
||||
/*
|
||||
* 函数功能:初始化点表模块(扫 phasor 基波实例映射、恢复默认源、清快照)
|
||||
* 函数功能:初始化点表模块(死区装 ROM 默认、清 COV/快照状态、恢复默认源)
|
||||
* 限定条件:内核启动前或 104 服务启动前,调一次
|
||||
* 函数说明:卡 9 起不再扫 phasor 实例(数据源 = 快照,槽位 = 语义通道,编译期
|
||||
* 直接可定);重复调用 = 全状态复位(单测 reset 依赖此语义)。
|
||||
*/
|
||||
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;
|
||||
s_yc_db[i] = k_yc[i].db_default;
|
||||
}
|
||||
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;
|
||||
(void)memset(s_yc_rep, 0, sizeof(s_yc_rep));
|
||||
(void)memset(s_yc_repq, 0, sizeof(s_yc_repq));
|
||||
(void)memset(s_yc_cnf, 0, sizeof(s_yc_cnf));
|
||||
s_yc_have = 0u;
|
||||
s_yc_seq = 0u;
|
||||
s_yc_seqmode = 1u;
|
||||
s_src = &k_default_src;
|
||||
s_yx_snap_ok = 0u;
|
||||
s_yx_last = 0u;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:替换数据源(NULL = 恢复板端默认源;单测注入假源)
|
||||
* 函数说明:注入源同时把 COV 测点口径切为**每次调用一测点**(假源无快照节拍,
|
||||
* 步进由调用方控制);默认源 = 测点按 meas 换帧(seq 去重)。换源
|
||||
* 不重建基线(基线状态统一由 init 复位,防跨源半截确认序列)。
|
||||
*/
|
||||
void iec104_pts_bind_src(const iec104_pts_src_t *src) {
|
||||
s_src = (src != NULL) ? src : &k_default_src;
|
||||
if (src != NULL) {
|
||||
s_src = src;
|
||||
s_yc_seqmode = 0u;
|
||||
} else {
|
||||
s_src = &k_default_src;
|
||||
s_yc_seqmode = 1u;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -135,35 +162,105 @@ uint32_t iec104_pts_yc_ioa(uint8_t idx) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:读遥测(值 + 品质 descriptor;源 -2 → NT,其余失败 → IV)
|
||||
* 返 回 值:0 有效 / -1 无效
|
||||
* 函数功能:品质域位映射(uint16 meas 域 → uint8 线上 QDS,卡 9)
|
||||
* 入口参数:q16 - 源侧品质(低字节与线上同值;高字节为 MEAS_QDS_CLIPPED 域内位)
|
||||
* 返 回 值:线上 QDS 字节 uint8_t
|
||||
* 函数说明:CLIPPED(硬件削顶,104 无对应位)映射为 IV——「削顶通道 104 恒
|
||||
* IV」口径(docs/任务规划/数据可信.md §8 风险表末行)改由快照品质
|
||||
* 驱动,不再靠点表绑死 -1;OV/NT/IV 透传,其余高位丢弃。
|
||||
*/
|
||||
static uint8_t s_q_map(uint16_t q16) {
|
||||
uint8_t w = (uint8_t)(q16 & (uint16_t)(IEC104_QDS_OV | IEC104_QDS_NT
|
||||
| IEC104_QDS_IV));
|
||||
|
||||
if ((q16 & (uint16_t)MEAS_QDS_CLIPPED) != 0u) {
|
||||
w |= (uint8_t)IEC104_QDS_IV;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:读单点遥测(统一源通道 + 品质归一,yc_read 与 COV 共用唯一读径)
|
||||
* 入口参数:idx - YC 表下标 v/q - 输出(值 / 线上 qds;调用方保证非空)
|
||||
* 返 回 值:0 有效;-1 IV(含 CLIPPED 映射);-2 NT(未就绪) int
|
||||
* 函数说明:ex 源在场 → 品质由源给(板端 = 快照槽位透传);否则退 legacy
|
||||
* yc_read,品质从返回值推导(-1→IV / -2→NT / 0→无位)——旧注入源
|
||||
* 行为与卡 9 前**完全一致**(单测假源零改动)。判定顺序 IV > NT:
|
||||
* 开机首帧 qds=IV|NT 按无效处理(NT 只留给纯暂态)。任何无效 →
|
||||
* 信息体清零(线上口径:主站只信品质)。
|
||||
*/
|
||||
static int s_yc_point(uint8_t idx, float *v, uint8_t *q) {
|
||||
int rc;
|
||||
uint16_t q16 = 0u;
|
||||
|
||||
if ((idx >= YC_N) || (s_src == NULL)
|
||||
|| ((s_src->yc_read == NULL) && (s_src->yc_read_ex == NULL))) {
|
||||
*v = 0.0f;
|
||||
*q = (uint8_t)IEC104_QDS_IV;
|
||||
return -1;
|
||||
}
|
||||
if (s_src->yc_read_ex != NULL) {
|
||||
rc = s_src->yc_read_ex(idx, v, &q16);
|
||||
} else {
|
||||
rc = s_src->yc_read(idx, v);
|
||||
q16 = (rc == -2) ? (uint16_t)MEAS_QDS_NT
|
||||
: ((rc != 0) ? (uint16_t)MEAS_QDS_IV : 0u);
|
||||
}
|
||||
(void)rc; /* 有效性由归一后的 q 终裁(IV/NT 即无效),源返回值不直通 */
|
||||
*q = s_q_map(q16);
|
||||
rc = ((*q & (uint8_t)IEC104_QDS_IV) != 0u) ? -1
|
||||
: (((*q & (uint8_t)IEC104_QDS_NT) != 0u) ? -2 : 0);
|
||||
if (rc != 0) {
|
||||
*v = 0.0f;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:读遥测(值 + 线上品质位;无效值清零,判据见 s_yc_point)
|
||||
* 返 回 值:0 有效 / -1 无效(NT 亦无效,品质位与 IV 区分) int
|
||||
*/
|
||||
int iec104_pts_yc_read(uint8_t idx, float *v, uint8_t *qds) {
|
||||
int rc;
|
||||
float val = 0.0f;
|
||||
uint8_t q = (uint8_t)IEC104_QDS_IV;
|
||||
|
||||
(void)s_yc_point(idx, &val, &q);
|
||||
if (v != NULL) {
|
||||
*v = 0.0f;
|
||||
*v = val;
|
||||
}
|
||||
if ((idx >= YC_N) || (s_src == NULL) || (s_src->yc_read == NULL)) {
|
||||
if (qds != NULL) {
|
||||
*qds = IEC104_QDS_IV;
|
||||
*qds = q;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
rc = s_src->yc_read(idx, v);
|
||||
if (rc == 0) {
|
||||
if (qds != NULL) {
|
||||
*qds = 0u;
|
||||
return (q == 0u) ? 0 : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:写死区运行时值(「数据可信」卡 9;卡 10 运行参数段的落点入口)
|
||||
* 入口参数:idx - YC 表下标 db - 工程量绝对死区(≥0) float
|
||||
* 返 回 值:0 成功;-1 越界/负值/NaN(RAM 不动) int
|
||||
* 限定条件:**iec104Task 上下文**(配置属主 = defaultTask,卡 10 接线时经
|
||||
* 104 任务落地本调用,勿跨任务直调——本表状态无锁)
|
||||
* 函数说明:成功时清零该点待确认计数——跨死区档位不保留半截确认序列;
|
||||
* 不隐式重建基线(上送基准延续,新死区即刻生效)。
|
||||
*/
|
||||
int iec104_pts_yc_set_deadband(uint8_t idx, float db) {
|
||||
if ((idx >= YC_N) || !(db >= 0.0f) || !(db < 1000000.0f)) {
|
||||
return -1; /* NaN 被 !(db>=0) 捕获(比较式写法,防 lint 报恒真) */
|
||||
}
|
||||
s_yc_db[idx] = db;
|
||||
s_yc_cnf[idx] = 0u;
|
||||
return 0;
|
||||
}
|
||||
if (v != NULL) {
|
||||
*v = 0.0f;
|
||||
}
|
||||
if (qds != NULL) {
|
||||
*qds = (rc == -2) ? IEC104_QDS_NT : IEC104_QDS_IV;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:读当前生效死区
|
||||
* 入口参数:idx - YC 表下标
|
||||
* 返 回 值:运行时死区;idx 越界返 0.0 float
|
||||
* 限定条件:任意上下文(单字 float 读,Cortex-M 原子)
|
||||
* 函数说明:UI 回显 / 卡 10 读写往返校验用;ROM 默认查点表,勿在此反推。
|
||||
*/
|
||||
float iec104_pts_yc_deadband(uint8_t idx) {
|
||||
return (idx < YC_N) ? s_yc_db[idx] : 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -238,28 +335,72 @@ void iec104_pts_cov_check(iec104_pts_cov_t *cov) {
|
||||
s_yx_snap_ok = 1u;
|
||||
}
|
||||
|
||||
/* YC:死区比对(仅对"本次有效 且 上次有快照"的点判定) */
|
||||
if ((s_src != NULL) && (s_src->yc_read != NULL)) {
|
||||
/* YC(卡 9):测点推进 = 板端源按快照换帧(100 ms poll vs 200 ms 快照,
|
||||
* 不去重则同一帧计两次 → "连续 2 点确认"退化成"连续 2 次轮询",单帧
|
||||
* 噪声即可被确认,抗噪语义失效);注入源 = 每次调用一测点。
|
||||
* 判定 = 死区连续 2 点确认 + 品质翻转直报(口径全文 → iec104_pts.h)。 */
|
||||
if ((s_src != NULL)
|
||||
&& ((s_src->yc_read != NULL) || (s_src->yc_read_ex != NULL))) {
|
||||
uint8_t step = 1u;
|
||||
|
||||
if (s_yc_seqmode != 0u) {
|
||||
uint32_t sq = meas_seq();
|
||||
|
||||
if (sq == s_yc_seq) {
|
||||
step = 0u; /* 未换帧:本 poll 不算新测量点 */
|
||||
} else {
|
||||
s_yc_seq = sq;
|
||||
}
|
||||
}
|
||||
if (step != 0u) {
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0u; i < YC_N; i++) {
|
||||
float v;
|
||||
uint8_t q;
|
||||
int rc = s_yc_point(i, &v, &q);
|
||||
|
||||
if (s_src->yc_read(i, &v) != 0) {
|
||||
if (((s_yc_have >> i) & 1u) == 0u) {
|
||||
if (rc == 0) { /* 首个有效读数只建线不上报(初值归总召) */
|
||||
s_yc_have |= (uint16_t)(1u << i);
|
||||
s_yc_rep[i] = v;
|
||||
s_yc_repq[i] = q;
|
||||
s_yc_cnf[i] = 0u;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (((s_yc_have >> i) & 1u) != 0u) {
|
||||
float d = v - s_yc_last[i];
|
||||
if (q != s_yc_repq[i]) {
|
||||
/* 品质翻转 = 事件直报(含 0x401d 的 IV 进出,卡 11) */
|
||||
local.yc_changed |= (uint16_t)(1u << i);
|
||||
s_yc_repq[i] = q;
|
||||
s_yc_cnf[i] = 0u;
|
||||
if (rc == 0) {
|
||||
s_yc_rep[i] = v;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (rc != 0) {
|
||||
s_yc_cnf[i] = 0u; /* 无效期间不计数(品质未变 = 状态延续) */
|
||||
continue;
|
||||
}
|
||||
{
|
||||
float d = v - s_yc_rep[i];
|
||||
|
||||
if (d < 0.0f) {
|
||||
d = -d;
|
||||
}
|
||||
if (d > k_yc[i].deadband) {
|
||||
if (d > s_yc_db[i]) {
|
||||
s_yc_cnf[i]++;
|
||||
if (s_yc_cnf[i] >= 2u) { /* 连续 2 越 → 确认:报 + 移基准 */
|
||||
local.yc_changed |= (uint16_t)(1u << i);
|
||||
s_yc_rep[i] = v;
|
||||
s_yc_cnf[i] = 0u;
|
||||
}
|
||||
} else {
|
||||
s_yc_cnf[i] = 0u; /* 回摆入死区 → 撤销候选(抗噪核心) */
|
||||
}
|
||||
}
|
||||
}
|
||||
s_yc_last[i] = v;
|
||||
s_yc_have |= (uint16_t)(1u << i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,24 +445,44 @@ int iec104_pts_set_write(uint32_t addr, float v, uint8_t select) {
|
||||
/* ============================ 板端默认源 ================================= */
|
||||
|
||||
/*
|
||||
* 函数功能:板端默认源 - 遥测 = 基波相量有效值(fAmSQ)
|
||||
* 返 回 值:0 / -1 无 phasor 源(削顶通道/频率未实现)/ -2 未满一周波(NT)
|
||||
* 函数功能:板端默认源 - 遥测 = L2 遥测快照直读(「数据可信」卡 9/卡 11)
|
||||
* 入口参数:idx - YC 表下标 out/qds - 值 + uint16 域品质(MEAS_QDS_*)
|
||||
* 返 回 值:0 / -1 越界或频率未新鲜(IV)/ -2 快照从未发布(NT) int
|
||||
* 限定条件:iec104Task 上下文(meas_get 为双区无锁读,App/algo/meas.h)
|
||||
* 函数说明:**不做任何本地判断**——电气路值/品质整体透传快照槽(削顶路快照
|
||||
* 已置 CLIPPED,s_q_map 映上线 IV;开机首帧 IV|NT 由 s_yc_point 按
|
||||
* IV 处理),"新不新、能不能信"全在发布侧一处决定(卡 8 设计意图,
|
||||
* 两处判断必打架)。频率路(PTS_SRC_FREQ):snap.freq_valid==0 →
|
||||
* IV(卡 11 DoD 原句);有效时值 = snap.freq_hz,与 freq_get() 同源。
|
||||
*/
|
||||
static int s_src_yc_read(uint8_t idx, float *out) {
|
||||
phasor_t p;
|
||||
int8_t pi;
|
||||
static int s_src_yc_read_ex(uint8_t idx, float *out, uint16_t *qds) {
|
||||
meas_snap_t snap;
|
||||
|
||||
if ((idx >= YC_N) || (out == NULL)) {
|
||||
if ((idx >= YC_N) || (out == NULL) || (qds == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
pi = s_yc_phasor_idx[idx];
|
||||
if (pi < 0) {
|
||||
return -1; /* 无 phasor 源(削顶通道/频率未实现) */
|
||||
if (meas_get(&snap) != 0) {
|
||||
*out = 0.0f; /* 从未发布(开机 <200 ms)= 暂态 */
|
||||
*qds = (uint16_t)(MEAS_QDS_IV | MEAS_QDS_NT);
|
||||
return -2;
|
||||
}
|
||||
if (phasor_get((uint8_t)pi, &p) != 0) {
|
||||
return -2; /* 未满一周波:未就绪(NT) */
|
||||
if (k_yc[idx].src == (uint8_t)PTS_SRC_FREQ) {
|
||||
if (snap.freq_valid == 0u) {
|
||||
*out = 0.0f;
|
||||
*qds = (uint16_t)MEAS_QDS_IV;
|
||||
return -1;
|
||||
}
|
||||
*out = p.fAmSQ; /* 有效值口径(系数已折算) */
|
||||
*out = snap.freq_hz;
|
||||
*qds = 0u;
|
||||
return 0;
|
||||
}
|
||||
if (k_yc[idx].sem < 0) {
|
||||
*out = 0.0f; /* 理论不可达:现无未绑测量量点 */
|
||||
*qds = (uint16_t)MEAS_QDS_IV;
|
||||
return -1;
|
||||
}
|
||||
*out = snap.yc[(uint8_t)k_yc[idx].sem];
|
||||
*qds = snap.qds[(uint8_t)k_yc[idx].sem];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
* phasor/prot_elm/prot_set 真实源;主机单测绑假源 → 协议栈全链
|
||||
* (asdu+pts+link)可离线跑(登记簿 A-4 约束 1)。
|
||||
* 点表口径(docs/算法/继电保护功能复现规划.md §1.5,验收 = 省电科院点表):
|
||||
* - YC:IOA 0x4011~0x4018 + 0x401d(频率),短浮点、系数 1;
|
||||
* ⚠ V0.1 有效通道仅 UA/UN/IA(TPAFE 三路,§1.6)——其余点**存在但置 IV**
|
||||
* (无效位),频率随 L1-7 落地前同样置 IV;
|
||||
* - YC:IOA 0x4011~0x4018 + 0x401d(频率),短浮点、系数 1;数据源 =
|
||||
* L2 遥测快照(App/algo/meas.h,「数据可信」卡 9/11):电气 8 路绑快照槽,
|
||||
* 有效性由快照品质驱动——V0.1 削顶路(docs/算法/继电保护功能复现规划.md
|
||||
* §1.6)快照置 CLIPPED → 本层映射为线上 IV(V0.2/N-18 后自动启用,绑定零
|
||||
* 改动,见 docs/任务规划/数据可信.md §10 行 N-18);0x401d 绑频率源,
|
||||
* freq_valid()==0 → IV;
|
||||
* - YX:IOA 1~33(§1.5 表(3));双点 = 开关位置类(YX1~4,本期无硬件 → IV),
|
||||
* 保护动作类 YX15~23 映射 prot_elm 状态,闭锁类 YX31~33 映射 prot_set;
|
||||
* - YK:IOA 0x6000+(§1.5 表(3));V0.1 无出口硬件(规划 R7)——
|
||||
@@ -21,6 +24,11 @@
|
||||
* 按未知 IOA(COT 14 + EVI)应答,登记为待办(设计文档)。
|
||||
* 线程约定:init/bind 内核启动前或建服务前;cov_check/read 仅 104 服务任务上下文。
|
||||
* 创建日期:2026-10-12(B4)
|
||||
* 修改记录:
|
||||
* 2026-10-25 DTU 项目组 卡 9/卡 11(「数据可信」,道D):YC 数据源 = L2 遥测
|
||||
* 快照(削顶路由品质驱动 IV);死区改运行时副本 +
|
||||
* set/get 入口;COV 遥测腿 = 死区 2 点确认(seq 去重)
|
||||
* + 品质变化即报;0x401d 绑频率源(freq_valid → IV)。
|
||||
*/
|
||||
#ifndef IEC104_PTS_H
|
||||
#define IEC104_PTS_H
|
||||
@@ -42,6 +50,11 @@ typedef struct {
|
||||
int (*set_read)(uint32_t addr, float *out);
|
||||
/* 定值写:select=1 预置校验(范围)/ 0 执行写入。返回 0 / -1 越界或未知 */
|
||||
int (*set_write)(uint32_t addr, float v, uint8_t select);
|
||||
/* 遥测读(带品质,卡 9 追加于表尾——旧源 NULL = 走 yc_read 退路,品质由
|
||||
* 返回值推导:-1 → IV、-2 → NT、0 → 无位,行为与旧源完全一致)。
|
||||
* qds = uint16 域位(App/algo/meas.h MEAS_QDS_*:低字节 = 线上 QDS 同值,
|
||||
* 高字节 CLIPPED 由本层映射线上 IV);返回 0 / -1 IV / -2 NT */
|
||||
int (*yc_read_ex)(uint8_t idx, float *out, uint16_t *qds);
|
||||
} iec104_pts_src_t;
|
||||
|
||||
/* ---------------- 变化检测结果(cov_check 输出) ---------------- */
|
||||
@@ -65,8 +78,15 @@ void iec104_pts_bind_src(const iec104_pts_src_t *src);
|
||||
/* ---------------- YC ---------------- */
|
||||
uint8_t iec104_pts_yc_count(void);
|
||||
uint32_t iec104_pts_yc_ioa(uint8_t idx);
|
||||
/* 读 YC:v 有效值(无效时为 0);qds 输出品质位(IV/NT 等)。返回 0/无效-1 */
|
||||
/* 读 YC:v 有效值(无效时为 0);qds 输出线上品质位(IV/NT/OV,CLIPPED 已映射
|
||||
* 为 IV)。返回 0/无效-1(NT 亦无效,品质位区分) */
|
||||
int iec104_pts_yc_read(uint8_t idx, float *v, uint8_t *qds);
|
||||
/* 死区运行时写(「数据可信」卡 9;卡 10 运行参数段的落点入口):
|
||||
* db = 工程量绝对值 ≥0;越界/负值/NaN → -1 且 RAM 不动;成功时清零该点
|
||||
* 待确认计数(跨死区基线不残留半截确认)。仅 104 服务任务上下文调用。 */
|
||||
int iec104_pts_yc_set_deadband(uint8_t idx, float db);
|
||||
/* 读当前生效死区(越界 idx 返 0) */
|
||||
float iec104_pts_yc_deadband(uint8_t idx);
|
||||
|
||||
/* ---------------- YX ---------------- */
|
||||
uint8_t iec104_pts_yx_count(void);
|
||||
@@ -77,10 +97,19 @@ void iec104_pts_yx_read(uint8_t idx, uint8_t *out);
|
||||
|
||||
/* ---------------- COV(每 poll 一次) ---------------- */
|
||||
/*
|
||||
* 函数功能:读全表快照并与上次比对(变位 + 死区),输出变化集
|
||||
* 函数功能:读全表并与上次比对(遥信变位 + 遥测死区 2 点确认 + 品质变化),
|
||||
* 输出变化集
|
||||
* 入口参数:cov - 输出(可为 NULL = 只刷快照不取变化)
|
||||
* 函数说明:首次调用只建快照、变化集全 0(突发由初始化/总召覆盖)。
|
||||
* 死区 = 点表内置绝对值(§1.5 运行参数 8020H 段本期取内置默认)。
|
||||
* 函数说明:遥测判据(「数据可信」卡 9,对标参考系统 CalfYcMea 死区 2 点确认,
|
||||
* 短板评测口径):**连续 2 个新测量点** |v - 上次上送值| > 死区才置变化位
|
||||
* (单点尖峰不确认——噪声回摆即撤销候选);品质位(线上 qds)相对上次
|
||||
* 上送值翻转 → 当拍直接置位(不等 2 点,有效性变化必须即时可见,
|
||||
* 含 0x401d 的 IV 进出)。死区 = 运行时副本(ROM 默认 = 点表列,
|
||||
* iec104_pts_yc_set_deadband() 覆盖——卡 10 运行参数段的接线点)。
|
||||
* 测量点定义:板端默认源 = **快照换帧**(meas seq 前进;100 ms poll 对
|
||||
* 200 ms 快照,同一帧重复比对会计数两次 → seq 去重是确认语义成立的
|
||||
* 前提);注入源(单测假源)= 每次调用一测点。首次读到有效值只建基线
|
||||
* 不上报(突发由总召覆盖)。
|
||||
*/
|
||||
void iec104_pts_cov_check(iec104_pts_cov_t *cov);
|
||||
|
||||
|
||||
+25
-13
@@ -36,17 +36,26 @@
|
||||
|
||||
| IOA | 点 | 来源 | V0.1 状态 |
|
||||
|---|---|---|---|
|
||||
| 0x4011 | 1Ua | phasor `C02-UA-F1` fAmSQ | ✅ 有效 |
|
||||
| 0x4012/0x4013 | 1Ub/1Uc | — | ❌ 发 IV(STM32 侧削顶,`docs/算法/继电保护功能复现规划.md` §1.6) |
|
||||
| 0x4014 | 1U0 | phasor `C03-UN-F1` | ✅ 有效(外部零序专用通道) |
|
||||
| 0x4015 | 1Ia | phasor `C01-IA-F1` | ✅ 有效 |
|
||||
| 0x4016~0x4018 | 1Ib/1Ic/1I0 | — | ❌ 发 IV(同上) |
|
||||
| 0x401D | 1f 频率 | 软件测频 | ❌ 发 IV(L1-7 未实现) |
|
||||
| 0x4011 | 1Ua | L2 遥测快照槽 `ADC_SEM_UA`(卡 9) | ✅ 有效 |
|
||||
| 0x4012/0x4013 | 1Ub/1Uc | 同表槽位;STM32 侧削顶(`docs/算法/继电保护功能复现规划.md` §1.6) | ❌ 发 IV——**品质驱动**(快照 CLIPPED 位映射,非点表绑死;V0.2/N-18 消失后零改动自动启用) |
|
||||
| 0x4014 | 1U0 | 快照槽 `ADC_SEM_UN`(外部零序专用通道) | ✅ 有效 |
|
||||
| 0x4015 | 1Ia | 快照槽 `ADC_SEM_IA` | ✅ 有效 |
|
||||
| 0x4016~0x4018 | 1Ib/1Ic/1I0 | 同 Ub/Uc:绑槽 + 品质驱动 | ❌ 发 IV |
|
||||
| 0x401D | 1f 频率 | 快照 `freq_hz`(卡 11 绑源;B8 自适应窗测频 `freq_get()` 同源) | ✅ 随测频收敛生效;`freq_valid()==0` → IV(卡 11 DoD) |
|
||||
|
||||
- 现读数为**工程量(引脚电压/电流一次折算后的二次口径)**——`App/algo/adc_cal` 标定折算层
|
||||
已于 2026-10-25 落地(卡 6 同步把死区按额定 0.5% 逐点重定:电压 0.5 V / 电流 0.005 A,
|
||||
频率维持 0.5 Hz 绝对值);标定系数默认=ROM 引脚 LSB,标准源注入复核(卡 12)仍待台架。
|
||||
- 相量未就绪(未满一周波)→ QDS 置 NT(0x20),与 IV(无效通道)语义区分。
|
||||
- **数据源 = L2 遥测快照**(`App/algo/meas.h`,「数据可信」卡 8/9):200 ms 基波有效值
|
||||
+ 每点品质,104 与 UI 共用同一份上游;读数单位 = ADC 引脚电压(eng=0,`App/algo/adc_cal`
|
||||
折算层 2026-10-25 落地;二次值等卡 12 标定置 VALID)。槽位值/品质整体透传,本层
|
||||
**不再自行判新旧**(快照 `seq` 仅供 COV 去重)。
|
||||
- 品质映射:快照 `MEAS_QDS_*` 低字节与线上 QDS 同值直传;**CLIPPED → IV**(「削顶通道
|
||||
恒 IV」口径不变、改由品质驱动,docs/任务规划/数据可信.md §8 风险表末行的单测要求);
|
||||
快照从未发布(开机 <200 ms)→ IV|NT;判定顺序 IV 优先于 NT。
|
||||
- 死区(卡 9):从「越死区即报」改为**连续 2 个新测量点越限才确认**——板端测量点 =
|
||||
快照换帧(100 ms 轮询 vs 200 ms 快照按 `seq` 去重,防同一帧把单点噪声重复计满 2 点;
|
||||
基准恒为**上次上送值**,非上次读值——防慢漂移把基准吃掉,参考系统同款);品质翻转
|
||||
当拍直报、不计数。死区数值 = 运行时副本(`iec104_pts_yc_set_deadband`,ROM 默认沿
|
||||
卡 6 额定 0.5% 档:0.5 V / 0.005 A / 0.5 Hz;卡 10 接 8020H 段后主站可读写);
|
||||
标准源注入复核(卡 12)待台架。
|
||||
|
||||
### 3.2 遥信 YX(IOA 1~33)
|
||||
|
||||
@@ -112,7 +121,8 @@
|
||||
- 总召(C_IC 组 1):actcon → 分片背景扫描(YX 双点组 SQ=1 → YX 单点组 SQ=1 →
|
||||
YC 组 SQ=1 → 频率单点)→ actterm;首召/ RBT 位 → COT=4(初始化),否则 COT=2。
|
||||
单次 poll 发送预算 4 个 ASDU(防大扫描饿死宿主任务)。
|
||||
- 突发:COV = 遥信变位 + 遥测死区(`iec104_pts_cov_check`),COT=3 逐点 SQ=0。
|
||||
- 突发:COV = 遥信变位 + 遥测**死区 2 点确认 + 品质翻转直报**(`iec104_pts_cov_check`,
|
||||
卡 9 语义见 §3.1 注),COT=3 逐点 SQ=0。
|
||||
- 周期:RUN 态 60 s 全 YC 上送 COT=1。
|
||||
- 遥控/定值写:两段式,失配/越界 → COT|PN 否定确认;未知 IOA → COT=14+EVI、
|
||||
错公共地址 → COT=13+EVI、未知类型 → COT=12+EVI。
|
||||
@@ -162,7 +172,7 @@
|
||||
|
||||
| 层 | 内容 |
|
||||
|---|---|
|
||||
| L0.5 | `test/host/iec104/`:APCI 重组/坏帧、STARTDT 握手、总召全流程(含 RBT/分片/预算)、COV、k/w 窗、t1/t2/t3(假时基)、遥控两段式与 PN、YK12 软压板两段转真 + 置脏(B7)、定值两段写 + set_sealed 后 selfcheck、C_RD(含本地项不可寻址)、C_CS(含闰年)、错地址/错类型 EVI;`test/host/prot_set/`:blob 往返 + 损坏整表拒绝(all-or-nothing)|
|
||||
| L0.5 | `test/host/iec104/`:APCI 重组/坏帧、STARTDT 握手、总召全流程(含 RBT/分片/预算)、COV、k/w 窗、t1/t2/t3(假时基)、遥控两段式与 PN、YK12 软压板两段转真 + 置脏(B7)、定值两段写 + set_sealed 后 selfcheck、C_RD(含本地项不可寻址)、C_CS(含闰年)、错地址/错类型 EVI;**板端默认源真实链**(ring→phasor→freq→meas 快照,非桩):值/品质透传、CLIPPED→IV、0x401D 绑频(收敛 ±0.02 Hz / 未新鲜 IV)、死区运行时化 + 2 点确认/回摆撤销、seq 去重(卡 9/11,TC-IEC104-025~028);`test/host/prot_set/`:blob 往返 + 损坏整表拒绝(all-or-nothing)|
|
||||
| L0 | `iec104-unit-test` 钩子 + cppcheck/coding-standard |
|
||||
| 台架 | `@test` 锚点(104 服务启动/监听行);**PC 主站客户端 `test/host/iec104_master.py`(纯标准库,B6 2026-10-12 就绪)**:STARTDT/总召四组+actterm/C_SE 定值两段写→YX15·16 变位(COT=3)/恢复复归/YK11 两段正答/C_RD 读回,台架往返 **18/18 PASS**(证据 `../测试说明/boot_log_data/20261012_B6_iec104_roundtrip_log.txt`);**B7 持久化模式 `--b7-pre/--b7-post/--b7-mark/--b7-check`**(中间 ST-LINK 复位):YK12 两段投退→保护退出/联动、**定值与压板态跨复位保持**(含非默认 7.5 往返),**21/21 + 13/13 + 4/4+4/4 PASS**(证据 `../测试说明/boot_log_data/20261012_B7_iec104_persist_log.txt`);**B9 SOE 腿**(同工具同轮回归):自发 YX 断言 **M_SP_TB_1 带 ts**(工具解析 type 30/1 双型)+ FTP 下载 `/log/soe.log` 经 `test/host/soe/decode_soe.py` 解码断言(校验和/seq 单调/CP56↔epoch UTC 交叉),pre 21/21 + post 13/13 不回归;lib60870 级第三方全流程归 B10 |
|
||||
|
||||
@@ -173,7 +183,8 @@
|
||||
双点带时标不做(V0.1 双点恒 IV,无意义)。
|
||||
3. YK1~4/13/14 否定确认——出口硬件确认后(R7)转真执行(YK12 已于 B7 转真)。
|
||||
4. ~~遥测死区 10.0 码值为拟定值~~——工程量死区已于 2026-10-25 卡 6 落地(额定 0.5%);
|
||||
死区参数挪入运行参数段(点表 8020H 段)主站可读写,仍归后续(「数据可信」卡 10)。
|
||||
卡 9(2026-10-25)已改**运行时副本 + set/get 入口 + 2 点确认**;主站可读写(8020H 段
|
||||
run_par 接线 `iec104_pts_yc_set_deadband`)仍归「数据可信」卡 10。
|
||||
5. 多主站/双链路冗余不做(单连接语义)。
|
||||
6. 主站侧验证工具 = `test/host/iec104_master.py`(B6 2026-10-12 就绪,台架往返 18/18,覆盖总召/变位/遥控/定值);**第三方送检环境仍未就绪**——lib60870 级第三方全流程归 B10。
|
||||
7. **后连优先未实现**(V0.1 = 首到优先):单连接 socket 连接态无法 accept,
|
||||
@@ -190,4 +201,5 @@
|
||||
| 2026-10-12 | **B7 定值持久化 + 软压板**:YK12 转真(§3.3,两段式 → `PS_GLOBAL_EN`);定值执行段改 `prot_set_set_sealed` 原子写+封存(§3.4,收口 B5 竞态窗口);本地项 `comm_addr=0` 不可寻址;持久化 = 脏标志 → `SYS_EVT_PROT_SET_SAVE` → defaultTask 原子写 `/prot_set.bin`,开机屏障前整表原子装载(损坏拒绝保默认 + 自检留痕);单测 +7(iec104 94 断言)+ prot_set blob 往返/损坏 33 断言 |
|
||||
| 2026-10-12 | **B7 台架腿闭环**(§7 台架行回填):主站工具加 `--b7-pre/--b7-post/--b7-mark/--b7-check` 四模式(中间 ST-LINK 复位);pre 21/21(YK12 OFF→低定值不动作 / ON→YX15·16 即动作)、post 13/13(**压板退出态跨复位保持** + 重启后联动在位)、mark/check 4/4+4/4(**非默认定值 7.5 跨复位保持**);开机日志 `[CFG] prot set loaded (/prot_set.bin)`;证据 `../测试说明/boot_log_data/20261012_B7_*` |
|
||||
| 2026-10-25 | **标定折算落地联动(卡 6)**:遥测读数由原始码值改工程量(§3.1 注已重写);死区按额定 0.5% 逐点重定(0.5 V / 0.005 A / 0.5 Hz),§8 第 4 条改「已落地,8020H 段仍归卡 10」 |
|
||||
| 2026-10-25 | **卡 9/卡 11(道D,「数据可信」M5/M6)**:YC 板端源改读 L2 遥测快照(削顶五路从点表绑死 -1 改为**槽位绑定 + 快照品质 CLIPPED→IV**,V0.2/N-18 零改动启用);`0x401D` 绑频率源(`freq_valid()==0` → IV);死区改运行时副本 + `iec104_pts_yc_set_deadband()`(卡 10 接线点);COV 遥测腿 = 死区连续 2 点确认(快照 `seq` 去重)+ 品质翻转直报;`iec104_pts_src_t` 表尾追加 `yc_read_ex`(旧源退路语义不变);单测 97→127(TC-IEC104-025~028 走真实 L2 链);台架腿(总召读回一致 / 频率 ±0.01 Hz)待排窗——主站工具已记 val+qds,无需改工具 |
|
||||
| 2026-10-12 | **B9 时标 SOE**:自发单点 YX 换 **M_SP_TB_1(30)**(SIQ+CP56,§3.2 注;总召/周期保持 NA 型);link cfg 增 `epoch_ms` 时标源(NULL/无效 → IV 如实);serv 绑 `sys_clock`(秒域 → ms 域=秒×1000);主站工具解析 type 30/1 双型;单测 iec104 94→97(TB 时标 + IV 路径,两种类型都断言);台架腿见 §7 B9 行;落盘侧见 `App/log/README.md` soe 节 |
|
||||
|
||||
@@ -1810,7 +1810,7 @@
|
||||
],
|
||||
"scope": "global",
|
||||
"frozen": false,
|
||||
"cursor": "TC-IEC104-023",
|
||||
"cursor": "TC-IEC104-028",
|
||||
"cursor_owner_only": true,
|
||||
"check_dangling": true,
|
||||
"allow_orphans": true,
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
* TC-IEC104-005 OPEN 态 I 帧忽略(序号不消费)
|
||||
* TC-IEC104-006 总召全流程:actcon→4 分片(首召 COT=4)→actterm;二召 COT=2;RBT→COT=4
|
||||
* TC-IEC104-007 遥信变位 COV(COT=3);无效位不触发
|
||||
* TC-IEC104-008 遥测死区 COV:死区内不发 / 越死区发
|
||||
* TC-IEC104-008 遥测死区 COV(卡 9 起 = 2 点确认):死区内不发 / 首越只挂起 /
|
||||
* 连续第 2 越点上送
|
||||
* TC-IEC104-009 k 窗:12 未确认停发;S 确认后恢复
|
||||
* TC-IEC104-010 w 阈:收满 8 发 S
|
||||
* TC-IEC104-011 t2 到期发 S
|
||||
@@ -33,6 +34,17 @@
|
||||
* TC-IEC104-021 C_TS / C_RP actcon
|
||||
* TC-IEC104-022 周期上送 COT=1(YC 组 + 频率)
|
||||
* TC-IEC104-023 k 窗满 COV 不丢事件(pend 暂存,窗开后补发)
|
||||
* —— 以下为「数据可信」卡 9/卡 11(道D,2026-10-25;板端默认源 = 真实
|
||||
L2 链 ring→phasor→freq→meas,非桩)——
|
||||
* TC-IEC104-025 板端源读快照(024 号被存量 B7 用例的裸标签占用):未发布
|
||||
* IV|NT / 值=基波有效值 / 削顶 CLIPPED
|
||||
* →线上 IV 清零 / 干净路品质 0 / 频率未新鲜 IV
|
||||
* TC-IEC104-026 0x401D 绑频:收敛后 ±0.02 Hz / freq_valid==0 → IV 清零
|
||||
* (卡 11 DoD 原句)
|
||||
* TC-IEC104-027 死区运行时化:set/get + 非法拒 + 运行档压住旧档步长 +
|
||||
* 2 点确认/回摆撤销/init 复位 ROM 默认
|
||||
* TC-IEC104-028 品质翻转直报(假源)+ 板端 seq 去重(同帧不计两点)+
|
||||
* 换帧只变品质时按集合直报
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 创建日期:2026-10-12(B4)
|
||||
@@ -54,6 +66,7 @@ static int s_total = 0, s_passed = 0, s_failed = 0;
|
||||
#include "sample_ring.c"
|
||||
#include "phasor.c"
|
||||
#include "freq.c"
|
||||
#include "meas.c" /* 卡 9:板端默认 YC 源 = L2 遥测快照(真实链,非桩) */
|
||||
#include "prot_elm.c"
|
||||
#include "iec104_pts.c"
|
||||
#include "iec104_link.c"
|
||||
@@ -515,11 +528,14 @@ static void tc_cov_yc(void)
|
||||
* 旧拟定码值死区 10 已由「数据可信」卡 6 重定) */
|
||||
iec104_link_poll(&g_lk, now + 100u);
|
||||
CHECK(cap_i_count() == 0, "TC-008 inside the deadband nothing is uploaded");
|
||||
s_f_yc[0] = 101.25f; /* 101.25-100.4=0.85 > 0.5 */
|
||||
s_f_yc[0] = 101.25f; /* 101.25-100=1.25 > 0.5,第 1 越点 */
|
||||
iec104_link_poll(&g_lk, now + 200u);
|
||||
CHECK(cap_i_count() == 0, "TC-IEC104-008 first deadband crossing only arms (2-point confirm)");
|
||||
iec104_link_poll(&g_lk, now + 300u); /* 第 2 个连续测点仍越 -> 确认上送 */
|
||||
CHECK((cap_i_count() == 1) && (cap_i(0, &c) == 0) && (c.type == 13u)
|
||||
&& (c.cot == IEC104_COT_SPONT) && (c.ioa == 0x4011u)
|
||||
&& (iec104_get_float(c.obj) == 101.25f), "TC-008 crossing the deadband uploads");
|
||||
&& (iec104_get_float(c.obj) == 101.25f),
|
||||
"TC-IEC104-008 second consecutive crossing uploads (Card 9 confirm)");
|
||||
}
|
||||
|
||||
static void feed_rd(uint32_t now)
|
||||
@@ -912,6 +928,178 @@ static void tc_cov_kfull(void)
|
||||
&& (c.cot == IEC104_COT_SPONT), "TC-023 once the window opens the backlogged event is sent, none lost");
|
||||
}
|
||||
|
||||
/* ========== 卡 9/卡 11:板端默认源(真实 L2 链:ring→phasor→freq→meas) ========== */
|
||||
|
||||
/* 与 App/task/adc_task.c 同型的单拍编排:压环 → phasor_run →(可选 freq_run)。
|
||||
* 9 路同幅错相正弦(整周波 → 各路基波有效值 = A/√2,与相位无关,期望好算) */
|
||||
static double s_ph2 = 0.0;
|
||||
static void snap_beats(int n, double amp, int run_freq)
|
||||
{
|
||||
float f[ADC_SEM_COUNT];
|
||||
int i;
|
||||
int s;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (s = 0; s < (int)ADC_SEM_TEMP; s++) {
|
||||
f[s] = (float)(amp * sin(s_ph2 + (double)s * 0.35));
|
||||
}
|
||||
f[ADC_SEM_TEMP] = 1234.0f;
|
||||
s_ph2 += 2.0 * 3.14159265358979323846 * 50.0 / 1000.0; /* 50 Hz */
|
||||
(void)sample_ring_push_frame(f, (uint8_t)ADC_SEM_COUNT);
|
||||
phasor_run();
|
||||
if (run_freq != 0) {
|
||||
freq_run();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 200 ms 发布拍(读同拍 freq 状态,adc_task v3.2 编排的镜像) */
|
||||
static void snap_pub(uint32_t ms, uint32_t clip_mask)
|
||||
{
|
||||
meas_tick(ms, freq_valid(), freq_last(), clip_mask);
|
||||
}
|
||||
|
||||
static void tc_pts_snap(void)
|
||||
{
|
||||
float v;
|
||||
uint8_t q;
|
||||
|
||||
reset_all(1000u);
|
||||
iec104_pts_bind_src(NULL); /* 板端默认源 = 真实快照链 */
|
||||
(void)phasor_init(); /* 环 + 相量双区清零 */
|
||||
(void)meas_init();
|
||||
CHECK((iec104_pts_yc_read(0u, &v, &q) == -1)
|
||||
&& (q == (uint8_t)(IEC104_QDS_IV | IEC104_QDS_NT)) && (v == 0.0f),
|
||||
"TC-IEC104-025 before first publish -> IV|NT, value zero");
|
||||
snap_beats(20, 100.0, 0);
|
||||
snap_pub(200u, 0xE6u); /* 削顶位图同板端默认构建(cl=0xE6) */
|
||||
CHECK((iec104_pts_yc_read(0u, &v, &q) == 0) && (q == 0u)
|
||||
&& (fabsf(v - 70.711f) < 0.1f),
|
||||
"TC-IEC104-025 UA = snapshot fundamental RMS (engineering domain)");
|
||||
CHECK((iec104_pts_yc_read(3u, &v, &q) == 0) && (q == 0u),
|
||||
"TC-IEC104-025 UN (bit3 not in 0xE6) stays valid");
|
||||
CHECK((iec104_pts_yc_read(4u, &v, &q) == 0) && (q == 0u),
|
||||
"TC-IEC104-025 IA valid");
|
||||
CHECK((iec104_pts_yc_read(1u, &v, &q) == -1) && (q == IEC104_QDS_IV)
|
||||
&& (v == 0.0f), "TC-IEC104-025 clipped UB: CLIPPED maps to wire IV, value zero");
|
||||
CHECK((iec104_pts_yc_read(2u, &v, &q) == -1) && (q == IEC104_QDS_IV),
|
||||
"TC-IEC104-025 clipped UC IV");
|
||||
CHECK((iec104_pts_yc_read(5u, &v, &q) == -1) && (q == IEC104_QDS_IV),
|
||||
"TC-IEC104-025 clipped IB IV");
|
||||
CHECK((iec104_pts_yc_read(8u, &v, &q) == -1) && (q == IEC104_QDS_IV),
|
||||
"TC-IEC104-025 freq point published but not fresh -> IV (Card 11 rule)");
|
||||
}
|
||||
|
||||
static void tc_pts_freq(void)
|
||||
{
|
||||
float v;
|
||||
uint8_t q;
|
||||
int k;
|
||||
|
||||
reset_all(1000u);
|
||||
iec104_pts_bind_src(NULL);
|
||||
(void)phasor_init();
|
||||
(void)freq_init();
|
||||
(void)meas_init();
|
||||
for (k = 0; k < 5; k++) { /* 100 拍:测频启动收敛需 20 拍 */
|
||||
snap_beats(20, 100.0, 1);
|
||||
snap_pub((uint32_t)(k + 1) * 200u, 0u);
|
||||
}
|
||||
CHECK(freq_valid() == 1u, "TC-IEC104-026 drive precondition: freq converged");
|
||||
CHECK((iec104_pts_yc_read(8u, &v, &q) == 0) && (q == 0u)
|
||||
&& (fabsf(v - 50.0f) <= 0.02f),
|
||||
"TC-IEC104-026 0x401D carries freq reading within 0.02 Hz of synthetic 50.000");
|
||||
for (k = 0; k < 3; k++) { /* 浮空:幅值门落下 */
|
||||
snap_beats(20, 0.0, 1);
|
||||
snap_pub((uint32_t)(6 + k) * 200u, 0u);
|
||||
}
|
||||
CHECK((freq_valid() == 0u) && (iec104_pts_yc_read(8u, &v, &q) == -1)
|
||||
&& (q == IEC104_QDS_IV) && (v == 0.0f),
|
||||
"TC-IEC104-026 freq_valid==0 -> IV with zeroed value (Card 11 DoD)");
|
||||
}
|
||||
|
||||
static void tc_db_runtime(void)
|
||||
{
|
||||
iec104_pts_cov_t cov;
|
||||
|
||||
reset_all(1000u); /* 假源在场 = 每次 cov_check 一测点 */
|
||||
CHECK((iec104_pts_yc_set_deadband(0u, 2.0f) == 0)
|
||||
&& (iec104_pts_yc_deadband(0u) == 2.0f),
|
||||
"TC-IEC104-027 runtime deadband write + readback");
|
||||
CHECK((iec104_pts_yc_set_deadband(9u, 1.0f) == -1)
|
||||
&& (iec104_pts_yc_set_deadband(0u, -0.1f) == -1)
|
||||
&& (iec104_pts_yc_deadband(0u) == 2.0f),
|
||||
"TC-IEC104-027 bad idx / negative rejected, RAM untouched");
|
||||
CHECK(iec104_pts_yc_deadband(8u) == 0.5f, "TC-IEC104-027 freq point ROM default kept");
|
||||
s_f_yc[0] = 100.0f;
|
||||
iec104_pts_cov_check(&cov); /* 建线 rep=100(档 2.0) */
|
||||
s_f_yc[0] = 101.0f; /* 越旧档 0.5、未越运行档 2.0 */
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) == 0u, "TC-IEC104-027 runtime db gates the old step");
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) == 0u, "TC-IEC104-027 2nd point under 2.0 still silent");
|
||||
|
||||
iec104_pts_init(); /* 恢复 ROM 默认档(0.5) */
|
||||
iec104_pts_bind_src(&g_fake);
|
||||
s_f_yc[0] = 100.0f;
|
||||
iec104_pts_cov_check(&cov); /* 建线 */
|
||||
s_f_yc[0] = 100.6f; /* d=0.6 > 0.5,第 1 越 */
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) == 0u, "TC-IEC104-027 crossing arms only (2-point)");
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) != 0u, "TC-IEC104-027 second consecutive crossing confirms");
|
||||
s_f_yc[0] = 101.4f; /* 新基准 100.6 起 d=0.8 第 1 越 */
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) == 0u, "TC-IEC104-027 pullback test step 1 armed");
|
||||
s_f_yc[0] = 100.8f; /* 回摆入死区 -> 撤销候选 */
|
||||
iec104_pts_cov_check(&cov);
|
||||
s_f_yc[0] = 101.4f; /* 重新起算:单点不报 */
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) == 0u, "TC-IEC104-027 pullback cleared pending count");
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) != 0u, "TC-IEC104-027 two fresh crossings confirm again");
|
||||
}
|
||||
|
||||
static void tc_cov_qds_seq(void)
|
||||
{
|
||||
iec104_pts_cov_t cov;
|
||||
|
||||
reset_all(1000u); /* 假源段:品质翻转 */
|
||||
s_f_yc[1] = 50.0f;
|
||||
iec104_pts_cov_check(&cov);
|
||||
s_f_yc_rc[1] = -1;
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0002u) != 0u, "TC-IEC104-028 valid->IV reported at once");
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0002u) == 0u, "TC-IEC104-028 IV steady state not repeated");
|
||||
s_f_yc_rc[1] = 0;
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0002u) != 0u, "TC-IEC104-028 IV->valid recovery reported at once");
|
||||
|
||||
iec104_pts_init(); /* 板端段:seq 去重 */
|
||||
iec104_pts_bind_src(NULL);
|
||||
(void)phasor_init();
|
||||
(void)meas_init();
|
||||
snap_beats(20, 100.0, 0);
|
||||
snap_pub(200u, 0u); /* seq=1 */
|
||||
iec104_pts_cov_check(&cov); /* 建线帧 */
|
||||
CHECK(cov.yc_changed == 0u, "TC-IEC104-028 baseline frame silent");
|
||||
snap_beats(20, 200.0, 0);
|
||||
snap_pub(400u, 0u); /* seq=2:第 1 越点 */
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) == 0u, "TC-IEC104-028 one new frame arms only");
|
||||
iec104_pts_cov_check(&cov);
|
||||
iec104_pts_cov_check(&cov); /* 无换帧:不得计为第 2 点 */
|
||||
CHECK((cov.yc_changed & 0x0001u) == 0u, "TC-IEC104-028 same frame never counts twice");
|
||||
snap_beats(20, 200.0, 0);
|
||||
snap_pub(600u, 0u); /* seq=3:连续第 2 越点 */
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x0001u) != 0u, "TC-IEC104-028 second new frame confirms");
|
||||
snap_pub(800u, 0xE6u); /* 换帧仅变品质(削顶注入) */
|
||||
iec104_pts_cov_check(&cov);
|
||||
CHECK((cov.yc_changed & 0x00E6u) == 0x00E6u,
|
||||
"TC-IEC104-028 clipped flip per frame reported as a set");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("=== IEC104 Protocol Stack Host Tests ===\n");
|
||||
@@ -939,6 +1127,10 @@ int main(void)
|
||||
tc_ts_rp();
|
||||
tc_periodic();
|
||||
tc_cov_kfull();
|
||||
tc_pts_snap();
|
||||
tc_pts_freq();
|
||||
tc_db_runtime();
|
||||
tc_cov_qds_seq();
|
||||
printf("=== IEC104 Tests: %d/%d PASSED (failed=%d) ===\n",
|
||||
s_passed, s_total, s_failed);
|
||||
return (s_failed == 0) ? 0 : 1;
|
||||
|
||||
Reference in New Issue
Block a user