Files
STM32F4-Base/IEC60870-Slave/104/IEC104_Link_Common.h
T
STF 4c55544f05
CI / L0 静态门禁 (pre-commit) (push) Failing after 45s
CI / L0.5 主机侧单测 (MSVC) (push) Failing after 42s
通信协议代码
2026-10-26 08:31:48 -04:00

571 lines
36 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.
/**
* 公共链路类型与接口:初始化、I/S序号、k/w窗口、S确认及TESTFR,两种角色共用。
* 业务调用方按本端角色包含Master_StartStop.h或Slave_StartStop.h即可同时获得本头文件的声明。
* 启停接口分别由角色头文件公开;Internal.h只声明实现之间的协作函数。
*
* 每条连接持有一份State,所有事件串行处理。Prepare/应答Handle成功只代表
* 报文已生成,须由调用方发送并按具体接口提交Complete;构帧不能当作发送完成。
* 完整状态校验集中在IEC104_Link.c;使用启停接口时再链接对应角色实现。
*/
#ifndef IEC104_LINK_COMMON_H
#define IEC104_LINK_COMMON_H
#include "IEC104_Codec.h"
#ifdef __cplusplus
extern "C" {
#endif
/** 每条TCP连接的本端角色;初始化后在该连接存续期间不得切换。 */
typedef enum {
IEC104_ROLE_INVALID = 0, /* 未初始化或损坏标记;正常链路接口拒绝此值 */
IEC104_ROLE_CONTROLLING, /* 控制站:主动发起STARTDT/STOPDT并等待CON */
IEC104_ROLE_CONTROLLED /* 被控站:接收STARTDT/STOPDT_ACT并发送CON */
} IEC104_LinkRole_t;
/**
* 数据传输是否启用。被控站按START/STOP受理结果立即更新,与CON写入完成解耦。
* 控制站仍按原ACT/CON流程提交状态,并允许在启动过程中提前发送命令。
* 本字段不表达停止等待ACK;被控站STOPPED/STOP_DRAINING仍接受S确认。
*/
typedef enum {
IEC104_DT_STOPPED = 0, /* 数据传输未启用;具体接收/确认权限由角色及过程决定 */
IEC104_DT_STARTED /* 已提交启动;I帧收发还须满足当前dt_procedure的门控条件 */
} IEC104_DataTransferState_t;
/**
* STARTDT/STOPDT过程,控制站与被控站使用各自的合法值;TESTFR独立。
* 控制站:STOPPED/IDLE -> START_ACT_SEND_PENDING -> START_CON_WAITING -> STARTED/IDLE;
* STARTED/IDLE -> STOP_REQUESTED -> STOP_ACT_SEND_PENDING -> STOP_CON_WAITING -> STOPPED/IDLE。
* 被控站使用以下三个逻辑状态:
* - STOPPED/IDLE:停用;
* - STARTED/IDLE:启用,受理START立即进入;
* - STOPPED/STOP_DRAINING:停用并等待确认,受理STOP立即进入。
* 停止确认满足后生成CON并回STOPPED/IDLE;任何阶段受理START都进入STARTED/IDLE。
* 被控站不保存CON发送半态或相反ACT暂存标志,已有CON只由发送FIFO维护。
*/
typedef enum {
IEC104_DT_PROC_IDLE = 0, /* 当前没有STARTDT或STOPDT过程 */
/* 控制站专用过程。 */
IEC104_DT_PROC_START_ACT_SEND_PENDING, /* STARTDT_ACT已生成,等待发送完成 */
IEC104_DT_PROC_START_CON_WAITING, /* STARTDT_ACT已发送,等待STARTDT_CON */
IEC104_DT_PROC_STOP_REQUESTED, /* 已受理主动停止,正在准备S确认/ACT */
IEC104_DT_PROC_STOP_ACT_SEND_PENDING, /* STOPDT_ACT已生成,等待发送完成 */
IEC104_DT_PROC_STOP_CON_WAITING, /* STOPDT_ACT已发送,等待STOPDT_CON */
/* 被控站专用过程。 */
IEC104_DT_PROC_STOP_DRAINING = 7 /* 被控站已停用,等待确认后生成STOPDT_CON */
} IEC104_DtProcedure_t;
/**
* 普通S确认帧的发送进度。
*
* 普通w/t2确认与两端STOPDT流程共用此状态;同一时刻只允许一个S确认在途。
* 成功路径为IDLE -> 生成S帧 -> SEND_PENDING -> Complete_S_Ack_Send -> IDLE。
* 普通确认和STOPDT准备接口都使用同一构帧步骤,冻结报文携带的N(R);
* Complete成功后才推进acked_nr。发送失败同样清除在途状态,但保持
* acked_nr不变并返回FATAL。
*/
typedef enum {
IEC104_S_ACK_IDLE = 0, /* 无S帧等待完成;此时s_ack_nr必须为0 */
IEC104_S_ACK_SEND_PENDING /* S帧已生成;s_ack_nr冻结其实际N(R) */
} IEC104_SAckState_t;
/**
* 主动TESTFR探测状态;与dt_state和dt_procedure相互独立。
* 顺序为IDLE -> ACT_SEND_PENDING -> CON_PENDING -> IDLE。
* 调用方须先提交ACT完整发送结果,再处理TESTFR_CON;未等待时忽略CON,不缓存。
* Prepare_T3_Testfr按t3触发共用的内部准备路径,不创建另一套探测状态。
* TESTFR_ACT发送失败时Complete接口回到IDLE并返回FATAL。
*/
typedef enum {
IEC104_TESTFR_IDLE = 0, /* 没有正在进行的主动探测 */
IEC104_TESTFR_ACT_SEND_PENDING, /* TESTFR_ACT已生成,等待发送完成 */
IEC104_TESTFR_CON_PENDING /* TESTFR_ACT已完整发送,等待TESTFR_CON */
} IEC104_TestfrState_t;
/**
* 链路事件结果,必须与枚举值比较。
* 被控站START受理立即启用并生成CON,STOP受理立即停用并登记停止义务。
* 排空中的重复STOP返回IGNORED;停用IDLE下的STOP重新应答。
* CON完成仅检查发送结果;完成旧CON不改变当前启停状态。
* 控制站的多余CON仍按相应接口返回IGNORED;非法序号、角色、状态或发送失败为FATAL。
* FATAL由上层断链;失败前已受理的状态或发送事实不能回滚重放。
*/
typedef enum {
IEC104_LINK_RESULT_FATAL = -1, /* 当前连接必须由上层立即关闭 */
IEC104_LINK_RESULT_IGNORED = 0, /* 合法重复或没有匹配的在途过程 */
IEC104_LINK_RESULT_OK = 1, /* 本次处理成功,具体输出与状态变化见接口约定 */
} IEC104_LinkResult_t;
/** 主动停止请求的受理结果;除ACCEPTED外均不修改状态,必须按枚举值分支。 */
typedef enum {
IEC104_STOPDT_REQUEST_ERROR = -1, /* 参数、角色或状态非法 */
IEC104_STOPDT_REQUEST_ACCEPTED = 0, /* 已进入STOP_REQUESTED */
IEC104_STOPDT_REQUEST_ALREADY_STOPPED, /* 已STOPPED且没有启停过程 */
IEC104_STOPDT_REQUEST_IN_PROGRESS, /* 此前的主动停止仍在进行 */
IEC104_STOPDT_REQUEST_BUSY /* 另一个启停过程占用过程槽 */
} IEC104_StopdtRequestResult_t;
/** STOPDT报文准备结果;不是字节数,必须按枚举值分支。 */
typedef enum {
IEC104_STOPDT_PREPARE_ERROR = -1, /* 参数、角色、状态或编码结果非法 */
IEC104_STOPDT_NOT_ACTIVE = 0, /* 当前没有对应的停止流程 */
IEC104_STOPDT_FRAME_READY, /* 新报文及发送描述已生成 */
IEC104_STOPDT_WAIT_SEND, /* 等待已有S/ACT/CON的发送完成 */
IEC104_STOPDT_WAIT_PEER_ACK, /* 被控站等待对端确认本端I帧 */
IEC104_STOPDT_WAIT_PEER_CON /* 控制站等待STOPDT_CON */
} IEC104_StopdtPrepareResult_t;
/** STOPDT准备接口实际生成的报文类型,用于选择对应的发送完成接口。 */
typedef enum {
IEC104_STOPDT_FRAME_S_ACK, /* S确认:提交给Complete_S_Ack_Send */
IEC104_STOPDT_FRAME_ACT, /* 主动停止:提交给Complete_Stopdt_Act_Send */
IEC104_STOPDT_FRAME_CON /* 被动停止应答:提交给Complete_Stopdt_Con_Send */
} IEC104_StopdtFrameType_t;
/**
* STOPDT报文的发送描述,仅在Prepare返回FRAME_READY时写入。
* 调用方须与报文一起保存在同一FIFO节点中,最终发送结束后按frame_type分派
* 完成事件;frame_length为预期长度,Complete仍须传入实际最终发送字节数。
*/
typedef struct {
IEC104_StopdtFrameType_t frame_type; /* 本次生成的S确认、ACT或CON */
uint16_t frame_length; /* 完整APDU长度;当前三种报文均为6字节 */
} IEC104_StopdtTx_t;
/**
* I帧在Prepare成功时固定的发送快照。
*
* 调用方必须把该对象与当前发送报文关联保存,并在最终发送结束时原样
* 传给Complete_I_Send;不能用完成时刻的V(S)或V(R)重新构造快照。
*/
typedef struct {
uint16_t send_number; /* 本帧已预留且写入控制域的N(S),范围0..32767 */
uint16_t receive_number; /* 构帧时写入控制域的N(R),范围0..32767 */
uint16_t frame_length; /* 本帧完整APDU长度,用于判断是否最终完整发送 */
} IEC104_IFrameTx_t;
/**
* Link独占的I帧发送进度快照,SendBuffer不再复制这三个协议位置。
* 序号范围均为0..32767;ACK不能越过已提交本地完成的next_completion_ns。
* 顺序按循环距离检查,不能用普通整数大小比较回绕前后的序号。
* next_frame_ns在Prepare成功后推进;Manager完成整个跨模块事务后再核对
* 当前I帧、已提交ASDU数量和业务记录,不能在中间状态检查一致性。
*/
typedef struct {
uint16_t next_frame_ns; /* Link下一帧可分配的N(S) */
uint16_t next_completion_ns; /* 下一个尚未提交本地发送完成的I帧N(S) */
uint16_t peer_ack_nr; /* 已接受的对端累计确认位置,不代表本地完成 */
} IEC104_IFrameSendProgress_t;
/**
* 单条IEC-104连接的全部链路运行状态。
*
* 主要不变量:
* - vs、sent_vs、va、vr、acked_nr和s_ack_nr均为15位序号,按模32768运算;
* - distance(va, vs)是本端已经预留但尚未被对端确认的I帧数;
* - distance(sent_vs, vs)是尚未提交发送完成事件的I帧数,包含排队帧;
* - 上述两个区间均必须小于32768;Prepare同时保护两条边界,避免回绕歧义;
* - 先提交本地Complete,再处理覆盖该帧的ACK;distance(sent_vs,vs)<=distance(va,vs);
* - ACK仅允许推进到sent_vs,已完成未确认帧数为distance(va,sent_vs);
* - distance(acked_nr, vr)是已经接收但尚未由成功上线I/S帧确认的I帧数;
* - s_ack_state为IDLE时s_ack_nr必须为0;
* - role决定允许出现的dt_procedure,稳定状态由dt_state单独保存;
* - testfr_state独立于启停过程,可以与STARTDT/STOPDT过程并存。
* - 被控站仅使用IDLE或STOP_DRAINING;STOP_DRAINING必须同时为STOPPED。
*
* 本结构不包含锁、发送队列和时钟。一个连接上的所有Prepare、Handle、Complete
* 和Expired调用必须由上层串行化;TCP重连必须重新初始化状态并丢弃旧完成事件。
* 本结构不保存故障标志;Handle/Complete通过FATAL返回值报告致命故障,由连接层断连。
* 本结构保存单条连接的状态,连接组的选择/切换由上层负责。本实现允许控制站
* 在ACT之后、CON之前发送命令,适用条件见IEC104_Link_设计架构.md第3.2节;
* dt_state不能作为双向I帧的统一开关。
* 这些不变量依赖合法的事件序列维持;内部状态校验不保存发送队列历史,不能
* 证明完成事件身份或重建序号绕环次数。调用方不应直接改字段来跳过启停流程。
*/
typedef struct {
IEC104_LinkRole_t role; /* 本端固定角色;正常运行只能是两个有效角色之一 */
uint16_t vs; /* V(S):下一个尚未分配给发送队列I帧的N(S) */
uint16_t sent_vs; /* 下一个尚未提交发送完成事件的I帧N(S),按FIFO推进 */
uint16_t va; /* V(A):最早尚未被对端确认的本端发送序号 */
uint16_t vr; /* V(R):期望从对端收到的下一个I帧N(S) */
uint16_t acked_nr; /* 最近一次成功上线I/S帧实际携带的N(R) */
IEC104_SAckState_t s_ack_state; /* 普通确认及两端STOPDT共用的S帧发送进度 */
uint16_t s_ack_nr; /* 在途S帧携带的N(R)快照;IDLE时必须为0 */
IEC104_DataTransferState_t dt_state; /* 已提交的数据传输稳定状态 */
IEC104_DtProcedure_t dt_procedure; /* 当前唯一的STARTDT/STOPDT过程半态 */
IEC104_TestfrState_t testfr_state; /* 独立的主动TESTFR探测进度 */
} IEC104_LinkState_t;
/* 只读观察快照;连接层据unconfirmed_rx_count管理接收计时,不自行计算序号环距离。
* 启停/探测字段供诊断展示,是否应构帧须使用Can_Prepare查询,不能在外层组合状态条件。 */
typedef struct {
IEC104_LinkRole_t role; /* 本端固定角色 */
IEC104_DataTransferState_t dt_state; /* 已提交的启停稳定状态 */
IEC104_DtProcedure_t dt_procedure; /* 当前启停过程 */
IEC104_TestfrState_t testfr_state; /* 独立的主动探测进度 */
uint16_t unconfirmed_rx_count; /* 已接收且尚未由完整发送的I/S确认的I帧数 */
} IEC104_LinkStatus_t;
/* 完整校验后返回数值快照;1成功,0参数/状态非法,失败不改输出,不推进任何过程。 */
extern int IEC104_Link_Get_Status(const IEC104_LinkState_t *state, IEC104_LinkStatus_t *status);
/*
* 只读检查普通S是否应准备,与Prepare_S_Ack共用同一规划规则;w范围1..32767。
* immediate非0跳过w门限(例如t2已到期),仍检查启停门控、在途S及待确认数量。
* 1应准备,0当前无需/不能准备,-1参数或状态非法;不预留缓冲、不生成报文、不提交确认。
* 同一连接的查询和准备须串行执行;返回1后仍须处理实际Prepare/Manager排队结果。
*/
extern int IEC104_Link_Can_Prepare_S_Ack(const IEC104_LinkState_t *state, uint16_t w, int immediate);
/* 只读检查是否可开始一轮TESTFR;不检查t3时间。1可准备,0已有探测,-1状态非法。
* 与主动/t3构帧入口共用准入规则;查询不改变探测状态,调用方仍须处理实际准备结果。 */
extern int IEC104_Link_Can_Prepare_Testfr_Act(const IEC104_LinkState_t *state);
/**
* 适用端:控制站与被控站。
* 功能:把IEC 60870-5-104推荐默认参数写入一条连接的链路配置。
* 输入参数:config——待初始化的配置对象;允许为NULL。
* 输出参数:k=12、w=8、t1=15000ms、t2=10000ms、t3=20000ms。
* 返回值:无。
* 说明:本函数只复制默认值,不创建定时器;连接调度层可在初始化后按需改写。
*/
extern void IEC104_Link_Config_Default(IEC104_LinkConfig_t *config);
/**
* 适用端:控制站与被控站,由role参数固定当前连接的本端角色。
* 功能:为新连接初始化链路状态。
* 输入参数:state——待初始化的状态对象;role——CONTROLLING或CONTROLLED。
* 输出参数:成功时写入role,清零序号和确认快照,数据传输置STOPPED,
* 启停过程、S确认和TESTFR置IDLE。
* 返回值:1表示初始化成功;0表示state为NULL或role非法,此时不修改状态。
* 说明:仅初始化链路算法状态,连接配置由Config_Default单独初始化。
* 新连接处理任何链路事件前须初始化成功,不要求在TCP建连成功后才调用。
* 本模块未实现连接生命周期管理;旧事件隔离和状态内存安全复用由接入方负责。
*/
extern int IEC104_Link_State_Init(IEC104_LinkState_t *state,
IEC104_LinkRole_t role);
/**
* 功能:校验完整链路状态并读取I帧发送进度,不修改链路。
* 输入参数:state——本连接的链路状态。
* 输出参数:progress——成功时写入数值快照;失败时保持原值,不得与state重叠。
* 返回值:1表示读取成功;0表示指针或链路状态非法,不是链路事件结果。
* 说明:快照只表示调用时的进度,不预留序号,不证明TCP可用或事件属于本连接。
* 同一连接须串行调用;跨模块核对前须完成对应的Prepare/Commit、
* Complete/Commit_Send_Completion或Handle/原ASDU确认释放整个步骤。
*/
extern int IEC104_Link_Get_Send_Progress(
const IEC104_LinkState_t *state, IEC104_IFrameSendProgress_t *progress);
/**
* 功能:判断链路是否满足新连接绑定所需的初始状态条件,不修改状态。
* 输入参数:state——待检查链路,允许NULL。
* 输出参数:无。
* 返回值:1表示状态合法、序号与确认位置为0、STOPPED且各过程空闲;否则0。
* 说明:由Link维护初始状态规则;返回1不证明TCP为新连接,也不能用于故障恢复。
*/
extern int IEC104_Link_Is_Initial_State(const IEC104_LinkState_t *state);
/**
* 适用端:控制站与被控站。
* 功能:复位链路序号、S确认、启停和探测状态,清除待完成过程的算法记录。
* 输入参数:state——链路状态对象;允许为NULL。
* 输出参数:state——保留有效角色,序号及S快照清零,回到STOPPED/IDLE;
* S确认和TESTFR置IDLE。
* 返回值:无。
* 说明:本接口只复位链路算法字段,不能用于致命故障后在原连接上继续通信。
* 外部接入要求:调用方负责关闭故障连接,并防止旧事件提交到重新初始化后的状态;
* 对应连接管理、任务调度和定时器管理当前未实现,不属于本接口行为。
* 新连接处理链路事件前须用State_Init成功初始化完整状态并指定角色。
* 原角色非法时规范化为INVALID,不会自动选择角色;须用State_Init重新初始化。
* Reset会读取原role,不能对未初始化的自动变量调用本接口。
*/
extern void IEC104_Link_State_Reset(IEC104_LinkState_t *state);
/**
* 适用端:控制站与被控站。
* 功能:检查接收到的I帧序号,并在合法时更新接收和发送确认状态。
* 输入参数:state——链路状态;apci——已经通过基础格式检查的I帧APCI。
* 输出参数:成功时更新state->vr和state->va;未确认数量由acked_nr到vr的距离推导。
* 返回值:OK表示接收方向已经开放且序号合法并完成更新;FATAL表示接收方向未开放,
* 或参数、帧类型、状态、序号非法。
* 说明:控制站收到STARTDT_CON前禁止接收I帧;被控站受理START后立即允许接收。
* 被控站STOP受理后拒绝新I帧并返回FATAL;后到START成功受理后重新开放。
* 本端新I帧和S可在START_CON之后排队,实际发送不得越过已有控制帧。
* 控制站停止期间接收合法I帧后,上层须立即安排S帧。
* 本函数成功时只推进V(A)/V(R)。
* 捎带N(R)不得越过sent_vs;对应I帧的Complete须先于本次Handle提交。
*/
extern IEC104_LinkResult_t IEC104_Link_Handle_I_Frame(
IEC104_LinkState_t *state, const IEC104_ApciInfo_t *apci);
/**
* 适用端:控制站与被控站。
* 功能:检查接收到的S帧确认号,并在合法时更新V(A)。
* 输入参数:state——链路状态;apci——已经通过基础格式检查的S帧APCI。
* 输出参数:成功时将state->va更新为apci->receive_number。
* 返回值:OK表示接收阶段和确认号合法并完成更新;其他情况为FATAL且状态不变。
* 说明:STARTED时允许S;被控站STOPPED/STOP_DRAINING时仍接收ACK。
* 被控站STOPPED/IDLE及控制站等待STARTDT_CON时拒绝S帧。
* S帧接收只更新va,不提交发送完成边界sent_vs,也不推进接收确认位置acked_nr。
* N(R)不得越过sent_vs;异步接入须先提交对应发送结果,再分派相关ACK。
*/
extern IEC104_LinkResult_t IEC104_Link_Handle_S_Frame(
IEC104_LinkState_t *state, const IEC104_ApciInfo_t *apci);
/* 只读检查新I帧的启停、k窗口及序号边界,与Prepare_I_Frame共用规划逻辑。
* 返回1可准备,0当前门控/窗口阻塞,-1参数或状态非法;不编码、不预留N(S)。 */
extern int IEC104_Link_Can_Prepare_I_Frame(const IEC104_LinkState_t *state, uint16_t k);
/**
* 适用端:控制站与被控站;仅在本端数据传输方向允许时生成。
* 功能:检查数据传输状态和k窗口,构造I帧并在编码成功后预留其N(S);同连接调用须串行。
* 输入参数:state——链路状态;k——最大发送未确认I帧数,范围1..32767;
* asdu/asdu_len——完整ASDU及长度;frame/capacity——输出缓冲及容量;
* tx——由调用方随发送队列节点保存的序号和长度快照。
* 输出参数:成功时写入完整I帧和tx,并将V(S)循环加1。
* 返回值:成功返回完整APDU长度;0表示当前方向/阶段不允许、k窗口已满,
* 或新增预留将使未完成区间占满序号环;
* -1表示参数或链路状态非法。返回0/-1时不修改state、frame和tx。
* 说明:成功返回表示N(S)已经不可撤销地提交,报文必须进入该连接的严格FIFO队列;
* 两端STARTED/IDLE可预留;控制站还可在START_ACT_SEND_PENDING
* 和START_CON_WAITING预留,新I帧必须排在本次STARTDT_ACT之后。
* 调用方须先取得队列容量,将成功生成的ACT入队后再Prepare I帧;所有
* I/S/U帧在同一FIFO发送,先提交ACT完成再提交其后I帧完成。ACT失败须
* 丢弃整条连接及其队列,不能继续发送排在它后面的I帧。
* 后续发送失败必须断连,不得回滚V(S)。最终发送结果必须连同原tx传给
* IEC104_Link_Complete_I_Send(),完成阶段不能再次推进V(S)。
* 预留/排队时不启动等待确认的t1;发送层须自行限制排队和发送等待时间,
* 每次成功Prepare后恰好报告一次Complete,发送失败/超时也须报告失败长度。
*/
extern int IEC104_Link_Prepare_I_Frame(IEC104_LinkState_t *state,
uint16_t k,
const uint8_t *asdu,
uint16_t asdu_len,
uint8_t *frame,
uint16_t capacity,
IEC104_IFrameTx_t *tx);
/**
* 适用端:控制站与被控站。
* 功能:提交一帧由Prepare_I_Frame()生成的I帧最终本地发送结果。
* 输入参数:state——链路状态;tx——构帧成功时由调用方随队列节点保存的快照;
* sent_len——最终累计成功发送的字节数,等于tx->frame_length才算成功;发送失败也可传-1。
* 输出参数:完整发送、FIFO顺序及N(R)快照合法时更新acked_nr和sent_vs;
* 失败时均不推进,不回滚Prepare阶段的V(S)。
* 返回值:OK表示完整发送并成功提交;FATAL表示参数/状态非法、长度不符或
* 无待完成帧、完成顺序错误、N(R)快照失效。本接口没有IGNORED结果。
* 说明:Send限定为本地发送提交;返回OK不表示对端已经确认本帧。
* 部分写入尚在继续时不要调用;发送失败后上层连接管理器须断连。
* 本连接I/S完成事件须按发送FIFO恰好提交一次;本接口验证I帧N(S)==sent_vs。
* 发送层在整帧成功交给传输层时记录单调时间sent_at_ms并随完成事件传递;
* 不得用延迟执行回调时的当前时间代替实际完成时间。本接口不读取时钟。
* 成功后该帧进入等待ACK的区间;接收处理不得先于本次完成提交确认该帧。
* 完整APDU在传输层不再借用且本地完成已提交后可释放;等待ACK期间仍须保留
* 帧身份、序号快照、原始发送时间和业务关联,供确认、t1和故障回收使用。
* 业务原文的保留和重连恢复策略由发送管理层决定,链路完成不处理原文队列。
* 新连接不复用旧APDU、协议序号或完成事件。
*/
extern IEC104_LinkResult_t IEC104_Link_Complete_I_Send(
IEC104_LinkState_t *state, const IEC104_IFrameTx_t *tx, int sent_len);
/**
* 适用端:控制站与被控站。
* 功能:判断最早已完成发送但尚未被对端确认的I帧是否达到t1超时。
* 输入参数:state——链路状态;elapsed_ms——当前最早已完成未确认帧自整帧成功
* 交给传输层后经过的毫秒数,由调用方以该帧原始sent_at_ms计算;
* t1_ms——t1配置值,必须大于0。
* 输出参数:无,不修改链路状态。
* 返回值:1表示存在已完成未确认I帧且已经超时;0表示无此类帧或尚未超时;
* -1表示参数或链路序号状态非法。
* 说明:Complete_I_Send成功后,以及Handle_I/S_Frame成功推进V(A)后,调用方须
* 在同一串行调度区间重新选取最早已完成未确认帧;不存在则取消t1。
* 存在时以该帧原始发送完成时间作为起点;部分ACK后不可从当前时刻重计,
* 后续I帧Complete也不能延长前面未确认帧的截止时间。重复ACK不重置起点;
* 仅排队的帧不受此t1保护,超前于本地完成位置的ACK应被拒绝。
* 定时器只负责唤醒;回调必须校验连接/计时对象、重算当前帧elapsed_ms,
* 再调用本函数;只有返回1才按I帧确认超时断连。返回-1按非法状态处理。
* 本函数不保存时钟;使用宽位单调时间作差,超过uint32_t时饱和而非截断。
*/
extern int IEC104_Link_T1_I_Ack_Expired(
const IEC104_LinkState_t *state,
uint32_t elapsed_ms, uint32_t t1_ms);
/**
* 适用端:控制站与被控站。
* 功能:按w门限、显式立即确认或STOPDT排空要求生成一份普通S帧,并保存其N(R)快照。
* 输入参数:state——链路状态;w——接收确认门限,范围1..32767;
* immediate——非0跳过w门限,仍受启停状态和已有S在途限制;response——输出缓冲;
* capacity——缓冲实际容量,至少6字节。
* 输出参数:成功时response写入S帧,state转SEND_PENDING并保存构帧时V(R)。
* 返回值:6表示生成新S帧;0表示当前启停阶段不允许、未达到门限、
* 没有待确认数据或已有S帧在途;
* -1表示参数或状态非法。
* 说明:处于STOP_REQUESTED、STOP_ACT_SEND_PENDING、STOP_CON_WAITING或STOP_DRAINING时,
* 有待确认数据且无S在途时,即使immediate为0且未达到w,也会生成确认。生成不等于发送成功;
* 同一连接的I/S报文须按上线顺序串行发送,不能让较旧N(R)晚于较新N(R)上线。
* 被控站START受理后可准备S并排在CON之后;停用IDLE下不再准备普通S。
* 原接收时间和在途S快照不因启停改变。
*/
extern int IEC104_Link_Prepare_S_Ack(IEC104_LinkState_t *state,
uint16_t w, int immediate,
uint8_t *response, uint16_t capacity);
/**
* 适用端:控制站与被控站。
* 功能:提交公共S确认帧的最终发送结果,普通确认与两端STOPDT流程共用。
* 输入参数:state——链路状态;sent_len——最终累计发送字节数,恰好6表示成功。
* 输出参数:成功时用保存的N(R)推进acked_nr并回IDLE;发送失败或快照失效时
* 清除在途S帧且不推进确认位置,由上层断开连接。
* 返回值:OK表示完整发送并成功提交;IGNORED表示没有S帧等待完成;
* FATAL表示参数/状态非法、发送失败或快照失效。
* 说明:发送期间新收到的I帧仍保留在新acked_nr到V(R)之间;新连接初始化后必须
* 丢弃旧连接的完成事件。调用方必须与具体枚举值比较。
* 状态合法且无S在途时先返回IGNORED,不检查sent_len;状态非法则直接FATAL。
* S完成保留当前启停状态。这里的回IDLE仅指s_ack_state,不是dt_procedure。
* 普通确认及两端STOPDT中的S帧均由本接口完成。本接口不接收报文身份,
* 须按FIFO节点恰好分派一次。
*/
extern IEC104_LinkResult_t IEC104_Link_Complete_S_Ack_Send(
IEC104_LinkState_t *state, int sent_len);
/**
* 适用端:控制站与被控站。
* 功能:在最早已接收但本端尚未确认的I帧达到t2等待时间后生成S确认帧。
* 输入参数:state——链路状态;elapsed_ms——该接收帧等待本端确认的毫秒数;
* t2_ms——t2配置值,必须大于0;response——输出缓冲;
* capacity——缓冲实际容量,至少6字节。
* 输出参数:到期且可生成时写入S帧,并由普通S确认流程保存N(R)快照。
* 返回值:6表示生成S帧;0表示尚未到期、当前启停阶段不允许、
* 没有待确认I帧或已有S帧在途;
* -1表示参数或状态非法。
* 说明:本函数不读取系统时钟,也不维护计时起点;调用方必须使用单调时钟计算
* elapsed_ms。生成后仍由IEC104_Link_Complete_S_Ack_Send()提交最终发送结果。
* 即使尚未到期,也会完整校验参数和状态,非法输入返回-1。
* 启停及其他控制帧不重置t2,S由FIFO保证发送顺序。
*/
extern int IEC104_Link_Prepare_T2_Ack(IEC104_LinkState_t *state,
uint32_t elapsed_ms, uint32_t t2_ms,
uint8_t *response, uint16_t capacity);
/**
* 适用端:控制站与被控站;收到对端TESTFR_ACT时使用。
* 功能:独立处理已通过APCI解析的TESTFR_ACT,生成TESTFR_CON应答。
* 输入参数:apci——U帧且功能码为TESTFR_ACT;response——应答输出缓冲;
* capacity——缓冲实际容量,至少6字节。
* 输出参数:response——应答为68 04 83 00 00 00。
* 返回值:OK表示生成固定6字节应答;FATAL表示参数或报文非法。
* 说明:无状态接口,不修改启停状态、链路序号或I帧确认计数;
* 只生成应答,不执行发送,也不处理主动心跳及超时。
* TESTFR_CON发送没有对应链路Complete接口,发送失败由上层断连;不能
* 调用Complete_Testfr_Act_Send提交该应答,也不能据此结束本端主动探测。
*/
extern IEC104_LinkResult_t IEC104_Link_Handle_Testfr_Act(
const IEC104_ApciInfo_t *apci, uint8_t *response, uint16_t capacity);
/**
* 适用端:控制站与被控站。
* 功能:独立生成主动探测请求TESTFR_ACT,并标记等待最终发送结果。
* 输入参数:state——链路状态;request——请求输出缓冲;capacity——实际容量,至少6字节。
* 输出参数:request——写入68 04 43 00 00 00;state——探测转为ACT_SEND_PENDING。
* 返回值:6表示生成新请求;0表示已有探测进行中;-1表示参数或链路状态非法。
* 返回0或-1时不修改状态和输出缓冲。
* 说明:不执行网络发送;待发送完成和等待CON期间均不重复生成请求。
* 不受启停状态限制,不修改启停状态、序号及接收确认位置。
* 每次成功返回6都会建立一次完成义务:发送层必须保证恰好调用一次
* Complete_Testfr_Act_Send();发送超时或失败也必须用非6的最终长度报告。
* ACT完整发送后先提交Complete,再分派收到的TESTFR_CON,与主动启停顺序一致。
*/
extern int IEC104_Link_Prepare_Testfr_Act(IEC104_LinkState_t *state,
uint8_t *request,
uint16_t capacity);
/**
* 适用端:控制站与被控站。
* 功能:在链路空闲达到t3后生成主动探测请求TESTFR_ACT。
* 输入参数:state——链路状态;idle_elapsed_ms——距最近链路活动的毫秒数;
* t3_ms——t3配置值,必须大于0;request——请求输出缓冲;
* capacity——实际容量,至少6字节。
* 输出参数:到期且当前没有主动探测时生成TESTFR_ACT,并进入ACT_SEND_PENDING。
* 返回值:6表示生成新请求;0表示尚未到期或已有主动探测;
* -1表示参数或链路状态非法。返回0或-1时不修改状态和输出缓冲。
* 说明:本函数不读取时钟,也不维护最近活动时间;连接层统一定义有效链路活动,
* 据此更新t3的单调计时起点并计算idle_elapsed_ms,不得重置正在等待CON的t1起点。
* 返回6只表示生成报文,尚未发送;发送结果仍由Complete_Testfr_Act_Send()提交。
* 成功生成后同样要求发送层恰好报告一次最终完成结果。
* 即使尚未到期,也会完整校验参数和状态,非法输入返回-1。
*/
extern int IEC104_Link_Prepare_T3_Testfr(IEC104_LinkState_t *state,
uint32_t idle_elapsed_ms,
uint32_t t3_ms,
uint8_t *request,
uint16_t capacity);
/**
* 适用端:控制站与被控站。
* 功能:记录主动TESTFR_ACT的最终发送结果,成功后开始等待TESTFR_CON。
* 输入参数:state——链路状态;sent_len——最终成功发送的累计字节数;负值也表示失败。
* 输出参数:有匹配ACT时,恰好6字节转CON_PENDING;其他长度结束本次探测并回IDLE。
* 返回值:OK表示ACT完整发送并开始等待CON;
* IGNORED表示没有待完成的ACT;
* FATAL表示状态非法或发送失败。
* 说明:部分写入仍在继续时不要调用;发送失败后上层须断连,不得在原连接重试。
* 同一连接串行调用;须先提交ACT完整发送结果,再分派收到的TESTFR_CON。
* 状态合法但无匹配ACT时先返回IGNORED,不检查sent_len,也不修改状态。
* 新连接初始化后丢弃旧连接的发送完成和接收事件;调用方必须与具体枚举值比较;
* 本接口不修改启停及序号状态,也不操作外部定时器。返回OK后,由连接层以
* 本次ACT实际完整发送时刻为等待CON的t1起点,不能用延迟回调处理时刻代替。
*/
extern IEC104_LinkResult_t IEC104_Link_Complete_Testfr_Act_Send(
IEC104_LinkState_t *state, int sent_len);
/**
* 适用端:控制站与被控站;收到对端TESTFR_CON时使用。
* 功能:处理已通过APCI解析且当前正在等待的TESTFR_CON。
* 输入参数:state——链路状态;apci——U帧且功能码为TESTFR_CON。
* 输出参数:仅CON_PENDING时回IDLE;非OK时不修改状态。
* 返回值:OK表示接受当前探测的确认;IGNORED表示当前未等待CON;
* FATAL表示参数、报文或链路状态非法。
* 说明:不生成应答,不修改启停状态、序号和确认位置;输入校验先于等待状态检查。
* ACT_SEND_PENDING时返回IGNORED且不缓存CON;调用方须先完成本ACT的Complete。
* 收到对端TESTFR_ACT时须另行调用Handle_Testfr_Act生成应答,不结束本端的确认等待。
* 返回OK后由连接层取消本轮等待计时;本接口不操作外部定时器。
*/
extern IEC104_LinkResult_t IEC104_Link_Handle_Testfr_Con(
IEC104_LinkState_t *state, const IEC104_ApciInfo_t *apci);
/**
* 适用端:控制站与被控站。
* 功能:判断主动TESTFR_ACT发送成功后等待TESTFR_CON是否达到t1超时。
* 输入参数:state——链路状态;elapsed_ms——距当前探测ACT实际完整发送的毫秒数;
* t1_ms——t1配置值,必须大于0。
* 输出参数:无,不修改链路状态。
* 返回值:1表示正在等待TESTFR_CON且已经超时;0表示未等待或尚未超时;
* -1表示参数或链路状态非法。
* 说明:Complete_Testfr_Act_Send()返回OK后,由连接层以本次ACT实际完整发送时刻
* 为单调计时起点,Handle_Testfr_Con()返回OK后由连接层取消本轮等待计时;
* 重复请求、无匹配事件或t3活动更新均不得重置t1起点。
* 连接层定时器只用作唤醒;回调须校验连接代次,并在连接串行调度中按当前
* 有效探测的起点重新计算elapsed_ms,再调用本函数,只有返回1才按t1超时断连。
* 同一连接的旧探测回调也可能晚到,不能沿用它携带的旧起点或时间差判断新探测。
* 本函数不识别探测轮次,不读时钟,也不操作外部定时器或关闭连接。
* 状态或t1_ms非法时先返回-1;合法时ACT_SEND_PENDING返回0,该状态表示本地
* 发送结果尚未提交,须先Complete再处理CON。发送层须限定排队和发送期限,
* 成功Prepare后恰好一次Complete,发送超时也以失败长度报告,不能静默丢弃完成事件。
*/
extern int IEC104_Link_T1_Testfr_Con_Expired(
const IEC104_LinkState_t *state,
uint32_t elapsed_ms, uint32_t t1_ms);
#ifdef __cplusplus
}
#endif
#endif /* IEC104_LINK_COMMON_H */