From caef8f007e887b267e84d0eaa948ef1fb9753df9 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Tue, 8 Feb 2011 15:20:29 +0000 Subject: [PATCH] Start an optional timers module implementation. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1276 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- Source/timers.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 Source/timers.c diff --git a/Source/timers.c b/Source/timers.c new file mode 100644 index 000000000..e28b78f3a --- /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 ) +{ +} +/*-----------------------------------------------------------*/ -- 2.39.5