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 monitoring module. 32 */ 33 34 #ifndef CHANNEL_MONITOR_HPP_ 35 #define CHANNEL_MONITOR_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 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 #include "radio/radio.hpp" 48 49 namespace ot { 50 namespace Utils { 51 52 /** 53 * @addtogroup utils-channel-monitor 54 * 55 * @brief 56 * This module includes definitions monitoring quality of channels. 57 * 58 * @{ 59 */ 60 61 /** 62 * Implements the channel monitoring logic. 63 * 64 * Channel Monitoring will periodically monitor all channels to help determine the cleaner channels (channels 65 * with less interference). 66 * 67 * When Channel Monitoring is active, every `kSampleInterval`, a zero-duration Energy Scan is performed on every 68 * channel collecting a single RSSI sample per channel. The RSSI samples are compared with a pre-specified RSSI 69 * threshold `kRssiThreshold`. As an indicator of channel quality, the `ChannelMonitor` maintains and provides the 70 * average rate/percentage of RSSI samples that are above the threshold within (approximately) a specified sample 71 * window (referred to as "channel occupancy"). 72 * 73 */ 74 class ChannelMonitor : public InstanceLocator, private NonCopyable 75 { 76 public: 77 /** 78 * The channel RSSI sample interval in milliseconds. 79 * 80 */ 81 static constexpr uint32_t kSampleInterval = OPENTHREAD_CONFIG_CHANNEL_MONITOR_SAMPLE_INTERVAL; 82 83 /** 84 * The RSSI threshold in dBm. 85 * 86 * It is recommended that this value is set to same value as the CCA threshold used by radio. 87 * 88 */ 89 static constexpr int8_t kRssiThreshold = OPENTHREAD_CONFIG_CHANNEL_MONITOR_RSSI_THRESHOLD; 90 91 /** 92 * The averaging sample window length (in units of sample interval). 93 * 94 */ 95 static constexpr uint32_t kSampleWindow = OPENTHREAD_CONFIG_CHANNEL_MONITOR_SAMPLE_WINDOW; 96 97 /** 98 * Initializes the object. 99 * 100 * @param[in] aInstance A reference to the OpenThread instance. 101 * 102 */ 103 explicit ChannelMonitor(Instance &aInstance); 104 105 /** 106 * Starts the Channel Monitoring operation. 107 * 108 * Once started, any previously collected data is cleared. 109 * 110 * @retval kErrorNone Channel Monitoring started successfully. 111 * @retval kErrorAlready Channel Monitoring has already been started. 112 * 113 */ 114 Error Start(void); 115 116 /** 117 * Stops the Channel Monitoring operation. 118 * 119 * @note After `Stop()`, the previous data is still valid and can be read. 120 * 121 * @retval kErrorNone Channel Monitoring stopped successfully. 122 * @retval kErrorAlready Channel Monitoring has already been stopped. 123 * 124 */ 125 Error Stop(void); 126 127 /** 128 * Indicates whether the Channel Monitoring operation is started and running. 129 * 130 * @returns TRUE if the Channel Monitoring operation is running, FALSE otherwise. 131 * 132 */ IsRunning(void) const133 bool IsRunning(void) const { return mTimer.IsRunning(); } 134 135 /** 136 * Clears all currently stored data. 137 * 138 */ 139 void Clear(void); 140 141 /** 142 * Returns the total number of RSSI samples (per channel) taken so far (since call to `Start()`). 143 * 144 * @returns total number of RSSI sample taken since last call to `Start()`. 145 * 146 */ GetSampleCount(void) const147 uint32_t GetSampleCount(void) const { return mSampleCount; } 148 149 /** 150 * Returns the current channel occupancy for a given channel. 151 * 152 * The channel occupancy represents the average rate/percentage of RSSI samples that were above RSSI threshold 153 * `kRssiThreshold` ("bad" RSSI samples). 154 * 155 * For the first `kSampleWindow` samples, the average is maintained as the actual percentage (i.e., ratio of number 156 * of "bad" samples by total number of samples). After `kSampleWindow` samples, the averager uses an exponentially 157 * weighted moving average logic with weight coefficient `1/kSampleWindow` for new values. Practically, this means 158 * the occupancy is representative of up to `3 * kSampleWindow` last samples with highest weight given to the 159 * latest `kSampleWindow` samples. 160 * 161 * Max value of `0xffff` indicates all RSSI samples were above RSSI threshold (i.e. 100% of samples were "bad"). 162 * 163 * @param[in] aChannel The channel for which to get the link occupancy. 164 * 165 * @returns the current channel occupancy for the given channel. 166 * 167 */ 168 uint16_t GetChannelOccupancy(uint8_t aChannel) const; 169 170 /** 171 * Finds the best channel(s) (with least occupancy rate) in a given channel mask. 172 * 173 * The channels are compared based on their occupancy rate from `GetChannelOccupancy()` and lower occupancy rate 174 * is considered better. 175 * 176 * @param[in] aMask A channel mask (the search is limited to channels in @p aMask). 177 * @param[out] aOccupancy A reference to `uint16` to return the occupancy rate associated with best channel(s). 178 * 179 * @returns A channel mask containing the best channels. A mask is returned in case there are more than one 180 * channel with the same occupancy rate value. 181 * 182 */ 183 Mac::ChannelMask FindBestChannels(const Mac::ChannelMask &aMask, uint16_t &aOccupancy) const; 184 185 private: 186 #if (OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT && OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT) 187 static constexpr uint8_t kNumChannelMasks = 8; 188 #else 189 static constexpr uint8_t kNumChannelMasks = 4; 190 #endif 191 static constexpr uint8_t kNumChannels = (Radio::kChannelMax - Radio::kChannelMin + 1); 192 static constexpr uint32_t kTimerInterval = (kSampleInterval / kNumChannelMasks); 193 static constexpr uint16_t kMaxJitterInterval = 4096; 194 static constexpr uint32_t kMaxOccupancy = 0xffff; 195 196 void HandleTimer(void); 197 static void HandleEnergyScanResult(Mac::EnergyScanResult *aResult, void *aContext); 198 void HandleEnergyScanResult(Mac::EnergyScanResult *aResult); 199 void LogResults(void); 200 201 using ScanTimer = TimerMilliIn<ChannelMonitor, &ChannelMonitor::HandleTimer>; 202 203 static const uint32_t mScanChannelMasks[kNumChannelMasks]; 204 205 uint8_t mChannelMaskIndex : 3; 206 uint32_t mSampleCount : 29; 207 uint16_t mChannelOccupancy[kNumChannels]; 208 ScanTimer mTimer; 209 }; 210 211 /** 212 * @} 213 * 214 */ 215 216 } // namespace Utils 217 } // namespace ot 218 219 #endif // OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE 220 221 #endif // CHANNEL_MONITOR_HPP_ 222