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