FreeRTOS-timers.c

FreeRTOS-timers.c文件分析

#define tmrSTATUS_IS_ACTIVE                  ( ( uint8_t ) 0x01 )  /*有效*/

#define tmrSTATUS_IS_STATICALLY_ALLOCATED    ( ( uint8_t ) 0x02 )   /*静态申请内存*/

#define tmrSTATUS_IS_AUTORELOAD              ( ( uint8_t ) 0x04 )  /*自动重载*/

 

typedef struct tmrTimerControl                  /*  */

    {

        const char * pcTimerName;                   /*<<  定时器名称*/

       ListItem_t xTimerListItem;                      /*定时器列表条目,用来记录定时器超时时间点。*/

        TickType_t xTimerPeriodInTicks;            /*<<  定时器周期*/

        void * pvTimerID;                           /*<< 定时器id,/

        TimerCallbackFunction_t pxCallbackFunction; /*<< 定时器超时回调函数 *

        uint8_t ucStatus;                           /*<< 定时器状态,tmrSTATUS_IS_ACTIVE、tmrSTATUS_IS_STATICALLY_ALLOCATED、tmrSTATUS_IS_AUTORELOAD*/

    } xTIMER;

 

定时器指令

#define tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR    ( ( BaseType_t ) -2 )

#define tmrCOMMAND_EXECUTE_CALLBACK             ( ( BaseType_t ) -1 )

#define tmrCOMMAND_START_DONT_TRACE             ( ( BaseType_t ) 0 )

#define tmrCOMMAND_START                        ( ( BaseType_t ) 1 )

#define tmrCOMMAND_RESET                        ( ( BaseType_t ) 2 )

#define tmrCOMMAND_STOP                         ( ( BaseType_t ) 3 )

#define tmrCOMMAND_CHANGE_PERIOD                ( ( BaseType_t ) 4 )

#define tmrCOMMAND_DELETE                       ( ( BaseType_t ) 5 )

 

#define tmrFIRST_FROM_ISR_COMMAND               ( ( BaseType_t ) 6 )

#define tmrCOMMAND_START_FROM_ISR               ( ( BaseType_t ) 6 )

#define tmrCOMMAND_RESET_FROM_ISR               ( ( BaseType_t ) 7 )

#define tmrCOMMAND_STOP_FROM_ISR                ( ( BaseType_t ) 8 )

#define tmrCOMMAND_CHANGE_PERIOD_FROM_ISR       ( ( BaseType_t ) 9 )

 

typedef struct tmrTimerParameters

    {

        TickType_t xMessageValue; /*<< 消息值,一般用来记录执行定时器指令时的tick值,或者说起始tick值*/

        Timer_t * pxTimer;        /*<< 定时器指针*/

    } TimerParameter_t;

 

typedef struct tmrTimerQueueMessage

    {

        BaseType_t xMessageID; /*<< 定时器指令T */

        union

        {

            TimerParameter_t xTimerParameters;

 

            /* 没用到,不关心*/

            #if ( INCLUDE_xTimerPendFunctionCall == 1 )

                CallbackParameters_t xCallbackParameters;

            #endif /* INCLUDE_xTimerPendFunctionCall */

        } u;

    } DaemonTaskMessage_t;

 

    PRIVILEGED_DATA static List_t xActiveTimerList1;   /*有效定时器列表1*/

    PRIVILEGED_DATA static List_t xActiveTimerList2;  /*有效定时器列表2*/

    PRIVILEGED_DATA static List_t * pxCurrentTimerList; /*当前定时器列表指针*/

    PRIVILEGED_DATA static List_t * pxOverflowTimerList; /*溢出定时器列表指针*/

 

    PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;   /*定时器消息队列*/

    PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL; /*定时器任务句柄*/

 

BaseType_t xTimerCreateTimerTask( void )

功能:创建定时器任务

返回值:成功时返回1,否则返回0

 

TimerHandle_t xTimerCreate( const char * const pcTimerName, /*l*/

                                    const TickType_t xTimerPeriodInTicks,

                                    const UBaseType_t uxAutoReload,

                                    void * const pvTimerID,

                                    TimerCallbackFunction_t pxCallbackFunction )

功能:创建定时器

参数:

  1. pcTimerName 定时器名
  2. xTimerPeriodInTicks 定时器周期,单位:tick
  3. uxAutoReload 是否自动重载
  4. pvTimerID 定时器id
  5. pxCallbackFunction 定时器回调函数

返回值:成功时定时器句柄,否则返回NULL

 

BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,

                                     const BaseType_t xCommandID,

                                     const TickType_t xOptionalValue,

                                     BaseType_t * const pxHigherPriorityTaskWoken,

                                     const TickType_t xTicksToWait )

功能:执行定时器指令

参数:

  1. xTimer 定时器句柄
  2. xCommandID  指令id
  3. xOptionalValue 选项值,一般是执行指令时的tick值
  4. pxHigherPriorityTaskWoken 输出型参数,用来指示 是否有更高优先级的任务就绪
  5. xTicksToWait 等待超时时间

返回值:成功时返回1,否则返回0

 

TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )

功能:获取定时器任务句柄

返回值:定时器任务句柄

 

TickType_t xTimerGetPeriod( TimerHandle_t xTimer )

功能:获取定时器周期

参数:

  1. xTimer 定时器句柄

返回值:定时器周期

 

void vTimerSetReloadMode( TimerHandle_t xTimer,

                              const UBaseType_t uxAutoReload )

功能:设置是否自动重载

参数:

  1. xTimer定时器句柄
  2. uxAutoReload 1:自动重载,0:执行一次

 

UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer )

功能:获取任务重载模式

参数:

  1. xTimer 定时器句柄

返回值:自动重载返回1,执行一次返回0。

 

TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer )

功能:获取定时器超时时间

参数:

  1. xTimer 定时器句柄

返回值:定时器超时时间,即下一次执行时间

 

const char * pcTimerGetName( TimerHandle_t xTimer )

功能:获取定时器名

参数:

  1. xTimer 定时器句柄

返回值:定时器名

 

BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )

功能:获取定时器是否有效

参数:

  1. xTimer 定时器句柄

返回值:定时器有效返回,否则返回0

 

void * pvTimerGetTimerID( const TimerHandle_t xTimer )

功能:获取定时器id

参数:

  1. xTimer 定时器句柄

返回值:定时器id

 

void vTimerSetTimerID( TimerHandle_t xTimer,

                           void * pvNewID )

功能:设置定时器id

参数:

  1. xTimer 定时器句柄
  2. pvNewID 定时器id

 

重点分析

TimerHandle_t xTimerCreate( const char * const pcTimerName, /**/

                                    const TickType_t xTimerPeriodInTicks,

                                    const UBaseType_t uxAutoReload,

                                    void * const pvTimerID,

                                    TimerCallbackFunction_t pxCallbackFunction )

        {

            Timer_t * pxNewTimer;

 

            pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); 

 

            if( pxNewTimer != NULL )

            {

                pxNewTimer->ucStatus = 0x00;

                prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );

            }

 

            return pxNewTimer;

        }

 

 

static void prvInitialiseNewTimer( const char * const pcTimerName, /*l. */

                                       const TickType_t xTimerPeriodInTicks,

                                       const UBaseType_t uxAutoReload,

                                       void * const pvTimerID,

                                       TimerCallbackFunction_t pxCallbackFunction,

                                       Timer_t * pxNewTimer )

    {

        configASSERT( ( xTimerPeriodInTicks > 0 ) );

 

        if( pxNewTimer != NULL )

        {

            prvCheckForValidListAndQueue();

 

            pxNewTimer->pcTimerName = pcTimerName;

            pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;

            pxNewTimer->pvTimerID = pvTimerID;

            pxNewTimer->pxCallbackFunction = pxCallbackFunction;

            vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );

 

            if( uxAutoReload != pdFALSE )

            {

                pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;

            }

 

            traceTIMER_CREATE( pxNewTimer );

        }

    }

 

BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,

                                     const BaseType_t xCommandID,

                                     const TickType_t xOptionalValue,

                                     BaseType_t * const pxHigherPriorityTaskWoken,

                                     const TickType_t xTicksToWait )

    {

        BaseType_t xReturn = pdFAIL;

        DaemonTaskMessage_t xMessage;

 

        configASSERT( xTimer );

 

        if( xTimerQueue != NULL )

        {

            /* 创建一个定时器消息并发送到定时器消息队列*/

            xMessage.xMessageID = xCommandID;

            xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;

            xMessage.u.xTimerParameters.pxTimer = xTimer;

 

            if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )

            {

                if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )

                {

                    xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );

                }

                else

                {

                    xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );

                }

            }

            else

            {

                xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );

            }

 

            traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );

        }

        else

        {

            mtCOVERAGE_TEST_MARKER();

        }

 

        return xReturn;

    }

 

static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,

                                        const TickType_t xTimeNow )

    {

        BaseType_t xResult;

        Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /* */

 

        ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );

        traceTIMER_EXPIRED( pxTimer );

 

        if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )

        {

            if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )

            {

                xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );

                configASSERT( xResult );

                ( void ) xResult;

            }

            else

            {

                mtCOVERAGE_TEST_MARKER();

            }

        }

        else

        {

            pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;

            mtCOVERAGE_TEST_MARKER();

        }

 

        pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );

    }

 

定时器任务

static portTASK_FUNCTION( prvTimerTask, pvParameters )

    {

        TickType_t xNextExpireTime;

        BaseType_t xListWasEmpty;

 

        ( void ) pvParameters;

 

        for( ; ; )

        {

            /*  获取下一个超时时间*/

            xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );

 

            /*  处理定时器或者阻塞任务*/

            prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );

 

            /* 处理接收到的指令*/

            prvProcessReceivedCommands();

        }

    }

 

static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,

                                            BaseType_t xListWasEmpty )

    {

        TickType_t xTimeNow;

        BaseType_t xTimerListsWereSwitched;

 

        vTaskSuspendAll();

        {

            xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );

 

            if( xTimerListsWereSwitched == pdFALSE )

            {

                if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )

                {

                    ( void ) xTaskResumeAll();

                    prvProcessExpiredTimer( xNextExpireTime, xTimeNow );

                }

                else

                {

                    if( xListWasEmpty != pdFALSE )

                    {

                        xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );

                    }

 

                    vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );

 

                    if( xTaskResumeAll() == pdFALSE )

                    {

                        portYIELD_WITHIN_API();

                    }

                    else

                    {

                        mtCOVERAGE_TEST_MARKER();

                    }

                }

            }

            else

            {

                ( void ) xTaskResumeAll();

            }

        }

    }

 

 

 

 

 

从当前定时器列表获取第一个定时器的超时时间

static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )

    {

        TickType_t xNextExpireTime;

 

        *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );

 

        if( *pxListWasEmpty == pdFALSE )

        {

            xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );

        }

        else

        {

            xNextExpireTime = ( TickType_t ) 0U;

        }

 

        return xNextExpireTime;

    }

 

采样当前时间,记录上一次的采样时间处理定时器列表切换

static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )

    {

        TickType_t xTimeNow;

        PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*l*/

 

        xTimeNow = xTaskGetTickCount();

 

        if( xTimeNow < xLastTime )

        {

            prvSwitchTimerLists();

            *pxTimerListsWereSwitched = pdTRUE;

        }

        else

        {

            *pxTimerListsWereSwitched = pdFALSE;

        }

 

        xLastTime = xTimeNow;

 

        return xTimeNow;

    }

 

static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,

                                                  const TickType_t xNextExpiryTime,

                                                  const TickType_t xTimeNow,

                                                  const TickType_t xCommandTime )

    {

        BaseType_t xProcessTimerNow = pdFALSE;

 

        listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );

        listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );

 

        if( xNextExpiryTime <= xTimeNow )

        {

            if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /* */

            {

                xProcessTimerNow = pdTRUE;

            }

            else

            {

                vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );

            }

        }

        else

        {

            if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )

            {

                xProcessTimerNow = pdTRUE;

            }

            else

            {

                vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );

            }

        }

 

        return xProcessTimerNow;

    }

 

 

 

 

 static void prvProcessReceivedCommands( void )

    {

        DaemonTaskMessage_t xMessage;

        Timer_t * pxTimer;

        BaseType_t xTimerListsWereSwitched, xResult;

        TickType_t xTimeNow;

 

        while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /* */

        {

            if( xMessage.xMessageID >= ( BaseType_t ) 0 )

            {

                pxTimer = xMessage.u.xTimerParameters.pxTimer;

 

                if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /**/

                {

                    ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );

                }

                else

                {

                    mtCOVERAGE_TEST_MARKER();

                }

 

                traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );

 

                xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );

 

                switch( xMessage.xMessageID )

                {

                    case tmrCOMMAND_START:

                    case tmrCOMMAND_START_FROM_ISR:

                    case tmrCOMMAND_RESET:

                    case tmrCOMMAND_RESET_FROM_ISR:

                    case tmrCOMMAND_START_DONT_TRACE:

                        /* Start or restart a timer. */

                        pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;

 

                        if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )

                        {

                            pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );

                            traceTIMER_EXPIRED( pxTimer );

 

                            if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )

                            {

                                xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );

                                configASSERT( xResult );

                                ( void ) xResult;

                            }

                            else

                            {

                                mtCOVERAGE_TEST_MARKER();

                            }

                        }

                        else

                        {

                            mtCOVERAGE_TEST_MARKER();

                        }

 

                        break;

 

                    case tmrCOMMAND_STOP:

                    case tmrCOMMAND_STOP_FROM_ISR:

                        pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;

                        break;

 

                    case tmrCOMMAND_CHANGE_PERIOD:

                    case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR:

                        pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;

                        pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;

                        configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );

 

                        ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );

                        break;

 

                    case tmrCOMMAND_DELETE:

                            {

                                if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 )

                                {

                                    vPortFree( pxTimer );

                                }

                                else

                                {

                                    pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;

                                }

                            }

                           break;

 

                    default:

                        /* Don't expect to get here. */

                        break;

                }

            }

        }

    }

 

 

 

 

 

static void prvSwitchTimerLists( void )

    {

        TickType_t xNextExpireTime, xReloadTime;

        List_t * pxTemp;

        Timer_t * pxTimer;

        BaseType_t xResult;

 

        while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )

        {

            xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );

 

            pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*li*/

            ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );

            traceTIMER_EXPIRED( pxTimer );

 

            pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );

 

            if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )

            {

                xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );

 

                if( xReloadTime > xNextExpireTime )

                {

                    listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );

                    listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );

                    vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );

                }

                else

                {

                    xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );

                    configASSERT( xResult );

                    ( void ) xResult;

                }

            }

            else

            {

                mtCOVERAGE_TEST_MARKER();

            }

        }

 

 

 

        pxTemp = pxCurrentTimerList;

        pxCurrentTimerList = pxOverflowTimerList;

        pxOverflowTimerList = pxTemp;

    }

posted @ 2022-08-08 20:44  明er  阅读(80)  评论(0)    收藏  举报