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