mirror of
https://github.com/espressif/openthread.git
synced 2026-08-05 10:27:49 +00:00
[link-quality] introduce RssAverager and keep track of average RSS for a received message (#1961)
This commit introduces a new class `RssAverager` (which contains the existing averaging logic from`LinkQualityInfo` class). It also updates `Message` class to maintain the average RSS for a received message (note that a message may be composed of multiple 802.15.4 fragments data frames each received with different signal strength). The `MeshForwarder::LogIp6Message()` is updated to log the RSS value for received/dropped messages.
This commit is contained in:
committed by
Jonathan Hui
parent
3078359e38
commit
92b0ddca0a
@@ -163,6 +163,14 @@ bool otMessageIsLinkSecurityEnabled(otMessage *aMessage);
|
||||
*/
|
||||
void otMessageSetDirectTransmission(otMessage *aMessage, bool aEnabled);
|
||||
|
||||
/**
|
||||
* This function returns the average RSS (received signal strength) associated with the message.
|
||||
*
|
||||
* @returns The average RSS value (in dBm) or OT_RADIO_RSSI_INVALID if no average/RSS is available.
|
||||
*
|
||||
*/
|
||||
int8_t otMessageGetRss(otMessage *aMessage);
|
||||
|
||||
/**
|
||||
* Append bytes to a message.
|
||||
*
|
||||
|
||||
@@ -87,6 +87,12 @@ void otMessageSetDirectTransmission(otMessage *aMessage, bool aEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
int8_t otMessageGetRss(otMessage *aMessage)
|
||||
{
|
||||
Message *message = static_cast<Message *>(aMessage);
|
||||
return message->GetAverageRss();
|
||||
}
|
||||
|
||||
otError otMessageAppend(otMessage *aMessage, const void *aBuf, uint16_t aLength)
|
||||
{
|
||||
Message *message = static_cast<Message *>(aMessage);
|
||||
|
||||
@@ -315,7 +315,7 @@ otError otThreadGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo)
|
||||
aParentInfo->mRouterId = Mle::Mle::GetRouterId(parent->GetRloc16());
|
||||
aParentInfo->mNextHop = parent->GetNextHop();
|
||||
aParentInfo->mPathCost = parent->GetCost();
|
||||
aParentInfo->mLinkQualityIn = parent->GetLinkInfo().GetLinkQuality(aInstance->mThreadNetif.GetMac().GetNoiseFloor());
|
||||
aParentInfo->mLinkQualityIn = parent->GetLinkInfo().GetLinkQuality();
|
||||
aParentInfo->mLinkQualityOut = parent->GetLinkQualityOut();
|
||||
aParentInfo->mAge = static_cast<uint8_t>(TimerMilli::MsecToSec(TimerMilli::GetNow() -
|
||||
parent->GetLastHeard()));
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "thread/link_quality.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
@@ -96,6 +97,7 @@ struct MessageInfo
|
||||
uint16_t mLength; ///< Number of bytes within the message.
|
||||
uint16_t mOffset; ///< A byte offset within the message.
|
||||
uint16_t mDatagramTag; ///< The datagram tag used for 6LoWPAN fragmentation.
|
||||
RssAverager mRssAverager; ///< The averager maininting the received signal strength (RSS) average.
|
||||
|
||||
uint8_t mChildMask[8]; ///< A bit-vector to indicate which sleepy children need to receive this.
|
||||
uint8_t mTimeout; ///< Seconds remaining before dropping the message.
|
||||
@@ -617,6 +619,32 @@ public:
|
||||
*/
|
||||
void SetLinkSecurityEnabled(bool aEnabled) { mBuffer.mHead.mInfo.mLinkSecurity = aEnabled; }
|
||||
|
||||
/**
|
||||
* This method updates the average RSS (Received Signal Strength) associated with the message by adding the given
|
||||
* RSS value to the average. Note that a message can be composed of multiple 802.15.4 data frame fragments each
|
||||
* received with a different signal strength.
|
||||
*
|
||||
* @param[in] aRss A new RSS value (in dBm) to be added to average.
|
||||
*
|
||||
*/
|
||||
void AddRss(int8_t aRss) { mBuffer.mHead.mInfo.mRssAverager.Add(aRss); }
|
||||
|
||||
/**
|
||||
* This method returns the average RSS (Received Signal Strength) associated with the message.
|
||||
*
|
||||
* @returns The current average RSS value (in dBm) or OT_RADIO_RSSI_INVALID if no average is available.
|
||||
*
|
||||
*/
|
||||
int8_t GetAverageRss(void) const { return mBuffer.mHead.mInfo.mRssAverager.GetAverage(); }
|
||||
|
||||
/**
|
||||
* This method returns a const reference to RssAverager of the message.
|
||||
*
|
||||
* @returns A const reference to the RssAverager of the message.
|
||||
*
|
||||
*/
|
||||
const RssAverager &GetRssAverager(void) const { return mBuffer.mHead.mInfo.mRssAverager; }
|
||||
|
||||
/**
|
||||
* This method is used to update a checksum value.
|
||||
*
|
||||
|
||||
+101
-126
@@ -36,52 +36,34 @@
|
||||
#include "link_quality.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "utils/wrap_string.h"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "utils/wrap_string.h"
|
||||
|
||||
namespace ot {
|
||||
|
||||
enum
|
||||
// This array gives the decimal point digits representing 0/8, 1/8, ..., 7/8 (does not include the '.').
|
||||
static const char *const kDigitsString[8] =
|
||||
{
|
||||
kDefaultNoiseFloor = -100, // Default noise floor used if no average value is available.
|
||||
// 0/8, 1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8
|
||||
"0", "125", "25", "375", "5", "625", "75", "875"
|
||||
};
|
||||
|
||||
// This array gives the decimal point digits representing 0/8, 1/8, ..., 7/8 (it does not include the '.').
|
||||
static const char *const kLinkQualityDecimalDigitsString[8] =
|
||||
void RssAverager::Reset(void)
|
||||
{
|
||||
// 0/8, 1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8
|
||||
"000", "125", "250", "375", "500", "625", "750", "875"
|
||||
};
|
||||
|
||||
const char LinkQualityInfo::kUnknownRssString[] = "Unknown RSS";
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
|
||||
LinkQualityInfo::LinkQualityInfo(void)
|
||||
{
|
||||
Clear();
|
||||
mAverage = 0;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
void LinkQualityInfo::Clear(void)
|
||||
otError RssAverager::Add(int8_t aRss)
|
||||
{
|
||||
mRssAverage = 0;
|
||||
mCount = 0;
|
||||
mLinkQuality = 0;
|
||||
mLastRss = 0;
|
||||
}
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t newValue;
|
||||
uint16_t oldAverage;
|
||||
|
||||
void LinkQualityInfo::AddRss(int8_t aNoiseFloor, int8_t aRss)
|
||||
{
|
||||
uint16_t newValue;
|
||||
uint16_t oldAverage;
|
||||
|
||||
VerifyOrExit(aRss != OT_RADIO_RSSI_INVALID);
|
||||
|
||||
mLastRss = aRss;
|
||||
|
||||
// Restrict/Cap the RSS value to the closed range [0, -128] so the value can fit in 8 bits.
|
||||
VerifyOrExit(aRss != OT_RADIO_RSSI_INVALID, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
// Restrict the RSS value to the closed range [0, -128] so the RSS times precision multiple can fit in 11 bits.
|
||||
if (aRss > 0)
|
||||
{
|
||||
aRss = 0;
|
||||
@@ -90,116 +72,109 @@ void LinkQualityInfo::AddRss(int8_t aNoiseFloor, int8_t aRss)
|
||||
// Multiply the the RSS value by a precision multiple (currently -8).
|
||||
|
||||
newValue = static_cast<uint16_t>(-aRss);
|
||||
newValue <<= kRssAveragePrecisionMultipleBitShift;
|
||||
newValue <<= kPrecisionBitShift;
|
||||
|
||||
oldAverage = mRssAverage;
|
||||
|
||||
if (mCount >= kRssCountForWeightCoefficientOneEighth)
|
||||
{
|
||||
// New average = old average * 7/8 + new value * 1/8
|
||||
mRssAverage = static_cast<uint16_t>(((oldAverage << 3) - oldAverage + newValue) >> 3);
|
||||
}
|
||||
else if (mCount >= kRssCountForWeightCoefficientOneFourth)
|
||||
{
|
||||
// New average = old average * 3/4 + new value * 1/4
|
||||
mRssAverage = static_cast<uint16_t>(((oldAverage << 2) - oldAverage + newValue) >> 2);
|
||||
}
|
||||
else if (mCount >= kRssCountForWeightCoefficientOneHalf)
|
||||
{
|
||||
// New average = old average * 1/2 + new value * 1/2
|
||||
mRssAverage = (oldAverage + newValue) >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRssAverage = newValue;
|
||||
}
|
||||
|
||||
if (mCount < kRssCountMax)
|
||||
{
|
||||
mCount++;
|
||||
}
|
||||
|
||||
UpdateLinkQuality(aNoiseFloor);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
int8_t LinkQualityInfo::GetAverageRss(void) const
|
||||
{
|
||||
int8_t average = OT_RADIO_RSSI_INVALID;
|
||||
|
||||
if (mCount != 0)
|
||||
{
|
||||
average = -static_cast<int8_t>(mRssAverage >> kRssAveragePrecisionMultipleBitShift);
|
||||
|
||||
// Check for round up (e.g. average of -71.5 --> -72)
|
||||
|
||||
if ((mRssAverage & kRssAveragePrecisionMultipleBitMask) >= (kRssAveragePrecisionMultiple >> 1))
|
||||
{
|
||||
average--;
|
||||
}
|
||||
}
|
||||
|
||||
return average;
|
||||
}
|
||||
|
||||
uint16_t LinkQualityInfo::GetAverageRssAsEncodedWord(void) const
|
||||
{
|
||||
return mRssAverage;
|
||||
}
|
||||
|
||||
otError LinkQualityInfo::GetAverageRssAsString(char *aCharBuffer, size_t aBufferLen) const
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int charsWritten = 0;
|
||||
oldAverage = mAverage;
|
||||
|
||||
if (mCount == 0)
|
||||
{
|
||||
charsWritten = static_cast<int>(strlcpy(aCharBuffer, kUnknownRssString, aBufferLen));
|
||||
mCount++;
|
||||
mAverage = newValue;
|
||||
}
|
||||
else if (mCount < (1 << kCoeffBitShift) - 1)
|
||||
{
|
||||
mCount++;
|
||||
|
||||
// Maintain arithmetic mean.
|
||||
// newAverage = newValue * (1/mCount) + oldAverage * ((mCount -1)/mCount)
|
||||
mAverage = static_cast<uint16_t>(((oldAverage * (mCount - 1)) + newValue) / mCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
charsWritten = snprintf(aCharBuffer, aBufferLen, "%d.%s dBm",
|
||||
-(mRssAverage >> kRssAveragePrecisionMultipleBitShift),
|
||||
kLinkQualityDecimalDigitsString[mRssAverage & kRssAveragePrecisionMultipleBitMask]);
|
||||
// Maintain exponentially weighted moving average using coefficient of (1/2^kCoeffBitShift).
|
||||
// newAverage = + newValue * 1/2^j + oldAverage * (1 - 1/2^j), for j = kCoeffBitShift.
|
||||
|
||||
mAverage = static_cast<uint16_t>(((oldAverage << kCoeffBitShift) - oldAverage + newValue) >> kCoeffBitShift);
|
||||
}
|
||||
|
||||
VerifyOrExit(charsWritten >= 0, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
VerifyOrExit(charsWritten < static_cast<int>(aBufferLen), error = OT_ERROR_NO_BUFS);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t LinkQualityInfo::GetLinkMargin(int8_t aNoiseFloor) const
|
||||
int8_t RssAverager::GetAverage(void) const
|
||||
{
|
||||
return ConvertRssToLinkMargin(aNoiseFloor, GetAverageRss());
|
||||
}
|
||||
int8_t average;
|
||||
|
||||
uint8_t LinkQualityInfo::GetLinkQuality(int8_t aNoiseFloor)
|
||||
{
|
||||
UpdateLinkQuality(aNoiseFloor);
|
||||
VerifyOrExit(mCount != 0, average = OT_RADIO_RSSI_INVALID);
|
||||
|
||||
return mLinkQuality;
|
||||
}
|
||||
average = -static_cast<int8_t>(mAverage >> kPrecisionBitShift);
|
||||
|
||||
int8_t LinkQualityInfo::GetLastRss(void) const
|
||||
{
|
||||
return mLastRss;
|
||||
}
|
||||
// Check for possible round up (e.g., average of -71.5 --> -72)
|
||||
|
||||
void LinkQualityInfo::UpdateLinkQuality(int8_t aNoiseFloor)
|
||||
{
|
||||
if (mCount != 0)
|
||||
if ((mAverage & kPrecisionBitMask) >= (kPrecision >> 1))
|
||||
{
|
||||
mLinkQuality = CalculateLinkQuality(GetLinkMargin(aNoiseFloor), mLinkQuality);
|
||||
average--;
|
||||
}
|
||||
|
||||
exit:
|
||||
return average;
|
||||
}
|
||||
|
||||
const char *RssAverager::ToString(char *aBuf, uint16_t aSize) const
|
||||
{
|
||||
if (mCount == 0)
|
||||
{
|
||||
VerifyOrExit(aSize > 0);
|
||||
*aBuf = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLinkQuality = CalculateLinkQuality(GetLinkMargin(aNoiseFloor), kNoLastLinkQualityValue);
|
||||
snprintf(aBuf, aSize, "%d.%s", -(mAverage >> kPrecisionBitShift), kDigitsString[mAverage & kPrecisionBitMask]);
|
||||
}
|
||||
|
||||
exit:
|
||||
return aBuf;
|
||||
}
|
||||
|
||||
LinkQualityInfo::LinkQualityInfo(void):
|
||||
mLastRss(OT_RADIO_RSSI_INVALID)
|
||||
{
|
||||
mRssAverager.Reset();
|
||||
SetLinkQuality(0);
|
||||
}
|
||||
|
||||
void LinkQualityInfo::Clear(void)
|
||||
{
|
||||
mRssAverager.Reset();
|
||||
SetLinkQuality(0);
|
||||
mLastRss = OT_RADIO_RSSI_INVALID;
|
||||
}
|
||||
|
||||
void LinkQualityInfo::AddRss(int8_t aNoiseFloor, int8_t aRss)
|
||||
{
|
||||
uint8_t oldLinkQuality = kNoLinkQuality;
|
||||
|
||||
if (mRssAverager.HasAverage())
|
||||
{
|
||||
oldLinkQuality = GetLinkQuality();
|
||||
}
|
||||
|
||||
SuccessOrExit(mRssAverager.Add(aRss));
|
||||
|
||||
SetLinkQuality(CalculateLinkQuality(GetLinkMargin(aNoiseFloor), oldLinkQuality));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
const char *LinkQualityInfo::ToInfoString(char *aBuf, uint16_t aSize) const
|
||||
{
|
||||
char rssString[RssAverager::kStringSize];
|
||||
|
||||
snprintf(aBuf, aSize, "aveRss:%s, lastRss:%d, linkQuality:%d",
|
||||
mRssAverager.ToString(rssString, sizeof(rssString)), GetLastRss(), GetLinkQuality());
|
||||
|
||||
return aBuf;
|
||||
}
|
||||
|
||||
uint8_t LinkQualityInfo::ConvertRssToLinkMargin(int8_t aNoiseFloor, int8_t aRss)
|
||||
@@ -216,7 +191,7 @@ uint8_t LinkQualityInfo::ConvertRssToLinkMargin(int8_t aNoiseFloor, int8_t aRss)
|
||||
|
||||
uint8_t LinkQualityInfo::ConvertLinkMarginToLinkQuality(uint8_t aLinkMargin)
|
||||
{
|
||||
return CalculateLinkQuality(aLinkMargin, kNoLastLinkQualityValue);
|
||||
return CalculateLinkQuality(aLinkMargin, kNoLinkQuality);
|
||||
}
|
||||
|
||||
uint8_t LinkQualityInfo::ConvertRssToLinkQuality(int8_t aNoiseFloor, int8_t aRss)
|
||||
@@ -229,26 +204,26 @@ uint8_t LinkQualityInfo::CalculateLinkQuality(uint8_t aLinkMargin, uint8_t aLast
|
||||
uint8_t threshold1, threshold2, threshold3;
|
||||
uint8_t linkQuality = 0;
|
||||
|
||||
threshold1 = kLinkMarginThresholdForLinkQuality1;
|
||||
threshold2 = kLinkMarginThresholdForLinkQuality2;
|
||||
threshold3 = kLinkMarginThresholdForLinkQuality3;
|
||||
threshold1 = kThreshold1;
|
||||
threshold2 = kThreshold2;
|
||||
threshold3 = kThreshold3;
|
||||
|
||||
// Apply the hysteresis threshold based on the last link quality value.
|
||||
|
||||
switch (aLastLinkQuality)
|
||||
{
|
||||
case 0:
|
||||
threshold1 += kLinkMarginHysteresisThreshold;
|
||||
threshold1 += kHysteresisThreshold;
|
||||
|
||||
// Intentional fall-through to next case.
|
||||
|
||||
case 1:
|
||||
threshold2 += kLinkMarginHysteresisThreshold;
|
||||
threshold2 += kHysteresisThreshold;
|
||||
|
||||
// Intentional fall-through to next case.
|
||||
|
||||
case 2:
|
||||
threshold3 += kLinkMarginHysteresisThreshold;
|
||||
threshold3 += kHysteresisThreshold;
|
||||
|
||||
// Intentional fall-through to next case.
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
#ifndef LINK_QUALITY_HPP_
|
||||
#define LINK_QUALITY_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/types.h>
|
||||
|
||||
@@ -50,23 +48,132 @@ namespace ot {
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* This class implements a Received Signal Strength (RSS) averager.
|
||||
*
|
||||
* The average is maintained using an adaptive exponentially weighted moving filter.
|
||||
*
|
||||
*/
|
||||
class RssAverager
|
||||
{
|
||||
friend class LinkQualityInfo;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kStringSize = 10, ///< Max chars needed for a string representation of average (@sa ToString()).
|
||||
};
|
||||
|
||||
/**
|
||||
* This method reset the averager and clears the average value.
|
||||
*
|
||||
*/
|
||||
void Reset(void);
|
||||
|
||||
/**
|
||||
* This method indicates whether the averager contains an average (i.e., at least one RSS value has been added).
|
||||
*
|
||||
* @retval true If the average value is available (at least one RSS value has been added).
|
||||
* @retval false Averager is empty (no RSS value added yet).
|
||||
*
|
||||
*/
|
||||
bool HasAverage(void) const { return (mCount != 0); }
|
||||
|
||||
/**
|
||||
* This method adds a received signal strength (RSS) value to the average.
|
||||
*
|
||||
* If @p aRss is OT_RADIO_RSSI_INVALID, it is ignored and error status OT_ERROR_INVALID_ARGS is returned.
|
||||
* The value of RSS is capped at 0dBm (i.e., for any given RSS value higher than 0dBm, 0dBm is used instead).
|
||||
*
|
||||
* @param[in] aRss Received signal strength value (in dBm) to be added to the average.
|
||||
*
|
||||
* @retval OT_ERROR_NONE New RSS value added to average successfully.
|
||||
* @retval OT_ERROR_INVALID_ARGS Value of @p aRss is OT_RADIO_RSSI_INVALID.
|
||||
*
|
||||
*/
|
||||
otError Add(int8_t aRss);
|
||||
|
||||
/**
|
||||
* This method returns the current average signal strength value maintained by the averager.
|
||||
*
|
||||
* @returns The current average value (in dBm) or OT_RADIO_RSSI_INVALID if no average is available.
|
||||
*
|
||||
*/
|
||||
int8_t GetAverage(void) const;
|
||||
|
||||
/**
|
||||
* This method returns an raw/encoded version of current average signal strength value. The raw value is the
|
||||
* average multiplied by a precision factor (currently set as -8).
|
||||
*
|
||||
* @returns The current average multiplied by precision factor or zero if no average is available.
|
||||
*
|
||||
*/
|
||||
uint16_t GetRaw(void) const { return mAverage; }
|
||||
|
||||
/**
|
||||
* This method converts the current average RSS value to a human-readable string (e.g., "-80.375"). If the
|
||||
* average is unknown, empty string is returned.
|
||||
*
|
||||
* @param[out] aBuf A pointer to the char buffer.
|
||||
* @param[in] aSize The maximum size of the buffer.
|
||||
*
|
||||
* @returns A pointer to the char string buffer.
|
||||
*
|
||||
*/
|
||||
const char *ToString(char *aBuf, uint16_t aSize) const;
|
||||
|
||||
private:
|
||||
/*
|
||||
* The RssAverager uses an adaptive exponentially weighted filter to maintain the average. It keeps track of
|
||||
* current average and the number of added RSS values (up to a 8).
|
||||
*
|
||||
* For the first 8 added RSS values, the average is the arithmetic mean of the added values (e.g., if 5 values are
|
||||
* added, the average is sum of the 5 added RSS values divided by 5. After the 8th RSS value, a weighted filter is
|
||||
* used with coefficients (1/8, 7/8), i.e., newAverage = 1/8 * newRss + 7/8 * oldAverage.
|
||||
*
|
||||
* To add to accuracy of the averaging process, the RSS values and the maintained average are multiplied by a
|
||||
* precision factor of -8.
|
||||
*
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
kPrecisionBitShift = 3, // Precision multiple for RSS average (1 << PrecisionBitShift).
|
||||
kPrecision = (1 << kPrecisionBitShift),
|
||||
kPrecisionBitMask = (kPrecision - 1),
|
||||
|
||||
kCoeffBitShift = 3, // Coefficient used for exponentially weighted filter (1 << kCoeffBitShift).
|
||||
};
|
||||
|
||||
// Member variables fit into two bytes.
|
||||
|
||||
uint16_t mAverage : 11; // The raw average signal strength value (stored as RSS times precision multiple).
|
||||
uint8_t mCount : 3; // Number of RSS values added to averager so far (limited to 2^kCoeffBitShift-1).
|
||||
uint8_t mLinkQuality : 2; // Used by friend class LinkQualityInfo to store LinkQuality (0-3) value.
|
||||
};
|
||||
|
||||
/**
|
||||
* This class encapsulates/stores all relevant information about quality of a link, including average received signal
|
||||
* strength (RSS), link margin and link quality value (value in 0-3). The average is obtained using an adaptive
|
||||
* exponential moving average filter.
|
||||
* strength (RSS), last RSS, link margin, and link quality.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
class LinkQualityInfo
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kInfoStringSize = 50, ///< Max chars needed for the info string representation (@sa ToInfoString())
|
||||
};
|
||||
|
||||
/**
|
||||
* This constructor initializes an instance of the LinkQualityInfo class.
|
||||
* This constructor initializes the object.
|
||||
*
|
||||
*/
|
||||
LinkQualityInfo(void);
|
||||
|
||||
/**
|
||||
* This method clears the all the data in this instance.
|
||||
* This method clears the all the data in the object.
|
||||
*
|
||||
*/
|
||||
void Clear(void);
|
||||
@@ -86,7 +193,7 @@ public:
|
||||
* @returns The current average value or @c OT_RADIO_RSSI_INVALID if no average is available.
|
||||
*
|
||||
*/
|
||||
int8_t GetAverageRss(void) const;
|
||||
int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); }
|
||||
|
||||
/**
|
||||
* This method returns an encoded version of current average signal strength value. The encoded value is the
|
||||
@@ -95,20 +202,18 @@ public:
|
||||
* @returns The current average multiplied by precision factor or zero if no average is available.
|
||||
*
|
||||
*/
|
||||
uint16_t GetAverageRssAsEncodedWord(void) const;
|
||||
uint16_t GetAverageRssRaw(void) const { return mRssAverager.GetRaw(); }
|
||||
|
||||
/**
|
||||
* This method provides the current average received signal strength (RSS) as a human-readable string (e.g.,
|
||||
* "-80.375 dBm"). If the average is unknown, "unknown RSS" is used/returned in the buffer.
|
||||
* This method converts the link quality info to NULL-terminated info/debug human-readable string.
|
||||
*
|
||||
* @param[out] aCharBuffer A char buffer to store the string corresponding to current average value.
|
||||
* @param[in] aBufferLen The char buffer length.
|
||||
* @param[out] aBuf A pointer to the string buffer.
|
||||
* @param[in] aSize The maximum size of the string buffer.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully formed the string in the given char buffer.
|
||||
* @retval OT_ERROR_NO_BUFS The string representation of the average value could not fit in the given buffer.
|
||||
* @returns A pointer to the char string buffer.
|
||||
*
|
||||
*/
|
||||
otError GetAverageRssAsString(char *aCharBuffer, size_t aBufferLen) const;
|
||||
const char *ToInfoString(char *aBuf, uint16_t aSize) const;
|
||||
|
||||
/**
|
||||
* This method returns the link margin. The link margin is calculated using the link's current average received
|
||||
@@ -119,7 +224,7 @@ public:
|
||||
* @returns Link margin derived from average received signal strength and average noise floor.
|
||||
*
|
||||
*/
|
||||
uint8_t GetLinkMargin(int8_t aNoiseFloor) const;
|
||||
uint8_t GetLinkMargin(int8_t aNoiseFloor) const { return ConvertRssToLinkMargin(aNoiseFloor, GetAverageRss()); }
|
||||
|
||||
/**
|
||||
* Returns the current one-way link quality value. The link quality value is a number 0-3.
|
||||
@@ -135,8 +240,9 @@ public:
|
||||
* @param[in] aNoiseFloor The noise floor value (in dBm).
|
||||
*
|
||||
* @returns The current link quality value (value 0-3 as per Thread specification).
|
||||
*
|
||||
*/
|
||||
uint8_t GetLinkQuality(int8_t aNoiseFloor);
|
||||
uint8_t GetLinkQuality(void) const { return mRssAverager.mLinkQuality; }
|
||||
|
||||
/**
|
||||
* Returns the most recent RSS value.
|
||||
@@ -144,7 +250,7 @@ public:
|
||||
* @returns The most recent RSS
|
||||
*
|
||||
*/
|
||||
int8_t GetLastRss(void) const;
|
||||
int8_t GetLastRss(void) const { return mLastRss; }
|
||||
|
||||
/**
|
||||
* This method converts a received signal strength value to a link margin value.
|
||||
@@ -183,46 +289,25 @@ private:
|
||||
{
|
||||
// Constants for obtaining link quality from link margin:
|
||||
|
||||
kLinkMarginThresholdForLinkQuality3 = 20, // Link margin threshold for quality 3 link.
|
||||
kLinkMarginThresholdForLinkQuality2 = 10, // Link margin threshold for quality 2 link.
|
||||
kLinkMarginThresholdForLinkQuality1 = 2, // Link margin threshold for quality 1 link.
|
||||
kLinkMarginHysteresisThreshold = 2, // Link margin hysteresis threshold.
|
||||
kThreshold3 = 20, // Link margin threshold for quality 3 link.
|
||||
kThreshold2 = 10, // Link margin threshold for quality 2 link.
|
||||
kThreshold1 = 2, // Link margin threshold for quality 1 link.
|
||||
kHysteresisThreshold = 2, // Link margin hysteresis threshold.
|
||||
|
||||
kNoLastLinkQualityValue = 0xff, // Used to indicate that there is no previous/last link quality.
|
||||
|
||||
// Constants related to RSS adaptive exponential moving average filter:
|
||||
|
||||
kRssAveragePrecisionMultipleBitShift = 3, // Precision multiple for RSS average (1 << PrecisionBitShift).
|
||||
kRssAveragePrecisionMultiple = (1 << kRssAveragePrecisionMultipleBitShift),
|
||||
kRssAveragePrecisionMultipleBitMask = (kRssAveragePrecisionMultiple - 1),
|
||||
|
||||
kRssCountMax = 7, // mCount max limit value.
|
||||
|
||||
kRssCountForWeightCoefficientOneEighth = 5, // mCount threshold to use average weight coefficient of 1/8.
|
||||
kRssCountForWeightCoefficientOneFourth = 2, // mCount threshold to use average weight coefficient of 1/4.
|
||||
kRssCountForWeightCoefficientOneHalf = 1, // mCount threshold to use average weight coefficient of 1/2.
|
||||
kNoLinkQuality = 0xff, // Used to indicate that there is no previous/last link quality.
|
||||
};
|
||||
|
||||
/* Private method to update the mLinkQuality value. This is called when a new RSS value is added to average
|
||||
* or when GetLinkQuality() is invoked.
|
||||
*/
|
||||
void UpdateLinkQuality(int8_t aNoiseFloor);
|
||||
void SetLinkQuality(uint8_t aLinkQuality) { mRssAverager.mLinkQuality = aLinkQuality; }
|
||||
|
||||
/* Static private method to calculate the link quality from a given link margin while taking into account the last
|
||||
* link quality value and adding the hysteresis value to the thresholds. If there is no previous value for link
|
||||
* quality, the constant kNoLastLinkQualityValue should be passed as the second argument.
|
||||
* quality, the constant kNoLinkQuality should be passed as the second argument.
|
||||
*
|
||||
*/
|
||||
static uint8_t CalculateLinkQuality(uint8_t aLinkMargin, uint8_t aLastLinkQuality);
|
||||
|
||||
static const char kUnknownRssString[]; // Constant string used when RSS average is unknown.
|
||||
|
||||
// All data should fit into a 16-bit (uint16_t) value.
|
||||
|
||||
uint16_t mRssAverage : 11; // The encoded average signal strength value (stored as rss times precision multiple).
|
||||
uint8_t mCount : 3; // Number of RSS values added to average so far (limited to kRssCountMax).
|
||||
uint8_t mLinkQuality : 2; // Current link quality value (0-3).
|
||||
int8_t mLastRss;
|
||||
RssAverager mRssAverager;
|
||||
int8_t mLastRss;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1946,6 +1946,7 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
message->SetLinkSecurityEnabled(aMessageInfo.mLinkSecurity);
|
||||
message->SetPanId(aMessageInfo.mPanId);
|
||||
message->AddRss(aMessageInfo.mRss);
|
||||
headerLength = netif.GetLowpan().Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength,
|
||||
datagramLength);
|
||||
VerifyOrExit(headerLength > 0, error = OT_ERROR_PARSE);
|
||||
@@ -2019,6 +2020,7 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
// copy Fragment
|
||||
message->Write(message->GetOffset(), aFrameLength, aFrame);
|
||||
message->MoveOffset(aFrameLength);
|
||||
message->AddRss(aMessageInfo.mRss);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -2125,6 +2127,7 @@ void MeshForwarder::HandleLowpanHC(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
message->SetLinkSecurityEnabled(aMessageInfo.mLinkSecurity);
|
||||
message->SetPanId(aMessageInfo.mPanId);
|
||||
message->AddRss(aMessageInfo.mRss);
|
||||
|
||||
headerLength = netif.GetLowpan().Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, 0);
|
||||
VerifyOrExit(headerLength > 0, error = OT_ERROR_PARSE);
|
||||
@@ -2233,10 +2236,12 @@ void MeshForwarder::LogIp6Message(MessageAction aAction, const Message &aMessage
|
||||
uint16_t checksum = 0;
|
||||
Ip6::Header ip6Header;
|
||||
Ip6::IpProto protocol;
|
||||
char stringBuffer[Ip6::Address::kIp6AddressStringSize];
|
||||
const char *actionText;
|
||||
const char *priorityText;
|
||||
bool shouldLogRss = false;
|
||||
bool shouldLogSrcDstAddresses = true;
|
||||
char stringBuffer[Ip6::Address::kIp6AddressStringSize];
|
||||
char rssString[RssAverager::kStringSize];
|
||||
|
||||
VerifyOrExit(aMessage.GetType() == Message::kTypeIp6);
|
||||
|
||||
@@ -2279,6 +2284,7 @@ void MeshForwarder::LogIp6Message(MessageAction aAction, const Message &aMessage
|
||||
{
|
||||
case kMessageReceive:
|
||||
actionText = "Received";
|
||||
shouldLogRss = true;
|
||||
break;
|
||||
|
||||
case kMessageTransmit:
|
||||
@@ -2300,6 +2306,7 @@ void MeshForwarder::LogIp6Message(MessageAction aAction, const Message &aMessage
|
||||
|
||||
case kMessageDrop:
|
||||
actionText = "Dropping";
|
||||
shouldLogRss = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2332,7 +2339,7 @@ void MeshForwarder::LogIp6Message(MessageAction aAction, const Message &aMessage
|
||||
|
||||
otLogInfoMac(
|
||||
GetInstance(),
|
||||
"%s IPv6 %s msg, len:%d, chksum:%04x%s%s, sec:%s%s%s, prio:%s",
|
||||
"%s IPv6 %s msg, len:%d, chksum:%04x%s%s, sec:%s%s%s, prio:%s%s%s",
|
||||
actionText,
|
||||
Ip6::Ip6::IpProtoToString(protocol),
|
||||
aMessage.GetLength(),
|
||||
@@ -2342,7 +2349,9 @@ void MeshForwarder::LogIp6Message(MessageAction aAction, const Message &aMessage
|
||||
aMessage.IsLinkSecurityEnabled() ? "yes" : "no",
|
||||
(aError == OT_ERROR_NONE) ? "" : ", error:",
|
||||
(aError == OT_ERROR_NONE) ? "" : otThreadErrorToString(aError),
|
||||
priorityText
|
||||
priorityText,
|
||||
shouldLogRss ? "" : ", rss:",
|
||||
shouldLogRss ? "" : aMessage.GetRssAverager().ToString(rssString, sizeof(rssString))
|
||||
);
|
||||
|
||||
if (shouldLogSrcDstAddresses)
|
||||
|
||||
@@ -2515,7 +2515,7 @@ bool Mle::IsBetterParent(uint16_t aRloc16, uint8_t aLinkQuality, ConnectivityTlv
|
||||
{
|
||||
bool rval = false;
|
||||
|
||||
uint8_t candidateLinkQualityIn = mParentCandidate.GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor());
|
||||
uint8_t candidateLinkQualityIn = mParentCandidate.GetLinkInfo().GetLinkQuality();
|
||||
uint8_t candidateTwoWayLinkQuality = (candidateLinkQualityIn < mParentCandidate.GetLinkQualityOut())
|
||||
? candidateLinkQualityIn : mParentCandidate.GetLinkQualityOut();
|
||||
|
||||
|
||||
@@ -1123,7 +1123,7 @@ uint8_t MleRouter::GetLinkCost(uint8_t aRouterId)
|
||||
// NULL aRouterId indicates non-existing next hop, hence return kMaxRouteCost for it.
|
||||
VerifyOrExit(aRouterId != mRouterId && router != NULL && router->GetState() == Neighbor::kStateValid);
|
||||
|
||||
rval = router->GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor());
|
||||
rval = router->GetLinkInfo().GetLinkQuality();
|
||||
|
||||
if (rval > router->GetLinkQualityOut())
|
||||
{
|
||||
@@ -1637,7 +1637,7 @@ void MleRouter::UpdateRoutes(const RouteTlv &aRoute, uint8_t aRouterId)
|
||||
GetRloc16(i),
|
||||
GetRloc16(mRouters[i].GetNextHop()),
|
||||
mRouters[i].GetCost(),
|
||||
GetLinkCost(i), mRouters[i].GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor()),
|
||||
GetLinkCost(i), mRouters[i].GetLinkInfo().GetLinkQuality(),
|
||||
mRouters[i].GetLinkQualityOut());
|
||||
}
|
||||
|
||||
@@ -3624,7 +3624,7 @@ otError MleRouter::GetChildInfo(Child &aChild, otChildInfo &aChildInfo)
|
||||
aChildInfo.mChildId = GetChildId(aChild.GetRloc16());
|
||||
aChildInfo.mNetworkDataVersion = aChild.GetNetworkDataVersion();
|
||||
aChildInfo.mAge = TimerMilli::MsecToSec(TimerMilli::GetNow() - aChild.GetLastHeard());
|
||||
aChildInfo.mLinkQualityIn = aChild.GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor());
|
||||
aChildInfo.mLinkQualityIn = aChild.GetLinkInfo().GetLinkQuality();
|
||||
aChildInfo.mAverageRssi = aChild.GetLinkInfo().GetAverageRss();
|
||||
aChildInfo.mLastRssi = aChild.GetLinkInfo().GetLastRss();
|
||||
|
||||
@@ -3663,7 +3663,7 @@ otError MleRouter::GetRouterInfo(uint16_t aRouterId, otRouterInfo &aRouterInfo)
|
||||
aRouterInfo.mNextHop = router->GetNextHop();
|
||||
aRouterInfo.mLinkEstablished = router->GetState() == Neighbor::kStateValid;
|
||||
aRouterInfo.mPathCost = router->GetCost();
|
||||
aRouterInfo.mLinkQualityIn = router->GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor());
|
||||
aRouterInfo.mLinkQualityIn = router->GetLinkInfo().GetLinkQuality();
|
||||
aRouterInfo.mLinkQualityOut = router->GetLinkQualityOut();
|
||||
aRouterInfo.mAge = static_cast<uint8_t>(TimerMilli::MsecToSec(TimerMilli::GetNow() -
|
||||
router->GetLastHeard()));
|
||||
@@ -3725,7 +3725,7 @@ exit:
|
||||
aNeighInfo.mRloc16 = neighbor->GetRloc16();
|
||||
aNeighInfo.mLinkFrameCounter = neighbor->GetLinkFrameCounter();
|
||||
aNeighInfo.mMleFrameCounter = neighbor->GetMleFrameCounter();
|
||||
aNeighInfo.mLinkQualityIn = neighbor->GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor());
|
||||
aNeighInfo.mLinkQualityIn = neighbor->GetLinkInfo().GetLinkQuality();
|
||||
aNeighInfo.mAverageRssi = neighbor->GetLinkInfo().GetAverageRss();
|
||||
aNeighInfo.mLastRssi = neighbor->GetLinkInfo().GetLastRss();
|
||||
aNeighInfo.mRxOnWhenIdle = neighbor->IsRxOnWhenIdle();
|
||||
@@ -4235,7 +4235,6 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
|
||||
uint8_t linkQuality;
|
||||
uint8_t numChildren = 0;
|
||||
int8_t parentPriority = kParentPriorityMedium;
|
||||
int8_t noiseFloor = GetNetif().GetMac().GetNoiseFloor();
|
||||
|
||||
if (mParentPriority != kParentPriorityUnspecified)
|
||||
{
|
||||
@@ -4278,7 +4277,7 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
|
||||
break;
|
||||
|
||||
case OT_DEVICE_ROLE_CHILD:
|
||||
switch (mParent.GetLinkInfo().GetLinkQuality(noiseFloor))
|
||||
switch (mParent.GetLinkInfo().GetLinkQuality())
|
||||
{
|
||||
case 1:
|
||||
tlv.SetLinkQuality1(tlv.GetLinkQuality1() + 1);
|
||||
@@ -4293,7 +4292,7 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
|
||||
break;
|
||||
}
|
||||
|
||||
cost += LinkQualityToCost(mParent.GetLinkInfo().GetLinkQuality(noiseFloor));
|
||||
cost += LinkQualityToCost(mParent.GetLinkInfo().GetLinkQuality());
|
||||
break;
|
||||
|
||||
case OT_DEVICE_ROLE_ROUTER:
|
||||
@@ -4325,7 +4324,7 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
|
||||
continue;
|
||||
}
|
||||
|
||||
linkQuality = mRouters[i].GetLinkInfo().GetLinkQuality(noiseFloor);
|
||||
linkQuality = mRouters[i].GetLinkInfo().GetLinkQuality();
|
||||
|
||||
if (linkQuality > mRouters[i].GetLinkQualityOut())
|
||||
{
|
||||
@@ -4470,8 +4469,7 @@ void MleRouter::FillRouteTlv(RouteTlv &tlv)
|
||||
}
|
||||
else
|
||||
{
|
||||
tlv.SetLinkQualityIn(routeCount,
|
||||
mRouters[i].GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor()));
|
||||
tlv.SetLinkQualityIn(routeCount, mRouters[i].GetLinkInfo().GetLinkQuality());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4533,7 +4531,7 @@ bool MleRouter::HasOneNeighborwithComparableConnectivity(const RouteTlv &aRoute,
|
||||
continue;
|
||||
}
|
||||
|
||||
localLinkQuality = mRouters[i].GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor());
|
||||
localLinkQuality = mRouters[i].GetLinkInfo().GetLinkQuality();
|
||||
|
||||
if (localLinkQuality > mRouters[i].GetLinkQualityOut())
|
||||
{
|
||||
@@ -4662,7 +4660,7 @@ uint8_t MleRouter::GetMinDowngradeNeighborRouters(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
linkQuality = mRouters[i].GetLinkInfo().GetLinkQuality(GetNetif().GetMac().GetNoiseFloor());
|
||||
linkQuality = mRouters[i].GetLinkInfo().GetLinkQuality();
|
||||
|
||||
if (linkQuality > mRouters[i].GetLinkQualityOut())
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "thread/link_quality.hpp"
|
||||
#include "utils/wrap_string.h"
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.h"
|
||||
|
||||
namespace ot {
|
||||
@@ -45,9 +46,9 @@ enum
|
||||
kRssAverageMaxDiff = 16,
|
||||
kNumRssAdds = 300,
|
||||
|
||||
kEncodedAverageBitShift = 3,
|
||||
kEncodedAverageMultiple = (1 << kEncodedAverageBitShift),
|
||||
kEncodedAverageBitMask = (1 << kEncodedAverageBitShift) - 1,
|
||||
kRawAverageBitShift = 3,
|
||||
kRawAverageMultiple = (1 << kRawAverageBitShift),
|
||||
kRawAverageBitMask = (1 << kRawAverageBitShift) - 1,
|
||||
};
|
||||
|
||||
#define MIN_RSS(_rss1, _rss2) (((_rss1) < (_rss2)) ? (_rss1) : (_rss2))
|
||||
@@ -64,41 +65,34 @@ struct RssTestData
|
||||
|
||||
int8_t sNoiseFloor = -100; // dBm
|
||||
|
||||
// Checks the encoded average RSS value to match the value from GetAverageRss().
|
||||
void VerifyEncodedRssValue(LinkQualityInfo &aLinkInfo)
|
||||
// Check and verify the raw average RSS value to match the value from GetAverage().
|
||||
void VerifyRawRssValue(int8_t aAverage, uint16_t aRawValue)
|
||||
{
|
||||
int8_t rss = aLinkInfo.GetAverageRss();
|
||||
uint16_t encodedRss = aLinkInfo.GetAverageRssAsEncodedWord();
|
||||
|
||||
if (rss != OT_RADIO_RSSI_INVALID)
|
||||
if (aAverage != OT_RADIO_RSSI_INVALID)
|
||||
{
|
||||
VerifyOrQuit(rss == -static_cast<int16_t>((encodedRss + (kEncodedAverageMultiple / 2)) >> kEncodedAverageBitShift),
|
||||
"TestLinkQualityInfo failed - Ecoded RSS does not match the value from GetAverageRss().");
|
||||
VerifyOrQuit(aAverage == -static_cast<int16_t>((aRawValue + (kRawAverageMultiple / 2)) >> kRawAverageBitShift),
|
||||
"TestLinkQualityInfo failed - Raw value does not match the average.");
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrQuit(encodedRss == 0,
|
||||
"TestLinkQualityInfo failed - Ecoded RSS does not match the value from GetAverageRss().");
|
||||
VerifyOrQuit(aRawValue == 0, "TestLinkQualityInfo failed - Raw value does not match the average.");
|
||||
}
|
||||
}
|
||||
|
||||
// This function prints the values in the passed in link info instance. It is invoked as the final step in test-case.
|
||||
void PrintOutcome(LinkQualityInfo &aLinkInfo)
|
||||
{
|
||||
char stringBuf[kStringBuffferSize];
|
||||
char stringBuf[LinkQualityInfo::kInfoStringSize];
|
||||
|
||||
SuccessOrQuit(aLinkInfo.GetAverageRssAsString(stringBuf, sizeof(stringBuf)),
|
||||
"TestLinkQualityInfo failed - GetAverageRssAsString() failed.");
|
||||
VerifyOrQuit(aLinkInfo.ToInfoString(stringBuf, sizeof(stringBuf)) != NULL, "ToInfoString() returned NULL");
|
||||
|
||||
printf("AveRss = %-4d, \"%-14s\", ", aLinkInfo.GetAverageRss(), stringBuf);
|
||||
printf("LinkMargin = %-4d, LinkQuality = %d", aLinkInfo.GetLinkMargin(sNoiseFloor),
|
||||
aLinkInfo.GetLinkQuality(sNoiseFloor));
|
||||
printf("%s", stringBuf);
|
||||
|
||||
// This test-case succeeded.
|
||||
printf(" -> PASS\n");
|
||||
}
|
||||
|
||||
void TestLinkQualityData(RssTestData anRssData)
|
||||
void TestLinkQualityData(RssTestData aRssData)
|
||||
{
|
||||
LinkQualityInfo linkInfo;
|
||||
int8_t rss, ave, min, max;
|
||||
@@ -108,66 +102,101 @@ void TestLinkQualityData(RssTestData anRssData)
|
||||
min = kMinRssValue;
|
||||
max = kMaxRssValue;
|
||||
|
||||
for (i = 0; i < anRssData.mRssListSize; i++)
|
||||
for (i = 0; i < aRssData.mRssListSize; i++)
|
||||
{
|
||||
rss = anRssData.mRssList[i];
|
||||
rss = aRssData.mRssList[i];
|
||||
min = MIN_RSS(rss, min);
|
||||
max = MAX_RSS(rss, max);
|
||||
linkInfo.AddRss(sNoiseFloor, rss);
|
||||
ave = linkInfo.GetAverageRss();
|
||||
VerifyOrQuit(ave >= min,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is smaller than min value.");
|
||||
VerifyOrQuit(ave <= max,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is larger than min value");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
VerifyOrQuit(ave >= min, "TestLinkQualityInfo failed - GetAverageRss() is smaller than min value.");
|
||||
VerifyOrQuit(ave <= max, "TestLinkQualityInfo failed - GetAverageRss() is larger than min value");
|
||||
VerifyRawRssValue(linkInfo.GetAverageRss(), linkInfo.GetAverageRssRaw());
|
||||
printf("%02u) AddRss(%4d): ", (unsigned int)i, rss);
|
||||
PrintOutcome(linkInfo);
|
||||
}
|
||||
|
||||
VerifyOrQuit(linkInfo.GetLinkQuality(sNoiseFloor) == anRssData.mExpectedLinkQuality,
|
||||
VerifyOrQuit(linkInfo.GetLinkQuality() == aRssData.mExpectedLinkQuality,
|
||||
"TestLinkQualityInfo failed - GetLinkQuality() is incorrect");
|
||||
}
|
||||
|
||||
// Check and verify the raw average RSS value to match the value from GetAverage().
|
||||
void VerifyRawRssValue(RssAverager &aRssAverager)
|
||||
{
|
||||
int8_t average = aRssAverager.GetAverage();
|
||||
uint16_t rawValue = aRssAverager.GetRaw();
|
||||
|
||||
if (average != OT_RADIO_RSSI_INVALID)
|
||||
{
|
||||
VerifyOrQuit(average == -static_cast<int16_t>((rawValue + (kRawAverageMultiple / 2)) >> kRawAverageBitShift),
|
||||
"TestLinkQualityInfo failed - Raw value does not match the average.");
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrQuit(rawValue == 0, "TestLinkQualityInfo failed - Raw value does not match the average.");
|
||||
}
|
||||
}
|
||||
|
||||
// This function prints the values in the passed in link info instance. It is invoked as the final step in test-case.
|
||||
void PrintOutcome(RssAverager &aRssAverager)
|
||||
{
|
||||
char stringBuf[RssAverager::kStringSize];
|
||||
|
||||
VerifyOrQuit(aRssAverager.ToString(stringBuf, sizeof(stringBuf)) != NULL, "ToString() returned NULL");
|
||||
printf("%s", stringBuf);
|
||||
|
||||
// This test-case succeeded.
|
||||
printf(" -> PASS\n");
|
||||
}
|
||||
|
||||
|
||||
int8_t GetRandomRss(void)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
value = otPlatRandomGet() % 128;
|
||||
return static_cast<int8_t>(-value);
|
||||
}
|
||||
|
||||
void TestRssAveraging(void)
|
||||
{
|
||||
LinkQualityInfo linkInfo;
|
||||
RssAverager rssAverager;
|
||||
int8_t rss, rss2, ave;
|
||||
int16_t diff;
|
||||
size_t i, j, k;
|
||||
const int8_t rssValues[] = { kMinRssValue, -70, -40, -41, -10, kMaxRssValue};
|
||||
int16_t sum;
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Values after initialization.
|
||||
// Values after initialization/reset.
|
||||
|
||||
printf("\nAfter Initialization: ");
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == OT_RADIO_RSSI_INVALID,
|
||||
"TestLinkQualityInfo failed - Inital value from GetAverageRss() is incorrect.");
|
||||
VerifyOrQuit(linkInfo.GetLinkMargin(sNoiseFloor) == 0,
|
||||
"TestLinkQualityInfo failed - Inital value for link margin is incorrect.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
rssAverager.Reset();
|
||||
|
||||
printf("\nAfter Reset: ");
|
||||
VerifyOrQuit(rssAverager.GetAverage() == OT_RADIO_RSSI_INVALID,
|
||||
"TestLinkQualityInfo failed - Initial value from GetAverage() is incorrect.");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
PrintOutcome(rssAverager);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Adding a single value
|
||||
rss = -70;
|
||||
printf("AddRss(%d): ", rss);
|
||||
linkInfo.AddRss(sNoiseFloor, rss);
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == rss,
|
||||
"TestLinkQualityInfo - GetAverageRss() failed after a single AddRss().");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
rssAverager.Add(rss);
|
||||
VerifyOrQuit(rssAverager.GetAverage() == rss,
|
||||
"TestLinkQualityInfo - GetAverage() failed after a single AddRss().");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
PrintOutcome(rssAverager);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Clear
|
||||
// Reset
|
||||
|
||||
printf("Clear(): ");
|
||||
linkInfo.Clear();
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == OT_RADIO_RSSI_INVALID,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() after Clear() is incorrect.");
|
||||
VerifyOrQuit(linkInfo.GetLinkMargin(sNoiseFloor) == 0,
|
||||
"TestLinkQualityInfo failed - link margin value after Clear() is incorrect.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
printf("Reset(): ");
|
||||
rssAverager.Reset();
|
||||
VerifyOrQuit(rssAverager.GetAverage() == OT_RADIO_RSSI_INVALID,
|
||||
"TestLinkQualityInfo failed - GetAverage() after Reset() is incorrect.");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
PrintOutcome(rssAverager);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Adding the same value many times.
|
||||
@@ -176,19 +205,19 @@ void TestRssAveraging(void)
|
||||
|
||||
for (j = 0; j < sizeof(rssValues); j++)
|
||||
{
|
||||
linkInfo.Clear();
|
||||
rssAverager.Reset();
|
||||
rss = rssValues[j];
|
||||
printf("AddRss(%4d) %d times: ", rss, kNumRssAdds);
|
||||
|
||||
for (i = 0; i < kNumRssAdds; i++)
|
||||
{
|
||||
linkInfo.AddRss(sNoiseFloor, rss);
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == rss,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
rssAverager.Add(rss);
|
||||
VerifyOrQuit(rssAverager.GetAverage() == rss,
|
||||
"TestLinkQualityInfo failed - GetAverage() returned incorrect value.");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
}
|
||||
|
||||
PrintOutcome(linkInfo);
|
||||
PrintOutcome(rssAverager);
|
||||
|
||||
}
|
||||
|
||||
@@ -209,14 +238,14 @@ void TestRssAveraging(void)
|
||||
}
|
||||
|
||||
rss2 = rssValues[k];
|
||||
linkInfo.Clear();
|
||||
linkInfo.AddRss(sNoiseFloor, rss);
|
||||
linkInfo.AddRss(sNoiseFloor, rss2);
|
||||
rssAverager.Reset();
|
||||
rssAverager.Add(rss);
|
||||
rssAverager.Add(rss2);
|
||||
printf("AddRss(%4d), AddRss(%4d): ", rss, rss2);
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == ((rss + rss2) >> 1),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
VerifyOrQuit(rssAverager.GetAverage() == ((rss + rss2) >> 1),
|
||||
"TestLinkQualityInfo failed - GetAverage() returned incorrect value.");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
PrintOutcome(rssAverager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,22 +266,22 @@ void TestRssAveraging(void)
|
||||
}
|
||||
|
||||
rss2 = rssValues[k];
|
||||
linkInfo.Clear();
|
||||
rssAverager.Reset();
|
||||
|
||||
for (i = 0; i < kNumRssAdds; i++)
|
||||
{
|
||||
linkInfo.AddRss(sNoiseFloor, rss);
|
||||
rssAverager.Add(rss);
|
||||
}
|
||||
|
||||
linkInfo.AddRss(sNoiseFloor, rss2);
|
||||
rssAverager.Add(rss2);
|
||||
printf("AddRss(%4d) %d times, AddRss(%4d): ", rss, kNumRssAdds, rss2);
|
||||
ave = linkInfo.GetAverageRss();
|
||||
ave = rssAverager.GetAverage();
|
||||
VerifyOrQuit(ave >= MIN_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
"TestLinkQualityInfo failed - GetAverage() returned incorrect value.");
|
||||
VerifyOrQuit(ave <= MAX_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
"TestLinkQualityInfo failed - GetAverage() returned incorrect value.");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
PrintOutcome(rssAverager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,26 +302,53 @@ void TestRssAveraging(void)
|
||||
}
|
||||
|
||||
rss2 = rssValues[k];
|
||||
linkInfo.Clear();
|
||||
rssAverager.Reset();
|
||||
|
||||
for (i = 0; i < kNumRssAdds; i++)
|
||||
{
|
||||
linkInfo.AddRss(sNoiseFloor, rss);
|
||||
linkInfo.AddRss(sNoiseFloor, rss2);
|
||||
ave = linkInfo.GetAverageRss();
|
||||
rssAverager.Add(rss);
|
||||
rssAverager.Add(rss2);
|
||||
ave = rssAverager.GetAverage();
|
||||
VerifyOrQuit(ave >= MIN_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is smaller than min value.");
|
||||
"TestLinkQualityInfo failed - GetAverage() is smaller than min value.");
|
||||
VerifyOrQuit(ave <= MAX_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is larger than min value.");
|
||||
"TestLinkQualityInfo failed - GetAverage() is larger than min value.");
|
||||
diff = ave;
|
||||
diff -= (rss + rss2) >> 1;
|
||||
VerifyOrQuit(ABS(diff) <= kRssAverageMaxDiff,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is incorrect");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
"TestLinkQualityInfo failed - GetAverage() is incorrect");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
}
|
||||
|
||||
printf("[AddRss(%4d), AddRss(%4d)] %d times: ", rss, rss2, kNumRssAdds);
|
||||
PrintOutcome(linkInfo);
|
||||
PrintOutcome(rssAverager);
|
||||
}
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// For the first 8 values the average should be the arithmetic mean.
|
||||
|
||||
printf("- - - - - - - - - - - - - - - - - -\n");
|
||||
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
double mean;
|
||||
|
||||
rssAverager.Reset();
|
||||
sum = 0;
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (j = 1; j <= 8; j++)
|
||||
{
|
||||
rss = GetRandomRss();
|
||||
rssAverager.Add(rss);
|
||||
sum += rss;
|
||||
mean = static_cast<double>(sum) / j;
|
||||
VerifyOrQuit(ABS(rssAverager.GetAverage() - mean) < 1, "Average does not match the arithmetic mean!");
|
||||
VerifyRawRssValue(rssAverager);
|
||||
printf("AddRss(%4d) sum=%-5d, mean=%-8.2f RssAverager=", rss, sum, mean);
|
||||
PrintOutcome(rssAverager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user