From fcc9c7b70af2adb3db11acb8cd4848bc55259eb3 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 22 Dec 2022 14:55:29 -0800 Subject: [PATCH] [cli] add new command `neighbor linkquality` (#8508) This commit adds a new CLI command `neighbor linkqulaity` which prints the collected link quality info (such as frame error rate, message error rate, average/last RSSI) for all neighbors. --- src/cli/README.md | 13 +++++++++++++ src/cli/cli.cpp | 36 +++++++++++++++++++++++++++++++----- src/cli/cli_output.cpp | 12 ++++++++++++ src/cli/cli_output.hpp | 28 +++++++++++++++++++++++++++- 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/cli/README.md b/src/cli/README.md index df8a75327..4287798ed 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -2061,6 +2061,19 @@ Get the NAT64 translator packet and error counters. Done ``` +### neighbor linkquality + +Print link quality info for all neighbors. + +```bash +> neighbor linkquality +| RLOC16 | Extended MAC | Frame Error | Msg Error | Avg RSS | Last RSS | Age | ++--------+------------------+-------------+-----------+---------+----------+-------+ +| 0xe800 | 9e2fa4e1b84f92db | 0.00 % | 0.00 % | -46 | -48 | 1 | +| 0xc001 | 0ad7ed6beaa6016d | 4.67 % | 0.08 % | -68 | -72 | 10 | +Done +``` + ### neighbor list List RLOC16 of neighbors. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index d35bf3e12..fea81b9ac 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -1768,9 +1768,11 @@ template <> otError Interpreter::Process(Arg aArgs[]) OutputLine("count: %lu", ToUlong(otChannelMonitorGetSampleCount(GetInstancePtr()))); OutputLine("occupancies:"); + for (uint8_t channel = 0; channel < channelNum; channel++) { - uint32_t occupancy = 0; + uint16_t occupancy; + PercentageStringBuffer stringBuffer; if (!((1UL << channel) & channelMask)) { @@ -1779,11 +1781,10 @@ template <> otError Interpreter::Process(Arg aArgs[]) occupancy = otChannelMonitorGetChannelOccupancy(GetInstancePtr(), channel); - OutputFormat("ch %u (0x%04lx) ", channel, ToUlong(occupancy)); - occupancy = (occupancy * 10000) / 0xffff; - OutputLine("%2u.%02u%% busy", static_cast(occupancy / 100), - static_cast(occupancy % 100)); + OutputLine("ch %u (0x%04x) %6s%% busy", channel, occupancy, + PercentageToString(occupancy, stringBuffer)); } + OutputNewLine(); } } @@ -4987,6 +4988,31 @@ template <> otError Interpreter::Process(Arg aArgs[]) OutputNewLine(); } + else if (aArgs[0] == "linkquality") + { + static const char *const kLinkQualityTableTitles[] = { + "RLOC16", "Extended MAC", "Frame Error", "Msg Error", "Avg RSS", "Last RSS", "Age", + }; + + static const uint8_t kLinkQualityTableColumnWidths[] = { + 8, 18, 13, 11, 9, 10, 7, + }; + + OutputTableHeader(kLinkQualityTableTitles, kLinkQualityTableColumnWidths); + + while (otThreadGetNextNeighborInfo(GetInstancePtr(), &iterator, &neighborInfo) == OT_ERROR_NONE) + { + PercentageStringBuffer stringBuffer; + + OutputFormat("| 0x%04x | ", neighborInfo.mRloc16); + OutputExtAddress(neighborInfo.mExtAddress); + OutputFormat(" | %9s %% ", PercentageToString(neighborInfo.mFrameErrorRate, stringBuffer)); + OutputFormat("| %7s %% ", PercentageToString(neighborInfo.mMessageErrorRate, stringBuffer)); + OutputFormat("| %7d ", neighborInfo.mAverageRssi); + OutputFormat("| %8d ", neighborInfo.mLastRssi); + OutputLine("| %5lu |", ToUlong(neighborInfo.mAge)); + } + } else { error = OT_ERROR_INVALID_ARGS; diff --git a/src/cli/cli_output.cpp b/src/cli/cli_output.cpp index bdc6e9fbb..c70eacdd2 100644 --- a/src/cli/cli_output.cpp +++ b/src/cli/cli_output.cpp @@ -261,6 +261,18 @@ void Output::OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength) OutputFormat("]"); } + +const char *Output::PercentageToString(uint16_t aValue, PercentageStringBuffer &aBuffer) +{ + uint32_t scaledValue = aValue; + StringWriter writer(aBuffer.mChars, sizeof(aBuffer.mChars)); + + scaledValue = (scaledValue * 10000) / 0xffff; + writer.Append("%u.%02u", static_cast(scaledValue / 100), static_cast(scaledValue % 100)); + + return aBuffer.mChars; +} + #endif // OPENTHREAD_FTD || OPENTHREAD_MTD void Output::OutputFormatV(const char *aFormat, va_list aArguments) { mImplementer.OutputV(aFormat, aArguments); } diff --git a/src/cli/cli_output.hpp b/src/cli/cli_output.hpp index d617330f2..1c46935dc 100644 --- a/src/cli/cli_output.hpp +++ b/src/cli/cli_output.hpp @@ -204,7 +204,7 @@ public: otInstance *GetInstancePtr(void) { return mInstance; } /** - * This structure represents a buffer which is sued when converting a `uint64` value to string in decimal format. + * This structure represents a buffer which is used when converting a `uint64` value to string in decimal format. * */ struct Uint64StringBuffer @@ -440,6 +440,32 @@ public: */ void OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength); + /** + * This structure represents a buffer which is used when converting an encoded rate value to percentage string. + * + */ + struct PercentageStringBuffer + { + static constexpr uint16_t kSize = 7; ///< Size of a buffer + + char mChars[kSize]; ///< Char array (do not access the array directly). + }; + + /** + * This static method converts an encoded value to a percentage representation. + * + * The encoded @p aValue is assumed to be linearly scaled such that `0` maps to 0% and `0xffff` maps to 100%. + * + * The resulting string provides two decimal accuracy, e.g., "100.00", "0.00", "75.37". + * + * @param[in] aValue The encoded percentage value to convert. + * @param[in] aBuffer A buffer to allocate the string from. + * + * @returns A pointer to the start of the string (null-terminated) representation of @p aValue. + * + */ + static const char *PercentageToString(uint16_t aValue, PercentageStringBuffer &aBuffer); + #endif // OPENTHREAD_FTD || OPENTHREAD_MTD /**