From 727002e9fe1da6d5fc1464a539268a931fde1df3 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 7 Nov 2022 00:35:27 -0800 Subject: [PATCH] [cli] add `OutputUint64()` for 64-bit integer value in decimal format (#8354) This commit also adds a helper `Uint64ToString()` method to convert a `uint64_t` to decimal format string. The new methods allow us to output `uint64_t` values without needing to cast to `unsigned long long` and/or use of `%llu` (which may not be provided by certain embedded libraries). --- src/cli/cli.cpp | 92 +++++++++++++++++++++++------------- src/cli/cli_commissioner.cpp | 4 +- src/cli/cli_dataset.cpp | 10 ++-- src/cli/cli_joiner.cpp | 11 ++++- src/cli/cli_output.cpp | 34 +++++++++++++ src/cli/cli_output.hpp | 38 +++++++++++++++ 6 files changed, 149 insertions(+), 40 deletions(-) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 146654552..e1d5d2a93 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -876,45 +876,47 @@ template <> otError Interpreter::Process(Arg aArgs[]) otNat64InitAddressMappingIterator(GetInstancePtr(), &iterator); while (otNat64GetNextAddressMapping(GetInstancePtr(), &iterator, &mapping) == OT_ERROR_NONE) { - char ip4AddressString[OT_IP4_ADDRESS_STRING_SIZE]; - char ip6AddressString[OT_IP6_PREFIX_STRING_SIZE]; + char ip4AddressString[OT_IP4_ADDRESS_STRING_SIZE]; + char ip6AddressString[OT_IP6_PREFIX_STRING_SIZE]; + Uint64StringBuffer u64StringBuffer; otIp6AddressToString(&mapping.mIp6, ip6AddressString, sizeof(ip6AddressString)); otIp4AddressToString(&mapping.mIp4, ip4AddressString, sizeof(ip4AddressString)); - OutputFormat("| %016llx ", mapping.mId); + OutputFormat("| %08lx%08lx ", ToUlong(static_cast(mapping.mId >> 32)), + ToUlong(static_cast(mapping.mId & 0xffffffff))); OutputFormat("| %40s ", ip6AddressString); OutputFormat("| %16s ", ip4AddressString); - OutputFormat("| %5llus ", mapping.mRemainingTimeMs / 1000); - OutputFormat("| %8llu ", mapping.mCounters.mTotal.m4To6Packets); - OutputFormat("| %12llu ", mapping.mCounters.mTotal.m4To6Bytes); - OutputFormat("| %8llu ", mapping.mCounters.mTotal.m6To4Packets); - OutputFormat("| %12llu ", mapping.mCounters.mTotal.m6To4Bytes); + OutputFormat("| %5lus ", ToUlong(mapping.mRemainingTimeMs / 1000)); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mTotal.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mTotal.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mTotal.m6To4Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mTotal.m6To4Bytes, u64StringBuffer)); OutputLine("|"); OutputFormat("| %016s ", ""); OutputFormat("| %68s ", "TCP"); - OutputFormat("| %8llu ", mapping.mCounters.mTcp.m4To6Packets); - OutputFormat("| %12llu ", mapping.mCounters.mTcp.m4To6Bytes); - OutputFormat("| %8llu ", mapping.mCounters.mTcp.m6To4Packets); - OutputFormat("| %12llu ", mapping.mCounters.mTcp.m6To4Bytes); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mTcp.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mTcp.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mTcp.m6To4Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mTcp.m6To4Bytes, u64StringBuffer)); OutputLine("|"); OutputFormat("| %016s ", ""); OutputFormat("| %68s ", "UDP"); - OutputFormat("| %8llu ", mapping.mCounters.mUdp.m4To6Packets); - OutputFormat("| %12llu ", mapping.mCounters.mUdp.m4To6Bytes); - OutputFormat("| %8llu ", mapping.mCounters.mUdp.m6To4Packets); - OutputFormat("| %12llu ", mapping.mCounters.mUdp.m6To4Bytes); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mUdp.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mUdp.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mUdp.m6To4Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mUdp.m6To4Bytes, u64StringBuffer)); OutputLine("|"); OutputFormat("| %016s ", ""); OutputFormat("| %68s ", "ICMP"); - OutputFormat("| %8llu ", mapping.mCounters.mIcmp.m4To6Packets); - OutputFormat("| %12llu ", mapping.mCounters.mIcmp.m4To6Bytes); - OutputFormat("| %8llu ", mapping.mCounters.mIcmp.m6To4Packets); - OutputFormat("| %12llu ", mapping.mCounters.mIcmp.m6To4Bytes); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mIcmp.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mIcmp.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(mapping.mCounters.mIcmp.m6To4Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(mapping.mCounters.mIcmp.m6To4Bytes, u64StringBuffer)); OutputLine("|"); } } @@ -979,6 +981,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) otNat64ProtocolCounters counters; otNat64ErrorCounters errorCounters; + Uint64StringBuffer u64StringBuffer; OutputTableHeader(kNat64CounterTableHeader, kNat64CounterTableHeaderColumns); OutputTableHeader(kNat64CounterTableSubHeader, kNat64CounterTableSubHeaderColumns); @@ -986,20 +989,36 @@ template <> otError Interpreter::Process(Arg aArgs[]) otNat64GetCounters(GetInstancePtr(), &counters); otNat64GetErrorCounters(GetInstancePtr(), &errorCounters); - OutputLine("| %13s | %8llu | %12llu | %8llu | %12llu |", "Total", counters.mTotal.m4To6Packets, - counters.mTotal.m4To6Bytes, counters.mTotal.m6To4Packets, counters.mTotal.m6To4Bytes); - OutputLine("| %13s | %8llu | %12llu | %8llu | %12llu |", "TCP", counters.mTcp.m4To6Packets, - counters.mTcp.m4To6Bytes, counters.mTcp.m6To4Packets, counters.mTcp.m6To4Bytes); - OutputLine("| %13s | %8llu | %12llu | %8llu | %12llu |", "UDP", counters.mUdp.m4To6Packets, - counters.mUdp.m4To6Bytes, counters.mUdp.m6To4Packets, counters.mUdp.m6To4Bytes); - OutputLine("| %13s | %8llu | %12llu | %8llu | %12llu |", "ICMP", counters.mIcmp.m4To6Packets, - counters.mIcmp.m4To6Bytes, counters.mIcmp.m6To4Packets, counters.mIcmp.m6To4Bytes); + OutputFormat("| %13s ", "Total"); + OutputFormat("| %8s ", Uint64ToString(counters.mTotal.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(counters.mTotal.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(counters.mTotal.m6To4Packets, u64StringBuffer)); + OutputLine("| %12s |", Uint64ToString(counters.mTotal.m6To4Bytes, u64StringBuffer)); + + OutputFormat("| %13s ", "TCP"); + OutputFormat("| %8s ", Uint64ToString(counters.mTcp.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(counters.mTcp.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(counters.mTcp.m6To4Packets, u64StringBuffer)); + OutputLine("| %12s |", Uint64ToString(counters.mTcp.m6To4Bytes, u64StringBuffer)); + + OutputFormat("| %13s ", "UDP"); + OutputFormat("| %8s ", Uint64ToString(counters.mUdp.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(counters.mUdp.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(counters.mUdp.m6To4Packets, u64StringBuffer)); + OutputLine("| %12s |", Uint64ToString(counters.mUdp.m6To4Bytes, u64StringBuffer)); + + OutputFormat("| %13s ", "ICMP"); + OutputFormat("| %8s ", Uint64ToString(counters.mIcmp.m4To6Packets, u64StringBuffer)); + OutputFormat("| %12s ", Uint64ToString(counters.mIcmp.m4To6Bytes, u64StringBuffer)); + OutputFormat("| %8s ", Uint64ToString(counters.mIcmp.m6To4Packets, u64StringBuffer)); + OutputLine("| %12s |", Uint64ToString(counters.mIcmp.m6To4Bytes, u64StringBuffer)); OutputTableHeader(kNat64CounterTableErrorSubHeader, kNat64CounterTableErrorSubHeaderColumns); for (uint8_t i = 0; i < OT_NAT64_DROP_REASON_COUNT; i++) { - OutputLine("| %13s | %23llu | %23llu |", kNat64CounterErrorType[i], errorCounters.mCount4To6[i], - errorCounters.mCount6To4[i]); + OutputFormat("| %13s | %23s ", kNat64CounterErrorType[i], + Uint64ToString(errorCounters.mCount4To6[i], u64StringBuffer)); + OutputLine("| %23s |", Uint64ToString(errorCounters.mCount6To4[i], u64StringBuffer)); } } #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE @@ -2652,9 +2671,12 @@ template <> otError Interpreter::Process(Arg aArgs[]) for (const MleTimeCounterName &counter : kTimeCounterNames) { - OutputLine("Time %s Milli: %lu", counter.mName, mleCounters->*counter.mValuePtr); + OutputFormat("Time %s Milli: ", counter.mName); + OutputUint64Line(mleCounters->*counter.mValuePtr); } - OutputLine("Time Tracked Milli: %lu", mleCounters->mTrackedTime); + + OutputFormat("Time Tracked Milli: "); + OutputUint64Line(mleCounters->mTrackedTime); } #endif } @@ -5076,7 +5098,9 @@ template <> otError Interpreter::Process(Arg aArgs[]) networkTimeStatus = otNetworkTimeGet(GetInstancePtr(), &time); - OutputFormat("Network Time: %luus", time); + OutputFormat("Network Time: "); + OutputUint64(time); + OutputFormat("us"); switch (networkTimeStatus) { @@ -6336,7 +6360,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) } else if (aArgs[0] == "ms") { - OutputLine("%lu", otInstanceGetUptime(GetInstancePtr())); + OutputUint64Line(otInstanceGetUptime(GetInstancePtr())); } else { diff --git a/src/cli/cli_commissioner.cpp b/src/cli/cli_commissioner.cpp index bbbcfceb2..c1b842663 100644 --- a/src/cli/cli_commissioner.cpp +++ b/src/cli/cli_commissioner.cpp @@ -117,7 +117,9 @@ template <> otError Commissioner::Process(Arg aArgs[]) break; case OT_JOINER_INFO_TYPE_DISCERNER: - OutputFormat("| 0x%016llx/%2u", static_cast(joinerInfo.mSharedId.mDiscerner.mValue), + OutputFormat("| 0x%08lx%08lx/%2u", + static_cast(joinerInfo.mSharedId.mDiscerner.mValue >> 32), + static_cast(joinerInfo.mSharedId.mDiscerner.mValue & 0xffffffff), joinerInfo.mSharedId.mDiscerner.mLength); break; } diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index 9d4caf3b6..b1def8968 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -51,12 +51,14 @@ otError Dataset::Print(otOperationalDataset &aDataset) { if (aDataset.mComponents.mIsPendingTimestampPresent) { - OutputLine("Pending Timestamp: %lu", aDataset.mPendingTimestamp.mSeconds); + OutputFormat("Pending Timestamp: "); + OutputUint64Line(aDataset.mPendingTimestamp.mSeconds); } if (aDataset.mComponents.mIsActiveTimestampPresent) { - OutputLine("Active Timestamp: %lu", aDataset.mActiveTimestamp.mSeconds); + OutputFormat("Active Timestamp: "); + OutputUint64Line(aDataset.mActiveTimestamp.mSeconds); } if (aDataset.mComponents.mIsChannelPresent) @@ -264,7 +266,7 @@ template <> otError Dataset::Process(Arg aArgs[]) { if (sDataset.mComponents.mIsActiveTimestampPresent) { - OutputLine("%lu", sDataset.mActiveTimestamp.mSeconds); + OutputUint64Line(sDataset.mActiveTimestamp.mSeconds); } } else @@ -666,7 +668,7 @@ template <> otError Dataset::Process(Arg aArgs[]) { if (sDataset.mComponents.mIsPendingTimestampPresent) { - OutputLine("%lu", sDataset.mPendingTimestamp.mSeconds); + OutputUint64Line(sDataset.mPendingTimestamp.mSeconds); } } else diff --git a/src/cli/cli_joiner.cpp b/src/cli/cli_joiner.cpp index 82d0d3765..24b20ac38 100644 --- a/src/cli/cli_joiner.cpp +++ b/src/cli/cli_joiner.cpp @@ -62,7 +62,16 @@ template <> otError Joiner::Process(Arg aArgs[]) VerifyOrExit(discerner != nullptr, error = OT_ERROR_NOT_FOUND); - OutputLine("0x%llx/%u", static_cast(discerner->mValue), discerner->mLength); + if (discerner->mValue <= 0xffffffff) + { + OutputLine("0x%lx/%u", static_cast(discerner->mValue & 0xffffffff), discerner->mLength); + } + else + { + OutputLine("0x%lx%08lx/%u", static_cast(discerner->mValue >> 32), + static_cast(discerner->mValue & 0xffffffff), discerner->mLength); + } + error = OT_ERROR_NONE; } else diff --git a/src/cli/cli_output.cpp b/src/cli/cli_output.cpp index 7d383951c..dfbbf5583 100644 --- a/src/cli/cli_output.cpp +++ b/src/cli/cli_output.cpp @@ -127,6 +127,40 @@ void Output::OutputBytesLine(const uint8_t *aBytes, uint16_t aLength) OutputLine(""); } +const char *Output::Uint64ToString(uint64_t aUint64, Uint64StringBuffer &aBuffer) +{ + char *cur = &aBuffer.mChars[Uint64StringBuffer::kSize - 1]; + + *cur = '\0'; + + if (aUint64 == 0) + { + *(--cur) = '0'; + } + else + { + for (; aUint64 != 0; aUint64 /= 10) + { + *(--cur) = static_cast('0' + static_cast(aUint64 % 10)); + } + } + + return cur; +} + +void Output::OutputUint64(uint64_t aUint64) +{ + Uint64StringBuffer buffer; + + OutputFormat("%s", Uint64ToString(aUint64, buffer)); +} + +void Output::OutputUint64Line(uint64_t aUint64) +{ + OutputUint64(aUint64); + OutputLine(""); +} + void Output::OutputEnabledDisabledStatus(bool aEnabled) { OutputLine(aEnabled ? "Enabled" : "Disabled"); diff --git a/src/cli/cli_output.hpp b/src/cli/cli_output.hpp index d99fe4458..32216073c 100644 --- a/src/cli/cli_output.hpp +++ b/src/cli/cli_output.hpp @@ -202,6 +202,28 @@ public: */ otInstance *GetInstancePtr(void) { return mInstance; } + /** + * This structure represents a buffer which is sued when converting a `uint64` value to string in decimal format. + * + */ + struct Uint64StringBuffer + { + static constexpr uint16_t kSize = 21; ///< Size of a buffer + + char mChars[kSize]; ///< Char array (do not access the array directly). + }; + + /** + * This static method converts a `uint64_t` value to a decimal format string. + * + * @param[in] aUint64 The `uint64_t` 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 aUint64. + * + */ + static const char *Uint64ToString(uint64_t aUint64, Uint64StringBuffer &aBuffer); + /** * This method delivers a formatted output string to the CLI console. * @@ -312,6 +334,22 @@ public: */ void OutputExtAddressLine(const otExtAddress &aExtAddress) { OutputBytesLine(aExtAddress.m8); } + /** + * This method outputs a `uint64_t` value in decimal format. + * + * @param[in] aUint64 The `uint64_t` value to output. + * + */ + void OutputUint64(uint64_t aUint64); + + /** + * This method outputs a `uint64_t` value in decimal format and at the end it also outputs newline "\r\n". + * + * @param[in] aUint64 The `uint64_t` value to output. + * + */ + void OutputUint64Line(uint64_t aUint64); + /** * This method outputs "Enabled" or "Disabled" status to the CLI console (it also appends newline "\r\n"). *