Files
STM32F4-Base/IEC60870-Slave/104/IEC104_Link_Slave_StartStop.c
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

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;
}