blob: 072ffcf6a4139aed8b1d31fb20f9ec66cc70d90e [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
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700356Services
357========
358A service is a logical grouping of RPCs defined within a .proto file. ``pw_rpc``
359uses these .proto definitions to generate code for a base service, from which
360user-defined RPCs are implemented.
361
362``pw_rpc`` supports multiple protobuf libraries, and the generated code API
363depends on which is used.
364
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700365.. _module-pw_rpc-protobuf-library-apis:
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700366
367Protobuf library APIs
368=====================
369
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700370.. toctree::
371 :maxdepth: 1
372
373 nanopb/docs
374
375Testing a pw_rpc integration
376============================
377After setting up a ``pw_rpc`` server in your project, you can test that it is
378working as intended by registering the provided ``EchoService``, defined in
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800379``echo.proto``, which echoes back a message that it receives.
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700380
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800381.. literalinclude:: echo.proto
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700382 :language: protobuf
383 :lines: 14-
384
385For example, in C++ with nanopb:
386
387.. code:: c++
388
389 #include "pw_rpc/server.h"
390
391 // Include the apporpriate header for your protobuf library.
392 #include "pw_rpc/echo_service_nanopb.h"
393
394 constexpr pw::rpc::Channel kChannels[] = { /* ... */ };
395 static pw::rpc::Server server(kChannels);
396
397 static pw::rpc::EchoService echo_service;
398
399 void Init() {
Wyatt Hepler31b16ea2021-07-21 08:52:02 -0700400 server.RegisterService(echo_service);
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700401 }
402
Wyatt Hepler31b16ea2021-07-21 08:52:02 -0700403Benchmarking and stress testing
404-------------------------------
405
406.. toctree::
407 :maxdepth: 1
408 :hidden:
409
410 benchmark
411
412``pw_rpc`` provides an RPC service and Python module for stress testing and
413benchmarking a ``pw_rpc`` deployment. See :ref:`module-pw_rpc-benchmark`.
414
Wyatt Hepler05d860d2021-09-22 09:43:10 -0700415Naming
416======
417
418Reserved names
419--------------
420``pw_rpc`` reserves a few service method names so they can be used for generated
421classes. The following names cannnot be used for service methods:
422
423- ``Client``
424- ``Service``
425- Any reserved words in the languages ``pw_rpc`` supports (e.g. ``class``).
426
427``pw_rpc`` does not reserve any service names, but the restriction of avoiding
428reserved words in supported languages applies.
429
430Service naming style
431--------------------
432``pw_rpc`` service names should use capitalized camel case and should not use
433the term "Service". Appending "Service" to a service name is redundant, similar
434to appending "Class" or "Function" to a class or function name. The
435C++ implementation class may use "Service" in its name, however.
436
437For example, a service for accessing a file system should simply be named
438``service FileSystem``, rather than ``service FileSystemService``, in the
439``.proto`` file.
440
441.. code-block:: protobuf
442
443 // file.proto
444 package pw.file;
445
446 service FileSystem {
447 rpc List(ListRequest) returns (stream ListResponse);
448 }
449
450The C++ service implementation class may append "Service" to the name.
451
452.. code-block:: cpp
453
454 // file_system_service.h
455 #include "pw_file/file.raw_rpc.pb.h"
456
457 namespace pw::file {
458
459 class FileSystemService : public pw_rpc::raw::FileSystem::Service<FileSystemService> {
Wyatt Hepler8e756e32021-11-18 09:59:27 -0800460 void List(ConstByteSpan request, RawServerWriter& writer);
Wyatt Hepler05d860d2021-09-22 09:43:10 -0700461 };
462
463 }
464
465For upstream Pigweed services, this naming style is a requirement. Note that
466some services created before this was established may use non-compliant
467names. For Pigweed users, this naming style is a suggestion.
468
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700469Protocol description
470====================
471Pigweed RPC servers and clients communicate using ``pw_rpc`` packets. These
472packets are used to send requests and responses, control streams, cancel ongoing
473RPCs, and report errors.
474
475Packet format
476-------------
477Pigweed RPC packets consist of a type and a set of fields. The packets are
478encoded as protocol buffers. The full packet format is described in
Wyatt Heplerba325e42021-03-08 14:23:34 -0800479``pw_rpc/pw_rpc/internal/packet.proto``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700480
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800481.. literalinclude:: internal/packet.proto
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700482 :language: protobuf
483 :lines: 14-
484
485The packet type and RPC type determine which fields are present in a Pigweed RPC
Wyatt Hepler0f262352020-07-29 09:51:27 -0700486packet. Each packet type is only sent by either the client or the server.
487These tables describe the meaning of and fields included with each packet type.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700488
Wyatt Hepler0f262352020-07-29 09:51:27 -0700489Client-to-server packets
490^^^^^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700491+-------------------+-------------------------------------+
492| packet type | description |
493+===================+=====================================+
494| REQUEST | Invoke an RPC |
495| | |
496| | .. code-block:: text |
497| | |
498| | - channel_id |
499| | - service_id |
500| | - method_id |
501| | - payload |
502| | (unary & server streaming only) |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700503| | - call_id (optional) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700504| | |
505+-------------------+-------------------------------------+
506| CLIENT_STREAM | Message in a client stream |
507| | |
508| | .. code-block:: text |
509| | |
510| | - channel_id |
511| | - service_id |
512| | - method_id |
513| | - payload |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700514| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700515| | |
516+-------------------+-------------------------------------+
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700517| CLIENT_STREAM_END | Client stream is complete |
518| | |
519| | .. code-block:: text |
520| | |
521| | - channel_id |
522| | - service_id |
523| | - method_id |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700524| | - call_id (if set in REQUEST) |
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700525| | |
526+-------------------+-------------------------------------+
Wyatt Hepler17169152021-10-20 18:46:08 -0700527| CLIENT_ERROR | Abort an ongoing RPC |
Wyatt Heplera9211162021-06-12 15:40:11 -0700528| | |
529| | .. code-block:: text |
530| | |
531| | - channel_id |
532| | - service_id |
533| | - method_id |
534| | - status |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700535| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700536| | |
537+-------------------+-------------------------------------+
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700538
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700539**Client errors**
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700540
Wyatt Hepler0f262352020-07-29 09:51:27 -0700541The client sends ``CLIENT_ERROR`` packets to a server when it receives a packet
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700542it did not request. If possible, the server should abort it.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700543
Wyatt Heplera9211162021-06-12 15:40:11 -0700544The status code indicates the type of error. The status code is logged, but all
545status codes result in the same action by the server: aborting the RPC.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700546
Wyatt Hepler17169152021-10-20 18:46:08 -0700547* ``CANCELLED`` -- The client requested that the RPC be cancelled.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700548* ``NOT_FOUND`` -- Received a packet for a service method the client does not
549 recognize.
550* ``FAILED_PRECONDITION`` -- Received a packet for a service method that the
551 client did not invoke.
Wyatt Hepler35240da2021-07-21 08:51:22 -0700552* ``DATA_LOSS`` -- Received a corrupt packet for a pending service method.
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700553* ``INVALID_ARGUMENT`` -- The server sent a packet type to an RPC that does not
554 support it (a ``SERVER_STREAM`` was sent to an RPC with no server stream).
Wyatt Hepler0f262352020-07-29 09:51:27 -0700555
556Server-to-client packets
557^^^^^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700558+-------------------+-------------------------------------+
559| packet type | description |
560+===================+=====================================+
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700561| RESPONSE | The RPC is complete |
562| | |
563| | .. code-block:: text |
564| | |
565| | - channel_id |
566| | - service_id |
567| | - method_id |
568| | - status |
569| | - payload |
570| | (unary & client streaming only) |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700571| | - call_id (if set in REQUEST) |
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700572| | |
573+-------------------+-------------------------------------+
574| SERVER_STREAM | Message in a server stream |
Wyatt Heplera9211162021-06-12 15:40:11 -0700575| | |
576| | .. code-block:: text |
577| | |
578| | - channel_id |
579| | - service_id |
580| | - method_id |
581| | - payload |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700582| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700583| | |
584+-------------------+-------------------------------------+
585| SERVER_ERROR | Received unexpected packet |
586| | |
587| | .. code-block:: text |
588| | |
589| | - channel_id |
590| | - service_id (if relevant) |
591| | - method_id (if relevant) |
592| | - status |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700593| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700594| | |
595+-------------------+-------------------------------------+
Wyatt Hepler0f262352020-07-29 09:51:27 -0700596
Alexei Frolov86e05de2021-10-19 16:52:31 -0700597All server packets contain the same client ID that was set in the initial
598request made by the client, if any.
599
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700600**Server errors**
Wyatt Hepler0f262352020-07-29 09:51:27 -0700601
602The server sends ``SERVER_ERROR`` packets when it receives a packet it cannot
603process. The client should abort any RPC for which it receives an error. The
604status field indicates the type of error.
605
606* ``NOT_FOUND`` -- The requested service or method does not exist.
Wyatt Heplera9211162021-06-12 15:40:11 -0700607* ``FAILED_PRECONDITION`` -- A client stream or cancel packet was sent for an
608 RPC that is not pending.
Wyatt Hepler01fc15b2021-06-10 18:15:59 -0700609* ``INVALID_ARGUMENT`` -- The client sent a packet type to an RPC that does not
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700610 support it (a ``CLIENT_STREAM`` was sent to an RPC with no client stream).
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700611* ``RESOURCE_EXHAUSTED`` -- The request came on a new channel, but a channel
612 could not be allocated for it.
Wyatt Hepler712d3672020-07-13 15:52:11 -0700613* ``INTERNAL`` -- The server was unable to respond to an RPC due to an
614 unrecoverable internal error.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700615
616Inovking a service method
617-------------------------
618Calling an RPC requires a specific sequence of packets. This section describes
619the protocol for calling service methods of each type: unary, server streaming,
620client streaming, and bidirectional streaming.
621
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700622The basic flow for all RPC invocations is as follows:
623
624 * Client sends a ``REQUEST`` packet. Includes a payload for unary & server
625 streaming RPCs.
626 * For client and bidirectional streaming RPCs, the client may send any number
627 of ``CLIENT_STREAM`` packets with payloads.
628 * For server and bidirectional streaming RPCs, the server may send any number
629 of ``SERVER_STREAM`` packets.
630 * The server sends a ``RESPONSE`` packet. Includes a payload for unary &
631 client streaming RPCs. The RPC is complete.
632
Wyatt Hepler17169152021-10-20 18:46:08 -0700633The client may cancel an ongoing RPC at any time by sending a ``CLIENT_ERROR``
634packet with status ``CANCELLED``. The server may finish an ongoing RPC at any
635time by sending the ``RESPONSE`` packet.
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700636
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700637Unary RPC
638^^^^^^^^^
639In a unary RPC, the client sends a single request and the server sends a single
640response.
641
Wyatt Hepler1d221242021-09-07 15:42:21 -0700642.. image:: unary_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700643
Wyatt Hepler17169152021-10-20 18:46:08 -0700644The client may attempt to cancel a unary RPC by sending a ``CLIENT_ERROR``
645packet with status ``CANCELLED``. The server sends no response to a cancelled
646RPC. If the server processes the unary RPC synchronously (the handling thread
647sends the response), it may not be possible to cancel the RPC.
Wyatt Heplera9211162021-06-12 15:40:11 -0700648
Wyatt Hepler1d221242021-09-07 15:42:21 -0700649.. image:: unary_rpc_cancelled.svg
Wyatt Heplera9211162021-06-12 15:40:11 -0700650
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700651Server streaming RPC
652^^^^^^^^^^^^^^^^^^^^
653In a server streaming RPC, the client sends a single request and the server
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700654sends any number of ``SERVER_STREAM`` packets followed by a ``RESPONSE`` packet.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700655
Wyatt Hepler1d221242021-09-07 15:42:21 -0700656.. image:: server_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700657
Wyatt Hepler17169152021-10-20 18:46:08 -0700658The client may terminate a server streaming RPC by sending a ``CLIENT_STREAM``
659packet with status ``CANCELLED``. The server sends no response.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700660
Wyatt Hepler1d221242021-09-07 15:42:21 -0700661.. image:: server_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700662
663Client streaming RPC
664^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700665In a client streaming RPC, the client starts the RPC by sending a ``REQUEST``
666packet with no payload. It then sends any number of messages in
667``CLIENT_STREAM`` packets, followed by a ``CLIENT_STREAM_END``. The server sends
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700668a single ``RESPONSE`` to finish the RPC.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700669
Wyatt Hepler1d221242021-09-07 15:42:21 -0700670.. image:: client_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700671
Wyatt Heplera9211162021-06-12 15:40:11 -0700672The server may finish the RPC at any time by sending its ``RESPONSE`` packet,
673even if it has not yet received the ``CLIENT_STREAM_END`` packet. The client may
Wyatt Hepler17169152021-10-20 18:46:08 -0700674terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
675``CANCELLED``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700676
Wyatt Hepler1d221242021-09-07 15:42:21 -0700677.. image:: client_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700678
679Bidirectional streaming RPC
680^^^^^^^^^^^^^^^^^^^^^^^^^^^
681In a bidirectional streaming RPC, the client sends any number of requests and
Wyatt Heplera9211162021-06-12 15:40:11 -0700682the server sends any number of responses. The client invokes the RPC by sending
683a ``REQUEST`` with no payload. It sends a ``CLIENT_STREAM_END`` packet when it
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700684has finished sending requests. The server sends a ``RESPONSE`` packet to finish
685the RPC.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700686
Wyatt Hepler1d221242021-09-07 15:42:21 -0700687.. image:: bidirectional_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700688
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700689The server may finish the RPC at any time by sending the ``RESPONSE`` packet,
690even if it has not received the ``CLIENT_STREAM_END`` packet. The client may
Wyatt Hepler17169152021-10-20 18:46:08 -0700691terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
692``CANCELLED``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700693
Wyatt Hepler1d221242021-09-07 15:42:21 -0700694.. image:: bidirectional_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700695
Wyatt Hepler948f5472020-06-02 16:52:28 -0700696RPC server
697==========
698Declare an instance of ``rpc::Server`` and register services with it.
699
700.. admonition:: TODO
701
702 Document the public interface
703
Alexei Frolovbf33d212020-09-15 17:13:45 -0700704Size report
705-----------
706The following size report showcases the memory usage of the core RPC server. It
707is configured with a single channel using a basic transport interface that
708directly reads from and writes to ``pw_sys_io``. The transport has a 128-byte
709packet buffer, which comprises the plurality of the example's RAM usage. This is
710not a suitable transport for an actual product; a real implementation would have
711additional overhead proportional to the complexity of the transport.
712
713.. include:: server_size
714
Wyatt Hepler948f5472020-06-02 16:52:28 -0700715RPC server implementation
716-------------------------
717
718The Method class
719^^^^^^^^^^^^^^^^
720The RPC Server depends on the ``pw::rpc::internal::Method`` class. ``Method``
721serves as the bridge between the ``pw_rpc`` server library and the user-defined
Wyatt Heplere95bd722020-11-23 07:49:47 -0800722RPC functions. Each supported protobuf implementation extends ``Method`` to
723implement its request and response proto handling. The ``pw_rpc`` server
724calls into the ``Method`` implementation through the base class's ``Invoke``
725function.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700726
Wyatt Heplere95bd722020-11-23 07:49:47 -0800727``Method`` implementations store metadata about each method, including a
728function pointer to the user-defined method implementation. They also provide
729``static constexpr`` functions for creating each type of method. ``Method``
730implementations must satisfy the ``MethodImplTester`` test class in
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -0700731``pw_rpc/internal/method_impl_tester.h``.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700732
Wyatt Heplere95bd722020-11-23 07:49:47 -0800733See ``pw_rpc/internal/method.h`` for more details about ``Method``.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700734
735Packet flow
736^^^^^^^^^^^
737
738Requests
739~~~~~~~~
740
Wyatt Hepler1d221242021-09-07 15:42:21 -0700741.. image:: request_packets.svg
Wyatt Hepler948f5472020-06-02 16:52:28 -0700742
743Responses
744~~~~~~~~~
745
Wyatt Hepler1d221242021-09-07 15:42:21 -0700746.. image:: response_packets.svg
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700747
748RPC client
749==========
750The RPC client is used to send requests to a server and manages the contexts of
751ongoing RPCs.
752
753Setting up a client
754-------------------
755The ``pw::rpc::Client`` class is instantiated with a list of channels that it
756uses to communicate. These channels can be shared with a server, but multiple
757clients cannot use the same channels.
758
759To send incoming RPC packets from the transport layer to be processed by a
760client, the client's ``ProcessPacket`` function is called with the packet data.
761
762.. code:: c++
763
764 #include "pw_rpc/client.h"
765
766 namespace {
767
768 pw::rpc::Channel my_channels[] = {
769 pw::rpc::Channel::Create<1>(&my_channel_output)};
770 pw::rpc::Client my_client(my_channels);
771
772 } // namespace
773
774 // Called when the transport layer receives an RPC packet.
775 void ProcessRpcPacket(ConstByteSpan packet) {
776 my_client.ProcessPacket(packet);
777 }
778
Alexei Frolov5a3a61c2020-10-01 18:51:41 -0700779.. _module-pw_rpc-making-calls:
780
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700781Making RPC calls
782----------------
783RPC calls are not made directly through the client, but using one of its
784registered channels instead. A service client class is generated from a .proto
785file for each selected protobuf library, which is then used to send RPC requests
786through a given channel. The API for this depends on the protobuf library;
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700787please refer to the
788:ref:`appropriate documentation<module-pw_rpc-protobuf-library-apis>`. Multiple
789service client implementations can exist simulatenously and share the same
790``Client`` class.
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700791
792When a call is made, a ``pw::rpc::ClientCall`` object is returned to the caller.
793This object tracks the ongoing RPC call, and can be used to manage it. An RPC
794call is only active as long as its ``ClientCall`` object is alive.
795
796.. tip::
797 Use ``std::move`` when passing around ``ClientCall`` objects to keep RPCs
798 alive.
799
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700800Example
801^^^^^^^
802.. code-block:: c++
803
804 #include "pw_rpc/echo_service_nanopb.h"
805
806 namespace {
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700807 // Generated clients are namespaced with their proto library.
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800808 using EchoClient = pw_rpc::nanopb::EchoService::Client;
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700809
Alexei Frolov73687fb2021-09-03 11:22:33 -0700810 // RPC channel ID on which to make client calls.
811 constexpr uint32_t kDefaultChannelId = 1;
812
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800813 EchoClient::EchoCall echo_call;
Alexei Frolovbebba902021-06-09 17:03:52 -0700814
815 // Callback invoked when a response is received. This is called synchronously
816 // from Client::ProcessPacket.
817 void EchoResponse(const pw_rpc_EchoMessage& response,
818 pw::Status status) {
819 if (status.ok()) {
820 PW_LOG_INFO("Received echo response: %s", response.msg);
821 } else {
822 PW_LOG_ERROR("Echo failed with status %d",
823 static_cast<int>(status.code()));
824 }
825 }
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700826
827 } // namespace
828
829 void CallEcho(const char* message) {
Alexei Frolov73687fb2021-09-03 11:22:33 -0700830 // Create a client to call the EchoService.
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800831 EchoClient echo_client(my_rpc_client, kDefaultChannelId);
Alexei Frolov73687fb2021-09-03 11:22:33 -0700832
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700833 pw_rpc_EchoMessage request = pw_rpc_EchoMessage_init_default;
834 pw::string::Copy(message, request.msg);
835
836 // By assigning the returned ClientCall to the global echo_call, the RPC
837 // call is kept alive until it completes. When a response is received, it
838 // will be logged by the handler function and the call will complete.
Alexei Frolov73687fb2021-09-03 11:22:33 -0700839 echo_call = echo_client.Echo(request, EchoResponse);
840 if (!echo_call.active()) {
841 // The RPC call was not sent. This could occur due to, for example, an
842 // invalid channel ID. Handle if necessary.
843 }
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700844 }
845
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700846Client implementation details
847-----------------------------
848
849The ClientCall class
850^^^^^^^^^^^^^^^^^^^^
851``ClientCall`` stores the context of an active RPC, and serves as the user's
852interface to the RPC client. The core RPC library provides a base ``ClientCall``
853class with common functionality, which is then extended for RPC client
854implementations tied to different protobuf libraries to provide convenient
855interfaces for working with RPCs.
856
857The RPC server stores a list of all of active ``ClientCall`` objects. When an
858incoming packet is recieved, it dispatches to one of its active calls, which
859then decodes the payload and presents it to the user.
Alexei Frolov3e280922021-04-12 14:53:06 -0700860
861ClientServer
862============
863Sometimes, a device needs to both process RPCs as a server, as well as making
864calls to another device as a client. To do this, both a client and server must
865be set up, and incoming packets must be sent to both of them.
866
867Pigweed simplifies this setup by providing a ``ClientServer`` class which wraps
868an RPC client and server with the same set of channels.
869
870.. code-block:: cpp
871
872 pw::rpc::Channel channels[] = {
873 pw::rpc::Channel::Create<1>(&channel_output)};
874
875 // Creates both a client and a server.
876 pw::rpc::ClientServer client_server(channels);
877
878 void ProcessRpcData(pw::ConstByteSpan packet) {
879 // Calls into both the client and the server, sending the packet to the
880 // appropriate one.
Alexei Frolovba93a432021-12-02 13:36:26 -0800881 client_server.ProcessPacket(packet);
Alexei Frolov3e280922021-04-12 14:53:06 -0700882 }
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800883
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800884Testing
885=======
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800886``pw_rpc`` provides utilities for unit testing RPC services and client calls.
887
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800888Client unit testing in C++
889--------------------------
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800890``pw_rpc`` supports invoking RPCs, simulating server responses, and checking
891what packets are sent by an RPC client in tests. Both raw and Nanopb interfaces
892are supported. Code that uses the raw API may be tested with the Nanopb test
893helpers, and vice versa.
894
895To test code that invokes RPCs, declare a ``RawClientTestContext`` or
896``NanopbClientTestContext``. These test context objects provide a
897preconfigured RPC client, channel, server fake, and buffer for encoding packets.
898These test classes are defined in ``pw_rpc/raw/client_testing.h`` and
899``pw_rpc/nanopb/client_testing.h``.
900
901Use the context's ``client()`` and ``channel()`` to invoke RPCs. Use the
902context's ``server()`` to simulate responses. To verify that the client sent the
903expected data, use the context's ``output()``, which is a ``FakeChannelOutput``.
904
905For example, the following tests a class that invokes an RPC. It checks that
906the expected data was sent and then simulates a response from the server.
907
908.. code-block:: cpp
909
910 #include "pw_rpc/raw/client_testing.h"
911
912 class ThingThatCallsRpcs {
913 public:
914 // To support injecting an RPC client for testing, classes that make RPC
915 // calls should take an RPC client and channel ID or an RPC service client
916 // (e.g. pw_rpc::raw::MyService::Client).
917 ThingThatCallsRpcs(pw::rpc::Client& client, uint32_t channel_id);
918
919 void DoSomethingThatInvokesAnRpc();
920
921 bool SetToTrueWhenRpcCompletes();
922 };
923
924 TEST(TestAThing, InvokesRpcAndHandlesResponse) {
925 RawClientTestContext context;
926 ThingThatCallsRpcs thing(context.client(), context.channel().id());
927
928 // Execute the code that invokes the MyService.TheMethod RPC.
929 things.DoSomethingThatInvokesAnRpc();
930
931 // Find and verify the payloads sent for the MyService.TheMethod RPC.
932 auto msgs = context.output().payloads<pw_rpc::raw::MyService::TheMethod>();
933 ASSERT_EQ(msgs.size(), 1u);
934
935 VerifyThatTheExpectedMessageWasSent(msgs.back());
936
937 // Send the response packet from the server and verify that the class reacts
938 // accordingly.
939 EXPECT_FALSE(thing.SetToTrueWhenRpcCompletes());
940
941 context_.server().SendResponse<pw_rpc::raw::MyService::TheMethod>(
942 final_message, OkStatus());
943
944 EXPECT_TRUE(thing.SetToTrueWhenRpcCompletes());
945 }
Ewout van Bekkum7f5b3052021-11-11 17:35:23 -0800946
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800947Integration testing with ``pw_rpc``
948-----------------------------------
949``pw_rpc`` provides utilities to simplify writing integration tests for systems
950that communicate with ``pw_rpc``. The integration test utitilies set up a socket
951to use for IPC between an RPC server and client process.
952
953The server binary uses the system RPC server facade defined
954``pw_rpc_system_server/rpc_server.h``. The client binary uses the functions
955defined in ``pw_rpc/integration_testing.h``:
956
957.. cpp:var:: constexpr uint32_t kChannelId
958
959 The RPC channel for integration test RPCs.
960
961.. cpp:function:: pw::rpc::Client& pw::rpc::integration_test::Client()
962
963 Returns the global RPC client for integration test use.
964
965.. cpp:function:: pw::Status pw::rpc::integration_test::InitializeClient(int argc, char* argv[], const char* usage_args = "PORT")
966
967 Initializes logging and the global RPC client for integration testing. Starts
968 a background thread that processes incoming.
969
Ewout van Bekkum7f5b3052021-11-11 17:35:23 -0800970Module Configuration Options
971============================
972The following configurations can be adjusted via compile-time configuration of
973this module, see the
974:ref:`module documentation <module-structure-compile-time-configuration>` for
975more details.
976
977.. c:macro:: PW_RPC_CLIENT_STREAM_END_CALLBACK
978
979 In client and bidirectional RPCs, pw_rpc clients may signal that they have
980 finished sending requests with a CLIENT_STREAM_END packet. While this can be
981 useful in some circumstances, it is often not necessary.
982
983 This option controls whether or not include a callback that is called when
984 the client stream ends. The callback is included in all ServerReader/Writer
985 objects as a pw::Function, so may have a significant cost.
986
987 This is disabled by default.
988
989.. c:macro:: PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
990
991 The Nanopb-based pw_rpc implementation allocates memory to use for Nanopb
992 structs for the request and response protobufs. The template function that
993 allocates these structs rounds struct sizes up to this value so that
994 different structs can be allocated with the same function. Structs with sizes
995 larger than this value cause an extra function to be created, which slightly
996 increases code size.
997
998 Ideally, this value will be set to the size of the largest Nanopb struct used
999 as an RPC request or response. The buffer can be stack or globally allocated
1000 (see ``PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE``).
1001
1002 This defaults to 64 Bytes.
1003
1004.. c:macro:: PW_RPC_USE_GLOBAL_MUTEX
1005
1006 Enable global synchronization for RPC calls. If this is set, a backend must
1007 be configured for pw_sync:mutex.
1008
1009 This is disabled by default.
1010
1011.. c:macro:: PW_RPC_CONFIG_LOG_LEVEL
1012
1013 The log level to use for this module. Logs below this level are omitted.
1014
1015 This defaults to ``PW_LOG_LEVEL_INFO``.
1016
1017.. c:macro:: PW_RPC_CONFIG_LOG_MODULE_NAME
1018
1019 The log module name to use for this module.
1020
1021 This defaults to ``"PW_RPC"``.
1022
1023.. c:macro:: PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
1024
1025 This option determines whether to allocate the Nanopb structs on the stack or
1026 in a global variable. Globally allocated structs are NOT thread safe, but
1027 work fine when the RPC server's ProcessPacket function is only called from
1028 one thread.
1029
1030 This is enabled by default.
Wyatt Hepler14439762021-11-09 09:16:32 -08001031
1032Sharing server and client code
1033==============================
1034Streaming RPCs support writing multiple requests or responses. To facilitate
1035sharing code between servers and clients, ``pw_rpc`` provides the
1036``pw::rpc::Writer`` interface. On the client side, a client or bidirectional
1037streaming RPC call object (``ClientWriter`` or ``ClientReaderWriter``) can be
1038used as a ``pw::rpc::Writer&``. On the server side, a server or bidirectional
1039streaming RPC call object (``ServerWriter`` or ``ServerReaderWriter``) can be
1040used as a ``pw::rpc::Writer&``.