From 2fbecc50d225f8856dac3881da3369b1ea88dc0f Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Wed, 26 Jun 2024 13:06:14 +0800 Subject: [PATCH] [posix] add rcp capability diag command to check the Spinel interface speed --- src/lib/spinel/radio_spinel.cpp | 6 ++ src/lib/spinel/radio_spinel.hpp | 9 +++ src/posix/platform/README_RCP_CAPS_DIAG.md | 11 +++ src/posix/platform/rcp_caps_diag.cpp | 86 ++++++++++++++++++++++ src/posix/platform/rcp_caps_diag.hpp | 9 +++ 5 files changed, 121 insertions(+) diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp index 605d1debaa1f..ae2622e696cc 100644 --- a/src/lib/spinel/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel.cpp @@ -1771,6 +1771,12 @@ void RadioSpinel::SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void mOutputContext = aContext; } +void RadioSpinel::GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, void *&aContext) +{ + aCallback = mOutputCallback; + aContext = mOutputContext; +} + otError RadioSpinel::PlatDiagProcess(const char *aString) { return Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString); diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index 4d30ff893fce..62027c2d8869 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -695,6 +695,15 @@ class RadioSpinel : private Logger * */ void SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext); + + /** + * Gets the diag output callback. + * + * @param[out] aCallback A reference to a function that is called on outputting diag messages. + * @param[out] aContext A reference to the user context. + * + */ + void GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, void *&aContext); #endif /** diff --git a/src/posix/platform/README_RCP_CAPS_DIAG.md b/src/posix/platform/README_RCP_CAPS_DIAG.md index c4f675f6ee98..782354b831ac 100644 --- a/src/posix/platform/README_RCP_CAPS_DIAG.md +++ b/src/posix/platform/README_RCP_CAPS_DIAG.md @@ -8,6 +8,7 @@ This module provides diag commands for checking RCP capabilities. - [capflags](#capflags) - [spinel](#spinel) +- [spinelspeed](#spinelspeed) ## Command Details @@ -112,3 +113,13 @@ PROP_VALUE_SET PHY_TX_POWER ------------------------------- OK PROP_VALUE_SET RADIO_COEX_ENABLE -------------------------- OK Done ``` + +### spinelspeed + +Check the speed of Spinel interface. + +```bash +> diag rcpcaps spinelspeed +SpinelSpeed ----------------------------------------------- 34414843 bps +Done +``` diff --git a/src/posix/platform/rcp_caps_diag.cpp b/src/posix/platform/rcp_caps_diag.cpp index 7a2242e38ec5..86d3e507c3db 100644 --- a/src/posix/platform/rcp_caps_diag.cpp +++ b/src/posix/platform/rcp_caps_diag.cpp @@ -461,6 +461,10 @@ otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength) { ProcessSpinel(); } + else if (strcmp(aArgs[1], "spinelspeed") == 0) + { + ProcessSpinelSpeed(); + } else { error = OT_ERROR_INVALID_COMMAND; @@ -616,6 +620,88 @@ bool RcpCapsDiag::IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_s return ret; } +void RcpCapsDiag::HandleDiagOutput(const char *aFormat, va_list aArguments, void *aContext) +{ + static_cast(aContext)->HandleDiagOutput(aFormat, aArguments); +} + +void RcpCapsDiag::HandleDiagOutput(const char *aFormat, va_list aArguments) +{ + int rval; + + VerifyOrExit(mDiagOutput != nullptr && mDiagOutputLength != 0); + rval = vsnprintf(mDiagOutput, mDiagOutputLength, aFormat, aArguments); + VerifyOrExit(rval >= 0); + + rval = (rval > mDiagOutputLength) ? mDiagOutputLength : rval; + mDiagOutput += rval; + mDiagOutputLength -= rval; + +exit: + return; +} + +void RcpCapsDiag::ProcessSpinelSpeed(void) +{ + static constexpr uint32_t kUsPerSec = 1000000; + static constexpr uint8_t kBitsPerByte = 8; + static constexpr uint8_t kSpinelHeaderSize = 4; + static constexpr uint8_t kZeroTerminatorSize = 1; + static const char *const kEchoCmd = "echo "; + static constexpr uint8_t kEchoPayloadLength = 200; + static constexpr uint8_t kNumTests = 100; + + otError error = OT_ERROR_NONE; + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {0}; + char output[OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE]; + uint16_t i; + uint16_t echoPayloadLength; + uint64_t startTimestamp; + uint64_t endTimestamp; + uint64_t sumTime = 0; + uint64_t sumLength = 0; + uint64_t speed; + otPlatDiagOutputCallback callback; + void *context; + + mRadioSpinel.GetDiagOutputCallback(callback, context); + mRadioSpinel.SetDiagOutputCallback(HandleDiagOutput, this); + + strncpy(cmd, kEchoCmd, sizeof(cmd) - 1); + echoPayloadLength = sizeof(cmd) - strlen(cmd) - 1; + echoPayloadLength = (kEchoPayloadLength < echoPayloadLength) ? kEchoPayloadLength : echoPayloadLength; + memset(cmd + strlen(cmd), '1', echoPayloadLength); + + for (i = 0; i < kNumTests; i++) + { + output[0] = '\0'; + mDiagOutput = output; + mDiagOutputLength = sizeof(output); + startTimestamp = otPlatTimeGet(); + + SuccessOrExit(error = mRadioSpinel.PlatDiagProcess(cmd)); + + endTimestamp = otPlatTimeGet(); + sumTime += endTimestamp - startTimestamp; + sumLength += kSpinelHeaderSize + strlen(cmd) + kZeroTerminatorSize + kSpinelHeaderSize + strlen(output) + + kZeroTerminatorSize; + } + + mRadioSpinel.SetDiagOutputCallback(callback, context); + +exit: + if (error == OT_ERROR_NONE) + { + speed = (sumLength * kBitsPerByte * kUsPerSec) / sumTime; + snprintf(output, sizeof(output), "%lu bps", speed); + OutputFormat("SpinelSpeed", output); + } + else + { + Output("Failed to test the Spinel speed: %s", otThreadErrorToString(error)); + } +} + void RcpCapsDiag::OutputFormat(const char *aName, const char *aValue) { static constexpr uint8_t kMaxNameLength = 56; diff --git a/src/posix/platform/rcp_caps_diag.hpp b/src/posix/platform/rcp_caps_diag.hpp index 05e06498b7b4..7d49190c703a 100644 --- a/src/posix/platform/rcp_caps_diag.hpp +++ b/src/posix/platform/rcp_caps_diag.hpp @@ -62,6 +62,8 @@ class RcpCapsDiag : mRadioSpinel(aRadioSpinel) , mOutputCallback(nullptr) , mOutputContext(nullptr) + , mDiagOutput(nullptr) + , mDiagOutputLength(0) { } @@ -109,6 +111,7 @@ class RcpCapsDiag }; void ProcessSpinel(void); + void ProcessSpinelSpeed(void); void ProcessCapabilityFlags(void); void TestSpinelCommands(Category aCategory); void TestRadioCapbilityFlags(void); @@ -120,6 +123,10 @@ class RcpCapsDiag const uint32_t *aFlags, uint16_t aNumbFlags); bool IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_size_t aCapsLength, uint32_t aCapability); + + static void HandleDiagOutput(const char *aFormat, va_list aArguments, void *aContext); + void HandleDiagOutput(const char *aFormat, va_list aArguments); + void OutputFormat(const char *aName, const char *aValue); void OutputResult(const SpinelEntry &aEntry, otError error); void Output(const char *aFormat, ...); @@ -133,6 +140,8 @@ class RcpCapsDiag Spinel::RadioSpinel &mRadioSpinel; otPlatDiagOutputCallback mOutputCallback; void *mOutputContext; + char *mDiagOutput; + uint16_t mDiagOutputLength; }; } // namespace Posix