Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 1 | /* |
Jonathan Hui | 4435017 | 2016-09-13 15:57:11 -0700 | [diff] [blame] | 2 | * Copyright (c) 2016, The OpenThread Authors. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 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 storing and processing link quality information. |
| 32 | */ |
| 33 | |
| 34 | #ifndef LINK_QUALITY_HPP_ |
| 35 | #define LINK_QUALITY_HPP_ |
| 36 | |
Abtin Keshavarzian | 2ea5644 | 2017-10-17 09:46:34 -0700 | [diff] [blame] | 37 | #include "openthread-core-config.h" |
| 38 | |
Jonathan Hui | 69d98d4 | 2018-02-06 14:14:57 -0800 | [diff] [blame] | 39 | #include <openthread/platform/radio.h> |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 40 | |
Li Cao | 2dc8d71 | 2020-11-04 08:06:04 +0800 | [diff] [blame] | 41 | #include "common/clearable.hpp" |
Abtin Keshavarzian | 2437a75 | 2020-02-16 22:09:58 -0800 | [diff] [blame] | 42 | #include "common/locator.hpp" |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 43 | #include "common/string.hpp" |
Abtin Keshavarzian | 052fccb | 2022-12-21 10:19:17 -0800 | [diff] [blame] | 44 | #include "thread/mle_types.hpp" |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 45 | |
Jonathan Hui | 1eabda6 | 2017-04-27 22:29:05 -0700 | [diff] [blame] | 46 | namespace ot { |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 47 | |
| 48 | /** |
| 49 | * @addtogroup core-link-quality |
| 50 | * |
| 51 | * @brief |
| 52 | * This module includes definitions for Thread link quality metrics. |
| 53 | * |
| 54 | * @{ |
| 55 | */ |
| 56 | |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 57 | /** |
| 58 | * This class implements an operation Success Rate Tracker. |
| 59 | * |
| 60 | * This can be used to track different link quality related metrics, e.g., CCA failure rate, frame tx success rate). |
| 61 | * The success rate is maintained using an exponential moving IIR averaging filter with a `uint16_t` as the storage. |
| 62 | * |
| 63 | */ |
Li Cao | 2dc8d71 | 2020-11-04 08:06:04 +0800 | [diff] [blame] | 64 | class SuccessRateTracker : public Clearable<SuccessRateTracker> |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 65 | { |
| 66 | public: |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 67 | static constexpr uint16_t kMaxRateValue = 0xffff; ///< Value corresponding to max (failure/success) rate of 100%. |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 68 | |
| 69 | /** |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 70 | * This method adds a sample (success or failure) to `SuccessRateTracker`. |
| 71 | * |
| 72 | * @param[in] aSuccess The sample status be added, `true` for success, `false` for failure. |
| 73 | * @param[in] aWeight The weight coefficient used for adding the new sample into average. |
| 74 | * |
| 75 | */ |
| 76 | void AddSample(bool aSuccess, uint16_t aWeight = kDefaultWeight); |
| 77 | |
| 78 | /** |
| 79 | * This method returns the average failure rate. |
| 80 | * |
| 81 | * @retval the average failure rate `[0-kMaxRateValue]` with `kMaxRateValue` corresponding to 100%. |
| 82 | * |
| 83 | */ |
Abtin Keshavarzian | 68a605f | 2018-01-31 12:40:23 -0800 | [diff] [blame] | 84 | uint16_t GetFailureRate(void) const { return mFailureRate; } |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 85 | |
| 86 | /** |
| 87 | * This method returns the average success rate. |
| 88 | * |
| 89 | * @retval the average success rate as [0-kMaxRateValue] with `kMaxRateValue` corresponding to 100%. |
| 90 | * |
| 91 | */ |
Abtin Keshavarzian | 68a605f | 2018-01-31 12:40:23 -0800 | [diff] [blame] | 92 | uint16_t GetSuccessRate(void) const { return kMaxRateValue - mFailureRate; } |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 93 | |
| 94 | private: |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 95 | static constexpr uint16_t kDefaultWeight = 64; |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 96 | |
Abtin Keshavarzian | 68a605f | 2018-01-31 12:40:23 -0800 | [diff] [blame] | 97 | uint16_t mFailureRate; |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 98 | }; |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 99 | |
| 100 | /** |
| 101 | * This class implements a Received Signal Strength (RSS) averager. |
| 102 | * |
| 103 | * The average is maintained using an adaptive exponentially weighted moving filter. |
| 104 | * |
| 105 | */ |
Li Cao | 2dc8d71 | 2020-11-04 08:06:04 +0800 | [diff] [blame] | 106 | class RssAverager : public Clearable<RssAverager> |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 107 | { |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 108 | public: |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 109 | static constexpr uint16_t kStringSize = 10; ///< Max string size for average (@sa ToString()). |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 110 | |
| 111 | /** |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 112 | * This type defines the fixed-length `String` object returned from `ToString()`. |
| 113 | * |
| 114 | */ |
| 115 | typedef String<kStringSize> InfoString; |
| 116 | |
| 117 | /** |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 118 | * This method indicates whether the averager contains an average (i.e., at least one RSS value has been added). |
| 119 | * |
| 120 | * @retval true If the average value is available (at least one RSS value has been added). |
| 121 | * @retval false Averager is empty (no RSS value added yet). |
| 122 | * |
| 123 | */ |
| 124 | bool HasAverage(void) const { return (mCount != 0); } |
| 125 | |
| 126 | /** |
| 127 | * This method adds a received signal strength (RSS) value to the average. |
| 128 | * |
Abtin Keshavarzian | ba4389a | 2022-08-30 09:10:18 -0700 | [diff] [blame] | 129 | * If @p aRss is `Radio::kInvalidRssi`, it is ignored and error status kErrorInvalidArgs is returned. |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 130 | * The value of RSS is capped at 0dBm (i.e., for any given RSS value higher than 0dBm, 0dBm is used instead). |
| 131 | * |
| 132 | * @param[in] aRss Received signal strength value (in dBm) to be added to the average. |
| 133 | * |
Abtin Keshavarzian | 7dca56e | 2021-03-15 21:07:07 -0700 | [diff] [blame] | 134 | * @retval kErrorNone New RSS value added to average successfully. |
Abtin Keshavarzian | ba4389a | 2022-08-30 09:10:18 -0700 | [diff] [blame] | 135 | * @retval kErrorInvalidArgs Value of @p aRss is `Radio::kInvalidRssi`. |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 136 | * |
| 137 | */ |
Abtin Keshavarzian | 7dca56e | 2021-03-15 21:07:07 -0700 | [diff] [blame] | 138 | Error Add(int8_t aRss); |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 139 | |
| 140 | /** |
| 141 | * This method returns the current average signal strength value maintained by the averager. |
| 142 | * |
Abtin Keshavarzian | ba4389a | 2022-08-30 09:10:18 -0700 | [diff] [blame] | 143 | * @returns The current average value (in dBm) or `Radio::kInvalidRssi` if no average is available. |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 144 | * |
| 145 | */ |
| 146 | int8_t GetAverage(void) const; |
| 147 | |
| 148 | /** |
| 149 | * This method returns an raw/encoded version of current average signal strength value. The raw value is the |
| 150 | * average multiplied by a precision factor (currently set as -8). |
| 151 | * |
| 152 | * @returns The current average multiplied by precision factor or zero if no average is available. |
| 153 | * |
| 154 | */ |
| 155 | uint16_t GetRaw(void) const { return mAverage; } |
| 156 | |
| 157 | /** |
| 158 | * This method converts the current average RSS value to a human-readable string (e.g., "-80.375"). If the |
| 159 | * average is unknown, empty string is returned. |
| 160 | * |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 161 | * @returns An `InfoString` object containing the string representation of average RSS. |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 162 | * |
| 163 | */ |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 164 | InfoString ToString(void) const; |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 165 | |
| 166 | private: |
| 167 | /* |
| 168 | * The RssAverager uses an adaptive exponentially weighted filter to maintain the average. It keeps track of |
| 169 | * current average and the number of added RSS values (up to a 8). |
| 170 | * |
| 171 | * For the first 8 added RSS values, the average is the arithmetic mean of the added values (e.g., if 5 values are |
| 172 | * added, the average is sum of the 5 added RSS values divided by 5. After the 8th RSS value, a weighted filter is |
| 173 | * used with coefficients (1/8, 7/8), i.e., newAverage = 1/8 * newRss + 7/8 * oldAverage. |
| 174 | * |
| 175 | * To add to accuracy of the averaging process, the RSS values and the maintained average are multiplied by a |
| 176 | * precision factor of -8. |
| 177 | * |
| 178 | */ |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 179 | static constexpr uint8_t kPrecisionBitShift = 3; // Precision multiple for RSS average (1 << PrecisionBitShift). |
| 180 | static constexpr uint8_t kPrecision = (1 << kPrecisionBitShift); |
| 181 | static constexpr uint8_t kPrecisionBitMask = (kPrecision - 1); |
| 182 | static constexpr uint8_t kCoeffBitShift = 3; // Coeff for exp weighted filter (1 << kCoeffBitShift). |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 183 | |
| 184 | // Member variables fit into two bytes. |
| 185 | |
Jonathan Hui | 69d98d4 | 2018-02-06 14:14:57 -0800 | [diff] [blame] | 186 | uint16_t mAverage : 11; // The raw average signal strength value (stored as RSS times precision multiple). |
| 187 | uint16_t mCount : 5; // Number of RSS values added to averager so far (limited to 2^kCoeffBitShift-1). |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 188 | }; |
| 189 | |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 190 | /** |
Li Cao | dc94758 | 2020-09-26 00:50:09 +0800 | [diff] [blame] | 191 | * This class implements a Link Quality Indicator (LQI) averager. |
| 192 | * |
| 193 | * It maintains the exponential moving average value of LQI. |
| 194 | * |
| 195 | */ |
Li Cao | 2dc8d71 | 2020-11-04 08:06:04 +0800 | [diff] [blame] | 196 | class LqiAverager : public Clearable<LqiAverager> |
Li Cao | dc94758 | 2020-09-26 00:50:09 +0800 | [diff] [blame] | 197 | { |
| 198 | public: |
| 199 | /** |
Li Cao | dc94758 | 2020-09-26 00:50:09 +0800 | [diff] [blame] | 200 | * This method adds a link quality indicator (LQI) value to the average. |
| 201 | * |
| 202 | * @param[in] aLqi Link Quality Indicator value to be added to the average. |
| 203 | * |
| 204 | */ |
| 205 | void Add(uint8_t aLqi); |
| 206 | |
| 207 | /** |
| 208 | * This method returns the current average link quality value maintained by the averager. |
| 209 | * |
| 210 | * @returns The current average value. |
| 211 | * |
| 212 | */ |
| 213 | uint8_t GetAverage(void) const { return mAverage; } |
| 214 | |
| 215 | /** |
| 216 | * This method returns the count of frames calculated so far. |
| 217 | * |
| 218 | * @returns The count of frames calculated. |
| 219 | * |
| 220 | */ |
| 221 | uint8_t GetCount(void) const { return mCount; } |
| 222 | |
| 223 | private: |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 224 | static constexpr uint8_t kCoeffBitShift = 3; // Coeff used for exp weighted filter (1 << kCoeffBitShift). |
Li Cao | dc94758 | 2020-09-26 00:50:09 +0800 | [diff] [blame] | 225 | |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 226 | uint8_t mAverage; // The average link quality indicator value. |
| 227 | uint8_t mCount; // Number of LQI values added to averager so far. |
Li Cao | dc94758 | 2020-09-26 00:50:09 +0800 | [diff] [blame] | 228 | }; |
| 229 | |
| 230 | /** |
Abtin Keshavarzian | 8714ec1 | 2022-05-09 14:17:33 -0700 | [diff] [blame] | 231 | * This enumeration represents the link quality constants. |
| 232 | * |
| 233 | * Link Quality is an integer in [0, 3]. A higher link quality indicates a more usable link, with 0 indicating that the |
| 234 | * link is non-existent or unusable. |
| 235 | * |
| 236 | */ |
| 237 | enum LinkQuality : uint8_t |
| 238 | { |
| 239 | kLinkQuality0 = 0, ///< Link quality 0 (non-existent link) |
| 240 | kLinkQuality1 = 1, ///< Link quality 1 |
| 241 | kLinkQuality2 = 2, ///< Link quality 2 |
| 242 | kLinkQuality3 = 3, ///< Link quality 3 |
| 243 | }; |
| 244 | |
Abtin Keshavarzian | 052fccb | 2022-12-21 10:19:17 -0800 | [diff] [blame] | 245 | constexpr uint8_t kCostForLinkQuality0 = Mle::kMaxRouteCost; ///< Link Cost for Link Quality 0. |
| 246 | constexpr uint8_t kCostForLinkQuality1 = 4; ///< Link Cost for Link Quality 1. |
| 247 | constexpr uint8_t kCostForLinkQuality2 = 2; ///< Link Cost for Link Quality 2. |
| 248 | constexpr uint8_t kCostForLinkQuality3 = 1; ///< Link Cost for Link Quality 3. |
| 249 | |
| 250 | /** |
| 251 | * This function converts link quality to route cost. |
| 252 | * |
| 253 | * @param[in] aLinkQuality The link quality to covert. |
| 254 | * |
| 255 | * @returns The route cost corresponding to @p aLinkQuality. |
| 256 | * |
| 257 | */ |
| 258 | uint8_t CostForLinkQuality(LinkQuality aLinkQuality); |
| 259 | |
Abtin Keshavarzian | 8714ec1 | 2022-05-09 14:17:33 -0700 | [diff] [blame] | 260 | /** |
Abtin Keshavarzian | ba00622 | 2022-08-25 14:10:29 -0700 | [diff] [blame] | 261 | * This function computes the link margin from a given noise floor and received signal strength. |
| 262 | * |
| 263 | * @param[in] aNoiseFloor The noise floor value (in dBm). |
| 264 | * @param[in] aRss The received signal strength value (in dBm). |
| 265 | * |
| 266 | * @returns The link margin value in dB. |
| 267 | * |
| 268 | */ |
| 269 | uint8_t ComputeLinkMargin(int8_t aNoiseFloor, int8_t aRss); |
| 270 | |
| 271 | /** |
| 272 | * This function converts a link margin value to a link quality value. |
| 273 | * |
| 274 | * @param[in] aLinkMargin The Link Margin in dB. |
| 275 | * |
| 276 | * @returns The link quality value (0-3). |
| 277 | * |
| 278 | */ |
| 279 | LinkQuality LinkQualityForLinkMargin(uint8_t aLinkMargin); |
| 280 | |
| 281 | /** |
| 282 | * This function gets the typical received signal strength value for a given link quality. |
| 283 | * |
| 284 | * @param[in] aNoiseFloor The noise floor value (in dBm). |
| 285 | * @param[in] aLinkQuality The link quality value in [0, 3]. |
| 286 | * |
| 287 | * @returns The typical platform RSSI in dBm. |
| 288 | * |
| 289 | */ |
| 290 | int8_t GetTypicalRssForLinkQuality(int8_t aNoiseFloor, LinkQuality aLinkQuality); |
| 291 | |
| 292 | /** |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 293 | * This class encapsulates/stores all relevant information about quality of a link, including average received signal |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 294 | * strength (RSS), last RSS, link margin, and link quality. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 295 | * |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 296 | */ |
Abtin Keshavarzian | 2437a75 | 2020-02-16 22:09:58 -0800 | [diff] [blame] | 297 | class LinkQualityInfo : public InstanceLocatorInit |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 298 | { |
Abtin Keshavarzian | ba00622 | 2022-08-25 14:10:29 -0700 | [diff] [blame] | 299 | friend LinkQuality LinkQualityForLinkMargin(uint8_t aLinkMargin); |
| 300 | friend int8_t GetTypicalRssForLinkQuality(int8_t aNoiseFloor, LinkQuality aLinkQuality); |
| 301 | |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 302 | public: |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 303 | static constexpr uint16_t kInfoStringSize = 50; ///< `InfoString` size (@sa ToInfoString()). |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 304 | |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 305 | /** |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 306 | * This type defines the fixed-length `String` object returned from `ToInfoString()`. |
| 307 | * |
| 308 | */ |
| 309 | typedef String<kInfoStringSize> InfoString; |
| 310 | |
| 311 | /** |
Abtin Keshavarzian | 2437a75 | 2020-02-16 22:09:58 -0800 | [diff] [blame] | 312 | * This method initializes the `LinkQualityInfo` object. |
| 313 | * |
| 314 | * @param[in] aInstance A reference to the OpenThread instance. |
| 315 | * |
| 316 | */ |
| 317 | void Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); } |
| 318 | |
| 319 | /** |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 320 | * This method clears the all the data in the object. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 321 | * |
| 322 | */ |
| 323 | void Clear(void); |
| 324 | |
| 325 | /** |
Abtin Keshavarzian | a1979fd | 2023-01-13 11:41:07 -0800 | [diff] [blame] | 326 | * This method clears the average RSS value. |
| 327 | * |
| 328 | */ |
Jonathan Hui | 3d39d24 | 2023-04-11 22:39:35 -0700 | [diff] [blame] | 329 | void ClearAverageRss(void) { mRssAverager.Clear(); } |
Abtin Keshavarzian | a1979fd | 2023-01-13 11:41:07 -0800 | [diff] [blame] | 330 | |
| 331 | /** |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 332 | * This method adds a new received signal strength (RSS) value to the average. |
| 333 | * |
Abtin Keshavarzian | b3976f5 | 2017-04-14 14:32:55 -0700 | [diff] [blame] | 334 | * @param[in] aRss A new received signal strength value (in dBm) to be added to the average. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 335 | * |
| 336 | */ |
Abtin Keshavarzian | 5cddf90 | 2020-02-16 23:16:01 -0800 | [diff] [blame] | 337 | void AddRss(int8_t aRss); |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 338 | |
| 339 | /** |
Abtin Keshavarzian | c2d2274 | 2018-01-22 08:56:18 -0800 | [diff] [blame] | 340 | * This method returns the current average received signal strength value. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 341 | * |
Abtin Keshavarzian | ba4389a | 2022-08-30 09:10:18 -0700 | [diff] [blame] | 342 | * @returns The current average value or `Radio::kInvalidRssi` if no average is available. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 343 | * |
| 344 | */ |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 345 | int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); } |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 346 | |
| 347 | /** |
| 348 | * This method returns an encoded version of current average signal strength value. The encoded value is the |
| 349 | * average multiplied by a precision factor (currently -8). |
| 350 | * |
| 351 | * @returns The current average multiplied by precision factor or zero if no average is available. |
| 352 | * |
| 353 | */ |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 354 | uint16_t GetAverageRssRaw(void) const { return mRssAverager.GetRaw(); } |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 355 | |
| 356 | /** |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 357 | * This method converts the link quality info to info/debug human-readable string. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 358 | * |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 359 | * @returns An `InfoString` representing the link quality info. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 360 | * |
| 361 | */ |
Abtin Keshavarzian | 4b918f8 | 2018-06-11 09:10:52 -0700 | [diff] [blame] | 362 | InfoString ToInfoString(void) const; |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 363 | |
| 364 | /** |
| 365 | * This method returns the link margin. The link margin is calculated using the link's current average received |
| 366 | * signal strength (RSS) and average noise floor. |
| 367 | * |
| 368 | * @returns Link margin derived from average received signal strength and average noise floor. |
| 369 | * |
| 370 | */ |
Abtin Keshavarzian | 5cddf90 | 2020-02-16 23:16:01 -0800 | [diff] [blame] | 371 | uint8_t GetLinkMargin(void) const; |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 372 | |
| 373 | /** |
| 374 | * Returns the current one-way link quality value. The link quality value is a number 0-3. |
| 375 | * |
| 376 | * The link quality is calculated by comparing the current link margin with a set of thresholds (per Thread spec). |
| 377 | * More specifically, link margin > 20 dB gives link quality 3, link margin > 10 dB gives link quality 2, |
| 378 | * link margin > 2 dB gives link quality 1, and link margin below or equal to 2 dB yields link quality of 0. |
| 379 | * |
| 380 | * In order to ensure that a link margin near the boundary of two different link quality values does not cause |
| 381 | * frequent changes, a hysteresis of 2 dB is applied when determining the link quality. For example, the average |
| 382 | * link margin must be at least 12 dB to change a quality 1 link to a quality 2 link. |
| 383 | * |
| 384 | * @returns The current link quality value (value 0-3 as per Thread specification). |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 385 | * |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 386 | */ |
Abtin Keshavarzian | 8714ec1 | 2022-05-09 14:17:33 -0700 | [diff] [blame] | 387 | LinkQuality GetLinkQuality(void) const { return mLinkQuality; } |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 388 | |
| 389 | /** |
Adam Eliot | 8952104 | 2017-03-28 09:41:57 -0700 | [diff] [blame] | 390 | * Returns the most recent RSS value. |
| 391 | * |
| 392 | * @returns The most recent RSS |
| 393 | * |
| 394 | */ |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 395 | int8_t GetLastRss(void) const { return mLastRss; } |
Adam Eliot | 8952104 | 2017-03-28 09:41:57 -0700 | [diff] [blame] | 396 | |
Abtin Keshavarzian | 68a605f | 2018-01-31 12:40:23 -0800 | [diff] [blame] | 397 | /** |
| 398 | * This method adds a MAC frame transmission status (success/failure) and updates the frame tx error rate. |
| 399 | * |
| 400 | * @param[in] aTxStatus Success/Failure of MAC frame transmission (`true` -> success, `false` -> failure). |
| 401 | * |
| 402 | */ |
Jonathan Hui | 69d98d4 | 2018-02-06 14:14:57 -0800 | [diff] [blame] | 403 | void AddFrameTxStatus(bool aTxStatus) |
| 404 | { |
Abtin Keshavarzian | 68a605f | 2018-01-31 12:40:23 -0800 | [diff] [blame] | 405 | mFrameErrorRate.AddSample(aTxStatus, OPENTHREAD_CONFIG_FRAME_TX_ERR_RATE_AVERAGING_WINDOW); |
| 406 | } |
| 407 | |
| 408 | /** |
| 409 | * This method adds a message transmission status (success/failure) and updates the message error rate. |
| 410 | * |
| 411 | * @param[in] aTxStatus Success/Failure of message (`true` -> success, `false` -> message tx failed). |
| 412 | * A larger (IPv6) message may be fragmented and sent as multiple MAC frames. The message |
| 413 | * transmission is considered a failure, if any of its fragments fail after all MAC retry |
| 414 | * attempts. |
| 415 | * |
| 416 | */ |
Jonathan Hui | 69d98d4 | 2018-02-06 14:14:57 -0800 | [diff] [blame] | 417 | void AddMessageTxStatus(bool aTxStatus) |
| 418 | { |
Abtin Keshavarzian | 68a605f | 2018-01-31 12:40:23 -0800 | [diff] [blame] | 419 | mMessageErrorRate.AddSample(aTxStatus, OPENTHREAD_CONFIG_IPV6_TX_ERR_RATE_AVERAGING_WINDOW); |
| 420 | } |
| 421 | |
| 422 | /** |
| 423 | * This method returns the MAC frame transmission error rate for the link. |
| 424 | * |
| 425 | * The rate is maintained over a window of (roughly) last `OPENTHREAD_CONFIG_FRAME_TX_ERR_RATE_AVERAGING_WINDOW` |
| 426 | * frame transmissions. |
| 427 | * |
| 428 | * @returns The error rate with maximum value `0xffff` corresponding to 100% failure rate. |
| 429 | * |
| 430 | */ |
| 431 | uint16_t GetFrameErrorRate(void) const { return mFrameErrorRate.GetFailureRate(); } |
| 432 | |
| 433 | /** |
| 434 | * This method returns the message error rate for the link. |
| 435 | * |
| 436 | * The rate is maintained over a window of (roughly) last `OPENTHREAD_CONFIG_IPV6_TX_ERR_RATE_AVERAGING_WINDOW` |
| 437 | * (IPv6) messages. |
| 438 | * |
| 439 | * Note that a larger (IPv6) message can be fragmented and sent as multiple MAC frames. The message transmission is |
| 440 | * considered a failure, if any of its fragments fail after all MAC retry attempts. |
| 441 | * |
| 442 | * @returns The error rate with maximum value `0xffff` corresponding to 100% failure rate. |
| 443 | * |
| 444 | */ |
| 445 | uint16_t GetMessageErrorRate(void) const { return mMessageErrorRate.GetFailureRate(); } |
| 446 | |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 447 | private: |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 448 | // Constants for obtaining link quality from link margin: |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 449 | |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 450 | static constexpr uint8_t kThreshold3 = 20; // Link margin threshold for quality 3 link. |
| 451 | static constexpr uint8_t kThreshold2 = 10; // Link margin threshold for quality 2 link. |
| 452 | static constexpr uint8_t kThreshold1 = 2; // Link margin threshold for quality 1 link. |
| 453 | static constexpr uint8_t kHysteresisThreshold = 2; // Link margin hysteresis threshold. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 454 | |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 455 | static constexpr int8_t kLinkQuality3LinkMargin = 50; // link margin for Link Quality 3 (21 - 255) |
| 456 | static constexpr int8_t kLinkQuality2LinkMargin = 15; // link margin for Link Quality 3 (21 - 255) |
| 457 | static constexpr int8_t kLinkQuality1LinkMargin = 5; // link margin for Link Quality 3 (21 - 255) |
| 458 | static constexpr int8_t kLinkQuality0LinkMargin = 0; // link margin for Link Quality 3 (21 - 255) |
rongli | 502c6ca | 2017-07-12 13:38:49 +0800 | [diff] [blame] | 459 | |
Abtin Keshavarzian | 312ef5a | 2021-08-06 10:22:11 -0700 | [diff] [blame] | 460 | static constexpr uint8_t kNoLinkQuality = 0xff; // Indicate that there is no previous/last link quality. |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 461 | |
Abtin Keshavarzian | 8714ec1 | 2022-05-09 14:17:33 -0700 | [diff] [blame] | 462 | void SetLinkQuality(LinkQuality aLinkQuality) { mLinkQuality = aLinkQuality; } |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 463 | |
Abtin Keshavarzian | 8714ec1 | 2022-05-09 14:17:33 -0700 | [diff] [blame] | 464 | static LinkQuality CalculateLinkQuality(uint8_t aLinkMargin, uint8_t aLastLinkQuality); |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 465 | |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 466 | RssAverager mRssAverager; |
Abtin Keshavarzian | 8714ec1 | 2022-05-09 14:17:33 -0700 | [diff] [blame] | 467 | LinkQuality mLinkQuality; |
Abtin Keshavarzian | 92b0ddc | 2017-07-11 09:10:54 -0700 | [diff] [blame] | 468 | int8_t mLastRss; |
Jonathan Hui | 2a9f1c7 | 2019-12-18 10:24:13 -0800 | [diff] [blame] | 469 | |
Abtin Keshavarzian | 68a605f | 2018-01-31 12:40:23 -0800 | [diff] [blame] | 470 | SuccessRateTracker mFrameErrorRate; |
| 471 | SuccessRateTracker mMessageErrorRate; |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 472 | }; |
| 473 | |
| 474 | /** |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 475 | * @} |
| 476 | */ |
| 477 | |
Jonathan Hui | 69d98d4 | 2018-02-06 14:14:57 -0800 | [diff] [blame] | 478 | } // namespace ot |
Abtin Keshavarzian | cb33898 | 2016-06-27 14:15:11 -0700 | [diff] [blame] | 479 | |
| 480 | #endif // LINK_QUALITY_HPP_ |