]> begriffs open source - cmsis-freertos/blob - Demo/Common/Minimal/TimerDemo.c
Update cmsis_os2.c
[cmsis-freertos] / Demo / Common / Minimal / TimerDemo.c
1 /*
2     FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
3     All rights reserved
4
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
6
7     This file is part of the FreeRTOS distribution.
8
9     FreeRTOS is free software; you can redistribute it and/or modify it under
10     the terms of the GNU General Public License (version 2) as published by the
11     Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
12
13     ***************************************************************************
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<
16     >>!   obliged to provide the source code for proprietary components     !<<
17     >>!   outside of the FreeRTOS kernel.                                   !<<
18     ***************************************************************************
19
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following
23     link: http://www.freertos.org/a00114.html
24
25     ***************************************************************************
26      *                                                                       *
27      *    FreeRTOS provides completely free yet professionally developed,    *
28      *    robust, strictly quality controlled, supported, and cross          *
29      *    platform software that is more than just the market leader, it     *
30      *    is the industry's de facto standard.                               *
31      *                                                                       *
32      *    Help yourself get started quickly while simultaneously helping     *
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *
34      *    tutorial book, reference manual, or both:                          *
35      *    http://www.FreeRTOS.org/Documentation                              *
36      *                                                                       *
37     ***************************************************************************
38
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
40     the FAQ page "My application does not run, what could be wrong?".  Have you
41     defined configASSERT()?
42
43     http://www.FreeRTOS.org/support - In return for receiving this top quality
44     embedded software for free we request you assist our global community by
45     participating in the support forum.
46
47     http://www.FreeRTOS.org/training - Investing in training allows your team to
48     be as productive as possible as early as possible.  Now you can receive
49     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
50     Ltd, and the world's leading authority on the world's leading RTOS.
51
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.
55
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
58
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
61     licenses offer ticketed support, indemnification and commercial middleware.
62
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety
64     engineered and independently SIL3 certified version for use in safety and
65     mission critical applications that require provable dependability.
66
67     1 tab == 4 spaces!
68 */
69
70
71 /*
72  * Tests the behaviour of timers.  Some timers are created before the scheduler
73  * is started, and some after.
74  */
75
76 /* Standard includes. */
77 #include <string.h>
78
79 /* Scheduler include files. */
80 #include "FreeRTOS.h"
81 #include "task.h"
82 #include "timers.h"
83
84 /* Demo program include files. */
85 #include "TimerDemo.h"
86
87 #if ( configTIMER_TASK_PRIORITY < 1 )
88         #error configTIMER_TASK_PRIORITY must be set to at least 1 for this test/demo to function correctly.
89 #endif
90
91 #define tmrdemoDONT_BLOCK                               ( ( TickType_t ) 0 )
92 #define tmrdemoONE_SHOT_TIMER_PERIOD    ( xBasePeriod * ( TickType_t ) 3 )
93 #define trmdemoNUM_TIMER_RESETS                 ( ( uint8_t ) 10 )
94
95 /*-----------------------------------------------------------*/
96
97 /* The callback functions used by the timers.  These each increment a counter
98 to indicate which timer has expired.  The auto-reload timers that are used by
99 the test task (as opposed to being used from an ISR) all share the same
100 prvAutoReloadTimerCallback() callback function, and use the ID of the
101 pxExpiredTimer parameter passed into that function to know which counter to
102 increment.  The other timers all have their own unique callback function and
103 simply increment their counters without using the callback function parameter. */
104 static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
105 static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer );
106 static void prvTimerTestTask( void *pvParameters );
107 static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
108 static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer );
109
110 /* The test functions used by the timer test task.  These manipulate the auto
111 reload and one shot timers in various ways, then delay, then inspect the timers
112 to ensure they have behaved as expected. */
113 static void prvTest1_CreateTimersWithoutSchedulerRunning( void );
114 static void prvTest2_CheckTaskAndTimersInitialState( void );
115 static void     prvTest3_CheckAutoReloadExpireRates( void );
116 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void );
117 static void prvTest5_CheckBasicOneShotTimerBehaviour( void );
118 static void prvTest6_CheckAutoReloadResetBehaviour( void );
119 static void prvResetStartConditionsForNextIteration( void );
120
121 /*-----------------------------------------------------------*/
122
123 /* Flag that will be latched to pdFAIL should any unexpected behaviour be
124 detected in any of the demo tests. */
125 static volatile BaseType_t xTestStatus = pdPASS;
126
127 /* Counter that is incremented on each cycle of a test.  This is used to
128 detect a stalled task - a test that is no longer running. */
129 static volatile uint32_t ulLoopCounter = 0;
130
131 /* A set of auto reload timers - each of which use the same callback function.
132 The callback function uses the timer ID to index into, and then increment, a
133 counter in the ucAutoReloadTimerCounters[] array.  The auto reload timers
134 referenced from xAutoReloadTimers[] are used by the prvTimerTestTask task. */
135 static TimerHandle_t xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
136 static uint8_t ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
137
138 /* The one shot timer is configured to use a callback function that increments
139 ucOneShotTimerCounter each time it gets called. */
140 static TimerHandle_t xOneShotTimer = NULL;
141 static uint8_t ucOneShotTimerCounter = ( uint8_t ) 0;
142
143 /* The ISR reload timer is controlled from the tick hook to exercise the timer
144 API functions that can be used from an ISR.  It is configured to increment
145 ucISRReloadTimerCounter each time its callback function is executed. */
146 static TimerHandle_t xISRAutoReloadTimer = NULL;
147 static uint8_t ucISRAutoReloadTimerCounter = ( uint8_t ) 0;
148
149 /* The ISR one shot timer is controlled from the tick hook to exercise the timer
150 API functions that can be used from an ISR.  It is configured to increment
151 ucISRReloadTimerCounter each time its callback function is executed. */
152 static TimerHandle_t xISROneShotTimer = NULL;
153 static uint8_t ucISROneShotTimerCounter = ( uint8_t ) 0;
154
155 /* The period of all the timers are a multiple of the base period.  The base
156 period is configured by the parameter to vStartTimerDemoTask(). */
157 static TickType_t xBasePeriod = 0;
158
159 /*-----------------------------------------------------------*/
160
161 void vStartTimerDemoTask( TickType_t xBasePeriodIn )
162 {
163         /* Start with the timer and counter arrays clear - this is only necessary
164         where the compiler does not clear them automatically on start up. */
165         memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) );
166         memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) );
167
168         /* Store the period from which all the timer periods will be generated from
169         (multiples of). */
170         xBasePeriod = xBasePeriodIn;
171
172         /* Create a set of timers for use by this demo/test. */
173         prvTest1_CreateTimersWithoutSchedulerRunning();
174
175         /* Create the task that will control and monitor the timers.  This is
176         created at a lower priority than the timer service task to ensure, as
177         far as it is concerned, commands on timers are actioned immediately
178         (sending a command to the timer service task will unblock the timer service
179         task, which will then preempt this task). */
180         if( xTestStatus != pdFAIL )
181         {
182                 xTaskCreate( prvTimerTestTask, "Tmr Tst", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );
183         }
184 }
185 /*-----------------------------------------------------------*/
186
187 static void prvTimerTestTask( void *pvParameters )
188 {
189         ( void ) pvParameters;
190
191         /* Create a one-shot timer for use later on in this test. */
192         xOneShotTimer = xTimerCreate(   "Oneshot Timer",                                /* Text name to facilitate debugging.  The kernel does not use this itself. */
193                                                                         tmrdemoONE_SHOT_TIMER_PERIOD,   /* The period for the timer. */
194                                                                         pdFALSE,                                                /* Don't auto-reload - hence a one shot timer. */
195                                                                         ( void * ) 0,                                   /* The timer identifier.  Initialise to 0, then increment each time it is called. */
196                                                                         prvOneShotTimerCallback );              /* The callback to be called when the timer expires. */
197
198         if( xOneShotTimer == NULL )
199         {
200                 xTestStatus = pdFAIL;
201                 configASSERT( xTestStatus );
202         }
203
204
205         /* Ensure all the timers are in their expected initial state.  This
206         depends on the timer service task having a higher priority than this task. */
207         prvTest2_CheckTaskAndTimersInitialState();
208
209         for( ;; )
210         {
211                 /* Check the auto reload timers expire at the expected/correct rates. */
212                 prvTest3_CheckAutoReloadExpireRates();
213
214                 /* Check the auto reload timers can be stopped correctly, and correctly
215                 report their state. */
216                 prvTest4_CheckAutoReloadTimersCanBeStopped();
217
218                 /* Check the one shot timer only calls its callback once after it has been
219                 started, and that it reports its state correctly. */
220                 prvTest5_CheckBasicOneShotTimerBehaviour();
221
222                 /* Check timer reset behaviour. */
223                 prvTest6_CheckAutoReloadResetBehaviour();
224
225                 /* Start the timers again to restart all the tests over again. */
226                 prvResetStartConditionsForNextIteration();
227         }
228 }
229 /*-----------------------------------------------------------*/
230
231 /* This is called to check that the created task is still running and has not
232 detected any errors. */
233 BaseType_t xAreTimerDemoTasksStillRunning( TickType_t xCycleFrequency )
234 {
235 static uint32_t ulLastLoopCounter = 0UL;
236 TickType_t xMaxBlockTimeUsedByTheseTests, xLoopCounterIncrementTimeMax;
237 static TickType_t xIterationsWithoutCounterIncrement = ( TickType_t ) 0, xLastCycleFrequency;
238
239         if( xLastCycleFrequency != xCycleFrequency )
240         {
241                 /* The cycle frequency has probably become much faster due to an error
242                 elsewhere.  Start counting Iterations again. */
243                 xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
244                 xLastCycleFrequency = xCycleFrequency;
245         }
246
247         /* Calculate the maximum number of times that it is permissible for this
248         function to be called without ulLoopCounter being incremented.  This is
249         necessary because the tests in this file block for extended periods, and the
250         block period might be longer than the time between calls to this function. */
251         xMaxBlockTimeUsedByTheseTests = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
252         xLoopCounterIncrementTimeMax = ( xMaxBlockTimeUsedByTheseTests / xCycleFrequency ) + 1;
253
254         /* If the demo task is still running then the loop counter is expected to
255         have incremented every xLoopCounterIncrementTimeMax calls. */
256         if( ulLastLoopCounter == ulLoopCounter )
257         {
258                 xIterationsWithoutCounterIncrement++;
259                 if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax )
260                 {
261                         /* The tests appear to be no longer running (stalled). */
262                         xTestStatus = pdFAIL;
263                         configASSERT( xTestStatus );
264                 }
265         }
266         else
267         {
268                 /* ulLoopCounter changed, so the count of times this function was called
269                 without a change can be reset to zero. */
270                 xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
271         }
272
273         ulLastLoopCounter = ulLoopCounter;
274
275         /* Errors detected in the task itself will have latched xTestStatus
276         to pdFAIL. */
277
278         return xTestStatus;
279 }
280 /*-----------------------------------------------------------*/
281
282 static void prvTest1_CreateTimersWithoutSchedulerRunning( void )
283 {
284 TickType_t xTimer;
285
286         for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )
287         {
288                 /* As the timer queue is not yet full, it should be possible to both
289                 create and start a timer.  These timers are being started before the
290                 scheduler has been started, so their block times should get set to zero
291                 within the timer API itself. */
292                 xAutoReloadTimers[ xTimer ] = xTimerCreate( "FR Timer",                                                 /* Text name to facilitate debugging.  The kernel does not use this itself. */
293                                                                                                         ( ( xTimer + ( TickType_t ) 1 ) * xBasePeriod ),/* The period for the timer.  The plus 1 ensures a period of zero is not specified. */
294                                                                                                         pdTRUE,                                                         /* Auto-reload is set to true. */
295                                                                                                         ( void * ) xTimer,                                      /* An identifier for the timer as all the auto reload timers use the same callback. */
296                                                                                                         prvAutoReloadTimerCallback );           /* The callback to be called when the timer expires. */
297
298                 if( xAutoReloadTimers[ xTimer ] == NULL )
299                 {
300                         xTestStatus = pdFAIL;
301                         configASSERT( xTestStatus );
302                 }
303                 else
304                 {
305                         configASSERT( strcmp( pcTimerGetName( xAutoReloadTimers[ xTimer ] ), "FR Timer" ) == 0 );
306
307                         /* The scheduler has not yet started, so the block period of
308                         portMAX_DELAY should just get set to zero in xTimerStart().  Also,
309                         the timer queue is not yet full so xTimerStart() should return
310                         pdPASS. */
311                         if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS )
312                         {
313                                 xTestStatus = pdFAIL;
314                                 configASSERT( xTestStatus );
315                         }
316                 }
317         }
318
319         /* The timers queue should now be full, so it should be possible to create
320         another timer, but not possible to start it (the timer queue will not get
321         drained until the scheduler has been started. */
322         xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( "FR Timer",                                       /* Text name to facilitate debugging.  The kernel does not use this itself. */
323                                                                                                         ( configTIMER_QUEUE_LENGTH * xBasePeriod ),     /* The period for the timer. */
324                                                                                                         pdTRUE,                                                                         /* Auto-reload is set to true. */
325                                                                                                         ( void * ) xTimer,                                                      /* An identifier for the timer as all the auto reload timers use the same callback. */
326                                                                                                         prvAutoReloadTimerCallback );                           /* The callback executed when the timer expires. */
327
328         if( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] == NULL )
329         {
330                 xTestStatus = pdFAIL;
331                 configASSERT( xTestStatus );
332         }
333         else
334         {
335                 if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS )
336                 {
337                         /* This time it would not be expected that the timer could be
338                         started at this point. */
339                         xTestStatus = pdFAIL;
340                         configASSERT( xTestStatus );
341                 }
342         }
343
344         /* Create the timers that are used from the tick interrupt to test the timer
345         API functions that can be called from an ISR. */
346         xISRAutoReloadTimer = xTimerCreate( "ISR AR",                                                   /* The text name given to the timer. */
347                                                                                 0xffff,                                                         /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
348                                                                                 pdTRUE,                                                         /* This is an auto reload timer. */
349                                                                                 ( void * ) NULL,                                        /* The identifier is not required. */
350                                                                                 prvISRAutoReloadTimerCallback );        /* The callback that is executed when the timer expires. */
351
352         xISROneShotTimer = xTimerCreate(        "ISR OS",                                                       /* The text name given to the timer. */
353                                                                                 0xffff,                                                         /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
354                                                                                 pdFALSE,                                                        /* This is a one shot timer. */
355                                                                                 ( void * ) NULL,                                        /* The identifier is not required. */
356                                                                                 prvISROneShotTimerCallback );           /* The callback that is executed when the timer expires. */
357
358         if( ( xISRAutoReloadTimer == NULL ) || ( xISROneShotTimer == NULL ) )
359         {
360                 xTestStatus = pdFAIL;
361                 configASSERT( xTestStatus );
362         }
363 }
364 /*-----------------------------------------------------------*/
365
366 static void prvTest2_CheckTaskAndTimersInitialState( void )
367 {
368 uint8_t ucTimer;
369
370         /* Ensure all the timers are in their expected initial state.  This     depends
371         on the timer service task having a higher priority than this task.
372
373         auto reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active,
374         and auto reload timer configTIMER_QUEUE_LENGTH should not yet be active (it
375         could not be started prior to the scheduler being started when it was
376         created). */
377         for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
378         {
379                 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
380                 {
381                         xTestStatus = pdFAIL;
382                         configASSERT( xTestStatus );
383                 }
384         }
385
386         if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] ) != pdFALSE )
387         {
388                 xTestStatus = pdFAIL;
389                 configASSERT( xTestStatus );
390         }
391 }
392 /*-----------------------------------------------------------*/
393
394 static void     prvTest3_CheckAutoReloadExpireRates( void )
395 {
396 uint8_t ucMaxAllowableValue, ucMinAllowableValue, ucTimer;
397 TickType_t xBlockPeriod, xTimerPeriod, xExpectedNumber;
398 UBaseType_t uxOriginalPriority;
399
400         /* Check the auto reload timers expire at the expected rates.  Do this at a
401         high priority for maximum accuracy.  This is ok as most of the time is spent
402         in the Blocked state. */
403         uxOriginalPriority = uxTaskPriorityGet( NULL );
404         vTaskPrioritySet( NULL, ( configMAX_PRIORITIES - 1 ) );
405
406         /* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow
407         all the auto reload timers to expire at least once. */
408         xBlockPeriod = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
409         vTaskDelay( xBlockPeriod );
410
411         /* Check that all the auto reload timers have called their callback
412         function the expected number of times. */
413         for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
414         {
415                 /* The expected number of expiries is equal to the block period divided
416                 by the timer period. */
417                 xTimerPeriod = ( ( ( TickType_t ) ucTimer + ( TickType_t ) 1 ) * xBasePeriod );
418                 xExpectedNumber = xBlockPeriod / xTimerPeriod;
419
420                 ucMaxAllowableValue = ( ( uint8_t ) xExpectedNumber ) ;
421                 ucMinAllowableValue = ( uint8_t ) ( ( uint8_t ) xExpectedNumber - ( uint8_t ) 1 ); /* Weird casting to try and please all compilers. */
422
423                 if( ( ucAutoReloadTimerCounters[ ucTimer ] < ucMinAllowableValue ) ||
424                         ( ucAutoReloadTimerCounters[ ucTimer ] > ucMaxAllowableValue )
425                         )
426                 {
427                         xTestStatus = pdFAIL;
428                         configASSERT( xTestStatus );
429                 }
430         }
431
432         /* Return to the original priority. */
433         vTaskPrioritySet( NULL, uxOriginalPriority );
434
435         if( xTestStatus == pdPASS )
436         {
437                 /* No errors have been reported so increment the loop counter so the
438                 check task knows this task is still running. */
439                 ulLoopCounter++;
440         }
441 }
442 /*-----------------------------------------------------------*/
443
444 static void prvTest4_CheckAutoReloadTimersCanBeStopped( void )
445 {
446 uint8_t ucTimer;
447
448         /* Check the auto reload timers can be stopped correctly, and correctly
449         report their state. */
450
451         /* Stop all the active timers. */
452         for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
453         {
454                 /* The timer has not been stopped yet! */
455                 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
456                 {
457                         xTestStatus = pdFAIL;
458                         configASSERT( xTestStatus );
459                 }
460
461                 /* Now stop the timer.  This will appear to happen immediately to
462                 this task because this task is running at a priority below the
463                 timer service task. */
464                 xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
465
466                 /* The timer should now be inactive. */
467                 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
468                 {
469                         xTestStatus = pdFAIL;
470                         configASSERT( xTestStatus );
471                 }
472         }
473
474         taskENTER_CRITICAL();
475         {
476                 /* The timer in array position configTIMER_QUEUE_LENGTH should not
477                 be active.  The critical section is used to ensure the timer does
478                 not call its callback between the next line running and the array
479                 being cleared back to zero, as that would mask an error condition. */
480                 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( uint8_t ) 0 )
481                 {
482                         xTestStatus = pdFAIL;
483                         configASSERT( xTestStatus );
484                 }
485
486                 /* Clear the timer callback count. */
487                 memset( ( void * ) ucAutoReloadTimerCounters, 0, sizeof( ucAutoReloadTimerCounters ) );
488         }
489         taskEXIT_CRITICAL();
490
491         /* The timers are now all inactive, so this time, after delaying, none
492         of the callback counters should have incremented. */
493         vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
494         for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
495         {
496                 if( ucAutoReloadTimerCounters[ ucTimer ] != ( uint8_t ) 0 )
497                 {
498                         xTestStatus = pdFAIL;
499                         configASSERT( xTestStatus );
500                 }
501         }
502
503         if( xTestStatus == pdPASS )
504         {
505                 /* No errors have been reported so increment the loop counter so
506                 the check task knows this task is still running. */
507                 ulLoopCounter++;
508         }
509 }
510 /*-----------------------------------------------------------*/
511
512 static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
513 {
514         /* Check the one shot timer only calls its callback once after it has been
515         started, and that it reports its state correctly. */
516
517         /* The one shot timer should not be active yet. */
518         if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
519         {
520                 xTestStatus = pdFAIL;
521                 configASSERT( xTestStatus );
522         }
523
524         if( ucOneShotTimerCounter != ( uint8_t ) 0 )
525         {
526                 xTestStatus = pdFAIL;
527                 configASSERT( xTestStatus );
528         }
529
530         /* Start the one shot timer and check that it reports its state correctly. */
531         xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
532         if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
533         {
534                 xTestStatus = pdFAIL;
535                 configASSERT( xTestStatus );
536         }
537
538         /* Delay for three times as long as the one shot timer period, then check
539         to ensure it has only called its callback once, and is now not in the
540         active state. */
541         vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( TickType_t ) 3 );
542
543         if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
544         {
545                 xTestStatus = pdFAIL;
546                 configASSERT( xTestStatus );
547         }
548
549         if( ucOneShotTimerCounter != ( uint8_t ) 1 )
550         {
551                 xTestStatus = pdFAIL;
552                 configASSERT( xTestStatus );
553         }
554         else
555         {
556                 /* Reset the one shot timer callback count. */
557                 ucOneShotTimerCounter = ( uint8_t ) 0;
558         }
559
560         if( xTestStatus == pdPASS )
561         {
562                 /* No errors have been reported so increment the loop counter so the
563                 check task knows this task is still running. */
564                 ulLoopCounter++;
565         }
566 }
567 /*-----------------------------------------------------------*/
568
569 static void prvTest6_CheckAutoReloadResetBehaviour( void )
570 {
571 uint8_t ucTimer;
572
573         /* Check timer reset behaviour. */
574
575         /* Restart the one shot timer and check it reports its status correctly. */
576         xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
577         if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
578         {
579                 xTestStatus = pdFAIL;
580                 configASSERT( xTestStatus );
581         }
582
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 );
586         if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
587         {
588                 xTestStatus = pdFAIL;
589                 configASSERT( xTestStatus );
590         }
591
592         for( ucTimer = 0; ucTimer < trmdemoNUM_TIMER_RESETS; ucTimer++ )
593         {
594                 /* Delay for half as long as the one shot timer period, then reset it.
595                 It should never expire while this is done, so its callback count should
596                 never increment. */
597                 vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 );
598
599                 /* Check both running timers are still active, but have not called their
600                 callback functions. */
601                 if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
602                 {
603                         xTestStatus = pdFAIL;
604                         configASSERT( xTestStatus );
605                 }
606
607                 if( ucOneShotTimerCounter != ( uint8_t ) 0 )
608                 {
609                         xTestStatus = pdFAIL;
610                         configASSERT( xTestStatus );
611                 }
612
613                 if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
614                 {
615                         xTestStatus = pdFAIL;
616                         configASSERT( xTestStatus );
617                 }
618
619                 if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] != ( uint8_t ) 0 )
620                 {
621                         xTestStatus = pdFAIL;
622                         configASSERT( xTestStatus );
623                 }
624
625                 /* Reset both running timers. */
626                 xTimerReset( xOneShotTimer, tmrdemoDONT_BLOCK );
627                 xTimerReset( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
628
629                 if( xTestStatus == pdPASS )
630                 {
631                         /* No errors have been reported so increment the loop counter so
632                         the check task knows this task is still running. */
633                         ulLoopCounter++;
634                 }
635         }
636
637         /* Finally delay long enough for both running timers to expire. */
638         vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
639
640         /* The timers were not reset during the above delay period so should now
641         both have called their callback functions. */
642         if( ucOneShotTimerCounter != ( uint8_t ) 1 )
643         {
644                 xTestStatus = pdFAIL;
645                 configASSERT( xTestStatus );
646         }
647
648         if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] == 0 )
649         {
650                 xTestStatus = pdFAIL;
651                 configASSERT( xTestStatus );
652         }
653
654         /* The one shot timer should no longer be active, while the auto reload
655         timer should still be active. */
656         if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
657         {
658                 xTestStatus = pdFAIL;
659                 configASSERT( xTestStatus );
660         }
661
662         if( xTimerIsTimerActive( xOneShotTimer ) == pdTRUE )
663         {
664                 xTestStatus = pdFAIL;
665                 configASSERT( xTestStatus );
666         }
667
668         /* Stop the auto reload timer again. */
669         xTimerStop( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
670
671         if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )
672         {
673                 xTestStatus = pdFAIL;
674                 configASSERT( xTestStatus );
675         }
676
677         /* Clear the timer callback counts, ready for another iteration of these
678         tests. */
679         ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( uint8_t ) 0;
680         ucOneShotTimerCounter = ( uint8_t ) 0;
681
682         if( xTestStatus == pdPASS )
683         {
684                 /* No errors have been reported so increment the loop counter so the check
685                 task knows this task is still running. */
686                 ulLoopCounter++;
687         }
688 }
689 /*-----------------------------------------------------------*/
690
691 static void prvResetStartConditionsForNextIteration( void )
692 {
693 uint8_t ucTimer;
694
695         /* Start the timers again to start all the tests over again. */
696
697         /* Start the timers again. */
698         for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
699         {
700                 /* The timer has not been started yet! */
701                 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
702                 {
703                         xTestStatus = pdFAIL;
704                         configASSERT( xTestStatus );
705                 }
706
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. */
710                 xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
711
712                 /* The timer should now be active. */
713                 if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
714                 {
715                         xTestStatus = pdFAIL;
716                         configASSERT( xTestStatus );
717                 }
718         }
719
720         if( xTestStatus == pdPASS )
721         {
722                 /* No errors have been reported so increment the loop counter so the
723                 check task knows this task is still running. */
724                 ulLoopCounter++;
725         }
726 }
727 /*-----------------------------------------------------------*/
728
729 void vTimerPeriodicISRTests( void )
730 {
731 static TickType_t uxTick = ( TickType_t ) -1;
732
733 #if( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) )
734         /* The timer service task is not the highest priority task, so it cannot
735         be assumed that timings will be exact.  Timers should never call their
736         callback before their expiry time, but a margin is permissible for calling
737         their callback after their expiry time.  If exact timing is required then
738         configTIMER_TASK_PRIORITY must be set to ensure the timer service task
739         is the highest priority task in the system.
740
741         This function is called from the tick hook.  The tick hook is called
742         even when the scheduler is suspended.  Therefore it is possible that the
743         uxTick count maintained in this function is temporarily ahead of the tick
744         count maintained by the kernel.  When this is the case a message posted from
745         this function will assume a time stamp in advance of the real time stamp,
746         which can result in a timer being processed before this function expects it
747         to.  For example, if the kernel's tick count was 100, and uxTick was 102,
748         then this function will not expect the timer to have expired until the
749         kernel's tick count is (102 + xBasePeriod), whereas in reality the timer
750         will expire when the kernel's tick count is (100 + xBasePeriod).  For this
751         reason xMargin is used as an allowable margin for premature timer expiries
752         as well as late timer expiries. */
753         #ifdef _WINDOWS_
754                 /* Windows is not real real time. */
755                 const TickType_t xMargin = 20;
756         #else
757                 const TickType_t xMargin = 6;
758         #endif /* _WINDOWS_ */
759 #else
760         #ifdef _WINDOWS_
761                 /* Windows is not real real time. */
762                 const TickType_t xMargin = 20;
763         #else
764                 const TickType_t xMargin = 4;
765         #endif /* _WINDOWS_ */
766 #endif
767
768
769         uxTick++;
770
771         if( uxTick == 0 )
772         {
773                 /* The timers will have been created, but not started.  Start them now
774                 by setting their period. */
775                 ucISRAutoReloadTimerCounter = 0;
776                 ucISROneShotTimerCounter = 0;
777
778                 /* It is possible that the timer task has not yet made room in the
779                 timer queue.  If the timers cannot be started then reset uxTick so
780                 another attempt is made later. */
781                 uxTick = ( TickType_t ) -1;
782
783                 /* Try starting first timer. */
784                 if( xTimerChangePeriodFromISR( xISRAutoReloadTimer, xBasePeriod, NULL ) == pdPASS )
785                 {
786                         /* First timer was started, try starting the second timer. */
787                         if( xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, NULL ) == pdPASS )
788                         {
789                                 /* Both timers were started, so set the uxTick back to its
790                                 proper value. */
791                                 uxTick = 0;
792                         }
793                         else
794                         {
795                                 /* Second timer could not be started, so stop the first one
796                                 again. */
797                                 xTimerStopFromISR( xISRAutoReloadTimer, NULL );
798                         }
799                 }
800         }
801         else if( uxTick == ( xBasePeriod - xMargin ) )
802         {
803                 /* Neither timer should have expired yet. */
804                 if( ( ucISRAutoReloadTimerCounter != 0 ) || ( ucISROneShotTimerCounter != 0 ) )
805                 {
806                         xTestStatus = pdFAIL;
807                         configASSERT( xTestStatus );
808                 }
809         }
810         else if( uxTick == ( xBasePeriod + xMargin ) )
811         {
812                 /* Both timers should now have expired once.  The auto reload timer will
813                 still be active, but the one shot timer should now have stopped. */
814                 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
815                 {
816                         xTestStatus = pdFAIL;
817                         configASSERT( xTestStatus );
818                 }
819         }
820         else if( uxTick == ( ( 2 * xBasePeriod ) - xMargin ) )
821         {
822                 /* The auto reload timer will still be active, but the one shot timer
823                 should now have stopped - however, at this time neither of the timers
824                 should have expired again since the last test. */
825                 if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
826                 {
827                         xTestStatus = pdFAIL;
828                         configASSERT( xTestStatus );
829                 }
830         }
831         else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) )
832         {
833                 /* The auto reload timer will still be active, but the one shot timer
834                 should now have stopped.  At this time the auto reload timer should have
835                 expired again, but the one shot timer count should not have changed. */
836                 if( ucISRAutoReloadTimerCounter != 2 )
837                 {
838                         xTestStatus = pdFAIL;
839                         configASSERT( xTestStatus );
840                 }
841
842                 if( ucISROneShotTimerCounter != 1 )
843                 {
844                         xTestStatus = pdFAIL;
845                         configASSERT( xTestStatus );
846                 }
847         }
848         else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( TickType_t ) 2U ) ) )
849         {
850                 /* The auto reload timer will still be active, but the one shot timer
851                 should now have stopped.  Again though, at this time, neither timer call
852                 back should have been called since the last test. */
853                 if( ucISRAutoReloadTimerCounter != 2 )
854                 {
855                         xTestStatus = pdFAIL;
856                         configASSERT( xTestStatus );
857                 }
858
859                 if( ucISROneShotTimerCounter != 1 )
860                 {
861                         xTestStatus = pdFAIL;
862                         configASSERT( xTestStatus );
863                 }
864         }
865         else if( uxTick == ( 3 * xBasePeriod ) )
866         {
867                 /* Start the one shot timer again. */
868                 xTimerStartFromISR( xISROneShotTimer, NULL );
869         }
870         else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) )
871         {
872                 /* The auto reload timer and one shot timer will be active.  At
873                 this time the auto reload timer should have     expired again, but the one
874                 shot timer count should not have changed yet. */
875                 if( ucISRAutoReloadTimerCounter != 3 )
876                 {
877                         xTestStatus = pdFAIL;
878                         configASSERT( xTestStatus );
879                 }
880
881                 if( ucISROneShotTimerCounter != 1 )
882                 {
883                         xTestStatus = pdFAIL;
884                         configASSERT( xTestStatus );
885                 }
886
887                 /* Now stop the auto reload timer.  The one shot timer was started
888                 a few ticks ago. */
889                 xTimerStopFromISR( xISRAutoReloadTimer, NULL );
890         }
891         else if( uxTick == ( 4 * ( xBasePeriod - xMargin ) ) )
892         {
893                 /* The auto reload timer is now stopped, and the one shot timer is
894                 active, but at this time neither timer should have expired since the
895                 last test. */
896                 if( ucISRAutoReloadTimerCounter != 3 )
897                 {
898                         xTestStatus = pdFAIL;
899                         configASSERT( xTestStatus );
900                 }
901
902                 if( ucISROneShotTimerCounter != 1 )
903                 {
904                         xTestStatus = pdFAIL;
905                         configASSERT( xTestStatus );
906                 }
907         }
908         else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) )
909         {
910                 /* The auto reload timer is now stopped, and the one shot timer is
911                 active.  The one shot timer should have expired again, but the auto
912                 reload timer should not have executed its callback. */
913                 if( ucISRAutoReloadTimerCounter != 3 )
914                 {
915                         xTestStatus = pdFAIL;
916                         configASSERT( xTestStatus );
917                 }
918
919                 if( ucISROneShotTimerCounter != 2 )
920                 {
921                         xTestStatus = pdFAIL;
922                         configASSERT( xTestStatus );
923                 }
924         }
925         else if( uxTick == ( 8 * xBasePeriod ) )
926         {
927                 /* The auto reload timer is now stopped, and the one shot timer has
928                 already expired and then stopped itself.  Both callback counters should
929                 not have incremented since the last test. */
930                 if( ucISRAutoReloadTimerCounter != 3 )
931                 {
932                         xTestStatus = pdFAIL;
933                         configASSERT( xTestStatus );
934                 }
935
936                 if( ucISROneShotTimerCounter != 2 )
937                 {
938                         xTestStatus = pdFAIL;
939                         configASSERT( xTestStatus );
940                 }
941
942                 /* Now reset the one shot timer. */
943                 xTimerResetFromISR( xISROneShotTimer, NULL );
944         }
945         else if( uxTick == ( ( 9 * xBasePeriod ) - xMargin ) )
946         {
947                 /* Only the one shot timer should be running, but it should not have
948                 expired since the last test.  Check the callback counters have not
949                 incremented, then reset the one shot timer again. */
950                 if( ucISRAutoReloadTimerCounter != 3 )
951                 {
952                         xTestStatus = pdFAIL;
953                         configASSERT( xTestStatus );
954                 }
955
956                 if( ucISROneShotTimerCounter != 2 )
957                 {
958                         xTestStatus = pdFAIL;
959                         configASSERT( xTestStatus );
960                 }
961
962                 xTimerResetFromISR( xISROneShotTimer, NULL );
963         }
964         else if( uxTick == ( ( 10 * xBasePeriod ) - ( 2 * xMargin ) ) )
965         {
966                 /* Only the one shot timer should be running, but it should not have
967                 expired since the last test.  Check the callback counters have not
968                 incremented, then reset the one shot timer again. */
969                 if( ucISRAutoReloadTimerCounter != 3 )
970                 {
971                         xTestStatus = pdFAIL;
972                         configASSERT( xTestStatus );
973                 }
974
975                 if( ucISROneShotTimerCounter != 2 )
976                 {
977                         xTestStatus = pdFAIL;
978                         configASSERT( xTestStatus );
979                 }
980
981                 xTimerResetFromISR( xISROneShotTimer, NULL );
982         }
983         else if( uxTick == ( ( 11 * xBasePeriod ) - ( 3 * xMargin ) ) )
984         {
985                 /* Only the one shot timer should be running, but it should not have
986                 expired since the last test.  Check the callback counters have not
987                 incremented, then reset the one shot timer once again. */
988                 if( ucISRAutoReloadTimerCounter != 3 )
989                 {
990                         xTestStatus = pdFAIL;
991                         configASSERT( xTestStatus );
992                 }
993
994                 if( ucISROneShotTimerCounter != 2 )
995                 {
996                         xTestStatus = pdFAIL;
997                         configASSERT( xTestStatus );
998                 }
999
1000                 xTimerResetFromISR( xISROneShotTimer, NULL );
1001         }
1002         else if( uxTick == ( ( 12 * xBasePeriod ) - ( 2 * xMargin ) ) )
1003         {
1004                 /* Only the one shot timer should have been running and this time it
1005                 should have     expired.  Check its callback count has been incremented.
1006                 The auto reload timer is still not running so should still have the same
1007                 count value.  This time the one shot timer is not reset so should not
1008                 restart from its expiry period again. */
1009                 if( ucISRAutoReloadTimerCounter != 3 )
1010                 {
1011                         xTestStatus = pdFAIL;
1012                         configASSERT( xTestStatus );
1013                 }
1014
1015                 if( ucISROneShotTimerCounter != 3 )
1016                 {
1017                         xTestStatus = pdFAIL;
1018                         configASSERT( xTestStatus );
1019                 }
1020         }
1021         else if( uxTick == ( 15 * xBasePeriod ) )
1022         {
1023                 /* Neither timer should be running now.  Check neither callback count
1024                 has incremented, then go back to the start to run these tests all
1025                 over again. */
1026                 if( ucISRAutoReloadTimerCounter != 3 )
1027                 {
1028                         xTestStatus = pdFAIL;
1029                         configASSERT( xTestStatus );
1030                 }
1031
1032                 if( ucISROneShotTimerCounter != 3 )
1033                 {
1034                         xTestStatus = pdFAIL;
1035                         configASSERT( xTestStatus );
1036                 }
1037
1038                 uxTick = ( TickType_t ) -1;
1039         }
1040 }
1041 /*-----------------------------------------------------------*/
1042
1043 /*** Timer callback functions are defined below here. ***/
1044
1045 static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
1046 {
1047 size_t uxTimerID;
1048
1049         uxTimerID = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
1050         if( uxTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
1051         {
1052                 ( ucAutoReloadTimerCounters[ uxTimerID ] )++;
1053         }
1054         else
1055         {
1056                 /* The timer ID appears to be unexpected (invalid). */
1057                 xTestStatus = pdFAIL;
1058                 configASSERT( xTestStatus );
1059         }
1060 }
1061 /*-----------------------------------------------------------*/
1062
1063 static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer )
1064 {
1065 /* A count is kept of the number of times this callback function is executed.
1066 The count is stored as the timer's ID.  This is only done to test the
1067 vTimerSetTimerID() function. */
1068 static size_t uxCallCount = 0;
1069 size_t uxLastCallCount;
1070
1071         /* Obtain the timer's ID, which should be a count of the number of times
1072         this callback function has been executed. */
1073         uxLastCallCount = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
1074         configASSERT( uxLastCallCount == uxCallCount );
1075
1076         /* Increment the call count, then save it back as the timer's ID.  This is
1077         only done to test the vTimerSetTimerID() API function. */
1078         uxLastCallCount++;
1079         vTimerSetTimerID( pxExpiredTimer, ( void * ) uxLastCallCount );
1080         uxCallCount++;
1081
1082         ucOneShotTimerCounter++;
1083 }
1084 /*-----------------------------------------------------------*/
1085
1086 static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
1087 {
1088         /* The parameter is not used in this case as only one timer uses this
1089         callback function. */
1090         ( void ) pxExpiredTimer;
1091
1092         ucISRAutoReloadTimerCounter++;
1093 }
1094 /*-----------------------------------------------------------*/
1095
1096 static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer )
1097 {
1098         /* The parameter is not used in this case as only one timer uses this
1099         callback function. */
1100         ( void ) pxExpiredTimer;
1101
1102         ucISROneShotTimerCounter++;
1103 }
1104 /*-----------------------------------------------------------*/
1105
1106
1107
1108