|
55 | 55 | #if ( configUSE_TIMERS == 1 ) |
56 | 56 |
|
57 | 57 | /* Misc definitions. */ |
58 | | - #define tmrNO_DELAY ( TickType_t ) 0U |
| 58 | + #define tmrNO_DELAY ( ( TickType_t ) 0U ) |
| 59 | + #define tmrMAX_TIME_BEFORE_OVERFLOW ( ( TickType_t ) -1 ) |
59 | 60 |
|
60 | 61 | /* The name assigned to the timer service task. This can be overridden by |
61 | 62 | * defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */ |
|
172 | 173 | const TickType_t xTimeNow, |
173 | 174 | const TickType_t xCommandTime ) PRIVILEGED_FUNCTION; |
174 | 175 |
|
| 176 | +/* |
| 177 | + * Reload the specified auto-reload timer. If the reloading is backlogged, |
| 178 | + * clear the backlog, calling the callback for each additional reload. When |
| 179 | + * this function returns, the next expiry time is after xTimeNow. |
| 180 | + */ |
| 181 | + static void prvReloadTimer( Timer_t * const pxTimer, |
| 182 | + TickType_t xExpiredTime, |
| 183 | + const TickType_t xTimeNow ) PRIVILEGED_FUNCTION; |
| 184 | + |
175 | 185 | /* |
176 | 186 | * An active timer has reached its expire time. Reload the timer if it is an |
177 | 187 | * auto-reload timer, then call its callback. |
|
502 | 512 | } |
503 | 513 | /*-----------------------------------------------------------*/ |
504 | 514 |
|
| 515 | + static void prvReloadTimer( Timer_t * const pxTimer, |
| 516 | + TickType_t xExpiredTime, |
| 517 | + const TickType_t xTimeNow ) |
| 518 | + { |
| 519 | + /* Insert the timer into the appropriate list for the next expiry time. |
| 520 | + * If the next expiry time has already passed, advance the expiry time, |
| 521 | + * call the callback function, and try again. */ |
| 522 | + while ( prvInsertTimerInActiveList( pxTimer, ( xExpiredTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xExpiredTime ) != pdFALSE ) |
| 523 | + { |
| 524 | + /* Advance the expiry time. */ |
| 525 | + xExpiredTime += pxTimer->xTimerPeriodInTicks; |
| 526 | + |
| 527 | + /* Call the timer callback. */ |
| 528 | + traceTIMER_EXPIRED( pxTimer ); |
| 529 | + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); |
| 530 | + } |
| 531 | + } |
| 532 | +/*-----------------------------------------------------------*/ |
| 533 | + |
505 | 534 | static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, |
506 | 535 | const TickType_t xTimeNow ) |
507 | 536 | { |
508 | | - BaseType_t xResult; |
509 | 537 | 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. */ |
510 | 538 |
|
511 | 539 | /* Remove the timer from the list of active timers. A check has already |
512 | 540 | * been performed to ensure the list is not empty. */ |
513 | | - |
514 | 541 | ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); |
515 | | - traceTIMER_EXPIRED( pxTimer ); |
516 | 542 |
|
517 | 543 | /* If the timer is an auto-reload timer then calculate the next |
518 | 544 | * expiry time and re-insert the timer in the list of active timers. */ |
519 | 545 | if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) |
520 | 546 | { |
521 | | - /* The timer is inserted into a list using a time relative to anything |
522 | | - * other than the current time. It will therefore be inserted into the |
523 | | - * correct list relative to the time this task thinks it is now. */ |
524 | | - if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE ) |
525 | | - { |
526 | | - /* The timer expired before it was added to the active timer |
527 | | - * list. Reload it now. */ |
528 | | - xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); |
529 | | - configASSERT( xResult ); |
530 | | - ( void ) xResult; |
531 | | - } |
532 | | - else |
533 | | - { |
534 | | - mtCOVERAGE_TEST_MARKER(); |
535 | | - } |
| 547 | + prvReloadTimer( pxTimer, xNextExpireTime, xTimeNow ); |
536 | 548 | } |
537 | 549 | else |
538 | 550 | { |
539 | 551 | pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; |
540 | | - mtCOVERAGE_TEST_MARKER(); |
541 | 552 | } |
542 | 553 |
|
543 | 554 | /* Call the timer callback. */ |
| 555 | + traceTIMER_EXPIRED( pxTimer ); |
544 | 556 | pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); |
545 | 557 | } |
546 | 558 | /*-----------------------------------------------------------*/ |
|
741 | 753 | { |
742 | 754 | DaemonTaskMessage_t xMessage; |
743 | 755 | Timer_t * pxTimer; |
744 | | - BaseType_t xTimerListsWereSwitched, xResult; |
| 756 | + BaseType_t xTimerListsWereSwitched; |
745 | 757 | TickType_t xTimeNow; |
746 | 758 |
|
747 | 759 | 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. */ |
|
802 | 814 | case tmrCOMMAND_START_FROM_ISR: |
803 | 815 | case tmrCOMMAND_RESET: |
804 | 816 | case tmrCOMMAND_RESET_FROM_ISR: |
805 | | - case tmrCOMMAND_START_DONT_TRACE: |
806 | 817 | /* Start or restart a timer. */ |
807 | 818 | pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE; |
808 | 819 |
|
809 | 820 | if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) |
810 | 821 | { |
811 | 822 | /* The timer expired before it was added to the active |
812 | 823 | * timer list. Process it now. */ |
813 | | - pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); |
814 | | - traceTIMER_EXPIRED( pxTimer ); |
815 | | - |
816 | 824 | if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) |
817 | 825 | { |
818 | | - xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); |
819 | | - configASSERT( xResult ); |
820 | | - ( void ) xResult; |
| 826 | + prvReloadTimer( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow ); |
821 | 827 | } |
822 | 828 | else |
823 | 829 | { |
824 | | - mtCOVERAGE_TEST_MARKER(); |
| 830 | + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; |
825 | 831 | } |
| 832 | + |
| 833 | + /* Call the timer callback. */ |
| 834 | + traceTIMER_EXPIRED( pxTimer ); |
| 835 | + pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); |
826 | 836 | } |
827 | 837 | else |
828 | 838 | { |
|
889 | 899 |
|
890 | 900 | static void prvSwitchTimerLists( void ) |
891 | 901 | { |
892 | | - TickType_t xNextExpireTime, xReloadTime; |
| 902 | + TickType_t xNextExpireTime; |
893 | 903 | List_t * pxTemp; |
894 | | - Timer_t * pxTimer; |
895 | | - BaseType_t xResult; |
896 | 904 |
|
897 | 905 | /* The tick count has overflowed. The timer lists must be switched. |
898 | 906 | * If there are any timers still referenced from the current timer list |
|
902 | 910 | { |
903 | 911 | xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); |
904 | 912 |
|
905 | | - /* Remove the timer from the list. */ |
906 | | - 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. */ |
907 | | - ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); |
908 | | - traceTIMER_EXPIRED( pxTimer ); |
909 | | - |
910 | | - /* Execute its callback, then send a command to restart the timer if |
911 | | - * it is an auto-reload timer. It cannot be restarted here as the lists |
912 | | - * have not yet been switched. */ |
913 | | - pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); |
914 | | - |
915 | | - if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) |
916 | | - { |
917 | | - /* Calculate the reload value, and if the reload value results in |
918 | | - * the timer going into the same timer list then it has already expired |
919 | | - * and the timer should be re-inserted into the current list so it is |
920 | | - * processed again within this loop. Otherwise a command should be sent |
921 | | - * to restart the timer to ensure it is only inserted into a list after |
922 | | - * the lists have been swapped. */ |
923 | | - xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ); |
924 | | - |
925 | | - if( xReloadTime > xNextExpireTime ) |
926 | | - { |
927 | | - listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime ); |
928 | | - listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); |
929 | | - vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) ); |
930 | | - } |
931 | | - else |
932 | | - { |
933 | | - xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY ); |
934 | | - configASSERT( xResult ); |
935 | | - ( void ) xResult; |
936 | | - } |
937 | | - } |
938 | | - else |
939 | | - { |
940 | | - mtCOVERAGE_TEST_MARKER(); |
941 | | - } |
| 913 | + /* Process the expired timer. For auto-reload timers, be careful to |
| 914 | + * process only expirations that occur on the current list. Further |
| 915 | + * expirations must wait until after the lists are switched. */ |
| 916 | + prvProcessExpiredTimer( xNextExpireTime, tmrMAX_TIME_BEFORE_OVERFLOW ); |
942 | 917 | } |
943 | 918 |
|
944 | 919 | pxTemp = pxCurrentTimerList; |
|
0 commit comments