Skip to main content
Pigweed's logo Pigweed
code_xml
  1. Home
  2. Reference
  3. C/C++
  4. Comms
  5. pw_cobs
Loading...
Searching...
No Matches
pw_cobs

Overview

Consistent Overhead Byte Stuffing (COBS) codec and zero-copy frame streamer.

Classes

class  pw::cobs::EncodeBuffer< kMaxPayloadSize >
 
class  pw::cobs::Streamer
 
class  pw::cobs::StreamerBuffer< kSizeBytes >
 
class  pw::cobs::Decoder
 
class  pw::cobs::DecoderBuffer< kSizeBytes >
 A Decoder with an inline decode buffer of kSizeBytes bytes. More...
 

Typedefs

using pw::cobs::EncodeBuffer< kMaxPayloadSize >::value_type = std::byte
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::size_type = size_t
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::difference_type = ptrdiff_t
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::reference = std::byte &
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::const_reference = const std::byte &
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::pointer = std::byte *
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::const_pointer = const std::byte *
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::iterator = containers::PtrIterator< EncodeBuffer >
 
using pw::cobs::EncodeBuffer< kMaxPayloadSize >::const_iterator = containers::ConstPtrIterator< EncodeBuffer >
 

Functions

constexpr size_t pw::cobs::MaxEncodedSize (size_t unencoded_size)
 
constexpr size_t pw::cobs::MaxDecodedSize (size_t encoded_size)
 
Result< ByteSpan > pw::cobs::Encode (ConstByteSpan input, ByteSpan output)
 
Result< ByteSpan > pw::cobs::Decode (ConstByteSpan encoded, ByteSpan output)
 
Result< ByteSpan > pw::cobs::EncodeInPlace (ByteSpan buffer, size_t payload_size)
 
 pw::cobs::EncodeBuffer< kMaxPayloadSize >::EncodeBuffer (ConstByteSpan initial)
 
constexpr std::byte * pw::cobs::EncodeBuffer< kMaxPayloadSize >::data ()
 
constexpr const std::byte * pw::cobs::EncodeBuffer< kMaxPayloadSize >::data () const
 
constexpr size_t pw::cobs::EncodeBuffer< kMaxPayloadSize >::size () const
 Current unencoded payload length in bytes.
 
static constexpr size_t pw::cobs::EncodeBuffer< kMaxPayloadSize >::max_size ()
 Maximum unencoded payload capacity in bytes.
 
static constexpr size_t pw::cobs::EncodeBuffer< kMaxPayloadSize >::capacity ()
 
constexpr bool pw::cobs::EncodeBuffer< kMaxPayloadSize >::empty () const
 
constexpr iterator pw::cobs::EncodeBuffer< kMaxPayloadSize >::begin ()
 
constexpr const_iterator pw::cobs::EncodeBuffer< kMaxPayloadSize >::begin () const
 
constexpr const_iterator pw::cobs::EncodeBuffer< kMaxPayloadSize >::cbegin () const
 
constexpr iterator pw::cobs::EncodeBuffer< kMaxPayloadSize >::end ()
 
constexpr const_iterator pw::cobs::EncodeBuffer< kMaxPayloadSize >::end () const
 
constexpr const_iterator pw::cobs::EncodeBuffer< kMaxPayloadSize >::cend () const
 
constexpr std::byte & pw::cobs::EncodeBuffer< kMaxPayloadSize >::operator[] (size_t index)
 
constexpr const std::byte & pw::cobs::EncodeBuffer< kMaxPayloadSize >::operator[] (size_t index) const
 
constexpr void pw::cobs::EncodeBuffer< kMaxPayloadSize >::clear ()
 Resets the unencoded payload length to 0 so a new payload can be built.
 
void pw::cobs::EncodeBuffer< kMaxPayloadSize >::resize (size_t new_size)
 
void pw::cobs::EncodeBuffer< kMaxPayloadSize >::push_back (std::byte b)
 
void pw::cobs::EncodeBuffer< kMaxPayloadSize >::append (ConstByteSpan bytes)
 
ConstByteSpan pw::cobs::EncodeBuffer< kMaxPayloadSize >::Encode ()
 
ConstByteSpan pw::cobs::EncodeBuffer< kMaxPayloadSize >::Encode (size_t payload_size)
 
constexpr pw::cobs::Streamer::Streamer (ByteSpan buffer, bool emit_leading_delimiter=false)
 
constexpr void pw::cobs::Streamer::Reset (bool emit_leading_delimiter=false)
 
ConstByteSpan pw::cobs::Streamer::Write (ConstByteSpan data)
 
ByteSpan pw::cobs::Streamer::Flush ()
 
ByteSpan pw::cobs::Streamer::Finish ()
 
constexpr ConstByteSpan pw::cobs::Streamer::AbortSequence () const
 
constexpr pw::cobs::StreamerBuffer< kSizeBytes >::StreamerBuffer (bool emit_leading_delimiter=false)
 
 pw::cobs::StreamerBuffer< kSizeBytes >::StreamerBuffer (const StreamerBuffer &)=delete
 
StreamerBuffer & pw::cobs::StreamerBuffer< kSizeBytes >::operator= (const StreamerBuffer &)=delete
 
 pw::cobs::StreamerBuffer< kSizeBytes >::StreamerBuffer (StreamerBuffer &&)=delete
 
StreamerBuffer & pw::cobs::StreamerBuffer< kSizeBytes >::operator= (StreamerBuffer &&)=delete
 
static constexpr size_t pw::cobs::StreamerBuffer< kSizeBytes >::max_size ()
 
constexpr pw::cobs::Decoder::Decoder (ByteSpan decode_buffer)
 
void pw::cobs::Decoder::Clear ()
 Discards any partially received frame and resets the decoder to idle.
 
constexpr bool pw::cobs::Decoder::in_progress () const
 
Result< ByteSpan > pw::cobs::Decoder::Process (std::byte b)
 
template<typename Callback >
void pw::cobs::Decoder::Process (ConstByteSpan data, Callback &&callback)
 
 pw::cobs::DecoderBuffer< kSizeBytes >::DecoderBuffer (const DecoderBuffer &)=delete
 
DecoderBuffer & pw::cobs::DecoderBuffer< kSizeBytes >::operator= (const DecoderBuffer &)=delete
 
 pw::cobs::DecoderBuffer< kSizeBytes >::DecoderBuffer (DecoderBuffer &&)=delete
 
DecoderBuffer & pw::cobs::DecoderBuffer< kSizeBytes >::operator= (DecoderBuffer &&)=delete
 
static constexpr size_t pw::cobs::DecoderBuffer< kSizeBytes >::max_size ()
 Returns the capacity of the decode buffer in bytes.
 

Variables

constexpr size_t pw::cobs::kMaxRunLength = 254
 Maximum number of contiguous non-zero bytes in a single COBS block.
 
static constexpr size_t pw::cobs::Streamer::kMinBufferSize = MaxEncodedSize(kMaxRunLength) + 1
 
static constexpr std::array< std::byte, 2 > pw::cobs::Streamer::kAbortSequence
 

Friends

Result< ByteSpan > pw::cobs::Streamer::Encode (ConstByteSpan input, ByteSpan output)
 
Result< ByteSpan > pw::cobs::Decoder::Decode (ConstByteSpan encoded, ByteSpan output)
 

Function Documentation

◆ AbortSequence()

constexpr ConstByteSpan pw::cobs::Streamer::AbortSequence ( ) const
inlineconstexpr

Returns the 2-byte abort sequence (0xFF, 0x00) to transmit if a prior Flush() has already sent bytes of the current frame on the wire, or an empty span if nothing has been flushed yet.

Call Reset() after aborting before starting a new frame.

◆ append()

template<size_t kMaxPayloadSize>
void pw::cobs::EncodeBuffer< kMaxPayloadSize >::append ( ConstByteSpan  bytes)
inline

Appends bytes to the unencoded payload.

Precondition
size() + bytes.size() <= max_size().

◆ data()

template<size_t kMaxPayloadSize>
constexpr std::byte * pw::cobs::EncodeBuffer< kMaxPayloadSize >::data ( )
inlineconstexpr

Pointer to the unencoded payload region ([data(), data() + size())).

Warning
Invalidated by Encode(), which overwrites the internal buffer in-place. Call clear() or resize() before writing a new payload.

◆ Decode()

Result< ByteSpan > pw::cobs::Decode ( ConstByteSpan  encoded,
ByteSpan  output 
)

Decodes a single 0x00-terminated COBS frame encoded into output.

Precondition
encoded and output must not overlap.
Returns
A Result containing the decoded payload subspan of output on success or one of the following error codes on failure:
  • DATA_LOSS: encoded is not a valid 0x00-terminated COBS frame.
  • RESOURCE_EXHAUSTED: output is too small to hold the decoded payload. Sizing output to MaxDecodedSize(encoded.size()) guarantees success.

◆ Decoder()

constexpr pw::cobs::Decoder::Decoder ( ByteSpan  decode_buffer)
inlineexplicitconstexpr

Constructs a Decoder that writes decoded payloads into decode_buffer.

Size decode_buffer to the maximum expected decoded payload length (or use DecoderBuffer<kMaxPayloadSize>).

◆ Encode() [1/3]

template<size_t kMaxPayloadSize>
ConstByteSpan pw::cobs::EncodeBuffer< kMaxPayloadSize >::Encode ( )
inline

Encodes the current size() payload bytes in-place and returns the resulting 0x00-terminated COBS frame.

Postcondition
The returned span is valid until the next mutation or Encode() call on this EncodeBuffer. Because Encode() overwrites the buffer in-place, call clear() or resize() before building a new payload.

◆ Encode() [2/3]

Result< ByteSpan > pw::cobs::Encode ( ConstByteSpan  input,
ByteSpan  output 
)

Encodes input into output as a 0x00-terminated COBS frame.

Precondition
input and output must not overlap (use EncodeInPlace() or EncodeBuffer for in-place encoding).
Returns
A Result containing the encoded frame subspan of output (including trailing 0x00) on success or one of the following error codes on failure:
  • RESOURCE_EXHAUSTED: output is too small to hold the encoded frame. Sizing output to MaxEncodedSize(input.size()) guarantees success.

◆ Encode() [3/3]

template<size_t kMaxPayloadSize>
ConstByteSpan pw::cobs::EncodeBuffer< kMaxPayloadSize >::Encode ( size_t  payload_size)
inline

Resizes the payload to payload_size bytes (for payloads written directly via data()) and encodes in-place.

Precondition
payload_size <= max_size().
Postcondition
Same as Encode().

◆ EncodeInPlace()

Result< ByteSpan > pw::cobs::EncodeInPlace ( ByteSpan  buffer,
size_t  payload_size 
)

Encodes a payload in-place inside buffer, appending a trailing 0x00 frame delimiter.

Prefer EncodeBuffer<kMaxPayloadSize> when allocating a fixed-capacity buffer on the stack or inside a class. Use EncodeInPlace directly when operating on an externally provided ByteSpan.

Precondition
buffer.size() >= MaxEncodedSize(payload_size).
The unencoded payload must be written at buffer.subspan(1, payload_size) before calling EncodeInPlace (buffer[0] must be left reserved in front of the payload).
Returns
A Result containing the encoded frame subspan at the start of buffer (including trailing 0x00) on success or one of the following error codes on failure:

◆ Finish()

ByteSpan pw::cobs::Streamer::Finish ( )

Finalizes the frame (appending the trailing 0x00 delimiter), resets the streamer for the next frame (emit_leading_delimiter = false), and returns the final wire chunk to transmit.

Postcondition
The returned ByteSpan points into buffer and remains valid until the next Write() or Reset() call.

◆ Flush()

ByteSpan pw::cobs::Streamer::Flush ( )

Drains completed output from the buffer and returns the wire chunk to transmit.

Returns an empty span if no complete block is ready to flush yet.

Postcondition
The returned ByteSpan points into buffer and remains valid until the next Write(), Flush(), Finish(), or Reset() call.

◆ in_progress()

constexpr bool pw::cobs::Decoder::in_progress ( ) const
inlineconstexpr

Returns true if a frame is currently being assembled (at least one non-zero byte has been received since the last 0x00 delimiter or Clear()).

◆ MaxDecodedSize()

constexpr size_t pw::cobs::MaxDecodedSize ( size_t  encoded_size)
constexpr

Returns the maximum possible decoded payload size in bytes for a 0x00-terminated COBS frame of encoded_size bytes.

Use this to size output buffers passed to Decode() or Decoder.

◆ MaxEncodedSize()

constexpr size_t pw::cobs::MaxEncodedSize ( size_t  unencoded_size)
constexpr

Returns the worst-case encoded frame size in bytes for a payload of unencoded_size bytes, including the trailing 0x00 delimiter.

Use this to size output buffers passed to Encode() or EncodeInPlace().

◆ Process() [1/2]

template<typename Callback >
void pw::cobs::Decoder::Process ( ConstByteSpan  data,
Callback &&  callback 
)
inline

Processes a chunk of incoming wire bytes and invokes callback with a Result<ByteSpan> (Ok, DataLoss, or ResourceExhausted) for each frame that terminates within data.

Postcondition
Each ByteSpan passed to callback points into decode_buffer and is only valid for the duration of that callback invocation.

◆ Process() [2/2]

Result< ByteSpan > pw::cobs::Decoder::Process ( std::byte  b)

Processes a single incoming wire byte b.

The decoder automatically resets at every 0x00 delimiter (whether the frame succeeded or failed), so the next byte begins a new frame without calling Clear().

Returns
  • UNAVAILABLE: Frame assembly is still in progress (or an idle 0x00 delimiter was ignored).
  • OK: A valid frame completed on a 0x00 delimiter. The returned ByteSpan points into decode_buffer and remains valid until the next Process() or Clear() call.
  • DATA_LOSS: A malformed or truncated frame ended at 0x00.
  • RESOURCE_EXHAUSTED: The decoded payload exceeded decode_buffer.size() (reported when the frame's closing 0x00 delimiter arrives).

◆ push_back()

template<size_t kMaxPayloadSize>
void pw::cobs::EncodeBuffer< kMaxPayloadSize >::push_back ( std::byte  b)
inline

Appends a single byte to the unencoded payload.

Precondition
size() < max_size().

◆ Reset()

constexpr void pw::cobs::Streamer::Reset ( bool  emit_leading_delimiter = false)
inlineconstexpr

Discards any buffered state and prepares to encode a new frame.

Parameters
emit_leading_delimiterIf true, prepends a leading 0x00 delimiter byte to the first chunk of the new frame.

◆ resize()

template<size_t kMaxPayloadSize>
void pw::cobs::EncodeBuffer< kMaxPayloadSize >::resize ( size_t  new_size)
inline

Sets the unencoded payload length to new_size bytes.

Precondition
new_size <= max_size().

◆ Streamer()

constexpr pw::cobs::Streamer::Streamer ( ByteSpan  buffer,
bool  emit_leading_delimiter = false 
)
inlineexplicitconstexpr

Constructs a Streamer that writes encoded chunks into buffer.

Precondition
buffer.size() >= kMinBufferSize to stream arbitrary payloads (or use StreamerBuffer<>, which provides the buffer automatically).
Parameters
emit_leading_delimiterIf true, prepends a leading 0x00 delimiter byte to the first emitted chunk to flush any prior line noise on the receiver.

◆ Write()

ConstByteSpan pw::cobs::Streamer::Write ( ConstByteSpan  data)

Encodes as much of data as fits into the output buffer and returns the unconsumed remainder of data.

Postcondition
If the returned span is empty, all of data was consumed and you may call Write() with the next payload piece or Finish() to end the frame.
If the returned span is non-empty, the output buffer is ready to drain: call Flush(), transmit that chunk, and pass the returned remainder back to Write().

Variable Documentation

◆ kAbortSequence

constexpr std::array<std::byte, 2> pw::cobs::Streamer::kAbortSequence
staticconstexpr
Initial value:
{std::byte{0xFF},
std::byte{0x00}}

2-byte sequence (0xFF, 0x00) that aborts an in-progress frame on the wire so the receiver discards it with DATA_LOSS.

◆ kMinBufferSize

constexpr size_t pw::cobs::Streamer::kMinBufferSize = MaxEncodedSize(kMaxRunLength) + 1
staticconstexpr

Minimum buffer size (257 bytes) required to stream arbitrarily large frames across multiple Flush() calls.

Friends

◆ Decode

Result< ByteSpan > Decode ( ConstByteSpan  encoded,
ByteSpan  output 
)
friend

Decodes a single 0x00-terminated COBS frame encoded into output.

Precondition
encoded and output must not overlap.
Returns
A Result containing the decoded payload subspan of output on success or one of the following error codes on failure:
  • DATA_LOSS: encoded is not a valid 0x00-terminated COBS frame.
  • RESOURCE_EXHAUSTED: output is too small to hold the decoded payload. Sizing output to MaxDecodedSize(encoded.size()) guarantees success.

◆ Encode

Result< ByteSpan > Encode ( ConstByteSpan  input,
ByteSpan  output 
)
friend

Encodes input into output as a 0x00-terminated COBS frame.

Precondition
input and output must not overlap (use EncodeInPlace() or EncodeBuffer for in-place encoding).
Returns
A Result containing the encoded frame subspan of output (including trailing 0x00) on success or one of the following error codes on failure:
  • RESOURCE_EXHAUSTED: output is too small to hold the encoded frame. Sizing output to MaxEncodedSize(input.size()) guarantees success.