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