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 (OPENTHREAD_FTD || \ 41 (OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE)) 42 43 #include <openthread/platform/radio.h> 44 45 #include "common/locator.hpp" 46 #include "common/non_copyable.hpp" 47 #include "common/timer.hpp" 48 #include "mac/mac.hpp" 49 50 namespace ot { 51 namespace Utils { 52 53 /** 54 * @addtogroup utils-channel-manager 55 * 56 * @brief 57 * This module includes definitions for Channel Manager. 58 * 59 * @{ 60 */ 61 62 /** 63 * Implements the Channel Manager. 64 * 65 */ 66 class ChannelManager : public InstanceLocator, private NonCopyable 67 { 68 public: 69 #if OPENTHREAD_FTD 70 /** 71 * Minimum delay (in seconds) used for network channel change. 72 * 73 */ 74 static constexpr uint16_t kMinimumDelay = OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_DELAY; 75 #endif 76 77 /** 78 * Initializes a `ChanelManager` object. 79 * 80 * @param[in] aInstance A reference to the OpenThread instance. 81 * 82 */ 83 explicit ChannelManager(Instance &aInstance); 84 85 #if OPENTHREAD_FTD 86 /** 87 * Requests a Thread network channel change. 88 * 89 * The Thread network switches to the given channel after a specified delay (@sa GetDelay()). The channel change is 90 * performed by updating the Pending Operational Dataset. 91 * 92 * A subsequent call to this method will cancel an ongoing previously requested channel change. 93 * 94 * If the requested channel changes, it will trigger a `Notifier` event `kEventChannelManagerNewChannelChanged`. 95 * 96 * @param[in] aChannel The new channel for the Thread network. 97 * 98 */ 99 void RequestNetworkChannelChange(uint8_t aChannel); 100 #endif 101 102 /** 103 * Gets the channel from the last successful call to `RequestNetworkChannelChange()` or `ChangeCslChannel()`. 104 * 105 * @returns The last requested channel, or zero if there has been no channel change request yet. 106 * 107 */ GetRequestedChannel(void) const108 uint8_t GetRequestedChannel(void) const { return mChannel; } 109 110 #if OPENTHREAD_FTD 111 /** 112 * Gets the delay (in seconds) used for a channel change. 113 * 114 * @returns The delay (in seconds) 115 * 116 */ GetDelay(void) const117 uint16_t GetDelay(void) const { return mDelay; } 118 119 /** 120 * Sets the delay (in seconds) used for a channel change. 121 * 122 * The delay should preferably be longer than maximum data poll interval used by all sleepy-end-devices within the 123 * Thread network. 124 * 125 * @param[in] aDelay Delay in seconds. 126 * 127 * @retval kErrorNone Delay was updated successfully. 128 * @retval kErrorInvalidArgs The given delay @p aDelay is shorter than `kMinimumDelay`. 129 * 130 */ 131 Error SetDelay(uint16_t aDelay); 132 #endif // OPENTHREAD_FTD 133 134 #if OPENTHREAD_FTD 135 /** 136 * Requests that `ChannelManager` checks and selects a new network channel and starts a network channel change. 137 * 138 * Unlike the `RequestChannelChange()` where the channel must be given as a parameter, this method asks the 139 * `ChannelManager` to select a channel by itself (based on the collected channel quality info). 140 * 141 * Once called, the `ChannelManager` will perform the following 3 steps: 142 * 143 * 1) `ChannelManager` decides if the channel change would be helpful. This check can be skipped if 144 * `aSkipQualityCheck` is set to true (forcing a channel selection to happen and skipping the quality check). 145 * This step uses the collected link quality metrics on the device (such as CCA failure rate, frame and message 146 * error rates per neighbor, etc.) to determine if the current channel quality is at the level that justifies 147 * a channel change. 148 * 149 * 2) If the first step passes, then `ChannelManager` selects a potentially better channel. It uses the collected 150 * channel occupancy data by `ChannelMonitor` module. The supported and favored channels are used at this step. 151 * (@sa SetSupportedChannels, @sa SetFavoredChannels). 152 * 153 * 3) If the newly selected channel is different from the current channel, `ChannelManager` requests/starts the 154 * channel change process (internally invoking a `RequestNetworkChannelChange()`). 155 * 156 * 157 * @param[in] aSkipQualityCheck Indicates whether the quality check (step 1) should be skipped. 158 * 159 * @retval kErrorNone Channel selection finished successfully. 160 * @retval kErrorNotFound Supported channels is empty, therefore could not select a channel. 161 * @retval kErrorInvalidState Thread is not enabled or not enough data to select new channel. 162 * 163 */ 164 Error RequestNetworkChannelSelect(bool aSkipQualityCheck); 165 #endif // OPENTHREAD_FTD 166 167 #if (OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) 168 /** 169 * Requests that `ChannelManager` checks and selects a new Csl channel and starts a channel change. 170 * 171 * Once called, the `ChannelManager` will perform the following 3 steps: 172 * 173 * 1) `ChannelManager` decides if the channel change would be helpful. This check can be skipped if 174 * `aSkipQualityCheck` is set to true (forcing a channel selection to happen and skipping the quality check). 175 * This step uses the collected link quality metrics on the device (such as CCA failure rate, frame and message 176 * error rates per neighbor, etc.) to determine if the current channel quality is at the level that justifies 177 * a channel change. 178 * 179 * 2) If the first step passes, then `ChannelManager` selects a potentially better channel. It uses the collected 180 * channel occupancy data by `ChannelMonitor` module. The supported and favored channels are used at this step. 181 * (@sa SetSupportedChannels, @sa SetFavoredChannels). 182 * 183 * 3) If the newly selected channel is different from the current Csl channel, `ChannelManager` starts the 184 * channel change process (internally invoking a `ChangeCslChannel()`). 185 * 186 * 187 * @param[in] aSkipQualityCheck Indicates whether the quality check (step 1) should be skipped. 188 * 189 * @retval kErrorNone Channel selection finished successfully. 190 * @retval kErrorNotFound Supported channels is empty, therefore could not select a channel. 191 * @retval kErrorInvalidState Thread is not enabled or not enough data to select new channel. 192 * 193 */ 194 Error RequestCslChannelSelect(bool aSkipQualityCheck); 195 #endif // (OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) 196 197 #if OPENTHREAD_FTD 198 /** 199 * Enables/disables the auto-channel-selection functionality. 200 * 201 * When enabled, `ChannelManager` will periodically invoke a `RequestChannelSelect(false)`. The period interval 202 * can be set by `SetAutoChannelSelectionInterval()`. 203 * 204 * @param[in] aEnabled Indicates whether to enable or disable this functionality. 205 * 206 */ 207 void SetAutoNetworkChannelSelectionEnabled(bool aEnabled); 208 209 /** 210 * Indicates whether the auto-channel-selection functionality is enabled or not. 211 * 212 * @returns TRUE if enabled, FALSE if disabled. 213 * 214 */ GetAutoNetworkChannelSelectionEnabled(void) const215 bool GetAutoNetworkChannelSelectionEnabled(void) const { return mAutoSelectEnabled; } 216 #endif 217 218 #if (OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) 219 /** 220 * Enables/disables the auto-channel-selection functionality. 221 * 222 * When enabled, `ChannelManager` will periodically invoke a `RequestChannelSelect(false)`. The period interval 223 * can be set by `SetAutoChannelSelectionInterval()`. 224 * 225 * @param[in] aEnabled Indicates whether to enable or disable this functionality. 226 * 227 */ 228 void SetAutoCslChannelSelectionEnabled(bool aEnabled); 229 230 /** 231 * Indicates whether the auto-channel-selection functionality is enabled or not. 232 * 233 * @returns TRUE if enabled, FALSE if disabled. 234 * 235 */ GetAutoCslChannelSelectionEnabled(void) const236 bool GetAutoCslChannelSelectionEnabled(void) const { return mAutoSelectCslEnabled; } 237 #endif 238 239 /** 240 * Sets the period interval (in seconds) used by auto-channel-selection functionality. 241 * 242 * @param[in] aInterval The interval (in seconds). 243 * 244 * @retval kErrorNone The interval was set successfully. 245 * @retval kErrorInvalidArgs The @p aInterval is not valid (zero). 246 * 247 */ 248 Error SetAutoChannelSelectionInterval(uint32_t aInterval); 249 250 /** 251 * Gets the period interval (in seconds) used by auto-channel-selection functionality. 252 * 253 * @returns The interval (in seconds). 254 * 255 */ GetAutoChannelSelectionInterval(void) const256 uint32_t GetAutoChannelSelectionInterval(void) const { return mAutoSelectInterval; } 257 258 /** 259 * Gets the supported channel mask. 260 * 261 * @returns The supported channels mask. 262 * 263 */ GetSupportedChannels(void) const264 uint32_t GetSupportedChannels(void) const { return mSupportedChannelMask.GetMask(); } 265 266 /** 267 * Sets the supported channel mask. 268 * 269 * @param[in] aChannelMask A channel mask. 270 * 271 */ 272 void SetSupportedChannels(uint32_t aChannelMask); 273 274 /** 275 * Gets the favored channel mask. 276 * 277 * @returns The favored channels mask. 278 * 279 */ GetFavoredChannels(void) const280 uint32_t GetFavoredChannels(void) const { return mFavoredChannelMask.GetMask(); } 281 282 /** 283 * Sets the favored channel mask. 284 * 285 * @param[in] aChannelMask A channel mask. 286 * 287 */ 288 void SetFavoredChannels(uint32_t aChannelMask); 289 290 /** 291 * Gets the CCA failure rate threshold 292 * 293 * @returns The CCA failure rate threshold 294 * 295 */ GetCcaFailureRateThreshold(void) const296 uint16_t GetCcaFailureRateThreshold(void) const { return mCcaFailureRateThreshold; } 297 298 /** 299 * Sets the CCA failure rate threshold 300 * 301 * @param[in] aThreshold A CCA failure rate threshold. 302 * 303 */ 304 void SetCcaFailureRateThreshold(uint16_t aThreshold); 305 306 private: 307 // Retry interval to resend Pending Dataset in case of tx failure (in ms). 308 static constexpr uint32_t kPendingDatasetTxRetryInterval = 20000; 309 310 // Maximum jitter/wait time to start a requested network channel change (in ms). 311 static constexpr uint32_t kRequestStartJitterInterval = 10000; 312 313 // The minimum number of RSSI samples required before using the collected data (by `ChannelMonitor`) to select 314 // a channel. 315 static constexpr uint32_t kMinChannelMonitorSampleCount = 316 OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_MONITOR_SAMPLE_COUNT; 317 318 // Minimum channel occupancy difference to prefer an unfavored channel over a favored one. 319 static constexpr uint16_t kThresholdToSkipFavored = OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_SKIP_FAVORED; 320 321 // Minimum channel occupancy difference between current channel and the selected channel to trigger the channel 322 // change process to start. 323 static constexpr uint16_t kThresholdToChangeChannel = OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_CHANGE_CHANNEL; 324 325 // Default auto-channel-selection period (in seconds). 326 static constexpr uint32_t kDefaultAutoSelectInterval = 327 OPENTHREAD_CONFIG_CHANNEL_MANAGER_DEFAULT_AUTO_SELECT_INTERVAL; 328 329 // Minimum CCA failure rate on current channel to start the channel selection process. 330 static constexpr uint16_t kCcaFailureRateThreshold = OPENTHREAD_CONFIG_CHANNEL_MANAGER_CCA_FAILURE_THRESHOLD; 331 332 enum State : uint8_t 333 { 334 kStateIdle, 335 kStateChangeRequested, 336 kStateChangeInProgress, 337 }; 338 339 #if OPENTHREAD_FTD 340 void StartDatasetUpdate(void); 341 static void HandleDatasetUpdateDone(Error aError, void *aContext); 342 void HandleDatasetUpdateDone(Error aError); 343 #endif 344 void HandleTimer(void); 345 void StartAutoSelectTimer(void); 346 Error RequestChannelSelect(bool aSkipQualityCheck); 347 Error RequestAutoChannelSelect(bool aSkipQualityCheck); 348 void RequestChannelChange(uint8_t aChannel); 349 350 #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 351 Error FindBetterChannel(uint8_t &aNewChannel, uint16_t &aOccupancy); 352 bool ShouldAttemptChannelChange(void); 353 #endif 354 355 #if (OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) 356 void ChangeCslChannel(uint8_t aChannel); 357 #endif 358 359 using ManagerTimer = TimerMilliIn<ChannelManager, &ChannelManager::HandleTimer>; 360 361 Mac::ChannelMask mSupportedChannelMask; 362 Mac::ChannelMask mFavoredChannelMask; 363 #if OPENTHREAD_FTD 364 uint16_t mDelay; 365 #endif 366 uint8_t mChannel; 367 uint8_t mChannelSelected; 368 State mState; 369 ManagerTimer mTimer; 370 uint32_t mAutoSelectInterval; 371 #if OPENTHREAD_FTD 372 bool mAutoSelectEnabled; 373 #endif 374 #if (OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE && OPENTHREAD_CONFIG_CHANNEL_MANAGER_CSL_CHANNEL_SELECT_ENABLE) 375 bool mAutoSelectCslEnabled; 376 #endif 377 uint16_t mCcaFailureRateThreshold; 378 }; 379 380 /** 381 * @} 382 * 383 */ 384 385 } // namespace Utils 386 } // namespace ot 387 388 #endif // OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE && OPENTHREAD_FTD 389 390 #endif // CHANNEL_MANAGER_HPP_ 391