---
title: Framing Details
description: Technical details of the framing system including frame components, header types, payload types, and parser state machine.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

This page covers the technical details of the framing system.

## Frame Components

Frames consist of two parts:

1. **Header**: Determines sync bytes and addressing
2. **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: `0x90` followed by `0x70 + 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 255
checksum = (sum2 << 8) | sum1
```

## Parser State Machine

The parser implements a state machine:

```
IDLE → wait for start byte(s)
HEADER → read header bytes
PAYLOAD → read length, msg_id, data
CHECKSUM → verify CRC
COMPLETE → return message
```

For Minimal payloads, the parser requires a message length callback to determine payload size.

## Usage in C++

```cpp
#include "frame_profiles.hpp"

using namespace FrameParsers;

// Using profiles
uint8_t buffer[1024];
ProfileStandardWriter writer(buffer, sizeof(buffer));
ProfileStandardAccumulatingReader reader;

// Encode
writer.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

```python
from frame_profiles import (
    ProfileStandardWriter,
    ProfileStandardAccumulatingReader,
)
from struct_frame.generated.messages import MyMessage, get_message_info

# Encode
msg = 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:

<Tabs>
  <TabItem label="C++">
  ```cpp
  // Custom: Tiny header with Extended payload
  using CustomConfig = FrameConfig<
      HeaderTiny,
      PayloadExtended
  >;

  FrameEncoderWithCrc<CustomConfig> encoder;
  BufferParserWithCrc<CustomConfig> parser;
  ```
  </TabItem>
</Tabs>

<Tabs>
  <TabItem label="Python">
  ```python
  from frame_profiles import ProfileConfig, HEADER_TINY_CONFIG, PAYLOAD_EXTENDED_CONFIG
  from 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)
  ```
  </TabItem>
</Tabs>

