1 /* 2 * Copyright (c) 2018, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for Channel Manager. 32 */ 33 34 #ifndef CHANNEL_MANAGER_HPP_ 35 #define CHANNEL_MANAGER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE 40 41 #if (OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE && !OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE) 42 #error "CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE requires OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE"; 43 #endif 44 45 #if (OPENTHREAD_FTD || OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) 46 47 #include <openthread/platform/radio.h> 48 49 #include "common/locator.hpp" 50 #include "common/non_copyable.hpp" 51 #include "common/timer.hpp" 52 #include "mac/mac.hpp" 53 54 namespace ot { 55 namespace Utils { 56 57 /** 58 * @addtogroup utils-channel-manager 59 * 60 * @brief 61 * This module includes definitions for Channel Manager. 62 * 63 * @{ 64 */ 65 66 /** 67 * Implements the Channel Manager. 68 * 69 */ 70 class ChannelManager : public InstanceLocator, private NonCopyable 71 { 72 public: 73 #if OPENTHREAD_FTD 74 /** 75 * Minimum delay (in seconds) used for network channel change. 76 * 77 */ 78 static constexpr uint16_t kMinimumDelay = OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_DELAY; 79 #endif 80 81 /** 82 * Initializes a `ChanelManager` object. 83 * 84 * @param[in] aInstance A reference to the OpenThread instance. 85 * 86 */ 87 explicit ChannelManager(Instance &aInstance); 88 89 #if OPENTHREAD_FTD 90 /** 91 * Requests a Thread network channel change. 92 * 93 * The Thread network switches to the given channel after a specified delay (@sa GetDelay()). The channel change is 94 * performed by updating the Pending Operational Dataset. 95 * 96 * A subsequent call to this method will cancel an ongoing previously requested channel change. 97 * 98 * If the requested channel changes, it will trigger a `Notifier` event `kEventChannelManagerNewChannelChanged`. 99 * 100 * @param[in] aChannel The new channel for the Thread network. 101 * 102 */ 103 void RequestNetworkChannelChange(uint8_t aChannel); 104 #endif 105 106 /** 107 * Gets the channel from the last successful call to `RequestNetworkChannelChange()` or `ChangeCslChannel()`. 108 * 109 * @returns The last requested channel, or zero if there has been no channel change request yet. 110 * 111 */ GetRequestedChannel(void) const112 uint8_t GetRequestedChannel(void) const { return mChannel; } 113 114 #if OPENTHREAD_FTD 115 /** 116 * Gets the delay (in seconds) used for a channel change. 117 * 118 * @returns The delay (in seconds) 119 * 120 */ GetDelay(void) const121 uint16_t GetDelay(void) const { return mDelay; } 122 123 /** 124 * Sets the delay (in seconds) used for a channel change. 125 * 126 * The delay should preferably be longer than maximum data poll interval used by all sleepy-end-devices within the 127 * Thread network. 128 * 129 * @param[in] aDelay Delay in seconds. 130 * 131 * @retval kErrorNone Delay was updated successfully. 132 * @retval kErrorInvalidArgs The given delay @p aDelay is shorter than `kMinimumDelay`. 133 * 134 */ 135 Error SetDelay(uint16_t aDelay); 136 #endif // OPENTHREAD_FTD 137 138 #if OPENTHREAD_FTD 139 /** 140 * Requests that `ChannelManager` checks and selects a new network channel and starts a network channel change. 141 * 142 * Unlike the `RequestChannelChange()` where the channel must be given as a parameter, this method asks the 143 * `ChannelManager` to select a channel by itself (based on the collected channel quality info). 144 * 145 * Once called, the `ChannelManager` will perform the following 3 steps: 146 * 147 * 1) `ChannelManager` decides if the channel change would be helpful. This check can be skipped if 148 * `aSkipQualityCheck` is set to true (forcing a channel selection to happen and skipping the quality check). 149 * This step uses the collected link quality metrics on the device (such as CCA failure rate, frame and message 150 * error rates per neighbor, etc.) to determine if the current channel quality is at the level that justifies 151 * a channel change. 152 * 153 * 2) If the first step passes, then `ChannelManager` selects a potentially better channel. It uses the collected 154 * channel occupancy data by `ChannelMonitor` module. The supported and favored channels are used at this step. 155 * (@sa SetSupportedChannels, @sa SetFavoredChannels). 156 * 157 * 3) If the newly selected channel is different from the current channel, `ChannelManager` requests/starts the 158 * channel change process (internally invoking a `RequestNetworkChannelChange()`). 159 * 160 * 161 * @param[in] aSkipQualityCheck Indicates whether the quality check (step 1) should be skipped. 162 * 163 * @retval kErrorNone Channel selection finished successfully. 164 * @retval kErrorNotFound Supported channels is empty, therefore could not select a channel. 165 * @retval kErrorInvalidState Thread is not enabled or not enough data to select new channel. 166 * 167 */ 168 Error RequestNetworkChannelSelect(bool aSkipQualityCheck); 169 #endif // OPENTHREAD_FTD 170 171 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE 172 /** 173 * Requests that `ChannelManager` checks and selects a new Csl channel and starts a channel change. 174 * 175 * Once called, the `ChannelManager` will perform the following 3 steps: 176 * 177 * 1) `ChannelManager` decides if the channel change would be helpful. This check can be skipped if 178 * `aSkipQualityCheck` is set to true (forcing a channel selection to happen and skipping the quality check). 179 * This step uses the collected link quality metrics on the device (such as CCA failure rate, frame and message 180 * error rates per neighbor, etc.) to determine if the current channel quality is at the level that justifies 181 * a channel change. 182 * 183 * 2) If the first step passes, then `ChannelManager` selects a potentially better channel. It uses the collected 184 * channel occupancy data by `ChannelMonitor` module. The supported and favored channels are used at this step. 185 * (@sa SetSupportedChannels, @sa SetFavoredChannels). 186 * 187 * 3) If the newly selected channel is different from the current Csl channel, `ChannelManager` starts the 188 * channel change process (internally invoking a `ChangeCslChannel()`). 189 * 190 * 191 * @param[in] aSkipQualityCheck Indicates whether the quality check (step 1) should be skipped. 192 * 193 * @retval kErrorNone Channel selection finished successfully. 194 * @retval kErrorNotFound Supported channels is empty, therefore could not select a channel. 195 * @retval kErrorInvalidState Thread is not enabled or not enough data to select new channel. 196 * 197 */ 198 Error RequestCslChannelSelect(bool aSkipQualityCheck); 199 #endif // OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE 200 201 #if OPENTHREAD_FTD 202 /** 203 * Enables/disables the auto-channel-selection functionality. 204 * 205 * When enabled, `ChannelManager` will periodically invoke a `RequestChannelSelect(false)`. The period interval 206 * can be set by `SetAutoChannelSelectionInterval()`. 207 * 208 * @param[in] aEnabled Indicates whether to enable or disable this functionality. 209 * 210 */ 211 void SetAutoNetworkChannelSelectionEnabled(bool aEnabled); 212 213 /** 214 * Indicates whether the auto-channel-selection functionality is enabled or not. 215 * 216 * @returns TRUE if enabled, FALSE if disabled. 217 * 218 */ GetAutoNetworkChannelSelectionEnabled(void) const219 bool GetAutoNetworkChannelSelectionEnabled(void) const { return mAutoSelectEnabled; } 220 #endif 221 222 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE 223 /** 224 * Enables/disables the auto-channel-selection functionality. 225 * 226 * When enabled, `ChannelManager` will periodically invoke a `RequestChannelSelect(false)`. The period interval 227 * can be set by `SetAutoChannelSelectionInterval()`. 228 * 229 * @param[in] aEnabled Indicates whether to enable or disable this functionality. 230 * 231 */ 232 void SetAutoCslChannelSelectionEnabled(bool aEnabled); 233 234 /** 235 * Indicates whether the auto-channel-selection functionality is enabled or not. 236 * 237 * @returns TRUE if enabled, FALSE if disabled. 238 * 239 */ GetAutoCslChannelSelectionEnabled(void) const240 bool GetAutoCslChannelSelectionEnabled(void) const { return mAutoSelectCslEnabled; } 241 #endif 242 243 /** 244 * Sets the period interval (in seconds) used by auto-channel-selection functionality. 245 * 246 * @param[in] aInterval The interval (in seconds). 247 * 248 * @retval kErrorNone The interval was set successfully. 249 * @retval kErrorInvalidArgs The @p aInterval is not valid (zero). 250 * 251 */ 252 Error SetAutoChannelSelectionInterval(uint32_t aInterval); 253 254 /** 255 * Gets the period interval (in seconds) used by auto-channel-selection functionality. 256 * 257 * @returns The interval (in seconds). 258 * 259 */ GetAutoChannelSelectionInterval(void) const260 uint32_t GetAutoChannelSelectionInterval(void) const { return mAutoSelectInterval; } 261 262 /** 263 * Gets the supported channel mask. 264 * 265 * @returns The supported channels mask. 266 * 267 */ GetSupportedChannels(void) const268 uint32_t GetSupportedChannels(void) const { return mSupportedChannelMask.GetMask(); } 269 270 /** 271 * Sets the supported channel mask. 272 * 273 * @param[in] aChannelMask A channel mask. 274 * 275 */ 276 void SetSupportedChannels(uint32_t aChannelMask); 277 278 /** 279 * Gets the favored channel mask. 280 * 281 * @returns The favored channels mask. 282 * 283 */ GetFavoredChannels(void) const284 uint32_t GetFavoredChannels(void) const { return mFavoredChannelMask.GetMask(); } 285 286 /** 287 * Sets the favored channel mask. 288 * 289 * @param[in] aChannelMask A channel mask. 290 * 291 */ 292 void SetFavoredChannels(uint32_t aChannelMask); 293 294 /** 295 * Gets the CCA failure rate threshold 296 * 297 * @returns The CCA failure rate threshold 298 * 299 */ GetCcaFailureRateThreshold(void) const300 uint16_t GetCcaFailureRateThreshold(void) const { return mCcaFailureRateThreshold; } 301 302 /** 303 * Sets the CCA failure rate threshold 304 * 305 * @param[in] aThreshold A CCA failure rate threshold. 306 * 307 */ 308 void SetCcaFailureRateThreshold(uint16_t aThreshold); 309 310 private: 311 // Retry interval to resend Pending Dataset in case of tx failure (in ms). 312 static constexpr uint32_t kPendingDatasetTxRetryInterval = 20000; 313 314 // Maximum jitter/wait time to start a requested network channel change (in ms). 315 static constexpr uint32_t kRequestStartJitterInterval = 10000; 316 317 // The minimum number of RSSI samples required before using the collected data (by `ChannelMonitor`) to select 318 // a channel. 319 static constexpr uint32_t kMinChannelMonitorSampleCount = 320 OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_MONITOR_SAMPLE_COUNT; 321 322 // Minimum channel occupancy difference to prefer an unfavored channel over a favored one. 323 static constexpr uint16_t kThresholdToSkipFavored = OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_SKIP_FAVORED; 324 325 // Minimum channel occupancy difference between current channel and the selected channel to trigger the channel 326 // change process to start. 327 static constexpr uint16_t kThresholdToChangeChannel = OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_CHANGE_CHANNEL; 328 329 // Default auto-channel-selection period (in seconds). 330 static constexpr uint32_t kDefaultAutoSelectInterval = 331 OPENTHREAD_CONFIG_CHANNEL_MANAGER_DEFAULT_AUTO_SELECT_INTERVAL; 332 333 // Minimum CCA failure rate on current channel to start the channel selection process. 334 static constexpr uint16_t kCcaFailureRateThreshold = OPENTHREAD_CONFIG_CHANNEL_MANAGER_CCA_FAILURE_THRESHOLD; 335 336 enum State : uint8_t 337 { 338 kStateIdle, 339 kStateChangeRequested, 340 kStateChangeInProgress, 341 }; 342 343 #if OPENTHREAD_FTD 344 void StartDatasetUpdate(void); 345 static void HandleDatasetUpdateDone(Error aError, void *aContext); 346 void HandleDatasetUpdateDone(Error aError); 347 #endif 348 void HandleTimer(void); 349 void StartAutoSelectTimer(void); 350 Error RequestChannelSelect(bool aSkipQualityCheck); 351 Error RequestAutoChannelSelect(bool aSkipQualityCheck); 352 void RequestChannelChange(uint8_t aChannel); 353 354 #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 355 Error FindBetterChannel(uint8_t &aNewChannel, uint16_t &aOccupancy); 356 bool ShouldAttemptChannelChange(void); 357 #endif 358 359 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE 360 void ChangeCslChannel(uint8_t aChannel); 361 #endif 362 363 using ManagerTimer = TimerMilliIn<ChannelManager, &ChannelManager::HandleTimer>; 364 365 Mac::ChannelMask mSupportedChannelMask; 366 Mac::ChannelMask mFavoredChannelMask; 367 #if OPENTHREAD_FTD 368 uint16_t mDelay; 369 #endif 370 uint8_t mChannel; 371 uint8_t mChannelSelected; 372 State mState; 373 ManagerTimer mTimer; 374 uint32_t mAutoSelectInterval; 375 #if OPENTHREAD_FTD 376 bool mAutoSelectEnabled; 377 #endif 378 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE 379 bool mAutoSelectCslEnabled; 380 #endif 381 uint16_t mCcaFailureRateThreshold; 382 }; 383 384 /** 385 * @} 386 * 387 */ 388 389 } // namespace Utils 390 } // namespace ot 391 392 #endif // #if (OPENTHREAD_FTD || OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) 393 #endif // #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE 394 395 #endif // CHANNEL_MANAGER_HPP_ 396