pw_rpc#
Efficient, low-code-size RPC system for embedded devices
Stable C++ Java JavaScript Python TypeScript
pw_rpc provides an embedded-friendly remote procedure call (RPC) system for
defining and invoking structured methods over arbitrary serial, bus, or packet
transports (UART, SPI, USB, BLE, Sockets). Services and messages are defined in
shared Protocol Buffer (.proto) files.
pw_rpc supports C++ (with Nanopb, pw_protobuf, or Raw RPC codegen), Python,
TypeScript, and Java.
syntax = "proto3";
package blinky;
import "pw_protobuf_protos/common.proto";
service Blinky {
// Toggles the LED on or off.
rpc ToggleLed(pw.protobuf.Empty) returns (pw.protobuf.Empty);
// Continuously blinks the board LED a specified number of times.
rpc Blink(BlinkRequest) returns (pw.protobuf.Empty);
}
message BlinkRequest {
// The interval at which to blink the LED, in milliseconds.
uint32 interval_ms = 1;
// The number of times to blink the LED.
optional uint32 blink_count = 2;
}
#include "pw_rpc/examples/blinky.rpc.pb.h"
#include "pw_system/rpc_server.h"
namespace blinky {
class BlinkyService final
: public blinky::pw_rpc::nanopb::Blinky::Service<BlinkyService> {
public:
pw::Status ToggleLed(const pw_protobuf_Empty&, pw_protobuf_Empty&) {
// Turn the LED off if it's currently on and vice versa
return pw::OkStatus();
}
pw::Status Blink(const blinky_BlinkRequest& request, pw_protobuf_Empty&) {
if (request.blink_count == 0) {
// Stop blinking
}
if (request.interval_ms > 0) {
// Change the blink interval
}
if (request.has_blink_count) {
// Blink request.blink_count times
}
return pw::OkStatus();
}
};
BlinkyService blinky_service;
} // namespace blinky
namespace pw::system {
void UserAppInit() {
pw::system::GetRpcServer().RegisterService(blinky::blinky_service);
}
} // namespace pw::system
proto_library(
name = "blinky_proto",
srcs = ["blinky.proto"],
deps = [
"//pw_protobuf:common_proto",
],
)
nanopb_proto_library(
name = "blinky_nanopb",
deps = [":blinky_proto"],
)
nanopb_rpc_proto_library(
name = "blinky_nanopb_rpc",
nanopb_proto_library_deps = [":blinky_nanopb"],
deps = [":blinky_proto"],
)
cc_library(
name = "blinky_service",
srcs = ["blinky_service.cc"],
deps = [
":blinky_nanopb_rpc",
"//pw_system:rpc_server",
],
)
Where to go next#
For Platform Engineers & System Architects.
Step-by-step checklist to bring up pw_rpc on target hardware:
transports, channels, RX/TX plumbing, and dispatch loops.
For Application Developers.
How to define .proto services, generate C++ code, implement unary
and streaming methods, and write unit tests.
Core C++ runtime mechanics: channels, call objects, synchronous call wrappers, concurrency rules, and test fixtures.
Lightweight C struct message generator (recommended for embedded C++).
Type-safe pure C++ message generator.
Zero-copy byte buffer RPCs and method fallback mechanics.
Python client library, custom channels, and pw_console tools.
WebSerial, WebUSB, and browser/Node.js client library.
Android and JVM client library in dev.pigweed.pw_rpc.
Tools for measuring throughput, latency, and fuzzer testing.
Packet wire format and envelope protocol specification.