diff --git a/src/posix/platform/hdlc_interface.cpp b/src/posix/platform/hdlc_interface.cpp index 391fdacd5..ffbc20650 100644 --- a/src/posix/platform/hdlc_interface.cpp +++ b/src/posix/platform/hdlc_interface.cpp @@ -135,6 +135,8 @@ HdlcInterface::HdlcInterface(SpinelInterface::ReceiveFrameCallback aCallback, , mHdlcDecoder(aFrameBuffer, HandleHdlcFrame, this) , mRadioUrl(nullptr) { + memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics)); + mInterfaceMetrics.mRcpInterfaceType = OT_POSIX_RCP_BUS_UART; } void HdlcInterface::OnRcpReset(void) @@ -252,6 +254,19 @@ otError HdlcInterface::Write(const uint8_t *aFrame, uint16_t aLength) exit: #endif // OPENTHREAD_POSIX_VIRTUAL_TIME + + mInterfaceMetrics.mTransferredFrameCount++; + if (error == OT_ERROR_NONE) + { + mInterfaceMetrics.mTxFrameCount++; + mInterfaceMetrics.mTxFrameByteCount += aLength; + mInterfaceMetrics.mTransferredValidFrameCount++; + } + else + { + mInterfaceMetrics.mTransferredGarbageFrameCount++; + } + return error; } @@ -654,12 +669,18 @@ void HdlcInterface::HandleHdlcFrame(void *aContext, otError aError) void HdlcInterface::HandleHdlcFrame(otError aError) { + mInterfaceMetrics.mTransferredFrameCount++; + if (aError == OT_ERROR_NONE) { + mInterfaceMetrics.mRxFrameCount++; + mInterfaceMetrics.mRxFrameByteCount += mReceiveFrameBuffer.GetLength(); + mInterfaceMetrics.mTransferredValidFrameCount++; mReceiveFrameCallback(mReceiveFrameContext); } else { + mInterfaceMetrics.mTransferredGarbageFrameCount++; mReceiveFrameBuffer.DiscardFrame(); otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError)); } diff --git a/src/posix/platform/hdlc_interface.hpp b/src/posix/platform/hdlc_interface.hpp index 32ada0346..4fa2ba00f 100644 --- a/src/posix/platform/hdlc_interface.hpp +++ b/src/posix/platform/hdlc_interface.hpp @@ -169,6 +169,14 @@ public: */ otError ResetConnection(void); + /** + * This method returns the RCP interface metrics. + * + * @returns The RCP interface metrics. + * + */ + const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; } + private: /** * This method instructs `HdlcInterface` to read and decode data from radio over the socket. @@ -258,6 +266,8 @@ private: Hdlc::Decoder mHdlcDecoder; const Url::Url *mRadioUrl; + otRcpInterfaceMetrics mInterfaceMetrics; + // Non-copyable, intentionally not implemented. HdlcInterface(const HdlcInterface &); HdlcInterface &operator=(const HdlcInterface &); diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index c8add468a..9a1a666bd 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -84,6 +84,22 @@ typedef struct otPlatformConfig ///< directly after initialization. } otPlatformConfig; +/** + * This structure represents RCP interface metrics. + * + */ +typedef struct otRcpInterfaceMetrics +{ + uint8_t mRcpInterfaceType; ///< The RCP interface type. + uint64_t mTransferredFrameCount; ///< The number of transferred frames. + uint64_t mTransferredValidFrameCount; ///< The number of transferred valid frames. + uint64_t mTransferredGarbageFrameCount; ///< The number of transferred garbage frames. + uint64_t mRxFrameCount; ///< The number of received frames. + uint64_t mRxFrameByteCount; ///< The number of received bytes. + uint64_t mTxFrameCount; ///< The number of transmitted frames. + uint64_t mTxFrameByteCount; ///< The number of transmitted bytes. +} otRcpInterfaceMetrics; + /** * This function performs all platform-specific initialization of OpenThread's drivers and initializes the OpenThread * instance. @@ -194,6 +210,14 @@ const char *otSysGetInfraNetifName(void); */ const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void); +/** + * This method returns the RCP interface metrics. + * + * @returns The RCP interface metrics. + * + */ +const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void); + #ifdef __cplusplus } // end of extern "C" #endif diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index da213df42..0b9d85c6a 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -665,3 +665,8 @@ const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void) { return sRadioSpinel.GetRadioSpinelMetrics(); } + +const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void) +{ + return sRadioSpinel.GetSpinelInterface().GetRcpInterfaceMetrics(); +} diff --git a/src/posix/platform/spi_interface.cpp b/src/posix/platform/spi_interface.cpp index 752dd44c1..33f6d0cac 100644 --- a/src/posix/platform/spi_interface.cpp +++ b/src/posix/platform/spi_interface.cpp @@ -74,15 +74,8 @@ SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback, , mResetGpioValueFd(-1) , mIntGpioValueFd(-1) , mSlaveResetCount(0) - , mSpiFrameCount(0) - , mSpiValidFrameCount(0) - , mSpiGarbageFrameCount(0) , mSpiDuplexFrameCount(0) , mSpiUnresponsiveFrameCount(0) - , mSpiRxFrameCount(0) - , mSpiRxFrameByteCount(0) - , mSpiTxFrameCount(0) - , mSpiTxFrameByteCount(0) , mSpiTxIsReady(false) , mSpiTxRefusedCount(0) , mSpiTxPayloadSize(0) @@ -94,13 +87,14 @@ SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback, void SpiInterface::OnRcpReset(void) { - mSpiValidFrameCount = 0; mSpiTxIsReady = false; mSpiTxRefusedCount = 0; mSpiTxPayloadSize = 0; mDidPrintRateLimitLog = false; mSpiSlaveDataLen = 0; memset(mSpiTxFrameBuffer, 0, sizeof(mSpiTxFrameBuffer)); + memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics)); + mInterfaceMetrics.mRcpInterfaceType = OT_POSIX_RCP_BUS_SPI; TriggerReset(); usleep(static_cast(mSpiResetDelay) * kUsecPerMsec); @@ -402,7 +396,7 @@ otError SpiInterface::DoSpiTransfer(uint8_t *aSpiRxFrameBuffer, uint32_t aTransf otDumpDebgPlat("SPI-TX", mSpiTxFrameBuffer, static_cast(transfer[1].len)); otDumpDebgPlat("SPI-RX", aSpiRxFrameBuffer, static_cast(transfer[1].len)); - mSpiFrameCount++; + mInterfaceMetrics.mTransferredFrameCount++; } return (ret < 0) ? OT_ERROR_FAILED : OT_ERROR_NONE; @@ -421,7 +415,7 @@ otError SpiInterface::PushPullSpi(void) Ncp::SpiFrame txFrame(mSpiTxFrameBuffer); uint16_t skipAlignAllowanceLength; - if (mSpiValidFrameCount == 0) + if (mInterfaceMetrics.mTransferredValidFrameCount == 0) { // Set the reset flag to indicate to our slave that we are coming up from scratch. txFrame.SetHeaderFlagByte(true); @@ -525,7 +519,7 @@ otError SpiInterface::PushPullSpi(void) else { // Header is full of garbage - mSpiGarbageFrameCount++; + mInterfaceMetrics.mTransferredGarbageFrameCount++; otLogWarnPlat("Garbage in header : %02X %02X %02X %02X %02X", spiRxFrame[0], spiRxFrame[1], spiRxFrame[2], spiRxFrame[3], spiRxFrame[4]); @@ -542,7 +536,7 @@ otError SpiInterface::PushPullSpi(void) if (!rxFrame.IsValid() || (slaveAcceptLen > kMaxFrameSize) || (mSpiSlaveDataLen > kMaxFrameSize)) { - mSpiGarbageFrameCount++; + mInterfaceMetrics.mTransferredGarbageFrameCount++; mSpiTxRefusedCount++; mSpiSlaveDataLen = 0; @@ -554,7 +548,7 @@ otError SpiInterface::PushPullSpi(void) ExitNow(); } - mSpiValidFrameCount++; + mInterfaceMetrics.mTransferredValidFrameCount++; if (rxFrame.IsResetFlagSet()) { @@ -567,9 +561,9 @@ otError SpiInterface::PushPullSpi(void) // Handle received packet, if any. if ((mSpiSlaveDataLen != 0) && (mSpiSlaveDataLen <= txFrame.GetHeaderAcceptLen())) { - mSpiRxFrameByteCount += mSpiSlaveDataLen; + mInterfaceMetrics.mRxFrameByteCount += mSpiSlaveDataLen; mSpiSlaveDataLen = 0; - mSpiRxFrameCount++; + mInterfaceMetrics.mRxFrameCount++; successfulExchanges++; // Set the skip length to skip align bytes and SPI frame header. @@ -594,8 +588,8 @@ otError SpiInterface::PushPullSpi(void) // that uplayer can pull another packet for us to send. successfulExchanges++; - mSpiTxFrameCount++; - mSpiTxFrameByteCount += mSpiTxPayloadSize; + mInterfaceMetrics.mTxFrameCount++; + mInterfaceMetrics.mTxFrameByteCount += mSpiTxPayloadSize; mSpiTxIsReady = false; mSpiTxPayloadSize = 0; @@ -833,16 +827,16 @@ void SpiInterface::LogError(const char *aString) void SpiInterface::LogStats(void) { - otLogInfoPlat("INFO: mSlaveResetCount=%" PRIu64, mSlaveResetCount); - otLogInfoPlat("INFO: mSpiFrameCount=%" PRIu64, mSpiFrameCount); - otLogInfoPlat("INFO: mSpiValidFrameCount=%" PRIu64, mSpiValidFrameCount); - otLogInfoPlat("INFO: mSpiDuplexFrameCount=%" PRIu64, mSpiDuplexFrameCount); - otLogInfoPlat("INFO: mSpiUnresponsiveFrameCount=%" PRIu64, mSpiUnresponsiveFrameCount); - otLogInfoPlat("INFO: mSpiGarbageFrameCount=%" PRIu64, mSpiGarbageFrameCount); - otLogInfoPlat("INFO: mSpiRxFrameCount=%" PRIu64, mSpiRxFrameCount); - otLogInfoPlat("INFO: mSpiRxFrameByteCount=%" PRIu64, mSpiRxFrameByteCount); - otLogInfoPlat("INFO: mSpiTxFrameCount=%" PRIu64, mSpiTxFrameCount); - otLogInfoPlat("INFO: mSpiTxFrameByteCount=%" PRIu64, mSpiTxFrameByteCount); + otLogInfoPlat("INFO: SlaveResetCount=%" PRIu64, mSlaveResetCount); + otLogInfoPlat("INFO: SpiDuplexFrameCount=%" PRIu64, mSpiDuplexFrameCount); + otLogInfoPlat("INFO: SpiUnresponsiveFrameCount=%" PRIu64, mSpiUnresponsiveFrameCount); + otLogInfoPlat("INFO: TransferredFrameCount=%" PRIu64, mInterfaceMetrics.mTransferredFrameCount); + otLogInfoPlat("INFO: TransferredValidFrameCount=%" PRIu64, mInterfaceMetrics.mTransferredValidFrameCount); + otLogInfoPlat("INFO: TransferredGarbageFrameCount=%" PRIu64, mInterfaceMetrics.mTransferredGarbageFrameCount); + otLogInfoPlat("INFO: RxFrameCount=%" PRIu64, mInterfaceMetrics.mRxFrameCount); + otLogInfoPlat("INFO: RxFrameByteCount=%" PRIu64, mInterfaceMetrics.mRxFrameByteCount); + otLogInfoPlat("INFO: TxFrameCount=%" PRIu64, mInterfaceMetrics.mTxFrameCount); + otLogInfoPlat("INFO: TxFrameByteCount=%" PRIu64, mInterfaceMetrics.mTxFrameByteCount); } } // namespace Posix } // namespace ot diff --git a/src/posix/platform/spi_interface.hpp b/src/posix/platform/spi_interface.hpp index 13bf00f86..b2e8a0268 100644 --- a/src/posix/platform/spi_interface.hpp +++ b/src/posix/platform/spi_interface.hpp @@ -159,6 +159,14 @@ public: */ otError ResetConnection(void) { return OT_ERROR_NONE; } + /** + * This method returns the RCP interface metrics. + * + * @returns The RCP interface metrics. + * + */ + const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; } + private: int SetupGpioHandle(int aFd, uint8_t aLine, uint32_t aHandleFlags, const char *aLabel); int SetupGpioEvent(int aFd, uint8_t aLine, uint32_t aHandleFlags, uint32_t aEventFlags, const char *aLabel); @@ -228,15 +236,8 @@ private: uint32_t mSpiSpeedHz; uint64_t mSlaveResetCount; - uint64_t mSpiFrameCount; - uint64_t mSpiValidFrameCount; - uint64_t mSpiGarbageFrameCount; uint64_t mSpiDuplexFrameCount; uint64_t mSpiUnresponsiveFrameCount; - uint64_t mSpiRxFrameCount; - uint64_t mSpiRxFrameByteCount; - uint64_t mSpiTxFrameCount; - uint64_t mSpiTxFrameByteCount; bool mSpiTxIsReady; uint16_t mSpiTxRefusedCount; @@ -248,6 +249,8 @@ private: bool mDidRxFrame; + otRcpInterfaceMetrics mInterfaceMetrics; + // Non-copyable, intentionally not implemented. SpiInterface(const SpiInterface &); SpiInterface &operator=(const SpiInterface &);