blob: dc633b5e6cb7bc1ce2320f2929875cface6a752e [file] [log] [blame]
.. _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/
<https://cs.opensource.google/pigweed/pigweed/+/main: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/<toolchain>/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 <http://openocd.org>`_.
.. 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
<https://github.com/python/cpython/issues/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-raspberry-pi-pico`
- :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