2026-06-09 17:27:24 +08:00
|
|
|
|
# softbus_edge
|
|
|
|
|
|
|
|
|
|
|
|
**路径:** `src/softbus_edge`
|
|
|
|
|
|
**构建目标:** `softbus_edge`(EXECUTABLE)
|
|
|
|
|
|
**层级:** L3 可执行层
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 概述
|
|
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
`softbus_edge` 是边缘代理进程,运行在靠近现场设备的一侧,负责:
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
- **物理域采集(ingress)**:按 `physical_*.json` 轮询 Modbus RTU/TCP 等设备,产出 `RawPacket`
|
|
|
|
|
|
- **上行(egress/uplink)**:经 TCP 将 `RawPacket`、心跳、注册信息发送给 `softbus_daemon`
|
|
|
|
|
|
- **下行(egress)**:接收 daemon 下发的 `ExecuteCommand`,写回物理设备(Modbus 写寄存器等)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
edge **不**加载逻辑点表、**不**操作 OPC UA、**不**运行 `protocol_modbus` 插件。协议解析与 OPC 绑定均在 daemon 侧完成。
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
| 模式 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| **正常模式** | libmodbus + `ModbusIngress`,读真实硬件 |
|
|
|
|
|
|
| **Mock 模式** | `--mock`,无硬件,模拟 Modbus 帧上行 |
|
|
|
|
|
|
| **独立模式** | daemon 未启动时 edge 仍可运行,后台重连 uplink |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 与 daemon 的职责边界(双域)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
2026-06-12 18:34:49 +08:00
|
|
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
|
|
|
|
│ edge(物理域) daemon(逻辑域) │
|
|
|
|
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
|
|
|
|
│ config/edge/ config/daemon/ │
|
|
|
|
|
|
│ edge.json daemon_profile.json │
|
|
|
|
|
|
│ physical_channels.json logical_points.json │
|
|
|
|
|
|
│ physical_devices.json bindings_global.json │
|
|
|
|
|
|
│ bindings_local.json(可选) topic_rule.json │
|
|
|
|
|
|
│ │
|
|
|
|
|
|
│ 读硬件 → RawPacket RawPacket → 插件解析 │
|
|
|
|
|
|
│ 写硬件 ← physicalPointId → bindings → OPC UA 节点 │
|
|
|
|
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 配置 | edge 是否加载 | 用途 |
|
|
|
|
|
|
|------|---------------|------|
|
|
|
|
|
|
| `physical_channels.json` | 是 | 串口 / TCP 通道参数 |
|
|
|
|
|
|
| `physical_devices.json` | 是 | 从站、寄存器、物理点 ID |
|
|
|
|
|
|
| `bindings_local.json` | 可选 | 下行写命令的**本地备用**解析(正常联调几乎不用) |
|
|
|
|
|
|
| `logical_points.json` | **否** | daemon 专用 |
|
|
|
|
|
|
| `bindings_global.json` | **否** | daemon 专用(上行绑定 + 下行路由) |
|
|
|
|
|
|
|
|
|
|
|
|
edge 上行时**不做** binding 初筛:所有已配置物理点都会采集并上报;是否绑定 OPC 由 daemon 的 `bindings_global.json` 决定(未绑定点进入 `edge/unbound/raw/...`)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 配置加载流程
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 入口文件
|
|
|
|
|
|
|
|
|
|
|
|
默认配置:`config/edge/edge.json`。子路径**相对 `edge.json` 所在目录**解析。
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"edge": {
|
|
|
|
|
|
"edgeId": "edge01",
|
|
|
|
|
|
"deviceId": "EdgeDevice_01",
|
|
|
|
|
|
"daemonHost": "127.0.0.1",
|
|
|
|
|
|
"daemonPort": 9000,
|
|
|
|
|
|
"heartbeatPeriodMs": 1000,
|
|
|
|
|
|
"uplinkReconnectPeriodMs": 5000,
|
|
|
|
|
|
"physicalChannels": "physical_channels.json",
|
|
|
|
|
|
"physicalDevices": "physical_devices.json",
|
|
|
|
|
|
"bindingsLocal": "bindings_local.json"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `edgeId` | 边缘实例 ID,uplink 注册与 daemon 路由用 |
|
|
|
|
|
|
| `deviceId` | 逻辑设备名(ACK 等场景) |
|
|
|
|
|
|
| `daemonHost` / `daemonPort` | 核心 uplink 地址 |
|
|
|
|
|
|
| `heartbeatPeriodMs` | 心跳周期(仅 uplink 已连接时发送) |
|
|
|
|
|
|
| `uplinkReconnectPeriodMs` | daemon 不可达时的重连间隔 |
|
|
|
|
|
|
| `physicalChannels` / `physicalDevices` | 物理层配置 |
|
|
|
|
|
|
| `bindingsLocal` | 可选;空则跳过 |
|
|
|
|
|
|
| `bindingsPatch` | 可选;热加载绑定补丁 |
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 启动时加载顺序(`EdgeRuntime::init`)
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
1. EdgeConfig.loadFromFile(--config)
|
|
|
|
|
|
2. PhysicalRegistry.loadChannels(physical_channels.json)
|
|
|
|
|
|
3. PhysicalRegistry.loadDevices(physical_devices.json, edgeId)
|
|
|
|
|
|
→ 物理点 ID 自动加前缀:edge01/phy_modbus_s1_r40001
|
|
|
|
|
|
4. [可选] BindingRegistry.loadLocal(bindings_local.json)
|
|
|
|
|
|
5. UplinkClient + CommandExecutor 初始化
|
|
|
|
|
|
6. DeviceFactory.createIngress → ModbusIngress 或 MockModbusIngress
|
|
|
|
|
|
7. ModbusChannelManager.openChannel(逐通道 libmodbus 连接)
|
|
|
|
|
|
8. uplink.connect();成功则 sendEdgeRegister(edgeId)
|
|
|
|
|
|
→ 失败仅 WARN,edge 独立运行并后台重连
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 物理通道(`physical_channels.json`)
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"channels": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"channelId": "serial_0",
|
|
|
|
|
|
"protocol": "modbus",
|
|
|
|
|
|
"transport": "rtu",
|
|
|
|
|
|
"port": "/dev/ttyS3",
|
|
|
|
|
|
"baudRate": 9600,
|
|
|
|
|
|
"parity": "N",
|
|
|
|
|
|
"dataBits": 8,
|
|
|
|
|
|
"stopBits": 1,
|
|
|
|
|
|
"pollIntervalMs": 500
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `transport` | `rtu`(串口)或 `tcp`(Modbus TCP,需 `host` + `tcpPort`) |
|
|
|
|
|
|
| `pollIntervalMs` | 该通道下所有点的轮询周期(当前整通道统一) |
|
|
|
|
|
|
|
|
|
|
|
|
### 3.4 物理设备与点(`physical_devices.json`)
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"devices": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"physicalDeviceId": "phy_modbus_slave_1",
|
|
|
|
|
|
"channelId": "serial_0",
|
|
|
|
|
|
"protocol": "modbus",
|
|
|
|
|
|
"slaveId": 1,
|
|
|
|
|
|
"points": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"physicalPointId": "phy_modbus_s1_r40001",
|
|
|
|
|
|
"register": 40001,
|
|
|
|
|
|
"function": 3,
|
|
|
|
|
|
"scale": 0.1,
|
|
|
|
|
|
"signalType": "AI",
|
|
|
|
|
|
"writable": false
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2026-06-09 17:27:24 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
运行时 `physicalPointId` 会变为 `{edgeId}/{physicalPointId}`,作为 `RawPacket.sourceId` 上报。
|
|
|
|
|
|
|
|
|
|
|
|
### 3.5 热加载
|
|
|
|
|
|
|
|
|
|
|
|
| 信号 | 行为 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `SIGHUP` | `reloadPhysical()`:重载 channels + devices,重建 Modbus 连接 |
|
|
|
|
|
|
| `SIGHUP` | `reloadBindingsPatch()`:若配置了 `bindingsPatch` 则增量应用 |
|
|
|
|
|
|
| 文件变更 | `ConfigWatcher` 监视 `physical_channels`、`physical_devices`、`bindingsPatch` |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 组件架构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
main.cpp
|
|
|
|
|
|
└── EdgeRuntime
|
|
|
|
|
|
├── PhysicalRegistry ← physical_*.json
|
|
|
|
|
|
├── BindingRegistry (local) ← bindings_local.json(可选)
|
|
|
|
|
|
├── ModbusChannelManager ← libmodbus RTU/TCP I/O
|
|
|
|
|
|
├── IIngressPort
|
|
|
|
|
|
│ ├── ModbusIngress ← 正常模式
|
|
|
|
|
|
│ └── MockModbusIngress ← --mock
|
|
|
|
|
|
├── ModbusEgress ← 下行写寄存器
|
|
|
|
|
|
├── CommandExecutor ← ExecuteCommand → Modbus 写 / mock
|
|
|
|
|
|
└── UplinkClient ← TcpUplinkClient 封装
|
|
|
|
|
|
```
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
|
|
|
|
|
### 4.1 IIngressPort — 入站抽象
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `open()` | 打开采集通道 |
|
|
|
|
|
|
| `close()` | 关闭采集通道 |
|
|
|
|
|
|
| `poll()` | 轮询,返回 `vector<RawPacket>` |
|
|
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
**ModbusIngress**:按 `pollIntervalMs` 遍历 `pollPoints()`,经 `ModbusChannelManager` 读寄存器,组装 Modbus 0x03 响应帧作为 `payload`。
|
|
|
|
|
|
|
|
|
|
|
|
**MockModbusIngress**:无硬件,生成递增值模拟帧。
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
### 4.2 ModbusChannelManager — 硬件 I/O
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
- 构建时链接 **libmodbus**(系统包或 `third_party/libmodbus` vendor)
|
|
|
|
|
|
- RTU:`modbus_new_rtu` + `modbus_read_registers` / `modbus_write_register`
|
|
|
|
|
|
- TCP:`modbus_new_tcp`(`transport: tcp` 时)
|
|
|
|
|
|
- 无 libmodbus 时退化为模拟读写(编译宏 `SOFTBUS_HAS_LIBMODBUS=0`)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
> edge **不使用** daemon 侧的 `protocol_modbus.so` 插件;插件仅用于 daemon 解析上行 RawPacket。
|
|
|
|
|
|
|
|
|
|
|
|
### 4.3 UplinkClient — 上行/下行
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
|
|
|
|
|
| 方法 | 说明 |
|
|
|
|
|
|
|------|------|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
| `connect()` / `disconnect()` | TCP 连接 daemon |
|
|
|
|
|
|
| `sendEdgeRegister(edgeId)` | 注册边缘实例 |
|
|
|
|
|
|
| `sendHeartbeat(deviceId)` | 心跳 |
|
|
|
|
|
|
| `sendRawPacket(RawPacket)` | 上行原始包 |
|
|
|
|
|
|
| `sendAck(SoftbusAck)` | 写命令 ACK |
|
|
|
|
|
|
| `poll()` | 接收下行 `ExecuteCommand` |
|
2026-06-09 17:27:24 +08:00
|
|
|
|
| `setCommandHandler(handler)` | 注册命令回调 |
|
|
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
协议详见 [UPLINK_WIRE_PROTOCOL.md](UPLINK_WIRE_PROTOCOL.md)。
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
### 4.4 CommandExecutor — 下行写
|
|
|
|
|
|
|
|
|
|
|
|
daemon 经 `bindings_global` 在命令中注入 `physicalPointId` + `edgeId`,edge 直接写 Modbus:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
ExecuteCommand.params.physicalPointId → PhysicalRegistry → ModbusEgress.write
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
仅当命令**缺少** `physicalPointId` 时,才用 `bindings_local.json` 做 `logicalPointId → physicalPointId` 备用解析。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 数据流
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
### 5.1 上行(采集 → OPC)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant HW as 现场设备
|
|
|
|
|
|
participant Edge as softbus_edge
|
|
|
|
|
|
participant Daemon as softbus_daemon
|
|
|
|
|
|
participant OPC as OPC UA
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
HW->>Edge: Modbus RTU/TCP 读寄存器
|
|
|
|
|
|
Edge->>Edge: ModbusIngress.poll → RawPacket
|
|
|
|
|
|
Note over Edge: sourceId = edge01/phy_xxx<br/>protocolTag = modbus
|
|
|
|
|
|
Edge->>Daemon: TCP rawPacket + edgeRegister/heartbeat
|
|
|
|
|
|
Daemon->>Daemon: protocol_modbus 解析帧
|
|
|
|
|
|
Daemon->>Daemon: bindings_global → logicalPointId
|
|
|
|
|
|
Daemon->>Daemon: logical_points → objectRef + scale
|
|
|
|
|
|
Daemon->>OPC: UaModelBinder 写节点值
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
逐步说明:
|
|
|
|
|
|
|
|
|
|
|
|
1. **edge**:`ModbusIngress` 读硬件 → `RawPacket{ sourceId=physicalPointId, payload=Modbus帧 }`
|
|
|
|
|
|
2. **edge**:`UplinkClient.sendRawPacket` → TCP JSON 行
|
|
|
|
|
|
3. **daemon**:`TransportBusBridge` 发布到总线 `edge/raw/{physicalPointId}`
|
|
|
|
|
|
4. **daemon**:`PipelineEngine` + `protocol_modbus` 插件解析 → 寄存器值
|
|
|
|
|
|
5. **daemon**:`bindings_global` 查绑定 → `logical_points` 得 OPC 路径 → scale → 写 OPC UA
|
|
|
|
|
|
|
|
|
|
|
|
未绑定物理点:daemon 发布到 `edge/unbound/raw/{physicalPointId}`,不写 OPC。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 下行(OPC 写 → 设备)
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant OPC as OPC UA 客户端
|
|
|
|
|
|
participant Daemon as softbus_daemon
|
|
|
|
|
|
participant Edge as softbus_edge
|
|
|
|
|
|
participant HW as 现场设备
|
|
|
|
|
|
|
|
|
|
|
|
OPC->>Daemon: ExecuteCommand (objectRef + value)
|
|
|
|
|
|
Daemon->>Daemon: bindings_global → physicalPointId + edgeId
|
|
|
|
|
|
Daemon->>Edge: TCP executeCommand
|
|
|
|
|
|
Edge->>Edge: CommandExecutor → ModbusEgress
|
|
|
|
|
|
Edge->>HW: libmodbus 写寄存器
|
|
|
|
|
|
Edge->>Daemon: TCP ack
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 5.3 主循环(`main.cpp`)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
|
|
|
|
|
```cpp
|
2026-06-12 18:34:49 +08:00
|
|
|
|
while (!shouldStop) {
|
|
|
|
|
|
ConfigWatcher.poll();
|
|
|
|
|
|
if (SIGHUP) { reloadPhysical(); reloadBindingsPatch(); }
|
|
|
|
|
|
|
|
|
|
|
|
runtime.tick(); // uplink.poll + ingress.poll + sendRawPacket
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
if (uplinkConnected && heartbeatDue)
|
|
|
|
|
|
sendHeartbeat(edgeId);
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
sleep(50ms);
|
2026-06-09 17:27:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
2026-06-09 17:27:24 +08:00
|
|
|
|
## 6. CLI 参数
|
|
|
|
|
|
|
|
|
|
|
|
| 参数 | 默认值 | 说明 |
|
|
|
|
|
|
|------|--------|------|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
| `--config <path>` | `config/edge/edge.json` | 边缘入口配置 |
|
|
|
|
|
|
| `--mock` | 关闭 | 使用 MockModbusIngress,跳过 physical 配置与 libmodbus |
|
|
|
|
|
|
| `--object-ref <path>` | `DemoSite/.../MotorTemperature` | Mock 模式下的模拟 sourceId |
|
|
|
|
|
|
|
|
|
|
|
|
> 不再使用 `--daemon host:port`;uplink 地址由 `edge.json` 的 `daemonHost` / `daemonPort` 指定。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 依赖
|
|
|
|
|
|
|
|
|
|
|
|
| 依赖 | 用途 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `softbus_core` | RawPacket、Logger、PlatformSignal、ConfigWatcher |
|
|
|
|
|
|
| `softbus_registry` | BindingRegistry(仅 local 可选) |
|
|
|
|
|
|
| `softbus_transport` | TcpUplinkClient、UplinkWire |
|
|
|
|
|
|
| `softbus_api` | ExecuteCommand、SoftbusAck |
|
|
|
|
|
|
| **libmodbus** | Modbus RTU/TCP 硬件 I/O(vendor 或系统包) |
|
|
|
|
|
|
| asio | TcpUplinkClient 底层 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 构建与运行
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
### 8.1 libmodbus
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
构建时自动选择:系统 `libmodbus-dev` 优先,否则编译 `third_party/libmodbus` 静态库进 edge。
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
```bash
|
|
|
|
|
|
cmake -B build
|
|
|
|
|
|
cmake --build build --target softbus_edge
|
2026-06-09 17:27:24 +08:00
|
|
|
|
```
|
2026-06-12 18:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
串口权限:`sudo usermod -aG dialout $USER`
|
|
|
|
|
|
|
|
|
|
|
|
### 8.2 运行示例
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. 先启动 daemon
|
|
|
|
|
|
./build/bin/softbus_daemon \
|
|
|
|
|
|
--config config/daemon/daemon_profile.json \
|
|
|
|
|
|
--logical-points config/daemon/logical_points.json \
|
|
|
|
|
|
--bindings-global config/daemon/bindings_global.json
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 启动 edge(真实 Modbus)
|
|
|
|
|
|
./build/bin/softbus_edge --config config/edge/edge.json
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 无硬件 / 无 daemon 调试
|
|
|
|
|
|
./build/bin/softbus_edge --config config/edge/edge.json --mock
|
|
|
|
|
|
|
|
|
|
|
|
# 4. 热加载物理配置
|
|
|
|
|
|
kill -HUP $(pidof softbus_edge)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
更多配置说明见 [edge_device_setup.md](edge_device_setup.md)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 未来扩展:CANopen 与以太网设备
|
|
|
|
|
|
|
|
|
|
|
|
当前仅 **Modbus RTU/TCP** 在 edge 侧有完整 ingress/egress。CANopen 与更多以太网协议按同一双域模型扩展。
|
|
|
|
|
|
|
|
|
|
|
|
### 9.1 目标架构
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
|
|
|
|
|
```
|
2026-06-12 18:34:49 +08:00
|
|
|
|
physical_channels.json ──→ ChannelDriver(按 protocol 选择)
|
|
|
|
|
|
physical_devices.json ──→ PhysicalRegistry
|
|
|
|
|
|
│
|
|
|
|
|
|
┌───────────┼───────────┐
|
|
|
|
|
|
▼ ▼ ▼
|
|
|
|
|
|
ModbusIngress CanIngress EthIngress(规划)
|
|
|
|
|
|
│ │ │
|
|
|
|
|
|
└───────────┴───────────┘
|
|
|
|
|
|
▼
|
|
|
|
|
|
RawPacket → UplinkClient
|
2026-06-09 17:27:24 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
daemon 侧已有对应解析插件(`protocol_modbus`、`protocol_canopen`),edge 只需换 ingress/driver,**上行仍是 RawPacket + protocolTag**。
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
### 9.2 CANopen(规划)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
| 层级 | 计划 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| **edge** | `CanIngress` + SocketCAN/`can0` 通道;SDO/PDO 读对象字典 → `RawPacket`,`protocolTag: "canopen"` |
|
|
|
|
|
|
| **配置** | `physical_channels` 增加 `transport: can`,`interface: can0`,`bitrate: 500000`;`physical_devices` 增加 `nodeId`、对象索引 |
|
|
|
|
|
|
| **daemon** | 已有 `protocol_canopen.so`(Framer/Parser 占位),绑定仍走 `bindings_global` |
|
|
|
|
|
|
| **EDS/DCF** | edge 侧加载 EDS 映射物理点 ↔ COB-ID/索引;daemon 不接收 EDS 全量 |
|
|
|
|
|
|
|
|
|
|
|
|
### 9.3 以太网设备(规划)
|
|
|
|
|
|
|
|
|
|
|
|
| 类型 | edge 侧 | 说明 |
|
|
|
|
|
|
|------|---------|------|
|
|
|
|
|
|
| **Modbus TCP** | 已支持 | `physical_channels` 设 `transport: tcp`,`host` + `tcpPort` |
|
|
|
|
|
|
| **裸 TCP / 自定义帧** | `EthIngress`(规划) | 按 channel 配置帧格式或插件化 driver |
|
|
|
|
|
|
| **UDP 组播** | 待定 | 适用于部分工业相机/传感器 |
|
|
|
|
|
|
|
|
|
|
|
|
以太网通道示例(Modbus TCP,已可用):
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"channelId": "eth_modbus_0",
|
|
|
|
|
|
"protocol": "modbus",
|
|
|
|
|
|
"transport": "tcp",
|
|
|
|
|
|
"host": "192.168.1.10",
|
|
|
|
|
|
"tcpPort": 502,
|
|
|
|
|
|
"pollIntervalMs": 200
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
### 9.4 edge 侧待增强(Modbus 及通用)
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
| 项 | 说明 |
|
|
|
|
|
|
|----|------|
|
|
|
|
|
|
| **ModbusPollScheduler** | 合并相邻寄存器读,减少串口占用 |
|
|
|
|
|
|
| **按点 pollInterval** | 不同信号类型不同采集周期 |
|
|
|
|
|
|
| **变化上报 / deadband** | 物理层过滤,减少 uplink 流量 |
|
|
|
|
|
|
| **DeviceDiscovery** | 总线扫描、动态写入 `physical_devices` |
|
|
|
|
|
|
| **多 ingress 并存** | 同一 edge 上 Modbus + CANopen 并行 |
|
|
|
|
|
|
|
|
|
|
|
|
上述优化均在**物理域**完成,不改变 daemon 双域模型。
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
---
|
2026-06-09 17:27:24 +08:00
|
|
|
|
|
2026-06-12 18:34:49 +08:00
|
|
|
|
## 10. 约束(CONSTRAINTS)
|
|
|
|
|
|
|
|
|
|
|
|
- edge **不得**直接操作 OPC UA 或加载 `protocol_*.so` 解析插件
|
|
|
|
|
|
- edge **不得**加载 `logical_points.json` / `bindings_global.json`
|
|
|
|
|
|
- ingress 实现须遵循 `IIngressPort`,便于接入 CANopen/Ethernet driver
|
|
|
|
|
|
- 上行统一为 `RawPacket`;`sourceId` 必须是 **physicalPointId**(含 edgeId 前缀)
|
|
|
|
|
|
- daemon 不可达时 edge **必须**能独立启动并采集(uplink 后台重连)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 11. 相关文档
|
|
|
|
|
|
|
|
|
|
|
|
| 文档 | 内容 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| [edge_device_setup.md](edge_device_setup.md) | 配置目录、双域、libmodbus、Mock |
|
|
|
|
|
|
| [UPLINK_WIRE_PROTOCOL.md](UPLINK_WIRE_PROTOCOL.md) | TCP JSON 线协议 |
|
|
|
|
|
|
| [softbus_daemon.md](softbus_daemon.md) | daemon 侧 Pipeline 与 OPC |
|
|
|
|
|
|
| [plugins.md](plugins.md) | protocol 插件(daemon 解析用) |
|