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

6.0 KiB
Raw Permalink Blame History

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

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

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 对应):

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 尚未完全初始化
  • init2init1 之后执行,此时 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 装置