C/C++ API Reference
Loading...
Searching...
No Matches
channel.h
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 <cstdint>
17#include <limits>
18#include <type_traits>
19
20#include "pw_assert/assert.h"
21#include "pw_bytes/span.h"
22#include "pw_result/result.h"
23#include "pw_rpc/internal/config.h"
24#include "pw_rpc/internal/lock.h"
25#include "pw_rpc/internal/packet.h"
26#include "pw_span/span.h"
27#include "pw_status/status.h"
28
29namespace pw::rpc {
30namespace internal {
31namespace test {
32
33template <typename, typename, uint32_t>
34class InvocationContext; // Forward declaration for friend statement
35
36} // namespace test
37
38class ChannelList; // Forward declaration for friend statement
39
40Status OverwriteChannelId(ByteSpan rpc_packet, uint32_t channel_id_under_128);
41
42} // namespace internal
43
45
51
59template <uint32_t kNewChannelId>
61 static_assert(kNewChannelId < 128u,
62 "Channel IDs must be less than 128 to avoid needing to "
63 "re-encode the packet");
64 return internal::OverwriteChannelId(rpc_packet, kNewChannelId);
65}
66
71 uint32_t new_channel_id) {
72 PW_ASSERT(new_channel_id < 128);
73 return internal::OverwriteChannelId(rpc_packet, new_channel_id);
74}
75
88constexpr size_t MaxSafePayloadSize(
89 size_t encode_buffer_size = cfg::kEncodingBufferSizeBytes) {
90 return encode_buffer_size > internal::Packet::kMinEncodedSizeWithoutPayload
91 ? encode_buffer_size -
92 internal::Packet::kMinEncodedSizeWithoutPayload
93 : 0;
94}
95
97 public:
98 // Returned from MaximumTransmissionUnit() to indicate that this ChannelOutput
99 // imposes no limits on the MTU.
100 static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max();
101
102 // Creates a channel output with the provided name. The name is used for
103 // logging only.
104 constexpr ChannelOutput(const char* name) : name_(name) {}
105
106 virtual ~ChannelOutput() = default;
107
108 constexpr const char* name() const { return name_; }
109
110 // Returns the maximum transmission unit that this ChannelOutput supports. If
111 // the ChannelOutput imposes no limit on the MTU, this function returns
112 // ChannelOutput::kUnlimited.
113 virtual size_t MaximumTransmissionUnit() { return kUnlimited; }
114
115 // Sends an encoded RPC packet. Returns OK if further packets may be sent,
116 // even if the current packet could not be sent. Returns any other status if
117 // the Channel is no longer able to send packets.
118 //
119 // The RPC system’s internal lock is held while this function is called. Avoid
120 // long-running operations, since these will delay any other users of the RPC
121 // system.
122 //
123 // !!! DANGER !!!
124 //
125 // No pw_rpc APIs may be accessed in this function! Implementations MUST NOT
126 // access any RPC endpoints (pw::rpc::Client, pw::rpc::Server) or call objects
127 // (pw::rpc::ServerReaderWriter, pw::rpc::ClientReaderWriter, etc.) inside the
128 // Send() function or any descendent calls. Doing so will result in deadlock!
129 // RPC APIs may be used by other threads, just not within Send().
130 //
131 // The buffer provided in packet must NOT be accessed outside of this
132 // function. It must be sent immediately or copied elsewhere before the
133 // function returns.
134 virtual Status Send(span<const std::byte> buffer)
135 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock()) = 0;
136
137 private:
138 const char* name_;
139};
140
142
143namespace internal {
144
145// Base class for rpc::Channel with internal-only public methods, which are
146// hidden in the public derived class.
148 public:
149 static constexpr uint32_t kUnassignedChannelId = 0;
150
151 // TODO: b/234876441 - Remove the Configure and set_channel_output functions.
152 // Users should call CloseChannel() / OpenChannel() to change a channel.
153 // This ensures calls are properly update and works consistently between
154 // static and dynamic channel allocation.
155
156 // Manually configures a dynamically-assignable channel with a specified ID
157 // and output. This is useful when a channel's parameters are not known until
158 // runtime. This can only be called once per channel.
159 template <typename UnusedType = void>
160 constexpr void Configure(uint32_t id, ChannelOutput& output) {
161 static_assert(
162 !cfg::kDynamicAllocationEnabled<UnusedType>,
163 "Configure() may not be used if PW_RPC_DYNAMIC_ALLOCATION is "
164 "enabled. Call CloseChannel/OpenChannel on the endpoint instead.");
165 PW_ASSERT(id_ == kUnassignedChannelId);
166 PW_ASSERT(id != kUnassignedChannelId);
167 id_ = id;
168 output_ = &output;
169 }
170
171 // Configure using an enum value channel ID.
172 template <typename T,
173 typename = std::enable_if_t<std::is_enum_v<T>>,
174 typename U = std::underlying_type_t<T>>
175 constexpr void Configure(T id, ChannelOutput& output) {
176 static_assert(
177 !cfg::kDynamicAllocationEnabled<T>,
178 "Configure() may not be used if PW_RPC_DYNAMIC_ALLOCATION is enabled. "
179 "Call CloseChannel/OpenChannel on the endpoint instead.");
180 static_assert(sizeof(U) <= sizeof(uint32_t));
181 const U kIntId = static_cast<U>(id);
182 PW_ASSERT(kIntId > 0);
183 return Configure<T>(static_cast<uint32_t>(kIntId), output);
184 }
185
186 // Reconfigures a channel with a new output. Depending on the output's
187 // implementatation, there might be unintended behavior if the output is in
188 // use.
189 template <typename UnusedType = void>
190 constexpr void set_channel_output(ChannelOutput& output) {
191 static_assert(
192 !cfg::kDynamicAllocationEnabled<UnusedType>,
193 "set_channel_output() may not be used if PW_RPC_DYNAMIC_ALLOCATION is "
194 "enabled. Call CloseChannel/OpenChannel on the endpoint instead.");
195 PW_ASSERT(id_ != kUnassignedChannelId);
196 output_ = &output;
197 }
198
199 constexpr uint32_t id() const { return id_; }
200 constexpr bool assigned() const { return id_ != kUnassignedChannelId; }
201
202 //
203 // Internal functions made private in the public Channel class.
204 //
205
206 // Invokes ChannelOutput::Send and returns its status. Any non-OK status
207 // indicates that the Channel is permanently closed.
208 Status Send(const Packet& packet) PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());
209
210 constexpr void Close() {
211 PW_ASSERT(id_ != kUnassignedChannelId);
212 id_ = kUnassignedChannelId;
213 output_ = nullptr;
214 }
215
216 // Returns the maximum payload size for this channel, factoring in the
217 // ChannelOutput's MTU and the RPC system's `pw::rpc::MaxSafePayloadSize()`.
218 size_t MaxWriteSizeBytes() const;
219
220 protected:
221 constexpr ChannelBase(uint32_t id, ChannelOutput* output)
222 : id_(id), output_(output) {}
223
224 private:
225 uint32_t id_;
226 ChannelOutput* output_;
227};
228
229} // namespace internal
230
231// Associates an ID with an interface for sending packets.
233 public:
234 // Creates a channel with a static ID. The channel's output can also be
235 // static, or it can set to null to allow dynamically opening connections
236 // through the channel.
237 template <uint32_t kId>
238 constexpr static Channel Create(ChannelOutput* output) {
239 static_assert(kId != kUnassignedChannelId, "Channel ID cannot be 0");
240 return Channel(kId, output);
241 }
242
243 // Creates a channel with a static ID from an enum value.
244 template <auto kId,
245 typename T = decltype(kId),
246 typename = std::enable_if_t<std::is_enum_v<T>>,
247 typename U = std::underlying_type_t<T>>
248 constexpr static Channel Create(ChannelOutput* output) {
249 constexpr U kIntId = static_cast<U>(kId);
250 static_assert(kIntId >= 0, "Channel ID cannot be negative");
251 static_assert(kIntId <= std::numeric_limits<uint32_t>::max(),
252 "Channel ID must fit in a uint32");
253 return Create<static_cast<uint32_t>(kIntId)>(output);
254 }
255
256 // Creates a dynamically assignable channel without a set ID or output.
257 constexpr Channel() : internal::ChannelBase(kUnassignedChannelId, nullptr) {}
258
259 private:
260 template <typename, typename, uint32_t>
262 friend class internal::ChannelList;
263
264 constexpr Channel(uint32_t id, ChannelOutput* output)
265 : internal::ChannelBase(id, output) {
266 PW_ASSERT(id != kUnassignedChannelId);
267 }
268
269 private:
270 // Hide internal-only methods defined in the internal::ChannelBase.
271 using internal::ChannelBase::Close;
272 using internal::ChannelBase::MaxWriteSizeBytes;
273 using internal::ChannelBase::Send;
274};
275
276} // namespace pw::rpc
Definition: result.h:143
Definition: status.h:120
Definition: channel.h:232
Definition: channel.h:96
Definition: channel.h:147
constexpr size_t MaxSafePayloadSize(size_t encode_buffer_size=cfg::kEncodingBufferSizeBytes)
Definition: channel.h:88
Status ChangeEncodedChannelId(ByteSpan rpc_packet)
Definition: channel.h:60
Result< uint32_t > ExtractChannelId(ConstByteSpan packet)
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146