4 #define tmrtestNUM_TIMERS 15
\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, Second tick inc */
\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
319 if( listGET_LIST_ITEM_VALUE( &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) != xTestCase[ x ].xExpectedCalculatedExpiryTime )
\r
323 if( listIS_CONTAINED_WITHIN( xTestCase[ x ].pxExpectedList, &( xAutoReloadTimers[ 0 ]->xTimerListItem ) ) == pdFALSE )
\r
327 if( uxAutoReloadTimerCounters[ 0 ] != xTestCase[ x ].uxExpectedCallbackCount )
\r
332 if( xTickCount < xTestCase[ x ].xStartTickCount ) /* The tick count has overflowed */
\r
334 if( xTestCase[ x ].pxExpectedList == &xActiveTimerList2 ) /* The timer expire time has overflowed. */
\r
336 if( xTestCase[ x ].xExpectedCalculatedExpiryTime <= xTickCount ) /* The timer expire time has passed */
\r
338 /* The expire time should never have passed when here is
\r
339 reached because the timer whould have been processed enough
\r
340 times to make the expire time catch up. */
\r
343 else /* The timer expire time has not passed. */
\r
345 prvCheckServiceTaskBehaviour( x, pdTRUE, pdTRUE );
\r
348 else /* The timer expire time has not overflowed. */
\r
350 /* If the timer expire time has not overflowed but the tick count has
\r
351 overflowed, then the timer expire time must have been passed. The
\r
352 expire time should never have passed when here is reached because
\r
353 the timer whould have been processed enough times to make the expire
\r
358 else /* The tick count has not overflowed. */
\r
360 if( xTestCase[ x ].pxExpectedList == &xActiveTimerList2 ) /* The timer expire time has overflowed */
\r
362 /* If the expire time has overflowed, but the tick count has not
\r
363 overflowed, then the timer expire time cannot have been passed. */
\r
364 prvCheckServiceTaskBehaviour( x, pdTRUE, pdFALSE );
\r
366 else /* The timer expire time has not overflowed. */
\r
368 if( xTickCount >= xTestCase[ x ].xExpectedCalculatedExpiryTime ) /* The timer expire time has passed */
\r
370 /* The expire time should never have passed when here is
\r
371 reached because the timer whould have been processed enough
\r
372 times to make the expire time catch up. */
\r
375 else /* The timer expire time has not passed. */
\r
377 prvCheckServiceTaskBehaviour( x, pdFALSE, pdFALSE );
\r
383 return xTestStatus;
\r
385 /*-----------------------------------------------------------*/
\r
387 portBASE_TYPE xTimerTest2_xTestFreeRunningBehaviour( unsigned portBASE_TYPE uxPeriodMultiplier )
\r
389 unsigned portBASE_TYPE uxExpectedIncrements, x, uxMix = 0, uxPeriod;
\r
390 const unsigned portBASE_TYPE uxMaxIterations = 0x1fffff;
\r
391 extern xList pxReadyTasksLists[];
\r
392 portTickType xNextExpireTime;
\r
393 portBASE_TYPE xListWasEmpty;
\r
394 extern xTaskHandle pxCurrentTCB;
\r
396 if( sizeof( portTickType ) != 2 )
\r
398 /* This test should be performed using 16bit ticks. */
\r
402 /* Initialise the test. This will create tmrtestNUM_TIMERS timers. */
\r
403 vTimerTest_Initialise();
\r
405 /* Give each timer a period, then start it running. */
\r
406 for( x = 0; x < tmrtestNUM_TIMERS; x++ )
\r
408 uxPeriod = ( x + ( unsigned portBASE_TYPE ) 1 ) * uxPeriodMultiplier;
\r
409 xTimerChangePeriod( xAutoReloadTimers[ x ], ( portTickType ) uxPeriod, 0 );
\r
410 xTimerStart( xAutoReloadTimers[ x ], 0 );
\r
411 prvProcessReceivedCommands();
\r
417 /* Simulate the task running. */
\r
418 while( x <= uxMaxIterations )
\r
420 /* Query the timers list to see if it contains any timers, and if so,
\r
421 obtain the time at which the next timer will expire. */
\r
422 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
\r
424 /* It is legitimate for tick increments to occur here. */
\r
425 if( ( uxMix < 2 ) && ( x < uxMaxIterations - 5 ) )
\r
427 vTaskIncrementTick();
\r
429 vTaskIncrementTick();
\r
431 vTaskIncrementTick();
\r
435 /* If a timer has expired, process it. Otherwise, block this task
\r
436 until either a timer does expire, or a command is received. */
\r
437 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
\r
439 /* If the task blocked, increment the tick until it unblocks. */
\r
440 while( listIS_CONTAINED_WITHIN( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) == pdFALSE )
\r
442 if( ( uxMix == 1 ) && ( x < ( uxMaxIterations + 3 ) ) )
\r
444 vTaskIncrementTick();
\r
446 vTaskIncrementTick();
\r
448 vTaskIncrementTick();
\r
451 if( ( uxMix == 2 ) && ( x < ( uxMaxIterations + 2 ) ) )
\r
453 vTaskIncrementTick();
\r
455 vTaskIncrementTick();
\r
460 vTaskIncrementTick();
\r
471 /* Make sure time does not go past that expected. */
\r
472 if( x > uxMaxIterations )
\r
474 xTickCount -= ( portTickType ) ( x - uxMaxIterations );
\r
477 /* Empty the command queue. */
\r
478 prvProcessReceivedCommands();
\r
481 /* Catch up with the tick count, if it was incremented more than once in one
\r
483 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
\r
484 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
\r
486 /* This time, if the task blocked, there is nothing left to do. If it didn't
\r
487 block then empty the command queue for good measure. */
\r
488 if( listIS_CONTAINED_WITHIN( ( xList * ) &( pxReadyTasksLists[ 0 ] ), &( ( ( tskTCBx * ) pxCurrentTCB )->xGenericListItem ) ) != pdFALSE )
\r
490 /* Empty the command queue. */
\r
491 prvProcessReceivedCommands();
\r
494 /* Check each timer has incremented the expected number of times. */
\r
495 for( x = 0; x < tmrtestNUM_TIMERS; x++ )
\r
497 uxPeriod = ( x + ( unsigned portBASE_TYPE ) 1 ) * uxPeriodMultiplier;
\r
498 uxExpectedIncrements = ( uxMaxIterations / ( unsigned portBASE_TYPE ) uxPeriod );
\r
500 if( ( uxExpectedIncrements - uxAutoReloadTimerCounters[ x ] ) > 1 )
\r
506 return xTestStatus;
\r
509 /*-----------------------------------------------------------*/
\r
511 void vRunTimerModuleTests( void )
\r
515 xTimerTest1_xTimeStartAndResetWakeTimeCalculation();
\r
517 for( x = 1; x < 1000; x++ )
\r
519 xTimerTest2_xTestFreeRunningBehaviour( x );
\r
525 #endif TIMER_TEST_H
\r