blob: 69e2238be81c6bbd2f28ebf6ddb2b6013d2292c4 [file] [log] [blame]
Richard Barry4d2adb72011-02-08 15:20:29 +00001/*
Richard Barrycc611262011-09-20 18:22:39 +00002 FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
Richard Barry89bf1cf2011-04-08 18:30:58 +00003
Richard Barry4d2adb72011-02-08 15:20:29 +00004
5 ***************************************************************************
Richard Barry89bf1cf2011-04-08 18:30:58 +00006 * *
7 * FreeRTOS tutorial books are available in pdf and paperback. *
8 * Complete, revised, and edited pdf reference manuals are also *
9 * available. *
10 * *
11 * Purchasing FreeRTOS documentation will not only help you, by *
12 * ensuring you get running as quickly as possible and with an *
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
14 * the FreeRTOS project to continue with its mission of providing *
15 * professional grade, cross platform, de facto standard solutions *
16 * for microcontrollers - completely free of charge! *
17 * *
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
19 * *
20 * Thank you for using FreeRTOS, and thank you for your support! *
21 * *
Richard Barry4d2adb72011-02-08 15:20:29 +000022 ***************************************************************************
23
Richard Barry89bf1cf2011-04-08 18:30:58 +000024
Richard Barry4d2adb72011-02-08 15:20:29 +000025 This file is part of the FreeRTOS distribution.
26
27 FreeRTOS is free software; you can redistribute it and/or modify it under
28 the terms of the GNU General Public License (version 2) as published by the
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
Richard Barry89bf1cf2011-04-08 18:30:58 +000030 >>>NOTE<<< The modification to the GPL is included to allow you to
31 distribute a combined work that includes FreeRTOS without being obliged to
32 provide the source code for proprietary components outside of the FreeRTOS
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
35 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
Richard Barry4d2adb72011-02-08 15:20:29 +000036 more details. You should have received a copy of the GNU General Public
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
39 by writing to Richard Barry, contact details for whom are available on the
40 FreeRTOS WEB site.
41
42 1 tab == 4 spaces!
43
44 http://www.FreeRTOS.org - Documentation, latest information, license and
45 contact details.
46
47 http://www.SafeRTOS.com - A version that is certified for use in safety
48 critical systems.
49
50 http://www.OpenRTOS.com - Commercial support, development, porting,
51 licensing and training services.
52*/
53
54/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
55all the API functions to use the MPU wrappers. That should only be done when
56task.h is included from an application file. */
57#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
58
59#include "FreeRTOS.h"
60#include "task.h"
61#include "queue.h"
62#include "timers.h"
63
64#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
65
Richard Barry8bd2d2f2011-03-31 14:09:21 +000066/* This entire source file will be skipped if the application is not configured
67to include software timer functionality. This #if is closed at the very bottom
Richard Barry37de2682011-04-05 20:19:54 +000068of this file. If you want to include software timer functionality then ensure
Richard Barry8bd2d2f2011-03-31 14:09:21 +000069configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
70#if ( configUSE_TIMERS == 1 )
71
Richard Barry4d2adb72011-02-08 15:20:29 +000072/* Misc definitions. */
Richard Barry4a5f1522011-02-08 16:21:15 +000073#define tmrNO_DELAY ( portTickType ) 0U
Richard Barry4d2adb72011-02-08 15:20:29 +000074
75/* The definition of the timers themselves. */
76typedef struct tmrTimerControl
77{
78 const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */
79 xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
80 portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
81 unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */
82 void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
83 tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
84} xTIMER;
85
Richard Barry0552fc82011-02-10 17:20:36 +000086/* The definition of messages that can be sent and received on the timer
Richard Barry4d2adb72011-02-08 15:20:29 +000087queue. */
88typedef struct tmrTimerQueueMessage
89{
Richard Barry896d8c52011-02-09 10:46:45 +000090 portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
Richard Barry3ba433e2011-02-11 16:17:37 +000091 portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
Richard Barry896d8c52011-02-09 10:46:45 +000092 xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
Richard Barry4d2adb72011-02-08 15:20:29 +000093} xTIMER_MESSAGE;
94
95
96/* The list in which active timers are stored. Timers are referenced in expire
97time order, with the nearest expiry time at the front of the list. Only the
98timer service task is allowed to access xActiveTimerList. */
Richard Barry7ee534e2011-02-10 19:09:35 +000099PRIVILEGED_DATA static xList xActiveTimerList1;
100PRIVILEGED_DATA static xList xActiveTimerList2;
101PRIVILEGED_DATA static xList *pxCurrentTimerList;
102PRIVILEGED_DATA static xList *pxOverflowTimerList;
Richard Barry4d2adb72011-02-08 15:20:29 +0000103
104/* A queue that is used to send commands to the timer service task. */
105PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
106
Richard Barrycc611262011-09-20 18:22:39 +0000107#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
Richard Barryfc99c142011-07-27 14:02:37 +0000108
109 PRIVILEGED_DATA static xTaskHandle xTimerTaskHandle = NULL;
110
111#endif
112
Richard Barry4d2adb72011-02-08 15:20:29 +0000113/*-----------------------------------------------------------*/
114
Richard Barry0552fc82011-02-10 17:20:36 +0000115/*
Richard Barry3ba433e2011-02-11 16:17:37 +0000116 * Initialise the infrastructure used by the timer service task if it has not
Richard Barry4a5f1522011-02-08 16:21:15 +0000117 * been initialised already.
118 */
Richard Barry4d2adb72011-02-08 15:20:29 +0000119static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
120
121/*
Richard Barry4a5f1522011-02-08 16:21:15 +0000122 * The timer service task (daemon). Timer functionality is controlled by this
Richard Barry0552fc82011-02-10 17:20:36 +0000123 * task. Other tasks communicate with the timer service task using the
Richard Barry4a5f1522011-02-08 16:21:15 +0000124 * xTimerQueue queue.
Richard Barry4d2adb72011-02-08 15:20:29 +0000125 */
126static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
127
Richard Barry4a5f1522011-02-08 16:21:15 +0000128/*
129 * Called by the timer service task to interpret and process a command it
Richard Barry0552fc82011-02-10 17:20:36 +0000130 * received on the timer queue.
Richard Barry4a5f1522011-02-08 16:21:15 +0000131 */
Richard Barryb4ff4822011-02-14 10:51:18 +0000132static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
Richard Barry4d2adb72011-02-08 15:20:29 +0000133
Richard Barry7ee534e2011-02-10 19:09:35 +0000134/*
Richard Barryb4ff4822011-02-14 10:51:18 +0000135 * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
136 * depending on if the expire time causes a timer counter overflow.
Richard Barry7ee534e2011-02-10 19:09:35 +0000137 */
Richard Barryefc3ba92011-02-20 10:59:58 +0000138static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
Richard Barry3ba433e2011-02-11 16:17:37 +0000139
140/*
141 * An active timer has reached its expire time. Reload the timer if it is an
142 * auto reload timer, then call its callback.
143 */
Richard Barryb4ff4822011-02-14 10:51:18 +0000144static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
Richard Barry3ba433e2011-02-11 16:17:37 +0000145
146/*
147 * The tick count has overflowed. Switch the timer lists after ensuring the
148 * current timer list does not still reference some timers.
149 */
Richard Barrycb238fc2011-02-28 16:10:08 +0000150static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
Richard Barryb4ff4822011-02-14 10:51:18 +0000151
152/*
153 * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
154 * if a tick count overflow occurred since prvSampleTimeNow() was last called.
155 */
156static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
157
158/*
159 * If the timer list contains any active timers then return the expire time of
160 * the timer that will expire first and set *pxListWasEmpty to false. If the
161 * timer list does not contain any timers then return 0 and set *pxListWasEmpty
162 * to pdTRUE.
163 */
Richard Barry2c1a85c2011-02-22 20:43:17 +0000164static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
Richard Barryb4ff4822011-02-14 10:51:18 +0000165
166/*
167 * If a timer has expired, process it. Otherwise, block the timer service task
168 * until either a timer does expire or a command is received.
169 */
170static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
Richard Barry7ee534e2011-02-10 19:09:35 +0000171
Richard Barry4d2adb72011-02-08 15:20:29 +0000172/*-----------------------------------------------------------*/
173
174portBASE_TYPE xTimerCreateTimerTask( void )
175{
176portBASE_TYPE xReturn = pdFAIL;
177
Richard Barry0552fc82011-02-10 17:20:36 +0000178 /* This function is called when the scheduler is started if
Richard Barry3ba433e2011-02-11 16:17:37 +0000179 configUSE_TIMERS is set to 1. Check that the infrastructure used by the
Richard Barry4a5f1522011-02-08 16:21:15 +0000180 timer service task has been created/initialised. If timers have already
181 been created then the initialisation will already have been performed. */
Richard Barry4d2adb72011-02-08 15:20:29 +0000182 prvCheckForValidListAndQueue();
183
184 if( xTimerQueue != NULL )
185 {
Richard Barrycc611262011-09-20 18:22:39 +0000186 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
Richard Barryfc99c142011-07-27 14:02:37 +0000187 {
188 /* Create the timer task, storing its handle in xTimerTaskHandle so
Richard Barrycc611262011-09-20 18:22:39 +0000189 it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
Richard Barryfc99c142011-07-27 14:02:37 +0000190 xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, &xTimerTaskHandle );
191 }
192 #else
193 {
194 /* Create the timer task without storing its handle. */
195 xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, NULL);
196 }
197 #endif
Richard Barry4d2adb72011-02-08 15:20:29 +0000198 }
199
Richard Barry0e620582011-04-01 18:45:44 +0000200 configASSERT( xReturn );
Richard Barry4d2adb72011-02-08 15:20:29 +0000201 return xReturn;
202}
203/*-----------------------------------------------------------*/
204
205xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
206{
207xTIMER *pxNewTimer;
208
209 /* Allocate the timer structure. */
Richard Barryefc3ba92011-02-20 10:59:58 +0000210 if( xTimerPeriodInTicks == ( portTickType ) 0U )
Richard Barry4d2adb72011-02-08 15:20:29 +0000211 {
Richard Barryefc3ba92011-02-20 10:59:58 +0000212 pxNewTimer = NULL;
213 configASSERT( ( xTimerPeriodInTicks > 0 ) );
Richard Barry4d2adb72011-02-08 15:20:29 +0000214 }
Richard Barryefc3ba92011-02-20 10:59:58 +0000215 else
216 {
217 pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
218 if( pxNewTimer != NULL )
219 {
220 /* Ensure the infrastructure used by the timer service task has been
221 created/initialised. */
222 prvCheckForValidListAndQueue();
223
Richard Barryefc3ba92011-02-20 10:59:58 +0000224 /* Initialise the timer structure members using the function parameters. */
225 pxNewTimer->pcTimerName = pcTimerName;
226 pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
227 pxNewTimer->uxAutoReload = uxAutoReload;
228 pxNewTimer->pvTimerID = pvTimerID;
229 pxNewTimer->pxCallbackFunction = pxCallbackFunction;
230 vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
Richard Barry0e620582011-04-01 18:45:44 +0000231
232 traceTIMER_CREATE( pxNewTimer );
233 }
234 else
235 {
236 traceTIMER_CREATE_FAILED();
Richard Barryefc3ba92011-02-20 10:59:58 +0000237 }
238 }
239
Richard Barry4d2adb72011-02-08 15:20:29 +0000240 return ( xTimerHandle ) pxNewTimer;
241}
242/*-----------------------------------------------------------*/
243
Richard Barryeb8f0232011-11-22 13:24:32 +0000244portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
Richard Barry4d2adb72011-02-08 15:20:29 +0000245{
246portBASE_TYPE xReturn = pdFAIL;
247xTIMER_MESSAGE xMessage;
248
Richard Barry896d8c52011-02-09 10:46:45 +0000249 /* Send a message to the timer service task to perform a particular action
250 on a particular timer definition. */
Richard Barry4d2adb72011-02-08 15:20:29 +0000251 if( xTimerQueue != NULL )
252 {
Richard Barry4a5f1522011-02-08 16:21:15 +0000253 /* Send a command to the timer service task to start the xTimer timer. */
Richard Barry896d8c52011-02-09 10:46:45 +0000254 xMessage.xMessageID = xCommandID;
255 xMessage.xMessageValue = xOptionalValue;
Richard Barry4d2adb72011-02-08 15:20:29 +0000256 xMessage.pxTimer = ( xTIMER * ) xTimer;
257
Richard Barryb4ff4822011-02-14 10:51:18 +0000258 if( pxHigherPriorityTaskWoken == NULL )
Richard Barry896d8c52011-02-09 10:46:45 +0000259 {
Richard Barryb4ff4822011-02-14 10:51:18 +0000260 if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
261 {
262 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
263 }
264 else
265 {
266 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
267 }
Richard Barry896d8c52011-02-09 10:46:45 +0000268 }
269 else
270 {
Richard Barryb4ff4822011-02-14 10:51:18 +0000271 xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
Richard Barry896d8c52011-02-09 10:46:45 +0000272 }
Richard Barry0e620582011-04-01 18:45:44 +0000273
274 traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
Richard Barry4d2adb72011-02-08 15:20:29 +0000275 }
Richard Barry8a9fb952011-02-21 09:38:33 +0000276
Richard Barry4d2adb72011-02-08 15:20:29 +0000277 return xReturn;
278}
279/*-----------------------------------------------------------*/
280
Richard Barrycc611262011-09-20 18:22:39 +0000281#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
Richard Barryfc99c142011-07-27 14:02:37 +0000282
Richard Barrycc611262011-09-20 18:22:39 +0000283 xTaskHandle xTimerGetTimerDaemonTaskHandle( void )
Richard Barryfc99c142011-07-27 14:02:37 +0000284 {
Richard Barrycc611262011-09-20 18:22:39 +0000285 /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
Richard Barryfc99c142011-07-27 14:02:37 +0000286 started, then xTimerTaskHandle will be NULL. */
287 configASSERT( ( xTimerTaskHandle != NULL ) );
288 return xTimerTaskHandle;
289 }
290
291#endif
292/*-----------------------------------------------------------*/
293
Richard Barryb4ff4822011-02-14 10:51:18 +0000294static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
Richard Barry3ba433e2011-02-11 16:17:37 +0000295{
296xTIMER *pxTimer;
Richard Barry2c1a85c2011-02-22 20:43:17 +0000297portBASE_TYPE xResult;
Richard Barry3ba433e2011-02-11 16:17:37 +0000298
Richard Barryb4ff4822011-02-14 10:51:18 +0000299 /* Remove the timer from the list of active timers. A check has already
300 been performed to ensure the list is not empty. */
301 pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
302 vListRemove( &( pxTimer->xTimerListItem ) );
Richard Barry0e620582011-04-01 18:45:44 +0000303 traceTIMER_EXPIRED( pxTimer );
Richard Barryb4ff4822011-02-14 10:51:18 +0000304
305 /* If the timer is an auto reload timer then calculate the next
306 expiry time and re-insert the timer in the list of active timers. */
Richard Barry37de2682011-04-05 20:19:54 +0000307 if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
Richard Barry3ba433e2011-02-11 16:17:37 +0000308 {
Richard Barryb4ff4822011-02-14 10:51:18 +0000309 /* This is the only time a timer is inserted into a list using
310 a time relative to anything other than the current time. It
311 will therefore be inserted into the correct list relative to
312 the time this task thinks it is now, even if a command to
313 switch lists due to a tick count overflow is already waiting in
314 the timer queue. */
Richard Barry8a9fb952011-02-21 09:38:33 +0000315 if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
316 {
317 /* The timer expired before it was added to the active timer
Richard Barry8b5a0042011-02-21 10:52:36 +0000318 list. Reload it now. */
Richard Barry2c1a85c2011-02-22 20:43:17 +0000319 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
320 configASSERT( xResult );
321 ( void ) xResult;
Richard Barry8a9fb952011-02-21 09:38:33 +0000322 }
Richard Barry3ba433e2011-02-11 16:17:37 +0000323 }
Richard Barryb4ff4822011-02-14 10:51:18 +0000324
325 /* Call the timer callback. */
326 pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
Richard Barry3ba433e2011-02-11 16:17:37 +0000327}
328/*-----------------------------------------------------------*/
329
Richard Barry4d2adb72011-02-08 15:20:29 +0000330static void prvTimerTask( void *pvParameters )
331{
Richard Barryb4ff4822011-02-14 10:51:18 +0000332portTickType xNextExpireTime;
333portBASE_TYPE xListWasEmpty;
Richard Barry4d2adb72011-02-08 15:20:29 +0000334
335 /* Just to avoid compiler warnings. */
336 ( void ) pvParameters;
337
338 for( ;; )
339 {
Richard Barryb4ff4822011-02-14 10:51:18 +0000340 /* Query the timers list to see if it contains any timers, and if so,
341 obtain the time at which the next timer will expire. */
Richard Barry2c1a85c2011-02-22 20:43:17 +0000342 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
Richard Barry3ba433e2011-02-11 16:17:37 +0000343
Richard Barryb4ff4822011-02-14 10:51:18 +0000344 /* If a timer has expired, process it. Otherwise, block this task
345 until either a timer does expire, or a command is received. */
346 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
347
348 /* Empty the command queue. */
349 prvProcessReceivedCommands();
Richard Barry4a5f1522011-02-08 16:21:15 +0000350 }
351}
352/*-----------------------------------------------------------*/
353
Richard Barryb4ff4822011-02-14 10:51:18 +0000354static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
355{
356portTickType xTimeNow;
357portBASE_TYPE xTimerListsWereSwitched;
358
359 vTaskSuspendAll();
360 {
361 /* Obtain the time now to make an assessment as to whether the timer
362 has expired or not. If obtaining the time causes the lists to switch
363 then don't process this timer as any timers that remained in the list
364 when the lists were switched will have been processed within the
365 prvSampelTimeNow() function. */
366 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
367 if( xTimerListsWereSwitched == pdFALSE )
368 {
369 /* The tick count has not overflowed, has the timer expired? */
370 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
371 {
Richard Barry2c1a85c2011-02-22 20:43:17 +0000372 xTaskResumeAll();
Richard Barryb4ff4822011-02-14 10:51:18 +0000373 prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
374 }
375 else
376 {
Richard Barryefc3ba92011-02-20 10:59:58 +0000377 /* The tick count has not overflowed, and the next expire
378 time has not been reached yet. This task should therefore
379 block to wait for the next expire time or a command to be
Richard Barryb4ff4822011-02-14 10:51:18 +0000380 received - whichever comes first. The following line cannot
Richard Barryefc3ba92011-02-20 10:59:58 +0000381 be reached unless xNextExpireTime > xTimeNow, except in the
Richard Barryb4ff4822011-02-14 10:51:18 +0000382 case when the current timer list is empty. */
383 vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
Richard Barry2c1a85c2011-02-22 20:43:17 +0000384
385 if( xTaskResumeAll() == pdFALSE )
386 {
387 /* Yield to wait for either a command to arrive, or the block time
388 to expire. If a command arrived between the critical section being
389 exited and this yield then the yield will not cause the task
390 to block. */
391 portYIELD_WITHIN_API();
392 }
Richard Barryb4ff4822011-02-14 10:51:18 +0000393 }
394 }
Richard Barry2c1a85c2011-02-22 20:43:17 +0000395 else
396 {
397 xTaskResumeAll();
398 }
Richard Barryb4ff4822011-02-14 10:51:18 +0000399 }
400}
401/*-----------------------------------------------------------*/
402
Richard Barry2c1a85c2011-02-22 20:43:17 +0000403static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
Richard Barryb4ff4822011-02-14 10:51:18 +0000404{
405portTickType xNextExpireTime;
406
407 /* Timers are listed in expiry time order, with the head of the list
408 referencing the task that will expire first. Obtain the time at which
409 the timer with the nearest expiry time will expire. If there are no
410 active timers then just set the next expire time to 0. That will cause
411 this task to unblock when the tick count overflows, at which point the
Richard Barryefc3ba92011-02-20 10:59:58 +0000412 timer lists will be switched and the next expiry time can be
Richard Barryb4ff4822011-02-14 10:51:18 +0000413 re-assessed. */
414 *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
415 if( *pxListWasEmpty == pdFALSE )
416 {
417 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
418 }
419 else
420 {
421 /* Ensure the task unblocks when the tick count rolls over. */
422 xNextExpireTime = ( portTickType ) 0U;
423 }
424
425 return xNextExpireTime;
426}
427/*-----------------------------------------------------------*/
428
429static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
430{
431portTickType xTimeNow;
432static portTickType xLastTime = ( portTickType ) 0U;
433
434 xTimeNow = xTaskGetTickCount();
435
436 if( xTimeNow < xLastTime )
437 {
Richard Barrycb238fc2011-02-28 16:10:08 +0000438 prvSwitchTimerLists( xLastTime );
Richard Barryb4ff4822011-02-14 10:51:18 +0000439 *pxTimerListsWereSwitched = pdTRUE;
440 }
441 else
442 {
443 *pxTimerListsWereSwitched = pdFALSE;
444 }
445
446 xLastTime = xTimeNow;
447
448 return xTimeNow;
449}
450/*-----------------------------------------------------------*/
451
Richard Barryefc3ba92011-02-20 10:59:58 +0000452static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
Richard Barry7ee534e2011-02-10 19:09:35 +0000453{
Richard Barryefc3ba92011-02-20 10:59:58 +0000454portBASE_TYPE xProcessTimerNow = pdFALSE;
455
Richard Barry7ee534e2011-02-10 19:09:35 +0000456 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
457 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
458
Richard Barryefc3ba92011-02-20 10:59:58 +0000459 if( xNextExpiryTime <= xTimeNow )
Richard Barry7ee534e2011-02-10 19:09:35 +0000460 {
Richard Barryefc3ba92011-02-20 10:59:58 +0000461 /* Has the expiry time elapsed between the command to start/reset a
462 timer was issued, and the time the command was processed? */
Richard Barry8a9fb952011-02-21 09:38:33 +0000463 if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )
Richard Barryefc3ba92011-02-20 10:59:58 +0000464 {
465 /* The time between a command being issued and the command being
466 processed actually exceeds the timers period. */
467 xProcessTimerNow = pdTRUE;
468 }
469 else
470 {
471 vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
472 }
Richard Barry7ee534e2011-02-10 19:09:35 +0000473 }
474 else
475 {
Richard Barryefc3ba92011-02-20 10:59:58 +0000476 if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
477 {
478 /* If, since the command was issued, the tick count has overflowed
479 but the expiry time has not, then the timer must have already passed
480 its expiry time and should be processed immediately. */
481 xProcessTimerNow = pdTRUE;
482 }
483 else
484 {
485 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
486 }
Richard Barry7ee534e2011-02-10 19:09:35 +0000487 }
Richard Barryefc3ba92011-02-20 10:59:58 +0000488
489 return xProcessTimerNow;
Richard Barry7ee534e2011-02-10 19:09:35 +0000490}
491/*-----------------------------------------------------------*/
492
Richard Barryb4ff4822011-02-14 10:51:18 +0000493static void prvProcessReceivedCommands( void )
Richard Barry4a5f1522011-02-08 16:21:15 +0000494{
495xTIMER_MESSAGE xMessage;
Richard Barry4a5f1522011-02-08 16:21:15 +0000496xTIMER *pxTimer;
Richard Barry2c1a85c2011-02-22 20:43:17 +0000497portBASE_TYPE xTimerListsWereSwitched, xResult;
Richard Barryb4ff4822011-02-14 10:51:18 +0000498portTickType xTimeNow;
499
500 /* In this case the xTimerListsWereSwitched parameter is not used, but it
501 must be present in the function call. */
502 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
Richard Barry4a5f1522011-02-08 16:21:15 +0000503
504 while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
505 {
506 pxTimer = xMessage.pxTimer;
507
Richard Barry3ba433e2011-02-11 16:17:37 +0000508 /* Is the timer already in a list of active timers? When the command
Richard Barry7ee534e2011-02-10 19:09:35 +0000509 is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the
510 command is to the task rather than to an individual timer. */
511 if( pxTimer != NULL )
Richard Barry896d8c52011-02-09 10:46:45 +0000512 {
Richard Barry7ee534e2011-02-10 19:09:35 +0000513 if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
514 {
Richard Barry3ba433e2011-02-11 16:17:37 +0000515 /* The timer is in a list, remove it. */
Richard Barry7ee534e2011-02-10 19:09:35 +0000516 vListRemove( &( pxTimer->xTimerListItem ) );
517 }
Richard Barry896d8c52011-02-09 10:46:45 +0000518 }
Richard Barry4a5f1522011-02-08 16:21:15 +0000519
Richard Barry0e620582011-04-01 18:45:44 +0000520 traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
521
Richard Barry4a5f1522011-02-08 16:21:15 +0000522 switch( xMessage.xMessageID )
523 {
Richard Barry896d8c52011-02-09 10:46:45 +0000524 case tmrCOMMAND_START :
525 /* Start or restart a timer. */
Richard Barryefc3ba92011-02-20 10:59:58 +0000526 if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )
527 {
528 /* The timer expired before it was added to the active timer
529 list. Process it now. */
Richard Barryefc3ba92011-02-20 10:59:58 +0000530 pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
531
Richard Barry37de2682011-04-05 20:19:54 +0000532 if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
Richard Barryefc3ba92011-02-20 10:59:58 +0000533 {
Richard Barry2c1a85c2011-02-22 20:43:17 +0000534 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
535 configASSERT( xResult );
536 ( void ) xResult;
Richard Barryefc3ba92011-02-20 10:59:58 +0000537 }
538 }
Richard Barry896d8c52011-02-09 10:46:45 +0000539 break;
Richard Barry4a5f1522011-02-08 16:21:15 +0000540
Richard Barry896d8c52011-02-09 10:46:45 +0000541 case tmrCOMMAND_STOP :
542 /* The timer has already been removed from the active list.
543 There is nothing to do here. */
544 break;
545
546 case tmrCOMMAND_CHANGE_PERIOD :
547 pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
Richard Barryefc3ba92011-02-20 10:59:58 +0000548 configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
549 prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
Richard Barry896d8c52011-02-09 10:46:45 +0000550 break;
551
552 case tmrCOMMAND_DELETE :
553 /* The timer has already been removed from the active list,
554 just free up the memory. */
555 vPortFree( pxTimer );
556 break;
557
558 default :
559 /* Don't expect to get here. */
560 break;
Richard Barry4d2adb72011-02-08 15:20:29 +0000561 }
562 }
Richard Barry3ba433e2011-02-11 16:17:37 +0000563}
564/*-----------------------------------------------------------*/
565
Richard Barrycb238fc2011-02-28 16:10:08 +0000566static void prvSwitchTimerLists( portTickType xLastTime )
Richard Barry3ba433e2011-02-11 16:17:37 +0000567{
Richard Barry0c95f332011-02-27 13:08:44 +0000568portTickType xNextExpireTime, xReloadTime;
Richard Barry3ba433e2011-02-11 16:17:37 +0000569xList *pxTemp;
Richard Barry8b5a0042011-02-21 10:52:36 +0000570xTIMER *pxTimer;
Richard Barry2c1a85c2011-02-22 20:43:17 +0000571portBASE_TYPE xResult;
Richard Barry3ba433e2011-02-11 16:17:37 +0000572
Richard Barryb4ff4822011-02-14 10:51:18 +0000573 /* Remove compiler warnings if configASSERT() is not defined. */
574 ( void ) xLastTime;
575
576 /* The tick count has overflowed. The timer lists must be switched.
577 If there are any timers still referenced from the current timer list
578 then they must have expired and should be processed before the lists
Richard Barry3ba433e2011-02-11 16:17:37 +0000579 are switched. */
580 while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
581 {
582 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
Richard Barry8b5a0042011-02-21 10:52:36 +0000583
584 /* Remove the timer from the list. */
585 pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
586 vListRemove( &( pxTimer->xTimerListItem ) );
587
588 /* Execute its callback, then send a command to restart the timer if
589 it is an auto-reload timer. It cannot be restarted here as the lists
590 have not yet been switched. */
591 pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
Richard Barry0c95f332011-02-27 13:08:44 +0000592
Richard Barry37de2682011-04-05 20:19:54 +0000593 if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
Richard Barry8b5a0042011-02-21 10:52:36 +0000594 {
Richard Barry0c95f332011-02-27 13:08:44 +0000595 /* Calculate the reload value, and if the reload value results in
596 the timer going into the same timer list then it has already expired
597 and the timer should be re-inserted into the current list so it is
598 processed again within this loop. Otherwise a command should be sent
599 to restart the timer to ensure it is only inserted into a list after
600 the lists have been swapped. */
601 xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
602 if( xReloadTime > xNextExpireTime )
603 {
604 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
605 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
606 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
607 }
608 else
609 {
610 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
611 configASSERT( xResult );
612 ( void ) xResult;
613 }
Richard Barry8b5a0042011-02-21 10:52:36 +0000614 }
Richard Barry3ba433e2011-02-11 16:17:37 +0000615 }
616
617 pxTemp = pxCurrentTimerList;
618 pxCurrentTimerList = pxOverflowTimerList;
619 pxOverflowTimerList = pxTemp;
Richard Barry4d2adb72011-02-08 15:20:29 +0000620}
621/*-----------------------------------------------------------*/
622
623static void prvCheckForValidListAndQueue( void )
624{
625 /* Check that the list from which active timers are referenced, and the
Richard Barry0552fc82011-02-10 17:20:36 +0000626 queue used to communicate with the timer service, have been
Richard Barry4d2adb72011-02-08 15:20:29 +0000627 initialised. */
628 taskENTER_CRITICAL();
629 {
630 if( xTimerQueue == NULL )
631 {
Richard Barry7ee534e2011-02-10 19:09:35 +0000632 vListInitialise( &xActiveTimerList1 );
633 vListInitialise( &xActiveTimerList2 );
634 pxCurrentTimerList = &xActiveTimerList1;
635 pxOverflowTimerList = &xActiveTimerList2;
Richard Barry37de2682011-04-05 20:19:54 +0000636 xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
Richard Barry4d2adb72011-02-08 15:20:29 +0000637 }
638 }
639 taskEXIT_CRITICAL();
640}
641/*-----------------------------------------------------------*/
642
Richard Barry896d8c52011-02-09 10:46:45 +0000643portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
644{
645portBASE_TYPE xTimerIsInActiveList;
646xTIMER *pxTimer = ( xTIMER * ) xTimer;
647
648 /* Is the timer in the list of active timers? */
649 taskENTER_CRITICAL();
650 {
Richard Barry7ee534e2011-02-10 19:09:35 +0000651 /* Checking to see if it is in the NULL list in effect checks to see if
652 it is referenced from either the current or the overflow timer lists in
653 one go, but the logic has to be reversed, hence the '!'. */
654 xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
Richard Barry896d8c52011-02-09 10:46:45 +0000655 }
656 taskEXIT_CRITICAL();
657
658 return xTimerIsInActiveList;
659}
660/*-----------------------------------------------------------*/
661
Richard Barry4a5f1522011-02-08 16:21:15 +0000662void *pvTimerGetTimerID( xTimerHandle xTimer )
Richard Barry4d2adb72011-02-08 15:20:29 +0000663{
Richard Barry4a5f1522011-02-08 16:21:15 +0000664xTIMER *pxTimer = ( xTIMER * ) xTimer;
Richard Barry4d2adb72011-02-08 15:20:29 +0000665
Richard Barry4a5f1522011-02-08 16:21:15 +0000666 return pxTimer->pvTimerID;
667}
668/*-----------------------------------------------------------*/
669
Richard Barry8bd2d2f2011-03-31 14:09:21 +0000670/* This entire source file will be skipped if the application is not configured
671to include software timer functionality. If you want to include software timer
672functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
673#endif /* configUSE_TIMERS == 1 */