Skip to main content

Packet Packing and Parsing

Topic provides two transport-facing features:

  • Topic::PackData() / Topic::PackRaw() to build a packet using the topic contract;
  • Topic::Server to parse incoming bytes into packets and deliver them back into registered topics.

Packing and parsing use:

  • the topic-name CRC32 key;
  • the fixed payload size;
  • the payload alignment requirement;
  • packet header and tail CRC checks.

Packing One Typed Message​

LibXR::Topic::Domain domain("msg");
auto topic = LibXR::Topic::CreateTopic<double>("temperature", &domain);

LibXR::Topic::PackedData<double> packet;
topic.PackData(36.5, packet, LibXR::MicrosecondTimestamp(123456));

Without a timestamp argument, Topic::NowTimestamp() is used:

topic.PackData(36.5, packet);

PackData() packs the payload passed to it, independently of Publish().

Packing Raw Payload Bytes​

When the payload bytes are already laid out according to the topic's type contract, use PackRaw():

double value = 72.72;
uint8_t raw_packet[LibXR::Topic::PACK_BASE_SIZE + sizeof(double)] = {};

topic.PackRaw(LibXR::ConstRawData(value),
LibXR::RawData(raw_packet, sizeof(raw_packet)),
LibXR::MicrosecondTimestamp(6006));

Constraints of PackRaw():

  • data.size_ must equal the topic's PayloadSize();
  • the output buffer must hold at least PACK_BASE_SIZE + payload_size;
  • null pointers return ErrorCode::PTR_NULL;
  • mismatched payload size returns ErrorCode::SIZE_ERR;
  • an undersized output buffer returns ErrorCode::NO_BUFF.

Packet Layout​

The header is fixed at 16 bytes, followed by a trailing packet CRC8:

FieldBytesMeaning
prefix1fixed packet prefix 0x5A
data_len_raw3little-endian 24-bit payload length
topic_name_crc324topic-name CRC32 key
timestamp_us_raw6little-endian 48-bit microsecond timestamp
version1packet version 0x01
pack_header_crc81header CRC8
payloadNpayload bytes
trailing crc81packet tail CRC8

So the total size is:

LibXR::Topic::PACK_BASE_SIZE + payload_size

and PACK_BASE_SIZE is 17.

Parsing a Byte Stream​

Topic::Server is the state-machine parser. Typical usage:

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

size_t delivered = server.ParseData(LibXR::ConstRawData(packet));

For callback or ISR paths, use:

server.ParseDataFromCallback(LibXR::ConstRawData(packet), true);

Processing steps of Server:

  • synchronize the input stream to the next packet start;
  • validate header and tail CRC;
  • look up the registered topic by topic_name_crc32;
  • publish the payload according to that topic's runtime contract.

Registering Topics​

server.Register(topic);

Registration checks two conditions (with ASSERT, active in Debug builds only):

  • payload_size + PACK_BASE_SIZE fits in the Server buffer length;
  • payload_alignment <= CACHE_LINE_SIZE.

The buffer_length of Server(buffer_length) is also the capacity of the internal byte queue: it sets the largest packet that can be received and limits the data passed to one ParseData() call. Data that exceeds the remaining queue space in one call is discarded as a whole.

Compatibility Rule During Parsing​

When Server publishes a packet to a topic, it handles a payload of a different length as follows:

  • if the packet payload is shorter than the topic's fixed payload size, only the prefix part is guaranteed valid and the remaining tail stays unspecified;
  • if the packet payload is longer than the topic's fixed payload size, only the prefix matching the topic size is kept and the rest is truncated.

This rule keeps compatibility with upstream payload lengths that deviate.

Minimal End-to-End Example​

LibXR::Topic::Domain domain("msg");
auto topic = LibXR::Topic::CreateTopic<double>("temperature", &domain);

double rx_value = 0.0;
auto cb = LibXR::Topic::Callback::Create(
[](bool, double* target, LibXR::MicrosecondTimestamp, double& data)
{
*target = data;
},
&rx_value);
topic.RegisterCallback(cb);

LibXR::Topic::PackedData<double> packet;
topic.PackData(48.48, packet, LibXR::MicrosecondTimestamp(4004));

LibXR::Topic::Server server(512);
server.Register(topic);
server.ParseData(LibXR::ConstRawData(packet));
Code block collapsed

The result is that Server parses the packet, republishes the payload into the topic, and the callback subscriber receives it.

Interface Summary​

InterfacePurpose
PackedData<T>strong-typed byte layout of a full packet
PackData()pack a typed payload using the topic contract
PackRaw()pack a raw payload using the topic contract
Server::Register()register a topic that may receive parsed packets
Server::ParseData()parse input bytes in normal context
Server::ParseDataFromCallback()parse input bytes in callback / ISR context

In-process publish-subscribe is covered on the Topic page; Linux inter-process sharing of large payloads is covered in LinuxSharedTopic.