boot: boot_serial: add COBS framing for raw serial recovery#2773
boot: boot_serial: add COBS framing for raw serial recovery#2773JPHutchins wants to merge 1 commit into
Conversation
Add BOOT_SERIAL_RAW_PROTOCOL_COBS, a framing layer on top of the raw
(non-console) SMP recovery protocol that wraps each SMP packet as:
COBS(header || payload || CRC16) || 0x00
The CRC16 is CRC-16/XMODEM (polynomial 0x1021, initial value 0x0000, no
reflection), computed over the header and payload and appended big-endian,
identical to the CRC used by the SMP over console encoding. The packet and
its CRC are then COBS-encoded, which removes every 0x00 from the stream, so
a single trailing 0x00 is an unambiguous frame delimiter.
Unlike the bare raw protocol, this encoding is self-synchronising: the
delimiter gives a resync point after any corruption or truncation, and the
CRC16 rejects damaged packets. It therefore takes over the role of the input
timeout, and the two are mutually exclusive. The existing
BOOT_SERIAL_RAW_PROTOCOL_INPUT_TIMEOUT option becomes one member of a new
choice, alongside the COBS option and BOOT_SERIAL_RAW_PROTOCOL_NONE (the
original unframed behaviour). Migration: a configuration that previously set
CONFIG_BOOT_SERIAL_RAW_PROTOCOL_INPUT_TIMEOUT=n to obtain the unframed raw
behaviour must now set CONFIG_BOOT_SERIAL_RAW_PROTOCOL_NONE=y; configurations
that leave the timeout at its default, or set it =y, are unaffected.
The COBS codec is a small dependency-free module (boot_serial/src/cobs.c)
rather than Zephyr's CONFIG_COBS, which is net_buf-based and would pull the
net_buf subsystem into serial recovery. It decodes in place, so the receive
buffer grows only by the COBS overhead (at most one byte per 254 input bytes,
under 1%) plus the delimiter.
The SMP client must be configured to use a matching COBS+CRC16 transport. No
stock mcumgr client speaks this encoding yet, so this option is provided for
evaluation and community review; the PR is intentionally a draft to gauge
interest.
A serial_recovery_raw_cobs.conf fragment and a matching Twister build test
(sample.bootloader.mcuboot.serial_recovery_raw_cobs) are added, along with a
native_sim ztest for the COBS codec (boot/zephyr/tests/cobs).
Signed-off-by: JP Hutchins <jp@intercreate.io>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nordicjm
left a comment
There was a problem hiding this comment.
frankly if you want a transport that has the delimiter then you should use SMP over console. The point in SMP itself is it's a binary protocol, raw data over any transport (e.g. UDP, UART, bluetooth, LoRaWAN, CAN, etc.) the only reason the UART one diverged is to allow support for messages over a serial terminal where a console is also used, there should not be custom parts on top of transports except specifically for SMP over console
Yeah, I do agree, generally, because the upload is not necessarily bound by the transport speed, it's usually bound by the flash write speed. We do have a situation here where we 1) want the smaller raw serial size (no base64) and 2) have a raw UART that benefits from the COBS + CRC16. This is not intended for merge because I think it muddies the waters for implementers to have not just 2, but 3 different serial transport options to deal with. |
Add BOOT_SERIAL_RAW_PROTOCOL_COBS, a framing layer on top of the raw (non-console) SMP recovery protocol that wraps each SMP packet as:
The CRC16 is CRC-16/XMODEM (polynomial 0x1021, initial value 0x0000, no reflection), computed over the header and payload and appended big-endian, identical to the CRC used by the SMP over console encoding. The packet and its CRC are then COBS-encoded, which removes every 0x00 from the stream, so a single trailing 0x00 is an unambiguous frame delimiter.
Unlike the bare raw protocol, this encoding is self-synchronising: the delimiter gives a resync point after any corruption or truncation, and the CRC16 rejects damaged packets. It therefore takes over the role of the input timeout, and the two are mutually exclusive. The existing BOOT_SERIAL_RAW_PROTOCOL_INPUT_TIMEOUT option becomes one member of a new choice, alongside the COBS option and BOOT_SERIAL_RAW_PROTOCOL_NONE (the original unframed behaviour). Migration: a configuration that previously set CONFIG_BOOT_SERIAL_RAW_PROTOCOL_INPUT_TIMEOUT=n to obtain the unframed raw behaviour must now set CONFIG_BOOT_SERIAL_RAW_PROTOCOL_NONE=y; configurations that leave the timeout at its default, or set it =y, are unaffected.
The COBS codec is a small dependency-free module (boot_serial/src/cobs.c) rather than Zephyr's CONFIG_COBS, which is net_buf-based and would pull the net_buf subsystem into serial recovery. It decodes in place, so the receive buffer grows only by the COBS overhead (at most one byte per 254 input bytes, under 1%) plus the delimiter.
The SMP client must be configured to use a matching COBS+CRC16 transport. No stock mcumgr client speaks this encoding yet, so this option is provided for evaluation and community review; the PR is intentionally a draft to gauge interest.
A serial_recovery_raw_cobs.conf fragment and a matching Twister build test (sample.bootloader.mcuboot.serial_recovery_raw_cobs) are added, along with a native_sim ztest for the COBS codec (boot/zephyr/tests/cobs).