RPC over HDLC example#
pw_hdlc: Simple, robust, and efficient serial communication
The pw_hdlc module includes an example of bringing up a 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 stm32f429i-disc1 board, but the instructions work with any target that has implemented pw_sys_io.
Get started#
1. Set up your board#
Connect the board you’ll be communicating with. For the
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.
. ./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 stm32f429i-disc1 board you can flash the image with OpenOCD.
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 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.
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()
:
>>> 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.
python pw_hdlc/rpc_example/example_script.py --device /dev/ttyACM0
You should see this output:
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.
. ./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.
./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.
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.
>>> device.rpcs.pw.rpc.EchoService.Echo(msg='Hello, world!')
(Status.OK, pw.rpc.EchoMessage(msg='Hello, world!'))
See also
The pw_console User Guide for more info on using the the pw_console UI.
The target docs for other RPC-enabled application examples: