diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 24b8b4d2069..b5d3931c1fd 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 4acdc403e19..3db8fae04b1 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 00aa65ef2ec..2048d1c3ba9 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; + + 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(); + } - Output("set radio from sleep to receive on channel %d\r\nstatus 0x%02x\r\n", mChannel, error); + 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 @@ Error Diags::ProcessGpio(uint8_t aArgsLength, char *aArgs[]) 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 354ac78c61e..0a724c8bf8d 100644 --- a/src/core/diags/factory_diags.hpp +++ b/src/core/diags/factory_diags.hpp @@ -177,6 +177,28 @@ class Diags : public InstanceLocator, private NonCopyable 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 @@ class Diags : public InstanceLocator, private NonCopyable 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 @@ class Diags : public InstanceLocator, private NonCopyable bool mDiagSendOn : 1; #endif + ReceiveConfig mReceiveConfig; otDiagOutputCallback mOutputCallback; void *mOutputContext; };