Change script for apply upstream code
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_hdlc_lite / docs.rst
1 .. _module-pw_hdlc_lite:
2
3 ------------
4 pw_hdlc_lite
5 ------------
6 `High-Level Data Link Control (HDLC)
7 <https://en.wikipedia.org/wiki/High-Level_Data_Link_Control>`_ is a data link
8 layer protocol intended for serial communication between devices. HDLC is
9 standardized as `ISO/IEC 13239:2002 <https://www.iso.org/standard/37010.html>`_.
10
11 The ``pw_hdlc_lite`` module provides a simple, robust frame-oriented
12 transport that uses a subset of the HDLC protocol. ``pw_hdlc_lite`` supports
13 sending between embedded devices or the host. It can be used with
14 :ref:`module-pw_rpc` to enable remote procedure calls (RPCs) on embedded on
15 devices.
16
17 **Why use the pw_hdlc_lite module?**
18
19   * Enables the transmission of RPCs and other data between devices over serial.
20   * Detects corruption and data loss.
21   * Light-weight, simple, and easy to use.
22   * Supports streaming to transport without buffering, since the length is not
23     encoded.
24
25 .. admonition:: Try it out!
26
27   For an example of how to use HDLC with :ref:`module-pw_rpc`, see the
28   :ref:`module-pw_hdlc_lite-rpc-example`.
29
30 .. toctree::
31   :maxdepth: 1
32   :hidden:
33
34   rpc_example/docs
35
36 Protocol Description
37 ====================
38
39 Frames
40 ------
41 The HDLC implementation in ``pw_hdlc_lite`` supports only HDLC information
42 frames. These frames are encoded as follows:
43
44 .. code-block:: text
45
46     _________________________________________
47     | | | |                          |    | |...
48     | | | |                          |    | |... [More frames]
49     |_|_|_|__________________________|____|_|...
50      F A C       Payload              FCS  F
51
52      F = flag byte (0x7e, the ~ character)
53      A = address field
54      C = control field
55      FCS = frame check sequence (CRC-32)
56
57
58 Encoding and sending data
59 -------------------------
60 This module first writes an initial frame delimiter byte (0x7E) to indicate the
61 beginning of the frame. Before sending any of the payload data through serial,
62 the special bytes are escaped:
63
64             +-------------------------+-----------------------+
65             | Unescaped Special Bytes | Escaped Special Bytes |
66             +=========================+=======================+
67             |           7E            |        7D 5E          |
68             +-------------------------+-----------------------+
69             |           7D            |        7D 5D          |
70             +-------------------------+-----------------------+
71
72 The bytes of the payload are escaped and written in a single pass. The
73 frame check sequence is calculated, escaped, and written after. After this, a
74 final frame delimiter byte (0x7E) is written to mark the end of the frame.
75
76 Decoding received bytes
77 -----------------------
78 Frames may be received in multiple parts, so we need to store the received data
79 in a buffer until the ending frame delimiter (0x7E) is read. When the
80 ``pw_hdlc_lite`` decoder receives data, it unescapes it and adds it to a buffer.
81 When the frame is complete, it calculates and verifies the frame check sequence
82 and does the following:
83
84 * If correctly verified, the decoder returns the decoded frame.
85 * If the checksum verification fails, the frame is discarded and an error is
86   reported.
87
88 API Usage
89 =========
90 There are two primary functions of the ``pw_hdlc_lite`` module:
91
92   * **Encoding** data by constructing a frame with the escaped payload bytes and
93     frame check sequence.
94   * **Decoding** data by unescaping the received bytes, verifying the frame
95     check sequence, and returning successfully decoded frames.
96
97 Encoder
98 -------
99 The Encoder API provides a single function that encodes data as an HDLC
100 information frame.
101
102 C++
103 ^^^
104 .. cpp:namespace:: pw
105
106 .. cpp:function:: Status hdlc_lite::WriteInformationFrame(uint8_t address, ConstByteSpan data, stream::Writer& writer)
107
108   Writes a span of data to a :ref:`pw::stream::Writer <module-pw_stream>` and
109   returns the status. This implementation uses the :ref:`module-pw_checksum`
110   module to compute the CRC-32 frame check sequence.
111
112 .. code-block:: cpp
113
114   #include "pw_hdlc_lite/encoder.h"
115   #include "pw_hdlc_lite/sys_io_stream.h"
116
117   int main() {
118     pw::stream::SysIoWriter serial_writer;
119     Status status = WriteInformationFrame(123 /* address */,
120                                           data,
121                                           serial_writer);
122     if (!status.ok()) {
123       PW_LOG_INFO("Writing frame failed! %s", status.str());
124     }
125   }
126
127 Python
128 ^^^^^^
129 .. automodule:: pw_hdlc_lite.encode
130   :members:
131
132 .. code-block:: python
133
134   import serial
135   from pw_hdlc_lite import encode
136
137   ser = serial.Serial()
138   ser.write(encode.information_frame(b'your data here!'))
139
140 Decoder
141 -------
142 The decoder class unescapes received bytes and adds them to a buffer. Complete,
143 valid HDLC frames are yielded as they are received.
144
145 C++
146 ^^^
147 .. cpp:class:: pw::hdlc_lite::Decoder
148
149   .. cpp:function:: pw::Result<Frame> Process(std::byte b)
150
151     Parses a single byte of an HDLC stream. Returns a Result with the complete
152     frame if the byte completes a frame. The status is the following:
153
154       - OK - A frame was successfully decoded. The Result contains the Frame,
155         which is invalidated by the next Process call.
156       - UNAVAILABLE - No frame is available.
157       - RESOURCE_EXHAUSTED - A frame completed, but it was too large to fit in
158         the decoder's buffer.
159       - DATA_LOSS - A frame completed, but it was invalid. The frame was
160         incomplete or the frame check sequence verification failed.
161
162   .. cpp:function:: void Process(pw::ConstByteSpan data, F&& callback, Args&&... args)
163
164     Processes a span of data and calls the provided callback with each frame or
165     error.
166
167 This example demonstrates reading individual bytes from ``pw::sys_io`` and
168 decoding HDLC frames:
169
170 .. code-block:: cpp
171
172   #include "pw_hdlc_lite/decoder.h"
173   #include "pw_sys_io/sys_io.h"
174
175   int main() {
176     std::byte data;
177     while (true) {
178       if (!pw::sys_io::ReadByte(&data).ok()) {
179         // Log serial reading error
180       }
181       Result<Frame> decoded_frame = decoder.Process(data);
182
183       if (decoded_frame.ok()) {
184         // Handle the decoded frame
185       }
186     }
187   }
188
189 Python
190 ^^^^^^
191 .. autoclass:: pw_hdlc_lite.decode.FrameDecoder
192   :members:
193
194 Below is an example using the decoder class to decode data read from serial:
195
196 .. code-block:: python
197
198   import serial
199   from pw_hdlc_lite import decode
200
201   ser = serial.Serial()
202   decoder = decode.FrameDecoder()
203
204   while True:
205       for frame in decoder.process_valid_frames(ser.read()):
206           # Handle the decoded frame
207
208 Additional features
209 ===================
210
211 pw::stream::SysIoWriter
212 ------------------------
213 The ``SysIoWriter`` C++ class implements the ``Writer`` interface with
214 ``pw::sys_io``. This Writer may be used by the C++ encoder to send HDLC frames
215 over serial.
216
217 HdlcRpcClient
218 -------------
219 .. autoclass:: pw_hdlc_lite.rpc.HdlcRpcClient
220   :members:
221
222 Roadmap
223 =======
224 - **Expanded protocol support** - ``pw_hdlc_lite`` currently only supports
225   information frames with a single address byte and control byte. Support for
226   different frame types and extended address or control fields may be added in
227   the future.
228
229 - **Higher performance** - We plan to improve the overall performance of the
230   decoder and encoder implementations by using SIMD/NEON.
231
232 Compatibility
233 =============
234 C++17