Framing Details
This page covers the technical details of the framing system.
Frame Components
Frames consist of two parts:
- Header: Determines sync bytes and addressing
- Payload: Determines length encoding and checksum
Header Types
Basic Header (2 bytes)
[0x90] [0x70 + PayloadType]Two-byte sync for reliable synchronization. Recommended for most applications.
Tiny Header (1 byte)
[0x70 + PayloadType]Single-byte sync for bandwidth-limited scenarios.
None Header (0 bytes)
(no header)For trusted links where synchronization isn’t needed.
Payload Types
Minimal
[MSG_ID] [PAYLOAD...]1 byte overhead. Requires message length lookup. No checksum or length field.
Default
[LENGTH] [MSG_ID] [PAYLOAD...] [CRC_HI] [CRC_LO]4 bytes overhead. Includes length (1 byte, max 255) and Fletcher-16 checksum.
Extended
[LENGTH_HI] [LENGTH_LO] [MSG_ID] [PAYLOAD...] [CRC_HI] [CRC_LO]5 bytes overhead. 16-bit length field (max 65535 bytes).
ExtendedMultiSystemStream
[LENGTH_HI] [LENGTH_LO] [SRC] [DST] [SEQ] [MSG_ID] [PAYLOAD...] [CRC_HI] [CRC_LO]8 bytes overhead. Adds source/destination addresses and sequence numbers for multi-node networks.
Frame Profiles
Profiles combine header + payload types:
| Profile | Header | Payload | Total Overhead |
|---|---|---|---|
| Standard | Basic | Default | 6 bytes |
| Sensor | Tiny | Minimal | 2 bytes |
| IPC | None | Minimal | 1 byte |
| Bulk | Basic | Extended | 8 bytes |
| Network | Basic | ExtendedMultiSystemStream | 11 bytes |
Checksum (Fletcher-16)
The Default and Extended payload types use Fletcher-16 checksum.
Magic Numbers:
- Basic frame start:
0x90followed by0x70 + PayloadType - Tiny frame start:
0x70 + PayloadType - Payload type base value:
0x70
The checksum algorithm:
For each byte in [LENGTH, MSG_ID, PAYLOAD]: sum1 = (sum1 + byte) mod 255 sum2 = (sum2 + sum1) mod 255checksum = (sum2 << 8) | sum1Parser State Machine
The parser implements a state machine:
IDLE → wait for start byte(s)HEADER → read header bytesPAYLOAD → read length, msg_id, dataCHECKSUM → verify CRCCOMPLETE → return messageFor Minimal payloads, the parser requires a message length callback to determine payload size.
Usage in C++
#include "frame_profiles.hpp"
using namespace FrameParsers;
// Using profilesuint8_t buffer[1024];ProfileStandardWriter writer(buffer, sizeof(buffer));ProfileStandardAccumulatingReader reader;
// Encodewriter.write(msg);send_data(writer.buffer(), writer.size());
// Decode (streaming)while (receiving) { if (auto result = reader.push_byte(read_byte())) { handle_message(result.msg_id, result.msg_data, result.msg_len); }}
// Decode (buffer)reader.add_data(buffer, buffer_size);while (auto result = reader.next()) { handle_message(result.msg_id, result.msg_data, result.msg_len);}Usage in Python
from frame_profiles import ( ProfileStandardWriter, ProfileStandardAccumulatingReader,)from struct_frame.generated.messages import MyMessage, get_message_info
# Encodemsg = MyMessage(value=42)writer = ProfileStandardWriter(1024)writer.write(msg)frame = writer.data()
# Decode (byte-by-byte streaming)reader = ProfileStandardAccumulatingReader(get_message_info=get_message_info)for byte in frame: result = reader.push_byte(byte) if result and result.valid: handle_message(result)
# Decode (buffer mode)reader2 = ProfileStandardAccumulatingReader(get_message_info=get_message_info)reader2.add_data(frame)result = reader2.next()if result and result.valid: handle_message(result)Custom Profiles
Create custom frame formats by combining header and payload types:
// Custom: Tiny header with Extended payloadusing CustomConfig = FrameConfig< HeaderTiny, PayloadExtended>;
FrameEncoderWithCrc<CustomConfig> encoder;BufferParserWithCrc<CustomConfig> parser;from frame_profiles import ProfileConfig, HEADER_TINY_CONFIG, PAYLOAD_EXTENDED_CONFIGfrom frame_profiles import BufferWriter, AccumulatingReader
custom_config = ProfileConfig(HEADER_TINY_CONFIG, PAYLOAD_EXTENDED_CONFIG, name="TinyExtended")writer = BufferWriter(custom_config, 1024)reader = AccumulatingReader(custom_config)