/* * IEC104遥控:单命令45、双命令46,COT=6激活、COT=8撤销。 * 每个Slave至多一个实例,每实例至多一个未释放事务;其他业务仍独立推进。 * 静态存储、串行事件循环;仅Accept显式调用一次应用动作,不保存回调。 * 返回信息由Submit_Return_Info沿原连接提交,确认/返回信息/终止保持顺序。 */ #ifndef IEC104_COMMAND_H #define IEC104_COMMAND_H #include "IEC104_Slave.h" #ifdef __cplusplus extern "C" { #endif typedef struct IEC104_Command IEC104_Command_t; /* 供无副作用的类型常量使用;45..51映射bit0..6,58..64映射bit7..13。 * 范围外为0,不作非法移位。第一版Create只接受45、46两位。 */ #define IEC104_COMMAND_TYPE_BIT(type) ((uint16_t)( \ ((type) >= 45U && (type) <= 51U) ? (1U << ((type) - 45U)) : \ (((type) >= 58U && (type) <= 64U) ? (1U << ((type) - 51U)) : 0U))) /* 期限以Net单调时钟计算,等于边界即到期;0仅禁用时长限制,等待阶段遇到时钟倒退仍终结。 */ typedef struct { uint16_t type_mask; /* 默认45|46,不能为空,不接受本版不支持的位。 */ uint16_t select_required_mask; /* 默认45|46,必须是type_mask子集;清除对应位允许直接执行。 */ uint32_t select_timeout_ms; /* 选择保持,默认30000,不得为0。 */ uint32_t decision_timeout_ms; /* 工作事件生成至Accept/Reject,默认15000;0禁用。 */ uint32_t execute_timeout_ms; /* 动作STARTED至Report_Result,默认60000;0禁用。 */ bool send_act_term; /* 成功后发ACT_TERM,默认true。 */ bool act_term_on_failure; /* 默认false;true且send_act_term时失败也发COT=10、P/N=0。 */ } IEC104_CommandConfig_t; /* 纯值请求。state编码为单命令0/1、双命令1/2;具体操作含义由应用点表定义。 * accepted_ms为Handle_Event受理时刻,不是报文在网络上的实际到达时刻。 */ typedef struct { uint64_t generation, receive_serial; uint64_t station_id; uint16_t common_address; uint8_t originator_address, type_id; uint32_t ioa; bool is_select, selected; uint8_t state, qualifier; uint64_t accepted_ms; } IEC104_CommandRequest_t; typedef enum { IEC104_COMMAND_SELECT = 1, IEC104_COMMAND_EXECUTE, IEC104_COMMAND_FINISHED } IEC104_CommandEventType_t; typedef enum { IEC104_COMMAND_FINISH_NONE = 0, IEC104_COMMAND_FINISH_COMPLETED, IEC104_COMMAND_FINISH_EXECUTION_FAILED, IEC104_COMMAND_FINISH_REJECTED, IEC104_COMMAND_FINISH_ACTION_FAILED, IEC104_COMMAND_FINISH_MISMATCH, IEC104_COMMAND_FINISH_DEACTIVATED, IEC104_COMMAND_FINISH_SELECT_TIMEOUT, IEC104_COMMAND_FINISH_DECISION_TIMEOUT, IEC104_COMMAND_FINISH_EXECUTE_TIMEOUT, IEC104_COMMAND_FINISH_CANCELLED, IEC104_COMMAND_FINISH_STOPPED, IEC104_COMMAND_FINISH_DISCONNECTED, IEC104_COMMAND_FINISH_CONNECTION_CHANGED, IEC104_COMMAND_FINISH_SEND_ERROR, IEC104_COMMAND_FINISH_SERVICE_ERROR } IEC104_CommandFinishReason_t; /* 事件是可保存的纯值,应答须原样传回;调用方不能用修改request改变实际执行内容。 * 任何工作事件曾被取走的事务,恰好交付一次FINISHED;后者无需应答。 * 应用跨循环持有站点/context或异步动作时,应在首个工作事件时自行Acquire, * FINISHED清理且物理输出确已结束后Release,不能等读到FINISHED后才申请引用。 */ typedef struct { IEC104_CommandEventType_t type; uint64_t instance_id, transaction_id, event_serial; IEC104_CommandRequest_t request; IEC104_CommandFinishReason_t reason; bool select_effect, execute_effect; } IEC104_CommandEvent_t; typedef enum { IEC104_COMMAND_ACTION_NOT_STARTED = 0, /* 必须保证没有任何副作用。 */ IEC104_COMMAND_ACTION_STARTED, /* 选择生效或输出启动;输出结果另行报告。 */ IEC104_COMMAND_ACTION_FAILED /* 未报告启动成功,但可能已留下副作用。 */ } IEC104_CommandActionResult_t; /* 须短时返回;request只在本次调用有效,不得保存指针、推进Slave或发布上报。 * 回调期间仅可Get_Status/Get_Transaction;其他修改入口拒绝重入。 */ typedef IEC104_CommandActionResult_t (*IEC104_CommandAction_t)(void *context, const IEC104_CommandRequest_t *request); typedef enum { IEC104_COMMAND_RESULT_SUCCEEDED = 1, IEC104_COMMAND_RESULT_FAILED } IEC104_CommandResult_t; typedef enum { IEC104_COMMAND_REJECT_NEGATIVE = 1, IEC104_COMMAND_REJECT_UNKNOWN_IOA } IEC104_CommandRejectCause_t; typedef enum { IEC104_COMMAND_EVENT_ERROR = -1, IEC104_COMMAND_EVENT_IGNORED = 0, IEC104_COMMAND_EVENT_HANDLED = 1 } IEC104_CommandEventResult_t; typedef enum { IEC104_COMMAND_NEXT_ERROR = -1, IEC104_COMMAND_NEXT_EMPTY = 0, IEC104_COMMAND_NEXT_READY = 1 } IEC104_CommandNextResult_t; typedef enum { IEC104_COMMAND_REPLY_STALE = -2, IEC104_COMMAND_REPLY_ERROR = -1, IEC104_COMMAND_REPLY_WAIT = 0, IEC104_COMMAND_REPLY_OK = 1 } IEC104_CommandReplyResult_t; typedef enum { IEC104_COMMAND_PHASE_SELECT_WAIT = 1, IEC104_COMMAND_PHASE_SELECTED, IEC104_COMMAND_PHASE_EXECUTE_WAIT, IEC104_COMMAND_PHASE_EXECUTING, IEC104_COMMAND_PHASE_ENDED } IEC104_CommandPhase_t; typedef struct { bool active; /* 尚未ENDED;不是当前连接是否可操作的保证。 */ IEC104_CommandPhase_t phase; bool confirm_submitted; /* 当前工作请求的确认已交给发送层,不表示写完或ACK。 */ bool result_reported, completed, term_submitted; } IEC104_CommandTransactionInfo_t; /* 累计计数从Create起维护;查询不改变阶段、不做超时转换。 * busy包括待消费FINISHED和未交接的事务应答,不包含独立短应答。 * need_process不因发送WAIT持续置true;每轮网络推进后仍须Process重试。 */ typedef struct { uint64_t generation; bool active, events_pending, need_process, timer_active; bool busy; uint32_t timeout_remaining_ms; unsigned pending_replies, pending_events; unsigned long accepted, selected, executed, completed, execution_failed, action_failed; unsigned long submitted, negative_submitted, return_info_submitted, waits; unsigned long rejected, app_rejected, busy_rejected, overloads, dropped_requests, cancelled; unsigned long deactivated, mismatches, select_timeouts, decision_timeouts, execute_timeouts; unsigned long clock_errors; } IEC104_CommandStatus_t; void IEC104_Command_Config_Default(IEC104_CommandConfig_t *config); /* config按值复制,必须非NULL;slave寿命覆盖实例。创建早于消费Slave通知。 * 池容量IEC104_COMMAND_CAPACITY默认等于TCP服务容量;独立应答容量 * IEC104_COMMAND_REPLY_CAPACITY默认4。配置/归属非法、重复绑定或池耗尽返回NULL。 */ IEC104_Command_t *IEC104_Command_Create(IEC104_Slave_t *slave, const IEC104_CommandConfig_t *config); /* 事务槽、未读事件和全部独立应答槽均空才成功;不隐式Cancel/Close。 */ bool IEC104_Command_Destroy(IEC104_Command_t *self); /* 结束事务并保留欠应用的FINISHED;清空未提交应答,保持会话激活,不回滚动作。 * 回调中/无效句柄无操作。ENDED事务保持首次终结原因,不重复产生FINISHED。 */ void IEC104_Command_Cancel(IEC104_Command_t *self); /* 按Slave FIFO分派全部连接/启停通知;通知消费不受后续WAIT_EVENTS阻挡。 * 仅45/46 I帧接手;非法请求可否定或丢新计数,HANDLED不表示已应答。 */ IEC104_CommandEventResult_t IEC104_Command_Handle_Event(IEC104_Command_t *self, const IEC104_SlaveEvent_t *event); /* 有界处理期限和全局FIFO队首;不调用应用。true包含等待或已终结,false为服务/参数错误。 */ bool IEC104_Command_Process(IEC104_Command_t *self); /* READY才修改event。工作事件先检查会话/期限;已有FINISHED可在离线时读取。 * 最后FINISHED读取可能释放事务站点引用;应用自己的引用仍需自行归还。 */ IEC104_CommandNextResult_t IEC104_Command_NextEvent(IEC104_Command_t *self, IEC104_CommandEvent_t *event); /* OK仅表示工作事件已消费,动作最多执行一次,不表示动作成功或确认已交接。 * SELECT的action可为NULL,选择生效但select_effect=false;EXECUTE必须提供action。 * WAIT未消费,STALE不得重试,ERROR为参数/重入错误且未调用动作。 */ IEC104_CommandReplyResult_t IEC104_Command_Accept(IEC104_Command_t *self, const IEC104_CommandEvent_t *event, IEC104_CommandAction_t action, void *context); IEC104_CommandReplyResult_t IEC104_Command_Reject(IEC104_Command_t *self, const IEC104_CommandEvent_t *event, IEC104_CommandRejectCause_t cause); /* 以下三个仅接受启动成功的原EXECUTE事件。结果报告一次后冻结;重复报告ERROR。 * Report_Result可早于ACT_CON交接,OK即停止执行期限。 */ IEC104_CommandReplyResult_t IEC104_Command_Report_Result(IEC104_Command_t *self, const IEC104_CommandEvent_t *event, IEC104_CommandResult_t result); /* 监视类型1..21/30..40,COT=11或3,P/N=0,TEST/CA与命令一致;完整校验对象。 * 模块有更早待交应答、确认未交接、网络背压或未读通知时WAIT,不缓存ASDU、也不占排序位置。 * OK固定帧序,不可重交;Complete后仍待收尾时ERROR,事务已结束则STALE。 * 发送错误终结事务,不可重试旧ASDU。 */ IEC104_CommandReplyResult_t IEC104_Command_Submit_Return_Info(IEC104_Command_t *self, const IEC104_CommandEvent_t *event, const IEC60870_Asdu_t *asdu); /* 结果须已报告;OK立即关闭返回阶段、冻结终止策略,Process负责后续发送。 * 仍待收尾时重复调用ERROR,事务已结束则STALE;WAIT未消费。 * 失败配置发TERM时P/N=0表示流程结束,不能据此认定设备成功。 */ IEC104_CommandReplyResult_t IEC104_Command_Complete(IEC104_Command_t *self, const IEC104_CommandEvent_t *event); /* 可查询仍保留事务的任一已交付事件;ENDED返回active=false。 * 槽已回收/事件不属于事务时false且不改info,不保留历史事务。 */ bool IEC104_Command_Get_Transaction(const IEC104_Command_t *self, const IEC104_CommandEvent_t *event, IEC104_CommandTransactionInfo_t *info); bool IEC104_Command_Get_Status(const IEC104_Command_t *self, IEC104_CommandStatus_t *status); #ifdef __cplusplus } #endif #endif /* IEC104_COMMAND_H */