]> git.sur5r.net Git - freertos/blob - Source/timers.c
Start an optional timers module implementation.
[freertos] / Source / timers.c
1 /* Need a method of switching to an overflow list. _RB_*/\r
2 \r
3 /*\r
4     FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
5 \r
6     ***************************************************************************\r
7     *                                                                         *\r
8     * If you are:                                                             *\r
9     *                                                                         *\r
10     *    + New to FreeRTOS,                                                   *\r
11     *    + Wanting to learn FreeRTOS or multitasking in general quickly       *\r
12     *    + Looking for basic training,                                        *\r
13     *    + Wanting to improve your FreeRTOS skills and productivity           *\r
14     *                                                                         *\r
15     * then take a look at the FreeRTOS books - available as PDF or paperback  *\r
16     *                                                                         *\r
17     *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *\r
18     *                  http://www.FreeRTOS.org/Documentation                  *\r
19     *                                                                         *\r
20     * A pdf reference manual is also available.  Both are usually delivered   *\r
21     * to your inbox within 20 minutes to two hours when purchased between 8am *\r
22     * and 8pm GMT (although please allow up to 24 hours in case of            *\r
23     * exceptional circumstances).  Thank you for your support!                *\r
24     *                                                                         *\r
25     ***************************************************************************\r
26 \r
27     This file is part of the FreeRTOS distribution.\r
28 \r
29     FreeRTOS is free software; you can redistribute it and/or modify it under\r
30     the terms of the GNU General Public License (version 2) as published by the\r
31     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
32     ***NOTE*** The exception to the GPL is included to allow you to distribute\r
33     a combined work that includes FreeRTOS without being obliged to provide the\r
34     source code for proprietary components outside of the FreeRTOS kernel.\r
35     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT\r
36     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
37     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
38     more details. You should have received a copy of the GNU General Public\r
39     License and the FreeRTOS license exception along with FreeRTOS; if not it\r
40     can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
41     by writing to Richard Barry, contact details for whom are available on the\r
42     FreeRTOS WEB site.\r
43 \r
44     1 tab == 4 spaces!\r
45 \r
46     http://www.FreeRTOS.org - Documentation, latest information, license and\r
47     contact details.\r
48 \r
49     http://www.SafeRTOS.com - A version that is certified for use in safety\r
50     critical systems.\r
51 \r
52     http://www.OpenRTOS.com - Commercial support, development, porting,\r
53     licensing and training services.\r
54 */\r
55 \r
56 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
57 all the API functions to use the MPU wrappers.  That should only be done when\r
58 task.h is included from an application file. */\r
59 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
60 \r
61 #include "FreeRTOS.h"\r
62 #include "task.h"\r
63 #include "queue.h"\r
64 #include "timers.h"\r
65 \r
66 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
67 \r
68 /* IDs for commands that can be sent/received on the timer queue. */\r
69 #define tmrSTART                0\r
70 \r
71 /* Misc definitions. */\r
72 #define timerNO_DELAY   ( portTickType ) 0U\r
73 \r
74 /* The definition of the timers themselves. */\r
75 typedef struct tmrTimerControl\r
76 {\r
77         const signed char               *pcTimerName;           /*<< Text name.  This is not used by the kernel, it is included simply to make debugging easier. */\r
78         xListItem                               xTimerListItem;         /*<< Standard linked list item as used by all kernel features for event management. */\r
79         portTickType                    xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */\r
80         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. */\r
81         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
82         tmrTIMER_CALLBACK               pxCallbackFunction;     /*<< The function that will be called when the timer expires. */\r
83 } xTIMER;\r
84 \r
85 /* The definition of messages that can be sent and received on the timer \r
86 queue. */\r
87 typedef struct tmrTimerQueueMessage\r
88 {\r
89         portBASE_TYPE                   xMessageID;\r
90         portTickType                    xMessageValue;\r
91         xTIMER *                                pxTimer;\r
92 } xTIMER_MESSAGE;\r
93 \r
94 \r
95 /* The list in which active timers are stored.  Timers are referenced in expire\r
96 time order, with the nearest expiry time at the front of the list.  Only the\r
97 timer service task is allowed to access xActiveTimerList. */\r
98 PRIVILEGED_DATA static xList xActiveTimerList;\r
99 \r
100 /* A queue that is used to send commands to the timer service task. */\r
101 PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;\r
102 \r
103 /*-----------------------------------------------------------*/\r
104 \r
105 /*\r
106  * Called when a timer is about to be modified.  If the timer is already in the\r
107  * list of active timers then it is removed prior to the modification.\r
108  */\r
109 static void prvRemoveTimerFromActiveList( xTIMER *pxTimer ) PRIVILEGED_FUNCTION;\r
110 \r
111 static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;\r
112 \r
113 /*\r
114  * The timer service task (daemon).\r
115  */\r
116 static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;\r
117 \r
118 \r
119 /* Handlers for commands received on the timer queue. */\r
120 static void prvTimerStart( xTIMER *pxTimer );\r
121 \r
122 /*-----------------------------------------------------------*/\r
123 \r
124 portBASE_TYPE xTimerCreateTimerTask( void )\r
125 {\r
126 portBASE_TYPE xReturn = pdFAIL;\r
127 \r
128         /* This function is called when the scheduler is started if \r
129         configUSE_TIMERS is set to 1. */\r
130         prvCheckForValidListAndQueue();\r
131 \r
132         if( xTimerQueue != NULL )\r
133         {\r
134                 xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Timers", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY, NULL );\r
135         }\r
136 \r
137         return xReturn;\r
138 }\r
139 /*-----------------------------------------------------------*/\r
140 \r
141 xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )\r
142 {\r
143 xTIMER *pxNewTimer;\r
144 \r
145         /* Allocate the timer structure. */\r
146         pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );\r
147         if( pxNewTimer != NULL )\r
148         {\r
149                 prvCheckForValidListAndQueue();\r
150 \r
151                 /* Initialise the timer structure members. */\r
152                 pxNewTimer->pcTimerName = pcTimerName;\r
153                 pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;\r
154                 pxNewTimer->uxAutoReload = uxAutoReload;\r
155                 pxNewTimer->pvTimerID = pvTimerID;\r
156                 pxNewTimer->pxCallbackFunction = pxCallbackFunction;\r
157                 vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );\r
158         }\r
159 \r
160         return ( xTimerHandle ) pxNewTimer;\r
161 }\r
162 /*-----------------------------------------------------------*/\r
163 \r
164 portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime )\r
165 {\r
166 portBASE_TYPE xReturn = pdFAIL;\r
167 xTIMER_MESSAGE xMessage;\r
168 \r
169         if( xTimerQueue != NULL )\r
170         {\r
171                 xMessage.xMessageID = tmrSTART;\r
172                 xMessage.pxTimer = ( xTIMER * ) xTimer;\r
173 \r
174                 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );\r
175         }\r
176 \r
177         return xReturn;\r
178 }\r
179 /*-----------------------------------------------------------*/\r
180 \r
181 void *pvTimerGetTimerID( xTimerHandle xTimer )\r
182 {\r
183 xTIMER *pxTimer = ( xTIMER * ) xTimer;\r
184 \r
185         return pxTimer->pvTimerID;\r
186 }\r
187 /*-----------------------------------------------------------*/\r
188 \r
189 static void prvRemoveTimerFromActiveList( xTIMER *pxTimer )\r
190 {\r
191         /* Is the timer already in the list of active timers? */\r
192         if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )\r
193         {\r
194                 /* The timer is in the list, remove it. */\r
195                 vListRemove( &( pxTimer->xTimerListItem ) );\r
196         }\r
197 }\r
198 /*-----------------------------------------------------------*/\r
199 \r
200 static void prvTimerTask( void *pvParameters )\r
201 {\r
202 portTickType xNextWakeTime, xTimeNow;\r
203 xTIMER *pxTimer;\r
204 xTIMER_MESSAGE xMessage;\r
205 \r
206         /* Just to avoid compiler warnings. */\r
207         ( void ) pvParameters;\r
208 \r
209         for( ;; )\r
210         {\r
211                 if( listLIST_IS_EMPTY( &xActiveTimerList ) == pdFALSE )\r
212                 {\r
213                         xNextWakeTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );\r
214                 }\r
215                 else\r
216                 {\r
217                         xNextWakeTime = portMAX_DELAY;\r
218                 }\r
219 \r
220                 if( xNextWakeTime <= xTaskGetTickCount() )\r
221                 {\r
222                         /* Remove the timer from the list.  This functionality relies on\r
223                         the list of active timers not being accessed from outside of this\r
224                         task. */\r
225                         pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );\r
226                         vListRemove( &( pxTimer->xTimerListItem ) );\r
227 \r
228                         if( pxTimer->uxAutoReload == pdTRUE )\r
229                         {\r
230                                 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextWakeTime + pxTimer->xTimerPeriodInTicks ) );\r
231                                 vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
232                         }\r
233 \r
234                         /* Call the timer callback. */\r
235                         pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );\r
236                 }\r
237                 else\r
238                 {\r
239                         /* Calculate the block time. */\r
240                         taskENTER_CRITICAL();\r
241                         {\r
242                                 xTimeNow = xTaskGetTickCount();\r
243                                 if( xTimeNow < xNextWakeTime )\r
244                                 {\r
245                                         vQueueWaitForMessageRestricted( xTimerQueue, ( xNextWakeTime - xTimeNow ) );\r
246                                 }\r
247                         }\r
248                         taskEXIT_CRITICAL();\r
249                         portYIELD_WITHIN_API();\r
250 \r
251                         while( xQueueReceive( xTimerQueue, &xMessage, timerNO_DELAY ) != pdFAIL )\r
252                         {\r
253                                 switch( xMessage.xMessageID )\r
254                                 {\r
255                                         case tmrSTART   :       prvTimerStart( xMessage.pxTimer );\r
256                                                                                 break;\r
257                                         default                 :       /* Don't expect to get here. */\r
258                                                                                 break;\r
259                                 }\r
260                         }\r
261                 }\r
262         }\r
263 }\r
264 /*-----------------------------------------------------------*/\r
265 \r
266 static void prvCheckForValidListAndQueue( void )\r
267 {\r
268         /* Check that the list from which active timers are referenced, and the\r
269         queue used to communicate with the timer service, have been \r
270         initialised. */\r
271         taskENTER_CRITICAL();\r
272         {\r
273                 if( xTimerQueue == NULL )\r
274                 {\r
275                         vListInitialise( &xActiveTimerList );\r
276                         xTimerQueue = xQueueCreate( configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );\r
277                 }\r
278         }\r
279         taskEXIT_CRITICAL();\r
280 }\r
281 /*-----------------------------------------------------------*/\r
282 \r
283 static void prvTimerStart( xTIMER *pxTimer )\r
284 {\r
285 portTickType xTimeToWake;\r
286 \r
287         if( pxTimer != NULL )\r
288         {\r
289                 /* Is the timer already in the list of active timers? */\r
290                 prvRemoveTimerFromActiveList( pxTimer );\r
291 \r
292                 xTimeToWake = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;\r
293                 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToWake );\r
294                 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
295                 vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
296         }\r
297 }\r
298 \r
299 \r
300 \r
301 \r
302 \r
303 \r
304 \r
305 \r
306 \r
307 \r
308 portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )\r
309 {\r
310         return pdFALSE;\r
311 }\r
312 \r
313 void vTimerStop( xTimerHandle xTimer )\r
314 {\r
315 }\r
316 \r
317 \r
318 void vTimerChangePeriod( xTimerHandle xTimer )\r
319 {\r
320 }\r
321 \r
322 void vTimerDelete( xTimerHandle xTimer )\r
323 {\r
324 }\r
325 /*-----------------------------------------------------------*/\r