www.freertos.org
Dependents: Nucleo freertos_test FreeRTOS_test freertos_bluetooth ... more
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
Generated on Tue Jul 12 2022 11:36:40 by 1.7.2