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

14 KiB
Raw Permalink Blame History

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 结构

<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         │
           └─────────────────────────────────────┘