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