#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
\r
/* IDs for commands that can be sent/received on the timer queue. */\r
-#define tmrSTART 0\r
+#define tmrCOMMAND_START 0\r
\r
/* Misc definitions. */\r
-#define timerNO_DELAY ( portTickType ) 0U\r
+#define tmrNO_DELAY ( portTickType ) 0U\r
\r
/* The definition of the timers themselves. */\r
typedef struct tmrTimerControl\r
*/\r
static void prvRemoveTimerFromActiveList( xTIMER *pxTimer ) PRIVILEGED_FUNCTION;\r
\r
+/*\r
+ * Send pxMessage to xTimerQueue using a block time of xBlockTime if the \r
+ * scheduler is running, or a block time of zero if the scheduler is not\r
+ * running.\r
+ */\r
+static portBASE_TYPE prvSendMessageToTimerServiceTask( xTIMER_MESSAGE *pxMessage, portTickType xBlockTime ) PRIVILEGED_FUNCTION;\r
+\r
+/* \r
+ * Initialise the infrustructure used by the timer service task if it has not\r
+ * been initialised already.\r
+ */\r
static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;\r
\r
/*\r
- * The timer service task (daemon).\r
+ * The timer service task (daemon). Timer functionality is controlled by this\r
+ * task. Other tasks communicate with the timer service task using the \r
+ * xTimerQueue queue.\r
*/\r
static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;\r
\r
+/* \r
+ * The following functions handle the commands that are sent to the timer\r
+ * service task via the xTimerQueue queue.\r
+ */\r
+static void prvTimerStart( xTIMER *pxTimer ) PRIVILEGED_FUNCTION;\r
\r
-/* Handlers for commands received on the timer queue. */\r
-static void prvTimerStart( xTIMER *pxTimer );\r
+/*\r
+ * Called by the timer service task to interpret and process a command it\r
+ * received on the timer queue. \r
+ */\r
+static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;\r
\r
/*-----------------------------------------------------------*/\r
\r
portBASE_TYPE xReturn = pdFAIL;\r
\r
/* This function is called when the scheduler is started if \r
- configUSE_TIMERS is set to 1. */\r
+ configUSE_TIMERS is set to 1. Check that the infrustructure used by the\r
+ timer service task has been created/initialised. If timers have already\r
+ been created then the initialisation will already have been performed. */\r
prvCheckForValidListAndQueue();\r
\r
if( xTimerQueue != NULL )\r
{\r
- xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Timers", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY, NULL );\r
+ xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Timers", configTIMER_TASK_STACK_DEPTH, NULL, configTIMER_TASK_PRIORITY, NULL );\r
}\r
\r
return xReturn;\r
pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );\r
if( pxNewTimer != NULL )\r
{\r
+ /* Ensure the infrustructure used by the timer service task has been\r
+ created/initialised. */\r
prvCheckForValidListAndQueue();\r
\r
- /* Initialise the timer structure members. */\r
+ /* Initialise the timer structure members using the function parameters. */\r
pxNewTimer->pcTimerName = pcTimerName;\r
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;\r
pxNewTimer->uxAutoReload = uxAutoReload;\r
portBASE_TYPE xReturn = pdFAIL;\r
xTIMER_MESSAGE xMessage;\r
\r
+ /* A timer cannot be started unless it is created, and creating a timer\r
+ will have resulted in the timer queue also being created. */\r
if( xTimerQueue != NULL )\r
{\r
- xMessage.xMessageID = tmrSTART;\r
+ /* Send a command to the timer service task to start the xTimer timer. */\r
+ xMessage.xMessageID = tmrCOMMAND_START;\r
xMessage.pxTimer = ( xTIMER * ) xTimer;\r
\r
- xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );\r
+ prvSendMessageToTimerServiceTask( &xMessage, xBlockTime );\r
}\r
\r
return xReturn;\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void *pvTimerGetTimerID( xTimerHandle xTimer )\r
-{\r
-xTIMER *pxTimer = ( xTIMER * ) xTimer;\r
-\r
- return pxTimer->pvTimerID;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRemoveTimerFromActiveList( xTIMER *pxTimer )\r
-{\r
- /* Is the timer already in the list of active timers? */\r
- if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )\r
- {\r
- /* The timer is in the list, remove it. */\r
- vListRemove( &( pxTimer->xTimerListItem ) );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
static void prvTimerTask( void *pvParameters )\r
{\r
-portTickType xNextWakeTime, xTimeNow;\r
+portTickType xNextExpireTime, xTimeNow;\r
xTIMER *pxTimer;\r
-xTIMER_MESSAGE xMessage;\r
\r
/* Just to avoid compiler warnings. */\r
( void ) pvParameters;\r
\r
for( ;; )\r
{\r
+ /* Timers are listed in expiry time order, with the head of the list\r
+ referencing the task that will expire first. Obtain the time at which\r
+ the timer with the nearest expiry time will expire. If there are no\r
+ active timers then just set the next expire time to the maximum possible\r
+ time to ensure this task does not run unnecessarily. */\r
if( listLIST_IS_EMPTY( &xActiveTimerList ) == pdFALSE )\r
{\r
- xNextWakeTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );\r
+ xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );\r
}\r
else\r
{\r
- xNextWakeTime = portMAX_DELAY;\r
+ xNextExpireTime = portMAX_DELAY;\r
}\r
\r
- if( xNextWakeTime <= xTaskGetTickCount() )\r
+ /* Has the timer expired? */\r
+ if( xNextExpireTime <= xTaskGetTickCount() )\r
{\r
- /* Remove the timer from the list. This functionality relies on\r
- the list of active timers not being accessed from outside of this\r
- task. */\r
+ /* Remove the timer from the list of active timers. */\r
pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );\r
vListRemove( &( pxTimer->xTimerListItem ) );\r
\r
+ /* If the timer is an autoreload timer then calculate the next\r
+ expiry time and re-insert the timer in the list of active timers. */\r
if( pxTimer->uxAutoReload == pdTRUE )\r
{\r
- listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextWakeTime + pxTimer->xTimerPeriodInTicks ) );\r
+ listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );\r
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
}\r
\r
}\r
else\r
{\r
- /* Calculate the block time. */\r
+ /* Block this task until the next timer expires, or a command is\r
+ received. */\r
taskENTER_CRITICAL();\r
{\r
xTimeNow = xTaskGetTickCount();\r
- if( xTimeNow < xNextWakeTime )\r
+ if( xTimeNow < xNextExpireTime )\r
{\r
- vQueueWaitForMessageRestricted( xTimerQueue, ( xNextWakeTime - xTimeNow ) );\r
+ /* This is a simple fast function - a yield will not be \r
+ performed until after this critical section exits. */\r
+ vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );\r
}\r
}\r
taskEXIT_CRITICAL();\r
+\r
+ /* Yield to wait for either a command to arrive, or the block time \r
+ to expire. If a command arrived between the critical section being \r
+ exited and this yeild then the yield will just return to the same\r
+ task. */\r
portYIELD_WITHIN_API();\r
\r
- while( xQueueReceive( xTimerQueue, &xMessage, timerNO_DELAY ) != pdFAIL )\r
- {\r
- switch( xMessage.xMessageID )\r
- {\r
- case tmrSTART : prvTimerStart( xMessage.pxTimer );\r
+ /* Empty the command queue, if it contains any commands. */\r
+ prvProcessReceivedCommands();\r
+ }\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvProcessReceivedCommands( void )\r
+{\r
+xTIMER_MESSAGE xMessage;\r
+portTickType xTimeToExpire;\r
+xTIMER *pxTimer;\r
+\r
+ while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )\r
+ {\r
+ pxTimer = xMessage.pxTimer;\r
+\r
+ /* Is the timer already in the list of active timers? */\r
+ prvRemoveTimerFromActiveList( pxTimer );\r
+\r
+ switch( xMessage.xMessageID )\r
+ {\r
+ case tmrCOMMAND_START : /* Start or restart a timer. */\r
+ xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;\r
+ listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );\r
+ listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
+ vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
break;\r
- default : /* Don't expect to get here. */\r
+\r
+ default : /* Don't expect to get here. */\r
break;\r
- }\r
- }\r
}\r
}\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
-static void prvTimerStart( xTIMER *pxTimer )\r
+void *pvTimerGetTimerID( xTimerHandle xTimer )\r
{\r
-portTickType xTimeToWake;\r
+xTIMER *pxTimer = ( xTIMER * ) xTimer;\r
\r
- if( pxTimer != NULL )\r
- {\r
- /* Is the timer already in the list of active timers? */\r
- prvRemoveTimerFromActiveList( pxTimer );\r
+ return pxTimer->pvTimerID;\r
+}\r
+/*-----------------------------------------------------------*/\r
\r
- xTimeToWake = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;\r
- listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToWake );\r
- listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
- vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
+static void prvRemoveTimerFromActiveList( xTIMER *pxTimer )\r
+{\r
+ /* Is the timer already in the list of active timers? */\r
+ if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )\r
+ {\r
+ /* The timer is in the list, remove it. */\r
+ vListRemove( &( pxTimer->xTimerListItem ) );\r
}\r
}\r
+/*-----------------------------------------------------------*/\r
\r
+static portBASE_TYPE prvSendMessageToTimerServiceTask( xTIMER_MESSAGE *pxMessage, portTickType xBlockTime )\r
+{\r
+portBASE_TYPE xReturn;\r
\r
+ if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )\r
+ {\r
+ xReturn = xQueueSendToBack( xTimerQueue, pxMessage, xBlockTime );\r
+ }\r
+ else\r
+ {\r
+ xReturn = xQueueSendToBack( xTimerQueue, pxMessage, tmrNO_DELAY );\r
+ }\r
\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
\r
\r
\r