RTU/mimo/plan/libiec修改计划.md

290 lines
10 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.

# libiec 修改计划
**日期**: 2026-06-29
**状态**: 阶段一二已完成 ✅ | 阶段三待定
**基于**: CBB 库 V2.01.059 + RTU 项目 libiec 源码分析
---
## 1. 模块概览
libiec 是 RTU 项目中 60870 协议的应用适配层,负责将 CBB 库与数据中心datacenter桥接。
```
┌──────────────────────────┐
│ libcom_decode (通信层) │
│ 原始数据 → interface路由 │
└──────────┬───────────────┘
┌──────────▼───────────────┐
│ libiec (本模块) │
│ ┌─────────────────────┐ │
│ │ iec.cpp │ │
│ │ • CS10x 实例管理(×3) │ │
│ │ • 101/104 自动识别 │ │
│ │ • 收发/定时调度 │ │
│ └────────┬────────────┘ │
│ │ │
│ ┌────────▼────────────┐ │
│ │ iec_method.cpp │ │
│ │ • 19个CBB回调实现 │ │
│ │ • 4个全局数据队列 │ │
│ └────────┬────────────┘ │
│ │ │
│ ┌────────▼────────────┐ │
│ │ iec_point.cpp │ │
│ │ • 信号→IEC回调绑定 │ │
│ │ • YX/YC变化检测 │ │
│ └────────┬────────────┘ │
│ │ │
│ ┌────────▼────────────┐ │
│ │ iec_cfg_parse.cpp │ │
│ │ • XML配置解析 │ │
│ └─────────────────────┘ │
└───────────────────────────┘
┌──────────▼───────────────┐
│ libdatacenter (数据中心) │
│ 信号池 / SOE队列 / 故障 │
└──────────────────────────┘
```
---
## 2. 发现的问题
### 2.1 🐛 Bug: GetDdValueByGroup 始终返回 0
**文件**: `iec_method.cpp:540-577`
**现象**: 电度总召/组召获取值时,函数计算了 `usMin`/`usMax` 但结尾直接 `return 0`,从未填充 `pstInfo`
```cpp
int32_t GetDdValueByGroup(..., TimeDd_Info *pstInfo, ...)
{
// ... 计算 usMin, usMax ...
// 缺少: 根据 usIdx 从 vec_dd 获取值并填充 pstInfo
return 0; // BUG: 永远返回 0pstInfo 未填充
}
```
**修复**: 根据 `usIdx` 和计算的 `usMin`/`usMax` 范围从 `vec_dd` 中读取实际电度值填充 `pstInfo`
### 2.2 🐛 Bug: YX 变化回调被禁用
**文件**: `iec_point.cpp:22-28`
**现象**: 遥信值变化被检测到,但既未写入 SOE 队列,也未更新 `p_last_data`
```cpp
if(val != last_val)
{
// UserWriteDisturbYx(i, val); // 被注释
LOG_I("...");
// *(uint8_t *)p_last_data = val; // 被注释 → 每次变化都触发回调
}
```
**修复**:
1. 恢复 `UserWriteSoeEvent(i, val, ...)` 调用,确保 YX 变化能入 SOE 队列
2. 恢复 `*(uint8_t *)p_last_data = val` 避免重复触发
### 2.3 🐛 Bug: SOE 事件中 ucType 未赋值
**文件**: `iec_method.cpp:397-411`
**现象**: `UserWriteSoeEvent` 写入 SOE 时未设置 `ucType`,后续 `GetSOE` 依赖此字段判断单/双点。
```cpp
p_soe_info->usYxPot = usIndex;
p_soe_info->ucState = ucState;
p_soe_info->uiSeconds = uiSeconds;
p_soe_info->usMs = usMs;
// 缺失: p_soe_info->ucType = ...;
```
**修复**: 从 `vec_st[idx].type` 或配置获取遥信类型并赋值。
### 2.4 🐛 Bug: GetFaultEvent 时间双重写入
**文件**: `iec_method.cpp:718-724`
**现象**: 先用 `StampToCp56` 计算时间,紧接着 `memcpy` 覆盖,前者无效。
```cpp
StampToCp56(&pstInfo->staSoe[i].stCTime, ..., ...); // 被覆盖
memcpy(&pstInfo->staSoe[i].stCTime, &..., sizeof(stCP56Time2a)); // 覆盖前者
```
**修复**: 删除 `StampToCp56` 调用,保留 `memcpy`(数据已在入队时计算好)。
### 2.5 ⚠️ 问题: GetTimeItfs/SetTimeItfs 为空桩
**文件**: `iec_method.cpp:20-29`
**现象**: 对时功能完全不可用。
```cpp
int GetTimeItfs(__CP56Time2a *pTime) { return 0; }
int SetTimeItfs(__CP56Time2a *pTime) { return 0; }
```
**修复**: 实现 `GetTimeItfs` 调用系统时间,`SetTimeItfs` 调用 `settimeofday`
### 2.6 ⚠️ 问题: 遥控校验始终返回通过
**文件**: `iec_method.cpp:754-757`
**现象**: `Cs10xYkVerifyItfs` 始终返回 1允许遥控无实际校验逻辑。
```cpp
uint8_t Cs10xYkVerifyItfs(void *pvParam) { return 1; }
```
**修复**: 接入数据中心的远方/就地状态和软压板状态进行校验。
### 2.7 ⚠️ 问题: 硬编码起始地址与 XML inf 属性冲突
**文件**: `iec_method.cpp:9-11`
**现象**: YX/YC/DD 起始地址硬编码,但 XML 配置中已有 `inf` 属性。
```cpp
#define YX_START_PORT 0x01
#define YC_START_PORT 0x4001
#define DD_START_PORT 0x6401
```
`GetYcValueByGroup` 中:
```cpp
pstInfo->uiInfoAddr = p_mx_info->inf; // 使用了 XML 的 inf
```
`GetYcCountByGroup` 中:
```cpp
*puiStartInf = YC_START_PORT; // 仍用硬编码
*puiEndInf = YC_START_PORT + vec_mx.size();
```
**修复**: 统一使用 XML 配置中的 `inf` 值,移除硬编码起始地址。对于没有配置 `inf` 的点,自动分配序号。
### 2.8 ⚠️ 问题: 参数/文件/升级回调未注册
**文件**: `iec.cpp:117-125`
**现象**: CBB 库支持的参数读写、文件传输、软件升级功能均已注释。
```cpp
// CS10x_S_IECParamHandler(...) // 参数读写 → 未注册
// CS10x_S_GetParamInfoHandler(...) // 参数信息 → 未注册
// CS10x_S_FileReadOprtHandler(...) // 文件读取 → 未注册
// CS10x_S_FileWriteOprtHandler(...) // 文件写入 → 未注册
// CS10x_S_UpdateProcHandler(...) // 软件升级 → 未注册
```
**修复**: 根据需求逐步启用,实现对应的回调函数。
### 2.9 ⚠️ 问题: Dd 电度变化回调被禁用
**文件**: `iec_point.cpp:76-79`
**现象**: 电度值变化检测到,但未写入扰动电度队列。
```cpp
if(fabs(fVal - last_fVal) > 0.1)
{
// UserWriteDisturbDd(i, fVal, 0, 0); // 被注释
// *(float *)p_last_data = fVal; // 被注释
}
```
**修复**: 恢复 `UserWriteDisturbDd` 调用并更新 `p_last_data`
---
## 3. 执行步骤
### 阶段一:🐛 Bug 修复(高优先级)
| # | 步骤 | 文件 | 对应问题 |
|---|------|------|:---:|
| 1.1 | 修复 `GetDdValueByGroup` 返回值 | `iec_method.cpp` | 2.1 |
| 1.2 | 恢复 YX 变化 SOE 写入 | `iec_point.cpp` | 2.2 |
| 1.3 | 补充 SOE ucType 赋值 | `iec_method.cpp` | 2.3 |
| 1.4 | 删除 FaultEvent 双重时间写入 | `iec_method.cpp` | 2.4 |
### 阶段二:⚠️ 功能完善(中优先级)
| # | 步骤 | 文件 | 对应问题 |
|---|------|------|:---:|
| 2.1 | 实现 `GetTimeItfs`/`SetTimeItfs` | `iec_method.cpp` | 2.5 |
| 2.2 | 遥控校验接入数据中心 | `iec_method.cpp` | 2.6 |
| 2.3 | 恢复电度变化回调 | `iec_point.cpp` | 2.9 |
### 阶段三:🔧 架构优化(低优先级)
| # | 步骤 | 文件 | 对应问题 |
|---|------|------|:---:|
| 3.1 | 统一使用 XML `inf` 替代硬编码起始地址 | `iec_method.cpp` | 2.7 |
| 3.2 | 启用参数读写回调(按需) | `iec.cpp` + 新增 | 2.8 |
| 3.3 | 启用文件传输回调(按需) | `iec.cpp` + 新增 | 2.8 |
| 3.4 | 启用软件升级回调(按需) | `iec.cpp` + 新增 | 2.8 |
---
## 4. 修复细节
### 4.1 GetDdValueByGroup 修复
```cpp
int32_t GetDdValueByGroup(uint16_t usGroupID, uint16_t usIdx,
TimeDd_Info *pstInfo, void *pvParam, uint8_t ucTimeEn)
{
std::vector<stru_cfg_base> &vec_dd = iec_cfg_ptr_get()->vec_dd;
uint32_t dd_num = vec_dd.size();
if (usIdx >= dd_num) return 0;
// 确定索引范围
uint16_t usMin = 0, usMax = dd_num;
if (usGroupID != 0) {
if (ucTimeEn == 0) { usMin = 0; usMax = 8; }
else { usMin = 8; usMax = dd_num; }
}
if (usIdx >= usMax - usMin) return 0;
uint16_t idx = usMin + usIdx;
stru_cfg_base *p_dd_info = &vec_dd[idx];
pstInfo->uiInfoAddr = p_dd_info->inf;
pstInfo->fVal = p_dd_info->p_data ? *(float *)p_dd_info->p_data : 0.0f;
memset(&pstInfo->stCTime, 0, sizeof(__CP56Time2a));
return 1;
}
```
### 4.2 YX 变化恢复
```cpp
if (val != last_val) {
uint32_t ts_sec = time(NULL);
uint16_t ts_ms = 0;
UserWriteSoeEvent(i, val, ts_sec, ts_ms);
*(uint8_t *)p_last_data = val;
}
```
### 4.3 SOE ucType 补充
```cpp
p_soe_info->usYxPot = usIndex;
p_soe_info->ucState = ucState;
p_soe_info->ucType = vec_st[usIndex].type; // 新增
p_soe_info->uiSeconds = uiSeconds;
p_soe_info->usMs = usMs;
```
---
## 5. 预期影响
| 修复项 | 影响 |
|--------|------|
| 2.1 电度 | 电度总召/组召恢复正常 |
| 2.2 YX变化 | 遥信变位能正常产生 SOE 事件 |
| 2.3 SOE ucType | SOE 事件中单/双点遥信正确区分 |
| 2.4 FaultEvent | 消除无效代码,时间戳正确 |
| 2.5 对时 | CBB 库对时功能可用 |
| 2.6 遥控 | 遥控操作接入安全校验 |
| 2.9 电度变化 | 电度扰动数据正常上送 |