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