Skip to content

Commit

Permalink
[spinel] save the radio spinel metrics to temporary settings
Browse files Browse the repository at this point in the history
The otRadioSpinelMetrics includes metrics that record the count of the
RCP timeout and the count of RCP reboot and so on. After these events
happen, the Thread stack will exits and the system will re-start the
Thread stack again. In this case, metrics of the otRadioSpinelMetrics
will be cleared and metrics values are awalys 0.

This commit adds a temporary settings to store the radio spinel metrics.
The temporary settings will clear all settings after the system reboots.
  • Loading branch information
zhanglongxia committed Jan 2, 2025
1 parent 3560870 commit bebb16d
Show file tree
Hide file tree
Showing 8 changed files with 439 additions and 8 deletions.
79 changes: 75 additions & 4 deletions src/lib/spinel/radio_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ otRadioCaps RadioSpinel::sRadioCaps = OT_RADIO_CAPS_NONE;
RadioSpinel::RadioSpinel(void)
: Logger("RadioSpinel")
, mInstance(nullptr)
, mCallbacks()
, mCmdTidsInUse(0)
, mCmdNextTid(1)
, mTxRadioTid(0)
Expand Down Expand Up @@ -108,6 +109,7 @@ RadioSpinel::RadioSpinel(void)
, mTxRadioEndUs(UINT64_MAX)
, mRadioTimeRecalcStart(UINT64_MAX)
, mRadioTimeOffset(UINT64_MAX)
, mRadioSpinelMetrics(mCallbacks)
#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
, mVendorRestorePropertiesCallback(nullptr)
, mVendorRestorePropertiesContext(nullptr)
Expand All @@ -120,7 +122,6 @@ RadioSpinel::RadioSpinel(void)
, mTimeSyncOn(false)
, mSpinelDriver(nullptr)
{
memset(&mRadioSpinelMetrics, 0, sizeof(mRadioSpinelMetrics));
memset(&mCallbacks, 0, sizeof(mCallbacks));
}

Expand Down Expand Up @@ -170,6 +171,8 @@ void RadioSpinel::Init(bool aSkipRcpVersionCheck,
mTxRadioFrame.mPsdu = mTxPsdu;
mAckRadioFrame.mPsdu = mAckPsdu;

mRadioSpinelMetrics.Init();

exit:
SuccessOrDie(error);
}
Expand Down Expand Up @@ -2005,7 +2008,7 @@ void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
{
OT_UNUSED_VARIABLE(aStatus);

mRadioSpinelMetrics.mRcpUnexpectedResetCount++;
mRadioSpinelMetrics.IncreaseRcpUnexpectedResetCount();
LogCrit("Unexpected RCP reset: %s", spinel_status_to_cstr(aStatus));

#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
Expand All @@ -2019,7 +2022,7 @@ void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)

void RadioSpinel::HandleRcpTimeout(void)
{
mRadioSpinelMetrics.mRcpTimeoutCount++;
mRadioSpinelMetrics.IncreaseRcpTimeoutCount();

#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
mRcpFailure = kRcpFailureTimeout;
Expand Down Expand Up @@ -2055,7 +2058,7 @@ void RadioSpinel::RecoverFromRcpFailure(void)

LogWarn("RCP failure detected");

++mRadioSpinelMetrics.mRcpRestorationCount;
mRadioSpinelMetrics.IncreaseRcpRestorationCount();
++mRcpFailureCount;
if (mRcpFailureCount > kMaxFailureCount)
{
Expand Down Expand Up @@ -2457,5 +2460,73 @@ void RadioSpinel::HandleCompatibilityError(void)
DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
}

void RadioSpinel::Metrics::Init() { ReadMetrics(*reinterpret_cast<otRadioSpinelMetrics *>(this)); }

const otRadioSpinelMetrics *RadioSpinel::Metrics::GetMetrics(void) const
{
return reinterpret_cast<const otRadioSpinelMetrics *>(this);
}

bool RadioSpinel::Metrics::IsReadWriteCallbackValid(void) const
{
return (mCallbacks.mWriteRadioSpinelMetrics != nullptr) && (mCallbacks.mReadRadioSpinelMetrics != nullptr);
}

void RadioSpinel::Metrics::ReadMetrics(otRadioSpinelMetrics &aMetrics)
{
VerifyOrExit(IsReadWriteCallbackValid());

if (mCallbacks.mReadRadioSpinelMetrics(aMetrics, mCallbacks.mRadioSpinelMetricsContext) != OT_ERROR_NONE)
{
memset(&aMetrics, 0, sizeof(aMetrics));
mCallbacks.mWriteRadioSpinelMetrics(aMetrics, mCallbacks.mRadioSpinelMetricsContext);
}

exit:
return;
}

void RadioSpinel::Metrics::WriteMetrics(otRadioSpinelMetrics &aMetrics)
{
VerifyOrExit(IsReadWriteCallbackValid());
mCallbacks.mWriteRadioSpinelMetrics(aMetrics, mCallbacks.mRadioSpinelMetricsContext);

exit:
return;
}

void RadioSpinel::Metrics::IncreaseCount(MetricType aType)
{
otRadioSpinelMetrics &metrics = *reinterpret_cast<otRadioSpinelMetrics *>(this);

ReadMetrics(metrics);

IncreaseMetricCount(metrics, aType);

WriteMetrics(metrics);
}

void RadioSpinel::Metrics::IncreaseMetricCount(otRadioSpinelMetrics &aMetrics, MetricType aType)
{
switch (aType)
{
case kTypeTimeoutCount:
aMetrics.mRcpTimeoutCount++;
break;
case kTypeUnexpectResetCount:
aMetrics.mRcpUnexpectedResetCount++;
break;
case kTypeRestorationCount:
aMetrics.mRcpRestorationCount++;
break;
case kTypeSpinelParseErrorCount:
aMetrics.mSpinelParseErrorCount++;
break;
default:
OT_ASSERT(false);
break;
}
}

} // namespace Spinel
} // namespace ot
66 changes: 63 additions & 3 deletions src/lib/spinel/radio_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,28 @@ struct RadioSpinelCallbacks
*/
void (*mDiagTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError);
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE

/**
* This method writes the radio spinel metrics to the temporary storage.
*
* @param[in] aMetrics A reference to the radio spinel metrics.
* @param[in] aContext A pointer to application-specific context.
*/
void (*mWriteRadioSpinelMetrics)(const otRadioSpinelMetrics &aMetrics, void *aContext);

/**
* This method reads the radio spinel metrics from the temporary storage.
*
* @param[out] aMetrics A reference to the radio spinel metrics.
* @param[in] aContext A pointer to application-specific context.
*/
otError (*mReadRadioSpinelMetrics)(otRadioSpinelMetrics &aMetrics, void *aContext);

/**
* The pointer to application-specific context for methods `mWriteRadioSpinelMetrics` and
* `mReadRadioSpinelMetrics`.
*/
void *mRadioSpinelMetricsContext;
};

/**
Expand Down Expand Up @@ -958,7 +980,7 @@ class RadioSpinel : private Logger
*
* @returns The radio Spinel metrics.
*/
const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; }
const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return mRadioSpinelMetrics.GetMetrics(); }

#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
/**
Expand Down Expand Up @@ -1198,7 +1220,10 @@ class RadioSpinel : private Logger

void UpdateParseErrorCount(otError aError)
{
mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0;
if (aError == OT_ERROR_PARSE)
{
mRadioSpinelMetrics.IncreaseSpinelParseErrorCount();
}
}

otError SetMacKey(uint8_t aKeyIdMode,
Expand All @@ -1216,6 +1241,41 @@ class RadioSpinel : private Logger

void HandleCompatibilityError(void);

class Metrics : public otRadioSpinelMetrics
{
public:
Metrics(RadioSpinelCallbacks &aCallbacks)
: mCallbacks(aCallbacks)
{
memset(reinterpret_cast<otRadioSpinelMetrics *>(this), 0, sizeof(otRadioSpinelMetrics));
}

void Init();
const otRadioSpinelMetrics *GetMetrics(void) const;

void IncreaseRcpTimeoutCount(void) { IncreaseCount(kTypeTimeoutCount); }
void IncreaseRcpUnexpectedResetCount(void) { IncreaseCount(kTypeUnexpectResetCount); }
void IncreaseRcpRestorationCount(void) { IncreaseCount(kTypeRestorationCount); }
void IncreaseSpinelParseErrorCount(void) { IncreaseCount(kTypeSpinelParseErrorCount); }

private:
enum MetricType : uint8_t
{
kTypeTimeoutCount,
kTypeUnexpectResetCount,
kTypeRestorationCount,
kTypeSpinelParseErrorCount,
};

bool IsReadWriteCallbackValid(void) const;
void ReadMetrics(otRadioSpinelMetrics &aMetrics);
void WriteMetrics(otRadioSpinelMetrics &aMetrics);
void IncreaseCount(MetricType aType);
void IncreaseMetricCount(otRadioSpinelMetrics &aMetrics, MetricType aType);

RadioSpinelCallbacks &mCallbacks;
};

otInstance *mInstance;

RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer.
Expand Down Expand Up @@ -1317,7 +1377,7 @@ class RadioSpinel : private Logger

MaxPowerTable mMaxPowerTable;

otRadioSpinelMetrics mRadioSpinelMetrics;
Metrics mRadioSpinelMetrics;

#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
otRadioSpinelVendorRestorePropertiesCallback mVendorRestorePropertiesCallback;
Expand Down
1 change: 1 addition & 0 deletions src/posix/platform/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ add_library(openthread-posix
spinel_manager.cpp
spi_interface.cpp
system.cpp
temp_settings.cpp
trel.cpp
udp.cpp
utils.cpp
Expand Down
10 changes: 10 additions & 0 deletions src/posix/platform/openthread-posix-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,14 @@
#define OPENTHREAD_POSIX_CONFIG_TREL_SELECT_INFRA_IF 0
#endif

/**
* @def OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE
*
* Define as 1 to enable the temporary settings. The key-value pairs stored in the temporary settings will be erased
* after the system is rebooted.
*/
#ifndef OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE
#define OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE 1
#endif

#endif // OPENTHREAD_PLATFORM_POSIX_CONFIG_H_
20 changes: 19 additions & 1 deletion src/posix/platform/radio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ Radio::Radio(void)
#if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
, mRcpCapsDiag(mRadioSpinel)
#endif
#if OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE
, mTempSettings()
#endif
{
}

Expand Down Expand Up @@ -94,6 +97,12 @@ void Radio::Init(const char *aUrl)
callbacks.mReceiveDone = otPlatRadioReceiveDone;
callbacks.mTransmitDone = otPlatRadioTxDone;
callbacks.mTxStarted = otPlatRadioTxStarted;
#if OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE
callbacks.mWriteRadioSpinelMetrics = WriteRadioSpinelMetrics;
callbacks.mReadRadioSpinelMetrics = ReadRadioSpinelMetrics;
callbacks.mRadioSpinelMetricsContext = reinterpret_cast<void *>(this);
mTempSettings.Init();
#endif

resetRadio = !mRadioUrl.HasParam("no-reset");
skipCompatibilityCheck = mRadioUrl.HasParam("skip-rcp-compatibility-check");
Expand All @@ -105,6 +114,15 @@ void Radio::Init(const char *aUrl)
ProcessRadioUrl(mRadioUrl);
}

void Radio::Deinit(void)
{
mRadioSpinel.Deinit();

#if OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE
mTempSettings.Deinit();
#endif
}

void Radio::ProcessRadioUrl(const RadioUrl &aRadioUrl)
{
const char *region;
Expand Down Expand Up @@ -215,7 +233,7 @@ ot::Spinel::RadioSpinel &GetRadioSpinel(void) { return sRadio.GetRadioSpinel();
ot::Posix::RcpCapsDiag &GetRcpCapsDiag(void) { return sRadio.GetRcpCapsDiag(); }
#endif

void platformRadioDeinit(void) { GetRadioSpinel().Deinit(); }
void platformRadioDeinit(void) { sRadio.Deinit(); }

void platformRadioHandleStateChange(otInstance *aInstance, otChangedFlags aFlags)
{
Expand Down
32 changes: 32 additions & 0 deletions src/posix/platform/radio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "rcp_caps_diag.hpp"
#include "spi_interface.hpp"
#include "spinel_manager.hpp"
#include "temp_settings.hpp"
#include "vendor_interface.hpp"
#include "common/code_utils.hpp"
#include "lib/spinel/radio_spinel.hpp"
Expand Down Expand Up @@ -68,6 +69,11 @@ class Radio : public Logger<Radio>
*/
void Init(const char *aUrl);

/**
* De-initializes the Thread radio.
*/
void Deinit(void);

/**
* Acts as an accessor to the spinel interface instance used by the radio.
*
Expand Down Expand Up @@ -95,6 +101,28 @@ class Radio : public Logger<Radio>
void ProcessRadioUrl(const RadioUrl &aRadioUrl);
void ProcessMaxPowerTable(const RadioUrl &aRadioUrl);

#if OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE
static void WriteRadioSpinelMetrics(const otRadioSpinelMetrics &aMetrics, void *aContext)
{
reinterpret_cast<Radio *>(aContext)->WriteRadioSpinelMetrics(aMetrics);
}

void WriteRadioSpinelMetrics(const otRadioSpinelMetrics &aMetrics)
{
mTempSettings.WriteRadioSpinelMetrics(aMetrics);
}

static otError ReadRadioSpinelMetrics(otRadioSpinelMetrics &aMetrics, void *aContext)
{
return reinterpret_cast<Radio *>(aContext)->ReadRadioSpinelMetrics(aMetrics);
}

otError ReadRadioSpinelMetrics(otRadioSpinelMetrics &aMetrics)
{
return mTempSettings.ReadRadioSpinelMetrics(aMetrics);
}
#endif

#if OPENTHREAD_POSIX_CONFIG_SPINEL_HDLC_INTERFACE_ENABLE && OPENTHREAD_POSIX_CONFIG_SPINEL_SPI_INTERFACE_ENABLE
static constexpr size_t kSpinelInterfaceRawSize = sizeof(ot::Posix::SpiInterface) > sizeof(ot::Posix::HdlcInterface)
? sizeof(ot::Posix::SpiInterface)
Expand Down Expand Up @@ -125,6 +153,10 @@ class Radio : public Logger<Radio>
#if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
RcpCapsDiag mRcpCapsDiag;
#endif

#if OPENTHREAD_POSIX_CONFIG_TEMP_SETTINGS_ENABLE
TempSettings mTempSettings;
#endif
};

} // namespace Posix
Expand Down
Loading

0 comments on commit bebb16d

Please sign in to comment.