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.
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
Generated on Tue Jul 12 2022 22:22:38 by 1.7.2