www.freertos.org

Dependents:   Nucleo freertos_test FreeRTOS_test freertos_bluetooth ... more

Committer:
rgrover1
Date:
Fri Jan 24 14:56:04 2014 +0000
Revision:
0:8e57f3e9cc89
Making FreeRTOS available as a library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 0:8e57f3e9cc89 1 /*
rgrover1 0:8e57f3e9cc89 2 FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
rgrover1 0:8e57f3e9cc89 3 All rights reserved
rgrover1 0:8e57f3e9cc89 4
rgrover1 0:8e57f3e9cc89 5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
rgrover1 0:8e57f3e9cc89 6
rgrover1 0:8e57f3e9cc89 7 ***************************************************************************
rgrover1 0:8e57f3e9cc89 8 * *
rgrover1 0:8e57f3e9cc89 9 * FreeRTOS provides completely free yet professionally developed, *
rgrover1 0:8e57f3e9cc89 10 * robust, strictly quality controlled, supported, and cross *
rgrover1 0:8e57f3e9cc89 11 * platform software that has become a de facto standard. *
rgrover1 0:8e57f3e9cc89 12 * *
rgrover1 0:8e57f3e9cc89 13 * Help yourself get started quickly and support the FreeRTOS *
rgrover1 0:8e57f3e9cc89 14 * project by purchasing a FreeRTOS tutorial book, reference *
rgrover1 0:8e57f3e9cc89 15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
rgrover1 0:8e57f3e9cc89 16 * *
rgrover1 0:8e57f3e9cc89 17 * Thank you! *
rgrover1 0:8e57f3e9cc89 18 * *
rgrover1 0:8e57f3e9cc89 19 ***************************************************************************
rgrover1 0:8e57f3e9cc89 20
rgrover1 0:8e57f3e9cc89 21 This file is part of the FreeRTOS distribution.
rgrover1 0:8e57f3e9cc89 22
rgrover1 0:8e57f3e9cc89 23 FreeRTOS is free software; you can redistribute it and/or modify it under
rgrover1 0:8e57f3e9cc89 24 the terms of the GNU General Public License (version 2) as published by the
rgrover1 0:8e57f3e9cc89 25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
rgrover1 0:8e57f3e9cc89 26
rgrover1 0:8e57f3e9cc89 27 >>! NOTE: The modification to the GPL is included to allow you to distribute
rgrover1 0:8e57f3e9cc89 28 >>! a combined work that includes FreeRTOS without being obliged to provide
rgrover1 0:8e57f3e9cc89 29 >>! the source code for proprietary components outside of the FreeRTOS
rgrover1 0:8e57f3e9cc89 30 >>! kernel.
rgrover1 0:8e57f3e9cc89 31
rgrover1 0:8e57f3e9cc89 32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
rgrover1 0:8e57f3e9cc89 33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
rgrover1 0:8e57f3e9cc89 34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
rgrover1 0:8e57f3e9cc89 35 link: http://www.freertos.org/a00114.html
rgrover1 0:8e57f3e9cc89 36
rgrover1 0:8e57f3e9cc89 37 1 tab == 4 spaces!
rgrover1 0:8e57f3e9cc89 38
rgrover1 0:8e57f3e9cc89 39 ***************************************************************************
rgrover1 0:8e57f3e9cc89 40 * *
rgrover1 0:8e57f3e9cc89 41 * Having a problem? Start by reading the FAQ "My application does *
rgrover1 0:8e57f3e9cc89 42 * not run, what could be wrong?" *
rgrover1 0:8e57f3e9cc89 43 * *
rgrover1 0:8e57f3e9cc89 44 * http://www.FreeRTOS.org/FAQHelp.html *
rgrover1 0:8e57f3e9cc89 45 * *
rgrover1 0:8e57f3e9cc89 46 ***************************************************************************
rgrover1 0:8e57f3e9cc89 47
rgrover1 0:8e57f3e9cc89 48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
rgrover1 0:8e57f3e9cc89 49 license and Real Time Engineers Ltd. contact details.
rgrover1 0:8e57f3e9cc89 50
rgrover1 0:8e57f3e9cc89 51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
rgrover1 0:8e57f3e9cc89 52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
rgrover1 0:8e57f3e9cc89 53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
rgrover1 0:8e57f3e9cc89 54
rgrover1 0:8e57f3e9cc89 55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
rgrover1 0:8e57f3e9cc89 56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
rgrover1 0:8e57f3e9cc89 57 licenses offer ticketed support, indemnification and middleware.
rgrover1 0:8e57f3e9cc89 58
rgrover1 0:8e57f3e9cc89 59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
rgrover1 0:8e57f3e9cc89 60 engineered and independently SIL3 certified version for use in safety and
rgrover1 0:8e57f3e9cc89 61 mission critical applications that require provable dependability.
rgrover1 0:8e57f3e9cc89 62
rgrover1 0:8e57f3e9cc89 63 1 tab == 4 spaces!
rgrover1 0:8e57f3e9cc89 64 */
rgrover1 0:8e57f3e9cc89 65
rgrover1 0:8e57f3e9cc89 66 /* Standard includes. */
rgrover1 0:8e57f3e9cc89 67 #include <stdlib.h>
rgrover1 0:8e57f3e9cc89 68
rgrover1 0:8e57f3e9cc89 69 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
rgrover1 0:8e57f3e9cc89 70 all the API functions to use the MPU wrappers. That should only be done when
rgrover1 0:8e57f3e9cc89 71 task.h is included from an application file. */
rgrover1 0:8e57f3e9cc89 72 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
rgrover1 0:8e57f3e9cc89 73
rgrover1 0:8e57f3e9cc89 74 #include "FreeRTOS.h"
rgrover1 0:8e57f3e9cc89 75 #include "task.h"
rgrover1 0:8e57f3e9cc89 76 #include "queue.h"
rgrover1 0:8e57f3e9cc89 77 #include "timers.h"
rgrover1 0:8e57f3e9cc89 78
rgrover1 0:8e57f3e9cc89 79 /* Lint e961 and e750 are suppressed as a MISRA exception justified because the
rgrover1 0:8e57f3e9cc89 80 MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
rgrover1 0:8e57f3e9cc89 81 header files above, but not in this file, in order to generate the correct
rgrover1 0:8e57f3e9cc89 82 privileged Vs unprivileged linkage and placement. */
rgrover1 0:8e57f3e9cc89 83 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
rgrover1 0:8e57f3e9cc89 84
rgrover1 0:8e57f3e9cc89 85
rgrover1 0:8e57f3e9cc89 86 /* This entire source file will be skipped if the application is not configured
rgrover1 0:8e57f3e9cc89 87 to include software timer functionality. This #if is closed at the very bottom
rgrover1 0:8e57f3e9cc89 88 of this file. If you want to include software timer functionality then ensure
rgrover1 0:8e57f3e9cc89 89 configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
rgrover1 0:8e57f3e9cc89 90 #if ( configUSE_TIMERS == 1 )
rgrover1 0:8e57f3e9cc89 91
rgrover1 0:8e57f3e9cc89 92 /* Misc definitions. */
rgrover1 0:8e57f3e9cc89 93 #define tmrNO_DELAY ( portTickType ) 0U
rgrover1 0:8e57f3e9cc89 94
rgrover1 0:8e57f3e9cc89 95 /* The definition of the timers themselves. */
rgrover1 0:8e57f3e9cc89 96 typedef struct tmrTimerControl
rgrover1 0:8e57f3e9cc89 97 {
rgrover1 0:8e57f3e9cc89 98 const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */
rgrover1 0:8e57f3e9cc89 99 xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
rgrover1 0:8e57f3e9cc89 100 portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
rgrover1 0:8e57f3e9cc89 101 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. */
rgrover1 0:8e57f3e9cc89 102 void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
rgrover1 0:8e57f3e9cc89 103 tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
rgrover1 0:8e57f3e9cc89 104 } xTIMER;
rgrover1 0:8e57f3e9cc89 105
rgrover1 0:8e57f3e9cc89 106 /* The definition of messages that can be sent and received on the timer
rgrover1 0:8e57f3e9cc89 107 queue. */
rgrover1 0:8e57f3e9cc89 108 typedef struct tmrTimerQueueMessage
rgrover1 0:8e57f3e9cc89 109 {
rgrover1 0:8e57f3e9cc89 110 portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
rgrover1 0:8e57f3e9cc89 111 portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
rgrover1 0:8e57f3e9cc89 112 xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
rgrover1 0:8e57f3e9cc89 113 } xTIMER_MESSAGE;
rgrover1 0:8e57f3e9cc89 114
rgrover1 0:8e57f3e9cc89 115 /*lint -e956 A manual analysis and inspection has been used to determine which
rgrover1 0:8e57f3e9cc89 116 static variables must be declared volatile. */
rgrover1 0:8e57f3e9cc89 117
rgrover1 0:8e57f3e9cc89 118 /* The list in which active timers are stored. Timers are referenced in expire
rgrover1 0:8e57f3e9cc89 119 time order, with the nearest expiry time at the front of the list. Only the
rgrover1 0:8e57f3e9cc89 120 timer service task is allowed to access xActiveTimerList. */
rgrover1 0:8e57f3e9cc89 121 PRIVILEGED_DATA static xList xActiveTimerList1;
rgrover1 0:8e57f3e9cc89 122 PRIVILEGED_DATA static xList xActiveTimerList2;
rgrover1 0:8e57f3e9cc89 123 PRIVILEGED_DATA static xList *pxCurrentTimerList;
rgrover1 0:8e57f3e9cc89 124 PRIVILEGED_DATA static xList *pxOverflowTimerList;
rgrover1 0:8e57f3e9cc89 125
rgrover1 0:8e57f3e9cc89 126 /* A queue that is used to send commands to the timer service task. */
rgrover1 0:8e57f3e9cc89 127 PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
rgrover1 0:8e57f3e9cc89 128
rgrover1 0:8e57f3e9cc89 129 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
rgrover1 0:8e57f3e9cc89 130
rgrover1 0:8e57f3e9cc89 131 PRIVILEGED_DATA static xTaskHandle xTimerTaskHandle = NULL;
rgrover1 0:8e57f3e9cc89 132
rgrover1 0:8e57f3e9cc89 133 #endif
rgrover1 0:8e57f3e9cc89 134
rgrover1 0:8e57f3e9cc89 135 /*lint +e956 */
rgrover1 0:8e57f3e9cc89 136
rgrover1 0:8e57f3e9cc89 137 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 138
rgrover1 0:8e57f3e9cc89 139 /*
rgrover1 0:8e57f3e9cc89 140 * Initialise the infrastructure used by the timer service task if it has not
rgrover1 0:8e57f3e9cc89 141 * been initialised already.
rgrover1 0:8e57f3e9cc89 142 */
rgrover1 0:8e57f3e9cc89 143 static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 144
rgrover1 0:8e57f3e9cc89 145 /*
rgrover1 0:8e57f3e9cc89 146 * The timer service task (daemon). Timer functionality is controlled by this
rgrover1 0:8e57f3e9cc89 147 * task. Other tasks communicate with the timer service task using the
rgrover1 0:8e57f3e9cc89 148 * xTimerQueue queue.
rgrover1 0:8e57f3e9cc89 149 */
rgrover1 0:8e57f3e9cc89 150 static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 151
rgrover1 0:8e57f3e9cc89 152 /*
rgrover1 0:8e57f3e9cc89 153 * Called by the timer service task to interpret and process a command it
rgrover1 0:8e57f3e9cc89 154 * received on the timer queue.
rgrover1 0:8e57f3e9cc89 155 */
rgrover1 0:8e57f3e9cc89 156 static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 157
rgrover1 0:8e57f3e9cc89 158 /*
rgrover1 0:8e57f3e9cc89 159 * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
rgrover1 0:8e57f3e9cc89 160 * depending on if the expire time causes a timer counter overflow.
rgrover1 0:8e57f3e9cc89 161 */
rgrover1 0:8e57f3e9cc89 162 static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 163
rgrover1 0:8e57f3e9cc89 164 /*
rgrover1 0:8e57f3e9cc89 165 * An active timer has reached its expire time. Reload the timer if it is an
rgrover1 0:8e57f3e9cc89 166 * auto reload timer, then call its callback.
rgrover1 0:8e57f3e9cc89 167 */
rgrover1 0:8e57f3e9cc89 168 static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 169
rgrover1 0:8e57f3e9cc89 170 /*
rgrover1 0:8e57f3e9cc89 171 * The tick count has overflowed. Switch the timer lists after ensuring the
rgrover1 0:8e57f3e9cc89 172 * current timer list does not still reference some timers.
rgrover1 0:8e57f3e9cc89 173 */
rgrover1 0:8e57f3e9cc89 174 static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 175
rgrover1 0:8e57f3e9cc89 176 /*
rgrover1 0:8e57f3e9cc89 177 * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
rgrover1 0:8e57f3e9cc89 178 * if a tick count overflow occurred since prvSampleTimeNow() was last called.
rgrover1 0:8e57f3e9cc89 179 */
rgrover1 0:8e57f3e9cc89 180 static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 181
rgrover1 0:8e57f3e9cc89 182 /*
rgrover1 0:8e57f3e9cc89 183 * If the timer list contains any active timers then return the expire time of
rgrover1 0:8e57f3e9cc89 184 * the timer that will expire first and set *pxListWasEmpty to false. If the
rgrover1 0:8e57f3e9cc89 185 * timer list does not contain any timers then return 0 and set *pxListWasEmpty
rgrover1 0:8e57f3e9cc89 186 * to pdTRUE.
rgrover1 0:8e57f3e9cc89 187 */
rgrover1 0:8e57f3e9cc89 188 static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 189
rgrover1 0:8e57f3e9cc89 190 /*
rgrover1 0:8e57f3e9cc89 191 * If a timer has expired, process it. Otherwise, block the timer service task
rgrover1 0:8e57f3e9cc89 192 * until either a timer does expire or a command is received.
rgrover1 0:8e57f3e9cc89 193 */
rgrover1 0:8e57f3e9cc89 194 static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
rgrover1 0:8e57f3e9cc89 195
rgrover1 0:8e57f3e9cc89 196 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 197
rgrover1 0:8e57f3e9cc89 198 portBASE_TYPE xTimerCreateTimerTask( void )
rgrover1 0:8e57f3e9cc89 199 {
rgrover1 0:8e57f3e9cc89 200 portBASE_TYPE xReturn = pdFAIL;
rgrover1 0:8e57f3e9cc89 201
rgrover1 0:8e57f3e9cc89 202 /* This function is called when the scheduler is started if
rgrover1 0:8e57f3e9cc89 203 configUSE_TIMERS is set to 1. Check that the infrastructure used by the
rgrover1 0:8e57f3e9cc89 204 timer service task has been created/initialised. If timers have already
rgrover1 0:8e57f3e9cc89 205 been created then the initialisation will already have been performed. */
rgrover1 0:8e57f3e9cc89 206 prvCheckForValidListAndQueue();
rgrover1 0:8e57f3e9cc89 207
rgrover1 0:8e57f3e9cc89 208 if( xTimerQueue != NULL )
rgrover1 0:8e57f3e9cc89 209 {
rgrover1 0:8e57f3e9cc89 210 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
rgrover1 0:8e57f3e9cc89 211 {
rgrover1 0:8e57f3e9cc89 212 /* Create the timer task, storing its handle in xTimerTaskHandle so
rgrover1 0:8e57f3e9cc89 213 it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
rgrover1 0:8e57f3e9cc89 214 xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
rgrover1 0:8e57f3e9cc89 215 }
rgrover1 0:8e57f3e9cc89 216 #else
rgrover1 0:8e57f3e9cc89 217 {
rgrover1 0:8e57f3e9cc89 218 /* Create the timer task without storing its handle. */
rgrover1 0:8e57f3e9cc89 219 xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL);
rgrover1 0:8e57f3e9cc89 220 }
rgrover1 0:8e57f3e9cc89 221 #endif
rgrover1 0:8e57f3e9cc89 222 }
rgrover1 0:8e57f3e9cc89 223
rgrover1 0:8e57f3e9cc89 224 configASSERT( xReturn );
rgrover1 0:8e57f3e9cc89 225 return xReturn;
rgrover1 0:8e57f3e9cc89 226 }
rgrover1 0:8e57f3e9cc89 227 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 228
rgrover1 0:8e57f3e9cc89 229 xTimerHandle xTimerCreate( const signed char * const pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
rgrover1 0:8e57f3e9cc89 230 {
rgrover1 0:8e57f3e9cc89 231 xTIMER *pxNewTimer;
rgrover1 0:8e57f3e9cc89 232
rgrover1 0:8e57f3e9cc89 233 /* Allocate the timer structure. */
rgrover1 0:8e57f3e9cc89 234 if( xTimerPeriodInTicks == ( portTickType ) 0U )
rgrover1 0:8e57f3e9cc89 235 {
rgrover1 0:8e57f3e9cc89 236 pxNewTimer = NULL;
rgrover1 0:8e57f3e9cc89 237 }
rgrover1 0:8e57f3e9cc89 238 else
rgrover1 0:8e57f3e9cc89 239 {
rgrover1 0:8e57f3e9cc89 240 pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
rgrover1 0:8e57f3e9cc89 241 if( pxNewTimer != NULL )
rgrover1 0:8e57f3e9cc89 242 {
rgrover1 0:8e57f3e9cc89 243 /* Ensure the infrastructure used by the timer service task has been
rgrover1 0:8e57f3e9cc89 244 created/initialised. */
rgrover1 0:8e57f3e9cc89 245 prvCheckForValidListAndQueue();
rgrover1 0:8e57f3e9cc89 246
rgrover1 0:8e57f3e9cc89 247 /* Initialise the timer structure members using the function parameters. */
rgrover1 0:8e57f3e9cc89 248 pxNewTimer->pcTimerName = pcTimerName;
rgrover1 0:8e57f3e9cc89 249 pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
rgrover1 0:8e57f3e9cc89 250 pxNewTimer->uxAutoReload = uxAutoReload;
rgrover1 0:8e57f3e9cc89 251 pxNewTimer->pvTimerID = pvTimerID;
rgrover1 0:8e57f3e9cc89 252 pxNewTimer->pxCallbackFunction = pxCallbackFunction;
rgrover1 0:8e57f3e9cc89 253 vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
rgrover1 0:8e57f3e9cc89 254
rgrover1 0:8e57f3e9cc89 255 traceTIMER_CREATE( pxNewTimer );
rgrover1 0:8e57f3e9cc89 256 }
rgrover1 0:8e57f3e9cc89 257 else
rgrover1 0:8e57f3e9cc89 258 {
rgrover1 0:8e57f3e9cc89 259 traceTIMER_CREATE_FAILED();
rgrover1 0:8e57f3e9cc89 260 }
rgrover1 0:8e57f3e9cc89 261 }
rgrover1 0:8e57f3e9cc89 262
rgrover1 0:8e57f3e9cc89 263 /* 0 is not a valid value for xTimerPeriodInTicks. */
rgrover1 0:8e57f3e9cc89 264 configASSERT( ( xTimerPeriodInTicks > 0 ) );
rgrover1 0:8e57f3e9cc89 265
rgrover1 0:8e57f3e9cc89 266 return ( xTimerHandle ) pxNewTimer;
rgrover1 0:8e57f3e9cc89 267 }
rgrover1 0:8e57f3e9cc89 268 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 269
rgrover1 0:8e57f3e9cc89 270 portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
rgrover1 0:8e57f3e9cc89 271 {
rgrover1 0:8e57f3e9cc89 272 portBASE_TYPE xReturn = pdFAIL;
rgrover1 0:8e57f3e9cc89 273 xTIMER_MESSAGE xMessage;
rgrover1 0:8e57f3e9cc89 274
rgrover1 0:8e57f3e9cc89 275 /* Send a message to the timer service task to perform a particular action
rgrover1 0:8e57f3e9cc89 276 on a particular timer definition. */
rgrover1 0:8e57f3e9cc89 277 if( xTimerQueue != NULL )
rgrover1 0:8e57f3e9cc89 278 {
rgrover1 0:8e57f3e9cc89 279 /* Send a command to the timer service task to start the xTimer timer. */
rgrover1 0:8e57f3e9cc89 280 xMessage.xMessageID = xCommandID;
rgrover1 0:8e57f3e9cc89 281 xMessage.xMessageValue = xOptionalValue;
rgrover1 0:8e57f3e9cc89 282 xMessage.pxTimer = ( xTIMER * ) xTimer;
rgrover1 0:8e57f3e9cc89 283
rgrover1 0:8e57f3e9cc89 284 if( pxHigherPriorityTaskWoken == NULL )
rgrover1 0:8e57f3e9cc89 285 {
rgrover1 0:8e57f3e9cc89 286 if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
rgrover1 0:8e57f3e9cc89 287 {
rgrover1 0:8e57f3e9cc89 288 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
rgrover1 0:8e57f3e9cc89 289 }
rgrover1 0:8e57f3e9cc89 290 else
rgrover1 0:8e57f3e9cc89 291 {
rgrover1 0:8e57f3e9cc89 292 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
rgrover1 0:8e57f3e9cc89 293 }
rgrover1 0:8e57f3e9cc89 294 }
rgrover1 0:8e57f3e9cc89 295 else
rgrover1 0:8e57f3e9cc89 296 {
rgrover1 0:8e57f3e9cc89 297 xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
rgrover1 0:8e57f3e9cc89 298 }
rgrover1 0:8e57f3e9cc89 299
rgrover1 0:8e57f3e9cc89 300 traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
rgrover1 0:8e57f3e9cc89 301 }
rgrover1 0:8e57f3e9cc89 302
rgrover1 0:8e57f3e9cc89 303 return xReturn;
rgrover1 0:8e57f3e9cc89 304 }
rgrover1 0:8e57f3e9cc89 305 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 306
rgrover1 0:8e57f3e9cc89 307 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
rgrover1 0:8e57f3e9cc89 308
rgrover1 0:8e57f3e9cc89 309 xTaskHandle xTimerGetTimerDaemonTaskHandle( void )
rgrover1 0:8e57f3e9cc89 310 {
rgrover1 0:8e57f3e9cc89 311 /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
rgrover1 0:8e57f3e9cc89 312 started, then xTimerTaskHandle will be NULL. */
rgrover1 0:8e57f3e9cc89 313 configASSERT( ( xTimerTaskHandle != NULL ) );
rgrover1 0:8e57f3e9cc89 314 return xTimerTaskHandle;
rgrover1 0:8e57f3e9cc89 315 }
rgrover1 0:8e57f3e9cc89 316
rgrover1 0:8e57f3e9cc89 317 #endif
rgrover1 0:8e57f3e9cc89 318 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 319
rgrover1 0:8e57f3e9cc89 320 static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
rgrover1 0:8e57f3e9cc89 321 {
rgrover1 0:8e57f3e9cc89 322 xTIMER *pxTimer;
rgrover1 0:8e57f3e9cc89 323 portBASE_TYPE xResult;
rgrover1 0:8e57f3e9cc89 324
rgrover1 0:8e57f3e9cc89 325 /* Remove the timer from the list of active timers. A check has already
rgrover1 0:8e57f3e9cc89 326 been performed to ensure the list is not empty. */
rgrover1 0:8e57f3e9cc89 327 pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
rgrover1 0:8e57f3e9cc89 328 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
rgrover1 0:8e57f3e9cc89 329 traceTIMER_EXPIRED( pxTimer );
rgrover1 0:8e57f3e9cc89 330
rgrover1 0:8e57f3e9cc89 331 /* If the timer is an auto reload timer then calculate the next
rgrover1 0:8e57f3e9cc89 332 expiry time and re-insert the timer in the list of active timers. */
rgrover1 0:8e57f3e9cc89 333 if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
rgrover1 0:8e57f3e9cc89 334 {
rgrover1 0:8e57f3e9cc89 335 /* This is the only time a timer is inserted into a list using
rgrover1 0:8e57f3e9cc89 336 a time relative to anything other than the current time. It
rgrover1 0:8e57f3e9cc89 337 will therefore be inserted into the correct list relative to
rgrover1 0:8e57f3e9cc89 338 the time this task thinks it is now, even if a command to
rgrover1 0:8e57f3e9cc89 339 switch lists due to a tick count overflow is already waiting in
rgrover1 0:8e57f3e9cc89 340 the timer queue. */
rgrover1 0:8e57f3e9cc89 341 if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
rgrover1 0:8e57f3e9cc89 342 {
rgrover1 0:8e57f3e9cc89 343 /* The timer expired before it was added to the active timer
rgrover1 0:8e57f3e9cc89 344 list. Reload it now. */
rgrover1 0:8e57f3e9cc89 345 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
rgrover1 0:8e57f3e9cc89 346 configASSERT( xResult );
rgrover1 0:8e57f3e9cc89 347 ( void ) xResult;
rgrover1 0:8e57f3e9cc89 348 }
rgrover1 0:8e57f3e9cc89 349 }
rgrover1 0:8e57f3e9cc89 350
rgrover1 0:8e57f3e9cc89 351 /* Call the timer callback. */
rgrover1 0:8e57f3e9cc89 352 pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
rgrover1 0:8e57f3e9cc89 353 }
rgrover1 0:8e57f3e9cc89 354 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 355
rgrover1 0:8e57f3e9cc89 356 static void prvTimerTask( void *pvParameters )
rgrover1 0:8e57f3e9cc89 357 {
rgrover1 0:8e57f3e9cc89 358 portTickType xNextExpireTime;
rgrover1 0:8e57f3e9cc89 359 portBASE_TYPE xListWasEmpty;
rgrover1 0:8e57f3e9cc89 360
rgrover1 0:8e57f3e9cc89 361 /* Just to avoid compiler warnings. */
rgrover1 0:8e57f3e9cc89 362 ( void ) pvParameters;
rgrover1 0:8e57f3e9cc89 363
rgrover1 0:8e57f3e9cc89 364 for( ;; )
rgrover1 0:8e57f3e9cc89 365 {
rgrover1 0:8e57f3e9cc89 366 /* Query the timers list to see if it contains any timers, and if so,
rgrover1 0:8e57f3e9cc89 367 obtain the time at which the next timer will expire. */
rgrover1 0:8e57f3e9cc89 368 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
rgrover1 0:8e57f3e9cc89 369
rgrover1 0:8e57f3e9cc89 370 /* If a timer has expired, process it. Otherwise, block this task
rgrover1 0:8e57f3e9cc89 371 until either a timer does expire, or a command is received. */
rgrover1 0:8e57f3e9cc89 372 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
rgrover1 0:8e57f3e9cc89 373
rgrover1 0:8e57f3e9cc89 374 /* Empty the command queue. */
rgrover1 0:8e57f3e9cc89 375 prvProcessReceivedCommands();
rgrover1 0:8e57f3e9cc89 376 }
rgrover1 0:8e57f3e9cc89 377 }
rgrover1 0:8e57f3e9cc89 378 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 379
rgrover1 0:8e57f3e9cc89 380 static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
rgrover1 0:8e57f3e9cc89 381 {
rgrover1 0:8e57f3e9cc89 382 portTickType xTimeNow;
rgrover1 0:8e57f3e9cc89 383 portBASE_TYPE xTimerListsWereSwitched;
rgrover1 0:8e57f3e9cc89 384
rgrover1 0:8e57f3e9cc89 385 vTaskSuspendAll();
rgrover1 0:8e57f3e9cc89 386 {
rgrover1 0:8e57f3e9cc89 387 /* Obtain the time now to make an assessment as to whether the timer
rgrover1 0:8e57f3e9cc89 388 has expired or not. If obtaining the time causes the lists to switch
rgrover1 0:8e57f3e9cc89 389 then don't process this timer as any timers that remained in the list
rgrover1 0:8e57f3e9cc89 390 when the lists were switched will have been processed within the
rgrover1 0:8e57f3e9cc89 391 prvSampelTimeNow() function. */
rgrover1 0:8e57f3e9cc89 392 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
rgrover1 0:8e57f3e9cc89 393 if( xTimerListsWereSwitched == pdFALSE )
rgrover1 0:8e57f3e9cc89 394 {
rgrover1 0:8e57f3e9cc89 395 /* The tick count has not overflowed, has the timer expired? */
rgrover1 0:8e57f3e9cc89 396 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
rgrover1 0:8e57f3e9cc89 397 {
rgrover1 0:8e57f3e9cc89 398 ( void ) xTaskResumeAll();
rgrover1 0:8e57f3e9cc89 399 prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
rgrover1 0:8e57f3e9cc89 400 }
rgrover1 0:8e57f3e9cc89 401 else
rgrover1 0:8e57f3e9cc89 402 {
rgrover1 0:8e57f3e9cc89 403 /* The tick count has not overflowed, and the next expire
rgrover1 0:8e57f3e9cc89 404 time has not been reached yet. This task should therefore
rgrover1 0:8e57f3e9cc89 405 block to wait for the next expire time or a command to be
rgrover1 0:8e57f3e9cc89 406 received - whichever comes first. The following line cannot
rgrover1 0:8e57f3e9cc89 407 be reached unless xNextExpireTime > xTimeNow, except in the
rgrover1 0:8e57f3e9cc89 408 case when the current timer list is empty. */
rgrover1 0:8e57f3e9cc89 409 vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
rgrover1 0:8e57f3e9cc89 410
rgrover1 0:8e57f3e9cc89 411 if( xTaskResumeAll() == pdFALSE )
rgrover1 0:8e57f3e9cc89 412 {
rgrover1 0:8e57f3e9cc89 413 /* Yield to wait for either a command to arrive, or the block time
rgrover1 0:8e57f3e9cc89 414 to expire. If a command arrived between the critical section being
rgrover1 0:8e57f3e9cc89 415 exited and this yield then the yield will not cause the task
rgrover1 0:8e57f3e9cc89 416 to block. */
rgrover1 0:8e57f3e9cc89 417 portYIELD_WITHIN_API();
rgrover1 0:8e57f3e9cc89 418 }
rgrover1 0:8e57f3e9cc89 419 }
rgrover1 0:8e57f3e9cc89 420 }
rgrover1 0:8e57f3e9cc89 421 else
rgrover1 0:8e57f3e9cc89 422 {
rgrover1 0:8e57f3e9cc89 423 ( void ) xTaskResumeAll();
rgrover1 0:8e57f3e9cc89 424 }
rgrover1 0:8e57f3e9cc89 425 }
rgrover1 0:8e57f3e9cc89 426 }
rgrover1 0:8e57f3e9cc89 427 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 428
rgrover1 0:8e57f3e9cc89 429 static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
rgrover1 0:8e57f3e9cc89 430 {
rgrover1 0:8e57f3e9cc89 431 portTickType xNextExpireTime;
rgrover1 0:8e57f3e9cc89 432
rgrover1 0:8e57f3e9cc89 433 /* Timers are listed in expiry time order, with the head of the list
rgrover1 0:8e57f3e9cc89 434 referencing the task that will expire first. Obtain the time at which
rgrover1 0:8e57f3e9cc89 435 the timer with the nearest expiry time will expire. If there are no
rgrover1 0:8e57f3e9cc89 436 active timers then just set the next expire time to 0. That will cause
rgrover1 0:8e57f3e9cc89 437 this task to unblock when the tick count overflows, at which point the
rgrover1 0:8e57f3e9cc89 438 timer lists will be switched and the next expiry time can be
rgrover1 0:8e57f3e9cc89 439 re-assessed. */
rgrover1 0:8e57f3e9cc89 440 *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
rgrover1 0:8e57f3e9cc89 441 if( *pxListWasEmpty == pdFALSE )
rgrover1 0:8e57f3e9cc89 442 {
rgrover1 0:8e57f3e9cc89 443 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
rgrover1 0:8e57f3e9cc89 444 }
rgrover1 0:8e57f3e9cc89 445 else
rgrover1 0:8e57f3e9cc89 446 {
rgrover1 0:8e57f3e9cc89 447 /* Ensure the task unblocks when the tick count rolls over. */
rgrover1 0:8e57f3e9cc89 448 xNextExpireTime = ( portTickType ) 0U;
rgrover1 0:8e57f3e9cc89 449 }
rgrover1 0:8e57f3e9cc89 450
rgrover1 0:8e57f3e9cc89 451 return xNextExpireTime;
rgrover1 0:8e57f3e9cc89 452 }
rgrover1 0:8e57f3e9cc89 453 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 454
rgrover1 0:8e57f3e9cc89 455 static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
rgrover1 0:8e57f3e9cc89 456 {
rgrover1 0:8e57f3e9cc89 457 portTickType xTimeNow;
rgrover1 0:8e57f3e9cc89 458 PRIVILEGED_DATA static portTickType xLastTime = ( portTickType ) 0U; /*lint !e956 Variable is only accessible to one task. */
rgrover1 0:8e57f3e9cc89 459
rgrover1 0:8e57f3e9cc89 460 xTimeNow = xTaskGetTickCount();
rgrover1 0:8e57f3e9cc89 461
rgrover1 0:8e57f3e9cc89 462 if( xTimeNow < xLastTime )
rgrover1 0:8e57f3e9cc89 463 {
rgrover1 0:8e57f3e9cc89 464 prvSwitchTimerLists( xLastTime );
rgrover1 0:8e57f3e9cc89 465 *pxTimerListsWereSwitched = pdTRUE;
rgrover1 0:8e57f3e9cc89 466 }
rgrover1 0:8e57f3e9cc89 467 else
rgrover1 0:8e57f3e9cc89 468 {
rgrover1 0:8e57f3e9cc89 469 *pxTimerListsWereSwitched = pdFALSE;
rgrover1 0:8e57f3e9cc89 470 }
rgrover1 0:8e57f3e9cc89 471
rgrover1 0:8e57f3e9cc89 472 xLastTime = xTimeNow;
rgrover1 0:8e57f3e9cc89 473
rgrover1 0:8e57f3e9cc89 474 return xTimeNow;
rgrover1 0:8e57f3e9cc89 475 }
rgrover1 0:8e57f3e9cc89 476 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 477
rgrover1 0:8e57f3e9cc89 478 static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
rgrover1 0:8e57f3e9cc89 479 {
rgrover1 0:8e57f3e9cc89 480 portBASE_TYPE xProcessTimerNow = pdFALSE;
rgrover1 0:8e57f3e9cc89 481
rgrover1 0:8e57f3e9cc89 482 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
rgrover1 0:8e57f3e9cc89 483 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
rgrover1 0:8e57f3e9cc89 484
rgrover1 0:8e57f3e9cc89 485 if( xNextExpiryTime <= xTimeNow )
rgrover1 0:8e57f3e9cc89 486 {
rgrover1 0:8e57f3e9cc89 487 /* Has the expiry time elapsed between the command to start/reset a
rgrover1 0:8e57f3e9cc89 488 timer was issued, and the time the command was processed? */
rgrover1 0:8e57f3e9cc89 489 if( ( xTimeNow - xCommandTime ) >= pxTimer->xTimerPeriodInTicks )
rgrover1 0:8e57f3e9cc89 490 {
rgrover1 0:8e57f3e9cc89 491 /* The time between a command being issued and the command being
rgrover1 0:8e57f3e9cc89 492 processed actually exceeds the timers period. */
rgrover1 0:8e57f3e9cc89 493 xProcessTimerNow = pdTRUE;
rgrover1 0:8e57f3e9cc89 494 }
rgrover1 0:8e57f3e9cc89 495 else
rgrover1 0:8e57f3e9cc89 496 {
rgrover1 0:8e57f3e9cc89 497 vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
rgrover1 0:8e57f3e9cc89 498 }
rgrover1 0:8e57f3e9cc89 499 }
rgrover1 0:8e57f3e9cc89 500 else
rgrover1 0:8e57f3e9cc89 501 {
rgrover1 0:8e57f3e9cc89 502 if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
rgrover1 0:8e57f3e9cc89 503 {
rgrover1 0:8e57f3e9cc89 504 /* If, since the command was issued, the tick count has overflowed
rgrover1 0:8e57f3e9cc89 505 but the expiry time has not, then the timer must have already passed
rgrover1 0:8e57f3e9cc89 506 its expiry time and should be processed immediately. */
rgrover1 0:8e57f3e9cc89 507 xProcessTimerNow = pdTRUE;
rgrover1 0:8e57f3e9cc89 508 }
rgrover1 0:8e57f3e9cc89 509 else
rgrover1 0:8e57f3e9cc89 510 {
rgrover1 0:8e57f3e9cc89 511 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
rgrover1 0:8e57f3e9cc89 512 }
rgrover1 0:8e57f3e9cc89 513 }
rgrover1 0:8e57f3e9cc89 514
rgrover1 0:8e57f3e9cc89 515 return xProcessTimerNow;
rgrover1 0:8e57f3e9cc89 516 }
rgrover1 0:8e57f3e9cc89 517 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 518
rgrover1 0:8e57f3e9cc89 519 static void prvProcessReceivedCommands( void )
rgrover1 0:8e57f3e9cc89 520 {
rgrover1 0:8e57f3e9cc89 521 xTIMER_MESSAGE xMessage;
rgrover1 0:8e57f3e9cc89 522 xTIMER *pxTimer;
rgrover1 0:8e57f3e9cc89 523 portBASE_TYPE xTimerListsWereSwitched, xResult;
rgrover1 0:8e57f3e9cc89 524 portTickType xTimeNow;
rgrover1 0:8e57f3e9cc89 525
rgrover1 0:8e57f3e9cc89 526 while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */
rgrover1 0:8e57f3e9cc89 527 {
rgrover1 0:8e57f3e9cc89 528 pxTimer = xMessage.pxTimer;
rgrover1 0:8e57f3e9cc89 529
rgrover1 0:8e57f3e9cc89 530 if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
rgrover1 0:8e57f3e9cc89 531 {
rgrover1 0:8e57f3e9cc89 532 /* The timer is in a list, remove it. */
rgrover1 0:8e57f3e9cc89 533 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
rgrover1 0:8e57f3e9cc89 534 }
rgrover1 0:8e57f3e9cc89 535
rgrover1 0:8e57f3e9cc89 536 traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
rgrover1 0:8e57f3e9cc89 537
rgrover1 0:8e57f3e9cc89 538 /* In this case the xTimerListsWereSwitched parameter is not used, but
rgrover1 0:8e57f3e9cc89 539 it must be present in the function call. prvSampleTimeNow() must be
rgrover1 0:8e57f3e9cc89 540 called after the message is received from xTimerQueue so there is no
rgrover1 0:8e57f3e9cc89 541 possibility of a higher priority task adding a message to the message
rgrover1 0:8e57f3e9cc89 542 queue with a time that is ahead of the timer daemon task (because it
rgrover1 0:8e57f3e9cc89 543 pre-empted the timer daemon task after the xTimeNow value was set). */
rgrover1 0:8e57f3e9cc89 544 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
rgrover1 0:8e57f3e9cc89 545
rgrover1 0:8e57f3e9cc89 546 switch( xMessage.xMessageID )
rgrover1 0:8e57f3e9cc89 547 {
rgrover1 0:8e57f3e9cc89 548 case tmrCOMMAND_START :
rgrover1 0:8e57f3e9cc89 549 /* Start or restart a timer. */
rgrover1 0:8e57f3e9cc89 550 if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )
rgrover1 0:8e57f3e9cc89 551 {
rgrover1 0:8e57f3e9cc89 552 /* The timer expired before it was added to the active timer
rgrover1 0:8e57f3e9cc89 553 list. Process it now. */
rgrover1 0:8e57f3e9cc89 554 pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
rgrover1 0:8e57f3e9cc89 555
rgrover1 0:8e57f3e9cc89 556 if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
rgrover1 0:8e57f3e9cc89 557 {
rgrover1 0:8e57f3e9cc89 558 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
rgrover1 0:8e57f3e9cc89 559 configASSERT( xResult );
rgrover1 0:8e57f3e9cc89 560 ( void ) xResult;
rgrover1 0:8e57f3e9cc89 561 }
rgrover1 0:8e57f3e9cc89 562 }
rgrover1 0:8e57f3e9cc89 563 break;
rgrover1 0:8e57f3e9cc89 564
rgrover1 0:8e57f3e9cc89 565 case tmrCOMMAND_STOP :
rgrover1 0:8e57f3e9cc89 566 /* The timer has already been removed from the active list.
rgrover1 0:8e57f3e9cc89 567 There is nothing to do here. */
rgrover1 0:8e57f3e9cc89 568 break;
rgrover1 0:8e57f3e9cc89 569
rgrover1 0:8e57f3e9cc89 570 case tmrCOMMAND_CHANGE_PERIOD :
rgrover1 0:8e57f3e9cc89 571 pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
rgrover1 0:8e57f3e9cc89 572 configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
rgrover1 0:8e57f3e9cc89 573
rgrover1 0:8e57f3e9cc89 574 /* The new period does not really have a reference, and can be
rgrover1 0:8e57f3e9cc89 575 longer or shorter than the old one. The command time is
rgrover1 0:8e57f3e9cc89 576 therefore set to the current time, and as the period cannot be
rgrover1 0:8e57f3e9cc89 577 zero the next expiry time can only be in the future, meaning
rgrover1 0:8e57f3e9cc89 578 (unlike for the xTimerStart() case above) there is no fail case
rgrover1 0:8e57f3e9cc89 579 that needs to be handled here. */
rgrover1 0:8e57f3e9cc89 580 ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
rgrover1 0:8e57f3e9cc89 581 break;
rgrover1 0:8e57f3e9cc89 582
rgrover1 0:8e57f3e9cc89 583 case tmrCOMMAND_DELETE :
rgrover1 0:8e57f3e9cc89 584 /* The timer has already been removed from the active list,
rgrover1 0:8e57f3e9cc89 585 just free up the memory. */
rgrover1 0:8e57f3e9cc89 586 vPortFree( pxTimer );
rgrover1 0:8e57f3e9cc89 587 break;
rgrover1 0:8e57f3e9cc89 588
rgrover1 0:8e57f3e9cc89 589 default :
rgrover1 0:8e57f3e9cc89 590 /* Don't expect to get here. */
rgrover1 0:8e57f3e9cc89 591 break;
rgrover1 0:8e57f3e9cc89 592 }
rgrover1 0:8e57f3e9cc89 593 }
rgrover1 0:8e57f3e9cc89 594 }
rgrover1 0:8e57f3e9cc89 595 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 596
rgrover1 0:8e57f3e9cc89 597 static void prvSwitchTimerLists( portTickType xLastTime )
rgrover1 0:8e57f3e9cc89 598 {
rgrover1 0:8e57f3e9cc89 599 portTickType xNextExpireTime, xReloadTime;
rgrover1 0:8e57f3e9cc89 600 xList *pxTemp;
rgrover1 0:8e57f3e9cc89 601 xTIMER *pxTimer;
rgrover1 0:8e57f3e9cc89 602 portBASE_TYPE xResult;
rgrover1 0:8e57f3e9cc89 603
rgrover1 0:8e57f3e9cc89 604 /* Remove compiler warnings if configASSERT() is not defined. */
rgrover1 0:8e57f3e9cc89 605 ( void ) xLastTime;
rgrover1 0:8e57f3e9cc89 606
rgrover1 0:8e57f3e9cc89 607 /* The tick count has overflowed. The timer lists must be switched.
rgrover1 0:8e57f3e9cc89 608 If there are any timers still referenced from the current timer list
rgrover1 0:8e57f3e9cc89 609 then they must have expired and should be processed before the lists
rgrover1 0:8e57f3e9cc89 610 are switched. */
rgrover1 0:8e57f3e9cc89 611 while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
rgrover1 0:8e57f3e9cc89 612 {
rgrover1 0:8e57f3e9cc89 613 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
rgrover1 0:8e57f3e9cc89 614
rgrover1 0:8e57f3e9cc89 615 /* Remove the timer from the list. */
rgrover1 0:8e57f3e9cc89 616 pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
rgrover1 0:8e57f3e9cc89 617 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
rgrover1 0:8e57f3e9cc89 618
rgrover1 0:8e57f3e9cc89 619 /* Execute its callback, then send a command to restart the timer if
rgrover1 0:8e57f3e9cc89 620 it is an auto-reload timer. It cannot be restarted here as the lists
rgrover1 0:8e57f3e9cc89 621 have not yet been switched. */
rgrover1 0:8e57f3e9cc89 622 pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
rgrover1 0:8e57f3e9cc89 623
rgrover1 0:8e57f3e9cc89 624 if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
rgrover1 0:8e57f3e9cc89 625 {
rgrover1 0:8e57f3e9cc89 626 /* Calculate the reload value, and if the reload value results in
rgrover1 0:8e57f3e9cc89 627 the timer going into the same timer list then it has already expired
rgrover1 0:8e57f3e9cc89 628 and the timer should be re-inserted into the current list so it is
rgrover1 0:8e57f3e9cc89 629 processed again within this loop. Otherwise a command should be sent
rgrover1 0:8e57f3e9cc89 630 to restart the timer to ensure it is only inserted into a list after
rgrover1 0:8e57f3e9cc89 631 the lists have been swapped. */
rgrover1 0:8e57f3e9cc89 632 xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
rgrover1 0:8e57f3e9cc89 633 if( xReloadTime > xNextExpireTime )
rgrover1 0:8e57f3e9cc89 634 {
rgrover1 0:8e57f3e9cc89 635 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
rgrover1 0:8e57f3e9cc89 636 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
rgrover1 0:8e57f3e9cc89 637 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
rgrover1 0:8e57f3e9cc89 638 }
rgrover1 0:8e57f3e9cc89 639 else
rgrover1 0:8e57f3e9cc89 640 {
rgrover1 0:8e57f3e9cc89 641 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
rgrover1 0:8e57f3e9cc89 642 configASSERT( xResult );
rgrover1 0:8e57f3e9cc89 643 ( void ) xResult;
rgrover1 0:8e57f3e9cc89 644 }
rgrover1 0:8e57f3e9cc89 645 }
rgrover1 0:8e57f3e9cc89 646 }
rgrover1 0:8e57f3e9cc89 647
rgrover1 0:8e57f3e9cc89 648 pxTemp = pxCurrentTimerList;
rgrover1 0:8e57f3e9cc89 649 pxCurrentTimerList = pxOverflowTimerList;
rgrover1 0:8e57f3e9cc89 650 pxOverflowTimerList = pxTemp;
rgrover1 0:8e57f3e9cc89 651 }
rgrover1 0:8e57f3e9cc89 652 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 653
rgrover1 0:8e57f3e9cc89 654 static void prvCheckForValidListAndQueue( void )
rgrover1 0:8e57f3e9cc89 655 {
rgrover1 0:8e57f3e9cc89 656 /* Check that the list from which active timers are referenced, and the
rgrover1 0:8e57f3e9cc89 657 queue used to communicate with the timer service, have been
rgrover1 0:8e57f3e9cc89 658 initialised. */
rgrover1 0:8e57f3e9cc89 659 taskENTER_CRITICAL();
rgrover1 0:8e57f3e9cc89 660 {
rgrover1 0:8e57f3e9cc89 661 if( xTimerQueue == NULL )
rgrover1 0:8e57f3e9cc89 662 {
rgrover1 0:8e57f3e9cc89 663 vListInitialise( &xActiveTimerList1 );
rgrover1 0:8e57f3e9cc89 664 vListInitialise( &xActiveTimerList2 );
rgrover1 0:8e57f3e9cc89 665 pxCurrentTimerList = &xActiveTimerList1;
rgrover1 0:8e57f3e9cc89 666 pxOverflowTimerList = &xActiveTimerList2;
rgrover1 0:8e57f3e9cc89 667 xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
rgrover1 0:8e57f3e9cc89 668 }
rgrover1 0:8e57f3e9cc89 669 }
rgrover1 0:8e57f3e9cc89 670 taskEXIT_CRITICAL();
rgrover1 0:8e57f3e9cc89 671 }
rgrover1 0:8e57f3e9cc89 672 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 673
rgrover1 0:8e57f3e9cc89 674 portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
rgrover1 0:8e57f3e9cc89 675 {
rgrover1 0:8e57f3e9cc89 676 portBASE_TYPE xTimerIsInActiveList;
rgrover1 0:8e57f3e9cc89 677 xTIMER *pxTimer = ( xTIMER * ) xTimer;
rgrover1 0:8e57f3e9cc89 678
rgrover1 0:8e57f3e9cc89 679 /* Is the timer in the list of active timers? */
rgrover1 0:8e57f3e9cc89 680 taskENTER_CRITICAL();
rgrover1 0:8e57f3e9cc89 681 {
rgrover1 0:8e57f3e9cc89 682 /* Checking to see if it is in the NULL list in effect checks to see if
rgrover1 0:8e57f3e9cc89 683 it is referenced from either the current or the overflow timer lists in
rgrover1 0:8e57f3e9cc89 684 one go, but the logic has to be reversed, hence the '!'. */
rgrover1 0:8e57f3e9cc89 685 xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
rgrover1 0:8e57f3e9cc89 686 }
rgrover1 0:8e57f3e9cc89 687 taskEXIT_CRITICAL();
rgrover1 0:8e57f3e9cc89 688
rgrover1 0:8e57f3e9cc89 689 return xTimerIsInActiveList;
rgrover1 0:8e57f3e9cc89 690 }
rgrover1 0:8e57f3e9cc89 691 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 692
rgrover1 0:8e57f3e9cc89 693 void *pvTimerGetTimerID( xTimerHandle xTimer )
rgrover1 0:8e57f3e9cc89 694 {
rgrover1 0:8e57f3e9cc89 695 xTIMER *pxTimer = ( xTIMER * ) xTimer;
rgrover1 0:8e57f3e9cc89 696
rgrover1 0:8e57f3e9cc89 697 return pxTimer->pvTimerID;
rgrover1 0:8e57f3e9cc89 698 }
rgrover1 0:8e57f3e9cc89 699 /*-----------------------------------------------------------*/
rgrover1 0:8e57f3e9cc89 700
rgrover1 0:8e57f3e9cc89 701 /* This entire source file will be skipped if the application is not configured
rgrover1 0:8e57f3e9cc89 702 to include software timer functionality. If you want to include software timer
rgrover1 0:8e57f3e9cc89 703 functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
rgrover1 0:8e57f3e9cc89 704 #endif /* configUSE_TIMERS == 1 */
rgrover1 0:8e57f3e9cc89 705
rgrover1 0:8e57f3e9cc89 706
rgrover1 0:8e57f3e9cc89 707