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