112 lines
4.6 KiB
C
112 lines
4.6 KiB
C
/**
|
|
* 子站启停的受理语义:START立即激活,STOP立即停用并等待确认。
|
|
* CON是发送任务,完成时不回写启停状态;后到START可结束尚未生成CON的停止等待。
|
|
* 已生成的CON始终按FIFO完成;不暂存相反方向ACT,不重置序号,所有调用串行。
|
|
*/
|
|
#include "IEC104_Link_Slave_StartStop.h"
|
|
#include "IEC104_Link_Internal.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
/* 调用方先预留发送空间;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;
|
|
}
|