Continue work on timers module - work in progress.
diff --git a/Source/timers.c b/Source/timers.c
index e28b78f..e1d464d 100644
--- a/Source/timers.c
+++ b/Source/timers.c
@@ -66,10 +66,10 @@
 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE

 

 /* IDs for commands that can be sent/received on the timer queue. */

-#define tmrSTART		0

+#define tmrCOMMAND_START		0

 

 /* Misc definitions. */

-#define timerNO_DELAY	( portTickType ) 0U

+#define tmrNO_DELAY		( portTickType ) 0U

 

 /* The definition of the timers themselves. */

 typedef struct tmrTimerControl

@@ -108,16 +108,37 @@
  */

 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;

 

 /*

- * 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;

 

+/* 

+ * 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 xReturn = pdFAIL;

 

 	/* 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();

 

 	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;

@@ -146,9 +169,11 @@
 	pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );

 	if( pxNewTimer != NULL )

 	{

+		/* Ensure the infrustructure used by the timer service task has been

+		created/initialised. */

 		prvCheckForValidListAndQueue();

 

-		/* Initialise the timer structure members. */

+		/* Initialise the timer structure members using the function parameters. */

 		pxNewTimer->pcTimerName = pcTimerName;

 		pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;

 		pxNewTimer->uxAutoReload = uxAutoReload;

@@ -166,68 +191,57 @@
 portBASE_TYPE xReturn = pdFAIL;

 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 )

 	{

-		xMessage.xMessageID = tmrSTART;

+		/* Send a command to the timer service task to start the xTimer timer. */

+		xMessage.xMessageID = tmrCOMMAND_START;

 		xMessage.pxTimer = ( xTIMER * ) xTimer;

 

-		xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );

+		prvSendMessageToTimerServiceTask( &xMessage, xBlockTime );

 	}

 

 	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 )

 {

-portTickType xNextWakeTime, xTimeNow;

+portTickType xNextExpireTime, xTimeNow;

 xTIMER *pxTimer;

-xTIMER_MESSAGE xMessage;

 

 	/* Just to avoid compiler warnings. */

 	( void ) pvParameters;

 

 	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 )

 		{

-			xNextWakeTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );

+			xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );

 		}

 		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

-			the list of active timers not being accessed from outside of this

-			task. */

+			/* Remove the timer from the list of active timers. */

 			pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );

 			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 )

 			{

-				listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextWakeTime + pxTimer->xTimerPeriodInTicks ) );

+				listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );

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

 			}

 

@@ -236,28 +250,57 @@
 		}

 		else

 		{

-			/* Calculate the block time. */

+			/* Block this task until the next timer expires, or a command is

+			received. */

 			taskENTER_CRITICAL();

 			{

 				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();

+

+			/* 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();

 

-			while( xQueueReceive( xTimerQueue, &xMessage, timerNO_DELAY ) != pdFAIL )

-			{

-				switch( xMessage.xMessageID )

-				{

-					case tmrSTART	:	prvTimerStart( xMessage.pxTimer );

+			/* 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 )

+		{

+			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;

-					default			:	/* Don't expect to get here. */

+

+			default			:			/* Don't expect to get here. */

 										break;

-				}

-			}

 		}

 	}

 }

@@ -280,24 +323,41 @@
 }

 /*-----------------------------------------------------------*/

 

-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? */

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

 	{

-		/* Is the timer already in the list of active timers? */

-		prvRemoveTimerFromActiveList( pxTimer );

-

-		xTimeToWake = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;

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

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

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

+		/* The timer is in the list, remove it. */

+		vListRemove( &( 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;

+}

+/*-----------------------------------------------------------*/