Files
openthread/tests/unit/test_timer.cpp
T
Abtin Keshavarzian f7fd2b0813 [timer] add RemoveAll() method for use by unit test (#6814)
This commit adds a new static method `Timer::RemoveAll()` which
removes all running timers from the `Scheduler`. This method is only
intended for use by by `test_timer` unit test, allowing it to remove
any timers that may be started from constructors of different objects
in an OT instance before starting the unit test. With this change, we
can have timers started from constructors.

To ensure that the `RemoveAll()` is only used by the unit test, it is
defined as a `protected` method which can still be used in the test
which defines and uses `TestTimer` as a sub-class of `Timer`.
2021-07-14 12:10:21 -07:00

685 lines
28 KiB
C++

/*
* Copyright (c) 2016, 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.
*/
#include "test_platform.h"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/timer.hpp"
enum
{
kCallCountIndexAlarmStop = 0,
kCallCountIndexAlarmStart,
kCallCountIndexTimerHandler,
kCallCountIndexMax
};
uint32_t sNow;
uint32_t sPlatT0;
uint32_t sPlatDt;
bool sTimerOn;
uint32_t sCallCount[kCallCountIndexMax];
void testTimerAlarmStop(otInstance *)
{
sTimerOn = false;
sCallCount[kCallCountIndexAlarmStop]++;
}
void testTimerAlarmStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
{
sTimerOn = true;
sCallCount[kCallCountIndexAlarmStart]++;
sPlatT0 = aT0;
sPlatDt = aDt;
}
uint32_t testTimerAlarmGetNow(void)
{
return sNow;
}
void InitTestTimer(void)
{
g_testPlatAlarmStop = testTimerAlarmStop;
g_testPlatAlarmStartAt = testTimerAlarmStartAt;
g_testPlatAlarmGetNow = testTimerAlarmGetNow;
}
void InitCounters(void)
{
memset(sCallCount, 0, sizeof(sCallCount));
}
/**
* `TestTimer` sub-classes `ot::TimerMilli` and provides a handler and a counter to keep track of number of times timer
* gets fired.
*/
template <typename TimerType> class TestTimer : public TimerType
{
public:
explicit TestTimer(ot::Instance &aInstance)
: TimerType(aInstance, TestTimer::HandleTimerFired)
, mFiredCounter(0)
{
}
static void HandleTimerFired(ot::Timer &aTimer) { static_cast<TestTimer &>(aTimer).HandleTimerFired(); }
void HandleTimerFired(void)
{
sCallCount[kCallCountIndexTimerHandler]++;
mFiredCounter++;
}
uint32_t GetFiredCounter(void) { return mFiredCounter; }
void ResetFiredCounter(void) { mFiredCounter = 0; }
static void RemoveAll(ot::Instance &aInstance) { TimerType::RemoveAll(aInstance); }
private:
uint32_t mFiredCounter; //< Number of times timer has been fired so far
};
template <typename TimerType> void AlarmFired(otInstance *aInstance);
template <> void AlarmFired<ot::TimerMilli>(otInstance *aInstance)
{
otPlatAlarmMilliFired(aInstance);
}
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
template <> void AlarmFired<ot::TimerMicro>(otInstance *aInstance)
{
otPlatAlarmMicroFired(aInstance);
}
#endif
/**
* Test the TimerScheduler's behavior of one timer started and fired.
*/
template <typename TimerType> int TestOneTimer(void)
{
const uint32_t kTimeT0 = 1000;
const uint32_t kTimerInterval = 10;
ot::Instance * instance = testInitInstance();
TestTimer<TimerType> timer(*instance);
// Test one Timer basic operation.
TestTimer<TimerType>::RemoveAll(*instance);
InitTestTimer();
InitCounters();
printf("TestOneTimer() ");
sNow = kTimeT0;
timer.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == 1000 && sPlatDt == 10, "Start params Failed.");
VerifyOrQuit(timer.IsRunning(), "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
sNow += kTimerInterval;
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "Handler CallCount Failed.");
VerifyOrQuit(timer.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == false, "Platform Timer State Failed.");
// Test one Timer that spans the 32-bit wrap.
InitCounters();
sNow = 0 - (kTimerInterval - 2);
timer.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == 0 - (kTimerInterval - 2) && sPlatDt == 10, "Start params Failed.");
VerifyOrQuit(timer.IsRunning(), "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
sNow += kTimerInterval;
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "Handler CallCount Failed.");
VerifyOrQuit(timer.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == false, "Platform Timer State Failed.");
// Test one Timer that is late by several msec
InitCounters();
sNow = kTimeT0;
timer.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == 1000 && sPlatDt == 10, "Start params Failed.");
VerifyOrQuit(timer.IsRunning(), "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
sNow += kTimerInterval + 5;
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "Handler CallCount Failed.");
VerifyOrQuit(timer.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == false, "Platform Timer State Failed.");
// Test one Timer that is early by several msec
InitCounters();
sNow = kTimeT0;
timer.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == 1000 && sPlatDt == 10, "Start params Failed.");
VerifyOrQuit(timer.IsRunning(), "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
sNow += kTimerInterval - 2;
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(timer.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(sTimerOn == true, "Platform Timer State Failed.");
sNow += kTimerInterval;
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "Handler CallCount Failed.");
VerifyOrQuit(timer.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == false, "Platform Timer State Failed.");
printf(" --> PASSED\n");
testFreeInstance(instance);
return 0;
}
/**
* Test the TimerScheduler's behavior of two timers started and fired.
*/
template <typename TimerType> int TestTwoTimers(void)
{
const uint32_t kTimeT0 = 1000;
const uint32_t kTimerInterval = 10;
ot::Instance * instance = testInitInstance();
TestTimer<TimerType> timer1(*instance);
TestTimer<TimerType> timer2(*instance);
TestTimer<TimerType>::RemoveAll(*instance);
InitTestTimer();
printf("TestTwoTimers() ");
// Test when second timer stars at the fire time of first timer (before alarm callback).
InitCounters();
sNow = kTimeT0;
timer1.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == kTimeT0 && sPlatDt == kTimerInterval, "Start params Failed.");
VerifyOrQuit(timer1.IsRunning(), "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
sNow += kTimerInterval;
timer2.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == kTimeT0 && sPlatDt == kTimerInterval, "Start params Failed.");
VerifyOrQuit(timer1.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "Handler CallCount Failed.");
VerifyOrQuit(timer1.GetFiredCounter() == 1, "Fire Counter failed.");
VerifyOrQuit(sPlatT0 == sNow && sPlatDt == kTimerInterval, "Start params Failed.");
VerifyOrQuit(timer1.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(sTimerOn == true, "Platform Timer State Failed.");
sNow += kTimerInterval;
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 2, "Handler CallCount Failed.");
VerifyOrQuit(timer2.GetFiredCounter() == 1, "Fire Counter failed.");
VerifyOrQuit(timer1.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == false, "Platform Timer State Failed.");
// Test when second timer starts at the fire time of first timer (before AlarmFired<TimerType>()) and its fire time
// is before the first timer. Ensure that the second timer handler is invoked before the first one.
InitCounters();
timer1.ResetFiredCounter();
timer2.ResetFiredCounter();
sNow = kTimeT0;
timer1.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == kTimeT0 && sPlatDt == kTimerInterval, "Start params Failed.");
VerifyOrQuit(timer1.IsRunning(), "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
sNow += kTimerInterval;
timer2.StartAt(ot::TimeMilli(kTimeT0), kTimerInterval - 2); // Timer 2 is even before timer 1
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(timer1.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "Handler CallCount Failed.");
VerifyOrQuit(timer2.GetFiredCounter() == 1, "Fire Counter failed.");
VerifyOrQuit(sPlatT0 == sNow && sPlatDt == 0, "Start params Failed.");
VerifyOrQuit(timer1.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == true, "Platform Timer State Failed.");
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 2, "Handler CallCount Failed.");
VerifyOrQuit(timer1.GetFiredCounter() == 1, "Fire Counter failed.");
VerifyOrQuit(timer1.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == false, "Platform Timer State Failed.");
// Timer 1 fire callback is late by some ticks/ms, and second timer is scheduled (before call to
// AlarmFired) with a maximum interval. This is to test (corner-case) scenario where the fire time of two
// timers spanning over the maximum interval.
InitCounters();
timer1.ResetFiredCounter();
timer2.ResetFiredCounter();
sNow = kTimeT0;
timer1.Start(kTimerInterval);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == kTimeT0 && sPlatDt == kTimerInterval, "Start params Failed.");
VerifyOrQuit(timer1.IsRunning(), "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
sNow += kTimerInterval + 5;
timer2.Start(ot::Timer::kMaxDelay);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 1, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "Handler CallCount Failed.");
VerifyOrQuit(timer1.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(sTimerOn, "Platform Timer State Failed.");
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 1, "Handler CallCount Failed.");
VerifyOrQuit(timer1.GetFiredCounter() == 1, "Fire Counter failed.");
VerifyOrQuit(sPlatT0 == sNow, "Start params Failed.");
VerifyOrQuit(sPlatDt == ot::Timer::kMaxDelay, "Start params Failed.");
VerifyOrQuit(timer1.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == true, "Timer running Failed.");
VerifyOrQuit(sTimerOn == true, "Platform Timer State Failed.");
sNow += ot::Timer::kMaxDelay;
AlarmFired<TimerType>(instance);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 1, "Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 2, "Handler CallCount Failed.");
VerifyOrQuit(timer2.GetFiredCounter() == 1, "Fire Counter failed.");
VerifyOrQuit(timer1.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(timer2.IsRunning() == false, "Timer running Failed.");
VerifyOrQuit(sTimerOn == false, "Platform Timer State Failed.");
printf(" --> PASSED\n");
testFreeInstance(instance);
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).
*/
template <typename TimerType> static void TenTimers(uint32_t aTimeShift)
{
const uint32_t kNumTimers = 10;
const uint32_t kNumTriggers = 7;
const uint32_t kTimeT0[kNumTimers] = {1000, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008};
const uint32_t kTimerInterval[kNumTimers] = {
20, 100, (ot::Timer::kMaxDelay - kTimeT0[2]), 100000, 1000000, 10, ot::Timer::kMaxDelay, 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 kMaxDuration
// 6 kMaxDuration + 1005
const uint32_t kTriggerTimes[kNumTriggers] = {
1014, 1020, 1100, 1207, 101004, ot::Timer::kMaxDelay, ot::Timer::kMaxDelay + kTimeT0[6]};
// Expected timers fired by each kTriggerTimes[] value
// Trigger # Timers Fired
// 0 5
// 1 0
// 2 1
// 3 7, 8
// 4 9, 3
// 5 4, 2
// 6 6
const bool kTimerStateAfterTrigger[kNumTriggers][kNumTimers] = {
{true, true, true, true, true, false, true, true, true, true}, // 5
{false, true, true, true, true, false, true, true, true, true}, // 0
{false, false, true, true, true, false, true, true, true, true}, // 1
{false, false, true, true, true, false, true, false, false, true}, // 7, 8
{false, false, true, false, true, false, true, false, false, false}, // 9, 3
{false, false, false, false, false, false, true, false, false, false}, // 4, 2
{false, false, false, false, false, false, false, false, false, false} // 6
};
const bool kSchedulerStateAfterTrigger[kNumTriggers] = {true, true, true, true, true, true, false};
const uint32_t kTimerHandlerCountAfterTrigger[kNumTriggers] = {1, 2, 3, 5, 7, 9, 10};
const uint32_t kTimerStopCountAfterTrigger[kNumTriggers] = {0, 0, 0, 0, 0, 0, 1};
const uint32_t kTimerStartCountAfterTrigger[kNumTriggers] = {3, 4, 5, 7, 9, 11, 11};
ot::Instance *instance = testInitInstance();
TestTimer<TimerType> timer0(*instance);
TestTimer<TimerType> timer1(*instance);
TestTimer<TimerType> timer2(*instance);
TestTimer<TimerType> timer3(*instance);
TestTimer<TimerType> timer4(*instance);
TestTimer<TimerType> timer5(*instance);
TestTimer<TimerType> timer6(*instance);
TestTimer<TimerType> timer7(*instance);
TestTimer<TimerType> timer8(*instance);
TestTimer<TimerType> timer9(*instance);
TestTimer<TimerType> *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.
TestTimer<TimerType>::RemoveAll(*instance);
InitTestTimer();
InitCounters();
for (i = 0; i < kNumTimers; i++)
{
sNow = kTimeT0[i] + aTimeShift;
timers[i]->Start(kTimerInterval[i]);
}
// given the order in which timers are started, the TimerScheduler should call otPlatAlarmMilliStartAt 2 times.
// one for timer[0] and one for timer[5] which will supercede timer[0].
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == 2, "TestTenTimer: Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == 0, "TestTenTimer: Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == 0, "TestTenTimer: Handler CallCount Failed.");
VerifyOrQuit(sPlatT0 == kTimeT0[5] + aTimeShift, "TestTenTimer: Start params Failed.");
VerifyOrQuit(sPlatDt == kTimerInterval[5], "TestTenTimer: Start params Failed.");
VerifyOrQuit(sTimerOn, "TestTenTimer: Platform Timer State Failed.");
for (i = 0; i < kNumTimers; i++)
{
VerifyOrQuit(timers[i]->IsRunning(), "TestTenTimer: Timer running Failed.");
}
// Issue the triggers and test the State after each trigger.
for (size_t trigger = 0; trigger < kNumTriggers; trigger++)
{
sNow = kTriggerTimes[trigger] + aTimeShift;
do
{
// By design, each call to AlarmFired<TimerType>() can result in 0 or 1 calls to a timer handler.
// For some combinations of sNow and Timers queued, it is necessary to call AlarmFired<TimerType>()
// multiple times in order to handle all the expired timers. It can be determined that another
// timer is ready to be triggered by examining the aDt arg passed into otPlatAlarmMilliStartAt(). If
// that value is 0, then AlarmFired should be fired immediately. This loop calls
// AlarmFired<TimerType>() the requisite number of times based on the aDt argument.
AlarmFired<TimerType>(instance);
} while (sPlatDt == 0);
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStart] == kTimerStartCountAfterTrigger[trigger],
"TestTenTimer: Start CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexAlarmStop] == kTimerStopCountAfterTrigger[trigger],
"TestTenTimer: Stop CallCount Failed.");
VerifyOrQuit(sCallCount[kCallCountIndexTimerHandler] == kTimerHandlerCountAfterTrigger[trigger],
"TestTenTimer: Handler CallCount Failed.");
VerifyOrQuit(sTimerOn == kSchedulerStateAfterTrigger[trigger], "TestTenTimer: Platform Timer State Failed.");
for (i = 0; i < kNumTimers; i++)
{
VerifyOrQuit(timers[i]->IsRunning() == kTimerStateAfterTrigger[trigger][i],
"TestTenTimer: Timer running Failed.");
}
}
for (i = 0; i < kNumTimers; i++)
{
VerifyOrQuit(timers[i]->GetFiredCounter() == 1, "TestTenTimer: Timer fired counter Failed.");
}
printf("--> PASSED\n");
testFreeInstance(instance);
}
template <typename TimerType> 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::kMaxDelay, ot::Timer::kMaxDelay + 1020U,
};
size_t i;
for (i = 0; i < OT_ARRAY_LENGTH(kTimeShift); i++)
{
TenTimers<TimerType>(kTimeShift[i]);
}
return 0;
}
/**
* Test the `Timer::Time` class.
*/
int TestTimerTime(void)
{
const uint32_t kMaxTime = 0xffffffff;
const uint32_t kStartTimes[] = {0, 100, kMaxTime / 2, kMaxTime - 100, kMaxTime};
const uint32_t kDurations[] = {1, 100, ot::Timer::kMaxDelay - 1, ot::Timer::kMaxDelay};
ot::Time t1;
ot::Time t2;
for (uint32_t startTime : kStartTimes)
{
for (uint32_t duration : kDurations)
{
printf("TestTimerTime() start=%-10x duration=%-10x ", startTime, duration);
t1.SetValue(startTime);
VerifyOrQuit(t1.GetValue() == startTime, "Time::SetValue() failed.");
t2 = t1;
VerifyOrQuit(t1.GetValue() == startTime, "Time assignment failed.");
VerifyOrQuit(t1 == t2, "Time == failed.");
VerifyOrQuit(!(t1 != t2), "Time != failed.");
VerifyOrQuit(!(t1 < t2), "Time < failed.");
VerifyOrQuit((t1 <= t2), "Time <= failed.");
VerifyOrQuit(!(t1 > t2), "Time > failed.");
VerifyOrQuit((t1 >= t2), "Time >= failed.");
VerifyOrQuit(t2 - t1 == 0, "Time difference failed");
t2 = t1 + duration;
VerifyOrQuit(!(t1 == t2), "Time == failed.");
VerifyOrQuit((t1 != t2), "Time != failed.");
VerifyOrQuit((t1 < t2), "Time < failed.");
VerifyOrQuit((t1 <= t2), "Time <= failed.");
VerifyOrQuit(!(t1 > t2), "Time > failed.");
VerifyOrQuit(!(t1 >= t2), "Time >= failed.");
VerifyOrQuit(t2 - t1 == duration, "Time difference failed");
t2 = t1;
t2 += duration;
VerifyOrQuit(!(t1 == t2), "Time == failed.");
VerifyOrQuit((t1 != t2), "Time != failed.");
VerifyOrQuit((t1 < t2), "Time < failed.");
VerifyOrQuit((t1 <= t2), "Time <= failed.");
VerifyOrQuit(!(t1 > t2), "Time > failed.");
VerifyOrQuit(!(t1 >= t2), "Time >= failed.");
VerifyOrQuit(t2 - t1 == duration, "Time difference failed");
t2 = t1 - duration;
VerifyOrQuit(!(t1 == t2), "Time == failed.");
VerifyOrQuit((t1 != t2), "Time != failed.");
VerifyOrQuit(!(t1 < t2), "Time < failed.");
VerifyOrQuit(!(t1 <= t2), "Time <= failed.");
VerifyOrQuit((t1 > t2), "Time > failed.");
VerifyOrQuit((t1 >= t2), "Time >= failed.");
VerifyOrQuit(t1 - t2 == duration, "Time difference failed");
t2 = t1;
t2 -= duration;
VerifyOrQuit(!(t1 == t2), "Time == failed.");
VerifyOrQuit((t1 != t2), "Time != failed.");
VerifyOrQuit(!(t1 < t2), "Time < failed.");
VerifyOrQuit(!(t1 <= t2), "Time <= failed.");
VerifyOrQuit((t1 > t2), "Time > failed.");
VerifyOrQuit((t1 >= t2), "Time >= failed.");
VerifyOrQuit(t1 - t2 == duration, "Time difference failed");
t2 = t1.GetDistantFuture();
VerifyOrQuit((t1 < t2), "GetDistanceFuture() failed");
t2 += 1;
VerifyOrQuit(!(t1 < t2), "GetDistanceFuture() failed");
t2 = t1.GetDistantPast();
VerifyOrQuit((t1 > t2), "GetDistantPast() failed");
t2 -= 1;
VerifyOrQuit(!(t1 > t2), "GetDistantPast() failed");
printf("--> PASSED\n");
}
}
return 0;
}
template <typename TimerType> void RunTimerTests(void)
{
TestOneTimer<TimerType>();
TestTwoTimers<TimerType>();
TestTenTimers<TimerType>();
}
int main(void)
{
RunTimerTests<ot::TimerMilli>();
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
RunTimerTests<ot::TimerMicro>();
#endif
TestTimerTime();
printf("All tests passed\n");
return 0;
}