xref: /aosp_15_r20/external/pigweed/pw_hdlc/api.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_hdlc-api:
2
3=============
4API reference
5=============
6.. pigweed-module-subpage::
7   :name: pw_hdlc
8
9The ``pw_hdlc`` API has 3 conceptual parts:
10
11* :ref:`module-pw_hdlc-api-encoder`: Encode data as HDLC unnumbered
12  information frames.
13* :ref:`module-pw_hdlc-api-decoder`: Decode HDLC frames from a stream of data.
14* :ref:`module-pw_hdlc-api-rpc`: Use RPC over HDLC.
15
16.. _module-pw_hdlc-api-encoder:
17
18-------
19Encoder
20-------
21
22Single-Function Encoding
23========================
24Pigweed offers a single function which will encode an HDLC frame in each of
25C++, Python, and TypeScript:
26
27.. tab-set::
28
29   .. tab-item:: C++
30      :sync: cpp
31
32      .. doxygenfunction:: pw::hdlc::WriteUIFrame(uint64_t address, ConstByteSpan data, stream::Writer &writer)
33
34      Example:
35
36      .. code-block:: cpp
37
38         // Writes a span of data to a pw::stream::Writer and returns the status. This
39         // implementation uses the pw_checksum module to compute the CRC-32 frame check
40         // sequence.
41
42         #include "pw_hdlc/encoder.h"
43         #include "pw_hdlc/sys_io_stream.h"
44
45         int main() {
46           pw::stream::SysIoWriter serial_writer;
47           Status status = WriteUIFrame(123 /* address */, data, serial_writer);
48           if (!status.ok()) {
49             PW_LOG_INFO("Writing frame failed! %s", status.str());
50           }
51         }
52
53   .. tab-item:: Python
54      :sync: py
55
56      .. automodule:: pw_hdlc.encode
57         :members:
58         :noindex:
59
60      Example:
61
62      .. code-block:: python
63
64         # Read bytes from serial and encode HDLC frames
65
66         import serial
67         from pw_hdlc import encode
68
69         ser = serial.Serial()
70         address = 123
71         ser.write(encode.ui_frame(address, b'your data here!'))
72
73   .. tab-item:: TypeScript
74      :sync: ts
75
76      ``Encoder`` provides a way to build complete, escaped HDLC unnumbered
77      information frames.
78
79      .. js:method:: Encoder.uiFrame(address, data)
80         :noindex:
81
82         :param number address: frame address.
83         :param Uint8Array data: frame data.
84         :returns: ``Uint8Array`` containing a complete HDLC frame.
85
86Piecemeal Encoding
87==================
88
89Additionally, the C++ API provides an API for piecemeal encoding of an HDLC
90frame. This allows frames to be encoded gradually without ever holding an
91entire frame in memory at once.
92
93.. doxygenclass:: pw::hdlc::Encoder
94
95.. _module-pw_hdlc-api-decoder:
96
97-------
98Decoder
99-------
100.. tab-set::
101
102   .. tab-item:: C++
103      :sync: cpp
104
105      .. doxygenclass:: pw::hdlc::Decoder
106         :members:
107
108      Example:
109
110      .. code-block:: cpp
111
112         // Read individual bytes from pw::sys_io and decode HDLC frames.
113
114         #include "pw_hdlc/decoder.h"
115         #include "pw_sys_io/sys_io.h"
116
117         int main() {
118           std::byte data;
119           while (true) {
120             if (!pw::sys_io::ReadByte(&data).ok()) {
121               // Log serial reading error
122             }
123             Result<Frame> decoded_frame = decoder.Process(data);
124
125             if (decoded_frame.ok()) {
126               // Handle the decoded frame
127             }
128           }
129         }
130
131   .. tab-item:: Python
132      :sync: py
133
134      .. autoclass:: pw_hdlc.decode.FrameDecoder
135         :members:
136         :noindex:
137
138      Example:
139
140      .. code-block:: python
141
142         # Decode data read from serial
143
144         import serial
145         from pw_hdlc import decode
146
147         ser = serial.Serial()
148         decoder = decode.FrameDecoder()
149
150         while True:
151             for frame in decoder.process_valid_frames(ser.read()):
152                 # Handle the decoded frame
153
154      It is possible to decode HDLC frames from a stream using different protocols or
155      unstructured data. This is not recommended, but may be necessary when
156      introducing HDLC to an existing system.
157
158      The ``FrameAndNonFrameDecoder`` Python class supports working with raw data and
159      HDLC frames in the same stream.
160
161      .. autoclass:: pw_hdlc.decode.FrameAndNonFrameDecoder
162        :members:
163        :noindex:
164
165   .. tab-item:: TypeScript
166      :sync: ts
167
168      ``Decoder`` unescapes received bytes and adds them to a buffer. Complete,
169      valid HDLC frames are yielded as they are received.
170
171      .. js:method:: Decoder.process(data)
172         :noindex:
173
174         :param Uint8Array data: bytes to be decoded.
175         :yields: HDLC frames, including corrupt frames.
176                  The ``Frame.ok()`` method whether the frame is valid.
177
178      .. js:method:: processValidFrames(data)
179         :noindex:
180
181         :param Uint8Array data: bytes to be decoded.
182         :yields: Valid HDLC frames, logging any errors.
183
184.. _module-pw_hdlc-api-rpc:
185
186---
187RPC
188---
189
190.. tab-set::
191
192   .. tab-item:: C++
193      :sync: cpp
194
195      ``RpcChannelOutput`` implements the ``pw::rpc::ChannelOutput`` interface
196      of ``pw_rpc``, simplifying the process of creating an RPC channel over HDLC.
197      A ``pw::stream::Writer`` must be provided as the underlying transport
198      implementation.
199
200      If your HDLC routing path has a Maximum Transmission Unit (MTU) limitation,
201      use the ``FixedMtuChannelOutput`` to verify that the currently configured
202      max RPC payload size (dictated by the static encode buffer of ``pw_rpc``)
203      will always fit safely within the limits of the fixed HDLC MTU *after*
204      HDLC encoding.
205
206   .. tab-item:: Python
207      :sync: py
208
209      The ``pw_hdlc`` Python package includes utilities to HDLC-encode and
210      decode RPC packets, with examples of RPC client implementations in Python.
211      It also provides abstractions for interfaces used to receive RPC Packets.
212
213      The ``pw_hdlc.rpc.CancellableReader`` and ``pw_hdlc.rpc.RpcClient``
214      classes and derived classes are context-managed to cleanly cancel the
215      read process and stop the reader thread. The ``pw_hdlc.rpc.SocketReader``
216      and ``pw_hdlc.rpc.SerialReader`` also close the provided interface on
217      context exit. It is recommended to use these in a context statement. For
218      example:
219
220      .. code-block:: python
221
222         import serial
223         from pw_hdlc import rpc
224         from pw_rpc import client_utils
225
226         if __name__ == '__main__':
227             serial_device = serial.Serial('/dev/ttyACM0')
228             with client_utils.SerialReader(serial_device) as reader:
229                 with rpc.HdlcRpcClient(
230                     reader,
231                     [],
232                     rpc.default_channels(serial_device.write)) as rpc_client:
233                     # Do something with rpc_client.
234
235             # The serial_device object is closed, and reader thread stopped.
236             return 0
237
238      .. autoclass:: pw_hdlc.rpc.channel_output
239         :members:
240         :noindex:
241
242      .. autoclass:: pw_hdlc.rpc.default_channels
243         :members:
244         :noindex:
245
246      .. autoclass:: pw_hdlc.rpc.HdlcRpcClient
247         :members:
248         :noindex:
249
250      .. autoclass:: pw_hdlc.rpc.HdlcRpcLocalServerAndClient
251         :members:
252         :noindex:
253
254   .. tab-item:: TypeScript
255      :sync: ts
256
257      The TypeScript library doesn't have an RPC interface.
258
259-----------------
260More pw_hdlc docs
261-----------------
262.. include:: docs.rst
263   :start-after: .. pw_hdlc-nav-start
264   :end-before: .. pw_hdlc-nav-end
265