571 lines
36 KiB
C
571 lines
36 KiB
C
/**
|
||
* 公共链路类型与接口:初始化、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 */
|