1 // Copyright 2023 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 transfer module. 16 #pragma once 17 18 #include <chrono> 19 #include <cinttypes> 20 #include <limits> 21 22 #include "pw_chrono/system_clock.h" 23 #include "pw_preprocessor/compiler.h" 24 25 // The log level to use for this module. Logs below this level are omitted. 26 #ifndef PW_TRANSFER_CONFIG_LOG_LEVEL 27 #define PW_TRANSFER_CONFIG_LOG_LEVEL PW_LOG_LEVEL_INFO 28 #endif // PW_TRANSFER_CONFIG_LOG_LEVEL 29 30 // Turns on logging of individual chunks. Data and parameter chunk logging has 31 // additional configuration 32 #ifndef PW_TRANSFER_CONFIG_DEBUG_CHUNKS 33 #define PW_TRANSFER_CONFIG_DEBUG_CHUNKS 0 34 #endif // PW_TRANSFER_CONFIG_DEBUG_CHUNKS 35 36 // Turns on logging of data and parameter chunks. 37 #ifndef PW_TRANSFER_CONFIG_DEBUG_DATA_CHUNKS 38 #define PW_TRANSFER_CONFIG_DEBUG_DATA_CHUNKS 0 39 #endif // PW_TRANSFER_CONFIG_DEBUG_DATA_CHUNKS 40 41 #ifdef PW_TRANSFER_DEFAULT_MAX_RETRIES 42 #pragma message( \ 43 "PW_TRANSFER_DEFAULT_MAX_RETRIES is deprecated; " \ 44 "Use PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES and " \ 45 "PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES instead.") 46 #endif // PW_TRANSFER_DEFAULT_MAX_RETRIES 47 48 #ifdef PW_TRANSFER_DEFAULT_TIMEOUT_MS 49 #pragma message( \ 50 "PW_TRANSFER_DEFAULT_TIMEOUT_MS is deprecated; " \ 51 "Use PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS and " \ 52 "PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS instead.") 53 #endif // PW_TRANSFER_DEFAULT_TIMEOUT_MS 54 55 // The default maximum number of times a transfer client should retry sending a 56 // chunk when no response is received. Can later be configured per-transfer when 57 // starting one. 58 #ifndef PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES 59 60 // Continue to accept the old deprecated setting until projects have migrated. 61 #ifdef PW_TRANSFER_DEFAULT_MAX_RETRIES 62 #define PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES PW_TRANSFER_DEFAULT_MAX_RETRIES 63 #else 64 #define PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES 3 65 #endif // PW_TRANSFER_DEFAULT_MAX_RETRIES 66 67 #endif // PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES 68 69 static_assert(PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES >= 0 && 70 PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES <= 71 static_cast<uint32_t>(std::numeric_limits<uint8_t>::max())); 72 73 // The default maximum number of times a transfer server should retry sending a 74 // chunk when no response is received. 75 // 76 // In typical setups, retries are driven by the client, and timeouts on the 77 // server are used only to clean up resources, so this defaults to 0. 78 #ifndef PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES 79 80 // Continue to accept the old deprecated setting until projects have migrated. 81 #ifdef PW_TRANSFER_DEFAULT_MAX_RETRIES 82 #define PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES PW_TRANSFER_DEFAULT_MAX_RETRIES 83 #else 84 #define PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES 0 85 #endif // PW_TRANSFER_DEFAULT_MAX_RETRIES 86 87 #endif // PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES 88 89 // GCC emits spurious -Wtype-limits warnings for the static_assert. 90 PW_MODIFY_DIAGNOSTICS_PUSH(); 91 PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wtype-limits"); 92 static_assert(PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES >= 0 && 93 PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES <= 94 std::numeric_limits<uint8_t>::max()); 95 PW_MODIFY_DIAGNOSTICS_POP(); 96 97 // The default maximum number of times a transfer should retry sending a chunk 98 // over the course of its entire lifetime. 99 // This number should be high, particularly if long-running transfers are 100 // expected. Its purpose is to prevent transfers from getting stuck in an 101 // infinite loop. 102 #ifndef PW_TRANSFER_DEFAULT_MAX_LIFETIME_RETRIES 103 #define PW_TRANSFER_DEFAULT_MAX_LIFETIME_RETRIES \ 104 (static_cast<uint32_t>(PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES) * 1000u) 105 #endif // PW_TRANSFER_DEFAULT_MAX_LIFETIME_RETRIES 106 107 static_assert(PW_TRANSFER_DEFAULT_MAX_LIFETIME_RETRIES > 108 PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES && 109 PW_TRANSFER_DEFAULT_MAX_LIFETIME_RETRIES <= 110 std::numeric_limits<uint32_t>::max()); 111 112 // The default amount of time, in milliseconds, to wait for a chunk to arrive 113 // in a transfer client before retrying. This can later be configured 114 // per-transfer. 115 #ifndef PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS 116 117 // Continue to accept the old deprecated setting until projects have migrated. 118 #ifdef PW_TRANSFER_DEFAULT_TIMEOUT_MS 119 #define PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS PW_TRANSFER_DEFAULT_TIMEOUT_MS 120 #else 121 #define PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS 2000 122 #endif // PW_TRANSFER_DEFAULT_TIMEOUT_MS 123 124 #endif // PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS 125 126 static_assert(PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS > 0); 127 128 // The default amount of time, in milliseconds, to wait for a chunk to arrive 129 // on the server before retrying. This can later be configured per-transfer. 130 #ifndef PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS 131 132 // Continue to accept the old deprecated setting until projects have migrated. 133 #ifdef PW_TRANSFER_DEFAULT_TIMEOUT_MS 134 #define PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS PW_TRANSFER_DEFAULT_TIMEOUT_MS 135 #else 136 #define PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS \ 137 (static_cast<uint32_t>(PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS) * 5u) 138 #endif // PW_TRANSFER_DEFAULT_TIMEOUT_MS 139 140 #endif // PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS 141 142 static_assert(PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS > 0); 143 144 // The default amount of time, in milliseconds, for a client to wait for an 145 // initial response from the transfer server before retrying. This can later be 146 // configured // per-transfer. 147 // 148 // This is set separately to PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS as transfers 149 // may require additional time for resource initialization (e.g. erasing a flash 150 // region before writing to it). 151 #ifndef PW_TRANSFER_DEFAULT_INITIAL_TIMEOUT_MS 152 #define PW_TRANSFER_DEFAULT_INITIAL_TIMEOUT_MS \ 153 PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS 154 #endif // PW_TRANSFER_DEFAULT_INITIAL_TIMEOUT_MS 155 156 static_assert(PW_TRANSFER_DEFAULT_INITIAL_TIMEOUT_MS > 0); 157 158 // The fractional position within a window at which a receive transfer should 159 // extend its window size to minimize the amount of time the transmitter 160 // spends blocked. 161 // 162 // For example, a divisor of 2 will extend the window when half of the 163 // requested data has been received, a divisor of three will extend at a third 164 // of the window, and so on. 165 #ifndef PW_TRANSFER_DEFAULT_EXTEND_WINDOW_DIVISOR 166 #define PW_TRANSFER_DEFAULT_EXTEND_WINDOW_DIVISOR 2 167 #endif // PW_TRANSFER_DEFAULT_EXTEND_WINDOW_DIVISOR 168 169 static_assert(PW_TRANSFER_DEFAULT_EXTEND_WINDOW_DIVISOR > 1); 170 171 // Number of chunks to send repetitative logs at full rate before reducing to 172 // rate_limit. Retransmit parameter chunks will restart at this chunk count 173 // limit. 174 // Default is first 10 parameter logs will be sent, then reduced to one log 175 // every `RATE_PERIOD_MS` 176 #ifndef PW_TRANSFER_LOG_DEFAULT_CHUNKS_BEFORE_RATE_LIMIT 177 #define PW_TRANSFER_LOG_DEFAULT_CHUNKS_BEFORE_RATE_LIMIT 10 178 #endif // PW_TRANSFER_LOG_DEFAULT_CHUNKS_BEFORE_RATE_LIMIT 179 180 static_assert(PW_TRANSFER_LOG_DEFAULT_CHUNKS_BEFORE_RATE_LIMIT > 0); 181 182 // The minimum time between repetative logs after the rate limit has been 183 // applied (after CHUNKS_BEFORE_RATE_LIMIT parameter chunks). 184 // Default is to reduce repetative logs to once every 10 seconds after 185 // `CHUNKS_BEFORE_RATE_LIMIT` parameter chunks have been sent. 186 #ifndef PW_TRANSFER_LOG_DEFAULT_RATE_PERIOD_MS 187 #define PW_TRANSFER_LOG_DEFAULT_RATE_PERIOD_MS 10000 188 #endif // PW_TRANSFER_DEFAULT_MIN_RATE_PERIOD_MS 189 190 static_assert(PW_TRANSFER_LOG_DEFAULT_RATE_PERIOD_MS >= 0); 191 192 // Maximum time to wait for a transfer event to be processed before dropping 193 // further queued events. In systems which can perform long-running operations 194 // to process transfer data, this can be used to prevent threads from blocking 195 // for extended periods. A value of 0 results in indefinite blocking. 196 #ifndef PW_TRANSFER_EVENT_PROCESSING_TIMEOUT_MS 197 #define PW_TRANSFER_EVENT_PROCESSING_TIMEOUT_MS \ 198 PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS 199 #endif // PW_TRANSFER_EVENT_PROCESSING_TIMEOUT_MS 200 201 static_assert(PW_TRANSFER_EVENT_PROCESSING_TIMEOUT_MS >= 0); 202 203 namespace pw::transfer::cfg { 204 205 inline constexpr uint8_t kDefaultMaxClientRetries = 206 PW_TRANSFER_DEFAULT_MAX_CLIENT_RETRIES; 207 inline constexpr uint8_t kDefaultMaxServerRetries = 208 PW_TRANSFER_DEFAULT_MAX_SERVER_RETRIES; 209 inline constexpr uint16_t kDefaultMaxLifetimeRetries = 210 PW_TRANSFER_DEFAULT_MAX_LIFETIME_RETRIES; 211 212 inline constexpr chrono::SystemClock::duration kDefaultClientTimeout = 213 chrono::SystemClock::for_at_least( 214 std::chrono::milliseconds(PW_TRANSFER_DEFAULT_CLIENT_TIMEOUT_MS)); 215 inline constexpr chrono::SystemClock::duration kDefaultServerTimeout = 216 chrono::SystemClock::for_at_least( 217 std::chrono::milliseconds(PW_TRANSFER_DEFAULT_SERVER_TIMEOUT_MS)); 218 219 inline constexpr chrono::SystemClock::duration kDefaultInitialChunkTimeout = 220 chrono::SystemClock::for_at_least( 221 std::chrono::milliseconds(PW_TRANSFER_DEFAULT_INITIAL_TIMEOUT_MS)); 222 223 inline constexpr uint32_t kDefaultExtendWindowDivisor = 224 PW_TRANSFER_DEFAULT_EXTEND_WINDOW_DIVISOR; 225 226 inline constexpr uint16_t kLogDefaultChunksBeforeRateLimit = 227 PW_TRANSFER_LOG_DEFAULT_CHUNKS_BEFORE_RATE_LIMIT; 228 inline constexpr chrono::SystemClock::duration kLogDefaultRateLimit = 229 chrono::SystemClock::for_at_least( 230 std::chrono::milliseconds(PW_TRANSFER_LOG_DEFAULT_RATE_PERIOD_MS)); 231 232 inline constexpr bool kWaitForEventProcessingIndefinitely = 233 PW_TRANSFER_EVENT_PROCESSING_TIMEOUT_MS == 0; 234 inline constexpr chrono::SystemClock::duration kEventProcessingTimeout = 235 chrono::SystemClock::for_at_least( 236 std::chrono::milliseconds(PW_TRANSFER_EVENT_PROCESSING_TIMEOUT_MS)); 237 238 } // namespace pw::transfer::cfg 239