• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 <cstdint>
17 #include <span>
18 #include <thread>
19 
20 #include "pw_hdlc/rpc_channel.h"
21 #include "pw_hdlc/rpc_packets.h"
22 #include "pw_rpc/integration_testing.h"
23 #include "pw_status/try.h"
24 #include "pw_stream/socket_stream.h"
25 
26 namespace pw::rpc::integration_test {
27 
28 // Wraps an RPC client with a socket stream and a channel configured to use it.
29 // Useful for integration tests that run across a socket.
30 template <size_t kMaxTransmissionUnit>
31 class SocketClientContext {
32  public:
SocketClientContext()33   constexpr SocketClientContext()
34       : channel_output_(stream_, hdlc::kDefaultRpcAddress, "socket"),
35         channel_(Channel::Create<kChannelId>(&channel_output_)),
36         client_(std::span(&channel_, 1)) {}
37 
client()38   Client& client() { return client_; }
39 
40   // Connects to the specified host:port and starts a background thread to read
41   // packets from the socket.
Start(const char * host,uint16_t port)42   Status Start(const char* host, uint16_t port) {
43     PW_TRY(stream_.Connect(host, port));
44     std::thread{&SocketClientContext::ProcessPackets, this}.detach();
45     return OkStatus();
46   }
47 
48   // Calls Start for localhost.
Start(uint16_t port)49   Status Start(uint16_t port) { return Start("localhost", port); }
50 
51  private:
52   void ProcessPackets();
53 
54   stream::SocketStream stream_;
55   hdlc::RpcChannelOutput channel_output_;
56   Channel channel_;
57   Client client_;
58 };
59 
60 template <size_t kMaxTransmissionUnit>
ProcessPackets()61 void SocketClientContext<kMaxTransmissionUnit>::ProcessPackets() {
62   std::byte decode_buffer[kMaxTransmissionUnit];
63   hdlc::Decoder decoder(decode_buffer);
64 
65   while (true) {
66     std::byte byte[1];
67     Result<ByteSpan> read = stream_.Read(byte);
68 
69     if (!read.ok() || read->size() == 0u) {
70       continue;
71     }
72 
73     if (auto result = decoder.Process(*byte); result.ok()) {
74       hdlc::Frame& frame = result.value();
75       if (frame.address() == hdlc::kDefaultRpcAddress) {
76         PW_ASSERT(client_.ProcessPacket(frame.data()).ok());
77       }
78     }
79   }
80 }
81 
82 }  // namespace pw::rpc::integration_test
83