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 /// Note: The dependencies of pw_rpc depend on the value of PW_RPC_YIELD_MODE. 95 /// When building pw_rpc with Bazel, you should NOT set this module config value 96 /// directly. Instead, tell the build system which value you wish to select by 97 /// adding one of the following constraint_values to the target platform: 98 /// 99 /// - `@pigweed//pw_rpc:yield_mode_busy_loop` 100 /// - `@pigweed//pw_rpc:yield_mode_busy_sleep` (the default) 101 /// - `@pigweed//pw_rpc:yield_mode_busy_yield` 102 #ifndef PW_RPC_YIELD_MODE 103 #if PW_RPC_USE_GLOBAL_MUTEX == 0 104 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_BUSY_LOOP 105 #else 106 #define PW_RPC_YIELD_MODE PW_RPC_YIELD_MODE_SLEEP 107 #endif // PW_RPC_USE_GLOBAL_MUTEX == 0 108 #endif // PW_RPC_YIELD_MODE 109 110 /// @def PW_RPC_YIELD_MODE_BUSY_LOOP 111 /// @def PW_RPC_YIELD_MODE_SLEEP 112 /// @def PW_RPC_YIELD_MODE_YIELD 113 /// 114 /// Supported configuration values for @c_macro{PW_RPC_YIELD_MODE}. 115 // LINT.IfChange 116 #define PW_RPC_YIELD_MODE_BUSY_LOOP 100 117 #define PW_RPC_YIELD_MODE_SLEEP 101 118 #define PW_RPC_YIELD_MODE_YIELD 102 119 // LINT.ThenChange(//pw_rpc/BUILD.bazel) 120 121 /// If `PW_RPC_YIELD_MODE == PW_RPC_YIELD_MODE_SLEEP`, 122 /// `PW_RPC_YIELD_SLEEP_DURATION` sets how long to sleep during each iteration 123 /// of the yield loop. The value must be a constant expression that converts to 124 /// a @cpp_type{pw::chrono::SystemClock::duration}. 125 #ifndef PW_RPC_YIELD_SLEEP_DURATION 126 127 // When building for a desktop operating system, use a 1ms sleep by default. 128 // 1-tick duration sleeps can result in spurious timeouts. 129 #if defined(_WIN32) || defined(__APPLE__) || \ 130 defined(__linux__) && !defined(__ZEPHYR__) 131 #define PW_RPC_YIELD_SLEEP_DURATION std::chrono::milliseconds(1) 132 #else 133 #define PW_RPC_YIELD_SLEEP_DURATION pw::chrono::SystemClock::duration(1) 134 #endif // defined(_WIN32) || defined(__APPLE__) || defined(__linux__) 135 // && !defined(__ZEPHYR__) 136 137 #endif // PW_RPC_YIELD_SLEEP_DURATION 138 139 // PW_RPC_YIELD_SLEEP_DURATION is not needed for non-sleep yield modes. 140 #if PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP 141 #undef PW_RPC_YIELD_SLEEP_DURATION 142 #endif // PW_RPC_YIELD_MODE != PW_RPC_YIELD_MODE_SLEEP 143 144 /// pw_rpc call objects wait for their callbacks to complete before they are 145 /// moved or destoyed. Deadlocks occur if a callback: 146 /// 147 /// - attempts to destroy its call object, 148 /// - attempts to move its call object while the call is still active, or 149 /// - never returns. 150 /// 151 /// If `PW_RPC_CALLBACK_TIMEOUT_TICKS` is greater than 0, then `PW_CRASH` is 152 /// invoked if a thread waits for an RPC callback to complete for more than the 153 /// specified tick count. 154 /// 155 /// A "tick" in this context is one iteration of a loop that yields releases the 156 /// RPC lock and yields the thread according to @c_macro{PW_RPC_YIELD_MODE}. By 157 /// default, the thread yields with a 1-tick call to 158 /// @cpp_func{pw::this_thread::sleep_for()}. 159 #ifndef PW_RPC_CALLBACK_TIMEOUT_TICKS 160 #define PW_RPC_CALLBACK_TIMEOUT_TICKS 10000 161 #endif // PW_RPC_CALLBACK_TIMEOUT_TICKS 162 163 /// Whether pw_rpc should use dynamic memory allocation internally. If enabled, 164 /// pw_rpc dynamically allocates channels and its encoding buffer. RPC users may 165 /// use dynamic allocation independently of this option (e.g. to allocate pw_rpc 166 /// call objects). 167 /// 168 /// The semantics for allocating and initializing channels change depending on 169 /// this option. If dynamic allocation is disabled, pw_rpc endpoints (servers or 170 /// clients) use an externally-allocated, fixed-size array of channels. That 171 /// array must include unassigned channels or existing channels must be closed 172 /// to add new channels. 173 /// 174 /// If dynamic allocation is enabled, an span of channels may be passed to the 175 /// endpoint at construction, but these channels are only used to initialize its 176 /// internal channels container. External channel objects are NOT used by the 177 /// endpoint and cannot be updated if dynamic allocation is enabled. No 178 /// unassigned channels should be passed to the endpoint; they will be ignored. 179 /// Any number of channels may be added to the endpoint, without closing 180 /// existing channels, but adding channels will use more memory. 181 #ifndef PW_RPC_DYNAMIC_ALLOCATION 182 #define PW_RPC_DYNAMIC_ALLOCATION 0 183 #endif // PW_RPC_DYNAMIC_ALLOCATION 184 185 #if defined(PW_RPC_DYNAMIC_CONTAINER) || \ 186 defined(PW_RPC_DYNAMIC_CONTAINER_INCLUDE) 187 static_assert( 188 PW_RPC_DYNAMIC_ALLOCATION == 1, 189 "PW_RPC_DYNAMIC_ALLOCATION is disabled, so PW_RPC_DYNAMIC_CONTAINER and " 190 "PW_RPC_DYNAMIC_CONTAINER_INCLUDE have no effect and should not be set."); 191 #endif // PW_RPC_DYNAMIC_CONTAINER || PW_RPC_DYNAMIC_CONTAINER_INCLUDE 192 193 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this macro must expand to 194 /// a container capable of storing objects of the provided type. This container 195 /// will be used internally by pw_rpc to allocate the channels list and encoding 196 /// buffer. Defaults to `std::vector<type>`, but may be set to any type that 197 /// supports the following `std::vector` operations: 198 /// 199 /// - Default construction 200 /// - `emplace_back()` 201 /// - `pop_back()` 202 /// - `back()` 203 /// - `resize()` 204 /// - `clear()` 205 /// - Range-based for loop iteration (`begin()`, `end()`) 206 /// 207 #ifndef PW_RPC_DYNAMIC_CONTAINER 208 #define PW_RPC_DYNAMIC_CONTAINER(type) std::vector<type> 209 #endif // PW_RPC_DYNAMIC_CONTAINER 210 211 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this header file is 212 /// included in files that use @c_macro{PW_RPC_DYNAMIC_CONTAINER}. Defaults to 213 /// `<vector>`, but may be set in conjunction with 214 /// @c_macro{PW_RPC_DYNAMIC_CONTAINER} to use a different container type for 215 /// dynamic allocations in pw_rpc. 216 #ifndef PW_RPC_DYNAMIC_CONTAINER_INCLUDE 217 #define PW_RPC_DYNAMIC_CONTAINER_INCLUDE <vector> 218 #endif // PW_RPC_DYNAMIC_CONTAINER_INCLUDE 219 220 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this macro must expand to 221 /// a statement that creates a `std::unique_ptr`-like smart pointer. 222 /// @param type The type of the object to construct (e.g. with `new`) 223 /// @param ... Arguments to pass to the constructor, if any 224 #ifndef PW_RPC_MAKE_UNIQUE_PTR 225 #define PW_RPC_MAKE_UNIQUE_PTR(type, ...) \ 226 std::unique_ptr<type>(new type(__VA_ARGS__)) 227 #endif // PW_RPC_DYNAMIC_CONTAINER 228 229 /// If @c_macro{PW_RPC_DYNAMIC_ALLOCATION} is enabled, this header file is 230 /// included in files that use @c_macro{PW_RPC_MAKE_UNIQUE_PTR}. Defaults to 231 /// `<memory>` for `std::make_unique`. 232 #ifndef PW_RPC_MAKE_UNIQUE_PTR_INCLUDE 233 #define PW_RPC_MAKE_UNIQUE_PTR_INCLUDE <memory> 234 #endif // PW_RPC_MAKE_UNIQUE_PTR_INCLUDE 235 236 /// Size of the global RPC packet encoding buffer in bytes. If dynamic 237 /// allocation is enabled, this value is only used for test helpers that 238 /// allocate RPC encoding buffers. 239 #ifndef PW_RPC_ENCODING_BUFFER_SIZE_BYTES 240 #define PW_RPC_ENCODING_BUFFER_SIZE_BYTES 512 241 #endif // PW_RPC_ENCODING_BUFFER_SIZE_BYTES 242 243 /// The log level to use for this module. Logs below this level are omitted. 244 #ifndef PW_RPC_CONFIG_LOG_LEVEL 245 #define PW_RPC_CONFIG_LOG_LEVEL PW_LOG_LEVEL_INFO 246 #endif // PW_RPC_CONFIG_LOG_LEVEL 247 248 /// The log module name to use for this module. 249 #ifndef PW_RPC_CONFIG_LOG_MODULE_NAME 250 #define PW_RPC_CONFIG_LOG_MODULE_NAME "PW_RPC" 251 #endif // PW_RPC_CONFIG_LOG_MODULE_NAME 252 253 namespace pw::rpc::cfg { 254 255 template <typename...> 256 constexpr std::bool_constant<PW_RPC_COMPLETION_REQUEST_CALLBACK> 257 kClientStreamEndCallbackEnabled; 258 259 template <typename...> 260 constexpr std::bool_constant<PW_RPC_METHOD_STORES_TYPE> kMethodStoresType; 261 262 template <typename...> 263 constexpr std::bool_constant<PW_RPC_DYNAMIC_ALLOCATION> 264 kDynamicAllocationEnabled; 265 266 inline constexpr size_t kNanopbStructMinBufferSize = 267 PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE; 268 269 inline constexpr size_t kEncodingBufferSizeBytes = 270 PW_RPC_ENCODING_BUFFER_SIZE_BYTES; 271 272 #undef PW_RPC_NANOPB_STRUCT_MIN_BUFFER_SIZE 273 #undef PW_RPC_ENCODING_BUFFER_SIZE_BYTES 274 275 } // namespace pw::rpc::cfg 276 277 /// This option determines whether to allocate the Nanopb structs on the stack 278 /// or in a global variable. Globally allocated structs are NOT thread safe, but 279 /// work fine when the RPC server's ProcessPacket function is only called from 280 /// one thread. 281 #ifndef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 282 #define PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 1 283 #endif // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 284 285 /// @private Internal macro for declaring the Nanopb struct; do not use. 286 #if PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 287 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS 288 #else 289 #define _PW_RPC_NANOPB_STRUCT_STORAGE_CLASS static 290 #endif // PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 291 292 #undef PW_RPC_NANOPB_STRUCT_BUFFER_STACK_ALLOCATE 293