• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_rpc:
2
3======
4pw_rpc
5======
6The ``pw_rpc`` module provides a system for defining and invoking remote
7procedure calls (RPCs) on a device.
8
9This 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
17  ts/docs
18
19.. admonition:: Try it out!
20
21  For a quick intro to ``pw_rpc``, see the
22  :ref:`module-pw_hdlc-rpc-example` in the :ref:`module-pw_hdlc` module.
23
24.. warning::
25
26  This documentation is under construction. Many sections are outdated or
27  incomplete. The content needs to be reorgnanized.
28
29---------------
30Implementations
31---------------
32Pigweed provides several client and server implementations of ``pw_rpc``.
33
34.. list-table::
35  :header-rows: 1
36
37  * - Language
38    - Server
39    - Client
40  * - C++ (raw)
41    - ✅
42    - ✅
43  * - C++ (Nanopb)
44    - ✅
45    - ✅
46  * - C++ (pw_protobuf)
47    - ✅
48    - ✅
49  * - Java
50    -
51    - ✅
52  * - Python
53    -
54    - ✅
55  * - TypeScript
56    -
57    - in development
58
59-------------
60RPC semantics
61-------------
62The semantics of ``pw_rpc`` are similar to `gRPC
63<https://grpc.io/docs/what-is-grpc/core-concepts/>`_.
64
65RPC call lifecycle
66==================
67In ``pw_rpc``, an RPC begins when the client sends an initial packet. The server
68receives the packet, looks up the relevant service method, then calls into the
69RPC function. The RPC is considered active until the server sends a status to
70finish the RPC. The client may terminate an ongoing RPC by cancelling it.
71
72Depending the type of RPC, the client and server exchange zero or more protobuf
73request or response payloads. There are four RPC types:
74
75* **Unary**. The client sends one request and the server sends one
76  response with a status.
77* **Server streaming**. The client sends one request and the server sends zero
78  or more responses followed by a status.
79* **Client streaming**. The client sends zero or more requests and the server
80  sends one response with a status.
81* **Bidirectional streaming**. The client sends zero or more requests and the
82  server sends zero or more responses followed by a status.
83
84Events
85------
86The key events in the RPC lifecycle are:
87
88* **Start**. The client initiates the RPC. The server's RPC body executes.
89* **Finish**. The server sends a status and completes the RPC. The client calls
90  a callback.
91* **Request**. The client sends a request protobuf. The server calls a callback
92  when it receives it. In unary and server streaming RPCs, there is only one
93  request and it is handled when the RPC starts.
94* **Response**. The server sends a response protobuf. The client calls a
95  callback when it receives it. In unary and client streaming RPCs, there is
96  only one response and it is handled when the RPC completes.
97* **Error**. The server or client terminates the RPC abnormally with a status.
98  The receiving endpoint calls a callback.
99* **Client stream end**. The client sends a message that it has finished sending
100  requests. The server calls a callback when it receives it. Some servers may
101  ignore the client stream end. The client stream end is only relevant for
102  client and bidirectional streaming RPCs.
103
104Status codes
105============
106``pw_rpc`` call objects (``ClientReaderWriter``, ``ServerReaderWriter``, etc.)
107use certain status codes to indicate what occurred. These codes are returned
108from functions like ``Write()`` or ``Finish()``.
109
110* ``OK`` -- The operation succeeded.
111* ``UNAVAILABLE`` -- The channel is not currently registered with the server or
112  client.
113* ``UNKNOWN`` -- Sending a packet failed due to an unrecoverable
114  :cpp:func:`pw::rpc::ChannelOutput::Send` error.
115
116Unrequested responses
117=====================
118``pw_rpc`` supports sending responses to RPCs that have not yet been invoked by
119a client. This is useful in testing and in situations like an RPC that triggers
120reboot. After the reboot, the device opens the writer object and sends its
121response to the client.
122
123The C++ API for opening a server reader/writer takes the generated RPC function
124as a template parameter. The server to use, channel ID, and service instance are
125passed as arguments. The API is the same for all RPC types, except the
126appropriate reader/writer class must be used.
127
128.. code-block:: c++
129
130  // Open a ServerWriter for a server streaming RPC.
131  auto writer = RawServerWriter::Open<pw_rpc::raw::ServiceName::MethodName>(
132      server, channel_id, service_instance);
133
134  // Send some responses, even though the client has not yet called this RPC.
135  CHECK_OK(writer.Write(encoded_response_1));
136  CHECK_OK(writer.Write(encoded_response_2));
137
138  // Finish the RPC.
139  CHECK_OK(writer.Finish(OkStatus()));
140
141---------------
142Creating an RPC
143---------------
144
1451. RPC service declaration
146==========================
147Pigweed RPCs are declared in a protocol buffer service definition.
148
149* `Protocol Buffer service documentation
150  <https://developers.google.com/protocol-buffers/docs/proto3#services>`_
151* `gRPC service definition documentation
152  <https://grpc.io/docs/what-is-grpc/core-concepts/#service-definition>`_
153
154.. code-block:: protobuf
155
156  syntax = "proto3";
157
158  package foo.bar;
159
160  message Request {}
161
162  message Response {
163    int32 number = 1;
164  }
165
166  service TheService {
167    rpc MethodOne(Request) returns (Response) {}
168    rpc MethodTwo(Request) returns (stream Response) {}
169  }
170
171This protocol buffer is declared in a ``BUILD.gn`` file as follows:
172
173.. code-block:: python
174
175  import("//build_overrides/pigweed.gni")
176  import("$dir_pw_protobuf_compiler/proto.gni")
177
178  pw_proto_library("the_service_proto") {
179    sources = [ "foo_bar/the_service.proto" ]
180  }
181
182.. admonition:: proto2 or proto3 syntax?
183
184  Always use proto3 syntax rather than proto2 for new protocol buffers. Proto2
185  protobufs can be compiled for ``pw_rpc``, but they are not as well supported
186  as proto3. Specifically, ``pw_rpc`` lacks support for non-zero default values
187  in proto2. When using Nanopb with ``pw_rpc``, proto2 response protobufs with
188  non-zero field defaults should be manually initialized to the default struct.
189
190  In the past, proto3 was sometimes avoided because it lacked support for field
191  presence detection. Fortunately, this has been fixed: proto3 now supports
192  ``optional`` fields, which are equivalent to proto2 ``optional`` fields.
193
194  If you need to distinguish between a default-valued field and a missing field,
195  mark the field as ``optional``. The presence of the field can be detected
196  with ``std::optional``, a ``HasField(name)``, or ``has_<field>`` member,
197  depending on the library.
198
199  Optional fields have some overhead --- if using Nanopb, default-valued fields
200  are included in the encoded proto, and the proto structs have a
201  ``has_<field>`` flag for each optional field. Use plain fields if field
202  presence detection is not needed.
203
204  .. code-block:: protobuf
205
206    syntax = "proto3";
207
208    message MyMessage {
209      // Leaving this field unset is equivalent to setting it to 0.
210      int32 number = 1;
211
212      // Setting this field to 0 is different from leaving it unset.
213      optional int32 other_number = 2;
214    }
215
2162. RPC code generation
217======================
218``pw_rpc`` generates a C++ header file for each ``.proto`` file. This header is
219generated in the build output directory. Its exact location varies by build
220system and toolchain, but the C++ include path always matches the sources
221declaration in the ``pw_proto_library``. The ``.proto`` extension is replaced
222with an extension corresponding to the protobuf library in use.
223
224================== =============== =============== =============
225Protobuf libraries Build subtarget Protobuf header pw_rpc header
226================== =============== =============== =============
227Raw only           .raw_rpc        (none)          .raw_rpc.pb.h
228Nanopb or raw      .nanopb_rpc     .pb.h           .rpc.pb.h
229pw_protobuf or raw .pwpb_rpc       .pwpb.h         .rpc.pwpb.h
230================== =============== =============== =============
231
232For example, the generated RPC header for ``"foo_bar/the_service.proto"`` is
233``"foo_bar/the_service.rpc.pb.h"`` for Nanopb or
234``"foo_bar/the_service.raw_rpc.pb.h"`` for raw RPCs.
235
236The generated header defines a base class for each RPC service declared in the
237``.proto`` file. A service named ``TheService`` in package ``foo.bar`` would
238generate the following base class for pw_protobuf:
239
240.. cpp:class:: template <typename Implementation> foo::bar::pw_rpc::pwpb::TheService::Service
241
2423. RPC service definition
243=========================
244The serivce class is implemented by inheriting from the generated RPC service
245base class and defining a method for each RPC. The methods must match the name
246and function signature for one of the supported protobuf implementations.
247Services may mix and match protobuf implementations within one service.
248
249.. tip::
250
251  The generated code includes RPC service implementation stubs. You can
252  reference or copy and paste these to get started with implementing a service.
253  These stub classes are generated at the bottom of the pw_rpc proto header.
254
255  To use the stubs, do the following:
256
257  #. Locate the generated RPC header in the build directory. For example:
258
259     .. code-block:: sh
260
261       find out/ -name <proto_name>.rpc.pwpb.h
262
263  #. Scroll to the bottom of the generated RPC header.
264  #. Copy the stub class declaration to a header file.
265  #. Copy the member function definitions to a source file.
266  #. Rename the class or change the namespace, if desired.
267  #. List these files in a build target with a dependency on the
268     ``pw_proto_library``.
269
270A pw_protobuf implementation of this service would be as follows:
271
272.. code-block:: cpp
273
274  #include "foo_bar/the_service.rpc.pwpb.h"
275
276  namespace foo::bar {
277
278  class TheService : public pw_rpc::pwpb::TheService::Service<TheService> {
279   public:
280    pw::Status MethodOne(const Request::Message& request,
281                         Response::Message& response) {
282      // implementation
283      response.number = 123;
284      return pw::OkStatus();
285    }
286
287    void MethodTwo(const Request::Message& request,
288                   ServerWriter<Response::Message>& response) {
289      // implementation
290      response.Write({.number = 123});
291    }
292  };
293
294  }  // namespace foo::bar
295
296The pw_protobuf implementation would be declared in a ``BUILD.gn``:
297
298.. code-block:: python
299
300  import("//build_overrides/pigweed.gni")
301
302  import("$dir_pw_build/target_types.gni")
303
304  pw_source_set("the_service") {
305    public_configs = [ ":public" ]
306    public = [ "public/foo_bar/service.h" ]
307    public_deps = [ ":the_service_proto.pwpb_rpc" ]
308  }
309
3104. Register the service with a server
311=====================================
312This example code sets up an RPC server with an :ref:`HDLC<module-pw_hdlc>`
313channel output and the example service.
314
315.. code-block:: cpp
316
317  // Set up the output channel for the pw_rpc server to use. This configures the
318  // pw_rpc server to use HDLC over UART; projects not using UART and HDLC must
319  // adapt this as necessary.
320  pw::stream::SysIoWriter writer;
321  pw::rpc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
322      writer, pw::hdlc::kDefaultRpcAddress, "HDLC output");
323
324  // Allocate an array of channels for the server to use. If dynamic allocation
325  // is enabled (PW_RPC_DYNAMIC_ALLOCATION=1), the server can be initialized
326  // without any channels, and they can be added later.
327  pw::rpc::Channel channels[] = {
328      pw::rpc::Channel::Create<1>(&hdlc_channel_output)};
329
330  // Declare the pw_rpc server with the HDLC channel.
331  pw::rpc::Server server(channels);
332
333  foo::bar::TheService the_service;
334  pw::rpc::SomeOtherService some_other_service;
335
336  void RegisterServices() {
337    // Register the foo.bar.TheService example service and another service.
338    server.RegisterService(the_service, some_other_service);
339  }
340
341  int main() {
342    // Set up the server.
343    RegisterServices();
344
345    // Declare a buffer for decoding incoming HDLC frames.
346    std::array<std::byte, kMaxTransmissionUnit> input_buffer;
347
348    PW_LOG_INFO("Starting pw_rpc server");
349    pw::hdlc::ReadAndProcessPackets(server, input_buffer);
350  }
351
352--------
353Channels
354--------
355``pw_rpc`` sends all of its packets over channels. These are logical,
356application-layer routes used to tell the RPC system where a packet should go.
357
358Channels over a client-server connection must all have a unique ID, which can be
359assigned statically at compile time or dynamically.
360
361.. code-block:: cpp
362
363  // Creating a channel with the static ID 3.
364  pw::rpc::Channel static_channel = pw::rpc::Channel::Create<3>(&output);
365
366  // Grouping channel IDs within an enum can lead to clearer code.
367  enum ChannelId {
368    kUartChannel = 1,
369    kSpiChannel = 2,
370  };
371
372  // Creating a channel with a static ID defined within an enum.
373  pw::rpc::Channel another_static_channel =
374      pw::rpc::Channel::Create<ChannelId::kUartChannel>(&output);
375
376  // Creating a channel with a dynamic ID (note that no output is provided; it
377  // will be set when the channel is used.
378  pw::rpc::Channel dynamic_channel;
379
380Sometimes, the ID and output of a channel are not known at compile time as they
381depend on information stored on the physical device. To support this use case, a
382dynamically-assignable channel can be configured once at runtime with an ID and
383output.
384
385.. code-block:: cpp
386
387  // Create a dynamic channel without a compile-time ID or output.
388  pw::rpc::Channel dynamic_channel;
389
390  void Init() {
391    // Called during boot to pull the channel configuration from the system.
392    dynamic_channel.Configure(GetChannelId(), some_output);
393  }
394
395Adding and removing channels
396============================
397New channels may be registered with the ``OpenChannel`` function. If dynamic
398allocation is enabled (:c:macro:`PW_RPC_DYNAMIC_ALLOCATION` is 1), any number of
399channels may be registered. If dynamic allocation is disabled, new channels may
400only be registered if there are availale channel slots in the span provided to
401the RPC endpoint at construction.
402
403A channel may be closed and unregistered with an endpoint by calling
404``ChannelClose`` on the endpoint with the corresponding channel ID.  This
405will terminate any pending calls and call their ``on_error`` callback
406with the ``ABORTED`` status.
407
408.. code-block:: cpp
409
410  // When a channel is closed, any pending calls will receive
411  // on_error callbacks with ABORTED status.
412  client->CloseChannel(1);
413
414--------
415Services
416--------
417A service is a logical grouping of RPCs defined within a .proto file. ``pw_rpc``
418uses these .proto definitions to generate code for a base service, from which
419user-defined RPCs are implemented.
420
421``pw_rpc`` supports multiple protobuf libraries, and the generated code API
422depends on which is used.
423
424Services must be registered with a server in order to call their methods.
425Services may later be unregistered, which aborts calls for methods in that
426service and prevents future calls to them, until the service is re-registered.
427
428.. _module-pw_rpc-protobuf-library-apis:
429
430---------------------
431Protobuf library APIs
432---------------------
433
434.. toctree::
435  :maxdepth: 1
436
437  pwpb/docs
438  nanopb/docs
439
440----------------------------
441Testing a pw_rpc integration
442----------------------------
443After setting up a ``pw_rpc`` server in your project, you can test that it is
444working as intended by registering the provided ``EchoService``, defined in
445``echo.proto``, which echoes back a message that it receives.
446
447.. literalinclude:: echo.proto
448  :language: protobuf
449  :lines: 14-
450
451For example, in C++ with pw_protobuf:
452
453.. code:: c++
454
455  #include "pw_rpc/server.h"
456
457  // Include the apporpriate header for your protobuf library.
458  #include "pw_rpc/echo_service_pwpb.h"
459
460  constexpr pw::rpc::Channel kChannels[] = { /* ... */ };
461  static pw::rpc::Server server(kChannels);
462
463  static pw::rpc::EchoService echo_service;
464
465  void Init() {
466    server.RegisterService(echo_service);
467  }
468
469Benchmarking and stress testing
470===============================
471
472.. toctree::
473  :maxdepth: 1
474  :hidden:
475
476  benchmark
477
478``pw_rpc`` provides an RPC service and Python module for stress testing and
479benchmarking a ``pw_rpc`` deployment. See :ref:`module-pw_rpc-benchmark`.
480
481------
482Naming
483------
484
485Reserved names
486==============
487``pw_rpc`` reserves a few service method names so they can be used for generated
488classes. The following names cannnot be used for service methods:
489
490- ``Client``
491- ``Service``
492- Any reserved words in the languages ``pw_rpc`` supports (e.g. ``class``).
493
494``pw_rpc`` does not reserve any service names, but the restriction of avoiding
495reserved words in supported languages applies.
496
497Service naming style
498====================
499``pw_rpc`` service names should use capitalized camel case and should not use
500the term "Service". Appending "Service" to a service name is redundant, similar
501to appending "Class" or "Function" to a class or function name. The
502C++ implementation class may use "Service" in its name, however.
503
504For example, a service for accessing a file system should simply be named
505``service FileSystem``, rather than ``service FileSystemService``, in the
506``.proto`` file.
507
508.. code-block:: protobuf
509
510  // file.proto
511  package pw.file;
512
513  service FileSystem {
514      rpc List(ListRequest) returns (stream ListResponse);
515  }
516
517The C++ service implementation class may append "Service" to the name.
518
519.. code-block:: cpp
520
521  // file_system_service.h
522  #include "pw_file/file.raw_rpc.pb.h"
523
524  namespace pw::file {
525
526  class FileSystemService : public pw_rpc::raw::FileSystem::Service<FileSystemService> {
527    void List(ConstByteSpan request, RawServerWriter& writer);
528  };
529
530  }  // namespace pw::file
531
532For upstream Pigweed services, this naming style is a requirement. Note that
533some services created before this was established may use non-compliant
534names. For Pigweed users, this naming style is a suggestion.
535
536------------------------------
537C++ payload sizing limitations
538------------------------------
539The individual size of each sent RPC request or response is limited by
540``pw_rpc``'s ``PW_RPC_ENCODING_BUFFER_SIZE_BYTES`` configuration option when
541using Pigweed's C++ implementation. While multiple RPC messages can be enqueued
542(as permitted by the underlying transport), if a single individual sent message
543exceeds the limitations of the statically allocated encode buffer, the packet
544will fail to encode and be dropped.
545
546This applies to all C++ RPC service implementations (nanopb, raw, and pwpb),
547so it's important to ensure request and response message sizes do not exceed
548this limitation.
549
550As ``pw_rpc`` has some additional encoding overhead, a helper,
551``pw::rpc::MaxSafePayloadSize()`` is provided to expose the practical max RPC
552message payload size.
553
554.. code-block:: cpp
555
556  #include "pw_file/file.raw_rpc.pb.h"
557  #include "pw_rpc/channel.h"
558
559  namespace pw::file {
560
561  class FileSystemService : public pw_rpc::raw::FileSystem::Service<FileSystemService> {
562   public:
563    void List(ConstByteSpan request, RawServerWriter& writer);
564
565   private:
566    // Allocate a buffer for building proto responses.
567    static constexpr size_t kEncodeBufferSize = pw::rpc::MaxSafePayloadSize();
568    std::array<std::byte, kEncodeBufferSize> encode_buffer_;
569  };
570
571  }  // namespace pw::file
572
573--------------------
574Protocol description
575--------------------
576Pigweed RPC servers and clients communicate using ``pw_rpc`` packets. These
577packets are used to send requests and responses, control streams, cancel ongoing
578RPCs, and report errors.
579
580Packet format
581=============
582Pigweed RPC packets consist of a type and a set of fields. The packets are
583encoded as protocol buffers. The full packet format is described in
584``pw_rpc/pw_rpc/internal/packet.proto``.
585
586.. literalinclude:: internal/packet.proto
587  :language: protobuf
588  :lines: 14-
589
590The packet type and RPC type determine which fields are present in a Pigweed RPC
591packet. Each packet type is only sent by either the client or the server.
592These tables describe the meaning of and fields included with each packet type.
593
594Client-to-server packets
595------------------------
596+-------------------+-------------------------------------+
597| packet type       | description                         |
598+===================+=====================================+
599| REQUEST           | Invoke an RPC                       |
600|                   |                                     |
601|                   | .. code-block:: text                |
602|                   |                                     |
603|                   |   - channel_id                      |
604|                   |   - service_id                      |
605|                   |   - method_id                       |
606|                   |   - payload                         |
607|                   |     (unary & server streaming only) |
608|                   |   - call_id (optional)              |
609|                   |                                     |
610+-------------------+-------------------------------------+
611| CLIENT_STREAM     | Message in a client stream          |
612|                   |                                     |
613|                   | .. code-block:: text                |
614|                   |                                     |
615|                   |   - channel_id                      |
616|                   |   - service_id                      |
617|                   |   - method_id                       |
618|                   |   - payload                         |
619|                   |   - call_id (if set in REQUEST)     |
620|                   |                                     |
621+-------------------+-------------------------------------+
622| CLIENT_STREAM_END | Client stream is complete           |
623|                   |                                     |
624|                   | .. code-block:: text                |
625|                   |                                     |
626|                   |   - channel_id                      |
627|                   |   - service_id                      |
628|                   |   - method_id                       |
629|                   |   - call_id (if set in REQUEST)     |
630|                   |                                     |
631+-------------------+-------------------------------------+
632| CLIENT_ERROR      | Abort an ongoing RPC                |
633|                   |                                     |
634|                   | .. code-block:: text                |
635|                   |                                     |
636|                   |   - channel_id                      |
637|                   |   - service_id                      |
638|                   |   - method_id                       |
639|                   |   - status                          |
640|                   |   - call_id (if set in REQUEST)     |
641|                   |                                     |
642+-------------------+-------------------------------------+
643
644**Client errors**
645
646The client sends ``CLIENT_ERROR`` packets to a server when it receives a packet
647it did not request. If possible, the server should abort it.
648
649The status code indicates the type of error. The status code is logged, but all
650status codes result in the same action by the server: aborting the RPC.
651
652* ``CANCELLED`` -- The client requested that the RPC be cancelled.
653* ``ABORTED`` -- The RPC was aborted due its channel being closed.
654* ``NOT_FOUND`` -- Received a packet for a service method the client does not
655  recognize.
656* ``FAILED_PRECONDITION`` -- Received a packet for a service method that the
657  client did not invoke.
658* ``DATA_LOSS`` -- Received a corrupt packet for a pending service method.
659* ``INVALID_ARGUMENT`` -- The server sent a packet type to an RPC that does not
660  support it (a ``SERVER_STREAM`` was sent to an RPC with no server stream).
661* ``UNAVAILABLE`` -- Received a packet for an unknown channel.
662
663Server-to-client packets
664------------------------
665+-------------------+-------------------------------------+
666| packet type       | description                         |
667+===================+=====================================+
668| RESPONSE          | The RPC is complete                 |
669|                   |                                     |
670|                   | .. code-block:: text                |
671|                   |                                     |
672|                   |   - channel_id                      |
673|                   |   - service_id                      |
674|                   |   - method_id                       |
675|                   |   - status                          |
676|                   |   - payload                         |
677|                   |     (unary & client streaming only) |
678|                   |   - call_id (if set in REQUEST)     |
679|                   |                                     |
680+-------------------+-------------------------------------+
681| SERVER_STREAM     | Message in a server stream          |
682|                   |                                     |
683|                   | .. code-block:: text                |
684|                   |                                     |
685|                   |   - channel_id                      |
686|                   |   - service_id                      |
687|                   |   - method_id                       |
688|                   |   - payload                         |
689|                   |   - call_id (if set in REQUEST)     |
690|                   |                                     |
691+-------------------+-------------------------------------+
692| SERVER_ERROR      | Received unexpected packet          |
693|                   |                                     |
694|                   | .. code-block:: text                |
695|                   |                                     |
696|                   |   - channel_id                      |
697|                   |   - service_id (if relevant)        |
698|                   |   - method_id (if relevant)         |
699|                   |   - status                          |
700|                   |   - call_id (if set in REQUEST)     |
701|                   |                                     |
702+-------------------+-------------------------------------+
703
704All server packets contain the same ``call_id`` that was set in the initial
705request made by the client, if any.
706
707**Server errors**
708
709The server sends ``SERVER_ERROR`` packets when it receives a packet it cannot
710process. The client should abort any RPC for which it receives an error. The
711status field indicates the type of error.
712
713* ``NOT_FOUND`` -- The requested service or method does not exist.
714* ``FAILED_PRECONDITION`` -- A client stream or cancel packet was sent for an
715  RPC that is not pending.
716* ``INVALID_ARGUMENT`` -- The client sent a packet type to an RPC that does not
717  support it (a ``CLIENT_STREAM`` was sent to an RPC with no client stream).
718* ``RESOURCE_EXHAUSTED`` -- The request came on a new channel, but a channel
719  could not be allocated for it.
720* ``ABORTED`` -- The RPC was aborted due its channel being closed.
721* ``INTERNAL`` -- The server was unable to respond to an RPC due to an
722  unrecoverable internal error.
723* ``UNAVAILABLE`` -- Received a packet for an unknown channel.
724
725Inovking a service method
726=========================
727Calling an RPC requires a specific sequence of packets. This section describes
728the protocol for calling service methods of each type: unary, server streaming,
729client streaming, and bidirectional streaming.
730
731The basic flow for all RPC invocations is as follows:
732
733  * Client sends a ``REQUEST`` packet. Includes a payload for unary & server
734    streaming RPCs.
735  * For client and bidirectional streaming RPCs, the client may send any number
736    of ``CLIENT_STREAM`` packets with payloads.
737  * For server and bidirectional streaming RPCs, the server may send any number
738    of ``SERVER_STREAM`` packets.
739  * The server sends a ``RESPONSE`` packet. Includes a payload for unary &
740    client streaming RPCs. The RPC is complete.
741
742The client may cancel an ongoing RPC at any time by sending a ``CLIENT_ERROR``
743packet with status ``CANCELLED``. The server may finish an ongoing RPC at any
744time by sending the ``RESPONSE`` packet.
745
746Unary RPC
747---------
748In a unary RPC, the client sends a single request and the server sends a single
749response.
750
751.. image:: unary_rpc.svg
752
753The client may attempt to cancel a unary RPC by sending a ``CLIENT_ERROR``
754packet with status ``CANCELLED``. The server sends no response to a cancelled
755RPC. If the server processes the unary RPC synchronously (the handling thread
756sends the response), it may not be possible to cancel the RPC.
757
758.. image:: unary_rpc_cancelled.svg
759
760Server streaming RPC
761--------------------
762In a server streaming RPC, the client sends a single request and the server
763sends any number of ``SERVER_STREAM`` packets followed by a ``RESPONSE`` packet.
764
765.. image:: server_streaming_rpc.svg
766
767The client may terminate a server streaming RPC by sending a ``CLIENT_STREAM``
768packet with status ``CANCELLED``. The server sends no response.
769
770.. image:: server_streaming_rpc_cancelled.svg
771
772Client streaming RPC
773--------------------
774In a client streaming RPC, the client starts the RPC by sending a ``REQUEST``
775packet with no payload. It then sends any number of messages in
776``CLIENT_STREAM`` packets, followed by a ``CLIENT_STREAM_END``. The server sends
777a single ``RESPONSE`` to finish the RPC.
778
779.. image:: client_streaming_rpc.svg
780
781The server may finish the RPC at any time by sending its ``RESPONSE`` packet,
782even if it has not yet received the ``CLIENT_STREAM_END`` packet. The client may
783terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
784``CANCELLED``.
785
786.. image:: client_streaming_rpc_cancelled.svg
787
788Bidirectional streaming RPC
789--------------------^^^^^^^
790In a bidirectional streaming RPC, the client sends any number of requests and
791the server sends any number of responses. The client invokes the RPC by sending
792a ``REQUEST`` with no payload. It sends a ``CLIENT_STREAM_END`` packet when it
793has finished sending requests. The server sends a ``RESPONSE`` packet to finish
794the RPC.
795
796.. image:: bidirectional_streaming_rpc.svg
797
798The server may finish the RPC at any time by sending the ``RESPONSE`` packet,
799even if it has not received the ``CLIENT_STREAM_END`` packet. The client may
800terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
801``CANCELLED``.
802
803.. image:: bidirectional_streaming_rpc_cancelled.svg
804
805-------
806C++ API
807-------
808
809RPC server
810==========
811Declare an instance of ``rpc::Server`` and register services with it.
812
813.. admonition:: TODO
814
815  Document the public interface
816
817Size report
818-----------
819The following size report showcases the memory usage of the core RPC server. It
820is configured with a single channel using a basic transport interface that
821directly reads from and writes to ``pw_sys_io``. The transport has a 128-byte
822packet buffer, which comprises the plurality of the example's RAM usage. This is
823not a suitable transport for an actual product; a real implementation would have
824additional overhead proportional to the complexity of the transport.
825
826.. include:: server_size
827
828RPC server implementation
829-------------------------
830
831The Method class
832^^^^^^^^^^^^^^^^
833The RPC Server depends on the ``pw::rpc::internal::Method`` class. ``Method``
834serves as the bridge between the ``pw_rpc`` server library and the user-defined
835RPC functions. Each supported protobuf implementation extends ``Method`` to
836implement its request and response proto handling. The ``pw_rpc`` server
837calls into the ``Method`` implementation through the base class's ``Invoke``
838function.
839
840``Method`` implementations store metadata about each method, including a
841function pointer to the user-defined method implementation. They also provide
842``static constexpr`` functions for creating each type of method. ``Method``
843implementations must satisfy the ``MethodImplTester`` test class in
844``pw_rpc/internal/method_impl_tester.h``.
845
846See ``pw_rpc/internal/method.h`` for more details about ``Method``.
847
848Packet flow
849^^^^^^^^^^^
850
851Requests
852........
853
854.. image:: request_packets.svg
855
856Responses
857.........
858
859.. image:: response_packets.svg
860
861RPC client
862==========
863The RPC client is used to send requests to a server and manages the contexts of
864ongoing RPCs.
865
866Setting up a client
867-------------------
868The ``pw::rpc::Client`` class is instantiated with a list of channels that it
869uses to communicate. These channels can be shared with a server, but multiple
870clients cannot use the same channels.
871
872To send incoming RPC packets from the transport layer to be processed by a
873client, the client's ``ProcessPacket`` function is called with the packet data.
874
875.. code:: c++
876
877  #include "pw_rpc/client.h"
878
879  namespace {
880
881  pw::rpc::Channel my_channels[] = {
882      pw::rpc::Channel::Create<1>(&my_channel_output)};
883  pw::rpc::Client my_client(my_channels);
884
885  }  // namespace
886
887  // Called when the transport layer receives an RPC packet.
888  void ProcessRpcPacket(ConstByteSpan packet) {
889    my_client.ProcessPacket(packet);
890  }
891
892Note that client processing such as callbacks will be invoked within
893the body of ``ProcessPacket``.
894
895If certain packets need to be filtered out, or if certain client processing
896needs to be invoked from a specific thread or context, the ``PacketMeta`` class
897can be used to determine which service or channel a packet is targeting. After
898filtering, ``ProcessPacket`` can be called from the appropriate environment.
899
900.. _module-pw_rpc-making-calls:
901
902Making RPC calls
903----------------
904RPC calls are not made directly through the client, but using one of its
905registered channels instead. A service client class is generated from a .proto
906file for each selected protobuf library, which is then used to send RPC requests
907through a given channel. The API for this depends on the protobuf library;
908please refer to the
909:ref:`appropriate documentation<module-pw_rpc-protobuf-library-apis>`. Multiple
910service client implementations can exist simulatenously and share the same
911``Client`` class.
912
913When a call is made, a call object is returned to the caller. This object tracks
914the ongoing RPC call, and can be used to manage it. An RPC call is only active
915as long as its call object is alive.
916
917.. tip::
918  Use ``std::move`` when passing around call objects to keep RPCs alive.
919
920Example
921^^^^^^^
922.. code-block:: c++
923
924  #include "pw_rpc/echo_service_nanopb.h"
925
926  namespace {
927  // Generated clients are namespaced with their proto library.
928  using EchoClient = pw_rpc::nanopb::EchoService::Client;
929
930  // RPC channel ID on which to make client calls. RPC calls cannot be made on
931  // channel 0 (Channel::kUnassignedChannelId).
932  constexpr uint32_t kDefaultChannelId = 1;
933
934  pw::rpc::NanopbUnaryReceiver<pw_rpc_EchoMessage> echo_call;
935
936  // Callback invoked when a response is received. This is called synchronously
937  // from Client::ProcessPacket.
938  void EchoResponse(const pw_rpc_EchoMessage& response,
939                    pw::Status status) {
940    if (status.ok()) {
941      PW_LOG_INFO("Received echo response: %s", response.msg);
942    } else {
943      PW_LOG_ERROR("Echo failed with status %d",
944                   static_cast<int>(status.code()));
945    }
946  }
947
948  }  // namespace
949
950  void CallEcho(const char* message) {
951    // Create a client to call the EchoService.
952    EchoClient echo_client(my_rpc_client, kDefaultChannelId);
953
954    pw_rpc_EchoMessage request{};
955    pw::string::Copy(message, request.msg);
956
957    // By assigning the returned call to the global echo_call, the RPC
958    // call is kept alive until it completes. When a response is received, it
959    // will be logged by the handler function and the call will complete.
960    echo_call = echo_client.Echo(request, EchoResponse);
961    if (!echo_call.active()) {
962      // The RPC call was not sent. This could occur due to, for example, an
963      // invalid channel ID. Handle if necessary.
964    }
965  }
966
967Call objects
968============
969An RPC call is represented by a call object. Server and client calls use the
970same base call class in C++, but the public API is different depending on the
971type of call (see `RPC call lifecycle`_) and whether it is being used by the
972server or client.
973
974The public call types are as follows:
975
976.. list-table::
977  :header-rows: 1
978
979  * - RPC Type
980    - Server call
981    - Client call
982  * - Unary
983    - ``(Raw|Nanopb|Pwpb)UnaryResponder``
984    - ``(Raw|Nanopb|Pwpb)UnaryReceiver``
985  * - Server streaming
986    - ``(Raw|Nanopb|Pwpb)ServerWriter``
987    - ``(Raw|Nanopb|Pwpb)ClientReader``
988  * - Client streaming
989    - ``(Raw|Nanopb|Pwpb)ServerReader``
990    - ``(Raw|Nanopb|Pwpb)ClientWriter``
991  * - Bidirectional streaming
992    - ``(Raw|Nanopb|Pwpb)ServerReaderWriter``
993    - ``(Raw|Nanopb|Pwpb)ClientReaderWriter``
994
995Client call API
996---------------
997Client call objects provide a few common methods.
998
999.. cpp:class:: pw::rpc::ClientCallType
1000
1001  The ``ClientCallType`` will be one of the following types:
1002
1003  - ``(Raw|Nanopb|Pwpb)UnaryReceiver`` for unary
1004  - ``(Raw|Nanopb|Pwpb)ClientReader`` for server streaming
1005  - ``(Raw|Nanopb|Pwpb)ClientWriter`` for client streaming
1006  - ``(Raw|Nanopb|Pwpb)ClientReaderWriter`` for bidirectional streaming
1007
1008  .. cpp:function:: bool active() const
1009
1010    Returns true if the call is active.
1011
1012  .. cpp:function:: uint32_t channel_id() const
1013
1014    Returns the channel ID of this call, which is 0 if the call is inactive.
1015
1016  .. cpp:function:: uint32_t id() const
1017
1018    Returns the call ID, a unique identifier for this call.
1019
1020  .. cpp:function:: void Write(RequestType)
1021
1022    Only available on client and bidirectional streaming calls. Sends a stream
1023    request. Returns:
1024
1025    - ``OK`` - the request was successfully sent
1026    - ``FAILED_PRECONDITION`` - the writer is closed
1027    - ``INTERNAL`` - pw_rpc was unable to encode message; does not apply to raw
1028      calls
1029    - other errors - the :cpp:class:`ChannelOutput` failed to send the packet;
1030      the error codes are determined by the :cpp:class:`ChannelOutput`
1031      implementation
1032
1033  .. cpp:function:: pw::Status CloseClientStream()
1034
1035    Only available on client and bidirectional streaming calls. Notifies the
1036    server that no further client stream messages will be sent.
1037
1038  .. cpp:function:: pw::Status Cancel()
1039
1040    Cancels this RPC. Closes the call and sends a ``CANCELLED`` error to the
1041    server. Return statuses are the same as :cpp:func:`Write`.
1042
1043  .. cpp:function:: void Abandon()
1044
1045    Closes this RPC locally. Sends a ``CLIENT_STREAM_END``, but no cancellation
1046    packet. Future packets for this RPC are dropped, and the client sends a
1047    ``FAILED_PRECONDITION`` error in response because the call is not active.
1048
1049  .. cpp:function:: void set_on_completed(pw::Function<void(ResponseTypeIfUnaryOnly, pw::Status)>)
1050
1051    Sets the callback that is called when the RPC completes normally. The
1052    signature depends on whether the call has a unary or stream response.
1053
1054  .. cpp:function:: void set_on_error(pw::Function<void(pw::Status)>)
1055
1056    Sets the callback that is called when the RPC is terminated due to an error.
1057
1058  .. cpp:function:: void set_on_next(pw::Function<void(ResponseType)>)
1059
1060    Only available on server and bidirectional streaming calls. Sets the callback
1061    that is called for each stream response.
1062
1063Callbacks
1064---------
1065The C++ call objects allow users to set callbacks that are invoked when RPC
1066`events`_ occur.
1067
1068.. list-table::
1069  :header-rows: 1
1070
1071  * - Name
1072    - Stream signature
1073    - Non-stream signature
1074    - Server
1075    - Client
1076  * - ``on_error``
1077    - ``void(pw::Status)``
1078    - ``void(pw::Status)``
1079    - ✅
1080    - ✅
1081  * - ``on_next``
1082    - n/a
1083    - ``void(const PayloadType&)``
1084    - ✅
1085    - ✅
1086  * - ``on_completed``
1087    - ``void(pw::Status)``
1088    - ``void(const PayloadType&, pw::Status)``
1089    -
1090    - ✅
1091  * - ``on_client_stream_end``
1092    - ``void()``
1093    - n/a
1094    - ✅ (:c:macro:`optional <PW_RPC_CLIENT_STREAM_END_CALLBACK>`)
1095    -
1096
1097Limitations and restrictions
1098^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1099RPC callbacks are free to perform most actions, including invoking new RPCs or
1100cancelling pending calls. However, the C++ implementation imposes some
1101limitations and restrictions that must be observed.
1102
1103Destructors & moves wait for callbacks to complete
1104...................................................
1105* Callbacks must not destroy their call object. Attempting to do so will result
1106  in deadlock.
1107* Other threads may destroy a call while its callback is running, but that
1108  thread will block until all callbacks complete.
1109* Callbacks must not move their call object if it the call is still active. They
1110  may move their call object after it has terminated. Callbacks may move a
1111  different call into their call object, since moving closes the destination
1112  call.
1113* Other threads may move a call object while it has a callback running, but they
1114  will block until the callback completes if the call is still active.
1115
1116.. warning::
1117
1118   Deadlocks or crashes occur if a callback:
1119
1120   - attempts to destroy its call object
1121   - attempts to move its call object while the call is still active
1122   - never returns
1123
1124   If ``pw_rpc`` a callback violates these restrictions, a crash may occur,
1125   depending on the value of :c:macro:`PW_RPC_CALLBACK_TIMEOUT_TICKS`. These
1126   crashes have a message like the following:
1127
1128   .. code-block:: text
1129
1130      A callback for RPC 1:cc0f6de0/31e616ce has not finished after 10000 ticks.
1131      This may indicate that an RPC callback attempted to destroy or move its own
1132      call object, which is not permitted. Fix this condition or change the value of
1133      PW_RPC_CALLBACK_TIMEOUT_TICKS to avoid this crash.
1134
1135      See https://pigweed.dev/pw_rpc#destructors-moves-wait-for-callbacks-to-complete
1136      for details.
1137
1138Only one thread at a time may execute ``on_next``
1139.................................................
1140Only one thread may execute the ``on_next`` callback for a specific service
1141method at a time. If a second thread calls ``ProcessPacket()`` with a stream
1142packet before the ``on_next`` callback for the previous packet completes, the
1143second packet will be dropped. The RPC endpoint logs a warning when this occurs.
1144
1145Example warning for a dropped stream packet:
1146
1147.. code-block:: text
1148
1149  WRN  Received stream packet for 1:cc0f6de0/31e616ce before the callback for
1150       a previous packet completed! This packet will be dropped. This can be
1151       avoided by handling packets for a particular RPC on only one thread.
1152
1153RPC calls introspection
1154=======================
1155``pw_rpc`` provides ``pw_rpc/method_info.h`` header that allows to obtain
1156information about the generated RPC method in compile time.
1157
1158For now it provides only two types: ``MethodRequestType<RpcMethod>`` and
1159``MethodResponseType<RpcMethod>``. They are aliases to the types that are used
1160as a request and response respectively for the given RpcMethod.
1161
1162Example
1163-------
1164We have an RPC service ``SpecialService`` with ``MyMethod`` method:
1165
1166.. code-block:: protobuf
1167
1168  package some.package;
1169  service SpecialService {
1170    rpc MyMethod(MyMethodRequest) returns (MyMethodResponse) {}
1171  }
1172
1173We also have a templated Storage type alias:
1174
1175.. code-block:: c++
1176
1177  template <auto kMethod>
1178  using Storage =
1179     std::pair<MethodRequestType<kMethod>, MethodResponseType<kMethod>>;
1180
1181``Storage<some::package::pw_rpc::pwpb::SpecialService::MyMethod>`` will
1182instantiate as:
1183
1184.. code-block:: c++
1185
1186  std::pair<some::package::MyMethodRequest::Message,
1187            some::package::MyMethodResponse::Message>;
1188
1189.. note::
1190
1191  Only nanopb and pw_protobuf have real types as
1192  ``MethodRequestType<RpcMethod>``/``MethodResponseType<RpcMethod>``. Raw has
1193  them both set as ``void``. In reality, they are ``pw::ConstByteSpan``. Any
1194  helper/trait that wants to use this types for raw methods should do a custom
1195  implementation that copies the bytes under the span instead of copying just
1196  the span.
1197
1198Client Synchronous Call wrappers
1199================================
1200If synchronous behavior is desired when making client calls, users can use one
1201of the ``SynchronousCall<RpcMethod>`` wrapper functions to make their RPC call.
1202These wrappers effectively wrap the asynchronous Client RPC call with a timed
1203thread notification and return once a result is known or a timeout has occurred.
1204These return a ``SynchronousCallResult<Response>`` object, which can be queried
1205to determine whether any error scenarios occurred and, if not, access the
1206response.
1207
1208``SynchronousCall<RpcMethod>`` will block indefinitely, whereas
1209``SynchronousCallFor<RpcMethod>`` and ``SynchronousCallUntil<RpcMethod>`` will
1210block for a given timeout or until a deadline, respectively. All wrappers work
1211with both the standalone static RPC functions and the generated Client member
1212methods.
1213
1214.. note:: Use of the SynchronousCall wrappers requires a TimedThreadNotification
1215   backend.
1216.. note:: Only nanopb and pw_protobuf Unary RPC methods are supported.
1217
1218Example
1219-------
1220.. code-block:: c++
1221
1222  #include "pw_rpc/synchronous_call.h"
1223
1224  void InvokeUnaryRpc() {
1225    pw::rpc::Client client;
1226    pw::rpc::Channel channel;
1227
1228    RoomInfoRequest request;
1229    SynchronousCallResult<RoomInfoResponse> result =
1230      SynchronousCall<Chat::GetRoomInformation>(client, channel.id(), request);
1231
1232    if (result.is_rpc_error()) {
1233      ShutdownClient(client);
1234    } else if (result.is_server_error()) {
1235      HandleServerError(result.status());
1236    } else if (result.is_timeout()) {
1237      // SynchronousCall will block indefinitely, so we should never get here.
1238      PW_UNREACHABLE();
1239    }
1240    HandleRoomInformation(std::move(result).response());
1241  }
1242
1243  void AnotherExample() {
1244    pw_rpc::nanopb::Chat::Client chat_client(client, channel);
1245    constexpr auto kTimeout = pw::chrono::SystemClock::for_at_least(500ms);
1246
1247    RoomInfoRequest request;
1248    auto result = SynchronousCallFor<Chat::GetRoomInformation>(
1249        chat_client, request, kTimeout);
1250
1251    if (result.is_timeout()) {
1252      RetryRoomRequest();
1253    } else {
1254    ...
1255    }
1256  }
1257
1258The ``SynchronousCallResult<Response>`` is also compatible with the PW_TRY
1259family of macros, but users should be aware that their use will lose information
1260about the type of error. This should only be used if the caller will handle all
1261error scenarios the same.
1262
1263.. code-block:: c++
1264
1265  pw::Status SyncRpc() {
1266    const RoomInfoRequest request;
1267    PW_TRY_ASSIGN(const RoomInfoResponse& response,
1268                  SynchronousCall<Chat::GetRoomInformation>(client, request));
1269    HandleRoomInformation(response);
1270    return pw::OkStatus();
1271  }
1272
1273ClientServer
1274============
1275Sometimes, a device needs to both process RPCs as a server, as well as making
1276calls to another device as a client. To do this, both a client and server must
1277be set up, and incoming packets must be sent to both of them.
1278
1279Pigweed simplifies this setup by providing a ``ClientServer`` class which wraps
1280an RPC client and server with the same set of channels.
1281
1282.. code-block:: cpp
1283
1284  pw::rpc::Channel channels[] = {
1285      pw::rpc::Channel::Create<1>(&channel_output)};
1286
1287  // Creates both a client and a server.
1288  pw::rpc::ClientServer client_server(channels);
1289
1290  void ProcessRpcData(pw::ConstByteSpan packet) {
1291    // Calls into both the client and the server, sending the packet to the
1292    // appropriate one.
1293    client_server.ProcessPacket(packet);
1294  }
1295
1296Testing
1297=======
1298``pw_rpc`` provides utilities for unit testing RPC services and client calls.
1299
1300Client unit testing in C++
1301--------------------------
1302``pw_rpc`` supports invoking RPCs, simulating server responses, and checking
1303what packets are sent by an RPC client in tests. Raw, Nanopb and Pwpb interfaces
1304are supported. Code that uses the raw API may be tested with the raw test
1305helpers, and vice versa. The Nanopb and Pwpb APIs also provides a test helper
1306with a real client-server pair that supports testing of asynchronous messaging.
1307
1308To test sychronous code that invokes RPCs, declare a ``RawClientTestContext``,
1309``PwpbClientTestContext``,  or ``NanopbClientTestContext``. These test context
1310objects provide a preconfigured RPC client, channel, server fake, and buffer for
1311encoding packets.
1312
1313These test classes are defined in ``pw_rpc/raw/client_testing.h``,
1314``pw_rpc/pwpb/client_testing.h``, or ``pw_rpc/nanopb/client_testing.h``.
1315
1316Use the context's ``client()`` and ``channel()`` to invoke RPCs. Use the
1317context's ``server()`` to simulate responses. To verify that the client sent the
1318expected data, use the context's ``output()``, which is a ``FakeChannelOutput``.
1319
1320For example, the following tests a class that invokes an RPC. It checks that
1321the expected data was sent and then simulates a response from the server.
1322
1323.. code-block:: cpp
1324
1325  #include "pw_rpc/raw/client_testing.h"
1326
1327  class ClientUnderTest {
1328   public:
1329    // To support injecting an RPC client for testing, classes that make RPC
1330    // calls should take an RPC client and channel ID or an RPC service client
1331    // (e.g. pw_rpc::raw::MyService::Client).
1332    ClientUnderTest(pw::rpc::Client& client, uint32_t channel_id);
1333
1334    void DoSomethingThatInvokesAnRpc();
1335
1336    bool SetToTrueWhenRpcCompletes();
1337  };
1338
1339  TEST(TestAThing, InvokesRpcAndHandlesResponse) {
1340    RawClientTestContext context;
1341    ClientUnderTest thing(context.client(), context.channel().id());
1342
1343    // Execute the code that invokes the MyService.TheMethod RPC.
1344    things.DoSomethingThatInvokesAnRpc();
1345
1346    // Find and verify the payloads sent for the MyService.TheMethod RPC.
1347    auto msgs = context.output().payloads<pw_rpc::raw::MyService::TheMethod>();
1348    ASSERT_EQ(msgs.size(), 1u);
1349
1350    VerifyThatTheExpectedMessageWasSent(msgs.back());
1351
1352    // Send the response packet from the server and verify that the class reacts
1353    // accordingly.
1354    EXPECT_FALSE(thing.SetToTrueWhenRpcCompletes());
1355
1356    context_.server().SendResponse<pw_rpc::raw::MyService::TheMethod>(
1357        final_message, OkStatus());
1358
1359    EXPECT_TRUE(thing.SetToTrueWhenRpcCompletes());
1360  }
1361
1362To test client code that uses asynchronous responses, encapsulates multiple
1363rpc calls to one or more services, or uses a custom service implemenation,
1364declare a ``NanopbClientServerTestContextThreaded`` or
1365``PwpbClientServerTestContextThreaded``. These test object are defined in
1366``pw_rpc/nanopb/client_server_testing_threaded.h`` and
1367``pw_rpc/pwpb/client_server_testing_threaded.h``.
1368
1369Use the context's ``server()`` to register a ``Service`` implementation, and
1370``client()`` and ``channel()`` to invoke RPCs. Create a ``Thread`` using the
1371context as a ``ThreadCore`` to have it asycronously forward request/responses or
1372call ``ForwardNewPackets`` to synchronously process all messages. To verify that
1373the client/server sent the expected data, use the context's
1374``request(uint32_t index)`` and ``response(uint32_t index)`` to retrieve the
1375ordered messages.
1376
1377For example, the following tests a class that invokes an RPC and blocks till a
1378response is received. It verifies that expected data was both sent and received.
1379
1380.. code-block:: cpp
1381
1382  #include "my_library_protos/my_service.rpc.pb.h"
1383  #include "pw_rpc/nanopb/client_server_testing_threaded.h"
1384  #include "pw_thread_stl/options.h"
1385
1386  class ClientUnderTest {
1387   public:
1388    // To support injecting an RPC client for testing, classes that make RPC
1389    // calls should take an RPC client and channel ID or an RPC service client
1390    // (e.g. pw_rpc::raw::MyService::Client).
1391    ClientUnderTest(pw::rpc::Client& client, uint32_t channel_id);
1392
1393    Status BlockOnResponse(uint32_t value);
1394  };
1395
1396
1397  class TestService final : public MyService<TestService> {
1398   public:
1399    Status TheMethod(const pw_rpc_test_TheMethod& request,
1400                        pw_rpc_test_TheMethod& response) {
1401      response.value = request.integer + 1;
1402      return pw::OkStatus();
1403    }
1404  };
1405
1406  TEST(TestServiceTest, ReceivesUnaryRpcReponse) {
1407    NanopbClientServerTestContextThreaded<> ctx(pw::thread::stl::Options{});
1408    TestService service;
1409    ctx.server().RegisterService(service);
1410    ClientUnderTest client(ctx.client(), ctx.channel().id());
1411
1412    // Execute the code that invokes the MyService.TheMethod RPC.
1413    constexpr uint32_t value = 1;
1414    const auto result = client.BlockOnResponse(value);
1415    const auto request = ctx.request<MyService::TheMethod>(0);
1416    const auto response = ctx.resonse<MyService::TheMethod>(0);
1417
1418    // Verify content of messages
1419    EXPECT_EQ(result, pw::OkStatus());
1420    EXPECT_EQ(request.value, value);
1421    EXPECT_EQ(response.value, value + 1);
1422  }
1423
1424Synchronous versions of these test contexts also exist that may be used on
1425non-threaded systems ``NanopbClientServerTestContext`` and
1426``PwpbClientServerTestContext``. While these do not allow for asynchronous
1427messaging they support the use of service implemenations and use a similar
1428syntax. When these are used ``.ForwardNewPackets()`` should be called after each
1429rpc call to trigger sending of queued messages.
1430
1431For example, the following tests a class that invokes an RPC that is responded
1432to with a test service implemenation.
1433
1434.. code-block:: cpp
1435
1436  #include "my_library_protos/my_service.rpc.pb.h"
1437  #include "pw_rpc/nanopb/client_server_testing.h"
1438
1439  class ClientUnderTest {
1440   public:
1441    ClientUnderTest(pw::rpc::Client& client, uint32_t channel_id);
1442
1443    Status SendRpcCall(uint32_t value);
1444  };
1445
1446
1447  class TestService final : public MyService<TestService> {
1448   public:
1449    Status TheMethod(const pw_rpc_test_TheMethod& request,
1450                        pw_rpc_test_TheMethod& response) {
1451      response.value = request.integer + 1;
1452      return pw::OkStatus();
1453    }
1454  };
1455
1456  TEST(TestServiceTest, ReceivesUnaryRpcReponse) {
1457    NanopbClientServerTestContext<> ctx();
1458    TestService service;
1459    ctx.server().RegisterService(service);
1460    ClientUnderTest client(ctx.client(), ctx.channel().id());
1461
1462    // Execute the code that invokes the MyService.TheMethod RPC.
1463    constexpr uint32_t value = 1;
1464    const auto result = client.SendRpcCall(value);
1465    // Needed after ever RPC call to trigger forward of packets
1466    ctx.ForwardNewPackets();
1467    const auto request = ctx.request<MyService::TheMethod>(0);
1468    const auto response = ctx.resonse<MyService::TheMethod>(0);
1469
1470    // Verify content of messages
1471    EXPECT_EQ(result, pw::OkStatus());
1472    EXPECT_EQ(request.value, value);
1473    EXPECT_EQ(response.value, value + 1);
1474  }
1475
1476SendResponseIfCalled() helper
1477-----------------------------
1478``SendResponseIfCalled()`` function waits on ``*ClientTestContext*`` output to
1479have a call for the specified method and then responses to it. It supports
1480timeout for the waiting part (default timeout is 100ms).
1481
1482.. code:: c++
1483
1484  #include "pw_rpc/test_helpers.h"
1485
1486  pw::rpc::PwpbClientTestContext client_context;
1487  other::pw_rpc::pwpb::OtherService::Client other_service_client(
1488      client_context.client(), client_context.channel().id());
1489
1490  PW_PWPB_TEST_METHOD_CONTEXT(MyService, GetData)
1491  context(other_service_client);
1492  context.call({});
1493
1494  ASSERT_OK(pw::rpc::test::SendResponseIfCalled<
1495            other::pw_rpc::pwpb::OtherService::GetPart>(
1496      client_context, {.value = 42}));
1497
1498  // At this point MyService::GetData handler received the GetPartResponse.
1499
1500Integration testing with ``pw_rpc``
1501-----------------------------------
1502``pw_rpc`` provides utilities to simplify writing integration tests for systems
1503that communicate with ``pw_rpc``. The integration test utitilies set up a socket
1504to use for IPC between an RPC server and client process.
1505
1506The server binary uses the system RPC server facade defined
1507``pw_rpc_system_server/rpc_server.h``. The client binary uses the functions
1508defined in ``pw_rpc/integration_testing.h``:
1509
1510.. cpp:var:: constexpr uint32_t kChannelId
1511
1512  The RPC channel for integration test RPCs.
1513
1514.. cpp:function:: pw::rpc::Client& pw::rpc::integration_test::Client()
1515
1516 Returns the global RPC client for integration test use.
1517
1518.. cpp:function:: pw::Status pw::rpc::integration_test::InitializeClient(int argc, char* argv[], const char* usage_args = "PORT")
1519
1520  Initializes logging and the global RPC client for integration testing. Starts
1521  a background thread that processes incoming.
1522
1523Module Configuration Options
1524============================
1525The following configurations can be adjusted via compile-time configuration of
1526this module, see the
1527:ref:`module documentation <module-structure-compile-time-configuration>` for
1528more details.
1529
1530.. doxygenfile:: pw_rpc/public/pw_rpc/internal/config.h
1531  :sections: define
1532
1533Sharing server and client code
1534==============================
1535Streaming RPCs support writing multiple requests or responses. To facilitate
1536sharing code between servers and clients, ``pw_rpc`` provides the
1537``pw::rpc::Writer`` interface. On the client side, a client or bidirectional
1538streaming RPC call object (``ClientWriter`` or ``ClientReaderWriter``) can be
1539used as a ``pw::rpc::Writer&``. On the server side, a server or bidirectional
1540streaming RPC call object (``ServerWriter`` or ``ServerReaderWriter``) can be
1541used as a ``pw::rpc::Writer&``.
1542
1543Zephyr
1544======
1545To enable ``pw_rpc.*`` for Zephyr add ``CONFIG_PIGWEED_RPC=y`` to the project's
1546configuration. This will enable the Kconfig menu for the following:
1547
1548* ``pw_rpc.server`` which can be enabled via ``CONFIG_PIGWEED_RPC_SERVER=y``.
1549* ``pw_rpc.client`` which can be enabled via ``CONFIG_PIGWEED_RPC_CLIENT=y``.
1550* ``pw_rpc.client_server`` which can be enabled via
1551  ``CONFIG_PIGWEED_RPC_CLIENT_SERVER=y``.
1552* ``pw_rpc.common` which can be enabled via ``CONFIG_PIGWEED_RPC_COMMON=y``.
1553
1554Encoding and sending packets
1555============================
1556``pw_rpc`` has to manage interactions among multiple RPC clients, servers,
1557client calls, and server calls. To safely synchronize these interactions with
1558minimal overhead, ``pw_rpc`` uses a single, global mutex (when
1559``PW_RPC_USE_GLOBAL_MUTEX`` is enabled).
1560
1561Because ``pw_rpc`` uses a global mutex, it also uses a global buffer to encode
1562outgoing packets. The size of the buffer is set with
1563``PW_RPC_ENCODING_BUFFER_SIZE_BYTES``, which defaults to 512 B. If dynamic
1564allocation is enabled, this size does not affect how large RPC messages can be,
1565but it is still used for sizing buffers in test utilities.
1566
1567Users of ``pw_rpc`` must implement the :cpp:class:`pw::rpc::ChannelOutput`
1568interface.
1569
1570.. _module-pw_rpc-ChannelOutput:
1571.. cpp:class:: pw::rpc::ChannelOutput
1572
1573  ``pw_rpc`` endpoints use :cpp:class:`ChannelOutput` instances to send packets.
1574  Systems that integrate pw_rpc must use one or more :cpp:class:`ChannelOutput`
1575  instances.
1576
1577  .. cpp:member:: static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max()
1578
1579    Value returned from :cpp:func:`MaximumTransmissionUnit` to indicate an
1580    unlimited MTU.
1581
1582  .. cpp:function:: virtual size_t MaximumTransmissionUnit()
1583
1584    Returns the size of the largest packet the :cpp:class:`ChannelOutput` can
1585    send. :cpp:class:`ChannelOutput` implementations should only override this
1586    function if they impose a limit on the MTU. The default implementation
1587    returns :cpp:member:`kUnlimited`, which indicates that there is no MTU
1588    limit.
1589
1590  .. cpp:function:: virtual pw::Status Send(span<std::byte> packet)
1591
1592    Sends an encoded RPC packet. Returns OK if further packets may be sent, even
1593    if the current packet could not be sent. Returns any other status if the
1594    Channel is no longer able to send packets.
1595
1596    The RPC system's internal lock is held while this function is called. Avoid
1597    long-running operations, since these will delay any other users of the RPC
1598    system.
1599
1600    .. danger::
1601
1602      No ``pw_rpc`` APIs may be accessed in this function! Implementations MUST
1603      NOT access any RPC endpoints (:cpp:class:`pw::rpc::Client`,
1604      :cpp:class:`pw::rpc::Server`) or call objects
1605      (:cpp:class:`pw::rpc::ServerReaderWriter`,
1606      :cpp:class:`pw::rpc::ClientReaderWriter`, etc.) inside the :cpp:func:`Send`
1607      function or any descendent calls. Doing so will result in deadlock! RPC APIs
1608      may be used by other threads, just not within :cpp:func:`Send`.
1609
1610      The buffer provided in ``packet`` must NOT be accessed outside of this
1611      function. It must be sent immediately or copied elsewhere before the
1612      function returns.
1613