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