.. _module-pw_hdlc-rpc-example: ===================== RPC over HDLC example ===================== .. pigweed-module-subpage:: :name: pw_hdlc The :ref:`module-pw_hdlc` module includes an example of bringing up a :ref:`module-pw_rpc` server that can be used to invoke RPCs. The example code is located at `//pw_hdlc/rpc_example/ `_. This tutorial walks through invoking RPCs interactively and with a script using the RPC over HDLC example. The example implementation of the ``system_server`` facade from ``pw_rpc`` sends HDLC-encoded RPC packets via ``pw_sys_io``. It has blocking sends and reads so it is not suitable for performance-sensitive applications. This mostly serves as a simplistic example for quickly bringing up RPC over HDLC on bare-metal targets. .. note:: This tutorial assumes that you've got a :ref:`target-stm32f429i-disc1` board, but the instructions work with any target that has implemented :ref:`module-pw_sys_io`. ----------- Get started ----------- 1. Set up your board ==================== Connect the board you'll be communicating with. For the :ref:`target-stm32f429i-disc1` board, connect the mini USB port, and note which serial device it appears as (e.g. ``/dev/ttyACM0``). 2. Build Pigweed ================ Activate the Pigweed environment and run the default build. .. code-block:: console . ./activate.sh pw package install nanopb gn gen out --args='dir_pw_third_party_nanopb="//environment/packages/nanopb"' ninja -C out 3. Flash the firmware image =========================== After a successful build, the binary for the example will be located at ``//out//obj/pw_hdlc/rpc_example/bin/rpc_example.elf``. Flash this image to your board. If you are using the :ref:`target-stm32f429i-disc1` board you can flash the image with `OpenOCD `_. .. code-block:: console openocd -f \ targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/openocd_stm32f4xx.cfg \ -c "program \ out/stm32f429i_disc1_debug/obj/pw_hdlc/rpc_example/bin/rpc_example.elf \ verify reset exit" 4. Invoke RPCs from an interactive console ========================================== The RPC console uses :ref:`module-pw_console` to make a rich interactive console for working with ``pw_rpc``. Run the RPC console with the following command, replacing ``/dev/ttyACM0`` with the correct serial device for your board. .. code-block:: console pw-system-console --no-rpc-logging --proto-globs pw_rpc/echo.proto \ --device /dev/ttyACM0 RPCs may be accessed through the predefined ``rpcs`` variable. RPCs are organized by their protocol buffer package and RPC service, as defined in a .proto file. The ``Echo`` method is part of the ``EchoService``, which is in the ``pw.rpc`` package. To invoke it synchronously, call ``rpcs.pw.rpc.EchoService.Echo()``: .. code-block:: pycon >>> device.rpcs.pw.rpc.EchoService.Echo(msg='Hello, world!') (Status.OK, pw.rpc.EchoMessage(msg='Hello, world!')) 5. Invoke RPCs with a script ============================ RPCs may also be invoked from Python scripts. Close the RPC console if it is running, and execute the example script. Set the ``--device`` argument to the serial port for your device. .. code-block:: console python pw_hdlc/rpc_example/example_script.py --device /dev/ttyACM0 You should see this output: .. code-block:: text The status was Status.OK The payload was msg: "Hello" The device says: Goodbye! ------------------------- Local RPC example project ------------------------- This example is similar to the above example, except it uses a socket to connect a server to a client, both running on the host. 1. Build Pigweed ================ Activate the Pigweed environment and build the code. .. code-block:: console . ./activate.sh pw package install nanopb gn gen out --args='dir_pw_third_party_nanopb="//environment/packages/nanopb"' ninja -C out 2. Start the server =================== Run a ``pw_rpc`` server in one terminal window. .. code-block:: console ./out/pw_strict_host_clang_debug/obj/pw_hdlc/rpc_example/bin/rpc_example 3. Start the client =================== In a separate Pigweed-activated terminal, run the ``pw-system-console`` RPC client with ``--proto-globs`` set to ``pw_rpc/echo.proto``. Additional protos can be added if needed. .. code-block:: console pw-system-console --no-rpc-logging --proto-globs pw_rpc/echo.proto \ --socket-addr default .. tip:: The ``--socket-addr`` value may be replaced with an IP and port separated by a colon, e.g. ``127.0.0.1:33000``. If using a Unix socket, the path to the file follows ``file:``, e.g. ``file:/path/to/unix/socket``. Unix socket Python support is pending, see `python/cpython#77589 `_. .. tip:: The default RPC channel ID (``1``) can be overriden with ``--channel-id``. 4. Invoke RPCs from the client ============================== Invoke RPCs from the interactive console on the client side. .. code-block:: pycon >>> device.rpcs.pw.rpc.EchoService.Echo(msg='Hello, world!') (Status.OK, pw.rpc.EchoMessage(msg='Hello, world!')) .. seealso:: - The :ref:`module-pw_console` :bdg-ref-primary-line:`module-pw_console-user_guide` for more info on using the the pw_console UI. - The target docs for other RPC-enabled application examples: - :bdg-ref-primary-line:`target-host-device-simulator` - :bdg-ref-primary-line:`target-rp2040` - :bdg-ref-primary-line:`target-stm32f429i-disc1-stm32cube` ----------------- More pw_hdlc docs ----------------- .. include:: ../docs.rst :start-after: .. pw_hdlc-nav-start :end-before: .. pw_hdlc-nav-end