# API-libdatacenter — 数据中心模块 > 版本: v3.0 > 日期: 2026-07-07 > 状态: 已实现(对齐 RTU 原工程 v1+v2 全部功能) --- ## 1. 模块概述 libdatacenter 是 RTU 通讯装置的核心数据中间层,负责: | 功能 | 说明 | |------|------| | 信号注册与管理 | 5 种信号类型(out/in/yk/ao/param)统一存储和 XXH3 哈希索引 | | 回路阻断 | 通过 `module_id` 实现"修改信号的模块不收到自己的回调" | | 延迟变化检测 | out 信号采用脏标记 + 100ms 批量检测,避免频繁回调 | | SBO 控制流程 | 支持直控(Direct)和选控(Select-Before-Operate)两种模式 | | 参数元数据 | min/max/step/unit 值校验 | | 配置文件持久化 | 通过 libxml C 接口读写 param.xml/self_param.xml | | 事件队列 | SOE 事件、扰动数据、故障录波三类队列(支持多消费者) | | 异步执行 | yk/ao/param 异步控制 + 超时检测 + 取消 | | 命令调试 | 通过 libcmd 注册 `datacenter` 命令,交互式查看信号 | ### 架构依赖 ``` libmy_xxhash → libxml → libcmd ↘ ↙ libdatacenter ``` --- ## 2. 数据结构 ### 2.1 控制类型 ```c typedef enum { DC_CTRL_NONE = 0, /**< 无控制 */ DC_CTRL_DIRECT = 1, /**< 直控(直接执行) */ DC_CTRL_SBO = 2 /**< 选控(Select-Before-Operate) */ } dc_ctrl_type_t; ``` ### 2.2 控制步骤 ```c typedef enum { DC_STEP_READY = 0, /**< 就绪 */ DC_STEP_SELECT = 1, /**< 选择 */ DC_STEP_DIRECT = 2, /**< 执行 */ DC_STEP_CANCEL = 3 /**< 取消 */ } dc_ctrl_step_t; ``` ### 2.3 SBO 状态转换 ``` READY ──→ SELECT(锁住信号,暂存值到 ctrl.p_data) │ │ │ ├──→ DIRECT(返校比对 → 写入 → ctrl.step = READY) │ │ │ └──→ CANCEL(回退,ctrl.step = READY) │ └──→ DIRECT(直控:直接写入) ``` ### 2.4 控制上下文 ```c typedef struct { uint8_t step; /**< 当前步骤 */ uint8_t type; /**< 控制类型 */ uint8_t data_type; /**< 数据类型 */ uint8_t reserved; /**< 保留 */ void *p_data; /**< SELECT时暂存选择值,DIRECT时返校比对 */ } dc_ctrl_t; ``` ### 2.5 参数元数据 ```c typedef struct { float min; /**< 最小值 */ float max; /**< 最大值 */ float step; /**< 步长 */ char unit[32]; /**< 单位 */ } dc_param_meta_t; ``` ### 2.6 错误码 | 值 | 名称 | 说明 | |----|------|------| | 0 | DC_OK | 成功 | | -1 | DC_ERR_PARAM | 参数错误 | | -2 | DC_ERR_NOTFOUND | 信号不存在 | | -3 | DC_ERR_TYPE | 数据类型不匹配 | | -4 | DC_ERR_STEP | SBO 步骤错误 | | -5 | DC_ERR_VAL | 值校验失败 | | -6 | DC_ERR_TIMEOUT | 异步超时 | | -7 | DC_ERR_BUSY | 忙 | | -8 | DC_ERR_MEM | 内存不足 | | -9 | DC_ERR_FULL | 队列已满 | | -10 | DC_ERR_LOCKED | 已锁定 | | -11 | DC_ERR_EXISTS | 重复注册 | | -12 | DC_ERR_CANCEL | 已取消 | --- ## 3. 接口函数 ### 3.1 模块生命周期 | 函数 | 说明 | |------|------| | `dc_init(cfg_dir)` | 初始化,自动加载 param.xml | | `dc_cleanup()` | 清理所有资源 | | `dc_run_100ms()` | 每100ms:out变化检测 + 事件弹出 + 异步超时 | | `dc_run_1000ms()` | 每1000ms:参数变更检测 → 写 self_param.xml | ### 3.2 Out 信号(遥测/遥信) | 函数 | 说明 | |------|------| | `dc_signal_out(saddr, desc, data_type, p_data, module_id)` | 注册输出信号 | | `dc_signal_out_with_callback(..., cb, module_id)` | 注册 + 延迟变化回调 | | `dc_signal_out_link_with_callback(saddr, pp_data, cb, module_id)` | 链接已有信号 | | `dc_set_out_signal_val(saddr, set_data, module_id)` | 设值(脏标记 + 延迟回调) | ### 3.3 In 信号(输入信号,链接 out) | 函数 | 说明 | |------|------| | `dc_signal_in(saddr, desc, link_saddr, pp_data, module_id)` | 注册并关联 out | | `dc_signal_in_with_callback(..., cb, module_id)` | 注册 + 回调(挂在 out 上) | ### 3.4 YK 信号(遥控) | 函数 | 说明 | |------|------| | `dc_signal_yk(...)` | 注册遥控信号 | | `dc_signal_yk_link_with_callback(...)` | 链接已有 | | `dc_signal_yk_set_status(saddr, step, ctrl, p_data, module_id)` | 同步控制 | | `dc_yk_exec_async(saddr, step, ctrl, p_data, module_id, result_cb, arg, timeout, req_id)` | 异步控制 | | `dc_yk_set_result(req_id, result, err)` | 异步结果通知 | | `dc_yk_cancel_async(req_id)` | 取消异步 | | `dc_yk_register_exec_cb(saddr, exec_cb, ctx)` | 注册执行回调 | ### 3.5 AO 信号(模拟输出) | 函数 | 说明 | |------|------| | `dc_signal_ao(...)` | 注册 AO 信号 | | `dc_signal_ao_link_with_callback(...)` | 链接已有 | | `dc_signal_ao_set_val(saddr, step, ctrl, p_data, module_id)` | 同步控制(SBO + 值校验) | | `dc_signal_ao_set_val_without_check(...)` | 无校验设值 | | `dc_ao_exec_async(...)` | 异步控制 | | `dc_ao_set_result(...)` | 异步结果通知 | | `dc_ao_cancel_async(...)` | 取消异步 | | `dc_ao_register_exec_cb(...)` | 注册执行回调 | ### 3.6 Param 信号(定值,多区) | 函数 | 说明 | |------|------| | `dc_signal_param(saddr, desc, data_type, ctrl_type, pp_data, num_zones, cb, module_id)` | 注册参数 | | `dc_signal_param_link_with_callback(...)` | 链接已有 | | `dc_signal_param_set_val(saddr, step, ctrl, zone, p_data, module_id)` | 同步设值 | | `dc_signal_param_set_val_without_check(...)` | 无校验设值 | | `dc_param_exec_async(...)` | 异步控制 | | `dc_param_set_result(...)` | 异步结果通知 | | `dc_param_cancel_async(...)` | 取消异步 | | `dc_param_register_exec_cb(...)` | 注册执行回调 | ### 3.7 信号查询 | 函数 | 说明 | |------|------| | `dc_get_out_signal_info(saddr, desc, desc_len, data_type, pp_data)` | 查询 out | | `dc_get_in_signal_info(...)` | 查询 in | | `dc_get_ao_signal_info(saddr, desc, desc_len, data_type, p_meta, ctrl_type, pp_data)` | 查询 AO(含元数据) | | `dc_get_param_signal_info(saddr, desc, desc_len, data_type, p_meta, ctrl_type, p_data_array, p_count)` | 查询 Param(多区) | | `dc_get_yk_signal_info(...)` | 查询 YK | | `dc_get_signal_val(p_data, data_type, buf, buf_len)` | 值 → 字符串 | | `dc_get_signal_count(type_str)` | 按类型统计 | | `dc_get_signal_info_by_id(type_str, id, ...)` | 按 ID 查询 | ### 3.8 事件队列 | 函数 | 说明 | |------|------| | `dc_event_queue_push(p_soe)` | SOE 入队 | | `dc_event_register_queue_pop(cb)` | 注册 SOE 消费回调 | | `dc_disturb_dd_queue_push(p_dd)` | 扰动数据入队 | | `dc_disturb_dd_register_queue_pop(cb)` | 注册扰动消费回调 | | `dc_fault_queue_push(p_fault)` | 故障数据入队 | | `dc_fault_register_queue_pop(cb)` | 注册故障消费回调 | ### 3.9 类型工具 | 函数 | 说明 | |------|------| | `dc_get_type_name(data_type)` | ID → 名称(35 → "uint32_t") | | `dc_get_type_id_by_name(name)` | 名称 → ID("float" → 38) | | `dc_get_type_len(data_type)` | 获取字节长度 | | `dc_create_data(data_type)` / `dc_destroy_data(p_data, data_type)` | 类型感知的分配/释放 | | `dc_copy_val(dst, src, data_type)` / `dc_compare_val(p1, p2, data_type)` | 类型感知的复制/比较 | | `dc_set_val_from_str(p_data, data_type, str)` | 字符串 → 值 | ### 3.10 配置与异步管理 | 函数 | 说明 | |------|------| | `dc_param_cfg_changed()` | 查询是否有未保存变更 | | `dc_async_pending_count()` | 异步请求 pending 数 | | `dc_async_set_default_timeout(ms)` | 全局默认超时 | | `dc_async_set_timeout_yk/ao/param(ms)` | 各类型默认超时 | | `dc_save_out_signals_xml(path)` | 导出 out 信号到 XML | --- ## 4. 使用示例 ```c #include "myDatacenter.h" #include static void on_out_changed(const char *saddr, uint8_t data_type, const void *p_new, const void *p_old) { printf("out %s: %d → %d\n", saddr, *(int *)p_old, *(int *)p_new); } static void on_yk_changed(const char *saddr, dc_ctrl_step_t step, uint8_t data_type, uint8_t zone, const void *p_data) { printf("yk %s step=%d val=%d\n", saddr, step, *(uint8_t *)p_data); } int main(void) { /* 初始化,自动加载 param.xml */ dc_init("/etc/rtu/config/"); /* 注册 out 信号 */ int yc_val = 0; dc_signal_out("RPC1:YC:1:val", "母线电压", DATA_TYPE_S32, &yc_val, "protocol_104"); /* 另一个模块链接 out 信号并注册回调 */ void *p_linked = NULL; dc_signal_out_link_with_callback("RPC1:YC:1:val", &p_linked, on_out_changed, "web_server"); /* 注册 yk 信号(直控模式) */ uint8_t yk_val = 0; dc_signal_yk("RPC1:YK:1:val", "开关合闸", DATA_TYPE_U8, DC_CTRL_DIRECT, &yk_val, on_yk_changed, "protocol_104"); /* 修改 out 信号值(回路阻断:protocol_104 自身的回调不会被触发) */ yc_val = 220; dc_set_out_signal_val("RPC1:YC:1:val", &yc_val, "protocol_104"); /* 100ms 周期:on_out_changed 被调用 */ dc_run_100ms(); /* YK 直控执行(同步回调:on_yk_changed 立即触发) */ dc_ctrl_t ctrl = {0}; ctrl.type = DC_CTRL_DIRECT; ctrl.data_type = DATA_TYPE_U8; uint8_t new_val = 1; dc_signal_yk_set_status("RPC1:YK:1:val", DC_STEP_DIRECT, &ctrl, &new_val, "web_server"); dc_cleanup(); return 0; } ``` --- ## 5. 依赖关系 | 依赖 | 模块 | 用途 | |------|------|------| | ⇩ | `myBase.h` | 基础类型定义(DATA_TYPE_* 宏) | | ⇩ | `myLog.h` | 日志输出 | | ⇩ | `libmy_xxhash` | XXH3_128bits 哈希查找(O(1)) | | ⇩ | `libxml` | 纯 C 接口 XML 解析(param.xml/self_param.xml) | | ⇩ | `libcmd` | 命令注册(`datacenter` 调试面板) | --- ## 6. 源文件组成(15 文件,对齐 RTU 原工程) | 文件 | 职责 | |------|------| | `inc/myDatacenter.h` | 纯 C 对外接口(60+ API) | | `src/dc_internal.h` | C++ 内部声明(哈希/信号表/异步队列) | | `src/dc_core.cpp` | 全局变量 + XXH128 哈希 + dc_init/run | | `src/dc_signal_out.cpp` | Out 信号注册/链接/设值 | | `src/dc_signal_in.cpp` | In 信号注册(关联 out) | | `src/dc_signal_yk.cpp` | YK 注册 + 同步/异步控制 | | `src/dc_signal_ao.cpp` | AO 注册 + 同步/异步控制 + SBO | | `src/dc_signal_param.cpp` | Param 多区定值 + 同步/异步控制 | | `src/dc_signal_query.cpp` | 全部 get_xxx_info 函数 | | `src/dc_signal_util.cpp` | 19 种类型工具函数 | | `src/dc_signal_check.cpp` | SBO 校验 + 值校验 + YK 校验 | | `src/dc_signal_show.cpp` | 命令注册 + XML 导出 | | `src/dc_param_cfg.cpp` | param.xml 解析 + self_param.xml 保存 | | `src/dc_event.cpp` | SOE/扰动/故障事件队列 | | `src/dc_async.cpp` | 异步请求队列(入队/超时/取消/清理) | | `src/dc_api_wrap.cpp` | C API 包装(get_type_name 等) | --- ## 7. 新旧工程差异 | 维度 | RTU v1 | RTU v2 | 新工程 | |------|--------|--------|--------| | 接口语言 | C++ (std::string) | 纯 C (const char*) | 纯 C + Allman 风格 | | 哈希 | XXH128 multimap | 同 v1 | unordered_map + XXH128 hasher | | 参数文件 | tinyxml2 嵌入 | 同 v1 | libxml C 接口 | | 异步执行 | 无 | _exec_async 系列 | _exec_async 系列 | | 回路阻断 | ✓ | ✓ | ✓ | | SBO 流程 | ✓ | ✓ | ✓ | | 多区定值 | ✓ | ✓ | ✓ | | 错误码 | -1/0 | enum dc_error_t | enum dc_error_t(12种) | | 命令调试 | cmd_dc | 无 | CMD_REGISTER_C(libcmd) | | 文件数 | 13 .cpp | 8 .cpp | 15 .cpp(按功能拆分) |