From 971f05f7600c508802a4b4e0b2eadef801272969 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Sat, 14 Dec 2024 07:31:51 +0800 Subject: [PATCH] [diag] add diag receive command to show received specified number of frames (#11039) The `diag frame` command can set the frame to be sent. But developers has no command to check if the received frame is the same as the sent frame. This commit adds the command `diag receive [async] [lpr]` to show the detailed info of specified number of received frames. --- src/cli/cli.cpp | 12 ++- src/core/diags/README.md | 20 +++++ src/core/diags/factory_diags.cpp | 132 +++++++++++++++++++++++++++++-- src/core/diags/factory_diags.hpp | 26 ++++++ 4 files changed, 183 insertions(+), 7 deletions(-) diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 24b8b4d20..b5d3931c1 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -199,7 +199,17 @@ void Interpreter::HandleDiagOutput(const char *aFormat, va_list aArguments, void static_cast(aContext)->HandleDiagOutput(aFormat, aArguments); } -void Interpreter::HandleDiagOutput(const char *aFormat, va_list aArguments) { OutputFormatV(aFormat, aArguments); } +void Interpreter::HandleDiagOutput(const char *aFormat, va_list aArguments) +{ + if (strcmp(aFormat, "OT_ERROR_NONE") == 0) + { + OutputResult(OT_ERROR_NONE); + } + else + { + OutputFormatV(aFormat, aArguments); + } +} #endif template <> otError Interpreter::Process(Arg aArgs[]) diff --git a/src/core/diags/README.md b/src/core/diags/README.md index 4acdc403e..3db8fae04 100644 --- a/src/core/diags/README.md +++ b/src/core/diags/README.md @@ -218,6 +218,26 @@ set radio from sleep to receive on channel 11 status 0x00 ``` +### diag radio receive \[async\] \ \[lpr\] + +Set the radio to receive mode and receive a specified number of frames. + +- async: Use the non-blocking mode. +- number: The number of frames expected to be received. +- l: Show Lqi. +- p: Show Psdu. +- r: Show Rssi. + +```bash +> diag radio receive 5 lpr +0, rssi:-49, lqi:119, len:10, psdu:000102030405060771e +1, rssi:-51, lqi:112, len:10, psdu:000102030405060771e +2, rssi:-42, lqi:120, len:10, psdu:000102030405060771e +3, rssi:-54, lqi:111, len:10, psdu:000102030405060771e +4, rssi:-56, lqi:108, len:10, psdu:000102030405060771e +Done +``` + ### diag radio state Return the state of the radio. diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp index 00aa65ef2..2048d1c3b 100644 --- a/src/core/diags/factory_diags.cpp +++ b/src/core/diags/factory_diags.cpp @@ -587,6 +587,50 @@ void Diags::TransmitPacket(void) IgnoreError(Get().Transmit(*static_cast(mTxPacket))); } +Error Diags::ParseReceiveConfigFormat(const char *aFormat, ReceiveConfig &aConfig) +{ + Error error = kErrorNone; + + VerifyOrExit(aFormat != nullptr, error = kErrorInvalidArgs); + + for (const char *arg = aFormat; *arg != '\0'; arg++) + { + switch (*arg) + { + case 'r': + aConfig.mShowRssi = true; + break; + + case 'l': + aConfig.mShowLqi = true; + break; + + case 'p': + aConfig.mShowPsdu = true; + break; + + default: + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + +exit: + return error; +} + +Error Diags::RadioReceive(void) +{ + Error error; + + SuccessOrExit(error = Get().Receive(mChannel)); + SuccessOrExit(error = Get().SetTransmitPower(mTxPower)); + otPlatDiagChannelSet(mChannel); + otPlatDiagTxPowerSet(mTxPower); + +exit: + return error; +} + Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[]) { Error error = kErrorInvalidArgs; @@ -601,12 +645,44 @@ Error Diags::ProcessRadio(uint8_t aArgsLength, char *aArgs[]) } else if (StringMatch(aArgs[0], "receive")) { - SuccessOrExit(error = Get().Receive(mChannel)); - SuccessOrExit(error = Get().SetTransmitPower(mTxPower)); - otPlatDiagChannelSet(mChannel); - otPlatDiagTxPowerSet(mTxPower); + ReceiveConfig receiveConfig; - Output("set radio from sleep to receive on channel %d\r\nstatus 0x%02x\r\n", mChannel, error); + aArgs++; + aArgsLength--; + + if (aArgsLength == 0) + { + SuccessOrExit(error = RadioReceive()); + Output("set radio from sleep to receive on channel %d\r\nstatus 0x%02x\r\n", mChannel, error); + ExitNow(); + } + + if (StringMatch(aArgs[0], "async")) + { + aArgs++; + aArgsLength--; + receiveConfig.mIsAsyncCommand = true; + } + + VerifyOrExit(aArgsLength > 0); + SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint16(aArgs[0], receiveConfig.mNumFrames)); + aArgs++; + aArgsLength--; + + if (aArgsLength > 0) + { + SuccessOrExit(error = ParseReceiveConfigFormat(aArgs[0], receiveConfig)); + } + + SuccessOrExit(error = RadioReceive()); + + receiveConfig.mIsEnabled = true; + mReceiveConfig = receiveConfig; + + if (!mReceiveConfig.mIsAsyncCommand) + { + error = kErrorPending; + } } else if (StringMatch(aArgs[0], "state")) { @@ -668,10 +744,54 @@ void Diags::AlarmFired(void) } } +void Diags::OutputReceivedFrame(const otRadioFrame *aFrame) +{ + VerifyOrExit(mReceiveConfig.mIsEnabled && (aFrame != nullptr)); + + Output("%u", mReceiveConfig.mReceiveCount++); + + if (mReceiveConfig.mShowRssi) + { + Output(", rssi:%d", aFrame->mInfo.mRxInfo.mRssi); + } + + if (mReceiveConfig.mShowLqi) + { + Output(", lqi:%u", aFrame->mInfo.mRxInfo.mLqi); + } + + if (mReceiveConfig.mShowPsdu) + { + static constexpr uint16_t kBufSize = 255; + char buf[kBufSize]; + StringWriter writer(buf, sizeof(buf)); + + writer.AppendHexBytes(aFrame->mPsdu, aFrame->mLength); + Output(", len:%u, psdu:%s", aFrame->mLength, buf); + } + + Output("\r\n"); + + if (mReceiveConfig.mReceiveCount >= mReceiveConfig.mNumFrames) + { + mReceiveConfig.mIsEnabled = false; + + if (!mReceiveConfig.mIsAsyncCommand) + { + Output("OT_ERROR_NONE"); + } + } + +exit: + return; +} + void Diags::ReceiveDone(otRadioFrame *aFrame, Error aError) { if (aError == kErrorNone) { + OutputReceivedFrame(aFrame); + // for sensitivity test, only record the rssi and lqi for the first and last packet if (mStats.mReceivedPackets == 0) { @@ -910,7 +1030,7 @@ exit: void Diags::AppendErrorResult(Error aError) { - if (aError != kErrorNone) + if ((aError != kErrorNone) && (aError != kErrorPending)) { Output("failed\r\nstatus %#x\r\n", aError); } diff --git a/src/core/diags/factory_diags.hpp b/src/core/diags/factory_diags.hpp index 354ac78c6..0a724c8bf 100644 --- a/src/core/diags/factory_diags.hpp +++ b/src/core/diags/factory_diags.hpp @@ -177,6 +177,28 @@ private: RawPowerSetting mRawPowerSetting; }; + struct ReceiveConfig + { + ReceiveConfig(void) + : mIsEnabled(false) + , mIsAsyncCommand(false) + , mShowRssi(true) + , mShowLqi(true) + , mShowPsdu(false) + , mReceiveCount(0) + , mNumFrames(0) + { + } + + bool mIsEnabled : 1; + bool mIsAsyncCommand : 1; + bool mShowRssi : 1; + bool mShowLqi : 1; + bool mShowPsdu : 1; + uint16_t mReceiveCount; + uint16_t mNumFrames; + }; + Error ParseCmd(char *aString, uint8_t &aArgsLength, char *aArgs[]); Error ProcessChannel(uint8_t aArgsLength, char *aArgs[]); Error ProcessFrame(uint8_t aArgsLength, char *aArgs[]); @@ -198,6 +220,9 @@ private: Error GetRawPowerSetting(RawPowerSetting &aRawPowerSetting); Error GetPowerSettings(uint8_t aChannel, PowerSettings &aPowerSettings); + Error ParseReceiveConfigFormat(const char *aFormat, ReceiveConfig &aConfig); + Error RadioReceive(void); + void OutputReceivedFrame(const otRadioFrame *aFrame); void TransmitPacket(void); void Output(const char *aFormat, ...); @@ -223,6 +248,7 @@ private: bool mDiagSendOn : 1; #endif + ReceiveConfig mReceiveConfig; otDiagOutputCallback mOutputCallback; void *mOutputContext; };