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 /* 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         /* Send a message to the timer service task to perform a particular action
462          * on a particular timer definition. */
463         if( ( xTimerQueue != NULL ) && ( xTimer != NULL ) )
464         {
465             /* Send a command to the timer service task to start the xTimer timer. */
466             xMessage.xMessageID = xCommandID;
467             xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
468             xMessage.u.xTimerParameters.pxTimer = xTimer;
469 
470             configASSERT( xCommandID < tmrFIRST_FROM_ISR_COMMAND );
471 
472             if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
473             {
474                 if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
475                 {
476                     xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
477                 }
478                 else
479                 {
480                     xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
481                 }
482             }
483 
484             traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
485         }
486         else
487         {
488             mtCOVERAGE_TEST_MARKER();
489         }
490 
491         traceRETURN_xTimerGenericCommandFromTask( xReturn );
492 
493         return xReturn;
494     }
495 /*-----------------------------------------------------------*/
496 
xTimerGenericCommandFromISR(TimerHandle_t xTimer,const BaseType_t xCommandID,const TickType_t xOptionalValue,BaseType_t * const pxHigherPriorityTaskWoken,const TickType_t xTicksToWait)497     BaseType_t xTimerGenericCommandFromISR( TimerHandle_t xTimer,
498                                             const BaseType_t xCommandID,
499                                             const TickType_t xOptionalValue,
500                                             BaseType_t * const pxHigherPriorityTaskWoken,
501                                             const TickType_t xTicksToWait )
502     {
503         BaseType_t xReturn = pdFAIL;
504         DaemonTaskMessage_t xMessage;
505 
506         ( void ) xTicksToWait;
507 
508         traceENTER_xTimerGenericCommandFromISR( xTimer, xCommandID, xOptionalValue, pxHigherPriorityTaskWoken, xTicksToWait );
509 
510         /* Send a message to the timer service task to perform a particular action
511          * on a particular timer definition. */
512         if( ( xTimerQueue != NULL ) && ( xTimer != NULL ) )
513         {
514             /* Send a command to the timer service task to start the xTimer timer. */
515             xMessage.xMessageID = xCommandID;
516             xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
517             xMessage.u.xTimerParameters.pxTimer = xTimer;
518 
519             configASSERT( xCommandID >= tmrFIRST_FROM_ISR_COMMAND );
520 
521             if( xCommandID >= tmrFIRST_FROM_ISR_COMMAND )
522             {
523                 xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
524             }
525 
526             traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
527         }
528         else
529         {
530             mtCOVERAGE_TEST_MARKER();
531         }
532 
533         traceRETURN_xTimerGenericCommandFromISR( xReturn );
534 
535         return xReturn;
536     }
537 /*-----------------------------------------------------------*/
538 
xTimerGetTimerDaemonTaskHandle(void)539     TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )
540     {
541         traceENTER_xTimerGetTimerDaemonTaskHandle();
542 
543         /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
544          * started, then xTimerTaskHandle will be NULL. */
545         configASSERT( ( xTimerTaskHandle != NULL ) );
546 
547         traceRETURN_xTimerGetTimerDaemonTaskHandle( xTimerTaskHandle );
548 
549         return xTimerTaskHandle;
550     }
551 /*-----------------------------------------------------------*/
552 
xTimerGetPeriod(TimerHandle_t xTimer)553     TickType_t xTimerGetPeriod( TimerHandle_t xTimer )
554     {
555         Timer_t * pxTimer = xTimer;
556 
557         traceENTER_xTimerGetPeriod( xTimer );
558 
559         configASSERT( xTimer );
560 
561         traceRETURN_xTimerGetPeriod( pxTimer->xTimerPeriodInTicks );
562 
563         return pxTimer->xTimerPeriodInTicks;
564     }
565 /*-----------------------------------------------------------*/
566 
vTimerSetReloadMode(TimerHandle_t xTimer,const BaseType_t xAutoReload)567     void vTimerSetReloadMode( TimerHandle_t xTimer,
568                               const BaseType_t xAutoReload )
569     {
570         Timer_t * pxTimer = xTimer;
571 
572         traceENTER_vTimerSetReloadMode( xTimer, xAutoReload );
573 
574         configASSERT( xTimer );
575         taskENTER_CRITICAL();
576         {
577             if( xAutoReload != pdFALSE )
578             {
579                 pxTimer->ucStatus |= ( uint8_t ) tmrSTATUS_IS_AUTORELOAD;
580             }
581             else
582             {
583                 pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_AUTORELOAD );
584             }
585         }
586         taskEXIT_CRITICAL();
587 
588         traceRETURN_vTimerSetReloadMode();
589     }
590 /*-----------------------------------------------------------*/
591 
xTimerGetReloadMode(TimerHandle_t xTimer)592     BaseType_t xTimerGetReloadMode( TimerHandle_t xTimer )
593     {
594         Timer_t * pxTimer = xTimer;
595         BaseType_t xReturn;
596 
597         traceENTER_xTimerGetReloadMode( xTimer );
598 
599         configASSERT( xTimer );
600         portBASE_TYPE_ENTER_CRITICAL();
601         {
602             if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0U )
603             {
604                 /* Not an auto-reload timer. */
605                 xReturn = pdFALSE;
606             }
607             else
608             {
609                 /* Is an auto-reload timer. */
610                 xReturn = pdTRUE;
611             }
612         }
613         portBASE_TYPE_EXIT_CRITICAL();
614 
615         traceRETURN_xTimerGetReloadMode( xReturn );
616 
617         return xReturn;
618     }
619 
uxTimerGetReloadMode(TimerHandle_t xTimer)620     UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer )
621     {
622         UBaseType_t uxReturn;
623 
624         traceENTER_uxTimerGetReloadMode( xTimer );
625 
626         uxReturn = ( UBaseType_t ) xTimerGetReloadMode( xTimer );
627 
628         traceRETURN_uxTimerGetReloadMode( uxReturn );
629 
630         return uxReturn;
631     }
632 /*-----------------------------------------------------------*/
633 
xTimerGetExpiryTime(TimerHandle_t xTimer)634     TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer )
635     {
636         Timer_t * pxTimer = xTimer;
637         TickType_t xReturn;
638 
639         traceENTER_xTimerGetExpiryTime( xTimer );
640 
641         configASSERT( xTimer );
642         xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) );
643 
644         traceRETURN_xTimerGetExpiryTime( xReturn );
645 
646         return xReturn;
647     }
648 /*-----------------------------------------------------------*/
649 
650     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
xTimerGetStaticBuffer(TimerHandle_t xTimer,StaticTimer_t ** ppxTimerBuffer)651         BaseType_t xTimerGetStaticBuffer( TimerHandle_t xTimer,
652                                           StaticTimer_t ** ppxTimerBuffer )
653         {
654             BaseType_t xReturn;
655             Timer_t * pxTimer = xTimer;
656 
657             traceENTER_xTimerGetStaticBuffer( xTimer, ppxTimerBuffer );
658 
659             configASSERT( ppxTimerBuffer != NULL );
660 
661             if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) != 0U )
662             {
663                 /* MISRA Ref 11.3.1 [Misaligned access] */
664                 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
665                 /* coverity[misra_c_2012_rule_11_3_violation] */
666                 *ppxTimerBuffer = ( StaticTimer_t * ) pxTimer;
667                 xReturn = pdTRUE;
668             }
669             else
670             {
671                 xReturn = pdFALSE;
672             }
673 
674             traceRETURN_xTimerGetStaticBuffer( xReturn );
675 
676             return xReturn;
677         }
678     #endif /* configSUPPORT_STATIC_ALLOCATION */
679 /*-----------------------------------------------------------*/
680 
pcTimerGetName(TimerHandle_t xTimer)681     const char * pcTimerGetName( TimerHandle_t xTimer )
682     {
683         Timer_t * pxTimer = xTimer;
684 
685         traceENTER_pcTimerGetName( xTimer );
686 
687         configASSERT( xTimer );
688 
689         traceRETURN_pcTimerGetName( pxTimer->pcTimerName );
690 
691         return pxTimer->pcTimerName;
692     }
693 /*-----------------------------------------------------------*/
694 
prvReloadTimer(Timer_t * const pxTimer,TickType_t xExpiredTime,const TickType_t xTimeNow)695     static void prvReloadTimer( Timer_t * const pxTimer,
696                                 TickType_t xExpiredTime,
697                                 const TickType_t xTimeNow )
698     {
699         /* Insert the timer into the appropriate list for the next expiry time.
700          * If the next expiry time has already passed, advance the expiry time,
701          * call the callback function, and try again. */
702         while( prvInsertTimerInActiveList( pxTimer, ( xExpiredTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xExpiredTime ) != pdFALSE )
703         {
704             /* Advance the expiry time. */
705             xExpiredTime += pxTimer->xTimerPeriodInTicks;
706 
707             /* Call the timer callback. */
708             traceTIMER_EXPIRED( pxTimer );
709             pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
710         }
711     }
712 /*-----------------------------------------------------------*/
713 
prvProcessExpiredTimer(const TickType_t xNextExpireTime,const TickType_t xTimeNow)714     static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
715                                         const TickType_t xTimeNow )
716     {
717         /* MISRA Ref 11.5.3 [Void pointer assignment] */
718         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
719         /* coverity[misra_c_2012_rule_11_5_violation] */
720         Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
721 
722         /* Remove the timer from the list of active timers.  A check has already
723          * been performed to ensure the list is not empty. */
724 
725         ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
726 
727         /* If the timer is an auto-reload timer then calculate the next
728          * expiry time and re-insert the timer in the list of active timers. */
729         if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0U )
730         {
731             prvReloadTimer( pxTimer, xNextExpireTime, xTimeNow );
732         }
733         else
734         {
735             pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
736         }
737 
738         /* Call the timer callback. */
739         traceTIMER_EXPIRED( pxTimer );
740         pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
741     }
742 /*-----------------------------------------------------------*/
743 
portTASK_FUNCTION(prvTimerTask,pvParameters)744     static portTASK_FUNCTION( prvTimerTask, pvParameters )
745     {
746         TickType_t xNextExpireTime;
747         BaseType_t xListWasEmpty;
748 
749         /* Just to avoid compiler warnings. */
750         ( void ) pvParameters;
751 
752         #if ( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 )
753         {
754             /* Allow the application writer to execute some code in the context of
755              * this task at the point the task starts executing.  This is useful if the
756              * application includes initialisation code that would benefit from
757              * executing after the scheduler has been started. */
758             vApplicationDaemonTaskStartupHook();
759         }
760         #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
761 
762         for( ; configCONTROL_INFINITE_LOOP(); )
763         {
764             /* Query the timers list to see if it contains any timers, and if so,
765              * obtain the time at which the next timer will expire. */
766             xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
767 
768             /* If a timer has expired, process it.  Otherwise, block this task
769              * until either a timer does expire, or a command is received. */
770             prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
771 
772             /* Empty the command queue. */
773             prvProcessReceivedCommands();
774         }
775     }
776 /*-----------------------------------------------------------*/
777 
prvProcessTimerOrBlockTask(const TickType_t xNextExpireTime,BaseType_t xListWasEmpty)778     static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,
779                                             BaseType_t xListWasEmpty )
780     {
781         TickType_t xTimeNow;
782         BaseType_t xTimerListsWereSwitched;
783 
784         vTaskSuspendAll();
785         {
786             /* Obtain the time now to make an assessment as to whether the timer
787              * has expired or not.  If obtaining the time causes the lists to switch
788              * then don't process this timer as any timers that remained in the list
789              * when the lists were switched will have been processed within the
790              * prvSampleTimeNow() function. */
791             xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
792 
793             if( xTimerListsWereSwitched == pdFALSE )
794             {
795                 /* The tick count has not overflowed, has the timer expired? */
796                 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
797                 {
798                     ( void ) xTaskResumeAll();
799                     prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
800                 }
801                 else
802                 {
803                     /* The tick count has not overflowed, and the next expire
804                      * time has not been reached yet.  This task should therefore
805                      * block to wait for the next expire time or a command to be
806                      * received - whichever comes first.  The following line cannot
807                      * be reached unless xNextExpireTime > xTimeNow, except in the
808                      * case when the current timer list is empty. */
809                     if( xListWasEmpty != pdFALSE )
810                     {
811                         /* The current timer list is empty - is the overflow list
812                          * also empty? */
813                         xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
814                     }
815 
816                     vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
817 
818                     if( xTaskResumeAll() == pdFALSE )
819                     {
820                         /* Yield to wait for either a command to arrive, or the
821                          * block time to expire.  If a command arrived between the
822                          * critical section being exited and this yield then the yield
823                          * will not cause the task to block. */
824                         taskYIELD_WITHIN_API();
825                     }
826                     else
827                     {
828                         mtCOVERAGE_TEST_MARKER();
829                     }
830                 }
831             }
832             else
833             {
834                 ( void ) xTaskResumeAll();
835             }
836         }
837     }
838 /*-----------------------------------------------------------*/
839 
prvGetNextExpireTime(BaseType_t * const pxListWasEmpty)840     static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )
841     {
842         TickType_t xNextExpireTime;
843 
844         /* Timers are listed in expiry time order, with the head of the list
845          * referencing the task that will expire first.  Obtain the time at which
846          * the timer with the nearest expiry time will expire.  If there are no
847          * active timers then just set the next expire time to 0.  That will cause
848          * this task to unblock when the tick count overflows, at which point the
849          * timer lists will be switched and the next expiry time can be
850          * re-assessed.  */
851         *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
852 
853         if( *pxListWasEmpty == pdFALSE )
854         {
855             xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
856         }
857         else
858         {
859             /* Ensure the task unblocks when the tick count rolls over. */
860             xNextExpireTime = ( TickType_t ) 0U;
861         }
862 
863         return xNextExpireTime;
864     }
865 /*-----------------------------------------------------------*/
866 
prvSampleTimeNow(BaseType_t * const pxTimerListsWereSwitched)867     static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
868     {
869         TickType_t xTimeNow;
870         PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U;
871 
872         xTimeNow = xTaskGetTickCount();
873 
874         if( xTimeNow < xLastTime )
875         {
876             prvSwitchTimerLists();
877             *pxTimerListsWereSwitched = pdTRUE;
878         }
879         else
880         {
881             *pxTimerListsWereSwitched = pdFALSE;
882         }
883 
884         xLastTime = xTimeNow;
885 
886         return xTimeNow;
887     }
888 /*-----------------------------------------------------------*/
889 
prvInsertTimerInActiveList(Timer_t * const pxTimer,const TickType_t xNextExpiryTime,const TickType_t xTimeNow,const TickType_t xCommandTime)890     static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,
891                                                   const TickType_t xNextExpiryTime,
892                                                   const TickType_t xTimeNow,
893                                                   const TickType_t xCommandTime )
894     {
895         BaseType_t xProcessTimerNow = pdFALSE;
896 
897         listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
898         listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
899 
900         if( xNextExpiryTime <= xTimeNow )
901         {
902             /* Has the expiry time elapsed between the command to start/reset a
903              * timer was issued, and the time the command was processed? */
904             if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )
905             {
906                 /* The time between a command being issued and the command being
907                  * processed actually exceeds the timers period.  */
908                 xProcessTimerNow = pdTRUE;
909             }
910             else
911             {
912                 vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
913             }
914         }
915         else
916         {
917             if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
918             {
919                 /* If, since the command was issued, the tick count has overflowed
920                  * but the expiry time has not, then the timer must have already passed
921                  * its expiry time and should be processed immediately. */
922                 xProcessTimerNow = pdTRUE;
923             }
924             else
925             {
926                 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
927             }
928         }
929 
930         return xProcessTimerNow;
931     }
932 /*-----------------------------------------------------------*/
933 
prvProcessReceivedCommands(void)934     static void prvProcessReceivedCommands( void )
935     {
936         DaemonTaskMessage_t xMessage = { 0 };
937         Timer_t * pxTimer;
938         BaseType_t xTimerListsWereSwitched;
939         TickType_t xTimeNow;
940 
941         while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
942         {
943             #if ( INCLUDE_xTimerPendFunctionCall == 1 )
944             {
945                 /* Negative commands are pended function calls rather than timer
946                  * commands. */
947                 if( xMessage.xMessageID < ( BaseType_t ) 0 )
948                 {
949                     const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters );
950 
951                     /* The timer uses the xCallbackParameters member to request a
952                      * callback be executed.  Check the callback is not NULL. */
953                     configASSERT( pxCallback );
954 
955                     /* Call the function. */
956                     pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 );
957                 }
958                 else
959                 {
960                     mtCOVERAGE_TEST_MARKER();
961                 }
962             }
963             #endif /* INCLUDE_xTimerPendFunctionCall */
964 
965             /* Commands that are positive are timer commands rather than pended
966              * function calls. */
967             if( xMessage.xMessageID >= ( BaseType_t ) 0 )
968             {
969                 /* The messages uses the xTimerParameters member to work on a
970                  * software timer. */
971                 pxTimer = xMessage.u.xTimerParameters.pxTimer;
972 
973                 if( pxTimer != NULL )
974                 {
975                     if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
976                     {
977                         /* The timer is in a list, remove it. */
978                         ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
979                     }
980                     else
981                     {
982                         mtCOVERAGE_TEST_MARKER();
983                     }
984 
985                     traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
986 
987                     /* In this case the xTimerListsWereSwitched parameter is not used, but
988                      *  it must be present in the function call.  prvSampleTimeNow() must be
989                      *  called after the message is received from xTimerQueue so there is no
990                      *  possibility of a higher priority task adding a message to the message
991                      *  queue with a time that is ahead of the timer daemon task (because it
992                      *  pre-empted the timer daemon task after the xTimeNow value was set). */
993                     xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
994 
995                     switch( xMessage.xMessageID )
996                     {
997                         case tmrCOMMAND_START:
998                         case tmrCOMMAND_START_FROM_ISR:
999                         case tmrCOMMAND_RESET:
1000                         case tmrCOMMAND_RESET_FROM_ISR:
1001                             /* Start or restart a timer. */
1002                             pxTimer->ucStatus |= ( uint8_t ) tmrSTATUS_IS_ACTIVE;
1003 
1004                             if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )
1005                             {
1006                                 /* The timer expired before it was added to the active
1007                                  * timer list.  Process it now. */
1008                                 if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0U )
1009                                 {
1010                                     prvReloadTimer( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow );
1011                                 }
1012                                 else
1013                                 {
1014                                     pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
1015                                 }
1016 
1017                                 /* Call the timer callback. */
1018                                 traceTIMER_EXPIRED( pxTimer );
1019                                 pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
1020                             }
1021                             else
1022                             {
1023                                 mtCOVERAGE_TEST_MARKER();
1024                             }
1025 
1026                             break;
1027 
1028                         case tmrCOMMAND_STOP:
1029                         case tmrCOMMAND_STOP_FROM_ISR:
1030                             /* The timer has already been removed from the active list. */
1031                             pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
1032                             break;
1033 
1034                         case tmrCOMMAND_CHANGE_PERIOD:
1035                         case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR:
1036                             pxTimer->ucStatus |= ( uint8_t ) tmrSTATUS_IS_ACTIVE;
1037                             pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
1038                             configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
1039 
1040                             /* The new period does not really have a reference, and can
1041                              * be longer or shorter than the old one.  The command time is
1042                              * therefore set to the current time, and as the period cannot
1043                              * be zero the next expiry time can only be in the future,
1044                              * meaning (unlike for the xTimerStart() case above) there is
1045                              * no fail case that needs to be handled here. */
1046                             ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
1047                             break;
1048 
1049                         case tmrCOMMAND_DELETE:
1050                             #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
1051                             {
1052                                 /* The timer has already been removed from the active list,
1053                                  * just free up the memory if the memory was dynamically
1054                                  * allocated. */
1055                                 if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 )
1056                                 {
1057                                     vPortFree( pxTimer );
1058                                 }
1059                                 else
1060                                 {
1061                                     pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
1062                                 }
1063                             }
1064                             #else /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
1065                             {
1066                                 /* If dynamic allocation is not enabled, the memory
1067                                  * could not have been dynamically allocated. So there is
1068                                  * no need to free the memory - just mark the timer as
1069                                  * "not active". */
1070                                 pxTimer->ucStatus &= ( ( uint8_t ) ~tmrSTATUS_IS_ACTIVE );
1071                             }
1072                             #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
1073                             break;
1074 
1075                         default:
1076                             /* Don't expect to get here. */
1077                             break;
1078                     }
1079                 }
1080                 else
1081                 {
1082                     mtCOVERAGE_TEST_MARKER();
1083                 }
1084             }
1085         }
1086     }
1087 /*-----------------------------------------------------------*/
1088 
prvSwitchTimerLists(void)1089     static void prvSwitchTimerLists( void )
1090     {
1091         TickType_t xNextExpireTime;
1092         List_t * pxTemp;
1093 
1094         /* The tick count has overflowed.  The timer lists must be switched.
1095          * If there are any timers still referenced from the current timer list
1096          * then they must have expired and should be processed before the lists
1097          * are switched. */
1098         while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
1099         {
1100             xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
1101 
1102             /* Process the expired timer.  For auto-reload timers, be careful to
1103              * process only expirations that occur on the current list.  Further
1104              * expirations must wait until after the lists are switched. */
1105             prvProcessExpiredTimer( xNextExpireTime, tmrMAX_TIME_BEFORE_OVERFLOW );
1106         }
1107 
1108         pxTemp = pxCurrentTimerList;
1109         pxCurrentTimerList = pxOverflowTimerList;
1110         pxOverflowTimerList = pxTemp;
1111     }
1112 /*-----------------------------------------------------------*/
1113 
prvCheckForValidListAndQueue(void)1114     static void prvCheckForValidListAndQueue( void )
1115     {
1116         /* Check that the list from which active timers are referenced, and the
1117          * queue used to communicate with the timer service, have been
1118          * initialised. */
1119         taskENTER_CRITICAL();
1120         {
1121             if( xTimerQueue == NULL )
1122             {
1123                 vListInitialise( &xActiveTimerList1 );
1124                 vListInitialise( &xActiveTimerList2 );
1125                 pxCurrentTimerList = &xActiveTimerList1;
1126                 pxOverflowTimerList = &xActiveTimerList2;
1127 
1128                 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
1129                 {
1130                     /* The timer queue is allocated statically in case
1131                      * configSUPPORT_DYNAMIC_ALLOCATION is 0. */
1132                     PRIVILEGED_DATA static StaticQueue_t xStaticTimerQueue;
1133                     PRIVILEGED_DATA static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ];
1134 
1135                     xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
1136                 }
1137                 #else
1138                 {
1139                     xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ) );
1140                 }
1141                 #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
1142 
1143                 #if ( configQUEUE_REGISTRY_SIZE > 0 )
1144                 {
1145                     if( xTimerQueue != NULL )
1146                     {
1147                         vQueueAddToRegistry( xTimerQueue, "TmrQ" );
1148                     }
1149                     else
1150                     {
1151                         mtCOVERAGE_TEST_MARKER();
1152                     }
1153                 }
1154                 #endif /* configQUEUE_REGISTRY_SIZE */
1155             }
1156             else
1157             {
1158                 mtCOVERAGE_TEST_MARKER();
1159             }
1160         }
1161         taskEXIT_CRITICAL();
1162     }
1163 /*-----------------------------------------------------------*/
1164 
xTimerIsTimerActive(TimerHandle_t xTimer)1165     BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
1166     {
1167         BaseType_t xReturn;
1168         Timer_t * pxTimer = xTimer;
1169 
1170         traceENTER_xTimerIsTimerActive( xTimer );
1171 
1172         configASSERT( xTimer );
1173 
1174         /* Is the timer in the list of active timers? */
1175         portBASE_TYPE_ENTER_CRITICAL();
1176         {
1177             if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0U )
1178             {
1179                 xReturn = pdFALSE;
1180             }
1181             else
1182             {
1183                 xReturn = pdTRUE;
1184             }
1185         }
1186         portBASE_TYPE_EXIT_CRITICAL();
1187 
1188         traceRETURN_xTimerIsTimerActive( xReturn );
1189 
1190         return xReturn;
1191     }
1192 /*-----------------------------------------------------------*/
1193 
pvTimerGetTimerID(const TimerHandle_t xTimer)1194     void * pvTimerGetTimerID( const TimerHandle_t xTimer )
1195     {
1196         Timer_t * const pxTimer = xTimer;
1197         void * pvReturn;
1198 
1199         traceENTER_pvTimerGetTimerID( xTimer );
1200 
1201         configASSERT( xTimer );
1202 
1203         taskENTER_CRITICAL();
1204         {
1205             pvReturn = pxTimer->pvTimerID;
1206         }
1207         taskEXIT_CRITICAL();
1208 
1209         traceRETURN_pvTimerGetTimerID( pvReturn );
1210 
1211         return pvReturn;
1212     }
1213 /*-----------------------------------------------------------*/
1214 
vTimerSetTimerID(TimerHandle_t xTimer,void * pvNewID)1215     void vTimerSetTimerID( TimerHandle_t xTimer,
1216                            void * pvNewID )
1217     {
1218         Timer_t * const pxTimer = xTimer;
1219 
1220         traceENTER_vTimerSetTimerID( xTimer, pvNewID );
1221 
1222         configASSERT( xTimer );
1223 
1224         taskENTER_CRITICAL();
1225         {
1226             pxTimer->pvTimerID = pvNewID;
1227         }
1228         taskEXIT_CRITICAL();
1229 
1230         traceRETURN_vTimerSetTimerID();
1231     }
1232 /*-----------------------------------------------------------*/
1233 
1234     #if ( INCLUDE_xTimerPendFunctionCall == 1 )
1235 
xTimerPendFunctionCallFromISR(PendedFunction_t xFunctionToPend,void * pvParameter1,uint32_t ulParameter2,BaseType_t * pxHigherPriorityTaskWoken)1236         BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend,
1237                                                   void * pvParameter1,
1238                                                   uint32_t ulParameter2,
1239                                                   BaseType_t * pxHigherPriorityTaskWoken )
1240         {
1241             DaemonTaskMessage_t xMessage;
1242             BaseType_t xReturn;
1243 
1244             traceENTER_xTimerPendFunctionCallFromISR( xFunctionToPend, pvParameter1, ulParameter2, pxHigherPriorityTaskWoken );
1245 
1246             /* Complete the message with the function parameters and post it to the
1247              * daemon task. */
1248             xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
1249             xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1250             xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1251             xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1252 
1253             xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
1254 
1255             tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1256             traceRETURN_xTimerPendFunctionCallFromISR( xReturn );
1257 
1258             return xReturn;
1259         }
1260 
1261     #endif /* INCLUDE_xTimerPendFunctionCall */
1262 /*-----------------------------------------------------------*/
1263 
1264     #if ( INCLUDE_xTimerPendFunctionCall == 1 )
1265 
xTimerPendFunctionCall(PendedFunction_t xFunctionToPend,void * pvParameter1,uint32_t ulParameter2,TickType_t xTicksToWait)1266         BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend,
1267                                            void * pvParameter1,
1268                                            uint32_t ulParameter2,
1269                                            TickType_t xTicksToWait )
1270         {
1271             DaemonTaskMessage_t xMessage;
1272             BaseType_t xReturn;
1273 
1274             traceENTER_xTimerPendFunctionCall( xFunctionToPend, pvParameter1, ulParameter2, xTicksToWait );
1275 
1276             /* This function can only be called after a timer has been created or
1277              * after the scheduler has been started because, until then, the timer
1278              * queue does not exist. */
1279             configASSERT( xTimerQueue );
1280 
1281             /* Complete the message with the function parameters and post it to the
1282              * daemon task. */
1283             xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
1284             xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
1285             xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
1286             xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
1287 
1288             xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
1289 
1290             tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
1291             traceRETURN_xTimerPendFunctionCall( xReturn );
1292 
1293             return xReturn;
1294         }
1295 
1296     #endif /* INCLUDE_xTimerPendFunctionCall */
1297 /*-----------------------------------------------------------*/
1298 
1299     #if ( configUSE_TRACE_FACILITY == 1 )
1300 
uxTimerGetTimerNumber(TimerHandle_t xTimer)1301         UBaseType_t uxTimerGetTimerNumber( TimerHandle_t xTimer )
1302         {
1303             traceENTER_uxTimerGetTimerNumber( xTimer );
1304 
1305             traceRETURN_uxTimerGetTimerNumber( ( ( Timer_t * ) xTimer )->uxTimerNumber );
1306 
1307             return ( ( Timer_t * ) xTimer )->uxTimerNumber;
1308         }
1309 
1310     #endif /* configUSE_TRACE_FACILITY */
1311 /*-----------------------------------------------------------*/
1312 
1313     #if ( configUSE_TRACE_FACILITY == 1 )
1314 
vTimerSetTimerNumber(TimerHandle_t xTimer,UBaseType_t uxTimerNumber)1315         void vTimerSetTimerNumber( TimerHandle_t xTimer,
1316                                    UBaseType_t uxTimerNumber )
1317         {
1318             traceENTER_vTimerSetTimerNumber( xTimer, uxTimerNumber );
1319 
1320             ( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber;
1321 
1322             traceRETURN_vTimerSetTimerNumber();
1323         }
1324 
1325     #endif /* configUSE_TRACE_FACILITY */
1326 /*-----------------------------------------------------------*/
1327 
1328 /*
1329  * Reset the state in this file. This state is normally initialized at start up.
1330  * This function must be called by the application before restarting the
1331  * scheduler.
1332  */
vTimerResetState(void)1333     void vTimerResetState( void )
1334     {
1335         xTimerQueue = NULL;
1336         xTimerTaskHandle = NULL;
1337     }
1338 /*-----------------------------------------------------------*/
1339 
1340 /* This entire source file will be skipped if the application is not configured
1341  * to include software timer functionality.  If you want to include software timer
1342  * functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
1343 #endif /* configUSE_TIMERS == 1 */
1344