blob: 2ca0593d5a6fdd5365a3e9151ec6c60ce90a1ad1 [file] [log] [blame]
Abtin Keshavarziancb338982016-06-27 14:15:11 -07001/*
Jonathan Hui44350172016-09-13 15:57:11 -07002 * Copyright (c) 2016, The OpenThread Authors.
Abtin Keshavarziancb338982016-06-27 14:15:11 -07003 * 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
Shu Chen6e3d6632017-06-13 02:05:40 +080037#include <openthread/platform/radio.h>
Jonathan Huifbfd76a2017-05-05 11:28:29 -070038#include <openthread/types.h>
Abtin Keshavarziancb338982016-06-27 14:15:11 -070039
Jonathan Hui1eabda62017-04-27 22:29:05 -070040namespace ot {
Abtin Keshavarziancb338982016-06-27 14:15:11 -070041
42/**
43 * @addtogroup core-link-quality
44 *
45 * @brief
46 * This module includes definitions for Thread link quality metrics.
47 *
48 * @{
49 */
50
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -070051
52/**
53 * This class implements a Received Signal Strength (RSS) averager.
54 *
55 * The average is maintained using an adaptive exponentially weighted moving filter.
56 *
57 */
58class RssAverager
59{
60 friend class LinkQualityInfo;
61
62public:
63 enum
64 {
65 kStringSize = 10, ///< Max chars needed for a string representation of average (@sa ToString()).
66 };
67
68 /**
69 * This method reset the averager and clears the average value.
70 *
71 */
72 void Reset(void);
73
74 /**
75 * This method indicates whether the averager contains an average (i.e., at least one RSS value has been added).
76 *
77 * @retval true If the average value is available (at least one RSS value has been added).
78 * @retval false Averager is empty (no RSS value added yet).
79 *
80 */
81 bool HasAverage(void) const { return (mCount != 0); }
82
83 /**
84 * This method adds a received signal strength (RSS) value to the average.
85 *
86 * If @p aRss is OT_RADIO_RSSI_INVALID, it is ignored and error status OT_ERROR_INVALID_ARGS is returned.
87 * The value of RSS is capped at 0dBm (i.e., for any given RSS value higher than 0dBm, 0dBm is used instead).
88 *
89 * @param[in] aRss Received signal strength value (in dBm) to be added to the average.
90 *
91 * @retval OT_ERROR_NONE New RSS value added to average successfully.
92 * @retval OT_ERROR_INVALID_ARGS Value of @p aRss is OT_RADIO_RSSI_INVALID.
93 *
94 */
95 otError Add(int8_t aRss);
96
97 /**
98 * This method returns the current average signal strength value maintained by the averager.
99 *
100 * @returns The current average value (in dBm) or OT_RADIO_RSSI_INVALID if no average is available.
101 *
102 */
103 int8_t GetAverage(void) const;
104
105 /**
106 * This method returns an raw/encoded version of current average signal strength value. The raw value is the
107 * average multiplied by a precision factor (currently set as -8).
108 *
109 * @returns The current average multiplied by precision factor or zero if no average is available.
110 *
111 */
112 uint16_t GetRaw(void) const { return mAverage; }
113
114 /**
115 * This method converts the current average RSS value to a human-readable string (e.g., "-80.375"). If the
116 * average is unknown, empty string is returned.
117 *
118 * @param[out] aBuf A pointer to the char buffer.
119 * @param[in] aSize The maximum size of the buffer.
120 *
121 * @returns A pointer to the char string buffer.
122 *
123 */
124 const char *ToString(char *aBuf, uint16_t aSize) const;
125
126private:
127 /*
128 * The RssAverager uses an adaptive exponentially weighted filter to maintain the average. It keeps track of
129 * current average and the number of added RSS values (up to a 8).
130 *
131 * For the first 8 added RSS values, the average is the arithmetic mean of the added values (e.g., if 5 values are
132 * added, the average is sum of the 5 added RSS values divided by 5. After the 8th RSS value, a weighted filter is
133 * used with coefficients (1/8, 7/8), i.e., newAverage = 1/8 * newRss + 7/8 * oldAverage.
134 *
135 * To add to accuracy of the averaging process, the RSS values and the maintained average are multiplied by a
136 * precision factor of -8.
137 *
138 */
139
140 enum
141 {
142 kPrecisionBitShift = 3, // Precision multiple for RSS average (1 << PrecisionBitShift).
143 kPrecision = (1 << kPrecisionBitShift),
144 kPrecisionBitMask = (kPrecision - 1),
145
146 kCoeffBitShift = 3, // Coefficient used for exponentially weighted filter (1 << kCoeffBitShift).
147 };
148
149 // Member variables fit into two bytes.
150
151 uint16_t mAverage : 11; // The raw average signal strength value (stored as RSS times precision multiple).
152 uint8_t mCount : 3; // Number of RSS values added to averager so far (limited to 2^kCoeffBitShift-1).
153 uint8_t mLinkQuality : 2; // Used by friend class LinkQualityInfo to store LinkQuality (0-3) value.
154};
155
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700156/**
157 * This class encapsulates/stores all relevant information about quality of a link, including average received signal
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700158 * strength (RSS), last RSS, link margin, and link quality.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700159 *
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700160 */
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700161class LinkQualityInfo
162{
rongli502c6ca2017-07-12 13:38:49 +0800163
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700164public:
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700165 enum
166 {
167 kInfoStringSize = 50, ///< Max chars needed for the info string representation (@sa ToInfoString())
168 };
169
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700170 /**
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700171 * This constructor initializes the object.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700172 *
173 */
174 LinkQualityInfo(void);
175
176 /**
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700177 * This method clears the all the data in the object.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700178 *
179 */
180 void Clear(void);
181
182 /**
183 * This method adds a new received signal strength (RSS) value to the average.
184 *
Shu Chen66f6e702017-05-05 11:38:37 +0800185 * @param[in] aNoiseFloor The noise floor value (in dBm).
Abtin Keshavarzianb3976f52017-04-14 14:32:55 -0700186 * @param[in] aRss A new received signal strength value (in dBm) to be added to the average.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700187 *
188 */
Shu Chen66f6e702017-05-05 11:38:37 +0800189 void AddRss(int8_t aNoiseFloor, int8_t aRss);
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700190
191 /**
192 * This method returns the current average signal strength value.
193 *
Shu Chen6e3d6632017-06-13 02:05:40 +0800194 * @returns The current average value or @c OT_RADIO_RSSI_INVALID if no average is available.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700195 *
196 */
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700197 int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); }
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700198
199 /**
200 * This method returns an encoded version of current average signal strength value. The encoded value is the
201 * average multiplied by a precision factor (currently -8).
202 *
203 * @returns The current average multiplied by precision factor or zero if no average is available.
204 *
205 */
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700206 uint16_t GetAverageRssRaw(void) const { return mRssAverager.GetRaw(); }
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700207
208 /**
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700209 * This method converts the link quality info to NULL-terminated info/debug human-readable string.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700210 *
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700211 * @param[out] aBuf A pointer to the string buffer.
212 * @param[in] aSize The maximum size of the string buffer.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700213 *
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700214 * @returns A pointer to the char string buffer.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700215 *
216 */
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700217 const char *ToInfoString(char *aBuf, uint16_t aSize) const;
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700218
219 /**
220 * This method returns the link margin. The link margin is calculated using the link's current average received
221 * signal strength (RSS) and average noise floor.
222 *
Shu Chen66f6e702017-05-05 11:38:37 +0800223 * @param[in] aNoiseFloor The noise floor value (in dBm).
Jonathan Hui28a56452016-08-29 21:49:50 -0700224 *
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700225 * @returns Link margin derived from average received signal strength and average noise floor.
226 *
227 */
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700228 uint8_t GetLinkMargin(int8_t aNoiseFloor) const { return ConvertRssToLinkMargin(aNoiseFloor, GetAverageRss()); }
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700229
230 /**
231 * Returns the current one-way link quality value. The link quality value is a number 0-3.
232 *
233 * The link quality is calculated by comparing the current link margin with a set of thresholds (per Thread spec).
234 * More specifically, link margin > 20 dB gives link quality 3, link margin > 10 dB gives link quality 2,
235 * link margin > 2 dB gives link quality 1, and link margin below or equal to 2 dB yields link quality of 0.
236 *
237 * In order to ensure that a link margin near the boundary of two different link quality values does not cause
238 * frequent changes, a hysteresis of 2 dB is applied when determining the link quality. For example, the average
239 * link margin must be at least 12 dB to change a quality 1 link to a quality 2 link.
240 *
Shu Chen66f6e702017-05-05 11:38:37 +0800241 * @param[in] aNoiseFloor The noise floor value (in dBm).
Jonathan Hui28a56452016-08-29 21:49:50 -0700242 *
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700243 * @returns The current link quality value (value 0-3 as per Thread specification).
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700244 *
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700245 */
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700246 uint8_t GetLinkQuality(void) const { return mRssAverager.mLinkQuality; }
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700247
248 /**
Adam Eliot89521042017-03-28 09:41:57 -0700249 * Returns the most recent RSS value.
250 *
251 * @returns The most recent RSS
252 *
253 */
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700254 int8_t GetLastRss(void) const { return mLastRss; }
Adam Eliot89521042017-03-28 09:41:57 -0700255
256 /**
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700257 * This method converts a received signal strength value to a link margin value.
258 *
Shu Chen66f6e702017-05-05 11:38:37 +0800259 * @param[in] aNoiseFloor The noise floor value (in dBm).
Abtin Keshavarzianb3976f52017-04-14 14:32:55 -0700260 * @param[in] aRss The received signal strength value (in dBm).
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700261 *
262 * @returns The link margin value.
263 *
264 */
Shu Chen66f6e702017-05-05 11:38:37 +0800265 static uint8_t ConvertRssToLinkMargin(int8_t aNoiseFloor, int8_t aRss);
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700266
267 /**
268 * This method converts a link margin value to a link quality value.
269 *
270 * @param[in] aLinkMargin The Link Margin in dB.
271 *
272 * @returns The link quality value (0-3).
273 *
274 */
275 static uint8_t ConvertLinkMarginToLinkQuality(uint8_t aLinkMargin);
276
277 /**
278 * This method converts a received signal strength value to a link quality value.
279 *
Shu Chen66f6e702017-05-05 11:38:37 +0800280 * @param[in] aNoiseFloor The noise floor value (in dBm).
Abtin Keshavarzianb3976f52017-04-14 14:32:55 -0700281 * @param[in] aRss The received signal strength value (in dBm).
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700282 *
283 * @returns The link quality value (0-3).
284 *
285 */
Shu Chen66f6e702017-05-05 11:38:37 +0800286 static uint8_t ConvertRssToLinkQuality(int8_t aNoiseFloor, int8_t aRss);
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700287
rongli502c6ca2017-07-12 13:38:49 +0800288 /**
289 * This method converts a link quality value to a typical received signal strength value .
290 * @note only for test
291 *
292 * @param[in] aNoiseFloor The noise floor value (in dBm).
293 * @param[in] aLinkQuality The link quality value in [0, 3].
294 *
295 * @returns The typical platform rssi.
296 *
297 */
298 static int8_t ConvertLinkQualityToRss(int8_t aNoiseFloor, uint8_t aLinkQuality);
299
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700300private:
301 enum
302 {
303 // Constants for obtaining link quality from link margin:
304
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700305 kThreshold3 = 20, // Link margin threshold for quality 3 link.
306 kThreshold2 = 10, // Link margin threshold for quality 2 link.
307 kThreshold1 = 2, // Link margin threshold for quality 1 link.
308 kHysteresisThreshold = 2, // Link margin hysteresis threshold.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700309
rongli502c6ca2017-07-12 13:38:49 +0800310 // constants for test:
311
312 kLinkQuality3LinkMargin = 50, ///< link margin for Link Quality 3 (21 - 255)
313 kLinkQuality2LinkMargin = 15, ///< link margin for Link Quality 3 (21 - 255)
314 kLinkQuality1LinkMargin = 5, ///< link margin for Link Quality 3 (21 - 255)
315 kLinkQuality0LinkMargin = 0, ///< link margin for Link Quality 3 (21 - 255)
316
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700317 kNoLinkQuality = 0xff, // Used to indicate that there is no previous/last link quality.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700318 };
319
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700320 void SetLinkQuality(uint8_t aLinkQuality) { mRssAverager.mLinkQuality = aLinkQuality; }
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700321
322 /* Static private method to calculate the link quality from a given link margin while taking into account the last
323 * link quality value and adding the hysteresis value to the thresholds. If there is no previous value for link
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700324 * quality, the constant kNoLinkQuality should be passed as the second argument.
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700325 *
326 */
327 static uint8_t CalculateLinkQuality(uint8_t aLinkMargin, uint8_t aLastLinkQuality);
328
Abtin Keshavarzian92b0ddc2017-07-11 09:10:54 -0700329 RssAverager mRssAverager;
330 int8_t mLastRss;
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700331};
332
333/**
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700334 * @}
335 */
336
Jonathan Hui1eabda62017-04-27 22:29:05 -0700337} // namespace ot
Abtin Keshavarziancb338982016-06-27 14:15:11 -0700338
339#endif // LINK_QUALITY_HPP_