• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
225         if __name__ == '__main__':
226             serial_device = serial.Serial('/dev/ttyACM0')
227             with rpc.SerialReader(serial_device) as reader:
228                 with rpc.HdlcRpcClient(
229                     reader,
230                     [],
231                     rpc.default_channels(serial_device.write)) as rpc_client:
232                     # Do something with rpc_client.
233
234             # The serial_device object is closed, and reader thread stopped.
235             return 0
236
237      .. autoclass:: pw_hdlc.rpc.channel_output
238         :members:
239         :noindex:
240
241      .. autoclass:: pw_hdlc.rpc.CancellableReader
242         :members:
243         :noindex:
244
245      .. autoclass:: pw_hdlc.rpc.SelectableReader
246         :members:
247         :noindex:
248
249      .. autoclass:: pw_hdlc.rpc.SocketReader
250         :members:
251         :noindex:
252
253      .. autoclass:: pw_hdlc.rpc.SerialReader
254         :members:
255         :noindex:
256
257      .. autoclass:: pw_hdlc.rpc.DataReaderAndExecutor
258         :members:
259         :noindex:
260
261      .. autoclass:: pw_hdlc.rpc.default_channels
262         :members:
263         :noindex:
264
265      .. autoclass:: pw_hdlc.rpc.RpcClient
266         :members:
267         :noindex:
268
269      .. autoclass:: pw_hdlc.rpc.HdlcRpcClient
270         :members:
271         :noindex:
272
273      .. autoclass:: pw_hdlc.rpc.NoEncodingSingleChannelRpcClient
274         :members:
275         :noindex:
276
277      .. autoclass:: pw_hdlc.rpc.SocketSubprocess
278         :members:
279         :noindex:
280
281      .. autoclass:: pw_hdlc.rpc.HdlcRpcLocalServerAndClient
282         :members:
283         :noindex:
284
285   .. tab-item:: TypeScript
286      :sync: ts
287
288      The TypeScript library doesn't have an RPC interface.
289
290-----------------
291More pw_hdlc docs
292-----------------
293.. include:: docs.rst
294   :start-after: .. pw_hdlc-nav-start
295   :end-before: .. pw_hdlc-nav-end
296