xref: /aosp_15_r20/external/pigweed/pw_system/hdlc_rpc_server.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 
15 #include <array>
16 #include <cstddef>
17 #include <cstdint>
18 #include <cstdio>
19 #include <mutex>
20 
21 #include "pw_assert/check.h"
22 #include "pw_hdlc/decoder.h"
23 #include "pw_hdlc/default_addresses.h"
24 #include "pw_hdlc/encoded_size.h"
25 #include "pw_hdlc/rpc_channel.h"
26 #include "pw_log/log.h"
27 #include "pw_rpc/channel.h"
28 #include "pw_sync/mutex.h"
29 #include "pw_system/config.h"
30 #include "pw_system/io.h"
31 #include "pw_system/rpc_server.h"
32 #include "pw_trace/trace.h"
33 
34 #if PW_SYSTEM_DEFAULT_CHANNEL_ID != PW_SYSTEM_LOGGING_CHANNEL_ID && \
35     PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS == PW_SYSTEM_LOGGING_RPC_HDLC_ADDRESS
36 #error \
37     "Default and logging addresses must be different to support multiple channels."
38 #endif
39 
40 namespace pw::system {
41 namespace {
42 
43 constexpr size_t kMaxTransmissionUnit = PW_SYSTEM_MAX_TRANSMISSION_UNIT;
44 
45 static_assert(kMaxTransmissionUnit ==
46               hdlc::MaxEncodedFrameSize(rpc::cfg::kEncodingBufferSizeBytes));
47 
48 #if PW_SYSTEM_DEFAULT_CHANNEL_ID == PW_SYSTEM_LOGGING_CHANNEL_ID
49 hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
50     GetWriter(), PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS, "HDLC channel");
51 rpc::Channel channels[] = {
52     rpc::Channel::Create<kDefaultRpcChannelId>(&hdlc_channel_output)};
53 #else
54 class SynchronizedChannelOutput : public rpc::ChannelOutput {
55  public:
SynchronizedChannelOutput(stream::Writer & writer,uint64_t address,const char * channel_name)56   SynchronizedChannelOutput(stream::Writer& writer,
57                             uint64_t address,
58                             const char* channel_name)
59       : rpc::ChannelOutput(channel_name),
60         inner_(writer, address, channel_name) {}
61 
Send(span<const std::byte> buffer)62   Status Send(span<const std::byte> buffer) override {
63     std::lock_guard guard(mtx_);
64     auto s = inner_.Send(buffer);
65     return s;
66   }
67 
MaximumTransmissionUnit()68   size_t MaximumTransmissionUnit() override {
69     std::lock_guard guard(mtx_);
70     auto s = inner_.MaximumTransmissionUnit();
71     return s;
72   }
73 
74  private:
75   sync::Mutex mtx_;
76   hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> inner_ PW_GUARDED_BY(mtx_);
77 };
78 
79 SynchronizedChannelOutput hdlc_channel_output[] = {
80     SynchronizedChannelOutput(GetWriter(),
81                               PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS,
82                               "HDLC default channel"),
83     SynchronizedChannelOutput(GetWriter(),
84                               PW_SYSTEM_LOGGING_RPC_HDLC_ADDRESS,
85                               "HDLC logging channel"),
86 };
87 rpc::Channel channels[] = {
88     rpc::Channel::Create<kDefaultRpcChannelId>(&hdlc_channel_output[0]),
89     rpc::Channel::Create<kLoggingRpcChannelId>(&hdlc_channel_output[1]),
90 };
91 #endif
92 rpc::Server server(channels);
93 
94 constexpr size_t kDecoderBufferSize =
95     hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
96 // Declare a buffer for decoding incoming HDLC frames.
97 std::array<std::byte, kDecoderBufferSize> input_buffer;
98 hdlc::Decoder decoder(input_buffer);
99 
100 std::array<std::byte, 1> data;
101 
102 }  // namespace
103 
GetRpcServer()104 rpc::Server& GetRpcServer() { return server; }
105 
106 class RpcDispatchThread final : public thread::ThreadCore {
107  public:
108   RpcDispatchThread() = default;
109   RpcDispatchThread(const RpcDispatchThread&) = delete;
110   RpcDispatchThread(RpcDispatchThread&&) = delete;
111   RpcDispatchThread& operator=(const RpcDispatchThread&) = delete;
112   RpcDispatchThread& operator=(RpcDispatchThread&&) = delete;
113 
Run()114   void Run() override {
115     PW_LOG_INFO("Running RPC server");
116     while (true) {
117       auto ret_val = GetReader().Read(data);
118       if (!ret_val.ok()) {
119         continue;
120       }
121       for (std::byte byte : ret_val.value()) {
122         if (auto result = decoder.Process(byte); result.ok()) {
123           hdlc::Frame& frame = result.value();
124           PW_TRACE_SCOPE("RPC process frame");
125           if (frame.address() == PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS ||
126               frame.address() == PW_SYSTEM_LOGGING_RPC_HDLC_ADDRESS) {
127             if (!server.ProcessPacket(frame.data()).ok()) {
128               PW_LOG_ERROR("Failed to process packet");
129             }
130           }
131         }
132       }
133     }
134   }
135 };
136 
GetRpcDispatchThread()137 thread::ThreadCore& GetRpcDispatchThread() {
138   static RpcDispatchThread rpc_dispatch_thread;
139   return rpc_dispatch_thread;
140 }
141 
142 }  // namespace pw::system
143