1 /* 2 * FreeRTOS Kernel V10.4.3 3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 * this software and associated documentation files (the "Software"), to deal in 7 * the Software without restriction, including without limitation the rights to 8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 * the Software, and to permit persons to whom the Software is furnished to do so, 10 * subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in all 13 * copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * https://www.FreeRTOS.org 23 * https://github.com/FreeRTOS 24 * 25 */ 26 27 /* Standard includes. */ 28 #include <stdlib.h> 29 30 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining 31 * all the API functions to use the MPU wrappers. That should only be done when 32 * task.h is included from an application file. */ 33 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE 34 35 #include "FreeRTOS.h" 36 #include "task.h" 37 #include "queue.h" 38 #include "timers.h" 39 40 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 0 ) 41 #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available. 42 #endif 43 44 #ifdef ESP_PLATFORM 45 #define taskCRITICAL_MUX &xTimerMux 46 #undef taskENTER_CRITICAL 47 #undef taskEXIT_CRITICAL 48 #undef taskENTER_CRITICAL_ISR 49 #undef taskEXIT_CRITICAL_ISR 50 #define taskENTER_CRITICAL( ) portENTER_CRITICAL( taskCRITICAL_MUX ) 51 #define taskEXIT_CRITICAL( ) portEXIT_CRITICAL( taskCRITICAL_MUX ) 52 #define taskENTER_CRITICAL_ISR( ) portENTER_CRITICAL_ISR( taskCRITICAL_MUX ) 53 #define taskEXIT_CRITICAL_ISR( ) portEXIT_CRITICAL_ISR( taskCRITICAL_MUX ) 54 #endif 55 56 /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified 57 * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined 58 * for the header files above, but not in this file, in order to generate the 59 * correct privileged Vs unprivileged linkage and placement. */ 60 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */ 61 62 63 /* This entire source file will be skipped if the application is not configured 64 * to include software timer functionality. This #if is closed at the very bottom 65 * of this file. If you want to include software timer functionality then ensure 66 * configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ 67 #if ( configUSE_TIMERS == 1 ) 68 69 /* Misc definitions. */ 70 #define tmrNO_DELAY ( TickType_t ) 0U 71 72 /* The name assigned to the timer service task. This can be overridden by 73 * defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */ 74 #ifndef configTIMER_SERVICE_TASK_NAME 75 #define configTIMER_SERVICE_TASK_NAME "Tmr Svc" 76 #endif 77 78 /* Bit definitions used in the ucStatus member of a timer structure. */ 79 #define tmrSTATUS_IS_ACTIVE ( ( uint8_t ) 0x01 ) 80 #define tmrSTATUS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 0x02 ) 81 #define tmrSTATUS_IS_AUTORELOAD ( ( uint8_t ) 0x04 ) 82 83 /* The definition of the timers themselves. */ 84 typedef struct tmrTimerControl /* The old naming convention is used to prevent breaking kernel aware debuggers. */ 85 { 86 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. */ 87 ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */ 88 TickType_t xTimerPeriodInTicks; /*<< How quickly and often the timer expires. */ 89 void * pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */ 90 TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */ 91 #if ( configUSE_TRACE_FACILITY == 1 ) 92 UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */ 93 #endif 94 uint8_t ucStatus; /*<< Holds bits to say if the timer was statically allocated or not, and if it is active or not. */ 95 } xTIMER; 96 97 /* The old xTIMER name is maintained above then typedefed to the new Timer_t 98 * name below to enable the use of older kernel aware debuggers. */ 99 typedef xTIMER Timer_t; 100 101 /* The definition of messages that can be sent and received on the timer queue. 102 * Two types of message can be queued - messages that manipulate a software timer, 103 * and messages that request the execution of a non-timer related callback. The 104 * two message types are defined in two separate structures, xTimerParametersType 105 * and xCallbackParametersType respectively. */ 106 typedef struct tmrTimerParameters 107 { 108 TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ 109 Timer_t * pxTimer; /*<< The timer to which the command will be applied. */ 110 } TimerParameter_t; 111 112 113 typedef struct tmrCallbackParameters 114 { 115 PendedFunction_t pxCallbackFunction; /* << The callback function to execute. */ 116 void * pvParameter1; /* << The value that will be used as the callback functions first parameter. */ 117 uint32_t ulParameter2; /* << The value that will be used as the callback functions second parameter. */ 118 } CallbackParameters_t; 119 120 /* The structure that contains the two message types, along with an identifier 121 * that is used to determine which message type is valid. */ 122 typedef struct tmrTimerQueueMessage 123 { 124 BaseType_t xMessageID; /*<< The command being sent to the timer service task. */ 125 union 126 { 127 TimerParameter_t xTimerParameters; 128 129 /* Don't include xCallbackParameters if it is not going to be used as 130 * it makes the structure (and therefore the timer queue) larger. */ 131 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) 132 CallbackParameters_t xCallbackParameters; 133 #endif /* INCLUDE_xTimerPendFunctionCall */ 134 } u; 135 } DaemonTaskMessage_t; 136 137 /*lint -save -e956 A manual analysis and inspection has been used to determine 138 * which static variables must be declared volatile. */ 139 140 /* The list in which active timers are stored. Timers are referenced in expire 141 * time order, with the nearest expiry time at the front of the list. Only the 142 * timer service task is allowed to access these lists. 143 * xActiveTimerList1 and xActiveTimerList2 could be at function scope but that 144 * breaks some kernel aware debuggers, and debuggers that reply on removing the 145 * static qualifier. */ 146 PRIVILEGED_DATA static List_t xActiveTimerList1; 147 PRIVILEGED_DATA static List_t xActiveTimerList2; 148 PRIVILEGED_DATA static List_t * pxCurrentTimerList; 149 PRIVILEGED_DATA static List_t * pxOverflowTimerList; 150 151 /* A queue that is used to send commands to the timer service task. */ 152 PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; 153 PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; 154 155 #ifdef ESP_PLATFORM 156 /* Mux. We use a single mux for all the timers for now. ToDo: maybe increase granularity here? */ 157 PRIVILEGED_DATA portMUX_TYPE xTimerMux = portMUX_INITIALIZER_UNLOCKED; 158 #endif // ESP_PLATFORM 159 160 /*lint -restore */ 161 162 /*-----------------------------------------------------------*/ 163 164 /* 165 * Initialise the infrastructure used by the timer service task if it has not 166 * been initialised already. 167 */ 168 static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION; 169 170 /* 171 * The timer service task (daemon). Timer functionality is controlled by this 172 * task. Other tasks communicate with the timer service task using the 173 * xTimerQueue queue. 174 */ 175 static portTASK_FUNCTION_PROTO( prvTimerTask, pvParameters ) PRIVILEGED_FUNCTION; 176 177 /* 178 * Called by the timer service task to interpret and process a command it 179 * received on the timer queue. 180 */ 181 static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION; 182 183 /* 184 * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, 185 * depending on if the expire time causes a timer counter overflow. 186 */ 187 static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, 188 const TickType_t xNextExpiryTime, 189 const TickType_t xTimeNow, 190 const TickType_t xCommandTime ) PRIVILEGED_FUNCTION; 191 192 /* 193 * An active timer has reached its expire time. Reload the timer if it is an 194 * auto-reload timer, then call its callback. 195 */ 196 static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, 197 const TickType_t xTimeNow ) PRIVILEGED_FUNCTION; 198 199 /* 200 * The tick count has overflowed. Switch the timer lists after ensuring the 201 * current timer list does not still reference some timers. 202 */ 203 static void prvSwitchTimerLists( void ) PRIVILEGED_FUNCTION; 204 205 /* 206 * Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE 207 * if a tick count overflow occurred since prvSampleTimeNow() was last called. 208 */ 209 static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION; 210 211 /* 212 * If the timer list contains any active timers then return the expire time of 213 * the timer that will expire first and set *pxListWasEmpty to false. If the 214 * timer list does not contain any timers then return 0 and set *pxListWasEmpty 215 * to pdTRUE. 216 */ 217 static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIVILEGED_FUNCTION; 218 219 /* 220 * If a timer has expired, process it. Otherwise, block the timer service task 221 * until either a timer does expire or a command is received. 222 */ 223 static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, 224 BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION; 225 226 /* 227 * Called after a Timer_t structure has been allocated either statically or 228 * dynamically to fill in the structure's members. 229 */ 230 static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 231 const TickType_t xTimerPeriodInTicks, 232 const UBaseType_t uxAutoReload, 233 void * const pvTimerID, 234 TimerCallbackFunction_t pxCallbackFunction, 235 Timer_t * pxNewTimer ) PRIVILEGED_FUNCTION; 236 /*-----------------------------------------------------------*/ 237 xTimerCreateTimerTask(void)238 BaseType_t xTimerCreateTimerTask( void ) 239 { 240 BaseType_t xReturn = pdFAIL; 241 242 /* This function is called when the scheduler is started if 243 * configUSE_TIMERS is set to 1. Check that the infrastructure used by the 244 * timer service task has been created/initialised. If timers have already 245 * been created then the initialisation will already have been performed. */ 246 prvCheckForValidListAndQueue(); 247 248 if( xTimerQueue != NULL ) 249 { 250 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 251 { 252 StaticTask_t * pxTimerTaskTCBBuffer = NULL; 253 StackType_t * pxTimerTaskStackBuffer = NULL; 254 uint32_t ulTimerTaskStackSize; 255 256 vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); 257 xTimerTaskHandle = xTaskCreateStaticPinnedToCore( prvTimerTask, 258 configTIMER_SERVICE_TASK_NAME, 259 ulTimerTaskStackSize, 260 NULL, 261 ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, 262 pxTimerTaskStackBuffer, 263 pxTimerTaskTCBBuffer, 264 0 ); 265 266 if( xTimerTaskHandle != NULL ) 267 { 268 xReturn = pdPASS; 269 } 270 } 271 #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ 272 { 273 xReturn = xTaskCreatePinnedToCore( prvTimerTask, 274 configTIMER_SERVICE_TASK_NAME, 275 configTIMER_TASK_STACK_DEPTH, 276 NULL, 277 ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, 278 &xTimerTaskHandle, 0 ); 279 } 280 #endif /* configSUPPORT_STATIC_ALLOCATION */ 281 } 282 else 283 { 284 mtCOVERAGE_TEST_MARKER(); 285 } 286 287 configASSERT( xReturn ); 288 return xReturn; 289 } 290 /*-----------------------------------------------------------*/ 291 292 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 293 xTimerCreate(const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction)294 TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 295 const TickType_t xTimerPeriodInTicks, 296 const UBaseType_t uxAutoReload, 297 void * const pvTimerID, 298 TimerCallbackFunction_t pxCallbackFunction ) 299 { 300 Timer_t * pxNewTimer; 301 302 pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of Timer_t is always a pointer to the timer's mame. */ 303 304 if( pxNewTimer != NULL ) 305 { 306 /* Status is thus far zero as the timer is not created statically 307 * and has not been started. The auto-reload bit may get set in 308 * prvInitialiseNewTimer. */ 309 pxNewTimer->ucStatus = 0x00; 310 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); 311 } 312 313 return pxNewTimer; 314 } 315 316 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ 317 /*-----------------------------------------------------------*/ 318 319 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 320 xTimerCreateStatic(const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction,StaticTimer_t * pxTimerBuffer)321 TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 322 const TickType_t xTimerPeriodInTicks, 323 const UBaseType_t uxAutoReload, 324 void * const pvTimerID, 325 TimerCallbackFunction_t pxCallbackFunction, 326 StaticTimer_t * pxTimerBuffer ) 327 { 328 Timer_t * pxNewTimer; 329 330 #if ( configASSERT_DEFINED == 1 ) 331 { 332 /* Sanity check that the size of the structure used to declare a 333 * variable of type StaticTimer_t equals the size of the real timer 334 * structure. */ 335 volatile size_t xSize = sizeof( StaticTimer_t ); 336 configASSERT( xSize == sizeof( Timer_t ) ); 337 ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ 338 } 339 #endif /* configASSERT_DEFINED */ 340 341 /* A pointer to a StaticTimer_t structure MUST be provided, use it. */ 342 configASSERT( pxTimerBuffer ); 343 pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 !e9087 StaticTimer_t is a pointer to a Timer_t, so guaranteed to be aligned and sized correctly (checked by an assert()), so this is safe. */ 344 345 if( pxNewTimer != NULL ) 346 { 347 /* Timers can be created statically or dynamically so note this 348 * timer was created statically in case it is later deleted. The 349 * auto-reload bit may get set in prvInitialiseNewTimer(). */ 350 pxNewTimer->ucStatus = tmrSTATUS_IS_STATICALLY_ALLOCATED; 351 352 prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); 353 } 354 355 return pxNewTimer; 356 } 357 358 #endif /* configSUPPORT_STATIC_ALLOCATION */ 359 /*-----------------------------------------------------------*/ 360 prvInitialiseNewTimer(const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction,Timer_t * pxNewTimer)361 static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 362 const TickType_t xTimerPeriodInTicks, 363 const UBaseType_t uxAutoReload, 364 void * const pvTimerID, 365 TimerCallbackFunction_t pxCallbackFunction, 366 Timer_t * pxNewTimer ) 367 { 368 /* 0 is not a valid value for xTimerPeriodInTicks. */ 369 configASSERT( ( xTimerPeriodInTicks > 0 ) ); 370 371 if( pxNewTimer != NULL ) 372 { 373 /* Ensure the infrastructure used by the timer service task has been 374 * created/initialised. */ 375 prvCheckForValidListAndQueue(); 376 377 /* Initialise the timer structure members using the function 378 * parameters. */ 379 pxNewTimer->pcTimerName = pcTimerName; 380 pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; 381 pxNewTimer->pvTimerID = pvTimerID; 382 pxNewTimer->pxCallbackFunction = pxCallbackFunction; 383 vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); 384 385 if( uxAutoReload != pdFALSE ) 386 { 387 pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; 388 } 389 390 traceTIMER_CREATE( pxNewTimer ); 391 } 392 } 393 /*-----------------------------------------------------------*/ 394 xTimerGenericCommand(TimerHandle_t xTimer,const BaseType_t xCommandID,const TickType_t xOptionalValue,BaseType_t * const pxHigherPriorityTaskWoken,const TickType_t xTicksToWait)395 BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, 396 const BaseType_t xCommandID, 397 const TickType_t xOptionalValue, 398 BaseType_t * const pxHigherPriorityTaskWoken, 399 const TickType_t xTicksToWait ) 400 { 401 BaseType_t xReturn = pdFAIL; 402 DaemonTaskMessage_t xMessage; 403 404 configASSERT( xTimer ); 405 406 /* Send a message to the timer service task to perform a particular action 407 * on a particular timer definition. */ 408 if( xTimerQueue != NULL ) 409 { 410 /* Send a command to the timer service task to start the xTimer timer. */ 411 xMessage.xMessageID = xCommandID; 412 xMessage.u.xTimerParameters.xMessageValue = xOptionalValue; 413 xMessage.u.xTimerParameters.pxTimer = xTimer; 414 415 if( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) 416 { 417 if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) 418 { 419 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait ); 420 } 421 else 422 { 423 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY ); 424 } 425 } 426 else 427 { 428 xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); 429 } 430 431 traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn ); 432 } 433 else 434 { 435 mtCOVERAGE_TEST_MARKER(); 436 } 437 438 return xReturn; 439 } 440 /*-----------------------------------------------------------*/ 441 xTimerGetTimerDaemonTaskHandle(void)442 TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) 443 { 444 /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been 445 * started, then xTimerTaskHandle will be NULL. */ 446 configASSERT( ( xTimerTaskHandle != NULL ) ); 447 return xTimerTaskHandle; 448 } 449 /*-----------------------------------------------------------*/ 450 xTimerGetPeriod(TimerHandle_t xTimer)451 TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) 452 { 453 Timer_t * pxTimer = xTimer; 454 455 configASSERT( xTimer ); 456 return pxTimer->xTimerPeriodInTicks; 457 } 458 /*-----------------------------------------------------------*/ 459 vTimerSetReloadMode(TimerHandle_t xTimer,const UBaseType_t uxAutoReload)460 void vTimerSetReloadMode( TimerHandle_t xTimer, 461 const UBaseType_t uxAutoReload ) 462 { 463 Timer_t * pxTimer = xTimer; 464 465 configASSERT( xTimer ); 466 taskENTER_CRITICAL(); 467 { 468 if( uxAutoReload != pdFALSE ) 469 { 470 pxTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; 471 } 472 else 473 { 474 pxTimer->ucStatus &= ~tmrSTATUS_IS_AUTORELOAD; 475 } 476 } 477 taskEXIT_CRITICAL(); 478 } 479 /*-----------------------------------------------------------*/ 480 uxTimerGetReloadMode(TimerHandle_t xTimer)481 UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer ) 482 { 483 Timer_t * pxTimer = xTimer; 484 UBaseType_t uxReturn; 485 486 configASSERT( xTimer ); 487 taskENTER_CRITICAL( ); 488 { 489 if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0 ) 490 { 491 /* Not an auto-reload timer. */ 492 uxReturn = ( UBaseType_t ) pdFALSE; 493 } 494 else 495 { 496 /* Is an auto-reload timer. */ 497 uxReturn = ( UBaseType_t ) pdTRUE; 498 } 499 } 500 taskEXIT_CRITICAL(); 501 502 return uxReturn; 503 } 504 /*-----------------------------------------------------------*/ 505 xTimerGetExpiryTime(TimerHandle_t xTimer)506 TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) 507 { 508 Timer_t * pxTimer = xTimer; 509 TickType_t xReturn; 510 511 configASSERT( xTimer ); 512 xReturn = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) ); 513 return xReturn; 514 } 515 /*-----------------------------------------------------------*/ 516 pcTimerGetName(TimerHandle_t xTimer)517 const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 518 { 519 Timer_t * pxTimer = xTimer; 520 521 configASSERT( xTimer ); 522 return pxTimer->pcTimerName; 523 } 524 /*-----------------------------------------------------------*/ 525 prvProcessExpiredTimer(const TickType_t xNextExpireTime,const TickType_t xTimeNow)526 static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, 527 const TickType_t xTimeNow ) 528 { 529 BaseType_t xResult; 530 Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ 531 532 /* Remove the timer from the list of active timers. A check has already 533 * been performed to ensure the list is not empty. */ 534 535 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); 536 traceTIMER_EXPIRED( pxTimer ); 537 538 /* If the timer is an auto-reload timer then calculate the next 539 * expiry time and re-insert the timer in the list of active timers. */ 540 if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) 541 { 542 /* The timer is inserted into a list using a time relative to anything 543 * other than the current time. It will therefore be inserted into the 544 * correct list relative to the time this task thinks it is now. */ 545 if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE ) 546 { 547 /* The timer expired before it was added to the active timer 548 * list. Reload it now. */ 549 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); 550 configASSERT( xResult ); 551 ( void ) xResult; 552 } 553 else 554 { 555 mtCOVERAGE_TEST_MARKER(); 556 } 557 } 558 else 559 { 560 pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; 561 mtCOVERAGE_TEST_MARKER(); 562 } 563 564 /* Call the timer callback. */ 565 pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); 566 } 567 /*-----------------------------------------------------------*/ 568 portTASK_FUNCTION(prvTimerTask,pvParameters)569 static portTASK_FUNCTION( prvTimerTask, pvParameters ) 570 { 571 TickType_t xNextExpireTime; 572 BaseType_t xListWasEmpty; 573 574 /* Just to avoid compiler warnings. */ 575 ( void ) pvParameters; 576 577 #if ( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 ) 578 { 579 extern void vApplicationDaemonTaskStartupHook( void ); 580 581 /* Allow the application writer to execute some code in the context of 582 * this task at the point the task starts executing. This is useful if the 583 * application includes initialisation code that would benefit from 584 * executing after the scheduler has been started. */ 585 vApplicationDaemonTaskStartupHook(); 586 } 587 #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */ 588 589 for( ; ; ) 590 { 591 /* Query the timers list to see if it contains any timers, and if so, 592 * obtain the time at which the next timer will expire. */ 593 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty ); 594 595 /* If a timer has expired, process it. Otherwise, block this task 596 * until either a timer does expire, or a command is received. */ 597 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty ); 598 599 /* Empty the command queue. */ 600 prvProcessReceivedCommands(); 601 } 602 } 603 /*-----------------------------------------------------------*/ 604 prvProcessTimerOrBlockTask(const TickType_t xNextExpireTime,BaseType_t xListWasEmpty)605 static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, 606 BaseType_t xListWasEmpty ) 607 { 608 TickType_t xTimeNow; 609 BaseType_t xTimerListsWereSwitched; 610 611 #ifdef ESP_PLATFORM 612 taskENTER_CRITICAL(); 613 #else 614 vTaskSuspendAll(); 615 #endif // ESP_PLATFORM 616 { 617 /* Obtain the time now to make an assessment as to whether the timer 618 * has expired or not. If obtaining the time causes the lists to switch 619 * then don't process this timer as any timers that remained in the list 620 * when the lists were switched will have been processed within the 621 * prvSampleTimeNow() function. */ 622 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); 623 624 if( xTimerListsWereSwitched == pdFALSE ) 625 { 626 /* The tick count has not overflowed, has the timer expired? */ 627 if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) ) 628 { 629 #ifdef ESP_PLATFORM 630 taskEXIT_CRITICAL(); 631 #else 632 ( void ) xTaskResumeAll(); 633 #endif // ESP_PLATFORM 634 prvProcessExpiredTimer( xNextExpireTime, xTimeNow ); 635 } 636 else 637 { 638 /* The tick count has not overflowed, and the next expire 639 * time has not been reached yet. This task should therefore 640 * block to wait for the next expire time or a command to be 641 * received - whichever comes first. The following line cannot 642 * be reached unless xNextExpireTime > xTimeNow, except in the 643 * case when the current timer list is empty. */ 644 if( xListWasEmpty != pdFALSE ) 645 { 646 /* The current timer list is empty - is the overflow list 647 * also empty? */ 648 xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList ); 649 } 650 651 vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); 652 653 #ifdef ESP_PLATFORM // IDF-3755 654 taskEXIT_CRITICAL(); 655 #else 656 if( xTaskResumeAll() == pdFALSE ) 657 #endif // ESP_PLATFORM 658 { 659 /* Yield to wait for either a command to arrive, or the 660 * block time to expire. If a command arrived between the 661 * critical section being exited and this yield then the yield 662 * will not cause the task to block. */ 663 portYIELD_WITHIN_API(); 664 } 665 #ifndef ESP_PLATFORM // IDF-3755 666 else 667 { 668 mtCOVERAGE_TEST_MARKER(); 669 } 670 #endif // ESP_PLATFORM 671 } 672 } 673 else 674 { 675 #ifdef ESP_PLATFORM // IDF-3755 676 taskEXIT_CRITICAL(); 677 #else 678 ( void ) xTaskResumeAll(); 679 #endif // ESP_PLATFORM 680 } 681 } 682 } 683 /*-----------------------------------------------------------*/ 684 prvGetNextExpireTime(BaseType_t * const pxListWasEmpty)685 static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) 686 { 687 TickType_t xNextExpireTime; 688 689 /* Timers are listed in expiry time order, with the head of the list 690 * referencing the task that will expire first. Obtain the time at which 691 * the timer with the nearest expiry time will expire. If there are no 692 * active timers then just set the next expire time to 0. That will cause 693 * this task to unblock when the tick count overflows, at which point the 694 * timer lists will be switched and the next expiry time can be 695 * re-assessed. */ 696 *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList ); 697 698 if( *pxListWasEmpty == pdFALSE ) 699 { 700 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); 701 } 702 else 703 { 704 /* Ensure the task unblocks when the tick count rolls over. */ 705 xNextExpireTime = ( TickType_t ) 0U; 706 } 707 708 return xNextExpireTime; 709 } 710 /*-----------------------------------------------------------*/ 711 prvSampleTimeNow(BaseType_t * const pxTimerListsWereSwitched)712 static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched ) 713 { 714 TickType_t xTimeNow; 715 PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */ 716 717 xTimeNow = xTaskGetTickCount(); 718 719 if( xTimeNow < xLastTime ) 720 { 721 prvSwitchTimerLists(); 722 *pxTimerListsWereSwitched = pdTRUE; 723 } 724 else 725 { 726 *pxTimerListsWereSwitched = pdFALSE; 727 } 728 729 xLastTime = xTimeNow; 730 731 return xTimeNow; 732 } 733 /*-----------------------------------------------------------*/ 734 prvInsertTimerInActiveList(Timer_t * const pxTimer,const TickType_t xNextExpiryTime,const TickType_t xTimeNow,const TickType_t xCommandTime)735 static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, 736 const TickType_t xNextExpiryTime, 737 const TickType_t xTimeNow, 738 const TickType_t xCommandTime ) 739 { 740 BaseType_t xProcessTimerNow = pdFALSE; 741 742 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime ); 743 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); 744 745 if( xNextExpiryTime <= xTimeNow ) 746 { 747 /* Has the expiry time elapsed between the command to start/reset a 748 * timer was issued, and the time the command was processed? */ 749 if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 750 { 751 /* The time between a command being issued and the command being 752 * processed actually exceeds the timers period. */ 753 xProcessTimerNow = pdTRUE; 754 } 755 else 756 { 757 vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) ); 758 } 759 } 760 else 761 { 762 if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) ) 763 { 764 /* If, since the command was issued, the tick count has overflowed 765 * but the expiry time has not, then the timer must have already passed 766 * its expiry time and should be processed immediately. */ 767 xProcessTimerNow = pdTRUE; 768 } 769 else 770 { 771 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); 772 } 773 } 774 775 return xProcessTimerNow; 776 } 777 /*-----------------------------------------------------------*/ 778 prvProcessReceivedCommands(void)779 static void prvProcessReceivedCommands( void ) 780 { 781 DaemonTaskMessage_t xMessage; 782 Timer_t * pxTimer; 783 BaseType_t xTimerListsWereSwitched, xResult; 784 TickType_t xTimeNow; 785 786 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. */ 787 { 788 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) 789 { 790 /* Negative commands are pended function calls rather than timer 791 * commands. */ 792 if( xMessage.xMessageID < ( BaseType_t ) 0 ) 793 { 794 const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters ); 795 796 /* The timer uses the xCallbackParameters member to request a 797 * callback be executed. Check the callback is not NULL. */ 798 configASSERT( pxCallback ); 799 800 /* Call the function. */ 801 pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 ); 802 } 803 else 804 { 805 mtCOVERAGE_TEST_MARKER(); 806 } 807 } 808 #endif /* INCLUDE_xTimerPendFunctionCall */ 809 810 /* Commands that are positive are timer commands rather than pended 811 * function calls. */ 812 if( xMessage.xMessageID >= ( BaseType_t ) 0 ) 813 { 814 /* The messages uses the xTimerParameters member to work on a 815 * software timer. */ 816 pxTimer = xMessage.u.xTimerParameters.pxTimer; 817 818 if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */ 819 { 820 /* The timer is in a list, remove it. */ 821 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); 822 } 823 else 824 { 825 mtCOVERAGE_TEST_MARKER(); 826 } 827 828 traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue ); 829 830 /* In this case the xTimerListsWereSwitched parameter is not used, but 831 * it must be present in the function call. prvSampleTimeNow() must be 832 * called after the message is received from xTimerQueue so there is no 833 * possibility of a higher priority task adding a message to the message 834 * queue with a time that is ahead of the timer daemon task (because it 835 * pre-empted the timer daemon task after the xTimeNow value was set). */ 836 xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); 837 838 switch( xMessage.xMessageID ) 839 { 840 case tmrCOMMAND_START: 841 case tmrCOMMAND_START_FROM_ISR: 842 case tmrCOMMAND_RESET: 843 case tmrCOMMAND_RESET_FROM_ISR: 844 case tmrCOMMAND_START_DONT_TRACE: 845 /* Start or restart a timer. */ 846 pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE; 847 848 if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) 849 { 850 /* The timer expired before it was added to the active 851 * timer list. Process it now. */ 852 pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); 853 traceTIMER_EXPIRED( pxTimer ); 854 855 if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) 856 { 857 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); 858 configASSERT( xResult ); 859 ( void ) xResult; 860 } 861 else 862 { 863 mtCOVERAGE_TEST_MARKER(); 864 } 865 } 866 else 867 { 868 mtCOVERAGE_TEST_MARKER(); 869 } 870 871 break; 872 873 case tmrCOMMAND_STOP: 874 case tmrCOMMAND_STOP_FROM_ISR: 875 /* The timer has already been removed from the active list. */ 876 pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; 877 break; 878 879 case tmrCOMMAND_CHANGE_PERIOD: 880 case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR: 881 pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE; 882 pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; 883 configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); 884 885 /* The new period does not really have a reference, and can 886 * be longer or shorter than the old one. The command time is 887 * therefore set to the current time, and as the period cannot 888 * be zero the next expiry time can only be in the future, 889 * meaning (unlike for the xTimerStart() case above) there is 890 * no fail case that needs to be handled here. */ 891 ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); 892 break; 893 894 case tmrCOMMAND_DELETE: 895 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) 896 { 897 /* The timer has already been removed from the active list, 898 * just free up the memory if the memory was dynamically 899 * allocated. */ 900 if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 ) 901 { 902 vPortFree( pxTimer ); 903 } 904 else 905 { 906 pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; 907 } 908 } 909 #else /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */ 910 { 911 /* If dynamic allocation is not enabled, the memory 912 * could not have been dynamically allocated. So there is 913 * no need to free the memory - just mark the timer as 914 * "not active". */ 915 pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; 916 } 917 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ 918 break; 919 920 default: 921 /* Don't expect to get here. */ 922 break; 923 } 924 } 925 } 926 } 927 /*-----------------------------------------------------------*/ 928 prvSwitchTimerLists(void)929 static void prvSwitchTimerLists( void ) 930 { 931 TickType_t xNextExpireTime, xReloadTime; 932 List_t * pxTemp; 933 Timer_t * pxTimer; 934 BaseType_t xResult; 935 936 /* The tick count has overflowed. The timer lists must be switched. 937 * If there are any timers still referenced from the current timer list 938 * then they must have expired and should be processed before the lists 939 * are switched. */ 940 while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) 941 { 942 xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); 943 944 /* Remove the timer from the list. */ 945 pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ 946 ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); 947 traceTIMER_EXPIRED( pxTimer ); 948 949 /* Execute its callback, then send a command to restart the timer if 950 * it is an auto-reload timer. It cannot be restarted here as the lists 951 * have not yet been switched. */ 952 pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); 953 954 if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) 955 { 956 /* Calculate the reload value, and if the reload value results in 957 * the timer going into the same timer list then it has already expired 958 * and the timer should be re-inserted into the current list so it is 959 * processed again within this loop. Otherwise a command should be sent 960 * to restart the timer to ensure it is only inserted into a list after 961 * the lists have been swapped. */ 962 xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ); 963 964 if( xReloadTime > xNextExpireTime ) 965 { 966 listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime ); 967 listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); 968 vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); 969 } 970 else 971 { 972 xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); 973 configASSERT( xResult ); 974 ( void ) xResult; 975 } 976 } 977 else 978 { 979 mtCOVERAGE_TEST_MARKER(); 980 } 981 } 982 983 pxTemp = pxCurrentTimerList; 984 pxCurrentTimerList = pxOverflowTimerList; 985 pxOverflowTimerList = pxTemp; 986 } 987 /*-----------------------------------------------------------*/ 988 prvCheckForValidListAndQueue(void)989 static void prvCheckForValidListAndQueue( void ) 990 { 991 /* Check that the list from which active timers are referenced, and the 992 * queue used to communicate with the timer service, have been 993 * initialised. */ 994 taskENTER_CRITICAL(); 995 { 996 if( xTimerQueue == NULL ) 997 { 998 vListInitialise( &xActiveTimerList1 ); 999 vListInitialise( &xActiveTimerList2 ); 1000 pxCurrentTimerList = &xActiveTimerList1; 1001 pxOverflowTimerList = &xActiveTimerList2; 1002 1003 #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) 1004 { 1005 /* The timer queue is allocated statically in case 1006 * configSUPPORT_DYNAMIC_ALLOCATION is 0. */ 1007 PRIVILEGED_DATA static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */ 1008 PRIVILEGED_DATA static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */ 1009 1010 xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue ); 1011 } 1012 #else 1013 { 1014 xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) ); 1015 } 1016 #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ 1017 1018 #if ( configQUEUE_REGISTRY_SIZE > 0 ) 1019 { 1020 if( xTimerQueue != NULL ) 1021 { 1022 vQueueAddToRegistry( xTimerQueue, "TmrQ" ); 1023 } 1024 else 1025 { 1026 mtCOVERAGE_TEST_MARKER(); 1027 } 1028 } 1029 #endif /* configQUEUE_REGISTRY_SIZE */ 1030 } 1031 else 1032 { 1033 mtCOVERAGE_TEST_MARKER(); 1034 } 1035 } 1036 taskEXIT_CRITICAL(); 1037 } 1038 /*-----------------------------------------------------------*/ 1039 xTimerIsTimerActive(TimerHandle_t xTimer)1040 BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) 1041 { 1042 BaseType_t xReturn; 1043 Timer_t * pxTimer = xTimer; 1044 1045 configASSERT( xTimer ); 1046 1047 /* Is the timer in the list of active timers? */ 1048 taskENTER_CRITICAL(); 1049 { 1050 if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0 ) 1051 { 1052 xReturn = pdFALSE; 1053 } 1054 else 1055 { 1056 xReturn = pdTRUE; 1057 } 1058 } 1059 taskEXIT_CRITICAL(); 1060 1061 return xReturn; 1062 } /*lint !e818 Can't be pointer to const due to the typedef. */ 1063 /*-----------------------------------------------------------*/ 1064 pvTimerGetTimerID(const TimerHandle_t xTimer)1065 void * pvTimerGetTimerID( const TimerHandle_t xTimer ) 1066 { 1067 Timer_t * const pxTimer = xTimer; 1068 void * pvReturn; 1069 1070 configASSERT( xTimer ); 1071 1072 taskENTER_CRITICAL(); 1073 { 1074 pvReturn = pxTimer->pvTimerID; 1075 } 1076 taskEXIT_CRITICAL(); 1077 1078 return pvReturn; 1079 } 1080 /*-----------------------------------------------------------*/ 1081 vTimerSetTimerID(TimerHandle_t xTimer,void * pvNewID)1082 void vTimerSetTimerID( TimerHandle_t xTimer, 1083 void * pvNewID ) 1084 { 1085 Timer_t * const pxTimer = xTimer; 1086 1087 configASSERT( xTimer ); 1088 1089 taskENTER_CRITICAL(); 1090 { 1091 pxTimer->pvTimerID = pvNewID; 1092 } 1093 taskEXIT_CRITICAL(); 1094 } 1095 /*-----------------------------------------------------------*/ 1096 1097 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) 1098 xTimerPendFunctionCallFromISR(PendedFunction_t xFunctionToPend,void * pvParameter1,uint32_t ulParameter2,BaseType_t * pxHigherPriorityTaskWoken)1099 BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, 1100 void * pvParameter1, 1101 uint32_t ulParameter2, 1102 BaseType_t * pxHigherPriorityTaskWoken ) 1103 { 1104 DaemonTaskMessage_t xMessage; 1105 BaseType_t xReturn; 1106 1107 /* Complete the message with the function parameters and post it to the 1108 * daemon task. */ 1109 xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR; 1110 xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; 1111 xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; 1112 xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; 1113 1114 xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); 1115 1116 tracePEND_FUNC_CALL_FROM_ISR( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); 1117 1118 return xReturn; 1119 } 1120 1121 #endif /* INCLUDE_xTimerPendFunctionCall */ 1122 /*-----------------------------------------------------------*/ 1123 1124 #if ( INCLUDE_xTimerPendFunctionCall == 1 ) 1125 xTimerPendFunctionCall(PendedFunction_t xFunctionToPend,void * pvParameter1,uint32_t ulParameter2,TickType_t xTicksToWait)1126 BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, 1127 void * pvParameter1, 1128 uint32_t ulParameter2, 1129 TickType_t xTicksToWait ) 1130 { 1131 DaemonTaskMessage_t xMessage; 1132 BaseType_t xReturn; 1133 1134 /* This function can only be called after a timer has been created or 1135 * after the scheduler has been started because, until then, the timer 1136 * queue does not exist. */ 1137 configASSERT( xTimerQueue ); 1138 1139 /* Complete the message with the function parameters and post it to the 1140 * daemon task. */ 1141 xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK; 1142 xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; 1143 xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; 1144 xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; 1145 1146 xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait ); 1147 1148 tracePEND_FUNC_CALL( xFunctionToPend, pvParameter1, ulParameter2, xReturn ); 1149 1150 return xReturn; 1151 } 1152 1153 #endif /* INCLUDE_xTimerPendFunctionCall */ 1154 /*-----------------------------------------------------------*/ 1155 1156 #if ( configUSE_TRACE_FACILITY == 1 ) 1157 uxTimerGetTimerNumber(TimerHandle_t xTimer)1158 UBaseType_t uxTimerGetTimerNumber( TimerHandle_t xTimer ) 1159 { 1160 return ( ( Timer_t * ) xTimer )->uxTimerNumber; 1161 } 1162 1163 #endif /* configUSE_TRACE_FACILITY */ 1164 /*-----------------------------------------------------------*/ 1165 1166 #if ( configUSE_TRACE_FACILITY == 1 ) 1167 vTimerSetTimerNumber(TimerHandle_t xTimer,UBaseType_t uxTimerNumber)1168 void vTimerSetTimerNumber( TimerHandle_t xTimer, 1169 UBaseType_t uxTimerNumber ) 1170 { 1171 ( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber; 1172 } 1173 1174 #endif /* configUSE_TRACE_FACILITY */ 1175 /*-----------------------------------------------------------*/ 1176 1177 /* This entire source file will be skipped if the application is not configured 1178 * to include software timer functionality. If you want to include software timer 1179 * functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ 1180 #endif /* configUSE_TIMERS == 1 */ 1181