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