# 协议插件

**路径：** `src/plugins`  
**构建目标：** `protocol_modbus`、`protocol_canopen`（SHARED 库）  
**层级：** L2 协议层

## 1. 概述

协议插件以动态库（`.so` / `.dll`）形式实现 `IFramer` 与 `IParser` 接口，由 `PluginLoader` 在运行时加载。守护进程 Pipeline 通过插件完成原始字节的分帧与语义解析。

## 2. CONSTRAINTS

- 插件须通过 C ABI 导出 `create_framer` / `create_parser` / `destroy_*` 函数。
- 插件仅依赖 `softbus_core`，不得链接 daemon、opcua 或 transport。
- 解析输出必须为 `DOMMessage`，不得引入传输层特定字段。
- 新增协议插件须遵循相同目录结构与 CMake 宏 `softbus_add_plugin`。
- Phase 1 modbus 插件硬编码寄存器 40001，不读取 ObjectModel 映射表。

## 3. 插件接口

### 3.1 IFramer

```cpp
class IFramer {
public:
    virtual FrameResult extract(const uint8_t* data, std::size_t size) = 0;
    virtual const char* protocolName() const = 0;
};
```

**FrameResult 字段：**

| 字段 | 说明 |
|------|------|
| `success` | 是否成功提取完整帧 |
| `consumedBytes` | 已消费字节数 |
| `frameStartOffset` | 帧起始偏移 |
| `frame` | 提取的完整帧数据 |

### 3.2 IParser

```cpp
class IParser {
public:
    virtual ParseResult parseFrame(const uint8_t* data, std::size_t size,
                                   const std::string& sourceId) = 0;
    virtual const char* protocolName() const = 0;
};
```

**ParseResult 字段：**

| 字段 | 说明 |
|------|------|
| `success` | 是否解析成功 |
| `message` | 输出的 `DOMMessage` |

### 3.3 C ABI 导出

每个插件须实现：

```cpp
extern "C" SOFTBUS_PLUGIN_API IFramer* create_framer();
extern "C" SOFTBUS_PLUGIN_API void destroy_framer(IFramer* framer);
extern "C" SOFTBUS_PLUGIN_API IParser* create_parser();
extern "C" SOFTBUS_PLUGIN_API void destroy_parser(IParser* parser);
```

## 4. protocol_modbus

**路径：** `src/plugins/protocol_modbus`  
**输出：** `libprotocol_modbus.so`

### 4.1 组件

| 组件 | 文件 | 职责 |
|------|------|------|
| `ModbusFramer` | `ModbusFramer.h/.cpp` | 识别 func=0x03 响应帧 |
| `ModbusParser` | `ModbusParser.h/.cpp` | 解析寄存器值 → DOMMessage |
| `modbus_plugin.cpp` | C ABI 导出 | 工厂函数 |

### 4.2 ModbusFramer

- 识别 Modbus RTU 功能码 0x03（读保持寄存器）响应帧
- 根据字节计数与数据长度判断帧完整性
- 输出完整帧供 Parser 消费

### 4.3 ModbusParser

- 解析 0x03 响应帧中的寄存器值
- 应用缩放因子 0.1（硬编码）
- 输出 `DOMMessage`：
  - `id` = sourceId
  - `value` = `{"registerValue": <scaled_value>}`
  - `quality` = `"Good"`

### 4.4 Phase 1 限制

- 仅支持功能码 0x03 响应
- 硬编码寄存器地址 40001
- 不读取 `ObjectModelRegistry` 的寄存器映射

### 4.5 数据流

```
RawPacket.payload (Modbus bytes)
  → ModbusFramer.extract() → 完整帧
  → ModbusParser.parseFrame() → DOMMessage
  → UaModelBinder.bind()
```

## 5. protocol_canopen

**路径：** `src/plugins/protocol_canopen`  
**输出：** `libprotocol_canopen.so`

### 5.1 组件状态

| 组件 | Phase 1 状态 |
|------|-------------|
| `CanopenFramer` | stub（空实现） |
| `CanopenParser` | stub（空实现） |
| `CanopenObjectDictionary` | stub |
| `EdsDcfLoader` | stub |
| `CanopenNodeManager` | stub |
| `CanopenMapper` | stub |
| `canopen_plugin.cpp` | C ABI 导出存在，功能未实现 |

### 5.2 规划结构

```
CanopenFramer        ← CAN 帧分帧
CanopenParser        ← PDO/SDO 解析
CanopenObjectDictionary ← 对象字典管理
EdsDcfLoader         ← EDS/DCF 文件加载
CanopenNodeManager   ← 节点状态管理
CanopenMapper        ← 对象字典 → DOMMessage 映射
```

### 5.3 集成状态

- `daemon_profile.json` 已配置 `"canopen": "protocol_canopen"`
- `CoreService` Phase 1 **仅加载 modbus 插件**，canopen 未接入

## 6. 插件开发指南

### 6.1 目录结构

```
src/plugins/protocol_<name>/
├── CMakeLists.txt
├── include/<name>/
│   ├── <Name>Framer.h
│   └── <Name>Parser.h
└── src/
    ├── <Name>Framer.cpp
    ├── <Name>Parser.cpp
    └── <name>_plugin.cpp
```

### 6.2 CMakeLists.txt 模板

```cmake
softbus_add_plugin(protocol_<name>
    SOURCES
        src/<Name>Framer.cpp
        src/<Name>Parser.cpp
        src/<name>_plugin.cpp
    DEPENDS softbus_core
)
```

### 6.3 开发步骤

1. 实现 `IFramer::extract()` — 从字节流提取完整协议帧
2. 实现 `IParser::parseFrame()` — 将帧解析为 `DOMMessage`
3. 在 `<name>_plugin.cpp` 中导出 C ABI 工厂函数
4. 在 `daemon_profile.json` → `plugins` 中注册插件名
5. 在 `CoreService` 中加载并注入 `PipelineEngine`

### 6.4 DOMMessage 输出约定

| 字段 | 要求 |
|------|------|
| `id` | 设为 sourceId（objectRef 路径） |
| `sourceId` | 保持传入值 |
| `domain` | 来自模型或默认 `"Process"` |
| `quality` | `"Good"` / `"Bad"` / `"Uncertain"` |
| `value` | JSON 对象，至少含 `"value"` 或 `"registerValue"` 数值字段 |

## 7. 插件搜索与加载

守护进程通过 `CoreService::resolvePluginPath()` 搜索插件，配置文件 `daemon_profile.json`：

```json
{
  "plugins": {
    "modbus": "protocol_modbus",
    "canopen": "protocol_canopen"
  }
}
```

键名（如 `modbus`）用于代码中选择插件，值（如 `protocol_modbus`）用于文件名解析。

## 8. 构建

```bash
cmake --build build --target protocol_modbus
cmake --build build --target protocol_canopen
```

输出：`build/lib/libprotocol_modbus.so`、`build/lib/libprotocol_canopen.so`

## 9. Phase 2 规划

- modbus 插件读取 `ObjectModelRegistry` 寄存器映射
- 实现 canopen 插件完整功能
- 支持多插件并行加载与协议自动选择
- 插件热加载与版本管理
