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 控制类型
typedef enum
{
DC_CTRL_NONE = 0, /**< 无控制 */
DC_CTRL_DIRECT = 1, /**< 直控(直接执行) */
DC_CTRL_SBO = 2 /**< 选控(Select-Before-Operate) */
} dc_ctrl_type_t;
2.2 控制步骤
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 控制上下文
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 参数元数据
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. 使用示例
#include "myDatacenter.h"
#include <stdio.h>
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(按功能拆分) |
7.1 版本历史
| 日期 |
版本 |
变更 |
| 2026-07-07 |
v3.0 |
初始实现,对齐 RTU 原工程 v1+v2 |
| 2026-07-10 |
v3.1 |
Bug 修复 + 原工程功能补全(详见下表) |
v3.1 修复明细(2026-07-10)
| # |
文件 |
变更 |
说明 |
| 1 |
dc_async.cpp |
🔧 死锁修复 |
timeout_check() 持锁调回调 → 先收集列表,解锁后批量调用 |
| 2 |
dc_api_wrap.cpp |
🔧 线程安全 |
dc_get_type_name() static string → thread_local char[32] |
| 3 |
dc_event.cpp |
🔧 队列防溢 |
SOE/扰动/故障队列无上限 → EVENT_QUEUE_MAX_SIZE=1024 |
| 4 |
dc_signal_out.cpp |
🔧 回路阻断竞态 |
last_caller_module 多模块覆盖 → 新增 dirty_by_multi 标志 |
| 5 |
dc_signal_check.cpp |
➕ 值范围校验 |
dc_check_val_valid 扩展为 12 种数值类型 min/max 范围 + bool 0/1 校验 |
| 6 |
dc_signal_check.cpp |
➕ strcmp 替代 |
dc_check_ctrl_val_valid 对 C8/C32/C64/C128/STR 改用 strcmp |
| 7 |
dc_signal_util.cpp |
➕ 线程安全 API |
新增 dc_internal_type_name() buffer 版类型名称查询 |
已知未完成
| 功能 |
优先级 |
说明 |
| 事件队列自动补时间戳 |
🟡 |
push 时 sec==0 && ms==0 自动获取当前时间 |
dc_param_cfg_register_read_cb/save_cb 钩子 |
🟡 |
SPEC D29-D30,当前直接内置 tinyxml2 |
vec_p_default_data |
🟢 |
param 信号出厂默认值 |