diff --git a/.idea/editor.xml b/.idea/editor.xml index f81c5eb..27a89fb 100644 --- a/.idea/editor.xml +++ b/.idea/editor.xml @@ -1,6 +1,253 @@ + \ No newline at end of file diff --git a/DESIGN.md b/DESIGN.md index 0a411b9..15cfa8d 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -2,7 +2,7 @@ ## 1. 设计目标 -轻量级 C 语言数据路由库。发送与接收能力分开声明,每个端口独立设置发送类型和接收类型,支持多外设一对多广播路由。 +轻量级 C 语言数据路由库。发送与接收能力分开声明,端口绑定 `send_type` 和外设 handler 列表。调用 `datarouter_send_(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_(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_(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_()" 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_ - @enduml ``` @@ -71,11 +68,11 @@ Callbacks --> Impl : 实现 on_recv_ | 文件 | 职责 | |------|------| -| `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_ ### 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_ ``` 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" ``` diff --git a/README.md b/README.md index 882d3fb..ddd54a1 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # DataRouter -轻量级 C 语言数据路由库。**发送能力和接收能力分开声明**,端口独立设置 send_type 和 recv_type,支持多外设一对多广播路由。 +轻量级 C 语言数据路由库。**发送能力和接收能力分开声明**,端口绑定 `send_type` 和外设 handler 列表。调用 `datarouter_send_(data, len)` 时自动广播到所有匹配端口。 ## 概念 | 术语 | 说明 | |------|------| -| **发送能力 (Send Capability)** | 编译期声明的可发送报文类型,生成 `datarouter_send_()` | -| **接收能力 (Recv Capability)** | 编译期声明的可接收报文类型,生成 `datarouter_on_recv_()` | -| **端口 (Port)** | 运行期连接点,独立设置 send_type + recv_type + handler 列表 | +| **发送能力 (Send Capability)** | 编译期声明的可发送报文类型,生成 `datarouter_send_(data, len)` | +| **接收能力 (Recv Capability)** | 编译期声明的可接收报文类型,生成 `datarouter_on_recv_(port, data, len)` | +| **端口 (Port)** | 运行期创建的连接点,包含 `send_type` + handler 列表 | | **Handler** | 用户实现的物理外设发送函数,一个端口可注册多个(默认上限 4) | ## 快速开始 @@ -27,14 +27,11 @@ DATAROUTER_RECV(command, "Remote control command") ``` -> 库默认自带一份示例配置。将你的 `datarouter_config.h` 放到项目目录, -> 编译时添加 `-I /path/to/your/config` 即可覆盖。无需修改库源代码。 +> 库自带默认配置。将你的 `datarouter_config.h` 放到项目目录, +> 编译时添加 `-I /path/to/your/config` 即可覆盖。无需修改库源码。 > -> **注意**:确保你的配置目录在包含路径中出现在库目录之前,否则编译 `datarouter.c` -> 时仍会使用库的默认配置。在 CMake 中可参考: > ```cmake -> # 你的 CMakeLists.txt -> include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) # 全局优先 +> include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) > add_subdirectory(path/to/DataRouter) > target_link_libraries(my_app DataRouter) > ``` @@ -56,26 +53,17 @@ static void tcp_send(uint32_t port_id, const void *data, size_t len) { ```c datarouter_init(); -/* —— 只发送:传感器上报 —— */ +/* —— 传感器上报:sensor 报文走 UART + TCP —— */ 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 -/* —— 只接收:RTCM 修正 —— */ -datarouter_port_t rx = datarouter_port_create(); -datarouter_port_set_recv_type(rx, DATAROUTER_RECV_rtcm); -// 外设收到数据后由用户调回调: -datarouter_on_recv_rtcm(rx, data, len); +/* 不指定端口,库自动广播到所有 send_type=sensor 的端口 */ +datarouter_send_sensor("temperature:25.3", 16); // → UART + TCP -/* —— 同时收发:状态上报 + 命令接收 —— */ -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); +/* —— 接收:实现回调,外设数据到达后自行调用 —— */ +datarouter_on_recv_rtcm(rx_port, data, len); ``` ### 4. 实现接收回调 @@ -84,10 +72,6 @@ datarouter_on_recv_command(bi, "reboot", 6); 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); -} ``` ## API 一览 @@ -107,8 +91,6 @@ 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); // 移除 @@ -119,12 +101,13 @@ int datarouter_port_handler_count(port); // 当前数量 ### 发送触发(每个 SEND 能力生成一个) ```c -int datarouter_send_sensor(port, data, len); // 0 成功 / -1 未初始化 -int datarouter_send_status(port, data, len); // -2 端口无效 - // -3 send_type 不匹配 - // -4 无 handler +int datarouter_send_sensor(const void *data, size_t len); // 0 成功 +int datarouter_send_status(const void *data, size_t len); // -1 未初始化 + // -2 无匹配端口 ``` +不指定端口,库遍历所有端口,`send_type` 匹配的逐一调用其全部 handler。 + ### 接收回调(每个 RECV 能力生成一个声明) ```c @@ -149,17 +132,18 @@ const char *datarouter_recv_cap_desc(int cap_id); ## 路由模型 ``` -send_sensor(port, data, len) +datarouter_send_sensor("temperature:25.3", 16) │ - ├─→ handler[0] = uart_send → UART - ├─→ handler[1] = tcp_send → TCP - └─→ handler[2] = can_send → CAN + ├─→ port 0 (send_type=sensor) handlers[0]=uart_send → UART + │ handlers[1]=tcp_send → TCP + └─→ port 1 (send_type=sensor) handlers[0]=can_send → CAN ``` -- 一个端口可注册多个 handler(一对多广播) +- 调用 `send_(data, len)` 时,库遍历所有端口,自动匹配 `send_type` +- 每个端口可注册多个 handler(一对多广播) - 同一 handler 可注册到多个端口(多路复用) -- 运行时通过 `add_handler` / `remove_handler` 动态改变路由 -- 清空 handler 列表后发送返回 -4 +- 运行时通过 `add_handler` / `remove_handler` / `port_delete` 动态改变路由 +- 无任何端口匹配该 `send_type` 时返回 -2 ## 编译 @@ -183,18 +167,19 @@ ctest --test-dir build ./build/test_datarouter ``` -当前 27 个测试用例,覆盖端口管理、send_type/recv_type 独立设置、handler 增删、一对多广播、接收回调、能力元数据、错误边界。 +当前 22 个测试用例,覆盖端口管理、send_type 与 handler 设置、自动广播路由、接收回调、能力元数据。 ## 文件结构 ``` -datarouter_config.h 发送 + 接收能力配置(用户编辑) -datarouter.h 公共 API + X-macro 展开 -datarouter.c 实现(端口表 + handler 遍历) -example.c 收发分离使用示例 -tests/test_datarouter.c 单元测试(27 用例) -DESIGN.md 详细设计文档(含 PlantUML 图) -TEST_CASES.md 测试用例文档 +datarouter_config.h 发送 + 接收能力配置(用户可覆盖) +datarouter.h 公共 API + X-macro 展开 +datarouter.c 实现(端口表 + send 遍历) +datarouter_config_template.h 外部配置模板 +example.c 使用示例 +tests/test_datarouter.c 单元测试(22 用例) +DESIGN.md 详细设计文档(含 PlantUML 图) +TEST_CASES.md 测试用例文档 ``` ## 依赖 diff --git a/TEST_CASES.md b/TEST_CASES.md index 28b2b9b..95e185e 100644 --- a/TEST_CASES.md +++ b/TEST_CASES.md @@ -17,7 +17,6 @@ cmake -S . -B build cmake --build build ctest --test-dir build -# 或直接运行: ./build/test_datarouter ``` @@ -27,68 +26,53 @@ ctest --test-dir build | # | 测试名 | 描述 | 步骤 | 预期 | |---|--------|------|------|------| -| 1 | `error_uninit` | 未 init 时发送 | 不调 init 直接 `send_sensor(0, ...)` | 返回 -1 | +| 1 | `error_uninit` | 未 init 时发送 | `send_sensor("d", 1)` | 返回 -1 | ### 2. 端口管理(4 个) | # | 测试名 | 描述 | 步骤 | 预期 | |---|--------|------|------|------| | 2 | `port_create_basic` | 基本创建 | `port_create()` | 返回 ≥ 0 | -| 3 | `port_create_max` | 满容量(64) | 循环创建到满再尝试 | 64 个成功,第 65 个 INVALID | +| 3 | `port_create_max` | 满容量 64 | 循环创建到满再尝试 | 64 个成功,第 65 个 INVALID | | 4 | `port_delete_invalid` | 删除无效 ID | `delete(-1)` + `delete(999)` | 不崩溃 | -| 5 | `port_default_state` | 默认状态 | 创建端口,查 send/recv/handler | send_type=-1, recv_type=-1, count=0 | +| 5 | `port_default_state` | 默认状态 | 新建端口,查 send_type / handler count | `send_type=-1`, `count=0` | -### 3. send_type / recv_type 独立设置(6 个) +### 3. send_type 与 handler(3 个) | # | 测试名 | 描述 | 步骤 | 预期 | |---|--------|------|------|------| -| 6 | `send_type_set_get` | 设置发送类型 | `set_send_type(sensor)` → `get_send_type()` | 返回 sensor | -| 7 | `recv_type_set_get` | 设置接收类型 | `set_recv_type(rtcm)` → `get_recv_type()` | 返回 rtcm | -| 8 | `types_independent` | 收发互不干扰 | 同时 `set_send_type(sensor)` + `set_recv_type(command)` | get_send=sensor, get_recv=command | -| 9 | `send_type_clear` | 清除发送类型 | `set_send_type(sensor)` → `set_send_type(-1)` | `get_send_type()` == -1 | -| 10 | `recv_type_clear` | 清除接收类型 | `set_recv_type(rtcm)` → `set_recv_type(-1)` | `get_recv_type()` == -1 | -| 11 | `types_from_invalid` | 无效端口查类型 | `get_send_type(-1/999)` / `get_recv_type(-1/999)` | 均返回 -1 | +| 6 | `send_type_set_get` | 设置并清除 send_type | `set_send_type(sensor)` → `get` → `set(-1)` → `get` | sensor → -1 | +| 7 | `handler_add_remove` | 添加后移除 handler | add(h) count=1 → remove(h) count=0 | count 正确 | +| 8 | `handler_clear` | 清除全部 handler | add → clear | count == 0 | -### 4. handler 增删(2 个) +### 4. 发送 — 自动广播(11 个) | # | 测试名 | 描述 | 步骤 | 预期 | |---|--------|------|------|------| -| 12 | `handler_add_remove` | 添加后移除 | ① add(a) add(b) count=2 ② remove(a) count=1 | count 正确 | -| 13 | `handler_clear` | 清除全部 | add 后 clear | count == 0 | +| 9 | `send_no_match_port` | 无匹配端口 | 不创建任何端口,直接 `send_sensor` | 返回 -2 | +| 10 | `send_one_port_one_handler` | 单端口单 handler | 创建端口中 send_type + add(h) → send | 返回 0;handler 1 次 | +| 11 | `send_one_port_multi_handler` | 单端口双 handler | add(h) + add(h2) → send | handler 2 次 | +| 12 | `send_multi_ports_same_type` | 两端口同类型 | p1(sensor,h) + p2(sensor,h) → send | handler 2 次,各端口一次 | +| 13 | `send_multi_port_multi_handler` | 多端口多 handler | p1(h,h2) + p2(h3) → send | handler 3 次 | +| 14 | `send_type_filter` | 类型过滤 | p1(sensor,h) + p2(status,h) → `send_sensor` | 只触发 p1 | +| 15 | `send_after_remove_handler` | 移除 handler 后 | add(h) → send count=1 → remove(h) → send | 第二次返回 -2 | +| 16 | `send_after_delete_port` | 删除端口后 | 创建→设好→删除→send | 返回 -2 | +| 17 | `send_zero_length` | 零长度数据 | send("x", 0) | 返回 0;handler 被调 | +| 18 | `send_null_data` | NULL 数据 | send(NULL, 0) | 返回 0;handler 被调 | +| 19 | `send_multi_cap` | 多能力独立 | p1(sensor) + p2(status) → 分别 send_sensor + send_status | 各触发匹配的端口 | -### 5. 发送触发(9 个) +### 5. 接收回调(1 个) | # | 测试名 | 描述 | 步骤 | 预期 | |---|--------|------|------|------| -| 14 | `send_one_handler` | 单 handler 发送 | send_type + add_handler → send_sensor | 返回 0;handler 被调用 1 次 | -| 15 | `send_multi_handlers` | 三个 handler 广播 | 注册 3 个 handler 后 send | 返回 0;handler 被调用 3 次 | -| 16 | `send_type_mismatch` | 发送类型不匹配 | set_send_type(sensor) 但调用 send_status | 返回 -3;handler 不被调用 | -| 17 | `send_no_handler` | 未注册 handler | 只 set_send_type 不 add_handler | 返回 -4 | -| 18 | `send_no_send_type` | 没有 send_type | 端口只有 recv_type,调 send_sensor | 返回 -3 | -| 19 | `send_remove_handler` | 移除后少广播 | 注册 2 handler → send count=2 → remove 1 → send count=1 | 数量正确 | -| 20 | `send_clear_handlers` | 清空后无法发送 | add → clear → send | 返回 -4 | -| 21 | `send_zero_length` | 零长度数据 | send(port, "x", 0) | 返回 0;handler 被调用 | -| 22 | `send_null_data` | NULL 数据 | send(port, NULL, 0) | 返回 0;handler 被调用 | +| 20 | `recv_callback` | 用户实现接收回调 | `on_recv_rtcm(0, "d", 1)` | 回调被触发 | -### 6. 接收回调(1 个) +### 6. 能力元数据(2 个) | # | 测试名 | 描述 | 步骤 | 预期 | |---|--------|------|------|------| -| 23 | `recv_callbacks` | 用户实现接收回调 | ① `on_recv_rtcm(0, ...)` ② `on_recv_command(1, ...)` | 各自触发,互不干扰 | - -### 7. 能力元数据(2 个) - -| # | 测试名 | 描述 | 步骤 | 预期 | -|---|--------|------|------|------| -| 24 | `send_cap_meta` | 发送能力元数据 | 查 count / name / desc / 边界 | SEND 两组正确 | -| 25 | `recv_cap_meta` | 接收能力元数据 | 查 count / name / desc / 边界 | RECV 两组正确 | - -### 8. 错误处理(2 个) - -| # | 测试名 | 描述 | 步骤 | 预期 | -|---|--------|------|------|------| -| 26 | `error_invalid_port` | 无效端口 | `send_sensor(999/-1, ...)` | 均返回 -2 | -| 27 | `error_deleted_port` | 已删除端口 | 创建→设好→删除→send | 返回 -2 | +| 21 | `send_cap_meta` | 发送能力元数据 | count / name / desc / 边界 | SEND 两组正确 | +| 22 | `recv_cap_meta` | 接收能力元数据 | count / name / desc / 边界 | RECV 两组正确 | ## 覆盖矩阵 @@ -96,11 +80,9 @@ ctest --test-dir build |----------|:------:|------------| | 未初始化 | 1 | send → -1 | | 端口管理 | 4 | 创建/满容量/删除异常/默认状态 | -| send_type / recv_type | 6 | 设置/清除/独立/无效端口 | -| handler 增删 | 2 | 添加/移除/清空 | -| 发送触发 | 9 | 单播/多播/类型不匹配/无handler/无send_type/移除后/清空后/零长/NULL | +| send_type & handler | 3 | 设置/清除/添加/移除/清空 | +| 发送自动广播 | 11 | 无匹配/单播/多 handler 单端口/多端口同类型/多端口多 handler/类型过滤/移除后/删除后/零长/NULL/多能力独立 | | 接收回调 | 1 | 用户实现覆盖弱符号 | | 能力元数据 | 2 | SEND 与 RECV 两组独立查询 | -| 错误处理 | 2 | 无效端口/已删除端口 | -**总计:27 个测试用例** +**总计:22 个测试用例** diff --git a/build/example b/build/example index 9499c22..6e019f2 100755 Binary files a/build/example and b/build/example differ diff --git a/build/test_datarouter b/build/test_datarouter index edf203e..4615576 100755 Binary files a/build/test_datarouter and b/build/test_datarouter differ diff --git a/datarouter.c b/datarouter.c index fd93586..b3064b3 100644 --- a/datarouter.c +++ b/datarouter.c @@ -1,6 +1,5 @@ /** * @file datarouter.c - * @brief 数据路由库 —— 实现 */ #include "datarouter.h" @@ -18,7 +17,6 @@ typedef struct { int send_type; - int recv_type; datarouter_send_handler_t handlers[DATAROUTER_MAX_HANDLERS_PER_PORT]; int count; uint8_t in_use; @@ -27,7 +25,7 @@ typedef struct { static port_entry_t ports[DATAROUTER_MAX_PORTS]; static uint8_t initialized; -/* ---- 发送能力元数据 ---- */ +/* ---- 元数据 ---- */ static const char *send_names[] = { #define DATAROUTER_SEND(id, desc) #id, @@ -41,8 +39,6 @@ static const char *send_descs[] = { #undef DATAROUTER_SEND }; -/* ---- 接收能力元数据 ---- */ - static const char *recv_names[] = { #define DATAROUTER_RECV(id, desc) #id, DATAROUTER_RECV_CAPABILITIES @@ -55,29 +51,31 @@ static const char *recv_descs[] = { #undef DATAROUTER_RECV }; -/* ---- 弱符号接收回调默认实现 ---- */ +/* ---- 弱符号接收回调 ---- */ #define DATAROUTER_RECV(id, desc) \ DATAROUTER_WEAK void datarouter_on_recv_##id( \ uint32_t port_id, const void *data, size_t len) \ - { \ - (void)port_id; (void)data; (void)len; \ - } + { (void)port_id; (void)data; (void)len; } DATAROUTER_RECV_CAPABILITIES #undef DATAROUTER_RECV -/* ---- 发送触发函数实现 ---- */ +/* ---- 发送触发函数 ---- */ #define DATAROUTER_SEND(id, desc) \ - int datarouter_send_##id(uint32_t port_id, const void *data, size_t len) \ + int datarouter_send_##id(const void *data, size_t len) \ { \ if (!initialized) return -1; \ - if (port_id >= DATAROUTER_MAX_PORTS || !ports[port_id].in_use) return -2; \ - if (ports[port_id].send_type != DATAROUTER_SEND_##id) return -3; \ - if (ports[port_id].count == 0) return -4; \ - for (int _i = 0; _i < ports[port_id].count; _i++) \ - ports[port_id].handlers[_i](port_id, data, len); \ - return 0; \ + int called = 0; \ + for (uint32_t _p = 0; _p < DATAROUTER_MAX_PORTS; _p++) { \ + if (!ports[_p].in_use) continue; \ + if (ports[_p].send_type != DATAROUTER_SEND_##id) continue; \ + for (int _h = 0; _h < ports[_p].count; _h++) { \ + ports[_p].handlers[_h](_p, data, len); \ + called = 1; \ + } \ + } \ + return called ? 0 : -2; \ } DATAROUTER_SEND_CAPABILITIES #undef DATAROUTER_SEND @@ -104,7 +102,6 @@ datarouter_port_t datarouter_port_create(void) if (!ports[i].in_use) { ports[i].in_use = 1; ports[i].send_type = -1; - ports[i].recv_type = -1; ports[i].count = 0; return (datarouter_port_t)i; } @@ -133,20 +130,6 @@ int datarouter_port_get_send_type(datarouter_port_t port) return ports[port].send_type; } -void datarouter_port_set_recv_type(datarouter_port_t port, int cap_id) -{ - if (!initialized) return; - if (port < 0 || port >= DATAROUTER_MAX_PORTS || !ports[port].in_use) return; - ports[port].recv_type = cap_id; -} - -int datarouter_port_get_recv_type(datarouter_port_t port) -{ - if (!initialized) return -1; - if (port < 0 || port >= DATAROUTER_MAX_PORTS || !ports[port].in_use) return -1; - return ports[port].recv_type; -} - int datarouter_port_add_handler(datarouter_port_t port, datarouter_send_handler_t handler) { if (!initialized) return -1; @@ -187,36 +170,10 @@ int datarouter_port_handler_count(datarouter_port_t port) /* ---- 元数据查询 ---- */ -int datarouter_send_cap_count(void) -{ - return DATAROUTER_SEND_CAP_COUNT; -} +int datarouter_send_cap_count(void) { return DATAROUTER_SEND_CAP_COUNT; } +const char *datarouter_send_cap_name(int c) { return (c<0||c>=DATAROUTER_SEND_CAP_COUNT)?NULL:send_names[c]; } +const char *datarouter_send_cap_desc(int c) { return (c<0||c>=DATAROUTER_SEND_CAP_COUNT)?NULL:send_descs[c]; } -const char *datarouter_send_cap_name(int cap_id) -{ - if (cap_id < 0 || cap_id >= DATAROUTER_SEND_CAP_COUNT) return NULL; - return send_names[cap_id]; -} - -const char *datarouter_send_cap_desc(int cap_id) -{ - if (cap_id < 0 || cap_id >= DATAROUTER_SEND_CAP_COUNT) return NULL; - return send_descs[cap_id]; -} - -int datarouter_recv_cap_count(void) -{ - return DATAROUTER_RECV_CAP_COUNT; -} - -const char *datarouter_recv_cap_name(int cap_id) -{ - if (cap_id < 0 || cap_id >= DATAROUTER_RECV_CAP_COUNT) return NULL; - return recv_names[cap_id]; -} - -const char *datarouter_recv_cap_desc(int cap_id) -{ - if (cap_id < 0 || cap_id >= DATAROUTER_RECV_CAP_COUNT) return NULL; - return recv_descs[cap_id]; -} +int datarouter_recv_cap_count(void) { return DATAROUTER_RECV_CAP_COUNT; } +const char *datarouter_recv_cap_name(int c) { return (c<0||c>=DATAROUTER_RECV_CAP_COUNT)?NULL:recv_names[c]; } +const char *datarouter_recv_cap_desc(int c) { return (c<0||c>=DATAROUTER_RECV_CAP_COUNT)?NULL:recv_descs[c]; } diff --git a/datarouter.h b/datarouter.h index 26aa877..ba1163b 100644 --- a/datarouter.h +++ b/datarouter.h @@ -4,20 +4,16 @@ * * ## 概念 * - * - **发送能力 (Send Capability)**:编译期声明的可发送报文类型 - * - **接收能力 (Recv Capability)**:编译期声明的可接收报文类型 - * - **端口 (Port)**:运行期连接点,独立设置 send_type + recv_type + 外设 handler 列表 + * - **发送能力**:编译期声明的可发送报文类型,生成 datarouter_send_(data, len) + * - **接收能力**:编译期声明的可接收报文类型,生成 datarouter_on_recv_(port, data, len) + * - **端口**:运行期创建的连接点,包含 send_type + handler 列表 * - * ## 使用流程 + * ## 路由 * - * 1. 创建 datarouter_config.h 声明发送和接收能力(见 datarouter_config_template.h) - * 2. 编译时通过 -I 指向你的配置目录;若无,库使用内置默认配置 - * 3. datarouter_init() 初始化 - * 4. port_create() 创建端口 - * 5. port_set_send_type() 设置发送类型 / port_set_recv_type() 设置接收类型 - * 6. port_add_handler() 注册外设发送函数 - * 7. 调 datarouter_send_() 触发发送(库调用所有 handler) - * 8. 实现 datarouter_on_recv_() 处理接收数据 + * 调用 datarouter_send_(data, len) 时,库遍历所有端口, + * 找到 send_type 匹配的端口,逐一调用其全部 handler。无需指定从哪个端口发送。 + * + * 接收侧由用户自行调用 datarouter_on_recv_(port, data, len) 处理外设收到的数据。 */ #ifndef DATAROUTER_H @@ -26,14 +22,6 @@ #include #include -/* - * 配置加载策略: - * 1. 优先从 include path 搜索 (用户提供的版本) - * 2. 找不到则回退到库自带的 "datarouter_config.h"(默认配置) - * - * 用户只需将自己的 datarouter_config.h 放到项目目录, - * 编译时添加 -I /path/to/your/config 即可覆盖内置配置。 - */ #if defined(__has_include) # if __has_include() # include @@ -66,7 +54,7 @@ enum datarouter_recv_cap { DATAROUTER_RECV_CAP_COUNT }; -/* ========== 外设发送 handler 类型 ========== */ +/* ========== 外设发送 handler ========== */ typedef void (*datarouter_send_handler_t)(uint32_t port_id, const void *data, size_t len); @@ -74,14 +62,14 @@ typedef void (*datarouter_send_handler_t)(uint32_t port_id, const void *data, si #define DATAROUTER_MAX_HANDLERS_PER_PORT 4 #endif -/* ========== 发送触发函数(每个发送能力生成一个) ========== */ +/* ========== 发送触发函数 ========== */ #define DATAROUTER_SEND(id, desc) \ - int datarouter_send_##id(uint32_t port_id, const void *data, size_t len); + int datarouter_send_##id(const void *data, size_t len); DATAROUTER_SEND_CAPABILITIES #undef DATAROUTER_SEND -/* ========== 接收回调声明(每个接收能力生成一个,用户实现) ========== */ +/* ========== 接收回调声明 ========== */ #define DATAROUTER_RECV(id, desc) \ void datarouter_on_recv_##id(uint32_t port_id, const void *data, size_t len); @@ -101,8 +89,6 @@ void datarouter_port_delete(datarouter_port_t port); void datarouter_port_set_send_type(datarouter_port_t port, int cap_id); int datarouter_port_get_send_type(datarouter_port_t port); -void datarouter_port_set_recv_type(datarouter_port_t port, int cap_id); -int datarouter_port_get_recv_type(datarouter_port_t port); int datarouter_port_add_handler(datarouter_port_t port, datarouter_send_handler_t handler); int datarouter_port_remove_handler(datarouter_port_t port, datarouter_send_handler_t handler); diff --git a/example.c b/example.c index 2760478..5895b5e 100644 --- a/example.c +++ b/example.c @@ -1,93 +1,73 @@ /** * @file example.c - * @brief 数据路由库使用示例 * - * 展示: - * - 发送能力和接收能力分开声明(sensor 只发送,rtcm 只接收) - * - 端口独立设置 send_type 和 recv_type - * - 一个端口可同时拥有发送和接收能力 + * 调用 datarouter_send_sensor(data, len) 无需指定端口, + * 库自动广播到所有 send_type=sensor 的端口。 */ #include "datarouter.h" #include -#include - -/* ---- 外设发送 handler ---- */ static void uart_send(uint32_t port_id, const void *data, size_t len) { - printf("[UART] port %u: %.*s\n", port_id, (int)len, (const char *)data); + printf("[UART port %u] %.*s\n", port_id, (int)len, (const char *)data); } static void tcp_send(uint32_t port_id, const void *data, size_t len) { - printf("[TCP] port %u: %.*s\n", port_id, (int)len, (const char *)data); + printf("[TCP port %u] %.*s\n", port_id, (int)len, (const char *)data); } -/* ---- 接收回调实现 ---- */ - -void datarouter_on_recv_rtcm(uint32_t port_id, const void *data, size_t len) +static void can_send(uint32_t port_id, const void *data, size_t len) { - printf("[RX:rtcm] port %u: %.*s\n", port_id, (int)len, (const char *)data); + printf("[CAN port %u] %.*s\n", port_id, (int)len, (const char *)data); } void datarouter_on_recv_command(uint32_t port_id, const void *data, size_t len) { - printf("[RX:cmd] port %u: %.*s\n", port_id, (int)len, (const char *)data); + printf("[RX:cmd port %u] %.*s\n", port_id, (int)len, (const char *)data); } int main(void) { datarouter_init(); - /* 查询能力 */ - printf("Send capabilities: %d\n", datarouter_send_cap_count()); + printf("Capabilities:\n"); for (int i = 0; i < datarouter_send_cap_count(); i++) printf(" SEND [%d] %s - %s\n", i, datarouter_send_cap_name(i), datarouter_send_cap_desc(i)); - printf("Recv capabilities: %d\n", datarouter_recv_cap_count()); - for (int i = 0; i < datarouter_recv_cap_count(); i++) - printf(" RECV [%d] %s - %s\n", i, - datarouter_recv_cap_name(i), datarouter_recv_cap_desc(i)); - /* - * 端口 A:只有发送能力 —— 上报传感器数据 + * 创建两个端口,都设 send_type=sensor,各绑不同外设。 + * 调用 datarouter_send_sensor() 时两个端口同时触发。 */ - datarouter_port_t tx_port = datarouter_port_create(); - datarouter_port_set_send_type(tx_port, DATAROUTER_SEND_sensor); - datarouter_port_add_handler(tx_port, uart_send); - datarouter_port_add_handler(tx_port, 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); - printf("\n--- send sensor (UART + TCP) ---\n"); - datarouter_send_sensor(tx_port, "temperature:25.3", 16); - /* 该端口没有 recv_type,不能接收任何报文 */ + datarouter_port_t p2 = datarouter_port_create(); + datarouter_port_set_send_type(p2, DATAROUTER_SEND_sensor); + datarouter_port_add_handler(p2, can_send); - /* - * 端口 B:只有接收能力 —— 接收 RTCM 修正 - */ - datarouter_port_t rtcm_port = datarouter_port_create(); - datarouter_port_set_recv_type(rtcm_port, DATAROUTER_RECV_rtcm); - /* 没有 send_type,也没有 handler —— 不能发送 */ + /* 不指定端口,自动广播到所有 sensor 端口 */ + printf("\n--- send_sensor (auto-route to ALL sensor ports) ---\n"); + datarouter_send_sensor("temperature:25.3", 16); - printf("\n--- simulate receive RTCM ---\n"); - datarouter_on_recv_rtcm(rtcm_port, "rtcm_data_v3.2", 14); + /* 运行时移除一个 handler,下次发送不再触发它 */ + printf("\n--- remove TCP handler from p1, resend ---\n"); + datarouter_port_remove_handler(p1, tcp_send); + datarouter_send_sensor("temperature:26.1", 16); - /* - * 端口 C:同时有收发能力 —— 接收命令 + 上报状态 - */ - datarouter_port_t bi_port = datarouter_port_create(); - datarouter_port_set_send_type(bi_port, DATAROUTER_SEND_status); - datarouter_port_set_recv_type(bi_port, DATAROUTER_RECV_command); - datarouter_port_add_handler(bi_port, uart_send); + /* 接收侧:用户自行调用回调 */ + printf("\n--- recv command ---\n"); + datarouter_on_recv_command(0, "reboot", 6); - printf("\n--- bidirectional port ---\n"); - datarouter_send_status(bi_port, "status:OK", 9); - datarouter_on_recv_command(bi_port, "reboot", 6); + /* 删除一个端口,触发时不再走它 */ + printf("\n--- delete p2 (CAN), resend ---\n"); + datarouter_port_delete(p2); + datarouter_send_sensor("temperature:27.0", 16); - /* 清理 */ - datarouter_port_delete(tx_port); - datarouter_port_delete(rtcm_port); - datarouter_port_delete(bi_port); + datarouter_port_delete(p1); return 0; } diff --git a/tests/test_datarouter.c b/tests/test_datarouter.c index 8f895fa..9e81b7b 100644 --- a/tests/test_datarouter.c +++ b/tests/test_datarouter.c @@ -1,15 +1,5 @@ /** * @file test_datarouter.c - * @brief 数据路由库单元测试 - * - * 覆盖: - * - 端口管理 - * - send_type / recv_type 独立设置 - * - 多 handler 增删 - * - 发送调用(一对多广播) - * - 接收回调 - * - 发送/接收能力元数据各自独立 - * - 错误处理 */ #include "datarouter.h" @@ -17,7 +7,7 @@ #include /* ================================================================ - * 测试框架 + * 框架 * ================================================================ */ static int _total_run, _total_pass, _total_fail; @@ -66,19 +56,19 @@ cleanup: \ * ================================================================ */ static int _h_cnt; -static void _h(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } -static void _h_a(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } -static void _h_b(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } -static void _h_c(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } -static void _h_d(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } -static void reset_h(void) { _h_cnt = 0; } +static int _h_port[16]; +static int _h_pos; +static void _h(uint32_t p, const void *d, size_t l) { (void)d; (void)l; _h_cnt++; if (_h_pos<16) _h_port[_h_pos++]=p; } +static void _h2(uint32_t p, const void *d, size_t l) { (void)d; (void)l; _h_cnt++; if (_h_pos<16) _h_port[_h_pos++]=p; } +static void _h3(uint32_t p, const void *d, size_t l) { (void)d; (void)l; _h_cnt++; if (_h_pos<16) _h_port[_h_pos++]=p; } +static void reset_h(void) { _h_cnt = 0; _h_pos = 0; } /* ================================================================ * 1. 未初始化 * ================================================================ */ TEST_START(error_uninit) - CHECK(datarouter_send_sensor(0, "d", 1) == -1, "expected -1"); + CHECK(datarouter_send_sensor("d", 1) == -1, "expected -1"); TEST_END() /* ================================================================ @@ -86,7 +76,7 @@ TEST_END() * ================================================================ */ TEST_START(port_create_basic) - CHECK(FIXTURE_CREATE(&_fix) >= 0, "create failed"); + CHECK(FIXTURE_CREATE(&_fix) >= 0, NULL); TEST_END() TEST_START(port_create_max) @@ -106,68 +96,28 @@ TEST_END() TEST_START(port_default_state) datarouter_port_t p = FIXTURE_CREATE(&_fix); - CHECK(datarouter_port_get_send_type(p) == -1, "send_type should be -1"); - CHECK(datarouter_port_get_recv_type(p) == -1, "recv_type should be -1"); - CHECK(datarouter_port_handler_count(p) == 0, "handler count 0"); + CHECK(datarouter_port_get_send_type(p) == -1, NULL); + CHECK(datarouter_port_handler_count(p) == 0, NULL); TEST_END() /* ================================================================ - * 3. send_type / recv_type 独立设置 + * 3. send_type 与 handler * ================================================================ */ TEST_START(send_type_set_get) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); CHECK(datarouter_port_get_send_type(p) == DATAROUTER_SEND_sensor, NULL); -TEST_END() - -TEST_START(recv_type_set_get) - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_recv_type(p, DATAROUTER_RECV_rtcm); - CHECK(datarouter_port_get_recv_type(p) == DATAROUTER_RECV_rtcm, NULL); -TEST_END() - -TEST_START(types_independent) - /* 一个端口同时设置 send_type 和 recv_type,互不干扰 */ - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); - datarouter_port_set_recv_type(p, DATAROUTER_RECV_command); - CHECK(datarouter_port_get_send_type(p) == DATAROUTER_SEND_sensor, NULL); - CHECK(datarouter_port_get_recv_type(p) == DATAROUTER_RECV_command, NULL); -TEST_END() - -TEST_START(send_type_clear) - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_set_send_type(p, -1); CHECK(datarouter_port_get_send_type(p) == -1, NULL); TEST_END() -TEST_START(recv_type_clear) - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_recv_type(p, DATAROUTER_RECV_rtcm); - datarouter_port_set_recv_type(p, -1); - CHECK(datarouter_port_get_recv_type(p) == -1, NULL); -TEST_END() - -TEST_START(types_from_invalid) - CHECK(datarouter_port_get_send_type(-1) == -1, NULL); - CHECK(datarouter_port_get_recv_type(-1) == -1, NULL); - CHECK(datarouter_port_get_send_type(999) == -1, NULL); - CHECK(datarouter_port_get_recv_type(999) == -1, NULL); -TEST_END() - -/* ================================================================ - * 4. 多 handler - * ================================================================ */ - TEST_START(handler_add_remove) datarouter_port_t p = FIXTURE_CREATE(&_fix); - CHECK(datarouter_port_add_handler(p, _h_a) == 0, NULL); - CHECK(datarouter_port_add_handler(p, _h_b) == 0, NULL); - CHECK(datarouter_port_handler_count(p) == 2, NULL); - CHECK(datarouter_port_remove_handler(p, _h_a) == 0, NULL); + CHECK(datarouter_port_add_handler(p, _h) == 0, NULL); CHECK(datarouter_port_handler_count(p) == 1, NULL); + CHECK(datarouter_port_remove_handler(p, _h) == 0, NULL); + CHECK(datarouter_port_handler_count(p) == 0, NULL); TEST_END() TEST_START(handler_clear) @@ -178,67 +128,93 @@ TEST_START(handler_clear) TEST_END() /* ================================================================ - * 5. 发送触发 + * 4. 发送 — 自动广播 * ================================================================ */ -TEST_START(send_one_handler) +TEST_START(send_no_match_port) + /* 没有端口配置该 send_type */ + CHECK(datarouter_send_sensor("d", 1) == -2, "expected -2"); +TEST_END() + +TEST_START(send_one_port_one_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); reset_h(); - CHECK(datarouter_send_sensor(p, "d", 1) == 0, NULL); - CHECK(_h_cnt == 1, "handler called %d times", _h_cnt); + CHECK(datarouter_send_sensor("d", 1) == 0, NULL); + CHECK(_h_cnt == 1, "cnt=%d", _h_cnt); + CHECK(_h_port[0] == (int)p, "port=%d", _h_port[0]); TEST_END() -TEST_START(send_multi_handlers) - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); - datarouter_port_add_handler(p, _h_a); - datarouter_port_add_handler(p, _h_b); - datarouter_port_add_handler(p, _h_c); - reset_h(); - CHECK(datarouter_send_sensor(p, "d", 1) == 0, NULL); - CHECK(_h_cnt == 3, "handler called %d times", _h_cnt); -TEST_END() - -TEST_START(send_type_mismatch) +TEST_START(send_one_port_multi_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); + datarouter_port_add_handler(p, _h2); reset_h(); - CHECK(datarouter_send_status(p, "d", 1) == -3, "expected -3"); - CHECK(_h_cnt == 0, NULL); + CHECK(datarouter_send_sensor("d", 1) == 0, NULL); + CHECK(_h_cnt == 2, "cnt=%d", _h_cnt); TEST_END() -TEST_START(send_no_handler) - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); - CHECK(datarouter_send_sensor(p, "d", 1) == -4, "expected -4"); +TEST_START(send_multi_ports_same_type) + /* 两个端口同类型,各一个 handler */ + datarouter_port_t p1 = FIXTURE_CREATE(&_fix); + datarouter_port_t p2 = FIXTURE_CREATE(&_fix); + datarouter_port_set_send_type(p1, DATAROUTER_SEND_sensor); + datarouter_port_set_send_type(p2, DATAROUTER_SEND_sensor); + datarouter_port_add_handler(p1, _h); + datarouter_port_add_handler(p2, _h); + reset_h(); + CHECK(datarouter_send_sensor("d", 1) == 0, NULL); + CHECK(_h_cnt == 2, "cnt=%d", _h_cnt); + /* p1 和 p2 各触发一次 */ + CHECK((_h_port[0]==p1 && _h_port[1]==p2) || + (_h_port[0]==p2 && _h_port[1]==p1), "ports %d,%d", _h_port[0], _h_port[1]); TEST_END() -TEST_START(send_no_send_type) - /* 端口只有 recv_type,没有 send_type */ - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_recv_type(p, DATAROUTER_RECV_rtcm); - CHECK(datarouter_send_sensor(p, "d", 1) == -3, "expected -3 (send_type unset)"); +TEST_START(send_multi_port_multi_handler) + datarouter_port_t p1 = FIXTURE_CREATE(&_fix); + datarouter_port_t p2 = FIXTURE_CREATE(&_fix); + datarouter_port_set_send_type(p1, DATAROUTER_SEND_sensor); + datarouter_port_set_send_type(p2, DATAROUTER_SEND_sensor); + datarouter_port_add_handler(p1, _h); + datarouter_port_add_handler(p1, _h2); /* p1 两个 */ + datarouter_port_add_handler(p2, _h3); /* p2 一个 */ + reset_h(); + CHECK(datarouter_send_sensor("d", 1) == 0, NULL); + CHECK(_h_cnt == 3, "cnt=%d", _h_cnt); TEST_END() -TEST_START(send_remove_handler) - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); - datarouter_port_add_handler(p, _h_a); - datarouter_port_add_handler(p, _h_b); - reset_h(); datarouter_send_sensor(p, "d", 1); CHECK(_h_cnt == 2, NULL); - datarouter_port_remove_handler(p, _h_a); - reset_h(); datarouter_send_sensor(p, "d", 1); CHECK(_h_cnt == 1, NULL); +TEST_START(send_type_filter) + /* 两个端口不同类型,只触发匹配的 */ + datarouter_port_t p1 = FIXTURE_CREATE(&_fix); + datarouter_port_t p2 = FIXTURE_CREATE(&_fix); + datarouter_port_set_send_type(p1, DATAROUTER_SEND_sensor); + datarouter_port_set_send_type(p2, DATAROUTER_SEND_status); + datarouter_port_add_handler(p1, _h); + datarouter_port_add_handler(p2, _h); + reset_h(); + CHECK(datarouter_send_sensor("d", 1) == 0, NULL); + CHECK(_h_cnt == 1, "cnt=%d", _h_cnt); + CHECK(_h_port[0] == (int)p1, "only p1 should fire"); TEST_END() -TEST_START(send_clear_handlers) +TEST_START(send_after_remove_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); - datarouter_port_clear_handlers(p); - CHECK(datarouter_send_sensor(p, "d", 1) == -4, "expected -4"); + reset_h(); datarouter_send_sensor("d", 1); CHECK(_h_cnt == 1, NULL); + datarouter_port_remove_handler(p, _h); + CHECK(datarouter_send_sensor("d", 1) == -2, "expected -2 after remove"); +TEST_END() + +TEST_START(send_after_delete_port) + datarouter_port_t p = FIXTURE_CREATE(&_fix); + datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); + datarouter_port_add_handler(p, _h); + datarouter_port_delete(p); + CHECK(datarouter_send_sensor("d", 1) == -2, "expected -2"); + _fix.count--; TEST_END() TEST_START(send_zero_length) @@ -246,7 +222,7 @@ TEST_START(send_zero_length) datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); reset_h(); - CHECK(datarouter_send_sensor(p, "x", 0) == 0, NULL); + CHECK(datarouter_send_sensor("x", 0) == 0, NULL); CHECK(_h_cnt == 1, NULL); TEST_END() @@ -255,38 +231,47 @@ TEST_START(send_null_data) datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); reset_h(); - CHECK(datarouter_send_sensor(p, NULL, 0) == 0, NULL); + CHECK(datarouter_send_sensor(NULL, 0) == 0, NULL); CHECK(_h_cnt == 1, NULL); TEST_END() -/* ================================================================ - * 6. 接收回调 - * ================================================================ */ - -static int _rx_r, _rx_c; -void datarouter_on_recv_rtcm(uint32_t p, const void *d, size_t l) - { (void)p; (void)d; (void)l; _rx_r++; } -void datarouter_on_recv_command(uint32_t p, const void *d, size_t l) - { (void)p; (void)d; (void)l; _rx_c++; } - -TEST_START(recv_callbacks) - _rx_r = _rx_c = 0; - datarouter_on_recv_rtcm(0, "d", 1); - CHECK(_rx_r == 1 && _rx_c == 0, "rtcm=%d cmd=%d", _rx_r, _rx_c); - datarouter_on_recv_command(1, "d", 1); - CHECK(_rx_r == 1 && _rx_c == 1, "rtcm=%d cmd=%d", _rx_r, _rx_c); +TEST_START(send_multi_cap) + /* 发送 status 不影响 sensor 端口 */ + datarouter_port_t p1 = FIXTURE_CREATE(&_fix); + datarouter_port_t p2 = FIXTURE_CREATE(&_fix); + datarouter_port_set_send_type(p1, DATAROUTER_SEND_sensor); + datarouter_port_set_send_type(p2, DATAROUTER_SEND_status); + datarouter_port_add_handler(p1, _h); + datarouter_port_add_handler(p2, _h); + reset_h(); + CHECK(datarouter_send_sensor("d", 1) == 0, NULL); + CHECK(_h_cnt == 1, "sensor: cnt=%d", _h_cnt); + CHECK(datarouter_send_status("d", 1) == 0, NULL); + CHECK(_h_cnt == 2, "status: cnt=%d", _h_cnt); TEST_END() /* ================================================================ - * 7. 能力元数据(两组独立) + * 5. 接收回调 + * ================================================================ */ + +static int _rx_r; +void datarouter_on_recv_rtcm(uint32_t p, const void *d, size_t l) + { (void)p; (void)d; (void)l; _rx_r++; } + +TEST_START(recv_callback) + _rx_r = 0; + datarouter_on_recv_rtcm(0, "d", 1); + CHECK(_rx_r == 1, "cnt=%d", _rx_r); +TEST_END() + +/* ================================================================ + * 6. 能力元数据 * ================================================================ */ TEST_START(send_cap_meta) CHECK(datarouter_send_cap_count() == 2, NULL); CHECK(strcmp(datarouter_send_cap_name(0), "sensor") == 0, NULL); CHECK(strcmp(datarouter_send_cap_desc(0), "Sensor data report") == 0, NULL); - CHECK(strcmp(datarouter_send_cap_name(1), "status") == 0, NULL); - CHECK(strcmp(datarouter_send_cap_desc(1), "Device status report") == 0, NULL); CHECK(datarouter_send_cap_name(-1) == NULL, NULL); CHECK(datarouter_send_cap_name(99) == NULL, NULL); TEST_END() @@ -295,35 +280,15 @@ TEST_START(recv_cap_meta) CHECK(datarouter_recv_cap_count() == 2, NULL); CHECK(strcmp(datarouter_recv_cap_name(0), "rtcm") == 0, NULL); CHECK(strcmp(datarouter_recv_cap_desc(0), "RTCM correction data") == 0, NULL); - CHECK(strcmp(datarouter_recv_cap_name(1), "command") == 0, NULL); - CHECK(strcmp(datarouter_recv_cap_desc(1), "Remote control command") == 0, NULL); CHECK(datarouter_recv_cap_name(-1) == NULL, NULL); CHECK(datarouter_recv_cap_desc(99) == NULL, NULL); TEST_END() -/* ================================================================ - * 8. 错误 - * ================================================================ */ - -TEST_START(error_invalid_port) - CHECK(datarouter_send_sensor(999, "d", 1) == -2, NULL); - CHECK(datarouter_send_sensor(-1, "d", 1) == -2, NULL); -TEST_END() - -TEST_START(error_deleted_port) - datarouter_port_t p = FIXTURE_CREATE(&_fix); - datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); - datarouter_port_add_handler(p, _h); - datarouter_port_delete(p); - CHECK(datarouter_send_sensor(p, "d", 1) == -2, NULL); - _fix.count--; -TEST_END() - /* ================================================================ * 主函数 * ================================================================ */ -#define RUN(name) do { reset_h(); test_##name(); } while (0) +#define RUN(name) do { reset_h(); _rx_r = 0; test_##name(); } while (0) int main(void) { @@ -341,35 +306,29 @@ int main(void) RUN(port_default_state); printf("\n"); - datarouter_reset(); datarouter_init(); - printf("[send_type / recv_type]\n"); + datarouter_reset(); datarouter_init(); + printf("[send_type & handler]\n"); RUN(send_type_set_get); - RUN(recv_type_set_get); - RUN(types_independent); - RUN(send_type_clear); - RUN(recv_type_clear); - RUN(types_from_invalid); - printf("\n"); - - printf("[handler add/remove]\n"); RUN(handler_add_remove); RUN(handler_clear); printf("\n"); - printf("[send trigger]\n"); - RUN(send_one_handler); - RUN(send_multi_handlers); - RUN(send_type_mismatch); - RUN(send_no_handler); - RUN(send_no_send_type); - RUN(send_remove_handler); - RUN(send_clear_handlers); + printf("[send — auto broadcast]\n"); + RUN(send_no_match_port); + RUN(send_one_port_one_handler); + RUN(send_one_port_multi_handler); + RUN(send_multi_ports_same_type); + RUN(send_multi_port_multi_handler); + RUN(send_type_filter); + RUN(send_after_remove_handler); + RUN(send_after_delete_port); RUN(send_zero_length); RUN(send_null_data); + RUN(send_multi_cap); printf("\n"); printf("[receive callback]\n"); - RUN(recv_callbacks); + RUN(recv_callback); printf("\n"); printf("[capability metadata]\n"); @@ -377,11 +336,6 @@ int main(void) RUN(recv_cap_meta); printf("\n"); - printf("[error handling]\n"); - RUN(error_invalid_port); - RUN(error_deleted_port); - printf("\n"); - printf("==============================\n"); printf(" total: %d | pass: %d | fail: %d\n\n", _total_run, _total_pass, _total_fail);