1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_rpc_transport: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker================ 4*61c4878aSAndroid Build Coastguard Workerpw_rpc_transport 5*61c4878aSAndroid Build Coastguard Worker================ 6*61c4878aSAndroid Build Coastguard WorkerThe ``pw_rpc_transport`` provides a transport layer for ``pw_rpc``. 7*61c4878aSAndroid Build Coastguard Worker 8*61c4878aSAndroid Build Coastguard Worker.. warning:: 9*61c4878aSAndroid Build Coastguard Worker This is an experimental module currently under development. APIs and 10*61c4878aSAndroid Build Coastguard Worker functionality may change at any time. 11*61c4878aSAndroid Build Coastguard Worker 12*61c4878aSAndroid Build Coastguard Worker``pw_rpc`` provides a system for defining and invoking remote procedure calls 13*61c4878aSAndroid Build Coastguard Worker(RPCs) on a device. It does not include any transports for sending these RPC 14*61c4878aSAndroid Build Coastguard Workercalls. On a real device there could be multiple ways of inter-process and/or 15*61c4878aSAndroid Build Coastguard Workerinter-core communication: hardware mailboxes, shared memory, network sockets, 16*61c4878aSAndroid Build Coastguard WorkerUnix domain sockets. ``pw_rpc_transport`` provides means to implement various 17*61c4878aSAndroid Build Coastguard Workertransports and integrate them with ``pw_rpc`` services. 18*61c4878aSAndroid Build Coastguard Worker 19*61c4878aSAndroid Build Coastguard Worker``pw_rpc_transport`` relies on the assumption that a ``pw_rpc`` channel ID 20*61c4878aSAndroid Build Coastguard Workeruniquely identifies both sides of an RPC conversation. It allows developers to 21*61c4878aSAndroid Build Coastguard Workerdefine transports, egresses and ingresses for various channel IDs and choose 22*61c4878aSAndroid Build Coastguard Workerwhat framing will be used to send RPC packets over those transports. 23*61c4878aSAndroid Build Coastguard Worker 24*61c4878aSAndroid Build Coastguard WorkerRpcFrame 25*61c4878aSAndroid Build Coastguard Worker-------- 26*61c4878aSAndroid Build Coastguard WorkerFramed RPC data ready to be sent via ``RpcFrameSender``. Consists of a header 27*61c4878aSAndroid Build Coastguard Workerand a payload. Some RPC transport encodings may not require a header and put 28*61c4878aSAndroid Build Coastguard Workerall of the framed data into the payload (in which case the header can be 29*61c4878aSAndroid Build Coastguard Workeran empty span). 30*61c4878aSAndroid Build Coastguard Worker 31*61c4878aSAndroid Build Coastguard WorkerA single RPC packet can be split into multiple ``RpcFrame``'s depending on the 32*61c4878aSAndroid Build Coastguard WorkerMTU of the transport. 33*61c4878aSAndroid Build Coastguard Worker 34*61c4878aSAndroid Build Coastguard WorkerAll frames for an RPC packet are expected to be sent and received in order 35*61c4878aSAndroid Build Coastguard Workerwithout being interleaved by other packets' frames. 36*61c4878aSAndroid Build Coastguard Worker 37*61c4878aSAndroid Build Coastguard WorkerRpcFrameSender 38*61c4878aSAndroid Build Coastguard Worker-------------- 39*61c4878aSAndroid Build Coastguard WorkerSends RPC frames over some communication channel (e.g. a hardware mailbox, 40*61c4878aSAndroid Build Coastguard Workershared memory, or a socket). It exposes its MTU size and generally only knows 41*61c4878aSAndroid Build Coastguard Workerhow to send an ``RpcFrame`` of a size that doesn't exceed that MTU. 42*61c4878aSAndroid Build Coastguard Worker 43*61c4878aSAndroid Build Coastguard WorkerRpcPacketEncoder / RpcPacketDecoder 44*61c4878aSAndroid Build Coastguard Worker----------------------------------- 45*61c4878aSAndroid Build Coastguard Worker``RpcPacketEncoder`` is used to split and frame an RPC packet. 46*61c4878aSAndroid Build Coastguard Worker``RpcPacketDecoder`` then does the opposite e.g. stitches together received 47*61c4878aSAndroid Build Coastguard Workerframes and removes any framing added by the encoder. 48*61c4878aSAndroid Build Coastguard Worker 49*61c4878aSAndroid Build Coastguard WorkerRpcEgressHandler 50*61c4878aSAndroid Build Coastguard Worker---------------- 51*61c4878aSAndroid Build Coastguard WorkerProvides means of sending an RPC packet to its destination. Typically it ties 52*61c4878aSAndroid Build Coastguard Workertogether an ``RpcPacketEncoder`` and ``RpcFrameSender``. 53*61c4878aSAndroid Build Coastguard Worker 54*61c4878aSAndroid Build Coastguard WorkerRpcIngressHandler 55*61c4878aSAndroid Build Coastguard Worker----------------- 56*61c4878aSAndroid Build Coastguard WorkerProvides means of receiving RPC packets over some transport. Typically it has 57*61c4878aSAndroid Build Coastguard Workerlogic for reading RPC frames from some transport (a network connection, 58*61c4878aSAndroid Build Coastguard Workershared memory, or a hardware mailbox), stitching and decoding them with 59*61c4878aSAndroid Build Coastguard Worker``RpcPacketDecoder`` and passing full RPC packets to their intended processor 60*61c4878aSAndroid Build Coastguard Workervia ``RpcPacketProcessor``. 61*61c4878aSAndroid Build Coastguard Worker 62*61c4878aSAndroid Build Coastguard WorkerRpcPacketProcessor 63*61c4878aSAndroid Build Coastguard Worker------------------ 64*61c4878aSAndroid Build Coastguard WorkerUsed by ``RpcIngressHandler`` to send the received RPC packet to its intended 65*61c4878aSAndroid Build Coastguard Workerhandler (e.g. a pw_rpc ``Service``). 66*61c4878aSAndroid Build Coastguard Worker 67*61c4878aSAndroid Build Coastguard Worker-------------------- 68*61c4878aSAndroid Build Coastguard WorkerCreating a transport 69*61c4878aSAndroid Build Coastguard Worker-------------------- 70*61c4878aSAndroid Build Coastguard WorkerRPC transports implement ``pw::rpc::RpcFrameSender``. The transport exposes its 71*61c4878aSAndroid Build Coastguard Workermaximum transmission unit (MTU) and only knows how to send packets of up to the 72*61c4878aSAndroid Build Coastguard Workersize of that MTU. 73*61c4878aSAndroid Build Coastguard Worker 74*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 75*61c4878aSAndroid Build Coastguard Worker 76*61c4878aSAndroid Build Coastguard Worker class MyRpcTransport : public RpcFrameSender { 77*61c4878aSAndroid Build Coastguard Worker public: 78*61c4878aSAndroid Build Coastguard Worker size_t mtu() const override { return 128; } 79*61c4878aSAndroid Build Coastguard Worker 80*61c4878aSAndroid Build Coastguard Worker Status Send(RpcFrame frame) override { 81*61c4878aSAndroid Build Coastguard Worker // Send the frame via mailbox, shared memory or some other mechanism... 82*61c4878aSAndroid Build Coastguard Worker } 83*61c4878aSAndroid Build Coastguard Worker }; 84*61c4878aSAndroid Build Coastguard Worker 85*61c4878aSAndroid Build Coastguard Worker-------------------------- 86*61c4878aSAndroid Build Coastguard WorkerIntegration with pw_stream 87*61c4878aSAndroid Build Coastguard Worker-------------------------- 88*61c4878aSAndroid Build Coastguard WorkerAn RpcFrameSender implementaion that wraps a ``pw::stream::Writer`` is provided 89*61c4878aSAndroid Build Coastguard Workerby ``pw::rpc::StreamRpcFrameSender``. As the stream interface doesn't know 90*61c4878aSAndroid Build Coastguard Workerabout MTU's, it's up to the user to select one. 91*61c4878aSAndroid Build Coastguard Worker 92*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 93*61c4878aSAndroid Build Coastguard Worker 94*61c4878aSAndroid Build Coastguard Worker stream::SysIoWriter writer; 95*61c4878aSAndroid Build Coastguard Worker StreamRpcFrameSender<kMtu> sender(writer); 96*61c4878aSAndroid Build Coastguard Worker 97*61c4878aSAndroid Build Coastguard WorkerA thread to feed data to a ``pw::rpc::RpcIngressHandler`` from a 98*61c4878aSAndroid Build Coastguard Worker``pw::stream::Reader`` is provided by ``pw::rpc::StreamRpcDispatcher``. 99*61c4878aSAndroid Build Coastguard Worker 100*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 101*61c4878aSAndroid Build Coastguard Worker 102*61c4878aSAndroid Build Coastguard Worker rpc::HdlcRpcIngress<kMaxRpcPacketSize> hdlc_ingress(...); 103*61c4878aSAndroid Build Coastguard Worker stream::SysIoReader reader; 104*61c4878aSAndroid Build Coastguard Worker 105*61c4878aSAndroid Build Coastguard Worker // Feed Hdlc ingress with bytes from sysio. 106*61c4878aSAndroid Build Coastguard Worker rpc::StreamRpcDispatcher<kMaxSysioRead> sysio_dispatcher(reader, 107*61c4878aSAndroid Build Coastguard Worker hdlc_ingress); 108*61c4878aSAndroid Build Coastguard Worker 109*61c4878aSAndroid Build Coastguard Worker thread::DetachedThread(SysioDispatcherThreadOptions(), 110*61c4878aSAndroid Build Coastguard Worker sysio_dispatcher); 111*61c4878aSAndroid Build Coastguard Worker 112*61c4878aSAndroid Build Coastguard Worker------------------------------------------- 113*61c4878aSAndroid Build Coastguard WorkerUsing transports: a sample three-node setup 114*61c4878aSAndroid Build Coastguard Worker------------------------------------------- 115*61c4878aSAndroid Build Coastguard Worker 116*61c4878aSAndroid Build Coastguard WorkerA transport must be properly registered in order for ``pw_rpc`` to correctly 117*61c4878aSAndroid Build Coastguard Workerroute its packets. Below is an example of using a ``SocketRpcTransport`` and 118*61c4878aSAndroid Build Coastguard Workera (hypothetical) ``SharedMemoryRpcTransport`` to set up RPC connectivity between 119*61c4878aSAndroid Build Coastguard Workerthree endpoints. 120*61c4878aSAndroid Build Coastguard Worker 121*61c4878aSAndroid Build Coastguard WorkerNode A runs ``pw_rpc`` clients who want to talk to nodes B and C using 122*61c4878aSAndroid Build Coastguard Worker``kChannelAB`` and ``kChannelAC`` respectively. However there is no direct 123*61c4878aSAndroid Build Coastguard Workerconnectivity from A to C: only B can talk to C over shared memory while A can 124*61c4878aSAndroid Build Coastguard Workertalk to B over a socket connection. Also, some services on A are self-hosted 125*61c4878aSAndroid Build Coastguard Workerand accessed from the same process on ``kChannelAA``: 126*61c4878aSAndroid Build Coastguard Worker 127*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 128*61c4878aSAndroid Build Coastguard Worker 129*61c4878aSAndroid Build Coastguard Worker // Set up A->B transport over a network socket where B is a server 130*61c4878aSAndroid Build Coastguard Worker // and A is a client. 131*61c4878aSAndroid Build Coastguard Worker SocketRpcTransport<kSocketReadBufferSize> a_to_b_transport( 132*61c4878aSAndroid Build Coastguard Worker SocketRpcTransport<kSocketReadBufferSize>::kAsClient, "localhost", 133*61c4878aSAndroid Build Coastguard Worker kNodeBPortNumber); 134*61c4878aSAndroid Build Coastguard Worker 135*61c4878aSAndroid Build Coastguard Worker // LocalRpcEgress handles RPC packets received from other nodes and destined 136*61c4878aSAndroid Build Coastguard Worker // to this node. 137*61c4878aSAndroid Build Coastguard Worker LocalRpcEgress<kLocalEgressQueueSize, kMaxPacketSize> local_egress; 138*61c4878aSAndroid Build Coastguard Worker // HdlcRpcEgress applies HDLC framing to all packets outgoing over the A->B 139*61c4878aSAndroid Build Coastguard Worker // transport. 140*61c4878aSAndroid Build Coastguard Worker HdlcRpcEgress<kMaxPacketSize> a_to_b_egress("a->b", a_to_b_transport); 141*61c4878aSAndroid Build Coastguard Worker 142*61c4878aSAndroid Build Coastguard Worker // List of channels for all packets originated locally at A. 143*61c4878aSAndroid Build Coastguard Worker std::array tx_channels = { 144*61c4878aSAndroid Build Coastguard Worker // Self-destined packets go directly to local egress. 145*61c4878aSAndroid Build Coastguard Worker Channel::Create<kChannelAA>(&local_egress), 146*61c4878aSAndroid Build Coastguard Worker // Packets to B and C go over A->B transport. 147*61c4878aSAndroid Build Coastguard Worker Channel::Create<kChannelAB>(&a_to_b_egress), 148*61c4878aSAndroid Build Coastguard Worker Channel::Create<kChannelAC>(&a_to_b_egress), 149*61c4878aSAndroid Build Coastguard Worker }; 150*61c4878aSAndroid Build Coastguard Worker 151*61c4878aSAndroid Build Coastguard Worker // Here we list all egresses for the packets _incoming_ from B. 152*61c4878aSAndroid Build Coastguard Worker std::array b_rx_channels = { 153*61c4878aSAndroid Build Coastguard Worker // Packets on both AB and AC channels are destined locally; hence sending 154*61c4878aSAndroid Build Coastguard Worker // to the local egress. 155*61c4878aSAndroid Build Coastguard Worker ChannelEgress{kChannelAB, local_egress}, 156*61c4878aSAndroid Build Coastguard Worker ChannelEgress{kChannelAC, local_egress}, 157*61c4878aSAndroid Build Coastguard Worker }; 158*61c4878aSAndroid Build Coastguard Worker 159*61c4878aSAndroid Build Coastguard Worker // HdlcRpcIngress complements HdlcRpcEgress: all packets received on 160*61c4878aSAndroid Build Coastguard Worker // `b_rx_channels` are assumed to have HDLC framing. 161*61c4878aSAndroid Build Coastguard Worker HdlcRpcIngress<kMaxPacketSize> b_ingress(b_rx_channels); 162*61c4878aSAndroid Build Coastguard Worker 163*61c4878aSAndroid Build Coastguard Worker // Local egress needs to know how to send received packets to their target 164*61c4878aSAndroid Build Coastguard Worker // pw_rpc service. 165*61c4878aSAndroid Build Coastguard Worker ServiceRegistry registry(tx_channels); 166*61c4878aSAndroid Build Coastguard Worker local_egress.set_packet_processor(registry); 167*61c4878aSAndroid Build Coastguard Worker // Socket transport needs to be aware of what ingress it's handling. 168*61c4878aSAndroid Build Coastguard Worker a_to_b_transport.set_ingress(b_ingress); 169*61c4878aSAndroid Build Coastguard Worker 170*61c4878aSAndroid Build Coastguard Worker // Both RpcSocketTransport and LocalRpcEgress are ThreadCore's and 171*61c4878aSAndroid Build Coastguard Worker // need to be started in order for packet processing to start. 172*61c4878aSAndroid Build Coastguard Worker DetachedThread(/*...*/, a_to_b_transport); 173*61c4878aSAndroid Build Coastguard Worker DetachedThread(/*...*/, local_egress); 174*61c4878aSAndroid Build Coastguard Worker 175*61c4878aSAndroid Build Coastguard WorkerNode B setup is the most complicated since it needs to deal with egress 176*61c4878aSAndroid Build Coastguard Workerand ingress from both A and B and needs to support two kinds of transports. Note 177*61c4878aSAndroid Build Coastguard Workerthat A is unaware of which transport and framing B is using when talking to C: 178*61c4878aSAndroid Build Coastguard Worker 179*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 180*61c4878aSAndroid Build Coastguard Worker 181*61c4878aSAndroid Build Coastguard Worker // This is the server counterpart to A's client socket. 182*61c4878aSAndroid Build Coastguard Worker SocketRpcTransport<kSocketReadBufferSize> b_to_a_transport( 183*61c4878aSAndroid Build Coastguard Worker SocketRpcTransport<kSocketReadBufferSize>::kAsServer, "localhost", 184*61c4878aSAndroid Build Coastguard Worker kNodeBPortNumber); 185*61c4878aSAndroid Build Coastguard Worker 186*61c4878aSAndroid Build Coastguard Worker SharedMemoryRpcTransport b_to_c_transport(/*...*/); 187*61c4878aSAndroid Build Coastguard Worker 188*61c4878aSAndroid Build Coastguard Worker LocalRpcEgress<kLocalEgressQueueSize, kMaxPacketSize> local_egress; 189*61c4878aSAndroid Build Coastguard Worker HdlcRpcEgress<kMaxPacketSize> b_to_a_egress("b->a", b_to_a_transport); 190*61c4878aSAndroid Build Coastguard Worker // SimpleRpcEgress applies a very simple length-prefixed framing to B->C 191*61c4878aSAndroid Build Coastguard Worker // traffic (because HDLC adds unnecessary overhead over shared memory). 192*61c4878aSAndroid Build Coastguard Worker SimpleRpcEgress<kMaxPacketSize> b_to_c_egress("b->c", b_to_c_transport); 193*61c4878aSAndroid Build Coastguard Worker 194*61c4878aSAndroid Build Coastguard Worker // List of channels for all packets originated locally at B (note that in 195*61c4878aSAndroid Build Coastguard Worker // this example B doesn't need to talk to C directly; it only proxies for A). 196*61c4878aSAndroid Build Coastguard Worker std::array tx_channels = { 197*61c4878aSAndroid Build Coastguard Worker Channel::Create<kChannelAB>(&b_to_a_egress), 198*61c4878aSAndroid Build Coastguard Worker }; 199*61c4878aSAndroid Build Coastguard Worker 200*61c4878aSAndroid Build Coastguard Worker // Here we list all egresses for the packets _incoming_ from A. 201*61c4878aSAndroid Build Coastguard Worker std::array a_rx_channels = { 202*61c4878aSAndroid Build Coastguard Worker ChannelEgress{kChannelAB, local_egress}, 203*61c4878aSAndroid Build Coastguard Worker ChannelEgress{kChannelAC, b_to_c_egress}, 204*61c4878aSAndroid Build Coastguard Worker }; 205*61c4878aSAndroid Build Coastguard Worker 206*61c4878aSAndroid Build Coastguard Worker // Here we list all egresses for the packets _incoming_ from C. 207*61c4878aSAndroid Build Coastguard Worker std::array c_rx_channels = { 208*61c4878aSAndroid Build Coastguard Worker ChannelEgress{kChannelAC, b_to_a_egress}, 209*61c4878aSAndroid Build Coastguard Worker }; 210*61c4878aSAndroid Build Coastguard Worker 211*61c4878aSAndroid Build Coastguard Worker HdlcRpcIngress<kMaxPacketSize> b_ingress(b_rx_channels); 212*61c4878aSAndroid Build Coastguard Worker SimpleRpcIngress<kMaxPacketSize> c_ingress(c_rx_channels); 213*61c4878aSAndroid Build Coastguard Worker 214*61c4878aSAndroid Build Coastguard Worker ServiceRegistry registry(tx_channels); 215*61c4878aSAndroid Build Coastguard Worker local_egress.set_packet_processor(registry); 216*61c4878aSAndroid Build Coastguard Worker 217*61c4878aSAndroid Build Coastguard Worker b_to_a_transport.set_ingress(a_ingress); 218*61c4878aSAndroid Build Coastguard Worker b_to_c_transport.set_ingress(c_ingress); 219*61c4878aSAndroid Build Coastguard Worker 220*61c4878aSAndroid Build Coastguard Worker DetachedThread({}, b_to_a_transport); 221*61c4878aSAndroid Build Coastguard Worker DetachedThread({}, b_to_c_transport); 222*61c4878aSAndroid Build Coastguard Worker DetachedThread({}, local_egress); 223*61c4878aSAndroid Build Coastguard Worker 224*61c4878aSAndroid Build Coastguard WorkerNode C setup is straightforward since it only needs to handle ingress from B: 225*61c4878aSAndroid Build Coastguard Worker 226*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 227*61c4878aSAndroid Build Coastguard Worker 228*61c4878aSAndroid Build Coastguard Worker SharedMemoryRpcTransport c_to_b_transport(/*...*/); 229*61c4878aSAndroid Build Coastguard Worker LocalRpcEgress<kLocalEgressQueueSize, kMaxPacketSize> local_egress; 230*61c4878aSAndroid Build Coastguard Worker SimpleRpcEgress<kMaxPacketSize> c_to_b_egress("c->b", c_to_b_transport); 231*61c4878aSAndroid Build Coastguard Worker 232*61c4878aSAndroid Build Coastguard Worker std::array tx_channels = { 233*61c4878aSAndroid Build Coastguard Worker Channel::Create<kChannelAC>(&c_to_b_egress), 234*61c4878aSAndroid Build Coastguard Worker }; 235*61c4878aSAndroid Build Coastguard Worker 236*61c4878aSAndroid Build Coastguard Worker // Here we list all egresses for the packets _incoming_ from B. 237*61c4878aSAndroid Build Coastguard Worker std::array b_rx_channels = { 238*61c4878aSAndroid Build Coastguard Worker ChannelEgress{kChannelAC, local_egress}, 239*61c4878aSAndroid Build Coastguard Worker }; 240*61c4878aSAndroid Build Coastguard Worker 241*61c4878aSAndroid Build Coastguard Worker SimpleRpcIngress<kMaxPacketSize> b_ingress(b_rx_channels); 242*61c4878aSAndroid Build Coastguard Worker 243*61c4878aSAndroid Build Coastguard Worker ServiceRegistry registry(tx_channels); 244*61c4878aSAndroid Build Coastguard Worker local_egress.set_packet_processor(registry); 245*61c4878aSAndroid Build Coastguard Worker 246*61c4878aSAndroid Build Coastguard Worker c_to_b_transport.set_ingress(b_ingress); 247*61c4878aSAndroid Build Coastguard Worker 248*61c4878aSAndroid Build Coastguard Worker DetachedThread(/*...*/, c_to_b_transport); 249*61c4878aSAndroid Build Coastguard Worker DetachedThread(/*...*/, local_egress); 250