7iwind ccde2f73e9
CI / host (push) Successful in 7s
CI / cortex-m (push) Successful in 7s
Release / release (push) Successful in 16s
Merge pull request 'fix: 修正缺失构建平台的错误' (#35) from feature/route into main
Reviewed-on: #35
2026-07-27 00:30:21 +08:00
2026-07-25 23:08:48 +08:00
2026-07-25 23:08:48 +08:00

DataRouter

轻量级 C 语言数据路由库。发送能力和接收能力分开声明,端口绑定 send_type 和外设 handler 列表。调用 dr_send_<id>(data, len) 时自动广播到所有匹配端口。

概念

术语 说明
发送能力 (Send Capability) 编译期声明的可发送报文类型,生成 dr_send_<id>(data, len)
接收能力 (Recv Capability) 编译期声明的可接收报文类型,生成 dr_on_recv_<id>(port, data, len)
端口 (Port) 运行期创建的连接点,包含 send_type + handler 列表
Handler 用户实现的物理外设发送函数,一个端口可注册多个(默认上限 4)

快速开始

1. 声明能力

创建自己的 dr_config.h(可参考 dr_config_template.h):

#define DR_SEND_CAPABILITIES \
    DR_SEND(sensor, "Sensor data report")   \
    DR_SEND(status, "Device status report")

#define DR_RECV_CAPABILITIES \
    DR_RECV(rtcm,    "RTCM correction data")   \
    DR_RECV(command, "Remote control command")

库自带默认配置。将你的 dr_config.h 放到项目目录, 编译时添加 -I /path/to/your/config 即可覆盖。无需修改库源码。

include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(path/to/DataRouter)
target_link_libraries(my_app DataRouter)

2. 实现外设发送 handler

static void uart_send(uint32_t port_id, const void *data, size_t len) {
    HAL_UART_Transmit(&huart1, data, len, 1000);
}

static void tcp_send(uint32_t port_id, const void *data, size_t len) {
    send(tcp_socket, data, len, 0);
}

3. 创建端口

dr_init();

/* —— 传感器上报:sensor 报文走 UART + TCP —— */
dr_port_t tx = dr_port_create();
dr_port_set_send_type(tx, DR_SEND_sensor);
dr_port_add_handler(tx, uart_send);
dr_port_add_handler(tx, tcp_send);

/* 不指定端口,库自动广播到所有 send_type=sensor 的端口 */
dr_send_sensor("temperature:25.3", 16);  // → UART + TCP

/* —— 接收:实现回调,外设数据到达后自行调用 —— */
dr_on_recv_rtcm(rx_port, data, len);

4. 实现接收回调

void dr_on_recv_rtcm(uint32_t port_id, const void *data, size_t len) {
    apply_rtcm_correction(data, len);
}

API 一览

初始化

void dr_init(void);    // 幂等初始化
void dr_reset(void);   // 重置全部状态

端口管理

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);               // -1 = 未设置

int   dr_port_add_handler(port, handler);        // 注册外设 handler
int   dr_port_remove_handler(port, handler);     // 移除
void  dr_port_clear_handlers(port);              // 清除全部
int   dr_port_handler_count(port);               // 当前数量

发送触发(每个 SEND 能力生成一个)

int dr_send_sensor(const void *data, size_t len);   // 0 成功
int dr_send_status(const void *data, size_t len);   // -1 未初始化
                                                             // -2 无匹配端口

不指定端口,库遍历所有端口,send_type 匹配的逐一调用其全部 handler。

接收回调(每个 RECV 能力生成一个声明)

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);

库提供弱符号默认空实现,用户定义同名函数覆盖。

能力元数据(两组独立)

int         dr_send_cap_count(void);
const char *dr_send_cap_name(int cap_id);
const char *dr_send_cap_desc(int cap_id);

int         dr_recv_cap_count(void);
const char *dr_recv_cap_name(int cap_id);
const char *dr_recv_cap_desc(int cap_id);

路由模型

dr_send_sensor("temperature:25.3", 16)
  │
  ├─→ 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
  • 调用 send_<id>(data, len) 时,库遍历所有端口,自动匹配 send_type
  • 每个端口可注册多个 handler(一对多广播)
  • 同一 handler 可注册到多个端口(多路复用)
  • 运行时通过 add_handler / remove_handler / port_delete 动态改变路由
  • 无任何端口匹配该 send_type 时返回 -2

编译

cmake -S . -B build
cmake --build build

可选配置:

cmake -DCMAKE_C_FLAGS="-DDR_MAX_PORTS=128 -DDR_MAX_HANDLERS_PER_PORT=8"

嵌入式 / Cortex-M 构建

库支持 arm-none-eabi-gcc 交叉编译,提供 7 个 CMake preset 覆盖常见 Cortex-M 目标:

# 列出所有 preset
cmake --list-presets

# Cortex-M3(软浮点)
cmake --preset cm3
cmake --build --preset cm3

# Cortex-M4F(硬件浮点,单精度)
cmake --preset cm4-hard
cmake --build --preset cm4-hard

# Cortex-M7F(硬件浮点,双精度)
cmake --preset cm7-hard-dp
cmake --build --preset cm7-hard-dp

使用 preset 编译需要 arm-none-eabi-gcc 在 PATH 中。 各 preset 均启用 DR_SOURCE_ONLY 模式——只提供源文件路径, 你需要将 datarouter.c 加入自己的 target 以继承项目编译标志:

# 你的 CMakeLists.txt
set(DR_SOURCE_ONLY ON)
FetchContent_MakeAvailable(datarouter)
target_sources(my_app PRIVATE ${datarouter_SOURCE_DIR}/datarouter.c)
target_include_directories(my_app PRIVATE ${datarouter_SOURCE_DIR})

编译兼容性矩阵

启用 DR_COMPILE_CHECK 可自动检测 arm-none-eabi-gcc 并对 CM3/CM4/CM7 各变体执行编译验证:

cmake -B build-check -DDR_COMPILE_CHECK=ON
cmake --build build-check          # 生成 check_cm3, check_cm4-hard, … 等 target
# 或单独检查某个变体:
make check_cm7-hard-dp

内置 CMake Preset 列表

Preset 目标 FPU ABI
cm3 Cortex-M3 无 soft
cm4-soft Cortex-M4 无 soft
cm4-hard Cortex-M4F FPv4-SP-D16 hard
cm7-soft Cortex-M7 无 soft
cm7-hard-sp Cortex-M7F FPv5-SP-D16 hard
cm7-hard-dp Cortex-M7F FPv5-D16 hard

测试

cmake --build build
ctest --test-dir build
# 或直接运行
./build/test_datarouter

当前 22 个测试用例,覆盖端口管理、send_type 与 handler 设置、自动广播路由、接收回调、能力元数据。

文件结构

dr_config.h             发送 + 接收能力配置(用户可覆盖)
datarouter.h                    公共 API + X-macro 展开
datarouter.c                    实现(端口表 + send 遍历)
dr_config_template.h    外部配置模板
example.c                       使用示例
tests/test_datarouter.c         单元测试(22 用例)
DESIGN.md                       详细设计文档(含 PlantUML 图)
TEST_CASES.md                   测试用例文档

依赖

  • C11 编译器
  • CMake ≥ 3.10
  • 无第三方库依赖
S
Description
No description provided
Readme MIT
282 KiB
2026-07-30 10:53:04 +08:00
Languages
C 74.5%
CMake 25.5%