ADR-0001 — USB protocol framing¶
Status: Accepted — 2026-04-22
Context¶
The device has to carry configuration, synchronous bus transactions, unsolicited events (GPIO IRQs, bus faults), streaming data (ADC at up to 500 kSPS, logic capture, CAN frames), and OTA control — all on a single USB 2.0 Full-Speed link with ~1.1 MB/s of usable bulk bandwidth.
Three realistic framings were on the table early in design:
- AT-style ASCII commands on CDC-ACM, like the FTDI-FT232H /
CH341 / MCP2221 family of bridges. Familiar, works with
screenandminicom, but parsing is expensive, binary payloads are painful, and latency suffers under concurrent streams. - USB HID reports. Classless, 64-byte fixed report size. Great for keyboards; terrible for an adaptive 16-channel bulk protocol that wants frames up to 4 kB.
- A minimal vendor-defined bulk protocol — RPBP. 16-byte header, length field, sequence for pipelining, CRC-32C for integrity, optional CBOR payloads for the bits that need forward-compatibility.
Decision¶
Define RPBP v1 (RPBridge Protocol) as a binary framing on a dedicated vendor bulk endpoint. Use:
- Fixed 16-byte little-endian header.
- Trailing 4-byte CRC-32C (Castagnoli polynomial 0x1EDC6F41) for detecting firmware bugs and ESD bit flips, independent of the USB transport CRC.
- Channel multiplexing inside the single bulk pipe for parallel control / stream / event paths, rather than a separate USB interface per subsystem.
- Credit-based flow control so one saturated stream cannot starve the others.
- CBOR (RFC 8949) for capability maps and extensible command payloads — no schema compiler, small library footprint.
CAN uses a separate gs_usb-compatible vendor interface so that
mainline drivers/net/can/usb/gs_usb.ko binds it automatically. UART
traffic is carried over three standard CDC-ACM interfaces. RPBP only
covers the remaining subsystems (I²C, SPI, GPIO, PWM, ADC, UART phy
selection, events, OTA triggers).
The full wire format is specified in
docs/protocol/rpbp-v1.md.
Consequences¶
Positive:
- Sub-millisecond round-trip for short commands, sustained ~900 kB/s on bulk streams — within USB-FS ceiling.
- Binary-structured payloads for hot paths (
memcpyon the MCU), CBOR only where forward-compat is valued. - One implementation of the framing:
rpbridge-protocolRust crate, mirrored byfirmware/src/rpbp/in C anddriver/src/rpbp.rsin kernel Rust. Golden vectors undertests/golden/keep them in sync.
Negative:
- We give up "plug it into
screen" discoverability for the non-UART subsystems. Mitigated byrpbridge-ctlin userspace. - Every language binding has to carry an RPBP framer. Acceptable — the framer is ~300 LoC.
Supersedes¶
Supersedes the original architecture draft's "Command-Framing" section, which left the framing deliberately vague.