• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 // Configuration macros for the pw_rpc module.
16 #pragma once
17 
18 #include <cstddef>
19 #include <type_traits>
20 
21 #if defined(PW_RPC_CLIENT_STREAM_END_CALLBACK) && \
22     PW_RPC_CLIENT_STREAM_END_CALLBACK
23 #pragma message(                                                \
24     "Warning PW_RPC_CLIENT_STREAM_END_CALLBACK is deprecated! " \
25     "Use PW_RPC_COMPLETION_REQUEST_CALLBACK instead.")
26 #define PW_RPC_COMPLETION_REQUEST_CALLBACK 1
27 #endif
28 
29 #undef PW_RPC_CLIENT_STREAM_END_CALLBACK
30 
31 /// pw_rpc clients may request call completion by sending
32 /// `CLIENT_REQUEST_COMPLETION` packet. For client streaming or bi-direction
33 /// RPCs, this also indicates that the client is done sending requests. While
34 /// this can be useful in some circumstances, it is often not necessary.
35 ///
36 /// This option controls whether or not include a callback that is called when
37 /// the client stream requests for completion. The callback is included in all
38 /// ServerReader/Writer objects as a @cpp_type{pw::Function}, so may have a
39 /// significant cost.
40 ///
41 /// This is disabled by default.
42 #ifndef PW_RPC_COMPLETION_REQUEST_CALLBACK
43 #define PW_RPC_COMPLETION_REQUEST_CALLBACK 0
44 #endif  // PW_RPC_COMPLETION_REQUEST_CALLBACK
45 
46 /// pw_rpc Method's can include their MethodType as a runtime accessible
47 /// variable.
48 ///
49 /// This isn't needed for most applications so is disabled by default.
50 #ifndef PW_RPC_METHOD_STORES_TYPE
51 #define PW_RPC_METHOD_STORES_TYPE 0
52 #endif  // PW_RPC_METHOD_STORES_TYPE
53 
54 /// The Nanopb-based pw_rpc implementation allocates memory to use for Nanopb
55 /// structs for the request and response protobufs. The template function that
56 /// allocates these structs rounds struct sizes up to this value so that
57 /// different structs can be allocated with the same function. Structs with
58 /// sizes larger than this value cause an extra function to be created, which
59 /// slightly increases code size.
60 ///
61 /// Ideally, this value will be set to the size of the largest Nanopb struct
62 /// used as an RPC request or response. The buffer can be stack or globally
63 /// allocated (see @c_macro{PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE}).
64 ///
65 /// This defaults to 64 bytes.
66 #ifndef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
67 #define PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 64
68 #endif  // PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
69 
70 /// Enable global synchronization for RPC calls. If this is set, a backend must
71 /// be configured for pw_sync:mutex.
72 ///
73 /// This is enabled by default.
74 #ifndef PW_RPC_USE_GLOBAL_MUTEX
75 #define PW_RPC_USE_GLOBAL_MUTEX 1
76 #endif  // PW_RPC_USE_GLOBAL_MUTEX
77 
78 /// pw_rpc must yield the current thread when waiting for a callback to complete
79 /// in a different thread. PW_RPC_YIELD_MODE determines how to yield. There are
80 /// three supported settings:
81 ///
82 ///   - @c_macro{PW_RPC_YIELD_MODE_BUSY_LOOP} - Do nothing. Release and
83 ///     reacquire the RPC lock in a busy loop. @c_macro{PW_RPC_USE_GLOBAL_MUTEX}
84 ///     must be 0.
85 ///   - @c_macro{PW_RPC_YIELD_MODE_SLEEP} - Yield with 1-tick calls to
86 ///     @cpp_func{pw::this_thread::sleep_for()}. A backend must be configured
87 ///     for pw_thread:sleep.
88 ///   - @c_macro{PW_RPC_YIELD_MODE_YIELD} - Yield with
89 ///     @cpp_func{pw::this_thread::yield()}. A backend must be configured for
90 ///     pw_thread:yield. IMPORTANT: On some platforms,
91 ///     @cpp_func{pw::this_thread::yield()} does not yield to lower priority
92 ///     tasks and should not be used here.
93 ///
94 #ifndef PW_RPC_YIELD_MODE
95 #if PW_RPC_USE_GLOBAL_MUTEX == 0
96 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_BUSY_LOOP
97 #else
98 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_SLEEP
99 #endif  // PW_RPC_USE_GLOBAL_MUTEX == 0
100 #endif  // PW_RPC_YIELD_MODE
101 
102 /// @def PW_RPC_YIELD_MODE_BUSY_LOOP
103 /// @def PW_RPC_YIELD_MODE_SLEEP
104 /// @def PW_RPC_YIELD_MODE_YIELD
105 ///
106 /// Supported configuration values for @c_macro{PW_RPC_YIELD_MODE}.
107 #define PW_RPC_YIELD_MODE_BUSY_LOOP 100
108 #define PW_RPC_YIELD_MODE_SLEEP 101
109 #define PW_RPC_YIELD_MODE_YIELD 102
110 
111 /// If `PW_RPC_YIELD_MODE == PW_RPC_YIELD_MODE_SLEEP`,
112 /// `PW_RPC_YIELD_SLEEP_DURATION` sets how long to sleep during each iteration
113 /// of the yield loop. The value must be a constant expression that converts to
114 /// a @cpp_type{pw::chrono::SystemClock::duration}.
115 #ifndef PW_RPC_YIELD_SLEEP_DURATION
116 
117 // When building for a desktop operating system, use a 1ms sleep by default.
118 // 1-tick duration sleeps can result in spurious timeouts.
119 #if defined(_WIN32) || defined(__APPLE__) || \
120     defined(__linux__) && !defined(__ZEPHYR__)
121 #define PW_RPC_YIELD_SLEEP_DURATION std::chrono::milliseconds(1)
122 #else
123 #define PW_RPC_YIELD_SLEEP_DURATION pw::chrono::SystemClock::duration(1)
124 #endif  // defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
125         // && !defined(__ZEPHYR__)
126 
127 #endif  // PW_RPC_YIELD_SLEEP_DURATION
128 
129 // PW_RPC_YIELD_SLEEP_DURATION is not needed for non-sleep yield modes.
130 #if PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP
131 #undef PW_RPC_YIELD_SLEEP_DURATION
132 #endif  // PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP
133 
134 /// pw_rpc call objects wait for their callbacks to complete before they are
135 /// moved or destoyed. Deadlocks occur if a callback:
136 ///
137 ///   - attempts to destroy its call object,
138 ///   - attempts to move its call object while the call is still active, or
139 ///   - never returns.
140 ///
141 /// If `PW_RPC_CALLBACK_TIMEOUT_TICKS` is greater than 0, then `PW_CRASH` is
142 /// invoked if a thread waits for an RPC callback to complete for more than the
143 /// specified tick count.
144 ///
145 /// A "tick" in this context is one iteration of a loop that yields releases the
146 /// RPC lock and yields the thread according to @c_macro{PW_RPC_YIELD_MODE}. By
147 /// default, the thread yields with a 1-tick call to
148 /// @cpp_func{pw::this_thread::sleep_for()}.
149 #ifndef PW_RPC_CALLBACK_TIMEOUT_TICKS
150 #define PW_RPC_CALLBACK_TIMEOUT_TICKS 10000
151 #endif  // PW_RPC_CALLBACK_TIMEOUT_TICKS
152 
153 /// Whether pw_rpc should use dynamic memory allocation internally. If enabled,
154 /// pw_rpc dynamically allocates channels and its encoding buffer. RPC users may
155 /// use dynamic allocation independently of this option (e.g. to allocate pw_rpc
156 /// call objects).
157 ///
158 /// The semantics for allocating and initializing channels change depending on
159 /// this option. If dynamic allocation is disabled, pw_rpc endpoints (servers or
160 /// clients) use an externally-allocated, fixed-size array of channels.  That
161 /// array must include unassigned channels or existing channels must be closed
162 /// to add new channels.
163 ///
164 /// If dynamic allocation is enabled, an span of channels may be passed to the
165 /// endpoint at construction, but these channels are only used to initialize its
166 /// internal channels container. External channel objects are NOT used by the
167 /// endpoint and cannot be updated if dynamic allocation is enabled. No
168 /// unassigned channels should be passed to the endpoint; they will be ignored.
169 /// Any number of channels may be added to the endpoint, without closing
170 /// existing channels, but adding channels will use more memory.
171 #ifndef PW_RPC_DYNAMIC_ALLOCATION
172 #define PW_RPC_DYNAMIC_ALLOCATION 0
173 #endif  // PW_RPC_DYNAMIC_ALLOCATION
174 
175 #if defined(PW_RPC_DYNAMIC_CONTAINER) || \
176     defined(PW_RPC_DYNAMIC_CONTAINER_INCLUDE)
177 static_assert(
178     PW_RPC_DYNAMIC_ALLOCATION == 1,
179     "PW_RPC_DYNAMIC_ALLOCATION is disabled, so PW_RPC_DYNAMIC_CONTAINER and "
180     "PW_RPC_DYNAMIC_CONTAINER_INCLUDE have no effect and should not be set.");
181 #endif  // PW_RPC_DYNAMIC_CONTAINER || PW_RPC_DYNAMIC_CONTAINER_INCLUDE
182 
183 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this macro must expand to
184 /// a container capable of storing objects of the provided type. This container
185 /// will be used internally by pw_rpc to allocate the channels list and encoding
186 /// buffer. Defaults to `std::vector<type>`, but may be set to any type that
187 /// supports the following `std::vector` operations:
188 ///
189 ///   - Default construction
190 ///   - `emplace_back()`
191 ///   - `pop_back()`
192 ///   - `back()`
193 ///   - `resize()`
194 ///   - `clear()`
195 ///   - Range-based for loop iteration (`begin()`, `end()`)
196 ///
197 #ifndef PW_RPC_DYNAMIC_CONTAINER
198 #define PW_RPC_DYNAMIC_CONTAINER(type) std::vector<type>
199 #endif  // PW_RPC_DYNAMIC_CONTAINER
200 
201 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this header file is
202 /// included in files that use @c_macro{PW_RPC_DYNAMIC_CONTAINER}. Defaults to
203 /// `<vector>`, but may be set in conjunction with
204 /// @c_macro{PW_RPC_DYNAMIC_CONTAINER} to use a different container type for
205 /// dynamic allocations in pw_rpc.
206 #ifndef PW_RPC_DYNAMIC_CONTAINER_INCLUDE
207 #define PW_RPC_DYNAMIC_CONTAINER_INCLUDE <vector>
208 #endif  // PW_RPC_DYNAMIC_CONTAINER_INCLUDE
209 
210 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this macro must expand to
211 /// a statement that creates a `std::unique_ptr`-like smart pointer.
212 /// @param type The type of the object to construct (e.g. with `new`)
213 /// @param ... Arguments to pass to the constructor, if any
214 #ifndef PW_RPC_MAKE_UNIQUE_PTR
215 #define PW_RPC_MAKE_UNIQUE_PTR(type, ...) \
216   std::unique_ptr<type>(new type(__VA_ARGS__))
217 #endif  // PW_RPC_DYNAMIC_CONTAINER
218 
219 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this header file is
220 /// included in files that use @c_macro{PW_RPC_MAKE_UNIQUE_PTR}. Defaults to
221 /// `<memory>` for `std::make_unique`.
222 #ifndef PW_RPC_MAKE_UNIQUE_PTR_INCLUDE
223 #define PW_RPC_MAKE_UNIQUE_PTR_INCLUDE <memory>
224 #endif  // PW_RPC_MAKE_UNIQUE_PTR_INCLUDE
225 
226 /// Size of the global RPC packet encoding buffer in bytes. If dynamic
227 /// allocation is enabled, this value is only used for test helpers that
228 /// allocate RPC encoding buffers.
229 #ifndef PW_RPC_ENCODING_BUFFER_SIZE_BYTES
230 #define PW_RPC_ENCODING_BUFFER_SIZE_BYTES 512
231 #endif  // PW_RPC_ENCODING_BUFFER_SIZE_BYTES
232 
233 /// The log level to use for this module. Logs below this level are omitted.
234 #ifndef PW_RPC_CONFIG_LOG_LEVEL
235 #define PW_RPC_CONFIG_LOG_LEVEL PW_LOG_LEVEL_INFO
236 #endif  // PW_RPC_CONFIG_LOG_LEVEL
237 
238 /// The log module name to use for this module.
239 #ifndef PW_RPC_CONFIG_LOG_MODULE_NAME
240 #define PW_RPC_CONFIG_LOG_MODULE_NAME "PW_RPC"
241 #endif  // PW_RPC_CONFIG_LOG_MODULE_NAME
242 
243 namespace pw::rpc::cfg {
244 
245 template <typename...>
246 constexpr std::bool_constant<PW_RPC_COMPLETION_REQUEST_CALLBACK>
247     kClientStreamEndCallbackEnabled;
248 
249 template <typename...>
250 constexpr std::bool_constant<PW_RPC_METHOD_STORES_TYPE> kMethodStoresType;
251 
252 template <typename...>
253 constexpr std::bool_constant<PW_RPC_DYNAMIC_ALLOCATION>
254     kDynamicAllocationEnabled;
255 
256 inline constexpr size_t kNanopbStructMinBufferSize =
257     PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE;
258 
259 inline constexpr size_t kEncodingBufferSizeBytes =
260     PW_RPC_ENCODING_BUFFER_SIZE_BYTES;
261 
262 #undef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE
263 #undef PW_RPC_ENCODING_BUFFER_SIZE_BYTES
264 
265 }  // namespace pw::rpc::cfg
266 
267 /// This option determines whether to allocate the Nanopb structs on the stack
268 /// or in a global variable. Globally allocated structs are NOT thread safe, but
269 /// work fine when the RPC server's ProcessPacket function is only called from
270 /// one thread.
271 #ifndef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
272 #define PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 1
273 #endif  // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
274 
275 /// @private Internal macro for declaring the Nanopb struct; do not use.
276 #if PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
277 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS
278 #else
279 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS static
280 #endif  // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
281 
282 #undef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE
283