blob: 25554f05a1f146b65d44492229283d06a70ad6ab [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 Hepler592b5a12022-02-01 17:55:21 -080024.. warning::
Alexei Frolov26e3ae62020-05-04 17:06:17 -070025
Wyatt Hepler592b5a12022-02-01 17:55:21 -080026 This documentation is under construction. Many sections are outdated or
27 incomplete. The content needs to be reorgnanized.
Wyatt Hepler455b4922020-09-18 00:19:21 -070028
Wyatt Hepler3b4f89a2021-12-06 16:18:53 -080029Implementations
30===============
31Pigweed provides several client and server implementations of ``pw_rpc``.
32
33.. list-table::
34 :header-rows: 1
35
36 * - Language
37 - Server
38 - Client
39 * - C++ (raw)
40 - ✅
41 - ✅
42 * - C++ (Nanopb)
43 - ✅
44 - ✅
45 * - C++ (pw_protobuf)
46 - planned
47 - planned
48 * - Java
49 -
50 - in development
51 * - Python
52 -
53 - ✅
54 * - TypeScript
55 -
56 - in development
57
Wyatt Hepler85e91402021-08-05 12:48:03 -070058RPC semantics
59=============
60The semantics of ``pw_rpc`` are similar to `gRPC
61<https://grpc.io/docs/what-is-grpc/core-concepts/>`_.
62
63RPC call lifecycle
64------------------
65In ``pw_rpc``, an RPC begins when the client sends a request packet. The server
66receives the request, looks up the relevant service method, then calls into the
67RPC function. The RPC is considered active until the server sends a response
68packet with the RPC's status. The client may terminate an ongoing RPC by
69cancelling it.
70
71``pw_rpc`` supports only one RPC invocation per service/method/channel. If a
72client calls an ongoing RPC on the same channel, the server cancels the ongoing
73call and reinvokes the RPC with the new request. This applies to unary and
74streaming RPCs, though the server may not have an opportunity to cancel a
75synchronously handled unary RPC before it completes. The same RPC may be invoked
76multiple times simultaneously if the invocations are on different channels.
77
Wyatt Hepler592b5a12022-02-01 17:55:21 -080078Status codes
79------------
80``pw_rpc`` call objects (``ClientReaderWriter``, ``ServerReaderWriter``, etc.)
81use certain status codes to indicate what occurred. These codes are returned
82from functions like ``Write()`` or ``Finish()``.
83
84* ``OK`` -- The operation succeeded.
85* ``UNAVAILABLE`` -- The channel is not currently registered with the server or
86 client.
87* ``UNKNOWN`` -- Sending a packet failed due to an unrecoverable
88 :cpp:func:`pw::rpc::ChannelOutput::Send` error.
89
Wyatt Hepler5a3a36b2021-09-08 11:15:05 -070090Unrequested responses
91---------------------
92``pw_rpc`` supports sending responses to RPCs that have not yet been invoked by
93a client. This is useful in testing and in situations like an RPC that triggers
94reboot. After the reboot, the device opens the writer object and sends its
95response to the client.
96
Wyatt Heplerd95e1e92021-09-14 22:10:51 -070097The C++ API for opening a server reader/writer takes the generated RPC function
98as a template parameter. The server to use, channel ID, and service instance are
99passed as arguments. The API is the same for all RPC types, except the
100appropriate reader/writer class must be used.
Wyatt Hepler5a3a36b2021-09-08 11:15:05 -0700101
Wyatt Heplerd95e1e92021-09-14 22:10:51 -0700102.. code-block:: c++
103
104 // Open a ServerWriter for a server streaming RPC.
105 auto writer = RawServerWriter::Open<pw_rpc::raw::ServiceName::MethodName>(
106 server, channel_id, service_instance);
107
108 // Send some responses, even though the client has not yet called this RPC.
109 CHECK_OK(writer.Write(encoded_response_1));
110 CHECK_OK(writer.Write(encoded_response_2));
111
112 // Finish the RPC.
113 CHECK_OK(writer.Finish(OkStatus()));
Wyatt Hepler5a3a36b2021-09-08 11:15:05 -0700114
Wyatt Hepler455b4922020-09-18 00:19:21 -0700115Creating an RPC
116===============
117
1181. RPC service declaration
119--------------------------
120Pigweed RPCs are declared in a protocol buffer service definition.
121
122* `Protocol Buffer service documentation
123 <https://developers.google.com/protocol-buffers/docs/proto3#services>`_
124* `gRPC service definition documentation
125 <https://grpc.io/docs/what-is-grpc/core-concepts/#service-definition>`_
126
127.. code-block:: protobuf
128
129 syntax = "proto3";
130
131 package foo.bar;
132
133 message Request {}
134
135 message Response {
136 int32 number = 1;
137 }
138
139 service TheService {
140 rpc MethodOne(Request) returns (Response) {}
141 rpc MethodTwo(Request) returns (stream Response) {}
142 }
143
144This protocol buffer is declared in a ``BUILD.gn`` file as follows:
145
146.. code-block:: python
147
148 import("//build_overrides/pigweed.gni")
149 import("$dir_pw_protobuf_compiler/proto.gni")
150
151 pw_proto_library("the_service_proto") {
152 sources = [ "foo_bar/the_service.proto" ]
153 }
154
Wyatt Hepler830d26d2021-02-17 09:07:43 -0800155.. admonition:: proto2 or proto3 syntax?
156
157 Always use proto3 syntax rather than proto2 for new protocol buffers. Proto2
158 protobufs can be compiled for ``pw_rpc``, but they are not as well supported
159 as proto3. Specifically, ``pw_rpc`` lacks support for non-zero default values
160 in proto2. When using Nanopb with ``pw_rpc``, proto2 response protobufs with
161 non-zero field defaults should be manually initialized to the default struct.
162
163 In the past, proto3 was sometimes avoided because it lacked support for field
164 presence detection. Fortunately, this has been fixed: proto3 now supports
165 ``optional`` fields, which are equivalent to proto2 ``optional`` fields.
166
167 If you need to distinguish between a default-valued field and a missing field,
168 mark the field as ``optional``. The presence of the field can be detected
169 with a ``HasField(name)`` or ``has_<field>`` member, depending on the library.
170
171 Optional fields have some overhead --- default-valued fields are included in
172 the encoded proto, and, if using Nanopb, the proto structs have a
173 ``has_<field>`` flag for each optional field. Use plain fields if field
174 presence detection is not needed.
175
176 .. code-block:: protobuf
177
178 syntax = "proto3";
179
180 message MyMessage {
181 // Leaving this field unset is equivalent to setting it to 0.
182 int32 number = 1;
183
184 // Setting this field to 0 is different from leaving it unset.
185 optional int32 other_number = 2;
186 }
187
Wyatt Hepler8779bcd2020-11-25 07:25:16 -08001882. RPC code generation
189----------------------
190``pw_rpc`` generates a C++ header file for each ``.proto`` file. This header is
191generated in the build output directory. Its exact location varies by build
192system and toolchain, but the C++ include path always matches the sources
193declaration in the ``pw_proto_library``. The ``.proto`` extension is replaced
194with an extension corresponding to the protobuf library in use.
Wyatt Hepler455b4922020-09-18 00:19:21 -0700195
Wyatt Hepler8779bcd2020-11-25 07:25:16 -0800196================== =============== =============== =============
197Protobuf libraries Build subtarget Protobuf header pw_rpc header
198================== =============== =============== =============
199Raw only .raw_rpc (none) .raw_rpc.pb.h
200Nanopb or raw .nanopb_rpc .pb.h .rpc.pb.h
201pw_protobuf or raw .pwpb_rpc .pwpb.h .rpc.pwpb.h
202================== =============== =============== =============
203
204For example, the generated RPC header for ``"foo_bar/the_service.proto"`` is
205``"foo_bar/the_service.rpc.pb.h"`` for Nanopb or
206``"foo_bar/the_service.raw_rpc.pb.h"`` for raw RPCs.
207
208The generated header defines a base class for each RPC service declared in the
209``.proto`` file. A service named ``TheService`` in package ``foo.bar`` would
Wyatt Heplerd2496322021-09-10 17:22:14 -0700210generate the following base class for Nanopb:
Wyatt Hepler455b4922020-09-18 00:19:21 -0700211
Wyatt Heplerd2496322021-09-10 17:22:14 -0700212.. cpp:class:: template <typename Implementation> foo::bar::pw_rpc::nanopb::TheService::Service
Wyatt Hepler455b4922020-09-18 00:19:21 -0700213
Wyatt Hepler8779bcd2020-11-25 07:25:16 -08002143. RPC service definition
215-------------------------
216The serivce class is implemented by inheriting from the generated RPC service
217base class and defining a method for each RPC. The methods must match the name
218and function signature for one of the supported protobuf implementations.
219Services may mix and match protobuf implementations within one service.
220
221.. tip::
222
223 The generated code includes RPC service implementation stubs. You can
224 reference or copy and paste these to get started with implementing a service.
225 These stub classes are generated at the bottom of the pw_rpc proto header.
226
Wyatt Heplerdf38ed12021-03-24 08:42:48 -0700227 To use the stubs, do the following:
228
229 #. Locate the generated RPC header in the build directory. For example:
230
231 .. code-block:: sh
232
233 find out/ -name <proto_name>.rpc.pb.h
234
235 #. Scroll to the bottom of the generated RPC header.
236 #. Copy the stub class declaration to a header file.
237 #. Copy the member function definitions to a source file.
238 #. Rename the class or change the namespace, if desired.
239 #. List these files in a build target with a dependency on the
240 ``pw_proto_library``.
241
Wyatt Hepler455b4922020-09-18 00:19:21 -0700242A Nanopb implementation of this service would be as follows:
243
244.. code-block:: cpp
245
Wyatt Hepler8779bcd2020-11-25 07:25:16 -0800246 #include "foo_bar/the_service.rpc.pb.h"
247
Wyatt Hepler455b4922020-09-18 00:19:21 -0700248 namespace foo::bar {
249
Wyatt Heplerd2496322021-09-10 17:22:14 -0700250 class TheService : public pw_rpc::nanopb::TheService::Service<TheService> {
Wyatt Hepler455b4922020-09-18 00:19:21 -0700251 public:
Wyatt Hepler8e756e32021-11-18 09:59:27 -0800252 pw::Status MethodOne(const foo_bar_Request& request,
Wyatt Hepler455b4922020-09-18 00:19:21 -0700253 foo_bar_Response& response) {
254 // implementation
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800255 return pw::OkStatus();
Wyatt Hepler455b4922020-09-18 00:19:21 -0700256 }
257
Wyatt Hepler8e756e32021-11-18 09:59:27 -0800258 void MethodTwo(const foo_bar_Request& request,
Wyatt Hepler455b4922020-09-18 00:19:21 -0700259 ServerWriter<foo_bar_Response>& response) {
260 // implementation
261 response.Write(foo_bar_Response{.number = 123});
262 }
263 };
264
265 } // namespace foo::bar
266
267The Nanopb implementation would be declared in a ``BUILD.gn``:
268
269.. code-block:: python
270
271 import("//build_overrides/pigweed.gni")
272
273 import("$dir_pw_build/target_types.gni")
274
275 pw_source_set("the_service") {
276 public_configs = [ ":public" ]
277 public = [ "public/foo_bar/service.h" ]
Wyatt Hepler8779bcd2020-11-25 07:25:16 -0800278 public_deps = [ ":the_service_proto.nanopb_rpc" ]
Wyatt Hepler455b4922020-09-18 00:19:21 -0700279 }
280
281.. attention::
282
283 pw_rpc's generated classes will support using ``pw_protobuf`` or raw buffers
284 (no protobuf library) in the future.
285
Wyatt Hepler8779bcd2020-11-25 07:25:16 -08002864. Register the service with a server
Wyatt Hepler455b4922020-09-18 00:19:21 -0700287-------------------------------------
Alexei Frolovd3e5cb72021-01-08 13:08:45 -0800288This example code sets up an RPC server with an :ref:`HDLC<module-pw_hdlc>`
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700289channel output and the example service.
Wyatt Hepler455b4922020-09-18 00:19:21 -0700290
291.. code-block:: cpp
292
293 // Set up the output channel for the pw_rpc server to use. This configures the
294 // pw_rpc server to use HDLC over UART; projects not using UART and HDLC must
295 // adapt this as necessary.
296 pw::stream::SysIoWriter writer;
297 pw::rpc::RpcChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
Alexei Frolovd3e5cb72021-01-08 13:08:45 -0800298 writer, pw::hdlc::kDefaultRpcAddress, "HDLC output");
Wyatt Hepler455b4922020-09-18 00:19:21 -0700299
300 pw::rpc::Channel channels[] = {
301 pw::rpc::Channel::Create<1>(&hdlc_channel_output)};
302
303 // Declare the pw_rpc server with the HDLC channel.
304 pw::rpc::Server server(channels);
305
Wyatt Hepler7566bc82022-02-15 15:09:00 -0800306 foo::bar::TheService the_service;
307 pw::rpc::SomeOtherService some_other_service;
Wyatt Hepler455b4922020-09-18 00:19:21 -0700308
309 void RegisterServices() {
Wyatt Hepler7566bc82022-02-15 15:09:00 -0800310 // Register the foo.bar.TheService example service and another service.
311 server.RegisterService(the_service, some_other_service);
Wyatt Hepler455b4922020-09-18 00:19:21 -0700312 }
313
314 int main() {
315 // Set up the server.
316 RegisterServices();
317
318 // Declare a buffer for decoding incoming HDLC frames.
319 std::array<std::byte, kMaxTransmissionUnit> input_buffer;
320
321 PW_LOG_INFO("Starting pw_rpc server");
Alexei Frolovd3e5cb72021-01-08 13:08:45 -0800322 pw::hdlc::ReadAndProcessPackets(
Wyatt Hepler455b4922020-09-18 00:19:21 -0700323 server, hdlc_channel_output, input_buffer);
324 }
Wyatt Hepler948f5472020-06-02 16:52:28 -0700325
Alexei Frolov1c670a22021-04-09 10:18:17 -0700326Channels
327========
328``pw_rpc`` sends all of its packets over channels. These are logical,
329application-layer routes used to tell the RPC system where a packet should go.
330
331Channels over a client-server connection must all have a unique ID, which can be
332assigned statically at compile time or dynamically.
333
334.. code-block:: cpp
335
336 // Creating a channel with the static ID 3.
337 pw::rpc::Channel static_channel = pw::rpc::Channel::Create<3>(&output);
338
339 // Grouping channel IDs within an enum can lead to clearer code.
340 enum ChannelId {
341 kUartChannel = 1,
342 kSpiChannel = 2,
343 };
344
345 // Creating a channel with a static ID defined within an enum.
346 pw::rpc::Channel another_static_channel =
347 pw::rpc::Channel::Create<ChannelId::kUartChannel>(&output);
348
349 // Creating a channel with a dynamic ID (note that no output is provided; it
350 // will be set when the channel is used.
351 pw::rpc::Channel dynamic_channel;
352
Alexei Frolov567e6702021-04-13 09:13:02 -0700353Sometimes, the ID and output of a channel are not known at compile time as they
354depend on information stored on the physical device. To support this use case, a
355dynamically-assignable channel can be configured once at runtime with an ID and
356output.
357
358.. code-block:: cpp
359
360 // Create a dynamic channel without a compile-time ID or output.
361 pw::rpc::Channel dynamic_channel;
362
363 void Init() {
364 // Called during boot to pull the channel configuration from the system.
365 dynamic_channel.Configure(GetChannelId(), some_output);
366 }
367
Wyatt Hepler3d57eaa2022-02-01 18:31:07 -0800368Adding and removing channels
369----------------------------
370New channels may be registered with the ``OpenChannel`` function. If dynamic
371allocation is enabled (:c:macro:`PW_RPC_DYNAMIC_ALLOCATION` is 1), any number of
372channels may be registered. If dynamic allocation is disabled, new channels may
373only be registered if there are availale channel slots in the span provided to
374the RPC endpoint at construction.
375
Erik Gilling3b7159a2022-01-20 20:37:01 +0000376A channel may be closed and unregistered with an endpoint by calling
377``ChannelClose`` on the endpoint with the corresponding channel ID. This
378will terminate any pending calls and call their ``on_error`` callback
379with the ``ABORTED`` status.
380
381.. code-block:: cpp
382
383 // When a channel is closed, any pending calls will receive
384 // on_error callbacks with ABORTED status.
385 client->CloseChannel(1);
386
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700387Services
388========
389A service is a logical grouping of RPCs defined within a .proto file. ``pw_rpc``
390uses these .proto definitions to generate code for a base service, from which
391user-defined RPCs are implemented.
392
393``pw_rpc`` supports multiple protobuf libraries, and the generated code API
394depends on which is used.
395
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700396.. _module-pw_rpc-protobuf-library-apis:
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700397
398Protobuf library APIs
399=====================
400
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700401.. toctree::
402 :maxdepth: 1
403
404 nanopb/docs
405
406Testing a pw_rpc integration
407============================
408After setting up a ``pw_rpc`` server in your project, you can test that it is
409working as intended by registering the provided ``EchoService``, defined in
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800410``echo.proto``, which echoes back a message that it receives.
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700411
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800412.. literalinclude:: echo.proto
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700413 :language: protobuf
414 :lines: 14-
415
416For example, in C++ with nanopb:
417
418.. code:: c++
419
420 #include "pw_rpc/server.h"
421
422 // Include the apporpriate header for your protobuf library.
423 #include "pw_rpc/echo_service_nanopb.h"
424
425 constexpr pw::rpc::Channel kChannels[] = { /* ... */ };
426 static pw::rpc::Server server(kChannels);
427
428 static pw::rpc::EchoService echo_service;
429
430 void Init() {
Wyatt Hepler31b16ea2021-07-21 08:52:02 -0700431 server.RegisterService(echo_service);
Alexei Frolov7c7a3862020-07-16 15:36:02 -0700432 }
433
Wyatt Hepler31b16ea2021-07-21 08:52:02 -0700434Benchmarking and stress testing
435-------------------------------
436
437.. toctree::
438 :maxdepth: 1
439 :hidden:
440
441 benchmark
442
443``pw_rpc`` provides an RPC service and Python module for stress testing and
444benchmarking a ``pw_rpc`` deployment. See :ref:`module-pw_rpc-benchmark`.
445
Wyatt Hepler05d860d2021-09-22 09:43:10 -0700446Naming
447======
448
449Reserved names
450--------------
451``pw_rpc`` reserves a few service method names so they can be used for generated
452classes. The following names cannnot be used for service methods:
453
454- ``Client``
455- ``Service``
456- Any reserved words in the languages ``pw_rpc`` supports (e.g. ``class``).
457
458``pw_rpc`` does not reserve any service names, but the restriction of avoiding
459reserved words in supported languages applies.
460
461Service naming style
462--------------------
463``pw_rpc`` service names should use capitalized camel case and should not use
464the term "Service". Appending "Service" to a service name is redundant, similar
465to appending "Class" or "Function" to a class or function name. The
466C++ implementation class may use "Service" in its name, however.
467
468For example, a service for accessing a file system should simply be named
469``service FileSystem``, rather than ``service FileSystemService``, in the
470``.proto`` file.
471
472.. code-block:: protobuf
473
474 // file.proto
475 package pw.file;
476
477 service FileSystem {
478 rpc List(ListRequest) returns (stream ListResponse);
479 }
480
481The C++ service implementation class may append "Service" to the name.
482
483.. code-block:: cpp
484
485 // file_system_service.h
486 #include "pw_file/file.raw_rpc.pb.h"
487
488 namespace pw::file {
489
490 class FileSystemService : public pw_rpc::raw::FileSystem::Service<FileSystemService> {
Wyatt Hepler8e756e32021-11-18 09:59:27 -0800491 void List(ConstByteSpan request, RawServerWriter& writer);
Wyatt Hepler05d860d2021-09-22 09:43:10 -0700492 };
493
494 }
495
496For upstream Pigweed services, this naming style is a requirement. Note that
497some services created before this was established may use non-compliant
498names. For Pigweed users, this naming style is a suggestion.
499
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700500Protocol description
501====================
502Pigweed RPC servers and clients communicate using ``pw_rpc`` packets. These
503packets are used to send requests and responses, control streams, cancel ongoing
504RPCs, and report errors.
505
506Packet format
507-------------
508Pigweed RPC packets consist of a type and a set of fields. The packets are
509encoded as protocol buffers. The full packet format is described in
Wyatt Heplerba325e42021-03-08 14:23:34 -0800510``pw_rpc/pw_rpc/internal/packet.proto``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700511
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800512.. literalinclude:: internal/packet.proto
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700513 :language: protobuf
514 :lines: 14-
515
516The packet type and RPC type determine which fields are present in a Pigweed RPC
Wyatt Hepler0f262352020-07-29 09:51:27 -0700517packet. Each packet type is only sent by either the client or the server.
518These tables describe the meaning of and fields included with each packet type.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700519
Wyatt Hepler0f262352020-07-29 09:51:27 -0700520Client-to-server packets
521^^^^^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700522+-------------------+-------------------------------------+
523| packet type | description |
524+===================+=====================================+
525| REQUEST | Invoke an RPC |
526| | |
527| | .. code-block:: text |
528| | |
529| | - channel_id |
530| | - service_id |
531| | - method_id |
532| | - payload |
533| | (unary & server streaming only) |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700534| | - call_id (optional) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700535| | |
536+-------------------+-------------------------------------+
537| CLIENT_STREAM | Message in a client stream |
538| | |
539| | .. code-block:: text |
540| | |
541| | - channel_id |
542| | - service_id |
543| | - method_id |
544| | - payload |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700545| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700546| | |
547+-------------------+-------------------------------------+
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700548| CLIENT_STREAM_END | Client stream is complete |
549| | |
550| | .. code-block:: text |
551| | |
552| | - channel_id |
553| | - service_id |
554| | - method_id |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700555| | - call_id (if set in REQUEST) |
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700556| | |
557+-------------------+-------------------------------------+
Wyatt Hepler17169152021-10-20 18:46:08 -0700558| CLIENT_ERROR | Abort an ongoing RPC |
Wyatt Heplera9211162021-06-12 15:40:11 -0700559| | |
560| | .. code-block:: text |
561| | |
562| | - channel_id |
563| | - service_id |
564| | - method_id |
565| | - status |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700566| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700567| | |
568+-------------------+-------------------------------------+
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700569
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700570**Client errors**
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700571
Wyatt Hepler0f262352020-07-29 09:51:27 -0700572The client sends ``CLIENT_ERROR`` packets to a server when it receives a packet
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700573it did not request. If possible, the server should abort it.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700574
Wyatt Heplera9211162021-06-12 15:40:11 -0700575The status code indicates the type of error. The status code is logged, but all
576status codes result in the same action by the server: aborting the RPC.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700577
Wyatt Hepler17169152021-10-20 18:46:08 -0700578* ``CANCELLED`` -- The client requested that the RPC be cancelled.
Erik Gilling3b7159a2022-01-20 20:37:01 +0000579* ``ABORTED`` -- The RPC was aborted due its channel being closed.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700580* ``NOT_FOUND`` -- Received a packet for a service method the client does not
581 recognize.
582* ``FAILED_PRECONDITION`` -- Received a packet for a service method that the
583 client did not invoke.
Wyatt Hepler35240da2021-07-21 08:51:22 -0700584* ``DATA_LOSS`` -- Received a corrupt packet for a pending service method.
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700585* ``INVALID_ARGUMENT`` -- The server sent a packet type to an RPC that does not
586 support it (a ``SERVER_STREAM`` was sent to an RPC with no server stream).
Wyatt Hepler3d57eaa2022-02-01 18:31:07 -0800587* ``UNAVAILABLE`` -- Received a packet for an unknown channel.
Wyatt Hepler0f262352020-07-29 09:51:27 -0700588
589Server-to-client packets
590^^^^^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700591+-------------------+-------------------------------------+
592| packet type | description |
593+===================+=====================================+
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700594| RESPONSE | The RPC is complete |
595| | |
596| | .. code-block:: text |
597| | |
598| | - channel_id |
599| | - service_id |
600| | - method_id |
601| | - status |
602| | - payload |
603| | (unary & client streaming only) |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700604| | - call_id (if set in REQUEST) |
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700605| | |
606+-------------------+-------------------------------------+
607| SERVER_STREAM | Message in a server stream |
Wyatt Heplera9211162021-06-12 15:40:11 -0700608| | |
609| | .. code-block:: text |
610| | |
611| | - channel_id |
612| | - service_id |
613| | - method_id |
614| | - payload |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700615| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700616| | |
617+-------------------+-------------------------------------+
618| SERVER_ERROR | Received unexpected packet |
619| | |
620| | .. code-block:: text |
621| | |
622| | - channel_id |
623| | - service_id (if relevant) |
624| | - method_id (if relevant) |
625| | - status |
Alexei Frolov86e05de2021-10-19 16:52:31 -0700626| | - call_id (if set in REQUEST) |
Wyatt Heplera9211162021-06-12 15:40:11 -0700627| | |
628+-------------------+-------------------------------------+
Wyatt Hepler0f262352020-07-29 09:51:27 -0700629
Erik Gilling1f9e3552022-01-21 18:49:20 +0000630All server packets contain the same ``call_id`` that was set in the initial
Alexei Frolov86e05de2021-10-19 16:52:31 -0700631request made by the client, if any.
632
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700633**Server errors**
Wyatt Hepler0f262352020-07-29 09:51:27 -0700634
635The server sends ``SERVER_ERROR`` packets when it receives a packet it cannot
636process. The client should abort any RPC for which it receives an error. The
637status field indicates the type of error.
638
639* ``NOT_FOUND`` -- The requested service or method does not exist.
Wyatt Heplera9211162021-06-12 15:40:11 -0700640* ``FAILED_PRECONDITION`` -- A client stream or cancel packet was sent for an
641 RPC that is not pending.
Wyatt Hepler01fc15b2021-06-10 18:15:59 -0700642* ``INVALID_ARGUMENT`` -- The client sent a packet type to an RPC that does not
Wyatt Hepler82db4b12021-09-23 09:10:12 -0700643 support it (a ``CLIENT_STREAM`` was sent to an RPC with no client stream).
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700644* ``RESOURCE_EXHAUSTED`` -- The request came on a new channel, but a channel
645 could not be allocated for it.
Erik Gilling3b7159a2022-01-20 20:37:01 +0000646* ``ABORTED`` -- The RPC was aborted due its channel being closed.
Wyatt Hepler712d3672020-07-13 15:52:11 -0700647* ``INTERNAL`` -- The server was unable to respond to an RPC due to an
648 unrecoverable internal error.
Wyatt Hepler3d57eaa2022-02-01 18:31:07 -0800649* ``UNAVAILABLE`` -- Received a packet for an unknown channel.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700650
651Inovking a service method
652-------------------------
653Calling an RPC requires a specific sequence of packets. This section describes
654the protocol for calling service methods of each type: unary, server streaming,
655client streaming, and bidirectional streaming.
656
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700657The basic flow for all RPC invocations is as follows:
658
659 * Client sends a ``REQUEST`` packet. Includes a payload for unary & server
660 streaming RPCs.
661 * For client and bidirectional streaming RPCs, the client may send any number
662 of ``CLIENT_STREAM`` packets with payloads.
663 * For server and bidirectional streaming RPCs, the server may send any number
664 of ``SERVER_STREAM`` packets.
665 * The server sends a ``RESPONSE`` packet. Includes a payload for unary &
666 client streaming RPCs. The RPC is complete.
667
Wyatt Hepler17169152021-10-20 18:46:08 -0700668The client may cancel an ongoing RPC at any time by sending a ``CLIENT_ERROR``
669packet with status ``CANCELLED``. The server may finish an ongoing RPC at any
670time by sending the ``RESPONSE`` packet.
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700671
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700672Unary RPC
673^^^^^^^^^
674In a unary RPC, the client sends a single request and the server sends a single
675response.
676
Wyatt Hepler1d221242021-09-07 15:42:21 -0700677.. image:: unary_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700678
Wyatt Hepler17169152021-10-20 18:46:08 -0700679The client may attempt to cancel a unary RPC by sending a ``CLIENT_ERROR``
680packet with status ``CANCELLED``. The server sends no response to a cancelled
681RPC. If the server processes the unary RPC synchronously (the handling thread
682sends the response), it may not be possible to cancel the RPC.
Wyatt Heplera9211162021-06-12 15:40:11 -0700683
Wyatt Hepler1d221242021-09-07 15:42:21 -0700684.. image:: unary_rpc_cancelled.svg
Wyatt Heplera9211162021-06-12 15:40:11 -0700685
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700686Server streaming RPC
687^^^^^^^^^^^^^^^^^^^^
688In a server streaming RPC, the client sends a single request and the server
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700689sends any number of ``SERVER_STREAM`` packets followed by a ``RESPONSE`` packet.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700690
Wyatt Hepler1d221242021-09-07 15:42:21 -0700691.. image:: server_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700692
Wyatt Hepler17169152021-10-20 18:46:08 -0700693The client may terminate a server streaming RPC by sending a ``CLIENT_STREAM``
694packet with status ``CANCELLED``. The server sends no response.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700695
Wyatt Hepler1d221242021-09-07 15:42:21 -0700696.. image:: server_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700697
698Client streaming RPC
699^^^^^^^^^^^^^^^^^^^^
Wyatt Heplera9211162021-06-12 15:40:11 -0700700In a client streaming RPC, the client starts the RPC by sending a ``REQUEST``
701packet with no payload. It then sends any number of messages in
702``CLIENT_STREAM`` packets, followed by a ``CLIENT_STREAM_END``. The server sends
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700703a single ``RESPONSE`` to finish the RPC.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700704
Wyatt Hepler1d221242021-09-07 15:42:21 -0700705.. image:: client_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700706
Wyatt Heplera9211162021-06-12 15:40:11 -0700707The server may finish the RPC at any time by sending its ``RESPONSE`` packet,
708even if it has not yet received the ``CLIENT_STREAM_END`` packet. The client may
Wyatt Hepler17169152021-10-20 18:46:08 -0700709terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
710``CANCELLED``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700711
Wyatt Hepler1d221242021-09-07 15:42:21 -0700712.. image:: client_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700713
714Bidirectional streaming RPC
715^^^^^^^^^^^^^^^^^^^^^^^^^^^
716In a bidirectional streaming RPC, the client sends any number of requests and
Wyatt Heplera9211162021-06-12 15:40:11 -0700717the server sends any number of responses. The client invokes the RPC by sending
718a ``REQUEST`` with no payload. It sends a ``CLIENT_STREAM_END`` packet when it
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700719has finished sending requests. The server sends a ``RESPONSE`` packet to finish
720the RPC.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700721
Wyatt Hepler1d221242021-09-07 15:42:21 -0700722.. image:: bidirectional_streaming_rpc.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700723
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700724The server may finish the RPC at any time by sending the ``RESPONSE`` packet,
725even if it has not received the ``CLIENT_STREAM_END`` packet. The client may
Wyatt Hepler17169152021-10-20 18:46:08 -0700726terminate the RPC at any time by sending a ``CLIENT_ERROR`` packet with status
727``CANCELLED``.
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700728
Wyatt Hepler1d221242021-09-07 15:42:21 -0700729.. image:: bidirectional_streaming_rpc_cancelled.svg
Wyatt Hepler067dd7e2020-07-14 19:34:32 -0700730
Wyatt Hepler948f5472020-06-02 16:52:28 -0700731RPC server
732==========
733Declare an instance of ``rpc::Server`` and register services with it.
734
735.. admonition:: TODO
736
737 Document the public interface
738
Alexei Frolovbf33d212020-09-15 17:13:45 -0700739Size report
740-----------
741The following size report showcases the memory usage of the core RPC server. It
742is configured with a single channel using a basic transport interface that
743directly reads from and writes to ``pw_sys_io``. The transport has a 128-byte
744packet buffer, which comprises the plurality of the example's RAM usage. This is
745not a suitable transport for an actual product; a real implementation would have
746additional overhead proportional to the complexity of the transport.
747
748.. include:: server_size
749
Wyatt Hepler948f5472020-06-02 16:52:28 -0700750RPC server implementation
751-------------------------
752
753The Method class
754^^^^^^^^^^^^^^^^
755The RPC Server depends on the ``pw::rpc::internal::Method`` class. ``Method``
756serves as the bridge between the ``pw_rpc`` server library and the user-defined
Wyatt Heplere95bd722020-11-23 07:49:47 -0800757RPC functions. Each supported protobuf implementation extends ``Method`` to
758implement its request and response proto handling. The ``pw_rpc`` server
759calls into the ``Method`` implementation through the base class's ``Invoke``
760function.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700761
Wyatt Heplere95bd722020-11-23 07:49:47 -0800762``Method`` implementations store metadata about each method, including a
763function pointer to the user-defined method implementation. They also provide
764``static constexpr`` functions for creating each type of method. ``Method``
765implementations must satisfy the ``MethodImplTester`` test class in
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -0700766``pw_rpc/internal/method_impl_tester.h``.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700767
Wyatt Heplere95bd722020-11-23 07:49:47 -0800768See ``pw_rpc/internal/method.h`` for more details about ``Method``.
Wyatt Hepler948f5472020-06-02 16:52:28 -0700769
770Packet flow
771^^^^^^^^^^^
772
773Requests
774~~~~~~~~
775
Wyatt Hepler1d221242021-09-07 15:42:21 -0700776.. image:: request_packets.svg
Wyatt Hepler948f5472020-06-02 16:52:28 -0700777
778Responses
779~~~~~~~~~
780
Wyatt Hepler1d221242021-09-07 15:42:21 -0700781.. image:: response_packets.svg
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700782
783RPC client
784==========
785The RPC client is used to send requests to a server and manages the contexts of
786ongoing RPCs.
787
788Setting up a client
789-------------------
790The ``pw::rpc::Client`` class is instantiated with a list of channels that it
791uses to communicate. These channels can be shared with a server, but multiple
792clients cannot use the same channels.
793
794To send incoming RPC packets from the transport layer to be processed by a
795client, the client's ``ProcessPacket`` function is called with the packet data.
796
797.. code:: c++
798
799 #include "pw_rpc/client.h"
800
801 namespace {
802
803 pw::rpc::Channel my_channels[] = {
804 pw::rpc::Channel::Create<1>(&my_channel_output)};
805 pw::rpc::Client my_client(my_channels);
806
807 } // namespace
808
809 // Called when the transport layer receives an RPC packet.
810 void ProcessRpcPacket(ConstByteSpan packet) {
811 my_client.ProcessPacket(packet);
812 }
813
Alexei Frolov5a3a61c2020-10-01 18:51:41 -0700814.. _module-pw_rpc-making-calls:
815
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700816Making RPC calls
817----------------
818RPC calls are not made directly through the client, but using one of its
819registered channels instead. A service client class is generated from a .proto
820file for each selected protobuf library, which is then used to send RPC requests
821through a given channel. The API for this depends on the protobuf library;
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -0700822please refer to the
823:ref:`appropriate documentation<module-pw_rpc-protobuf-library-apis>`. Multiple
824service client implementations can exist simulatenously and share the same
825``Client`` class.
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700826
827When a call is made, a ``pw::rpc::ClientCall`` object is returned to the caller.
828This object tracks the ongoing RPC call, and can be used to manage it. An RPC
829call is only active as long as its ``ClientCall`` object is alive.
830
831.. tip::
832 Use ``std::move`` when passing around ``ClientCall`` objects to keep RPCs
833 alive.
834
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700835Example
836^^^^^^^
837.. code-block:: c++
838
839 #include "pw_rpc/echo_service_nanopb.h"
840
841 namespace {
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700842 // Generated clients are namespaced with their proto library.
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800843 using EchoClient = pw_rpc::nanopb::EchoService::Client;
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700844
Alexei Frolov73687fb2021-09-03 11:22:33 -0700845 // RPC channel ID on which to make client calls.
846 constexpr uint32_t kDefaultChannelId = 1;
847
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800848 EchoClient::EchoCall echo_call;
Alexei Frolovbebba902021-06-09 17:03:52 -0700849
850 // Callback invoked when a response is received. This is called synchronously
851 // from Client::ProcessPacket.
852 void EchoResponse(const pw_rpc_EchoMessage& response,
853 pw::Status status) {
854 if (status.ok()) {
855 PW_LOG_INFO("Received echo response: %s", response.msg);
856 } else {
857 PW_LOG_ERROR("Echo failed with status %d",
858 static_cast<int>(status.code()));
859 }
860 }
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700861
862 } // namespace
863
864 void CallEcho(const char* message) {
Alexei Frolov73687fb2021-09-03 11:22:33 -0700865 // Create a client to call the EchoService.
Alexei Frolov39d8c5c2021-11-24 10:16:31 -0800866 EchoClient echo_client(my_rpc_client, kDefaultChannelId);
Alexei Frolov73687fb2021-09-03 11:22:33 -0700867
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700868 pw_rpc_EchoMessage request = pw_rpc_EchoMessage_init_default;
869 pw::string::Copy(message, request.msg);
870
871 // By assigning the returned ClientCall to the global echo_call, the RPC
872 // call is kept alive until it completes. When a response is received, it
873 // will be logged by the handler function and the call will complete.
Alexei Frolov73687fb2021-09-03 11:22:33 -0700874 echo_call = echo_client.Echo(request, EchoResponse);
875 if (!echo_call.active()) {
876 // The RPC call was not sent. This could occur due to, for example, an
877 // invalid channel ID. Handle if necessary.
878 }
Alexei Frolov2d737bc2021-04-27 23:03:09 -0700879 }
880
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700881Client implementation details
882-----------------------------
883
884The ClientCall class
885^^^^^^^^^^^^^^^^^^^^
886``ClientCall`` stores the context of an active RPC, and serves as the user's
887interface to the RPC client. The core RPC library provides a base ``ClientCall``
888class with common functionality, which is then extended for RPC client
889implementations tied to different protobuf libraries to provide convenient
890interfaces for working with RPCs.
891
892The RPC server stores a list of all of active ``ClientCall`` objects. When an
893incoming packet is recieved, it dispatches to one of its active calls, which
894then decodes the payload and presents it to the user.
Alexei Frolov3e280922021-04-12 14:53:06 -0700895
896ClientServer
897============
898Sometimes, a device needs to both process RPCs as a server, as well as making
899calls to another device as a client. To do this, both a client and server must
900be set up, and incoming packets must be sent to both of them.
901
902Pigweed simplifies this setup by providing a ``ClientServer`` class which wraps
903an RPC client and server with the same set of channels.
904
905.. code-block:: cpp
906
907 pw::rpc::Channel channels[] = {
908 pw::rpc::Channel::Create<1>(&channel_output)};
909
910 // Creates both a client and a server.
911 pw::rpc::ClientServer client_server(channels);
912
913 void ProcessRpcData(pw::ConstByteSpan packet) {
914 // Calls into both the client and the server, sending the packet to the
915 // appropriate one.
Alexei Frolovba93a432021-12-02 13:36:26 -0800916 client_server.ProcessPacket(packet);
Alexei Frolov3e280922021-04-12 14:53:06 -0700917 }
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800918
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800919Testing
920=======
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800921``pw_rpc`` provides utilities for unit testing RPC services and client calls.
922
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800923Client unit testing in C++
924--------------------------
Wyatt Hepler9732a8e2021-11-10 16:31:41 -0800925``pw_rpc`` supports invoking RPCs, simulating server responses, and checking
926what packets are sent by an RPC client in tests. Both raw and Nanopb interfaces
927are supported. Code that uses the raw API may be tested with the Nanopb test
928helpers, and vice versa.
929
930To test code that invokes RPCs, declare a ``RawClientTestContext`` or
931``NanopbClientTestContext``. These test context objects provide a
932preconfigured RPC client, channel, server fake, and buffer for encoding packets.
933These test classes are defined in ``pw_rpc/raw/client_testing.h`` and
934``pw_rpc/nanopb/client_testing.h``.
935
936Use the context's ``client()`` and ``channel()`` to invoke RPCs. Use the
937context's ``server()`` to simulate responses. To verify that the client sent the
938expected data, use the context's ``output()``, which is a ``FakeChannelOutput``.
939
940For example, the following tests a class that invokes an RPC. It checks that
941the expected data was sent and then simulates a response from the server.
942
943.. code-block:: cpp
944
945 #include "pw_rpc/raw/client_testing.h"
946
947 class ThingThatCallsRpcs {
948 public:
949 // To support injecting an RPC client for testing, classes that make RPC
950 // calls should take an RPC client and channel ID or an RPC service client
951 // (e.g. pw_rpc::raw::MyService::Client).
952 ThingThatCallsRpcs(pw::rpc::Client& client, uint32_t channel_id);
953
954 void DoSomethingThatInvokesAnRpc();
955
956 bool SetToTrueWhenRpcCompletes();
957 };
958
959 TEST(TestAThing, InvokesRpcAndHandlesResponse) {
960 RawClientTestContext context;
961 ThingThatCallsRpcs thing(context.client(), context.channel().id());
962
963 // Execute the code that invokes the MyService.TheMethod RPC.
964 things.DoSomethingThatInvokesAnRpc();
965
966 // Find and verify the payloads sent for the MyService.TheMethod RPC.
967 auto msgs = context.output().payloads<pw_rpc::raw::MyService::TheMethod>();
968 ASSERT_EQ(msgs.size(), 1u);
969
970 VerifyThatTheExpectedMessageWasSent(msgs.back());
971
972 // Send the response packet from the server and verify that the class reacts
973 // accordingly.
974 EXPECT_FALSE(thing.SetToTrueWhenRpcCompletes());
975
976 context_.server().SendResponse<pw_rpc::raw::MyService::TheMethod>(
977 final_message, OkStatus());
978
979 EXPECT_TRUE(thing.SetToTrueWhenRpcCompletes());
980 }
Ewout van Bekkum7f5b3052021-11-11 17:35:23 -0800981
Wyatt Hepler1215a9d2021-11-10 08:55:47 -0800982Integration testing with ``pw_rpc``
983-----------------------------------
984``pw_rpc`` provides utilities to simplify writing integration tests for systems
985that communicate with ``pw_rpc``. The integration test utitilies set up a socket
986to use for IPC between an RPC server and client process.
987
988The server binary uses the system RPC server facade defined
989``pw_rpc_system_server/rpc_server.h``. The client binary uses the functions
990defined in ``pw_rpc/integration_testing.h``:
991
992.. cpp:var:: constexpr uint32_t kChannelId
993
994 The RPC channel for integration test RPCs.
995
996.. cpp:function:: pw::rpc::Client& pw::rpc::integration_test::Client()
997
998 Returns the global RPC client for integration test use.
999
1000.. cpp:function:: pw::Status pw::rpc::integration_test::InitializeClient(int argc, char* argv[], const char* usage_args = "PORT")
1001
1002 Initializes logging and the global RPC client for integration testing. Starts
1003 a background thread that processes incoming.
1004
Ewout van Bekkum7f5b3052021-11-11 17:35:23 -08001005Module Configuration Options
1006============================
1007The following configurations can be adjusted via compile-time configuration of
1008this module, see the
1009:ref:`module documentation <module-structure-compile-time-configuration>` for
1010more details.
1011
1012.. c:macro:: PW_RPC_CLIENT_STREAM_END_CALLBACK
1013
1014 In client and bidirectional RPCs, pw_rpc clients may signal that they have
1015 finished sending requests with a CLIENT_STREAM_END packet. While this can be
1016 useful in some circumstances, it is often not necessary.
1017
1018 This option controls whether or not include a callback that is called when
1019 the client stream ends. The callback is included in all ServerReader/Writer
1020 objects as a pw::Function, so may have a significant cost.
1021
1022 This is disabled by default.
1023
1024.. c:macro:: PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
1025
1026 The Nanopb-based pw_rpc implementation allocates memory to use for Nanopb
1027 structs for the request and response protobufs. The template function that
1028 allocates these structs rounds struct sizes up to this value so that
1029 different structs can be allocated with the same function. Structs with sizes
1030 larger than this value cause an extra function to be created, which slightly
1031 increases code size.
1032
1033 Ideally, this value will be set to the size of the largest Nanopb struct used
1034 as an RPC request or response. The buffer can be stack or globally allocated
1035 (see ``PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE``).
1036
1037 This defaults to 64 Bytes.
1038
1039.. c:macro:: PW_RPC_USE_GLOBAL_MUTEX
1040
1041 Enable global synchronization for RPC calls. If this is set, a backend must
1042 be configured for pw_sync:mutex.
1043
1044 This is disabled by default.
1045
Wyatt Hepler3d57eaa2022-02-01 18:31:07 -08001046.. c:macro:: PW_RPC_DYNAMIC_ALLOCATION
1047
1048 Whether pw_rpc should use dynamic memory allocation internally. If enabled,
1049 pw_rpc dynamically allocates channels and its encoding buffers. RPC users may
1050 use dynamic allocation independently of this option (e.g. to allocate pw_rpc
1051 call objects).
1052
1053 The semantics for allocating and initializing channels change depending on
1054 this option. If dynamic allocation is disabled, pw_rpc endpoints (servers or
1055 clients) use an externally-allocated, fixed-size array of channels.
1056 That array must include unassigned channels or existing channels must be
1057 closed to add new channels.
1058
1059 If dynamic allocation is enabled, an span of channels may be passed to the
1060 endpoint at construction, but these channels are only used to initialize its
1061 internal std::vector of channels. External channel objects are NOT used by
1062 the endpoint cannot be updated if dynamic allocation is enabled. No
1063 unassigned channels should be passed to the endpoint; they will be ignored.
1064 Any number of channels may be added to the endpoint, without closing existing
1065 channels, but adding channels will use more memory.
1066
Ewout van Bekkum7f5b3052021-11-11 17:35:23 -08001067.. c:macro:: PW_RPC_CONFIG_LOG_LEVEL
1068
1069 The log level to use for this module. Logs below this level are omitted.
1070
1071 This defaults to ``PW_LOG_LEVEL_INFO``.
1072
1073.. c:macro:: PW_RPC_CONFIG_LOG_MODULE_NAME
1074
1075 The log module name to use for this module.
1076
1077 This defaults to ``"PW_RPC"``.
1078
1079.. c:macro:: PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
1080
1081 This option determines whether to allocate the Nanopb structs on the stack or
1082 in a global variable. Globally allocated structs are NOT thread safe, but
1083 work fine when the RPC server's ProcessPacket function is only called from
1084 one thread.
1085
1086 This is enabled by default.
Wyatt Hepler14439762021-11-09 09:16:32 -08001087
1088Sharing server and client code
1089==============================
1090Streaming RPCs support writing multiple requests or responses. To facilitate
1091sharing code between servers and clients, ``pw_rpc`` provides the
1092``pw::rpc::Writer`` interface. On the client side, a client or bidirectional
1093streaming RPC call object (``ClientWriter`` or ``ClientReaderWriter``) can be
1094used as a ``pw::rpc::Writer&``. On the server side, a server or bidirectional
1095streaming RPC call object (``ServerWriter`` or ``ServerReaderWriter``) can be
1096used as a ``pw::rpc::Writer&``.
Yuval Peressb8f3ad22021-10-26 22:55:27 -06001097
1098Zephyr
1099======
1100To enable ``pw_rpc.*`` for Zephyr add ``CONFIG_PIGWEED_RPC=y`` to the project's
1101configuration. This will enable the Kconfig menu for the following:
1102
1103* ``pw_rpc.server`` which can be enabled via ``CONFIG_PIGWEED_RPC_SERVER=y``.
1104* ``pw_rpc.client`` which can be enabled via ``CONFIG_PIGWEED_RPC_CLIENT=y``.
1105* ``pw_rpc.client_server`` which can be enabled via
1106 ``CONFIG_PIGWEED_RPC_CLIENT_SERVER=y``.
1107* ``pw_rpc.common` which can be enabled via ``CONFIG_PIGWEED_RPC_COMMON=y``.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001108
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001109Encoding and sending packets
1110============================
1111``pw_rpc`` has to manage interactions among multiple RPC clients, servers,
1112client calls, and server calls. To safely synchronize these interactions with
1113minimal overhead, ``pw_rpc`` uses a single, global mutex (when
1114``PW_RPC_USE_GLOBAL_MUTEX`` is enabled).
1115
1116Because ``pw_rpc`` uses a global mutex, it also uses a global buffer to encode
1117outgoing packets. The size of the buffer is set with
1118``PW_RPC_ENCODING_BUFFER_SIZE``, which defaults to 512 B.
1119
1120Users of ``pw_rpc`` must implement the :cpp:class:`pw::rpc::ChannelOutput`
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001121interface.
1122
Chad Norvellee40edd2022-02-25 13:29:53 -08001123.. _module-pw_rpc-ChannelOutput:
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001124.. cpp:class:: pw::rpc::ChannelOutput
1125
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001126 ``pw_rpc`` endpoints use :cpp:class:`ChannelOutput` instances to send packets.
1127 Systems that integrate pw_rpc must use one or more :cpp:class:`ChannelOutput`
1128 instances.
1129
1130 .. cpp:member:: static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max()
1131
1132 Value returned from :cpp:func:`MaximumTransmissionUnit` to indicate an
1133 unlimited MTU.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001134
1135 .. cpp:function:: virtual size_t MaximumTransmissionUnit()
1136
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001137 Returns the size of the largest packet the :cpp:class:`ChannelOutput` can
1138 send. :cpp:class:`ChannelOutput` implementations should only override this
1139 function if they impose a limit on the MTU. The default implementation
1140 returns :cpp:member:`kUnlimited`, which indicates that there is no MTU
1141 limit.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001142
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001143 .. cpp:function:: virtual pw::Status Send(std::span<std::byte> packet)
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001144
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001145 Sends an encoded RPC packet. Returns OK if further packets may be sent, even
1146 if the current packet could not be sent. Returns any other status if the
1147 Channel is no longer able to send packets.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001148
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001149 The RPC system's internal lock is held while this function is called. Avoid
1150 long-running operations, since these will delay any other users of the RPC
1151 system.
Wyatt Hepler5fdaeac2022-01-20 18:00:40 -08001152
Wyatt Heplercfedcc42022-01-26 15:08:39 -08001153 .. danger::
1154
1155 No ``pw_rpc`` APIs may be accessed in this function! Implementations MUST
1156 NOT access any RPC endpoints (:cpp:class:`pw::rpc::Client`,
1157 :cpp:class:`pw::rpc::Server`) or call objects
1158 (:cpp:class:`pw::rpc::ServerReaderWriter`,
1159 :cpp:class:`pw::rpc::ClientReaderWriter`, etc.) inside the :cpp:func:`Send`
1160 function or any descendent calls. Doing so will result in deadlock! RPC APIs
1161 may be used by other threads, just not within :cpp:func:`Send`.
1162
1163 The buffer provided in ``packet`` must NOT be accessed outside of this
1164 function. It must be sent immediately or copied elsewhere before the
1165 function returns.