# 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 |
