Port of TI's CC3100 Websock camera demo. Using FreeRTOS, mbedTLS, also parts of Arducam for cams ov5642 and 0v2640. Can also use MT9D111. Work in progress. Be warned some parts maybe a bit flacky. This is for Seeed Arch max only, for an M3, see the demo for CM3 using the 0v5642 aducam mini.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers timers.c Source File

timers.c

00001 /*
00002     FreeRTOS V8.2.1 - Copyright (C) 2015 Real Time Engineers Ltd.
00003     All rights reserved
00004 
00005     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
00006 
00007     This file is part of the FreeRTOS distribution.
00008 
00009     FreeRTOS is free software; you can redistribute it and/or modify it under
00010     the terms of the GNU General Public License (version 2) as published by the
00011     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
00012 
00013     ***************************************************************************
00014     >>!   NOTE: The modification to the GPL is included to allow you to     !<<
00015     >>!   distribute a combined work that includes FreeRTOS without being   !<<
00016     >>!   obliged to provide the source code for proprietary components     !<<
00017     >>!   outside of the FreeRTOS kernel.                                   !<<
00018     ***************************************************************************
00019 
00020     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
00021     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00022     FOR A PARTICULAR PURPOSE.  Full license text is available on the following
00023     link: http://www.freertos.org/a00114.html
00024 
00025     ***************************************************************************
00026      *                                                                       *
00027      *    FreeRTOS provides completely free yet professionally developed,    *
00028      *    robust, strictly quality controlled, supported, and cross          *
00029      *    platform software that is more than just the market leader, it     *
00030      *    is the industry's de facto standard.                               *
00031      *                                                                       *
00032      *    Help yourself get started quickly while simultaneously helping     *
00033      *    to support the FreeRTOS project by purchasing a FreeRTOS           *
00034      *    tutorial book, reference manual, or both:                          *
00035      *    http://www.FreeRTOS.org/Documentation                              *
00036      *                                                                       *
00037     ***************************************************************************
00038 
00039     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
00040     the FAQ page "My application does not run, what could be wrong?".  Have you
00041     defined configASSERT()?
00042 
00043     http://www.FreeRTOS.org/support - In return for receiving this top quality
00044     embedded software for free we request you assist our global community by
00045     participating in the support forum.
00046 
00047     http://www.FreeRTOS.org/training - Investing in training allows your team to
00048     be as productive as possible as early as possible.  Now you can receive
00049     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
00050     Ltd, and the world's leading authority on the world's leading RTOS.
00051 
00052     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
00053     including FreeRTOS+Trace - an indispensable productivity tool, a DOS
00054     compatible FAT file system, and our tiny thread aware UDP/IP stack.
00055 
00056     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
00057     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
00058 
00059     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
00060     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
00061     licenses offer ticketed support, indemnification and commercial middleware.
00062 
00063     http://www.SafeRTOS.com - High Integrity Systems also provide a safety
00064     engineered and independently SIL3 certified version for use in safety and
00065     mission critical applications that require provable dependability.
00066 
00067     1 tab == 4 spaces!
00068 */
00069 
00070 /* Standard includes. */
00071 #include <stdlib.h>
00072 
00073 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
00074 all the API functions to use the MPU wrappers.  That should only be done when
00075 task.h is included from an application file. */
00076 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
00077 
00078 #include "FreeRTOS.h"
00079 #include "task.h"
00080 #include "queue.h"
00081 #include "timers.h"
00082 
00083 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 )
00084     #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available.
00085 #endif
00086 
00087 /* Lint e961 and e750 are suppressed as a MISRA exception justified because the
00088 MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
00089 header files above, but not in this file, in order to generate the correct
00090 privileged Vs unprivileged linkage and placement. */
00091 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
00092 
00093 
00094 /* This entire source file will be skipped if the application is not configured
00095 to include software timer functionality.  This #if is closed at the very bottom
00096 of this file.  If you want to include software timer functionality then ensure
00097 configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
00098 #if ( configUSE_TIMERS == 1 )
00099 
00100 /* Misc definitions. */
00101 #define tmrNO_DELAY     ( TickType_t ) 0U
00102 
00103 /* The definition of the timers themselves. */
00104 typedef struct tmrTimerControl
00105 {
00106     const char              *pcTimerName;       /*<< Text name.  This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
00107     ListItem_t              xTimerListItem;     /*<< Standard linked list item as used by all kernel features for event management. */
00108     TickType_t              xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
00109     UBaseType_t             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. */
00110     void                    *pvTimerID;         /*<< An ID to identify the timer.  This allows the timer to be identified when the same callback is used for multiple timers. */
00111     TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */
00112     #if( configUSE_TRACE_FACILITY == 1 )
00113         UBaseType_t         uxTimerNumber;      /*<< An ID assigned by trace tools such as FreeRTOS+Trace */
00114     #endif
00115 } xTIMER;
00116 
00117 /* The old xTIMER name is maintained above then typedefed to the new Timer_t
00118 name below to enable the use of older kernel aware debuggers. */
00119 typedef xTIMER Timer_t;
00120 
00121 /* The definition of messages that can be sent and received on the timer queue.
00122 Two types of message can be queued - messages that manipulate a software timer,
00123 and messages that request the execution of a non-timer related callback.  The
00124 two message types are defined in two separate structures, xTimerParametersType
00125 and xCallbackParametersType respectively. */
00126 typedef struct tmrTimerParameters
00127 {
00128     TickType_t          xMessageValue;      /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
00129     Timer_t *           pxTimer;            /*<< The timer to which the command will be applied. */
00130 } TimerParameter_t;
00131 
00132 
00133 typedef struct tmrCallbackParameters
00134 {
00135     PendedFunction_t    pxCallbackFunction; /* << The callback function to execute. */
00136     void *pvParameter1;                     /* << The value that will be used as the callback functions first parameter. */
00137     uint32_t ulParameter2;                  /* << The value that will be used as the callback functions second parameter. */
00138 } CallbackParameters_t;
00139 
00140 /* The structure that contains the two message types, along with an identifier
00141 that is used to determine which message type is valid. */
00142 typedef struct tmrTimerQueueMessage
00143 {
00144     BaseType_t          xMessageID;         /*<< The command being sent to the timer service task. */
00145     union
00146     {
00147         TimerParameter_t xTimerParameters;
00148 
00149         /* Don't include xCallbackParameters if it is not going to be used as
00150         it makes the structure (and therefore the timer queue) larger. */
00151         #if ( INCLUDE_xTimerPendFunctionCall == 1 )
00152             CallbackParameters_t xCallbackParameters;
00153         #endif /* INCLUDE_xTimerPendFunctionCall */
00154     } u;
00155 } DaemonTaskMessage_t;
00156 
00157 /*lint -e956 A manual analysis and inspection has been used to determine which
00158 static variables must be declared volatile. */
00159 
00160 /* The list in which active timers are stored.  Timers are referenced in expire
00161 time order, with the nearest expiry time at the front of the list.  Only the
00162 timer service task is allowed to access these lists. */
00163 PRIVILEGED_DATA static List_t xActiveTimerList1;
00164 PRIVILEGED_DATA static List_t xActiveTimerList2;
00165 PRIVILEGED_DATA static List_t *pxCurrentTimerList;
00166 PRIVILEGED_DATA static List_t *pxOverflowTimerList;
00167 
00168 /* A queue that is used to send commands to the timer service task. */
00169 PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
00170 
00171 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
00172 
00173     PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
00174 
00175 #endif
00176 
00177 /*lint +e956 */
00178 
00179 /*-----------------------------------------------------------*/
00180 
00181 /*
00182  * Initialise the infrastructure used by the timer service task if it has not
00183  * been initialised already.
00184  */
00185 static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
00186 
00187 /*
00188  * The timer service task (daemon).  Timer functionality is controlled by this
00189  * task.  Other tasks communicate with the timer service task using the
00190  * xTimerQueue queue.
00191  */
00192 static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
00193 
00194 /*
00195  * Called by the timer service task to interpret and process a command it
00196  * received on the timer queue.
00197  */
00198 static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
00199 
00200 /*
00201  * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
00202  * depending on if the expire time causes a timer counter overflow.
00203  */
00204 static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) PRIVILEGED_FUNCTION;
00205 
00206 /*
00207  * An active timer has reached its expire time.  Reload the timer if it is an
00208  * auto reload timer, then call its callback.
00209  */
00210 static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
00211 
00212 /*
00213  * The tick count has overflowed.  Switch the timer lists after ensuring the
00214  * current timer list does not still reference some timers.
00215  */
00216 static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION;
00217 
00218 /*
00219  * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
00220  * if a tick count overflow occurred since prvSampleTimeNow() was last called.
00221  */
00222 static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
00223 
00224 /*
00225  * If the timer list contains any active timers then return the expire time of
00226  * the timer that will expire first and set *pxListWasEmpty to false.  If the
00227  * timer list does not contain any timers then return 0 and set *pxListWasEmpty
00228  * to pdTRUE.
00229  */
00230 static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION;
00231 
00232 /*
00233  * If a timer has expired, process it.  Otherwise, block the timer service task
00234  * until either a timer does expire or a command is received.
00235  */
00236 static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, const BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION;
00237 
00238 /*-----------------------------------------------------------*/
00239 
00240 BaseType_t xTimerCreateTimerTask( void )
00241 {
00242 BaseType_t xReturn = pdFAIL;
00243 
00244     /* This function is called when the scheduler is started if
00245     configUSE_TIMERS is set to 1.  Check that the infrastructure used by the
00246     timer service task has been created/initialised.  If timers have already
00247     been created then the initialisation will already have been performed. */
00248     prvCheckForValidListAndQueue();
00249 
00250     if( xTimerQueue != NULL )
00251     {
00252         #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
00253         {
00254             /* Create the timer task, storing its handle in xTimerTaskHandle so
00255             it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
00256             xReturn = xTaskCreate( prvTimerTask, "Tmr Svc", ( uint16_t ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
00257         }
00258         #else
00259         {
00260             /* Create the timer task without storing its handle. */
00261             xReturn = xTaskCreate( prvTimerTask, "Tmr Svc", ( uint16_t ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL);
00262         }
00263         #endif
00264     }
00265     else
00266     {
00267         mtCOVERAGE_TEST_MARKER();
00268     }
00269 
00270     configASSERT( xReturn );
00271     return xReturn;
00272 }
00273 /*-----------------------------------------------------------*/
00274 
00275 TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
00276 {
00277 Timer_t *pxNewTimer;
00278 
00279     /* Allocate the timer structure. */
00280     if( xTimerPeriodInTicks == ( TickType_t ) 0U )
00281     {
00282         pxNewTimer = NULL;
00283     }
00284     else
00285     {
00286         pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
00287         if( pxNewTimer != NULL )
00288         {
00289             /* Ensure the infrastructure used by the timer service task has been
00290             created/initialised. */
00291             prvCheckForValidListAndQueue();
00292 
00293             /* Initialise the timer structure members using the function parameters. */
00294             pxNewTimer->pcTimerName = pcTimerName;
00295             pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
00296             pxNewTimer->uxAutoReload = uxAutoReload;
00297             pxNewTimer->pvTimerID = pvTimerID;
00298             pxNewTimer->pxCallbackFunction = pxCallbackFunction;
00299             vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
00300 
00301             traceTIMER_CREATE( pxNewTimer );
00302         }
00303         else
00304         {
00305             traceTIMER_CREATE_FAILED();
00306         }
00307     }
00308 
00309     /* 0 is not a valid value for xTimerPeriodInTicks. */
00310     configASSERT( ( xTimerPeriodInTicks > 0 ) );
00311 
00312     return ( TimerHandle_t ) pxNewTimer;
00313 }
00314 /*-----------------------------------------------------------*/
00315 
00316 BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait )
00317 {
00318 BaseType_t xReturn = pdFAIL;
00319 DaemonTaskMessage_t xMessage;
00320 
00321     /* Send a message to the timer service task to perform a particular action
00322     on a particular timer definition. */
00323     if( xTimerQueue != NULL )
00324     {
00325         /* Send a command to the timer service task to start the xTimer timer. */
00326         xMessage.xMessageID = xCommandID;
00327         xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
00328         xMessage.u.xTimerParameters.pxTimer = ( Timer_t * ) xTimer;
00329 
00330         if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
00331         {
00332             if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
00333             {
00334                 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
00335             }
00336             else
00337             {
00338                 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
00339             }
00340         }
00341         else
00342         {
00343             xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
00344         }
00345 
00346         traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
00347     }
00348     else
00349     {
00350         mtCOVERAGE_TEST_MARKER();
00351     }
00352 
00353     return xReturn;
00354 }
00355 /*-----------------------------------------------------------*/
00356 
00357 #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
00358 
00359     TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )
00360     {
00361         /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
00362         started, then xTimerTaskHandle will be NULL. */
00363         configASSERT( ( xTimerTaskHandle != NULL ) );
00364         return xTimerTaskHandle;
00365     }
00366 
00367 #endif
00368 /*-----------------------------------------------------------*/
00369 
00370 const char * pcTimerGetTimerName( TimerHandle_t xTimer )
00371 {
00372 Timer_t *pxTimer = ( Timer_t * ) xTimer;
00373 
00374     return pxTimer->pcTimerName;
00375 }
00376 /*-----------------------------------------------------------*/
00377 
00378 static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow )
00379 {
00380 BaseType_t xResult;
00381 Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
00382 
00383     /* Remove the timer from the list of active timers.  A check has already
00384     been performed to ensure the list is not empty. */
00385     ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
00386     traceTIMER_EXPIRED( pxTimer );
00387 
00388     /* If the timer is an auto reload timer then calculate the next
00389     expiry time and re-insert the timer in the list of active timers. */
00390     if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
00391     {
00392         /* The timer is inserted into a list using a time relative to anything
00393         other than the current time.  It will therefore be inserted into the
00394         correct list relative to the time this task thinks it is now. */
00395         if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
00396         {
00397             /* The timer expired before it was added to the active timer
00398             list.  Reload it now.  */
00399             xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
00400             configASSERT( xResult );
00401             ( void ) xResult;
00402         }
00403         else
00404         {
00405             mtCOVERAGE_TEST_MARKER();
00406         }
00407     }
00408     else
00409     {
00410         mtCOVERAGE_TEST_MARKER();
00411     }
00412 
00413     /* Call the timer callback. */
00414     pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
00415 }
00416 /*-----------------------------------------------------------*/
00417 
00418 static void prvTimerTask( void *pvParameters )
00419 {
00420 TickType_t xNextExpireTime;
00421 BaseType_t xListWasEmpty;
00422 
00423     /* Just to avoid compiler warnings. */
00424     ( void ) pvParameters;
00425 
00426     for( ;; )
00427     {
00428         /* Query the timers list to see if it contains any timers, and if so,
00429         obtain the time at which the next timer will expire. */
00430         xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
00431 
00432         /* If a timer has expired, process it.  Otherwise, block this task
00433         until either a timer does expire, or a command is received. */
00434         prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
00435 
00436         /* Empty the command queue. */
00437         prvProcessReceivedCommands();
00438     }
00439 }
00440 /*-----------------------------------------------------------*/
00441 
00442 static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, const BaseType_t xListWasEmpty )
00443 {
00444 TickType_t xTimeNow;
00445 BaseType_t xTimerListsWereSwitched;
00446 
00447     vTaskSuspendAll();
00448     {
00449         /* Obtain the time now to make an assessment as to whether the timer
00450         has expired or not.  If obtaining the time causes the lists to switch
00451         then don't process this timer as any timers that remained in the list
00452         when the lists were switched will have been processed within the
00453         prvSampleTimeNow() function. */
00454         xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
00455         if( xTimerListsWereSwitched == pdFALSE )
00456         {
00457             /* The tick count has not overflowed, has the timer expired? */
00458             if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
00459             {
00460                 ( void ) xTaskResumeAll();
00461                 prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
00462             }
00463             else
00464             {
00465                 /* The tick count has not overflowed, and the next expire
00466                 time has not been reached yet.  This task should therefore
00467                 block to wait for the next expire time or a command to be
00468                 received - whichever comes first.  The following line cannot
00469                 be reached unless xNextExpireTime > xTimeNow, except in the
00470                 case when the current timer list is empty. */
00471                 vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
00472 
00473                 if( xTaskResumeAll() == pdFALSE )
00474                 {
00475                     /* Yield to wait for either a command to arrive, or the
00476                     block time to expire.  If a command arrived between the
00477                     critical section being exited and this yield then the yield
00478                     will not cause the task to block. */
00479                     portYIELD_WITHIN_API();
00480                 }
00481                 else
00482                 {
00483                     mtCOVERAGE_TEST_MARKER();
00484                 }
00485             }
00486         }
00487         else
00488         {
00489             ( void ) xTaskResumeAll();
00490         }
00491     }
00492 }
00493 /*-----------------------------------------------------------*/
00494 
00495 static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )
00496 {
00497 TickType_t xNextExpireTime;
00498 
00499     /* Timers are listed in expiry time order, with the head of the list
00500     referencing the task that will expire first.  Obtain the time at which
00501     the timer with the nearest expiry time will expire.  If there are no
00502     active timers then just set the next expire time to 0.  That will cause
00503     this task to unblock when the tick count overflows, at which point the
00504     timer lists will be switched and the next expiry time can be
00505     re-assessed.  */
00506     *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
00507     if( *pxListWasEmpty == pdFALSE )
00508     {
00509         xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
00510     }
00511     else
00512     {
00513         /* Ensure the task unblocks when the tick count rolls over. */
00514         xNextExpireTime = ( TickType_t ) 0U;
00515     }
00516 
00517     return xNextExpireTime;
00518 }
00519 /*-----------------------------------------------------------*/
00520 
00521 static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
00522 {
00523 TickType_t xTimeNow;
00524 PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */
00525 
00526     xTimeNow = xTaskGetTickCount();
00527 
00528     if( xTimeNow < xLastTime )
00529     {
00530         prvSwitchTimerLists();
00531         *pxTimerListsWereSwitched = pdTRUE;
00532     }
00533     else
00534     {
00535         *pxTimerListsWereSwitched = pdFALSE;
00536     }
00537 
00538     xLastTime = xTimeNow;
00539 
00540     return xTimeNow;
00541 }
00542 /*-----------------------------------------------------------*/
00543 
00544 static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime )
00545 {
00546 BaseType_t xProcessTimerNow = pdFALSE;
00547 
00548     listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
00549     listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
00550 
00551     if( xNextExpiryTime <= xTimeNow )
00552     {
00553         /* Has the expiry time elapsed between the command to start/reset a
00554         timer was issued, and the time the command was processed? */
00555         if( ( xTimeNow - xCommandTime ) >= pxTimer->xTimerPeriodInTicks )
00556         {
00557             /* The time between a command being issued and the command being
00558             processed actually exceeds the timers period.  */
00559             xProcessTimerNow = pdTRUE;
00560         }
00561         else
00562         {
00563             vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
00564         }
00565     }
00566     else
00567     {
00568         if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
00569         {
00570             /* If, since the command was issued, the tick count has overflowed
00571             but the expiry time has not, then the timer must have already passed
00572             its expiry time and should be processed immediately. */
00573             xProcessTimerNow = pdTRUE;
00574         }
00575         else
00576         {
00577             vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
00578         }
00579     }
00580 
00581     return xProcessTimerNow;
00582 }
00583 /*-----------------------------------------------------------*/
00584 
00585 static void prvProcessReceivedCommands( void )
00586 {
00587 DaemonTaskMessage_t xMessage;
00588 Timer_t *pxTimer;
00589 BaseType_t xTimerListsWereSwitched, xResult;
00590 TickType_t xTimeNow;
00591 
00592     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. */
00593     {
00594         #if ( INCLUDE_xTimerPendFunctionCall == 1 )
00595         {
00596             /* Negative commands are pended function calls rather than timer
00597             commands. */
00598             if( xMessage.xMessageID < ( BaseType_t ) 0 )
00599             {
00600                 const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters );
00601 
00602                 /* The timer uses the xCallbackParameters member to request a
00603                 callback be executed.  Check the callback is not NULL. */
00604                 configASSERT( pxCallback );
00605 
00606                 /* Call the function. */
00607                 pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 );
00608             }
00609             else
00610             {
00611                 mtCOVERAGE_TEST_MARKER();
00612             }
00613         }
00614         #endif /* INCLUDE_xTimerPendFunctionCall */
00615 
00616         /* Commands that are positive are timer commands rather than pended
00617         function calls. */
00618         if( xMessage.xMessageID >= ( BaseType_t ) 0 )
00619         {
00620             /* The messages uses the xTimerParameters member to work on a
00621             software timer. */
00622             pxTimer = xMessage.u.xTimerParameters.pxTimer;
00623 
00624             if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
00625             {
00626                 /* The timer is in a list, remove it. */
00627                 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
00628             }
00629             else
00630             {
00631                 mtCOVERAGE_TEST_MARKER();
00632             }
00633 
00634             traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
00635 
00636             /* In this case the xTimerListsWereSwitched parameter is not used, but
00637             it must be present in the function call.  prvSampleTimeNow() must be
00638             called after the message is received from xTimerQueue so there is no
00639             possibility of a higher priority task adding a message to the message
00640             queue with a time that is ahead of the timer daemon task (because it
00641             pre-empted the timer daemon task after the xTimeNow value was set). */
00642             xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
00643 
00644             switch( xMessage.xMessageID )
00645             {
00646                 case tmrCOMMAND_START :
00647                 case tmrCOMMAND_START_FROM_ISR :
00648                 case tmrCOMMAND_RESET :
00649                 case tmrCOMMAND_RESET_FROM_ISR :
00650                 case tmrCOMMAND_START_DONT_TRACE :
00651                     /* Start or restart a timer. */
00652                     if( prvInsertTimerInActiveList( pxTimer,  xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) == pdTRUE )
00653                     {
00654                         /* The timer expired before it was added to the active
00655                         timer list.  Process it now. */
00656                         pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
00657                         traceTIMER_EXPIRED( pxTimer );
00658 
00659                         if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
00660                         {
00661                             xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
00662                             configASSERT( xResult );
00663                             ( void ) xResult;
00664                         }
00665                         else
00666                         {
00667                             mtCOVERAGE_TEST_MARKER();
00668                         }
00669                     }
00670                     else
00671                     {
00672                         mtCOVERAGE_TEST_MARKER();
00673                     }
00674                     break;
00675 
00676                 case tmrCOMMAND_STOP :
00677                 case tmrCOMMAND_STOP_FROM_ISR :
00678                     /* The timer has already been removed from the active list.
00679                     There is nothing to do here. */
00680                     break;
00681 
00682                 case tmrCOMMAND_CHANGE_PERIOD :
00683                 case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR :
00684                     pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
00685                     configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
00686 
00687                     /* The new period does not really have a reference, and can be
00688                     longer or shorter than the old one.  The command time is
00689                     therefore set to the current time, and as the period cannot be
00690                     zero the next expiry time can only be in the future, meaning
00691                     (unlike for the xTimerStart() case above) there is no fail case
00692                     that needs to be handled here. */
00693                     ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
00694                     break;
00695 
00696                 case tmrCOMMAND_DELETE :
00697                     /* The timer has already been removed from the active list,
00698                     just free up the memory. */
00699                     vPortFree( pxTimer );
00700                     break;
00701 
00702                 default :
00703                     /* Don't expect to get here. */
00704                     break;
00705             }
00706         }
00707     }
00708 }
00709 /*-----------------------------------------------------------*/
00710 
00711 static void prvSwitchTimerLists( void )
00712 {
00713 TickType_t xNextExpireTime, xReloadTime;
00714 List_t *pxTemp;
00715 Timer_t *pxTimer;
00716 BaseType_t xResult;
00717 
00718     /* The tick count has overflowed.  The timer lists must be switched.
00719     If there are any timers still referenced from the current timer list
00720     then they must have expired and should be processed before the lists
00721     are switched. */
00722     while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
00723     {
00724         xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
00725 
00726         /* Remove the timer from the list. */
00727         pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
00728         ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
00729         traceTIMER_EXPIRED( pxTimer );
00730 
00731         /* Execute its callback, then send a command to restart the timer if
00732         it is an auto-reload timer.  It cannot be restarted here as the lists
00733         have not yet been switched. */
00734         pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
00735 
00736         if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
00737         {
00738             /* Calculate the reload value, and if the reload value results in
00739             the timer going into the same timer list then it has already expired
00740             and the timer should be re-inserted into the current list so it is
00741             processed again within this loop.  Otherwise a command should be sent
00742             to restart the timer to ensure it is only inserted into a list after
00743             the lists have been swapped. */
00744             xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
00745             if( xReloadTime > xNextExpireTime )
00746             {
00747                 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
00748                 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
00749                 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
00750             }
00751             else
00752             {
00753                 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
00754                 configASSERT( xResult );
00755                 ( void ) xResult;
00756             }
00757         }
00758         else
00759         {
00760             mtCOVERAGE_TEST_MARKER();
00761         }
00762     }
00763 
00764     pxTemp = pxCurrentTimerList;
00765     pxCurrentTimerList = pxOverflowTimerList;
00766     pxOverflowTimerList = pxTemp;
00767 }
00768 /*-----------------------------------------------------------*/
00769 
00770 static void prvCheckForValidListAndQueue( void )
00771 {
00772     /* Check that the list from which active timers are referenced, and the
00773     queue used to communicate with the timer service, have been
00774     initialised. */
00775     taskENTER_CRITICAL();
00776     {
00777         if( xTimerQueue == NULL )
00778         {
00779             vListInitialise( &xActiveTimerList1 );
00780             vListInitialise( &xActiveTimerList2 );
00781             pxCurrentTimerList = &xActiveTimerList1;
00782             pxOverflowTimerList = &xActiveTimerList2;
00783             xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );
00784             configASSERT( xTimerQueue );
00785 
00786             #if ( configQUEUE_REGISTRY_SIZE > 0 )
00787             {
00788                 if( xTimerQueue != NULL )
00789                 {
00790                     vQueueAddToRegistry( xTimerQueue, "TmrQ" );
00791                 }
00792                 else
00793                 {
00794                     mtCOVERAGE_TEST_MARKER();
00795                 }
00796             }
00797             #endif /* configQUEUE_REGISTRY_SIZE */
00798         }
00799         else
00800         {
00801             mtCOVERAGE_TEST_MARKER();
00802         }
00803     }
00804     taskEXIT_CRITICAL();
00805 }
00806 /*-----------------------------------------------------------*/
00807 
00808 BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
00809 {
00810 BaseType_t xTimerIsInActiveList;
00811 Timer_t *pxTimer = ( Timer_t * ) xTimer;
00812 
00813     /* Is the timer in the list of active timers? */
00814     taskENTER_CRITICAL();
00815     {
00816         /* Checking to see if it is in the NULL list in effect checks to see if
00817         it is referenced from either the current or the overflow timer lists in
00818         one go, but the logic has to be reversed, hence the '!'. */
00819         xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
00820     }
00821     taskEXIT_CRITICAL();
00822 
00823     return xTimerIsInActiveList;
00824 } /*lint !e818 Can't be pointer to const due to the typedef. */
00825 /*-----------------------------------------------------------*/
00826 
00827 void *pvTimerGetTimerID( const TimerHandle_t xTimer )
00828 {
00829 Timer_t * const pxTimer = ( Timer_t * ) xTimer;
00830 void *pvReturn;
00831 
00832     configASSERT( xTimer );
00833 
00834     taskENTER_CRITICAL();
00835     {
00836         pvReturn = pxTimer->pvTimerID;
00837     }
00838     taskEXIT_CRITICAL();
00839 
00840     return pvReturn;
00841 }
00842 /*-----------------------------------------------------------*/
00843 
00844 void vTimerSetTimerID( const TimerHandle_t xTimer, void *pvNewID )
00845 {
00846 Timer_t * const pxTimer = ( Timer_t * ) xTimer;
00847 
00848     configASSERT( xTimer );
00849 
00850     taskENTER_CRITICAL();
00851     {
00852         pxTimer->pvTimerID = pvNewID;
00853     }
00854     taskEXIT_CRITICAL();
00855 }
00856 /*-----------------------------------------------------------*/
00857 
00858 #if( INCLUDE_xTimerPendFunctionCall == 1 )
00859 
00860     BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken )
00861     {
00862     DaemonTaskMessage_t xMessage;
00863     BaseType_t xReturn;
00864 
00865         /* Complete the message with the function parameters and post it to the
00866         daemon task. */
00867         xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
00868         xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
00869         xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
00870         xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
00871 
00872         xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
00873 
00874         tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
00875 
00876         return xReturn;
00877     }
00878 
00879 #endif /* INCLUDE_xTimerPendFunctionCall */
00880 /*-----------------------------------------------------------*/
00881 
00882 #if( INCLUDE_xTimerPendFunctionCall == 1 )
00883 
00884     BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait )
00885     {
00886     DaemonTaskMessage_t xMessage;
00887     BaseType_t xReturn;
00888 
00889         /* This function can only be called after a timer has been created or
00890         after the scheduler has been started because, until then, the timer
00891         queue does not exist. */
00892         configASSERT( xTimerQueue );
00893 
00894         /* Complete the message with the function parameters and post it to the
00895         daemon task. */
00896         xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
00897         xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
00898         xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
00899         xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
00900 
00901         xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
00902 
00903         tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn );
00904 
00905         return xReturn;
00906     }
00907 
00908 #endif /* INCLUDE_xTimerPendFunctionCall */
00909 /*-----------------------------------------------------------*/
00910 
00911 /* This entire source file will be skipped if the application is not configured
00912 to include software timer functionality.  If you want to include software timer
00913 functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
00914 #endif /* configUSE_TIMERS == 1 */
00915 
00916 
00917 
00918