blob: 5b466719d1b06114eb0552a82bd6897ebd3d84f7 [file] [log] [blame]
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -07001.. _module-pw_rpc:
Alexei Frolov26e3ae62020-05-04 17:06:17 -07002
3------
4pw_rpc
5------
6The ``pw_rpc`` module provides a system for defining and invoking remote
7procedure calls (RPCs) on a device.
8
Wyatt Hepler830d26d2021-02-17 09:07:43 -08009This document discusses the ``pw_rpc`` protocol and its C++ implementation.
10``pw_rpc`` implementations for other languages are described in their own
11documents:
12
13.. toctree::
14 :maxdepth: 1
15
16 py/docs
Jared Weinsteind4649112021-08-19 12:27:23 -070017 ts/docs
Wyatt Hepler830d26d2021-02-17 09:07:43 -080018
Wyatt Hepler455b4922020-09-18 00:19:21 -070019.. admonition:: Try it out!
20
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -070021 For a quick intro to ``pw_rpc``, see the
Alexei Frolovd3e5cb72021-01-08 13:08:45 -080022 :ref:`module-pw_hdlc-rpc-example` in the :ref:`module-pw_hdlc` module.
Wyatt Hepler455b4922020-09-18 00:19:21 -070023
Wyatt Hepler067dd7e2020-07-14 19:34:32 -070024.. attention::
Alexei Frolov26e3ae62020-05-04 17:06:17 -070025
Wyatt Hepler455b4922020-09-18 00:19:21 -070026 This documentation is under construction.
27
Wyatt Hepler3b4f89a2021-12-06 16:18:53 -080028Implementations
29===============
30Pigweed provides several client and server implementations of ``pw_rpc``.
31
32.. list-table::
33 :header-rows: 1
34
35 * - Language
36 - Server
37 - Client
38 * - C++ (raw)
39 - ✅
40 - ✅
41 * - C++ (Nanopb)
42 - ✅
43 - ✅
44 * - C++ (pw_protobuf)
45 - planned
46 - planned
47 * - Java
48 -
49 - in development
50 * - Python
51 -
52 - ✅
53 * - TypeScript
54 -
55 - in development
56
Wyatt Hepler85e91402021-08-05 12:48:03 -070057RPC semantics
58=============
59The semantics of ``pw_rpc`` are similar to `gRPC
60<https://grpc.io/docs/what-is-grpc/core-concepts/>`_.
61
62RPC call lifecycle
63------------------
64In ``pw_rpc``, an RPC begins when the client sends a request packet. The server
65receives the request, looks up the relevant service method, then calls into the
66RPC function. The RPC is considered active until the server sends a response
67packet with the RPC's status. The client may terminate an ongoing RPC by
68cancelling it.
69
70``pw_rpc`` supports only one RPC invocation per service/method/channel. If a
71client calls an ongoing RPC on the same channel, the server cancels the ongoing
72call and reinvokes the RPC with the new request. This applies to unary and
73streaming RPCs, though the server may not have an opportunity to cancel a
74synchronously handled unary RPC before it completes. The same RPC may be invoked
75multiple times simultaneously if the invocations are on different channels.
76
Wyatt Hepler5a3a36b2021-09-08 11:15:05 -070077Unrequested responses
78---------------------
79``pw_rpc`` supports sending responses to RPCs that have not yet been invoked by
80a client. This is useful in testing and in situations like an RPC that triggers
81reboot. After the reboot, the device opens the writer object and sends its
82response to the client.
83
Wyatt Heplerd95e1e92021-09-14 22:10:51 -070084The C++ API for opening a server reader/writer takes the generated RPC function
85as a template parameter. The server to use, channel ID, and service instance are
86passed as arguments. The API is the same for all RPC types, except the
87appropriate reader/writer class must be used.
Wyatt Hepler5a3a36b2021-09-08 11:15:05 -070088
Wyatt Heplerd95e1e92021-09-14 22:10:51 -070089.. code-block:: c++
90
91 // Open a ServerWriter for a server streaming RPC.
92 auto writer = RawServerWriter::Open<pw_rpc::raw::ServiceName::MethodName>(
93 server, channel_id, service_instance);
94
95 // Send some responses, even though the client has not yet called this RPC.
96 CHECK_OK(writer.Write(encoded_response_1));
97 CHECK_OK(writer.Write(encoded_response_2));
98
99 // Finish the RPC.
100 CHECK_OK(writer.Finish(OkStatus()));
Wyatt Hepler5a3a36b2021-09-08 11:15:05 -0700101
Wyatt Hepler455b4922020-09-18 00:19:21 -0700102Creating an RPC
103===============
104
1051. RPC service declaration
106--------------------------
107Pigweed RPCs are declared in a protocol buffer service definition.
108
109* `Protocol Buffer service documentation
110 <https://developers.google.com/protocol-buffers/docs/proto3#services>`_
111* `gRPC service definition documentation
112 <https://grpc.io/docs/what-is-grpc/core-concepts/#service-definition>`_
113
114.. code-block:: protobuf
115
116 syntax = "proto3";
117
118 package foo.bar;
119
120 message Request {}
121
122 message Response {
123 int32 number = 1;
124 }
125
126 service TheService {
127 rpc MethodOne(Request) returns (Response) {}
128 rpc MethodTwo(Request) returns (stream Response) {}
129 }
130
131This protocol buffer is declared in a ``BUILD.gn`` file as follows:
132
133.. code-block:: python
134
135 import("//build_overrides/pigweed.gni")
136 import("$dir_pw_protobuf_compiler/proto.gni")
137
138 pw_proto_library("the_service_proto") {
139 sources = [ "foo_bar/the_service.proto" ]
140 }
141
Wyatt Hepler830d26d2021-02-17 09:07:43 -0800142.. admonition:: proto2 or proto3 syntax?
143
144 Always use proto3 syntax rather than proto2 for new protocol buffers. Proto2
145 protobufs can be compiled for ``pw_rpc``, but they are not as well supported
146 as proto3. Specifically, ``pw_rpc`` lacks support for non-zero default values
147 in proto2. When using Nanopb with ``pw_rpc``, proto2 response protobufs with
148 non-zero field defaults should be manually initialized to the default struct.
149
150 In the past, proto3 was sometimes avoided because it lacked support for field
151 presence detection. Fortunately, this has been fixed: proto3 now supports
152 ``optional`` fields, which are equivalent to proto2 ``optional`` fields.
153
154 If you need to distinguish between a default-valued field and a missing field,
155 mark the field as ``optional``. The presence of the field can be detected
156 with a ``HasField(name)`` or ``has_<field>`` member, depending on the library.
157
158 Optional fields have some overhead --- default-valued fields are included in
159 the encoded proto, and, if using Nanopb, the proto structs have a
160 ``has_<field>`` flag for each optional field. Use plain fields if field
161 presence detection is not needed.
162
163 .. code-block:: protobuf
164
165 syntax = "proto3";
166
167 message MyMessage {
168 // Leaving this field unset is equivalent to setting it to 0.
169 int32 number = 1;
170
171 // Setting this field to 0 is different from leaving it unset.
172 optional int32 other_number = 2;
173 }
174
Wyatt Hepler8779bcd2020-11-25 07:25:16 -08001752. RPC code generation
176----------------------
177``pw_rpc`` generates a C++ header file for each ``.proto`` file. This header is
178generated in the build output directory. Its exact location varies by build
179system and toolchain, but the C++ include path always matches the sources
180declaration in the ``pw_proto_library``. The ``.proto`` extension is replaced
181with an extension corresponding to the protobuf library in use.
Wyatt Hepler455b4922020-09-18 00:19:21 -0700182
Wyatt Hepler8779bcd2020-11-25 07:25:16 -0800183================== =============== =============== =============
184Protobuf libraries Build subtarget Protobuf header pw_rpc header
185================== =============== =============== =============
186Raw only .raw_rpc (none) .raw_rpc.pb.h
187Nanopb or raw .nanopb_rpc .pb.h .rpc.pb.h
188pw_protobuf or raw .pwpb_rpc .pwpb.h .rpc.pwpb.h
189================== =============== =============== =============
190
191For example, the generated RPC header for ``"foo_bar/the_service.proto"`` is
192``"foo_bar/the_service.rpc.pb.h"`` for Nanopb or
193``"foo_bar/the_service.raw_rpc.pb.h"`` for raw RPCs.
194
195The generated header defines a base class for each RPC service declared in the
196``.proto`` file. A service named ``TheService`` in package ``foo.bar`` would
Wyatt Heplerd2496322021-09-10 17:22:14 -0700197generate the following base class for Nanopb:
Wyatt Hepler455b4922020-09-18 00:19:21 -0700198
Wyatt Heplerd2496322021-09-10 17:22:14 -0700199.. cpp:class:: template <typename Implementation> foo::bar::pw_rpc::nanopb::TheService::Service
Wyatt Hepler455b4922020-09-18 00:19:21 -0700200
Wyatt Hepler8779bcd2020-11-25 07:25:16 -08002013. RPC service definition
202-------------------------
203The serivce class is implemented by inheriting from the generated RPC service
204base class and defining a method for each RPC. The methods must match the name
205and function signature for one of the supported protobuf implementations.
206Services may mix and match protobuf implementations within one service.
207
208.. tip::
209
210 The generated code includes RPC service implementation stubs. You can
211 reference or copy and paste these to get started with implementing a service.
212 These stub classes are generated at the bottom of the pw_rpc proto header.
213
Wyatt Heplerdf38ed12021-03-24 08:42:48 -0700214 To use the stubs, do the following:
215
216 #. Locate the generated RPC header in the build directory. For example:
217
218 .. code-block:: sh
219
220 find out/ -name <proto_name>.rpc.pb.h
221
222 #. Scroll to the bottom of the generated RPC header.
223 #. Copy the stub class declaration to a header file.
224 #. Copy the member function definitions to a source file.
225 #. Rename the class or change the namespace, if desired.
226 #. List these files in a build target with a dependency on the
227 ``pw_proto_library``.
228
Wyatt Hepler455b4922020-09-18 00:19:21 -0700229A Nanopb implementation of this service would be as follows:
230
231.. code-block:: cpp
232
Wyatt Hepler8779bcd2020-11-25 07:25:16 -0800233 #include "foo_bar/the_service.rpc.pb.h"
234
Wyatt Hepler455b4922020-09-18 00:19:21 -0700235 namespace foo::bar {
236
Wyatt Heplerd2496322021-09-10 17:22:14 -0700237 class TheService : public pw_rpc::nanopb::TheService::Service<TheService> {
Wyatt Hepler455b4922020-09-18 00:19:21 -0700238 public:
Wyatt Hepler8e756e32021-11-18 09:59:27 -0800239 pw::Status MethodOne(const foo_bar_Request& request,
Wyatt Hepler455b4922020-09-18 00:19:21 -0700240 foo_bar_Response& response) {
241 // implementation
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800242 return pw::OkStatus();
Wyatt Hepler455b4922020-09-18 00:19:21 -0700243 }
244
Wyatt Hepler8e756e32021-11-18 09:59:27 -0800245 void MethodTwo(const foo_bar_Request& request,
Wyatt Hepler455b4922020-09-18 00:19:21 -0700246 ServerWriter<foo_bar_Response>& response) {
247 // implementation
248 response.Write(foo_bar_Response{.number = 123});
249 }
250 };
251
252 } // namespace foo::bar
253
254The Nanopb implementation would be declared in a ``BUILD.gn``:
255
256.. code-block:: python
257
258 import("//build_overrides/pigweed.gni")
259
260 import("$dir_pw_build/target_types.gni")
261
262 pw_source_set("the_service") {
263 public_configs = [ ":public" ]
264 public = [ "public/foo_bar/service.h" ]
Wyatt Hepler8779bcd2020-11-25 07:25:16 -0800265 public_deps = [ ":the_service_proto.nanopb_rpc" ]
Wyatt Hepler455b4922020-09-18 00:19:21 -0700266 }
267
268.. attention::
269
270 pw_rpc's generated classes will support using ``pw_protobuf`` or raw buffers
271 (no protobuf library) in the future.
272
Wyatt Hepler8779bcd2020-11-25 07:25:16 -08002734. Register the service with a server
Wyatt Hepler455b4922020-09-18 00:19:21 -0700274-------------------------------------
Alexei Frolovd3e5cb72021-01-08 13:08:45 -0800275This example code sets up an RPC server with an :ref:`HDLC<module-pw_hdlc>`
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700276channel output and the example service.
Wyatt Hepler455b4922020-09-18 00:19:21 -0700277
278.. code-block:: cpp
279
280 // Set up the output channel for the pw_rpc server to use. This configures the
281 // pw_rpc server to use HDLC over UART; projects not using UART and HDLC must
282 // adapt this as necessary.
283 pw::stream::SysIoWriter writer;
284 pw::rpc::RpcChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
Alexei Frolovd3e5cb72021-01-08 13:08:45 -0800285 writer, pw::hdlc::kDefaultRpcAddress, "HDLC output");
Wyatt Hepler455b4922020-09-18 00:19:21 -0700286
287 pw::rpc::Channel channels[] = {
288 pw::rpc::Channel::Create<1>(&hdlc_channel_output)};
289
290 // Declare the pw_rpc server with the HDLC channel.
291 pw::rpc::Server server(channels);
292
293 pw::rpc::TheService the_service;
294
295 void RegisterServices() {
296 // Register the foo.bar.TheService example service.
297 server.Register(the_service);
298
299 // Register other services
300 }
301
302 int main() {
303 // Set up the server.
304 RegisterServices();
305
306 // Declare a buffer for decoding incoming HDLC frames.
307 std::array<std::byte, kMaxTransmissionUnit> input_buffer;
308
309 PW_LOG_INFO("Starting pw_rpc server");
Alexei Frolovd3e5cb72021-01-08 13:08:45 -0800310 pw::hdlc::ReadAndProcessPackets(
Wyatt Hepler455b4922020-09-18 00:19:21 -0700311 server, hdlc_channel_output, input_buffer);
312 }
Wyatt Hepler948f5472020-06-02 16:52:28 -0700313
Alexei Frolov1c670a22021-04-09 10:18:17 -0700314Channels
315========
316``pw_rpc`` sends all of its packets over channels. These are logical,
317application-layer routes used to tell the RPC system where a packet should go.
318
319Channels over a client-server connection must all have a unique ID, which can be
320assigned statically at compile time or dynamically.
321
322.. code-block:: cpp
323
324 // Creating a channel with the static ID 3.
325 pw::rpc::Channel static_channel = pw::rpc::Channel::Create<3>(&output);
326
327 // Grouping channel IDs within an enum can lead to clearer code.
328 enum ChannelId {
329 kUartChannel = 1,
330 kSpiChannel = 2,
331 };
332
333 // Creating a channel with a static ID defined within an enum.
334 pw::rpc::Channel another_static_channel =
335 pw::rpc::Channel::Create<ChannelId::kUartChannel>(&output);
336
337 // Creating a channel with a dynamic ID (note that no output is provided; it
338 // will be set when the channel is used.
339 pw::rpc::Channel dynamic_channel;
340
Alexei Frolov567e6702021-04-13 09:13:02 -0700341Sometimes, the ID and output of a channel are not known at compile time as they
342depend on information stored on the physical device. To support this use case, a
343dynamically-assignable channel can be configured once at runtime with an ID and
344output.
345
346.. code-block:: cpp
347
348 // Create a dynamic channel without a compile-time ID or output.
349 pw::rpc::Channel dynamic_channel;
350
351 void Init() {
352 // Called during boot to pull the channel configuration from the system.
353 dynamic_channel.Configure(GetChannelId(), some_output);
354 }
355
Erik Gilling3b7159a2022-01-20 20:37:01 +0000356A channel may be closed and unregistered with an endpoint by calling
357``ChannelClose`` on the endpoint with the corresponding channel ID. This
358will terminate any pending calls and call their ``on_error`` callback
359with the ``ABORTED`` status.
360
361.. code-block:: cpp
362
363 // When a channel is closed, any pending calls will receive
364 // on_error callbacks with ABORTED status.
365 client->CloseChannel(1);
366
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700367Services
368========
369A service is a logical grouping of RPCs defined within a .proto file. ``pw_rpc``
370uses these .proto definitions to generate code for a base service, from which
371user-defined RPCs are implemented.
372
373``pw_rpc`` supports multiple protobuf libraries, and the generated code API
374depends on which is used.
375
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700376.. _module-pw_rpc-protobuf-library-apis:
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700377
378Protobuf library APIs
379=====================
380
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700381.. toctree::
382 :maxdepth: 1
383
384 nanopb/docs
385
386Testing a pw_rpc integration
387============================
388After setting up a ``pw_rpc`` server in your project, you can test that it is
389working as intended by registering the provided ``EchoService``, defined in
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800390``echo.proto``, which echoes back a message that it receives.
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700391
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800392.. literalinclude:: echo.proto
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700393 :language: protobuf
394 :lines: 14-
395
396For example, in C++ with nanopb:
397
398.. code:: c++
399
400 #include "pw_rpc/server.h"
401
402 // Include the apporpriate header for your protobuf library.
403 #include "pw_rpc/echo_service_nanopb.h"
404
405 constexpr pw::rpc::Channel kChannels[] = { /* ... */ };
406 static pw::rpc::Server server(kChannels);
407
408 static pw::rpc::EchoService echo_service;
409
410 void Init() {
Wyatt Hepler31b16ea2021-07-21 08:52:02 -0700411 server.RegisterService(echo_service);
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700412 }
413
Wyatt Hepler31b16ea2021-07-21 08:52:02 -0700414Benchmarking and stress testing
415-------------------------------
416
417.. toctree::
418 :maxdepth: 1
419 :hidden:
420
421 benchmark
422
423``pw_rpc`` provides an RPC service and Python module for stress testing and
424benchmarking a ``pw_rpc`` deployment. See :ref:`module-pw_rpc-benchmark`.
425
Wyatt Hepler05d860d2021-09-22 09:43:10 -0700426Naming
427======
428
429Reserved names
430--------------
431``pw_rpc`` reserves a few service method names so they can be used for generated
432classes. The following names cannnot be used for service methods:
433
434- ``Client``
435- ``Service``
436- Any reserved words in the languages ``pw_rpc`` supports (e.g. ``class``).
437
438``pw_rpc`` does not reserve any service names, but the restriction of avoiding
439reserved words in supported languages applies.
440
441Service naming style
442--------------------
443``pw_rpc`` service names should use capitalized camel case and should not use
444the term "Service". Appending "Service" to a service name is redundant, similar
445to appending "Class" or "Function" to a class or function name. The
446C++ implementation class may use "Service" in its name, however.
447
448For example, a service for accessing a file system should simply be named
449``service FileSystem``, rather than ``service FileSystemService``, in the
450``.proto`` file.
451
452.. code-block:: protobuf
453
454 // file.proto
455 package pw.file;
456
457 service FileSystem {
458 rpc List(ListRequest) returns (stream ListResponse);
459 }
460
461The C++ service implementation class may append "Service" to the name.
462
463.. code-block:: cpp
464
465 // file_system_service.h
466 #include "pw_file/file.raw_rpc.pb.h"
467
468 namespace pw::file {
469
470 class FileSystemService : public pw_rpc::raw::FileSystem::Service<FileSystemService> {
Wyatt Hepler8e756e32021-11-18 09:59:27 -0800471 void List(ConstByteSpan request, RawServerWriter& writer);
Wyatt Hepler05d860d2021-09-22 09:43:10 -0700472 };
473
474 }
475
476For upstream Pigweed services, this naming style is a requirement. Note that
477some services created before this was established may use non-compliant
478names. For Pigweed users, this naming style is a suggestion.
479
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700480Protocol description
481====================
482Pigweed RPC servers and clients communicate using ``pw_rpc`` packets. These
483packets are used to send requests and responses, control streams, cancel ongoing
484RPCs, and report errors.
485
486Packet format
487-------------
488Pigweed RPC packets consist of a type and a set of fields. The packets are
489encoded as protocol buffers. The full packet format is described in
Wyatt Heplerba325e42021-03-08 14:23:34 -0800490``pw_rpc/pw_rpc/internal/packet.proto``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700491
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800492.. literalinclude:: internal/packet.proto
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700493 :language: protobuf
494 :lines: 14-
495
496The packet type and RPC type determine which fields are present in a Pigweed RPC
Wyatt Hepler0f262352020-07-29 09:51:27 -0700497packet. Each packet type is only sent by either the client or the server.
498These tables describe the meaning of and fields included with each packet type.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700499
Wyatt Hepler0f262352020-07-29 09:51:27 -0700500Client-to-server packets
501^^^^^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700502+-------------------+-------------------------------------+
503| packet type | description |
504+===================+=====================================+
505| REQUEST | Invoke an RPC |
506| | |
507| | .. code-block:: text |
508| | |
509| | - channel_id |
510| | - service_id |
511| | - method_id |
512| | - payload |
513| | (unary & server streaming only) |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700514| | - call_id (optional) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700515| | |
516+-------------------+-------------------------------------+
517| CLIENT_STREAM | Message in a client stream |
518| | |
519| | .. code-block:: text |
520| | |
521| | - channel_id |
522| | - service_id |
523| | - method_id |
524| | - payload |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700525| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700526| | |
527+-------------------+-------------------------------------+
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700528| CLIENT_STREAM_END | Client stream is complete |
529| | |
530| | .. code-block:: text |
531| | |
532| | - channel_id |
533| | - service_id |
534| | - method_id |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700535| | - call_id (if set in REQUEST) |
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700536| | |
537+-------------------+-------------------------------------+
Wyatt Hepler17169152021-10-20 18:46:08 -0700538| CLIENT_ERROR | Abort an ongoing RPC |
Wyatt Heplera9211162021-06-12 15:40:11 -0700539| | |
540| | .. code-block:: text |
541| | |
542| | - channel_id |
543| | - service_id |
544| | - method_id |
545| | - status |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700546| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700547| | |
548+-------------------+-------------------------------------+
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700549
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700550**Client errors**
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700551
Wyatt Hepler0f262352020-07-29 09:51:27 -0700552The client sends ``CLIENT_ERROR`` packets to a server when it receives a packet
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700553it did not request. If possible, the server should abort it.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700554
Wyatt Heplera9211162021-06-12 15:40:11 -0700555The status code indicates the type of error. The status code is logged, but all
556status codes result in the same action by the server: aborting the RPC.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700557
Wyatt Hepler17169152021-10-20 18:46:08 -0700558* ``CANCELLED`` -- The client requested that the RPC be cancelled.
Erik Gilling3b7159a2022-01-20 20:37:01 +0000559* ``ABORTED`` -- The RPC was aborted due its channel being closed.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700560* ``NOT_FOUND`` -- Received a packet for a service method the client does not
561 recognize.
562* ``FAILED_PRECONDITION`` -- Received a packet for a service method that the
563 client did not invoke.
Wyatt Hepler35240da2021-07-21 08:51:22 -0700564* ``DATA_LOSS`` -- Received a corrupt packet for a pending service method.
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700565* ``INVALID_ARGUMENT`` -- The server sent a packet type to an RPC that does not
566 support it (a ``SERVER_STREAM`` was sent to an RPC with no server stream).
Wyatt Hepler0f262352020-07-29 09:51:27 -0700567
568Server-to-client packets
569^^^^^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700570+-------------------+-------------------------------------+
571| packet type | description |
572+===================+=====================================+
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700573| RESPONSE | The RPC is complete |
574| | |
575| | .. code-block:: text |
576| | |
577| | - channel_id |
578| | - service_id |
579| | - method_id |
580| | - status |
581| | - payload |
582| | (unary & client streaming only) |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700583| | - call_id (if set in REQUEST) |
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700584| | |
585+-------------------+-------------------------------------+
586| SERVER_STREAM | Message in a server stream |
Wyatt Heplera9211162021-06-12 15:40:11 -0700587| | |
588| | .. code-block:: text |
589| | |
590| | - channel_id |
591| | - service_id |
592| | - method_id |
593| | - payload |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700594| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700595| | |
596+-------------------+-------------------------------------+
597| SERVER_ERROR | Received unexpected packet |
598| | |
599| | .. code-block:: text |
600| | |
601| | - channel_id |
602| | - service_id (if relevant) |
603| | - method_id (if relevant) |
604| | - status |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700605| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700606| | |
607+-------------------+-------------------------------------+
Wyatt Hepler0f262352020-07-29 09:51:27 -0700608
Erik Gilling1f9e3552022-01-21 18:49:20 +0000609All server packets contain the same ``call_id`` that was set in the initial
Alexei Frolov86e05de2021-10-19 16:52:31 -0700610request made by the client, if any.
611
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700612**Server errors**
Wyatt Hepler0f262352020-07-29 09:51:27 -0700613
614The server sends ``SERVER_ERROR`` packets when it receives a packet it cannot
615process. The client should abort any RPC for which it receives an error. The
616status field indicates the type of error.
617
618* ``NOT_FOUND`` -- The requested service or method does not exist.
Wyatt Heplera9211162021-06-12 15:40:11 -0700619* ``FAILED_PRECONDITION`` -- A client stream or cancel packet was sent for an
620 RPC that is not pending.
Wyatt Hepler01fc15b2021-06-10 18:15:59 -0700621* ``INVALID_ARGUMENT`` -- The client sent a packet type to an RPC that does not
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700622 support it (a ``CLIENT_STREAM`` was sent to an RPC with no client stream).
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700623* ``RESOURCE_EXHAUSTED`` -- The request came on a new channel, but a channel
624 could not be allocated for it.
Erik Gilling3b7159a2022-01-20 20:37:01 +0000625* ``ABORTED`` -- The RPC was aborted due its channel being closed.
Wyatt Hepler712d3672020-07-13 15:52:11 -0700626* ``INTERNAL`` -- The server was unable to respond to an RPC due to an
627 unrecoverable internal error.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700628
629Inovking a service method
630-------------------------
631Calling an RPC requires a specific sequence of packets. This section describes
632the protocol for calling service methods of each type: unary, server streaming,
633client streaming, and bidirectional streaming.
634
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700635The basic flow for all RPC invocations is as follows:
636
637 * Client sends a ``REQUEST`` packet. Includes a payload for unary & server
638 streaming RPCs.
639 * For client and bidirectional streaming RPCs, the client may send any number
640 of ``CLIENT_STREAM`` packets with payloads.
641 * For server and bidirectional streaming RPCs, the server may send any number
642 of ``SERVER_STREAM`` packets.
643 * The server sends a ``RESPONSE`` packet. Includes a payload for unary &
644 client streaming RPCs. The RPC is complete.
645
Wyatt Hepler17169152021-10-20 18:46:08 -0700646The client may cancel an ongoing RPC at any time by sending a ``CLIENT_ERROR``
647packet with status ``CANCELLED``. The server may finish an ongoing RPC at any
648time by sending the ``RESPONSE`` packet.
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700649
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700650Unary RPC
651^^^^^^^^^
652In a unary RPC, the client sends a single request and the server sends a single
653response.
654
Wyatt Hepler1d221242021-09-07 15:42:21 -0700655.. image:: unary_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700656
Wyatt Hepler17169152021-10-20 18:46:08 -0700657The client may attempt to cancel a unary RPC by sending a ``CLIENT_ERROR``
658packet with status ``CANCELLED``. The server sends no response to a cancelled
659RPC. If the server processes the unary RPC synchronously (the handling thread
660sends the response), it may not be possible to cancel the RPC.
Wyatt Heplera9211162021-06-12 15:40:11 -0700661
Wyatt Hepler1d221242021-09-07 15:42:21 -0700662.. image:: unary_rpc_cancelled.svg
Wyatt Heplera9211162021-06-12 15:40:11 -0700663
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700664Server streaming RPC
665^^^^^^^^^^^^^^^^^^^^
666In a server streaming RPC, the client sends a single request and the server
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700667sends any number of ``SERVER_STREAM`` packets followed by a ``RESPONSE`` packet.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700668
Wyatt Hepler1d221242021-09-07 15:42:21 -0700669.. image:: server_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700670
Wyatt Hepler17169152021-10-20 18:46:08 -0700671The client may terminate a server streaming RPC by sending a ``CLIENT_STREAM``
672packet with status ``CANCELLED``. The server sends no response.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700673
Wyatt Hepler1d221242021-09-07 15:42:21 -0700674.. image:: server_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700675
676Client streaming RPC
677^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700678In a client streaming RPC, the client starts the RPC by sending a ``REQUEST``
679packet with no payload. It then sends any number of messages in
680``CLIENT_STREAM`` packets, followed by a ``CLIENT_STREAM_END``. The server sends
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700681a single ``RESPONSE`` to finish the RPC.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700682
Wyatt Hepler1d221242021-09-07 15:42:21 -0700683.. image:: client_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700684
Wyatt Heplera9211162021-06-12 15:40:11 -0700685The server may finish the RPC at any time by sending its ``RESPONSE`` packet,
686even if it has not yet received the ``CLIENT_STREAM_END`` packet. The client may
Wyatt Hepler17169152021-10-20 18:46:08 -0700687terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
688``CANCELLED``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700689
Wyatt Hepler1d221242021-09-07 15:42:21 -0700690.. image:: client_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700691
692Bidirectional streaming RPC
693^^^^^^^^^^^^^^^^^^^^^^^^^^^
694In a bidirectional streaming RPC, the client sends any number of requests and
Wyatt Heplera9211162021-06-12 15:40:11 -0700695the server sends any number of responses. The client invokes the RPC by sending
696a ``REQUEST`` with no payload. It sends a ``CLIENT_STREAM_END`` packet when it
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700697has finished sending requests. The server sends a ``RESPONSE`` packet to finish
698the RPC.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700699
Wyatt Hepler1d221242021-09-07 15:42:21 -0700700.. image:: bidirectional_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700701
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700702The server may finish the RPC at any time by sending the ``RESPONSE`` packet,
703even if it has not received the ``CLIENT_STREAM_END`` packet. The client may
Wyatt Hepler17169152021-10-20 18:46:08 -0700704terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
705``CANCELLED``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700706
Wyatt Hepler1d221242021-09-07 15:42:21 -0700707.. image:: bidirectional_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700708
Wyatt Hepler948f5472020-06-02 16:52:28 -0700709RPC server
710==========
711Declare an instance of ``rpc::Server`` and register services with it.
712
713.. admonition:: TODO
714
715 Document the public interface
716
Alexei Frolovbf33d212020-09-15 17:13:45 -0700717Size report
718-----------
719The following size report showcases the memory usage of the core RPC server. It
720is configured with a single channel using a basic transport interface that
721directly reads from and writes to ``pw_sys_io``. The transport has a 128-byte
722packet buffer, which comprises the plurality of the example's RAM usage. This is
723not a suitable transport for an actual product; a real implementation would have
724additional overhead proportional to the complexity of the transport.
725
726.. include:: server_size
727
Wyatt Hepler948f5472020-06-02 16:52:28 -0700728RPC server implementation
729-------------------------
730
731The Method class
732^^^^^^^^^^^^^^^^
733The RPC Server depends on the ``pw::rpc::internal::Method`` class. ``Method``
734serves as the bridge between the ``pw_rpc`` server library and the user-defined
Wyatt Heplere95bd722020-11-23 07:49:47 -0800735RPC functions. Each supported protobuf implementation extends ``Method`` to
736implement its request and response proto handling. The ``pw_rpc`` server
737calls into the ``Method`` implementation through the base class's ``Invoke``
738function.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700739
Wyatt Heplere95bd722020-11-23 07:49:47 -0800740``Method`` implementations store metadata about each method, including a
741function pointer to the user-defined method implementation. They also provide
742``static constexpr`` functions for creating each type of method. ``Method``
743implementations must satisfy the ``MethodImplTester`` test class in
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -0700744``pw_rpc/internal/method_impl_tester.h``.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700745
Wyatt Heplere95bd722020-11-23 07:49:47 -0800746See ``pw_rpc/internal/method.h`` for more details about ``Method``.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700747
748Packet flow
749^^^^^^^^^^^
750
751Requests
752~~~~~~~~
753
Wyatt Hepler1d221242021-09-07 15:42:21 -0700754.. image:: request_packets.svg
Wyatt Hepler948f5472020-06-02 16:52:28 -0700755
756Responses
757~~~~~~~~~
758
Wyatt Hepler1d221242021-09-07 15:42:21 -0700759.. image:: response_packets.svg
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700760
761RPC client
762==========
763The RPC client is used to send requests to a server and manages the contexts of
764ongoing RPCs.
765
766Setting up a client
767-------------------
768The ``pw::rpc::Client`` class is instantiated with a list of channels that it
769uses to communicate. These channels can be shared with a server, but multiple
770clients cannot use the same channels.
771
772To send incoming RPC packets from the transport layer to be processed by a
773client, the client's ``ProcessPacket`` function is called with the packet data.
774
775.. code:: c++
776
777 #include "pw_rpc/client.h"
778
779 namespace {
780
781 pw::rpc::Channel my_channels[] = {
782 pw::rpc::Channel::Create<1>(&my_channel_output)};
783 pw::rpc::Client my_client(my_channels);
784
785 } // namespace
786
787 // Called when the transport layer receives an RPC packet.
788 void ProcessRpcPacket(ConstByteSpan packet) {
789 my_client.ProcessPacket(packet);
790 }
791
Alexei Frolov5a3a61c2020-10-01 18:51:41 -0700792.. _module-pw_rpc-making-calls:
793
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700794Making RPC calls
795----------------
796RPC calls are not made directly through the client, but using one of its
797registered channels instead. A service client class is generated from a .proto
798file for each selected protobuf library, which is then used to send RPC requests
799through a given channel. The API for this depends on the protobuf library;
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700800please refer to the
801:ref:`appropriate documentation<module-pw_rpc-protobuf-library-apis>`. Multiple
802service client implementations can exist simulatenously and share the same
803``Client`` class.
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700804
805When a call is made, a ``pw::rpc::ClientCall`` object is returned to the caller.
806This object tracks the ongoing RPC call, and can be used to manage it. An RPC
807call is only active as long as its ``ClientCall`` object is alive.
808
809.. tip::
810 Use ``std::move`` when passing around ``ClientCall`` objects to keep RPCs
811 alive.
812
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700813Example
814^^^^^^^
815.. code-block:: c++
816
817 #include "pw_rpc/echo_service_nanopb.h"
818
819 namespace {
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700820 // Generated clients are namespaced with their proto library.
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800821 using EchoClient = pw_rpc::nanopb::EchoService::Client;
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700822
Alexei Frolov73687fb2021-09-03 11:22:33 -0700823 // RPC channel ID on which to make client calls.
824 constexpr uint32_t kDefaultChannelId = 1;
825
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800826 EchoClient::EchoCall echo_call;
Alexei Frolovbebba902021-06-09 17:03:52 -0700827
828 // Callback invoked when a response is received. This is called synchronously
829 // from Client::ProcessPacket.
830 void EchoResponse(const pw_rpc_EchoMessage& response,
831 pw::Status status) {
832 if (status.ok()) {
833 PW_LOG_INFO("Received echo response: %s", response.msg);
834 } else {
835 PW_LOG_ERROR("Echo failed with status %d",
836 static_cast<int>(status.code()));
837 }
838 }
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700839
840 } // namespace
841
842 void CallEcho(const char* message) {
Alexei Frolov73687fb2021-09-03 11:22:33 -0700843 // Create a client to call the EchoService.
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800844 EchoClient echo_client(my_rpc_client, kDefaultChannelId);
Alexei Frolov73687fb2021-09-03 11:22:33 -0700845
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700846 pw_rpc_EchoMessage request = pw_rpc_EchoMessage_init_default;
847 pw::string::Copy(message, request.msg);
848
849 // By assigning the returned ClientCall to the global echo_call, the RPC
850 // call is kept alive until it completes. When a response is received, it
851 // will be logged by the handler function and the call will complete.
Alexei Frolov73687fb2021-09-03 11:22:33 -0700852 echo_call = echo_client.Echo(request, EchoResponse);
853 if (!echo_call.active()) {
854 // The RPC call was not sent. This could occur due to, for example, an
855 // invalid channel ID. Handle if necessary.
856 }
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700857 }
858
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700859Client implementation details
860-----------------------------
861
862The ClientCall class
863^^^^^^^^^^^^^^^^^^^^
864``ClientCall`` stores the context of an active RPC, and serves as the user's
865interface to the RPC client. The core RPC library provides a base ``ClientCall``
866class with common functionality, which is then extended for RPC client
867implementations tied to different protobuf libraries to provide convenient
868interfaces for working with RPCs.
869
870The RPC server stores a list of all of active ``ClientCall`` objects. When an
871incoming packet is recieved, it dispatches to one of its active calls, which
872then decodes the payload and presents it to the user.
Alexei Frolov3e280922021-04-12 14:53:06 -0700873
874ClientServer
875============
876Sometimes, a device needs to both process RPCs as a server, as well as making
877calls to another device as a client. To do this, both a client and server must
878be set up, and incoming packets must be sent to both of them.
879
880Pigweed simplifies this setup by providing a ``ClientServer`` class which wraps
881an RPC client and server with the same set of channels.
882
883.. code-block:: cpp
884
885 pw::rpc::Channel channels[] = {
886 pw::rpc::Channel::Create<1>(&channel_output)};
887
888 // Creates both a client and a server.
889 pw::rpc::ClientServer client_server(channels);
890
891 void ProcessRpcData(pw::ConstByteSpan packet) {
892 // Calls into both the client and the server, sending the packet to the
893 // appropriate one.
Alexei Frolovba93a432021-12-02 13:36:26 -0800894 client_server.ProcessPacket(packet);
Alexei Frolov3e280922021-04-12 14:53:06 -0700895 }
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800896
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800897Testing
898=======
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800899``pw_rpc`` provides utilities for unit testing RPC services and client calls.
900
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800901Client unit testing in C++
902--------------------------
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800903``pw_rpc`` supports invoking RPCs, simulating server responses, and checking
904what packets are sent by an RPC client in tests. Both raw and Nanopb interfaces
905are supported. Code that uses the raw API may be tested with the Nanopb test
906helpers, and vice versa.
907
908To test code that invokes RPCs, declare a ``RawClientTestContext`` or
909``NanopbClientTestContext``. These test context objects provide a
910preconfigured RPC client, channel, server fake, and buffer for encoding packets.
911These test classes are defined in ``pw_rpc/raw/client_testing.h`` and
912``pw_rpc/nanopb/client_testing.h``.
913
914Use the context's ``client()`` and ``channel()`` to invoke RPCs. Use the
915context's ``server()`` to simulate responses. To verify that the client sent the
916expected data, use the context's ``output()``, which is a ``FakeChannelOutput``.
917
918For example, the following tests a class that invokes an RPC. It checks that
919the expected data was sent and then simulates a response from the server.
920
921.. code-block:: cpp
922
923 #include "pw_rpc/raw/client_testing.h"
924
925 class ThingThatCallsRpcs {
926 public:
927 // To support injecting an RPC client for testing, classes that make RPC
928 // calls should take an RPC client and channel ID or an RPC service client
929 // (e.g. pw_rpc::raw::MyService::Client).
930 ThingThatCallsRpcs(pw::rpc::Client& client, uint32_t channel_id);
931
932 void DoSomethingThatInvokesAnRpc();
933
934 bool SetToTrueWhenRpcCompletes();
935 };
936
937 TEST(TestAThing, InvokesRpcAndHandlesResponse) {
938 RawClientTestContext context;
939 ThingThatCallsRpcs thing(context.client(), context.channel().id());
940
941 // Execute the code that invokes the MyService.TheMethod RPC.
942 things.DoSomethingThatInvokesAnRpc();
943
944 // Find and verify the payloads sent for the MyService.TheMethod RPC.
945 auto msgs = context.output().payloads<pw_rpc::raw::MyService::TheMethod>();
946 ASSERT_EQ(msgs.size(), 1u);
947
948 VerifyThatTheExpectedMessageWasSent(msgs.back());
949
950 // Send the response packet from the server and verify that the class reacts
951 // accordingly.
952 EXPECT_FALSE(thing.SetToTrueWhenRpcCompletes());
953
954 context_.server().SendResponse<pw_rpc::raw::MyService::TheMethod>(
955 final_message, OkStatus());
956
957 EXPECT_TRUE(thing.SetToTrueWhenRpcCompletes());
958 }
Ewout van Bekkum7f5b3052021-11-11 17:35:23 -0800959
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800960Integration testing with ``pw_rpc``
961-----------------------------------
962``pw_rpc`` provides utilities to simplify writing integration tests for systems
963that communicate with ``pw_rpc``. The integration test utitilies set up a socket
964to use for IPC between an RPC server and client process.
965
966The server binary uses the system RPC server facade defined
967``pw_rpc_system_server/rpc_server.h``. The client binary uses the functions
968defined in ``pw_rpc/integration_testing.h``:
969
970.. cpp:var:: constexpr uint32_t kChannelId
971
972 The RPC channel for integration test RPCs.
973
974.. cpp:function:: pw::rpc::Client& pw::rpc::integration_test::Client()
975
976 Returns the global RPC client for integration test use.
977
978.. cpp:function:: pw::Status pw::rpc::integration_test::InitializeClient(int argc, char* argv[], const char* usage_args = "PORT")
979
980 Initializes logging and the global RPC client for integration testing. Starts
981 a background thread that processes incoming.
982
Ewout van Bekkum7f5b3052021-11-11 17:35:23 -0800983Module Configuration Options
984============================
985The following configurations can be adjusted via compile-time configuration of
986this module, see the
987:ref:`module documentation <module-structure-compile-time-configuration>` for
988more details.
989
990.. c:macro:: PW_RPC_CLIENT_STREAM_END_CALLBACK
991
992 In client and bidirectional RPCs, pw_rpc clients may signal that they have
993 finished sending requests with a CLIENT_STREAM_END packet. While this can be
994 useful in some circumstances, it is often not necessary.
995
996 This option controls whether or not include a callback that is called when
997 the client stream ends. The callback is included in all ServerReader/Writer
998 objects as a pw::Function, so may have a significant cost.
999
1000 This is disabled by default.
1001
1002.. c:macro:: PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
1003
1004 The Nanopb-based pw_rpc implementation allocates memory to use for Nanopb
1005 structs for the request and response protobufs. The template function that
1006 allocates these structs rounds struct sizes up to this value so that
1007 different structs can be allocated with the same function. Structs with sizes
1008 larger than this value cause an extra function to be created, which slightly
1009 increases code size.
1010
1011 Ideally, this value will be set to the size of the largest Nanopb struct used
1012 as an RPC request or response. The buffer can be stack or globally allocated
1013 (see ``PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE``).
1014
1015 This defaults to 64 Bytes.
1016
1017.. c:macro:: PW_RPC_USE_GLOBAL_MUTEX
1018
1019 Enable global synchronization for RPC calls. If this is set, a backend must
1020 be configured for pw_sync:mutex.
1021
1022 This is disabled by default.
1023
1024.. c:macro:: PW_RPC_CONFIG_LOG_LEVEL
1025
1026 The log level to use for this module. Logs below this level are omitted.
1027
1028 This defaults to ``PW_LOG_LEVEL_INFO``.
1029
1030.. c:macro:: PW_RPC_CONFIG_LOG_MODULE_NAME
1031
1032 The log module name to use for this module.
1033
1034 This defaults to ``"PW_RPC"``.
1035
1036.. c:macro:: PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
1037
1038 This option determines whether to allocate the Nanopb structs on the stack or
1039 in a global variable. Globally allocated structs are NOT thread safe, but
1040 work fine when the RPC server's ProcessPacket function is only called from
1041 one thread.
1042
1043 This is enabled by default.
Wyatt Hepler14439762021-11-09 09:16:32 -08001044
1045Sharing server and client code
1046==============================
1047Streaming RPCs support writing multiple requests or responses. To facilitate
1048sharing code between servers and clients, ``pw_rpc`` provides the
1049``pw::rpc::Writer`` interface. On the client side, a client or bidirectional
1050streaming RPC call object (``ClientWriter`` or ``ClientReaderWriter``) can be
1051used as a ``pw::rpc::Writer&``. On the server side, a server or bidirectional
1052streaming RPC call object (``ServerWriter`` or ``ServerReaderWriter``) can be
1053used as a ``pw::rpc::Writer&``.
Yuval Peressb8f3ad22021-10-26 22:55:27 -06001054
1055Zephyr
1056======
1057To enable ``pw_rpc.*`` for Zephyr add ``CONFIG_PIGWEED_RPC=y`` to the project's
1058configuration. This will enable the Kconfig menu for the following:
1059
1060* ``pw_rpc.server`` which can be enabled via ``CONFIG_PIGWEED_RPC_SERVER=y``.
1061* ``pw_rpc.client`` which can be enabled via ``CONFIG_PIGWEED_RPC_CLIENT=y``.
1062* ``pw_rpc.client_server`` which can be enabled via
1063 ``CONFIG_PIGWEED_RPC_CLIENT_SERVER=y``.
1064* ``pw_rpc.common` which can be enabled via ``CONFIG_PIGWEED_RPC_COMMON=y``.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001065
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001066Encoding and sending packets
1067============================
1068``pw_rpc`` has to manage interactions among multiple RPC clients, servers,
1069client calls, and server calls. To safely synchronize these interactions with
1070minimal overhead, ``pw_rpc`` uses a single, global mutex (when
1071``PW_RPC_USE_GLOBAL_MUTEX`` is enabled).
1072
1073Because ``pw_rpc`` uses a global mutex, it also uses a global buffer to encode
1074outgoing packets. The size of the buffer is set with
1075``PW_RPC_ENCODING_BUFFER_SIZE``, which defaults to 512 B.
1076
1077Users of ``pw_rpc`` must implement the :cpp:class:`pw::rpc::ChannelOutput`
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001078interface.
1079
1080.. cpp:class:: pw::rpc::ChannelOutput
1081
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001082 ``pw_rpc`` endpoints use :cpp:class:`ChannelOutput` instances to send packets.
1083 Systems that integrate pw_rpc must use one or more :cpp:class:`ChannelOutput`
1084 instances.
1085
1086 .. cpp:member:: static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max()
1087
1088 Value returned from :cpp:func:`MaximumTransmissionUnit` to indicate an
1089 unlimited MTU.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001090
1091 .. cpp:function:: virtual size_t MaximumTransmissionUnit()
1092
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001093 Returns the size of the largest packet the :cpp:class:`ChannelOutput` can
1094 send. :cpp:class:`ChannelOutput` implementations should only override this
1095 function if they impose a limit on the MTU. The default implementation
1096 returns :cpp:member:`kUnlimited`, which indicates that there is no MTU
1097 limit.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001098
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001099 .. cpp:function:: virtual pw::Status Send(std::span<std::byte> packet)
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001100
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001101 Sends an encoded RPC packet. Returns OK if further packets may be sent, even
1102 if the current packet could not be sent. Returns any other status if the
1103 Channel is no longer able to send packets.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001104
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001105 The RPC system's internal lock is held while this function is called. Avoid
1106 long-running operations, since these will delay any other users of the RPC
1107 system.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001108
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001109 .. danger::
1110
1111 No ``pw_rpc`` APIs may be accessed in this function! Implementations MUST
1112 NOT access any RPC endpoints (:cpp:class:`pw::rpc::Client`,
1113 :cpp:class:`pw::rpc::Server`) or call objects
1114 (:cpp:class:`pw::rpc::ServerReaderWriter`,
1115 :cpp:class:`pw::rpc::ClientReaderWriter`, etc.) inside the :cpp:func:`Send`
1116 function or any descendent calls. Doing so will result in deadlock! RPC APIs
1117 may be used by other threads, just not within :cpp:func:`Send`.
1118
1119 The buffer provided in ``packet`` must NOT be accessed outside of this
1120 function. It must be sent immediately or copied elsewhere before the
1121 function returns.