跳到主要内容

Message 消息系统

LibXR 中的 Message 模块是一个基于 发布-订阅(Publish-Subscribe)模式 的高效、线程安全的消息传输与处理机制。支持同步、异步、队列与回调多种订阅方式,集成数据缓存、校验与打包传输能力,是模块解耦与实时通信的重要工具。


功能特点

  • 支持多个订阅者同时接收同一主题数据;
  • 支持:
    • 同步订阅(阻塞等待);
    • 异步订阅(主动轮询);
    • 队列订阅(缓存历史);
    • 回调订阅(实时响应);
  • 内部采用 红黑树 + 无锁链表 管理主题与订阅者;
  • 提供标准化的 消息打包与解析机制,适用于串口、CAN、网络等链路;
  • 支持数据完整性校验、拼包粘包处理与碎片恢复。

快速上手

创建 Topic 并发布消息

auto domain = LibXR::Topic::Domain("sensor_data");
auto topic = LibXR::Topic::CreateTopic<float>("temperature", &domain, true);

float temp = 23.5f;
topic.Publish(temp);

同步订阅(阻塞)

float received_temp;
auto sync = LibXR::Topic::SyncSubscriber<float>("temperature", received_temp, &domain);

if (sync.Wait(1000) == ErrorCode::OK)
printf("同步接收温度: %.2f\n", received_temp);

异步订阅(非阻塞)

auto async = LibXR::Topic::ASyncSubscriber<float>("temperature", &domain);

if (async.Available()) {
float latest_temp = async.GetData();
printf("异步接收温度: %.2f\n", latest_temp);
}
async.StartWaiting();

队列订阅(历史缓存)

LibXR::LockFreeQueue<float> queue(10);
auto que_sub = LibXR::Topic::QueuedSubscriber<float>("temperature", queue, &domain);

float temp;
if (queue.Pop(temp) == ErrorCode::OK)
printf("队列接收温度: %.2f\n", temp);

回调订阅(实时处理)

float latest_temp = 0.0f;
auto cb = LibXR::Topic::Callback::Create(
[](bool, void* arg, LibXR::RawData& data) {
*reinterpret_cast<float*>(arg) = *reinterpret_cast<float*>(data.addr_);
}, &latest_temp);

topic.RegisterCallback(cb);

类接口概览

类 / 方法说明
CreateTopic<T>()创建主题(带缓存与校验)
Publish()发布数据
SyncSubscriber同步等待数据
ASyncSubscriber异步读取最新数据
QueuedSubscriber存入队列,保留历史
RegisterCallback()注册回调函数
DumpData()导出缓存数据或打包数据
PackData()手动构造带头消息
Server::ParseData()消息解包与转发
Server::Register()注册解析目标 Topic

消息打包与解析机制

LibXR 提供统一的打包格式 PackedData<T> 和服务端解析器 Server

打包数据示例

topic.Publish(36.5f);
LibXR::Topic::PackedData<float> pkt;
topic.DumpData(pkt);

数据包格式

字段含义
0xA5固定头部
CRC32Topic 名称校验
Length数据长度(24 位)
CRC8头部校验
Data实际数据
CRC8尾部校验

服务端解析示例

LibXR::Topic::Server server(512);
server.Register(topic);
server.ParseData(ConstRawData(pkt));

会自动处理粘包与拆包,校验数据并放弃无效数据。然后将数据发布到对应的Topic。


数据导出与 PackData

读取缓存数据

double val = 0;
topic.DumpData(val); // 获取最新数据

打包为网络格式

LibXR::Topic::PackedData<double> pkt;
topic.DumpData(pkt); // 带头 + 校验

手动打包任意数据

double value = 123.45;
RawData src(value);
uint8_t buffer[128];
RawData dst(buffer, sizeof(buffer));

Topic::PackData(topic.GetKey(), dst, src);

方法对比总结

场景推荐方法是否依赖缓存是否打包
获取最新值DumpData(DataType)✅ 是❌ 否
网络打包DumpData(PackedData&)✅ 是✅ 是
自定义 bufferDumpData<Mode>(RawData, pack)✅ 是可选
独立打包PackData()❌ 否✅ 是

应用场景

  • 串口/网络消息结构化封装与解析;
  • MCU 与主控通信的高效通道;
  • 数据转发 / 日志传输 / 状态同步;
  • 支持碎片恢复与异步解析。

注意事项

  • 同一 Domain 名称将复用对象;
  • 同一域名下的同名 Topic 将共享实例,配置需一致;
  • Topic 为轻量包装类,支持拷贝与传参;
  • 若未发布数据,DumpData() 会返回 ErrorCode::EMPTY
  • PackData() 可脱离缓存使用,适合日志或模拟数据生成。