04997e48aa
同族第二道:代码注释面。41 个 run_unit_test.py 文件头与引用行、common harness 与两份 README、4 个 *_test.c 文件头、App/** 14 处(含 BOM 文件 App/cfg/cfg_file.c)、 GD5F nand_ftl.c 1 处,共 73 站点 / 64 文件;措辞取「主机侧纯逻辑单元测试运行器 (纯标准库)」避免同行「主机侧」重复。 零行为改动(机器证据,不是口头): - 17 个 .c/.h 剥掉注释后与 HEAD **逐字节相同**; - 42 个 .py 走 ast.dump 比较、仅归一 docstring(真实字符串字面量参与比较,故旗标或 输出文本被动过必然报红)→ 全部相等;behaviour_changed=0。 - py_compile 42/42;抽跑 watchdog 47/47、freq 46/46(动手前先取基线,改后同数); CR 字节 0、EF BF BD 0、BOM 与 HEAD 逐一一致、check_bom_drift rc=0。 刻意未动:6 处字符串字面量(FTP 应答 "215 UNIX Type: L8"、lftpd_test.c SYST 断言、 console_log_test.c 的 "L1\r\n"、phasor_test.c 的 "L2-in ring" 文案与 printf 标题)—— 改了就是改测试输出/行为;UI 设计令牌层 L0(ui_tokens.h、ui_content_page.c)与 test/host/README.md 的算法层号是**另外的族**。 两条 SyntaxWarning(ftp_cfg / net_cfg 文件头 \S 转义)**HEAD 同样存在**,已对 HEAD 副本 复现证明非本次引入,未顺手改。
142 lines
6.9 KiB
C
142 lines
6.9 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)主机侧纯逻辑单测可离线跑(分层约束)。
|
||
* 参数(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"
|
||
|
||
/* 服务端口真源已迁 [comm] 段(道G task-8):工厂默认 2404 = IEC104_COMM_DEF_PORT,
|
||
* 运行期取 iec104_comm_port()(App/protocol/iec104/iec104_comm.h)。原死 define
|
||
* IEC104_PORT 全仓零 .c 消费,2026-10-26 删除(旧引用见 docs/UI设计/页面扩充详细方案.md)。 */
|
||
|
||
/* 链路参数(标准默认值) */
|
||
#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);
|
||
/* 时标源(B9):当前 epoch 毫秒(M_SP_TB_1 自发用)。
|
||
* NULL 或返回 UINT64_MAX = 时钟无效 → CP56 IV 位如实置位。
|
||
* 纯读(sys_clock 推算),不得阻塞、不得有副作用。 */
|
||
uint64_t (*epoch_ms)(void *ctx);
|
||
} 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 */
|