1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <array> 17 18 #include "pw_assert/assert.h" 19 #include "pw_hdlc/encoded_size.h" 20 #include "pw_hdlc/encoder.h" 21 #include "pw_rpc/channel.h" 22 #include "pw_span/span.h" 23 #include "pw_stream/stream.h" 24 25 namespace pw::hdlc { 26 27 // Custom HDLC ChannelOutput class to write and read data through serial using 28 // the HDLC protocol. 29 // 30 // WARNING: This ChannelOutput is not thread-safe. If thread-safety is required, 31 // create a similar class that adds a mtuex to Send. 32 class RpcChannelOutput : public rpc::ChannelOutput { 33 public: 34 // The RpcChannelOutput class does not own the buffer it uses to store the 35 // protobuf bytes. This buffer is specified at the time of creation along with 36 // a writer object to which will be used to write and send the bytes. RpcChannelOutput(stream::Writer & writer,uint64_t address,const char * channel_name)37 constexpr RpcChannelOutput(stream::Writer& writer, 38 uint64_t address, 39 const char* channel_name) 40 : ChannelOutput(channel_name), writer_(writer), address_(address) {} 41 Send(span<const std::byte> buffer)42 Status Send(span<const std::byte> buffer) override { 43 return hdlc::WriteUIFrame(address_, buffer, writer_); 44 } 45 46 private: 47 stream::Writer& writer_; 48 const uint64_t address_; 49 }; 50 51 // A RpcChannelOutput that ensures all packets produced by pw_rpc will safely 52 // fit in the specified MTU after HDLC encoding. 53 template <size_t kMaxTransmissionUnit> 54 class FixedMtuChannelOutput : public RpcChannelOutput { 55 public: FixedMtuChannelOutput(stream::Writer & writer,uint64_t address,const char * channel_name)56 constexpr FixedMtuChannelOutput(stream::Writer& writer, 57 uint64_t address, 58 const char* channel_name) 59 : RpcChannelOutput(writer, address, channel_name) {} 60 61 // Provide a constexpr helper for the maximum safe payload size. MaxSafePayloadSize()62 static constexpr size_t MaxSafePayloadSize() { 63 static_assert(rpc::cfg::kEncodingBufferSizeBytes <= 64 hdlc::MaxSafePayloadSize(kMaxTransmissionUnit), 65 "pw_rpc's encode buffer is large enough to produce HDLC " 66 "frames that will exceed the bounds of this channel's MTU"); 67 static_assert( 68 rpc::MaxSafePayloadSize( 69 hdlc::MaxSafePayloadSize(kMaxTransmissionUnit)) > 0, 70 "The combined MTU and RPC encode buffer size do not afford enough " 71 "space for any RPC payload data to safely be encoded into RPC packets"); 72 return rpc::MaxSafePayloadSize( 73 hdlc::MaxSafePayloadSize(kMaxTransmissionUnit)); 74 } 75 76 // Users of pw_rpc should only care about the maximum payload size, despite 77 // this being labeled as a MTU. MaximumTransmissionUnit()78 size_t MaximumTransmissionUnit() override { return MaxSafePayloadSize(); } 79 }; 80 81 } // namespace pw::hdlc 82