mirror of
https://github.com/espressif/openthread.git
synced 2026-08-06 18:57:47 +00:00
[spinel] save the radio spinel metrics to temporary settings (#11058)
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.
This commit is contained in:
@@ -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)
|
||||
@@ -108,6 +109,7 @@ RadioSpinel::RadioSpinel(void)
|
||||
, mTxRadioEndUs(UINT64_MAX)
|
||||
, mRadioTimeRecalcStart(UINT64_MAX)
|
||||
, mRadioTimeOffset(UINT64_MAX)
|
||||
, mMetrics(mCallbacks)
|
||||
#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
|
||||
, mVendorRestorePropertiesCallback(nullptr)
|
||||
, mVendorRestorePropertiesContext(nullptr)
|
||||
@@ -120,7 +122,6 @@ RadioSpinel::RadioSpinel(void)
|
||||
, mTimeSyncOn(false)
|
||||
, mSpinelDriver(nullptr)
|
||||
{
|
||||
memset(&mRadioSpinelMetrics, 0, sizeof(mRadioSpinelMetrics));
|
||||
memset(&mCallbacks, 0, sizeof(mCallbacks));
|
||||
}
|
||||
|
||||
@@ -170,6 +171,8 @@ void RadioSpinel::Init(bool aSkipRcpVersionCheck,
|
||||
mTxRadioFrame.mPsdu = mTxPsdu;
|
||||
mAckRadioFrame.mPsdu = mAckPsdu;
|
||||
|
||||
mMetrics.Init();
|
||||
|
||||
exit:
|
||||
SuccessOrDie(error);
|
||||
}
|
||||
@@ -2005,7 +2008,7 @@ void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aStatus);
|
||||
|
||||
mRadioSpinelMetrics.mRcpUnexpectedResetCount++;
|
||||
mMetrics.IncrementRcpUnexpectedResetCount();
|
||||
LogCrit("Unexpected RCP reset: %s", spinel_status_to_cstr(aStatus));
|
||||
|
||||
#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
|
||||
@@ -2019,7 +2022,7 @@ void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
|
||||
|
||||
void RadioSpinel::HandleRcpTimeout(void)
|
||||
{
|
||||
mRadioSpinelMetrics.mRcpTimeoutCount++;
|
||||
mMetrics.IncrementRcpTimeoutCount();
|
||||
|
||||
#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
|
||||
mRcpFailure = kRcpFailureTimeout;
|
||||
@@ -2055,7 +2058,7 @@ void RadioSpinel::RecoverFromRcpFailure(void)
|
||||
|
||||
LogWarn("RCP failure detected");
|
||||
|
||||
++mRadioSpinelMetrics.mRcpRestorationCount;
|
||||
mMetrics.IncrementRcpRestorationCount();
|
||||
++mRcpFailureCount;
|
||||
if (mRcpFailureCount > kMaxFailureCount)
|
||||
{
|
||||
@@ -2457,5 +2460,60 @@ void RadioSpinel::HandleCompatibilityError(void)
|
||||
DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
|
||||
}
|
||||
|
||||
void RadioSpinel::MetricsTracker::Init(void) { RestoreMetrics(); }
|
||||
|
||||
void RadioSpinel::MetricsTracker::RestoreMetrics(void)
|
||||
{
|
||||
VerifyOrExit((mCallbacks.mSaveRadioSpinelMetrics != nullptr) && (mCallbacks.mRestoreRadioSpinelMetrics != nullptr));
|
||||
|
||||
if (mCallbacks.mRestoreRadioSpinelMetrics(mMetrics, mCallbacks.mRadioSpinelMetricsContext) != OT_ERROR_NONE)
|
||||
{
|
||||
memset(&mMetrics, 0, sizeof(mMetrics));
|
||||
mCallbacks.mSaveRadioSpinelMetrics(mMetrics, mCallbacks.mRadioSpinelMetricsContext);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RadioSpinel::MetricsTracker::SaveMetrics(void)
|
||||
{
|
||||
VerifyOrExit(mCallbacks.mSaveRadioSpinelMetrics != nullptr);
|
||||
mCallbacks.mSaveRadioSpinelMetrics(mMetrics, mCallbacks.mRadioSpinelMetricsContext);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RadioSpinel::MetricsTracker::IncrementCount(MetricType aType)
|
||||
{
|
||||
RestoreMetrics();
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case kTypeTimeoutCount:
|
||||
mMetrics.mRcpTimeoutCount++;
|
||||
break;
|
||||
|
||||
case kTypeUnexpectResetCount:
|
||||
mMetrics.mRcpUnexpectedResetCount++;
|
||||
break;
|
||||
|
||||
case kTypeRestorationCount:
|
||||
mMetrics.mRcpRestorationCount++;
|
||||
break;
|
||||
|
||||
case kTypeSpinelParseErrorCount:
|
||||
mMetrics.mSpinelParseErrorCount++;
|
||||
break;
|
||||
|
||||
default:
|
||||
OT_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
SaveMetrics();
|
||||
}
|
||||
|
||||
} // namespace Spinel
|
||||
} // namespace ot
|
||||
|
||||
@@ -134,6 +134,28 @@ struct RadioSpinelCallbacks
|
||||
*/
|
||||
void (*mDiagTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError);
|
||||
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
|
||||
/**
|
||||
* This method saves 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 (*mSaveRadioSpinelMetrics)(const otRadioSpinelMetrics &aMetrics, void *aContext);
|
||||
|
||||
/**
|
||||
* This method restores 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 (*mRestoreRadioSpinelMetrics)(otRadioSpinelMetrics &aMetrics, void *aContext);
|
||||
|
||||
/**
|
||||
* The pointer to application-specific context for methods `mSaveRadioSpinelMetrics()` and
|
||||
* `mRestoreRadioSpinelMetrics()`.
|
||||
*/
|
||||
void *mRadioSpinelMetricsContext;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -958,7 +980,7 @@ public:
|
||||
*
|
||||
* @returns The radio Spinel metrics.
|
||||
*/
|
||||
const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; }
|
||||
const otRadioSpinelMetrics &GetRadioSpinelMetrics(void) const { return mMetrics.GetMetrics(); }
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
/**
|
||||
@@ -1198,7 +1220,10 @@ private:
|
||||
|
||||
void UpdateParseErrorCount(otError aError)
|
||||
{
|
||||
mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0;
|
||||
if (aError == OT_ERROR_PARSE)
|
||||
{
|
||||
mMetrics.IncrementSpinelParseErrorCount();
|
||||
}
|
||||
}
|
||||
|
||||
otError SetMacKey(uint8_t aKeyIdMode,
|
||||
@@ -1216,6 +1241,42 @@ private:
|
||||
|
||||
void HandleCompatibilityError(void);
|
||||
|
||||
typedef otRadioSpinelMetrics Metrics;
|
||||
|
||||
class MetricsTracker
|
||||
{
|
||||
public:
|
||||
explicit MetricsTracker(RadioSpinelCallbacks &aCallbacks)
|
||||
: mCallbacks(aCallbacks)
|
||||
{
|
||||
memset(&mMetrics, 0, sizeof(mMetrics));
|
||||
}
|
||||
|
||||
void Init(void);
|
||||
void IncrementRcpTimeoutCount(void) { IncrementCount(kTypeTimeoutCount); }
|
||||
void IncrementRcpUnexpectedResetCount(void) { IncrementCount(kTypeUnexpectResetCount); }
|
||||
void IncrementRcpRestorationCount(void) { IncrementCount(kTypeRestorationCount); }
|
||||
void IncrementSpinelParseErrorCount(void) { IncrementCount(kTypeSpinelParseErrorCount); }
|
||||
|
||||
const Metrics &GetMetrics(void) const { return mMetrics; }
|
||||
|
||||
private:
|
||||
enum MetricType : uint8_t
|
||||
{
|
||||
kTypeTimeoutCount,
|
||||
kTypeUnexpectResetCount,
|
||||
kTypeRestorationCount,
|
||||
kTypeSpinelParseErrorCount,
|
||||
};
|
||||
|
||||
void RestoreMetrics(void);
|
||||
void SaveMetrics(void);
|
||||
void IncrementCount(MetricType aType);
|
||||
|
||||
RadioSpinelCallbacks &mCallbacks;
|
||||
Metrics mMetrics;
|
||||
};
|
||||
|
||||
otInstance *mInstance;
|
||||
|
||||
RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer.
|
||||
@@ -1315,9 +1376,8 @@ private:
|
||||
uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset.
|
||||
uint64_t mRadioTimeOffset; ///< Time difference with estimated RCP time minus host time.
|
||||
|
||||
MaxPowerTable mMaxPowerTable;
|
||||
|
||||
otRadioSpinelMetrics mRadioSpinelMetrics;
|
||||
MaxPowerTable mMaxPowerTable;
|
||||
MetricsTracker mMetrics;
|
||||
|
||||
#if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
|
||||
otRadioSpinelVendorRestorePropertiesCallback mVendorRestorePropertiesCallback;
|
||||
|
||||
@@ -150,6 +150,7 @@ add_library(openthread-posix
|
||||
spinel_manager.cpp
|
||||
spi_interface.cpp
|
||||
system.cpp
|
||||
tmp_storage.cpp
|
||||
trel.cpp
|
||||
udp.cpp
|
||||
utils.cpp
|
||||
|
||||
@@ -425,4 +425,14 @@
|
||||
#define OPENTHREAD_POSIX_CONFIG_TREL_SELECT_INFRA_IF 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
*
|
||||
* Define as 1 to enable the temporary storage. The key-value pairs stored in the temporary storage will be erased
|
||||
* after the system is rebooted.
|
||||
*/
|
||||
#ifndef OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
#define OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE 1
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_PLATFORM_POSIX_CONFIG_H_
|
||||
|
||||
@@ -67,6 +67,9 @@ Radio::Radio(void)
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
|
||||
, mRcpCapsDiag(mRadioSpinel)
|
||||
#endif
|
||||
#if OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
, mTmpStorage()
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
@@ -94,6 +97,12 @@ void Radio::Init(const char *aUrl)
|
||||
callbacks.mReceiveDone = otPlatRadioReceiveDone;
|
||||
callbacks.mTransmitDone = otPlatRadioTxDone;
|
||||
callbacks.mTxStarted = otPlatRadioTxStarted;
|
||||
#if OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
callbacks.mSaveRadioSpinelMetrics = SaveRadioSpinelMetrics;
|
||||
callbacks.mRestoreRadioSpinelMetrics = RestoreRadioSpinelMetrics;
|
||||
callbacks.mRadioSpinelMetricsContext = this;
|
||||
mTmpStorage.Init();
|
||||
#endif
|
||||
|
||||
resetRadio = !mRadioUrl.HasParam("no-reset");
|
||||
skipCompatibilityCheck = mRadioUrl.HasParam("skip-rcp-compatibility-check");
|
||||
@@ -105,6 +114,15 @@ void Radio::Init(const char *aUrl)
|
||||
ProcessRadioUrl(mRadioUrl);
|
||||
}
|
||||
|
||||
void Radio::Deinit(void)
|
||||
{
|
||||
mRadioSpinel.Deinit();
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
mTmpStorage.Deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Radio::ProcessRadioUrl(const RadioUrl &aRadioUrl)
|
||||
{
|
||||
const char *region;
|
||||
@@ -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)
|
||||
{
|
||||
@@ -1064,7 +1082,7 @@ otError otPlatResetToBootloader(otInstance *aInstance)
|
||||
}
|
||||
#endif
|
||||
|
||||
const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void) { return GetRadioSpinel().GetRadioSpinelMetrics(); }
|
||||
const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void) { return &GetRadioSpinel().GetRadioSpinelMetrics(); }
|
||||
|
||||
const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "rcp_caps_diag.hpp"
|
||||
#include "spi_interface.hpp"
|
||||
#include "spinel_manager.hpp"
|
||||
#include "tmp_storage.hpp"
|
||||
#include "vendor_interface.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "lib/spinel/radio_spinel.hpp"
|
||||
@@ -68,6 +69,11 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -95,6 +101,25 @@ private:
|
||||
void ProcessRadioUrl(const RadioUrl &aRadioUrl);
|
||||
void ProcessMaxPowerTable(const RadioUrl &aRadioUrl);
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
static void SaveRadioSpinelMetrics(const otRadioSpinelMetrics &aMetrics, void *aContext)
|
||||
{
|
||||
reinterpret_cast<Radio *>(aContext)->SaveRadioSpinelMetrics(aMetrics);
|
||||
}
|
||||
|
||||
void SaveRadioSpinelMetrics(const otRadioSpinelMetrics &aMetrics) { mTmpStorage.SaveRadioSpinelMetrics(aMetrics); }
|
||||
|
||||
static otError RestoreRadioSpinelMetrics(otRadioSpinelMetrics &aMetrics, void *aContext)
|
||||
{
|
||||
return reinterpret_cast<Radio *>(aContext)->RestoreRadioSpinelMetrics(aMetrics);
|
||||
}
|
||||
|
||||
otError RestoreRadioSpinelMetrics(otRadioSpinelMetrics &aMetrics)
|
||||
{
|
||||
return mTmpStorage.RestoreRadioSpinelMetrics(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)
|
||||
@@ -125,6 +150,10 @@ private:
|
||||
#if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
|
||||
RcpCapsDiag mRcpCapsDiag;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
TmpStorage mTmpStorage;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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
|
||||
* This file implements the temporary storage module for saving, restoring and deleting the temporary key-value pairs.
|
||||
* All temporary key-value pairs will be deleted after the system reboots.
|
||||
*/
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
#include "platform-posix.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#else
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "tmp_storage.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
void TmpStorage::Init(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
time_t storedBootTime;
|
||||
time_t currentBootTime;
|
||||
uint16_t valueLength = sizeof(time_t);
|
||||
|
||||
VerifyOrDie(SettingsFileInit() == OT_ERROR_NONE, OT_EXIT_FAILURE);
|
||||
|
||||
currentBootTime = GetBootTime();
|
||||
|
||||
error = mStorageFile.Get(kKeyBootTime, 0, reinterpret_cast<uint8_t *>(&storedBootTime), &valueLength);
|
||||
|
||||
// If failed to get the boot time or the current boot time doesn't match the stored boot time, it means
|
||||
// the system has been rebooted.
|
||||
if ((error != OT_ERROR_NONE) || (valueLength != sizeof(time_t)) || !BootTimeMatch(storedBootTime, currentBootTime))
|
||||
{
|
||||
mStorageFile.Wipe();
|
||||
mStorageFile.Set(kKeyBootTime, reinterpret_cast<const uint8_t *>(¤tBootTime),
|
||||
static_cast<uint16_t>(sizeof(currentBootTime)));
|
||||
}
|
||||
}
|
||||
|
||||
void TmpStorage::Deinit(void) { mStorageFile.Deinit(); }
|
||||
|
||||
void TmpStorage::SaveRadioSpinelMetrics(const otRadioSpinelMetrics &aMetrics)
|
||||
{
|
||||
mStorageFile.Set(kKeyRadioSpinelMetrics, reinterpret_cast<const uint8_t *>(&aMetrics),
|
||||
static_cast<uint16_t>(sizeof(aMetrics)));
|
||||
}
|
||||
|
||||
otError TmpStorage::RestoreRadioSpinelMetrics(otRadioSpinelMetrics &aMetrics)
|
||||
{
|
||||
uint16_t valueLength = sizeof(aMetrics);
|
||||
|
||||
return mStorageFile.Get(kKeyRadioSpinelMetrics, 0, reinterpret_cast<uint8_t *>(&aMetrics), &valueLength);
|
||||
}
|
||||
|
||||
otError TmpStorage::SettingsFileInit(void)
|
||||
{
|
||||
static constexpr size_t kMaxFileBaseNameSize = 32;
|
||||
char fileBaseName[kMaxFileBaseNameSize];
|
||||
const char *offset = getenv("PORT_OFFSET");
|
||||
uint64_t eui64;
|
||||
|
||||
otPlatRadioGetIeeeEui64(gInstance, reinterpret_cast<uint8_t *>(&eui64));
|
||||
eui64 = ot::BigEndian::HostSwap64(eui64);
|
||||
|
||||
snprintf(fileBaseName, sizeof(fileBaseName), "%s_%" PRIx64 "-tmp", ((offset == nullptr) ? "0" : offset), eui64);
|
||||
VerifyOrDie(strlen(fileBaseName) < kMaxFileBaseNameSize, OT_EXIT_FAILURE);
|
||||
|
||||
return mStorageFile.Init(fileBaseName);
|
||||
}
|
||||
|
||||
time_t TmpStorage::GetBootTime(void)
|
||||
{
|
||||
time_t curTime;
|
||||
time_t upTime;
|
||||
|
||||
#ifdef __linux__
|
||||
struct sysinfo info;
|
||||
VerifyOrDie(sysinfo(&info) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
upTime = info.uptime;
|
||||
#else
|
||||
{
|
||||
int mib[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
struct timeval boottime;
|
||||
size_t size = sizeof(boottime);
|
||||
|
||||
VerifyOrDie(sysctl(mib, OT_ARRAY_LENGTH(mib), &boottime, &size, NULL, 0) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
upTime = boottime.tv_sec;
|
||||
}
|
||||
#endif
|
||||
|
||||
VerifyOrDie(time(&curTime) != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
return (curTime - upTime);
|
||||
}
|
||||
|
||||
bool TmpStorage::BootTimeMatch(time_t aBootTimeA, time_t aBootTimeB)
|
||||
{
|
||||
time_t diff = (aBootTimeA > aBootTimeB) ? (aBootTimeA - aBootTimeB) : (aBootTimeB - aBootTimeA);
|
||||
|
||||
// The uptime and the current time are not strictly synchronized. The calculated boot time has 1 second of jitter.
|
||||
return diff < 2;
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
#endif // OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
|
||||
#ifndef OT_POSIX_PLATFORM_TMP_STORAGE_HPP_
|
||||
#define OT_POSIX_PLATFORM_TMP_STORAGE_HPP_
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
#include "platform-posix.h"
|
||||
|
||||
#include "settings_file.hpp"
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
class TmpStorage
|
||||
{
|
||||
public:
|
||||
TmpStorage(void)
|
||||
: mStorageFile()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the initialization for the temporary storage.
|
||||
*/
|
||||
void Init(void);
|
||||
|
||||
/**
|
||||
* Performs the de-initialization for the temporary storage.
|
||||
*/
|
||||
void Deinit(void);
|
||||
|
||||
/**
|
||||
* Saves the radio spinel metrics to the temporary storage.
|
||||
*
|
||||
* @param[in] aMetrics A reference to the radio spinel metrics.
|
||||
*/
|
||||
void SaveRadioSpinelMetrics(const otRadioSpinelMetrics &aMetrics);
|
||||
|
||||
/**
|
||||
* Restores the radio spinel metrics from the temporary storage.
|
||||
*
|
||||
* @param[out] aMetrics A reference to the radio spinel metrics.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The radio spinel metrics was found and fetched successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND The radio spinel metrics was not found in the setting store.
|
||||
*/
|
||||
otError RestoreRadioSpinelMetrics(otRadioSpinelMetrics &aMetrics);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kKeyBootTime = 1,
|
||||
kKeyRadioSpinelMetrics = 2,
|
||||
};
|
||||
|
||||
otError SettingsFileInit(void);
|
||||
time_t GetBootTime(void);
|
||||
bool BootTimeMatch(time_t aBootTimeA, time_t aBootTimeB);
|
||||
|
||||
SettingsFile mStorageFile;
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
#endif // OPENTHREAD_POSIX_CONFIG_TMP_STORAGE_ENABLE
|
||||
#endif // OT_POSIX_PLATFORM_TMP_STORAGE_HPP_
|
||||
Reference in New Issue
Block a user