4 #define tmrtestNUM_TIMERS 2
\r
7 extern portTickType xTickCount;
\r
8 extern xTaskHandle pxCurrentTCB;
\r
9 extern portTickType xNumOfOverflows;
\r
11 static void vTimerTest_Initialise( void );
\r
12 static portBASE_TYPE xTimerTest1_xTimeStartAndResetWakeTimeCalculation( void );
\r
13 portBASE_TYPE xTimerTest2_xTestFreeRunningBehaviour( unsigned portBASE_TYPE uxPeriodMultiplier );
\r
15 static void prvCheckServiceTaskBehaviour( portBASE_TYPE x, portBASE_TYPE xExpireTimeHasOverflowed, portBASE_TYPE xTickCountOverflowed );
\r
17 static void prvTestFailed( void );
\r
19 xTIMER *xAutoReloadTimers[ tmrtestNUM_TIMERS ];
\r
20 unsigned portBASE_TYPE uxAutoReloadTimerCounters[ tmrtestNUM_TIMERS ];
\r
21 portBASE_TYPE xTestStatus = pdPASS;
\r
22 xTaskHandle xTestTask1 = NULL, xTestTask2 = NULL;
\r
26 portTickType xStartTickCount;
\r
27 portTickType xTimerPeriod;
\r
28 portTickType xTickIncrementBetweenCommandAndProcessing;
\r
29 portTickType xExpectedCalculatedExpiryTime;
\r
30 xList * pxExpectedList;
\r
31 unsigned portBASE_TYPE uxExpectedCallbackCount;
\r
34 const struct xTestData xTestCase[] =
\r
36 /* xStartTickCount, xTimerPeriod, Tck Inc, Expected Expire Time, Expected list, Expected callback count */
\r
38 /* Test cases when the command to start a timer and the processing of the
\r
39 start command execute without the tick count incrementing in between. */
\r
40 { portMAX_DELAY - 8, 2, 0, ( portMAX_DELAY - 8 ) + 2, &xActiveTimerList1, 0 }, /* Expire before an overflow. */
\r
41 { portMAX_DELAY - 8, 8, 0, ( portMAX_DELAY - 8 ) + 8, &xActiveTimerList1, 0 }, /* Expire immediately before and overflow. */
\r
42 { portMAX_DELAY - 8, 9, 0, 0, &xActiveTimerList2, 0 }, /* Expire on an overflow. */
\r
43 { portMAX_DELAY - 8, portMAX_DELAY, 0, ( ( portMAX_DELAY - 8 ) - 1 ), &xActiveTimerList2, 0 }, /* Delay for the longest possible time. */
\r
44 { portMAX_DELAY, portMAX_DELAY, 0, ( portMAX_DELAY - 1 ), &xActiveTimerList2, 0 }, /* Delay for the longest possible time starting from the maximum tick count. */
\r
45 { 0, portMAX_DELAY, 0, ( portMAX_DELAY ), &xActiveTimerList1, 0 }, /* Delay for the maximum ticks, starting with from the minimum tick count. */
\r
47 /* Test cases when the command to start a timer and the processing of the
\r
48 start command execute at different tick count values. */
\r
49 { portMAX_DELAY - 8, 2, 1, ( portMAX_DELAY - 8 ) + 2, &xActiveTimerList1, 0 }, /* The expire time does not overflow, and the tick count does not overflow between the command and processing the command. */
\r
50 { portMAX_DELAY - 8, 8, 2, ( portMAX_DELAY - 8 ) + 8, &xActiveTimerList1, 0 }, /* The expire time does not overflow but is on the portMAX_DELAY limit, and the tick count does not overflow between the command and processing the command. */
\r
51 { portMAX_DELAY - 8, 9, 3, 0, &xActiveTimerList2, 0 }, /* The expire time overflows to 0, and the tick count does not overflow between the command and processing the command. */
\r
52 { portMAX_DELAY - 2, 9, 1, ( portMAX_DELAY - 2 ) + 9, &xActiveTimerList2, 0 }, /* The expire time overflows, but the tick count does not overflow between the command and processing the command. */
\r
53 { portMAX_DELAY - 2, 9, 3, ( portMAX_DELAY - 2 ) + 9, &xActiveTimerList2, 0 }, /* The timer overflows between the command and processing the command. The expire time also overflows. */
\r
55 /* Add tests where the timer should have expired by the time the command is processed. */
\r
56 { 10, 9, 10, ( 10 + ( 2 * 9 ) ), &xActiveTimerList1, 1 }, /* Nothing overflows, but the time between the timer being set and the command being processed is greater than the timers expiry time. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded. */
\r
57 { portMAX_DELAY - 2, 9, 10, ( portMAX_DELAY - 2 ) + ( 2 * 9 ), &xActiveTimerList2, 1 }, /* The timer overflows between the command and processing the command. The expire time also overflows and the number of ticks that occur between the command and the processing exceeds the timer expiry period. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/
\r
58 { portMAX_DELAY - 2, 9, 9, ( portMAX_DELAY - 2 ) + ( 2 * 9 ), &xActiveTimerList2, 1 }, /* The timer overflows between the command and processing the command. The expire time also overflows and the number of ticks between command and processing equals the timer expiry period. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/
\r
60 { portMAX_DELAY - 20, 9, 21, ( portMAX_DELAY - 20 ) + ( 3 * 9 ), &xActiveTimerList2, 2 }, /* The tick count has overflowed but the timer expire time has not overflowed. The tick count overflows to 0. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/
\r
61 { portMAX_DELAY - 20, 9, 22, ( portMAX_DELAY - 20 ) + ( 3 * 9 ), &xActiveTimerList2, 2 }, /* The tick count has overflowed but the timer expire time has not overflowed. The tick count overflows to greater than 0. The timer should get processed immediately, so the expected expire time is twice the period as the timer will get auto-reloaded.*/
\r
62 { portMAX_DELAY - 5, 2, 20, ( portMAX_DELAY - 5 ) + ( 11 * 2 ), &xActiveTimerList2, 10 }, /* The tick and expire time overflow, but the first expire time overflow results in a time that is less than the tick count. */
\r
65 typedef struct tskTaskControlBlockx
\r
67 volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
\r
69 #if ( portUSING_MPU_WRAPPERS == 1 )
\r
70 xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
\r
73 xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
\r
74 xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
\r
75 unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
\r
76 portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
\r
77 signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
\r
79 #if ( portSTACK_GROWTH > 0 )
\r
80 portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
\r
83 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
\r
84 unsigned portBASE_TYPE uxCriticalNesting;
\r
87 #if ( configUSE_TRACE_FACILITY == 1 )
\r
88 unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
\r
91 #if ( configUSE_MUTEXES == 1 )
\r
92 unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
\r
95 #if ( configUSE_APPLICATION_TASK_TAG == 1 )
\r
96 pdTASK_HOOK_CODE pxTaskTag;
\r
99 #if ( configGENERATE_RUN_TIME_STATS == 1 )
\r
100 unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
\r
105 /*-----------------------------------------------------------*/
\r
107 static void vAutoReloadTimerCallback( xTIMER *pxTimer )
\r
109 portBASE_TYPE xTimerID = ( portBASE_TYPE ) pxTimer->pvTimerID;
\r
111 if( xTimerID < tmrtestNUM_TIMERS )
\r
113 ( uxAutoReloadTimerCounters[ xTimerID ] )++;
\r
120 /*-----------------------------------------------------------*/
\r
122 static void vTimerTest_Initialise( void )
\r
124 portBASE_TYPE xTimerNumber;
\r
125 extern void prvInitialiseTaskLists( void );
\r
126 extern portBASE_TYPE xSchedulerRunning;
\r
128 prvInitialiseTaskLists();
\r
129 xTimerQueue = NULL;
\r
130 xSchedulerRunning = pdTRUE;
\r
132 for( xTimerNumber = 0; xTimerNumber < tmrtestNUM_TIMERS; xTimerNumber++ )
\r
134 /* Delete any existing timers. */
\r
135 if( xAutoReloadTimers[ xTimerNumber ] != NULL )
\r
137 vPortFree( xAutoReloadTimers[ xTimerNumber ] );
\r
140 /* Create new autoreload timers. */
\r
141 xAutoReloadTimers[ xTimerNumber ] = xTimerCreate( "Timer", 0xffff, pdTRUE, ( void * ) xTimerNumber, vAutoReloadTimerCallback );
\r
142 uxAutoReloadTimerCounters[ xTimerNumber ] = 0;
\r
143 if( xAutoReloadTimers == NULL )
\r
149 /* Initialise lists so they are empty. */
\r
150 vListInitialise( &xActiveTimerList1 );
\r
151 vListInitialise( &xActiveTimerList2 );
\r
153 /* Call prvSampleTimeNow with a tick count of zero so it sets its
\r
154 internal static "last time" variable to zero. */
\r
156 xNumOfOverflows = 0;
\r
157 prvSampleTimeNow( &xTimerNumber );
\r
159 /* Initialise the list pointers in case prvSampleTimeNow() changed them. */
\r
160 pxCurrentTimerList = &xActiveTimerList1;
\r
161 pxOverflowTimerList = &xActiveTimerList2;
\r
163 // if( xTestTask1 == NULL )
\r
165 xTaskCreate( (pdTASK_CODE)prvTestFailed, "Task1", configMINIMAL_STACK_SIZE, NULL, 0, &xTestTask1 );
\r
168 // if( xTestTask2 == NULL )
\r
170 xTaskCreate( (pdTASK_CODE)prvTestFailed, "Task1", configMINIMAL_STACK_SIZE, NULL, 0, &xTestTask2 );
\r
173 pxCurrentTCB = xTestTask1;
\r
175 /*-----------------------------------------------------------*/
\r
177 static void prvTestFailed( void )
\r
179 static unsigned long ulFailures = 0;
\r
182 xTestStatus = pdFAIL;
\r
184 /*-----------------------------------------------------------*/
\r
186 static void prvCheckServiceTaskBehaviour( portBASE_TYPE x, portBASE_TYPE xExpireTimeHasOverflowed, portBASE_TYPE xTickCountOverflowed )
\r
188 portBASE_TYPE xListWasEmpty;
\r
189 portTickType xNextExpireTime;
\r
190 extern xList * volatile pxOverflowDelayedTaskList, *pxDelayedTaskList;
\r
191 extern xList pxReadyTasksLists[];
\r
193 xListWasEmpty = portMAX_DELAY;
\r
194 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
\r
196 /* If the timer expire time has overflowed it should be present in the overflow
\r
197 list of active timers, unless the tick count has also overflowed and the expire
\r
198 time has not passed. If the expire time has not overflowed it should be
\r
199 present in the current list of active timers. Either way, its expire time should
\r
200 equal the expected expire time. */
\r
201 if( ( xExpireTimeHasOverflowed == pdTRUE ) && ( xTickCountOverflowed == pdFALSE ) )
\r
203 /* The timer will be in the overflow list, so prvGetNextExpireTime()
\r
204 should not have found it, but instead returned an expire time that
\r
205 will ensure the timer service task will unblock when the lists need
\r
207 if( ( xNextExpireTime != 0 ) || ( xListWasEmpty == pdFALSE ) )
\r
214 if( ( xNextExpireTime != xTestCase[ x ].xExpectedCalculatedExpiryTime ) || ( xListWasEmpty != pdFALSE ) )
\r
220 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
\r
222 /* Has the timer expired the expected number of times? */
\r
223 if( uxAutoReloadTimerCounters[ 0 ] != xTestCase[ x ].uxExpectedCallbackCount )
\r
228 /* The task should now be blocked. It should only appear in the overflow
\r
229 delayed task list if xNextExpireTime is equal to 0. */
\r
230 if( xNextExpireTime == 0 )
\r
232 if( listIS_CONTAINED_WITHIN( pxOverflowDelayedTaskList, &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) == pdFALSE )
\r
237 if( listGET_LIST_ITEM_VALUE( &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) != 0 )
\r
244 if( listIS_CONTAINED_WITHIN( pxDelayedTaskList, &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) == pdFALSE )
\r
249 if( listGET_LIST_ITEM_VALUE( &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) != xTestCase[ x ].xExpectedCalculatedExpiryTime )
\r
255 /* The timer should have be re-loaded, and still be referenced from one
\r
256 or other of the active lists. */
\r
257 if( listGET_LIST_ITEM_VALUE( &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) != xTestCase[ x ].xExpectedCalculatedExpiryTime )
\r
261 if( listIS_CONTAINED_WITHIN( NULL, &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) == pdTRUE )
\r
266 /* Move the task back to the ready list from the delayed list. */
\r
267 vListRemove( &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) );
\r
268 vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) );
\r
270 /*-----------------------------------------------------------*/
\r
272 static portBASE_TYPE xTimerTest1_xTimeStartAndResetWakeTimeCalculation( void )
\r
274 portBASE_TYPE x, xListWasEmpty;
\r
275 portTickType xNextExpireTime;
\r
277 if( sizeof( portTickType ) != 2 )
\r
279 /* This test should be performed using 16bit ticks. */
\r
283 for( x = 0; x < ( sizeof( xTestCase ) / sizeof( struct xTestData ) ); x++ )
\r
285 /* Set everything back to its start condition. */
\r
286 vTimerTest_Initialise();
\r
288 /* Load the tick count with the test case data. */
\r
289 xTickCount = xTestCase[ x ].xStartTickCount;
\r
291 /* Query the timers list to see if it contains any timers, and if so,
\r
292 obtain the time at which the next timer will expire. The list should be
\r
293 empty, so 0 should be returned (to cause the task to unblock when a
\r
294 tick overflow occurs. Likewise xListWasEmpty should be set to pdTRUE. */
\r
295 xListWasEmpty = portMAX_DELAY;
\r
296 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
\r
298 if( ( xListWasEmpty != pdTRUE ) || ( xNextExpireTime != ( portTickType ) 0 ) )
\r
305 /* Call prvProcessReceivedCommands() just so the code under test knows
\r
306 what the tick count is in the pre-condition state. */
\r
307 prvProcessReceivedCommands();
\r
309 xAutoReloadTimers[ 0 ]->xTimerPeriodInTicks = xTestCase[ x ].xTimerPeriod;
\r
310 xTimerStart( xAutoReloadTimers[ 0 ], 0 );
\r
312 /* Move the tick count on to the time at which the command should be
\r
314 xTickCount += xTestCase[ x ].xTickIncrementBetweenCommandAndProcessing;
\r
316 /* Process the sent command with the updated tick count. */
\r
317 prvProcessReceivedCommands();
\r
321 if( listGET_LIST_ITEM_VALUE( &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) != xTestCase[ x ].xExpectedCalculatedExpiryTime )
\r
325 if( listIS_CONTAINED_WITHIN( xTestCase[ x ].pxExpectedList, &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) == pdFALSE )
\r
329 if( uxAutoReloadTimerCounters[ 0 ] != xTestCase[ x ].uxExpectedCallbackCount )
\r
334 if( xTickCount < xTestCase[ x ].xStartTickCount ) /* The tick count has overflowed */
\r
336 if( xTestCase[ x ].pxExpectedList == &xActiveTimerList2 ) /* The timer expire time has overflowed. */
\r
338 if( xTestCase[ x ].xExpectedCalculatedExpiryTime <= xTickCount ) /* The timer expire time has passed */
\r
340 /* The expire time should never have passed when here is
\r
341 reached because the timer whould have been processed enough
\r
342 times to make the expire time catch up. */
\r
345 else /* The timer expire time has not passed. */
\r
347 prvCheckServiceTaskBehaviour( x, pdTRUE, pdTRUE );
\r
350 else /* The timer expire time has not overflowed. */
\r
352 /* If the timer expire time has not overflowed but the tick count has
\r
353 overflowed, then the timer expire time must have been passed. The
\r
354 expire time should never have passed when here is reached because
\r
355 the timer whould have been processed enough times to make the expire
\r
360 else /* The tick count has not overflowed. */
\r
362 if( xTestCase[ x ].pxExpectedList == &xActiveTimerList2 ) /* The timer expire time has overflowed */
\r
364 /* If the expire time has overflowed, but the tick count has not
\r
365 overflowed, then the timer expire time cannot have been passed. */
\r
366 prvCheckServiceTaskBehaviour( x, pdTRUE, pdFALSE );
\r
368 else /* The timer expire time has not overflowed. */
\r
370 if( xTickCount >= xTestCase[ x ].xExpectedCalculatedExpiryTime ) /* The timer expire time has passed */
\r
372 /* The expire time should never have passed when here is
\r
373 reached because the timer whould have been processed enough
\r
374 times to make the expire time catch up. */
\r
377 else /* The timer expire time has not passed. */
\r
379 prvCheckServiceTaskBehaviour( x, pdFALSE, pdFALSE );
\r
385 return xTestStatus;
\r
387 /*-----------------------------------------------------------*/
\r
389 portBASE_TYPE xTimerTest2_xTestFreeRunningBehaviour( unsigned portBASE_TYPE uxPeriodMultiplier )
\r
391 unsigned portBASE_TYPE uxExpectedIncrements, x, uxMix = 0, uxPeriod;
\r
392 const unsigned portBASE_TYPE uxMaxIterations = 0xffff;
\r
393 extern xList pxReadyTasksLists[];
\r
394 portTickType xNextExpireTime;
\r
395 portBASE_TYPE xListWasEmpty;
\r
396 extern xTaskHandle pxCurrentTCB;
\r
398 if( sizeof( portTickType ) != 2 )
\r
400 /* This test should be performed using 16bit ticks. */
\r
404 /* Initialise the test. This will create tmrtestNUM_TIMERS timers. */
\r
405 vTimerTest_Initialise();
\r
407 /* Give each timer a period, then start it running. */
\r
408 for( x = 0; x < tmrtestNUM_TIMERS; x++ )
\r
410 uxPeriod = ( x + ( unsigned portBASE_TYPE ) 1 ) * uxPeriodMultiplier;
\r
411 xTimerChangePeriod( xAutoReloadTimers[ x ], ( portTickType ) uxPeriod, 0 );
\r
412 xTimerStart( xAutoReloadTimers[ x ], 0 );
\r
413 prvProcessReceivedCommands();
\r
419 /* Simulate the task running. */
\r
420 while( x <= uxMaxIterations )
\r
422 /* Query the timers list to see if it contains any timers, and if so,
\r
423 obtain the time at which the next timer will expire. */
\r
424 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
\r
426 /* It is legitimate for tick increments to occur here. */
\r
427 if( ( uxMix < 2 ) && ( x < ( uxMaxIterations + 3 ) ) )
\r
429 vTaskIncrementTick();
\r
431 vTaskIncrementTick();
\r
433 vTaskIncrementTick();
\r
437 /* If a timer has expired, process it. Otherwise, block this task
\r
438 until either a timer does expire, or a command is received. */
\r
439 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
\r
441 /* If the task blocked, increment the tick until it unblocks. */
\r
442 while( listIS_CONTAINED_WITHIN( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) == pdFALSE )
\r
444 if( ( uxMix == 1 ) && ( x < ( uxMaxIterations + 3 ) ) )
\r
446 vTaskIncrementTick();
\r
448 vTaskIncrementTick();
\r
450 vTaskIncrementTick();
\r
453 if( ( uxMix == 2 ) && ( x < ( uxMaxIterations + 2 ) ) )
\r
455 vTaskIncrementTick();
\r
457 vTaskIncrementTick();
\r
462 vTaskIncrementTick();
\r
473 /* Make sure time does not go past that expected. */
\r
474 if( x > uxMaxIterations )
\r
476 xTickCount -= ( portTickType ) ( x - uxMaxIterations );
\r
479 /* Empty the command queue. */
\r
480 prvProcessReceivedCommands();
\r
483 /* Catch up with the tick count, if it was incremented more than once in one
\r
485 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
\r
486 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
\r
488 /* This time, if the task blocked, there is nothing left to do. If it didn't
\r
489 block then empty the command queue for good measure. */
\r
490 if( listIS_CONTAINED_WITHIN( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) != pdFALSE )
\r
492 /* Empty the command queue. */
\r
493 prvProcessReceivedCommands();
\r
496 /* Check each timer has incremented the expected number of times. */
\r
497 for( x = 0; x < tmrtestNUM_TIMERS; x++ )
\r
499 uxPeriod = ( x + ( unsigned portBASE_TYPE ) 1 ) * uxPeriodMultiplier;
\r
500 uxExpectedIncrements = ( uxMaxIterations / ( unsigned portBASE_TYPE ) uxPeriod );
\r
502 if( uxAutoReloadTimerCounters[ x ] != uxExpectedIncrements )
\r
508 return xTestStatus;
\r
511 /*-----------------------------------------------------------*/
\r
513 void vRunTimerModuleTests( void )
\r
515 xTimerTest1_xTimeStartAndResetWakeTimeCalculation();
\r
516 xTimerTest2_xTestFreeRunningBehaviour( 1 );
\r
517 xTimerTest2_xTestFreeRunningBehaviour( 10 );
\r
518 xTimerTest2_xTestFreeRunningBehaviour( 25 );
\r
519 xTimerTest2_xTestFreeRunningBehaviour( 50 );
\r
520 xTimerTest2_xTestFreeRunningBehaviour( 121 );
\r
525 #endif TIMER_TEST_H
\r