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