mirror of
https://github.com/espressif/openthread.git
synced 2026-09-12 04:00:10 +00:00
Enhance the calculation of link quality metrics (#197)
This commit adds a new class `LinkQualityInfo` which stores all relevant information about quality of a link, including average received signal strength (RSS), link margin, and link quality value. The RSS average is obtained using an adaptive exponential moving average filter. A unit-test is also added for the new class. The Neighbor class now includes an instance of LinkQualityInfo. The RSS average is updated from 'mac.cpp' whenever a valid/verified packet is received from the corresponding neighbor. The mesh_forwarder, mle_router, and mle modules are modified to use the new methods from the newly added class. This change addresses issue #175.
This commit is contained in:
committed by
Jonathan Hui
parent
3635bb9691
commit
cb33898827
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Nest Labs, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test_util.h"
|
||||
#include <openthread.h>
|
||||
#include <thread/link_quality.hpp>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace Thread {
|
||||
|
||||
extern"C" void otSignalTaskletPending(void)
|
||||
{
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
kMaxRssValue = 0,
|
||||
kMinRssValue = -128,
|
||||
|
||||
kStringBuffferSize = 80,
|
||||
|
||||
kRssAverageMaxDiff = 16,
|
||||
kNumRssAdds = 300,
|
||||
|
||||
kEncodedAverageBitShift = 3,
|
||||
kEncodedAverageMultiple = (1 << kEncodedAverageBitShift),
|
||||
kEncodedAverageBitMask = (1 << kEncodedAverageBitShift) - 1,
|
||||
};
|
||||
|
||||
#define MIN_RSS(_rss1, _rss2) (((_rss1) < (_rss2)) ? (_rss1) : (_rss2))
|
||||
#define MAX_RSS(_rss1, _rss2) (((_rss1) < (_rss2)) ? (_rss2) : (_rss1))
|
||||
#define ABS(value) (((value) >= 0) ? (value) : -(value))
|
||||
|
||||
// This struct contains RSS values and test data for checking link quality info calss.
|
||||
struct RssTestData
|
||||
{
|
||||
const int8_t *mRssList; // Array of RSS values.
|
||||
size_t mRssListSize; // Size of RSS list.
|
||||
uint8_t mExpectedLinkQuality; // Expected final link quality value.
|
||||
};
|
||||
|
||||
// Checks the encoded average RSS value to match the value from GetAverageRss().
|
||||
void VerifyEncodedRssValue(LinkQualityInfo &aLinkInfo)
|
||||
{
|
||||
int8_t rss = aLinkInfo.GetAverageRss();
|
||||
uint16_t encodedRss = aLinkInfo.GetAverageRssAsEncodedWord();
|
||||
|
||||
if (rss != LinkQualityInfo::kUnknownRss)
|
||||
{
|
||||
VerifyOrQuit(rss == -static_cast<int16_t>((encodedRss + (kEncodedAverageMultiple / 2)) >> kEncodedAverageBitShift),
|
||||
"TestLinkQualityInfo failed - Ecoded RSS does not match the value from GetAverageRss().");
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrQuit(encodedRss == 0,
|
||||
"TestLinkQualityInfo failed - Ecoded RSS does not match the value from GetAverageRss().");
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
SuccessOrQuit(aLinkInfo.GetAverageRssAsString(stringBuf, sizeof(stringBuf)),
|
||||
"TestLinkQualityInfo failed - GetAverageRssAsString() failed.");
|
||||
|
||||
printf("AveRss = %-4d, \"%-14s\", ", aLinkInfo.GetAverageRss(), stringBuf);
|
||||
printf("LinkMargin = %-4d, LinkQuality = %d", aLinkInfo.GetLinkMargin(), aLinkInfo.GetLinkQuality());
|
||||
|
||||
// This test-case succeeded.
|
||||
printf(" -> PASS\n");
|
||||
}
|
||||
|
||||
void TestLinkQualityData(RssTestData anRssData)
|
||||
{
|
||||
LinkQualityInfo linkInfo;
|
||||
int8_t rss, ave, min, max;
|
||||
size_t i;
|
||||
|
||||
printf("- - - - - - - - - - - - - - - - - -\n");
|
||||
min = kMinRssValue;
|
||||
max = kMaxRssValue;
|
||||
|
||||
for (i = 0; i < anRssData.mRssListSize; i++)
|
||||
{
|
||||
rss = anRssData.mRssList[i];
|
||||
min = MIN_RSS(rss, min);
|
||||
max = MAX_RSS(rss, max);
|
||||
linkInfo.AddRss(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);
|
||||
printf("%02u) AddRss(%4d): ", (unsigned int)i, rss);
|
||||
PrintOutcome(linkInfo);
|
||||
}
|
||||
|
||||
VerifyOrQuit(linkInfo.GetLinkQuality() == anRssData.mExpectedLinkQuality,
|
||||
"TestLinkQualityInfo failed - GetLinkQuality() is incorrect");
|
||||
}
|
||||
|
||||
void TestRssAveraging(void)
|
||||
{
|
||||
LinkQualityInfo linkInfo;
|
||||
int8_t rss, rss2, ave;
|
||||
int16_t diff;
|
||||
size_t i, j, k;
|
||||
const int8_t rssValues[] = { kMinRssValue, -70, -40, -41, -10, kMaxRssValue};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Values after initialization.
|
||||
|
||||
printf("\nAfter Initialization: ");
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == LinkQualityInfo::kUnknownRss,
|
||||
"TestLinkQualityInfo failed - Inital value from GetAverageRss() is incorrect.");
|
||||
VerifyOrQuit(linkInfo.GetLinkMargin() == 0,
|
||||
"TestLinkQualityInfo failed - Inital value for link margin is incorrect.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Adding a single value
|
||||
rss = -70;
|
||||
printf("AddRss(%d): ", rss);
|
||||
linkInfo.AddRss(rss);
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == rss,
|
||||
"TestLinkQualityInfo - GetAverageRss() failed after a single AddRss().");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Clear
|
||||
|
||||
printf("Clear(): ");
|
||||
linkInfo.Clear();
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == LinkQualityInfo::kUnknownRss,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() after Clear() is incorrect.");
|
||||
VerifyOrQuit(linkInfo.GetLinkMargin() == 0,
|
||||
"TestLinkQualityInfo failed - link margin value after Clear() is incorrect.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Adding the same value many times.
|
||||
|
||||
printf("- - - - - - - - - - - - - - - - - -\n");
|
||||
|
||||
for (j = 0; j < sizeof(rssValues); j++)
|
||||
{
|
||||
linkInfo.Clear();
|
||||
rss = rssValues[j];
|
||||
printf("AddRss(%4d) %d times: ", rss, kNumRssAdds);
|
||||
|
||||
for (i = 0; i < kNumRssAdds; i++)
|
||||
{
|
||||
linkInfo.AddRss(rss);
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == rss,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
}
|
||||
|
||||
PrintOutcome(linkInfo);
|
||||
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Adding two RSS values:
|
||||
|
||||
printf("- - - - - - - - - - - - - - - - - -\n");
|
||||
|
||||
for (j = 0; j < sizeof(rssValues); j++)
|
||||
{
|
||||
rss = rssValues[j];
|
||||
|
||||
for (k = 0; k < sizeof(rssValues); k++)
|
||||
{
|
||||
if (k == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rss2 = rssValues[k];
|
||||
linkInfo.Clear();
|
||||
linkInfo.AddRss(rss);
|
||||
linkInfo.AddRss(rss2);
|
||||
printf("AddRss(%4d), AddRss(%4d): ", rss, rss2);
|
||||
VerifyOrQuit(linkInfo.GetAverageRss() == ((rss + rss2) >> 1),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
}
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Adding one value many times and a different value once:
|
||||
|
||||
printf("- - - - - - - - - - - - - - - - - -\n");
|
||||
|
||||
for (j = 0; j < sizeof(rssValues); j++)
|
||||
{
|
||||
rss = rssValues[j];
|
||||
|
||||
for (k = 0; k < sizeof(rssValues); k++)
|
||||
{
|
||||
if (k == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rss2 = rssValues[k];
|
||||
linkInfo.Clear();
|
||||
|
||||
for (i = 0; i < kNumRssAdds; i++)
|
||||
{
|
||||
linkInfo.AddRss(rss);
|
||||
}
|
||||
|
||||
linkInfo.AddRss(rss2);
|
||||
printf("AddRss(%4d) %d times, AddRss(%4d): ", rss, kNumRssAdds, rss2);
|
||||
ave = linkInfo.GetAverageRss();
|
||||
VerifyOrQuit(ave >= MIN_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
VerifyOrQuit(ave <= MAX_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() returned incorrect value.");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
PrintOutcome(linkInfo);
|
||||
}
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Adding two alteraing values many times:
|
||||
|
||||
printf("- - - - - - - - - - - - - - - - - -\n");
|
||||
|
||||
for (j = 0; j < sizeof(rssValues); j++)
|
||||
{
|
||||
rss = rssValues[j];
|
||||
|
||||
for (k = 0; k < sizeof(rssValues); k++)
|
||||
{
|
||||
if (k == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rss2 = rssValues[k];
|
||||
linkInfo.Clear();
|
||||
|
||||
for (i = 0; i < kNumRssAdds; i++)
|
||||
{
|
||||
linkInfo.AddRss(rss);
|
||||
linkInfo.AddRss(rss2);
|
||||
ave = linkInfo.GetAverageRss();
|
||||
VerifyOrQuit(ave >= MIN_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is smaller than min value.");
|
||||
VerifyOrQuit(ave <= MAX_RSS(rss, rss2),
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is larger than min value.");
|
||||
diff = ave;
|
||||
diff -= (rss + rss2) >> 1;
|
||||
VerifyOrQuit(ABS(diff) <= kRssAverageMaxDiff,
|
||||
"TestLinkQualityInfo failed - GetAverageRss() is incorrect");
|
||||
VerifyEncodedRssValue(linkInfo);
|
||||
}
|
||||
|
||||
printf("[AddRss(%4d), AddRss(%4d)] %d times: ", rss, rss2, kNumRssAdds);
|
||||
PrintOutcome(linkInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestLinkQualityCalculations(void)
|
||||
{
|
||||
const int8_t rssList1[] = { -81, -80, -79, -78, -76, -80, -77, -75, -77, -76, -77, -74};
|
||||
const RssTestData rssData1 =
|
||||
{
|
||||
rssList1, // mRssList
|
||||
sizeof(rssList1), // mRssListSize
|
||||
3 // mExpectedLinkQuality
|
||||
};
|
||||
|
||||
const int8_t rssList2[] = { -90, -80, -85 };
|
||||
const RssTestData rssData2 =
|
||||
{
|
||||
rssList2, // mRssList
|
||||
sizeof(rssList2), // mRssListSize
|
||||
2 // mExpectedLinkQuality
|
||||
};
|
||||
|
||||
const int8_t rssList3[] = { -95, -96, -98, -99, -100, -100, -98, -99, -100, -100, -100, -100, -100 };
|
||||
const RssTestData rssData3 =
|
||||
{
|
||||
rssList3, // mRssList
|
||||
sizeof(rssList3), // mRssListSize
|
||||
0 // mExpectedLinkQuality
|
||||
};
|
||||
|
||||
const int8_t rssList4[] = { -75, -100, -100, -100, -100, -100, -95, -92, -93, -94, -93, -93 };
|
||||
const RssTestData rssData4 =
|
||||
{
|
||||
rssList4, // mRssList
|
||||
sizeof(rssList4), // mRssListSize
|
||||
1 // mExpectedLinkQuality
|
||||
};
|
||||
|
||||
TestLinkQualityData(rssData1);
|
||||
TestLinkQualityData(rssData2);
|
||||
TestLinkQualityData(rssData3);
|
||||
TestLinkQualityData(rssData4);
|
||||
}
|
||||
|
||||
} // namespace Thread
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Thread::TestRssAveraging();
|
||||
Thread::TestLinkQualityCalculations();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user