]> begriffs open source - freertos/blob - timers.c
added multiple idle tasks
[freertos] / timers.c
1 /*
2  * FreeRTOS Kernel V10.4.3
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
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.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  */
26
27 /* Standard includes. */
28 #include <stdlib.h>
29
30 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
31  * all the API functions to use the MPU wrappers.  That should only be done when
32  * task.h is included from an application file. */
33 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
34
35 #include "FreeRTOS.h"
36 #include "task.h"
37 #include "queue.h"
38 #include "timers.h"
39
40 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 )
41     #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available.
42 #endif
43
44 /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
45  * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
46  * for the header files above, but not in this file, in order to generate the
47  * correct privileged Vs unprivileged linkage and placement. */
48 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */
49
50
51 /* This entire source file will be skipped if the application is not configured
52  * to include software timer functionality.  This #if is closed at the very bottom
53  * of this file.  If you want to include software timer functionality then ensure
54  * configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
55 #if ( configUSE_TIMERS == 1 )
56
57 /* Misc definitions. */
58     #define tmrNO_DELAY    ( TickType_t ) 0U
59
60 /* The name assigned to the timer service task.  This can be overridden by
61  * defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
62     #ifndef configTIMER_SERVICE_TASK_NAME
63         #define configTIMER_SERVICE_TASK_NAME    "Tmr Svc"
64     #endif
65
66 /* Bit definitions used in the ucStatus member of a timer structure. */
67     #define tmrSTATUS_IS_ACTIVE                  ( ( uint8_t ) 0x01 )
68     #define tmrSTATUS_IS_STATICALLY_ALLOCATED    ( ( uint8_t ) 0x02 )
69     #define tmrSTATUS_IS_AUTORELOAD              ( ( uint8_t ) 0x04 )
70
71 /* The definition of the timers themselves. */
72     typedef struct tmrTimerControl                  /* The old naming convention is used to prevent breaking kernel aware debuggers. */
73     {
74         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. */
75         ListItem_t xTimerListItem;                  /*<< Standard linked list item as used by all kernel features for event management. */
76         TickType_t xTimerPeriodInTicks;             /*<< How quickly and often the timer expires. */
77         void * pvTimerID;                           /*<< An ID to identify the timer.  This allows the timer to be identified when the same callback is used for multiple timers. */
78         portTIMER_CALLBACK_ATTRIBUTE
79         TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */
80         #if ( configUSE_TRACE_FACILITY == 1 )
81             UBaseType_t uxTimerNumber;              /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
82         #endif
83         uint8_t ucStatus;                           /*<< Holds bits to say if the timer was statically allocated or not, and if it is active or not. */
84     } xTIMER;
85
86 /* The old xTIMER name is maintained above then typedefed to the new Timer_t
87  * name below to enable the use of older kernel aware debuggers. */
88     typedef xTIMER Timer_t;
89
90 /* The definition of messages that can be sent and received on the timer queue.
91  * Two types of message can be queued - messages that manipulate a software timer,
92  * and messages that request the execution of a non-timer related callback.  The
93  * two message types are defined in two separate structures, xTimerParametersType
94  * and xCallbackParametersType respectively. */
95     typedef struct tmrTimerParameters
96     {
97         TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
98         Timer_t * pxTimer;        /*<< The timer to which the command will be applied. */
99     } TimerParameter_t;
100
101
102     typedef struct tmrCallbackParameters
103     {
104         portTIMER_CALLBACK_ATTRIBUTE
105         PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */
106         void * pvParameter1;                 /* << The value that will be used as the callback functions first parameter. */
107         uint32_t ulParameter2;               /* << The value that will be used as the callback functions second parameter. */
108     } CallbackParameters_t;
109
110 /* The structure that contains the two message types, along with an identifier
111  * that is used to determine which message type is valid. */
112     typedef struct tmrTimerQueueMessage
113     {
114         BaseType_t xMessageID; /*<< The command being sent to the timer service task. */
115         union
116         {
117             TimerParameter_t xTimerParameters;
118
119             /* Don't include xCallbackParameters if it is not going to be used as
120              * it makes the structure (and therefore the timer queue) larger. */
121             #if ( INCLUDE_xTimerPendFunctionCall == 1 )
122                 CallbackParameters_t xCallbackParameters;
123             #endif /* INCLUDE_xTimerPendFunctionCall */
124         } u;
125     } DaemonTaskMessage_t;
126
127 /*lint -save -e956 A manual analysis and inspection has been used to determine
128  * which static variables must be declared volatile. */
129
130 /* The list in which active timers are stored.  Timers are referenced in expire
131  * time order, with the nearest expiry time at the front of the list.  Only the
132  * timer service task is allowed to access these lists.
133  * xActiveTimerList1 and xActiveTimerList2 could be at function scope but that
134  * breaks some kernel aware debuggers, and debuggers that reply on removing the
135  * static qualifier. */
136     PRIVILEGED_DATA static List_t xActiveTimerList1;
137     PRIVILEGED_DATA static List_t xActiveTimerList2;
138     PRIVILEGED_DATA static List_t * pxCurrentTimerList;
139     PRIVILEGED_DATA static List_t * pxOverflowTimerList;
140
141 /* A queue that is used to send commands to the timer service task. */
142     PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
143     PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
144
145 /*lint -restore */
146
147 /*-----------------------------------------------------------*/
148
149 /*
150  * Initialise the infrastructure used by the timer service task if it has not
151  * been initialised already.
152  */
153     static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
154
155 /*
156  * The timer service task (daemon).  Timer functionality is controlled by this
157  * task.  Other tasks communicate with the timer service task using the
158  * xTimerQueue queue.
159  */
160     static portTASK_FUNCTION_PROTO( prvTimerTask, pvParameters ) PRIVILEGED_FUNCTION;
161
162 /*
163  * Called by the timer service task to interpret and process a command it
164  * received on the timer queue.
165  */
166     static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
167
168 /*
169  * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
170  * depending on if the expire time causes a timer counter overflow.
171  */
172     static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,
173                                                   const TickType_t xNextExpiryTime,
174                                                   const TickType_t xTimeNow,
175                                                   const TickType_t xCommandTime ) PRIVILEGED_FUNCTION;
176
177 /*
178  * An active timer has reached its expire time.  Reload the timer if it is an
179  * auto-reload timer, then call its callback.
180  */
181     static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
182                                         const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
183
184 /*
185  * The tick count has overflowed.  Switch the timer lists after ensuring the
186  * current timer list does not still reference some timers.
187  */
188     static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION;
189
190 /*
191  * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
192  * if a tick count overflow occurred since prvSampleTimeNow() was last called.
193  */
194     static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
195
196 /*
197  * If the timer list contains any active timers then return the expire time of
198  * the timer that will expire first and set *pxListWasEmpty to false.  If the
199  * timer list does not contain any timers then return 0 and set *pxListWasEmpty
200  * to pdTRUE.
201  */
202     static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION;
203
204 /*
205  * If a timer has expired, process it.  Otherwise, block the timer service task
206  * until either a timer does expire or a command is received.
207  */
208     static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,
209                                             BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION;
210
211 /*
212  * Called after a Timer_t structure has been allocated either statically or
213  * dynamically to fill in the structure's members.
214  */
215     static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
216                                        const TickType_t xTimerPeriodInTicks,
217                                        const UBaseType_t uxAutoReload,
218                                        void * const pvTimerID,
219                                        TimerCallbackFunction_t pxCallbackFunction,
220                                        Timer_t * pxNewTimer ) PRIVILEGED_FUNCTION;
221 /*-----------------------------------------------------------*/
222
223     BaseType_t xTimerCreateTimerTask( void )
224     {
225         BaseType_t xReturn = pdFAIL;
226
227         /* This function is called when the scheduler is started if
228          * configUSE_TIMERS is set to 1.  Check that the infrastructure used by the
229          * timer service task has been created/initialised.  If timers have already
230          * been created then the initialisation will already have been performed. */
231         prvCheckForValidListAndQueue();
232
233         if( xTimerQueue != NULL )
234         {
235             #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
236                 {
237                     StaticTask_t * pxTimerTaskTCBBuffer = NULL;
238                     StackType_t * pxTimerTaskStackBuffer = NULL;
239                     uint32_t ulTimerTaskStackSize;
240
241                     vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
242                     xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
243                                                           configTIMER_SERVICE_TASK_NAME,
244                                                           ulTimerTaskStackSize,
245                                                           NULL,
246                                                           ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
247                                                           pxTimerTaskStackBuffer,
248                                                           pxTimerTaskTCBBuffer );
249
250                     if( xTimerTaskHandle != NULL )
251                     {
252                         xReturn = pdPASS;
253                     }
254                 }
255             #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
256                 {
257                     xReturn = xTaskCreate( prvTimerTask,
258                                            configTIMER_SERVICE_TASK_NAME,
259                                            configTIMER_TASK_STACK_DEPTH,
260                                            NULL,
261                                            ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
262                                            &xTimerTaskHandle );
263                 }
264             #endif /* configSUPPORT_STATIC_ALLOCATION */
265         }
266         else
267         {
268             mtCOVERAGE_TEST_MARKER();
269         }
270
271         configASSERT( xReturn );
272         return xReturn;
273     }
274 /*-----------------------------------------------------------*/
275
276     #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
277
278         TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
279                                     const TickType_t xTimerPeriodInTicks,
280                                     const UBaseType_t uxAutoReload,
281                                     void * const pvTimerID,
282                                     TimerCallbackFunction_t pxCallbackFunction )
283         {
284             Timer_t * pxNewTimer;
285
286             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. */
287
288             if( pxNewTimer != NULL )
289             {
290                 /* Status is thus far zero as the timer is not created statically
291                  * and has not been started.  The auto-reload bit may get set in
292                  * prvInitialiseNewTimer. */
293                 pxNewTimer->ucStatus = 0x00;
294                 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
295             }
296
297             return pxNewTimer;
298         }
299
300     #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
301 /*-----------------------------------------------------------*/
302
303     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
304
305         TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
306                                           const TickType_t xTimerPeriodInTicks,
307                                           const UBaseType_t uxAutoReload,
308                                           void * const pvTimerID,
309                                           TimerCallbackFunction_t pxCallbackFunction,
310                                           StaticTimer_t * pxTimerBuffer )
311         {
312             Timer_t * pxNewTimer;
313
314             #if ( configASSERT_DEFINED == 1 )
315                 {
316                     /* Sanity check that the size of the structure used to declare a
317                      * variable of type StaticTimer_t equals the size of the real timer
318                      * structure. */
319                     volatile size_t xSize = sizeof( StaticTimer_t );
320                     configASSERT( xSize == sizeof( Timer_t ) );
321                     ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */
322                 }
323             #endif /* configASSERT_DEFINED */
324
325             /* A pointer to a StaticTimer_t structure MUST be provided, use it. */
326             configASSERT( pxTimerBuffer );
327             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. */
328
329             if( pxNewTimer != NULL )
330             {
331                 /* Timers can be created statically or dynamically so note this
332                  * timer was created statically in case it is later deleted.  The
333                  * auto-reload bit may get set in prvInitialiseNewTimer(). */
334                 pxNewTimer->ucStatus = tmrSTATUS_IS_STATICALLY_ALLOCATED;
335
336                 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
337             }
338
339             return pxNewTimer;
340         }
341
342     #endif /* configSUPPORT_STATIC_ALLOCATION */
343 /*-----------------------------------------------------------*/
344
345     static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
346                                        const TickType_t xTimerPeriodInTicks,
347                                        const UBaseType_t uxAutoReload,
348                                        void * const pvTimerID,
349                                        TimerCallbackFunction_t pxCallbackFunction,
350                                        Timer_t * pxNewTimer )
351     {
352         /* 0 is not a valid value for xTimerPeriodInTicks. */
353         configASSERT( ( xTimerPeriodInTicks > 0 ) );
354
355         if( pxNewTimer != NULL )
356         {
357             /* Ensure the infrastructure used by the timer service task has been
358              * created/initialised. */
359             prvCheckForValidListAndQueue();
360
361             /* Initialise the timer structure members using the function
362              * parameters. */
363             pxNewTimer->pcTimerName = pcTimerName;
364             pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
365             pxNewTimer->pvTimerID = pvTimerID;
366             pxNewTimer->pxCallbackFunction = pxCallbackFunction;
367             vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
368
369             if( uxAutoReload != pdFALSE )
370             {
371                 pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
372             }
373
374             traceTIMER_CREATE( pxNewTimer );
375         }
376     }
377 /*-----------------------------------------------------------*/
378
379     BaseType_t xTimerGenericCommandFromTask( TimerHandle_t xTimer,
380                                              const BaseType_t xCommandID,
381                                              const TickType_t xOptionalValue,
382                                              BaseType_t * const pxHigherPriorityTaskWoken,
383                                              const TickType_t xTicksToWait )
384     {
385         BaseType_t xReturn = pdFAIL;
386         DaemonTaskMessage_t xMessage;
387
388         configASSERT( xTimer );
389
390         /* Send a message to the timer service task to perform a particular action
391          * on a particular timer definition. */
392         if( xTimerQueue != NULL )
393         {
394             /* Send a command to the timer service task to start the xTimer timer. */
395             xMessage.xMessageID = xCommandID;
396             xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
397             xMessage.u.xTimerParameters.pxTimer = xTimer;
398
399             configASSERT( xCommandID < tmrFIRST_FROM_ISR_COMMAND );
400
401             if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
402             {
403                 if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
404                 {
405                     xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
406                 }
407                 else
408                 {
409                     xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
410                 }
411             }
412
413             traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
414         }
415         else
416         {
417             mtCOVERAGE_TEST_MARKER();
418         }
419
420         return xReturn;
421     }
422 /*-----------------------------------------------------------*/
423
424     BaseType_t xTimerGenericCommandFromISR( TimerHandle_t xTimer,
425                                             const BaseType_t xCommandID,
426                                             const TickType_t xOptionalValue,
427                                             BaseType_t * const pxHigherPriorityTaskWoken,
428                                             const TickType_t xTicksToWait )
429     {
430         BaseType_t xReturn = pdFAIL;
431         DaemonTaskMessage_t xMessage;
432
433         configASSERT( xTimer );
434
435         /* Send a message to the timer service task to perform a particular action
436          * on a particular timer definition. */
437         if( xTimerQueue != NULL )
438         {
439             /* Send a command to the timer service task to start the xTimer timer. */
440             xMessage.xMessageID = xCommandID;
441             xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
442             xMessage.u.xTimerParameters.pxTimer = xTimer;
443
444             configASSERT( xCommandID >= tmrFIRST_FROM_ISR_COMMAND );
445
446             if( xCommandID >= tmrFIRST_FROM_ISR_COMMAND )
447             {
448                 xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
449             }
450
451             traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
452         }
453         else
454         {
455             mtCOVERAGE_TEST_MARKER();
456         }
457
458         return xReturn;
459     }
460 /*-----------------------------------------------------------*/
461
462     TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )
463     {
464         /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
465          * started, then xTimerTaskHandle will be NULL. */
466         configASSERT( ( xTimerTaskHandle != NULL ) );
467         return xTimerTaskHandle;
468     }
469 /*-----------------------------------------------------------*/
470
471     TickType_t xTimerGetPeriod( TimerHandle_t xTimer )
472     {
473         Timer_t * pxTimer = xTimer;
474
475         configASSERT( xTimer );
476         return pxTimer->xTimerPeriodInTicks;
477     }
478 /*-----------------------------------------------------------*/
479
480     void vTimerSetReloadMode( TimerHandle_t xTimer,
481                               const UBaseType_t uxAutoReload )
482     {
483         Timer_t * pxTimer = xTimer;
484
485         configASSERT( xTimer );
486         taskENTER_CRITICAL();
487         {
488             if( uxAutoReload != pdFALSE )
489             {
490                 pxTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
491             }
492             else
493             {
494                 pxTimer->ucStatus &= ~tmrSTATUS_IS_AUTORELOAD;
495             }
496         }
497         taskEXIT_CRITICAL();
498     }
499 /*-----------------------------------------------------------*/
500
501     UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer )
502     {
503         Timer_t * pxTimer = xTimer;
504         UBaseType_t uxReturn;
505
506         configASSERT( xTimer );
507         taskENTER_CRITICAL();
508         {
509             if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0 )
510             {
511                 /* Not an auto-reload timer. */
512                 uxReturn = ( UBaseType_t ) pdFALSE;
513             }
514             else
515             {
516                 /* Is an auto-reload timer. */
517                 uxReturn = ( UBaseType_t ) pdTRUE;
518             }
519         }
520         taskEXIT_CRITICAL();
521
522         return uxReturn;
523     }
524 /*-----------------------------------------------------------*/
525
526     TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer )
527     {
528         Timer_t * pxTimer = xTimer;
529         TickType_t xReturn;
530
531         configASSERT( xTimer );
532         xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) );
533         return xReturn;
534     }
535 /*-----------------------------------------------------------*/
536
537     const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
538     {
539         Timer_t * pxTimer = xTimer;
540
541         configASSERT( xTimer );
542         return pxTimer->pcTimerName;
543     }
544 /*-----------------------------------------------------------*/
545
546     static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
547                                         const TickType_t xTimeNow )
548     {
549         BaseType_t xResult;
550         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. */
551
552         /* Remove the timer from the list of active timers.  A check has already
553          * been performed to ensure the list is not empty. */
554
555         ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
556         traceTIMER_EXPIRED( pxTimer );
557
558         /* If the timer is an auto-reload timer then calculate the next
559          * expiry time and re-insert the timer in the list of active timers. */
560         if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
561         {
562             /* The timer is inserted into a list using a time relative to anything
563              * other than the current time.  It will therefore be inserted into the
564              * correct list relative to the time this task thinks it is now. */
565             if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )
566             {
567                 /* The timer expired before it was added to the active timer
568                  * list.  Reload it now.  */
569                 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
570                 configASSERT( xResult );
571                 ( void ) xResult;
572             }
573             else
574             {
575                 mtCOVERAGE_TEST_MARKER();
576             }
577         }
578         else
579         {
580             pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
581             mtCOVERAGE_TEST_MARKER();
582         }
583
584         /* Call the timer callback. */
585         pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
586     }
587 /*-----------------------------------------------------------*/
588
589     static portTASK_FUNCTION( prvTimerTask, pvParameters )
590     {
591         TickType_t xNextExpireTime;
592         BaseType_t xListWasEmpty;
593
594         /* Just to avoid compiler warnings. */
595         ( void ) pvParameters;
596
597         #if ( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 )
598             {
599                 extern void vApplicationDaemonTaskStartupHook( void );
600
601                 /* Allow the application writer to execute some code in the context of
602                  * this task at the point the task starts executing.  This is useful if the
603                  * application includes initialisation code that would benefit from
604                  * executing after the scheduler has been started. */
605                 vApplicationDaemonTaskStartupHook();
606             }
607         #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
608
609         for( ; ; )
610         {
611             /* Query the timers list to see if it contains any timers, and if so,
612              * obtain the time at which the next timer will expire. */
613             xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
614
615             /* If a timer has expired, process it.  Otherwise, block this task
616              * until either a timer does expire, or a command is received. */
617             prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
618
619             /* Empty the command queue. */
620             prvProcessReceivedCommands();
621         }
622     }
623 /*-----------------------------------------------------------*/
624
625     static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,
626                                             BaseType_t xListWasEmpty )
627     {
628         TickType_t xTimeNow;
629         BaseType_t xTimerListsWereSwitched;
630
631         vTaskSuspendAll();
632         {
633             /* Obtain the time now to make an assessment as to whether the timer
634              * has expired or not.  If obtaining the time causes the lists to switch
635              * then don't process this timer as any timers that remained in the list
636              * when the lists were switched will have been processed within the
637              * prvSampleTimeNow() function. */
638             xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
639
640             if( xTimerListsWereSwitched == pdFALSE )
641             {
642                 /* The tick count has not overflowed, has the timer expired? */
643                 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
644                 {
645                     ( void ) xTaskResumeAll();
646                     prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
647                 }
648                 else
649                 {
650                     /* The tick count has not overflowed, and the next expire
651                      * time has not been reached yet.  This task should therefore
652                      * block to wait for the next expire time or a command to be
653                      * received - whichever comes first.  The following line cannot
654                      * be reached unless xNextExpireTime > xTimeNow, except in the
655                      * case when the current timer list is empty. */
656                     if( xListWasEmpty != pdFALSE )
657                     {
658                         /* The current timer list is empty - is the overflow list
659                          * also empty? */
660                         xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
661                     }
662
663                     vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
664
665                     if( xTaskResumeAll() == pdFALSE )
666                     {
667                         /* Yield to wait for either a command to arrive, or the
668                          * block time to expire.  If a command arrived between the
669                          * critical section being exited and this yield then the yield
670                          * will not cause the task to block. */
671                         vTaskYieldWithinAPI();
672                     }
673                     else
674                     {
675                         mtCOVERAGE_TEST_MARKER();
676                     }
677                 }
678             }
679             else
680             {
681                 ( void ) xTaskResumeAll();
682             }
683         }
684     }
685 /*-----------------------------------------------------------*/
686
687     static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )
688     {
689         TickType_t xNextExpireTime;
690
691         /* Timers are listed in expiry time order, with the head of the list
692          * referencing the task that will expire first.  Obtain the time at which
693          * the timer with the nearest expiry time will expire.  If there are no
694          * active timers then just set the next expire time to 0.  That will cause
695          * this task to unblock when the tick count overflows, at which point the
696          * timer lists will be switched and the next expiry time can be
697          * re-assessed.  */
698         *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
699
700         if( *pxListWasEmpty == pdFALSE )
701         {
702             xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
703         }
704         else
705         {
706             /* Ensure the task unblocks when the tick count rolls over. */
707             xNextExpireTime = ( TickType_t ) 0U;
708         }
709
710         return xNextExpireTime;
711     }
712 /*-----------------------------------------------------------*/
713
714     static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
715     {
716         TickType_t xTimeNow;
717         PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */
718
719         xTimeNow = xTaskGetTickCount();
720
721         if( xTimeNow < xLastTime )
722         {
723             prvSwitchTimerLists();
724             *pxTimerListsWereSwitched = pdTRUE;
725         }
726         else
727         {
728             *pxTimerListsWereSwitched = pdFALSE;
729         }
730
731         xLastTime = xTimeNow;
732
733         return xTimeNow;
734     }
735 /*-----------------------------------------------------------*/
736
737     static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,
738                                                   const TickType_t xNextExpiryTime,
739                                                   const TickType_t xTimeNow,
740                                                   const TickType_t xCommandTime )
741     {
742         BaseType_t xProcessTimerNow = pdFALSE;
743
744         listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
745         listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
746
747         if( xNextExpiryTime <= xTimeNow )
748         {
749             /* Has the expiry time elapsed between the command to start/reset a
750              * timer was issued, and the time the command was processed? */
751             if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
752             {
753                 /* The time between a command being issued and the command being
754                  * processed actually exceeds the timers period.  */
755                 xProcessTimerNow = pdTRUE;
756             }
757             else
758             {
759                 vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
760             }
761         }
762         else
763         {
764             if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
765             {
766                 /* If, since the command was issued, the tick count has overflowed
767                  * but the expiry time has not, then the timer must have already passed
768                  * its expiry time and should be processed immediately. */
769                 xProcessTimerNow = pdTRUE;
770             }
771             else
772             {
773                 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
774             }
775         }
776
777         return xProcessTimerNow;
778     }
779 /*-----------------------------------------------------------*/
780
781     static void prvProcessReceivedCommands( void )
782     {
783         DaemonTaskMessage_t xMessage;
784         Timer_t * pxTimer;
785         BaseType_t xTimerListsWereSwitched, xResult;
786         TickType_t xTimeNow;
787
788         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. */
789         {
790             #if ( INCLUDE_xTimerPendFunctionCall == 1 )
791                 {
792                     /* Negative commands are pended function calls rather than timer
793                      * commands. */
794                     if( xMessage.xMessageID < ( BaseType_t ) 0 )
795                     {
796                         const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters );
797
798                         /* The timer uses the xCallbackParameters member to request a
799                          * callback be executed.  Check the callback is not NULL. */
800                         configASSERT( pxCallback );
801
802                         /* Call the function. */
803                         pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 );
804                     }
805                     else
806                     {
807                         mtCOVERAGE_TEST_MARKER();
808                     }
809                 }
810             #endif /* INCLUDE_xTimerPendFunctionCall */
811
812             /* Commands that are positive are timer commands rather than pended
813              * function calls. */
814             if( xMessage.xMessageID >= ( BaseType_t ) 0 )
815             {
816                 /* The messages uses the xTimerParameters member to work on a
817                  * software timer. */
818                 pxTimer = xMessage.u.xTimerParameters.pxTimer;
819
820                 if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */
821                 {
822                     /* The timer is in a list, remove it. */
823                     ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
824                 }
825                 else
826                 {
827                     mtCOVERAGE_TEST_MARKER();
828                 }
829
830                 traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
831
832                 /* In this case the xTimerListsWereSwitched parameter is not used, but
833                  *  it must be present in the function call.  prvSampleTimeNow() must be
834                  *  called after the message is received from xTimerQueue so there is no
835                  *  possibility of a higher priority task adding a message to the message
836                  *  queue with a time that is ahead of the timer daemon task (because it
837                  *  pre-empted the timer daemon task after the xTimeNow value was set). */
838                 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
839
840                 switch( xMessage.xMessageID )
841                 {
842                     case tmrCOMMAND_START:
843                     case tmrCOMMAND_START_FROM_ISR:
844                     case tmrCOMMAND_RESET:
845                     case tmrCOMMAND_RESET_FROM_ISR:
846                     case tmrCOMMAND_START_DONT_TRACE:
847                         /* Start or restart a timer. */
848                         pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
849
850                         if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )
851                         {
852                             /* The timer expired before it was added to the active
853                              * timer list.  Process it now. */
854                             pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
855                             traceTIMER_EXPIRED( pxTimer );
856
857                             if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
858                             {
859                                 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
860                                 configASSERT( xResult );
861                                 ( void ) xResult;
862                             }
863                             else
864                             {
865                                 mtCOVERAGE_TEST_MARKER();
866                             }
867                         }
868                         else
869                         {
870                             mtCOVERAGE_TEST_MARKER();
871                         }
872
873                         break;
874
875                     case tmrCOMMAND_STOP:
876                     case tmrCOMMAND_STOP_FROM_ISR:
877                         /* The timer has already been removed from the active list. */
878                         pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
879                         break;
880
881                     case tmrCOMMAND_CHANGE_PERIOD:
882                     case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR:
883                         pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
884                         pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
885                         configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
886
887                         /* The new period does not really have a reference, and can
888                          * be longer or shorter than the old one.  The command time is
889                          * therefore set to the current time, and as the period cannot
890                          * be zero the next expiry time can only be in the future,
891                          * meaning (unlike for the xTimerStart() case above) there is
892                          * no fail case that needs to be handled here. */
893                         ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
894                         break;
895
896                     case tmrCOMMAND_DELETE:
897                         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
898                             {
899                                 /* The timer has already been removed from the active list,
900                                  * just free up the memory if the memory was dynamically
901                                  * allocated. */
902                                 if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 )
903                                 {
904                                     vPortFree( pxTimer );
905                                 }
906                                 else
907                                 {
908                                     pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
909                                 }
910                             }
911                         #else /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
912                             {
913                                 /* If dynamic allocation is not enabled, the memory
914                                  * could not have been dynamically allocated. So there is
915                                  * no need to free the memory - just mark the timer as
916                                  * "not active". */
917                                 pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
918                             }
919                         #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
920                         break;
921
922                     default:
923                         /* Don't expect to get here. */
924                         break;
925                 }
926             }
927         }
928     }
929 /*-----------------------------------------------------------*/
930
931     static void prvSwitchTimerLists( void )
932     {
933         TickType_t xNextExpireTime, xReloadTime;
934         List_t * pxTemp;
935         Timer_t * pxTimer;
936         BaseType_t xResult;
937
938         /* The tick count has overflowed.  The timer lists must be switched.
939          * If there are any timers still referenced from the current timer list
940          * then they must have expired and should be processed before the lists
941          * are switched. */
942         while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
943         {
944             xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
945
946             /* Remove the timer from the list. */
947             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. */
948             ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
949             traceTIMER_EXPIRED( pxTimer );
950
951             /* Execute its callback, then send a command to restart the timer if
952              * it is an auto-reload timer.  It cannot be restarted here as the lists
953              * have not yet been switched. */
954             pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
955
956             if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
957             {
958                 /* Calculate the reload value, and if the reload value results in
959                  * the timer going into the same timer list then it has already expired
960                  * and the timer should be re-inserted into the current list so it is
961                  * processed again within this loop.  Otherwise a command should be sent
962                  * to restart the timer to ensure it is only inserted into a list after
963                  * the lists have been swapped. */
964                 xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
965
966                 if( xReloadTime > xNextExpireTime )
967                 {
968                     listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
969                     listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
970                     vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
971                 }
972                 else
973                 {
974                     xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
975                     configASSERT( xResult );
976                     ( void ) xResult;
977                 }
978             }
979             else
980             {
981                 mtCOVERAGE_TEST_MARKER();
982             }
983         }
984
985         pxTemp = pxCurrentTimerList;
986         pxCurrentTimerList = pxOverflowTimerList;
987         pxOverflowTimerList = pxTemp;
988     }
989 /*-----------------------------------------------------------*/
990
991     static void prvCheckForValidListAndQueue( void )
992     {
993         /* Check that the list from which active timers are referenced, and the
994          * queue used to communicate with the timer service, have been
995          * initialised. */
996         taskENTER_CRITICAL();
997         {
998             if( xTimerQueue == NULL )
999             {
1000                 vListInitialise( &xActiveTimerList1 );
1001                 vListInitialise( &xActiveTimerList2 );
1002                 pxCurrentTimerList = &xActiveTimerList1;
1003                 pxOverflowTimerList = &xActiveTimerList2;
1004
1005                 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
1006                     {
1007                         /* The timer queue is allocated statically in case
1008                          * configSUPPORT_DYNAMIC_ALLOCATION is 0. */
1009                         PRIVILEGED_DATA static StaticQueue_t xStaticTimerQueue;                                                                          /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
1010                         PRIVILEGED_DATA 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. */
1011
1012                         xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
1013                     }
1014                 #else
1015                     {
1016                         xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );
1017                     }
1018                 #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
1019
1020                 #if ( configQUEUE_REGISTRY_SIZE > 0 )
1021                     {
1022                         if( xTimerQueue != NULL )
1023                         {
1024                             vQueueAddToRegistry( xTimerQueue, "TmrQ" );
1025                         }
1026                         else
1027                         {
1028                             mtCOVERAGE_TEST_MARKER();
1029                         }
1030                     }
1031                 #endif /* configQUEUE_REGISTRY_SIZE */
1032             }
1033             else
1034             {
1035                 mtCOVERAGE_TEST_MARKER();
1036             }
1037         }
1038         taskEXIT_CRITICAL();
1039     }
1040 /*-----------------------------------------------------------*/
1041
1042     BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
1043     {
1044         BaseType_t xReturn;
1045         Timer_t * pxTimer = xTimer;
1046
1047         configASSERT( xTimer );
1048
1049         /* Is the timer in the list of active timers? */
1050         taskENTER_CRITICAL();
1051         {
1052             if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0 )
1053             {
1054                 xReturn = pdFALSE;
1055             }
1056             else
1057             {
1058                 xReturn = pdTRUE;
1059             }
1060         }
1061         taskEXIT_CRITICAL();
1062
1063         return xReturn;
1064     } /*lint !e818 Can't be pointer to const due to the typedef. */
1065 /*-----------------------------------------------------------*/
1066
1067     void * pvTimerGetTimerID( const TimerHandle_t xTimer )
1068     {
1069         Timer_t * const pxTimer = xTimer;
1070         void * pvReturn;
1071
1072         configASSERT( xTimer );
1073
1074         taskENTER_CRITICAL();
1075         {
1076             pvReturn = pxTimer->pvTimerID;
1077         }
1078         taskEXIT_CRITICAL();
1079
1080         return pvReturn;
1081     }
1082 /*-----------------------------------------------------------*/
1083
1084     void vTimerSetTimerID( TimerHandle_t xTimer,
1085                            void * pvNewID )
1086     {
1087         Timer_t * const pxTimer = xTimer;
1088
1089         configASSERT( xTimer );
1090
1091         taskENTER_CRITICAL();
1092         {
1093             pxTimer->pvTimerID = pvNewID;
1094         }
1095         taskEXIT_CRITICAL();
1096     }
1097 /*-----------------------------------------------------------*/
1098
1099     #if ( INCLUDE_xTimerPendFunctionCall == 1 )
1100
1101         BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend,
1102                                                   void * pvParameter1,
1103                                                   uint32_t ulParameter2,
1104                                                   BaseType_t * pxHigherPriorityTaskWoken )
1105         {
1106             DaemonTaskMessage_t xMessage;
1107             BaseType_t xReturn;
1108
1109             /* Complete the message with the function parameters and post it to the
1110              * daemon task. */
1111             xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
1112             xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1113             xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1114             xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1115
1116             xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
1117
1118             tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1119
1120             return xReturn;
1121         }
1122
1123     #endif /* INCLUDE_xTimerPendFunctionCall */
1124 /*-----------------------------------------------------------*/
1125
1126     #if ( INCLUDE_xTimerPendFunctionCall == 1 )
1127
1128         BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend,
1129                                            void * pvParameter1,
1130                                            uint32_t ulParameter2,
1131                                            TickType_t xTicksToWait )
1132         {
1133             DaemonTaskMessage_t xMessage;
1134             BaseType_t xReturn;
1135
1136             /* This function can only be called after a timer has been created or
1137              * after the scheduler has been started because, until then, the timer
1138              * queue does not exist. */
1139             configASSERT( xTimerQueue );
1140
1141             /* Complete the message with the function parameters and post it to the
1142              * daemon task. */
1143             xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
1144             xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1145             xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1146             xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1147
1148             xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
1149
1150             tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1151
1152             return xReturn;
1153         }
1154
1155     #endif /* INCLUDE_xTimerPendFunctionCall */
1156 /*-----------------------------------------------------------*/
1157
1158     #if ( configUSE_TRACE_FACILITY == 1 )
1159
1160         UBaseType_t uxTimerGetTimerNumber( TimerHandle_t xTimer )
1161         {
1162             return ( ( Timer_t * ) xTimer )->uxTimerNumber;
1163         }
1164
1165     #endif /* configUSE_TRACE_FACILITY */
1166 /*-----------------------------------------------------------*/
1167
1168     #if ( configUSE_TRACE_FACILITY == 1 )
1169
1170         void vTimerSetTimerNumber( TimerHandle_t xTimer,
1171                                    UBaseType_t uxTimerNumber )
1172         {
1173             ( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber;
1174         }
1175
1176     #endif /* configUSE_TRACE_FACILITY */
1177 /*-----------------------------------------------------------*/
1178
1179 /* This entire source file will be skipped if the application is not configured
1180  * to include software timer functionality.  If you want to include software timer
1181  * functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
1182 #endif /* configUSE_TIMERS == 1 */