1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_rpc-cpp: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker===================== 4*61c4878aSAndroid Build Coastguard WorkerC++ server and client 5*61c4878aSAndroid Build Coastguard Worker===================== 6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module-subpage:: 7*61c4878aSAndroid Build Coastguard Worker :name: pw_rpc 8*61c4878aSAndroid Build Coastguard Worker 9*61c4878aSAndroid Build Coastguard WorkerThis page provides further guidance on how to use the C++ server 10*61c4878aSAndroid Build Coastguard Workerand client libraries. 11*61c4878aSAndroid Build Coastguard Worker 12*61c4878aSAndroid Build Coastguard Worker---------- 13*61c4878aSAndroid Build Coastguard WorkerRPC server 14*61c4878aSAndroid Build Coastguard Worker---------- 15*61c4878aSAndroid Build Coastguard WorkerDeclare an instance of ``rpc::Server`` and register services with it. 16*61c4878aSAndroid Build Coastguard Worker 17*61c4878aSAndroid Build Coastguard WorkerSize report 18*61c4878aSAndroid Build Coastguard Worker=========== 19*61c4878aSAndroid Build Coastguard WorkerThe following size report showcases the memory usage of the core RPC server. It 20*61c4878aSAndroid Build Coastguard Workeris configured with a single channel using a basic transport interface that 21*61c4878aSAndroid Build Coastguard Workerdirectly reads from and writes to ``pw_sys_io``. The transport has a 128-byte 22*61c4878aSAndroid Build Coastguard Workerpacket buffer, which comprises the plurality of the example's RAM usage. This is 23*61c4878aSAndroid Build Coastguard Workernot a suitable transport for an actual product; a real implementation would have 24*61c4878aSAndroid Build Coastguard Workeradditional overhead proportional to the complexity of the transport. 25*61c4878aSAndroid Build Coastguard Worker 26*61c4878aSAndroid Build Coastguard Worker.. include:: server_size 27*61c4878aSAndroid Build Coastguard Worker 28*61c4878aSAndroid Build Coastguard WorkerRPC server implementation 29*61c4878aSAndroid Build Coastguard Worker========================= 30*61c4878aSAndroid Build Coastguard Worker 31*61c4878aSAndroid Build Coastguard WorkerThe Method class 32*61c4878aSAndroid Build Coastguard Worker---------------- 33*61c4878aSAndroid Build Coastguard WorkerThe RPC Server depends on the ``pw::rpc::internal::Method`` class. ``Method`` 34*61c4878aSAndroid Build Coastguard Workerserves as the bridge between the ``pw_rpc`` server library and the user-defined 35*61c4878aSAndroid Build Coastguard WorkerRPC functions. Each supported protobuf implementation extends ``Method`` to 36*61c4878aSAndroid Build Coastguard Workerimplement its request and response proto handling. The ``pw_rpc`` server 37*61c4878aSAndroid Build Coastguard Workercalls into the ``Method`` implementation through the base class's ``Invoke`` 38*61c4878aSAndroid Build Coastguard Workerfunction. 39*61c4878aSAndroid Build Coastguard Worker 40*61c4878aSAndroid Build Coastguard Worker``Method`` implementations store metadata about each method, including a 41*61c4878aSAndroid Build Coastguard Workerfunction pointer to the user-defined method implementation. They also provide 42*61c4878aSAndroid Build Coastguard Worker``static constexpr`` functions for creating each type of method. ``Method`` 43*61c4878aSAndroid Build Coastguard Workerimplementations must satisfy the ``MethodImplTester`` test class in 44*61c4878aSAndroid Build Coastguard Worker``pw_rpc/internal/method_impl_tester.h``. 45*61c4878aSAndroid Build Coastguard Worker 46*61c4878aSAndroid Build Coastguard WorkerSee ``pw_rpc/internal/method.h`` for more details about ``Method``. 47*61c4878aSAndroid Build Coastguard Worker 48*61c4878aSAndroid Build Coastguard WorkerPacket flow 49*61c4878aSAndroid Build Coastguard Worker----------- 50*61c4878aSAndroid Build Coastguard Worker 51*61c4878aSAndroid Build Coastguard WorkerRequests 52*61c4878aSAndroid Build Coastguard Worker^^^^^^^^ 53*61c4878aSAndroid Build Coastguard Worker 54*61c4878aSAndroid Build Coastguard Worker.. mermaid:: 55*61c4878aSAndroid Build Coastguard Worker :alt: Request Packet Flow 56*61c4878aSAndroid Build Coastguard Worker 57*61c4878aSAndroid Build Coastguard Worker flowchart LR 58*61c4878aSAndroid Build Coastguard Worker packets[Packets] 59*61c4878aSAndroid Build Coastguard Worker 60*61c4878aSAndroid Build Coastguard Worker subgraph pw_rpc [pw_rpc Library] 61*61c4878aSAndroid Build Coastguard Worker direction TB 62*61c4878aSAndroid Build Coastguard Worker internalMethod[[internal::Method]] 63*61c4878aSAndroid Build Coastguard Worker Server --> Service --> internalMethod 64*61c4878aSAndroid Build Coastguard Worker end 65*61c4878aSAndroid Build Coastguard Worker 66*61c4878aSAndroid Build Coastguard Worker packets --> Server 67*61c4878aSAndroid Build Coastguard Worker 68*61c4878aSAndroid Build Coastguard Worker generatedServices{{generated services}} 69*61c4878aSAndroid Build Coastguard Worker userDefinedRPCs(user-defined RPCs) 70*61c4878aSAndroid Build Coastguard Worker 71*61c4878aSAndroid Build Coastguard Worker generatedServices --> userDefinedRPCs 72*61c4878aSAndroid Build Coastguard Worker internalMethod --> generatedServices 73*61c4878aSAndroid Build Coastguard Worker 74*61c4878aSAndroid Build Coastguard WorkerResponses 75*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^ 76*61c4878aSAndroid Build Coastguard Worker 77*61c4878aSAndroid Build Coastguard Worker.. mermaid:: 78*61c4878aSAndroid Build Coastguard Worker :alt: Request Packet Flow 79*61c4878aSAndroid Build Coastguard Worker 80*61c4878aSAndroid Build Coastguard Worker flowchart LR 81*61c4878aSAndroid Build Coastguard Worker generatedServices{{generated services}} 82*61c4878aSAndroid Build Coastguard Worker userDefinedRPCs(user-defined RPCs) 83*61c4878aSAndroid Build Coastguard Worker 84*61c4878aSAndroid Build Coastguard Worker subgraph pw_rpc [pw_rpc Library] 85*61c4878aSAndroid Build Coastguard Worker direction TB 86*61c4878aSAndroid Build Coastguard Worker internalMethod[[internal::Method]] 87*61c4878aSAndroid Build Coastguard Worker internalMethod --> Server --> Channel 88*61c4878aSAndroid Build Coastguard Worker end 89*61c4878aSAndroid Build Coastguard Worker 90*61c4878aSAndroid Build Coastguard Worker packets[Packets] 91*61c4878aSAndroid Build Coastguard Worker Channel --> packets 92*61c4878aSAndroid Build Coastguard Worker 93*61c4878aSAndroid Build Coastguard Worker userDefinedRPCs --> generatedServices 94*61c4878aSAndroid Build Coastguard Worker generatedServices --> internalMethod 95*61c4878aSAndroid Build Coastguard Worker 96*61c4878aSAndroid Build Coastguard Worker---------- 97*61c4878aSAndroid Build Coastguard WorkerRPC client 98*61c4878aSAndroid Build Coastguard Worker---------- 99*61c4878aSAndroid Build Coastguard WorkerThe RPC client is used to send requests to a server and manages the contexts of 100*61c4878aSAndroid Build Coastguard Workerongoing RPCs. 101*61c4878aSAndroid Build Coastguard Worker 102*61c4878aSAndroid Build Coastguard WorkerSetting up a client 103*61c4878aSAndroid Build Coastguard Worker=================== 104*61c4878aSAndroid Build Coastguard WorkerThe ``pw::rpc::Client`` class is instantiated with a list of channels that it 105*61c4878aSAndroid Build Coastguard Workeruses to communicate. These channels can be shared with a server, but multiple 106*61c4878aSAndroid Build Coastguard Workerclients cannot use the same channels. 107*61c4878aSAndroid Build Coastguard Worker 108*61c4878aSAndroid Build Coastguard WorkerTo send incoming RPC packets from the transport layer to be processed by a 109*61c4878aSAndroid Build Coastguard Workerclient, the client's ``ProcessPacket`` function is called with the packet data. 110*61c4878aSAndroid Build Coastguard Worker 111*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 112*61c4878aSAndroid Build Coastguard Worker 113*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/client.h" 114*61c4878aSAndroid Build Coastguard Worker 115*61c4878aSAndroid Build Coastguard Worker namespace { 116*61c4878aSAndroid Build Coastguard Worker 117*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel my_channels[] = { 118*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel::Create<1>(&my_channel_output)}; 119*61c4878aSAndroid Build Coastguard Worker pw::rpc::Client my_client(my_channels); 120*61c4878aSAndroid Build Coastguard Worker 121*61c4878aSAndroid Build Coastguard Worker } // namespace 122*61c4878aSAndroid Build Coastguard Worker 123*61c4878aSAndroid Build Coastguard Worker // Called when the transport layer receives an RPC packet. 124*61c4878aSAndroid Build Coastguard Worker void ProcessRpcPacket(ConstByteSpan packet) { 125*61c4878aSAndroid Build Coastguard Worker my_client.ProcessPacket(packet); 126*61c4878aSAndroid Build Coastguard Worker } 127*61c4878aSAndroid Build Coastguard Worker 128*61c4878aSAndroid Build Coastguard WorkerNote that client processing such as callbacks will be invoked within 129*61c4878aSAndroid Build Coastguard Workerthe body of ``ProcessPacket``. 130*61c4878aSAndroid Build Coastguard Worker 131*61c4878aSAndroid Build Coastguard WorkerIf certain packets need to be filtered out, or if certain client processing 132*61c4878aSAndroid Build Coastguard Workerneeds to be invoked from a specific thread or context, the ``PacketMeta`` class 133*61c4878aSAndroid Build Coastguard Workercan be used to determine which service or channel a packet is targeting. After 134*61c4878aSAndroid Build Coastguard Workerfiltering, ``ProcessPacket`` can be called from the appropriate environment. 135*61c4878aSAndroid Build Coastguard Worker 136*61c4878aSAndroid Build Coastguard Worker.. _module-pw_rpc-making-calls: 137*61c4878aSAndroid Build Coastguard Worker 138*61c4878aSAndroid Build Coastguard WorkerMaking RPC calls 139*61c4878aSAndroid Build Coastguard Worker================ 140*61c4878aSAndroid Build Coastguard WorkerRPC calls are not made directly through the client, but using one of its 141*61c4878aSAndroid Build Coastguard Workerregistered channels instead. A service client class is generated from a .proto 142*61c4878aSAndroid Build Coastguard Workerfile for each selected protobuf library, which is then used to send RPC requests 143*61c4878aSAndroid Build Coastguard Workerthrough a given channel. The API for this depends on the protobuf library; 144*61c4878aSAndroid Build Coastguard Workerplease refer to the 145*61c4878aSAndroid Build Coastguard Worker:ref:`appropriate documentation <module-pw_rpc-libraries>`. Multiple 146*61c4878aSAndroid Build Coastguard Workerservice client implementations can exist simulatenously and share the same 147*61c4878aSAndroid Build Coastguard Worker``Client`` class. 148*61c4878aSAndroid Build Coastguard Worker 149*61c4878aSAndroid Build Coastguard WorkerWhen a call is made, a call object is returned to the caller. This object tracks 150*61c4878aSAndroid Build Coastguard Workerthe ongoing RPC call, and can be used to manage it. An RPC call is only active 151*61c4878aSAndroid Build Coastguard Workeras long as its call object is alive. 152*61c4878aSAndroid Build Coastguard Worker 153*61c4878aSAndroid Build Coastguard Worker.. tip:: 154*61c4878aSAndroid Build Coastguard Worker 155*61c4878aSAndroid Build Coastguard Worker Use ``std::move`` when passing around call objects to keep RPCs alive. 156*61c4878aSAndroid Build Coastguard Worker 157*61c4878aSAndroid Build Coastguard WorkerExample 158*61c4878aSAndroid Build Coastguard Worker------- 159*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 160*61c4878aSAndroid Build Coastguard Worker 161*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/echo_service_nanopb.h" 162*61c4878aSAndroid Build Coastguard Worker 163*61c4878aSAndroid Build Coastguard Worker namespace { 164*61c4878aSAndroid Build Coastguard Worker // Generated clients are namespaced with their proto library. 165*61c4878aSAndroid Build Coastguard Worker using EchoClient = pw_rpc::nanopb::EchoService::Client; 166*61c4878aSAndroid Build Coastguard Worker 167*61c4878aSAndroid Build Coastguard Worker // RPC channel ID on which to make client calls. RPC calls cannot be made on 168*61c4878aSAndroid Build Coastguard Worker // channel 0 (Channel::kUnassignedChannelId). 169*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kDefaultChannelId = 1; 170*61c4878aSAndroid Build Coastguard Worker 171*61c4878aSAndroid Build Coastguard Worker pw::rpc::NanopbUnaryReceiver<pw_rpc_EchoMessage> echo_call; 172*61c4878aSAndroid Build Coastguard Worker 173*61c4878aSAndroid Build Coastguard Worker // Callback invoked when a response is received. This is called synchronously 174*61c4878aSAndroid Build Coastguard Worker // from Client::ProcessPacket. 175*61c4878aSAndroid Build Coastguard Worker void EchoResponse(const pw_rpc_EchoMessage& response, 176*61c4878aSAndroid Build Coastguard Worker pw::Status status) { 177*61c4878aSAndroid Build Coastguard Worker if (status.ok()) { 178*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Received echo response: %s", response.msg); 179*61c4878aSAndroid Build Coastguard Worker } else { 180*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Echo failed with status %d", 181*61c4878aSAndroid Build Coastguard Worker static_cast<int>(status.code())); 182*61c4878aSAndroid Build Coastguard Worker } 183*61c4878aSAndroid Build Coastguard Worker } 184*61c4878aSAndroid Build Coastguard Worker 185*61c4878aSAndroid Build Coastguard Worker } // namespace 186*61c4878aSAndroid Build Coastguard Worker 187*61c4878aSAndroid Build Coastguard Worker void CallEcho(const char* message) { 188*61c4878aSAndroid Build Coastguard Worker // Create a client to call the EchoService. 189*61c4878aSAndroid Build Coastguard Worker EchoClient echo_client(my_rpc_client, kDefaultChannelId); 190*61c4878aSAndroid Build Coastguard Worker 191*61c4878aSAndroid Build Coastguard Worker pw_rpc_EchoMessage request{}; 192*61c4878aSAndroid Build Coastguard Worker pw::string::Copy(message, request.msg); 193*61c4878aSAndroid Build Coastguard Worker 194*61c4878aSAndroid Build Coastguard Worker // By assigning the returned call to the global echo_call, the RPC 195*61c4878aSAndroid Build Coastguard Worker // call is kept alive until it completes. When a response is received, it 196*61c4878aSAndroid Build Coastguard Worker // will be logged by the handler function and the call will complete. 197*61c4878aSAndroid Build Coastguard Worker echo_call = echo_client.Echo(request, EchoResponse); 198*61c4878aSAndroid Build Coastguard Worker if (!echo_call.active()) { 199*61c4878aSAndroid Build Coastguard Worker // The RPC call was not sent. This could occur due to, for example, an 200*61c4878aSAndroid Build Coastguard Worker // invalid channel ID. Handle if necessary. 201*61c4878aSAndroid Build Coastguard Worker } 202*61c4878aSAndroid Build Coastguard Worker } 203*61c4878aSAndroid Build Coastguard Worker 204*61c4878aSAndroid Build Coastguard Worker-------- 205*61c4878aSAndroid Build Coastguard WorkerChannels 206*61c4878aSAndroid Build Coastguard Worker-------- 207*61c4878aSAndroid Build Coastguard Worker``pw_rpc`` sends all of its packets over channels. These are logical, 208*61c4878aSAndroid Build Coastguard Workerapplication-layer routes used to tell the RPC system where a packet should go. 209*61c4878aSAndroid Build Coastguard Worker 210*61c4878aSAndroid Build Coastguard WorkerChannels over a client-server connection must all have a unique ID, which can be 211*61c4878aSAndroid Build Coastguard Workerassigned statically at compile time or dynamically. 212*61c4878aSAndroid Build Coastguard Worker 213*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 214*61c4878aSAndroid Build Coastguard Worker 215*61c4878aSAndroid Build Coastguard Worker // Creating a channel with the static ID 3. 216*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel static_channel = pw::rpc::Channel::Create<3>(&output); 217*61c4878aSAndroid Build Coastguard Worker 218*61c4878aSAndroid Build Coastguard Worker // Grouping channel IDs within an enum can lead to clearer code. 219*61c4878aSAndroid Build Coastguard Worker enum ChannelId { 220*61c4878aSAndroid Build Coastguard Worker kUartChannel = 1, 221*61c4878aSAndroid Build Coastguard Worker kSpiChannel = 2, 222*61c4878aSAndroid Build Coastguard Worker }; 223*61c4878aSAndroid Build Coastguard Worker 224*61c4878aSAndroid Build Coastguard Worker // Creating a channel with a static ID defined within an enum. 225*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel another_static_channel = 226*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel::Create<ChannelId::kUartChannel>(&output); 227*61c4878aSAndroid Build Coastguard Worker 228*61c4878aSAndroid Build Coastguard Worker // Creating a channel with a dynamic ID (note that no output is provided; it 229*61c4878aSAndroid Build Coastguard Worker // will be set when the channel is used. 230*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel dynamic_channel; 231*61c4878aSAndroid Build Coastguard Worker 232*61c4878aSAndroid Build Coastguard WorkerSometimes, the ID and output of a channel are not known at compile time as they 233*61c4878aSAndroid Build Coastguard Workerdepend on information stored on the physical device. To support this use case, a 234*61c4878aSAndroid Build Coastguard Workerdynamically-assignable channel can be configured once at runtime with an ID and 235*61c4878aSAndroid Build Coastguard Workeroutput. 236*61c4878aSAndroid Build Coastguard Worker 237*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 238*61c4878aSAndroid Build Coastguard Worker 239*61c4878aSAndroid Build Coastguard Worker // Create a dynamic channel without a compile-time ID or output. 240*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel dynamic_channel; 241*61c4878aSAndroid Build Coastguard Worker 242*61c4878aSAndroid Build Coastguard Worker void Init() { 243*61c4878aSAndroid Build Coastguard Worker // Called during boot to pull the channel configuration from the system. 244*61c4878aSAndroid Build Coastguard Worker dynamic_channel.Configure(GetChannelId(), some_output); 245*61c4878aSAndroid Build Coastguard Worker } 246*61c4878aSAndroid Build Coastguard Worker 247*61c4878aSAndroid Build Coastguard WorkerAdding and removing channels 248*61c4878aSAndroid Build Coastguard Worker============================ 249*61c4878aSAndroid Build Coastguard WorkerNew channels may be registered with the ``OpenChannel`` function. If dynamic 250*61c4878aSAndroid Build Coastguard Workerallocation is enabled (:c:macro:`PW_RPC_DYNAMIC_ALLOCATION` is 1), any number of 251*61c4878aSAndroid Build Coastguard Workerchannels may be registered. If dynamic allocation is disabled, new channels may 252*61c4878aSAndroid Build Coastguard Workeronly be registered if there are availale channel slots in the span provided to 253*61c4878aSAndroid Build Coastguard Workerthe RPC endpoint at construction. 254*61c4878aSAndroid Build Coastguard Worker 255*61c4878aSAndroid Build Coastguard WorkerA channel may be closed and unregistered with an endpoint by calling 256*61c4878aSAndroid Build Coastguard Worker``ChannelClose`` on the endpoint with the corresponding channel ID. This 257*61c4878aSAndroid Build Coastguard Workerwill terminate any pending calls and call their ``on_error`` callback 258*61c4878aSAndroid Build Coastguard Workerwith the ``ABORTED`` status. 259*61c4878aSAndroid Build Coastguard Worker 260*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 261*61c4878aSAndroid Build Coastguard Worker 262*61c4878aSAndroid Build Coastguard Worker // When a channel is closed, any pending calls will receive 263*61c4878aSAndroid Build Coastguard Worker // on_error callbacks with ABORTED status. 264*61c4878aSAndroid Build Coastguard Worker client->CloseChannel(1); 265*61c4878aSAndroid Build Coastguard Worker 266*61c4878aSAndroid Build Coastguard Worker.. _module-pw_rpc-remap: 267*61c4878aSAndroid Build Coastguard Worker 268*61c4878aSAndroid Build Coastguard WorkerRemapping channels 269*61c4878aSAndroid Build Coastguard Worker================== 270*61c4878aSAndroid Build Coastguard WorkerSome pw_rpc deployments may find it helpful to remap channel IDs in RPC packets. 271*61c4878aSAndroid Build Coastguard WorkerThis can remove the need for globally known channel IDs. Clients can use a 272*61c4878aSAndroid Build Coastguard Workergeneric channel ID. The server remaps the generic channel ID to an ID associated 273*61c4878aSAndroid Build Coastguard Workerwith the transport the client is using. 274*61c4878aSAndroid Build Coastguard Worker 275*61c4878aSAndroid Build Coastguard Worker.. cpp:namespace-push:: pw::rpc 276*61c4878aSAndroid Build Coastguard Worker 277*61c4878aSAndroid Build Coastguard Worker.. doxygengroup:: pw_rpc_channel_functions 278*61c4878aSAndroid Build Coastguard Worker :content-only: 279*61c4878aSAndroid Build Coastguard Worker 280*61c4878aSAndroid Build Coastguard Worker.. cpp:namespace-pop:: 281*61c4878aSAndroid Build Coastguard Worker 282*61c4878aSAndroid Build Coastguard WorkerA future revision of the pw_rpc protocol will remove the need for global channel 283*61c4878aSAndroid Build Coastguard WorkerIDs without requiring remapping. 284*61c4878aSAndroid Build Coastguard Worker 285*61c4878aSAndroid Build Coastguard WorkerExample deployment 286*61c4878aSAndroid Build Coastguard Worker================== 287*61c4878aSAndroid Build Coastguard WorkerThis section describes a hypothetical pw_rpc deployment that supports arbitrary 288*61c4878aSAndroid Build Coastguard Workerpw_rpc clients with one pw_rpc server. Note that this assumes that the 289*61c4878aSAndroid Build Coastguard Workerunderlying transport provides some sort of addressing that the server-side can 290*61c4878aSAndroid Build Coastguard Workerassociate with a channel ID. 291*61c4878aSAndroid Build Coastguard Worker 292*61c4878aSAndroid Build Coastguard Worker- A pw_rpc server is running on one core. A variable number of pw_rpc clients 293*61c4878aSAndroid Build Coastguard Worker need to call RPCs on the server from a different core. 294*61c4878aSAndroid Build Coastguard Worker- The client core opens a socket (or similar feature) to connect to the server 295*61c4878aSAndroid Build Coastguard Worker core. 296*61c4878aSAndroid Build Coastguard Worker- The server core detects the inbound connection and allocates a new channel ID. 297*61c4878aSAndroid Build Coastguard Worker It creates a new channel by calling :cpp:func:`pw::rpc::Server::OpenChannel` 298*61c4878aSAndroid Build Coastguard Worker with the channel ID and a :cpp:class:`pw::rpc::ChannelOutput` associated with 299*61c4878aSAndroid Build Coastguard Worker the new connection. 300*61c4878aSAndroid Build Coastguard Worker- The server maintains a mapping between channel IDs and pw_rpc client 301*61c4878aSAndroid Build Coastguard Worker connections. 302*61c4878aSAndroid Build Coastguard Worker- On the client core, pw_rpc clients all use the same channel ID (e.g. ``1``). 303*61c4878aSAndroid Build Coastguard Worker- As packets arrive from pw_rpc client connections, the server-side code calls 304*61c4878aSAndroid Build Coastguard Worker :cpp:func:`pw::rpc::ChangeEncodedChannelId` on the encoded packet to replace 305*61c4878aSAndroid Build Coastguard Worker the generic channel ID (``1``) with the server-side channel ID allocated when 306*61c4878aSAndroid Build Coastguard Worker the client connected. The encoded packet is then passed to 307*61c4878aSAndroid Build Coastguard Worker :cpp:func:`pw::rpc::Server::ProcessPacket`. 308*61c4878aSAndroid Build Coastguard Worker- When the server sends pw_rpc packets, the :cpp:class:`pw::rpc::ChannelOutput` 309*61c4878aSAndroid Build Coastguard Worker calls :cpp:func:`pw::rpc::ChangeEncodedChannelId` to set the channel ID back 310*61c4878aSAndroid Build Coastguard Worker to the generic ``1``. 311*61c4878aSAndroid Build Coastguard Worker 312*61c4878aSAndroid Build Coastguard Worker------------------------------ 313*61c4878aSAndroid Build Coastguard WorkerC++ payload sizing limitations 314*61c4878aSAndroid Build Coastguard Worker------------------------------ 315*61c4878aSAndroid Build Coastguard WorkerThe individual size of each sent RPC request or response is limited by 316*61c4878aSAndroid Build Coastguard Worker``pw_rpc``'s ``PW_RPC_ENCODING_BUFFER_SIZE_BYTES`` configuration option when 317*61c4878aSAndroid Build Coastguard Workerusing Pigweed's C++ implementation. While multiple RPC messages can be enqueued 318*61c4878aSAndroid Build Coastguard Worker(as permitted by the underlying transport), if a single individual sent message 319*61c4878aSAndroid Build Coastguard Workerexceeds the limitations of the statically allocated encode buffer, the packet 320*61c4878aSAndroid Build Coastguard Workerwill fail to encode and be dropped. 321*61c4878aSAndroid Build Coastguard Worker 322*61c4878aSAndroid Build Coastguard WorkerThis applies to all C++ RPC service implementations (nanopb, raw, and pwpb), 323*61c4878aSAndroid Build Coastguard Workerso it's important to ensure request and response message sizes do not exceed 324*61c4878aSAndroid Build Coastguard Workerthis limitation. 325*61c4878aSAndroid Build Coastguard Worker 326*61c4878aSAndroid Build Coastguard WorkerAs ``pw_rpc`` has some additional encoding overhead, a helper, 327*61c4878aSAndroid Build Coastguard Worker``pw::rpc::MaxSafePayloadSize()`` is provided to expose the practical max RPC 328*61c4878aSAndroid Build Coastguard Workermessage payload size. 329*61c4878aSAndroid Build Coastguard Worker 330*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 331*61c4878aSAndroid Build Coastguard Worker 332*61c4878aSAndroid Build Coastguard Worker #include "pw_file/file.raw_rpc.pb.h" 333*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/channel.h" 334*61c4878aSAndroid Build Coastguard Worker 335*61c4878aSAndroid Build Coastguard Worker namespace pw::file { 336*61c4878aSAndroid Build Coastguard Worker 337*61c4878aSAndroid Build Coastguard Worker class FileSystemService : public pw_rpc::raw::FileSystem::Service<FileSystemService> { 338*61c4878aSAndroid Build Coastguard Worker public: 339*61c4878aSAndroid Build Coastguard Worker void List(ConstByteSpan request, RawServerWriter& writer); 340*61c4878aSAndroid Build Coastguard Worker 341*61c4878aSAndroid Build Coastguard Worker private: 342*61c4878aSAndroid Build Coastguard Worker // Allocate a buffer for building proto responses. 343*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kEncodeBufferSize = pw::rpc::MaxSafePayloadSize(); 344*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kEncodeBufferSize> encode_buffer_; 345*61c4878aSAndroid Build Coastguard Worker }; 346*61c4878aSAndroid Build Coastguard Worker 347*61c4878aSAndroid Build Coastguard Worker } // namespace pw::file 348*61c4878aSAndroid Build Coastguard Worker 349*61c4878aSAndroid Build Coastguard Worker------------ 350*61c4878aSAndroid Build Coastguard WorkerCall objects 351*61c4878aSAndroid Build Coastguard Worker------------ 352*61c4878aSAndroid Build Coastguard WorkerAn RPC call is represented by a call object. Server and client calls use the 353*61c4878aSAndroid Build Coastguard Workersame base call class in C++, but the public API is different depending on the 354*61c4878aSAndroid Build Coastguard Workertype of call and whether it is being used by the server or client. See 355*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_rpc-design-lifecycle`. 356*61c4878aSAndroid Build Coastguard Worker 357*61c4878aSAndroid Build Coastguard WorkerThe public call types are as follows: 358*61c4878aSAndroid Build Coastguard Worker 359*61c4878aSAndroid Build Coastguard Worker.. list-table:: 360*61c4878aSAndroid Build Coastguard Worker :header-rows: 1 361*61c4878aSAndroid Build Coastguard Worker 362*61c4878aSAndroid Build Coastguard Worker * - RPC Type 363*61c4878aSAndroid Build Coastguard Worker - Server call 364*61c4878aSAndroid Build Coastguard Worker - Client call 365*61c4878aSAndroid Build Coastguard Worker * - Unary 366*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)UnaryResponder`` 367*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)UnaryReceiver`` 368*61c4878aSAndroid Build Coastguard Worker * - Server streaming 369*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ServerWriter`` 370*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ClientReader`` 371*61c4878aSAndroid Build Coastguard Worker * - Client streaming 372*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ServerReader`` 373*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ClientWriter`` 374*61c4878aSAndroid Build Coastguard Worker * - Bidirectional streaming 375*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ServerReaderWriter`` 376*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ClientReaderWriter`` 377*61c4878aSAndroid Build Coastguard Worker 378*61c4878aSAndroid Build Coastguard WorkerClient call API 379*61c4878aSAndroid Build Coastguard Worker=============== 380*61c4878aSAndroid Build Coastguard WorkerClient call objects provide a few common methods. 381*61c4878aSAndroid Build Coastguard Worker 382*61c4878aSAndroid Build Coastguard Worker.. cpp:class:: pw::rpc::ClientCallType 383*61c4878aSAndroid Build Coastguard Worker 384*61c4878aSAndroid Build Coastguard Worker The ``ClientCallType`` will be one of the following types: 385*61c4878aSAndroid Build Coastguard Worker 386*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)UnaryReceiver`` for unary 387*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ClientReader`` for server streaming 388*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ClientWriter`` for client streaming 389*61c4878aSAndroid Build Coastguard Worker - ``(Raw|Nanopb|Pwpb)ClientReaderWriter`` for bidirectional streaming 390*61c4878aSAndroid Build Coastguard Worker 391*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: bool active() const 392*61c4878aSAndroid Build Coastguard Worker 393*61c4878aSAndroid Build Coastguard Worker Returns true if the call is active. 394*61c4878aSAndroid Build Coastguard Worker 395*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: uint32_t channel_id() const 396*61c4878aSAndroid Build Coastguard Worker 397*61c4878aSAndroid Build Coastguard Worker Returns the channel ID of this call, which is 0 if the call is inactive. 398*61c4878aSAndroid Build Coastguard Worker 399*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: uint32_t id() const 400*61c4878aSAndroid Build Coastguard Worker 401*61c4878aSAndroid Build Coastguard Worker Returns the call ID, a unique identifier for this call. 402*61c4878aSAndroid Build Coastguard Worker 403*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: void Write(RequestType) 404*61c4878aSAndroid Build Coastguard Worker 405*61c4878aSAndroid Build Coastguard Worker Only available on client and bidirectional streaming calls. Sends a stream 406*61c4878aSAndroid Build Coastguard Worker request. Returns: 407*61c4878aSAndroid Build Coastguard Worker 408*61c4878aSAndroid Build Coastguard Worker - ``OK`` - the request was successfully sent 409*61c4878aSAndroid Build Coastguard Worker - ``FAILED_PRECONDITION`` - the writer is closed 410*61c4878aSAndroid Build Coastguard Worker - ``INTERNAL`` - pw_rpc was unable to encode message; does not apply to 411*61c4878aSAndroid Build Coastguard Worker raw calls 412*61c4878aSAndroid Build Coastguard Worker - other errors - the :cpp:class:`ChannelOutput` failed to send the packet; 413*61c4878aSAndroid Build Coastguard Worker the error codes are determined by the :cpp:class:`ChannelOutput` 414*61c4878aSAndroid Build Coastguard Worker implementation 415*61c4878aSAndroid Build Coastguard Worker 416*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: void WriteCallback(Function<StatusWithSize(ByteSpan)>) 417*61c4878aSAndroid Build Coastguard Worker 418*61c4878aSAndroid Build Coastguard Worker Raw RPC only. Invokes the provided callback with the available RPC payload 419*61c4878aSAndroid Build Coastguard Worker buffer, allowing payloads to be encoded directly into it. Sends a stream 420*61c4878aSAndroid Build Coastguard Worker packet with the payload if the callback is successful. 421*61c4878aSAndroid Build Coastguard Worker 422*61c4878aSAndroid Build Coastguard Worker The buffer provided to the callback is only valid for the duration of the 423*61c4878aSAndroid Build Coastguard Worker callback. The callback should return an OK status with the size of the 424*61c4878aSAndroid Build Coastguard Worker encoded payload on success, or an error status on failure. 425*61c4878aSAndroid Build Coastguard Worker 426*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: pw::Status RequestCompletion() 427*61c4878aSAndroid Build Coastguard Worker 428*61c4878aSAndroid Build Coastguard Worker Notifies the server that client has requested for call completion. On 429*61c4878aSAndroid Build Coastguard Worker client and bidirectional streaming calls no further client stream messages 430*61c4878aSAndroid Build Coastguard Worker will be sent. 431*61c4878aSAndroid Build Coastguard Worker 432*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: pw::Status Cancel() 433*61c4878aSAndroid Build Coastguard Worker 434*61c4878aSAndroid Build Coastguard Worker Cancels this RPC. Closes the call and sends a ``CANCELLED`` error to the 435*61c4878aSAndroid Build Coastguard Worker server. Return statuses are the same as :cpp:func:`Write`. 436*61c4878aSAndroid Build Coastguard Worker 437*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: void Abandon() 438*61c4878aSAndroid Build Coastguard Worker 439*61c4878aSAndroid Build Coastguard Worker Closes this RPC locally. Sends a ``CLIENT_REQUEST_COMPLETION``, but no cancellation 440*61c4878aSAndroid Build Coastguard Worker packet. Future packets for this RPC are dropped, and the client sends a 441*61c4878aSAndroid Build Coastguard Worker ``FAILED_PRECONDITION`` error in response because the call is not active. 442*61c4878aSAndroid Build Coastguard Worker 443*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: void CloseAndWaitForCallbacks() 444*61c4878aSAndroid Build Coastguard Worker 445*61c4878aSAndroid Build Coastguard Worker Abandons this RPC and additionally blocks on completion of any running callbacks. 446*61c4878aSAndroid Build Coastguard Worker 447*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: void set_on_completed(pw::Function<void(ResponseTypeIfUnaryOnly, pw::Status)>) 448*61c4878aSAndroid Build Coastguard Worker 449*61c4878aSAndroid Build Coastguard Worker Sets the callback that is called when the RPC completes normally. The 450*61c4878aSAndroid Build Coastguard Worker signature depends on whether the call has a unary or stream response. 451*61c4878aSAndroid Build Coastguard Worker 452*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: void set_on_error(pw::Function<void(pw::Status)>) 453*61c4878aSAndroid Build Coastguard Worker 454*61c4878aSAndroid Build Coastguard Worker Sets the callback that is called when the RPC is terminated due to an error. 455*61c4878aSAndroid Build Coastguard Worker 456*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: void set_on_next(pw::Function<void(ResponseType)>) 457*61c4878aSAndroid Build Coastguard Worker 458*61c4878aSAndroid Build Coastguard Worker Only available on server and bidirectional streaming calls. Sets the callback 459*61c4878aSAndroid Build Coastguard Worker that is called for each stream response. 460*61c4878aSAndroid Build Coastguard Worker 461*61c4878aSAndroid Build Coastguard WorkerCallbacks 462*61c4878aSAndroid Build Coastguard Worker========= 463*61c4878aSAndroid Build Coastguard WorkerThe C++ call objects allow users to set callbacks that are invoked when RPC 464*61c4878aSAndroid Build Coastguard Worker:ref:`events <module-pw_rpc-design-events>` occur. 465*61c4878aSAndroid Build Coastguard Worker 466*61c4878aSAndroid Build Coastguard Worker.. list-table:: 467*61c4878aSAndroid Build Coastguard Worker :header-rows: 1 468*61c4878aSAndroid Build Coastguard Worker 469*61c4878aSAndroid Build Coastguard Worker * - Name 470*61c4878aSAndroid Build Coastguard Worker - Stream signature 471*61c4878aSAndroid Build Coastguard Worker - Non-stream signature 472*61c4878aSAndroid Build Coastguard Worker - Server 473*61c4878aSAndroid Build Coastguard Worker - Client 474*61c4878aSAndroid Build Coastguard Worker * - ``on_error`` 475*61c4878aSAndroid Build Coastguard Worker - ``void(pw::Status)`` 476*61c4878aSAndroid Build Coastguard Worker - ``void(pw::Status)`` 477*61c4878aSAndroid Build Coastguard Worker - ✅ 478*61c4878aSAndroid Build Coastguard Worker - ✅ 479*61c4878aSAndroid Build Coastguard Worker * - ``on_next`` 480*61c4878aSAndroid Build Coastguard Worker - n/a 481*61c4878aSAndroid Build Coastguard Worker - ``void(const PayloadType&)`` 482*61c4878aSAndroid Build Coastguard Worker - ✅ 483*61c4878aSAndroid Build Coastguard Worker - ✅ 484*61c4878aSAndroid Build Coastguard Worker * - ``on_completed`` 485*61c4878aSAndroid Build Coastguard Worker - ``void(pw::Status)`` 486*61c4878aSAndroid Build Coastguard Worker - ``void(const PayloadType&, pw::Status)`` 487*61c4878aSAndroid Build Coastguard Worker - 488*61c4878aSAndroid Build Coastguard Worker - ✅ 489*61c4878aSAndroid Build Coastguard Worker * - ``on_client_requested_completion`` 490*61c4878aSAndroid Build Coastguard Worker - ``void()`` 491*61c4878aSAndroid Build Coastguard Worker - n/a 492*61c4878aSAndroid Build Coastguard Worker - ✅ (:c:macro:`optional <PW_RPC_COMPLETION_REQUEST_CALLBACK>`) 493*61c4878aSAndroid Build Coastguard Worker - 494*61c4878aSAndroid Build Coastguard Worker 495*61c4878aSAndroid Build Coastguard WorkerLimitations and restrictions 496*61c4878aSAndroid Build Coastguard Worker---------------------------- 497*61c4878aSAndroid Build Coastguard WorkerRPC callbacks are free to perform most actions, including invoking new RPCs or 498*61c4878aSAndroid Build Coastguard Workercancelling pending calls. However, the C++ implementation imposes some 499*61c4878aSAndroid Build Coastguard Workerlimitations and restrictions that must be observed. 500*61c4878aSAndroid Build Coastguard Worker 501*61c4878aSAndroid Build Coastguard WorkerDestructors & moves wait for callbacks to complete 502*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 503*61c4878aSAndroid Build Coastguard Worker* Callbacks must not destroy their call object. Attempting to do so will result 504*61c4878aSAndroid Build Coastguard Worker in deadlock. 505*61c4878aSAndroid Build Coastguard Worker* Other threads may destroy a call while its callback is running, but that 506*61c4878aSAndroid Build Coastguard Worker thread will block until all callbacks complete. 507*61c4878aSAndroid Build Coastguard Worker* Callbacks must not move their call object if it the call is still active. They 508*61c4878aSAndroid Build Coastguard Worker may move their call object after it has terminated. Callbacks may move a 509*61c4878aSAndroid Build Coastguard Worker different call into their call object, since moving closes the destination 510*61c4878aSAndroid Build Coastguard Worker call. 511*61c4878aSAndroid Build Coastguard Worker* Other threads may move a call object while it has a callback running, but they 512*61c4878aSAndroid Build Coastguard Worker will block until the callback completes if the call is still active. 513*61c4878aSAndroid Build Coastguard Worker 514*61c4878aSAndroid Build Coastguard Worker.. warning:: 515*61c4878aSAndroid Build Coastguard Worker 516*61c4878aSAndroid Build Coastguard Worker Deadlocks or crashes occur if a callback: 517*61c4878aSAndroid Build Coastguard Worker 518*61c4878aSAndroid Build Coastguard Worker - attempts to destroy its call object 519*61c4878aSAndroid Build Coastguard Worker - attempts to move its call object while the call is still active 520*61c4878aSAndroid Build Coastguard Worker - never returns 521*61c4878aSAndroid Build Coastguard Worker 522*61c4878aSAndroid Build Coastguard Worker If ``pw_rpc`` a callback violates these restrictions, a crash may occur, 523*61c4878aSAndroid Build Coastguard Worker depending on the value of :c:macro:`PW_RPC_CALLBACK_TIMEOUT_TICKS`. These 524*61c4878aSAndroid Build Coastguard Worker crashes have a message like the following: 525*61c4878aSAndroid Build Coastguard Worker 526*61c4878aSAndroid Build Coastguard Worker .. code-block:: text 527*61c4878aSAndroid Build Coastguard Worker 528*61c4878aSAndroid Build Coastguard Worker A callback for RPC 1:cc0f6de0/31e616ce has not finished after 10000 ticks. 529*61c4878aSAndroid Build Coastguard Worker This may indicate that an RPC callback attempted to destroy or move its own 530*61c4878aSAndroid Build Coastguard Worker call object, which is not permitted. Fix this condition or change the value of 531*61c4878aSAndroid Build Coastguard Worker PW_RPC_CALLBACK_TIMEOUT_TICKS to avoid this crash. 532*61c4878aSAndroid Build Coastguard Worker 533*61c4878aSAndroid Build Coastguard Worker See https://pigweed.dev/pw_rpc#destructors-moves-wait-for-callbacks-to-complete 534*61c4878aSAndroid Build Coastguard Worker for details. 535*61c4878aSAndroid Build Coastguard Worker 536*61c4878aSAndroid Build Coastguard WorkerOnly one thread at a time may execute ``on_next`` 537*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 538*61c4878aSAndroid Build Coastguard WorkerOnly one thread may execute the ``on_next`` callback for a specific service 539*61c4878aSAndroid Build Coastguard Workermethod at a time. If a second thread calls ``ProcessPacket()`` with a stream 540*61c4878aSAndroid Build Coastguard Workerpacket before the ``on_next`` callback for the previous packet completes, the 541*61c4878aSAndroid Build Coastguard Workersecond packet will be dropped. The RPC endpoint logs a warning when this occurs. 542*61c4878aSAndroid Build Coastguard Worker 543*61c4878aSAndroid Build Coastguard WorkerExample warning for a dropped stream packet: 544*61c4878aSAndroid Build Coastguard Worker 545*61c4878aSAndroid Build Coastguard Worker.. code-block:: text 546*61c4878aSAndroid Build Coastguard Worker 547*61c4878aSAndroid Build Coastguard Worker WRN Received stream packet for 1:cc0f6de0/31e616ce before the callback for 548*61c4878aSAndroid Build Coastguard Worker a previous packet completed! This packet will be dropped. This can be 549*61c4878aSAndroid Build Coastguard Worker avoided by handling packets for a particular RPC on only one thread. 550*61c4878aSAndroid Build Coastguard Worker 551*61c4878aSAndroid Build Coastguard Worker----------------------- 552*61c4878aSAndroid Build Coastguard WorkerRPC calls introspection 553*61c4878aSAndroid Build Coastguard Worker----------------------- 554*61c4878aSAndroid Build Coastguard Worker``pw_rpc`` provides ``pw_rpc/method_info.h`` header that allows to obtain 555*61c4878aSAndroid Build Coastguard Workerinformation about the generated RPC method in compile time. 556*61c4878aSAndroid Build Coastguard Worker 557*61c4878aSAndroid Build Coastguard WorkerFor now it provides only two types: ``MethodRequestType<RpcMethod>`` and 558*61c4878aSAndroid Build Coastguard Worker``MethodResponseType<RpcMethod>``. They are aliases to the types that are used 559*61c4878aSAndroid Build Coastguard Workeras a request and response respectively for the given RpcMethod. 560*61c4878aSAndroid Build Coastguard Worker 561*61c4878aSAndroid Build Coastguard WorkerExample 562*61c4878aSAndroid Build Coastguard Worker======= 563*61c4878aSAndroid Build Coastguard WorkerWe have an RPC service ``SpecialService`` with ``MyMethod`` method: 564*61c4878aSAndroid Build Coastguard Worker 565*61c4878aSAndroid Build Coastguard Worker.. code-block:: protobuf 566*61c4878aSAndroid Build Coastguard Worker 567*61c4878aSAndroid Build Coastguard Worker package some.package; 568*61c4878aSAndroid Build Coastguard Worker service SpecialService { 569*61c4878aSAndroid Build Coastguard Worker rpc MyMethod(MyMethodRequest) returns (MyMethodResponse) {} 570*61c4878aSAndroid Build Coastguard Worker } 571*61c4878aSAndroid Build Coastguard Worker 572*61c4878aSAndroid Build Coastguard WorkerWe also have a templated Storage type alias: 573*61c4878aSAndroid Build Coastguard Worker 574*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 575*61c4878aSAndroid Build Coastguard Worker 576*61c4878aSAndroid Build Coastguard Worker template <auto kMethod> 577*61c4878aSAndroid Build Coastguard Worker using Storage = 578*61c4878aSAndroid Build Coastguard Worker std::pair<MethodRequestType<kMethod>, MethodResponseType<kMethod>>; 579*61c4878aSAndroid Build Coastguard Worker 580*61c4878aSAndroid Build Coastguard Worker``Storage<some::package::pw_rpc::pwpb::SpecialService::MyMethod>`` will 581*61c4878aSAndroid Build Coastguard Workerinstantiate as: 582*61c4878aSAndroid Build Coastguard Worker 583*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 584*61c4878aSAndroid Build Coastguard Worker 585*61c4878aSAndroid Build Coastguard Worker std::pair<some::package::MyMethodRequest::Message, 586*61c4878aSAndroid Build Coastguard Worker some::package::MyMethodResponse::Message>; 587*61c4878aSAndroid Build Coastguard Worker 588*61c4878aSAndroid Build Coastguard Worker.. note:: 589*61c4878aSAndroid Build Coastguard Worker 590*61c4878aSAndroid Build Coastguard Worker Only nanopb and pw_protobuf have real types as 591*61c4878aSAndroid Build Coastguard Worker ``MethodRequestType<RpcMethod>``/``MethodResponseType<RpcMethod>``. Raw has 592*61c4878aSAndroid Build Coastguard Worker them both set as ``void``. In reality, they are ``pw::ConstByteSpan``. Any 593*61c4878aSAndroid Build Coastguard Worker helper/trait that wants to use this types for raw methods should do a custom 594*61c4878aSAndroid Build Coastguard Worker implementation that copies the bytes under the span instead of copying just 595*61c4878aSAndroid Build Coastguard Worker the span. 596*61c4878aSAndroid Build Coastguard Worker 597*61c4878aSAndroid Build Coastguard Worker.. _module-pw_rpc-client-sync-call-wrappers: 598*61c4878aSAndroid Build Coastguard Worker 599*61c4878aSAndroid Build Coastguard Worker-------------------------------- 600*61c4878aSAndroid Build Coastguard WorkerClient synchronous call wrappers 601*61c4878aSAndroid Build Coastguard Worker-------------------------------- 602*61c4878aSAndroid Build Coastguard Worker.. doxygenfile:: pw_rpc/synchronous_call.h 603*61c4878aSAndroid Build Coastguard Worker :sections: detaileddescription 604*61c4878aSAndroid Build Coastguard Worker 605*61c4878aSAndroid Build Coastguard WorkerExample 606*61c4878aSAndroid Build Coastguard Worker======= 607*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 608*61c4878aSAndroid Build Coastguard Worker 609*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/synchronous_call.h" 610*61c4878aSAndroid Build Coastguard Worker 611*61c4878aSAndroid Build Coastguard Worker void InvokeUnaryRpc() { 612*61c4878aSAndroid Build Coastguard Worker pw::rpc::Client client; 613*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel channel; 614*61c4878aSAndroid Build Coastguard Worker 615*61c4878aSAndroid Build Coastguard Worker RoomInfoRequest request; 616*61c4878aSAndroid Build Coastguard Worker SynchronousCallResult<RoomInfoResponse> result = 617*61c4878aSAndroid Build Coastguard Worker SynchronousCall<Chat::GetRoomInformation>(client, channel.id(), request); 618*61c4878aSAndroid Build Coastguard Worker 619*61c4878aSAndroid Build Coastguard Worker if (result.is_rpc_error()) { 620*61c4878aSAndroid Build Coastguard Worker ShutdownClient(client); 621*61c4878aSAndroid Build Coastguard Worker } else if (result.is_server_error()) { 622*61c4878aSAndroid Build Coastguard Worker HandleServerError(result.status()); 623*61c4878aSAndroid Build Coastguard Worker } else if (result.is_timeout()) { 624*61c4878aSAndroid Build Coastguard Worker // SynchronousCall will block indefinitely, so we should never get here. 625*61c4878aSAndroid Build Coastguard Worker PW_UNREACHABLE(); 626*61c4878aSAndroid Build Coastguard Worker } 627*61c4878aSAndroid Build Coastguard Worker HandleRoomInformation(std::move(result).response()); 628*61c4878aSAndroid Build Coastguard Worker } 629*61c4878aSAndroid Build Coastguard Worker 630*61c4878aSAndroid Build Coastguard Worker void AnotherExample() { 631*61c4878aSAndroid Build Coastguard Worker pw_rpc::nanopb::Chat::Client chat_client(client, channel); 632*61c4878aSAndroid Build Coastguard Worker constexpr auto kTimeout = pw::chrono::SystemClock::for_at_least(500ms); 633*61c4878aSAndroid Build Coastguard Worker 634*61c4878aSAndroid Build Coastguard Worker RoomInfoRequest request; 635*61c4878aSAndroid Build Coastguard Worker auto result = SynchronousCallFor<Chat::GetRoomInformation>( 636*61c4878aSAndroid Build Coastguard Worker chat_client, request, kTimeout); 637*61c4878aSAndroid Build Coastguard Worker 638*61c4878aSAndroid Build Coastguard Worker if (result.is_timeout()) { 639*61c4878aSAndroid Build Coastguard Worker RetryRoomRequest(); 640*61c4878aSAndroid Build Coastguard Worker } else { 641*61c4878aSAndroid Build Coastguard Worker ... 642*61c4878aSAndroid Build Coastguard Worker } 643*61c4878aSAndroid Build Coastguard Worker } 644*61c4878aSAndroid Build Coastguard Worker 645*61c4878aSAndroid Build Coastguard WorkerThe ``SynchronousCallResult<Response>`` is also compatible with the 646*61c4878aSAndroid Build Coastguard Worker:c:macro:`PW_TRY` family of macros, but users should be aware that their use 647*61c4878aSAndroid Build Coastguard Workerwill lose information about the type of error. This should only be used if the 648*61c4878aSAndroid Build Coastguard Workercaller will handle all error scenarios the same. 649*61c4878aSAndroid Build Coastguard Worker 650*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 651*61c4878aSAndroid Build Coastguard Worker 652*61c4878aSAndroid Build Coastguard Worker pw::Status SyncRpc() { 653*61c4878aSAndroid Build Coastguard Worker const RoomInfoRequest request; 654*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(const RoomInfoResponse& response, 655*61c4878aSAndroid Build Coastguard Worker SynchronousCall<Chat::GetRoomInformation>(client, request)); 656*61c4878aSAndroid Build Coastguard Worker HandleRoomInformation(response); 657*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 658*61c4878aSAndroid Build Coastguard Worker } 659*61c4878aSAndroid Build Coastguard Worker 660*61c4878aSAndroid Build Coastguard Worker------------ 661*61c4878aSAndroid Build Coastguard WorkerClientServer 662*61c4878aSAndroid Build Coastguard Worker------------ 663*61c4878aSAndroid Build Coastguard WorkerSometimes, a device needs to both process RPCs as a server, as well as making 664*61c4878aSAndroid Build Coastguard Workercalls to another device as a client. To do this, both a client and server must 665*61c4878aSAndroid Build Coastguard Workerbe set up, and incoming packets must be sent to both of them. 666*61c4878aSAndroid Build Coastguard Worker 667*61c4878aSAndroid Build Coastguard WorkerPigweed simplifies this setup by providing a ``ClientServer`` class which wraps 668*61c4878aSAndroid Build Coastguard Workeran RPC client and server with the same set of channels. 669*61c4878aSAndroid Build Coastguard Worker 670*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 671*61c4878aSAndroid Build Coastguard Worker 672*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel channels[] = { 673*61c4878aSAndroid Build Coastguard Worker pw::rpc::Channel::Create<1>(&channel_output)}; 674*61c4878aSAndroid Build Coastguard Worker 675*61c4878aSAndroid Build Coastguard Worker // Creates both a client and a server. 676*61c4878aSAndroid Build Coastguard Worker pw::rpc::ClientServer client_server(channels); 677*61c4878aSAndroid Build Coastguard Worker 678*61c4878aSAndroid Build Coastguard Worker void ProcessRpcData(pw::ConstByteSpan packet) { 679*61c4878aSAndroid Build Coastguard Worker // Calls into both the client and the server, sending the packet to the 680*61c4878aSAndroid Build Coastguard Worker // appropriate one. 681*61c4878aSAndroid Build Coastguard Worker client_server.ProcessPacket(packet); 682*61c4878aSAndroid Build Coastguard Worker } 683*61c4878aSAndroid Build Coastguard Worker 684*61c4878aSAndroid Build Coastguard Worker.. _module-pw_rpc-cpp-testing: 685*61c4878aSAndroid Build Coastguard Worker 686*61c4878aSAndroid Build Coastguard Worker------- 687*61c4878aSAndroid Build Coastguard WorkerTesting 688*61c4878aSAndroid Build Coastguard Worker------- 689*61c4878aSAndroid Build Coastguard Worker``pw_rpc`` provides utilities for unit testing RPC services and client calls. 690*61c4878aSAndroid Build Coastguard Worker 691*61c4878aSAndroid Build Coastguard WorkerClient unit testing in C++ 692*61c4878aSAndroid Build Coastguard Worker========================== 693*61c4878aSAndroid Build Coastguard Worker``pw_rpc`` supports invoking RPCs, simulating server responses, and checking 694*61c4878aSAndroid Build Coastguard Workerwhat packets are sent by an RPC client in tests. Raw, Nanopb and Pwpb interfaces 695*61c4878aSAndroid Build Coastguard Workerare supported. Code that uses the raw API may be tested with the raw test 696*61c4878aSAndroid Build Coastguard Workerhelpers, and vice versa. The Nanopb and Pwpb APIs also provides a test helper 697*61c4878aSAndroid Build Coastguard Workerwith a real client-server pair that supports testing of asynchronous messaging. 698*61c4878aSAndroid Build Coastguard Worker 699*61c4878aSAndroid Build Coastguard WorkerTo test synchronous code that invokes RPCs, declare a ``RawClientTestContext``, 700*61c4878aSAndroid Build Coastguard Worker``PwpbClientTestContext``, or ``NanopbClientTestContext``. These test context 701*61c4878aSAndroid Build Coastguard Workerobjects provide a preconfigured RPC client, channel, server fake, and buffer for 702*61c4878aSAndroid Build Coastguard Workerencoding packets. 703*61c4878aSAndroid Build Coastguard Worker 704*61c4878aSAndroid Build Coastguard WorkerThese test classes are defined in ``pw_rpc/raw/client_testing.h``, 705*61c4878aSAndroid Build Coastguard Worker``pw_rpc/pwpb/client_testing.h``, or ``pw_rpc/nanopb/client_testing.h``. 706*61c4878aSAndroid Build Coastguard Worker 707*61c4878aSAndroid Build Coastguard WorkerUse the context's ``client()`` and ``channel()`` to invoke RPCs. Use the 708*61c4878aSAndroid Build Coastguard Workercontext's ``server()`` to simulate responses. To verify that the client sent the 709*61c4878aSAndroid Build Coastguard Workerexpected data, use the context's ``output()``, which is a ``FakeChannelOutput``. 710*61c4878aSAndroid Build Coastguard Worker 711*61c4878aSAndroid Build Coastguard WorkerFor example, the following tests a class that invokes an RPC. It checks that 712*61c4878aSAndroid Build Coastguard Workerthe expected data was sent and then simulates a response from the server. 713*61c4878aSAndroid Build Coastguard Worker 714*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 715*61c4878aSAndroid Build Coastguard Worker 716*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/raw/client_testing.h" 717*61c4878aSAndroid Build Coastguard Worker 718*61c4878aSAndroid Build Coastguard Worker class ClientUnderTest { 719*61c4878aSAndroid Build Coastguard Worker public: 720*61c4878aSAndroid Build Coastguard Worker // To support injecting an RPC client for testing, classes that make RPC 721*61c4878aSAndroid Build Coastguard Worker // calls should take an RPC client and channel ID or an RPC service client 722*61c4878aSAndroid Build Coastguard Worker // (e.g. pw_rpc::raw::MyService::Client). 723*61c4878aSAndroid Build Coastguard Worker ClientUnderTest(pw::rpc::Client& client, uint32_t channel_id); 724*61c4878aSAndroid Build Coastguard Worker 725*61c4878aSAndroid Build Coastguard Worker void DoSomethingThatInvokesAnRpc(); 726*61c4878aSAndroid Build Coastguard Worker 727*61c4878aSAndroid Build Coastguard Worker bool SetToTrueWhenRpcCompletes(); 728*61c4878aSAndroid Build Coastguard Worker }; 729*61c4878aSAndroid Build Coastguard Worker 730*61c4878aSAndroid Build Coastguard Worker TEST(TestAThing, InvokesRpcAndHandlesResponse) { 731*61c4878aSAndroid Build Coastguard Worker RawClientTestContext context; 732*61c4878aSAndroid Build Coastguard Worker ClientUnderTest thing(context.client(), context.channel().id()); 733*61c4878aSAndroid Build Coastguard Worker 734*61c4878aSAndroid Build Coastguard Worker // Execute the code that invokes the MyService.TheMethod RPC. 735*61c4878aSAndroid Build Coastguard Worker things.DoSomethingThatInvokesAnRpc(); 736*61c4878aSAndroid Build Coastguard Worker 737*61c4878aSAndroid Build Coastguard Worker // Find and verify the payloads sent for the MyService.TheMethod RPC. 738*61c4878aSAndroid Build Coastguard Worker auto msgs = context.output().payloads<pw_rpc::raw::MyService::TheMethod>(); 739*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(msgs.size(), 1u); 740*61c4878aSAndroid Build Coastguard Worker 741*61c4878aSAndroid Build Coastguard Worker VerifyThatTheExpectedMessageWasSent(msgs.back()); 742*61c4878aSAndroid Build Coastguard Worker 743*61c4878aSAndroid Build Coastguard Worker // Send the response packet from the server and verify that the class reacts 744*61c4878aSAndroid Build Coastguard Worker // accordingly. 745*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(thing.SetToTrueWhenRpcCompletes()); 746*61c4878aSAndroid Build Coastguard Worker 747*61c4878aSAndroid Build Coastguard Worker context_.server().SendResponse<pw_rpc::raw::MyService::TheMethod>( 748*61c4878aSAndroid Build Coastguard Worker final_message, OkStatus()); 749*61c4878aSAndroid Build Coastguard Worker 750*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(thing.SetToTrueWhenRpcCompletes()); 751*61c4878aSAndroid Build Coastguard Worker } 752*61c4878aSAndroid Build Coastguard Worker 753*61c4878aSAndroid Build Coastguard WorkerTo test client code that uses asynchronous responses, encapsulates multiple 754*61c4878aSAndroid Build Coastguard Workerrpc calls to one or more services, or uses a custom service implementation, 755*61c4878aSAndroid Build Coastguard Workerdeclare a ``NanopbClientServerTestContextThreaded`` or 756*61c4878aSAndroid Build Coastguard Worker``PwpbClientServerTestContextThreaded``. These test object are defined in 757*61c4878aSAndroid Build Coastguard Worker``pw_rpc/nanopb/client_server_testing_threaded.h`` and 758*61c4878aSAndroid Build Coastguard Worker``pw_rpc/pwpb/client_server_testing_threaded.h``. 759*61c4878aSAndroid Build Coastguard Worker 760*61c4878aSAndroid Build Coastguard WorkerUse the context's ``server()`` to register a ``Service`` implementation, and 761*61c4878aSAndroid Build Coastguard Worker``client()`` and ``channel()`` to invoke RPCs. Create a ``Thread`` using the 762*61c4878aSAndroid Build Coastguard Workercontext as a ``ThreadCore`` to have it asynchronously forward request/responses or 763*61c4878aSAndroid Build Coastguard Workercall ``ForwardNewPackets`` to synchronously process all messages. To verify that 764*61c4878aSAndroid Build Coastguard Workerthe client/server sent the expected data, use the context's 765*61c4878aSAndroid Build Coastguard Worker``request(uint32_t index)`` and ``response(uint32_t index)`` to retrieve the 766*61c4878aSAndroid Build Coastguard Workerordered messages. 767*61c4878aSAndroid Build Coastguard Worker 768*61c4878aSAndroid Build Coastguard WorkerFor example, the following tests a class that invokes an RPC and blocks till a 769*61c4878aSAndroid Build Coastguard Workerresponse is received. It verifies that expected data was both sent and received. 770*61c4878aSAndroid Build Coastguard Worker 771*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 772*61c4878aSAndroid Build Coastguard Worker 773*61c4878aSAndroid Build Coastguard Worker #include "my_library_protos/my_service.rpc.pb.h" 774*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/nanopb/client_server_testing_threaded.h" 775*61c4878aSAndroid Build Coastguard Worker #include "pw_thread_stl/options.h" 776*61c4878aSAndroid Build Coastguard Worker 777*61c4878aSAndroid Build Coastguard Worker class ClientUnderTest { 778*61c4878aSAndroid Build Coastguard Worker public: 779*61c4878aSAndroid Build Coastguard Worker // To support injecting an RPC client for testing, classes that make RPC 780*61c4878aSAndroid Build Coastguard Worker // calls should take an RPC client and channel ID or an RPC service client 781*61c4878aSAndroid Build Coastguard Worker // (e.g. pw_rpc::raw::MyService::Client). 782*61c4878aSAndroid Build Coastguard Worker ClientUnderTest(pw::rpc::Client& client, uint32_t channel_id); 783*61c4878aSAndroid Build Coastguard Worker 784*61c4878aSAndroid Build Coastguard Worker Status BlockOnResponse(uint32_t value); 785*61c4878aSAndroid Build Coastguard Worker }; 786*61c4878aSAndroid Build Coastguard Worker 787*61c4878aSAndroid Build Coastguard Worker 788*61c4878aSAndroid Build Coastguard Worker class TestService final : public MyService<TestService> { 789*61c4878aSAndroid Build Coastguard Worker public: 790*61c4878aSAndroid Build Coastguard Worker Status TheMethod(const pw_rpc_test_TheMethod& request, 791*61c4878aSAndroid Build Coastguard Worker pw_rpc_test_TheMethod& response) { 792*61c4878aSAndroid Build Coastguard Worker response.value = request.integer + 1; 793*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 794*61c4878aSAndroid Build Coastguard Worker } 795*61c4878aSAndroid Build Coastguard Worker }; 796*61c4878aSAndroid Build Coastguard Worker 797*61c4878aSAndroid Build Coastguard Worker TEST(TestServiceTest, ReceivesUnaryRpcResponse) { 798*61c4878aSAndroid Build Coastguard Worker NanopbClientServerTestContextThreaded<> ctx(pw::thread::stl::Options{}); 799*61c4878aSAndroid Build Coastguard Worker TestService service; 800*61c4878aSAndroid Build Coastguard Worker ctx.server().RegisterService(service); 801*61c4878aSAndroid Build Coastguard Worker ClientUnderTest client(ctx.client(), ctx.channel().id()); 802*61c4878aSAndroid Build Coastguard Worker 803*61c4878aSAndroid Build Coastguard Worker // Execute the code that invokes the MyService.TheMethod RPC. 804*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t value = 1; 805*61c4878aSAndroid Build Coastguard Worker const auto result = client.BlockOnResponse(value); 806*61c4878aSAndroid Build Coastguard Worker const auto request = ctx.request<MyService::TheMethod>(0); 807*61c4878aSAndroid Build Coastguard Worker const auto response = ctx.response<MyService::TheMethod>(0); 808*61c4878aSAndroid Build Coastguard Worker 809*61c4878aSAndroid Build Coastguard Worker // Verify content of messages 810*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result, pw::OkStatus()); 811*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(request.value, value); 812*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(response.value, value + 1); 813*61c4878aSAndroid Build Coastguard Worker } 814*61c4878aSAndroid Build Coastguard Worker 815*61c4878aSAndroid Build Coastguard WorkerUse the context's 816*61c4878aSAndroid Build Coastguard Worker``response(uint32_t index, Response<kMethod>& response)`` to decode messages 817*61c4878aSAndroid Build Coastguard Workerinto a provided response object. You would use this version if decoder callbacks 818*61c4878aSAndroid Build Coastguard Workerare needed to fully decode a message. For instance if it uses ``repeated`` 819*61c4878aSAndroid Build Coastguard Workerfields. 820*61c4878aSAndroid Build Coastguard Worker 821*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 822*61c4878aSAndroid Build Coastguard Worker 823*61c4878aSAndroid Build Coastguard Worker TestResponse::Message response{}; 824*61c4878aSAndroid Build Coastguard Worker response.repeated_field.SetDecoder( 825*61c4878aSAndroid Build Coastguard Worker [&values](TestResponse::StreamDecoder& decoder) { 826*61c4878aSAndroid Build Coastguard Worker return decoder.ReadRepeatedField(values); 827*61c4878aSAndroid Build Coastguard Worker }); 828*61c4878aSAndroid Build Coastguard Worker ctx.response<test::GeneratedService::TestAnotherUnaryRpc>(0, response); 829*61c4878aSAndroid Build Coastguard Worker 830*61c4878aSAndroid Build Coastguard WorkerSynchronous versions of these test contexts also exist that may be used on 831*61c4878aSAndroid Build Coastguard Workernon-threaded systems ``NanopbClientServerTestContext`` and 832*61c4878aSAndroid Build Coastguard Worker``PwpbClientServerTestContext``. While these do not allow for asynchronous 833*61c4878aSAndroid Build Coastguard Workermessaging they support the use of service implementations and use a similar 834*61c4878aSAndroid Build Coastguard Workersyntax. When these are used ``.ForwardNewPackets()`` should be called after each 835*61c4878aSAndroid Build Coastguard Workerrpc call to trigger sending of queued messages. 836*61c4878aSAndroid Build Coastguard Worker 837*61c4878aSAndroid Build Coastguard WorkerFor example, the following tests a class that invokes an RPC that is responded 838*61c4878aSAndroid Build Coastguard Workerto with a test service implementation. 839*61c4878aSAndroid Build Coastguard Worker 840*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 841*61c4878aSAndroid Build Coastguard Worker 842*61c4878aSAndroid Build Coastguard Worker #include "my_library_protos/my_service.rpc.pb.h" 843*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/nanopb/client_server_testing.h" 844*61c4878aSAndroid Build Coastguard Worker 845*61c4878aSAndroid Build Coastguard Worker class ClientUnderTest { 846*61c4878aSAndroid Build Coastguard Worker public: 847*61c4878aSAndroid Build Coastguard Worker ClientUnderTest(pw::rpc::Client& client, uint32_t channel_id); 848*61c4878aSAndroid Build Coastguard Worker 849*61c4878aSAndroid Build Coastguard Worker Status SendRpcCall(uint32_t value); 850*61c4878aSAndroid Build Coastguard Worker }; 851*61c4878aSAndroid Build Coastguard Worker 852*61c4878aSAndroid Build Coastguard Worker 853*61c4878aSAndroid Build Coastguard Worker class TestService final : public MyService<TestService> { 854*61c4878aSAndroid Build Coastguard Worker public: 855*61c4878aSAndroid Build Coastguard Worker Status TheMethod(const pw_rpc_test_TheMethod& request, 856*61c4878aSAndroid Build Coastguard Worker pw_rpc_test_TheMethod& response) { 857*61c4878aSAndroid Build Coastguard Worker response.value = request.integer + 1; 858*61c4878aSAndroid Build Coastguard Worker return pw::OkStatus(); 859*61c4878aSAndroid Build Coastguard Worker } 860*61c4878aSAndroid Build Coastguard Worker }; 861*61c4878aSAndroid Build Coastguard Worker 862*61c4878aSAndroid Build Coastguard Worker TEST(TestServiceTest, ReceivesUnaryRpcResponse) { 863*61c4878aSAndroid Build Coastguard Worker NanopbClientServerTestContext<> ctx(); 864*61c4878aSAndroid Build Coastguard Worker TestService service; 865*61c4878aSAndroid Build Coastguard Worker ctx.server().RegisterService(service); 866*61c4878aSAndroid Build Coastguard Worker ClientUnderTest client(ctx.client(), ctx.channel().id()); 867*61c4878aSAndroid Build Coastguard Worker 868*61c4878aSAndroid Build Coastguard Worker // Execute the code that invokes the MyService.TheMethod RPC. 869*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t value = 1; 870*61c4878aSAndroid Build Coastguard Worker const auto result = client.SendRpcCall(value); 871*61c4878aSAndroid Build Coastguard Worker // Needed after ever RPC call to trigger forward of packets 872*61c4878aSAndroid Build Coastguard Worker ctx.ForwardNewPackets(); 873*61c4878aSAndroid Build Coastguard Worker const auto request = ctx.request<MyService::TheMethod>(0); 874*61c4878aSAndroid Build Coastguard Worker const auto response = ctx.response<MyService::TheMethod>(0); 875*61c4878aSAndroid Build Coastguard Worker 876*61c4878aSAndroid Build Coastguard Worker // Verify content of messages 877*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(result, pw::OkStatus()); 878*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(request.value, value); 879*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(response.value, value + 1); 880*61c4878aSAndroid Build Coastguard Worker } 881*61c4878aSAndroid Build Coastguard Worker 882*61c4878aSAndroid Build Coastguard WorkerCustom packet processing for ClientServerTestContext 883*61c4878aSAndroid Build Coastguard Worker==================================================== 884*61c4878aSAndroid Build Coastguard WorkerOptional constructor arguments for nanopb/pwpb ``*ClientServerTestContext`` and 885*61c4878aSAndroid Build Coastguard Worker``*ClientServerTestContextThreaded`` allow allow customized packet processing. 886*61c4878aSAndroid Build Coastguard WorkerBy default the only thing is done is ``ProcessPacket()`` call on the 887*61c4878aSAndroid Build Coastguard Worker``ClientServer`` instance. 888*61c4878aSAndroid Build Coastguard Worker 889*61c4878aSAndroid Build Coastguard WorkerFor cases when additional instrumentation or offloading to separate thread is 890*61c4878aSAndroid Build Coastguard Workerneeded, separate client and server processors can be passed to context 891*61c4878aSAndroid Build Coastguard Workerconstructors. A packet processor is a function that returns ``pw::Status`` and 892*61c4878aSAndroid Build Coastguard Workeraccepts two arguments: ``pw::rpc::ClientServer&`` and ``pw::ConstByteSpan``. 893*61c4878aSAndroid Build Coastguard WorkerDefault packet processing is equivalent to the next processor: 894*61c4878aSAndroid Build Coastguard Worker 895*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 896*61c4878aSAndroid Build Coastguard Worker 897*61c4878aSAndroid Build Coastguard Worker [](ClientServer& client_server, pw::ConstByteSpan packet) -> pw::Status { 898*61c4878aSAndroid Build Coastguard Worker return client_server.ProcessPacket(packet); 899*61c4878aSAndroid Build Coastguard Worker }; 900*61c4878aSAndroid Build Coastguard Worker 901*61c4878aSAndroid Build Coastguard WorkerThe Server processor will be applied to all packets sent to the server (i.e. 902*61c4878aSAndroid Build Coastguard Workerrequests) and client processor will be applied to all packets sent to the client 903*61c4878aSAndroid Build Coastguard Worker(i.e. responses). 904*61c4878aSAndroid Build Coastguard Worker 905*61c4878aSAndroid Build Coastguard Worker.. note:: 906*61c4878aSAndroid Build Coastguard Worker 907*61c4878aSAndroid Build Coastguard Worker The packet processor MUST call ``ClientServer::ProcessPacket()`` method. 908*61c4878aSAndroid Build Coastguard Worker Otherwise the packet won't be processed. 909*61c4878aSAndroid Build Coastguard Worker 910*61c4878aSAndroid Build Coastguard Worker.. note:: 911*61c4878aSAndroid Build Coastguard Worker 912*61c4878aSAndroid Build Coastguard Worker If the packet processor offloads processing to the separate thread, it MUST 913*61c4878aSAndroid Build Coastguard Worker copy the ``packet``. After the packet processor returns, the underlying array 914*61c4878aSAndroid Build Coastguard Worker can go out of scope or be reused for other purposes. 915*61c4878aSAndroid Build Coastguard Worker 916*61c4878aSAndroid Build Coastguard WorkerSendResponseIfCalled() helper 917*61c4878aSAndroid Build Coastguard Worker============================= 918*61c4878aSAndroid Build Coastguard Worker``SendResponseIfCalled()`` function waits on ``*ClientTestContext*`` output to 919*61c4878aSAndroid Build Coastguard Workerhave a call for the specified method and then responses to it. It supports 920*61c4878aSAndroid Build Coastguard Workertimeout for the waiting part (default timeout is 100ms). 921*61c4878aSAndroid Build Coastguard Worker 922*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 923*61c4878aSAndroid Build Coastguard Worker 924*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/test_helpers.h" 925*61c4878aSAndroid Build Coastguard Worker 926*61c4878aSAndroid Build Coastguard Worker pw::rpc::PwpbClientTestContext client_context; 927*61c4878aSAndroid Build Coastguard Worker other::pw_rpc::pwpb::OtherService::Client other_service_client( 928*61c4878aSAndroid Build Coastguard Worker client_context.client(), client_context.channel().id()); 929*61c4878aSAndroid Build Coastguard Worker 930*61c4878aSAndroid Build Coastguard Worker PW_PWPB_TEST_METHOD_CONTEXT(MyService, GetData) 931*61c4878aSAndroid Build Coastguard Worker context(other_service_client); 932*61c4878aSAndroid Build Coastguard Worker context.call({}); 933*61c4878aSAndroid Build Coastguard Worker 934*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK(pw::rpc::test::SendResponseIfCalled< 935*61c4878aSAndroid Build Coastguard Worker other::pw_rpc::pwpb::OtherService::GetPart>( 936*61c4878aSAndroid Build Coastguard Worker client_context, {.value = 42})); 937*61c4878aSAndroid Build Coastguard Worker 938*61c4878aSAndroid Build Coastguard Worker // At this point MyService::GetData handler received the GetPartResponse. 939*61c4878aSAndroid Build Coastguard Worker 940*61c4878aSAndroid Build Coastguard WorkerIntegration testing with ``pw_rpc`` 941*61c4878aSAndroid Build Coastguard Worker=================================== 942*61c4878aSAndroid Build Coastguard Worker``pw_rpc`` provides utilities to simplify writing integration tests for systems 943*61c4878aSAndroid Build Coastguard Workerthat communicate with ``pw_rpc``. The integration test utitilies set up a socket 944*61c4878aSAndroid Build Coastguard Workerto use for IPC between an RPC server and client process. 945*61c4878aSAndroid Build Coastguard Worker 946*61c4878aSAndroid Build Coastguard WorkerThe server binary uses the system RPC server facade defined 947*61c4878aSAndroid Build Coastguard Worker``pw_rpc_system_server/rpc_server.h``. The client binary uses the functions 948*61c4878aSAndroid Build Coastguard Workerdefined in ``pw_rpc/integration_testing.h``: 949*61c4878aSAndroid Build Coastguard Worker 950*61c4878aSAndroid Build Coastguard Worker.. cpp:var:: constexpr uint32_t kChannelId 951*61c4878aSAndroid Build Coastguard Worker 952*61c4878aSAndroid Build Coastguard Worker The RPC channel for integration test RPCs. 953*61c4878aSAndroid Build Coastguard Worker 954*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::rpc::Client& pw::rpc::integration_test::Client() 955*61c4878aSAndroid Build Coastguard Worker 956*61c4878aSAndroid Build Coastguard Worker Returns the global RPC client for integration test use. 957*61c4878aSAndroid Build Coastguard Worker 958*61c4878aSAndroid Build Coastguard Worker.. cpp:function:: pw::Status pw::rpc::integration_test::InitializeClient(int argc, char* argv[], const char* usage_args = "PORT") 959*61c4878aSAndroid Build Coastguard Worker 960*61c4878aSAndroid Build Coastguard Worker Initializes logging and the global RPC client for integration testing. Starts 961*61c4878aSAndroid Build Coastguard Worker a background thread that processes incoming. 962*61c4878aSAndroid Build Coastguard Worker 963*61c4878aSAndroid Build Coastguard Worker--------------------- 964*61c4878aSAndroid Build Coastguard WorkerConfiguration options 965*61c4878aSAndroid Build Coastguard Worker--------------------- 966*61c4878aSAndroid Build Coastguard WorkerThe following configurations can be adjusted via compile-time configuration of 967*61c4878aSAndroid Build Coastguard Workerthis module, see the 968*61c4878aSAndroid Build Coastguard Worker:ref:`module documentation <module-structure-compile-time-configuration>` for 969*61c4878aSAndroid Build Coastguard Workermore details. 970*61c4878aSAndroid Build Coastguard Worker 971*61c4878aSAndroid Build Coastguard Worker.. doxygenfile:: pw_rpc/public/pw_rpc/internal/config.h 972*61c4878aSAndroid Build Coastguard Worker :sections: define 973*61c4878aSAndroid Build Coastguard Worker 974*61c4878aSAndroid Build Coastguard Worker------------------------------ 975*61c4878aSAndroid Build Coastguard WorkerSharing server and client code 976*61c4878aSAndroid Build Coastguard Worker------------------------------ 977*61c4878aSAndroid Build Coastguard WorkerStreaming RPCs support writing multiple requests or responses. To facilitate 978*61c4878aSAndroid Build Coastguard Workersharing code between servers and clients, ``pw_rpc`` provides the 979*61c4878aSAndroid Build Coastguard Worker``pw::rpc::Writer`` interface. On the client side, a client or bidirectional 980*61c4878aSAndroid Build Coastguard Workerstreaming RPC call object (``ClientWriter`` or ``ClientReaderWriter``) can be 981*61c4878aSAndroid Build Coastguard Workerused as a ``pw::rpc::Writer&``. On the server side, a server or bidirectional 982*61c4878aSAndroid Build Coastguard Workerstreaming RPC call object (``ServerWriter`` or ``ServerReaderWriter``) can be 983*61c4878aSAndroid Build Coastguard Workerused as a ``pw::rpc::Writer&``. Call ``as_writer()`` to get a ``Writer&`` of the 984*61c4878aSAndroid Build Coastguard Workerclient or server call object. 985*61c4878aSAndroid Build Coastguard Worker 986*61c4878aSAndroid Build Coastguard Worker---------------------------- 987*61c4878aSAndroid Build Coastguard WorkerEncoding and sending packets 988*61c4878aSAndroid Build Coastguard Worker---------------------------- 989*61c4878aSAndroid Build Coastguard Worker``pw_rpc`` has to manage interactions among multiple RPC clients, servers, 990*61c4878aSAndroid Build Coastguard Workerclient calls, and server calls. To safely synchronize these interactions with 991*61c4878aSAndroid Build Coastguard Workerminimal overhead, ``pw_rpc`` uses a single, global mutex (when 992*61c4878aSAndroid Build Coastguard Worker``PW_RPC_USE_GLOBAL_MUTEX`` is enabled). 993*61c4878aSAndroid Build Coastguard Worker 994*61c4878aSAndroid Build Coastguard WorkerBecause ``pw_rpc`` uses a global mutex, it also uses a global buffer to encode 995*61c4878aSAndroid Build Coastguard Workeroutgoing packets. The size of the buffer is set with 996*61c4878aSAndroid Build Coastguard Worker``PW_RPC_ENCODING_BUFFER_SIZE_BYTES``, which defaults to 512 B. If dynamic 997*61c4878aSAndroid Build Coastguard Workerallocation is enabled, this size does not affect how large RPC messages can be, 998*61c4878aSAndroid Build Coastguard Workerbut it is still used for sizing buffers in test utilities. 999*61c4878aSAndroid Build Coastguard Worker 1000*61c4878aSAndroid Build Coastguard WorkerUsers of ``pw_rpc`` must implement the :cpp:class:`pw::rpc::ChannelOutput` 1001*61c4878aSAndroid Build Coastguard Workerinterface. 1002*61c4878aSAndroid Build Coastguard Worker 1003*61c4878aSAndroid Build Coastguard Worker.. _module-pw_rpc-ChannelOutput: 1004*61c4878aSAndroid Build Coastguard Worker.. cpp:class:: pw::rpc::ChannelOutput 1005*61c4878aSAndroid Build Coastguard Worker 1006*61c4878aSAndroid Build Coastguard Worker ``pw_rpc`` endpoints use :cpp:class:`ChannelOutput` instances to send 1007*61c4878aSAndroid Build Coastguard Worker packets. Systems that integrate pw_rpc must use one or more 1008*61c4878aSAndroid Build Coastguard Worker :cpp:class:`ChannelOutput` instances. 1009*61c4878aSAndroid Build Coastguard Worker 1010*61c4878aSAndroid Build Coastguard Worker .. cpp:member:: static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max() 1011*61c4878aSAndroid Build Coastguard Worker 1012*61c4878aSAndroid Build Coastguard Worker Value returned from :cpp:func:`MaximumTransmissionUnit` to indicate an 1013*61c4878aSAndroid Build Coastguard Worker unlimited MTU. 1014*61c4878aSAndroid Build Coastguard Worker 1015*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: virtual size_t MaximumTransmissionUnit() 1016*61c4878aSAndroid Build Coastguard Worker 1017*61c4878aSAndroid Build Coastguard Worker Returns the size of the largest packet the :cpp:class:`ChannelOutput` can 1018*61c4878aSAndroid Build Coastguard Worker send. :cpp:class:`ChannelOutput` implementations should only override this 1019*61c4878aSAndroid Build Coastguard Worker function if they impose a limit on the MTU. The default implementation 1020*61c4878aSAndroid Build Coastguard Worker returns :cpp:member:`kUnlimited`, which indicates that there is no MTU 1021*61c4878aSAndroid Build Coastguard Worker limit. 1022*61c4878aSAndroid Build Coastguard Worker 1023*61c4878aSAndroid Build Coastguard Worker .. cpp:function:: virtual pw::Status Send(span<std::byte> packet) 1024*61c4878aSAndroid Build Coastguard Worker 1025*61c4878aSAndroid Build Coastguard Worker Sends an encoded RPC packet. Returns OK if further packets may be sent, 1026*61c4878aSAndroid Build Coastguard Worker even if the current packet could not be sent. Returns any other status if 1027*61c4878aSAndroid Build Coastguard Worker the Channel is no longer able to send packets. 1028*61c4878aSAndroid Build Coastguard Worker 1029*61c4878aSAndroid Build Coastguard Worker The RPC system's internal lock is held while this function is 1030*61c4878aSAndroid Build Coastguard Worker called. Avoid long-running operations, since these will delay any other 1031*61c4878aSAndroid Build Coastguard Worker users of the RPC system. 1032*61c4878aSAndroid Build Coastguard Worker 1033*61c4878aSAndroid Build Coastguard Worker .. danger:: 1034*61c4878aSAndroid Build Coastguard Worker 1035*61c4878aSAndroid Build Coastguard Worker No ``pw_rpc`` APIs may be accessed in this function! Implementations 1036*61c4878aSAndroid Build Coastguard Worker MUST NOT access any RPC endpoints (:cpp:class:`pw::rpc::Client`, 1037*61c4878aSAndroid Build Coastguard Worker :cpp:class:`pw::rpc::Server`) or call objects 1038*61c4878aSAndroid Build Coastguard Worker (:cpp:class:`pw::rpc::ServerReaderWriter` 1039*61c4878aSAndroid Build Coastguard Worker :cpp:class:`pw::rpc::ClientReaderWriter`, etc.) inside the 1040*61c4878aSAndroid Build Coastguard Worker :cpp:func:`Send` function or any descendent calls. Doing so will result 1041*61c4878aSAndroid Build Coastguard Worker in deadlock! RPC APIs may be used by other threads, just not within 1042*61c4878aSAndroid Build Coastguard Worker :cpp:func:`Send`. 1043*61c4878aSAndroid Build Coastguard Worker 1044*61c4878aSAndroid Build Coastguard Worker The buffer provided in ``packet`` must NOT be accessed outside of this 1045*61c4878aSAndroid Build Coastguard Worker function. It must be sent immediately or copied elsewhere before the 1046*61c4878aSAndroid Build Coastguard Worker function returns. 1047