mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 05:21:59 -04:00
Continue work on timers module - work in progress.
This commit is contained in:
parent
812632fd1c
commit
4a5f1529d0
168
Source/timers.c
168
Source/timers.c
|
@ -66,10 +66,10 @@ task.h is included from an application file. */
|
||||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||||
|
|
||||||
/* IDs for commands that can be sent/received on the timer queue. */
|
/* IDs for commands that can be sent/received on the timer queue. */
|
||||||
#define tmrSTART 0
|
#define tmrCOMMAND_START 0
|
||||||
|
|
||||||
/* Misc definitions. */
|
/* Misc definitions. */
|
||||||
#define timerNO_DELAY ( portTickType ) 0U
|
#define tmrNO_DELAY ( portTickType ) 0U
|
||||||
|
|
||||||
/* The definition of the timers themselves. */
|
/* The definition of the timers themselves. */
|
||||||
typedef struct tmrTimerControl
|
typedef struct tmrTimerControl
|
||||||
|
@ -108,16 +108,37 @@ PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
|
||||||
*/
|
*/
|
||||||
static void prvRemoveTimerFromActiveList( xTIMER *pxTimer ) PRIVILEGED_FUNCTION;
|
static void prvRemoveTimerFromActiveList( xTIMER *pxTimer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send pxMessage to xTimerQueue using a block time of xBlockTime if the
|
||||||
|
* scheduler is running, or a block time of zero if the scheduler is not
|
||||||
|
* running.
|
||||||
|
*/
|
||||||
|
static portBASE_TYPE prvSendMessageToTimerServiceTask( xTIMER_MESSAGE *pxMessage, portTickType xBlockTime ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialise the infrustructure used by the timer service task if it has not
|
||||||
|
* been initialised already.
|
||||||
|
*/
|
||||||
static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
|
static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The timer service task (daemon).
|
* The timer service task (daemon). Timer functionality is controlled by this
|
||||||
|
* task. Other tasks communicate with the timer service task using the
|
||||||
|
* xTimerQueue queue.
|
||||||
*/
|
*/
|
||||||
static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
|
static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following functions handle the commands that are sent to the timer
|
||||||
|
* service task via the xTimerQueue queue.
|
||||||
|
*/
|
||||||
|
static void prvTimerStart( xTIMER *pxTimer ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/* Handlers for commands received on the timer queue. */
|
/*
|
||||||
static void prvTimerStart( xTIMER *pxTimer );
|
* Called by the timer service task to interpret and process a command it
|
||||||
|
* received on the timer queue.
|
||||||
|
*/
|
||||||
|
static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -126,12 +147,14 @@ portBASE_TYPE xTimerCreateTimerTask( void )
|
||||||
portBASE_TYPE xReturn = pdFAIL;
|
portBASE_TYPE xReturn = pdFAIL;
|
||||||
|
|
||||||
/* This function is called when the scheduler is started if
|
/* This function is called when the scheduler is started if
|
||||||
configUSE_TIMERS is set to 1. */
|
configUSE_TIMERS is set to 1. Check that the infrustructure used by the
|
||||||
|
timer service task has been created/initialised. If timers have already
|
||||||
|
been created then the initialisation will already have been performed. */
|
||||||
prvCheckForValidListAndQueue();
|
prvCheckForValidListAndQueue();
|
||||||
|
|
||||||
if( xTimerQueue != NULL )
|
if( xTimerQueue != NULL )
|
||||||
{
|
{
|
||||||
xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Timers", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY, NULL );
|
xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Timers", configTIMER_TASK_STACK_DEPTH, NULL, configTIMER_TASK_PRIORITY, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
return xReturn;
|
return xReturn;
|
||||||
|
@ -146,9 +169,11 @@ xTIMER *pxNewTimer;
|
||||||
pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
|
pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
|
||||||
if( pxNewTimer != NULL )
|
if( pxNewTimer != NULL )
|
||||||
{
|
{
|
||||||
|
/* Ensure the infrustructure used by the timer service task has been
|
||||||
|
created/initialised. */
|
||||||
prvCheckForValidListAndQueue();
|
prvCheckForValidListAndQueue();
|
||||||
|
|
||||||
/* Initialise the timer structure members. */
|
/* Initialise the timer structure members using the function parameters. */
|
||||||
pxNewTimer->pcTimerName = pcTimerName;
|
pxNewTimer->pcTimerName = pcTimerName;
|
||||||
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
|
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
|
||||||
pxNewTimer->uxAutoReload = uxAutoReload;
|
pxNewTimer->uxAutoReload = uxAutoReload;
|
||||||
|
@ -166,68 +191,57 @@ portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime )
|
||||||
portBASE_TYPE xReturn = pdFAIL;
|
portBASE_TYPE xReturn = pdFAIL;
|
||||||
xTIMER_MESSAGE xMessage;
|
xTIMER_MESSAGE xMessage;
|
||||||
|
|
||||||
|
/* A timer cannot be started unless it is created, and creating a timer
|
||||||
|
will have resulted in the timer queue also being created. */
|
||||||
if( xTimerQueue != NULL )
|
if( xTimerQueue != NULL )
|
||||||
{
|
{
|
||||||
xMessage.xMessageID = tmrSTART;
|
/* Send a command to the timer service task to start the xTimer timer. */
|
||||||
|
xMessage.xMessageID = tmrCOMMAND_START;
|
||||||
xMessage.pxTimer = ( xTIMER * ) xTimer;
|
xMessage.pxTimer = ( xTIMER * ) xTimer;
|
||||||
|
|
||||||
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
|
prvSendMessageToTimerServiceTask( &xMessage, xBlockTime );
|
||||||
}
|
}
|
||||||
|
|
||||||
return xReturn;
|
return xReturn;
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void *pvTimerGetTimerID( xTimerHandle xTimer )
|
|
||||||
{
|
|
||||||
xTIMER *pxTimer = ( xTIMER * ) xTimer;
|
|
||||||
|
|
||||||
return pxTimer->pvTimerID;
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static void prvRemoveTimerFromActiveList( xTIMER *pxTimer )
|
|
||||||
{
|
|
||||||
/* Is the timer already in the list of active timers? */
|
|
||||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
|
||||||
{
|
|
||||||
/* The timer is in the list, remove it. */
|
|
||||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
|
||||||
|
|
||||||
static void prvTimerTask( void *pvParameters )
|
static void prvTimerTask( void *pvParameters )
|
||||||
{
|
{
|
||||||
portTickType xNextWakeTime, xTimeNow;
|
portTickType xNextExpireTime, xTimeNow;
|
||||||
xTIMER *pxTimer;
|
xTIMER *pxTimer;
|
||||||
xTIMER_MESSAGE xMessage;
|
|
||||||
|
|
||||||
/* Just to avoid compiler warnings. */
|
/* Just to avoid compiler warnings. */
|
||||||
( void ) pvParameters;
|
( void ) pvParameters;
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
|
/* Timers are listed in expiry time order, with the head of the list
|
||||||
|
referencing the task that will expire first. Obtain the time at which
|
||||||
|
the timer with the nearest expiry time will expire. If there are no
|
||||||
|
active timers then just set the next expire time to the maximum possible
|
||||||
|
time to ensure this task does not run unnecessarily. */
|
||||||
if( listLIST_IS_EMPTY( &xActiveTimerList ) == pdFALSE )
|
if( listLIST_IS_EMPTY( &xActiveTimerList ) == pdFALSE )
|
||||||
{
|
{
|
||||||
xNextWakeTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );
|
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xNextWakeTime = portMAX_DELAY;
|
xNextExpireTime = portMAX_DELAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( xNextWakeTime <= xTaskGetTickCount() )
|
/* Has the timer expired? */
|
||||||
|
if( xNextExpireTime <= xTaskGetTickCount() )
|
||||||
{
|
{
|
||||||
/* Remove the timer from the list. This functionality relies on
|
/* Remove the timer from the list of active timers. */
|
||||||
the list of active timers not being accessed from outside of this
|
|
||||||
task. */
|
|
||||||
pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );
|
pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );
|
||||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||||
|
|
||||||
|
/* If the timer is an autoreload timer then calculate the next
|
||||||
|
expiry time and re-insert the timer in the list of active timers. */
|
||||||
if( pxTimer->uxAutoReload == pdTRUE )
|
if( pxTimer->uxAutoReload == pdTRUE )
|
||||||
{
|
{
|
||||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextWakeTime + pxTimer->xTimerPeriodInTicks ) );
|
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );
|
||||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,31 +250,60 @@ xTIMER_MESSAGE xMessage;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Calculate the block time. */
|
/* Block this task until the next timer expires, or a command is
|
||||||
|
received. */
|
||||||
taskENTER_CRITICAL();
|
taskENTER_CRITICAL();
|
||||||
{
|
{
|
||||||
xTimeNow = xTaskGetTickCount();
|
xTimeNow = xTaskGetTickCount();
|
||||||
if( xTimeNow < xNextWakeTime )
|
if( xTimeNow < xNextExpireTime )
|
||||||
{
|
{
|
||||||
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextWakeTime - xTimeNow ) );
|
/* This is a simple fast function - a yield will not be
|
||||||
|
performed until after this critical section exits. */
|
||||||
|
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
/* Yield to wait for either a command to arrive, or the block time
|
||||||
|
to expire. If a command arrived between the critical section being
|
||||||
|
exited and this yeild then the yield will just return to the same
|
||||||
|
task. */
|
||||||
portYIELD_WITHIN_API();
|
portYIELD_WITHIN_API();
|
||||||
|
|
||||||
while( xQueueReceive( xTimerQueue, &xMessage, timerNO_DELAY ) != pdFAIL )
|
/* Empty the command queue, if it contains any commands. */
|
||||||
|
prvProcessReceivedCommands();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvProcessReceivedCommands( void )
|
||||||
{
|
{
|
||||||
|
xTIMER_MESSAGE xMessage;
|
||||||
|
portTickType xTimeToExpire;
|
||||||
|
xTIMER *pxTimer;
|
||||||
|
|
||||||
|
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
|
||||||
|
{
|
||||||
|
pxTimer = xMessage.pxTimer;
|
||||||
|
|
||||||
|
/* Is the timer already in the list of active timers? */
|
||||||
|
prvRemoveTimerFromActiveList( pxTimer );
|
||||||
|
|
||||||
switch( xMessage.xMessageID )
|
switch( xMessage.xMessageID )
|
||||||
{
|
{
|
||||||
case tmrSTART : prvTimerStart( xMessage.pxTimer );
|
case tmrCOMMAND_START : /* Start or restart a timer. */
|
||||||
|
xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;
|
||||||
|
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );
|
||||||
|
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
||||||
|
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default : /* Don't expect to get here. */
|
default : /* Don't expect to get here. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvCheckForValidListAndQueue( void )
|
static void prvCheckForValidListAndQueue( void )
|
||||||
|
@ -280,24 +323,41 @@ static void prvCheckForValidListAndQueue( void )
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvTimerStart( xTIMER *pxTimer )
|
void *pvTimerGetTimerID( xTimerHandle xTimer )
|
||||||
{
|
{
|
||||||
portTickType xTimeToWake;
|
xTIMER *pxTimer = ( xTIMER * ) xTimer;
|
||||||
|
|
||||||
if( pxTimer != NULL )
|
return pxTimer->pvTimerID;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void prvRemoveTimerFromActiveList( xTIMER *pxTimer )
|
||||||
{
|
{
|
||||||
/* Is the timer already in the list of active timers? */
|
/* Is the timer already in the list of active timers? */
|
||||||
prvRemoveTimerFromActiveList( pxTimer );
|
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
||||||
|
{
|
||||||
xTimeToWake = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;
|
/* The timer is in the list, remove it. */
|
||||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToWake );
|
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
|
||||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
static portBASE_TYPE prvSendMessageToTimerServiceTask( xTIMER_MESSAGE *pxMessage, portTickType xBlockTime )
|
||||||
|
{
|
||||||
|
portBASE_TYPE xReturn;
|
||||||
|
|
||||||
|
if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
|
||||||
|
{
|
||||||
|
xReturn = xQueueSendToBack( xTimerQueue, pxMessage, xBlockTime );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xReturn = xQueueSendToBack( xTimerQueue, pxMessage, tmrNO_DELAY );
|
||||||
|
}
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue