141 lines
11 KiB
C
141 lines
11 KiB
C
/*
|
||
* 104时钟同步(C_CS_NA_1):接收主站校时请求,帮助应用校准供SOE、日志等使用的设备时间。
|
||
* 本模块负责校验、时区换算、站内滞留补偿及ACT_CON;实际设时由应用提供的action完成。
|
||
* Handle_Event/Process不调用应用代码;Execute_Next每次至多同步执行一个action,不保存回调。
|
||
* 设备日历与协议单调计时分开:设置设备时间不应改变Net提供的单调毫秒基准。
|
||
* 所有接口与Slave在同一线程串行调用;模块内应答严格按请求顺序。
|
||
* 执行后的ACT_CON使用Try路径,不越过HIGH/NORMAL待发原文;确认只回显请求时标。
|
||
* 退出顺序:Cancel -> Slave_Close -> 读空并分派通知 -> Destroy -> Remove_Station -> Slave_Destroy。
|
||
*/
|
||
#ifndef IEC104_CLOCK_SYNCHRONIZATION_H
|
||
#define IEC104_CLOCK_SYNCHRONIZATION_H
|
||
|
||
#include "IEC104_Slave.h"
|
||
#include "IEC60870_Time.h"
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
typedef struct IEC104_ClockSynchronization IEC104_ClockSynchronization_t;
|
||
|
||
typedef struct {
|
||
int16_t master_utc_offset_minutes; /* 主站标准当地时间减UTC的分钟数,-1439..1439;默认480,不含SU。 */
|
||
uint32_t execute_timeout_ms; /* 受理至执行检查的期限,单位ms,默认15000;0禁用期限,仍检查时间范围。 */
|
||
} IEC104_ClockSynchronizationConfig_t;
|
||
|
||
/* 交给action的只读纯值请求,指针仅在本次回调期间有效。
|
||
* utc_ms/local_time已补偿受理至base_ms的等待;应用不再叠加时区或同一段等待。
|
||
* 不补偿网络、Slave通知FIFO及action内部耗时;base_ms不是硬件实际生效时刻。 */
|
||
typedef struct {
|
||
uint64_t generation, receive_serial; /* generation:原TCP会话代次;receive_serial:原I帧接收流水号。 */
|
||
uint64_t station_id; /* 定向请求的原站点注册编号,不是CA;广播为0,不绑定某个目标站。 */
|
||
uint16_t common_address; /* 请求原CA,广播保留65535;逐站确认的CA由模块另行填写。 */
|
||
uint8_t originator_address; /* 请求原OA,供应用识别发起方;本字段不是权限校验结果。 */
|
||
IEC60870_CP56Time2a_t master_time; /* 原CP56解码值,IV=0,保留主站日历和SU;未作时区换算及滞留补偿。 */
|
||
IEC60870_WallTime_t local_time; /* 对应base_ms的固定UTC+8标准日历,可直接交给Clock_Set或RTC适配。 */
|
||
uint64_t utc_ms; /* 对应base_ms的UTC纪元毫秒,自1970-01-01 00:00:00 UTC起算。 */
|
||
/* accepted_ms:Handle_Event受理时刻;base_ms:执行检查时刻。均为Net单调毫秒,允许为0。 */
|
||
uint64_t accepted_ms, base_ms;
|
||
} IEC104_ClockSynchronizationRequest_t;
|
||
|
||
/* 应用同步设时动作:context由Execute_Next原样传入,允许NULL;request为本次校验后的只读请求。
|
||
* true报告设置成功,false未报告成功;false不保证时钟未变,模块不提供硬件回滚。
|
||
* 须短时完成,不保留request指针等待异步执行;权限、允许回拨幅度和设备操作由应用判断。
|
||
* 不得重入本模块的修改入口或推进Slave事件循环;回调内仅允许查询本模块Get_Status。
|
||
* 每条通过执行检查的新请求各调用一次,不按内容去重;主站重发旧时标仍可能再次回拨。 */
|
||
typedef bool (*IEC104_ClockSynchronizationAction_t)(void *context,
|
||
const IEC104_ClockSynchronizationRequest_t *request);
|
||
|
||
typedef enum {
|
||
IEC104_CLOCK_SYNCHRONIZATION_EVENT_ERROR = -1, /* 参数、事件归属、重入或内部准备失败。 */
|
||
IEC104_CLOCK_SYNCHRONIZATION_EVENT_IGNORED = 0, /* 非103 I帧或本模块当前不能接手的通知。 */
|
||
IEC104_CLOCK_SYNCHRONIZATION_EVENT_HANDLED = 1 /* 含拒绝和丢新,不表示已应答。 */
|
||
} IEC104_ClockSynchronizationEventResult_t;
|
||
|
||
typedef enum {
|
||
IEC104_CLOCK_SYNCHRONIZATION_EXECUTE_ERROR = -1, /* 参数、重入或服务状态查询失败;未调用action。 */
|
||
IEC104_CLOCK_SYNCHRONIZATION_EXECUTE_EMPTY = 0, /* 无可执行请求;仍可能有待提交应答。 */
|
||
IEC104_CLOCK_SYNCHRONIZATION_EXECUTE_WAIT = 1, /* 先处理未读Slave通知。 */
|
||
IEC104_CLOCK_SYNCHRONIZATION_EXECUTE_OK = 2 /* 已调用一次动作;确认可能因后续STOP/故障取消。 */
|
||
} IEC104_ClockSynchronizationExecuteResult_t;
|
||
|
||
/* 只读调度快照;计数从Create起累计,Cancel及连接启停不清零,不代表对端已经收到应答。 */
|
||
typedef struct {
|
||
uint64_t generation; /* 已分派给模块的会话代次;消费DISCONNECTED后为0。 */
|
||
bool active; /* 模块根据已分派通知及推进结果维护的激活状态,不替代当前网络状态查询。 */
|
||
bool events_pending; /* Slave尚有未读通知;应先NextEvent并按FIFO分派,再执行或续发。 */
|
||
bool execute_pending; /* 仍有占槽的待执行请求;不保证当前会话、期限已允许调用action。 */
|
||
bool confirm_pending; /* action已开始且确认尚未全部交接,含回调期间;不含仅校验失败的回复。 */
|
||
bool need_process; /* 当前有状态清理、到期或待尝试回复;false仍不能跳过每轮Process的WAIT重试。 */
|
||
bool timer_active; /* 存在尚未执行且启用了执行期限的请求。 */
|
||
uint32_t timeout_remaining_ms; /* 所有执行期限的最小剩余ms;到期为0,无计时任务时也为0。 */
|
||
unsigned pending_requests; /* 占用任务槽数,含待执行、回调中及待回复;一条广播始终只占一槽。 */
|
||
/* accepted:合法且成功入槽的请求数,含后来超时/取消者。
|
||
* executed:action已返回的次数;synchronized:其中返回true的次数。 */
|
||
unsigned long accepted, executed, synchronized;
|
||
/* submitted:发送层返回OK的ASDU数,广播逐目标计数;negative_submitted为其中P/N=1的数量。 */
|
||
unsigned long submitted, negative_submitted;
|
||
/* rejected:受理校验拒绝数,含无法应答的畸形请求,不含后续超时或action失败。
|
||
* waits:发送返回WAIT的次数,重试可重复累计;不计等待Slave通知的次数。
|
||
* cancelled:取消的占槽请求数,广播部分确认后取消也只计一次,不保证设备时间未变。
|
||
* overloads/dropped_requests:槽满丢新的次数/请求数,同时增加;对象数错误/对象截短只计rejected。
|
||
* timeouts:启用期限时,执行前到期或单调倒退而转否定的请求数。
|
||
* time_errors:执行检查的换算/范围失败,以及禁用期限时的单调倒退,不含受理校验拒绝。 */
|
||
unsigned long rejected, waits, cancelled, overloads, dropped_requests, timeouts, time_errors;
|
||
} IEC104_ClockSynchronizationStatus_t;
|
||
|
||
/* 向config写默认源时区480分钟、执行期限15000ms;config为NULL时无操作。
|
||
* 只填写配置,不创建实例;调用方可修改后交给Create。 */
|
||
void IEC104_ClockSynchronization_Config_Default(IEC104_ClockSynchronizationConfig_t *config);
|
||
/* 为有效slave创建独立校时实例;config须非NULL,按值复制,返回后不再借用配置指针。
|
||
* slave由应用拥有,寿命须覆盖本实例;可在Slave_Init前创建,但必须早于消费该服务的通知。
|
||
* 每服务只允许一个实例,按共用站点表路由;不分配堆内存、不建立监听、不保存应用action。
|
||
* 成功返回池内句柄;参数/配置非法、重复绑定或池/身份资源耗尽返回NULL。
|
||
* IEC104_CLOCK_SYNCHRONIZATION_CAPACITY默认等于TCP服务容量;
|
||
* IEC104_CLOCK_SYNCHRONIZATION_TASK_CAPACITY默认4,限定每实例的任务槽数。 */
|
||
IEC104_ClockSynchronization_t *IEC104_ClockSynchronization_Create(IEC104_Slave_t *slave,
|
||
const IEC104_ClockSynchronizationConfig_t *config);
|
||
/* 归还self占用的静态池槽;true成功,成功后必须停止使用旧句柄。
|
||
* 句柄无效、仍有占槽任务或处于action回调中返回false;不隐式Cancel,也不关闭Slave。 */
|
||
bool IEC104_ClockSynchronization_Destroy(IEC104_ClockSynchronization_t *self);
|
||
/* 取消self的全部占槽任务并归还站点引用/快照,每条请求增加一次cancelled。
|
||
* 不停用连接,可继续接手后续请求;不撤回已交接帧、不回滚设备时间。
|
||
* 无返回值;无效句柄或action回调中调用均无操作。 */
|
||
void IEC104_ClockSynchronization_Cancel(IEC104_ClockSynchronization_t *self);
|
||
/* 将event按Slave FIFO次序交给self;event须来自所属Slave的NextEvent或合法Copy_Event副本。
|
||
* 所有连接/启停通知都须分派,103 I帧由本模块接手;不修改输入事件,不调用action。
|
||
* 合法请求保存为待执行任务;错误回复可当场提交。COT/CA/IOA优先回45/46/47,
|
||
* 其余可对应的非法请求否定7;不能保留唯一完整对象时仅计拒绝,槽满丢新并计数、不断链。
|
||
* 广播只执行一次动作,按受理时的快照逐站确认;已删除的待提交目标跳过,新注册站不参与。
|
||
* 返回HANDLED包含保存、拒绝、丢新和状态通知处理,不表示已应答;IGNORED表示未接手;
|
||
* ERROR表示参数/归属/重入或内部准备失败,不可作为IGNORED继续生成兜底应答。 */
|
||
IEC104_ClockSynchronizationEventResult_t IEC104_ClockSynchronization_Handle_Event(
|
||
IEC104_ClockSynchronization_t *self, const IEC104_SlaveEvent_t *event);
|
||
/* 为self有界推进执行期限及队首回复,不调用action;须在每轮网络推进、通知分派后调用。
|
||
* true表示完成本轮检查,可能仍在等待、已取消任务或没有任务,不表示应答成功。
|
||
* 参数、重入、查询或组包错误返回false。发送ERROR/FATAL取消任务后返回true,
|
||
* 正常STOP待通知的ERROR先让出;应用继续消费Slave通知处理后续断线/启停。
|
||
* 即使need_process为false也须每轮调用,以重试发送WAIT;不能以忙循环代替网络推进。 */
|
||
bool IEC104_ClockSynchronization_Process(IEC104_ClockSynchronization_t *self);
|
||
/* 为self执行最早的待执行请求:action须非NULL,context原样传给它,本函数不保存两者。
|
||
* 先检查会话、未读通知、期限及补偿范围;每次至多调用一次action,过期请求只转为否定回复。
|
||
* 可越过较早的待回复任务执行后续请求,但确认仍按模块内请求顺序提交,不插队。
|
||
* OK表示action已经返回,可能报告失败,确认也可能待发或被后续STOP/故障取消;
|
||
* WAIT表示先处理Slave通知;EMPTY表示已无可执行请求,仍可能有待回复任务;
|
||
* ERROR为参数、重入或服务查询失败。WAIT/EMPTY/ERROR均未调用action。
|
||
* 动作开始后不再判该任务的执行期限;确认发送WAIT只重试确认,绝不重复动作。 */
|
||
IEC104_ClockSynchronizationExecuteResult_t IEC104_ClockSynchronization_Execute_Next(
|
||
IEC104_ClockSynchronization_t *self, IEC104_ClockSynchronizationAction_t action, void *context);
|
||
/* 将self的当前只读快照写入非NULL的status;true成功,句柄/参数或服务查询失败返回false且不改输出。
|
||
* 可在action回调内查询,不推进任务、不预留发送资源;正在执行的任务不计期限,confirm_pending为true。
|
||
* 执行后的确认走Try,已有HIGH/NORMAL待发内容会阻止提交;持续发布可能推迟确认。
|
||
* 需要确认先于新的带时标上报时,由发布方在confirm_pending期间暂停此类新上报并继续推进网络。 */
|
||
bool IEC104_ClockSynchronization_Get_Status(const IEC104_ClockSynchronization_t *self,
|
||
IEC104_ClockSynchronizationStatus_t *status);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif /* IEC104_CLOCK_SYNCHRONIZATION_H */
|