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