14 KiB
14 KiB
libiec61850m 模块工程文档
概述
libiec61850m 是 RTU 项目中 IEC 61850 MMS 客户端应用线程,位于 src/system/libiec61850m/。它作为应用层桥接器,将底层的 libmms_m 封装库与 RTU 的**数据中心(Datacenter)**连接起来,实现完整的 IEC 61850 客户端功能。
在系统架构中的位置
app_iec61850m (应用线程)
↓ 调用 API
libiec61850m (本模块) ──── 信号注册/回调
↓ 调用 libmms_m API ↓ dc_signal_*
libmms_m (协议封装层) Datacenter (数据中心)
↓ IEC 61850 Client API
libiec61850 (第三方库)
↓ MMS/TCP
远端 IED 设备
核心职责
- 配置解析:将 XML 配置文件解析为
stru_cfg结构 - 信号注册:将信号点注册到数据中心(out/yk/ao/param)
- 数据桥接:将 libmms_m 回调的数据转发到数据中心
- 遥控/设值转换:将数据中心的变化回调转为 libmms_m 事件
文件结构
src/system/libiec61850m/
├── inc/
│ ├── iec61850m.h ← 模块主头文件(app 入口声明)
│ └── parse_xml.h ← XML 配置解析声明
└── src/
├── iec61850m.cpp ← 核心实现(~830 行)
└── parse_xml.cpp ← XML 解析实现(~320 行)
引用头文件 release/inc/myMms_m.h(数据结构定义)。
1. XML 配置文件解析(parse_xml.cpp)
1.1 XML 结构
<Root>
<Para desc="描述" host_ip="192.168.1.100" host_port="102" ied="IEDNAME"/>
<Point desc="描述">
<St> <!-- 遥信 -->
<Item no="1" saddr="..." desc="..." type="2" fc="0" LDev="TEMPLATE" LNode="GGIO1" DoName="Ind1"/>
</St>
<Mx> <!-- 遥测 -->
<Item no="1" saddr="..." desc="..." type="6" fc="1" LDev="TEMPLATE" LNode="MMXU1" DoName="TotW"/>
</Mx>
<Co> <!-- 遥控 -->
<Item no="1" saddr="..." desc="..." type="2" fc="12" LDev="TEMPLATE" LNode="GGIO1" DoName="SPCSO1" ctlModel="2"/>
</Co>
<Ao> <!-- 模拟输出/设值 -->
<Item no="1" saddr="..." desc="..." type="6" fc="12" LDev="TEMPLATE" LNode="GGIO1" DoName="AnOut1"/>
</Ao>
<Param> <!-- 参数/定值 -->
<Item no="1" saddr="..." desc="..." type="6" fc="6" LDev="PROT" LNode="PDIS1" DoName="PhStr"/>
</Param>
</Point>
</Root>
1.2 元素/属性映射
| XML 元素 | 说明 |
|---|---|
Root |
根节点 |
Para |
连接参数(IP、端口、IED 名) |
Point |
信号点容器 |
St/Mx/Co/Ao/Param |
5 种信号类型子节点 |
Item |
单个信号点 |
| Item 属性 | 存储字段 | 说明 |
|---|---|---|
saddr |
item.saddr |
短地址(数据中心标识) |
desc |
item.desc |
描述 |
type |
item.type |
MMS 数据类型(MMS_BOOLEAN=2, FLOAT=6, INTEGER=4 等) |
fc |
item.fc |
功能约束(ST=0, MX=1, CO=12, SG=6 等) |
LDev |
item.ldev |
逻辑设备名 |
LNode |
item.lnode |
逻辑节点名 |
DoName |
item.doname |
数据对象名 |
ctlModel |
item.ctrl_model |
控制模型(仅 Co 类型需要) |
引用自动生成规则:
reference = ied + LDev + "/" + LNode + "." + DoName
例如: "IEDNAMETEMPLATE/GGIO1.Ind1"
1.3 公共 API
// 解析 XML 配置文件,返回 stru_cfg*
stru_cfg *parse_cfg(const std::string &cfg_file);
// 打印配置内容到 stdout
void show_cfg(stru_cfg &cfg);
2. 核心实现(iec61850m.cpp)
2.1 类型映射
// MMS 类型 → 本地 DATA_TYPE_* 类型
LOCAL std::map<uint8_t, uint8_t> g_mms_m_type_to_local_type = {
{MMS_BOOLEAN, DATA_TYPE_U8},
{MMS_INTEGER, DATA_TYPE_S32},
{MMS_UNSIGNED, DATA_TYPE_U32},
{MMS_FLOAT, DATA_TYPE_F32},
{MMS_STRING, DATA_TYPE_STR},
};
// IEC 61850 控制模型 → RTU 本地控制类型
LOCAL std::map<uint8_t, uint8_t> g_mms_m_ctrl_type_to_local_ctrl_type = {
{CONTROL_MODEL_STATUS_ONLY, SIGNAL_CTRL_TYPE::NONE},
{CONTROL_MODEL_DIRECT_NORMAL, SIGNAL_CTRL_TYPE::DIRECT_NORMAL},
{CONTROL_MODEL_SBO_NORMAL, SIGNAL_CTRL_TYPE::SBO_NORMAL},
{CONTROL_MODEL_DIRECT_ENHANCED, SIGNAL_CTRL_TYPE::DIRECT_NORMAL},
{CONTROL_MODEL_SBO_ENHANCED, SIGNAL_CTRL_TYPE::SBO_NORMAL},
};
2.2 模块实例管理
typedef struct {
int fd; // mms_m 客户端句柄
const char *prj_name; // 项目/配置文件名(如 "mms_m.xml")
int debug; // 调试标志(0=关, 1=开)
uint32_t connectionTimeout; // 连接超时 [毫秒, 默认10000]
stru_mms_m_event mms_event; // 预分配的事件(用于遥控/设值)
stru_cfg *p_cfg; // 配置指针
} stru_iec61850m_info;
LOCAL std::vector<stru_iec61850m_info> g_vec_iec61850m_info = {
{
.fd = -1,
.prj_name = "mms_m.xml",
.debug = MMS_M_DEBUG_PRINT_OFF,
.connectionTimeout = 10000,
.mms_event = { .p_func = mms_event_back },
.p_cfg = NULL,
}
};
当前只配置了一个客户端实例,配置文件路径为 <进程目录>/config/MMS/mms_m.xml。
2.3 初始化流程
app_iec61850m_init1()
├── dc_signal_out("iec61850m.run_cnt", ...) ← 注册运行计数
├── get_base_path() → g_61850m_prj_path ← "<进程目录>/config/MMS/"
│
└── iec61850m_init()
├── for each g_vec_iec61850m_info[i]:
│ ├── parse_cfg(g_61850m_prj_path + prj_name) ← 解析 XML
│ ├── show_cfg() ← 打印配置
│ │
│ ├── iec61850m_signal_init(*p_cfg) ← 注册信号到数据中心
│ │ ├── 为每个信号点分配数据内存 (dc_create_data_ptr_by_type)
│ │ ├── dc_signal_out() ← ST/MX 类型
│ │ ├── dc_signal_yk() ← CO 类型, 带 iec61850m_signal_co_change_callback
│ │ ├── dc_signal_ao() ← AO 类型, 带 iec61850m_signal_ao_change_callback
│ │ └── dc_signal_param() ← Param 类型, 带 iec61850m_signal_param_change_callback
│ │
│ ├── mms_m_out_init(p_cfg, debug, timeout) ← 启动 MMS 客户端
│ │
│ ├── mms_m_out_bind_param_zone_signal(fd, p_cfg->point.p_ao[0].saddr)
│ │ └── 将第一个 AO 信号绑定为定值区指示器
│ │
│ ├── mms_m_out_get_value(fd, mms_data_back) ← 注册数据回调
│ └── mms_m_out_get_connect_status(fd, iec61850m_connect_status) ← 注册状态回调
2.4 数据类型与信号注册详细
| 信号类型 | 数据中心函数 | 变化回调 | 参数说明 |
|---|---|---|---|
| ST(遥信) | dc_signal_out |
无(只读输出) | p_val[0] 为值 |
| MX(遥测) | dc_signal_out |
无(只读输出) | p_val[0] 为值 |
| CO(遥控) | dc_signal_yk |
iec61850m_signal_co_change_callback |
ctrl_model 映射为本地类型 |
| AO(模拟输出) | dc_signal_ao |
iec61850m_signal_ao_change_callback |
带 p_default[0] 默认值 |
| Param(参数) | dc_signal_param |
iec61850m_signal_param_change_callback |
带 p_default[0], p_val[0..N-1] 多区值 |
2.5 数据回传链路(mms_data_back)
mms_data_back() ← libmms_m 数据回调入口
│
├── 按 reason 过滤:
│ 忽略: REASON_DATA_CHANGE, REASON_GI,
│ REASON_INTEGRITY, REASON_ALL_CALL
│ 处理: REASON_READ_AO, REASON_READ_PARAM
│
├── 打印日志(按 MMS 类型格式化)
│
└── 按信号类型匹配并写入 Datacenter:
├── ST 点匹配: dc_set_out_signal_val(saddr, p_value)
├── MX 点匹配: dc_set_out_signal_val(saddr, p_value)
├── AO 点匹配: dc_signal_ao_set_val_without_check(saddr, local_type, p_value)
└── Param 点匹配:
dc_signal_param_set_val_without_check(saddr, local_type, set_zone-1, p_value)
注意:mms_data_back 只处理 AO 和 Param 的主动读取结果。数据变化和报告上送的数据通过 libmms_m 的报告回调机制直接输出,但当前代码中报告回调仅打印日志,未对接数据中心。
2.6 遥控/设值下发链路
Datacenter 信号变化
│
├── CO: iec61850m_signal_co_change_callback()
│ └── iec61850m_signal_change_decode() ← 解析 step/data_type/value
│ └── mms_send_control() ← 构造 mms_event
│ └── mms_m_out_do_set_yk() ← 发送到 libmms_m
│
├── AO: iec61850m_signal_ao_change_callback()
│ └── 同上流程 (ctrl_type = _MMS_M_EVENT_AO_WRITE)
│
└── Param: iec61850m_signal_param_change_callback()
└── 同上流程 (ctrl_type = _MMS_M_EVENT_PARAM_WRITE, 传入 set_zone+1)
2.7 连接上线后的处理
iec61850m_connect_status(fd, ON_LINE)
├── iec61850m_ext_demo(fd)
│ ├── mms_m_query_server(fd, ...) ← 查询 IED 信息
│ ├── mms_m_read_sg_info(fd, "PROT", ...) ← 读取定值组
│ └── 其他 ext demo(文件操作已注释)
│
├── mms_m_out_read_ao_or_params(fd, AO_READ, NULL) ← 读全部 AO
└── mms_m_out_read_ao_or_params(fd, PARAM_READ, NULL) ← 读全部参数
2.8 应用线程函数
void *app_iec61850m(void *arg)
{
// 标准 RTU app 线程模板
while (1) {
task_event_recv(p_event,
EV_TIMER1 | EV_TIMER2 | EV_TIMER3,
TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR,
TASK_EVENT_WAIT_FOREVER,
&event);
if (event & EV_TIMER1) { ; } // 10ms 定时器(预留)
if (event & EV_TIMER2) { ; } // 100ms 定时器(预留)
if (event & EV_TIMER3) {
p_app->run_cnt++; // 1s 定时器:运行计数
}
}
}
注意:app_iec61850m 线程本身不执行任何 MMS 操作。所有 MMS 通信由 libmms_m 内部的独立 pthread_task 线程驱动。
3. CLI 调试命令
iec61850m info # 查看所有客户端实例信息
iec61850m yk <fd> <saddr> <val> <ctrl_type> # 手动遥控(框架已有,部分代码注释)
iec61850m set <fd> <saddr> <val> <set_type> # 手动设值(框架已有)
注册方式:CMD_REGISTER("iec61850m", cmd_iec61850m, "iec61850客户端线程的控制命令")
4. 线程模型
RTU 主进程
├── app_sys 线程 (ap_sys.cpp)
├── ...
│
├── app_iec61850m 线程 (本模块)
│ └── 3 个标准 RTU 定时器 (10ms / 100ms / 1000ms)
│ └── 仅 1000ms 定时器:p_app->run_cnt++
│
├── libmms_m 内部线程 (pthread_task) ← 由 mms_m_out_init() 创建
│ └── 主循环 300ms 周期
│ ├── 连接状态维护
│ ├── 事件处理
│ └── 4 个业务定时器 (120s/60s/30s/20s)
│
└── libiec61850 库内部线程 (IedConnection 线程模式)
└── MMS 报文收发、报告处理
三层线程协作:
| 层级 | 线程 | 职责 |
|---|---|---|
| RTU 应用层 | app_iec61850m |
信号注册、运行计数 |
| 协议封装层 | libmms_m pthread_task |
连接管理、事件调度、数据路由 |
| 第三方库层 | libiec61850 内部 | MMS 协议栈、报告分发 |
5. 数据流向总览
┌──────────────────────────────┐
│ 远端 IED (服务端) │
└──────────┬───────────────────┘
│ MMS/TCP
┌──────────▼───────────────────┐
│ libiec61850 (第三方库) │
│ IedConnection + Report │
└──────────┬───────────────────┘
│
┌──────────────────┴──────────────────┐
│ libmms_m (封装层) │
│ ┌─────────────────────────────┐ │
│ │ mms_m_report_callback() │ │ ← 报告数据(当前仅打印)
│ │ mms_m_send_call_all() │ │ ← 周期总召
│ │ mms_m_send_read_ao/param() │ │ ← 读 AO/参数
│ │ mms_m_send_co() │ │ ← 遥控
│ │ mms_m_send_param_write() │ │ ← 设值
│ └──────────┬──────────────────┘ │
└─────────────┼───────────────────────┘
│ mms_m_out_value_cb
┌─────────────▼───────────────────────┐
│ libiec61850m (应用层) │
│ ┌──────────────────────────────┐ │
│ │ mms_data_back() │ │ ← 数据回调→Datacenter
│ │ iec61850m_signal_*_callback() │ │ ← Datacenter→遥控/设值
│ └──────────┬───────────────────┘ │
└─────────────┼───────────────────────┘
│ dc_signal_* / dc_set_*
┌─────────────▼───────────────────────┐
│ Datacenter (数据中心) │
│ out / in / yk / ao / param │
└─────────────────────────────────────┘