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