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