355 lines
14 KiB
Markdown
355 lines
14 KiB
Markdown
# 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 设备
|
||
```
|
||
|
||
### 核心职责
|
||
|
||
1. **配置解析**:将 XML 配置文件解析为 `stru_cfg` 结构
|
||
2. **信号注册**:将信号点注册到数据中心(out/yk/ao/param)
|
||
3. **数据桥接**:将 libmms_m 回调的数据转发到数据中心
|
||
4. **遥控/设值转换**:将数据中心的变化回调转为 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 结构
|
||
|
||
```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
|
||
|
||
```cpp
|
||
// 解析 XML 配置文件,返回 stru_cfg*
|
||
stru_cfg *parse_cfg(const std::string &cfg_file);
|
||
|
||
// 打印配置内容到 stdout
|
||
void show_cfg(stru_cfg &cfg);
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 核心实现(iec61850m.cpp)
|
||
|
||
### 2.1 类型映射
|
||
|
||
```cpp
|
||
// 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 模块实例管理
|
||
|
||
```cpp
|
||
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 应用线程函数
|
||
|
||
```cpp
|
||
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 调试命令
|
||
|
||
```bash
|
||
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 │
|
||
└─────────────────────────────────────┘
|
||
```
|