feat(libplc): PLC 逻辑引擎模块 + 文档补全 + 计划同步

## libplc 模块 (新)
- src/system/libplc/inc/plc.h / src/plc.cpp: 1252 行, 原工程完整复刻
- 10 种逻辑门 (AND/OR/NOT/62P/62D/RISING/FALLING/SR/RS)
- Kahn 拓扑排序 + 非阻塞定时器 (CLOCK_MONOTONIC)
- 嵌套 Comb XML 递归解析 + R/S 引脚属性
- self_ptl 遥信联动 + datacenter out 信号输出
- dc_get_signal_info_by_id 封装为 plc_set/get_out_value_by_id
- printf → PLC_DBG 可控调试宏 + 'plc dbg on|off' 命令开关
- 代码规范: Tab 缩进/条件分支分行/大括号独占行/函数注释
- 接口适配: func_proc_self_dir/dc_signal_out module_id 对齐
- release/src/system/libplc/makefile + release 头文件

## 文档补全 (之前开发未写文档)
- docs/system/libiec/API-libiec.md (26 个 CS10x 回调, 架构, MQ 流)
- docs/system/libcom_router/API-libcom_router.md
- docs/system/libself_ptl/API-libself_ptl.md
- docs/protocol/libicp67/API-libicp67.md

## 计划同步
- PLAN.md: 阶段 0~4 全部回写状态 
- COMPLETION.md: 清理陈旧 libiec  条目
- docs/README.md: 新增 libiec/libcom_router/libself_ptl/libicp67 索引
- PLAN.md 3.4: 新增 if/大括号/多语句格式规范
- 工作流: 新增 '回写 PLAN.md' 步骤

## X-Macro 注册
- app_modules.h: APP_MODULE(PLC, ...)
- release/src/system/makefile: SUBDIRS 新增 ./libplc
This commit is contained in:
ypc 2026-07-10 15:42:18 +08:00
parent 4976f1a181
commit b00b998ac1
12 changed files with 2964 additions and 32 deletions

View File

@ -37,7 +37,6 @@
| 通讯抽象层测试 | `test_comm.cpp`17项全通过 | ✅ | | 通讯抽象层测试 | `test_comm.cpp`17项全通过 | ✅ |
| Modbus 协议栈 | `libmodbus`(开源库 v3.1.12,导入+日志适配) | ✅ | | Modbus 协议栈 | `libmodbus`(开源库 v3.1.12,导入+日志适配) | ✅ |
| IEC 60870-5-104 | `lib60870`(原工程自研协议栈,导入) | ✅ | | IEC 60870-5-104 | `lib60870`(原工程自研协议栈,导入) | ✅ |
| IEC 点表解析 | `libiec` | ⬜ |
| Modbus 主站管理 | `libmodbus_m`(原工程自研模块,导入+适配) | ✅ | | Modbus 主站管理 | `libmodbus_m`(原工程自研模块,导入+适配) | ✅ |
| 通讯通道解码 | `libcom_decode` | ⬜ | | 通讯通道解码 | `libcom_decode` | ⬜ |
| Web 管理服务 | `libweb_server`3 文件拆分单线程EV_STOP 支持) | ✅ | | Web 管理服务 | `libweb_server`3 文件拆分单线程EV_STOP 支持) | ✅ |

80
PLAN.md
View File

@ -198,6 +198,26 @@ int my_module_do_something(uint32_t id, const char *data);
- 函数行数控制在 80 行以内 - 函数行数控制在 80 行以内
- 复杂逻辑拆分为独立静态函数 - 复杂逻辑拆分为独立静态函数
- 错误路径必须打 LOG_E - 错误路径必须打 LOG_E
- **if/for/while 等关键字后必须有空格**,如 `if (x)` 而非 `if(x)`
- **条件判断与分支必须分行**,禁止同行写法:
- ❌ `if (x) do_thing();`
- ❌ `if (x) { do_thing(); }`
- ❌ `if (x) {`(大括号不许同行)
- ✅ 统一为:
```c
if (x)
{
do_thing();
}
```
- 对 `for` / `while` / `else` / `else if` 同样适用,函数定义也须换行:
```c
static void foo(void)
{
...
}
```
- **多语句禁止同列**,如 `memset(&l, 0, sizeof(l)); l.dst_pin = -1;` 应各占一行
--- ---
@ -218,64 +238,64 @@ int my_module_do_something(uint32_t id, const char *data);
| 序号 | 任务 | 模块 | 产出 | 状态 | | 序号 | 任务 | 模块 | 产出 | 状态 |
|------|------|------|------|------| |------|------|------|------|------|
| 0.1 | 搭建构建系统 | — | `release/linux.mk`, `release/makefile`, `release/build.sh` | | | 0.1 | 搭建构建系统 | — | `release/linux.mk`, `release/makefile`, `release/build.sh` | |
| 0.2 | 创建 `myBase.h` 基础定义 | — | `release/inc/myBase.h`(宏、类型、大小端转换) | | | 0.2 | 创建 `myBase.h` 基础定义 | — | `release/inc/myBase.h`(宏、类型、大小端转换) | |
| 0.3 | 实现侵入式链表 | `liblist` | `src/public/liblist/inc/list.h` | | | 0.3 | 实现侵入式链表 | `liblist` | `src/public/liblist/inc/list.h` | |
| 0.4 | 实现日志系统 | `liblog` | `src/public/liblog/inc/myLog.h`, `src/myLog.c` | | | 0.4 | 实现日志系统 | `liblog` | `src/public/liblog/inc/myLog.h`, `src/myLog.c` | |
| 0.5 | 实现基础工具函数 | `libfunc` | `src/public/libfunc/inc/myFunc.h`, `src/myFunc.c` | | | 0.5 | 实现基础工具函数 | `libfunc` | `src/public/libfunc/inc/myFunc.h`, `src/myFunc.c` | |
| 0.6 | 创建全部预留模块的目录+stub | 所有 P3 | 7 个预留模块的目录骨架 + 返回 0 的 stub | | | 0.6 | 创建全部预留模块的目录+stub | 所有 P3 | 7 个预留模块的目录骨架 + 返回 0 的 stub | |
| 0.7 | 链表 + 日志单元测试 | — | `src/test/test_list.c`, `test_log.c` | | | 0.7 | 链表 + 日志单元测试 | — | `src/test/test_list.c`, `test_log.c` | |
| 0.8 | **编译验证 + 代码审查** | — | 全量编译通过、测试通过 | | | 0.8 | **编译验证 + 代码审查** | — | 全量编译通过、测试通过 | |
### 阶段 1数据基础设施 ### 阶段 1数据基础设施
| 序号 | 任务 | 模块 | 产出 | 状态 | | 序号 | 任务 | 模块 | 产出 | 状态 |
|------|------|------|------|------| |------|------|------|------|------|
| 1.1 | 实现 MD5 摘要算法 | `libmd5` | `src/public/libmd5/` | | | 1.1 | 实现 MD5 摘要算法 | `libmd5` | `src/public/libmd5/` | |
| 1.2 | 实现 xxHash 快速哈希 | `libmy_xxhash` | `src/public/libmy_xxhash/` | | | 1.2 | 实现 xxHash 快速哈希 | `libmy_xxhash` | `src/public/libmy_xxhash/` | |
| 1.3 | 实现 cJSON 解析 | `libcJSON` | `src/public/libcJSON/`(从 RTU 裁剪) | | | 1.3 | 实现 cJSON 解析 | `libcJSON` | `src/public/libcJSON/`(从 RTU 裁剪) | |
| 1.4 | 设计信号数据模型 | — | `dc_signal_t` 等结构体设计文档 | | | 1.4 | 设计信号数据模型 | — | `dc_signal_t` 等结构体设计文档 | |
| 1.5 | 实现数据中心 | `libdatacenter` | C 接口 CRUDC++ 内部用 std::map/vector | | | 1.5 | 实现数据中心 | `libdatacenter` | C 接口 CRUDC++ 内部用 std::map/vector | |
| 1.6 | 实现任务调度 | `libtask` | C 接口C++ 内部 std::thread + std::chrono | | | 1.6 | 实现任务调度 | `libtask` | C 接口C++ 内部 std::thread + std::chrono | |
| 1.7 | 编写单元测试 | — | `test_cjson.c`, `test_datacenter.cpp` | | | 1.7 | 编写单元测试 | — | `test_cjson.c`, `test_datacenter.cpp` | |
| 1.8 | **编译验证 + 代码审查** | — | 全量编译通过、测试通过 | | | 1.8 | **编译验证 + 代码审查** | — | 全量编译通过、测试通过 | |
### 阶段 2通讯与协议 ### 阶段 2通讯与协议
| 序号 | 任务 | 模块 | 产出 | 状态 | | 序号 | 任务 | 模块 | 产出 | 状态 |
|------|------|------|------|------| |------|------|------|------|------|
| 2.1 | 实现通讯抽象层 | `libcomm` | 串口/TCP 统一 C 接口,内部 C++ 封装 | | | 2.1 | 实现通讯抽象层 | `libcomm` | 串口/TCP 统一 C 接口,内部 C++ 封装 | |
| 2.2 | 实现命令处理框架 | `libcmd` | C 接口,内部 std::unordered_map + std::queue | | | 2.2 | 实现命令处理框架 | `libcmd` | C 接口,内部 std::unordered_map + std::queue | |
| 2.3 | 实现 XML 解析 | `libxml` | C 接口myXml.h内部 tinyxml2 C++ 实现 | | | 2.3 | 实现 XML 解析 | `libxml` | C 接口myXml.h内部 tinyxml2 C++ 实现 | |
| 2.4 | 实现 Modbus 协议栈 | `libmodbus` | RTU/TCP 从站纯C | | | 2.4 | 实现 Modbus 协议栈 | `libmodbus` | RTU/TCP 从站纯C | |
| 2.5 | 实现 IEC 60870-5-104 | `lib60870` | 总召、遥测、遥信、遥控纯C | | | 2.5 | 实现 IEC 60870-5-104 | `lib60870` | 总召、遥测、遥信、遥控纯C | |
| 2.6 | 实现 IEC 点表解析 | `libiec` | `src/system/libiec/` | | | 2.6 | 实现 IEC 点表解析 | `libiec` | `src/system/libiec/` | |
| 2.7 | 实现 Modbus 主站管理 | `libmodbus_m` | 轮询队列、采集调度 | | | 2.7 | 实现 Modbus 主站管理 | `libmodbus_m` | 轮询队列、采集调度 | |
| 2.8 | 编写单元测试 | — | `test_modbus.c`, `test_60870.c` | ⬜ | | 2.8 | 编写单元测试 | — | `test_modbus.c`, `test_60870.c` | ⬜ |
| 2.9 | **编译验证 + 代码审查** | — | 全量编译通过、测试通过 | | | 2.9 | **编译验证 + 代码审查** | — | 全量编译通过、测试通过 | |
### 阶段 3系统集成 ### 阶段 3系统集成
| 序号 | 任务 | 模块 | 产出 | 状态 | | 序号 | 任务 | 模块 | 产出 | 状态 |
|------|------|------|------|------| |------|------|------|------|------|
| 3.1 | 实现通讯通道解码 | `libcom_decode` | 多通道帧解析、协议识别分发 | ⬜ | | 3.1 | 实现通讯通道解码 | `libcom_decode` | 多通道帧解析、协议识别分发 | ⬜ |
| 3.2 | 实现 Web 管理服务 | `libweb_server` | REST API + WebSocket | | | 3.2 | 实现 Web 管理服务 | `libweb_server` | REST API + WebSocket | |
| 3.3 | 实现主程序入口 | `RTU` | 模块初始化、主循环 | | | 3.3 | 实现主程序入口 | `RTU` | 模块初始化、主循环 | |
| 3.4 | 端到端集成测试 | — | 多模块联调 | ⬜ | | 3.4 | 端到端集成测试 | — | 多模块联调 | ⬜ |
| 3.5 | **编译验证 + 代码审查** | — | x86 + ARM 交叉编译全通过 | | | 3.5 | **编译验证 + 代码审查** | — | x86 + ARM 交叉编译全通过 | |
| 3.6 | 编写 README 文档 | — | 编译指南、架构图、使用说明 | ⬜ | | 3.6 | 编写 README 文档 | — | 编译指南、架构图、使用说明 | ⬜ |
### 阶段 4后续扩展预留模块实现 ### 阶段 4后续扩展预留模块实现
| 序号 | 任务 | 模块 | 状态 | | 序号 | 任务 | 模块 | 状态 |
|------|------|------|------| |------|------|------|------|
| 4.1 | ICP67 专有协议 | `libicp67` | | | 4.1 | ICP67 专有协议 | `libicp67` | |
| 4.2 | IEC 61850 MMS 主站 | `libmms_m` + `libiec61850m` | ⬜ | | 4.2 | IEC 61850 MMS 主站 | `libmms_m` + `libiec61850m` | ⬜ |
| 4.3 | IEC 61850 MMS 从站 | `libmms_s` + `libiec61850s` | ⬜ | | 4.3 | IEC 61850 MMS 从站 | `libmms_s` + `libiec61850s` | ⬜ |
| 4.4 | 嵌入式 HTTP 服务 | `libmongoose` | | | 4.4 | 嵌入式 HTTP 服务 | `libmongoose` | |
| 4.5 | MQTT 客户端 | `libmy_mosquitto` | ⬜ | | 4.5 | MQTT 客户端 | `libmy_mosquitto` | ⬜ |
| 4.6 | PLC 逻辑引擎 | `libplc` | ⬜ | | 4.6 | PLC 逻辑引擎 | `libplc` | ⬜ |
| 4.7 | 内部自定义协议 | `libself_ptl` | | | 4.7 | 内部自定义协议 | `libself_ptl` | |
--- ---

View File

@ -30,6 +30,7 @@
|------|------|------|------| |------|------|------|------|
| libmodbus | [API-libmodbus.md](protocol/libmodbus/API-libmodbus.md) | C (开源库) | Modbus 协议栈 v3.1.12 | | libmodbus | [API-libmodbus.md](protocol/libmodbus/API-libmodbus.md) | C (开源库) | Modbus 协议栈 v3.1.12 |
| lib60870 | [API-lib60870.md](protocol/lib60870/API-lib60870.md) | C (自研) | IEC 60870-5-101/103/104 协议栈 | | lib60870 | [API-lib60870.md](protocol/lib60870/API-lib60870.md) | C (自研) | IEC 60870-5-101/103/104 协议栈 |
| libicp67 | [API-libicp67.md](protocol/libicp67/API-libicp67.md) | 纯 C | ICP67 自定义协议(帧解析+编解码+核心逻辑) |
| libmongoose | [API-libmongoose.md](protocol/libmongoose/API-libmongoose.md) | C (MIT 开源) | HTTP/WebSocket 嵌入式网络库 v7.22 | | libmongoose | [API-libmongoose.md](protocol/libmongoose/API-libmongoose.md) | C (MIT 开源) | HTTP/WebSocket 嵌入式网络库 v7.22 |
### 系统模块 (system/) ### 系统模块 (system/)
@ -37,7 +38,10 @@
| 模块 | 文档 | 语言 | 说明 | | 模块 | 文档 | 语言 | 说明 |
|------|------|------|------| |------|------|------|------|
| RTU | [API-RTU.md](system/RTU/API-RTU.md) | C + C++ | 主程序入口、X-Macro 框架、模块生命周期 | | RTU | [API-RTU.md](system/RTU/API-RTU.md) | C + C++ | 主程序入口、X-Macro 框架、模块生命周期 |
| libiec | [API-libiec.md](system/libiec/API-libiec.md) | C 接口+C++ 内部 | IEC-104 服务端26回调+环形缓冲+数据中心桥接) |
| libcom_router | [API-libcom_router.md](system/libcom_router/API-libcom_router.md) | C++ | 通信路由中枢(转发规则+协议绑定 dispatch |
| libmodbus_m | [API-libmodbus_m.md](system/libmodbus_m/API-libmodbus_m.md) | C++ | Modbus 主站管理(通道/点表/轮询/写入) | | libmodbus_m | [API-libmodbus_m.md](system/libmodbus_m/API-libmodbus_m.md) | C++ | Modbus 主站管理(通道/点表/轮询/写入) |
| libself_ptl | [API-libself_ptl.md](system/libself_ptl/API-libself_ptl.md) | C++ | 内部自定义协议应用层多FTU帧组装+文件操作) |
| libweb_server | [API-libweb_server.md](system/libweb_server/API-libweb_server.md) | C++ | Web 管理服务HTTP + WebSocket 实时推送) | | libweb_server | [API-libweb_server.md](system/libweb_server/API-libweb_server.md) | C++ | Web 管理服务HTTP + WebSocket 实时推送) |
``` ```

View File

@ -0,0 +1,271 @@
# libicp67 — ICP67 自定义协议库 API 参考
## 模块概述
**位置**: `src/protocol/libicp67/`
**定位**: ICP67 二进制协议引擎 — 负责帧定界、编解码、重传管理。纯 C 实现extern "C" 接口。
**依赖**: `liblog` (日志), POSIX `sem_t` (信号量)
**被依赖**: `libself_ptl` (自协议应用层)
## 协议帧格式
```
| 0x67 | len(2B) | 0x67 | src | dst | dir | ti | cot | info_addr(2B) | dev_addr(4B) | data... | CRC(1B) | 0x16 |
| 帧头1 | 长度 | 帧头2 | 源 | 目的 | 方向 |类型| 原因 | 信息体地址 | 设备地址 | 数据体 | 校验和 | 帧尾 |
```
- **帧头**: 0x67 0x67 (双字节定界)
- **校验**: 8-bit 累加和 (CRC8)
- **帧尾**: 0x16
- **设备地址**: src/dst 取值 0=维护软件, 1=主板, 2=主板, 3=采样板, 4=LCD
## 架构
```
libself_ptl (应用层)
├─ icp67_init() 初始化
├─ icp67_set_*_cb() 注册 17 个回调
libicp67 (协议引擎)
├─ icp67_search_frame() 帧定界
├─ icp67_decode() 解码分发
├─ icp67_timer_handler() 重传管理
├─ Sender 函数 (13个) 组帧发送
└─ 16 种 TI 解码函数
```
## 文件清单
| 文件 | 行数 | 说明 |
|---|---|---|
| `release/inc/myIcp67.h` | 331 | 公共契约: 帧结构、回调类型、`stru_icp67`、常量宏 |
| `src/protocol/libicp67/inc/icp67.h` | ~500 | 内部头: TI/COT枚举、ASDU结构体、内部API声明 |
| `src/protocol/libicp67/src/icp67_frame.c` | 126 | 帧定界、CRC校验、帧构造、调试打印 |
| `src/protocol/libicp67/src/icp67_decode.c` | 1024 | 16种TI解码+文件/ZIP子命令分发 |
| `src/protocol/libicp67/src/icp67_core.c` | 645 | 初始化、回调注册、重传管理、Sender函数、定时器 |
## 对外 API
### 初始化
```c
void icp67_init(stru_icp67 *p_icp67, icp67_send_cb send_cb, void *arg);
```
初始化协议实例,绑定发送回调和用户参数。内部自动绑定:
- `search_frame_cb``icp67_search_frame()`
- `decode_cb``icp67_decode()`
- `timer_handler_cb``icp67_timer_handler()`
- 创建重传信号量 `rtx_sem`
- 初始化 13 个 Sender 回调为内部函数
- 设置超时参数 `tm_out = 1000ms / 10ms = 100 tick`
```c
int icp67_set_ao_cfg_md5(stru_icp67 *p_icp67, uint8_t *p_md5);
```
设置 AO 参数配置的 MD5 校验值 (16字节),用于后续 TI_1/TI_2 帧的 MD5 验证。
### 回调注册 (17 个 setter)
**pop_out 类 (3 个)** — 解码后回调注册:
| 函数 | 注册回调 | 触发场景 |
|---|---|---|
| `icp67_set_ao_pop_out_cb` | `ao_pop_out_cb` | TI_1 参数读取响应 |
| `icp67_set_iec_point_tbl_pop_out_cb` | `iec_point_tbl_pop_out_cb` | TI_3 点表读取响应 |
| `icp67_set_self_check_pop_out_cb` | `self_check_pop_out_cb` | TI_6 自检响应 |
**文件操作类 (6 个):**
| 函数 | 注册回调 | 触发场景 |
|---|---|---|
| `icp67_set_dir_pop_out_cb` | `dir_pop_out_cb` | TI_11_2 目录响应 |
| `icp67_set_file_read_act_confirm_cb` | `file_read_act_confirm_cb` | TI_11_4 读文件激活响应 |
| `icp67_set_file_read_cb` | `file_read_cb` | TI_11_5 读文件内容 |
| `icp67_set_file_write_act_confirm_cb` | `file_write_act_confirm_cb` | TI_11_8 写文件激活响应 |
| `icp67_set_file_write_confirm_cb` | `file_write_confirm_cb` | TI_11_10 写文件确认 |
| `icp67_set_file_write_end_cb` | `file_write_end_cb` | TI_11_10 写文件结束 |
**ZIP 类 (2 个):**
| 函数 | 注册回调 | 触发场景 |
|---|---|---|
| `icp67_set_zip_dir_pop_out_cb` | `zip_dir_pop_out_cb` | TI_30_1 录波目录 |
| `icp67_set_zip_file_pop_out_cb` | `zip_file_pop_out_cb` | TI_30_3 录波文件内容 |
**数据传输类 (6 个):**
| 函数 | 注册回调 | 触发场景 |
|---|---|---|
| `icp67_set_mx_trans_cb` | `mx_trans_cb` | TI_200 遥测传输 |
| `icp67_set_st_trans_cb` | `st_trans_cb` | TI_201 遥信传输 |
| `icp67_set_dd_trans_cb` | `dd_trans_cb` | TI_202 电度传输 |
| `icp67_set_soe_trans_cb` | `soe_trans_cb` | TI_204 SOE 事件 |
| `icp67_set_fault_trans_cb` | `fault_trans_cb` | TI_205 故障事件 |
| `icp67_set_mx_change_cb` | `mx_change_cb` | TI_207 遥测扰动 |
### 帧操作 (内部 API)
```c
int icp67_search_frame(uint8_t *p_data, uint16_t len, uint16_t *p_pos, uint16_t *p_valid_len);
int icp67_decode(stru_icp67 *p_icp67, uint8_t *p_data, uint16_t len);
void icp67_timer_handler(stru_icp67 *p_icp67);
void icp67_make_head(uint8_t dst, uint8_t ti, uint8_t cot, uint16_t inf, uint8_t *p_tx, uint16_t *tx_len);
void icp67_make_tail(uint8_t *p_tx, uint16_t *tx_len);
void icp67_show_frame(uint8_t *p_data, uint16_t len);
```
### 重传管理 (线程安全)
```c
void icp67_rtx_flag_set(stru_icp67 *p_icp67, uint8_t flag, uint8_t resend_cnt, uint32_t tm_cnt);
void icp67_rtx_flag_get(stru_icp67 *p_icp67, uint8_t *flag, uint8_t *resend_cnt, uint32_t *tm_cnt);
void icp67_rtx_resend_inc(stru_icp67 *p_icp67);
void icp67_rtx_tm_inc(stru_icp67 *p_icp67);
```
所有读写操作通过 `rtx_sem` 信号量保护。
## 核心数据结构
### stru_icp67 — 协议实例
```c
typedef struct _icp67 {
void *arg; // 用户数据 (interface ID)
icp67_send_cb send_cb; // 发送回调 (→物理层)
icp67_search_frame_cb search_frame_cb; // 帧搜索
icp67_decode_cb decode_cb; // 解码
icp67_timer_handler_cb timer_handler_cb; // 定时器
stru_genneral_method method; // 回调表 (实例化)
uint8_t md5[16]; // AO参数MD5
uint8_t tx[2048]; // 发送缓冲区
uint8_t resend_tx[2048]; // 重发备份
uint8_t rtx_flag; // 重传标志
sem_t rtx_sem; // 重传信号量
uint8_t resend_cnt; // 重发计数
uint32_t tm_out; // 超时阈值
uint32_t tm_cnt; // 当前tick
} icp67;
```
### stru_genneral_method — 回调表 (29 个函数指针)
- **Sender 组** (13个): 方向 self_ptl → icp67 → 物理层
- ao_get, ao_set, iec_point_tbl_get, time_set, self_check_get
- upgrade_start, dir_read, file_read_act, file_write_act
- file_write, file_read_confirm, file_write_end_confirm
- **Receiver 组** (16个): 方向 物理层 → icp67 → self_ptl
- 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
## TI 消息类型清单
| TI | 名称 | COT | 方向 | 说明 |
|:--:|---|---|---|---|
| 1 | 读独立编码参数 | 5→7 | 请求→响应 | 带 MD5 校验的参数读取 |
| 2 | 写独立编码参数 | 6→7 | 激活→确认 | 参数写入,含 MD5 |
| 3 | 读组合编码参数 | 5→7 | 请求→响应 | 点表/校准数据,支持分帧 |
| 4 | 写组合编码参数 | - | - | 空桩 (未使用) |
| 5 | 对时 | 5→7 | 请求→响应 | 终端时间同步 |
| 6 | 自检读取 | 5→7 | 请求→响应 | 终端状态/版本号 |
| 9 | 升级 | 5→7 | 请求→响应 | 固件升级 |
| 11 | 文件操作 | 5→7 | 请求→响应 | 目录/文件读写, 9 种子命令 |
| 30 | 录波文件 | 5 | 上行 | ZIP 波形目录/文件传输 |
| 200 | 遥测传输 | 6 | 上行 | 采样板→主板 MX |
| 201 | 遥信传输 | 6 | 上行 | 采样板→主板 ST |
| 202 | 计量传输 | 6 | 上行 | 采样板→主板 DD |
| 203 | 遥控交互 | - | - | 空桩 (未使用) |
| 204 | SOE 传输 | 3 | 上行 | 事件顺序记录 |
| 205 | 故障传输 | 3 | 上行 | 故障事件 (含 ST+MX) |
| 207 | 扰动传输 | 3 | 上行 | 遥测扰动数据 |
## 与原工程的差异
| 维度 | 原 RTU (icp67.cpp) | 重构后 (纯C 4文件) |
|---|---|---|
| 回调表 | 全局 `g_genneral_method` | 实例化 `p_icp67->method` |
| TI 映射 | C++ `std::map` | C 数组 + 线性查表 |
| 故障解码 | `std::vector` | 固定数组 `[MAX_FAULT_*_INFO]` |
| 文件格式 | `icp67.cpp` (1429行) + `general_method.cpp` (88行) | 4 文件: frame(126) + decode(1024) + core(645) + header(~830) |
| 语言 | C++ | 纯 C (extern "C" 接口) |
| 常量 | 魔数 | 命名 `#define` (ICP67_TX_BUF_SIZE 等) |
| 空桩 | TI_4/TI_203 空 | LOG_E + RX_FLAG 设置 |
## 完成状态
### ✅ 已完成
- [x] 帧定界/校验 (search_frame, CRC)
- [x] 16 种 TI 解码 (含文件/ZIP 子命令)
- [x] 13 个 Sender 函数 (组帧发送)
- [x] 17 个回调 setter (实例化注册)
- [x] 重传管理 (4 函数, sem 线程安全)
- [x] 定时器处理 (10ms tick, 5 次重试)
- [x] TI_4/TI_203 空桩填充
- [x] 多实例隔离 (回调表实例化)
- [x] 魔数 → 命名常量
- [x] C 数组查表替代 std::map
- [x] 单元测试 (21 项全通过)
### ⬜ 未完成
- [ ] TI_203 遥控交互实现 (FTU 固件不支持, 暂缓)
> 以下两项因 FTU 固件不可改动, 已删除:
> ~~CRC 升级 (需 FTU 同步改帧格式)~~
> ~~帧序号/去重 (需 FTU 同步改帧格式)~~
## 新增功能 (2026-07-09)
### 可配置超时/重试
```c
// 旧
void icp67_init(stru_icp67 *p, icp67_send_cb cb, void *arg);
// 新: 传 0 使用默认值 (1000ms, 5次)
void icp67_init(stru_icp67 *p, icp67_send_cb cb, void *arg,
uint32_t tm_out_ms, uint8_t resend_max);
// 示例
icp67_init(&icp, send_cb, &iface, 2000, 3); // 串口慢速: 2s超时, 重试3次
icp67_init(&icp, send_cb, &iface, 0, 0); // 使用默认值
```
`stru_icp67` 新增字段: `resend_max`, `tm_out_ms`
### 零拷贝环形缓冲区搜索
```c
int icp67_search_frame_in_ring(const uint8_t *buf, uint16_t size,
uint16_t rptr, uint16_t cnt,
uint16_t *p_pos, uint16_t *p_valid_len);
```
直接从环形缓冲区读指针扫描帧, 省去 `get_rx_data()` 的 2048 字节 `memcpy`
`self_ptl` 已接入, 仅 IEC-104 检测保留一次全量拷贝。
## 测试覆盖
| 测试项 | 覆盖内容 | 状态 |
|---|---|---|
| T1 帧构造 | make_head + make_tail | ✅ |
| T2 帧搜索 | 正常帧、无效帧头、NULL参数 | ✅ |
| T3 CRC | 基本累加、溢出回绕 | ✅ |
| T4 初始化 | 绑定回调、信号量、超时参数 | ✅ |
| T5 重传管理 | set/get、resend_inc | ✅ |
| T6 回调注册 | 17 个 setter 全路径 | ✅ |
| T7 解码无效 | NULL参数 | ✅ |
| T8 定时器 | NULL、空闲态 | ✅ |
| T9 MD5 | 正常设置、NULL参数 | ✅ |
| T10 未知 TI | 0xFF 帧 | ✅ |
| T11 Sender | self_check_get、iec_point_tbl_get、NULL安全 | ✅ |
| T12 解码 TI | TI_1 MD5 匹配、TI_4 空桩 | ✅ |
| T13 多实例 | 实例间回调隔离 | ✅ |

View File

@ -0,0 +1,177 @@
# libcom_router — 通信路由中枢 API 参考
## 模块概述
**位置**: `src/system/libcom_router/`
**定位**: RTU 通信路由中枢。负责:
- 转发通道管理 (TCP/串口 → FTU 串口透传)
- FTU 串口接收分路 (按帧内容区分维护PC/self_ptl)
- 跨模块回调注册 (与 self_ptl 解耦)
**依赖**: `libcomm`, `libicp67`(帧头检测), `liblog`, `libdatacenter`
**不依赖**: self_ptl, libiec (通过 `app_wiring()` 运行时解耦)
## 架构
```
libcom_router
┌──────────┼──────────┐
│ │
转发通道(TCP) FTU 串口
│ │
Step1: 直接透传 ────→ ┌── Step2: 分路 ──┐
│ │
ICP67 dev=0 IEC 0x68 ICP67 dev=1
│ │ │
回传转发源 回传转发源 self_ptl
(维护软件) (维护软件) (RTU自身)
```
**注意**: RTU 自身的 IEC-104 不走 com_router由 libiec 直管 libcomm。
## 文件清单
| 文件 | 行数 | 说明 |
|---|---|---|
| `inc/com_router.h` | 98 | 通道配置、转发规则、回调注册 API |
| `src/com_router.cpp` | 385 | 通道管理、配置加载、状态回调、主循环 |
| `src/com_router_dispatch.cpp` | 191 | 转发透传 + FTU 串口分路 |
## 对外 API
### 配置加载
```c
int com_router_config_load(const char *json_path);
```
从 JSON 加载通道配置和转发规则。未调用时使用硬编码默认配置。
### 回调注册 (模块解耦)
```c
typedef void (*com_router_dispatch_cb)(uint32_t interface, const unsigned char *data, int len);
int com_router_register_dispatch(const char *bind_app, com_router_dispatch_cb cb);
```
协议模块通过此 API 接收 FTU 串口的 ICP67 dev=1 帧。
**调用者**: `app_sys.cpp``app_wiring()`
**示例**:
```c
com_router_register_dispatch("self_ptl", self_ptl_router_wrapper);
```
### 查询 API
```c
uint32_t com_router_interface_get(const char *key); // key → interface
int com_router_fd_get(const char *key); // key → socket_fd
int com_router_id_get_by_bind(const char *bind_app); // bind_app → ch_id
```
### 应用线程入口
```c
int app_com_router_init1(void *arg); // 创建通道 + 注册回调
int app_com_router_init2(void *arg); // 连接通道
void *app_com_router(void *arg); // 主循环
```
## 路由规则 (v2 — bind_app 协议绑定)
```
com_router_recv_cb(id, fd, data, len)
├─ Step 1: forward_rule → FTU串口透传
├─ Step 2: bind_app 非空 → dispatch 投递给注册协议
└─ Step 3: bind_app 为空 → FTU串口帧内容分路
├─ ICP67 dev=0 → 回传维护
├─ IEC → 回传维护
└─ ICP67 dev≠0 → MQ → self_ptl
```
**示例**: `tcp_master(:2404)` 配置 `bind_app="iec"` → 整帧直投 libiec
### bind_app 注册 API
```c
typedef void (*com_router_dispatch_cb)(uint32_t interface, const unsigned char *data, int len);
int com_router_register_dispatch(const char *bind_app, com_router_dispatch_cb cb);
```
## 配置结构
### 通道配置
```c
typedef struct {
char key[32]; // "serial_ftu"
char bind_app[16]; // "" (FTU串口不需要绑定)
int type; // COMM_TYPE_UART / COMM_TYPE_TCP_SERVER
union_comm_para para; // 通道参数
int id; // comm_create 返回值
int socket_fd; // 当前 fd, -1=未连接
uint32_t interface; // (id<<16)|fd
} com_channel_t;
```
### 转发规则
```c
typedef struct {
char listen_ip[32]; // "0.0.0.0"
int listen_port; // 2405
char target_type[16]; // "uart"
char target_dev[64]; // "/dev/ttyS1"
int sock_fd; // accept 后的 client fd
int target_ch_id; // 目标通道 id
} com_forward_rule_t;
```
## 默认配置 (硬编码兜底)
| 通道 | key | 类型 | bind_app | 说明 |
|---|---|---|---|---|
| 串口 | `serial_ftu` | UART 115200 | `""` | FTU连接, bind_app 空→帧内容分路 |
| TCP | `tcp_master` | TCP :2404 | `"iec"` | IEC-104主站, bind_app 绑定后直投 libiec |
| 转发规则 | 监听 | 目标 | 说明 |
|---|---|---|---|
| 维护透传 | 0.0.0.0:2405 | FTU 串口 | 维护软件直连 FTU |
## 多 FTU 扩展
```
新增 FTU 只需:
1. 配置加一个串口通道 + 一个转发规则
2. com_router 自动按帧的 dev_addr 分路
3. self_ptl 通过 interface 区分不同 FTU
```
## 完成状态
### ✅ 已完成
- [x] 通道创建/连接/状态回调
- [x] 转发通道 → FTU 串口透传
- [x] FTU 串口接收三路分路 (ICP67 dev=0 / IEC / ICP67 dev=1)
- [x] 跨模块回调注册 (app_wiring 解耦)
- [x] bind_app 协议绑定路由 + register_dispatch API
- [x] JSON 解析 channels/forward_rules/bind_app
- [x] TCP accept + 客户端 fd 管理
- [x] X-Macro + EV_STOP
- [x] 通道健康检测
### ⬜ 未完成
- [ ] 串口热插拔/自动重连
- [ ] 单元测试 (test_com_router.c)
- [ ] 通道流量统计上报 (EV_TIMER3)

View File

@ -0,0 +1,257 @@
# API-libiec — IEC 60870-5-104 服务端模块
> 版本: v1.0
> 日期: 2026-07-10
> 来源: 基于原工程 12 个 IEC 子文件聚合重构
> 状态: ✅ 已实现x86 + ARM 双平台编译通过(零警告)
---
## 1. 模块概述
libiec 是 RTU 通讯装置的 **IEC 60870-5-104 服务端(从站)模块**,作为 X-Macro 框架的线程模块运行。通过 `com_router``bind_app="iec"` 机制接收 TCP :2404 端口的主站连接数据,底层协议栈复用 `lib60870` 自研库。
| 功能 | 说明 |
|------|------|
| IEC-104 从站协议 | 支持 CS101 / CS104 两种链路类型 |
| 并发连接管理 | 最多 3 路并发主站连接 (MAX_IEC_NUM=3),槽位复用 |
| 超时回收 | 链路 600s 无活动自动回收 slot |
| XML 点表解析 | 从 `config/IEC60870/iec1014.xml` 解析 St/Mx/Co/Dd/Ao/Param 六类信号 |
| 数据中心桥接 | 信号变更回调自动写入 SOE/扰动遥测/故障/电度环形缓冲区 |
| 多主站分发 | 环形缓冲区多出指针 (out_ptrs),每路连接独立消费位置 |
| MQ 桥接 | COM_TO_IEC / IEC_TO_COM 双队列,通过 com_router 转发 |
| 26 个 CS10x 回调 | 完整实现总召、遥测、遥控、电度、参数、定值、文件传输、扰动 |
### 架构
```
com_router (bind_app=iec)
▼ MQ_COM_TO_IEC
iec104_data_rx()
CS10x_104Init / CS10x_DoRecv
▼ ┌──────────────────────────────────────────┐
│ │ 26 个回调 (protocol_register_callbacks) │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ │总召/遥信 │ │遥测/电度 │ │遥控/参数 │ │
│ │ │定值/对时 │ │故障/扰动 │ │文件传输 │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │
│ └──────────────────────────────────────────┘
▼ MQ_IEC_TO_COM → com_router → TCP → 主站
```
### 与原工程对比
| 维度 | 原工程 (12 文件) | 重构后 (3 文件) |
|------|-----------------|-----------------|
| 文件数 | 12 | 3 (~75% 减少) |
| 代码行数 | ~2500+ | 1474 |
| 槽位管理 | 分散在多文件 | 统一 g_iec[MAX_IEC_NUM] |
| 环形缓冲区 | 5 个独立结构体 | 4 个模板化 ring_*_t (sem + out_ptrs) |
| 回调注册 | 分散初始化 | protocol_register_callbacks() 集中 |
| 命令支持 | 无 | CMD_REGISTER_C 测试命令 |
| EV_STOP | 无 | 支持优雅退出 |
---
## 2. 文件结构
```
src/system/libiec/
├── inc/
│ ├── iec104.h # 公共头: stru_iec, iec_soe_info_t, iec_yc_info_t, API 声明
│ └── iec104_cfg.h # 点表配置: stru_iec_sig, stru_iec_cfg
└── src/
├── iec104.cpp # CS10x 初始化 + slot 管理 + 26 回调 + 收发桥接 (1252行)
├── iec104_cfg.cpp # XML 点表解析 (148行)
└── iec104_point.cpp # 数据中心桥接 — 信号变更回调 → 环形缓冲区 (290行)
release/
└── {x86,arm}/lib/
└── libiec.a # 编译产物
```
---
## 3. 核心数据结构
### 3.1 槽位结构 (`stru_iec`)
每路并发连接占用一个槽位,全局数组 `g_iec[MAX_IEC_NUM]` (MAX_IEC_NUM=3)
| 字段 | 类型 | 说明 |
|------|------|------|
| `is_busy` | `uint8_t` | 槽位占用标志0=空闲 |
| `iec_type` | `CS10x_Type` | CS104_TYPE_S / CS101_TYPE_S |
| `interface` | `uint32_t` | 通道唯一标识 (ch_id<<16 \| fd) |
| `tm_out` | `uint32_t` | 超时计数器 (ms),超过 600s 自动回收 |
| `rx[IEC_BUF_SIZE]` | `uint8_t[1024]` | 接收缓冲区 |
| `tx[IEC_BUF_SIZE]` | `uint8_t[1024]` | 发送缓冲区 |
| `pub[IEC_BUF_SIZE]` | `uint8_t[1024]` | 自主上传缓冲区 (总召/扰动) |
| `bak[IEC_BUF_SIZE]` | `uint8_t[1024]` | 备用缓冲区 |
| `cs10x` | `CS10x` | lib60870 协议栈句柄 |
### 3.2 环形缓冲区
4 个环形缓冲区均带独立信号量 (sem_t) 和多出指针 (out_ptrs),支持多主站并发消费:
| 缓冲区 | 容量 | 记录类型 | 用途 |
|--------|------|---------|------|
| `g_soe_ring` | 300 | SOE (时标+状态) | 遥信变位事件 |
| `g_yc_ring` | 200 | 扰动遥测 (idx+val) | 遥测越限扰动 |
| `g_fault_ring` | 200 | 故障 (SOE+遥测) | 故障录波事件 |
| `g_dd_ring` | 50 | 电度 (CP56Time2a+val) | 电度累计 |
### 3.3 点表配置 (`stru_iec_cfg`)
`config/IEC60870/iec1014.xml` 解析6 类信号向量:
| 向量 | 信号类型 | IOA 起始 | 默认类型 |
|------|---------|---------|---------|
| `vec_st` | 遥信 (St) | 0x0001 | DATA_TYPE_U8 |
| `vec_mx` | 遥测 (Mx) | 0x4001 | DATA_TYPE_F32 |
| `vec_co` | 遥控 (Co) | — | DATA_TYPE_U8 |
| `vec_dd` | 电度 (Dd) | 0x6401 | DATA_TYPE_F32 |
| `vec_ao` | 参数 (Ao) | — | 无默认 (XML 必须指定) |
| `vec_param` | 定值 (Param) | — | 无默认 (XML 必须指定) |
每条信号 (`stru_iec_sig`) 含: `link` (数据中心路径), `desc` (描述), `inf` (IOA), `type` (数据类型), `invert` (遥信取反), `factor`/`offset` (遥测系数偏移), `p_data` (数据指针)。
---
## 4. API 参考
### 4.1 公共头 API (iec104.h)
| 函数 | 功能 | 参数 | 返回值 |
|------|------|------|--------|
| `iec104_get_by_interface()` | 按 interface 查找 IEC 实例 | `uint32_t interface` | `stru_iec *` 或 NULL |
| `iec104_data_rx()` | MQ 数据入口 (从 com_router 接收) | `uint8_t *msg` | 0=成功, -1=失败 |
| `iec104_task()` | 10ms 定时器处理 | `uint16_t gap` (恒10) | void |
### 4.2 线程入口
| 函数 | 功能 | 说明 |
|------|------|------|
| `app_iec_init1()` | 第一阶段初始化 | 解析 XML 点表 (`iec_cfg_parse`) |
| `app_iec_init2()` | 第二阶段初始化 | 注册数据中心回调 (`iec104_point_init`) |
| `app_iec()` | 主循环 | `while(1)` 收 MQ_COM_TO_IEC + 10ms 定时处理 |
### 4.3 点表 API (iec104_cfg.h)
| 函数 | 功能 | 参数 | 返回值 |
|------|------|------|--------|
| `iec_cfg_ptr_get()` | 获取全局配置指针 | void | `stru_iec_cfg *` |
| `iec_cfg_parse()` | 解析 XML 点表文件 | `const char *xml_path` | 0=成功, -1=失败 |
### 4.4 环形缓冲区回调 (iec104_point.cpp → iec104.cpp)
| 函数 | 功能 |
|------|------|
| `cb_soe_write()` | 写入 SOE 记录 (遥信变位) |
| `cb_yc_disturb_write()` | 写入扰动遥测记录 |
| `cb_dd_disturb_write()` | 写入电度记录 |
| `cb_fault_write()` | 写入故障事件记录 |
---
## 5. CS10x 回调清单 (26 个)
### 5.1 时间 & 初始化 (4)
| 回调 | 功能 | CS10x 注册 |
|------|------|-----------|
| `cb_get_time` | 获取当前时间 (CP56Time2a) | 时钟回调 |
| `cb_set_time` | 设置系统时间 (对时) | 时钟回调 |
| `cb_104init_callback` | 接收 CS104 初始化完成通知 | 104 专用 |
| `cb_tm_send_result` | 对时报文发送结果通知 | COI 回调 |
### 5.2 总召 (3)
| 回调 | 功能 |
|------|------|
| `cb_st` | 遥信总召 — 遍历 vec_st 打包 SQ=1 报文 |
| `cb_mx` | 遥测总召 — 遍历 vec_mx 打包浮点报文 |
| `cb_dd` | 电度总召 — 遍历 vec_dd 打包 CP56Time2a 报文 |
### 5.3 遥控 (5)
| 回调 | 功能 |
|------|------|
| `cb_yk_set` | 遥控选择/执行 — 遍历 vec_co 查找 IOA, 写入 datacenter |
| `cb_yk_confirm_func` | 遥控确认回调 |
| `cb_yk_termination_func` | 遥控终止回调 |
| `cb_yk_order_func` | 遥控命令通知 |
| `cb_yx_over_time_confirm_func` | 遥信超时确认 |
### 5.4 参数 & 定值 (4)
| 回调 | 功能 |
|------|------|
| `cb_param_get_func` | 参数 (Ao) 读取 — 遍历 vec_ao |
| `cb_param_set_func` | 参数 (Ao) 设置 — 写 datacenter |
| `cb_offset_get_func` | 定值 (Param) 读取 — 遍历 vec_param |
| `cb_offset_set_func` | 定值 (Param) 设置 — 写 datacenter |
### 5.5 扰动 & 故障 (5)
| 回调 | 功能 |
|------|------|
| `cb_dir_num` | 目录数量查询 |
| `cb_soe_ring_get_one` | 从 SOE 环形缓冲区读取一条 |
| `cb_yc_ring_get_one` | 从扰动遥测环形缓冲区读取一条 |
| `cb_fault_ring_get_one` | 从故障环形缓冲区读取一条 |
| `cb_dd_ring_get_one` | 从电度环形缓冲区读取一条 |
### 5.6 文件传输 (5)
| 回调 | 功能 |
|------|------|
| `cb_file_read` | 文件读回调 |
| `cb_file_write` | 文件写回调 |
| `cb_file_wr_finish` | 文件写入完成回调 |
| `cb_file_call_func` | 文件服务调用 |
| `cb_dir_num` | 目录服务 (与扰动共用) |
---
## 6. MQ 消息流
```
主站 → TCP :2404 → com_router (bind_app=iec)
→ MQ_COM_TO_IEC
→ app_iec() 主循环收
→ CS10x_DoRecv()
→ 对应回调 → datacenter
datacenter 信号变更 (St/Mx)
→ on_st_change / on_mx_change 回调
→ cb_soe_write / cb_yc_disturb_write → 环形缓冲区
总召/扰动触发:
→ iec104_data_tx() → MQ_IEC_TO_COM
→ com_router → TCP → 主站
```
---
## 7. 配置依赖
| 配置文件 | 用途 |
|----------|------|
| `config/CHANNEL/channel_cfg.json` | TCP :2404 配置 `bind_app="iec"` |
| `config/IEC60870/iec1014.xml` | IEC 点表 (St/Mx/Co/Dd/Ao/Param) |
| `config/SYSTEM/app_config.json` | X-Macro 框架启停控制 |
---
## 8. 已知限制
- 扰动文件 (COMTRADE) 上传/下载: 回调已注册但无实际文件系统实现
- 遥控执行超时: 使用固定 30s 超时,不支持配置
- 缓冲区满: 环形缓冲写满后丢弃最早记录 (无 overflow 告警回调)
- 只有 IEC-104 从站模式,未实现主站模式 (CS10x_Type 预留 CS104_TYPE_M/CS101_TYPE_M)

View File

@ -0,0 +1,209 @@
# libself_ptl — 自协议应用层模块 API 参考
## 模块概述
**位置**: `src/system/libself_ptl/`
**定位**: RTU 系统中连接 ICP67 协议库与数据中心的上层集成模块。负责:
- ICP67 协议初始化
- 双协议帧解复用 (ICP67 + IEC-104)
- 信号注册到数据中心 (790 ST + 500 MX + 56 CO + 64 DD + 1564 AO)
- 17 个回调桥接到数据中心
- 定时器驱动重传管理
**依赖**: `libicp67` (协议引擎), `libdatacenter` (数据中心), `tinyxml2` (XML 解析), `liblog` (日志)
**被依赖**: `RTU 主程序` (通过 X-Macro 框架)
## 架构
```
config/SELF_PTL/self_ptl.xml (2988行, 790+ 信号)
self_ptl_cfg.cpp XML解析 (tinyxml2)
self_ptl.cpp 核心模块 (不依赖 com_router ✅)
├─ self_ptl_init() 初始化 ICP67 + 注册信号
├─ self_ptl_data_rx(if,*) 接收数据 (interface 区分多FTU)
├─ self_ptl_data_tx(*,if) 发送数据 (interface 定位通道)
└─ app_self_ptl() 线程主循环 (事件驱动)
│ app_wiring() 注册回调 (app_sys.cpp 集中解耦)
com_router (不直接依赖 ✅)
```
## 文件清单
| 文件 | 行数 | 说明 |
|---|---|---|
| `src/system/libself_ptl/inc/self_ptl.h` | 144 | 配置数据结构、双协议常量、事件定义 |
| `src/system/libself_ptl/inc/self_ptl_cfg.h` | 32 | XML 解析声明 |
| `src/system/libself_ptl/src/self_ptl.cpp` | 526 | 核心: 初始化、双协议解复用、信号注册、主循环 |
| `src/system/libself_ptl/src/self_ptl_cfg.cpp` | 336 | tinyxml2 解析 St/Mx/Co/Dd/Ao/Param |
| `src/system/libself_ptl/src/self_ptl_cb.cpp` | 251 | 17 个回调实现 (→数据中心桥接) |
## 对外 API
### 初始化 (C++ 实现, extern "C" 接口)
```c
int app_self_ptl_init1(void *arg); // 阶段1: 解析 XML + 初始化协议
int app_self_ptl_init2(void *arg); // 阶段2: 信号注册 (已在 init1 中完成)
void *app_self_ptl(void *arg); // 线程主循环
```
### 数据接收 (多 FTU 支持)
```c
void self_ptl_data_rx(uint32_t interface, uint8_t *p_data, uint16_t len);
```
从 com_router 接收原始帧数据。
- `interface`: (ch_id<<16)|fd, 区分多 FTU 来源
- 内部更新 `g_self_ptl.interface` 供发送回程
### 发送回调
```c
static void self_ptl_data_tx(uint8_t *p_tx, uint16_t tx_len, void *arg);
```
ICP67 协议引擎的发送回调。
- `arg` 指向 `g_self_ptl.interface`, 用于定位发送目标通道
- TODO: 完成后端 comm_send 调用
### 定时器
```c
void self_ptl_task(void);
```
每 10ms (EV_TIMER1) 调用一次,触发 ICP67 重传定时器。
## 配置文件格式
`config/SELF_PTL/self_ptl.xml` 结构:
```xml
<Root>
<St count="790">
<Signal saddr="self_ptl.st.1" desc="远方遥信1-手分遥信" inf="1"/>
...
</St>
<Mx count="500">
<Signal saddr="self_ptl.mx.1" desc="..." inf="1"/>
...
</Mx>
<Co count="56">
<Signal saddr="self_ptl.co.1" desc="..." inf="1"/>
...
</Co>
<Dd count="64">
...
</Dd>
<Ao count="1564" md5="60e612e1c2cd516e815d9a2dfd647f4b">
<Signal saddr="self_ptl.ao.1" desc="..." inf="1" type="float" unit="kV" min="0" max="100" step="0.01" value="0" default="0"/>
...
</Ao>
<Param count="0" md5="12345678123456781234567812345678"/>
</Root>
```
## 信号注册映射
| XML 段 | 信号类型 | 数据中心 API | saddr 格式 | 数据类型 |
|---|---|---|---|---|
| St | 遥信 | `dc_signal_out` | `self_ptl.st.N` | uint8 |
| Mx | 遥测 | `dc_signal_out` | `self_ptl.mx.N` | float |
| Co | 遥控 | `dc_signal_yk` | `self_ptl.co.N` | uint8 (SBO) |
| Dd | 电度 | `dc_signal_out` | `self_ptl.dd.N` | float |
| Ao | 参数 | `dc_signal_ao` | `self_ptl.ao.N` | float (SBO) |
| Param | 定值 | `dc_signal_param` | `self_ptl.param.N` | float (SBO) |
## 回调数据流
### 实时数据 (MX/ST/DD)
```
采样板 TI_200/201/202 → icp67_decode → p_icp67->method.mx_trans_cb
→ mx_trans() in self_ptl_cb.cpp
→ snprintf("self_ptl.mx.%d", info_addr)
→ dc_set_out_signal_val(saddr, &val, MODULE_SELF_PTL)
→ 数据中心 dirty 标记 + 100ms 延迟回调
```
### SOE 事件 / 故障 / 扰动
```
采样板 TI_204/205/207 → icp67_decode → fault_trans_cb / soe_trans_cb / mx_change_cb
→ 当前实现: LOG_I 记录
→ TODO: dc_event_queue_push / dc_fault_queue_push / dc_disturb_dd_queue_push
```
### 文件操作 / 升级 / 自检
```
维护软件 TI_6/9/11/30 → icp67_decode → 对应 pop_out/trans 回调
→ 当前实现: LOG_I 记录
→ TODO: 文件系统集成 / 升级流程 / 自检数据写入数据中心
```
## 环形缓冲区
```
stru_self_rx {
rptr, wptr (读写指针)
size = 2048 (缓冲区大小)
cnt (有效数据计数)
buf[2048] (数据缓冲区)
mutex (pthread_mutex_t 保护)
}
```
- `put_rx_data`: ISR 生产者 (锁保护)
- `get_rx_data`: 任务消费者 (锁保护)
- `clear_rx_data`: 帧处理完毕后清空
- 溢出处理: LOG_E + 丢弃旧数据
## 完成状态
### ✅ 已完成
- [x] ICP67 协议引擎初始化
- [x] 17 个回调注册 (icp67 → self_ptl)
- [x] XML 配置解析 (St/Mx/Co/Dd/Ao/Param, 2988行)
- [x] 信号注册到数据中心 (5 种信号类型)
- [x] 环形缓冲 (mutex 保护)
- [x] ICP67 帧搜索 + 解码调用链
- [x] IEC-104 帧检测 (I/S/U 帧分类, 已移除)
- [x] 定时器驱动 (EV_TIMER1)
- [x] X-Macro 框架集成
- [x] MX/ST/DD 实时数据 → 数据中心
- [x] 编译通过 (x86, 0 error)
- [x] **多 FTU interface 预留** (data_rx/data_tx 签名)
- [x] **模块解耦** (不依赖 com_router, app_wiring 集中连接)
- [x] **self_ptl_data_tx → comm_send** (发送路径打通)
- [x] **SOE/故障/扰动 → 数据中心** (dc_event/fault/disturb_queue_push)
- [x] **自检信号 → 数据中心** (self_check_pop_out → dc_set_out_signal_val)
- [x] **AO 参数 → 数据中心** (ao_pop_out → dc_set_out_signal_val)
### ⬜ 未完成
| 优先级 | 任务 | 说明 |
|:---:|---|---|
| 🟡 | 文件操作集成 | 6 个文件读写回调 → 文件系统 |
| 🟢 | 单元测试 | test_self_ptl.cpp |
## 与原工程的差异
| 维度 | 原 RTU (self_ptl.cpp) | 重构后 |
|---|---|---|
| 回调表 | 全局 `g_genneral_method` + `g_self_ptl.method` 副本 | 注册到 `p_icp67->method` (实例化) |
| IEC-104 | 独立 `iec_rx` 环形缓冲 + 完整 IEC 帧搜索 | 单 `icp67_rx` 环形缓冲 + 帧类型检测 |
| 测试命令 | `self_ptl_method_task()` (生产代码混入) | 移除 (仅保留核心功能) |
| 文件拆分 | 2 文件 (self_ptl.cpp 1400+行 + method.cpp 300+行) | 3 文件 (core 526 + cfg 336 + cb 251) |
| XML 解析 | 耦合在 `RTU/self_ptl_cfg.cpp` | 独立 `libself_ptl/self_ptl_cfg.cpp` |
| 事件模型 | `stru_msg_head` 包装 + 内部事件 | 直接调用 self_ptl_data_rx + EV_SELF_PTL_RX_COM |

View File

@ -0,0 +1,39 @@
include ./../../../linux.mk
L := $(notdir $(realpath $(CURDIR)/..))
M := libplc
O := $(LIB_REL)/$(M).a
S := $(SRC_ROOT_DIR)/$(L)/libplc/src
I := -I$(SRC_ROOT_DIR)/$(L)/libplc/inc -I$(SRC_ROOT_DIR)/$(L)/inc \
-I$(SRC_ROOT_DIR)/$(L)/libself_ptl/inc \
-I$(SRC_ROOT_DIR)/public/libdatacenter/inc -I$(SRC_ROOT_DIR)/public/liblog/inc \
-I$(SRC_ROOT_DIR)/public/libxml/inc -I$(SRC_ROOT_DIR)/public/libtask/inc \
-I$(SRC_ROOT_DIR)/public/libfunc/inc
B := $(CURDIR)/$(M)/obj
SRCS := $(wildcard $(S)/*.cpp) $(wildcard $(S)/*.c)
OBJS := $(patsubst $(S)/%.cpp, $(B)/%.o, $(patsubst $(S)/%.c, $(B)/%.o, $(SRCS)))
F := $(CXX_FLAGS) $(I)
.PHONY: all
all:
@mkdir -p $(ROOT_DIR)/release/inc
@$(MAKE) $(O)
$(O): $(OBJS)
@mkdir -p $(dir $@)
$(AR) rcs $@ $^
@echo "[$(M)] built"
$(B)/%.o: $(S)/%.cpp
@mkdir -p $(dir $@)
$(CXX) $(F) -c $< -o $@
$(B)/%.o: $(S)/%.c
@mkdir -p $(dir $@)
$(CC) $(C_FLAGS) $(I) -c $< -o $@
.PHONY: clean
clean:
rm -rf $(B) $(O)
.PHONY: rebuild
rebuild: clean all

View File

@ -1,7 +1,7 @@
include ./../../linux.mk include ./../../linux.mk
# app_sys.cpp 已合并到 RTU makefile 中,此处仅管理子模块 # app_sys.cpp 已合并到 RTU makefile 中,此处仅管理子模块
SUBDIRS := ./libmodbus_m ./libweb_server ./libcom_router ./libself_ptl ./libiec ./RTU SUBDIRS := ./libmodbus_m ./libweb_server ./libcom_router ./libself_ptl ./libiec ./libplc ./RTU
.PHONY: all clean rebuild .PHONY: all clean rebuild

View File

@ -23,6 +23,7 @@ APP_MODULE(WEB_SERVER, web_server, app_web_server_init1, app_web_server_init2, a
APP_MODULE(SELF_PTL, self_ptl, app_self_ptl_init1, app_self_ptl_init2, app_self_ptl) APP_MODULE(SELF_PTL, self_ptl, app_self_ptl_init1, app_self_ptl_init2, app_self_ptl)
APP_MODULE(COM_ROUTER, com_router, app_com_router_init1, app_com_router_init2, app_com_router) APP_MODULE(COM_ROUTER, com_router, app_com_router_init1, app_com_router_init2, app_com_router)
APP_MODULE(IEC, iec, app_iec_init1, app_iec_init2, app_iec) APP_MODULE(IEC, iec, app_iec_init1, app_iec_init2, app_iec)
APP_MODULE(PLC, plc, app_plc_init1, app_plc_init2, app_plc)
/* ============== 预留模块(阶段 2-3 实现后取消注释) ============== */ /* ============== 预留模块(阶段 2-3 实现后取消注释) ============== */
// APP_MODULE(COM_DECODE, com_decode, app_com_decode_init1, app_com_decode_init2, app_com_decode) // APP_MODULE(COM_DECODE, com_decode, app_com_decode_init1, app_com_decode_init2, app_com_decode)

View File

@ -0,0 +1,38 @@
/**
* @file plc.h
* @brief PLC
*
* @details plc.cpp PLC
* 10 AND/OR/NOT/62P/62D/RISING/FALLING/SR/RS +
* XML
*/
#ifndef _PLC_H_
#define _PLC_H_
#include "myBase.h"
#ifdef __cplusplus
extern "C" {
#endif
/** PLC 逻辑入口 — 按配置文件执行所有逻辑图 */
int PLC_Logic(void);
/** 动态设置 PLC 配置文件路径 */
void plc_set_config_path(const char *path);
/** 获取当前 PLC 配置文件路径 */
const char *plc_get_config_path(void);
/* =========================== 模块线程入口 =========================== */
int app_plc_init1(void *arg);
int app_plc_init2(void *arg);
void *app_plc(void *arg);
#ifdef __cplusplus
}
#endif
#endif /* _PLC_H_ */

File diff suppressed because it is too large Load Diff