1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include <array>
16*61c4878aSAndroid Build Coastguard Worker #include <cstddef>
17*61c4878aSAndroid Build Coastguard Worker #include <cstdint>
18*61c4878aSAndroid Build Coastguard Worker #include <cstdio>
19*61c4878aSAndroid Build Coastguard Worker #include <mutex>
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_hdlc/decoder.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_hdlc/default_addresses.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_hdlc/encoded_size.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_hdlc/rpc_channel.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/channel.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_sync/mutex.h"
29*61c4878aSAndroid Build Coastguard Worker #include "pw_system/config.h"
30*61c4878aSAndroid Build Coastguard Worker #include "pw_system/io.h"
31*61c4878aSAndroid Build Coastguard Worker #include "pw_system/rpc_server.h"
32*61c4878aSAndroid Build Coastguard Worker #include "pw_trace/trace.h"
33*61c4878aSAndroid Build Coastguard Worker
34*61c4878aSAndroid Build Coastguard Worker #if PW_SYSTEM_DEFAULT_CHANNEL_ID != PW_SYSTEM_LOGGING_CHANNEL_ID && \
35*61c4878aSAndroid Build Coastguard Worker PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS == PW_SYSTEM_LOGGING_RPC_HDLC_ADDRESS
36*61c4878aSAndroid Build Coastguard Worker #error \
37*61c4878aSAndroid Build Coastguard Worker "Default and logging addresses must be different to support multiple channels."
38*61c4878aSAndroid Build Coastguard Worker #endif
39*61c4878aSAndroid Build Coastguard Worker
40*61c4878aSAndroid Build Coastguard Worker namespace pw::system {
41*61c4878aSAndroid Build Coastguard Worker namespace {
42*61c4878aSAndroid Build Coastguard Worker
43*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxTransmissionUnit = PW_SYSTEM_MAX_TRANSMISSION_UNIT;
44*61c4878aSAndroid Build Coastguard Worker
45*61c4878aSAndroid Build Coastguard Worker static_assert(kMaxTransmissionUnit ==
46*61c4878aSAndroid Build Coastguard Worker hdlc::MaxEncodedFrameSize(rpc::cfg::kEncodingBufferSizeBytes));
47*61c4878aSAndroid Build Coastguard Worker
48*61c4878aSAndroid Build Coastguard Worker #if PW_SYSTEM_DEFAULT_CHANNEL_ID == PW_SYSTEM_LOGGING_CHANNEL_ID
49*61c4878aSAndroid Build Coastguard Worker hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
50*61c4878aSAndroid Build Coastguard Worker GetWriter(), PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS, "HDLC channel");
51*61c4878aSAndroid Build Coastguard Worker rpc::Channel channels[] = {
52*61c4878aSAndroid Build Coastguard Worker rpc::Channel::Create<kDefaultRpcChannelId>(&hdlc_channel_output)};
53*61c4878aSAndroid Build Coastguard Worker #else
54*61c4878aSAndroid Build Coastguard Worker class SynchronizedChannelOutput : public rpc::ChannelOutput {
55*61c4878aSAndroid Build Coastguard Worker public:
SynchronizedChannelOutput(stream::Writer & writer,uint64_t address,const char * channel_name)56*61c4878aSAndroid Build Coastguard Worker SynchronizedChannelOutput(stream::Writer& writer,
57*61c4878aSAndroid Build Coastguard Worker uint64_t address,
58*61c4878aSAndroid Build Coastguard Worker const char* channel_name)
59*61c4878aSAndroid Build Coastguard Worker : rpc::ChannelOutput(channel_name),
60*61c4878aSAndroid Build Coastguard Worker inner_(writer, address, channel_name) {}
61*61c4878aSAndroid Build Coastguard Worker
Send(span<const std::byte> buffer)62*61c4878aSAndroid Build Coastguard Worker Status Send(span<const std::byte> buffer) override {
63*61c4878aSAndroid Build Coastguard Worker std::lock_guard guard(mtx_);
64*61c4878aSAndroid Build Coastguard Worker auto s = inner_.Send(buffer);
65*61c4878aSAndroid Build Coastguard Worker return s;
66*61c4878aSAndroid Build Coastguard Worker }
67*61c4878aSAndroid Build Coastguard Worker
MaximumTransmissionUnit()68*61c4878aSAndroid Build Coastguard Worker size_t MaximumTransmissionUnit() override {
69*61c4878aSAndroid Build Coastguard Worker std::lock_guard guard(mtx_);
70*61c4878aSAndroid Build Coastguard Worker auto s = inner_.MaximumTransmissionUnit();
71*61c4878aSAndroid Build Coastguard Worker return s;
72*61c4878aSAndroid Build Coastguard Worker }
73*61c4878aSAndroid Build Coastguard Worker
74*61c4878aSAndroid Build Coastguard Worker private:
75*61c4878aSAndroid Build Coastguard Worker sync::Mutex mtx_;
76*61c4878aSAndroid Build Coastguard Worker hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> inner_ PW_GUARDED_BY(mtx_);
77*61c4878aSAndroid Build Coastguard Worker };
78*61c4878aSAndroid Build Coastguard Worker
79*61c4878aSAndroid Build Coastguard Worker SynchronizedChannelOutput hdlc_channel_output[] = {
80*61c4878aSAndroid Build Coastguard Worker SynchronizedChannelOutput(GetWriter(),
81*61c4878aSAndroid Build Coastguard Worker PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS,
82*61c4878aSAndroid Build Coastguard Worker "HDLC default channel"),
83*61c4878aSAndroid Build Coastguard Worker SynchronizedChannelOutput(GetWriter(),
84*61c4878aSAndroid Build Coastguard Worker PW_SYSTEM_LOGGING_RPC_HDLC_ADDRESS,
85*61c4878aSAndroid Build Coastguard Worker "HDLC logging channel"),
86*61c4878aSAndroid Build Coastguard Worker };
87*61c4878aSAndroid Build Coastguard Worker rpc::Channel channels[] = {
88*61c4878aSAndroid Build Coastguard Worker rpc::Channel::Create<kDefaultRpcChannelId>(&hdlc_channel_output[0]),
89*61c4878aSAndroid Build Coastguard Worker rpc::Channel::Create<kLoggingRpcChannelId>(&hdlc_channel_output[1]),
90*61c4878aSAndroid Build Coastguard Worker };
91*61c4878aSAndroid Build Coastguard Worker #endif
92*61c4878aSAndroid Build Coastguard Worker rpc::Server server(channels);
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker constexpr size_t kDecoderBufferSize =
95*61c4878aSAndroid Build Coastguard Worker hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
96*61c4878aSAndroid Build Coastguard Worker // Declare a buffer for decoding incoming HDLC frames.
97*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kDecoderBufferSize> input_buffer;
98*61c4878aSAndroid Build Coastguard Worker hdlc::Decoder decoder(input_buffer);
99*61c4878aSAndroid Build Coastguard Worker
100*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, 1> data;
101*61c4878aSAndroid Build Coastguard Worker
102*61c4878aSAndroid Build Coastguard Worker } // namespace
103*61c4878aSAndroid Build Coastguard Worker
GetRpcServer()104*61c4878aSAndroid Build Coastguard Worker rpc::Server& GetRpcServer() { return server; }
105*61c4878aSAndroid Build Coastguard Worker
106*61c4878aSAndroid Build Coastguard Worker class RpcDispatchThread final : public thread::ThreadCore {
107*61c4878aSAndroid Build Coastguard Worker public:
108*61c4878aSAndroid Build Coastguard Worker RpcDispatchThread() = default;
109*61c4878aSAndroid Build Coastguard Worker RpcDispatchThread(const RpcDispatchThread&) = delete;
110*61c4878aSAndroid Build Coastguard Worker RpcDispatchThread(RpcDispatchThread&&) = delete;
111*61c4878aSAndroid Build Coastguard Worker RpcDispatchThread& operator=(const RpcDispatchThread&) = delete;
112*61c4878aSAndroid Build Coastguard Worker RpcDispatchThread& operator=(RpcDispatchThread&&) = delete;
113*61c4878aSAndroid Build Coastguard Worker
Run()114*61c4878aSAndroid Build Coastguard Worker void Run() override {
115*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("Running RPC server");
116*61c4878aSAndroid Build Coastguard Worker while (true) {
117*61c4878aSAndroid Build Coastguard Worker auto ret_val = GetReader().Read(data);
118*61c4878aSAndroid Build Coastguard Worker if (!ret_val.ok()) {
119*61c4878aSAndroid Build Coastguard Worker continue;
120*61c4878aSAndroid Build Coastguard Worker }
121*61c4878aSAndroid Build Coastguard Worker for (std::byte byte : ret_val.value()) {
122*61c4878aSAndroid Build Coastguard Worker if (auto result = decoder.Process(byte); result.ok()) {
123*61c4878aSAndroid Build Coastguard Worker hdlc::Frame& frame = result.value();
124*61c4878aSAndroid Build Coastguard Worker PW_TRACE_SCOPE("RPC process frame");
125*61c4878aSAndroid Build Coastguard Worker if (frame.address() == PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS ||
126*61c4878aSAndroid Build Coastguard Worker frame.address() == PW_SYSTEM_LOGGING_RPC_HDLC_ADDRESS) {
127*61c4878aSAndroid Build Coastguard Worker if (!server.ProcessPacket(frame.data()).ok()) {
128*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Failed to process packet");
129*61c4878aSAndroid Build Coastguard Worker }
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker }
132*61c4878aSAndroid Build Coastguard Worker }
133*61c4878aSAndroid Build Coastguard Worker }
134*61c4878aSAndroid Build Coastguard Worker }
135*61c4878aSAndroid Build Coastguard Worker };
136*61c4878aSAndroid Build Coastguard Worker
GetRpcDispatchThread()137*61c4878aSAndroid Build Coastguard Worker thread::ThreadCore& GetRpcDispatchThread() {
138*61c4878aSAndroid Build Coastguard Worker static RpcDispatchThread rpc_dispatch_thread;
139*61c4878aSAndroid Build Coastguard Worker return rpc_dispatch_thread;
140*61c4878aSAndroid Build Coastguard Worker }
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker } // namespace pw::system
143