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