/* * 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/num_utils.hpp" #include "common/timer.hpp" #include "instance/instance.hpp" namespace ot { 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 `TimerMilli` and provides a handler and a counter to keep track of number of times timer * gets fired. */ template class TestTimer : public TimerType { public: explicit TestTimer(Instance &aInstance) : TimerType(aInstance, TestTimer::HandleTimerFired) , mFiredCounter(0) { } static void HandleTimerFired(Timer &aTimer) { static_cast(aTimer).HandleTimerFired(); } void HandleTimerFired(void) { sCallCount[kCallCountIndexTimerHandler]++; mFiredCounter++; } uint32_t GetFiredCounter(void) { return mFiredCounter; } void ResetFiredCounter(void) { mFiredCounter = 0; } static void RemoveAll(Instance &aInstance) { TimerType::RemoveAll(aInstance); } private: uint32_t mFiredCounter; //< Number of times timer has been fired so far }; template void AlarmFired(otInstance *aInstance); template <> void AlarmFired(otInstance *aInstance) { otPlatAlarmMilliFired(aInstance); } #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE template <> void AlarmFired(otInstance *aInstance) { otPlatAlarmMicroFired(aInstance); } #endif /** * Test the TimerScheduler's behavior of one timer started and fired. */ template int TestOneTimer(void) { const uint32_t kTimeT0 = 1000; const uint32_t kTimerInterval = 10; Instance *instance = testInitInstance(); TestTimer timer(*instance); // Test one Timer basic operation. TestTimer::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(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(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(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(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(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 int TestTwoTimers(void) { const uint32_t kTimeT0 = 1000; const uint32_t kTimerInterval = 10; Instance *instance = testInitInstance(); TestTimer timer1(*instance); TestTimer timer2(*instance); TestTimer::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(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(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()) 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(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(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(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(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(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 == 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 += Timer::kMaxDelay; AlarmFired(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 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, (Timer::kMaxDelay - kTimeT0[2]), 100000, 1000000, 10, 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, Timer::kMaxDelay, 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}; Instance *instance = testInitInstance(); TestTimer timer0(*instance); TestTimer timer1(*instance); TestTimer timer2(*instance); TestTimer timer3(*instance); TestTimer timer4(*instance); TestTimer timer5(*instance); TestTimer timer6(*instance); TestTimer timer7(*instance); TestTimer timer8(*instance); TestTimer timer9(*instance); TestTimer *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::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 supersede 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() 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() // 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() the requisite number of times based on the aDt argument. AlarmFired(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 int TestTenTimers(void) { // Time shift to change the start/fire time of ten timers. const uint32_t kTimeShift[] = { 0, 100000U, 0U - 1U, 0U - 1100U, Timer::kMaxDelay, Timer::kMaxDelay + 1020U, }; size_t i; for (i = 0; i < GetArrayLength(kTimeShift); i++) { TenTimers(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, Timer::kMaxDelay - 1, Timer::kMaxDelay}; Time t1; 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) && !(t1 > t2), "GetDistanceFuture() failed"); t2 += 1; VerifyOrQuit(!(t1 < t2) || (t1 > t2), "GetDistanceFuture() failed"); t2 = t1.GetDistantPast(); VerifyOrQuit((t1 > t2) && !(t1 < t2), "GetDistantPast() failed"); t2 -= 1; VerifyOrQuit(!(t1 > t2) || (t1 < t2), "GetDistantPast() failed"); VerifyOrQuit(Min(t1, t1.GetDistantFuture()) == t1); VerifyOrQuit(Min(t1.GetDistantFuture(), t1) == t1); VerifyOrQuit(Max(t1, t1.GetDistantPast()) == t1); VerifyOrQuit(Max(t1.GetDistantPast(), t1) == t1); printf("--> PASSED\n"); } } return 0; } template void RunTimerTests(void) { TestOneTimer(); TestTwoTimers(); TestTenTimers(); } } // namespace ot int main(void) { ot::RunTimerTests(); #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE ot::RunTimerTests(); #endif ot::TestTimerTime(); printf("All tests passed\n"); return 0; }