mirror of
https://github.com/espressif/openthread.git
synced 2026-08-01 16:47:47 +00:00
Timer: Modify timer implementation to store fire time (#1904)
This commit changes the `Timer` class to store the fire time instead of start time and duration. This simplifies the `Timer` implementation and reduces the size of a `Timer` instance. The `test_timer` unit test is also updated to add new test cases to verify correct timer behavior during 32-bit timer wrap. This commit also simplifies the key rotation implementation in `KeyManager` class. Since the key rotation time and guard time are provided in hours unit and can span multiple days, the code tracks number of hours since last key rotation in `mHoursSinceKeyRotation` (using a one hour interval timer). This is then used to decide when/if to change the key sequence.
This commit is contained in:
committed by
Jonathan Hui
parent
8b64f524b5
commit
f067d68f38
@@ -405,7 +405,7 @@ Message *Coap::CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLeng
|
||||
if (mRetransmissionTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
alarmFireTime = mRetransmissionTimer.Gett0() + mRetransmissionTimer.Getdt();
|
||||
alarmFireTime = mRetransmissionTimer.GetFireTime();
|
||||
|
||||
if (aCoapMetadata.IsEarlier(alarmFireTime))
|
||||
{
|
||||
|
||||
+13
-44
@@ -69,7 +69,7 @@ void TimerScheduler::Add(Timer &aTimer)
|
||||
|
||||
for (cur = mHead; cur; cur = cur->mNext)
|
||||
{
|
||||
if (TimerCompare(aTimer, *cur))
|
||||
if (IsStrictlyBefore(aTimer.mFireTime, cur->mFireTime))
|
||||
{
|
||||
if (prev)
|
||||
{
|
||||
@@ -126,18 +126,14 @@ exit:
|
||||
|
||||
void TimerScheduler::SetAlarm(void)
|
||||
{
|
||||
uint32_t now = otPlatAlarmGetNow();
|
||||
uint32_t elapsed;
|
||||
uint32_t remaining;
|
||||
|
||||
if (mHead == NULL)
|
||||
{
|
||||
otPlatAlarmStop(GetIp6()->GetInstance());
|
||||
}
|
||||
else
|
||||
{
|
||||
elapsed = now - mHead->mT0;
|
||||
remaining = (mHead->mDt > elapsed) ? mHead->mDt - elapsed : 0;
|
||||
uint32_t now = otPlatAlarmGetNow();
|
||||
uint32_t remaining = IsStrictlyBefore(now, mHead->mFireTime) ? (mHead->mFireTime - now) : 0;
|
||||
|
||||
otPlatAlarmStartAt(GetIp6()->GetInstance(), now, remaining);
|
||||
}
|
||||
@@ -146,21 +142,17 @@ void TimerScheduler::SetAlarm(void)
|
||||
extern "C" void otPlatAlarmFired(otInstance *aInstance)
|
||||
{
|
||||
otLogFuncEntry();
|
||||
aInstance->mIp6.mTimerScheduler.FireTimers();
|
||||
aInstance->mIp6.mTimerScheduler.ProcessTimers();
|
||||
otLogFuncExit();
|
||||
}
|
||||
|
||||
void TimerScheduler::FireTimers(void)
|
||||
void TimerScheduler::ProcessTimers(void)
|
||||
{
|
||||
uint32_t now = otPlatAlarmGetNow();
|
||||
uint32_t elapsed;
|
||||
Timer *timer = mHead;
|
||||
|
||||
if (timer)
|
||||
{
|
||||
elapsed = now - timer->mT0;
|
||||
|
||||
if (elapsed >= timer->mDt)
|
||||
if (!IsStrictlyBefore(otPlatAlarmGetNow(), timer->mFireTime))
|
||||
{
|
||||
Remove(*timer);
|
||||
timer->Fired();
|
||||
@@ -181,39 +173,16 @@ Ip6::Ip6 *TimerScheduler::GetIp6(void)
|
||||
return Ip6::Ip6FromTimerScheduler(this);
|
||||
}
|
||||
|
||||
bool TimerScheduler::TimerCompare(const Timer &aTimerA, const Timer &aTimerB)
|
||||
bool TimerScheduler::IsStrictlyBefore(uint32_t aTimeA, uint32_t aTimeB)
|
||||
{
|
||||
uint32_t now = otPlatAlarmGetNow();
|
||||
uint32_t elapsedA = now - aTimerA.mT0;
|
||||
uint32_t elapsedB = now - aTimerB.mT0;
|
||||
bool retval = false;
|
||||
uint32_t diff = aTimeA - aTimeB;
|
||||
|
||||
if (aTimerA.mDt >= elapsedA && aTimerB.mDt >= elapsedB)
|
||||
{
|
||||
uint32_t remainingA = aTimerA.mDt - elapsedA;
|
||||
uint32_t remainingB = aTimerB.mDt - elapsedB;
|
||||
// Three cases:
|
||||
// 1) aTimeA is before aTimeB => Difference is negative (last bit of difference is set) => Returning true.
|
||||
// 2) aTimeA is same as aTimeB => Difference is zero (last bit of difference is clear) => Returning false.
|
||||
// 3) aTimeA is after aTimeB => Difference is positive (last bit of difference is clear) => Returning false.
|
||||
|
||||
if (remainingA < remainingB)
|
||||
{
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
else if (aTimerA.mDt < elapsedA && aTimerB.mDt >= elapsedB)
|
||||
{
|
||||
retval = true;
|
||||
}
|
||||
else if (aTimerA.mDt < elapsedA && aTimerB.mDt < elapsedB)
|
||||
{
|
||||
uint32_t expiredByA = elapsedA - aTimerA.mDt;
|
||||
uint32_t expiredByB = elapsedB - aTimerB.mDt;
|
||||
|
||||
if (expiredByB < expiredByA)
|
||||
{
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
return ((diff & (1UL << 31)) != 0);
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
+39
-32
@@ -40,6 +40,7 @@
|
||||
#include <openthread/types.h>
|
||||
#include <openthread/platform/alarm.h>
|
||||
|
||||
#include "common/debug.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -90,12 +91,17 @@ public:
|
||||
void Remove(Timer &aTimer);
|
||||
|
||||
/**
|
||||
* This method processes all running timers.
|
||||
*
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* This method processes the running timers.
|
||||
*
|
||||
*/
|
||||
void FireTimers(void);
|
||||
void ProcessTimers(void);
|
||||
|
||||
private:
|
||||
/**
|
||||
* This method sets the platform alarm based on timer at front of the list.
|
||||
*
|
||||
*/
|
||||
void SetAlarm(void);
|
||||
|
||||
/**
|
||||
* This method returns the pointer to the parent Ip6 structure.
|
||||
@@ -105,20 +111,20 @@ public:
|
||||
*/
|
||||
Ip6::Ip6 *GetIp6(void);
|
||||
|
||||
private:
|
||||
void SetAlarm(void);
|
||||
|
||||
/**
|
||||
* This method compares two timers and returns a value to indicate
|
||||
* which timer will fire earlier.
|
||||
* This static method compares two times and indicates if the first time is strictly before (earlier) than the
|
||||
* second time.
|
||||
*
|
||||
* @param[in] aTimerA The first timer for comparison.
|
||||
* @param[in] aTimerB The second timer for comparison.
|
||||
* This method requires that the difference between the two given times to be smaller than kMaxDt.
|
||||
*
|
||||
* @param[in] aTimerA The first time for comparison.
|
||||
* @param[in] aTimerB The second time for comparison.
|
||||
*
|
||||
* @returns TRUE if aTimeA is before aTimeB.
|
||||
* @returns FALSE if aTimeA is same time or after aTimeB.
|
||||
*
|
||||
* @returns true if aTimerA will fire before aTimerB.
|
||||
* @returns false if aTimerA will fire at the same time or after aTimerB.
|
||||
*/
|
||||
static bool TimerCompare(const Timer &aTimerA, const Timer &aTimerB);
|
||||
static bool IsStrictlyBefore(uint32_t aTimeA, uint32_t aTimeB);
|
||||
|
||||
Timer *mHead;
|
||||
};
|
||||
@@ -132,6 +138,12 @@ class Timer
|
||||
friend class TimerScheduler;
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
kMaxDt = (1UL << 31) - 1, //< Maximum permitted value for parameter `aDt` in `Start` and `StartAt` method.
|
||||
};
|
||||
|
||||
/**
|
||||
* This function pointer is called when the timer expires.
|
||||
*
|
||||
@@ -151,32 +163,24 @@ public:
|
||||
mScheduler(aScheduler),
|
||||
mHandler(aHandler),
|
||||
mContext(aContext),
|
||||
mT0(0),
|
||||
mDt(0),
|
||||
mFireTime(0),
|
||||
mNext(this) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the start time in milliseconds for the timer.
|
||||
* This method returns the fire time of the timer.
|
||||
*
|
||||
* @returns The start time in milliseconds.
|
||||
* @returns The fire time in milliseconds.
|
||||
*
|
||||
*/
|
||||
uint32_t Gett0(void) const { return mT0; }
|
||||
|
||||
/**
|
||||
* This method returns the delta time in milliseconds for the timer.
|
||||
*
|
||||
* @returns The delta time.
|
||||
*
|
||||
*/
|
||||
uint32_t Getdt(void) const { return mDt; }
|
||||
uint32_t GetFireTime(void) const { return mFireTime; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the timer instance is running.
|
||||
*
|
||||
* @retval TRUE If the timer is running.
|
||||
* @retval FALSE If the timer is not running.
|
||||
*
|
||||
*/
|
||||
bool IsRunning(void) const { return (mNext != this); }
|
||||
|
||||
@@ -184,16 +188,20 @@ public:
|
||||
* This method schedules the timer to fire a @p dt milliseconds from now.
|
||||
*
|
||||
* @param[in] aDt The expire time in milliseconds from now.
|
||||
* (aDt must be smaller than or equal to kMaxDt).
|
||||
*
|
||||
*/
|
||||
void Start(uint32_t aDt) { StartAt(GetNow(), aDt); }
|
||||
|
||||
/**
|
||||
* This method schedules the timer to fire at @p dt milliseconds from @p t0.
|
||||
* This method schedules the timer to fire at @p aDt milliseconds from @p aT0.
|
||||
*
|
||||
* @param[in] aT0 The start time in milliseconds.
|
||||
* @param[in] aDt The expire time in milliseconds from @p t0.
|
||||
* @param[in] aDt The expire time in milliseconds from @p aT0.
|
||||
* (aDt must be smaller than or equal to kMaxDt).
|
||||
*
|
||||
*/
|
||||
void StartAt(uint32_t aT0, uint32_t aDt) { mT0 = aT0; mDt = aDt; mScheduler.Add(*this); }
|
||||
void StartAt(uint32_t aT0, uint32_t aDt) { assert(aDt <= kMaxDt); mFireTime = aT0 + aDt; mScheduler.Add(*this); }
|
||||
|
||||
/**
|
||||
* This method stops the timer.
|
||||
@@ -247,8 +255,7 @@ private:
|
||||
TimerScheduler &mScheduler;
|
||||
Handler mHandler;
|
||||
void *mContext;
|
||||
uint32_t mT0;
|
||||
uint32_t mDt;
|
||||
uint32_t mFireTime;
|
||||
Timer *mNext;
|
||||
};
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ Message *Client::CopyAndEnqueueMessage(const Message &aMessage, const QueryMetad
|
||||
if (mRetransmissionTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
nextTransmissionTime = mRetransmissionTimer.Gett0() + mRetransmissionTimer.Getdt();
|
||||
nextTransmissionTime = mRetransmissionTimer.GetFireTime();
|
||||
|
||||
if (aQueryMetadata.IsEarlier(nextTransmissionTime))
|
||||
{
|
||||
|
||||
@@ -192,7 +192,7 @@ void Mpl::AddBufferedMessage(Message &aMessage, uint16_t aSeedId, uint8_t aSeque
|
||||
if (mRetransmissionTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
nextTransmissionTime = mRetransmissionTimer.Gett0() + mRetransmissionTimer.Getdt();
|
||||
nextTransmissionTime = mRetransmissionTimer.GetFireTime();
|
||||
|
||||
if (messageMetadata.IsEarlier(nextTransmissionTime))
|
||||
{
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace ot {
|
||||
DataPollManager::DataPollManager(MeshForwarder &aMeshForwarder):
|
||||
mMeshForwarder(aMeshForwarder),
|
||||
mTimer(aMeshForwarder.GetNetif().GetIp6().mTimerScheduler, &DataPollManager::HandlePollTimer, this),
|
||||
mTimerStartTime(0),
|
||||
mExternalPollPeriod(0),
|
||||
mPollPeriod(0),
|
||||
mEnabled(false),
|
||||
@@ -327,11 +328,12 @@ void DataPollManager::ScheduleNextPoll(PollPeriodSelector aPollPeriodSelector)
|
||||
|
||||
if (mTimer.IsRunning())
|
||||
{
|
||||
mTimer.StartAt(mTimer.Gett0(), mPollPeriod);
|
||||
mTimer.StartAt(mTimerStartTime, mPollPeriod);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTimer.Start(mPollPeriod);
|
||||
mTimerStartTime = Timer::GetNow();
|
||||
mTimer.StartAt(mTimerStartTime, mPollPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,7 @@ private:
|
||||
|
||||
MeshForwarder &mMeshForwarder;
|
||||
Timer mTimer;
|
||||
uint32_t mTimerStartTime;
|
||||
uint32_t mExternalPollPeriod;
|
||||
uint32_t mPollPeriod;
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ KeyManager::KeyManager(ThreadNetif &aThreadNetif):
|
||||
mMleFrameCounter(0),
|
||||
mStoredMacFrameCounter(0),
|
||||
mStoredMleFrameCounter(0),
|
||||
mHoursSinceKeyRotation(0),
|
||||
mKeyRotationTime(kDefaultKeyRotationTime),
|
||||
mKeySwitchGuardTime(kDefaultKeySwitchGuardTime),
|
||||
mKeySwitchGuardEnabled(false),
|
||||
@@ -68,7 +69,7 @@ KeyManager::KeyManager(ThreadNetif &aThreadNetif):
|
||||
void KeyManager::Start(void)
|
||||
{
|
||||
mKeySwitchGuardEnabled = false;
|
||||
mKeyRotationTimer.Start(Timer::HoursToMsec(mKeyRotationTime));
|
||||
StartKeyRotationTimer();
|
||||
}
|
||||
|
||||
void KeyManager::Stop(void)
|
||||
@@ -170,25 +171,7 @@ void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence)
|
||||
mKeyRotationTimer.IsRunning() &&
|
||||
mKeySwitchGuardEnabled)
|
||||
{
|
||||
uint32_t now = Timer::GetNow();
|
||||
uint32_t guardStartTimestamp = mKeyRotationTimer.Gett0();
|
||||
uint32_t guardEndTimestamp = guardStartTimestamp + Timer::HoursToMsec(mKeySwitchGuardTime);
|
||||
|
||||
// Check for timer overflow
|
||||
if (guardEndTimestamp < mKeyRotationTimer.Gett0())
|
||||
{
|
||||
if ((now > guardStartTimestamp) || (now < guardEndTimestamp))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((now > guardStartTimestamp) && (now < guardEndTimestamp))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
VerifyOrExit(mHoursSinceKeyRotation < mKeySwitchGuardTime);
|
||||
}
|
||||
|
||||
mKeySequence = aKeySequence;
|
||||
@@ -200,7 +183,7 @@ void KeyManager::SetCurrentKeySequence(uint32_t aKeySequence)
|
||||
if (mKeyRotationTimer.IsRunning())
|
||||
{
|
||||
mKeySwitchGuardEnabled = true;
|
||||
mKeyRotationTimer.Start(Timer::HoursToMsec(mKeyRotationTime));
|
||||
StartKeyRotationTimer();
|
||||
}
|
||||
|
||||
mNetif.SetStateChangedFlags(OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER);
|
||||
@@ -252,7 +235,6 @@ otError KeyManager::SetKeyRotation(uint32_t aKeyRotation)
|
||||
otError result = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aKeyRotation >= static_cast<uint32_t>(kMinKeyRotationTime), result = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(aKeyRotation <= static_cast<uint32_t>(kMaxKeyRotationTime), result = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
mKeyRotationTime = aKeyRotation;
|
||||
|
||||
@@ -260,6 +242,12 @@ exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
void KeyManager::StartKeyRotationTimer(void)
|
||||
{
|
||||
mHoursSinceKeyRotation = 0;
|
||||
mKeyRotationTimer.Start(kOneHourIntervalInMsec);
|
||||
}
|
||||
|
||||
void KeyManager::HandleKeyRotationTimer(void *aContext)
|
||||
{
|
||||
static_cast<KeyManager *>(aContext)->HandleKeyRotationTimer();
|
||||
@@ -267,7 +255,21 @@ void KeyManager::HandleKeyRotationTimer(void *aContext)
|
||||
|
||||
void KeyManager::HandleKeyRotationTimer(void)
|
||||
{
|
||||
SetCurrentKeySequence(mKeySequence + 1);
|
||||
mHoursSinceKeyRotation++;
|
||||
|
||||
// Order of operations below is important. We should restart the timer (from
|
||||
// last fire time for one hour interval) before potentially calling
|
||||
// `SetCurrentKeySequence()`. `SetCurrentKeySequence()` uses the fact that
|
||||
// timer is running to decide to check for the guard time and to reset the
|
||||
// rotation timer (and the `mHoursSinceKeyRotation`) if it updates the key
|
||||
// sequence.
|
||||
|
||||
mKeyRotationTimer.StartAt(mKeyRotationTimer.GetFireTime(), kOneHourIntervalInMsec);
|
||||
|
||||
if (mHoursSinceKeyRotation >= mKeyRotationTime)
|
||||
{
|
||||
SetCurrentKeySequence(mKeySequence + 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
@@ -272,7 +272,7 @@ public:
|
||||
* This method sets the KeyRotation time.
|
||||
*
|
||||
* The KeyRotation time is the time interval after witch security key will be automatically rotated.
|
||||
* It's value shall be in range [kMinKeyRotationTime, kMaxKeyRotationTime].
|
||||
* Its value shall be larger than or equal to kMinKeyRotationTime.
|
||||
*
|
||||
* @param[in] aKeyRotation The KeyRotation value in hours.
|
||||
*
|
||||
@@ -328,14 +328,15 @@ private:
|
||||
enum
|
||||
{
|
||||
kMinKeyRotationTime = 1,
|
||||
kMaxKeyRotationTime = 0xffffffff / 3600u / 1000u,
|
||||
kDefaultKeyRotationTime = 672,
|
||||
kDefaultKeySwitchGuardTime = 624,
|
||||
kMacKeyOffset = 16,
|
||||
kOneHourIntervalInMsec = 3600u * 1000u,
|
||||
};
|
||||
|
||||
otError ComputeKey(uint32_t aKeySequence, uint8_t *aKey);
|
||||
|
||||
void StartKeyRotationTimer(void);
|
||||
static void HandleKeyRotationTimer(void *aContext);
|
||||
void HandleKeyRotationTimer(void);
|
||||
|
||||
@@ -353,6 +354,7 @@ private:
|
||||
uint32_t mStoredMacFrameCounter;
|
||||
uint32_t mStoredMleFrameCounter;
|
||||
|
||||
uint32_t mHoursSinceKeyRotation;
|
||||
uint32_t mKeyRotationTime;
|
||||
uint32_t mKeySwitchGuardTime;
|
||||
bool mKeySwitchGuardEnabled;
|
||||
|
||||
@@ -1975,7 +1975,7 @@ otError Mle::AddDelayedResponse(Message &aMessage, const Ip6::Address &aDestinat
|
||||
if (mDelayedResponseTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
alarmFireTime = mDelayedResponseTimer.Gett0() + mDelayedResponseTimer.Getdt();
|
||||
alarmFireTime = mDelayedResponseTimer.GetFireTime();
|
||||
|
||||
if (delayedResponse.IsEarlier(alarmFireTime))
|
||||
{
|
||||
|
||||
+80
-32
@@ -103,6 +103,8 @@ int TestOneTimer(void)
|
||||
InitTestTimer();
|
||||
InitCounters();
|
||||
|
||||
printf("TestOneTimer() ");
|
||||
|
||||
sNow = kTimeT0;
|
||||
timer.Start(kTimerInterval);
|
||||
|
||||
@@ -130,12 +132,12 @@ int TestOneTimer(void)
|
||||
sNow = 0 - (kTimerInterval - 2);
|
||||
timer.Start(kTimerInterval);
|
||||
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "TestOneTimer: Start CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestOneTimer: Stop CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "TestOneTimer: Handler CallCount Failed.\n");
|
||||
VerifyOrQuit(sPlatT0 == 0 - (kTimerInterval - 2) && sPlatDt == 10, "TestOneTimer: Start params Failed.\n");
|
||||
VerifyOrQuit(timer.IsRunning(), "TestOneTimer: Timer running Failed.\n");
|
||||
VerifyOrQuit(sTimerOn, "TestOneTimer: Platform Timer State Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "TestOneTimer: Start CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestOneTimer: Stop CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "TestOneTimer: Handler CallCount Failed.\n");
|
||||
VerifyOrQuit(sPlatT0 == 0 - (kTimerInterval - 2) && sPlatDt == 10, "TestOneTimer: Start params Failed.\n");
|
||||
VerifyOrQuit(timer.IsRunning(), "TestOneTimer: Timer running Failed.\n");
|
||||
VerifyOrQuit(sTimerOn, "TestOneTimer: Platform Timer State Failed.\n");
|
||||
|
||||
sNow += kTimerInterval;
|
||||
|
||||
@@ -205,13 +207,19 @@ int TestOneTimer(void)
|
||||
VerifyOrQuit(timer.IsRunning() == false, "TestOneTimer: Timer running Failed.\n");
|
||||
VerifyOrQuit(sTimerOn == false, "TestOneTimer: Platform Timer State Failed.\n");
|
||||
|
||||
printf(" --> PASSED\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the TimerScheduler's behavior of ten timers started and fired.
|
||||
*
|
||||
* `aTimeShift` is added to the t0 and trigger times for all timers. It can be used to check the ten timer behavior
|
||||
* at different start time (e.g., around a 32-bit wrap).
|
||||
*/
|
||||
int TestTenTimers(void)
|
||||
static void TenTimers(uint32_t aTimeShift)
|
||||
{
|
||||
const uint32_t kNumTimers = 10;
|
||||
const uint32_t kNumTriggers = 7;
|
||||
@@ -232,27 +240,27 @@ int TestTenTimers(void)
|
||||
{
|
||||
20,
|
||||
100,
|
||||
(0 - kTimeT0[2]),
|
||||
(ot::Timer::kMaxDt - kTimeT0[2]),
|
||||
100000,
|
||||
1000000,
|
||||
10,
|
||||
(1000 - kTimeT0[6]),
|
||||
ot::Timer::kMaxDt,
|
||||
200,
|
||||
200,
|
||||
200
|
||||
};
|
||||
// Expected timer fire order
|
||||
// timer # Trigger time
|
||||
// 5 1014
|
||||
// 0 1020
|
||||
// 1 1100
|
||||
// 7 1206
|
||||
// 8 1207
|
||||
// 9 1208
|
||||
// 3 101002
|
||||
// 4 1001003
|
||||
// 2 0 <timer wrapped>
|
||||
// 6 1000 <timer wrapped>
|
||||
// timer # Trigger time
|
||||
// 5 1014
|
||||
// 0 1020
|
||||
// 1 1100
|
||||
// 7 1206
|
||||
// 8 1207
|
||||
// 9 1208
|
||||
// 3 101002
|
||||
// 4 1001003
|
||||
// 2 kMaxDt
|
||||
// 6 kMaxDt + 1005
|
||||
const uint32_t kTriggerTimes[kNumTriggers] =
|
||||
{
|
||||
1014,
|
||||
@@ -260,9 +268,8 @@ int TestTenTimers(void)
|
||||
1100,
|
||||
1207,
|
||||
101004,
|
||||
/* timer wrap here */
|
||||
2,
|
||||
1000
|
||||
ot::Timer::kMaxDt,
|
||||
ot::Timer::kMaxDt + kTimeT0[6]
|
||||
};
|
||||
// Expected timers fired by each kTriggerTimes[] value
|
||||
// Trigger # Timers Fired
|
||||
@@ -341,9 +348,23 @@ int TestTenTimers(void)
|
||||
ot::Timer timer7(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[7]);
|
||||
ot::Timer timer8(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[8]);
|
||||
ot::Timer timer9(aInstance.mIp6.mTimerScheduler, TestTimerHandler, &timerContextHandleCounter[9]);
|
||||
ot::Timer *timers[kNumTimers] = {&timer0, &timer1, &timer2, &timer3, &timer4, &timer5, &timer6, &timer7, &timer8, &timer9};
|
||||
ot::Timer *timers[kNumTimers] =
|
||||
{
|
||||
&timer0,
|
||||
&timer1,
|
||||
&timer2,
|
||||
&timer3,
|
||||
&timer4,
|
||||
&timer5,
|
||||
&timer6,
|
||||
&timer7,
|
||||
&timer8,
|
||||
&timer9
|
||||
};
|
||||
size_t i;
|
||||
|
||||
printf("TestTenTimer() with aTimeShift=%-10u ", aTimeShift);
|
||||
|
||||
// Start the Ten timers.
|
||||
|
||||
InitTestTimer();
|
||||
@@ -351,17 +372,18 @@ int TestTenTimers(void)
|
||||
|
||||
for (i = 0; i < kNumTimers ; i++)
|
||||
{
|
||||
sNow = kTimeT0[i];
|
||||
sNow = kTimeT0[i] + aTimeShift;
|
||||
timers[i]->Start(kTimerInterval[i]);
|
||||
}
|
||||
|
||||
// given the order in which timers are started, the TimerScheduler should call otPlatAlarmStartAt 2 times.
|
||||
// one for timer[0] and one for timer[5] which will supercede timer[0].
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestTenTimer: Start CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestTenTimer: Stop CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "TestTenTimer: Handler CallCount Failed.\n");
|
||||
VerifyOrQuit(sPlatT0 == kTimeT0[5] && sPlatDt == kTimerInterval[5], "TestTenTimer: Start params Failed.\n");
|
||||
VerifyOrQuit(sTimerOn, "TestTenTimer: Platform Timer State Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestTenTimer: Start CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestTenTimer: Stop CallCount Failed.\n");
|
||||
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "TestTenTimer: Handler CallCount Failed.\n");
|
||||
VerifyOrQuit(sPlatT0 == kTimeT0[5] + aTimeShift, "TestTenTimer: Start params Failed.\n");
|
||||
VerifyOrQuit(sPlatDt == kTimerInterval[5], "TestTenTimer: Start params Failed.\n");
|
||||
VerifyOrQuit(sTimerOn, "TestTenTimer: Platform Timer State Failed.\n");
|
||||
|
||||
for (i = 0 ; i < kNumTimers ; i++)
|
||||
{
|
||||
@@ -372,7 +394,7 @@ int TestTenTimers(void)
|
||||
|
||||
for (size_t trigger = 0 ; trigger < kNumTriggers ; trigger++)
|
||||
{
|
||||
sNow = kTriggerTimes[trigger];
|
||||
sNow = kTriggerTimes[trigger] + aTimeShift;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -397,7 +419,10 @@ int TestTenTimers(void)
|
||||
|
||||
for (i = 0 ; i < kNumTimers ; i++)
|
||||
{
|
||||
VerifyOrQuit(timers[i]->IsRunning() == kTimerStateAfterTrigger[trigger][i], "TestTenTimer: Timer running Failed.\n");
|
||||
VerifyOrQuit(
|
||||
timers[i]->IsRunning() == kTimerStateAfterTrigger[trigger][i],
|
||||
"TestTenTimer: Timer running Failed.\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +431,29 @@ int TestTenTimers(void)
|
||||
VerifyOrQuit(timerContextHandleCounter[i] == 1, "TestTenTimer: Timer context counter Failed.\n");
|
||||
}
|
||||
|
||||
printf("--> PASSED\n");
|
||||
}
|
||||
|
||||
int TestTenTimers(void)
|
||||
{
|
||||
// Time shift to change the start/fire time of ten timers.
|
||||
const uint32_t kTimeShift[] =
|
||||
{
|
||||
0,
|
||||
100000U,
|
||||
0U - 1U,
|
||||
0U - 1100U,
|
||||
ot::Timer::kMaxDt,
|
||||
ot::Timer::kMaxDt + 1020U,
|
||||
};
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(kTimeShift) / sizeof(kTimeShift[0]); i++)
|
||||
{
|
||||
TenTimers(kTimeShift[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user