1.. _module-pw_hdlc-rpc-example: 2 3===================== 4RPC over HDLC example 5===================== 6.. pigweed-module-subpage:: 7 :name: pw_hdlc 8 9The :ref:`module-pw_hdlc` module includes an example of bringing up a 10:ref:`module-pw_rpc` server that can be used to invoke RPCs. The example code 11is located at `//pw_hdlc/rpc_example/ 12<https://cs.opensource.google/pigweed/pigweed/+/main:pw_hdlc/rpc_example/>`_. 13This tutorial walks through invoking RPCs interactively and with a script using 14the RPC over HDLC example. 15 16The example implementation of the ``system_server`` facade from ``pw_rpc`` 17sends HDLC-encoded RPC packets via ``pw_sys_io``. It has blocking sends and 18reads so it is not suitable for performance-sensitive applications. This 19mostly serves as a simplistic example for quickly bringing up RPC over HDLC 20on bare-metal targets. 21 22.. note:: 23 24 This tutorial assumes that you've got a :ref:`target-stm32f429i-disc1` 25 board, but the instructions work with any target that has implemented 26 :ref:`module-pw_sys_io`. 27 28----------- 29Get started 30----------- 31 321. Set up your board 33==================== 34Connect the board you'll be communicating with. For the 35:ref:`target-stm32f429i-disc1` board, connect the mini USB port, and note which 36serial device it appears as (e.g. ``/dev/ttyACM0``). 37 382. Build Pigweed 39================ 40Activate the Pigweed environment and run the default build. 41 42.. code-block:: console 43 44 . ./activate.sh 45 pw package install nanopb 46 gn gen out --args='dir_pw_third_party_nanopb="//environment/packages/nanopb"' 47 ninja -C out 48 493. Flash the firmware image 50=========================== 51After a successful build, the binary for the example will be located at 52``//out/<toolchain>/obj/pw_hdlc/rpc_example/bin/rpc_example.elf``. 53 54Flash this image to your board. If you are using the 55:ref:`target-stm32f429i-disc1` board you can flash the image with 56`OpenOCD <http://openocd.org>`_. 57 58.. code-block:: console 59 60 openocd -f \ 61 targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/openocd_stm32f4xx.cfg \ 62 -c "program \ 63 out/stm32f429i_disc1_debug/obj/pw_hdlc/rpc_example/bin/rpc_example.elf \ 64 verify reset exit" 65 664. Invoke RPCs from an interactive console 67========================================== 68The RPC console uses :ref:`module-pw_console` to make a rich interactive 69console for working with ``pw_rpc``. Run the RPC console with the following 70command, replacing ``/dev/ttyACM0`` with the correct serial device for your 71board. 72 73.. code-block:: console 74 75 pw-system-console --no-rpc-logging --proto-globs pw_rpc/echo.proto \ 76 --device /dev/ttyACM0 77 78RPCs may be accessed through the predefined ``rpcs`` variable. RPCs are 79organized by their protocol buffer package and RPC service, as defined in a 80.proto file. The ``Echo`` method is part of the ``EchoService``, which 81is in the ``pw.rpc`` package. To invoke it synchronously, call 82``rpcs.pw.rpc.EchoService.Echo()``: 83 84.. code-block:: pycon 85 86 >>> device.rpcs.pw.rpc.EchoService.Echo(msg='Hello, world!') 87 (Status.OK, pw.rpc.EchoMessage(msg='Hello, world!')) 88 895. Invoke RPCs with a script 90============================ 91RPCs may also be invoked from Python scripts. Close the RPC console if it is 92running, and execute the example script. Set the ``--device`` argument to the 93serial port for your device. 94 95.. code-block:: console 96 97 python pw_hdlc/rpc_example/example_script.py --device /dev/ttyACM0 98 99You should see this output: 100 101.. code-block:: text 102 103 The status was Status.OK 104 The payload was msg: "Hello" 105 106 The device says: Goodbye! 107 108------------------------- 109Local RPC example project 110------------------------- 111This example is similar to the above example, except it uses a socket to 112connect a server to a client, both running on the host. 113 1141. Build Pigweed 115================ 116Activate the Pigweed environment and build the code. 117 118.. code-block:: console 119 120 . ./activate.sh 121 pw package install nanopb 122 gn gen out --args='dir_pw_third_party_nanopb="//environment/packages/nanopb"' 123 ninja -C out 124 1252. Start the server 126=================== 127Run a ``pw_rpc`` server in one terminal window. 128 129.. code-block:: console 130 131 ./out/pw_strict_host_clang_debug/obj/pw_hdlc/rpc_example/bin/rpc_example 132 1333. Start the client 134=================== 135In a separate Pigweed-activated terminal, run the ``pw-system-console`` RPC 136client with ``--proto-globs`` set to ``pw_rpc/echo.proto``. Additional protos 137can be added if needed. 138 139.. code-block:: console 140 141 pw-system-console --no-rpc-logging --proto-globs pw_rpc/echo.proto \ 142 --socket-addr default 143 144.. tip:: 145 146 The ``--socket-addr`` value may be replaced with an IP and port separated by 147 a colon, e.g. ``127.0.0.1:33000``. If using a Unix socket, the path to the 148 file follows ``file:``, e.g. ``file:/path/to/unix/socket``. Unix socket 149 Python support is pending, see `python/cpython#77589 150 <https://github.com/python/cpython/issues/77589>`_. 151 152.. tip:: 153 154 The default RPC channel ID (``1``) can be overriden with ``--channel-id``. 155 1564. Invoke RPCs from the client 157============================== 158Invoke RPCs from the interactive console on the client side. 159 160.. code-block:: pycon 161 162 >>> device.rpcs.pw.rpc.EchoService.Echo(msg='Hello, world!') 163 (Status.OK, pw.rpc.EchoMessage(msg='Hello, world!')) 164 165.. seealso:: 166 167 - The :ref:`module-pw_console` 168 :bdg-ref-primary-line:`module-pw_console-user_guide` for more info on using 169 the the pw_console UI. 170 171 - The target docs for other RPC-enabled application examples: 172 173 - :bdg-ref-primary-line:`target-host-device-simulator` 174 - :bdg-ref-primary-line:`target-rp2040` 175 - :bdg-ref-primary-line:`target-stm32f429i-disc1-stm32cube` 176 177----------------- 178More pw_hdlc docs 179----------------- 180.. include:: ../docs.rst 181 :start-after: .. pw_hdlc-nav-start 182 :end-before: .. pw_hdlc-nav-end 183