diff --git a/src/core/api/radio_stats_api.cpp b/src/core/api/radio_stats_api.cpp index d4e72c767..770ab7105 100644 --- a/src/core/api/radio_stats_api.cpp +++ b/src/core/api/radio_stats_api.cpp @@ -41,9 +41,9 @@ using namespace ot; const otRadioTimeStats *otRadioTimeStatsGet(otInstance *aInstance) { - return &AsCoreType(aInstance).Get().GetStats(); + return &AsCoreType(aInstance).Get().GetStats(); } -void otRadioTimeStatsReset(otInstance *aInstance) { AsCoreType(aInstance).Get().ResetTime(); } +void otRadioTimeStatsReset(otInstance *aInstance) { AsCoreType(aInstance).Get().ResetTime(); } #endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) diff --git a/src/core/instance/instance.hpp b/src/core/instance/instance.hpp index 7b48fa249..3f7aa2977 100644 --- a/src/core/instance/instance.hpp +++ b/src/core/instance/instance.hpp @@ -751,7 +751,7 @@ template <> inline Radio &Instance::Get(void) { return mRadio; } template <> inline Radio::Callbacks &Instance::Get(void) { return mRadio.mCallbacks; } #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) -template <> inline RadioStatistics &Instance::Get(void) { return mRadio.mRadioStatistics; } +template <> inline Radio::Statistics &Instance::Get(void) { return mRadio.mStatistics; } #endif #if OPENTHREAD_CONFIG_UPTIME_ENABLE diff --git a/src/core/radio/radio.cpp b/src/core/radio/radio.cpp index 846481dc4..ef1860f71 100644 --- a/src/core/radio/radio.cpp +++ b/src/core/radio/radio.cpp @@ -117,19 +117,19 @@ Error Radio::Transmit(Mac::TxFrame &aFrame) #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) inline uint64_t UintSafeMinus(uint64_t aLhs, uint64_t aRhs) { return aLhs > aRhs ? (aLhs - aRhs) : 0; } -RadioStatistics::RadioStatistics(void) +Radio::Statistics::Statistics(void) : mStatus(kDisabled) { ResetTime(); } -void RadioStatistics::RecordStateChange(Status aStatus) +void Radio::Statistics::RecordStateChange(Status aStatus) { UpdateTime(); mStatus = aStatus; } -void RadioStatistics::HandleReceiveAt(uint32_t aDurationUs) +void Radio::Statistics::HandleReceiveAt(uint32_t aDurationUs) { // The actual rx time of ReceiveAt cannot be obtained from software level. This is a workaround. if (mStatus == kSleep) @@ -138,7 +138,7 @@ void RadioStatistics::HandleReceiveAt(uint32_t aDurationUs) } } -void RadioStatistics::RecordTxDone(otError aError, uint16_t aPsduLength) +void Radio::Statistics::RecordTxDone(otError aError, uint16_t aPsduLength) { if (aError == kErrorNone || aError == kErrorNoAck) { @@ -164,7 +164,7 @@ void RadioStatistics::RecordTxDone(otError aError, uint16_t aPsduLength) } } -void RadioStatistics::RecordRxDone(otError aError) +void Radio::Statistics::RecordRxDone(otError aError) { uint32_t ackTimeUs; @@ -183,23 +183,20 @@ exit: return; } -const otRadioTimeStats &RadioStatistics::GetStats(void) +const Radio::Statistics::TimeStats &Radio::Statistics::GetStats(void) { UpdateTime(); return mTimeStats; } -void RadioStatistics::ResetTime(void) +void Radio::Statistics::ResetTime(void) { - mTimeStats.mDisabledTime = 0; - mTimeStats.mSleepTime = 0; - mTimeStats.mRxTime = 0; - mTimeStats.mTxTime = 0; - mLastUpdateTime = TimerMicro::GetNow(); + ClearAllBytes(mTimeStats); + mLastUpdateTime = TimerMicro::GetNow(); } -void RadioStatistics::UpdateTime(void) +void Radio::Statistics::UpdateTime(void) { TimeMicro nowTime = TimerMicro::GetNow(); uint32_t timeElapsed = nowTime - mLastUpdateTime; diff --git a/src/core/radio/radio.hpp b/src/core/radio/radio.hpp index d8fef61c9..5a76b0ddd 100644 --- a/src/core/radio/radio.hpp +++ b/src/core/radio/radio.hpp @@ -79,59 +79,11 @@ static constexpr uint32_t kMinWakeupListenDuration = 100; * @{ */ -/** - * Implements the radio statistics logic. - * - * The radio statistics are the time when the radio in TX/RX/radio state. - * Since this class collects these statistics from pure software level and no platform API is involved, a simplified - * model is used to calculate the time of different radio states. The data may not be very accurate, but it's - * sufficient to provide a general understanding of the proportion of time a device is in different radio states. - * - * The simplified model is: - * - The RadioStats is only aware of 2 states: RX and sleep. - * - Each time `Radio::Receive` or `Radio::Sleep` is called, it will check the current state and add the time since - * last time the methods were called. For example, `Sleep` is first called and `Receive` is called after 1 second, - * then 1 second will be added to SleepTime and the current state switches to `Receive`. - * - The time of TX will be calculated from the callback of TransmitDone. If TX returns OT_ERROR_NONE or - * OT_ERROR_NO_ACK, the tx time will be added according to the number of bytes sent. And the SleepTime or RxTime - * will be reduced accordingly. - * - When `GetStats` is called, an operation will be executed to calcute the time for the last state. And the result - * will be returned. - */ -#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - -#if !OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE +#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) && \ + !OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE #error "OPENTHREAD_CONFIG_RADIO_STATS_ENABLE requires OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE". #endif -class RadioStatistics -{ -public: - enum Status : uint8_t - { - kDisabled, - kSleep, - kReceive, - }; - - explicit RadioStatistics(void); - - void RecordStateChange(Status aStatus); - void HandleReceiveAt(uint32_t aDurationUs); - void RecordTxDone(otError aError, uint16_t aPsduLength); - void RecordRxDone(otError aError); - const otRadioTimeStats &GetStats(void); - void ResetTime(void); - -private: - void UpdateTime(void); - - Status mStatus; - otRadioTimeStats mTimeStats; - TimeMicro mLastUpdateTime; -}; -#endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - /** * Represents an OpenThread radio abstraction. */ @@ -263,6 +215,71 @@ public: } }; +#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) + /** + * Implements the radio statistics logic. + * + * The radio statistics are the time when the radio in TX/RX/radio state. + * Since this class collects these statistics from pure software level + * and no platform API is involved, a simplified model is used to + * calculate the time of different radio states. The data may not be very + * accurate, but it's sufficient to provide a general understanding of + * the proportion of time a device is in different radio states. + * + * The simplified model is: + * - The radio statistics is only aware of 2 states: RX and sleep. + * - Each time `Radio::Receive` or `Radio::Sleep` is called, it will check + * the current state and add the time since last time the methods were + * called. For example, `Sleep` is first called and `Receive` is called + * after 1 second, then 1 second will be added to SleepTime and the + * current state switches to `Receive`. + * - The time of TX will be calculated from the callback of TransmitDone. + * If TX returns kErrorNone or kErrorNoAk, the tx time will be added + * according to the number of bytes sent. And the SleepTime or RxTime + * will be reduced accordingly. + * - When `GetStats` is called, an operation will be executed to calculate + * the time for the last state. And the result will be returned. + */ + class Statistics : private NonCopyable + { + friend class Radio; + friend class Callbacks; + + public: + using TimeStats = otRadioTimeStats; ///< Radio statistics (time spend in each state). + + /** + * Retrieves the current radio statistics. + * + * @return The current time statistics. + */ + const TimeStats &GetStats(void); + + /** + * Resets the radio statistics. + */ + void ResetTime(void); + + private: + enum Status : uint8_t{ + kDisabled, + kSleep, + kReceive, + }; + + Statistics(void); + void RecordStateChange(Status aStatus); + void HandleReceiveAt(uint32_t aDurationUs); + void RecordTxDone(otError aError, uint16_t aPsduLength); + void RecordRxDone(otError aError); + void UpdateTime(void); + + Status mStatus; + TimeStats mTimeStats; + TimeMicro mLastUpdateTime; + }; +#endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) + /** * Initializes the `Radio` object. * @@ -835,7 +852,7 @@ private: Callbacks mCallbacks; #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - RadioStatistics mRadioStatistics; + Statistics mStatistics; #endif }; @@ -912,7 +929,7 @@ inline otRadioState Radio::GetState(void) { return otPlatRadioGetState(GetInstan inline Error Radio::Enable(void) { #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - mRadioStatistics.RecordStateChange(RadioStatistics::kSleep); + mStatistics.RecordStateChange(Statistics::kSleep); #endif return otPlatRadioEnable(GetInstancePtr()); } @@ -920,7 +937,7 @@ inline Error Radio::Enable(void) inline Error Radio::Disable(void) { #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - mRadioStatistics.RecordStateChange(RadioStatistics::kDisabled); + mStatistics.RecordStateChange(Statistics::kDisabled); #endif return otPlatRadioDisable(GetInstancePtr()); } @@ -930,7 +947,7 @@ inline bool Radio::IsEnabled(void) { return otPlatRadioIsEnabled(GetInstancePtr( inline Error Radio::Sleep(void) { #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - mRadioStatistics.RecordStateChange(RadioStatistics::kSleep); + mStatistics.RecordStateChange(Statistics::kSleep); #endif return otPlatRadioSleep(GetInstancePtr()); } @@ -938,7 +955,7 @@ inline Error Radio::Sleep(void) inline Error Radio::Receive(uint8_t aChannel) { #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - mRadioStatistics.RecordStateChange(RadioStatistics::kReceive); + mStatistics.RecordStateChange(Statistics::kReceive); #endif return otPlatRadioReceive(GetInstancePtr(), aChannel); } @@ -950,7 +967,7 @@ inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDurat #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) if (error == kErrorNone) { - mRadioStatistics.HandleReceiveAt(aDuration); + mStatistics.HandleReceiveAt(aDuration); } #endif return error; diff --git a/src/core/radio/radio_callbacks.cpp b/src/core/radio/radio_callbacks.cpp index 736a5a31b..2689b0dcf 100644 --- a/src/core/radio/radio_callbacks.cpp +++ b/src/core/radio/radio_callbacks.cpp @@ -40,7 +40,7 @@ namespace ot { void Radio::Callbacks::HandleReceiveDone(Mac::RxFrame *aFrame, Error aError) { #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) - Get().RecordRxDone(aError); + Get().RecordRxDone(aError); #endif Get().HandleReceiveDone(aFrame, aError); } @@ -50,7 +50,7 @@ void Radio::Callbacks::HandleTransmitStarted(Mac::TxFrame &aFrame) { Get().RecordTxDone(aError, aFrame.GetLength()); + Get().RecordTxDone(aError, aFrame.GetLength()); #endif Get().HandleTransmitDone(aFrame, aAckFrame, aError); }