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