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