feat: 变更架构为广播,发送到所有绑定的端口

This commit is contained in:
2026-07-26 22:29:47 +08:00
parent e3c40c822b
commit e8ee92110b
10 changed files with 614 additions and 574 deletions
+118 -169
View File
@@ -2,7 +2,7 @@
## 1. 设计目标
轻量级 C 语言数据路由库。发送与接收能力分开声明,每个端口独立设置发送类型和接收类型,支持多外设一对多广播路由。
轻量级 C 语言数据路由库。发送与接收能力分开声明,端口绑定 `send_type` 和外设 handler 列表。调用 `datarouter_send_<id>(data, len)` 时自动遍历端口表,广播到所有 `send_type` 匹配的端口。
### 核心设计
@@ -12,27 +12,25 @@ DATAROUTER_SEND_CAPABILITIES DATAROUTER_RECV_CAPABILITIES
DATAROUTER_SEND(status, ...) DATAROUTER_RECV(command, ...)
│ │
▼ ▼
send_sensor(port, data) on_recv_rtcm(port, data)
send_status(port, data) on_recv_command(port, data)
│ (用户实现回调)
send_sensor(data, len) on_recv_rtcm(port, data, len)
│ (用户实现回调)
▼
端口校验 → for each handler(port, data)
│
┌────────┼────────┐
▼ ▼ ▼
UART TCP CAN
遍历端口表 → send_type 匹配?
│
▼
for each handler(port, data) ─── UART / TCP / CAN
```
**关键区别**:sensor 只声明发送,不生成接收回调;rtcm 只声明接收,不生成发送函数。端口可独立设置 send_type 和 recv_type,互不干扰。
**关键**:send 无 port_id 参数,自动路由到所有匹配端口。
### 设计原则
| 原则 | 说明 |
|------|------|
| 收发分离 | 发送能力和接收能力在配置中分开声明,按需组合 |
| 收发分离 | 发送/接收能力在配置中分开声明,按需组合 |
| 编译期确定能力 | 所有能力在 `datarouter_config.h` 中声明,库自动生成代码 |
| 运行期绑定外设 | 端口创建后,通过 `add_handler` 注册物理外设发送函数 |
| 一对多广播 | 一个端口可注册多个 handler,发送时逐一调用 |
| 自动广播 | `send_<id>(data, len)` 遍历所有端口,自动匹配 send_type |
| 不关心物理外设 | 库不依赖任何外设 API,只调用用户提供的 handler |
| 零动态内存 | 纯静态数组,无 malloc/free |
@@ -47,23 +45,22 @@ DATAROUTER_SEND_CAPABILITIES DATAROUTER_RECV_CAPABILITIES
left to right direction
rectangle "用户代码" as User {
component "应用逻辑" as App
component "datarouter_config.h\n声明发送+接收能力" as Cfg
component "应用逻辑\n调 send_<id>(data, len)" as App
component "datarouter_config.h\n声明能力" as Cfg
component "外设 handler\nUART / TCP / CAN" as Handlers
component "接收回调\n处理收到的报文" as Callbacks
component "接收回调\non_recv_<id>()" as Callbacks
}
database "DataRouter 库" as Lib {
component "datarouter.h\n公共 API + X-macro 展开" as Hdr
component "datarouter.c\n端口表 + handler 遍历" as Impl
component "datarouter.h\n公共 API + X-macro" as Hdr
component "datarouter.c\n端口表+遍历路由" as Impl
}
App --> Hdr
Cfg --> Hdr
Impl --> Cfg
Handlers --> Impl : 注册 handler
Handlers --> Impl : add_handler
Callbacks --> Impl : 实现 on_recv_<id>
@enduml
```
@@ -71,11 +68,11 @@ Callbacks --> Impl : 实现 on_recv_<id>
| 文件 | 职责 |
|------|------|
| `datarouter_config.h` | 分别声明 `SEND_CAPABILITIES` 和 `RECV_CAPABILITIES` |
| `datarouter.h` | 公共 API + X-macro 展开(两组枚举 + 声明) |
| `datarouter.c` | 端口表 + handler 列表遍历 + 弱符号回调 |
| `example.c` | 收发分离示例 |
| `tests/test_datarouter.c` | 27 个单元测试 |
| `datarouter_config.h` | 声明 `SEND_CAPABILITIES` 和 `RECV_CAPABILITIES` |
| `datarouter.h` | 公共 API + X-macro 展开 |
| `datarouter.c` | 端口表 + send 遍历 + 弱符号回调 |
| `example.c` | 使用示例 |
| `tests/test_datarouter.c` | 22 个单元测试 |
---
@@ -84,12 +81,10 @@ Callbacks --> Impl : 实现 on_recv_<id>
### 3.1 配置声明
```c
// 发送能力 —— 只生成发送触发函数
#define DATAROUTER_SEND_CAPABILITIES \
DATAROUTER_SEND(sensor, "Sensor data report") \
DATAROUTER_SEND(status, "Device status report")
// 接收能力 —— 只生成接收回调声明
#define DATAROUTER_RECV_CAPABILITIES \
DATAROUTER_RECV(rtcm, "RTCM correction data") \
DATAROUTER_RECV(command, "Remote control command")
@@ -99,75 +94,58 @@ Callbacks --> Impl : 实现 on_recv_<id>
```
DATAROUTER_SEND_CAPABILITIES 展开:
enum: DATAROUTER_SEND_sensor = 0,
DATAROUTER_SEND_status = 1,
DATAROUTER_SEND_CAP_COUNT = 2
发送函数: int datarouter_send_sensor(port, data, len);
int datarouter_send_status(port, data, len);
enum: sensor = 0, status = 1, SEND_CAP_COUNT = 2
发送函数: int datarouter_send_sensor(const void *data, size_t len);
int datarouter_send_status(const void *data, size_t len);
元数据: send_names[] = {"sensor", "status"}
send_descs[] = {"Sensor data report", "Device status report"}
DATAROUTER_RECV_CAPABILITIES 展开:
enum: DATAROUTER_RECV_rtcm = 0,
DATAROUTER_RECV_command = 1,
DATAROUTER_RECV_CAP_COUNT = 2
接收回调: void datarouter_on_recv_rtcm(port, data, len);
void datarouter_on_recv_command(port, data, len);
弱符号默认: 每个回调提供空的 weak 实现,用户覆盖
enum: rtcm = 0, command = 1, RECV_CAP_COUNT = 2
接收回调: void datarouter_on_recv_rtcm(uint32_t port, const void*, size_t);
void datarouter_on_recv_command(uint32_t port, const void*, size_t);
弱符号默认: 空实现,用户覆盖
元数据: recv_names[] = {"rtcm", "command"}
recv_descs[] = {"RTCM correction data", "Remote control command"}
```
### 3.3 端口组合示例
### 3.3 端口示例
```
端口 A: send_type = sensor, recv_type = -1 → 只发送
端口 B: send_type = -1, recv_type = rtcm → 只接收
端口 C: send_type = status, recv_type = command → 同时收发
端口 D: send_type = -1, recv_type = -1 → 无功能
端口 A: send_type = sensor, handlers=[uart_send, tcp_send]
端口 B: send_type = sensor, handlers=[can_send]
端口 C: send_type = status, handlers=[uart_send]
```
调用 `send_sensor("temp", 4)` → A 和 B 同时触发。
---
## 4. X-macro 代码生成
### 4.1 展开流程
```plantuml
@startuml
== datarouter.h:4 次展开 ==
== datarouter.h ==
-> datarouter_config.h: 获得两组宏列表
datarouter.h -> "第 1 遍":
#define DATAROUTER_SEND(id,desc) DATAROUTER_SEND_##id,
DATAROUTER_SEND_CAPABILITIES → 发送 enum
datarouter.h -> "1": #define DATAROUTER_SEND(id,desc) DATAROUTER_SEND_##id,
note right: 发送 enum
datarouter.h -> "第 2 遍":
#define DATAROUTER_RECV(id,desc) DATAROUTER_RECV_##id,
DATAROUTER_RECV_CAPABILITIES → 接收 enum
datarouter.h -> "2": #define DATAROUTER_RECV(id,desc) DATAROUTER_RECV_##id,
note right: 接收 enum
datarouter.h -> "第 3 遍":
#define DATAROUTER_SEND(id,desc) int datarouter_send_##id(...);
DATAROUTER_SEND_CAPABILITIES → 发送函数声明
datarouter.h -> "3": #define DATAROUTER_SEND(id,desc) int send_##id(data, len);
note right: 发送函数声明
datarouter.h -> "第 4 遍":
#define DATAROUTER_RECV(id,desc) void datarouter_on_recv_##id(...);
DATAROUTER_RECV_CAPABILITIES → 接收回调声明
datarouter.h -> "4": #define DATAROUTER_RECV(id,desc) void on_recv_##id(...);
note right: 接收回调声明
== datarouter.c:4 次展开 ==
datarouter.c -> "第 5 遍":
弱符号回调默认实现(DATAROUTER_RECV 展开)
datarouter.c -> "第 6 遍":
发送函数实现 body(DATAROUTER_SEND 展开)
校验 → 遍历 handler 列表
datarouter.c -> "第 7 ~ 8 遍":
send_names[] / send_descs[]
recv_names[] / recv_descs[]
== datarouter.c ==
datarouter.c -> "5": 弱符号回调默认实现
datarouter.c -> "6": 发送函数实现(遍历端口表)
datarouter.c -> "7~8": send_names[] / send_descs[] / recv_names[] / recv_descs[]
@enduml
```
@@ -181,21 +159,11 @@ datarouter.c -> "第 7 ~ 8 遍":
@startuml
skinparam classAttributeIconSize 0
enum "datarouter_send_cap" as S {
SENSOR
STATUS
SEND_CAP_COUNT
}
enum "datarouter_recv_cap" as R {
RTCM
COMMAND
RECV_CAP_COUNT
}
enum "datarouter_send_cap" as S { SENSOR, STATUS, SEND_CAP_COUNT }
enum "datarouter_recv_cap" as R { RTCM, COMMAND, RECV_CAP_COUNT }
class "port_entry_t" as Entry {
- int send_type
- int recv_type
- datarouter_send_handler_t handlers[]
- int count
- uint8_t in_use
@@ -206,8 +174,8 @@ class "datarouter_send_handler_t" as Handler {
}
class "发送函数" as Send {
+ int send_sensor(port, data, len)
+ int send_status(port, data, len)
+ int send_sensor(data, len)
+ int send_status(data, len)
}
class "接收回调" as Recv {
@@ -215,10 +183,9 @@ class "接收回调" as Recv {
+ void on_recv_command(port, data, len)
}
Entry --> S : send_type ∈ S enum / -1
Entry --> R : recv_type ∈ R enum / -1
Entry --> Handler : handlers[] 数组
Send --> Entry : 校验 send_type + 遍历 handlers
Entry --> S : send_type
Entry --> Handler : handlers[]
Send --> Entry : 遍历端口表 → 匹配 send_type → 遍历 handlers
Recv --> Entry : 用户根据业务调对应回调
@enduml
```
@@ -226,13 +193,12 @@ Recv --> Entry : 用户根据业务调对应回调
### 5.2 `port_entry_t`
```c
#define DATAROUTER_MAX_HANDLERS_PER_PORT 4 // 每端口最多 4 个外设
#define DATAROUTER_MAX_HANDLERS_PER_PORT 4
typedef struct {
int send_type; // DATAROUTER_SEND_xxx / -1
int recv_type; // DATAROUTER_RECV_xxx / -1
int send_type;
datarouter_send_handler_t handlers[DATAROUTER_MAX_HANDLERS_PER_PORT];
int count; // 当前 handler 数量
int count;
uint8_t in_use;
} port_entry_t;
```
@@ -259,28 +225,26 @@ void datarouter_reset(void); // 重置全部状态
### 6.2 端口管理
```c
datarouter_port_t datarouter_port_create(void); // 创建
void datarouter_port_delete(datarouter_port_t port); // 删除
datarouter_port_t datarouter_port_create(void);
void datarouter_port_delete(datarouter_port_t port);
void datarouter_port_set_send_type(port, int cap_id); // 设置发送类型
int datarouter_port_get_send_type(port); // -1 表示未设置
void datarouter_port_set_recv_type(port, int cap_id); // 设置接收类型
int datarouter_port_get_recv_type(port); // -1 表示未设置
void datarouter_port_set_send_type(port, int cap_id);
int datarouter_port_get_send_type(port);
int datarouter_port_add_handler(port, handler); // 注册外设 handler
int datarouter_port_remove_handler(port, handler); // 移除
void datarouter_port_clear_handlers(port); // 清除全部
int datarouter_port_handler_count(port); // 数量
int datarouter_port_add_handler(port, handler);
int datarouter_port_remove_handler(port, handler);
void datarouter_port_clear_handlers(port);
int datarouter_port_handler_count(port);
```
### 6.3 发送触发函数(每个 SEND 能力生成一个)
```c
int datarouter_send_sensor(port, data, len);
int datarouter_send_status(port, data, len);
int datarouter_send_sensor(const void *data, size_t len);
int datarouter_send_status(const void *data, size_t len);
```
返回值:0 成功 / -1 未初始化 / -2 端口无效 / -3 send_type 不匹配 / -4 无 handler
返回值:0 成功 / -1 未初始化 / -2 无端口匹配该 send_type
### 6.4 接收回调(每个 RECV 能力生成一个声明)
@@ -289,17 +253,15 @@ void datarouter_on_recv_rtcm(uint32_t port_id, const void *data, size_t len);
void datarouter_on_recv_command(uint32_t port_id, const void *data, size_t len);
```
库提供弱符号默认空实现,用户定义同名函数覆盖。
库提供弱符号默认空实现。
### 6.5 能力元数据(两组独立)
### 6.5 能力元数据
```c
// 发送能力
int datarouter_send_cap_count(void);
const char *datarouter_send_cap_name(int cap_id);
const char *datarouter_send_cap_desc(int cap_id);
// 接收能力
int datarouter_recv_cap_count(void);
const char *datarouter_recv_cap_name(int cap_id);
const char *datarouter_recv_cap_desc(int cap_id);
@@ -315,33 +277,35 @@ const char *datarouter_recv_cap_desc(int cap_id);
@startuml
actor "应用" as App
participant "datarouter_send_sensor()" as Send
participant "端口表" as Table
participant "端口表 ports[]" as Table
participant "handlers[]" as HList
participant "外设" as Dev
App -> Send : send_sensor(port=2, data, len)
App -> Send : send_sensor("temp:25.3", 9)
group 校验
group 初始化检查
Send -> Send : initialized?
alt 否 → return -1
end
Send -> Table : ports[2].in_use?
alt 否 → return -2
end
Send -> Table : ports[2].send_type == SENSOR?
alt 否 → return -3
end
Send -> Table : ports[2].count > 0?
alt 否 → return -4
end
group 遍历端口表
loop for p in 0..MAX_PORTS-1
Send -> Table : ports[p].in_use && ports[p].send_type == SENSOR ?
alt 匹配
loop for h in 0..count-1
Send -> HList : handlers[h](p, data, len)
HList -> Dev : 实际外设写入
end
end
end
end
loop for each handler in ports[2].handlers[]
Send -> HList : handlers[i](port, data, len)
HList -> Dev : 实际外设写入
alt 至少调了一次 handler
Send --> App : return 0
else 无匹配端口
Send --> App : return -2
end
Send --> App : return 0
@enduml
```
@@ -353,7 +317,7 @@ actor "外设" as Dev
participant "用户分发代码" as Dispatch
participant "on_recv_rtcm()" as Callback
Dev -> Dispatch : 收到数据,识别为 rtcm 类型
Dev -> Dispatch : 收到数据,识别为 rtcm
Dispatch -> Callback : on_recv_rtcm(port_id, data, len)
Callback --> Dispatch : void
@enduml
@@ -364,19 +328,14 @@ Callback --> Dispatch : void
```plantuml
@startuml
state "空闲" as Idle
state "已创建\nsend=-1 recv=-1" as Created
state "已创建\nsend_type=-1\ncount=0" as Created
state "已配置" as Config
[*] --> Idle : reset / 启动
Idle --> Created : port_create()
Created --> Config : set_send_type / set_recv_type / add_handler
Config --> Config : 独立切换 send_type / recv_type\n增删 handler
Config --> Created : set_send_type(-1) / set_recv_type(-1)\nclear_handlers
Created --> Config : set_send_type / add_handler
Config --> Config : 切换 send_type\n增删 handler
Config --> Created : set_send_type(-1) / clear_handlers
Created --> Idle : port_delete()
Config --> Idle : port_delete()
Idle --> Created : 复用 ID
@@ -387,42 +346,38 @@ Idle --> Created : 复用 ID
## 8. 路由场景
### 场景 1:传感器只发送(sensor → UART + TCP)
### 场景 1:sensor 广播到 UART + TCP + CAN
```c
datarouter_port_t p = datarouter_port_create();
datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor);
datarouter_port_add_handler(p, uart_send);
datarouter_port_add_handler(p, tcp_send);
datarouter_port_t p1 = datarouter_port_create();
datarouter_port_set_send_type(p1, DATAROUTER_SEND_sensor);
datarouter_port_add_handler(p1, uart_send);
datarouter_port_add_handler(p1, tcp_send);
datarouter_send_sensor(p, "temp:25.3", 9);
// → uart_send(p, "temp:25.3", 9)
// → tcp_send(p, "temp:25.3", 9)
datarouter_port_t p2 = datarouter_port_create();
datarouter_port_set_send_type(p2, DATAROUTER_SEND_sensor);
datarouter_port_add_handler(p2, can_send);
datarouter_send_sensor("temp:25.3", 9);
// → uart_send(p1, "temp:25.3", 9)
// → tcp_send(p1, "temp:25.3", 9)
// → can_send(p2, "temp:25.3", 9)
```
### 场景 2:RTCM 只接收
### 场景 2:仅接收
```c
datarouter_port_t p = datarouter_port_create();
datarouter_port_set_recv_type(p, DATAROUTER_RECV_rtcm);
// 无 send_type,不注册 handler
// 外设收到数据后由用户调回调:
datarouter_on_recv_rtcm(p, data, len);
void datarouter_on_recv_rtcm(uint32_t port_id, const void *data, size_t len) {
apply_rtcm_correction(data, len);
}
// 外设收到后:datarouter_on_recv_rtcm(port, data, len);
```
### 场景 3:双向端口(status 发送 + command 接收)
### 场景 3:运行时移除 handler
```c
datarouter_port_t p = datarouter_port_create();
datarouter_port_set_send_type(p, DATAROUTER_SEND_status);
datarouter_port_set_recv_type(p, DATAROUTER_RECV_command);
datarouter_port_add_handler(p, uart_send);
// 发送
datarouter_send_status(p, "status:OK", 9);
// 接收
datarouter_on_recv_command(p, "reboot", 6);
datarouter_port_remove_handler(p1, tcp_send);
// 下次 send_sensor 不再触发 tcp
```
---
@@ -451,30 +406,24 @@ Weak ..> Result : 后备
| 返回值 | 含义 |
|:------:|------|
| 0 | 成功,所有 handler 被调用 |
| 0 | 成功,至少有一个 handler 被调用 |
| -1 | 库未初始化(未调 init) |
| -2 | 端口无效(越界/未创建/已删除) |
| -3 | 端口 send_type 与调用的发送函数不匹配 |
| -4 | 端口 handler 列表为空(count == 0) |
| -2 | 无端口匹配该 send_type(或匹配端口均无 handler) |
---
## 11. 配置扩展
### 增加能力
```c
#define DATAROUTER_SEND_CAPABILITIES \
DATAROUTER_SEND(sensor, "Sensor data") \
DATAROUTER_SEND(debug, "Debug log") /* 新增发送能力 */
DATAROUTER_SEND(debug, "Debug log") /* 新增 */
#define DATAROUTER_RECV_CAPABILITIES \
DATAROUTER_RECV(rtcm, "RTCM data") \
DATAROUTER_RECV(ota, "OTA firmware") /* 新增接收能力 */
DATAROUTER_RECV(ota, "OTA firmware") /* 新增 */
```
### 自定义限制
```bash
cmake -DCMAKE_C_FLAGS="-DDATAROUTER_MAX_PORTS=128 -DDATAROUTER_MAX_HANDLERS_PER_PORT=8"
```