Firechip · open source
Consistent Overhead Byte Stuffing (COBS) turns any byte string
into one with no 0x00 bytes, so a single 0x00 can
delimit packets on a serial, USB, or BLE link. The Firechip family implements
it — plus COBS/R, a configurable delimiter, and framing — in Rust, Dart,
Kotlin, and Swift, all proven identical by one shared set of test vectors.
COBS replaces the interior zero with a length code, leaving the payload zero-free — so the trailing 0x00 is an unambiguous frame boundary. Overhead is at most one byte per 254.
cobs_codec_rs
#![no_std], zero-dependency crate for embedded and serial work; optional serde / defmt.
cargo add cobs_codec_rs
cobs_codec
All-platform, dart:convert-native Codecs with stream framing for Flutter and CLI.
dart pub add cobs_codec
cobs_codec
Pure-Kotlin for Android / JVM, with java.io streams and a coroutines Flow API.
implementation("dev.firechip:cobs_codec:1.2.0")
CobsCodec
Stdlib-only (no Foundation) — macOS, iOS, tvOS, watchOS, Linux, and embedded Swift.
.package(url: ".../cobs_codec_swift.git", from: "1.0.0")
One deterministic set of JSON-Lines vectors (basic COBS, COBS/R, configurable-sentinel, and decode-error cases). Every member checks itself against these in CI, which is why the four libraries produce byte-for-byte identical output. Any implementation can prove conformance too.
Teal bytes are COBS length codes; red
are the zeros being stuffed out; the faint trailing 00 is the frame delimiter added on the wire.
Watch COBS/R promote a large final byte into the code slot and drop the overhead byte entirely.
The encoder here is the same one the four libraries ship — verified byte-for-byte against all 2,261 vectors.
Lose a byte to line noise and the receiver just waits for the next 0x00 — it resyncs on the very next packet instead of losing the stream, the way length-prefixing does.
Overhead is data-independent — at most one byte per 254, where escape schemes (PPP, SLIP) can double a packet in the worst case.
max = n + ⌈n / 254⌉Encode and decode need no allocation and run in-place or into a fixed buffer — the gold standard for MCUs (Arduino, STM32, ESP32) talking to a host, e.g. framing Protobuf.
The CPU sleeps while DMA collects bytes; a character-match or idle-line interrupt on 0x00 wakes it only for complete frames. Drop a byte to noise and alignment returns on the very next 0x00.
Binary structs — Protobuf, MessagePack — are riddled with 0x00 (a 16-bit 256 is 01 00), so a raw delimiter is impossible. COBS frames them at ~0.4% where escape stuffing can hit 100%.
On a shared bus, a node seeing a run with no 0x00 knows it is mid-transmission and stays quiet; the next 0x00 marks a fresh, addressable command frame.
Firmware images are zero-heavy. COBS gives the bootloader clean per-block boundaries to CRC-verify and flash a sector safely, even over a noisy link.
BLE / Zigbee bridges stream tiny packets millions of times a day. COBS/R drops the final byte whenever it can — measurably less radio time and battery per packet.
| Technique | Worst-case overhead | CPU | Resync after a lost byte |
|---|---|---|---|
| Length-prefix header | 0% — but desyncs catastrophically if a byte drops | Low | Poor — needs a timeout |
| Escape stuffing (PPP / HDLC) | up to 100% | Higher — variable loop | Fast — next delimiter |
| COBS / COBS/R | ~0.4% — 1 byte / 254 | Low — look-ahead pointer | Instant — next 0x00 |
COBS is a mathematical bound — about 0.39% worst case from a one-byte look-ahead — so nothing beats it on raw overhead for byte streams. But it isn't the only right answer in 2026:
| If you need… | Reach for | Because |
|---|---|---|
| Maximum bandwidth efficiency | COBS / COBS/R | Undefeated overhead over variable-length streams. |
| Gigabit-rate streaming | Multi-COBS | SIMD / parallel pipelines for high-end MCUs and FPGAs. |
| Zero CPU spent on framing | Length-prefix + idle line | Hardware UART timeout (RTO) and DMA do it all. |
| Self-delimiting IoT structs | Concatenated CBOR | Serialization and framing in one binary standard. |
How the Firechip family (first four, tinted) stacks up against Craig McQueen's reference implementations and other COBS libraries across C, C++, Rust, Python, and Swift. Full notes and links live in the conformance repo.
| Feature | cobs_codec_rsRust | cobs_codecDart | cobs_codecKotlin | CobsCodecSwift | cobs-cC · ref | cobsPython · ref | libcobsC | cobsRust · jamesmunns | cobs-codecRust · alvra | GlassGemSwift | SerialFillerC++ | KiToolsPython | esppC++ · ESP-IDF |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Basic COBS | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| COBS/R (reduced) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ○ | ○ | ○ | ○ | ○ | ○ | ○ |
| Configurable sentinel | ✓ | ✓ | ✓ | ✓ | ○ | ○ | ○ | ✓ | ✓ | ○ | ○ | ○ | ○ |
| In-place decode | ✓ | ✓ | ✓ | ✓ | ○ | ○ | ○ | ✓ | ○ | ○ | ○ | ○ | ○ |
| Incremental / streaming decode | ✓ | ✓ | ✓ | ✓ | ○ | ○ | ○ | ✓ | ✓async | ○ | ○ | ✓ | ✓ |
| Frame delimiting | ✓ | ✓ | ✓ | ✓ | ○ | ○ | ○ | ◐ | ✓ | ◐ | ○ | ◐ | ✓ |
| Size helpers (max length) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ○ | ✓ | ○ | ○ | ○ | ○ | ✓ |
| Typed error reporting | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ◐ | ✓ | ✓ | ○ | ✓ | ◐ | ○ |
| no_std / freestanding | ✓ | · | · | · | ✓ | ○ | ✓ | ✓ | ○ | · | ○ | · | ○ |
| Zero dependencies | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ○ | ○ | ✓ | ✓ | ○ | ○ |
| Native framework hooks | ◐serde/defmt | ✓dart:convert | ✓java.io/Flow | ○ | ○ | ○ | ○ | ◐serde/defmt | ✓tokio-util | ○ | ○ | ○ | ✓ESP-IDF |
| Verified against these vectors | ✓ | ✓ | ✓ | ✓ | source | source | ○ | ○ | ○ | ○ | ○ | ○ | ○ |