RTU_ALL_AI/release/inc/myDatacenter.h

559 lines
21 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file myDatacenter.h
* @brief 数据中心模块 — 纯 C 对外接口
* @details 信号注册/控制/查询 + 事件队列 + 异步执行 + 参数配置。
* 内部通过 libmy_xxhash 做 O(1) 哈希查找,
* 参数配置通过 libxml C 接口解耦。
* 对齐 RTU 原工程 libdatacenter v1 + v2 全部功能。
*/
#ifndef _MY_DATACENTER_H_
#define _MY_DATACENTER_H_
#include <stdint.h>
#include <stddef.h>
#include "xxhash.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ===== 地址/描述/模块/错误信息最大长度 ===== */
#define DC_SADDR_MAX_LEN 128
#define DC_DESC_MAX_LEN 256
#define DC_UNIT_MAX_LEN 32
#define DC_MODULE_MAX_LEN 64
#define DC_ERR_MSG_MAX_LEN 256
/* ===== 容量限制 ===== */
#define DC_MAX_CALLBACKS 16
#define DC_MAX_LINK_SADDRS 32
#define DC_MAX_DATA_ZONES 8
#define DC_MAX_PENDING 64
/** datacenter 自身模块标识 */
#define MODULE_DATACENTER "datacenter"
/* ===== 控制类型枚举 ===== */
typedef enum
{
DC_CTRL_NONE = 0, /**< 无控制 */
DC_CTRL_DIRECT = 1, /**< 直控(直接执行,无需选择-确认) */
DC_CTRL_SBO = 2 /**< 选控Select-Before-Operate 两阶段) */
} dc_ctrl_type_t;
/* ===== 控制步骤枚举 ===== */
typedef enum
{
DC_STEP_READY = 0, /**< 就绪/空闲 */
DC_STEP_SELECT = 1, /**< 选择SBO 第一步:锁住信号并暂存选择值) */
DC_STEP_DIRECT = 2, /**< 执行SBO 第二步确认写入,直控直接执行) */
DC_STEP_CANCEL = 3 /**< 取消(回退到 READY */
} dc_ctrl_step_t;
/* ===== 错误码枚举 ===== */
typedef enum
{
DC_OK = 0, /**< 成功 */
DC_ERR_PARAM = -1, /**< 参数错误NULL/越界) */
DC_ERR_NOTFOUND = -2, /**< 信号不存在 */
DC_ERR_TYPE = -3, /**< 数据类型不匹配 */
DC_ERR_STEP = -4, /**< SBO 步骤错误 */
DC_ERR_VAL = -5, /**< 值校验失败(越界/未变化) */
DC_ERR_TIMEOUT = -6, /**< 异步请求超时 */
DC_ERR_BUSY = -7, /**< 忙 */
DC_ERR_MEM = -8, /**< 内存不足 */
DC_ERR_FULL = -9, /**< 请求队列已满 */
DC_ERR_LOCKED = -10, /**< 已锁定 */
DC_ERR_EXISTS = -11, /**< 信号已存在(重复注册) */
DC_ERR_CANCEL = -12 /**< 异步请求已取消 */
} dc_error_t;
/* ===== 控制上下文 ===== */
typedef struct
{
uint8_t step; /**< 当前控制步骤dc_ctrl_step_t */
uint8_t type; /**< 控制类型dc_ctrl_type_t */
uint8_t data_type; /**< 数据类型DATA_TYPE_* */
uint8_t reserved; /**< 保留 */
void *p_data; /**< SELECT 时暂存选择值DIRECT 时用于返校比对 */
} dc_ctrl_t;
/* ===== 信号参数元数据min/max/step/unit ===== */
typedef struct
{
float min; /**< 最小值 */
float max; /**< 最大值 */
float step; /**< 步长 */
char unit[DC_UNIT_MAX_LEN]; /**< 单位(如 "kV", "A", "Hz" */
} dc_param_meta_t;
/* ===== 回调函数类型 ===== */
/**
* @brief out 信号值变更回调延迟触发100ms 周期批量检测后调用)
* @param saddr 信号地址
* @param data_type 数据类型
* @param p_new 新值指针
* @param p_old 旧值指针
*/
typedef void (*dc_out_change_cb_t)(const char *saddr, uint8_t data_type,
const void *p_new, const void *p_old);
/**
* @brief yk/ao/param 信号控制变更回调(同步触发,控制场景即时响应)
* @param saddr 信号地址
* @param step 控制步骤
* @param data_type 数据类型
* @param zone 定值区号param 信号使用,其他为 0
* @param p_data 数据指针
*/
typedef void (*dc_signal_change_cb_t)(const char *saddr, dc_ctrl_step_t step,
uint8_t data_type, uint8_t zone,
const void *p_data);
/** @brief 事件队列消费回调 */
typedef void (*dc_queue_pop_cb_t)(void *p_data);
/**
* @brief 异步请求完成回调通知发起方模块A
* @param req_id 请求 ID
* @param result 结果码DC_OK / DC_ERR_*
* @param err 错误信息(成功时为空)
* @param arg 用户参数
*/
typedef void (*dc_async_result_cb_t)(uint32_t req_id, int result,
const char *err, void *arg);
/**
* @brief 异步执行回调datacenter 调用模块B执行实际操作
* @param req_id 请求 ID
* @param saddr 信号地址
* @param step 控制步骤
* @param data_type 数据类型
* @param zone 定值区号
* @param p_data 操作数据
* @param ctx 模块上下文
* @return 0 已接受(稍后通过 dc_set_result 返回结果),-1 拒绝
*/
typedef int (*dc_async_exec_cb_t)(uint32_t req_id, const char *saddr,
dc_ctrl_step_t step, uint8_t data_type,
uint8_t zone, const void *p_data, void *ctx);
/* ===== 内部数据结构(对调用方透明,通过 API 访问) ===== */
/** 回调条目 */
typedef struct
{
char module_id[DC_MODULE_MAX_LEN];
dc_out_change_cb_t out_cb;
dc_signal_change_cb_t ctrl_cb;
} dc_cb_entry_t;
/** 信号节点 */
typedef struct
{
uint32_t id;
XXH128_hash_t hash;
char saddr[DC_SADDR_MAX_LEN];
char desc[DC_DESC_MAX_LEN];
uint8_t data_type;
uint8_t ctrl_type;
void **vec_p_data;
int vec_p_data_count;
void *p_last_data;
char link_saddr[DC_SADDR_MAX_LEN];
char **link_saddrs;
int link_count;
dc_param_meta_t param;
dc_cb_entry_t cb_list[DC_MAX_CALLBACKS];
int cb_count;
char last_caller_module[DC_MODULE_MAX_LEN];
dc_async_exec_cb_t exec_cb;
void *module_ctx;
} dc_signal_t;
/* ==================================================================
* 模块生命周期
* ================================================================== */
/**
* @brief 初始化数据中心
* @param cfg_dir 配置文件目录(用于查找 param.xml
* @return DC_OK 成功,<0 失败
*/
int dc_init(const char *cfg_dir);
/** @brief 清理数据中心,释放所有信号和队列资源 */
void dc_cleanup(void);
/**
* @brief 每 100ms 周期调用
* @details out 信号变化检测 + 批量触发回调 + 事件队列弹出 + 异步超时检测
*/
void dc_run_100ms(void);
/**
* @brief 每 1000ms 周期调用
* @details 检测参数配置变更标志,有变更则写 self_param.xml
*/
void dc_run_1000ms(void);
/* ==================================================================
* Out 信号注册(遥测/遥信输出)
* ================================================================== */
/**
* @brief 注册输出信号
* @param saddr 信号地址(唯一标识)
* @param desc 信号描述
* @param data_type 数据类型DATA_TYPE_*
* @param p_data 数据指针
* @param module_id 模块标识(用于回路阻断)
* @return DC_OK 成功DC_ERR_EXISTS 重复注册
*/
int dc_signal_out(const char *saddr, const char *desc, uint8_t data_type,
void *p_data, const char *module_id);
/**
* @brief 注册输出信号并绑定变化回调
* @param cb 值变更回调延迟触发100ms 批量检测后调用)
*/
int dc_signal_out_with_callback(const char *saddr, const char *desc,
uint8_t data_type, void *p_data,
dc_out_change_cb_t cb, const char *module_id);
/**
* @brief 链接已有 out 信号,获取数据指针并注册回调
* @param p_data 输出out 信号的数据指针
*/
int dc_signal_out_link_with_callback(const char *saddr, void **p_data,
dc_out_change_cb_t cb, const char *module_id);
/**
* @brief 设置输出信号值标记脏100ms 后触发变更检测和延迟回调)
* @param module_id 调用方模块标识(自身不会被回调——回路阻断)
*/
int dc_set_out_signal_val(const char *saddr, const void *set_data,
const char *module_id);
/* ==================================================================
* In 信号注册(输入信号,链接到 out 信号的数据指针)
* ================================================================== */
/**
* @brief 注册输入信号并链接到输出信号
* @param link_saddr 要链接的 out 信号地址
* @param p_data 输出:被链接 out 信号的数据指针
*/
int dc_signal_in(const char *saddr, const char *desc,
const char *link_saddr, void **p_data, const char *module_id);
/**
* @brief 注册输入信号并绑定回调(回调挂在被链接的 out 信号上)
*/
int dc_signal_in_with_callback(const char *saddr, const char *desc,
const char *link_saddr, void **p_data,
dc_out_change_cb_t cb, const char *module_id);
/* ==================================================================
* YK 信号(遥控)
* ================================================================== */
/**
* @brief 注册遥控信号
* @param ctrl_type 控制类型DC_CTRL_DIRECT 直控 / DC_CTRL_SBO 选控)
* @param cb 控制变更回调(同步触发)
*/
int dc_signal_yk(const char *saddr, const char *desc,
uint8_t data_type, uint8_t ctrl_type, void *p_data,
dc_signal_change_cb_t cb, const char *module_id);
/** @brief 链接已有 YK 信号,获取数据指针并注册回调 */
int dc_signal_yk_link_with_callback(const char *saddr, void **p_data,
dc_signal_change_cb_t cb, const char *module_id);
/**
* @brief YK 同步设置(处理 SBO 流程SELECT→DIRECT/CANCEL
* @param step 控制步骤
* @param ctrl 控制上下文(进入时携带 type/data_type/p_data执行完毕后回写当前 step
* @param p_data 操作数据
*/
int dc_signal_yk_set_status(const char *saddr, dc_ctrl_step_t step,
dc_ctrl_t *ctrl, const void *p_data,
const char *module_id);
/**
* @brief YK 异步远程执行
* @param result_cb 结果回调
* @param timeout_ms 超时时间毫秒0 使用默认值
* @param request_id 输出:请求 ID
*/
int dc_yk_exec_async(const char *saddr, dc_ctrl_step_t step,
const dc_ctrl_t *ctrl, const void *p_data,
const char *module_id,
dc_async_result_cb_t result_cb, void *user_arg,
uint32_t timeout_ms, uint32_t *request_id);
/** @brief 设置 YK 异步执行结果模块B回调 */
int dc_yk_set_result(uint32_t request_id, int result_code, const char *err_msg);
/** @brief 取消 YK 异步请求 */
int dc_yk_cancel_async(uint32_t request_id);
/** @brief 注册 YK 异步执行回调模块B初始化时调用 */
int dc_yk_register_exec_cb(const char *saddr, dc_async_exec_cb_t exec_cb,
void *module_ctx);
/* ==================================================================
* AO 信号(模拟输出)
* ================================================================== */
/**
* @brief 注册 AO 信号
* @param ctrl_type 控制类型
* @param cb 控制变更回调(同步触发)
*/
int dc_signal_ao(const char *saddr, const char *desc,
uint8_t data_type, uint8_t ctrl_type, void *p_data,
dc_signal_change_cb_t cb, const char *module_id);
/** @brief 链接已有 AO 信号 */
int dc_signal_ao_link_with_callback(const char *saddr, void **p_data,
dc_signal_change_cb_t cb, const char *module_id);
/**
* @brief AO 同步设置SBO 流程 + 值校验)
* @details DIRECT 执行后 ctrl->step 自动复位到 READY
*/
int dc_signal_ao_set_val(const char *saddr, dc_ctrl_step_t step,
dc_ctrl_t *ctrl, const void *p_data,
const char *module_id);
/** @brief AO 无校验设置(跳过 SBO 流程和值校验,用于初始化恢复) */
int dc_signal_ao_set_val_without_check(const char *saddr, uint8_t data_type,
const void *p_data, const char *module_id);
/** @brief AO 异步执行 */
int dc_ao_exec_async(const char *saddr, dc_ctrl_step_t step,
const dc_ctrl_t *ctrl, const void *p_data,
const char *module_id,
dc_async_result_cb_t result_cb, void *user_arg,
uint32_t timeout_ms, uint32_t *request_id);
/** @brief 设置 AO 异步执行结果 */
int dc_ao_set_result(uint32_t request_id, int result_code, const char *err_msg);
/** @brief 取消 AO 异步请求 */
int dc_ao_cancel_async(uint32_t request_id);
/** @brief 注册 AO 异步执行回调 */
int dc_ao_register_exec_cb(const char *saddr, dc_async_exec_cb_t exec_cb,
void *module_ctx);
/* ==================================================================
* Param 信号(参数/定值,多定值区)
* ================================================================== */
/**
* @brief 注册参数信号
* @param p_data 数据指针数组(每个 zone 一个指针)
* @param num_zones 定值区数量
*/
int dc_signal_param(const char *saddr, const char *desc,
uint8_t data_type, uint8_t ctrl_type,
void **p_data, int num_zones,
dc_signal_change_cb_t cb, const char *module_id);
/** @brief 链接已有参数信号 */
int dc_signal_param_link_with_callback(const char *saddr, void **p_data,
int num_zones,
dc_signal_change_cb_t cb,
const char *module_id);
/**
* @brief Param 同步设置SBO + zone 值校验)
* @param setting_zone 定值区号0-based
*/
int dc_signal_param_set_val(const char *saddr, dc_ctrl_step_t step,
dc_ctrl_t *ctrl, uint8_t setting_zone,
const void *p_data, const char *module_id);
/** @brief Param 无校验设置 */
int dc_signal_param_set_val_without_check(const char *saddr, uint8_t data_type,
uint8_t setting_zone,
const void *p_data,
const char *module_id);
/** @brief Param 异步执行 */
int dc_param_exec_async(const char *saddr, dc_ctrl_step_t step,
const dc_ctrl_t *ctrl, uint8_t setting_zone,
const void *p_data, const char *module_id,
dc_async_result_cb_t result_cb, void *user_arg,
uint32_t timeout_ms, uint32_t *request_id);
/** @brief 设置 Param 异步执行结果 */
int dc_param_set_result(uint32_t request_id, int result_code,
const char *err_msg);
/** @brief 取消 Param 异步请求 */
int dc_param_cancel_async(uint32_t request_id);
/** @brief 注册 Param 异步执行回调 */
int dc_param_register_exec_cb(const char *saddr, dc_async_exec_cb_t exec_cb,
void *module_ctx);
/* ==================================================================
* 信号查询
* ================================================================== */
/** @brief 查询 out 信号信息 */
int dc_get_out_signal_info(const char *saddr, char *desc, int desc_len,
uint8_t *data_type, void **p_data);
/** @brief 查询 in 信号信息 */
int dc_get_in_signal_info(const char *saddr, char *desc, int desc_len,
uint8_t *data_type, void **p_data);
/** @brief 查询 AO 信号信息(含参数元数据) */
int dc_get_ao_signal_info(const char *saddr, char *desc, int desc_len,
uint8_t *data_type, dc_param_meta_t *p_meta,
uint8_t *ctrl_type, void **p_data);
/**
* @brief 查询 Param 信号信息(含多区数据指针列表)
* @param p_data_array 输出:数据指针数组(调用方提供缓冲区)
* @param p_count 输出:定值区数量
*/
int dc_get_param_signal_info(const char *saddr, char *desc, int desc_len,
uint8_t *data_type, dc_param_meta_t *p_meta,
uint8_t *ctrl_type,
void **p_data_array, int *p_count);
/** @brief 查询 YK 信号信息 */
int dc_get_yk_signal_info(const char *saddr, char *desc, int desc_len,
uint8_t *data_type, uint8_t *ctrl_type, void **p_data);
/** @brief 获取信号值的字符串表示 */
int dc_get_signal_val(const void *p_data, uint8_t data_type,
char *buf, int buf_len);
/**
* @brief 按类型统计信号数量
* @param type_str 类型字符串:"out"/"in"/"yk"/"ao"/"param"
* @return 信号数量
*/
int dc_get_signal_count(const char *type_str);
/**
* @brief 按类型和 ID 查询信号基本信息(供前端遍历)
* @param type_str "out"/"in"/"yk"/"ao"/"param"
* @param id 信号 ID
* @param saddr/saddr_len 输出:信号地址
* @param desc/desc_len 输出:描述
* @param data_type_str/type_str_len 输出:数据类型名称
* @param ctrl_type 输出:控制类型
* @param link_str/link_len 输出:链接信号的逗号分隔列表
*/
int dc_get_signal_info_by_id(const char *type_str, uint32_t id,
char *saddr, int saddr_len,
char *desc, int desc_len,
char *data_type_str, int type_str_len,
uint8_t *ctrl_type,
char *link_str, int link_len);
/* ==================================================================
* 事件/扰动/故障队列
* ================================================================== */
/** @brief SOE 事件入队 */
int dc_event_queue_push(void *p_soe);
/** @brief 注册 SOE 事件消费回调(支持多消费者) */
int dc_event_register_queue_pop(dc_queue_pop_cb_t cb);
/** @brief 扰动数据入队 */
int dc_disturb_dd_queue_push(void *p_dd);
/** @brief 注册扰动数据消费回调 */
int dc_disturb_dd_register_queue_pop(dc_queue_pop_cb_t cb);
/** @brief 故障数据入队 */
int dc_fault_queue_push(void *p_fault);
/** @brief 注册故障数据消费回调 */
int dc_fault_register_queue_pop(dc_queue_pop_cb_t cb);
/* ==================================================================
* 类型工具函数
* ================================================================== */
/** @brief 数据类型 ID → 名称(如 35 → "uint32_t" */
const char *dc_get_type_name(uint8_t data_type);
/** @brief 名称 → 数据类型 ID如 "float" → 38 */
uint8_t dc_get_type_id_by_name(const char *name);
/** @brief 获取数据类型的字节长度 */
uint8_t dc_get_type_len(uint8_t data_type);
/** @brief 根据类型分配并清零内存 */
void *dc_create_data(uint8_t data_type);
/** @brief 根据类型释放内存 */
void dc_destroy_data(void *p_data, uint8_t data_type);
/** @brief 类型感知的值复制 */
int dc_copy_val(void *dst, const void *src, uint8_t data_type);
/** @brief 类型感知的值比较0 = 相等,-1 = 不等) */
int dc_compare_val(const void *p1, const void *p2, uint8_t data_type);
/** @brief 字符串 → 值(如 "3.14" → 3.14f */
int dc_set_val_from_str(void *p_data, uint8_t data_type, const char *str);
/* ==================================================================
* 参数配置与异步管理
* ================================================================== */
/** @brief 查询参数配置是否有未保存的变更0=无1=有) */
int dc_param_cfg_changed(void);
/** @brief 获取当前异步请求 pending 数量 */
int dc_async_pending_count(void);
/** @brief 设置全局默认异步超时时间(毫秒) */
void dc_async_set_default_timeout(uint32_t timeout_ms);
/** @brief 设置 YK 遥控默认异步超时0=使用全局默认) */
void dc_async_set_timeout_yk(uint32_t timeout_ms);
/** @brief 设置 AO 调节默认异步超时0=使用全局默认) */
void dc_async_set_timeout_ao(uint32_t timeout_ms);
/** @brief 设置 Param 定值默认异步超时0=使用全局默认) */
void dc_async_set_timeout_param(uint32_t timeout_ms);
/* ==================================================================
* 导出
* ================================================================== */
/**
* @brief 保存所有已注册 out 信号到 XML
* @param path 目标文件路径
* @return DC_OK 成功,<0 失败
*/
int dc_save_out_signals_xml(const char *path);
#ifdef __cplusplus
}
#endif
#endif /* _MY_DATACENTER_H_ */