203 lines
10 KiB
Plaintext
203 lines
10 KiB
Plaintext
/*
|
||
* 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 */
|