From 4866887933525c0920e22d60906021dfbc29e310 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 2 Mar 2026 11:31:27 -0600 Subject: [PATCH] [nexus] implement microsecond alarm platform APIs (#12580) This commit implements the otPlatAlarmMicro* platform APIs in the Nexus simulation environment. It also transitions the simulation's internal time base from millisecond to microsecond granularity to ensure that both millisecond and microsecond alarms operate on a consistent and shared time reference. Changes include: - Enabled OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE in Nexus config. - Updated Nexus::Core to use a 64-bit microsecond time base (mNow). - Implemented otPlatAlarmMicroGetNow, otPlatAlarmMicroStartAt, and otPlatAlarmMicroStop. - Refactored Nexus::Node to support separate millisecond and microsecond alarm instances (mAlarmMilli and mAlarmMicro). - Updated radio timestamps and PCAP logging to use the new high- resolution microsecond time base. - Adjusted simulation time advancement and alarm triggering logic to handle both alarm types correctly. --- tests/nexus/openthread-core-nexus-config.h | 2 +- tests/nexus/platform/nexus_alarm.cpp | 23 +++++++-- tests/nexus/platform/nexus_alarm.hpp | 1 - tests/nexus/platform/nexus_core.cpp | 59 ++++++++++++++++++---- tests/nexus/platform/nexus_core.hpp | 10 ++-- tests/nexus/platform/nexus_node.cpp | 3 +- tests/nexus/platform/nexus_node.hpp | 6 ++- 7 files changed, 80 insertions(+), 24 deletions(-) diff --git a/tests/nexus/openthread-core-nexus-config.h b/tests/nexus/openthread-core-nexus-config.h index fcc2b42d5..345ee5d1c 100644 --- a/tests/nexus/openthread-core-nexus-config.h +++ b/tests/nexus/openthread-core-nexus-config.h @@ -120,7 +120,7 @@ #define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0 #define OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 0 #define OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE 0 -#define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 0 +#define OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE 1 #define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE 0 #define OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE 1 #define OPENTHREAD_CONFIG_SEEKER_ENABLE 1 diff --git a/tests/nexus/platform/nexus_alarm.cpp b/tests/nexus/platform/nexus_alarm.cpp index 673f86528..253dac8bb 100644 --- a/tests/nexus/platform/nexus_alarm.cpp +++ b/tests/nexus/platform/nexus_alarm.cpp @@ -26,6 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include "nexus_alarm.hpp" @@ -36,7 +37,7 @@ namespace ot { namespace Nexus { //--------------------------------------------------------------------------------------------------------------------- -// otPlatAlarmMilli APIs +// otPlatAlarm Milli and Micro APIs extern "C" { @@ -44,15 +45,29 @@ uint32_t otPlatAlarmMilliGetNow(void) { return Core::Get().GetNow().GetValue(); void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) { - Alarm &alarm = AsNode(aInstance).mAlarm; + Alarm &alarm = AsNode(aInstance).mAlarmMilli; alarm.mScheduled = true; alarm.mAlarmTime.SetValue(aT0 + aDt); - Core::Get().UpdateNextAlarmTime(alarm); + Core::Get().UpdateNextAlarmMilli(alarm); } -void otPlatAlarmMilliStop(otInstance *aInstance) { AsNode(aInstance).mAlarm.mScheduled = false; } +void otPlatAlarmMilliStop(otInstance *aInstance) { AsNode(aInstance).mAlarmMilli.mScheduled = false; } + +uint32_t otPlatAlarmMicroGetNow(void) { return Core::Get().GetNowMicro().GetValue(); } + +void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) +{ + Alarm &alarm = AsNode(aInstance).mAlarmMicro; + + alarm.mScheduled = true; + alarm.mAlarmTime.SetValue(aT0 + aDt); + + Core::Get().UpdateNextAlarmMicro(alarm); +} + +void otPlatAlarmMicroStop(otInstance *aInstance) { AsNode(aInstance).mAlarmMicro.mScheduled = false; } } // extern "C" diff --git a/tests/nexus/platform/nexus_alarm.hpp b/tests/nexus/platform/nexus_alarm.hpp index efd76c34b..ca987f30e 100644 --- a/tests/nexus/platform/nexus_alarm.hpp +++ b/tests/nexus/platform/nexus_alarm.hpp @@ -38,7 +38,6 @@ struct Alarm { Alarm(void) { Reset(); } void Reset(void) { mScheduled = false; } - bool ShouldTrigger(Time aNow) const { return mScheduled && (aNow >= mAlarmTime); } bool mScheduled; Time mAlarmTime; diff --git a/tests/nexus/platform/nexus_core.cpp b/tests/nexus/platform/nexus_core.cpp index 5bba8a6d8..fd019a567 100644 --- a/tests/nexus/platform/nexus_core.cpp +++ b/tests/nexus/platform/nexus_core.cpp @@ -51,7 +51,7 @@ Core::Core(void) sCore = this; sInUse = true; - mNextAlarmTime = mNow.GetDistantFuture(); + mNextAlarmTime = NumericLimits::kMax; pcapFile = getenv("OT_NEXUS_PCAP_FILE"); @@ -256,27 +256,58 @@ Node &Core::CreateNode(void) return *node; } -void Core::UpdateNextAlarmTime(const Alarm &aAlarm) +void Core::UpdateNextAlarmMilli(const Alarm &aAlarm) { if (aAlarm.mScheduled) { - mNextAlarmTime = Min(mNextAlarmTime, Max(mNow, aAlarm.mAlarmTime)); + uint64_t alarmTime; + + if (GetNow() >= aAlarm.mAlarmTime) + { + alarmTime = mNow; + } + else + { + alarmTime = mNow - (mNow % 1000u) + (static_cast(aAlarm.mAlarmTime - GetNow()) * 1000u); + } + + mNextAlarmTime = Min(mNextAlarmTime, alarmTime); + } +} + +void Core::UpdateNextAlarmMicro(const Alarm &aAlarm) +{ + if (aAlarm.mScheduled) + { + uint64_t alarmTime; + + if (GetNowMicro() >= aAlarm.mAlarmTime) + { + alarmTime = mNow; + } + else + { + alarmTime = mNow + static_cast(aAlarm.mAlarmTime - GetNowMicro()); + } + + mNextAlarmTime = Min(mNextAlarmTime, alarmTime); } } void Core::AdvanceTime(uint32_t aDuration) { - TimeMilli targetTime = mNow + aDuration; + uint64_t targetTime = mNow + (static_cast(aDuration) * 1000u); while (mPendingAction || (mNextAlarmTime <= targetTime)) { - mNextAlarmTime = mNow.GetDistantFuture(); + mNextAlarmTime = NumericLimits::kMax; mPendingAction = false; for (Node &node : mNodes) { Process(node); - UpdateNextAlarmTime(node.mAlarm); + UpdateNextAlarmMilli(node.mAlarmMilli); + UpdateNextAlarmMicro(node.mAlarmMicro); } if (!mPendingAction) @@ -298,11 +329,17 @@ void Core::Process(Node &aNode) ProcessTrel(aNode); #endif - if (aNode.mAlarm.ShouldTrigger(mNow)) + if (aNode.mAlarmMilli.mScheduled && (GetNow() >= aNode.mAlarmMilli.mAlarmTime)) { - aNode.mAlarm.mScheduled = false; + aNode.mAlarmMilli.mScheduled = false; otPlatAlarmMilliFired(&aNode.GetInstance()); } + + if (aNode.mAlarmMicro.mScheduled && (GetNowMicro() >= aNode.mAlarmMicro.mAlarmTime)) + { + aNode.mAlarmMicro.mScheduled = false; + otPlatAlarmMicroFired(&aNode.GetInstance()); + } } void Core::ProcessRadio(Node &aNode) @@ -326,7 +363,7 @@ void Core::ProcessRadio(Node &aNode) ackRequested = aNode.mRadio.mTxFrame.GetAckRequest(); - mPcap.WriteFrame(aNode.mRadio.mTxFrame, mNow.GetValue() * 1000ull); + mPcap.WriteFrame(aNode.mRadio.mTxFrame, mNow); otPlatRadioTxStarted(&aNode.GetInstance(), &aNode.mRadio.mTxFrame); @@ -347,7 +384,7 @@ void Core::ProcessRadio(Node &aNode) Radio::Frame rxFrame(aNode.mRadio.mTxFrame); - rxFrame.mInfo.mRxInfo.mTimestamp = (mNow.GetValue() * 1000u); + rxFrame.mInfo.mRxInfo.mTimestamp = mNow; rxFrame.mInfo.mRxInfo.mRssi = kDefaultRxRssi; rxFrame.mInfo.mRxInfo.mLqi = 0; @@ -388,7 +425,7 @@ void Core::ProcessRadio(Node &aNode) (ackMode == kSendAckFramePending)); ackFrame.UpdateFcs(); - mPcap.WriteFrame(ackFrame, mNow.GetValue() * 1000ull); + mPcap.WriteFrame(ackFrame, mNow); otPlatRadioTxDone(&aNode.GetInstance(), &aNode.mRadio.mTxFrame, &ackFrame, kErrorNone); } diff --git a/tests/nexus/platform/nexus_core.hpp b/tests/nexus/platform/nexus_core.hpp index 41f3a3fa0..706d04a0e 100644 --- a/tests/nexus/platform/nexus_core.hpp +++ b/tests/nexus/platform/nexus_core.hpp @@ -55,7 +55,8 @@ public: Node &CreateNode(void); LinkedList &GetNodes(void) { return mNodes; } - TimeMilli GetNow(void) { return mNow; } + TimeMilli GetNow(void) { return TimeMilli(static_cast(mNow / 1000u)); } + TimeMicro GetNowMicro(void) { return TimeMicro(static_cast(mNow)); } void AdvanceTime(uint32_t aDuration); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -75,7 +76,8 @@ public: void SetActiveNode(Node *aNode) { mActiveNode = aNode; } Node *GetActiveNode(void) { return mActiveNode; } - void UpdateNextAlarmTime(const Alarm &aAlarm); + void UpdateNextAlarmMilli(const Alarm &aAlarm); + void UpdateNextAlarmMicro(const Alarm &aAlarm); void MarkPendingAction(void) { mPendingAction = true; } private: @@ -117,8 +119,8 @@ private: Array mNetworkKeys; uint16_t mCurNodeId; bool mPendingAction; - TimeMilli mNow; - TimeMilli mNextAlarmTime; + uint64_t mNow; + uint64_t mNextAlarmTime; Node *mActiveNode; }; diff --git a/tests/nexus/platform/nexus_node.cpp b/tests/nexus/platform/nexus_node.cpp index 39fcf734a..c2bc0d1de 100644 --- a/tests/nexus/platform/nexus_node.cpp +++ b/tests/nexus/platform/nexus_node.cpp @@ -38,7 +38,8 @@ void Node::Reset(void) uint32_t id = GetId(); mRadio.Reset(); - mAlarm.Reset(); + mAlarmMilli.Reset(); + mAlarmMicro.Reset(); mMdns.Reset(); mPendingTasklet = false; #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE diff --git a/tests/nexus/platform/nexus_node.hpp b/tests/nexus/platform/nexus_node.hpp index 5c966b438..95cfc3ba9 100644 --- a/tests/nexus/platform/nexus_node.hpp +++ b/tests/nexus/platform/nexus_node.hpp @@ -46,7 +46,8 @@ class Platform { public: Radio mRadio; - Alarm mAlarm; + Alarm mAlarmMilli; + Alarm mAlarmMicro; Mdns mMdns; Settings mSettings; #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE @@ -121,7 +122,8 @@ public: static Node &From(otInstance *aInstance) { return static_cast(*aInstance); } - using Platform::mAlarm; + using Platform::mAlarmMicro; + using Platform::mAlarmMilli; using Platform::mMdns; using Platform::mPendingTasklet; using Platform::mRadio;