Files
DataRouter/DESIGN.md
T
7iwind 1c3e48d59f
CI / host (pull_request) Successful in 2s
CI / cortex-m (pull_request) Successful in 5s
feat: 新增接收dispatch反向路由
2026-07-30 10:49:44 +08:00

189 lines
4.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 |