2 * FreeRTOS Kernel V10.1.1
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * http://www.FreeRTOS.org
23 * http://aws.amazon.com/freertos
28 /* Standard includes. */
31 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
32 all the API functions to use the MPU wrappers. That should only be done when
33 task.h is included from an application file. */
34 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
41 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 )
42 #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available.
45 /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
46 because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
47 for the header files above, but not in this file, in order to generate the
48 correct privileged Vs unprivileged linkage and placement. */
49 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */
52 /* This entire source file will be skipped if the application is not configured
53 to include software timer functionality. This #if is closed at the very bottom
54 of this file. If you want to include software timer functionality then ensure
55 configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
56 #if ( configUSE_TIMERS == 1 )
58 /* Misc definitions. */
59 #define tmrNO_DELAY ( TickType_t ) 0U
61 /* The name assigned to the timer service task. This can be overridden by
62 defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
63 #ifndef configTIMER_SERVICE_TASK_NAME
64 #define configTIMER_SERVICE_TASK_NAME "Tmr Svc"
67 /* The definition of the timers themselves. */
68 typedef struct tmrTimerControl /* The old naming convention is used to prevent breaking kernel aware debuggers. */
70 const char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
71 ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
72 TickType_t xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
73 UBaseType_t 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. */
74 void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
75 TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */
76 #if( configUSE_TRACE_FACILITY == 1 )
77 UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
80 #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
81 uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created statically so no attempt is made to free the memory again if the timer is later deleted. */
85 /* The old xTIMER name is maintained above then typedefed to the new Timer_t
86 name below to enable the use of older kernel aware debuggers. */
87 typedef xTIMER Timer_t;
89 /* The definition of messages that can be sent and received on the timer queue.
90 Two types of message can be queued - messages that manipulate a software timer,
91 and messages that request the execution of a non-timer related callback. The
92 two message types are defined in two separate structures, xTimerParametersType
93 and xCallbackParametersType respectively. */
94 typedef struct tmrTimerParameters
96 TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
97 Timer_t * pxTimer; /*<< The timer to which the command will be applied. */
101 typedef struct tmrCallbackParameters
103 PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */
104 void *pvParameter1; /* << The value that will be used as the callback functions first parameter. */
105 uint32_t ulParameter2; /* << The value that will be used as the callback functions second parameter. */
106 } CallbackParameters_t;
108 /* The structure that contains the two message types, along with an identifier
109 that is used to determine which message type is valid. */
110 typedef struct tmrTimerQueueMessage
112 BaseType_t xMessageID; /*<< The command being sent to the timer service task. */
115 TimerParameter_t xTimerParameters;
117 /* Don't include xCallbackParameters if it is not going to be used as
118 it makes the structure (and therefore the timer queue) larger. */
119 #if ( INCLUDE_xTimerPendFunctionCall == 1 )
120 CallbackParameters_t xCallbackParameters;
121 #endif /* INCLUDE_xTimerPendFunctionCall */
123 } DaemonTaskMessage_t;
125 /*lint -save -e956 A manual analysis and inspection has been used to determine
126 which static variables must be declared volatile. */
128 /* The list in which active timers are stored. Timers are referenced in expire
129 time order, with the nearest expiry time at the front of the list. Only the
130 timer service task is allowed to access these lists.
131 xActiveTimerList1 and xActiveTimerList2 could be at function scope but that
132 breaks some kernel aware debuggers, and debuggers that reply on removing the
134 PRIVILEGED_DATA static List_t xActiveTimerList1;
135 PRIVILEGED_DATA static List_t xActiveTimerList2;
136 PRIVILEGED_DATA static List_t *pxCurrentTimerList;
137 PRIVILEGED_DATA static List_t *pxOverflowTimerList;
139 /* A queue that is used to send commands to the timer service task. */
140 PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
141 PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
145 /*-----------------------------------------------------------*/
147 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
149 /* If static allocation is supported then the application must provide the
150 following callback function - which enables the application to optionally
151 provide the memory that will be used by the timer task as the task's stack
153 extern void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize );
158 * Initialise the infrastructure used by the timer service task if it has not
159 * been initialised already.
161 static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
164 * The timer service task (daemon). Timer functionality is controlled by this
165 * task. Other tasks communicate with the timer service task using the
168 static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
171 * Called by the timer service task to interpret and process a command it
172 * received on the timer queue.
174 static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
177 * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
178 * depending on if the expire time causes a timer counter overflow.
180 static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) PRIVILEGED_FUNCTION;
183 * An active timer has reached its expire time. Reload the timer if it is an
184 * auto reload timer, then call its callback.
186 static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
189 * The tick count has overflowed. Switch the timer lists after ensuring the
190 * current timer list does not still reference some timers.
192 static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION;
195 * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
196 * if a tick count overflow occurred since prvSampleTimeNow() was last called.
198 static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
201 * If the timer list contains any active timers then return the expire time of
202 * the timer that will expire first and set *pxListWasEmpty to false. If the
203 * timer list does not contain any timers then return 0 and set *pxListWasEmpty
206 static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION;
209 * If a timer has expired, process it. Otherwise, block the timer service task
210 * until either a timer does expire or a command is received.
212 static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION;
215 * Called after a Timer_t structure has been allocated either statically or
216 * dynamically to fill in the structure's members.
218 static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
219 const TickType_t xTimerPeriodInTicks,
220 const UBaseType_t uxAutoReload,
221 void * const pvTimerID,
222 TimerCallbackFunction_t pxCallbackFunction,
223 Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION;
224 /*-----------------------------------------------------------*/
226 BaseType_t xTimerCreateTimerTask( void )
228 BaseType_t xReturn = pdFAIL;
230 /* This function is called when the scheduler is started if
231 configUSE_TIMERS is set to 1. Check that the infrastructure used by the
232 timer service task has been created/initialised. If timers have already
233 been created then the initialisation will already have been performed. */
234 prvCheckForValidListAndQueue();
236 if( xTimerQueue != NULL )
238 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
240 StaticTask_t *pxTimerTaskTCBBuffer = NULL;
241 StackType_t *pxTimerTaskStackBuffer = NULL;
242 uint32_t ulTimerTaskStackSize;
244 vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
245 xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
246 configTIMER_SERVICE_TASK_NAME,
247 ulTimerTaskStackSize,
249 ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
250 pxTimerTaskStackBuffer,
251 pxTimerTaskTCBBuffer );
253 if( xTimerTaskHandle != NULL )
260 xReturn = xTaskCreate( prvTimerTask,
261 configTIMER_SERVICE_TASK_NAME,
262 configTIMER_TASK_STACK_DEPTH,
264 ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
267 #endif /* configSUPPORT_STATIC_ALLOCATION */
271 mtCOVERAGE_TEST_MARKER();
274 configASSERT( xReturn );
277 /*-----------------------------------------------------------*/
279 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
281 TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
282 const TickType_t xTimerPeriodInTicks,
283 const UBaseType_t uxAutoReload,
284 void * const pvTimerID,
285 TimerCallbackFunction_t pxCallbackFunction )
289 pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of Timer_t is always a pointer to the timer's mame. */
291 if( pxNewTimer != NULL )
293 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
295 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
297 /* Timers can be created statically or dynamically, so note this
298 timer was created dynamically in case the timer is later
300 pxNewTimer->ucStaticallyAllocated = pdFALSE;
302 #endif /* configSUPPORT_STATIC_ALLOCATION */
308 #endif /* configSUPPORT_STATIC_ALLOCATION */
309 /*-----------------------------------------------------------*/
311 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
313 TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
314 const TickType_t xTimerPeriodInTicks,
315 const UBaseType_t uxAutoReload,
316 void * const pvTimerID,
317 TimerCallbackFunction_t pxCallbackFunction,
318 StaticTimer_t *pxTimerBuffer )
322 #if( configASSERT_DEFINED == 1 )
324 /* Sanity check that the size of the structure used to declare a
325 variable of type StaticTimer_t equals the size of the real timer
327 volatile size_t xSize = sizeof( StaticTimer_t );
328 configASSERT( xSize == sizeof( Timer_t ) );
329 ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */
331 #endif /* configASSERT_DEFINED */
333 /* A pointer to a StaticTimer_t structure MUST be provided, use it. */
334 configASSERT( pxTimerBuffer );
335 pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 !e9087 StaticTimer_t is a pointer to a Timer_t, so guaranteed to be aligned and sized correctly (checked by an assert()), so this is safe. */
337 if( pxNewTimer != NULL )
339 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
341 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
343 /* Timers can be created statically or dynamically so note this
344 timer was created statically in case it is later deleted. */
345 pxNewTimer->ucStaticallyAllocated = pdTRUE;
347 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
353 #endif /* configSUPPORT_STATIC_ALLOCATION */
354 /*-----------------------------------------------------------*/
356 static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
357 const TickType_t xTimerPeriodInTicks,
358 const UBaseType_t uxAutoReload,
359 void * const pvTimerID,
360 TimerCallbackFunction_t pxCallbackFunction,
361 Timer_t *pxNewTimer )
363 /* 0 is not a valid value for xTimerPeriodInTicks. */
364 configASSERT( ( xTimerPeriodInTicks > 0 ) );
366 if( pxNewTimer != NULL )
368 /* Ensure the infrastructure used by the timer service task has been
369 created/initialised. */
370 prvCheckForValidListAndQueue();
372 /* Initialise the timer structure members using the function
374 pxNewTimer->pcTimerName = pcTimerName;
375 pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
376 pxNewTimer->uxAutoReload = uxAutoReload;
377 pxNewTimer->pvTimerID = pvTimerID;
378 pxNewTimer->pxCallbackFunction = pxCallbackFunction;
379 vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
380 traceTIMER_CREATE( pxNewTimer );
383 /*-----------------------------------------------------------*/
385 BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait )
387 BaseType_t xReturn = pdFAIL;
388 DaemonTaskMessage_t xMessage;
390 configASSERT( xTimer );
392 /* Send a message to the timer service task to perform a particular action
393 on a particular timer definition. */
394 if( xTimerQueue != NULL )
396 /* Send a command to the timer service task to start the xTimer timer. */
397 xMessage.xMessageID = xCommandID;
398 xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
399 xMessage.u.xTimerParameters.pxTimer = xTimer;
401 if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
403 if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
405 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
409 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
414 xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
417 traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
421 mtCOVERAGE_TEST_MARKER();
426 /*-----------------------------------------------------------*/
428 TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )
430 /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
431 started, then xTimerTaskHandle will be NULL. */
432 configASSERT( ( xTimerTaskHandle != NULL ) );
433 return xTimerTaskHandle;
435 /*-----------------------------------------------------------*/
437 TickType_t xTimerGetPeriod( TimerHandle_t xTimer )
439 Timer_t *pxTimer = xTimer;
441 configASSERT( xTimer );
442 return pxTimer->xTimerPeriodInTicks;
444 /*-----------------------------------------------------------*/
446 TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer )
448 Timer_t * pxTimer = xTimer;
451 configASSERT( xTimer );
452 xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) );
455 /*-----------------------------------------------------------*/
457 const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
459 Timer_t *pxTimer = xTimer;
461 configASSERT( xTimer );
462 return pxTimer->pcTimerName;
464 /*-----------------------------------------------------------*/
466 static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow )
469 Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
471 /* Remove the timer from the list of active timers. A check has already
472 been performed to ensure the list is not empty. */
473 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
474 traceTIMER_EXPIRED( pxTimer );
476 /* If the timer is an auto reload timer then calculate the next
477 expiry time and re-insert the timer in the list of active timers. */
478 if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
480 /* The timer is inserted into a list using a time relative to anything
481 other than the current time. It will therefore be inserted into the
482 correct list relative to the time this task thinks it is now. */
483 if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )
485 /* The timer expired before it was added to the active timer
486 list. Reload it now. */
487 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
488 configASSERT( xResult );
493 mtCOVERAGE_TEST_MARKER();
498 mtCOVERAGE_TEST_MARKER();
501 /* Call the timer callback. */
502 pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
504 /*-----------------------------------------------------------*/
506 static void prvTimerTask( void *pvParameters )
508 TickType_t xNextExpireTime;
509 BaseType_t xListWasEmpty;
511 /* Just to avoid compiler warnings. */
512 ( void ) pvParameters;
514 #if( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 )
516 extern void vApplicationDaemonTaskStartupHook( void );
518 /* Allow the application writer to execute some code in the context of
519 this task at the point the task starts executing. This is useful if the
520 application includes initialisation code that would benefit from
521 executing after the scheduler has been started. */
522 vApplicationDaemonTaskStartupHook();
524 #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
528 /* Query the timers list to see if it contains any timers, and if so,
529 obtain the time at which the next timer will expire. */
530 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
532 /* If a timer has expired, process it. Otherwise, block this task
533 until either a timer does expire, or a command is received. */
534 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
536 /* Empty the command queue. */
537 prvProcessReceivedCommands();
540 /*-----------------------------------------------------------*/
542 static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty )
545 BaseType_t xTimerListsWereSwitched;
549 /* Obtain the time now to make an assessment as to whether the timer
550 has expired or not. If obtaining the time causes the lists to switch
551 then don't process this timer as any timers that remained in the list
552 when the lists were switched will have been processed within the
553 prvSampleTimeNow() function. */
554 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
555 if( xTimerListsWereSwitched == pdFALSE )
557 /* The tick count has not overflowed, has the timer expired? */
558 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
560 ( void ) xTaskResumeAll();
561 prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
565 /* The tick count has not overflowed, and the next expire
566 time has not been reached yet. This task should therefore
567 block to wait for the next expire time or a command to be
568 received - whichever comes first. The following line cannot
569 be reached unless xNextExpireTime > xTimeNow, except in the
570 case when the current timer list is empty. */
571 if( xListWasEmpty != pdFALSE )
573 /* The current timer list is empty - is the overflow list
575 xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
578 vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
580 if( xTaskResumeAll() == pdFALSE )
582 /* Yield to wait for either a command to arrive, or the
583 block time to expire. If a command arrived between the
584 critical section being exited and this yield then the yield
585 will not cause the task to block. */
586 portYIELD_WITHIN_API();
590 mtCOVERAGE_TEST_MARKER();
596 ( void ) xTaskResumeAll();
600 /*-----------------------------------------------------------*/
602 static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )
604 TickType_t xNextExpireTime;
606 /* Timers are listed in expiry time order, with the head of the list
607 referencing the task that will expire first. Obtain the time at which
608 the timer with the nearest expiry time will expire. If there are no
609 active timers then just set the next expire time to 0. That will cause
610 this task to unblock when the tick count overflows, at which point the
611 timer lists will be switched and the next expiry time can be
613 *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
614 if( *pxListWasEmpty == pdFALSE )
616 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
620 /* Ensure the task unblocks when the tick count rolls over. */
621 xNextExpireTime = ( TickType_t ) 0U;
624 return xNextExpireTime;
626 /*-----------------------------------------------------------*/
628 static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
631 PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */
633 xTimeNow = xTaskGetTickCount();
635 if( xTimeNow < xLastTime )
637 prvSwitchTimerLists();
638 *pxTimerListsWereSwitched = pdTRUE;
642 *pxTimerListsWereSwitched = pdFALSE;
645 xLastTime = xTimeNow;
649 /*-----------------------------------------------------------*/
651 static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime )
653 BaseType_t xProcessTimerNow = pdFALSE;
655 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
656 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
658 if( xNextExpiryTime <= xTimeNow )
660 /* Has the expiry time elapsed between the command to start/reset a
661 timer was issued, and the time the command was processed? */
662 if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
664 /* The time between a command being issued and the command being
665 processed actually exceeds the timers period. */
666 xProcessTimerNow = pdTRUE;
670 vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
675 if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
677 /* If, since the command was issued, the tick count has overflowed
678 but the expiry time has not, then the timer must have already passed
679 its expiry time and should be processed immediately. */
680 xProcessTimerNow = pdTRUE;
684 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
688 return xProcessTimerNow;
690 /*-----------------------------------------------------------*/
692 static void prvProcessReceivedCommands( void )
694 DaemonTaskMessage_t xMessage;
696 BaseType_t xTimerListsWereSwitched, xResult;
699 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. */
701 #if ( INCLUDE_xTimerPendFunctionCall == 1 )
703 /* Negative commands are pended function calls rather than timer
705 if( xMessage.xMessageID < ( BaseType_t ) 0 )
707 const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters );
709 /* The timer uses the xCallbackParameters member to request a
710 callback be executed. Check the callback is not NULL. */
711 configASSERT( pxCallback );
713 /* Call the function. */
714 pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 );
718 mtCOVERAGE_TEST_MARKER();
721 #endif /* INCLUDE_xTimerPendFunctionCall */
723 /* Commands that are positive are timer commands rather than pended
725 if( xMessage.xMessageID >= ( BaseType_t ) 0 )
727 /* The messages uses the xTimerParameters member to work on a
729 pxTimer = xMessage.u.xTimerParameters.pxTimer;
731 if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */
733 /* The timer is in a list, remove it. */
734 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
738 mtCOVERAGE_TEST_MARKER();
741 traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
743 /* In this case the xTimerListsWereSwitched parameter is not used, but
744 it must be present in the function call. prvSampleTimeNow() must be
745 called after the message is received from xTimerQueue so there is no
746 possibility of a higher priority task adding a message to the message
747 queue with a time that is ahead of the timer daemon task (because it
748 pre-empted the timer daemon task after the xTimeNow value was set). */
749 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
751 switch( xMessage.xMessageID )
753 case tmrCOMMAND_START :
754 case tmrCOMMAND_START_FROM_ISR :
755 case tmrCOMMAND_RESET :
756 case tmrCOMMAND_RESET_FROM_ISR :
757 case tmrCOMMAND_START_DONT_TRACE :
758 /* Start or restart a timer. */
759 if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )
761 /* The timer expired before it was added to the active
762 timer list. Process it now. */
763 pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
764 traceTIMER_EXPIRED( pxTimer );
766 if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
768 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
769 configASSERT( xResult );
774 mtCOVERAGE_TEST_MARKER();
779 mtCOVERAGE_TEST_MARKER();
783 case tmrCOMMAND_STOP :
784 case tmrCOMMAND_STOP_FROM_ISR :
785 /* The timer has already been removed from the active list.
786 There is nothing to do here. */
789 case tmrCOMMAND_CHANGE_PERIOD :
790 case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR :
791 pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
792 configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
794 /* The new period does not really have a reference, and can
795 be longer or shorter than the old one. The command time is
796 therefore set to the current time, and as the period cannot
797 be zero the next expiry time can only be in the future,
798 meaning (unlike for the xTimerStart() case above) there is
799 no fail case that needs to be handled here. */
800 ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
803 case tmrCOMMAND_DELETE :
804 /* The timer has already been removed from the active list,
805 just free up the memory if the memory was dynamically
807 #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
809 /* The timer can only have been allocated dynamically -
811 vPortFree( pxTimer );
813 #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
815 /* The timer could have been allocated statically or
816 dynamically, so check before attempting to free the
818 if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
820 vPortFree( pxTimer );
824 mtCOVERAGE_TEST_MARKER();
827 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
831 /* Don't expect to get here. */
837 /*-----------------------------------------------------------*/
839 static void prvSwitchTimerLists( void )
841 TickType_t xNextExpireTime, xReloadTime;
846 /* The tick count has overflowed. The timer lists must be switched.
847 If there are any timers still referenced from the current timer list
848 then they must have expired and should be processed before the lists
850 while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
852 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
854 /* Remove the timer from the list. */
855 pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
856 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
857 traceTIMER_EXPIRED( pxTimer );
859 /* Execute its callback, then send a command to restart the timer if
860 it is an auto-reload timer. It cannot be restarted here as the lists
861 have not yet been switched. */
862 pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
864 if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
866 /* Calculate the reload value, and if the reload value results in
867 the timer going into the same timer list then it has already expired
868 and the timer should be re-inserted into the current list so it is
869 processed again within this loop. Otherwise a command should be sent
870 to restart the timer to ensure it is only inserted into a list after
871 the lists have been swapped. */
872 xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
873 if( xReloadTime > xNextExpireTime )
875 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
876 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
877 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
881 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
882 configASSERT( xResult );
888 mtCOVERAGE_TEST_MARKER();
892 pxTemp = pxCurrentTimerList;
893 pxCurrentTimerList = pxOverflowTimerList;
894 pxOverflowTimerList = pxTemp;
896 /*-----------------------------------------------------------*/
898 static void prvCheckForValidListAndQueue( void )
900 /* Check that the list from which active timers are referenced, and the
901 queue used to communicate with the timer service, have been
903 taskENTER_CRITICAL();
905 if( xTimerQueue == NULL )
907 vListInitialise( &xActiveTimerList1 );
908 vListInitialise( &xActiveTimerList2 );
909 pxCurrentTimerList = &xActiveTimerList1;
910 pxOverflowTimerList = &xActiveTimerList2;
912 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
914 /* The timer queue is allocated statically in case
915 configSUPPORT_DYNAMIC_ALLOCATION is 0. */
916 static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
917 static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
919 xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
923 xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );
927 #if ( configQUEUE_REGISTRY_SIZE > 0 )
929 if( xTimerQueue != NULL )
931 vQueueAddToRegistry( xTimerQueue, "TmrQ" );
935 mtCOVERAGE_TEST_MARKER();
938 #endif /* configQUEUE_REGISTRY_SIZE */
942 mtCOVERAGE_TEST_MARKER();
947 /*-----------------------------------------------------------*/
949 BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
951 BaseType_t xTimerIsInActiveList;
952 Timer_t *pxTimer = xTimer;
954 configASSERT( xTimer );
956 /* Is the timer in the list of active timers? */
957 taskENTER_CRITICAL();
959 /* Checking to see if it is in the NULL list in effect checks to see if
960 it is referenced from either the current or the overflow timer lists in
961 one go, but the logic has to be reversed, hence the '!'. */
962 if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdTRUE )
964 xTimerIsInActiveList = pdFALSE;
968 xTimerIsInActiveList = pdTRUE;
973 return xTimerIsInActiveList;
974 } /*lint !e818 Can't be pointer to const due to the typedef. */
975 /*-----------------------------------------------------------*/
977 void *pvTimerGetTimerID( const TimerHandle_t xTimer )
979 Timer_t * const pxTimer = xTimer;
982 configASSERT( xTimer );
984 taskENTER_CRITICAL();
986 pvReturn = pxTimer->pvTimerID;
992 /*-----------------------------------------------------------*/
994 void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID )
996 Timer_t * const pxTimer = xTimer;
998 configASSERT( xTimer );
1000 taskENTER_CRITICAL();
1002 pxTimer->pvTimerID = pvNewID;
1004 taskEXIT_CRITICAL();
1006 /*-----------------------------------------------------------*/
1008 #if( INCLUDE_xTimerPendFunctionCall == 1 )
1010 BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken )
1012 DaemonTaskMessage_t xMessage;
1015 /* Complete the message with the function parameters and post it to the
1017 xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
1018 xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1019 xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1020 xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1022 xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
1024 tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1029 #endif /* INCLUDE_xTimerPendFunctionCall */
1030 /*-----------------------------------------------------------*/
1032 #if( INCLUDE_xTimerPendFunctionCall == 1 )
1034 BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait )
1036 DaemonTaskMessage_t xMessage;
1039 /* This function can only be called after a timer has been created or
1040 after the scheduler has been started because, until then, the timer
1041 queue does not exist. */
1042 configASSERT( xTimerQueue );
1044 /* Complete the message with the function parameters and post it to the
1046 xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
1047 xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1048 xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1049 xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1051 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
1053 tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1058 #endif /* INCLUDE_xTimerPendFunctionCall */
1059 /*-----------------------------------------------------------*/
1061 #if ( configUSE_TRACE_FACILITY == 1 )
1063 UBaseType_t uxTimerGetTimerNumber( TimerHandle_t xTimer )
1065 return ( ( Timer_t * ) xTimer )->uxTimerNumber;
1068 #endif /* configUSE_TRACE_FACILITY */
1069 /*-----------------------------------------------------------*/
1071 #if ( configUSE_TRACE_FACILITY == 1 )
1073 void vTimerSetTimerNumber( TimerHandle_t xTimer, UBaseType_t uxTimerNumber )
1075 ( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber;
1078 #endif /* configUSE_TRACE_FACILITY */
1079 /*-----------------------------------------------------------*/
1081 /* This entire source file will be skipped if the application is not configured
1082 to include software timer functionality. If you want to include software timer
1083 functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
1084 #endif /* configUSE_TIMERS == 1 */