Files
STM32F4-Base/App/protocol/iec104/iec104_asdu.h
T
wandering1 1d96fc9f87 feat(soe): B9 动作记录 + 时标 SOE(L4-4/L4-5)+ 104 M_SP_TB_1 自发
- 新增 App/log/soe_rec.{c,h}:64B 定长 SOE 记录纯编解码(CP56Time2a
  时标 + 类型 + 元件号 + 单调序号 + 值 + sum8 撕裂校验),零 I/O 零 OS
  依赖,主机 L0.5 覆盖(32 断言,含与 iec104 CP56 解码器交叉互证)
- 新增 App/log/soe_store.{c,h}:protectTask 边沿投递(取时标 + 组记录 +
  SPSC 待发环/消息队列,零文件系统);defaultTask 经 syslog_drain 尾部
  排空落 /log/soe.log(卷锁 try / FA_WRITE|FA_OPEN_APPEND / 校验字节数 /
  容量满 unlink 重建,全套照 run.log 实证纪律;无卷损坏归类路径)
- protect_task.c:元件动作/返回、软压板投退、采样闭锁/恢复六类边沿
  → soe_store_post;post 内禁 DBG_*(protect 静态最坏链 872 B 不变,
  改前/改后 stack_report 九任务逐字节一致),丢弃留痕挪 drain 侧
- iec104:单点 YX 自发改 M_SP_TB_1(30) 带 CP56 时标(总召/周期保持
  M_SP_NA_1,单测两种都断言);link cfg 新增 epoch_ms 时标源回调
  (NULL/无效 → IV 位如实置位);serv 绑 sys_clock(秒域时基,
  ms 域 = 秒×1000,不造假亚秒)
- 主机单测:test/host/soe/(32 断言)+ iec104 94→97(TB 时标/IV);
  iec104_master.py 解析 type 30(B6/B7 流不回归);decode_soe.py
  台架解码断言工具(seq 单调/校验和/UTC 交叉)
- 注册:uvprojx + check_registration SIM_EXEMPT 点名(MCU-only 胶水)
- 文档(我方属主区):`App/log/README.md` 增 soe 节(64B 记录/单写者/
  post 禁 DBG/UTC 交叉坑);`docs/子系统设计/IEC104上行设计说明.md`
  §1 范围行 + §3.2 时标注 + §7 台架行 + §8 第 2 条销项 + 变更记录行

台架腿(bench 锁 B9,release --bench-pass):run_boot_test PASS;
--b7-pre 21/21、--b7-post 13/13(B6/B7 回归 + 确定性动作边沿);
自发 YX 上送 M_SP_TB_1 带 ts(11:00:51 动作 / 11:00:53 复归);
FTP 下载 /log/soe.log 30 条记录 decode PASS(seq 0..28 单调、
ELM_ASSERT 14 条、UTC 交叉一致);定值/压板已恢复默认。

台账 +1088 B(SPSC 环 512 + 静态 FIL 528 + 计数器)随合并由 Lead
回填(ram_baseline --write + check_mem_numbers --write)。

gate: only mem-budget/mem-numbers pending lead ledger backfill
(pre-commit --all-files: 29 Passed / 2 Failed / 0 Skipped;
hygiene self-check OK: no BOM/CRLF/mojibake/trailws/non-ASCII literal)

sync 追平 v2-on-ui(B8 freq + N33 抬栈)后复跑:@build 0/0
(Code=209492 RW=1104 ZI=154184);stack_report 九任务全 PASS、
protectTask 872 B/57% 不变;ci_local L0.5 15 runner 951/951
(freq 46 / soe 32 / iec104 97 / prot_set 90 / prot_elm 47)。
顺带修 protect_task.c 陈旧注释:定值巡检 31 项 → 40 项(B8 后)。
2026-10-12 19:38:13 +08:00

132 lines
7.0 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.
/*
* 模块名称:IEC 60870-5-104 ASDU 编解码(应用层,纯逻辑)
* 模块功能:104 规约应用服务数据单元(ASDU)的类型/传送原因常量、组帧与解析。
* **零 I/O、零平台依赖**(仅 stdint.h)→ 主机侧 L0.5 可离线单测
* (登记簿 A-4 约束 1"协议解析与硬件 I/O 分离")。
* 口径来源:docs/算法/继电保护功能复现规划.md §1.5(B0 产品定义)——
* 公共地址 2 字节、传送原因 2 字节、信息体地址 IOA **3 字节**(101 为 2 字节);
* 遥测上送**短浮点** M_ME_NC_1(系数 = 1);遥信双点上双点、其余单点;
* 遥控**双点命令**(选择 82H / 执行 02H,即 QDC 的 S 位 + 值 2)。
* 帧结构(本层只管 ASDU,APCI 6 字节头归 iec104_link):
* [type 1B][vsq 1B][cot 2B][ca 2B]( [ioa 3B][元素...] )*n
* 多信息体地址对象(SQ=0)每对象带独立 IOA;顺序对象(SQ=1)单 IOA + n 元素。
* 创建日期:2026-10-12(B4,W1 功能主线,登记簿见 docs/任务规划/)
*/
#ifndef IEC104_ASDU_H
#define IEC104_ASDU_H
#include <stdint.h>
/* ---------------- 类型标识(DL/T 634.5104,仅定义本期子集) ---------------- */
#define IEC104_T_M_SP_NA_1 1U /* 单点遥信 SIQ */
#define IEC104_T_M_DP_NA_1 3U /* 双点遥信 DIQ */
#define IEC104_T_M_SP_TB_1 30U /* 单点遥信+CP56时标 SIQ+7B(B9 SOE 自发) */
#define IEC104_T_M_ME_NC_1 13U /* 遥测短浮点 float+QDS(§1.5 口径) */
#define IEC104_T_C_SE_NC_1 50U /* 定值写(短浮点)float+QDS */
#define IEC104_T_C_DC_NA_1 52U /* 双点遥控 QDC(82H 选 / 02H 执行) */
#define IEC104_T_C_IC_NA_1 100U /* 总召 RQT */
#define IEC104_T_C_RD_NA_1 102U /* 读单个测量值 IOA only */
#define IEC104_T_C_CS_NA_1 103U /* 时钟同步 CP56Time2a */
#define IEC104_T_C_TS_NA_1 104U /* 试验 FBP 2B */
#define IEC104_T_C_RP_NA_1 105U /* 进程复位 RPA 1B */
/* ---------------- 传送原因 COT(低字节 6bit;高字节 T|PN|RBT/…) ---------- */
#define IEC104_COT_PERIODIC 1U /* 周期/循环 */
#define IEC104_COT_BG_SCAN 2U /* 背景扫描(总召响应) */
#define IEC104_COT_SPONT 3U /* 突发(cos) */
#define IEC104_COT_INIT 4U /* 初始化(总召 + RBT=1 时用) */
#define IEC104_COT_REQ 5U /* 请求(C_RD 响应) */
#define IEC104_COT_ACT 6U /* 激活 */
#define IEC104_COT_ACTCON 7U /* 激活确认 */
#define IEC104_COT_ACTTERM 8U /* 激活终止 */
#define IEC104_COT_DEACT 9U /* deactivate */
#define IEC104_COT_DEACTCON 10U /* 停止激活确认 */
#define IEC104_COT_UNK_COT 12U /* 未知传送原因 */
#define IEC104_COT_UNK_CA 13U /* 未知公共地址 */
#define IEC104_COT_UNK_IOA 14U /* 未知信息体地址(+EVI) */
#define IEC104_COT_BIT_T 0x80U /* COT 高字节 bit7:试验 */
#define IEC104_COT_BIT_PN 0x40U /* COT 高字节 bit6:否定确认 */
#define IEC104_COT_BIT_RBT 0x10U /* COT 高字节 bit4:请求链路仿真(总召初始化) */
/* ---------------- VSQ ---------------- */
#define IEC104_VSQ_SQ 0x80U /* 1 = 顺序地址(单 IOA + n 元素) */
#define IEC104_VSQ_N(n) ((uint8_t)((n) & 0x7FU))
/* ---------------- 遥信/遥测品质描述位(本期只用溢出/异常/非当前) --------- */
#define IEC104_QDS_OV 0x01U
#define IEC104_QDS_BL 0x10U /* blocked(闭锁) */
#define IEC104_QDS_NT 0x20U /* not top(暂态品质,遥测未就绪用) */
#define IEC104_QDS_IV 0x80U /* invalid(无效,通道不可用用) */
#define IEC104_DIQ_IV 0x80U
#define IEC104_SIQ_IV 0x80U
/* ---------------- 双点值(DIQ/QDC 低 2bit) ---------------- */
#define IEC104_DPC_DONTCARE 0U
#define IEC104_DPC_OFF 1U
#define IEC104_DPC_ON 2U
#define IEC104_QDC_S 0x80U /* 1 = 选择,0 = 执行(§1.5:82H/02H) */
/* ---------------- 总召 RQT ---------------- */
#define IEC104_RQT_GROUP1 20U /* 总查询(组 1) */
/* ---------------- ASDU 头(解析产物) ---------------- */
typedef struct {
uint8_t type; /* 类型标识 */
uint8_t vsq; /* 可变结构限定词 */
uint8_t cot; /* 传送原因低 6bit */
uint8_t cot_hi; /* COT 首字节的高位标志(T=0x80 / PN=0x40 / RBT=0x10 原样保留) */
uint8_t oa; /* 源发站地址(第 2 COT 字节;bit7 = EVI) */
uint16_t ca; /* 公共地址(链路地址 = ASDU 公共地址,2B) */
const uint8_t *obj; /* 信息体区首址(指向调用方缓冲,生命周期同 on_rx) */
uint16_t obj_len; /* 信息体区长度 */
} iec104_asdu_hdr_t;
/*
* 函数功能:解析 ASDU 头(不解析信息体——各命令的体解析在 iec104_link 内做)
* 入口参数:buf - ASDU 首址(不含 APCI);len - ASDU 长度
* hdr - 输出头
* 返 回 值:0 成功 / -1 参数或长度错(len < 6)
* 函数说明:纯只读,不改动 buf。
*/
int iec104_asdu_parse_hdr(const uint8_t *buf, uint16_t len, iec104_asdu_hdr_t *hdr);
/*
* 函数功能:写 ASDU 头
* 入口参数:buf - 目标缓冲(容量须 ≥ 6);type/vsq/cot/cot_hi/ca 见常量
* 返 回 值:固定 6(已写字节数)
*/
uint16_t iec104_asdu_put_hdr(uint8_t *buf, uint8_t type, uint8_t vsq,
uint8_t cot, uint8_t cot_hi, uint16_t ca);
/* ---------------- 小工具(IOA 3B 小端 / IEEE 短浮点小端) ---------------- */
/* IOA(3 字节小端)写入 */
void iec104_put_ioa(uint8_t *buf, uint32_t ioa);
/* IOA(3 字节小端)读取 */
uint32_t iec104_get_ioa(const uint8_t *buf);
/* IEEE754 float 按 104 小端写入(memcpy 位模式,不做字节序假设) */
void iec104_put_float(uint8_t *buf, float v);
/* IEEE754 float 按 104 小端读取 */
float iec104_get_float(const uint8_t *buf);
/* ---------------- CP56Time2a(C_CS 时钟同步用) ---------------- */
/*
* 函数功能:解析 CP56Time2a(7 字节)为 epoch 毫秒
* 入口参数:buf - 7B 首址;epoch_ms - 输出(UTC 毫秒)
* 返 回 值:0 成功 / -1 参数错 / -2 IV 位置起(时间无效,调用方应拒绝)
* 函数说明:年字段仅 7bit(0..127,基准 2000);月/日/时/分按 1.. 语义;
* 不处理 SU(夏令时)位——忽略。
*/
int iec104_cp56_to_epoch_ms(const uint8_t *buf, uint64_t *epoch_ms);
/*
* 函数功能:epoch 毫秒 → CP56Time2a(7 字节,UTC 分解)
* 入口参数:epoch_ms - UTC 毫秒;buf - 目标 7B
* 返 回 值:固定 7
* 函数说明:epoch_ms < 2000-01-01 时钳到 2000(年字段下限);IV 清 0。
*/
uint16_t iec104_epoch_ms_to_cp56(uint64_t epoch_ms, uint8_t *buf);
#endif /* IEC104_ASDU_H */