/** * 子站启停的受理语义:START立即激活,STOP立即停用并等待确认。 * CON是发送任务,完成时不回写启停状态;后到START可结束尚未生成CON的停止等待。 * 已生成的CON始终按FIFO完成;不暂存相反方向ACT,不重置序号,所有调用串行。 */ #include "IEC104_Link_Slave_StartStop.h" #include "IEC104_Link_Internal.h" #include /* 调用方先预留发送空间;OK受理START并生成一帧CON,非法输入不修改状态。 */ IEC104_LinkResult_t IEC104_Link_Handle_Startdt_Act( IEC104_LinkState_t *state, const IEC104_ApciInfo_t *apci, uint8_t *response, uint16_t capacity) { if (response == NULL || capacity < IEC104_APCI_LEN || !IEC104_Link_Role_Valid_Internal(state, IEC104_ROLE_CONTROLLED) || apci == NULL || apci->frame_type != IEC104_FRAME_TYPE_U || apci->u_function != IEC104_U_STARTDT_ACT) { return IEC104_LINK_RESULT_FATAL; } (void)IEC104_Build_Uframe(response, IEC104_U_STARTDT_CON); state->dt_state = IEC104_DT_STARTED; state->dt_procedure = IEC104_DT_PROC_IDLE; return IEC104_LINK_RESULT_OK; } /* CON可能属于后续STOP之前的请求;完成不能重新激活链路。 */ IEC104_LinkResult_t IEC104_Link_Complete_Startdt_Con_Send( IEC104_LinkState_t *state, int sent_len) { return IEC104_Link_Role_Valid_Internal(state, IEC104_ROLE_CONTROLLED) && sent_len == IEC104_APCI_LEN ? IEC104_LINK_RESULT_OK : IEC104_LINK_RESULT_FATAL; } /* 首个START_CON是否已写出不影响STOP受理;排空中的重复STOP不重启期限。 */ IEC104_LinkResult_t IEC104_Link_Handle_Stopdt_Act( IEC104_LinkState_t *state, const IEC104_ApciInfo_t *apci) { if (!IEC104_Link_Role_Valid_Internal(state, IEC104_ROLE_CONTROLLED) || apci == NULL || apci->frame_type != IEC104_FRAME_TYPE_U || apci->u_function != IEC104_U_STOPDT_ACT) { return IEC104_LINK_RESULT_FATAL; } if (state->dt_procedure == IEC104_DT_PROC_STOP_DRAINING) { return IEC104_LINK_RESULT_IGNORED; } state->dt_state = IEC104_DT_STOPPED; state->dt_procedure = IEC104_DT_PROC_STOP_DRAINING; return IEC104_LINK_RESULT_OK; } /* 覆盖全部接收数据的在途S已在FIFO中,可以先于CON排队,无须等实际写完。 */ static IEC104_StopdtPrepareResult_t Stopdt_Response_Status(const IEC104_LinkState_t *state) { if (state->dt_procedure != IEC104_DT_PROC_STOP_DRAINING) { return IEC104_STOPDT_NOT_ACTIVE; } if (state->s_ack_state == IEC104_S_ACK_SEND_PENDING) { if (state->s_ack_nr != state->vr) { return IEC104_STOPDT_WAIT_SEND; } } else if (IEC104_Link_Unconfirmed_Rx_Internal(state) > 0U) { return IEC104_STOPDT_FRAME_READY; } return state->va != state->vs ? IEC104_STOPDT_WAIT_PEER_ACK : IEC104_STOPDT_FRAME_READY; } int IEC104_Link_Can_Prepare_Stopdt_Response(const IEC104_LinkState_t *state) { if (!IEC104_Link_Role_Valid_Internal(state, IEC104_ROLE_CONTROLLED)) { return -1; } return Stopdt_Response_Status(state) == IEC104_STOPDT_FRAME_READY; } /* 先排S确认,全部已预留I帧获ACK后排STOP_CON;生成CON即结束协议排空状态。 */ IEC104_StopdtPrepareResult_t IEC104_Link_Prepare_Stopdt_Response( IEC104_LinkState_t *state, uint8_t *response, uint16_t capacity, IEC104_StopdtTx_t *tx) { IEC104_StopdtPrepareResult_t readiness; if (!IEC104_Link_Role_Valid_Internal(state, IEC104_ROLE_CONTROLLED) || response == NULL || capacity < IEC104_APCI_LEN || tx == NULL) { return IEC104_STOPDT_PREPARE_ERROR; } readiness = Stopdt_Response_Status(state); if (readiness != IEC104_STOPDT_FRAME_READY) { return readiness; } if (state->s_ack_state == IEC104_S_ACK_IDLE && IEC104_Link_Unconfirmed_Rx_Internal(state) > 0U) { if (IEC104_Link_Prepare_S_Ack_Internal(state, response, state->vr) != IEC104_APCI_LEN) { return IEC104_STOPDT_PREPARE_ERROR; } tx->frame_type = IEC104_STOPDT_FRAME_S_ACK; } else { (void)IEC104_Build_Uframe(response, IEC104_U_STOPDT_CON); state->dt_procedure = IEC104_DT_PROC_IDLE; tx->frame_type = IEC104_STOPDT_FRAME_CON; } tx->frame_length = IEC104_APCI_LEN; return IEC104_STOPDT_FRAME_READY; } /* 后到START可以已经激活链路,旧STOP_CON完成不得覆盖它。 */ IEC104_LinkResult_t IEC104_Link_Complete_Stopdt_Con_Send( IEC104_LinkState_t *state, int sent_len) { return IEC104_Link_Role_Valid_Internal(state, IEC104_ROLE_CONTROLLED) && sent_len == IEC104_APCI_LEN ? IEC104_LINK_RESULT_OK : IEC104_LINK_RESULT_FATAL; }