]> git.sur5r.net Git - freertos/commitdiff
Continue work on timers module - work in progress.
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Tue, 8 Feb 2011 16:21:15 +0000 (16:21 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Tue, 8 Feb 2011 16:21:15 +0000 (16:21 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1278 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

Source/timers.c

index e28b78f3adebceb7ab805ea84995fc2ea75223bd..e1d464db0e1a3a31af943d33d3303b0b75fc26c1 100644 (file)
@@ -66,10 +66,10 @@ task.h is included from an application file. */
 #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
@@ -108,16 +108,37 @@ PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
  */\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
@@ -126,12 +147,14 @@ portBASE_TYPE xTimerCreateTimerTask( void )
 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
@@ -146,9 +169,11 @@ xTIMER *pxNewTimer;
        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
@@ -166,68 +191,57 @@ portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime )
 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
@@ -236,28 +250,57 @@ xTIMER_MESSAGE xMessage;
                }\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
@@ -280,24 +323,41 @@ static void prvCheckForValidListAndQueue( void )
 }\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