Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Python Reference Implementation of Compact Frame Format

PyPI Changelog Tests License

Overview

Compact Frame Format (CFF) is a way of delineating messages (called the payload) in a byte stream. It is designed specifically with Microcontrollers (MCUs) in mind, leading to the following design goals:

  1. Take advantage of hardware acceleration like Direct Memory Access (DMA) controllers and the CRC peripherals available on most 32-bit MCUs. This precludes the use of delimiter-based packet boundaries that require the CPU to examine every byte.
  2. Exploit the fact that modern serial links are already reliable. Universal Serial Bus (USB), Controller Area Network Bus (CANBus), and Bluetooth Low Energy (BLE), already detect and retransmit lost or corrupted packets. Other serial interfaces like Universal Asynchronous Receiver-Transmitters (UART), Serial Peripheral Interface (SPI), and Inter-Integrated Circuit (I2C) are often reliable in practice, with extremely low error rates when the wiring is short and clean. Therefore, the it's okay for error recovery to be expensive, so long as it's possible and the happy path is cheap.
  3. Easy to implement and debug. Firmware running on MCUs is not amenable to taking dependencies on 3rd party libraries, so the implementation should be small enough to fit comfortably in a single file, and simple enough that you wouldn't mind implementing it yourself if you had to.
  4. Interoperate cleanly with binary serialization formats like FlatBuffers and CBOR.

In CFF, a frame consists of a header, a payload, and a payload CRC.

block-beta
  columns 6
  block:Header["Header<br><br><br>"]:4
    columns 4
    space:4
    Preamble FrameCounter["Frame Counter"] PayloadSize["Payload Size"] HeaderCRC["Header CRC"]
  end
  Payload
  PayloadCRC["Payload CRC"]

The header consists of:

  • A 2-byte preamble: [0xFA, 0xCE]. Note that this is better though of as an array of two bytes rather than an unsigned short (ushort) because it is transmitted as 0xFA, 0xCE (spelling face), whereas the ushort 0xFACE would be transmitted as 0xCE, 0xFA (spelling nothing) in little endian.
  • A little-endian ushort frame counter which increments for every frame sent and rolls over to 0 after 65,535 (2^16 - 1) frames have been sent.
  • A little-endian ushort payload size, in bytes. This gives a theoretical maximum payload size of 65,535, though few MCU-based applications would want to support this. A protocol making use of CFF can enforce smaller maximum payload sizes if desired. Note that this excludes both the header and the payload CRC at the end. In other words, the frame size is header_size + payload_size + crc_size.
  • A 16-bit header CRC (see below for details) calculated over the preamble, frame counter, and payload size. This allows the receiver to validate the header and, crucially, the payload size without having to read in the entire frame, as would be the case if there were just one CRC, at the end, covering the entire frame. The problem with having a single CRC is that the if the payload size is corrupted in such a way that it is extremely large (65,535 in the pathological case) the reciever will not detect this until it reads that many bytes, calculates the CRC, and discovers that it doesn't match. Depending on the transmitter's data rate at the time of the error, it could take a long time to receive this many bytes, making the issue look like a dropped link.

Both CRCs are calculated using CRC-16/CCITT-FALSE, with the following settings:

  • Width: 16
  • Polynomial: 0x1021
  • Init: 0xFFFF
  • RefIn/RefOut: false / false
  • XorOut: 0x0000
  • Check("123456789): 0x29B1l

Usage

Installation

Install the package using pip:

pip install compact-frame-format

Or using uv:

uv add compact-frame-format

Example

Here's a complete working example (from usage_example.py):

from compact_frame_format import Cff

# Create and send frames
messages = ["Hello", "World", "CFF"]
buffer = bytearray()

cff = Cff()

print("Creating frames:")
for i, message in enumerate(messages):
    payload = message.encode("utf-8")
    frame = cff.create(payload)

    print(f"  Frame {i}: {message} -> {len(frame)} bytes")

    # Simulate adding to receive buffer
    buffer.extend(frame)

print(f"\nBuffer contains {len(buffer)} bytes total")

# Parse all frames from buffer
received_frames, consumed_bytes = cff.parse_frames(bytes(buffer))

print(f"\nProcessed {consumed_bytes} bytes from buffer")
print("Received frames:")
for frame in received_frames:
    message = frame.payload.decode("utf-8")
    print(f"  Frame {frame.frame_counter}: {message}")

Development

Checkout the code:

git clone https://github.com/CompactFrameFormat/cff-python.git
cd cff-python

Create a new virtual environment:

uv venv && .venv\Scripts\activate.ps1

Install dependencies:

uv sync --all-extras

Install pre-commit hooks:

pre-commit install

Code Quality

This project uses Ruff for linting and formatting. Pre-commit hooks are configured to run code quality checks automatically.

Check code formatting and linting:

ruff check .
ruff format --check .

Format code and fix linting issues:

ruff check --fix . && ruff format .

Testing

Run the tests:

python -m pytest

Run tests with coverage:

python -m pytest --cov=compact_frame_format

Release files for compact-frame-format 1.0.0rc2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for compact-frame-format 1.0.0rc2
File Size Uploaded
compact_frame_format-1.0.0rc2.tar.gz 20.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for compact-frame-format 1.0.0rc2
File Interpreter ABI Platform
compact_frame_format-1.0.0rc2-py3-none-any.whl Python 3 none any Details

Total release size: 30.3 kB

Release files / compact_frame_format-1.0.0rc2.tar.gz

Download URL compact_frame_format-1.0.0rc2.tar.gz
Size 20.5 kB
Tags Source
SHA-256 checksum
How to use checksums
41233cbc8cdecd81950b14a593def4f26c3c5b9738272eaa66f89c25f60bae91
BLAKE2b-256 checksum
How to use checksums
da5d76d5976c04deab1fa9eb4023315aa634f8778b830246961db4d3456549b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 20, 2025.

Transparency log

Release files / compact_frame_format-1.0.0rc2-py3-none-any.whl

Download URL compact_frame_format-1.0.0rc2-py3-none-any.whl
Size 9.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5ee7e6548cd9279d87768b09b33751a0b92b01a14d8cae710d1e736c2c801fd0
BLAKE2b-256 checksum
How to use checksums
0b9f44afcaf9d1db4aef1ab4adfbc084c3268a644c6457dcfe5f49f2bb0340ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 20, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0rc2 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page