Files
softbus_OPC/docs/plugins.md

221 lines
5.8 KiB
Markdown
Raw Normal View History

2026-06-09 17:27:24 +08:00
# 协议插件
**路径:** `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` | 设为 sourceIdobjectRef 路径) |
| `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 插件完整功能
- 支持多插件并行加载与协议自动选择
- 插件热加载与版本管理