RTU/mimo/工程/libiec61850m模块分析.md

195 lines
6.0 KiB
Markdown
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.

# libiec61850m 模块分析
**日期**: 2026-06-12
**基于源码**: `src/system/libiec61850m/` (iec61850m.cpp, parse_xml.cpp, 共4个文件)
---
## 1. 模块定位
`libiec61850m` 位于系统层,是 `libmms_m` 的上层封装。它负责:
- 解析 XML 配置(`mms_m.xml`
- 编排各 IED 的信号初始化流程
- 将 MMS 读取的数据通过回调桥接到 `datacenter`
- 接收来自其他模块的遥控命令,转发到 `libmms_m`
**与其他模块的关系**:
```
app_sys (调度) → app_iec61850m (线程EV_TIMER 驱动)
libiec61850m (本模块,系统层封装)
↓ 调用 API
libmms_m (协议层,每个 IED 一个线程)
↓ IedConnection API
远方 IED 装置
```
## 2. 配置解析parse_xml.cpp
### 2.1 XML 结构
```xml
<mms_m rcb_numbers="01,02">
<IED name="PCS9700" ip="192.168.1.100" port="102">
<St><Signal no="1" reference="..." /></St>
<Mx><Signal no="1" reference="..." /></Mx>
<Co><Signal no="1" reference="..." /></Co>
<Ao><Signal no="1" reference="..." /></Ao>
<Param><Signal no="1" reference="..." /></Param>
</IED>
</mms_m>
```
### 2.2 解析流程
```
parse_mms_xml(path):
→ 加载 XML → <mms_m> 根元素
→ mms_m_parse_para(root, cfg):
提取全局 rcb_numbers 属性
→ 遍历每个 <IED> 子元素:
mms_m_parse_base(iedEle, cfg):
提取 name, ip, port
mms_m_parse_signals: 遍历 St/Mx/Co/Ao/Param
→ 每个 Signal: 提取 link(saddr), reference, type, ctrl_model
→ 存入 stru_mms_cfg 对应的 vector
存入 cfg.vec_ieds
```
### 2.3 数据结构
```cpp
typedef struct
{
std::string path; // XML 文件路径
int rcb_numbers_flag; // 是否有全局 rcb_numbers
std::string rcb_numbers; // 全局 RCB 编号(如 "01,02"
std::vector<stru_mms_ied_cfg> vec_ieds; // 各 IED 的配置
}stru_mms_cfg;
typedef struct
{
std::string name; // IED 名称
std::string ip; // IP 地址
int port; // MMS 端口(通常 102
std::string rcb_numbers; // 此 IED 的 RCB 编号
std::vector<stru_mms_signal> vec_st;
std::vector<stru_mms_signal> vec_mx;
std::vector<stru_mms_signal> vec_co;
std::vector<stru_mms_signal> vec_ao;
std::vector<stru_mms_signal> vec_param;
}stru_mms_ied_cfg;
```
`stru_mms_signal`(与 `myMms_m.h` 中的 `stru_point_item` 对应):
```cpp
typedef struct
{
char saddr[MMS_M_STR_LEN]; // 信号地址link 属性)
char reference[MMS_M_REF_LEN]; // MMS 对象引用
char desc[MMS_M_STR_LEN]; // 描述
uint8_t type; // 数据类型
uint8_t ctrl_model; // 控制模型
}stru_mms_signal;
```
## 3. 两阶段初始化
### 3.1 第一阶段:`app_iec61850m_init1`
```
1. 获取进程目录(/proc/self/exe → 项目根目录)
2. 解析 config/MMS/mms_m.xml → stru_mms_cfg
3. 为每个 IED:
a. 将信号配置转换为 libmms_m 需要的 stru_cfg 格式
b. 调用 mms_m_out_init(p_cfg, debug, timeout) → obj_fd
c. 调用 mms_m_out_get_value(obj_fd, iec61850m_value_callback)
注册数据回调 → 桥接到 datacenter
d. 调用 mms_m_out_get_connect_status(obj_fd, iec61850m_status_callback)
注册连接状态回调
4. 保存 obj_fd 列表到全局
```
### 3.2 第二阶段:`app_iec61850m_init2`
```
1. 遍历所有 IED 的 obj_fd:
a. mms_m_out_debug_print_swicth(fd, debug_flag) // 设置调试
b. 如果配置中指定了 rcb_numbers:
mms_m_out_set_rcb_numbers(fd, rcb_numbers)
c. 如果配置了定值区信号:
mms_m_out_bind_param_zone_signal(fd, zone_saddr)
```
### 3.3 为什么分两阶段
- `init1` 执行时 datacenter 尚未完全初始化
- `init2``init1` 之后执行,此时 datacenter 已就绪,可以安全注册信号绑定
## 4. 数据回调桥接
`iec61850m_value_callback` 是核心桥接函数,将 libmms_m 推送的 `stru_mms_m_out_value` 转换为 datacenter 操作:
```
iec61850m_value_callback(out_val):
→ 根据 out_val.reason 分类:
MMS_M_REASON_ALL_CALL: // 定时全数据刷新
MMS_M_REASON_READ_AO: // 主动读取 AO
MMS_M_REASON_READ_PARAM: // 主动读取 Param
IEC61850_REASON_DATA_CHANGE / QUALITY_CHANGE / GI:
// 报告触发
→ 写入 datacenter:
- ST/MX (out): dc_set_out_signal_val(name, p_value, type)
- AO: dc_signal_ao_set_val(...)
- Param: dc_signal_param_set_val(...)
- CO: // CO 由操作完成回调处理,不走数据回调
```
## 5. 遥控命令转发
其他模块(如 CLI、self_ptl通过以下路径下发遥控
```
外部模块 → iec61850m_do_set_yk(event)
→ 填充 stru_mms_m_event:
- app_fd: 目标 IED 句柄
- ctrl_type: SELECT/DIRECT/CANCEL
- saddr: 信号地址
- data: 操作数据
→ mms_m_out_do_set_yk(&event) → libmms_m 处理
```
## 6. 线程模型
```
app_iec61850m 线程:
while(1):
task_event_recv(EV_TIMER1 | EV_TIMER2 | EV_TIMER3)
EV_TIMER1 (10ms): 空闲
EV_TIMER2 (100ms): 空闲
EV_TIMER3 (1000ms): p_app->run_cnt++
```
主工作不在 `app_iec61850m` 线程中,而是在 libmms_m 为每个 IED 创建的独立线程 `mms_m_run_thread` 中。`app_iec61850m` 线程仅用于接收定时器事件和消息队列。
## 7. 模块间数据流
```
远方 IED 装置
↓ MMS 协议
libmms_m (mms_m_run_thread)
↓ mms_m_out_value_cb
iec61850m_value_callback
↓ dc_set_out_signal_val / dc_signal_ao_set_val / dc_signal_param_set_val
datacenter (signal_out/signal_ao/signal_param 表)
↓ 变更通知
其他模块 (self_ptl, com_channel, web_server, iec61850s)
控制方向(反向):
CLI / self_ptl
↓ dc_signal_yk_set_status / iec61850m_do_set_yk
libmms_m (事件队列 → mms_m_send_co)
↓ ControlObjectClient_select/operate/cancel
远方 IED 装置
```