Skip to content

Commit

Permalink
pw_hdlc: Follow new module docs guidelines
Browse files Browse the repository at this point in the history
Change-Id: I076a5b1668e2b761f20d9e7348a6d854e95a7206
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/184799
Commit-Queue: Kayce Basques <[email protected]>
Reviewed-by: Alexei Frolov <[email protected]>
Reviewed-by: Kayce Basques <[email protected]>
  • Loading branch information
Kayce Basques authored and CQ Bot Account committed Dec 20, 2023
1 parent 36bf818 commit ab20a82
Show file tree
Hide file tree
Showing 11 changed files with 500 additions and 290 deletions.
1 change: 1 addition & 0 deletions pw_hdlc/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ pw_doc_group("docs") {
"docs.rst",
"guide.rst",
"rpc_example/docs.rst",
"size.rst",
]
inputs = [
"py/pw_hdlc/decode.py",
Expand Down
71 changes: 43 additions & 28 deletions pw_hdlc/api.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
.. _module-pw_hdlc-api:

======================
pw_hdlc: API reference
======================
=============
API reference
=============
.. pigweed-module-subpage::
:name: pw_hdlc
:tagline: Lightweight, simple, and easy serial communication
:tagline: pw_hdlc: Simple, robust, and efficient serial communication

This page describes the :ref:`module-pw_hdlc-api-encoder`, :ref:`module-pw_hdlc-api-decoder`,
and :ref:`module-pw_hdlc-api-rpc` APIs of ``pw_hdlc``.
The ``pw_hdlc`` API has 3 conceptual parts:

* :ref:`module-pw_hdlc-api-encoder`: Encode data as HDLC unnumbered
information frames.
* :ref:`module-pw_hdlc-api-decoder`: Decode HDLC frames from a stream of data.
* :ref:`module-pw_hdlc-api-rpc`: Use RPC over HDLC.

.. _module-pw_hdlc-api-encoder:

Expand All @@ -20,13 +24,12 @@ unnumbered information frame.
.. tab-set::

.. tab-item:: C++
:sync: cpp

.. doxygenfunction:: pw::hdlc::WriteUIFrame(uint64_t address, ConstByteSpan data, stream::Writer &writer)

Example:

.. TODO: b/279648188 - Share this code between api.rst and guide.rst.
.. code-block:: cpp
// Writes a span of data to a pw::stream::Writer and returns the status. This
Expand All @@ -45,15 +48,14 @@ unnumbered information frame.
}
.. tab-item:: Python
:sync: py

.. automodule:: pw_hdlc.encode
:members:
:noindex:

Example:

.. TODO: b/279648188 - Share this code between api.rst and guide.rst.
.. code-block:: python
# Read bytes from serial and encode HDLC frames
Expand All @@ -66,33 +68,32 @@ unnumbered information frame.
ser.write(encode.ui_frame(address, b'your data here!'))
.. tab-item:: TypeScript
:sync: ts

The Encoder class provides a way to build complete, escaped HDLC UI frames.
``Encoder`` provides a way to build complete, escaped HDLC unnumbered
information frames.

.. js:method:: Encoder.uiFrame(address, data)
:noindex:

:param number address: frame address.
:param Uint8Array data: frame data.
:returns: Uint8Array containing a complete HDLC frame.
:returns: ``Uint8Array`` containing a complete HDLC frame.

.. _module-pw_hdlc-api-decoder:

Decoder
=======


.. tab-set::

.. tab-item:: C++
:sync: cpp

.. doxygenclass:: pw::hdlc::Decoder
:members:

Example:

.. TODO: b/279648188 - Share this code between api.rst and guide.rst.
.. code-block:: cpp
// Read individual bytes from pw::sys_io and decode HDLC frames.
Expand All @@ -115,15 +116,14 @@ Decoder
}
.. tab-item:: Python
:sync: py

.. autoclass:: pw_hdlc.decode.FrameDecoder
:members:
:noindex:

Example:

.. TODO: b/279648188 - Share this code between api.rst and guide.rst.
.. code-block:: python
# Decode data read from serial
Expand All @@ -150,16 +150,17 @@ Decoder
:noindex:

.. tab-item:: TypeScript
:sync: ts

The decoder class unescapes received bytes and adds them to a buffer. Complete,
``Decoder`` unescapes received bytes and adds them to a buffer. Complete,
valid HDLC frames are yielded as they are received.

.. js:method:: Decoder.process(data)
:noindex:

:param Uint8Array data: bytes to be decoded.
:yields: HDLC frames, including corrupt frames.
The Frame.ok() method whether the frame is valid.
The ``Frame.ok()`` method whether the frame is valid.

.. js:method:: processValidFrames(data)
:noindex:
Expand All @@ -175,26 +176,28 @@ RPC
.. tab-set::

.. tab-item:: C++
:sync: cpp

The ``RpcChannelOutput`` implements pw_rpc's ``pw::rpc::ChannelOutput``
interface, simplifying the process of creating an RPC channel over HDLC. A
``pw::stream::Writer`` must be provided as the underlying transport
``RpcChannelOutput`` implements the ``pw::rpc::ChannelOutput`` interface
of ``pw_rpc``, simplifying the process of creating an RPC channel over HDLC.
A ``pw::stream::Writer`` must be provided as the underlying transport
implementation.

If your HDLC routing path has a Maximum Transmission Unit (MTU) limitation,
using the ``FixedMtuChannelOutput`` is strongly recommended to verify that the
currently configured max RPC payload size (dictated by pw_rpc's static encode
buffer) will always fit safely within the limits of the fixed HDLC MTU *after*
use the ``FixedMtuChannelOutput`` to verify that the currently configured
max RPC payload size (dictated by the static encode buffer of ``pw_rpc``)
will always fit safely within the limits of the fixed HDLC MTU *after*
HDLC encoding.

.. tab-item:: Python
:sync: py

The ``pw_hdlc`` Python package includes utilities to HDLC-encode and
decode RPC packets, with examples of RPC Client implementations in Python.
decode RPC packets, with examples of RPC client implementations in Python.
It also provides abstractions for interfaces used to receive RPC Packets.

The ``pw_hdlc.rpc.CancellableReader`` and ``pw_hdlc.rpc.RpcClient``
classes and and derived classes are context-managed to cleanly cancel the
classes and derived classes are context-managed to cleanly cancel the
read process and stop the reader thread. The ``pw_hdlc.rpc.SocketReader``
and ``pw_hdlc.rpc.SerialReader`` also close the provided interface on
context exit. It is recommended to use these in a context statement. For
Expand Down Expand Up @@ -264,3 +267,15 @@ RPC
.. autoclass:: pw_hdlc.rpc.HdlcRpcLocalServerAndClient
:members:
:noindex:

.. tab-item:: TypeScript
:sync: ts

The TypeScript library doesn't have an RPC interface.

-----------------
More pw_hdlc docs
-----------------
.. include:: docs.rst
:start-after: .. pw_hdlc-nav-start
:end-before: .. pw_hdlc-nav-end
77 changes: 59 additions & 18 deletions pw_hdlc/design.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,42 @@
.. _module-pw_hdlc-design:

===============
pw_hdlc: Design
===============
================
Design & roadmap
================
.. pigweed-module-subpage::
:name: pw_hdlc
:tagline: Lightweight, simple, and easy serial communication
:tagline: pw_hdlc: Simple, robust, and efficient serial communication

``pw_hdlc`` implements a subset of the
`HDLC <https://en.wikipedia.org/wiki/High-Level_Data_Link_Control>`_
protocol.
.. pw_hdlc-overview-start
``pw_hdlc`` implements a subset of the `High-Level Data Link Control
<https://en.wikipedia.org/wiki/High-Level_Data_Link_Control>`_ (HDLC) protocol.
HDLC is a data link layer protocol intended for serial communication between
devices and is standardized as `ISO/IEC 13239:2002
<https://www.iso.org/standard/37010.html>`_.

.. pw_hdlc-overview-end
--------
Overview
--------
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 devices.

``pw_hdlc`` has two primary functions:

* **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.

Design considerations
=====================
* ``pw_hdlc`` only supports unnumbered information frames.
* It uses special escaped bytes to mark the beginning and end of a frame.
* Frame data is stored in a buffer until the end-of-frame delimiter byte is read.

--------------------
Protocol Description
Expand All @@ -36,30 +63,44 @@ information frames. These frames are encoded as follows:
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:
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 |
| ``7E`` | ``7D 5E`` |
+-------------------------+-----------------------+
| 7D | 7D 5D |
| ``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.
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:
Frames may be received in multiple parts, so ``pw_hdlc`` needs 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.

-------
Roadmap
-------
- **Expanded protocol support** - ``pw_hdlc`` currently only supports
unnumbered information frames. Support for different frame types and
extended control fields may be added in the future.

-----------------
More pw_hdlc docs
-----------------
.. include:: docs.rst
:start-after: .. pw_hdlc-nav-start
:end-before: .. pw_hdlc-nav-end
Loading

0 comments on commit ab20a82

Please sign in to comment.