2 * FreeRTOS Kernel V10.1.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
30 * Tests the behaviour of timers. Some timers are created before the scheduler
\r
31 * is started, and some after.
\r
34 /* Standard includes. */
\r
37 /* Scheduler include files. */
\r
38 #include "FreeRTOS.h"
\r
42 /* Demo program include files. */
\r
43 #include "TimerDemo.h"
\r
45 #if ( configTIMER_TASK_PRIORITY < 1 )
\r
46 #error configTIMER_TASK_PRIORITY must be set to at least 1 for this test/demo to function correctly.
\r
49 #define tmrdemoDONT_BLOCK ( ( TickType_t ) 0 )
\r
50 #define tmrdemoONE_SHOT_TIMER_PERIOD ( xBasePeriod * ( TickType_t ) 3 )
\r
51 #define trmdemoNUM_TIMER_RESETS ( ( uint8_t ) 10 )
\r
53 /*-----------------------------------------------------------*/
\r
55 /* The callback functions used by the timers. These each increment a counter
\r
56 to indicate which timer has expired. The auto-reload timers that are used by
\r
57 the test task (as opposed to being used from an ISR) all share the same
\r
58 prvAutoReloadTimerCallback() callback function, and use the ID of the
\r
59 pxExpiredTimer parameter passed into that function to know which counter to
\r
60 increment. The other timers all have their own unique callback function and
\r
61 simply increment their counters without using the callback function parameter. */
\r
62 static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
\r
63 static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer );
\r
64 static void prvTimerTestTask( void *pvParameters );
\r
65 static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
\r
66 static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer );
\r
68 /* The test functions used by the timer test task. These manipulate the auto
\r
69 reload and one shot timers in various ways, then delay, then inspect the timers
\r
70 to ensure they have behaved as expected. */
\r
71 static void prvTest1_CreateTimersWithoutSchedulerRunning( void );
\r
72 static void prvTest2_CheckTaskAndTimersInitialState( void );
\r
73 static void prvTest3_CheckAutoReloadExpireRates( void );
\r
74 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void );
\r
75 static void prvTest5_CheckBasicOneShotTimerBehaviour( void );
\r
76 static void prvTest6_CheckAutoReloadResetBehaviour( void );
\r
77 static void prvResetStartConditionsForNextIteration( void );
\r
79 /*-----------------------------------------------------------*/
\r
81 /* Flag that will be latched to pdFAIL should any unexpected behaviour be
\r
82 detected in any of the demo tests. */
\r
83 static volatile BaseType_t xTestStatus = pdPASS;
\r
85 /* Counter that is incremented on each cycle of a test. This is used to
\r
86 detect a stalled task - a test that is no longer running. */
\r
87 static volatile uint32_t ulLoopCounter = 0;
\r
89 /* A set of auto reload timers - each of which use the same callback function.
\r
90 The callback function uses the timer ID to index into, and then increment, a
\r
91 counter in the ucAutoReloadTimerCounters[] array. The auto reload timers
\r
92 referenced from xAutoReloadTimers[] are used by the prvTimerTestTask task. */
\r
93 static TimerHandle_t xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
\r
94 static uint8_t ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
\r
96 /* The one shot timer is configured to use a callback function that increments
\r
97 ucOneShotTimerCounter each time it gets called. */
\r
98 static TimerHandle_t xOneShotTimer = NULL;
\r
99 static uint8_t ucOneShotTimerCounter = ( uint8_t ) 0;
\r
101 /* The ISR reload timer is controlled from the tick hook to exercise the timer
\r
102 API functions that can be used from an ISR. It is configured to increment
\r
103 ucISRReloadTimerCounter each time its callback function is executed. */
\r
104 static TimerHandle_t xISRAutoReloadTimer = NULL;
\r
105 static uint8_t ucISRAutoReloadTimerCounter = ( uint8_t ) 0;
\r
107 /* The ISR one shot timer is controlled from the tick hook to exercise the timer
\r
108 API functions that can be used from an ISR. It is configured to increment
\r
109 ucISRReloadTimerCounter each time its callback function is executed. */
\r
110 static TimerHandle_t xISROneShotTimer = NULL;
\r
111 static uint8_t ucISROneShotTimerCounter = ( uint8_t ) 0;
\r
113 /* The period of all the timers are a multiple of the base period. The base
\r
114 period is configured by the parameter to vStartTimerDemoTask(). */
\r
115 static TickType_t xBasePeriod = 0;
\r
117 /*-----------------------------------------------------------*/
\r
119 void vStartTimerDemoTask( TickType_t xBasePeriodIn )
\r
121 /* Start with the timer and counter arrays clear - this is only necessary
\r
122 where the compiler does not clear them automatically on start up. */
\r
123 memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) );
\r
124 memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) );
\r
126 /* Store the period from which all the timer periods will be generated from
\r
128 xBasePeriod = xBasePeriodIn;
\r
130 /* Create a set of timers for use by this demo/test. */
\r
131 prvTest1_CreateTimersWithoutSchedulerRunning();
\r
133 /* Create the task that will control and monitor the timers. This is
\r
134 created at a lower priority than the timer service task to ensure, as
\r
135 far as it is concerned, commands on timers are actioned immediately
\r
136 (sending a command to the timer service task will unblock the timer service
\r
137 task, which will then preempt this task). */
\r
138 if( xTestStatus != pdFAIL )
\r
140 xTaskCreate( prvTimerTestTask, "Tmr Tst", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );
\r
143 /*-----------------------------------------------------------*/
\r
145 static void prvTimerTestTask( void *pvParameters )
\r
147 ( void ) pvParameters;
\r
149 /* Create a one-shot timer for use later on in this test. */
\r
150 xOneShotTimer = xTimerCreate( "Oneshot Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
151 tmrdemoONE_SHOT_TIMER_PERIOD, /* The period for the timer. */
\r
152 pdFALSE, /* Don't auto-reload - hence a one shot timer. */
\r
153 ( void * ) 0, /* The timer identifier. Initialise to 0, then increment each time it is called. */
\r
154 prvOneShotTimerCallback ); /* The callback to be called when the timer expires. */
\r
156 if( xOneShotTimer == NULL )
\r
158 xTestStatus = pdFAIL;
\r
159 configASSERT( xTestStatus );
\r
163 /* Ensure all the timers are in their expected initial state. This
\r
164 depends on the timer service task having a higher priority than this task. */
\r
165 prvTest2_CheckTaskAndTimersInitialState();
\r
169 /* Check the auto reload timers expire at the expected/correct rates. */
\r
170 prvTest3_CheckAutoReloadExpireRates();
\r
172 /* Check the auto reload timers can be stopped correctly, and correctly
\r
173 report their state. */
\r
174 prvTest4_CheckAutoReloadTimersCanBeStopped();
\r
176 /* Check the one shot timer only calls its callback once after it has been
\r
177 started, and that it reports its state correctly. */
\r
178 prvTest5_CheckBasicOneShotTimerBehaviour();
\r
180 /* Check timer reset behaviour. */
\r
181 prvTest6_CheckAutoReloadResetBehaviour();
\r
183 /* Start the timers again to restart all the tests over again. */
\r
184 prvResetStartConditionsForNextIteration();
\r
187 /*-----------------------------------------------------------*/
\r
189 /* This is called to check that the created task is still running and has not
\r
190 detected any errors. */
\r
191 BaseType_t xAreTimerDemoTasksStillRunning( TickType_t xCycleFrequency )
\r
193 static uint32_t ulLastLoopCounter = 0UL;
\r
194 TickType_t xMaxBlockTimeUsedByTheseTests, xLoopCounterIncrementTimeMax;
\r
195 static TickType_t xIterationsWithoutCounterIncrement = ( TickType_t ) 0, xLastCycleFrequency;
\r
197 if( xLastCycleFrequency != xCycleFrequency )
\r
199 /* The cycle frequency has probably become much faster due to an error
\r
200 elsewhere. Start counting Iterations again. */
\r
201 xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
\r
202 xLastCycleFrequency = xCycleFrequency;
\r
205 /* Calculate the maximum number of times that it is permissible for this
\r
206 function to be called without ulLoopCounter being incremented. This is
\r
207 necessary because the tests in this file block for extended periods, and the
\r
208 block period might be longer than the time between calls to this function. */
\r
209 xMaxBlockTimeUsedByTheseTests = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
\r
210 xLoopCounterIncrementTimeMax = ( xMaxBlockTimeUsedByTheseTests / xCycleFrequency ) + 1;
\r
212 /* If the demo task is still running then the loop counter is expected to
\r
213 have incremented every xLoopCounterIncrementTimeMax calls. */
\r
214 if( ulLastLoopCounter == ulLoopCounter )
\r
216 xIterationsWithoutCounterIncrement++;
\r
217 if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax )
\r
219 /* The tests appear to be no longer running (stalled). */
\r
220 xTestStatus = pdFAIL;
\r
225 /* ulLoopCounter changed, so the count of times this function was called
\r
226 without a change can be reset to zero. */
\r
227 xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
\r
230 ulLastLoopCounter = ulLoopCounter;
\r
232 /* Errors detected in the task itself will have latched xTestStatus
\r
235 return xTestStatus;
\r
237 /*-----------------------------------------------------------*/
\r
239 static void prvTest1_CreateTimersWithoutSchedulerRunning( void )
\r
243 for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )
\r
245 /* As the timer queue is not yet full, it should be possible to both
\r
246 create and start a timer. These timers are being started before the
\r
247 scheduler has been started, so their block times should get set to zero
\r
248 within the timer API itself. */
\r
249 xAutoReloadTimers[ xTimer ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
250 ( ( xTimer + ( TickType_t ) 1 ) * xBasePeriod ),/* The period for the timer. The plus 1 ensures a period of zero is not specified. */
\r
251 pdTRUE, /* Auto-reload is set to true. */
\r
252 ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */
\r
253 prvAutoReloadTimerCallback ); /* The callback to be called when the timer expires. */
\r
255 if( xAutoReloadTimers[ xTimer ] == NULL )
\r
257 xTestStatus = pdFAIL;
\r
258 configASSERT( xTestStatus );
\r
262 configASSERT( strcmp( pcTimerGetName( xAutoReloadTimers[ xTimer ] ), "FR Timer" ) == 0 );
\r
264 /* The scheduler has not yet started, so the block period of
\r
265 portMAX_DELAY should just get set to zero in xTimerStart(). Also,
\r
266 the timer queue is not yet full so xTimerStart() should return
\r
268 if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS )
\r
270 xTestStatus = pdFAIL;
\r
271 configASSERT( xTestStatus );
\r
276 /* The timers queue should now be full, so it should be possible to create
\r
277 another timer, but not possible to start it (the timer queue will not get
\r
278 drained until the scheduler has been started. */
\r
279 xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
\r
280 ( configTIMER_QUEUE_LENGTH * xBasePeriod ), /* The period for the timer. */
\r
281 pdTRUE, /* Auto-reload is set to true. */
\r
282 ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */
\r
283 prvAutoReloadTimerCallback ); /* The callback executed when the timer expires. */
\r
285 if( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] == NULL )
\r
287 xTestStatus = pdFAIL;
\r
288 configASSERT( xTestStatus );
\r
292 if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS )
\r
294 /* This time it would not be expected that the timer could be
\r
295 started at this point. */
\r
296 xTestStatus = pdFAIL;
\r
297 configASSERT( xTestStatus );
\r
301 /* Create the timers that are used from the tick interrupt to test the timer
\r
302 API functions that can be called from an ISR. */
\r
303 xISRAutoReloadTimer = xTimerCreate( "ISR AR", /* The text name given to the timer. */
\r
304 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
\r
305 pdTRUE, /* This is an auto reload timer. */
\r
306 ( void * ) NULL, /* The identifier is not required. */
\r
307 prvISRAutoReloadTimerCallback ); /* The callback that is executed when the timer expires. */
\r
309 xISROneShotTimer = xTimerCreate( "ISR OS", /* The text name given to the timer. */
\r
310 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
\r
311 pdFALSE, /* This is a one shot timer. */
\r
312 ( void * ) NULL, /* The identifier is not required. */
\r
313 prvISROneShotTimerCallback ); /* The callback that is executed when the timer expires. */
\r
315 if( ( xISRAutoReloadTimer == NULL ) || ( xISROneShotTimer == NULL ) )
\r
317 xTestStatus = pdFAIL;
\r
318 configASSERT( xTestStatus );
\r
321 /*-----------------------------------------------------------*/
\r
323 static void prvTest2_CheckTaskAndTimersInitialState( void )
\r
327 /* Ensure all the timers are in their expected initial state. This depends
\r
328 on the timer service task having a higher priority than this task.
\r
330 auto reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active,
\r
331 and auto reload timer configTIMER_QUEUE_LENGTH should not yet be active (it
\r
332 could not be started prior to the scheduler being started when it was
\r
334 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
336 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
\r
338 xTestStatus = pdFAIL;
\r
339 configASSERT( xTestStatus );
\r
343 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] ) != pdFALSE )
\r
345 xTestStatus = pdFAIL;
\r
346 configASSERT( xTestStatus );
\r
349 /*-----------------------------------------------------------*/
\r
351 static void prvTest3_CheckAutoReloadExpireRates( void )
\r
353 uint8_t ucMaxAllowableValue, ucMinAllowableValue, ucTimer;
\r
354 TickType_t xBlockPeriod, xTimerPeriod, xExpectedNumber;
\r
355 UBaseType_t uxOriginalPriority;
\r
357 /* Check the auto reload timers expire at the expected rates. Do this at a
\r
358 high priority for maximum accuracy. This is ok as most of the time is spent
\r
359 in the Blocked state. */
\r
360 uxOriginalPriority = uxTaskPriorityGet( NULL );
\r
361 vTaskPrioritySet( NULL, ( configMAX_PRIORITIES - 1 ) );
\r
363 /* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow
\r
364 all the auto reload timers to expire at least once. */
\r
365 xBlockPeriod = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
\r
366 vTaskDelay( xBlockPeriod );
\r
368 /* Check that all the auto reload timers have called their callback
\r
369 function the expected number of times. */
\r
370 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
372 /* The expected number of expiries is equal to the block period divided
\r
373 by the timer period. */
\r
374 xTimerPeriod = ( ( ( TickType_t ) ucTimer + ( TickType_t ) 1 ) * xBasePeriod );
\r
375 xExpectedNumber = xBlockPeriod / xTimerPeriod;
\r
377 ucMaxAllowableValue = ( ( uint8_t ) xExpectedNumber ) ;
\r
378 ucMinAllowableValue = ( uint8_t ) ( ( uint8_t ) xExpectedNumber - ( uint8_t ) 1 ); /* Weird casting to try and please all compilers. */
\r
380 if( ( ucAutoReloadTimerCounters[ ucTimer ] < ucMinAllowableValue ) ||
\r
381 ( ucAutoReloadTimerCounters[ ucTimer ] > ucMaxAllowableValue )
\r
384 xTestStatus = pdFAIL;
\r
385 configASSERT( xTestStatus );
\r
389 /* Return to the original priority. */
\r
390 vTaskPrioritySet( NULL, uxOriginalPriority );
\r
392 if( xTestStatus == pdPASS )
\r
394 /* No errors have been reported so increment the loop counter so the
\r
395 check task knows this task is still running. */
\r
399 /*-----------------------------------------------------------*/
\r
401 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void )
\r
405 /* Check the auto reload timers can be stopped correctly, and correctly
\r
406 report their state. */
\r
408 /* Stop all the active timers. */
\r
409 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
411 /* The timer has not been stopped yet! */
\r
412 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
\r
414 xTestStatus = pdFAIL;
\r
415 configASSERT( xTestStatus );
\r
418 /* Now stop the timer. This will appear to happen immediately to
\r
419 this task because this task is running at a priority below the
\r
420 timer service task. */
\r
421 xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
\r
423 /* The timer should now be inactive. */
\r
424 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
\r
426 xTestStatus = pdFAIL;
\r
427 configASSERT( xTestStatus );
\r
431 taskENTER_CRITICAL();
\r
433 /* The timer in array position configTIMER_QUEUE_LENGTH should not
\r
434 be active. The critical section is used to ensure the timer does
\r
435 not call its callback between the next line running and the array
\r
436 being cleared back to zero, as that would mask an error condition. */
\r
437 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( uint8_t ) 0 )
\r
439 xTestStatus = pdFAIL;
\r
440 configASSERT( xTestStatus );
\r
443 /* Clear the timer callback count. */
\r
444 memset( ( void * ) ucAutoReloadTimerCounters, 0, sizeof( ucAutoReloadTimerCounters ) );
\r
446 taskEXIT_CRITICAL();
\r
448 /* The timers are now all inactive, so this time, after delaying, none
\r
449 of the callback counters should have incremented. */
\r
450 vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
\r
451 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
453 if( ucAutoReloadTimerCounters[ ucTimer ] != ( uint8_t ) 0 )
\r
455 xTestStatus = pdFAIL;
\r
456 configASSERT( xTestStatus );
\r
460 if( xTestStatus == pdPASS )
\r
462 /* No errors have been reported so increment the loop counter so
\r
463 the check task knows this task is still running. */
\r
467 /*-----------------------------------------------------------*/
\r
469 static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
\r
471 /* Check the one shot timer only calls its callback once after it has been
\r
472 started, and that it reports its state correctly. */
\r
474 /* The one shot timer should not be active yet. */
\r
475 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
\r
477 xTestStatus = pdFAIL;
\r
478 configASSERT( xTestStatus );
\r
481 if( ucOneShotTimerCounter != ( uint8_t ) 0 )
\r
483 xTestStatus = pdFAIL;
\r
484 configASSERT( xTestStatus );
\r
487 /* Start the one shot timer and check that it reports its state correctly. */
\r
488 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
489 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
491 xTestStatus = pdFAIL;
\r
492 configASSERT( xTestStatus );
\r
495 /* Delay for three times as long as the one shot timer period, then check
\r
496 to ensure it has only called its callback once, and is now not in the
\r
498 vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( TickType_t ) 3 );
\r
500 if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
\r
502 xTestStatus = pdFAIL;
\r
503 configASSERT( xTestStatus );
\r
506 if( ucOneShotTimerCounter != ( uint8_t ) 1 )
\r
508 xTestStatus = pdFAIL;
\r
509 configASSERT( xTestStatus );
\r
513 /* Reset the one shot timer callback count. */
\r
514 ucOneShotTimerCounter = ( uint8_t ) 0;
\r
517 if( xTestStatus == pdPASS )
\r
519 /* No errors have been reported so increment the loop counter so the
\r
520 check task knows this task is still running. */
\r
524 /*-----------------------------------------------------------*/
\r
526 static void prvTest6_CheckAutoReloadResetBehaviour( void )
\r
530 /* Check timer reset behaviour. */
\r
532 /* Restart the one shot timer and check it reports its status correctly. */
\r
533 xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
534 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
536 xTestStatus = pdFAIL;
\r
537 configASSERT( xTestStatus );
\r
540 /* Restart one of the auto reload timers and check that it reports its
\r
541 status correctly. */
\r
542 xTimerStart( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
543 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
545 xTestStatus = pdFAIL;
\r
546 configASSERT( xTestStatus );
\r
549 for( ucTimer = 0; ucTimer < trmdemoNUM_TIMER_RESETS; ucTimer++ )
\r
551 /* Delay for half as long as the one shot timer period, then reset it.
\r
552 It should never expire while this is done, so its callback count should
\r
553 never increment. */
\r
554 vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 );
\r
556 /* Check both running timers are still active, but have not called their
\r
557 callback functions. */
\r
558 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
\r
560 xTestStatus = pdFAIL;
\r
561 configASSERT( xTestStatus );
\r
564 if( ucOneShotTimerCounter != ( uint8_t ) 0 )
\r
566 xTestStatus = pdFAIL;
\r
567 configASSERT( xTestStatus );
\r
570 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
572 xTestStatus = pdFAIL;
\r
573 configASSERT( xTestStatus );
\r
576 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] != ( uint8_t ) 0 )
\r
578 xTestStatus = pdFAIL;
\r
579 configASSERT( xTestStatus );
\r
582 /* Reset both running timers. */
\r
583 xTimerReset( xOneShotTimer, tmrdemoDONT_BLOCK );
\r
584 xTimerReset( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
586 if( xTestStatus == pdPASS )
\r
588 /* No errors have been reported so increment the loop counter so
\r
589 the check task knows this task is still running. */
\r
594 /* Finally delay long enough for both running timers to expire. */
\r
595 vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
\r
597 /* The timers were not reset during the above delay period so should now
\r
598 both have called their callback functions. */
\r
599 if( ucOneShotTimerCounter != ( uint8_t ) 1 )
\r
601 xTestStatus = pdFAIL;
\r
602 configASSERT( xTestStatus );
\r
605 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] == 0 )
\r
607 xTestStatus = pdFAIL;
\r
608 configASSERT( xTestStatus );
\r
611 /* The one shot timer should no longer be active, while the auto reload
\r
612 timer should still be active. */
\r
613 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
\r
615 xTestStatus = pdFAIL;
\r
616 configASSERT( xTestStatus );
\r
619 if( xTimerIsTimerActive( xOneShotTimer ) == pdTRUE )
\r
621 xTestStatus = pdFAIL;
\r
622 configASSERT( xTestStatus );
\r
625 /* Stop the auto reload timer again. */
\r
626 xTimerStop( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
\r
628 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )
\r
630 xTestStatus = pdFAIL;
\r
631 configASSERT( xTestStatus );
\r
634 /* Clear the timer callback counts, ready for another iteration of these
\r
636 ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( uint8_t ) 0;
\r
637 ucOneShotTimerCounter = ( uint8_t ) 0;
\r
639 if( xTestStatus == pdPASS )
\r
641 /* No errors have been reported so increment the loop counter so the check
\r
642 task knows this task is still running. */
\r
646 /*-----------------------------------------------------------*/
\r
648 static void prvResetStartConditionsForNextIteration( void )
\r
652 /* Start the timers again to start all the tests over again. */
\r
654 /* Start the timers again. */
\r
655 for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
\r
657 /* The timer has not been started yet! */
\r
658 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
\r
660 xTestStatus = pdFAIL;
\r
661 configASSERT( xTestStatus );
\r
664 /* Now start the timer. This will appear to happen immediately to
\r
665 this task because this task is running at a priority below the timer
\r
667 xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
\r
669 /* The timer should now be active. */
\r
670 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
\r
672 xTestStatus = pdFAIL;
\r
673 configASSERT( xTestStatus );
\r
677 if( xTestStatus == pdPASS )
\r
679 /* No errors have been reported so increment the loop counter so the
\r
680 check task knows this task is still running. */
\r
684 /*-----------------------------------------------------------*/
\r
686 void vTimerPeriodicISRTests( void )
\r
688 static TickType_t uxTick = ( TickType_t ) -1;
\r
690 #if( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) )
\r
691 /* The timer service task is not the highest priority task, so it cannot
\r
692 be assumed that timings will be exact. Timers should never call their
\r
693 callback before their expiry time, but a margin is permissible for calling
\r
694 their callback after their expiry time. If exact timing is required then
\r
695 configTIMER_TASK_PRIORITY must be set to ensure the timer service task
\r
696 is the highest priority task in the system.
\r
698 This function is called from the tick hook. The tick hook is called
\r
699 even when the scheduler is suspended. Therefore it is possible that the
\r
700 uxTick count maintained in this function is temporarily ahead of the tick
\r
701 count maintained by the kernel. When this is the case a message posted from
\r
702 this function will assume a time stamp in advance of the real time stamp,
\r
703 which can result in a timer being processed before this function expects it
\r
704 to. For example, if the kernel's tick count was 100, and uxTick was 102,
\r
705 then this function will not expect the timer to have expired until the
\r
706 kernel's tick count is (102 + xBasePeriod), whereas in reality the timer
\r
707 will expire when the kernel's tick count is (100 + xBasePeriod). For this
\r
708 reason xMargin is used as an allowable margin for premature timer expiries
\r
709 as well as late timer expiries. */
\r
711 /* Windows is not real real time. */
\r
712 const TickType_t xMargin = 20;
\r
714 const TickType_t xMargin = 6;
\r
715 #endif /* _WINDOWS_ */
\r
718 /* Windows is not real real time. */
\r
719 const TickType_t xMargin = 20;
\r
721 const TickType_t xMargin = 4;
\r
722 #endif /* _WINDOWS_ */
\r
730 /* The timers will have been created, but not started. Start them now
\r
731 by setting their period. */
\r
732 ucISRAutoReloadTimerCounter = 0;
\r
733 ucISROneShotTimerCounter = 0;
\r
735 /* It is possible that the timer task has not yet made room in the
\r
736 timer queue. If the timers cannot be started then reset uxTick so
\r
737 another attempt is made later. */
\r
738 uxTick = ( TickType_t ) -1;
\r
740 /* Try starting first timer. */
\r
741 if( xTimerChangePeriodFromISR( xISRAutoReloadTimer, xBasePeriod, NULL ) == pdPASS )
\r
743 /* First timer was started, try starting the second timer. */
\r
744 if( xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, NULL ) == pdPASS )
\r
746 /* Both timers were started, so set the uxTick back to its
\r
752 /* Second timer could not be started, so stop the first one
\r
754 xTimerStopFromISR( xISRAutoReloadTimer, NULL );
\r
758 else if( uxTick == ( xBasePeriod - xMargin ) )
\r
760 /* Neither timer should have expired yet. */
\r
761 if( ( ucISRAutoReloadTimerCounter != 0 ) || ( ucISROneShotTimerCounter != 0 ) )
\r
763 xTestStatus = pdFAIL;
\r
764 configASSERT( xTestStatus );
\r
767 else if( uxTick == ( xBasePeriod + xMargin ) )
\r
769 /* Both timers should now have expired once. The auto reload timer will
\r
770 still be active, but the one shot timer should now have stopped. */
\r
771 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
\r
773 xTestStatus = pdFAIL;
\r
774 configASSERT( xTestStatus );
\r
777 else if( uxTick == ( ( 2 * xBasePeriod ) - xMargin ) )
\r
779 /* The auto reload timer will still be active, but the one shot timer
\r
780 should now have stopped - however, at this time neither of the timers
\r
781 should have expired again since the last test. */
\r
782 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
\r
784 xTestStatus = pdFAIL;
\r
785 configASSERT( xTestStatus );
\r
788 else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) )
\r
790 /* The auto reload timer will still be active, but the one shot timer
\r
791 should now have stopped. At this time the auto reload timer should have
\r
792 expired again, but the one shot timer count should not have changed. */
\r
793 if( ucISRAutoReloadTimerCounter != 2 )
\r
795 xTestStatus = pdFAIL;
\r
796 configASSERT( xTestStatus );
\r
799 if( ucISROneShotTimerCounter != 1 )
\r
801 xTestStatus = pdFAIL;
\r
802 configASSERT( xTestStatus );
\r
805 else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( TickType_t ) 2U ) ) )
\r
807 /* The auto reload timer will still be active, but the one shot timer
\r
808 should now have stopped. Again though, at this time, neither timer call
\r
809 back should have been called since the last test. */
\r
810 if( ucISRAutoReloadTimerCounter != 2 )
\r
812 xTestStatus = pdFAIL;
\r
813 configASSERT( xTestStatus );
\r
816 if( ucISROneShotTimerCounter != 1 )
\r
818 xTestStatus = pdFAIL;
\r
819 configASSERT( xTestStatus );
\r
822 else if( uxTick == ( 3 * xBasePeriod ) )
\r
824 /* Start the one shot timer again. */
\r
825 xTimerStartFromISR( xISROneShotTimer, NULL );
\r
827 else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) )
\r
829 /* The auto reload timer and one shot timer will be active. At
\r
830 this time the auto reload timer should have expired again, but the one
\r
831 shot timer count should not have changed yet. */
\r
832 if( ucISRAutoReloadTimerCounter != 3 )
\r
834 xTestStatus = pdFAIL;
\r
835 configASSERT( xTestStatus );
\r
838 if( ucISROneShotTimerCounter != 1 )
\r
840 xTestStatus = pdFAIL;
\r
841 configASSERT( xTestStatus );
\r
844 /* Now stop the auto reload timer. The one shot timer was started
\r
845 a few ticks ago. */
\r
846 xTimerStopFromISR( xISRAutoReloadTimer, NULL );
\r
848 else if( uxTick == ( 4 * ( xBasePeriod - xMargin ) ) )
\r
850 /* The auto reload timer is now stopped, and the one shot timer is
\r
851 active, but at this time neither timer should have expired since the
\r
853 if( ucISRAutoReloadTimerCounter != 3 )
\r
855 xTestStatus = pdFAIL;
\r
856 configASSERT( xTestStatus );
\r
859 if( ucISROneShotTimerCounter != 1 )
\r
861 xTestStatus = pdFAIL;
\r
862 configASSERT( xTestStatus );
\r
865 else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) )
\r
867 /* The auto reload timer is now stopped, and the one shot timer is
\r
868 active. The one shot timer should have expired again, but the auto
\r
869 reload timer should not have executed its callback. */
\r
870 if( ucISRAutoReloadTimerCounter != 3 )
\r
872 xTestStatus = pdFAIL;
\r
873 configASSERT( xTestStatus );
\r
876 if( ucISROneShotTimerCounter != 2 )
\r
878 xTestStatus = pdFAIL;
\r
879 configASSERT( xTestStatus );
\r
882 else if( uxTick == ( 8 * xBasePeriod ) )
\r
884 /* The auto reload timer is now stopped, and the one shot timer has
\r
885 already expired and then stopped itself. Both callback counters should
\r
886 not have incremented since the last test. */
\r
887 if( ucISRAutoReloadTimerCounter != 3 )
\r
889 xTestStatus = pdFAIL;
\r
890 configASSERT( xTestStatus );
\r
893 if( ucISROneShotTimerCounter != 2 )
\r
895 xTestStatus = pdFAIL;
\r
896 configASSERT( xTestStatus );
\r
899 /* Now reset the one shot timer. */
\r
900 xTimerResetFromISR( xISROneShotTimer, NULL );
\r
902 else if( uxTick == ( ( 9 * xBasePeriod ) - xMargin ) )
\r
904 /* Only the one shot timer should be running, but it should not have
\r
905 expired since the last test. Check the callback counters have not
\r
906 incremented, then reset the one shot timer again. */
\r
907 if( ucISRAutoReloadTimerCounter != 3 )
\r
909 xTestStatus = pdFAIL;
\r
910 configASSERT( xTestStatus );
\r
913 if( ucISROneShotTimerCounter != 2 )
\r
915 xTestStatus = pdFAIL;
\r
916 configASSERT( xTestStatus );
\r
919 xTimerResetFromISR( xISROneShotTimer, NULL );
\r
921 else if( uxTick == ( ( 10 * xBasePeriod ) - ( 2 * xMargin ) ) )
\r
923 /* Only the one shot timer should be running, but it should not have
\r
924 expired since the last test. Check the callback counters have not
\r
925 incremented, then reset the one shot timer again. */
\r
926 if( ucISRAutoReloadTimerCounter != 3 )
\r
928 xTestStatus = pdFAIL;
\r
929 configASSERT( xTestStatus );
\r
932 if( ucISROneShotTimerCounter != 2 )
\r
934 xTestStatus = pdFAIL;
\r
935 configASSERT( xTestStatus );
\r
938 xTimerResetFromISR( xISROneShotTimer, NULL );
\r
940 else if( uxTick == ( ( 11 * xBasePeriod ) - ( 3 * xMargin ) ) )
\r
942 /* Only the one shot timer should be running, but it should not have
\r
943 expired since the last test. Check the callback counters have not
\r
944 incremented, then reset the one shot timer once again. */
\r
945 if( ucISRAutoReloadTimerCounter != 3 )
\r
947 xTestStatus = pdFAIL;
\r
948 configASSERT( xTestStatus );
\r
951 if( ucISROneShotTimerCounter != 2 )
\r
953 xTestStatus = pdFAIL;
\r
954 configASSERT( xTestStatus );
\r
957 xTimerResetFromISR( xISROneShotTimer, NULL );
\r
959 else if( uxTick == ( ( 12 * xBasePeriod ) - ( 2 * xMargin ) ) )
\r
961 /* Only the one shot timer should have been running and this time it
\r
962 should have expired. Check its callback count has been incremented.
\r
963 The auto reload timer is still not running so should still have the same
\r
964 count value. This time the one shot timer is not reset so should not
\r
965 restart from its expiry period again. */
\r
966 if( ucISRAutoReloadTimerCounter != 3 )
\r
968 xTestStatus = pdFAIL;
\r
969 configASSERT( xTestStatus );
\r
972 if( ucISROneShotTimerCounter != 3 )
\r
974 xTestStatus = pdFAIL;
\r
975 configASSERT( xTestStatus );
\r
978 else if( uxTick == ( 15 * xBasePeriod ) )
\r
980 /* Neither timer should be running now. Check neither callback count
\r
981 has incremented, then go back to the start to run these tests all
\r
983 if( ucISRAutoReloadTimerCounter != 3 )
\r
985 xTestStatus = pdFAIL;
\r
986 configASSERT( xTestStatus );
\r
989 if( ucISROneShotTimerCounter != 3 )
\r
991 xTestStatus = pdFAIL;
\r
992 configASSERT( xTestStatus );
\r
995 uxTick = ( TickType_t ) -1;
\r
998 /*-----------------------------------------------------------*/
\r
1000 /*** Timer callback functions are defined below here. ***/
\r
1002 static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
\r
1006 uxTimerID = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
\r
1007 if( uxTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
\r
1009 ( ucAutoReloadTimerCounters[ uxTimerID ] )++;
\r
1013 /* The timer ID appears to be unexpected (invalid). */
\r
1014 xTestStatus = pdFAIL;
\r
1015 configASSERT( xTestStatus );
\r
1018 /*-----------------------------------------------------------*/
\r
1020 static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer )
\r
1022 /* A count is kept of the number of times this callback function is executed.
\r
1023 The count is stored as the timer's ID. This is only done to test the
\r
1024 vTimerSetTimerID() function. */
\r
1025 static size_t uxCallCount = 0;
\r
1026 size_t uxLastCallCount;
\r
1028 /* Obtain the timer's ID, which should be a count of the number of times
\r
1029 this callback function has been executed. */
\r
1030 uxLastCallCount = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
\r
1031 configASSERT( uxLastCallCount == uxCallCount );
\r
1033 /* Increment the call count, then save it back as the timer's ID. This is
\r
1034 only done to test the vTimerSetTimerID() API function. */
\r
1035 uxLastCallCount++;
\r
1036 vTimerSetTimerID( pxExpiredTimer, ( void * ) uxLastCallCount );
\r
1039 ucOneShotTimerCounter++;
\r
1041 /*-----------------------------------------------------------*/
\r
1043 static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
\r
1045 /* The parameter is not used in this case as only one timer uses this
\r
1046 callback function. */
\r
1047 ( void ) pxExpiredTimer;
\r
1049 ucISRAutoReloadTimerCounter++;
\r
1051 /*-----------------------------------------------------------*/
\r
1053 static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer )
\r
1055 /* The parameter is not used in this case as only one timer uses this
\r
1056 callback function. */
\r
1057 ( void ) pxExpiredTimer;
\r
1059 ucISROneShotTimerCounter++;
\r
1061 /*-----------------------------------------------------------*/
\r