# libiec61850s 模块分析 **日期**: 2026-06-12 **基于源码**: `src/system/libiec61850s/` (iec61850s.cpp, parse_xml.cpp, 共4个文件) --- ## 1. 模块定位 `libiec61850s` 位于系统层,是 `libmms_s` 的上层封装。它负责将 datacenter 中的信号注册到 MMS 服务端模型中,使远方客户端能通过 IEC 61850 MMS 协议读取 RTU 数据并下发控制命令。 **与其他模块的关系**: ``` 远方 MMS 客户端 ↓ MMS 协议 libmms_s (协议层, IedServer) ↑↓ 回调 libiec61850s (本模块) ↑↓ dc_signal_* API datacenter (信号存储) ``` ## 2. 配置解析(parse_xml.cpp) ### 2.1 XML 结构 ```xml ``` 解析函数 `parse_mms_xml(path)` 使用 tinyxml2 遍历五类信号元素,提取 `link` 属性存入 `stru_mms_cfg`。 ### 2.2 数据结构 ```cpp typedef struct { char saddr[MMS_S_STR_LEN]; char desc[MMS_S_STR_LEN]; uint8_t type; uint8_t ctrl_model; }stru_mms_s_signal_base; typedef struct { std::vector vec_st; std::vector vec_mx; std::vector vec_co; std::vector vec_ao; std::vector vec_param; }stru_mms_cfg; ``` 配置保存在全局变量 `g_cfg` 中,通过 `mms_cfg_ptr_get()` 获取。 ## 3. 两阶段初始化 ### 3.1 `app_iec61850s_init1`(第一阶段) ``` 1. 获取进程目录 2. 解析 config/MMS/mms_s.xml → stru_mms_cfg 3. mms_s_dbg_switch(false) // 关闭调试 4. mms_s_file_path_set(base_path) // 设置文件服务根目录 5. mms_s_value_update_register(&g_mms_s_value_update_cb) // 注册值更新回调 ``` 此时仅完成配置解析和底层回调注册,datacenter 尚未就绪。 ### 3.2 `app_iec61850s_init2`(第二阶段) ``` 1. iec61850s_signals_init(): // 核心信号初始化 - iec61850s_st_signals_init: 对每个 ST 信号调用 dc_signal_out_link_with_callback → 获取 datacenter 信号指针 + 注册变更回调 → 回调: st_mx → mms_s_value_update (更新 MMS 模型) - iec61850s_mx_signals_init: 同上(MX 信号) - iec61850s_control_signals_init: 对每个 CO 信号: dc_get_yk_signal_info → 获取类型和 ctrl_model mms_s_control_register → 向 libmms_s 注册控制回调 回调接收远方控制命令 → dc_signal_yk_set_status - iec61850s_setting_signals_init: 对每个 AO 信号: dc_signal_ao_link_with_callback → 绑定 SP 定值 mms_s_setting_register → 注册写入回调 回调接收客户端修改 → dc_signal_ao_set_val - iec61850s_param_signals_init: 对每个 Param 信号: dc_get_param_signal_info → 获取各定值区指针 mms_s_param_register → 注册 ConfirmEditSG 回调 回调接收定值确认 → dc_signal_param_set_val 2. mms_s_init(PCS.icd, 102): 解析 ICD → 创建模型 → 启动 IedServer(端口 102) 3. mms_s_bind_param_zone_signal(zone_saddr, iec61850s_sg_change_callback): 绑定定值区号 → 定值区切换时自动同步 ``` ## 4. 信号方向与回调链 ### 4.1 数据上行(datacenter → MMS 客户端) ``` datacenter 信号变化 → iec61850s_st_mx_change_callback(saddr, type, p_data, p_last_data) → dc_get_signal_val → 格式化为字符串 → g_mms_s_value_update_cb(saddr, val_str) // 即 mms_s_value_update → IedServer_updateAttributeValue → 更新模型值 → 触发 RCB 报告 → 通知订阅客户端 ``` ### 4.2 控制下行(MMS 客户端 → datacenter) ``` 远方客户端控制命令 → libmms_s control_handler → iec61850s_control_callback(p_control, state): state == 1 (命令到达): 根据 ctrl_model: DIRECT/SBO: dc_signal_yk_set_status(SELECT + DIRECT) STATUS_ONLY: 日志记录 ``` ### 4.3 SP 定值修改(MMS 客户端 → datacenter) ``` 远方客户端修改 SP 定值 → libmms_s setting writeAccessHandler → iec61850s_setting_callback(p_setting, p_data): dc_set_signal_val_from_str → 解析字符串值 dc_signal_ao_set_val(SELECT + DIRECT or DIRECT only) ``` ### 4.4 定值组修改(MMS 客户端 → datacenter) ``` 远方客户端 ConfirmEditSG → libmms_s confirmEditSG_callback → iec61850s_param_callback(p_param, p_data, zone): dc_set_signal_val_from_str → 解析 dc_signal_param_set_val(zone, data) ``` ### 4.5 定值区切换同步 ``` datacenter 定值区号变化 → iec61850s_sg_change_callback(zone_saddr, new_act_sg): 找到对应的 setting 信号 dc_signal_ao_set_val: 同步新值到 AO 信号 设置 g_sg_zone_saddr / g_sg_zone_act_sg → check_sg_zone_change() (EV_TIMER3 中): mms_s_value_update: 更新 MMS 模型中 SGCB.ActSG 值 ``` ## 5. 主线程循环 ```cpp void *app_iec61850s(void *arg): while(1): task_event_recv(EV_TIMER1 | EV_TIMER2 | EV_TIMER3) EV_TIMER1 (10ms): 空闲 EV_TIMER2 (100ms): 空闲 EV_TIMER3 (1000ms): check_sg_zone_change() // 定值区号变更同步到 MMS 模型 p_app->run_cnt++ ``` ## 6. 全局变量 | 变量 | 类型 | 说明 | |------|------|------| | `g_vec_st` | `vector` | ST 信号列表(含 datacenter 指针) | | `g_vec_mx` | `vector` | MX 信号列表 | | `g_vec_control` | `vector` | 控制信号列表 | | `g_vec_setting` | `vector` | SP 定值信号列表 | | `g_vec_param` | `vector` | 定值组参数列表 | | `g_mms_s_value_update_cb` | 函数指针 | MMS 值更新回调(= mms_s_value_update) | | `g_sg_zone_saddr` | string | 待同步的定值区信号地址 | | `g_sg_zone_act_sg` | string | 待同步的新定值区号 | ## 7. 与 libiec61850m 的对比 | 特性 | libiec61850m (客户端) | libiec61850s (服务端) | |------|----------------------|----------------------| | 角色 | 主动读取/控制远方 IED | 被动响应远方客户端请求 | | 数据方向 | 拉取(All-Call/GI) | 推送(RCB 报告触发) | | 控制 | 下发控制命令 | 接收并执行控制命令 | | 连接 | 每个 IED 一个连接 | 监听端口,接受多客户端 | | 定时器 | T0(120s)/T1(60s)/T2(30s) | EV_TIMER3(1s) 仅定值区同步 |