701 lines
28 KiB
C++
701 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/array.hpp"
|
|
#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];
|
|
|
|
extern "C" {
|
|
|
|
void otPlatAlarmMilliStop(otInstance *)
|
|
{
|
|
sTimerOn = false;
|
|
sCallCount[kCallCountIndexAlarmStop]++;
|
|
}
|
|
|
|
void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
|
{
|
|
sTimerOn = true;
|
|
sCallCount[kCallCountIndexAlarmStart]++;
|
|
sPlatT0 = aT0;
|
|
sPlatDt = aDt;
|
|
}
|
|
|
|
uint32_t otPlatAlarmMilliGetNow(void)
|
|
{
|
|
return sNow;
|
|
}
|
|
|
|
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
|
void otPlatAlarmMicroStop(otInstance *)
|
|
{
|
|
sTimerOn = false;
|
|
sCallCount[kCallCountIndexAlarmStop]++;
|
|
}
|
|
|
|
void otPlatAlarmMicroStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
|
{
|
|
sTimerOn = true;
|
|
sCallCount[kCallCountIndexAlarmStart]++;
|
|
sPlatT0 = aT0;
|
|
sPlatDt = aDt;
|
|
}
|
|
|
|
uint32_t otPlatAlarmMicroGetNow(void)
|
|
{
|
|
return sNow;
|
|
}
|
|
#endif
|
|
|
|
} // extern "C"
|
|
|
|
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);
|
|
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);
|
|
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);
|
|
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::GetArrayLength(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;
|
|
}
|