s/pw_hdlc_lite/pw_hdlc/g
This renames the hdlc_lite module to just HDLC to accommodate for future
development.
Change-Id: Ic96502a9f41d3a10179435347d4e8615bc3ae844
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/29042
Reviewed-by: Keir Mierle <keir@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
diff --git a/pw_hdlc/docs.rst b/pw_hdlc/docs.rst
new file mode 100644
index 0000000..c8b574a
--- /dev/null
+++ b/pw_hdlc/docs.rst
@@ -0,0 +1,233 @@
+.. _module-pw_hdlc:
+
+-------
+pw_hdlc
+-------
+`High-Level Data Link Control (HDLC)
+<https://en.wikipedia.org/wiki/High-Level_Data_Link_Control>`_ is a data link
+layer protocol intended for serial communication between devices. HDLC is
+standardized as `ISO/IEC 13239:2002 <https://www.iso.org/standard/37010.html>`_.
+
+The ``pw_hdlc`` module provides a simple, robust frame-oriented transport that
+uses a subset of the HDLC protocol. ``pw_hdlc`` supports sending between
+embedded devices or the host. It can be used with :ref:`module-pw_rpc` to enable
+remote procedure calls (RPCs) on embedded on devices.
+
+**Why use the pw_hdlc module?**
+
+ * Enables the transmission of RPCs and other data between devices over serial.
+ * Detects corruption and data loss.
+ * Light-weight, simple, and easy to use.
+ * Supports streaming to transport without buffering, since the length is not
+ encoded.
+
+.. admonition:: Try it out!
+
+ For an example of how to use HDLC with :ref:`module-pw_rpc`, see the
+ :ref:`module-pw_hdlc-rpc-example`.
+
+.. toctree::
+ :maxdepth: 1
+ :hidden:
+
+ rpc_example/docs
+
+Protocol Description
+====================
+
+Frames
+------
+The HDLC implementation in ``pw_hdlc`` supports only HDLC unnumbered
+information frames. These frames are encoded as follows:
+
+.. code-block:: text
+
+ _________________________________________
+ | | | | | | |...
+ | | | | | | |... [More frames]
+ |_|_|_|__________________________|____|_|...
+ F A C Payload FCS F
+
+ F = flag byte (0x7e, the ~ character)
+ A = address field
+ C = control field
+ FCS = frame check sequence (CRC-32)
+
+
+Encoding and sending data
+-------------------------
+This module first writes an initial frame delimiter byte (0x7E) to indicate the
+beginning of the frame. Before sending any of the payload data through serial,
+the special bytes are escaped:
+
+ +-------------------------+-----------------------+
+ | Unescaped Special Bytes | Escaped Special Bytes |
+ +=========================+=======================+
+ | 7E | 7D 5E |
+ +-------------------------+-----------------------+
+ | 7D | 7D 5D |
+ +-------------------------+-----------------------+
+
+The bytes of the payload are escaped and written in a single pass. The
+frame check sequence is calculated, escaped, and written after. After this, a
+final frame delimiter byte (0x7E) is written to mark the end of the frame.
+
+Decoding received bytes
+-----------------------
+Frames may be received in multiple parts, so we need to store the received data
+in a buffer until the ending frame delimiter (0x7E) is read. When the
+``pw_hdlc`` decoder receives data, it unescapes it and adds it to a buffer.
+When the frame is complete, it calculates and verifies the frame check sequence
+and does the following:
+
+* If correctly verified, the decoder returns the decoded frame.
+* If the checksum verification fails, the frame is discarded and an error is
+ reported.
+
+API Usage
+=========
+There are two primary functions of the ``pw_hdlc`` module:
+
+ * **Encoding** data by constructing a frame with the escaped payload bytes and
+ frame check sequence.
+ * **Decoding** data by unescaping the received bytes, verifying the frame
+ check sequence, and returning successfully decoded frames.
+
+Encoder
+-------
+The Encoder API provides a single function that encodes data as an HDLC
+unnumbered information frame.
+
+C++
+^^^
+.. cpp:namespace:: pw
+
+.. cpp:function:: Status hdlc::WriteUIFrame(uint8_t address, ConstByteSpan data, stream::Writer& writer)
+
+ Writes a span of data to a :ref:`pw::stream::Writer <module-pw_stream>` and
+ returns the status. This implementation uses the :ref:`module-pw_checksum`
+ module to compute the CRC-32 frame check sequence.
+
+.. code-block:: cpp
+
+ #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());
+ }
+ }
+
+Python
+^^^^^^
+.. automodule:: pw_hdlc.encode
+ :members:
+
+.. code-block:: python
+
+ import serial
+ from pw_hdlc import encode
+
+ ser = serial.Serial()
+ ser.write(encode.ui_frame(b'your data here!'))
+
+Decoder
+-------
+The decoder class unescapes received bytes and adds them to a buffer. Complete,
+valid HDLC frames are yielded as they are received.
+
+C++
+^^^
+.. cpp:class:: pw::hdlc::Decoder
+
+ .. cpp:function:: pw::Result<Frame> Process(std::byte b)
+
+ Parses a single byte of an HDLC stream. Returns a Result with the complete
+ frame if the byte completes a frame. The status is the following:
+
+ - OK - A frame was successfully decoded. The Result contains the Frame,
+ which is invalidated by the next Process call.
+ - UNAVAILABLE - No frame is available.
+ - RESOURCE_EXHAUSTED - A frame completed, but it was too large to fit in
+ the decoder's buffer.
+ - DATA_LOSS - A frame completed, but it was invalid. The frame was
+ incomplete or the frame check sequence verification failed.
+
+ .. cpp:function:: void Process(pw::ConstByteSpan data, F&& callback, Args&&... args)
+
+ Processes a span of data and calls the provided callback with each frame or
+ error.
+
+This example demonstrates reading individual bytes from ``pw::sys_io`` and
+decoding HDLC frames:
+
+.. code-block:: cpp
+
+ #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
+ }
+ }
+ }
+
+Python
+^^^^^^
+.. autoclass:: pw_hdlc.decode.FrameDecoder
+ :members:
+
+Below is an example using the decoder class to decode data read from serial:
+
+.. code-block:: python
+
+ 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
+
+Additional features
+===================
+
+pw::stream::SysIoWriter
+------------------------
+The ``SysIoWriter`` C++ class implements the ``Writer`` interface with
+``pw::sys_io``. This Writer may be used by the C++ encoder to send HDLC frames
+over serial.
+
+HdlcRpcClient
+-------------
+.. autoclass:: pw_hdlc.rpc.HdlcRpcClient
+ :members:
+
+Roadmap
+=======
+- **Expanded protocol support** - ``pw_hdlc`` currently only supports
+ unnumbered information frames with a single address byte and control byte.
+ Support for different frame types and extended address or control fields may
+ be added in the future.
+
+- **Higher performance** - We plan to improve the overall performance of the
+ decoder and encoder implementations by using SIMD/NEON.
+
+Compatibility
+=============
+C++17