feat: 拆分发送和接收功能声明,优化config配置方式
This commit is contained in:
@@ -1,34 +1,48 @@
|
||||
# DataRouter
|
||||
|
||||
轻量级 C 语言数据路由库。编译期声明报文类型,运行期将端口绑定到物理外设发送函数,实现一对多广播路由。
|
||||
轻量级 C 语言数据路由库。**发送能力和接收能力分开声明**,端口独立设置 send_type 和 recv_type,支持多外设一对多广播路由。
|
||||
|
||||
## 概念
|
||||
|
||||
| 术语 | 说明 |
|
||||
|------|------|
|
||||
| **通道 (Channel)** | 编译期声明的报文类型(如 `sensor` / `status` / `control`) |
|
||||
| **端口 (Port)** | 运行期创建的连接点,绑定一个报文类型和 N 个外设发送 handler |
|
||||
| **路由** | 将报文类型连接到物理外设发送函数的过程 |
|
||||
| **发送能力 (Send Capability)** | 编译期声明的可发送报文类型,生成 `datarouter_send_<id>()` |
|
||||
| **接收能力 (Recv Capability)** | 编译期声明的可接收报文类型,生成 `datarouter_on_recv_<id>()` |
|
||||
| **端口 (Port)** | 运行期连接点,独立设置 send_type + recv_type + handler 列表 |
|
||||
| **Handler** | 用户实现的物理外设发送函数,一个端口可注册多个(默认上限 4) |
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 声明报文类型
|
||||
### 1. 声明能力
|
||||
|
||||
编辑 `datarouter_config.h`:
|
||||
创建自己的 `datarouter_config.h`(可参考 `datarouter_config_template.h`):
|
||||
|
||||
```c
|
||||
#define DATAROUTER_CHANNELS \
|
||||
DATAROUTER_CHANNEL(sensor, "Sensor data") \
|
||||
DATAROUTER_CHANNEL(status, "Status report") \
|
||||
DATAROUTER_CHANNEL(control, "Control command")
|
||||
#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")
|
||||
```
|
||||
|
||||
> 库默认自带一份示例配置。将你的 `datarouter_config.h` 放到项目目录,
|
||||
> 编译时添加 `-I /path/to/your/config` 即可覆盖。无需修改库源代码。
|
||||
>
|
||||
> **注意**:确保你的配置目录在包含路径中出现在库目录之前,否则编译 `datarouter.c`
|
||||
> 时仍会使用库的默认配置。在 CMake 中可参考:
|
||||
> ```cmake
|
||||
> # 你的 CMakeLists.txt
|
||||
> include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) # 全局优先
|
||||
> add_subdirectory(path/to/DataRouter)
|
||||
> target_link_libraries(my_app DataRouter)
|
||||
> ```
|
||||
|
||||
### 2. 实现外设发送 handler
|
||||
|
||||
```c
|
||||
static void uart_send(uint32_t port_id, const void *data, size_t len) {
|
||||
/* 调用具体外设 API 发送数据 */
|
||||
HAL_UART_Transmit(&huart1, data, len, 1000);
|
||||
}
|
||||
|
||||
@@ -37,27 +51,42 @@ static void tcp_send(uint32_t port_id, const void *data, size_t len) {
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 创建端口并注册 handler
|
||||
### 3. 创建端口
|
||||
|
||||
```c
|
||||
datarouter_init();
|
||||
|
||||
datarouter_port_t p = datarouter_port_create();
|
||||
datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor);
|
||||
/* —— 只发送:传感器上报 —— */
|
||||
datarouter_port_t tx = datarouter_port_create();
|
||||
datarouter_port_set_send_type(tx, DATAROUTER_SEND_sensor);
|
||||
datarouter_port_add_handler(tx, uart_send);
|
||||
datarouter_port_add_handler(tx, tcp_send);
|
||||
datarouter_send_sensor(tx, "temperature:25.3", 16); // → UART + TCP
|
||||
|
||||
/* 一个端口同时路由到两个外设 */
|
||||
datarouter_port_add_handler(p, uart_send);
|
||||
datarouter_port_add_handler(p, tcp_send);
|
||||
/* —— 只接收:RTCM 修正 —— */
|
||||
datarouter_port_t rx = datarouter_port_create();
|
||||
datarouter_port_set_recv_type(rx, DATAROUTER_RECV_rtcm);
|
||||
// 外设收到数据后由用户调回调:
|
||||
datarouter_on_recv_rtcm(rx, data, len);
|
||||
|
||||
/* 发送 → 同时走 UART 和 TCP */
|
||||
datarouter_send_sensor(p, "temperature:25.3", 16);
|
||||
/* —— 同时收发:状态上报 + 命令接收 —— */
|
||||
datarouter_port_t bi = datarouter_port_create();
|
||||
datarouter_port_set_send_type(bi, DATAROUTER_SEND_status);
|
||||
datarouter_port_set_recv_type(bi, DATAROUTER_RECV_command);
|
||||
datarouter_port_add_handler(bi, uart_send);
|
||||
datarouter_send_status(bi, "status:OK", 9);
|
||||
datarouter_on_recv_command(bi, "reboot", 6);
|
||||
```
|
||||
|
||||
### 4. 实现接收回调
|
||||
|
||||
```c
|
||||
void datarouter_on_recv_sensor(uint32_t port_id, const void *data, size_t len) {
|
||||
printf("received sensor data: %.*s\n", (int)len, (const char *)data);
|
||||
void datarouter_on_recv_rtcm(uint32_t port_id, const void *data, size_t len) {
|
||||
apply_rtcm_correction(data, len);
|
||||
}
|
||||
|
||||
void datarouter_on_recv_command(uint32_t port_id, const void *data, size_t len) {
|
||||
execute_command(data, len);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -66,48 +95,55 @@ void datarouter_on_recv_sensor(uint32_t port_id, const void *data, size_t len) {
|
||||
### 初始化
|
||||
|
||||
```c
|
||||
void datarouter_init(void); // 初始化(幂等)
|
||||
void datarouter_reset(void); // 重置全部状态
|
||||
void datarouter_init(void); // 幂等初始化
|
||||
void datarouter_reset(void); // 重置全部状态
|
||||
```
|
||||
|
||||
### 端口管理
|
||||
|
||||
```c
|
||||
datarouter_port_t datarouter_port_create(void); // 创建端口
|
||||
void datarouter_port_delete(datarouter_port_t port); // 删除端口
|
||||
void datarouter_port_set_type(port, int channel_id); // 设置报文类型
|
||||
int datarouter_port_get_type(port); // 获取报文类型
|
||||
int datarouter_port_add_handler(port, handler); // 注册外设 handler
|
||||
int datarouter_port_remove_handler(port, handler); // 移除 handler
|
||||
void datarouter_port_clear_handlers(port); // 清除全部 handler
|
||||
int datarouter_port_handler_count(port); // handler 数量
|
||||
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 = 未设置
|
||||
|
||||
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); // 当前数量
|
||||
```
|
||||
|
||||
### 发送触发(每通道一个,X-macro 自动生成)
|
||||
### 发送触发(每个 SEND 能力生成一个)
|
||||
|
||||
```c
|
||||
int datarouter_send_sensor(port, data, len); // 返回值:0 成功 / -1 未初始化
|
||||
int datarouter_send_status(port, data, len); // -2 端口无效
|
||||
int datarouter_send_control(port, data, len); // -3 类型不匹配
|
||||
// -4 无 handler
|
||||
int datarouter_send_sensor(port, data, len); // 0 成功 / -1 未初始化
|
||||
int datarouter_send_status(port, data, len); // -2 端口无效
|
||||
// -3 send_type 不匹配
|
||||
// -4 无 handler
|
||||
```
|
||||
|
||||
### 接收回调(每通道一个,用户实现)
|
||||
### 接收回调(每个 RECV 能力生成一个声明)
|
||||
|
||||
```c
|
||||
void datarouter_on_recv_sensor(uint32_t port_id, const void *data, size_t len);
|
||||
void datarouter_on_recv_status(uint32_t port_id, const void *data, size_t len);
|
||||
void datarouter_on_recv_control(uint32_t port_id, const void *data, size_t len);
|
||||
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);
|
||||
```
|
||||
|
||||
库提供弱符号默认空实现,用户定义同名函数即可覆盖。
|
||||
库提供弱符号默认空实现,用户定义同名函数覆盖。
|
||||
|
||||
### 通道元数据
|
||||
### 能力元数据(两组独立)
|
||||
|
||||
```c
|
||||
int datarouter_channel_count(void);
|
||||
const char *datarouter_channel_name(int channel_id);
|
||||
const char *datarouter_channel_desc(int channel_id);
|
||||
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);
|
||||
```
|
||||
|
||||
## 路由模型
|
||||
@@ -115,15 +151,15 @@ const char *datarouter_channel_desc(int channel_id);
|
||||
```
|
||||
send_sensor(port, data, len)
|
||||
│
|
||||
├─→ handler[0] = uart_send → UART 外设
|
||||
├─→ handler[1] = tcp_send → TCP 外设
|
||||
└─→ handler[2] = can_send → CAN 外设
|
||||
├─→ handler[0] = uart_send → UART
|
||||
├─→ handler[1] = tcp_send → TCP
|
||||
└─→ handler[2] = can_send → CAN
|
||||
```
|
||||
|
||||
- 一个端口可注册多个 handler(一对多广播)
|
||||
- 同一 handler 可注册到多个端口(多路复用)
|
||||
- 运行时通过 `add_handler` / `remove_handler` 动态改变路由
|
||||
- 清空 handler 后发送返回 -4
|
||||
- 清空 handler 列表后发送返回 -4
|
||||
|
||||
## 编译
|
||||
|
||||
@@ -132,7 +168,7 @@ cmake -S . -B build
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
可选配置项:
|
||||
可选配置:
|
||||
|
||||
```bash
|
||||
cmake -DCMAKE_C_FLAGS="-DDATAROUTER_MAX_PORTS=128 -DDATAROUTER_MAX_HANDLERS_PER_PORT=8"
|
||||
@@ -147,18 +183,18 @@ ctest --test-dir build
|
||||
./build/test_datarouter
|
||||
```
|
||||
|
||||
当前 36 个测试用例,覆盖端口管理、类型、handler 增删、一对多广播、接收回调、错误边界。
|
||||
当前 27 个测试用例,覆盖端口管理、send_type/recv_type 独立设置、handler 增删、一对多广播、接收回调、能力元数据、错误边界。
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
datarouter_config.h 报文类型配置(用户编辑)
|
||||
datarouter.h 公共 API + X-macro 展开
|
||||
datarouter.c 实现(端口表 + handler 调用)
|
||||
example.c 使用示例
|
||||
tests/test_datarouter.c 单元测试
|
||||
DESIGN.md 详细设计文档
|
||||
TEST_CASES.md 测试用例文档
|
||||
datarouter_config.h 发送 + 接收能力配置(用户编辑)
|
||||
datarouter.h 公共 API + X-macro 展开
|
||||
datarouter.c 实现(端口表 + handler 遍历)
|
||||
example.c 收发分离使用示例
|
||||
tests/test_datarouter.c 单元测试(27 用例)
|
||||
DESIGN.md 详细设计文档(含 PlantUML 图)
|
||||
TEST_CASES.md 测试用例文档
|
||||
```
|
||||
|
||||
## 依赖
|
||||
|
||||
Reference in New Issue
Block a user