90db528032
W1-0 台账三件套:scripts/ram_baseline.py(四模式)+ ram_baseline.tsv 趋势 + docs/内存管理/RAM预算台账.md + pre-commit mem-budget 钩子(RW_IRAM1/RW_CCM >92% 即 FAIL + Top-10 附表);审查报告 §5.5 三条闭环。 B4 IEC 60870-5-104 上行(被控站,TCP 2404):App/protocol/iec104/ 三模块 (asdu 编解码 / pts 点表+数据源 vtable / link APCI+FSM,纯逻辑零 I/O)+ App/task/iec104_serv.c(iec104Task,NET_READY 屏障 100ms 分片喂位)。 82 断言 L0.5 全绿 + iec104-unit-test 钩子(第 31 钩子); 设计说明 docs/子系统设计/IEC104上行设计说明.md 全量回填。 B5 protectTask(L3 板端接线):App/task/protect_task.c——20ms 判据节拍 prot_elm_run + L5-4 采样故障闭锁(adc_health 电平位→元件复位)+ L5-1 定值 校验和巡检;新增 prot_elm_request_reset() 收口跨上下文复归(104 YK11 落请求、 eval 头部消费);定值/元件初始化移入 app_main_init(内核前)。TC-PE-010 (prot_elm 28 用例)。 门禁与内存:TASK_WD_PROTECT=8 入 required_mask(产品 0x77→0x1F7、HW 层 0x1F5,看门狗单测 39 断言同步);FreeRTOS 堆 48→56KB(.ioc L1 参数 + FreeRTOSConfig.h 同步,RAM预算台账 §6 登记配额 48→56KB)。 ZI 144,008→152,204(+8,196 B = 堆 +8KB,B5 扩容);Code=204,348。 stack_report:protectTask 512 words 静态链 872 B/余 57%、iec104Task 640 words 1456 B/余 43% 均 PASS;RW_IRAM1 73.1% / RW_CCM 87.9%(<92%)。 验证:@build 0 错 0 警;ci_local 全绿(31 钩子 + 13 主机侧单测); doc-links 135 文档 PASS。登记簿 B4/B5 销项、W1 波次完成;保护规划/看门狗 说明/AGENTS(9 任务)/RAM 三文档全部同步。 遗留(验收窗口,非代码空洞):台架第三方 104 主站往返(送检窗口)、 标准源注入动作判据、@test PROT 锚点 + protect 栈水位 + 新堆 min_ever 复测。
137 lines
6.4 KiB
C
137 lines
6.4 KiB
C
/*
|
||
* 模块名称:IEC 60870-5-104 链路层(APCI + 状态机,纯逻辑)
|
||
* 模块功能:TCP 流 → APDU 重组、U/S/I 帧编解码、STARTDT/STOPDT/TESTFR、
|
||
* k/w 流量窗与 t1/t2/t3 超时、发送序号 N(S)/N(R) 管理,以及应用层
|
||
* 流程编排:总召(act→背景扫描→actterm,首召 RBT 用 COT=4)、
|
||
* 突发上送(COV,COT=3)、周期上送(COT=1)、读单个(C_RD→COT=5)、
|
||
* 双点遥控两段式(选择/执行,失配否定确认 PN)、定值读(C_RD)/
|
||
* 定值写(C_SE_NC 选择=范围校验 / 执行=写入+封存)、时钟同步(C_CS
|
||
* → clock_sync 回调)、试验(C_TS)与进程复位(C_RP,清快照)。
|
||
* **零 I/O**:收 = on_rx 喂 TCP 流片段,发 = send_apdu 回调,
|
||
* 时基 = 调用方注入 now_ms(tick ms,回绕安全:差值法)
|
||
* → 全栈(asdu+pts+link)主机侧 L0.5 可离线跑(登记簿 A-4 约束 1)。
|
||
* 参数(DL/T 634.5104 标准默认,§1.5 未另定):k=12 w=8 t1=15s t2=10s t3=20s。
|
||
* 端口:TCP **2404**(§1.5 B0 定义;本 DTU = 被控站/服务器,主站连入)。
|
||
* 线程约定:单实例单任务上下文(板端 = 104 服务在 netTask 消息循环内驱动,
|
||
* 见 iec104_serv 胶水层);非线程安全,禁止多任务共享一实例。
|
||
* 失败语义:send_apdu 内**不得阻塞**;发送失败由胶水层断链(主站会重连),
|
||
* 本层不感知发送失败。
|
||
* 创建日期:2026-10-12(B4)
|
||
*/
|
||
#ifndef IEC104_LINK_H
|
||
#define IEC104_LINK_H
|
||
|
||
#include <stdint.h>
|
||
|
||
#include "iec104_pts.h"
|
||
|
||
/* 服务端口(§1.5:以太网 TCP 2404) */
|
||
#define IEC104_PORT 2404U
|
||
|
||
/* 链路参数(标准默认值) */
|
||
#define IEC104_K_MAX 12U /* 未确认 I 帧上限 */
|
||
#define IEC104_W_MAX 8U /* 收到 I 帧未发确认的强制 S 阈值 */
|
||
#define IEC104_T1_MS 15000UL /* 发送/确认超时(超时 = 链路故障) */
|
||
#define IEC104_T2_MS 10000UL /* 无 I 发送时强制 S 确认超时(< t1) */
|
||
#define IEC104_T3_MS 20000UL /* 空闲发 TESTFR 周期(< t1) */
|
||
|
||
/* TCP 流重组缓冲:APDU 上限 253 + 半帧余量 */
|
||
#define IEC104_RXBUF_SZ 512U
|
||
|
||
/* 单次 poll 发送预算(ASDU 数)——防总召大扫描饿死宿主任务 */
|
||
#define IEC104_POLL_BUDGET 4U
|
||
|
||
/* 链路状态 */
|
||
typedef enum {
|
||
IEC104_ST_IDLE = 0, /* TCP 未建立(或已断开) */
|
||
IEC104_ST_OPEN, /* TCP 已建立,等 STARTDT act */
|
||
IEC104_ST_RUN, /* STARTDT 已确认,数据服务开 */
|
||
IEC104_ST_STOPPED /* STOPDT 已确认:停数据,保 S/TESTFR */
|
||
} iec104_state_t;
|
||
|
||
/* 配置与回调(ctx 原样回传给回调) */
|
||
typedef struct {
|
||
uint16_t ca; /* 公共地址 = 链路地址(2B,§1.5) */
|
||
/* 发一个完整 APDU(含 6B APCI 头)。不得阻塞;生命周期仅回调内有效 */
|
||
void (*send_apdu)(void *ctx, const uint8_t *apdu, uint16_t len);
|
||
/* C_CS 时钟同步:epoch 毫秒;NULL 或返回 -1 → 否定确认 */
|
||
int (*clock_sync)(void *ctx, uint64_t epoch_ms);
|
||
} iec104_link_cfg_t;
|
||
|
||
/* 链路实例(胶水层静态持有,零堆) */
|
||
typedef struct {
|
||
const iec104_link_cfg_t *cfg;
|
||
void *ctx;
|
||
iec104_state_t state;
|
||
uint8_t init_pending; /* 1 = 下次总召按初始化(COT=4 + RBT) */
|
||
/* 序号(0..32767,帧内 ×2) */
|
||
uint16_t tx_seq;
|
||
uint16_t rx_seq;
|
||
uint16_t tx_unacked; /* 已发 I 未获认(k 窗) */
|
||
uint16_t rx_unacked; /* 已收 I 未确认(w 阈) */
|
||
uint8_t testfr_pending; /* 1 = TESTFR act 未获 con(t1 同样约束它) */
|
||
/* 定时器到期时刻(now_ms 域;差值法判超时,回绕安全) */
|
||
uint32_t t1_deadline;
|
||
uint32_t t2_deadline;
|
||
uint32_t t3_deadline;
|
||
uint32_t now_ms;
|
||
/* TCP 流重组 */
|
||
uint8_t rx_buf[IEC104_RXBUF_SZ];
|
||
uint16_t rx_len;
|
||
/* 总召进度:0 无 / 1 背景扫描中 / 2 待发 actterm */
|
||
uint8_t interp_step;
|
||
uint8_t interp_yc_idx; /* 背景扫描 YC 游标 */
|
||
uint8_t interp_yx_idx; /* 背景扫描 YX 游标 */
|
||
uint8_t interp_cot; /* 本次总召用的 COT(BG_SCAN 或 INIT) */
|
||
/* 遥控选择暂存(执行段比对) */
|
||
uint32_t yk_sel_ioa; /* 0 = 无选择 */
|
||
uint8_t yk_sel_dpc;
|
||
/* 周期上送(COT=1)下次触发时刻 */
|
||
uint32_t period_next;
|
||
/* COV 待发暂存(k 窗满时保留到下次 poll,变化不许丢) */
|
||
uint64_t pend_yx;
|
||
uint16_t pend_yc;
|
||
} iec104_link_t;
|
||
|
||
/*
|
||
* 函数功能:初始化实例(置 IDLE、清序号;不发送任何帧)
|
||
* 入口参数:lk - 实例;cfg/ctx - 配置与回调上下文
|
||
*/
|
||
void iec104_link_init(iec104_link_t *lk, const iec104_link_cfg_t *cfg, void *ctx);
|
||
|
||
/*
|
||
* 函数功能:TCP 连接建立(新连接或重连后调用)
|
||
* 入口参数:now_ms - 当前时基
|
||
* 函数说明:序号清零、init_pending 置位(首召 = 初始化总召)、进 OPEN。
|
||
*/
|
||
void iec104_link_open(iec104_link_t *lk, uint32_t now_ms);
|
||
|
||
/*
|
||
* 函数功能:TCP 断开(对端断开或胶水层发送失败主动断链时调用)
|
||
* 函数说明:回 IDLE、清重组缓冲与选择暂存;不发送任何帧。
|
||
*/
|
||
void iec104_link_close(iec104_link_t *lk);
|
||
|
||
/*
|
||
* 函数功能:喂入 TCP 收到的流片段(任意切分/粘帧)
|
||
* 入口参数:data/len - 流片段;now_ms - 当前时基
|
||
* 函数说明:内部重组,凑齐 APDU 即处理;坏帧(起始符/长度非法)→ 视同链路
|
||
* 故障,实例回 IDLE(胶水层检测到 IDLE 跳变应断开 socket)。
|
||
* 返回后实例仍为 RUN 不代表对端合法——仅表示未触发断链条件。
|
||
*/
|
||
void iec104_link_on_rx(iec104_link_t *lk, const uint8_t *data, uint16_t len,
|
||
uint32_t now_ms);
|
||
|
||
/*
|
||
* 函数功能:周期驱动(定时器 + COV + 总召分片 + 周期上送)
|
||
* 入口参数:now_ms - 当前时基(建议 ≤100 ms 调一次)
|
||
* 函数说明:仅 RUN 态产生数据帧;STOPPED 态只处理 t2/t3(S/TESTFR)。
|
||
* 单次调用发送量 ≤ IEC104_POLL_BUDGET 个 ASDU。
|
||
*/
|
||
void iec104_link_poll(iec104_link_t *lk, uint32_t now_ms);
|
||
|
||
/* 当前状态(日志/看门狗用) */
|
||
iec104_state_t iec104_link_state(const iec104_link_t *lk);
|
||
|
||
#endif /* IEC104_LINK_H */
|