www.freertos.org

Dependents:   Nucleo freertos_test FreeRTOS_test freertos_bluetooth ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers timers.c Source File

timers.c

00001 /*
00002     FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. 
00003     All rights reserved
00004 
00005     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
00006 
00007     ***************************************************************************
00008      *                                                                       *
00009      *    FreeRTOS provides completely free yet professionally developed,    *
00010      *    robust, strictly quality controlled, supported, and cross          *
00011      *    platform software that has become a de facto standard.             *
00012      *                                                                       *
00013      *    Help yourself get started quickly and support the FreeRTOS         *
00014      *    project by purchasing a FreeRTOS tutorial book, reference          *
00015      *    manual, or both from: http://www.FreeRTOS.org/Documentation        *
00016      *                                                                       *
00017      *    Thank you!                                                         *
00018      *                                                                       *
00019     ***************************************************************************
00020 
00021     This file is part of the FreeRTOS distribution.
00022 
00023     FreeRTOS is free software; you can redistribute it and/or modify it under
00024     the terms of the GNU General Public License (version 2) as published by the
00025     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
00026 
00027     >>! NOTE: The modification to the GPL is included to allow you to distribute
00028     >>! a combined work that includes FreeRTOS without being obliged to provide
00029     >>! the source code for proprietary components outside of the FreeRTOS
00030     >>! kernel.
00031 
00032     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
00033     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00034     FOR A PARTICULAR PURPOSE.  Full license text is available from the following
00035     link: http://www.freertos.org/a00114.html
00036 
00037     1 tab == 4 spaces!
00038 
00039     ***************************************************************************
00040      *                                                                       *
00041      *    Having a problem?  Start by reading the FAQ "My application does   *
00042      *    not run, what could be wrong?"                                     *
00043      *                                                                       *
00044      *    http://www.FreeRTOS.org/FAQHelp.html                               *
00045      *                                                                       *
00046     ***************************************************************************
00047 
00048     http://www.FreeRTOS.org - Documentation, books, training, latest versions,
00049     license and Real Time Engineers Ltd. contact details.
00050 
00051     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
00052     including FreeRTOS+Trace - an indispensable productivity tool, a DOS
00053     compatible FAT file system, and our tiny thread aware UDP/IP stack.
00054 
00055     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
00056     Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS
00057     licenses offer ticketed support, indemnification and middleware.
00058 
00059     http://www.SafeRTOS.com - High Integrity Systems also provide a safety
00060     engineered and independently SIL3 certified version for use in safety and
00061     mission critical applications that require provable dependability.
00062 
00063     1 tab == 4 spaces!
00064 */
00065 
00066 /* Standard includes. */
00067 #include <stdlib.h>
00068 
00069 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
00070 all the API functions to use the MPU wrappers.  That should only be done when
00071 task.h is included from an application file. */
00072 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
00073 
00074 #include "FreeRTOS.h"
00075 #include "task.h"
00076 #include "queue.h"
00077 #include "timers.h"
00078 
00079 /* Lint e961 and e750 are suppressed as a MISRA exception justified because the
00080 MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
00081 header files above, but not in this file, in order to generate the correct
00082 privileged Vs unprivileged linkage and placement. */
00083 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
00084 
00085 
00086 /* This entire source file will be skipped if the application is not configured
00087 to include software timer functionality.  This #if is closed at the very bottom
00088 of this file.  If you want to include software timer functionality then ensure
00089 configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
00090 #if ( configUSE_TIMERS == 1 )
00091 
00092 /* Misc definitions. */
00093 #define tmrNO_DELAY     ( portTickType ) 0U
00094 
00095 /* The definition of the timers themselves. */
00096 typedef struct tmrTimerControl
00097 {
00098     const signed char       *pcTimerName;       /*<< Text name.  This is not used by the kernel, it is included simply to make debugging easier. */
00099     xListItem               xTimerListItem;     /*<< Standard linked list item as used by all kernel features for event management. */
00100     portTickType            xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
00101     unsigned portBASE_TYPE  uxAutoReload;       /*<< Set to pdTRUE if the timer should be automatically restarted once expired.  Set to pdFALSE if the timer is, in effect, a one shot timer. */
00102     void                    *pvTimerID;         /*<< An ID to identify the timer.  This allows the timer to be identified when the same callback is used for multiple timers. */
00103     tmrTIMER_CALLBACK       pxCallbackFunction; /*<< The function that will be called when the timer expires. */
00104 } xTIMER;
00105 
00106 /* The definition of messages that can be sent and received on the timer
00107 queue. */
00108 typedef struct tmrTimerQueueMessage
00109 {
00110     portBASE_TYPE           xMessageID;         /*<< The command being sent to the timer service task. */
00111     portTickType            xMessageValue;      /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
00112     xTIMER *                pxTimer;            /*<< The timer to which the command will be applied. */
00113 } xTIMER_MESSAGE;
00114 
00115 /*lint -e956 A manual analysis and inspection has been used to determine which
00116 static variables must be declared volatile. */
00117 
00118 /* The list in which active timers are stored.  Timers are referenced in expire
00119 time order, with the nearest expiry time at the front of the list.  Only the
00120 timer service task is allowed to access xActiveTimerList. */
00121 PRIVILEGED_DATA static xList xActiveTimerList1;
00122 PRIVILEGED_DATA static xList xActiveTimerList2;
00123 PRIVILEGED_DATA static xList *pxCurrentTimerList;
00124 PRIVILEGED_DATA static xList *pxOverflowTimerList;
00125 
00126 /* A queue that is used to send commands to the timer service task. */
00127 PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
00128 
00129 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
00130 
00131     PRIVILEGED_DATA static xTaskHandle xTimerTaskHandle = NULL;
00132 
00133 #endif
00134 
00135 /*lint +e956 */
00136 
00137 /*-----------------------------------------------------------*/
00138 
00139 /*
00140  * Initialise the infrastructure used by the timer service task if it has not
00141  * been initialised already.
00142  */
00143 static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
00144 
00145 /*
00146  * The timer service task (daemon).  Timer functionality is controlled by this
00147  * task.  Other tasks communicate with the timer service task using the
00148  * xTimerQueue queue.
00149  */
00150 static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
00151 
00152 /*
00153  * Called by the timer service task to interpret and process a command it
00154  * received on the timer queue.
00155  */
00156 static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
00157 
00158 /*
00159  * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
00160  * depending on if the expire time causes a timer counter overflow.
00161  */
00162 static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
00163 
00164 /*
00165  * An active timer has reached its expire time.  Reload the timer if it is an
00166  * auto reload timer, then call its callback.
00167  */
00168 static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
00169 
00170 /*
00171  * The tick count has overflowed.  Switch the timer lists after ensuring the
00172  * current timer list does not still reference some timers.
00173  */
00174 static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
00175 
00176 /*
00177  * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
00178  * if a tick count overflow occurred since prvSampleTimeNow() was last called.
00179  */
00180 static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
00181 
00182 /*
00183  * If the timer list contains any active timers then return the expire time of
00184  * the timer that will expire first and set *pxListWasEmpty to false.  If the
00185  * timer list does not contain any timers then return 0 and set *pxListWasEmpty
00186  * to pdTRUE.
00187  */
00188 static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
00189 
00190 /*
00191  * If a timer has expired, process it.  Otherwise, block the timer service task
00192  * until either a timer does expire or a command is received.
00193  */
00194 static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
00195 
00196 /*-----------------------------------------------------------*/
00197 
00198 portBASE_TYPE xTimerCreateTimerTask( void )
00199 {
00200 portBASE_TYPE xReturn = pdFAIL;
00201 
00202     /* This function is called when the scheduler is started if
00203     configUSE_TIMERS is set to 1.  Check that the infrastructure used by the
00204     timer service task has been created/initialised.  If timers have already
00205     been created then the initialisation will already have been performed. */
00206     prvCheckForValidListAndQueue();
00207 
00208     if( xTimerQueue != NULL )
00209     {
00210         #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
00211         {
00212             /* Create the timer task, storing its handle in xTimerTaskHandle so
00213             it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
00214             xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
00215         }
00216         #else
00217         {
00218             /* Create the timer task without storing its handle. */
00219             xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL);
00220         }
00221         #endif
00222     }
00223 
00224     configASSERT( xReturn );
00225     return xReturn;
00226 }
00227 /*-----------------------------------------------------------*/
00228 
00229 xTimerHandle xTimerCreate( const signed char * const pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
00230 {
00231 xTIMER *pxNewTimer;
00232 
00233     /* Allocate the timer structure. */
00234     if( xTimerPeriodInTicks == ( portTickType ) 0U )
00235     {
00236         pxNewTimer = NULL;
00237     }
00238     else
00239     {
00240         pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
00241         if( pxNewTimer != NULL )
00242         {
00243             /* Ensure the infrastructure used by the timer service task has been
00244             created/initialised. */
00245             prvCheckForValidListAndQueue();
00246 
00247             /* Initialise the timer structure members using the function parameters. */
00248             pxNewTimer->pcTimerName = pcTimerName;
00249             pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
00250             pxNewTimer->uxAutoReload = uxAutoReload;
00251             pxNewTimer->pvTimerID = pvTimerID;
00252             pxNewTimer->pxCallbackFunction = pxCallbackFunction;
00253             vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
00254 
00255             traceTIMER_CREATE( pxNewTimer );
00256         }
00257         else
00258         {
00259             traceTIMER_CREATE_FAILED();
00260         }
00261     }
00262 
00263     /* 0 is not a valid value for xTimerPeriodInTicks. */
00264     configASSERT( ( xTimerPeriodInTicks > 0 ) );
00265 
00266     return ( xTimerHandle ) pxNewTimer;
00267 }
00268 /*-----------------------------------------------------------*/
00269 
00270 portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
00271 {
00272 portBASE_TYPE xReturn = pdFAIL;
00273 xTIMER_MESSAGE xMessage;
00274 
00275     /* Send a message to the timer service task to perform a particular action
00276     on a particular timer definition. */
00277     if( xTimerQueue != NULL )
00278     {
00279         /* Send a command to the timer service task to start the xTimer timer. */
00280         xMessage.xMessageID = xCommandID;
00281         xMessage.xMessageValue = xOptionalValue;
00282         xMessage.pxTimer = ( xTIMER * ) xTimer;
00283 
00284         if( pxHigherPriorityTaskWoken == NULL )
00285         {
00286             if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
00287             {
00288                 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
00289             }
00290             else
00291             {
00292                 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
00293             }
00294         }
00295         else
00296         {
00297             xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
00298         }
00299 
00300         traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
00301     }
00302 
00303     return xReturn;
00304 }
00305 /*-----------------------------------------------------------*/
00306 
00307 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
00308 
00309     xTaskHandle xTimerGetTimerDaemonTaskHandle( void )
00310     {
00311         /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
00312         started, then xTimerTaskHandle will be NULL. */
00313         configASSERT( ( xTimerTaskHandle != NULL ) );
00314         return xTimerTaskHandle;
00315     }
00316 
00317 #endif
00318 /*-----------------------------------------------------------*/
00319 
00320 static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
00321 {
00322 xTIMER *pxTimer;
00323 portBASE_TYPE xResult;
00324 
00325     /* Remove the timer from the list of active timers.  A check has already
00326     been performed to ensure the list is not empty. */
00327     pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
00328     ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
00329     traceTIMER_EXPIRED( pxTimer );
00330 
00331     /* If the timer is an auto reload timer then calculate the next
00332     expiry time and re-insert the timer in the list of active timers. */
00333     if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
00334     {
00335         /* This is the only time a timer is inserted into a list using
00336         a time relative to anything other than the current time.  It
00337         will therefore be inserted into the correct list relative to
00338         the time this task thinks it is now, even if a command to
00339         switch lists due to a tick count overflow is already waiting in
00340         the timer queue. */
00341         if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
00342         {
00343             /* The timer expired before it was added to the active timer
00344             list.  Reload it now.  */
00345             xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
00346             configASSERT( xResult );
00347             ( void ) xResult;
00348         }
00349     }
00350 
00351     /* Call the timer callback. */
00352     pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
00353 }
00354 /*-----------------------------------------------------------*/
00355 
00356 static void prvTimerTask( void *pvParameters )
00357 {
00358 portTickType xNextExpireTime;
00359 portBASE_TYPE xListWasEmpty;
00360 
00361     /* Just to avoid compiler warnings. */
00362     ( void ) pvParameters;
00363 
00364     for( ;; )
00365     {
00366         /* Query the timers list to see if it contains any timers, and if so,
00367         obtain the time at which the next timer will expire. */
00368         xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
00369 
00370         /* If a timer has expired, process it.  Otherwise, block this task
00371         until either a timer does expire, or a command is received. */
00372         prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
00373 
00374         /* Empty the command queue. */
00375         prvProcessReceivedCommands();
00376     }
00377 }
00378 /*-----------------------------------------------------------*/
00379 
00380 static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
00381 {
00382 portTickType xTimeNow;
00383 portBASE_TYPE xTimerListsWereSwitched;
00384 
00385     vTaskSuspendAll();
00386     {
00387         /* Obtain the time now to make an assessment as to whether the timer
00388         has expired or not.  If obtaining the time causes the lists to switch
00389         then don't process this timer as any timers that remained in the list
00390         when the lists were switched will have been processed within the
00391         prvSampelTimeNow() function. */
00392         xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
00393         if( xTimerListsWereSwitched == pdFALSE )
00394         {
00395             /* The tick count has not overflowed, has the timer expired? */
00396             if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
00397             {
00398                 ( void ) xTaskResumeAll();
00399                 prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
00400             }
00401             else
00402             {
00403                 /* The tick count has not overflowed, and the next expire
00404                 time has not been reached yet.  This task should therefore
00405                 block to wait for the next expire time or a command to be
00406                 received - whichever comes first.  The following line cannot
00407                 be reached unless xNextExpireTime > xTimeNow, except in the
00408                 case when the current timer list is empty. */
00409                 vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
00410 
00411                 if( xTaskResumeAll() == pdFALSE )
00412                 {
00413                     /* Yield to wait for either a command to arrive, or the block time
00414                     to expire.  If a command arrived between the critical section being
00415                     exited and this yield then the yield will not cause the task
00416                     to block. */
00417                     portYIELD_WITHIN_API();
00418                 }
00419             }
00420         }
00421         else
00422         {
00423             ( void ) xTaskResumeAll();
00424         }
00425     }
00426 }
00427 /*-----------------------------------------------------------*/
00428 
00429 static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
00430 {
00431 portTickType xNextExpireTime;
00432 
00433     /* Timers are listed in expiry time order, with the head of the list
00434     referencing the task that will expire first.  Obtain the time at which
00435     the timer with the nearest expiry time will expire.  If there are no
00436     active timers then just set the next expire time to 0.  That will cause
00437     this task to unblock when the tick count overflows, at which point the
00438     timer lists will be switched and the next expiry time can be
00439     re-assessed.  */
00440     *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
00441     if( *pxListWasEmpty == pdFALSE )
00442     {
00443         xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
00444     }
00445     else
00446     {
00447         /* Ensure the task unblocks when the tick count rolls over. */
00448         xNextExpireTime = ( portTickType ) 0U;
00449     }
00450 
00451     return xNextExpireTime;
00452 }
00453 /*-----------------------------------------------------------*/
00454 
00455 static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
00456 {
00457 portTickType xTimeNow;
00458 PRIVILEGED_DATA static portTickType xLastTime = ( portTickType ) 0U; /*lint !e956 Variable is only accessible to one task. */
00459 
00460     xTimeNow = xTaskGetTickCount();
00461 
00462     if( xTimeNow < xLastTime )
00463     {
00464         prvSwitchTimerLists( xLastTime );
00465         *pxTimerListsWereSwitched = pdTRUE;
00466     }
00467     else
00468     {
00469         *pxTimerListsWereSwitched = pdFALSE;
00470     }
00471 
00472     xLastTime = xTimeNow;
00473 
00474     return xTimeNow;
00475 }
00476 /*-----------------------------------------------------------*/
00477 
00478 static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
00479 {
00480 portBASE_TYPE xProcessTimerNow = pdFALSE;
00481 
00482     listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
00483     listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
00484 
00485     if( xNextExpiryTime <= xTimeNow )
00486     {
00487         /* Has the expiry time elapsed between the command to start/reset a
00488         timer was issued, and the time the command was processed? */
00489         if( ( xTimeNow - xCommandTime ) >= pxTimer->xTimerPeriodInTicks )
00490         {
00491             /* The time between a command being issued and the command being
00492             processed actually exceeds the timers period.  */
00493             xProcessTimerNow = pdTRUE;
00494         }
00495         else
00496         {
00497             vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
00498         }
00499     }
00500     else
00501     {
00502         if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
00503         {
00504             /* If, since the command was issued, the tick count has overflowed
00505             but the expiry time has not, then the timer must have already passed
00506             its expiry time and should be processed immediately. */
00507             xProcessTimerNow = pdTRUE;
00508         }
00509         else
00510         {
00511             vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
00512         }
00513     }
00514 
00515     return xProcessTimerNow;
00516 }
00517 /*-----------------------------------------------------------*/
00518 
00519 static void prvProcessReceivedCommands( void )
00520 {
00521 xTIMER_MESSAGE xMessage;
00522 xTIMER *pxTimer;
00523 portBASE_TYPE xTimerListsWereSwitched, xResult;
00524 portTickType xTimeNow;
00525 
00526     while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */
00527     {
00528         pxTimer = xMessage.pxTimer;
00529 
00530         if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
00531         {
00532             /* The timer is in a list, remove it. */
00533             ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
00534         }
00535 
00536         traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
00537 
00538         /* In this case the xTimerListsWereSwitched parameter is not used, but 
00539         it must be present in the function call.  prvSampleTimeNow() must be 
00540         called after the message is received from xTimerQueue so there is no 
00541         possibility of a higher priority task adding a message to the message
00542         queue with a time that is ahead of the timer daemon task (because it
00543         pre-empted the timer daemon task after the xTimeNow value was set). */
00544         xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
00545 
00546         switch( xMessage.xMessageID )
00547         {
00548             case tmrCOMMAND_START :
00549                 /* Start or restart a timer. */
00550                 if( prvInsertTimerInActiveList( pxTimer,  xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )
00551                 {
00552                     /* The timer expired before it was added to the active timer
00553                     list.  Process it now. */
00554                     pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
00555 
00556                     if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
00557                     {
00558                         xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
00559                         configASSERT( xResult );
00560                         ( void ) xResult;
00561                     }
00562                 }
00563                 break;
00564 
00565             case tmrCOMMAND_STOP :
00566                 /* The timer has already been removed from the active list.
00567                 There is nothing to do here. */
00568                 break;
00569 
00570             case tmrCOMMAND_CHANGE_PERIOD :
00571                 pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
00572                 configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
00573 
00574                 /* The new period does not really have a reference, and can be
00575                 longer or shorter than the old one.  The command time is 
00576                 therefore set to the current time, and as the period cannot be
00577                 zero the next expiry time can only be in the future, meaning
00578                 (unlike for the xTimerStart() case above) there is no fail case
00579                 that needs to be handled here. */
00580                 ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
00581                 break;
00582 
00583             case tmrCOMMAND_DELETE :
00584                 /* The timer has already been removed from the active list,
00585                 just free up the memory. */
00586                 vPortFree( pxTimer );
00587                 break;
00588 
00589             default :
00590                 /* Don't expect to get here. */
00591                 break;
00592         }
00593     }
00594 }
00595 /*-----------------------------------------------------------*/
00596 
00597 static void prvSwitchTimerLists( portTickType xLastTime )
00598 {
00599 portTickType xNextExpireTime, xReloadTime;
00600 xList *pxTemp;
00601 xTIMER *pxTimer;
00602 portBASE_TYPE xResult;
00603 
00604     /* Remove compiler warnings if configASSERT() is not defined. */
00605     ( void ) xLastTime;
00606 
00607     /* The tick count has overflowed.  The timer lists must be switched.
00608     If there are any timers still referenced from the current timer list
00609     then they must have expired and should be processed before the lists
00610     are switched. */
00611     while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
00612     {
00613         xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
00614 
00615         /* Remove the timer from the list. */
00616         pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
00617         ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
00618 
00619         /* Execute its callback, then send a command to restart the timer if
00620         it is an auto-reload timer.  It cannot be restarted here as the lists
00621         have not yet been switched. */
00622         pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
00623 
00624         if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
00625         {
00626             /* Calculate the reload value, and if the reload value results in
00627             the timer going into the same timer list then it has already expired
00628             and the timer should be re-inserted into the current list so it is
00629             processed again within this loop.  Otherwise a command should be sent
00630             to restart the timer to ensure it is only inserted into a list after
00631             the lists have been swapped. */
00632             xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
00633             if( xReloadTime > xNextExpireTime )
00634             {
00635                 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
00636                 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
00637                 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
00638             }
00639             else
00640             {
00641                 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
00642                 configASSERT( xResult );
00643                 ( void ) xResult;
00644             }
00645         }
00646     }
00647 
00648     pxTemp = pxCurrentTimerList;
00649     pxCurrentTimerList = pxOverflowTimerList;
00650     pxOverflowTimerList = pxTemp;
00651 }
00652 /*-----------------------------------------------------------*/
00653 
00654 static void prvCheckForValidListAndQueue( void )
00655 {
00656     /* Check that the list from which active timers are referenced, and the
00657     queue used to communicate with the timer service, have been
00658     initialised. */
00659     taskENTER_CRITICAL();
00660     {
00661         if( xTimerQueue == NULL )
00662         {
00663             vListInitialise( &xActiveTimerList1 );
00664             vListInitialise( &xActiveTimerList2 );
00665             pxCurrentTimerList = &xActiveTimerList1;
00666             pxOverflowTimerList = &xActiveTimerList2;
00667             xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
00668         }
00669     }
00670     taskEXIT_CRITICAL();
00671 }
00672 /*-----------------------------------------------------------*/
00673 
00674 portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
00675 {
00676 portBASE_TYPE xTimerIsInActiveList;
00677 xTIMER *pxTimer = ( xTIMER * ) xTimer;
00678 
00679     /* Is the timer in the list of active timers? */
00680     taskENTER_CRITICAL();
00681     {
00682         /* Checking to see if it is in the NULL list in effect checks to see if
00683         it is referenced from either the current or the overflow timer lists in
00684         one go, but the logic has to be reversed, hence the '!'. */
00685         xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
00686     }
00687     taskEXIT_CRITICAL();
00688 
00689     return xTimerIsInActiveList;
00690 }
00691 /*-----------------------------------------------------------*/
00692 
00693 void *pvTimerGetTimerID( xTimerHandle xTimer )
00694 {
00695 xTIMER *pxTimer = ( xTIMER * ) xTimer;
00696 
00697     return pxTimer->pvTimerID;
00698 }
00699 /*-----------------------------------------------------------*/
00700 
00701 /* This entire source file will be skipped if the application is not configured
00702 to include software timer functionality.  If you want to include software timer
00703 functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
00704 #endif /* configUSE_TIMERS == 1 */
00705 
00706 
00707