Start an optional timers module implementation.
diff --git a/Source/timers.c b/Source/timers.c
new file mode 100644
index 0000000..e28b78f
--- /dev/null
+++ b/Source/timers.c
@@ -0,0 +1,325 @@
+/* Need a method of switching to an overflow list. _RB_*/
+
+/*
+ FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
+
+ ***************************************************************************
+ * *
+ * If you are: *
+ * *
+ * + New to FreeRTOS, *
+ * + Wanting to learn FreeRTOS or multitasking in general quickly *
+ * + Looking for basic training, *
+ * + Wanting to improve your FreeRTOS skills and productivity *
+ * *
+ * then take a look at the FreeRTOS books - available as PDF or paperback *
+ * *
+ * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ * A pdf reference manual is also available. Both are usually delivered *
+ * to your inbox within 20 minutes to two hours when purchased between 8am *
+ * and 8pm GMT (although please allow up to 24 hours in case of *
+ * exceptional circumstances). Thank you for your support! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
+ ***NOTE*** The exception to the GPL is included to allow you to distribute
+ a combined work that includes FreeRTOS without being obliged to provide the
+ source code for proprietary components outside of the FreeRTOS kernel.
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details. You should have received a copy of the GNU General Public
+ License and the FreeRTOS license exception along with FreeRTOS; if not it
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained
+ by writing to Richard Barry, contact details for whom are available on the
+ FreeRTOS WEB site.
+
+ 1 tab == 4 spaces!
+
+ http://www.FreeRTOS.org - Documentation, latest information, license and
+ contact details.
+
+ http://www.SafeRTOS.com - A version that is certified for use in safety
+ critical systems.
+
+ http://www.OpenRTOS.com - Commercial support, development, porting,
+ licensing and training services.
+*/
+
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
+all the API functions to use the MPU wrappers. That should only be done when
+task.h is included from an application file. */
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "timers.h"
+
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
+
+/* IDs for commands that can be sent/received on the timer queue. */
+#define tmrSTART 0
+
+/* Misc definitions. */
+#define timerNO_DELAY ( portTickType ) 0U
+
+/* The definition of the timers themselves. */
+typedef struct tmrTimerControl
+{
+ const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */
+ xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
+ portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
+ unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */
+ void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
+ tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
+} xTIMER;
+
+/* The definition of messages that can be sent and received on the timer
+queue. */
+typedef struct tmrTimerQueueMessage
+{
+ portBASE_TYPE xMessageID;
+ portTickType xMessageValue;
+ xTIMER * pxTimer;
+} xTIMER_MESSAGE;
+
+
+/* The list in which active timers are stored. Timers are referenced in expire
+time order, with the nearest expiry time at the front of the list. Only the
+timer service task is allowed to access xActiveTimerList. */
+PRIVILEGED_DATA static xList xActiveTimerList;
+
+/* A queue that is used to send commands to the timer service task. */
+PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Called when a timer is about to be modified. If the timer is already in the
+ * list of active timers then it is removed prior to the modification.
+ */
+static void prvRemoveTimerFromActiveList( xTIMER *pxTimer ) PRIVILEGED_FUNCTION;
+
+static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
+
+/*
+ * The timer service task (daemon).
+ */
+static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
+
+
+/* Handlers for commands received on the timer queue. */
+static void prvTimerStart( xTIMER *pxTimer );
+
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerCreateTimerTask( void )
+{
+portBASE_TYPE xReturn = pdFAIL;
+
+ /* This function is called when the scheduler is started if
+ configUSE_TIMERS is set to 1. */
+ prvCheckForValidListAndQueue();
+
+ if( xTimerQueue != NULL )
+ {
+ xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Timers", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY, NULL );
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
+{
+xTIMER *pxNewTimer;
+
+ /* Allocate the timer structure. */
+ pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
+ if( pxNewTimer != NULL )
+ {
+ prvCheckForValidListAndQueue();
+
+ /* Initialise the timer structure members. */
+ pxNewTimer->pcTimerName = pcTimerName;
+ pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
+ pxNewTimer->uxAutoReload = uxAutoReload;
+ pxNewTimer->pvTimerID = pvTimerID;
+ pxNewTimer->pxCallbackFunction = pxCallbackFunction;
+ vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
+ }
+
+ return ( xTimerHandle ) pxNewTimer;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTimerStart( xTimerHandle xTimer, portTickType xBlockTime )
+{
+portBASE_TYPE xReturn = pdFAIL;
+xTIMER_MESSAGE xMessage;
+
+ if( xTimerQueue != NULL )
+ {
+ xMessage.xMessageID = tmrSTART;
+ xMessage.pxTimer = ( xTIMER * ) xTimer;
+
+ xReturn = xQueueSendToBack( xTimerQueue, &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;
+xTIMER *pxTimer;
+xTIMER_MESSAGE xMessage;
+
+ /* Just to avoid compiler warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ if( listLIST_IS_EMPTY( &xActiveTimerList ) == pdFALSE )
+ {
+ xNextWakeTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );
+ }
+ else
+ {
+ xNextWakeTime = portMAX_DELAY;
+ }
+
+ if( xNextWakeTime <= xTaskGetTickCount() )
+ {
+ /* Remove the timer from the list. This functionality relies on
+ the list of active timers not being accessed from outside of this
+ task. */
+ pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );
+ vListRemove( &( pxTimer->xTimerListItem ) );
+
+ if( pxTimer->uxAutoReload == pdTRUE )
+ {
+ listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextWakeTime + pxTimer->xTimerPeriodInTicks ) );
+ vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
+ }
+
+ /* Call the timer callback. */
+ pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
+ }
+ else
+ {
+ /* Calculate the block time. */
+ taskENTER_CRITICAL();
+ {
+ xTimeNow = xTaskGetTickCount();
+ if( xTimeNow < xNextWakeTime )
+ {
+ vQueueWaitForMessageRestricted( xTimerQueue, ( xNextWakeTime - xTimeNow ) );
+ }
+ }
+ taskEXIT_CRITICAL();
+ portYIELD_WITHIN_API();
+
+ while( xQueueReceive( xTimerQueue, &xMessage, timerNO_DELAY ) != pdFAIL )
+ {
+ switch( xMessage.xMessageID )
+ {
+ case tmrSTART : prvTimerStart( xMessage.pxTimer );
+ break;
+ default : /* Don't expect to get here. */
+ break;
+ }
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckForValidListAndQueue( void )
+{
+ /* Check that the list from which active timers are referenced, and the
+ queue used to communicate with the timer service, have been
+ initialised. */
+ taskENTER_CRITICAL();
+ {
+ if( xTimerQueue == NULL )
+ {
+ vListInitialise( &xActiveTimerList );
+ xTimerQueue = xQueueCreate( configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
+ }
+ }
+ taskEXIT_CRITICAL();
+}
+/*-----------------------------------------------------------*/
+
+static void prvTimerStart( xTIMER *pxTimer )
+{
+portTickType xTimeToWake;
+
+ if( pxTimer != NULL )
+ {
+ /* 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 ) );
+ }
+}
+
+
+
+
+
+
+
+
+
+
+portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
+{
+ return pdFALSE;
+}
+
+void vTimerStop( xTimerHandle xTimer )
+{
+}
+
+
+void vTimerChangePeriod( xTimerHandle xTimer )
+{
+}
+
+void vTimerDelete( xTimerHandle xTimer )
+{
+}
+/*-----------------------------------------------------------*/