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

154 lines
8.4 KiB
Markdown
Raw Permalink 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.

# libicp67 协议库分析文档
## 1. 模块概述
**路径**: `src/protocol/libicp67/`
**定位**: ICP67 二进制协议库——用于维护软件与 RTU/FTU 自侧之间、以及主板与采样板之间通信的私有协议引擎。负责帧定界、编解码、重传管理。
**文件结构**:
```
src/protocol/libicp67/
├── inc/
│ ├── icp67.h -- TI/COT 常量、帧 ASDU 结构体
│ └── general_method.h -- icp67_get_genneral_method() 前向声明
└── src/
├── icp67.cpp -- 核心:搜帧、解码分发、初始化、组帧、重传
└── general_method.cpp -- 回调 setter、默认 sender 实现
release/inc/myIcp67.h -- 共享契约stru_head、stru_icp67、stru_genneral_method
```
## 2. 协议帧格式
```
| 0x67 | len(2B) | 0x67 | src | dst | dir | ti | cot | info_addr(2B) | dev_addr(4B) | data... | CRC(1B) | 0x16 |
| 帧头1 | 长度 | 帧头2 | 源 | 目的 | 方向 |类型| 传送原因 | 信息体地址 | 设备地址 | 数据体 | 校验和 | 帧尾 |
```
- **TI (Type Identifier)**: 16 种消息类型 (TI_1 ~ TI_207)
- **COT (Cause of Transmission)**: 请求(5)、激活(6)、正常确认(7)、终端响应(8)、MD5不匹配(20)
- **校验**: 8-bit 累加校验和 (data 部分)
- **设备地址**: src/dst 取值1=维护软件, 2=主板, 3=采样板, 4=LCD, 5=XTU
## 3. 核心数据结构
### 3.1 `stru_head` (1字节对齐)
帧头结构,包含所有固定头部字段 + 可变数据区。`len` 字段为 `info_addr` + `dev_addr` + `data[...]` 的总长度。
### 3.2 `stru_icp67` —— 协议实例
| 字段 | 用途 |
|------|------|
| `send_cb` / `search_frame_cb` / `decode_cb` / `timer_handler_cb` | 四个对外回调 |
| `tx[2048]` / `tx_len` | 发送缓冲区 |
| `resend_tx[2048]` / `resend_tx_len` | 重发备份缓冲区 |
| `rtx_flag` / `rtx_sem` / `resend_cnt` / `tm_out` / `tm_cnt` | 重传状态机 |
| `md5[16]` | AO 参数 MD5 校验值 |
| `arg` | 用户数据 (libself_ptl 传入 interface ID) |
### 3.3 `stru_genneral_method` —— 全局回调表
26 个函数指针,分为两组:
- **sender 组** (13个): ao_get, ao_set, iec_point_tbl_get, time_set, self_check_get, upgrade_start, dir_read, file_read_act/confirm, file_write_act/write/write_end_confirm
- **receiver 组** (13个): ao_pop_out, iec_point_tbl_pop_out, self_check_pop_out, dir_pop_out, file_read_act_confirm, file_read, file_write_act_confirm, file_write_confirm, file_write_end, zip_dir_pop_out, zip_file_pop_out, mx_trans, st_trans, dd_trans, soe_trans, fault_trans, mx_change
## 4. 核心函数
### 4.1 `icp67_init(p, send_cb, arg)`
绑定 `send_cb`、`search_frame_cb`(→icp67_search_frame)、`decode_cb`(→icp67_decode)、`timer_handler_cb`(→icp67_timer_handler)。初始化重传信号量、TM 周期(100)、重发计数(0)。
### 4.2 `icp67_search_frame(p_rx, rx_len, p_pos, p_len)`
帧定界器:扫描 `0x67 0x67`验证长度边界、CRC 校验和、帧尾 `0x16`。返回帧位置和有效长度。
### 4.3 `icp67_decode(p_icp67, p_data, len)`
顶层解码分发器:从帧头读取 `ti`,查 `g_map_ti_decode` 映射表,调用对应的 `icp67_decode_ti_{N}` 函数。
### 4.4 `icp67_timer_handler(p_icp67)`
重传定时器TX_FLAG 状态下,每 tick `tm_cnt++`,达到 `tm_out`(100 tick ≈ 1000ms) 且重发次数 < 5 重新发送 `resend_tx`超过 5 次清除 TX_FLAG
### 4.5 各 TI 解码函数
- TI_1: 读参数响应 `ao_pop_out_cb`
- TI_2: 写参数响应 (无数据仅确认)
- TI_3: IEC 点表响应 (支持分帧) `iec_point_tbl_pop_out_cb`
- TI_4: IEC 点表响应 (空桩)
- TI_5: 对时响应
- TI_6: 自检响应 `self_check_pop_out_cb`
- TI_9: 升级响应
- TI_11: 文件操作分发 (9种子命令)
- TI_30: ZIP 波形分发 (4种子命令)
- TI_200: MX 遥测传输 `mx_trans_cb`
- TI_201: ST 遥信传输 `st_trans_cb`
- TI_202: DD 电度传输 `dd_trans_cb`
- TI_203: 遥控 (空桩)
- TI_204: SOE 事件 `soe_trans_cb`
- TI_205: 故障事件 `fault_trans_cb`
- TI_207: 测量扰动 `mx_change_cb`
## 5. 与 libself_ptl 的交互
```
┌─── icp67_init() 初始化 ───┐
│ │
libself_ptl ◄────► g_genneral_method (26回调) ◄────► libicp67
(应用层) ├─ sender: self → icp67 │ (协议引擎)
└─ receiver: icp67 → self │
self_ptl_data_rx ──► search_frame_cb ──► decode_cb ──► method回调 ──► 数据中心
self_ptl_data_tx ◄── send_cb ◄── frame builder (sender函数)
```
## 6. 优缺点分析
### 6.1 优点
| # | 优点 | 说明 |
|---|------|------|
| A1 | **协议与业务分离** | 通过回调表实现清晰的分层架构ICP67 库不依赖任何上层模块 |
| A2 | **TI-COT 状态机完整** | 覆盖 16 种消息类型支持请求/确认/响应等完整交互模式 |
| A3 | **重传机制** | 内置超时重传 (5次×1s)保障可靠通信 |
| A4 | **分帧支持** | TI_3 (IEC 点表) 支持多帧数据传输带帧序号和续传标志 |
| A5 | **帧格式校验完善** | 帧头 0x67×2 + 长度验证 + CRC + 帧尾 0x16五重保障 |
| A6 | **MD5 参数校验** | 参数读写带 MD5 校验防止配置不匹配 |
### 6.2 缺点
| # | 缺点 | 严重程度 | 说明 |
|---|------|----------|------|
| D1 | **全局单例回调表** | 🔴 | `g_genneral_method` 是全局变量多实例场景下无法使用。`stru_icp67` 虽有实例字段但 decode 回调全部走全局表 |
| D2 | **空桩函数** | 🟡 | TI_4 (写IEC点表响应)、TI_203 (遥控) 等为空实现功能不完整 |
| D3 | **重传设计粗糙** | 🟡 | 只备份最后一条发送帧并发场景下只维护一个序列号重传期间收到响应会误清 flag |
| D4 | **CRC 校验弱** | 🟡 | 8-bit 累加和容易碰撞不适合工业环境的长帧 |
| D5 | **回调设置侵入式** | 🟡 | sender 回调的 setter 通过写函数指针体覆盖默认实现 callback 未设置的路径静默失败 |
| D6 | **硬编码参数** | 🟢 | 缓冲区 2048重试 5 超时 1000ms设备地址硬编码缺乏配置入口 |
| D7 | **无帧序号/去重** | 🟢 | 无应用层帧序号重复帧/乱序帧无法检测 |
| D8 | **C 风格内存操作** | 🟢 | 大量 `memcpy`裸指针运算默认结构体 pack(1) 对齐跨平台移植有隐患 |
## 7. 改进方向与措施
### 7.1 架构改进
| 方向 | 措施 | 优先级 |
|------|------|--------|
| **去全局化** | `g_genneral_method` 移入 `stru_icp67`decode 函数通过 `p_icp67->method.xxx_cb` 回调setter 改为 `icp67_set_xxx(p_icp67, cb)` | 🔴 |
| **状态机重构** | 引入独立的类/结构体管理多路请求状态 (request_id + state + timer)替代当前单一的 `rtx_flag/resend_cnt/tm_cnt` 三元组 | 🟡 |
### 7.2 协议增强
| 方向 | 措施 | 优先级 |
|------|------|--------|
| **CRC 升级** | 8-bit 累加和替换为 CRC-16/CRC-CCITT向后兼容可保留 CRC8 但增加 CRC16 字段 | 🟡 |
| **帧序号** | 在帧头增加 1 字节 frame_seq发送端递增接收端检测重复和丢帧 | 🟢 |
| **填充空桩** | 实现 TI_4TI_203 的空桩函数至少返回 NOT_SUPPORTED 确认 | 🟢 |
| **可配置参数** | 超时重试次数缓冲区大小通过 `icp67_init` 参数传入存储在 `stru_icp67` | 🟢 |
### 7.3 代码质量
| 方向 | 措施 | 优先级 |
|------|------|--------|
| **消除硬编码** | `#define`/`constexpr` 替代魔数 (0x67, 0x16, 2048, 5, 100 )统一放到 `icp67.h` | 🟡 |
| **回调返回值** | sender 回调统一返回 `int` (0=成功)decode 回调失败时返回错误码给应用层替代静默吞错 | 🟡 |
| **打包兼容** | `pack(1)` 改为显式 `uint8_t` 数组 + 序列化/反序列化函数消除跨平台对齐风险 | 🟢 |
## 8. 总结
`libicp67` 是一个功能完整但架构老旧的嵌入式协议库核心编解码和重传逻辑是可靠的主要问题集中在**全局单例耦合****可配置性不足**两个层面最高优先级的改进是将全局回调表实例化使其从"单设备绑定"升级为"多实例可复用"的协议引擎从而支撑多通道场景主板与多采样板同时通信)。