1 // Copyright 2022 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 <cinttypes> 17 18 #include "pb_decode.h" 19 #include "pb_encode.h" 20 #include "pw_rpc/internal/client_server_testing_threaded.h" 21 #include "pw_rpc/nanopb/fake_channel_output.h" 22 23 namespace pw::rpc { 24 namespace internal { 25 26 template <size_t kOutputSize, 27 size_t kMaxPackets, 28 size_t kPayloadsBufferSizeBytes> 29 class NanopbWatchableChannelOutput final 30 : public WatchableChannelOutput< 31 NanopbFakeChannelOutput<kMaxPackets, kPayloadsBufferSizeBytes>, 32 kOutputSize, 33 kMaxPackets, 34 kPayloadsBufferSizeBytes> { 35 private: 36 template <auto kMethod> 37 using MethodInfo = internal::MethodInfo<kMethod>; 38 template <auto kMethod> 39 using Response = typename MethodInfo<kMethod>::Response; 40 template <auto kMethod> 41 using Request = typename MethodInfo<kMethod>::Request; 42 43 using Base = WatchableChannelOutput< 44 NanopbFakeChannelOutput<kMaxPackets, kPayloadsBufferSizeBytes>, 45 kOutputSize, 46 kMaxPackets, 47 kPayloadsBufferSizeBytes>; 48 49 public: 50 constexpr NanopbWatchableChannelOutput( 51 TestPacketProcessor&& server_packet_processor = nullptr, 52 TestPacketProcessor&& client_packet_processor = nullptr) Base(std::move (server_packet_processor),std::move (client_packet_processor))53 : Base(std::move(server_packet_processor), 54 std::move(client_packet_processor)) {} 55 56 template <auto kMethod> response(uint32_t channel_id,uint32_t index)57 Response<kMethod> response(uint32_t channel_id, uint32_t index) 58 PW_LOCKS_EXCLUDED(Base::mutex_) { 59 std::lock_guard lock(Base::mutex_); 60 PW_ASSERT(Base::PacketCount() >= index); 61 return Base::output_.template responses<kMethod>(channel_id)[index]; 62 } 63 64 template <auto kMethod> response(uint32_t channel_id,uint32_t index,Response<kMethod> & response)65 void response(uint32_t channel_id, 66 uint32_t index, 67 Response<kMethod>& response) PW_LOCKS_EXCLUDED(Base::mutex_) { 68 std::lock_guard lock(Base::mutex_); 69 PW_ASSERT(Base::PacketCount() >= index); 70 auto payloads_view = Base::output_.template responses<kMethod>(channel_id); 71 PW_ASSERT(payloads_view.serde() 72 .Decode(payloads_view.payloads()[index], response) 73 .ok()); 74 } 75 76 template <auto kMethod> request(uint32_t channel_id,uint32_t index)77 Request<kMethod> request(uint32_t channel_id, uint32_t index) 78 PW_LOCKS_EXCLUDED(Base::mutex_) { 79 std::lock_guard lock(Base::mutex_); 80 PW_ASSERT(Base::PacketCount() >= index); 81 return Base::output_.template requests<kMethod>(channel_id)[index]; 82 } 83 }; 84 85 } // namespace internal 86 87 template <size_t kOutputSize = 128, 88 size_t kMaxPackets = 16, 89 size_t kPayloadsBufferSizeBytes = 128> 90 class NanopbClientServerTestContextThreaded final 91 : public internal::ClientServerTestContextThreaded< 92 internal::NanopbWatchableChannelOutput<kOutputSize, 93 kMaxPackets, 94 kPayloadsBufferSizeBytes>, 95 kOutputSize, 96 kMaxPackets, 97 kPayloadsBufferSizeBytes> { 98 private: 99 template <auto kMethod> 100 using MethodInfo = internal::MethodInfo<kMethod>; 101 template <auto kMethod> 102 using Response = typename MethodInfo<kMethod>::Response; 103 template <auto kMethod> 104 using Request = typename MethodInfo<kMethod>::Request; 105 106 using Base = internal::ClientServerTestContextThreaded< 107 internal::NanopbWatchableChannelOutput<kOutputSize, 108 kMaxPackets, 109 kPayloadsBufferSizeBytes>, 110 kOutputSize, 111 kMaxPackets, 112 kPayloadsBufferSizeBytes>; 113 114 public: 115 NanopbClientServerTestContextThreaded( 116 const thread::Options& options, 117 TestPacketProcessor&& server_packet_processor = nullptr, 118 TestPacketProcessor&& client_packet_processor = nullptr) Base(options,std::move (server_packet_processor),std::move (client_packet_processor))119 : Base(options, 120 std::move(server_packet_processor), 121 std::move(client_packet_processor)) {} 122 123 // Retrieve copy of request indexed by order of occurance 124 template <auto kMethod> request(uint32_t index)125 Request<kMethod> request(uint32_t index) { 126 return Base::channel_output_.template request<kMethod>(Base::channel().id(), 127 index); 128 } 129 130 // Retrieve copy of response indexed by order of occurance 131 template <auto kMethod> response(uint32_t index)132 Response<kMethod> response(uint32_t index) { 133 return Base::channel_output_.template response<kMethod>( 134 Base::channel().id(), index); 135 } 136 137 // Gives access to the RPC's indexed by order of occurance using passed 138 // Response object to parse using nanopb. Use this version when you need 139 // to set callback fields in the Response object before parsing. 140 template <auto kMethod> response(uint32_t index,Response<kMethod> & response)141 void response(uint32_t index, Response<kMethod>& response) { 142 return Base::channel_output_.template response<kMethod>( 143 Base::channel().id(), index, response); 144 } 145 }; 146 147 } // namespace pw::rpc 148