// Copyright 2023 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #pragma once #include "pw_bytes/span.h" #include "pw_function/function.h" #include "pw_status/status.h" namespace pw::rpc { // pw_rpc transport layer interfaces. // Framed RPC data ready to be sent via `RpcFrameSender`. Consists of a header // and a payload. Some RPC transport encodings may not require a header and put // all of the framed data into the payload (in which case the header can be // an empty span). // // A single RPC packet can be split into multiple RpcFrame's depending on the // MTU of the transport. // // All frames for an RPC packet are expected to be sent and received in order // without being interleaved by other packets' frames. struct RpcFrame { ConstByteSpan header; ConstByteSpan payload; }; // RpcFrameSender encapsulates the details of sending the packet over // some communication channel (e.g. a hardware mailbox, shared memory, or a // socket). It exposes its maximum transmission unit (MTU) size and generally // should know how to send an `RpcFrame` of a size that is smaller or equal than // the MTU. class RpcFrameSender { public: virtual ~RpcFrameSender() = default; virtual size_t MaximumTransmissionUnit() const = 0; virtual Status Send(RpcFrame frame) = 0; }; // Gets called by `RpcPacketEncoder` for each frame that it emits. using OnRpcFrameEncodedCallback = pw::Function; // Gets called by `RpcPacketDecoder` for each RPC packet that it detects. using OnRpcPacketDecodedCallback = pw::Function; // RpcPacketEncoder takes an RPC packet, the max frame size, splits the packet // into frames not exceeding that size and calls the provided callback with // each produced frame. template class RpcPacketEncoder { public: Status Encode(ConstByteSpan rpc_packet, size_t max_frame_size, OnRpcFrameEncodedCallback&& callback) { return static_cast(this)->Encode( rpc_packet, max_frame_size, std::move(callback)); } }; // RpcPacketDecoder finds and decodes RPC frames in the provided buffer. Once // all frames for an RPC packet are decoded, the callback is invoked with a // decoded RPC packet as an argument. // // Frames from the same RPC packet are expected to be received in order and // without being interleaved with frames from any other packets. template class RpcPacketDecoder { public: Status Decode(ConstByteSpan buffer, OnRpcPacketDecodedCallback&& callback) { return static_cast(this)->Decode(buffer, std::move(callback)); } }; // Provides means of sending an RPC packet. A typical implementation ties // transport and encoder together, although some implementations may not require // any encoding (e.g. LocalRpcEgress). class RpcEgressHandler { public: virtual ~RpcEgressHandler() = default; virtual Status SendRpcPacket(ConstByteSpan rpc_packet) = 0; }; // Provides means of receiving a stream of RPC packets. A typical implementation // ties transport and decoder together. class RpcIngressHandler { public: virtual ~RpcIngressHandler() = default; virtual Status ProcessIncomingData(ConstByteSpan buffer) = 0; }; // A decoded RPC packet is passed to RpcPacketProcessor for further handling. class RpcPacketProcessor { public: virtual ~RpcPacketProcessor() = default; virtual Status ProcessRpcPacket(ConstByteSpan rpc_packet) = 0; }; } // namespace pw::rpc