# DataRouter 详细设计文档 ## 1. 设计目标 轻量级 C 语言数据路由库。发送能力与接收能力分开声明,端口可独立设置 `send_type` 和 `recv_type`。发送时自动广播到所有匹配端口,接收时通过 `dr_port_dispatch()` 查表自动路由到回调。 ### 核心设计 ``` 发送: dr_send_sensor(data, len) │ ▼ 遍历端口表 → send_type 匹配? │ ▼ for each handler(port, data) ─── UART / TCP / CAN 接收: dr_port_dispatch(port, data, len) │ ▼ 查 recv_table[port.recv_type] │ ▼ dr_on_recv_rtcm(port, data, len) ← 用户实现 ``` --- ## 2. 数据结构 ### 2.1 `port_entry_t` ```c #define DR_MAX_HANDLERS_PER_PORT 4 typedef struct { int send_type; // DR_SEND_xxx / -1 int recv_type; // DR_RECV_xxx / -1 dr_send_handler_t handlers[DR_MAX_HANDLERS_PER_PORT]; int count; uint8_t in_use; } port_entry_t; ``` ### 2.2 接收回调函数指针表 ```c // 编译期由 X-macro 生成,DR_RECV_rtcm 的枚举值即为数组下标 static void (*const recv_table[DR_RECV_CAP_COUNT])(uint32_t, const void*, size_t) = { dr_on_recv_rtcm, dr_on_recv_command, }; ``` ### 2.3 端口表 ```c #define DR_MAX_PORTS 64 static port_entry_t ports[DR_MAX_PORTS]; static uint8_t initialized; ``` --- ## 3. API ### 3.1 端口管理 ```c dr_port_t dr_port_create(void); void dr_port_delete(dr_port_t port); void dr_port_set_send_type(port, int cap_id); int dr_port_get_send_type(port); void dr_port_set_recv_type(port, int cap_id); int dr_port_get_recv_type(port); int dr_port_add_handler(port, handler); int dr_port_remove_handler(port, handler); void dr_port_clear_handlers(port); int dr_port_handler_count(port); void dr_port_dispatch(port, data, len); // ← 自动路由接收 ``` ### 3.2 发送触发 ```c int dr_send_sensor(const void *data, size_t len); int dr_send_status(const void *data, size_t len); ``` 返回值:0 成功 / -1 未初始化 / -2 无匹配端口 ### 3.3 接收回调 ```c void dr_on_recv_rtcm(uint32_t port_id, const void *data, size_t len); void dr_on_recv_command(uint32_t port_id, const void *data, size_t len); ``` --- ## 4. 核心流程 ### 4.1 发送 ```plantuml @startuml actor App participant dr_send_sensor as Send participant ports[] as Table participant handlers[] as H App -> Send : send_sensor("temp", 9) loop for p in 0..MAX_PORTS-1 Send -> Table : in_use && send_type == SENSOR ? alt 匹配 loop for h in handlers Send -> H : handlers[h](p, data, len) end end end alt 至少调了一次 Send --> App : return 0 else 无匹配 Send --> App : return -2 end @enduml ``` ### 4.2 接收(dispatch) ```plantuml @startuml actor 外设ISR as Dev participant dr_port_dispatch as Dispatch participant recv_table[] as Table participant dr_on_recv_rtcm as Cb Dev -> Dispatch : dispatch(port, data, len) Dispatch -> Table : 查 recv_table[port.recv_type] Dispatch -> Cb : recv_table[rid](port, data, len) Cb --> Dev : void @enduml ``` --- ## 5. Dispatch 实现 `dr_port_dispatch` 是零分支的查表路由: ```c void dr_port_dispatch(dr_port_t port, const void *data, size_t len) { if (!initialized) return; if (port < 0 || port >= DR_MAX_PORTS || !ports[port].in_use) return; int rid = ports[port].recv_type; if (rid < 0 || rid >= DR_RECV_CAP_COUNT) return; recv_table[rid]((uint32_t)port, data, len); // 直接函数指针调用 } ``` `recv_table[]` 是 `const` 数组,编译期由 X-macro 生成。`DR_RECV_rtcm` 的枚举值等于数组下标,查表时间为 O(1),无分支预测开销,适合 ISR。 --- ## 6. 错误码 | 返回值 | 含义 | |:------:|------| | 0 | 成功 | | -1 | 库未初始化 | | -2 | 无端口匹配该 send_type | --- ## 7. 约束 | 约束 | 说明 | |------|------| | 能力声明 | 编译期固定,修改需重新编译 | | 最大端口数 | 默认 64,通过 `-D` 覆盖 | | 每端口 handler 上限 | 默认 4,通过 `-D` 覆盖 | | 线程安全 | 不支持(无锁),多线程需外部加锁 | | 弱符号 | GCC/Clang 原生支持 | | 内存分配 | 纯静态,无 malloc/free |