107 lines
5.9 KiB
C
107 lines
5.9 KiB
C
/*
|
||
* IEC 60870-5-101/104 共用时间源接口:读取当前日历、设置实际时钟。
|
||
* 读写日历统一采用固定UTC+8标准时间,年份1970..2099;CP56编码另限2000..2099。
|
||
* 此处的本地时间指固定UTC+8,不随Windows本地时区设置或夏令时变化。
|
||
* 时间源仅考虑Windows系统时钟和RTC,构建时二选一,业务直接调用Clock_Read/Clock_Set。
|
||
* Windows实现已提供;RTC目前只保留接入接口,具体芯片驱动暂不实现。
|
||
* 与IEC60870_Time的日期转换、CP56编解码分工;不自动接入ASDU或链路单调计时。
|
||
*/
|
||
#ifndef IEC60870_CLOCK_H
|
||
#define IEC60870_CLOCK_H
|
||
|
||
#include "IEC60870_Time.h"
|
||
|
||
/*
|
||
* 时间源编译选项:0=Windows系统时钟(默认,须在Windows构建),1=RTC预留接口。
|
||
* 这是编译时选择,不在运行期间切换;RTC模式不编译Windows读写代码。
|
||
* 选项须作用于IEC60870_Clock.c的编译,不能只在业务源文件中定义。
|
||
* RTC模式须由板级驱动实现下方的Clock_RTC_Read/Set;本模块不提供芯片驱动。
|
||
* 此选项与IEC60870_TIME_USE_PLATFORM的日期转换算法选择相互独立:
|
||
* 前者决定从哪里读取/设置当前时间,后者决定如何将UTC秒数转换为日历。
|
||
* RTC已提供约定的日历时,Clock读写入口不需要时间戳与日历之间的往返转换。
|
||
*/
|
||
#ifndef IEC60870_CLOCK_USE_RTC
|
||
#define IEC60870_CLOCK_USE_RTC 0
|
||
#endif
|
||
|
||
#if IEC60870_CLOCK_USE_RTC != 0 && IEC60870_CLOCK_USE_RTC != 1
|
||
#error "IEC60870_CLOCK_USE_RTC must be 0 (Windows) or 1 (RTC)"
|
||
#endif
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/*
|
||
* 时间源的读取结果。日历数值合法与时间质量分开表示。
|
||
* is_invalid=1仍须提供合法日历;没有可用日历时,平台读时函数应返回0。
|
||
* is_invalid=0仅表示未标记无效,不证明时钟已经校准或与外部时间源同步。
|
||
*/
|
||
typedef struct {
|
||
IEC60870_WallTime_t time; /* 固定UTC+8标准时间,ms为0..999,星期由公共入口重算 */
|
||
uint8_t is_invalid; /* 0=未标记无效,1=时间无效;可按业务约定传递给CP56的IV */
|
||
} IEC60870_ClockValue_t;
|
||
|
||
/*
|
||
* 构建:IEC60870_Clock.c + IEC60870_Time.c;Windows读写实现在Clock.c内部。
|
||
* 以后接RTC时,定义IEC60870_CLOCK_USE_RTC=1并加入实现下方RTC接口的板级驱动。
|
||
* 时间源由构建选择,公共接口不需要时钟对象、函数指针绑定或初始化。
|
||
* RTC等硬件仍须由应用按驱动要求初始化;同一时钟的读写由调用方串行执行。
|
||
* 本模块不提供设备锁,不进行动态内存分配。
|
||
*/
|
||
|
||
/**
|
||
* 功能:从构建时选定的时间源读取固定UTC+8标准时间,并校验日历和质量标志。
|
||
* 输入:value——接收结果的指针,不得为空。
|
||
* 输出:value——合法日历、星期(0=周日..6=周六)及源提供的is_invalid。
|
||
* 返回:1 取得格式合法的结果,is_invalid可能为1;0 参数非法、底层失败或结果非法。
|
||
* 说明:先读取局部变量,检查完成后才提交输出,失败不修改value。
|
||
* 局部结果的is_invalid初始为1,驱动应按实际状态明确填写0或1。
|
||
* 调用方须同时检查返回值和is_invalid,读取成功不等于时钟准确或已同步。
|
||
*/
|
||
int IEC60870_Clock_Read(IEC60870_ClockValue_t *value);
|
||
|
||
/**
|
||
* 功能:将固定UTC+8标准时间交给构建时选定的时间源设置实际时钟。
|
||
* 输入:local_time——非空,1970..2099的合法UTC+8标准时间;输入的weekday可忽略。
|
||
* 返回:1 底层报告设置成功;0 参数非法、平台不支持设时或底层未报告成功。
|
||
* 说明:先检查日历并重算星期,再将副本交给时间源实现,原始输入保持不变。
|
||
* Windows分支转换为UTC后调用系统设时接口;RTC分支直接将日历交给驱动。
|
||
* 本接口不接收IV/SU;校时报文须先通过CP56转换及业务校时条件检查。
|
||
* 不提供硬件写入回滚;失败时设备是否已有部分修改由具体驱动决定。
|
||
*/
|
||
int IEC60870_Clock_Set(const IEC60870_WallTime_t *local_time);
|
||
|
||
/*
|
||
* RTC预留接入接口:仅RTC模式需要由板级驱动实现,Windows模式不引用这两个符号。
|
||
* 业务调用上方公共入口,下面的函数由公共层同步调用,无需注册回调或绑定时钟对象。
|
||
* 不得保留输入/输出指针供返回后使用,也不能反向调用公共读写入口。
|
||
* 本模块仅声明,不提供空实现或默认成功结果;RTC硬件由应用按驱动要求初始化。
|
||
*/
|
||
|
||
/**
|
||
* 功能:由板级驱动读取RTC日历,供IEC60870_Clock_Read调用。
|
||
* 输入:value——公共层提供的非空局部结果,其is_invalid初始为1。
|
||
* 输出:value——一组一致的固定UTC+8日历和is_invalid=0/1;weekday由公共层重算。
|
||
* 返回:1 取得可供检查的日历;0 读取失败或没有可用日历。
|
||
* 说明:驱动负责寄存器格式转换及读取一致性,避免读到跨秒、跨日拼接的字段。
|
||
* RTC日历的时间基准由设备约定,驱动须保证输出为UTC+8;无毫秒能力时可填写ms=0。
|
||
* 即使日历数值合法,停振、掉电等状态仍可能使时间无效,须按实际状态填写质量。
|
||
*/
|
||
int IEC60870_Clock_RTC_Read(IEC60870_ClockValue_t *value);
|
||
|
||
/**
|
||
* 功能:由板级驱动设置RTC实际时钟,供IEC60870_Clock_Set调用。
|
||
* 输入:local_time——非空,公共层已校验并重算星期的UTC+8日历副本,只在调用期间有效。
|
||
* 返回:1 驱动报告设置成功;0 设置失败或设备不支持设置。
|
||
* 说明:驱动负责将日历转换为芯片要求的寄存器格式,按芯片能力处理毫秒。
|
||
* 只读驱动直接返回0;写入失败时可能已有部分寄存器改变,公共层不提供回滚。
|
||
*/
|
||
int IEC60870_Clock_RTC_Set(const IEC60870_WallTime_t *local_time);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* IEC60870_CLOCK_H */
|