pw_hdlc: How-to guide#
Pigweed AI summary: This guide provides instructions on how to use the Encoder and Decoder APIs of pw_hdlc, a lightweight and simple serial communication module. The guide includes code snippets in C++ and Python for encoding and decoding HDLC frames, as well as information on allocating buffers for encoding and decoding. The guide is organized into sections for encoding and decoding, each with their own subsections for allocating buffers.
This page shows you how to use the Encoder and Decoder APIs of pw_hdlc.
Encoding#
Pigweed AI summary: This section discusses encoding in C++ and Python using the HDLC module. It provides code examples for writing data to a stream and encoding HDLC frames. It also discusses allocating buffers for encoding and provides helper functions for determining buffer sizes.
// Writes a span of data to a pw::stream::Writer and returns the status. This
// implementation uses the pw_checksum module to compute the CRC-32 frame check
// sequence.
#include "pw_hdlc/encoder.h"
#include "pw_hdlc/sys_io_stream.h"
int main() {
pw::stream::SysIoWriter serial_writer;
Status status = WriteUIFrame(123 /* address */, data, serial_writer);
if (!status.ok()) {
PW_LOG_INFO("Writing frame failed! %s", status.str());
}
}
# Read bytes from serial and encode HDLC frames
import serial
from pw_hdlc import encode
ser = serial.Serial()
address = 123
ser.write(encode.ui_frame(address, b'your data here!'))
Allocating buffers when encoding#
Pigweed AI summary: This section discusses the allocation of buffers when encoding HDLC. The module provides helper functions to determine the size of buffers based on payload size and worst-case sizes of frames. The code includes constants for the maximum on-the-wire size of a single HDLC frame after encoding and the size of the RPC encode buffer. The function GetRpcEncodeBuffer() returns a constant byte span that is guaranteed to fit in the MTU after HDLC encoding.
Since HDLC’s encoding overhead changes with payload size and what data is being encoded, this module provides helper functions that are useful for determining the size of buffers by providing worst-case sizes of frames given a certain payload size and vice-versa.
#include "pw_assert/check.h"
#include "pw_bytes/span.h"
#include "pw_hdlc/encoder"
#include "pw_hdlc/encoded_size.h"
#include "pw_status/status.h"
// The max on-the-wire size in bytes of a single HDLC frame after encoding.
constexpr size_t kMtu = 512;
constexpr size_t kRpcEncodeBufferSize = pw::hdlc::MaxSafePayloadSize(kMtu);
std::array<std::byte, kRpcEncodeBufferSize> rpc_encode_buffer;
// Any data encoded to this buffer is guaranteed to fit in the MTU after
// HDLC encoding.
pw::ConstByteSpan GetRpcEncodeBuffer() {
return rpc_encode_buffer;
}
Decoding#
Pigweed AI summary: The article discusses decoding HDLC frames in C++ and Python. The C++ code reads individual bytes from pw::sys_io and decodes HDLC frames using pw_hdlc/decoder.h. The Python code uses serial to read data and pw_hdlc to decode frames. The article also mentions a helper function in the HDLC Decoder for allocating a buffer with lower overhead.
// Read individual bytes from pw::sys_io and decode HDLC frames.
#include "pw_hdlc/decoder.h"
#include "pw_sys_io/sys_io.h"
int main() {
std::byte data;
while (true) {
if (!pw::sys_io::ReadByte(&data).ok()) {
// Log serial reading error
}
Result<Frame> decoded_frame = decoder.Process(data);
if (decoded_frame.ok()) {
// Handle the decoded frame
}
}
}
# Decode data read from serial
import serial
from pw_hdlc import decode
ser = serial.Serial()
decoder = decode.FrameDecoder()
while True:
for frame in decoder.process_valid_frames(ser.read()):
# Handle the decoded frame
Allocating buffers when decoding#
Pigweed AI summary: The HDLC Decoder has a helper for allocating a buffer that has lower overhead since it doesn't require the entire escaped frame in-memory to decode. The code example provided shows how to create a decoder with a given MTU constraint and the required buffer size for the frame size.
The HDLC Decoder
has its own helper for allocating a buffer since it doesn’t
need the entire escaped frame in-memory to decode, and therefore has slightly
lower overhead.
#include "pw_hdlc/decoder.h"
// The max on-the-wire size in bytes of a single HDLC frame after encoding.
constexpr size_t kMtu = 512;
// Create a decoder given the MTU constraint.
constexpr size_t kDecoderBufferSize =
pw::hdlc::Decoder::RequiredBufferSizeForFrameSize(kMtu);
pw::hdlc::DecoderBuffer<kDecoderBufferSize> decoder;