3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * https://www.FreeRTOS.org
23 * https://github.com/FreeRTOS
29 * Tests the behaviour of timers. Some timers are created before the scheduler
30 * is started, and some after.
33 /* Standard includes. */
36 /* Scheduler include files. */
41 /* Demo program include files. */
42 #include "TimerDemo.h"
44 #if ( configTIMER_TASK_PRIORITY < 1 )
45 #error configTIMER_TASK_PRIORITY must be set to at least 1 for this test/demo to function correctly.
48 #define tmrdemoDONT_BLOCK ( ( TickType_t ) 0 )
49 #define tmrdemoONE_SHOT_TIMER_PERIOD ( xBasePeriod * ( TickType_t ) 3 )
50 #define tmrdemoNUM_TIMER_RESETS ( ( uint8_t ) 10 )
52 #ifndef tmrTIMER_TEST_TASK_STACK_SIZE
53 #define tmrTIMER_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
56 /*-----------------------------------------------------------*/
58 /* The callback functions used by the timers. These each increment a counter
59 * to indicate which timer has expired. The auto-reload timers that are used by
60 * the test task (as opposed to being used from an ISR) all share the same
61 * prvAutoReloadTimerCallback() callback function, and use the ID of the
62 * pxExpiredTimer parameter passed into that function to know which counter to
63 * increment. The other timers all have their own unique callback function and
64 * simply increment their counters without using the callback function parameter. */
65 static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
66 static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer );
67 static void prvTimerTestTask( void * pvParameters );
68 static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
69 static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer );
71 /* The test functions used by the timer test task. These manipulate the auto
72 * reload and one-shot timers in various ways, then delay, then inspect the timers
73 * to ensure they have behaved as expected. */
74 static void prvTest1_CreateTimersWithoutSchedulerRunning( void );
75 static void prvTest2_CheckTaskAndTimersInitialState( void );
76 static void prvTest3_CheckAutoReloadExpireRates( void );
77 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void );
78 static void prvTest5_CheckBasicOneShotTimerBehaviour( void );
79 static void prvTest6_CheckAutoReloadResetBehaviour( void );
80 static void prvTest7_CheckBacklogBehaviour( void );
81 static void prvResetStartConditionsForNextIteration( void );
83 /*-----------------------------------------------------------*/
85 /* Flag that will be latched to pdFAIL should any unexpected behaviour be
86 * detected in any of the demo tests. */
87 static volatile BaseType_t xTestStatus = pdPASS;
89 /* Flag indicating whether the testing includes the backlog demo. The backlog
90 * demo can be disruptive to other demos because the timer backlog is created by
91 * calling xTaskCatchUpTicks(). */
92 static uint8_t ucIsBacklogDemoEnabled = ( uint8_t ) pdFALSE;
94 /* Counter that is incremented on each cycle of a test. This is used to
95 * detect a stalled task - a test that is no longer running. */
96 static volatile uint32_t ulLoopCounter = 0;
98 /* A set of auto-reload timers - each of which use the same callback function.
99 * The callback function uses the timer ID to index into, and then increment, a
100 * counter in the ucAutoReloadTimerCounters[] array. The callback function stops
101 * xAutoReloadTimers[0] during its callback if ucIsStopNeededInTimerZeroCallback is
102 * pdTRUE. The auto-reload timers referenced from xAutoReloadTimers[] are used by
103 * the prvTimerTestTask task. */
104 static TimerHandle_t xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
105 static uint8_t ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
106 static uint8_t ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdFALSE;
108 /* The one-shot timer is configured to use a callback function that increments
109 * ucOneShotTimerCounter each time it gets called. */
110 static TimerHandle_t xOneShotTimer = NULL;
111 static uint8_t ucOneShotTimerCounter = ( uint8_t ) 0;
113 /* The ISR reload timer is controlled from the tick hook to exercise the timer
114 * API functions that can be used from an ISR. It is configured to increment
115 * ucISRReloadTimerCounter each time its callback function is executed. */
116 static TimerHandle_t xISRAutoReloadTimer = NULL;
117 static uint8_t ucISRAutoReloadTimerCounter = ( uint8_t ) 0;
119 /* The ISR one-shot timer is controlled from the tick hook to exercise the timer
120 * API functions that can be used from an ISR. It is configured to increment
121 * ucISRReloadTimerCounter each time its callback function is executed. */
122 static TimerHandle_t xISROneShotTimer = NULL;
123 static uint8_t ucISROneShotTimerCounter = ( uint8_t ) 0;
125 /* The period of all the timers are a multiple of the base period. The base
126 * period is configured by the parameter to vStartTimerDemoTask(). */
127 static TickType_t xBasePeriod = 0;
129 /*-----------------------------------------------------------*/
131 void vStartTimerDemoTask( TickType_t xBasePeriodIn )
133 /* Start with the timer and counter arrays clear - this is only necessary
134 * where the compiler does not clear them automatically on start up. */
135 memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) );
136 memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) );
138 /* Store the period from which all the timer periods will be generated from
140 xBasePeriod = xBasePeriodIn;
142 /* Create a set of timers for use by this demo/test. */
143 prvTest1_CreateTimersWithoutSchedulerRunning();
145 /* Create the task that will control and monitor the timers. This is
146 * created at a lower priority than the timer service task to ensure, as
147 * far as it is concerned, commands on timers are acted on immediately
148 * (sending a command to the timer service task will unblock the timer service
149 * task, which will then preempt this task). */
150 if( xTestStatus != pdFAIL )
152 xTaskCreate( prvTimerTestTask, "Tmr Tst", tmrTIMER_TEST_TASK_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );
155 /*-----------------------------------------------------------*/
157 void vTimerDemoIncludeBacklogTests( BaseType_t includeBacklogTests )
159 ucIsBacklogDemoEnabled = ( uint8_t ) includeBacklogTests;
161 /*-----------------------------------------------------------*/
163 static void prvTimerTestTask( void * pvParameters )
165 ( void ) pvParameters;
167 /* Create a one-shot timer for use later on in this test. For test purposes it
168 * is created as an auto-reload timer then converted to a one-shot timer. */
169 xOneShotTimer = xTimerCreate( "Oneshot Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
170 tmrdemoONE_SHOT_TIMER_PERIOD, /* The period for the timer. */
171 pdFALSE, /* Autoreload is false, so created as a one-shot timer. */
172 ( void * ) 0, /* The timer identifier. Initialise to 0, then increment each time it is called. */
173 prvOneShotTimerCallback ); /* The callback to be called when the timer expires. */
175 if( xOneShotTimer == NULL )
177 xTestStatus = pdFAIL;
178 configASSERT( xTestStatus );
181 /* Purely for test coverage purposes - change and query the reload mode to
182 * auto-reload then back to one-shot. */
184 /* Change timer to auto-reload. */
185 vTimerSetReloadMode( xOneShotTimer, pdTRUE );
187 /* Timer should now be auto-reload. */
188 configASSERT( uxTimerGetReloadMode( xOneShotTimer ) == pdTRUE );
190 /* Change timer to one-shot, which is what is needed for this test. */
191 vTimerSetReloadMode( xOneShotTimer, pdFALSE );
193 /* Check change to one-shot was successful. */
194 configASSERT( uxTimerGetReloadMode( xOneShotTimer ) == pdFALSE );
196 /* Ensure all the timers are in their expected initial state. This
197 * depends on the timer service task having a higher priority than this task. */
198 prvTest2_CheckTaskAndTimersInitialState();
202 /* Check the auto-reload timers expire at the expected/correct rates. */
203 prvTest3_CheckAutoReloadExpireRates();
205 /* Check the auto-reload timers can be stopped correctly, and correctly
206 * report their state. */
207 prvTest4_CheckAutoReloadTimersCanBeStopped();
209 /* Check the one-shot timer only calls its callback once after it has been
210 * started, and that it reports its state correctly. */
211 prvTest5_CheckBasicOneShotTimerBehaviour();
213 /* Check timer reset behaviour. */
214 prvTest6_CheckAutoReloadResetBehaviour();
216 /* Check timer behaviour when the timer task gets behind in its work. */
217 if( ucIsBacklogDemoEnabled == ( uint8_t ) pdTRUE )
219 prvTest7_CheckBacklogBehaviour();
222 /* Start the timers again to restart all the tests over again. */
223 prvResetStartConditionsForNextIteration();
226 /*-----------------------------------------------------------*/
228 /* This is called to check that the created task is still running and has not
229 * detected any errors. */
230 BaseType_t xAreTimerDemoTasksStillRunning( TickType_t xCycleFrequency )
232 static uint32_t ulLastLoopCounter = 0UL;
233 TickType_t xMaxBlockTimeUsedByTheseTests, xLoopCounterIncrementTimeMax;
234 static TickType_t xIterationsWithoutCounterIncrement = ( TickType_t ) 0, xLastCycleFrequency;
236 if( xLastCycleFrequency != xCycleFrequency )
238 /* The cycle frequency has probably become much faster due to an error
239 * elsewhere. Start counting Iterations again. */
240 xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
241 xLastCycleFrequency = xCycleFrequency;
244 /* Calculate the maximum number of times that it is permissible for this
245 * function to be called without ulLoopCounter being incremented. This is
246 * necessary because the tests in this file block for extended periods, and the
247 * block period might be longer than the time between calls to this function. */
248 xMaxBlockTimeUsedByTheseTests = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
249 xLoopCounterIncrementTimeMax = ( xMaxBlockTimeUsedByTheseTests / xCycleFrequency ) + 1;
251 /* If the demo task is still running then the loop counter is expected to
252 * have incremented every xLoopCounterIncrementTimeMax calls. */
253 if( ulLastLoopCounter == ulLoopCounter )
255 xIterationsWithoutCounterIncrement++;
257 if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax )
259 /* The tests appear to be no longer running (stalled). */
260 xTestStatus = pdFAIL;
265 /* ulLoopCounter changed, so the count of times this function was called
266 * without a change can be reset to zero. */
267 xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
270 ulLastLoopCounter = ulLoopCounter;
272 /* Errors detected in the task itself will have latched xTestStatus
277 /*-----------------------------------------------------------*/
279 static void prvTest1_CreateTimersWithoutSchedulerRunning( void )
283 for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )
285 /* As the timer queue is not yet full, it should be possible to both
286 * create and start a timer. These timers are being started before the
287 * scheduler has been started, so their block times should get set to zero
288 * within the timer API itself. */
289 xAutoReloadTimers[ xTimer ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
290 ( ( xTimer + ( TickType_t ) 1 ) * xBasePeriod ), /* The period for the timer. The plus 1 ensures a period of zero is not specified. */
291 pdTRUE, /* Auto-reload is set to true. */
292 ( void * ) xTimer, /* An identifier for the timer as all the auto-reload timers use the same callback. */
293 prvAutoReloadTimerCallback ); /* The callback to be called when the timer expires. */
295 if( xAutoReloadTimers[ xTimer ] == NULL )
297 xTestStatus = pdFAIL;
298 configASSERT( xTestStatus );
302 configASSERT( strcmp( pcTimerGetName( xAutoReloadTimers[ xTimer ] ), "FR Timer" ) == 0 );
304 /* The scheduler has not yet started, so the block period of
305 * portMAX_DELAY should just get set to zero in xTimerStart(). Also,
306 * the timer queue is not yet full so xTimerStart() should return
308 if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS )
310 xTestStatus = pdFAIL;
311 configASSERT( xTestStatus );
316 /* The timers queue should now be full, so it should be possible to create
317 * another timer, but not possible to start it (the timer queue will not get
318 * drained until the scheduler has been started. */
319 xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
320 ( configTIMER_QUEUE_LENGTH * xBasePeriod ), /* The period for the timer. */
321 pdTRUE, /* Auto-reload is set to true. */
322 ( void * ) xTimer, /* An identifier for the timer as all the auto-reload timers use the same callback. */
323 prvAutoReloadTimerCallback ); /* The callback executed when the timer expires. */
325 if( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] == NULL )
327 xTestStatus = pdFAIL;
328 configASSERT( xTestStatus );
332 if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS )
334 /* This time it would not be expected that the timer could be
335 * started at this point. */
336 xTestStatus = pdFAIL;
337 configASSERT( xTestStatus );
341 /* Create the timers that are used from the tick interrupt to test the timer
342 * API functions that can be called from an ISR. */
343 xISRAutoReloadTimer = xTimerCreate( "ISR AR", /* The text name given to the timer. */
344 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
345 pdTRUE, /* This is an auto-reload timer. */
346 ( void * ) NULL, /* The identifier is not required. */
347 prvISRAutoReloadTimerCallback ); /* The callback that is executed when the timer expires. */
349 xISROneShotTimer = xTimerCreate( "ISR OS", /* The text name given to the timer. */
350 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
351 pdFALSE, /* This is a one-shot timer. */
352 ( void * ) NULL, /* The identifier is not required. */
353 prvISROneShotTimerCallback ); /* The callback that is executed when the timer expires. */
355 if( ( xISRAutoReloadTimer == NULL ) || ( xISROneShotTimer == NULL ) )
357 xTestStatus = pdFAIL;
358 configASSERT( xTestStatus );
361 /*-----------------------------------------------------------*/
363 static void prvTest2_CheckTaskAndTimersInitialState( void )
367 /* Ensure all the timers are in their expected initial state. This depends
368 * on the timer service task having a higher priority than this task.
370 * auto-reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active,
371 * and auto-reload timer configTIMER_QUEUE_LENGTH should not yet be active (it
372 * could not be started prior to the scheduler being started when it was
374 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
376 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
378 xTestStatus = pdFAIL;
379 configASSERT( xTestStatus );
383 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] ) != pdFALSE )
385 xTestStatus = pdFAIL;
386 configASSERT( xTestStatus );
389 /*-----------------------------------------------------------*/
391 static void prvTest3_CheckAutoReloadExpireRates( void )
393 uint8_t ucMaxAllowableValue, ucMinAllowableValue, ucTimer;
394 TickType_t xBlockPeriod, xTimerPeriod, xExpectedNumber;
395 UBaseType_t uxOriginalPriority;
397 /* Check the auto-reload timers expire at the expected rates. Do this at a
398 * high priority for maximum accuracy. This is ok as most of the time is spent
399 * in the Blocked state. */
400 uxOriginalPriority = uxTaskPriorityGet( NULL );
401 vTaskPrioritySet( NULL, ( configMAX_PRIORITIES - 1 ) );
403 /* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow
404 * all the auto-reload timers to expire at least once. */
405 xBlockPeriod = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
406 vTaskDelay( xBlockPeriod );
408 /* Check that all the auto-reload timers have called their callback
409 * function the expected number of times. */
410 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
412 /* The expected number of expires is equal to the block period divided
413 * by the timer period. */
414 xTimerPeriod = ( ( ( TickType_t ) ucTimer + ( TickType_t ) 1 ) * xBasePeriod );
415 xExpectedNumber = xBlockPeriod / xTimerPeriod;
417 ucMaxAllowableValue = ( ( uint8_t ) xExpectedNumber );
418 ucMinAllowableValue = ( uint8_t ) ( ( uint8_t ) xExpectedNumber - ( uint8_t ) 1 ); /* Weird casting to try and please all compilers. */
420 if( ( ucAutoReloadTimerCounters[ ucTimer ] < ucMinAllowableValue ) ||
421 ( ucAutoReloadTimerCounters[ ucTimer ] > ucMaxAllowableValue )
424 xTestStatus = pdFAIL;
425 configASSERT( xTestStatus );
429 /* Return to the original priority. */
430 vTaskPrioritySet( NULL, uxOriginalPriority );
432 if( xTestStatus == pdPASS )
434 /* No errors have been reported so increment the loop counter so the
435 * check task knows this task is still running. */
439 /*-----------------------------------------------------------*/
441 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void )
445 /* Check the auto-reload timers can be stopped correctly, and correctly
446 * report their state. */
448 /* Stop all the active timers. */
449 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
451 /* The timer has not been stopped yet! */
452 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
454 xTestStatus = pdFAIL;
455 configASSERT( xTestStatus );
458 /* Now stop the timer. This will appear to happen immediately to
459 * this task because this task is running at a priority below the
460 * timer service task. */
461 xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
463 /* The timer should now be inactive. */
464 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
466 xTestStatus = pdFAIL;
467 configASSERT( xTestStatus );
471 taskENTER_CRITICAL();
473 /* The timer in array position configTIMER_QUEUE_LENGTH should not
474 * be active. The critical section is used to ensure the timer does
475 * not call its callback between the next line running and the array
476 * being cleared back to zero, as that would mask an error condition. */
477 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( uint8_t ) 0 )
479 xTestStatus = pdFAIL;
480 configASSERT( xTestStatus );
483 /* Clear the timer callback count. */
484 memset( ( void * ) ucAutoReloadTimerCounters, 0, sizeof( ucAutoReloadTimerCounters ) );
488 /* The timers are now all inactive, so this time, after delaying, none
489 * of the callback counters should have incremented. */
490 vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
492 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
494 if( ucAutoReloadTimerCounters[ ucTimer ] != ( uint8_t ) 0 )
496 xTestStatus = pdFAIL;
497 configASSERT( xTestStatus );
501 if( xTestStatus == pdPASS )
503 /* No errors have been reported so increment the loop counter so
504 * the check task knows this task is still running. */
508 /*-----------------------------------------------------------*/
510 static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
512 /* Check the one-shot timer only calls its callback once after it has been
513 * started, and that it reports its state correctly. */
515 /* The one-shot timer should not be active yet. */
516 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
518 xTestStatus = pdFAIL;
519 configASSERT( xTestStatus );
522 if( ucOneShotTimerCounter != ( uint8_t ) 0 )
524 xTestStatus = pdFAIL;
525 configASSERT( xTestStatus );
528 /* Start the one-shot timer and check that it reports its state correctly. */
529 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
531 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
533 xTestStatus = pdFAIL;
534 configASSERT( xTestStatus );
537 /* Delay for three times as long as the one-shot timer period, then check
538 * to ensure it has only called its callback once, and is now not in the
540 vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( TickType_t ) 3 );
542 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
544 xTestStatus = pdFAIL;
545 configASSERT( xTestStatus );
548 if( ucOneShotTimerCounter != ( uint8_t ) 1 )
550 xTestStatus = pdFAIL;
551 configASSERT( xTestStatus );
555 /* Reset the one-shot timer callback count. */
556 ucOneShotTimerCounter = ( uint8_t ) 0;
559 if( xTestStatus == pdPASS )
561 /* No errors have been reported so increment the loop counter so the
562 * check task knows this task is still running. */
566 /*-----------------------------------------------------------*/
568 static void prvTest6_CheckAutoReloadResetBehaviour( void )
572 /* Check timer reset behaviour. */
574 /* Restart the one-shot timer and check it reports its status correctly. */
575 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
577 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
579 xTestStatus = pdFAIL;
580 configASSERT( xTestStatus );
583 /* Restart one of the auto-reload timers and check that it reports its
584 * status correctly. */
585 xTimerStart( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
587 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
589 xTestStatus = pdFAIL;
590 configASSERT( xTestStatus );
593 for( ucTimer = 0; ucTimer < tmrdemoNUM_TIMER_RESETS; ucTimer++ )
595 /* Delay for half as long as the one-shot timer period, then reset it.
596 * It should never expire while this is done, so its callback count should
597 * never increment. */
598 vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 );
600 /* Check both running timers are still active, but have not called their
601 * callback functions. */
602 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
604 xTestStatus = pdFAIL;
605 configASSERT( xTestStatus );
608 if( ucOneShotTimerCounter != ( uint8_t ) 0 )
610 xTestStatus = pdFAIL;
611 configASSERT( xTestStatus );
614 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
616 xTestStatus = pdFAIL;
617 configASSERT( xTestStatus );
620 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] != ( uint8_t ) 0 )
622 xTestStatus = pdFAIL;
623 configASSERT( xTestStatus );
626 /* Reset both running timers. */
627 xTimerReset( xOneShotTimer, tmrdemoDONT_BLOCK );
628 xTimerReset( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
630 if( xTestStatus == pdPASS )
632 /* No errors have been reported so increment the loop counter so
633 * the check task knows this task is still running. */
638 /* Finally delay long enough for both running timers to expire. */
639 vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
641 /* The timers were not reset during the above delay period so should now
642 * both have called their callback functions. */
643 if( ucOneShotTimerCounter != ( uint8_t ) 1 )
645 xTestStatus = pdFAIL;
646 configASSERT( xTestStatus );
649 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] == 0 )
651 xTestStatus = pdFAIL;
652 configASSERT( xTestStatus );
655 /* The one-shot timer should no longer be active, while the auto-reload
656 * timer should still be active. */
657 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
659 xTestStatus = pdFAIL;
660 configASSERT( xTestStatus );
663 if( xTimerIsTimerActive( xOneShotTimer ) == pdTRUE )
665 xTestStatus = pdFAIL;
666 configASSERT( xTestStatus );
669 /* Stop the auto-reload timer again. */
670 xTimerStop( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
672 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )
674 xTestStatus = pdFAIL;
675 configASSERT( xTestStatus );
678 /* Clear the timer callback counts, ready for another iteration of these
680 ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( uint8_t ) 0;
681 ucOneShotTimerCounter = ( uint8_t ) 0;
683 if( xTestStatus == pdPASS )
685 /* No errors have been reported so increment the loop counter so the check
686 * task knows this task is still running. */
690 /*-----------------------------------------------------------*/
692 static void prvTest7_CheckBacklogBehaviour( void )
694 /* Use the first auto-reload timer to test stopping a timer from a
695 * backlogged callback. */
697 /* The timer has not been started yet! */
698 if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) != pdFALSE )
700 xTestStatus = pdFAIL;
701 configASSERT( xTestStatus );
704 /* Prompt the callback function to stop the timer. */
705 ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdTRUE;
707 /* Now start the timer. This will appear to happen immediately to
708 * this task because this task is running at a priority below the timer
709 * service task. Use a timer period of one tick so the call to
710 * xTaskCatchUpTicks() below has minimal impact on other tests that might
712 #define tmrdemoBACKLOG_TIMER_PERIOD ( ( TickType_t ) 1 )
713 xTimerChangePeriod( xAutoReloadTimers[ 0 ], tmrdemoBACKLOG_TIMER_PERIOD, tmrdemoDONT_BLOCK );
715 /* The timer should now be active. */
716 if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) == pdFALSE )
718 xTestStatus = pdFAIL;
719 configASSERT( xTestStatus );
722 /* Arrange for the callback to execute late enough that it will execute
723 * twice, back-to-back. The timer must handle the stop request properly
724 * in spite of the backlog of callbacks. */
725 #define tmrdemoEXPECTED_BACKLOG_EXPIRES ( ( TickType_t ) 2 )
726 xTaskCatchUpTicks( tmrdemoBACKLOG_TIMER_PERIOD * tmrdemoEXPECTED_BACKLOG_EXPIRES );
728 /* The timer should now be inactive. */
729 if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) != pdFALSE )
731 xTestStatus = pdFAIL;
732 configASSERT( xTestStatus );
735 /* Restore the standard timer period, and leave the timer inactive. */
736 xTimerChangePeriod( xAutoReloadTimers[ 0 ], xBasePeriod, tmrdemoDONT_BLOCK );
737 xTimerStop( xAutoReloadTimers[ 0 ], tmrdemoDONT_BLOCK );
739 /* Clear the reload count for the timer used in this test. */
740 ucAutoReloadTimerCounters[ 0 ] = ( uint8_t ) 0;
742 if( xTestStatus == pdPASS )
744 /* No errors have been reported so increment the loop counter so the check
745 * task knows this task is still running. */
749 /*-----------------------------------------------------------*/
751 static void prvResetStartConditionsForNextIteration( void )
755 /* Start the timers again to start all the tests over again. */
757 /* Start the timers again. */
758 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
760 /* The timer has not been started yet! */
761 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
763 xTestStatus = pdFAIL;
764 configASSERT( xTestStatus );
767 /* Now start the timer. This will appear to happen immediately to
768 * this task because this task is running at a priority below the timer
770 xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
772 /* The timer should now be active. */
773 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
775 xTestStatus = pdFAIL;
776 configASSERT( xTestStatus );
780 if( xTestStatus == pdPASS )
782 /* No errors have been reported so increment the loop counter so the
783 * check task knows this task is still running. */
787 /*-----------------------------------------------------------*/
789 void vTimerPeriodicISRTests( void )
791 static TickType_t uxTick = ( TickType_t ) -1;
793 #if ( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) )
795 /* The timer service task is not the highest priority task, so it cannot
796 * be assumed that timings will be exact. Timers should never call their
797 * callback before their expiry time, but a margin is permissible for calling
798 * their callback after their expiry time. If exact timing is required then
799 * configTIMER_TASK_PRIORITY must be set to ensure the timer service task
800 * is the highest priority task in the system.
802 * This function is called from the tick hook. The tick hook is called
803 * even when the scheduler is suspended. Therefore it is possible that the
804 * uxTick count maintained in this function is temporarily ahead of the tick
805 * count maintained by the kernel. When this is the case a message posted from
806 * this function will assume a time stamp in advance of the real time stamp,
807 * which can result in a timer being processed before this function expects it
808 * to. For example, if the kernel's tick count was 100, and uxTick was 102,
809 * then this function will not expect the timer to have expired until the
810 * kernel's tick count is (102 + xBasePeriod), whereas in reality the timer
811 * will expire when the kernel's tick count is (100 + xBasePeriod). For this
812 * reason xMargin is used as an allowable margin for premature timer expires
813 * as well as late timer expires. */
815 /* Windows is not real real time. */
816 const TickType_t xMargin = 20;
818 const TickType_t xMargin = 6;
819 #endif /* _WINDOWS_ */
822 /* Windows is not real real time. */
823 const TickType_t xMargin = 20;
825 const TickType_t xMargin = 4;
826 #endif /* _WINDOWS_ */
827 #endif /* if ( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) ) */
834 /* The timers will have been created, but not started. Start them now
835 * by setting their period. */
836 ucISRAutoReloadTimerCounter = 0;
837 ucISROneShotTimerCounter = 0;
839 /* It is possible that the timer task has not yet made room in the
840 * timer queue. If the timers cannot be started then reset uxTick so
841 * another attempt is made later. */
842 uxTick = ( TickType_t ) -1;
844 /* Try starting first timer. */
845 if( xTimerChangePeriodFromISR( xISRAutoReloadTimer, xBasePeriod, NULL ) == pdPASS )
847 /* First timer was started, try starting the second timer. */
848 if( xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, NULL ) == pdPASS )
850 /* Both timers were started, so set the uxTick back to its
856 /* Second timer could not be started, so stop the first one
858 xTimerStopFromISR( xISRAutoReloadTimer, NULL );
862 else if( uxTick == ( xBasePeriod - xMargin ) )
864 /* Neither timer should have expired yet. */
865 if( ( ucISRAutoReloadTimerCounter != 0 ) || ( ucISROneShotTimerCounter != 0 ) )
867 xTestStatus = pdFAIL;
868 configASSERT( xTestStatus );
871 else if( uxTick == ( xBasePeriod + xMargin ) )
873 /* Both timers should now have expired once. The auto-reload timer will
874 * still be active, but the one-shot timer should now have stopped. */
875 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
877 xTestStatus = pdFAIL;
878 configASSERT( xTestStatus );
881 else if( uxTick == ( ( 2 * xBasePeriod ) - xMargin ) )
883 /* The auto-reload timer will still be active, but the one-shot timer
884 * should now have stopped - however, at this time neither of the timers
885 * should have expired again since the last test. */
886 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
888 xTestStatus = pdFAIL;
889 configASSERT( xTestStatus );
892 else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) )
894 /* The auto-reload timer will still be active, but the one-shot timer
895 * should now have stopped. At this time the auto-reload timer should have
896 * expired again, but the one-shot timer count should not have changed. */
897 if( ucISRAutoReloadTimerCounter != 2 )
899 xTestStatus = pdFAIL;
900 configASSERT( xTestStatus );
903 if( ucISROneShotTimerCounter != 1 )
905 xTestStatus = pdFAIL;
906 configASSERT( xTestStatus );
909 else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( TickType_t ) 2U ) ) )
911 /* The auto-reload timer will still be active, but the one-shot timer
912 * should now have stopped. Again though, at this time, neither timer call
913 * back should have been called since the last test. */
914 if( ucISRAutoReloadTimerCounter != 2 )
916 xTestStatus = pdFAIL;
917 configASSERT( xTestStatus );
920 if( ucISROneShotTimerCounter != 1 )
922 xTestStatus = pdFAIL;
923 configASSERT( xTestStatus );
926 else if( uxTick == ( 3 * xBasePeriod ) )
928 /* Start the one-shot timer again. */
929 xTimerStartFromISR( xISROneShotTimer, NULL );
931 else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) )
933 /* The auto-reload timer and one-shot timer will be active. At
934 * this time the auto-reload timer should have expired again, but the one
935 * shot timer count should not have changed yet. */
936 if( ucISRAutoReloadTimerCounter != 3 )
938 xTestStatus = pdFAIL;
939 configASSERT( xTestStatus );
942 if( ucISROneShotTimerCounter != 1 )
944 xTestStatus = pdFAIL;
945 configASSERT( xTestStatus );
948 /* Now stop the auto-reload timer. The one-shot timer was started
949 * a few ticks ago. */
950 xTimerStopFromISR( xISRAutoReloadTimer, NULL );
952 else if( uxTick == ( 4 * ( xBasePeriod - xMargin ) ) )
954 /* The auto-reload timer is now stopped, and the one-shot timer is
955 * active, but at this time neither timer should have expired since the
957 if( ucISRAutoReloadTimerCounter != 3 )
959 xTestStatus = pdFAIL;
960 configASSERT( xTestStatus );
963 if( ucISROneShotTimerCounter != 1 )
965 xTestStatus = pdFAIL;
966 configASSERT( xTestStatus );
969 else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) )
971 /* The auto-reload timer is now stopped, and the one-shot timer is
972 * active. The one-shot timer should have expired again, but the auto
973 * reload timer should not have executed its callback. */
974 if( ucISRAutoReloadTimerCounter != 3 )
976 xTestStatus = pdFAIL;
977 configASSERT( xTestStatus );
980 if( ucISROneShotTimerCounter != 2 )
982 xTestStatus = pdFAIL;
983 configASSERT( xTestStatus );
986 else if( uxTick == ( 8 * xBasePeriod ) )
988 /* The auto-reload timer is now stopped, and the one-shot timer has
989 * already expired and then stopped itself. Both callback counters should
990 * not have incremented since the last test. */
991 if( ucISRAutoReloadTimerCounter != 3 )
993 xTestStatus = pdFAIL;
994 configASSERT( xTestStatus );
997 if( ucISROneShotTimerCounter != 2 )
999 xTestStatus = pdFAIL;
1000 configASSERT( xTestStatus );
1003 /* Now reset the one-shot timer. */
1004 xTimerResetFromISR( xISROneShotTimer, NULL );
1006 else if( uxTick == ( ( 9 * xBasePeriod ) - xMargin ) )
1008 /* Only the one-shot timer should be running, but it should not have
1009 * expired since the last test. Check the callback counters have not
1010 * incremented, then reset the one-shot timer again. */
1011 if( ucISRAutoReloadTimerCounter != 3 )
1013 xTestStatus = pdFAIL;
1014 configASSERT( xTestStatus );
1017 if( ucISROneShotTimerCounter != 2 )
1019 xTestStatus = pdFAIL;
1020 configASSERT( xTestStatus );
1023 xTimerResetFromISR( xISROneShotTimer, NULL );
1025 else if( uxTick == ( ( 10 * xBasePeriod ) - ( 2 * xMargin ) ) )
1027 /* Only the one-shot timer should be running, but it should not have
1028 * expired since the last test. Check the callback counters have not
1029 * incremented, then reset the one-shot timer again. */
1030 if( ucISRAutoReloadTimerCounter != 3 )
1032 xTestStatus = pdFAIL;
1033 configASSERT( xTestStatus );
1036 if( ucISROneShotTimerCounter != 2 )
1038 xTestStatus = pdFAIL;
1039 configASSERT( xTestStatus );
1042 xTimerResetFromISR( xISROneShotTimer, NULL );
1044 else if( uxTick == ( ( 11 * xBasePeriod ) - ( 3 * xMargin ) ) )
1046 /* Only the one-shot timer should be running, but it should not have
1047 * expired since the last test. Check the callback counters have not
1048 * incremented, then reset the one-shot timer once again. */
1049 if( ucISRAutoReloadTimerCounter != 3 )
1051 xTestStatus = pdFAIL;
1052 configASSERT( xTestStatus );
1055 if( ucISROneShotTimerCounter != 2 )
1057 xTestStatus = pdFAIL;
1058 configASSERT( xTestStatus );
1061 xTimerResetFromISR( xISROneShotTimer, NULL );
1063 else if( uxTick == ( ( 12 * xBasePeriod ) - ( 2 * xMargin ) ) )
1065 /* Only the one-shot timer should have been running and this time it
1066 * should have expired. Check its callback count has been incremented.
1067 * The auto-reload timer is still not running so should still have the same
1068 * count value. This time the one-shot timer is not reset so should not
1069 * restart from its expiry period again. */
1070 if( ucISRAutoReloadTimerCounter != 3 )
1072 xTestStatus = pdFAIL;
1073 configASSERT( xTestStatus );
1076 if( ucISROneShotTimerCounter != 3 )
1078 xTestStatus = pdFAIL;
1079 configASSERT( xTestStatus );
1082 else if( uxTick == ( 15 * xBasePeriod ) )
1084 /* Neither timer should be running now. Check neither callback count
1085 * has incremented, then go back to the start to run these tests all
1087 if( ucISRAutoReloadTimerCounter != 3 )
1089 xTestStatus = pdFAIL;
1090 configASSERT( xTestStatus );
1093 if( ucISROneShotTimerCounter != 3 )
1095 xTestStatus = pdFAIL;
1096 configASSERT( xTestStatus );
1099 uxTick = ( TickType_t ) -1;
1102 /*-----------------------------------------------------------*/
1104 /*** Timer callback functions are defined below here. ***/
1106 static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
1110 uxTimerID = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
1112 if( uxTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
1114 ( ucAutoReloadTimerCounters[ uxTimerID ] )++;
1116 /* Stop timer ID 0 if requested. */
1117 if( ( uxTimerID == ( size_t ) 0 ) && ( ucIsStopNeededInTimerZeroCallback == ( uint8_t ) pdTRUE ) )
1119 xTimerStop( pxExpiredTimer, tmrdemoDONT_BLOCK );
1120 ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdFALSE;
1125 /* The timer ID appears to be unexpected (invalid). */
1126 xTestStatus = pdFAIL;
1127 configASSERT( xTestStatus );
1130 /*-----------------------------------------------------------*/
1132 static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer )
1134 /* A count is kept of the number of times this callback function is executed.
1135 * The count is stored as the timer's ID. This is only done to test the
1136 * vTimerSetTimerID() function. */
1137 static size_t uxCallCount = 0;
1138 size_t uxLastCallCount;
1140 /* Obtain the timer's ID, which should be a count of the number of times
1141 * this callback function has been executed. */
1142 uxLastCallCount = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
1143 configASSERT( uxLastCallCount == uxCallCount );
1145 /* Increment the call count, then save it back as the timer's ID. This is
1146 * only done to test the vTimerSetTimerID() API function. */
1148 vTimerSetTimerID( pxExpiredTimer, ( void * ) uxLastCallCount );
1151 ucOneShotTimerCounter++;
1153 /*-----------------------------------------------------------*/
1155 static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
1157 /* The parameter is not used in this case as only one timer uses this
1158 * callback function. */
1159 ( void ) pxExpiredTimer;
1161 ucISRAutoReloadTimerCounter++;
1163 /*-----------------------------------------------------------*/
1165 static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer )
1167 /* The parameter is not used in this case as only one timer uses this
1168 * callback function. */
1169 ( void ) pxExpiredTimer;
1171 ucISROneShotTimerCounter++;
1173 /*-----------------------------------------------------------*/