From 7e7da0e21149925d42f26f2e563e15c0b17226b2 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Thu, 7 Jul 2022 11:30:23 +0800 Subject: [PATCH] [spinel] add an API to get the radio spinel metrics (#7859) When the RCP is not stable, it causes the Thread stack to crash. To better know the stability of the RCP, this commit adds an API to return the radio spinel metrics. --- src/lib/spinel/radio_spinel.hpp | 15 +++++ src/lib/spinel/radio_spinel_impl.hpp | 15 +++++ src/lib/spinel/radio_spinel_metrics.h | 58 +++++++++++++++++++ .../include/openthread/openthread-system.h | 10 ++++ src/posix/platform/radio.cpp | 5 ++ 5 files changed, 103 insertions(+) create mode 100644 src/lib/spinel/radio_spinel_metrics.h diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index bfa1a18b3..b0d3b463f 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -37,6 +37,7 @@ #include #include "openthread-spinel-config.h" +#include "radio_spinel_metrics.h" #include "spinel.h" #include "spinel_interface.hpp" #include "core/radio/max_power_table.hpp" @@ -877,6 +878,14 @@ public: */ otError SendReset(uint8_t aResetType); + /** + * This method returns the radio Spinel metrics. + * + * @returns The radio Spinel metrics. + * + */ + const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; } + private: enum { @@ -982,6 +991,10 @@ private: #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 void RestoreProperties(void); #endif + void UpdateParseErrorCount(otError aError) + { + mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0; + } otInstance *mInstance; @@ -1066,6 +1079,8 @@ private: int64_t mRadioTimeOffset; ///< Time difference with estimated RCP time minus host time. MaxPowerTable mMaxPowerTable; + + otRadioSpinelMetrics mRadioSpinelMetrics; }; } // namespace Spinel diff --git a/src/lib/spinel/radio_spinel_impl.hpp b/src/lib/spinel/radio_spinel_impl.hpp index 0073817ae..c9eda5c48 100644 --- a/src/lib/spinel/radio_spinel_impl.hpp +++ b/src/lib/spinel/radio_spinel_impl.hpp @@ -218,6 +218,7 @@ RadioSpinel::RadioSpinel(void) , mRadioTimeOffset(0) { mVersion[0] = '\0'; + memset(&mRadioSpinelMetrics, 0, sizeof(mRadioSpinelMetrics)); } template @@ -482,6 +483,8 @@ exit: mRxFrameBuffer.DiscardFrame(); otLogWarnPlat("Error handling hdlc frame: %s", otThreadErrorToString(error)); } + + UpdateParseErrorCount(error); } template @@ -535,6 +538,7 @@ exit: aFrameBuffer.DiscardFrame(); } + UpdateParseErrorCount(error); LogIfFail("Error processing notification", error); } @@ -556,6 +560,7 @@ void RadioSpinel::HandleNotification(const ui HandleValueIs(key, data, static_cast(len)); exit: + UpdateParseErrorCount(error); LogIfFail("Error processing saved notification", error); } @@ -597,6 +602,7 @@ void RadioSpinel::HandleResponse(const uint8_ } exit: + UpdateParseErrorCount(error); LogIfFail("Error processing response", error); } @@ -829,6 +835,7 @@ void RadioSpinel::HandleWaitingResponse(uint3 } exit: + UpdateParseErrorCount(mError); LogIfFail("Error processing result", mError); } @@ -936,6 +943,7 @@ void RadioSpinel::HandleValueIs(spinel_prop_k } exit: + UpdateParseErrorCount(error); LogIfFail("Failed to handle ValueIs", error); } @@ -1007,6 +1015,7 @@ otError RadioSpinel::ParseRadioFrame(otRadioF } exit: + UpdateParseErrorCount(error); LogIfFail("Handle radio frame failed", error); return error; } @@ -1924,6 +1933,7 @@ void RadioSpinel::HandleTransmitDone(uint32_t exit: mState = kStateTransmitDone; mTxError = error; + UpdateParseErrorCount(error); LogIfFail("Handle transmit done failed", error); } @@ -2117,6 +2127,7 @@ uint32_t RadioSpinel::GetRadioChannelMask(boo channelMask &= mMaxPowerTable.GetSupportedChannelMask(); exit: + UpdateParseErrorCount(error); LogIfFail("Get radio channel mask failed", error); return channelMask; } @@ -2211,6 +2222,7 @@ void RadioSpinel::HandleRcpUnexpectedReset(sp { OT_UNUSED_VARIABLE(aStatus); + mRadioSpinelMetrics.mRcpUnexpectedResetCount++; otLogCritPlat("Unexpected RCP reset: %s", spinel_status_to_cstr(aStatus)); #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 @@ -2223,6 +2235,8 @@ void RadioSpinel::HandleRcpUnexpectedReset(sp template void RadioSpinel::HandleRcpTimeout(void) { + mRadioSpinelMetrics.mRcpTimeoutCount++; + #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 mRcpFailed = true; #else @@ -2245,6 +2259,7 @@ void RadioSpinel::RecoverFromRcpFailure(void) otLogWarnPlat("RCP failure detected"); + ++mRadioSpinelMetrics.mRcpRestorationCount; ++mRcpFailureCount; if (mRcpFailureCount > kMaxFailureCount) { diff --git a/src/lib/spinel/radio_spinel_metrics.h b/src/lib/spinel/radio_spinel_metrics.h new file mode 100644 index 000000000..438e14c8a --- /dev/null +++ b/src/lib/spinel/radio_spinel_metrics.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file includes the definitions of the radio spinel metrics. + */ + +#ifndef RADIO_SPINEL_METRICS_H_ +#define RADIO_SPINEL_METRICS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This structure represents the radio spinel metrics. + * + */ +typedef struct otRadioSpinelMetrics +{ + uint32_t mRcpTimeoutCount; ///< The number of RCP timeouts. + uint32_t mRcpUnexpectedResetCount; ///< The number of RCP unexcepted resets. + uint32_t mRcpRestorationCount; ///< The number of RCP restorations. + uint32_t mSpinelParseErrorCount; ///< The number of spinel frame parse errors. +} otRadioSpinelMetrics; + +#ifdef __cplusplus +} // end of extern "C" +#endif + +#endif // RADIO_SPINEL_METRICS_H_ diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index e8210703b..c8add468a 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -45,6 +45,8 @@ #include #include +#include "lib/spinel/radio_spinel_metrics.h" + #ifdef __cplusplus extern "C" { #endif @@ -184,6 +186,14 @@ unsigned int otSysGetThreadNetifIndex(void); */ const char *otSysGetInfraNetifName(void); +/** + * This method returns the radio spinel metrics. + * + * @returns The radio spinel metrics. + * + */ +const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void); + #ifdef __cplusplus } // end of extern "C" #endif diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index 2e2ecdf8d..da213df42 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -660,3 +660,8 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t a OT_UNUSED_VARIABLE(aDuration); return OT_ERROR_NOT_IMPLEMENTED; } + +const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void) +{ + return sRadioSpinel.GetRadioSpinelMetrics(); +}