Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 1 | /*
|
Richard Barry | cc61126 | 2011-09-20 18:22:39 +0000 | [diff] [blame] | 2 | FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
|
Richard Barry | 89bf1cf | 2011-04-08 18:30:58 +0000 | [diff] [blame] | 3 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 4 |
|
| 5 | ***************************************************************************
|
Richard Barry | 89bf1cf | 2011-04-08 18:30:58 +0000 | [diff] [blame] | 6 | * *
|
| 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 Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 22 | ***************************************************************************
|
| 23 |
|
Richard Barry | 89bf1cf | 2011-04-08 18:30:58 +0000 | [diff] [blame] | 24 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 25 | 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 Barry | 89bf1cf | 2011-04-08 18:30:58 +0000 | [diff] [blame] | 30 | >>>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 Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 36 | 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
|
| 55 | all the API functions to use the MPU wrappers. That should only be done when
|
| 56 | task.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 Barry | 8bd2d2f | 2011-03-31 14:09:21 +0000 | [diff] [blame] | 66 | /* This entire source file will be skipped if the application is not configured
|
| 67 | to include software timer functionality. This #if is closed at the very bottom
|
Richard Barry | 37de268 | 2011-04-05 20:19:54 +0000 | [diff] [blame] | 68 | of this file. If you want to include software timer functionality then ensure
|
Richard Barry | 8bd2d2f | 2011-03-31 14:09:21 +0000 | [diff] [blame] | 69 | configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
|
| 70 | #if ( configUSE_TIMERS == 1 )
|
| 71 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 72 | /* Misc definitions. */
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 73 | #define tmrNO_DELAY ( portTickType ) 0U
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 74 |
|
| 75 | /* The definition of the timers themselves. */
|
| 76 | typedef 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 Barry | 0552fc8 | 2011-02-10 17:20:36 +0000 | [diff] [blame] | 86 | /* The definition of messages that can be sent and received on the timer
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 87 | queue. */
|
| 88 | typedef struct tmrTimerQueueMessage
|
| 89 | {
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 90 | portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 91 | portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 92 | xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 93 | } xTIMER_MESSAGE;
|
| 94 |
|
| 95 |
|
| 96 | /* The list in which active timers are stored. Timers are referenced in expire
|
| 97 | time order, with the nearest expiry time at the front of the list. Only the
|
| 98 | timer service task is allowed to access xActiveTimerList. */
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 99 | PRIVILEGED_DATA static xList xActiveTimerList1;
|
| 100 | PRIVILEGED_DATA static xList xActiveTimerList2;
|
| 101 | PRIVILEGED_DATA static xList *pxCurrentTimerList;
|
| 102 | PRIVILEGED_DATA static xList *pxOverflowTimerList;
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 103 |
|
| 104 | /* A queue that is used to send commands to the timer service task. */
|
| 105 | PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
|
| 106 |
|
Richard Barry | cc61126 | 2011-09-20 18:22:39 +0000 | [diff] [blame] | 107 | #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
Richard Barry | fc99c14 | 2011-07-27 14:02:37 +0000 | [diff] [blame] | 108 |
|
| 109 | PRIVILEGED_DATA static xTaskHandle xTimerTaskHandle = NULL;
|
| 110 |
|
| 111 | #endif
|
| 112 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 113 | /*-----------------------------------------------------------*/
|
| 114 |
|
Richard Barry | 0552fc8 | 2011-02-10 17:20:36 +0000 | [diff] [blame] | 115 | /*
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 116 | * Initialise the infrastructure used by the timer service task if it has not
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 117 | * been initialised already.
|
| 118 | */
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 119 | static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
|
| 120 |
|
| 121 | /*
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 122 | * The timer service task (daemon). Timer functionality is controlled by this
|
Richard Barry | 0552fc8 | 2011-02-10 17:20:36 +0000 | [diff] [blame] | 123 | * task. Other tasks communicate with the timer service task using the
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 124 | * xTimerQueue queue.
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 125 | */
|
| 126 | static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
|
| 127 |
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 128 | /*
|
| 129 | * Called by the timer service task to interpret and process a command it
|
Richard Barry | 0552fc8 | 2011-02-10 17:20:36 +0000 | [diff] [blame] | 130 | * received on the timer queue.
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 131 | */
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 132 | static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 133 |
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 134 | /*
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 135 | * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
|
| 136 | * depending on if the expire time causes a timer counter overflow.
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 137 | */
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 138 | static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 139 |
|
| 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 Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 144 | static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 145 |
|
| 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 Barry | cb238fc | 2011-02-28 16:10:08 +0000 | [diff] [blame] | 150 | static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 151 |
|
| 152 | /*
|
| 153 | * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
|
| 154 | * if a tick count overflow occurred since prvSampleTimeNow() was last called.
|
| 155 | */
|
| 156 | static 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 Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 164 | static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 165 |
|
| 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 | */
|
| 170 | static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 171 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 172 | /*-----------------------------------------------------------*/
|
| 173 |
|
| 174 | portBASE_TYPE xTimerCreateTimerTask( void )
|
| 175 | {
|
| 176 | portBASE_TYPE xReturn = pdFAIL;
|
| 177 |
|
Richard Barry | 0552fc8 | 2011-02-10 17:20:36 +0000 | [diff] [blame] | 178 | /* This function is called when the scheduler is started if
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 179 | configUSE_TIMERS is set to 1. Check that the infrastructure used by the
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 180 | timer service task has been created/initialised. If timers have already
|
| 181 | been created then the initialisation will already have been performed. */
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 182 | prvCheckForValidListAndQueue();
|
| 183 |
|
| 184 | if( xTimerQueue != NULL )
|
| 185 | {
|
Richard Barry | cc61126 | 2011-09-20 18:22:39 +0000 | [diff] [blame] | 186 | #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
Richard Barry | fc99c14 | 2011-07-27 14:02:37 +0000 | [diff] [blame] | 187 | {
|
| 188 | /* Create the timer task, storing its handle in xTimerTaskHandle so
|
Richard Barry | cc61126 | 2011-09-20 18:22:39 +0000 | [diff] [blame] | 189 | it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
|
Richard Barry | fc99c14 | 2011-07-27 14:02:37 +0000 | [diff] [blame] | 190 | 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 Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 198 | }
|
| 199 |
|
Richard Barry | 0e62058 | 2011-04-01 18:45:44 +0000 | [diff] [blame] | 200 | configASSERT( xReturn );
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 201 | return xReturn;
|
| 202 | }
|
| 203 | /*-----------------------------------------------------------*/
|
| 204 |
|
| 205 | xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
|
| 206 | {
|
| 207 | xTIMER *pxNewTimer;
|
| 208 |
|
| 209 | /* Allocate the timer structure. */
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 210 | if( xTimerPeriodInTicks == ( portTickType ) 0U )
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 211 | {
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 212 | pxNewTimer = NULL;
|
| 213 | configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 214 | }
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 215 | 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 Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 224 | /* 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 Barry | 0e62058 | 2011-04-01 18:45:44 +0000 | [diff] [blame] | 231 |
|
| 232 | traceTIMER_CREATE( pxNewTimer );
|
| 233 | }
|
| 234 | else
|
| 235 | {
|
| 236 | traceTIMER_CREATE_FAILED();
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 237 | }
|
| 238 | }
|
| 239 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 240 | return ( xTimerHandle ) pxNewTimer;
|
| 241 | }
|
| 242 | /*-----------------------------------------------------------*/
|
| 243 |
|
Richard Barry | eb8f023 | 2011-11-22 13:24:32 +0000 | [diff] [blame] | 244 | portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 245 | {
|
| 246 | portBASE_TYPE xReturn = pdFAIL;
|
| 247 | xTIMER_MESSAGE xMessage;
|
| 248 |
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 249 | /* Send a message to the timer service task to perform a particular action
|
| 250 | on a particular timer definition. */
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 251 | if( xTimerQueue != NULL )
|
| 252 | {
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 253 | /* Send a command to the timer service task to start the xTimer timer. */
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 254 | xMessage.xMessageID = xCommandID;
|
| 255 | xMessage.xMessageValue = xOptionalValue;
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 256 | xMessage.pxTimer = ( xTIMER * ) xTimer;
|
| 257 |
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 258 | if( pxHigherPriorityTaskWoken == NULL )
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 259 | {
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 260 | if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
|
| 261 | {
|
| 262 | xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
|
| 263 | }
|
| 264 | else
|
| 265 | {
|
| 266 | xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
|
| 267 | }
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 268 | }
|
| 269 | else
|
| 270 | {
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 271 | xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 272 | }
|
Richard Barry | 0e62058 | 2011-04-01 18:45:44 +0000 | [diff] [blame] | 273 |
|
| 274 | traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 275 | }
|
Richard Barry | 8a9fb95 | 2011-02-21 09:38:33 +0000 | [diff] [blame] | 276 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 277 | return xReturn;
|
| 278 | }
|
| 279 | /*-----------------------------------------------------------*/
|
| 280 |
|
Richard Barry | cc61126 | 2011-09-20 18:22:39 +0000 | [diff] [blame] | 281 | #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
Richard Barry | fc99c14 | 2011-07-27 14:02:37 +0000 | [diff] [blame] | 282 |
|
Richard Barry | cc61126 | 2011-09-20 18:22:39 +0000 | [diff] [blame] | 283 | xTaskHandle xTimerGetTimerDaemonTaskHandle( void )
|
Richard Barry | fc99c14 | 2011-07-27 14:02:37 +0000 | [diff] [blame] | 284 | {
|
Richard Barry | cc61126 | 2011-09-20 18:22:39 +0000 | [diff] [blame] | 285 | /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
|
Richard Barry | fc99c14 | 2011-07-27 14:02:37 +0000 | [diff] [blame] | 286 | started, then xTimerTaskHandle will be NULL. */
|
| 287 | configASSERT( ( xTimerTaskHandle != NULL ) );
|
| 288 | return xTimerTaskHandle;
|
| 289 | }
|
| 290 |
|
| 291 | #endif
|
| 292 | /*-----------------------------------------------------------*/
|
| 293 |
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 294 | static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 295 | {
|
| 296 | xTIMER *pxTimer;
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 297 | portBASE_TYPE xResult;
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 298 |
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 299 | /* 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 Barry | 0e62058 | 2011-04-01 18:45:44 +0000 | [diff] [blame] | 303 | traceTIMER_EXPIRED( pxTimer );
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 304 |
|
| 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 Barry | 37de268 | 2011-04-05 20:19:54 +0000 | [diff] [blame] | 307 | if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 308 | {
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 309 | /* 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 Barry | 8a9fb95 | 2011-02-21 09:38:33 +0000 | [diff] [blame] | 315 | if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
|
| 316 | {
|
| 317 | /* The timer expired before it was added to the active timer
|
Richard Barry | 8b5a004 | 2011-02-21 10:52:36 +0000 | [diff] [blame] | 318 | list. Reload it now. */
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 319 | xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
|
| 320 | configASSERT( xResult );
|
| 321 | ( void ) xResult;
|
Richard Barry | 8a9fb95 | 2011-02-21 09:38:33 +0000 | [diff] [blame] | 322 | }
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 323 | }
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 324 |
|
| 325 | /* Call the timer callback. */
|
| 326 | pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 327 | }
|
| 328 | /*-----------------------------------------------------------*/
|
| 329 |
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 330 | static void prvTimerTask( void *pvParameters )
|
| 331 | {
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 332 | portTickType xNextExpireTime;
|
| 333 | portBASE_TYPE xListWasEmpty;
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 334 |
|
| 335 | /* Just to avoid compiler warnings. */
|
| 336 | ( void ) pvParameters;
|
| 337 |
|
| 338 | for( ;; )
|
| 339 | {
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 340 | /* 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 Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 342 | xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 343 |
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 344 | /* 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 Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 350 | }
|
| 351 | }
|
| 352 | /*-----------------------------------------------------------*/
|
| 353 |
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 354 | static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
|
| 355 | {
|
| 356 | portTickType xTimeNow;
|
| 357 | portBASE_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 Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 372 | xTaskResumeAll();
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 373 | prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
|
| 374 | }
|
| 375 | else
|
| 376 | {
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 377 | /* 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 Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 380 | received - whichever comes first. The following line cannot
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 381 | be reached unless xNextExpireTime > xTimeNow, except in the
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 382 | case when the current timer list is empty. */
|
| 383 | vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 384 |
|
| 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 Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 393 | }
|
| 394 | }
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 395 | else
|
| 396 | {
|
| 397 | xTaskResumeAll();
|
| 398 | }
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 399 | }
|
| 400 | }
|
| 401 | /*-----------------------------------------------------------*/
|
| 402 |
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 403 | static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 404 | {
|
| 405 | portTickType 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 Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 412 | timer lists will be switched and the next expiry time can be
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 413 | 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 |
|
| 429 | static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
|
| 430 | {
|
| 431 | portTickType xTimeNow;
|
| 432 | static portTickType xLastTime = ( portTickType ) 0U;
|
| 433 |
|
| 434 | xTimeNow = xTaskGetTickCount();
|
| 435 |
|
| 436 | if( xTimeNow < xLastTime )
|
| 437 | {
|
Richard Barry | cb238fc | 2011-02-28 16:10:08 +0000 | [diff] [blame] | 438 | prvSwitchTimerLists( xLastTime );
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 439 | *pxTimerListsWereSwitched = pdTRUE;
|
| 440 | }
|
| 441 | else
|
| 442 | {
|
| 443 | *pxTimerListsWereSwitched = pdFALSE;
|
| 444 | }
|
| 445 |
|
| 446 | xLastTime = xTimeNow;
|
| 447 |
|
| 448 | return xTimeNow;
|
| 449 | }
|
| 450 | /*-----------------------------------------------------------*/
|
| 451 |
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 452 | static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 453 | {
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 454 | portBASE_TYPE xProcessTimerNow = pdFALSE;
|
| 455 |
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 456 | listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
|
| 457 | listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
| 458 |
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 459 | if( xNextExpiryTime <= xTimeNow )
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 460 | {
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 461 | /* Has the expiry time elapsed between the command to start/reset a
|
| 462 | timer was issued, and the time the command was processed? */
|
Richard Barry | 8a9fb95 | 2011-02-21 09:38:33 +0000 | [diff] [blame] | 463 | if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 464 | {
|
| 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 Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 473 | }
|
| 474 | else
|
| 475 | {
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 476 | 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 Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 487 | }
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 488 |
|
| 489 | return xProcessTimerNow;
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 490 | }
|
| 491 | /*-----------------------------------------------------------*/
|
| 492 |
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 493 | static void prvProcessReceivedCommands( void )
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 494 | {
|
| 495 | xTIMER_MESSAGE xMessage;
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 496 | xTIMER *pxTimer;
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 497 | portBASE_TYPE xTimerListsWereSwitched, xResult;
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 498 | portTickType 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 Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 503 |
|
| 504 | while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
|
| 505 | {
|
| 506 | pxTimer = xMessage.pxTimer;
|
| 507 |
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 508 | /* Is the timer already in a list of active timers? When the command
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 509 | 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 Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 512 | {
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 513 | if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
| 514 | {
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 515 | /* The timer is in a list, remove it. */
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 516 | vListRemove( &( pxTimer->xTimerListItem ) );
|
| 517 | }
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 518 | }
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 519 |
|
Richard Barry | 0e62058 | 2011-04-01 18:45:44 +0000 | [diff] [blame] | 520 | traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
|
| 521 |
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 522 | switch( xMessage.xMessageID )
|
| 523 | {
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 524 | case tmrCOMMAND_START :
|
| 525 | /* Start or restart a timer. */
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 526 | 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 Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 530 | pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
|
| 531 |
|
Richard Barry | 37de268 | 2011-04-05 20:19:54 +0000 | [diff] [blame] | 532 | if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 533 | {
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 534 | xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
|
| 535 | configASSERT( xResult );
|
| 536 | ( void ) xResult;
|
Richard Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 537 | }
|
| 538 | }
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 539 | break;
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 540 |
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 541 | 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 Barry | efc3ba9 | 2011-02-20 10:59:58 +0000 | [diff] [blame] | 548 | configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
|
| 549 | prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 550 | 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 Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 561 | }
|
| 562 | }
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 563 | }
|
| 564 | /*-----------------------------------------------------------*/
|
| 565 |
|
Richard Barry | cb238fc | 2011-02-28 16:10:08 +0000 | [diff] [blame] | 566 | static void prvSwitchTimerLists( portTickType xLastTime )
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 567 | {
|
Richard Barry | 0c95f33 | 2011-02-27 13:08:44 +0000 | [diff] [blame] | 568 | portTickType xNextExpireTime, xReloadTime;
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 569 | xList *pxTemp;
|
Richard Barry | 8b5a004 | 2011-02-21 10:52:36 +0000 | [diff] [blame] | 570 | xTIMER *pxTimer;
|
Richard Barry | 2c1a85c | 2011-02-22 20:43:17 +0000 | [diff] [blame] | 571 | portBASE_TYPE xResult;
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 572 |
|
Richard Barry | b4ff482 | 2011-02-14 10:51:18 +0000 | [diff] [blame] | 573 | /* 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 Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 579 | are switched. */
|
| 580 | while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
|
| 581 | {
|
| 582 | xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
|
Richard Barry | 8b5a004 | 2011-02-21 10:52:36 +0000 | [diff] [blame] | 583 |
|
| 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 Barry | 0c95f33 | 2011-02-27 13:08:44 +0000 | [diff] [blame] | 592 |
|
Richard Barry | 37de268 | 2011-04-05 20:19:54 +0000 | [diff] [blame] | 593 | if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
|
Richard Barry | 8b5a004 | 2011-02-21 10:52:36 +0000 | [diff] [blame] | 594 | {
|
Richard Barry | 0c95f33 | 2011-02-27 13:08:44 +0000 | [diff] [blame] | 595 | /* 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 Barry | 8b5a004 | 2011-02-21 10:52:36 +0000 | [diff] [blame] | 614 | }
|
Richard Barry | 3ba433e | 2011-02-11 16:17:37 +0000 | [diff] [blame] | 615 | }
|
| 616 |
|
| 617 | pxTemp = pxCurrentTimerList;
|
| 618 | pxCurrentTimerList = pxOverflowTimerList;
|
| 619 | pxOverflowTimerList = pxTemp;
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 620 | }
|
| 621 | /*-----------------------------------------------------------*/
|
| 622 |
|
| 623 | static void prvCheckForValidListAndQueue( void )
|
| 624 | {
|
| 625 | /* Check that the list from which active timers are referenced, and the
|
Richard Barry | 0552fc8 | 2011-02-10 17:20:36 +0000 | [diff] [blame] | 626 | queue used to communicate with the timer service, have been
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 627 | initialised. */
|
| 628 | taskENTER_CRITICAL();
|
| 629 | {
|
| 630 | if( xTimerQueue == NULL )
|
| 631 | {
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 632 | vListInitialise( &xActiveTimerList1 );
|
| 633 | vListInitialise( &xActiveTimerList2 );
|
| 634 | pxCurrentTimerList = &xActiveTimerList1;
|
| 635 | pxOverflowTimerList = &xActiveTimerList2;
|
Richard Barry | 37de268 | 2011-04-05 20:19:54 +0000 | [diff] [blame] | 636 | xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 637 | }
|
| 638 | }
|
| 639 | taskEXIT_CRITICAL();
|
| 640 | }
|
| 641 | /*-----------------------------------------------------------*/
|
| 642 |
|
Richard Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 643 | portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
|
| 644 | {
|
| 645 | portBASE_TYPE xTimerIsInActiveList;
|
| 646 | xTIMER *pxTimer = ( xTIMER * ) xTimer;
|
| 647 |
|
| 648 | /* Is the timer in the list of active timers? */
|
| 649 | taskENTER_CRITICAL();
|
| 650 | {
|
Richard Barry | 7ee534e | 2011-02-10 19:09:35 +0000 | [diff] [blame] | 651 | /* 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 Barry | 896d8c5 | 2011-02-09 10:46:45 +0000 | [diff] [blame] | 655 | }
|
| 656 | taskEXIT_CRITICAL();
|
| 657 |
|
| 658 | return xTimerIsInActiveList;
|
| 659 | }
|
| 660 | /*-----------------------------------------------------------*/
|
| 661 |
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 662 | void *pvTimerGetTimerID( xTimerHandle xTimer )
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 663 | {
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 664 | xTIMER *pxTimer = ( xTIMER * ) xTimer;
|
Richard Barry | 4d2adb7 | 2011-02-08 15:20:29 +0000 | [diff] [blame] | 665 |
|
Richard Barry | 4a5f152 | 2011-02-08 16:21:15 +0000 | [diff] [blame] | 666 | return pxTimer->pvTimerID;
|
| 667 | }
|
| 668 | /*-----------------------------------------------------------*/
|
| 669 |
|
Richard Barry | 8bd2d2f | 2011-03-31 14:09:21 +0000 | [diff] [blame] | 670 | /* This entire source file will be skipped if the application is not configured
|
| 671 | to include software timer functionality. If you want to include software timer
|
| 672 | functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
|
| 673 | #endif /* configUSE_TIMERS == 1 */
|