Packet Format
Fusain uses a binary packet format with delimiters, addressing, and error detection.
Structure
All packets follow this structure:
Field |
Size |
Description |
|---|---|---|
START |
1 byte |
Start delimiter ( |
LENGTH |
1 byte |
Payload length in bytes (0-114) |
ADDRESS |
8 bytes |
64-bit device address (little-endian) |
PAYLOAD |
0-114 bytes |
CBOR-encoded message (includes type and data) |
CRC |
2 bytes |
CRC-16-CCITT checksum (big-endian) |
END |
1 byte |
End delimiter ( |
Packet Size: 13 bytes overhead + payload = 13-127 bytes total (unstuffed).
Wire Format Size: Byte stuffing expands packets on the wire:
Calculation |
Size |
|---|---|
Unstuffed content (LENGTH + ADDRESS + PAYLOAD + CRC) |
1 + 8 + 114 + 2 = 125 bytes max |
Worst-case stuffing (every byte escaped) |
125 × 2 = 250 bytes |
Add START and END delimiters |
250 + 2 = 252 bytes |
Maximum wire size |
252 bytes (2,016 bits) |
For buffer sizing, see Buffers.
Payload Structure: The CBOR payload is encoded as a two-element array
[type, data] where type is the message type identifier (see
Message Types) and data is a CBOR map with message-specific fields
(see Packet Payloads).
Addressing
The ADDRESS field identifies the source or destination device.
Command packets (controller to appliance): ADDRESS is the destination.
Data packets (appliance to controller): ADDRESS is the source.
Special Addresses
Address |
Purpose |
|---|---|
|
Broadcast (all devices) |
|
Stateless (routers, subscriptions) |
Address Assignment
Addresses SHOULD be globally unique. Appliances MAY use a MAC address, serial number, or other hardware identifier. Appliances MUST include their own address in data packets. Appliances MUST silently ignore packets addressed to other devices.
Broadcast Behavior
When an appliance receives a broadcast command:
The command MUST be processed normally
The appliance MUST NOT respond (to prevent bus collisions)
Exception: DISCOVERY_REQUEST triggers a response after a random delay (0-50ms)
CRC Calculation
Fusain uses CRC-16-CCITT for error detection.
Algorithm Parameters
Parameter |
Value |
|---|---|
Polynomial |
|
Initial value |
|
XOR out |
|
Reflect in |
False |
Reflect out |
False |
Coverage
The CRC is calculated over: LENGTH + ADDRESS + PAYLOAD.
The START and END delimiters are NOT included in the CRC calculation.
Byte Order
The CRC MUST be transmitted big-endian (MSB first, then LSB).
Byte Order Rationale
The framing layer uses two byte orders:
Field |
Byte Order |
Rationale |
|---|---|---|
ADDRESS |
Little-endian |
Native byte order for ARM Cortex-M and x86 processors |
CRC |
Big-endian |
Historical convention from CRC-16-CCITT telecommunications usage |
Why little-endian for ADDRESS?
The target platforms (RP2350 ARM Cortex-M33, x86 desktop tools) are little-endian. Using native byte order allows direct memory access without byte-swapping:
// Direct read - no conversion needed on little-endian hardware
uint64_t address = *(uint64_t*)&packet->address;
Why big-endian for CRC?
CRC-16-CCITT originated in ITU-T telecommunications standards (X.25, HDLC) where network byte order (big-endian) was the convention. Many protocols follow this:
HDLC, SDLC - Big-endian CRC
PPP Frame Check Sequence - Big-endian CRC
Kermit, XMODEM - Big-endian CRC
Maintaining this convention ensures compatibility with existing CRC implementations and aligns with developer expectations for CRC-16-CCITT.
CRC Selection Rationale
Fusain uses CRC-16-CCITT for error detection. This section documents the rationale for this choice.
Hamming Distance Performance
Based on Koopman’s CRC research:
Hamming Distance |
Max Data Length |
Error Detection |
|---|---|---|
HD=4 |
32,751 bits (~4KB) |
All 1, 2, 3-bit errors |
HD=5 |
241 bits (~30 bytes) |
All 1-4 bit errors |
HD=6 |
135 bits (~17 bytes) |
All 1-5 bit errors |
For Fusain packets (max 252 bytes = 2,016 bits on wire), CRC-16-CCITT provides:
HD=4: Detects all 1, 2, and 3-bit errors
Burst error detection: Any burst ≤16 bits
Undetected error probability: ~1/65,536 for random errors
Why CRC-16-CCITT Is Appropriate
Sufficient for Packet Sizes: Fusain packets are well under the 32,751-bit HD=4 limit.
Industry Standard: CRC-16-CCITT is widely used in embedded protocols (X.25, HDLC, Bluetooth, PPP).
Zephyr Native Support: Zephyr provides optimized implementations via
crc16_itu_t(). See Zephyr Integration for integration details.Low Overhead: 2 bytes per packet is acceptable for our message sizes.
Alternative Consideration
For applications requiring stronger error detection, CRC-32K/4.2 (Koopman polynomial 0x93A409EB) provides HD=6 at packet sizes up to ~770 bytes. This could be adopted as a future enhancement if needed for noisier environments or safety certification.
References
Byte Stuffing
To prevent delimiter bytes from appearing in the packet data, byte stuffing is applied to the packet content (LENGTH, ADDRESS, PAYLOAD, and CRC) before the START and END delimiters are added. The delimiters themselves MUST NOT be escaped.
Escape Sequences
Byte |
Escaped As |
Purpose |
|---|---|---|
|
|
Escape START delimiter |
|
|
Escape END delimiter |
|
|
Escape the escape byte |
Processing Order
When transmitting:
Encode the message as CBOR (type + data map)
Build the packet (LENGTH, ADDRESS, CBOR payload)
Calculate CRC over the packet
Append CRC to the packet
Apply byte stuffing to the entire packet (including CRC)
Add START delimiter before and END delimiter after
When receiving:
Detect START delimiter
Read bytes until END delimiter, or 256 bytes (see Buffers)
If buffer limit reached, discard and return to step 1
Apply byte unstuffing
Extract CRC from the unstuffed data
Verify CRC over LENGTH + ADDRESS + PAYLOAD
Decode CBOR payload to extract message type and data
Process the message if CRC is valid
Data Types
Payloads use CBOR encoding. The canonical schema is defined in fusain.cddl.
For implementation details, see Implementation Guide. For communication
patterns and telemetry, see Communication Patterns.
Framing Layer Types
These fixed-size types are used in the packet framing (not CBOR-encoded):
Type |
Encoding |
|---|---|
ADDRESS |
Unsigned 64-bit integer, little-endian |
CRC |
Unsigned 16-bit integer, big-endian |
CBOR Payload Types
Message payloads use CBOR’s self-describing encoding:
Type |
CBOR Encoding |
|---|---|
uint |
Variable-length unsigned integer (1-9 bytes depending on value) |
int |
Variable-length signed integer |
float |
IEEE 754 float (half, single, or double precision) |
bool |
Single byte: |
tstr |
UTF-8 text string with length prefix |
nil |
Single byte: |