From fa81b21f4c861d2bcf02e101787557d36c67d7b7 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Wed, 31 May 2023 13:31:14 +0800 Subject: [PATCH] [link-quality] fix corner case of `ScaleRawValueToRssi` (#9102) Currently if we call `ScaleRawValueToRssi` with value 0 or 1, the result is incorrect. Because it tries to static_cast `-130` or `-129` to `int8_t`. I think it's not worthwhile to widen int8_t to int16_t only for the 2 corner cases. So I prefer returning the smallest value -128 for the 2 cases. --- src/core/common/num_utils.hpp | 23 +++++++++++++++++++++++ src/core/thread/link_metrics.cpp | 2 +- tests/unit/test_link_quality.cpp | 7 +++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/core/common/num_utils.hpp b/src/core/common/num_utils.hpp index 6e4b81e6c..598324098 100644 --- a/src/core/common/num_utils.hpp +++ b/src/core/common/num_utils.hpp @@ -131,6 +131,29 @@ template uint16_t ClampToUint16(UintType aValue) return static_cast(Min(aValue, static_cast(NumericLimits::kMax))); } +/** + * Returns a clamped version of given integer to a `int8_t`. + * + * If @p aValue is smaller than min value of a `int8_t`, the min value of `int8_t` is returned. + * If @p aValue is larger than max value of a `int8_t`, the max value of `int8_t` is returned. + * + * @tparam IntType The value type (MUST be `int16_t`, `int32_t`, or `int64_t`). + * + * @param[in] aValue The value to clamp. + * + * @returns The clamped version of @p aValue to `int8_t`. + * + */ +template int8_t ClampToInt8(IntType aValue) +{ + static_assert(TypeTraits::IsSame::kValue || TypeTraits::IsSame::kValue || + TypeTraits::IsSame::kValue, + "IntType must be `int16_t, `int32_t`, or `int64_t`"); + + return static_cast(Clamp(aValue, static_cast(NumericLimits::kMin), + static_cast(NumericLimits::kMax))); +} + /** * This template function performs a three-way comparison between two values. * diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index cfe784c4f..12e7d4a1c 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -812,7 +812,7 @@ int8_t ScaleRawValueToRssi(uint8_t aRawValue) value = DivideAndRoundToClosest(value, NumericLimits::kMax); value += kMinRssi; - return static_cast(value); + return ClampToInt8(value); } } // namespace LinkMetrics diff --git a/tests/unit/test_link_quality.cpp b/tests/unit/test_link_quality.cpp index 2562ec8ef..8070abe52 100644 --- a/tests/unit/test_link_quality.cpp +++ b/tests/unit/test_link_quality.cpp @@ -518,6 +518,13 @@ public: VerifyOrQuit(LinkMetrics::ScaleRssiToRawValue(1) == 255); VerifyOrQuit(LinkMetrics::ScaleRssiToRawValue(10) == 255); VerifyOrQuit(LinkMetrics::ScaleRssiToRawValue(127) == 255); + + // Test corner case of ScaleRawValueToRssi + for (uint8_t rawValue = 0; rawValue < 2; rawValue++) + { + int8_t rssi = LinkMetrics::ScaleRawValueToRssi(rawValue); + printf("\nRaw Value: %u -> RSSI : %-3d", rawValue, rssi); + } } };