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