From 475b1cbd6a8b81b33c7a50cc6d51ddee55e666d1 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Thu, 21 Nov 2013 21:46:08 +0000 Subject: [PATCH] Add event_groups.c and associated functions in other core files. Added xTimerPendCallbackFromISR() to provide a centralised deferred interrupt handling mechanism. Add xPortGetLowestEverFreeHeapSize() to heap_4.c. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2112 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/event_groups.c | 442 +++++++++++++++ FreeRTOS/Source/include/FreeRTOS.h | 19 +- FreeRTOS/Source/include/event_groups.h | 625 ++++++++++++++++++++++ FreeRTOS/Source/include/list.h | 26 +- FreeRTOS/Source/include/portable.h | 1 + FreeRTOS/Source/include/projdefs.h | 6 +- FreeRTOS/Source/include/task.h | 39 +- FreeRTOS/Source/include/timers.h | 96 +++- FreeRTOS/Source/portable/MemMang/heap_4.c | 12 + FreeRTOS/Source/tasks.c | 123 ++++- FreeRTOS/Source/timers.c | 208 ++++--- 11 files changed, 1514 insertions(+), 83 deletions(-) create mode 100644 FreeRTOS/Source/event_groups.c create mode 100644 FreeRTOS/Source/include/event_groups.h diff --git a/FreeRTOS/Source/event_groups.c b/FreeRTOS/Source/event_groups.c new file mode 100644 index 000000000..eb186c191 --- /dev/null +++ b/FreeRTOS/Source/event_groups.c @@ -0,0 +1,442 @@ +/* + FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + 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 modification 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include + +/* 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 + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "event_groups.h" + +/* Lint e961 and e750 are suppressed as a MISRA exception justified because the +MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the +header files above, but not in this file, in order to generate the correct +privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ + +#if ( INCLUDE_xEventGroupSetBitFromISR == 1 ) && ( configUSE_TIMERS == 0 ) + #error configUSE_TIMERS must be set to 1 to make the xEventGroupSetBitFromISR() function available. +#endif + +#if ( INCLUDE_xEventGroupSetBitFromISR == 1 ) && ( INCLUDE_xTimerPendCallbackFromISR == 0 ) + #error INCLUDE_xTimerPendCallbackFromISR must also be set to one to make the xEventGroupSetBitFromISR() function available. +#endif + + +#if configUSE_16_BIT_TICKS == 1 + #define taskCLEAR_EVENTS_ON_EXIT_BIT 0x0100U + #define taskUNBLOCKED_DUE_TO_BIT_SET_BIT 0x0200U + #define taskWAIT_FOR_ALL_BITS 0x0400U + #define taskEVENT_BITS_CONTROL_BYTES 0xff00U +#else + #define taskCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL + #define taskUNBLOCKED_DUE_TO_BIT_SET_BIT 0x02000000UL + #define taskWAIT_FOR_ALL_BITS 0x04000000UL + #define taskEVENT_BITS_CONTROL_BYTES 0xff000000UL +#endif + +typedef struct EventBitsDefinition +{ + xEventBitsType uxEventBits; + xList xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */ +} xEVENT_BITS; + +/* Used internally only. */ +typedef struct EVENT_GROUP_CALLBACK_PARAMTERS +{ + xEventGroupHandle xTargetEventGroup; + xEventBitsType xBitsToSet; +} xEventGroupCallbackParameters; + +/*-----------------------------------------------------------*/ + +xEventGroupHandle xEventGroupCreate( void ) +{ +xEVENT_BITS *pxEventBits; + + pxEventBits = pvPortMalloc( sizeof( xEVENT_BITS ) ); + if( pxEventBits != NULL ) + { + pxEventBits->uxEventBits = 0; + vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + } + + return ( xEventGroupHandle ) pxEventBits; +} +/*-----------------------------------------------------------*/ + +xEventBitsType xEventGroupSync( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToSet, xEventBitsType uxBitsToWaitFor, portTickType xBlockTime ) +{ +xEventBitsType uxOriginalBitValue, uxReturn; +xEVENT_BITS *pxEventBits = ( xEVENT_BITS * ) xEventGroup; +portBASE_TYPE xYieldedAlready; + + vTaskSuspendAll(); + { + uxOriginalBitValue = pxEventBits->uxEventBits; + + ( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet ); + + if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + /* All the rendezvous bits will have been set once this task set + its bits - no need to block. */ + uxReturn = ( uxOriginalBitValue | uxBitsToSet ); + + /* Rendezvous always clear the bits. They will have been cleared + already unless this is the only task in the rendezvous. */ + pxEventBits->uxEventBits &= uxBitsToWaitFor; + + xBlockTime = 0; + } + else + { + if( xBlockTime != ( portTickType ) 0 ) + { + /* Store the bits that the calling task is waiting for in the + task's event list item so the kernel knows when a match is + found. Then enter the blocked state. */ + vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | taskCLEAR_EVENTS_ON_EXIT_BIT | taskWAIT_FOR_ALL_BITS ), xBlockTime ); + } + else + { + /* The rendezvous bits were not set, but no block time was + specified - just return the current event bit value. */ + uxReturn = pxEventBits->uxEventBits; + } + } + } + xYieldedAlready = xTaskResumeAll(); + + if( xBlockTime != ( portTickType ) 0 ) + { + if( xYieldedAlready == pdFALSE ) + { + portYIELD_WITHIN_API(); + } + + /* The task blocked to wait for its required bits to be set - at this + point either the required bits were set or the block time expired. If + the required bits were set they will have been stored in the task's + event list item, and they should now be retrieved then cleared. */ + uxReturn = uxTaskResetEventItemValue(); + + if( ( uxReturn & taskUNBLOCKED_DUE_TO_BIT_SET_BIT ) == ( xEventBitsType ) 0 ) + { + /* The task timed out, just return the current event bit value. */ + uxReturn = pxEventBits->uxEventBits; + } + else + { + /* The task unblocked because the bits were set. Clear the control + bits before returning the value. */ + uxReturn &= ~taskEVENT_BITS_CONTROL_BYTES; + } + } + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +xEventBitsType xEventGroupWaitBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToWaitFor, portBASE_TYPE xClearOnExit, portBASE_TYPE xWaitForAllBits, portTickType xBlockTime ) +{ +xEVENT_BITS *pxEventBits = ( xEVENT_BITS * ) xEventGroup; +const xEventBitsType uxCurrentEventBits = pxEventBits->uxEventBits; +xEventBitsType uxReturn, uxControlBits = 0; + + /* Check the user is not attempting to wait on the bits used by the kernel + itself, and that at least one bit is being requested. */ + configASSERT( ( uxBitsToWaitFor & taskEVENT_BITS_CONTROL_BYTES ) == 0 ); + configASSERT( uxBitsToWaitFor != 0 ); + + taskENTER_CRITICAL(); + { + if( xWaitForAllBits == pdFALSE ) + { + /* Task only has to wait for one bit within uxBitsToWaitFor to be set. Is + one already set? */ + if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( xEventBitsType ) 0 ) + { + /* At least one of the bits was set. No need to block. */ + xBlockTime = 0; + } + } + else + { + /* Task has to wait for all the bits in uxBitsToWaitFor to be set. Are they + set already? */ + if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor ) + { + /* All the bits were set, no need to block. */ + xBlockTime = 0; + } + } + + /* The task can return now if either its wait condition is already met + or the requested block time is 0. */ + if( xBlockTime == ( portTickType ) 0 ) + { + /* No need to block, just set the return value. */ + uxReturn = uxCurrentEventBits; + + if( xClearOnExit != pdFALSE ) + { + /* The user requested the bits be cleared again prior to exiting + this function. */ + pxEventBits->uxEventBits &= ~uxBitsToWaitFor; + } + } + else + { + /* The task is going to block to wait for its required bits to be + set. uxControlBits are used to remember the specified behaviour of + this call to xEventGroupWaitBits() - for use when the event bits + unblock the task. */ + if( xClearOnExit != pdFALSE ) + { + uxControlBits |= taskCLEAR_EVENTS_ON_EXIT_BIT; + } + + if( xWaitForAllBits != pdFALSE ) + { + uxControlBits |= taskWAIT_FOR_ALL_BITS; + } + + /* Store the bits that the calling task is waiting for in the + task's event list item so the kernel knows when a match is + found. Then enter the blocked state. */ + vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xBlockTime ); + portYIELD_WITHIN_API(); + } + } + taskEXIT_CRITICAL(); + + if( xBlockTime != ( portTickType ) 0 ) + { + /* The task blocked to wait for its required bits to be set - at this + point either the required bits were set or the block time expired. If + the required bits were set they will have been stored in the task's + event list item, and they should now be retrieved then cleared. */ + uxReturn = uxTaskResetEventItemValue(); + + if( ( uxReturn & taskUNBLOCKED_DUE_TO_BIT_SET_BIT ) == ( xEventBitsType ) 0 ) + { + /* The task timed out, just return the current event bit value. */ + uxReturn = pxEventBits->uxEventBits; + } + else + { + /* The task unblocked because the bits were set. Clear the control + bits before returning the value. */ + uxReturn &= ~taskEVENT_BITS_CONTROL_BYTES; + } + } + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +xEventBitsType xEventGroupClearBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToClear ) +{ +xEVENT_BITS *pxEventBits = ( xEVENT_BITS * ) xEventGroup; +xEventBitsType uxReturn; + + /* Check the user is not attempting to clear the bits used by the kernel + itself. */ + configASSERT( ( uxBitsToClear & taskEVENT_BITS_CONTROL_BYTES ) == 0 ); + + uxBitsToClear = ~uxBitsToClear; + taskENTER_CRITICAL(); + { + /* The value returned is the event group value prior to the bits being + cleared. */ + uxReturn = pxEventBits->uxEventBits; + + /* Clear the bits. */ + pxEventBits->uxEventBits &= uxBitsToClear; + } + taskEXIT_CRITICAL(); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + +xEventBitsType xEventGroupSetBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToSet ) +{ +xListItem *pxListItem, *pxNext; +xListItem const *pxListEnd; +xList *pxList; +xEventBitsType uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits; +xEVENT_BITS *pxEventBits = ( xEVENT_BITS * ) xEventGroup; +portBASE_TYPE xMatchFound = pdFALSE; + + /* Check the user is not attempting to set the bits used by the kernel + itself. */ + configASSERT( ( uxBitsToSet & taskEVENT_BITS_CONTROL_BYTES ) == 0 ); + + pxList = &( pxEventBits->xTasksWaitingForBits ); + pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ + pxListItem = listGET_HEAD_ENTRY( pxList ); + vTaskSuspendAll(); + { + /* Set the bits. */ + pxEventBits->uxEventBits |= uxBitsToSet; + + /* See if the new bit value should unblock any tasks. */ + while( pxListItem != pxListEnd ) + { + pxNext = listGET_NEXT( pxListItem ); + uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem ); + + /* Split the bits waited for from the control bits. */ + uxControlBits = uxBitsWaitedFor & taskEVENT_BITS_CONTROL_BYTES; + uxBitsWaitedFor &= ~taskEVENT_BITS_CONTROL_BYTES; + + if( ( uxControlBits & taskWAIT_FOR_ALL_BITS ) == ( xEventBitsType ) 0 ) + { + /* Just looking for single bit being set. */ + if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( xEventBitsType ) 0 ) + { + xMatchFound = pdTRUE; + } + } + else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor ) + { + /* All bits are set. */ + xMatchFound = pdTRUE; + } + else + { + /* Need all bits to be set, but not all the bits were set. */ + } + + if( xMatchFound != pdFALSE ) + { + /* The bits match. Should the bits be cleared on exit? */ + if( ( uxControlBits & taskCLEAR_EVENTS_ON_EXIT_BIT ) != ( xEventBitsType ) 0 ) + { + uxBitsToClear |= uxBitsWaitedFor; + } + + /* Store the actual event flag value in the task's event list + item before removing the task from the event list. The + taskUNBLOCKED_DUE_TO_BIT_SET_BIT bit is set so the task knows + that is was unblocked due to its required bits matching, rather + than because it timed out. */ + ( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | taskUNBLOCKED_DUE_TO_BIT_SET_BIT ); + } + + /* Move onto the next list item. Note pxListItem->pxNext is not + used here as the list item may have been removed from the event list + and inserted into the ready/pending reading list. */ + pxListItem = pxNext; + } + + /* Clear any bits that matched when the taskCLEAR_EVENTS_ON_EXIT_BIT + bit was set in the control word. */ + pxEventBits->uxEventBits &= ~uxBitsToClear; + } + ( void ) xTaskResumeAll(); + + return pxEventBits->uxEventBits; +} +/*-----------------------------------------------------------*/ + +void vEventGroupDelete( xEventGroupHandle xEventGroup ) +{ +xEVENT_BITS *pxEventBits = ( xEVENT_BITS * ) xEventGroup; +const xList *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); + + vTaskSuspendAll(); + { + while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( unsigned portBASE_TYPE ) 0 ) + { + /* Unblock the task, returning 0 as the event list is being deleted + and cannot therefore have any bits set. */ + configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( xListItem * ) &( pxTasksWaitingForBits->xListEnd ) ); + ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, ( portTickType ) 0 ); + } + + vPortFree( pxEventBits ); + } + ( void ) xTaskResumeAll(); +} +/*-----------------------------------------------------------*/ + +/* For internal use only - execute a 'set bits' command that was pended from +an interrupt. */ +void vEventGroupSetBitsCallback( void *pvEventGroup, unsigned long ulBitsToSet ) +{ + ( void ) xEventGroupSetBits( pvEventGroup, ( xEventBitsType ) ulBitsToSet ); +} + + diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index 5956500cc..f8e68f86f 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -92,9 +92,10 @@ is included as it is used by the port layer. */ conform. */ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); - - - +/* The type that holds event bits always matches portTickType - therefore the +number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1, +32 bits if set to 0. */ +typedef portTickType xEventBitsType; /* * Check all the required application specific macros have been defined. @@ -190,6 +191,10 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #define configUSE_TIMERS 0 #endif +#ifndef configUSE_EVENT_GROUPS + #define configUSE_EVENT_GROUPS 0 +#endif + #ifndef configUSE_COUNTING_SEMAPHORES #define configUSE_COUNTING_SEMAPHORES 0 #endif @@ -218,6 +223,14 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); #define INCLUDE_xTaskResumeFromISR 1 #endif +#ifndef INCLUDE_xEventGroupSetBitFromISR + #define INCLUDE_xEventGroupSetBitFromISR 0 +#endif + +#ifndef INCLUDE_xTimerPendCallbackFromISR + #define INCLUDE_xTimerPendCallbackFromISR 0 +#endif + #ifndef configASSERT #define configASSERT( x ) #define configASSERT_DEFINED 0 diff --git a/FreeRTOS/Source/include/event_groups.h b/FreeRTOS/Source/include/event_groups.h new file mode 100644 index 000000000..36a4c85b3 --- /dev/null +++ b/FreeRTOS/Source/include/event_groups.h @@ -0,0 +1,625 @@ +/* + FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + 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 modification 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef EVENT_GROUPS_H +#define EVENT_GROUPS_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h" must appear in source files before "include event_groups.h" +#endif + +#include "timers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * An event group is a collection of bits to which an application can assign a + * meaning. For example, an application may create an event group to convey + * the status of various CAN bus related events in which bit 0 might mean "A CAN + * message has been received and is ready for processing", bit 1 might mean "The + * application has queued a message that is ready for sending onto the CAN + * network", and bit 2 might mean "it is time to send a SYNC message onto the + * CAN network" etc. A task can then test the bit values to see which events + * are active, and optionally enter the Blocked state to wait for a specified + * bit or a group of specified bits to be active. To continue the CAN bus + * example, a CAN controlling task can enter the Blocked state (and therefore + * not consume any processing time) until either bit 0, bit 1 or bit 2 are + * active, at which time the bit that was actually active would inform the task + * which action it had to take (process a received message, send a message, or + * send a SYNC). + * + * The event groups implementation contains intelligence to avoid race + * conditions that would otherwise occur were an application to use a simple + * variable for the same purpose. This is particularly important with respect + * to when a bit within an event group is to be cleared, and when bits have to + * be set and then tested atomically - as is the case where event groups are + * used to create a synchronisation point between multiple tasks (a + * 'rendezvous'). + * + * \defgroup EventGroup + */ + + + +/** + * event_groups.h + * + * Type by which event groups are referenced. For example, a call to + * xEventGroupCreate() returns an xEventGroupHandle variable that can then + * be used as a parameter to other event group functions. + * + * \defgroup xEventGroupHandle xEventGroupHandle + * \ingroup EventGroup + */ +typedef void * xEventGroupHandle; + +/** + * event_groups.h + *
+ xEventGroupHandle xEventGroupCreate( void );
+ 
+ * + * Create a new event group. This function cannot be called from an interrupt. + * + * Although event groups are not related to ticks, for internal implementation + * reasons the number of bits available for use in an event group is dependent + * on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If + * configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit + * 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has + * 24 usable bits (bit 0 to bit 23). The xEventBitsType type is used to store + * event bits within an event group. + * + * @return If the event group was created then a handle to the event group is + * returned. If there was insufficient FreeRTOS heap available to create the + * event group then NULL is returned. See http://www.freertos.org/a00111.html + * + * Example usage: +
+	// Declare a variable to hold the created event group.
+	xEventGroupHandle xCreatedEventGroup;
+
+	// Attempt to create the event group.
+	xCreatedEventGroup = xEventGroupCreate();
+
+	// Was the event group created successfully?
+	if( xCreatedEventGroup == NULL )
+	{
+		// The event group was not created because there was insufficient
+		// FreeRTOS heap available.
+	}
+	else
+	{
+		// The event group was created.
+	}
+   
+ * \defgroup xEventGroupCreate xEventGroupCreate + * \ingroup EventGroup + */ +xEventGroupHandle xEventGroupCreate( void ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	xEventBitsType xEventGroupWaitBits( xEventGroupHandle xEventGroup,
+										xEventBitsType uxBitsToWaitFor,
+										portBASE_TYPE xClearOnExit,
+										portBASE_TYPE xWaitForAllBits,
+										portTickType xBlockTime );
+ 
+ * + * [Potentially] block to wait for one or more bits to be set within a + * previously created event group. + * + * This function cannot be called from an interrupt. + * + * @param xEventGroup The event group in which the bits are being tested. The + * event group must have previously been created using a call to + * xEventGroupCreate(). + * + * @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test + * inside the event group. For example, to wait for bit 0 and/or bit 2 set + * uxBitsToWaitFor to 0x05. To wait for bits 0 and/or bit 1 and/or bit 2 set + * uxBitsToWaitFor to 0x07. Etc. + * + * @param xClearOnExit If xClearOnExit is set to pdTRUE then any bits within + * uxBitsToWaitFor that are set within the event group will be cleared before + * xEventGroupWaitBits() returns. If xClearOnExit is set to pdFALSE then the + * bits set in the event group are not altered when the call to + * xEventGroupWaitBits() returns. + * + * @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then + * xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor + * are set or the specified block time expires. If xWaitForAllBits is set to + * pdFALSE then xEventGroupWaitBits() will return when any one of the bits set + * in uxBitsToWaitFor is set or the specified block time expires. + * + * @param xBlockTime The maximum amount of time (specified in 'ticks') to wait + * for one/all (depending on the xWaitForAllBits value) of the bits specified by + * uxBitsToWaitFor to become set. + * + * @return The value of the event group at the time either the bits being waited + * for became set, or the block time expired. Test the return value to know + * which bits were set. If xEventGroupWaitBits() returned because its timeout + * expired then not all the bits being waited for will be set. If + * xEventGroupWaitBits() returned because the bits it was waiting for were set + * then the returned value is the event group value before any bits were + * automatically cleared because the xClearOnExit parameter was set to pdTRUE. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( xEventGroupHandle xEventGroup )
+   {
+   xEventBitsType uxBits;
+   const portTickType xBlockTime = 100 / portTICK_RATE_MS;
+
+		// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
+		// the event group.  Clear the bits before exiting.
+		uxBits = xEventGroupWaitBits(
+					xEventGroup,	// The event group being tested.
+					BIT_0 | BIT_4,	// The bits within the event group to wait for.
+					pdTRUE,			// BIT_0 and BIT_4 should be cleared before returning.
+					pdFALSE,		// Don't wait for both bits, either bit will do.
+					xBlockTime );	// Wait a maximum of 100ms for either bit to be set.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// xEventGroupWaitBits() returned because both bits were set.
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// xEventGroupWaitBits() returned because just BIT_0 was set.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// xEventGroupWaitBits() returned because just BIT_4 was set.
+		}
+		else
+		{
+			// xEventGroupWaitBits() returned because xBlockTime ticks passed
+			// without either BIT_0 or BIT_4 becoming set.
+		}
+   }
+   
+ * \defgroup xEventGroupWaitBits xEventGroupWaitBits + * \ingroup EventGroup + */ +xEventBitsType xEventGroupWaitBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToWaitFor, portBASE_TYPE xClearOnExit, portBASE_TYPE xWaitForAllBits, portTickType xBlockTime ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	xEventBitsType xEventGroupClearBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToClear );
+ 
+ * + * Clear bits within an event group. This function cannot be called from an + * interrupt. + * + * @param xEventGroup The event group in which the bits are to be cleared. + * + * @param uxBitsToClear A bitwise value that indicates the bit or bits to clear + * in the event group. For example, to clear bit 3 only, set uxBitsToClear to + * 0x08. To clear bit 3 and bit 0 set uxBitsToClear to 0x09. + * + * @return The value of the event group before the specified bits were cleared. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( xEventGroupHandle xEventGroup )
+   {
+   xEventBitsType uxBits;
+
+		// Clear bit 0 and bit 4 in xEventGroup.
+		uxBits = xEventGroupClearBits(
+								xEventGroup,	// The event group being updated.
+								BIT_0 | BIT_4 );// The bits being cleared.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// Both bit 0 and bit 4 were set before the call to
+			// xEventGroupClearBits() was called.  Both will now be clear (not
+			// set).
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// Bit 0 was set before xEventGroupClearBits() was called.  It will
+			// now be clear.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// Bit 4 was set before xEventGroupClearBits() was called.  It will
+			// now be clear.
+		}
+		else
+		{
+			// Neither bit 0 nor bit 4 were set in the first place.
+		}
+   }
+   
+ * \defgroup xEventGroupClearBits xEventGroupClearBits + * \ingroup EventGroup + */ +xEventBitsType xEventGroupClearBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToClear ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	xEventBitsType xEventGroupSetBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToSet );
+ 
+ * + * Set bits within an event group. + * This function cannot be called from an interrupt. xEventGroupSetBitsFromISR() + * is a version that can be called from an interrupt. + * + * Setting bits in an event group will automatically unblock tasks that are + * blocked waiting for the bits. + * + * @param xEventGroup The event group in which the bits are to be set. + * + * @param uxBitsToSet A bitwise value that indicates the bit or bits to set. + * For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3 + * and bit 0 set uxBitsToSet to 0x09. + * + * @return The value of the event group at the time the call to + * xEventGroupSetBits() returns. There are two reasons why the returned value + * might have the bits specified by the uxBitsToSet parameter cleared. First, + * if setting a bit results in a task that was waiting for the bit leaving the + * blocked state then it is possible the bit will be cleared automatically + * (see the xClearBitOnExit parameter of xEventGroupWaitBits()). Second, any + * unblocked (or otherwise Ready state) task that has a priority above that of + * the task that called xEventGroupSetBits() will execute and may change the + * event group value before the call to xEventGroupSetBits() returns. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   void aFunction( xEventGroupHandle xEventGroup )
+   {
+   xEventBitsType uxBits;
+
+		// Set bit 0 and bit 4 in xEventGroup.
+		uxBits = xEventGroupSetBits(
+							xEventGroup,	// The event group being updated.
+							BIT_0 | BIT_4 );// The bits being set.
+
+		if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
+		{
+			// Both bit 0 and bit 4 remained set when the function returned.
+		}
+		else if( ( uxBits & BIT_0 ) != 0 )
+		{
+			// Bit 0 remained set when the function returned, but bit 4 was
+			// cleared.  It might be that bit 4 was cleared automatically as a
+			// task that was waiting for bit 4 was removed from the Blocked
+			// state.
+		}
+		else if( ( uxBits & BIT_4 ) != 0 )
+		{
+			// Bit 4 remained set when the function returned, but bit 0 was
+			// cleared.  It might be that bit 0 was cleared automatically as a
+			// task that was waiting for bit 0 was removed from the Blocked
+			// state.
+		}
+		else
+		{
+			// Neither bit 0 nor bit 4 remained set.  It might be that a task
+			// was waiting for either or both of the bits to be set, and the
+			// bits were cleared as the task left the Blocked state.
+		}
+   }
+   
+ * \defgroup xEventGroupSetBits xEventGroupSetBits + * \ingroup EventGroup + */ +xEventBitsType xEventGroupSetBits( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToSet ) PRIVILEGED_FUNCTION; + +/** + * event_groups.h + *
+	xEventBitsType xEventGroupSetBitsFromISR( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToSet, portBASE_TYPE *pxHigherPriorityTaskWoken );
+ 
+ * + * A version of xEventGroupSetBits() that can be called from an interrupt. + * + * Setting bits in an event group is not a deterministic operation because there + * are an unknown number of tasks that may be waiting for the bit or bits being + * set. FreeRTOS does not allow nondeterministic operations to be performed in + * interrupts or from critical sections. Therefore xEventGroupSetBitFromISR() + * sends a message to the timer task to have the set operation performed in the + * context of the timer task - where a scheduler lock is used in place of a + * critical section. + * + * @param xEventGroup The event group in which the bits are to be set. + * + * @param uxBitsToSet A bitwise value that indicates the bit or bits to set. + * For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3 + * and bit 0 set uxBitsToSet to 0x09. + * + * @ pxHigherPriorityTaskWoken As mentioned above, calling this function will + * result in a message being sent to the timer daemon task. If the priority of + * the timer daemon task is higher than the priority of the currently running + * task (the task the interrupt interrupted) then *pxHigherPriorityTaskWoken + * will be set to pdTRUE by xEventGroupSetBitsFromISR(), indicating that a + * context switch should be requested before the interrupt exits. For that + * reason *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the + * example code below. + * + * @return If the callback request was registered successfully then pdPASS is + * returned, otherwise pdFALSE is returned. pdFALSE will be returned if the + * timer service queue was full. + * + * Example usage: +
+   #define BIT_0	( 1 << 0 )
+   #define BIT_4	( 1 << 4 )
+
+   // An event group which it is assume has already been created by a call to
+   // xEventGroupCreate().
+   xEventGroupHandle xEventGroup;
+
+   void anInterruptHandler( void )
+   {
+   portBASE_TYPE xHigherPriorityTaskWoken;
+
+		// xHigherPriorityTaskWoken must be initialised to pdFALSE;
+		xHigherPriorityTaskWoken = pdFALSE;
+
+		// Set bit 0 and bit 4 in xEventGroup.
+		uxBits = xEventGroupSetBitsFromISR(
+							xEventGroup,	// The event group being updated.
+							BIT_0 | BIT_4   // The bits being set.
+							&xHigherPriorityTaskWoken );
+
+		// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
+		// switch should be requested.  The macro used is port specific and will
+		// be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to
+		// the documentation page for the port being used.
+		portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
+   }
+   
+ * \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR + * \ingroup EventGroup + */ +#define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendCallbackFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( unsigned long ) uxBitsToSet, pxHigherPriorityTaskWoken ) + +/** + * event_groups.h + *
+	xEventBitsType xEventGroupSync(	xEventGroupHandle xEventGroup,
+									xEventBitsType uxBitsToSet,
+									xEventBitsType uxBitsToWaitFor,
+									portTickType xBlockTime );
+ 
+ * + * Atomically set bits within an event group, then wait for a combination of + * bits to be set within the same event group. This functionality is typically + * used to synchronise multiple tasks, where each task has to wait for the other + * tasks to reach a synchronisation point before proceeding. + * + * This function cannot be used from an interrupt. + * + * The function will return before its block time expires if the bits specified + * by the uxBitsToWait parameter are set, or become set within that time. In + * this case all the bits specified by uxBitsToWait will be automatically + * cleared before the function returns. + * + * @param xEventGroup The event group in which the bits are being tested. The + * event group must have previously been created using a call to + * xEventGroupCreate(). + * + * @param uxBitsToSet The bits to set in the event group before determining + * if, and possibly waiting for, all the bits specified by the uxBitsToWait + * parameter are set. + * + * @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test + * inside the event group. For example, to wait for bit 0 and bit 2 set + * uxBitsToWaitFor to 0x05. To wait for bits 0 and bit 1 and bit 2 set + * uxBitsToWaitFor to 0x07. Etc. + * + * @param xBlockTime The maximum amount of time (specified in 'ticks') to wait + * for all of the bits specified by uxBitsToWaitFor to become set. + * + * @return The value of the event group at the time either the bits being waited + * for became set, or the block time expired. Test the return value to know + * which bits were set. If xEventGroupSync() returned because its timeout + * expired then not all the bits being waited for will be set. If + * xEventGroupSync() returned because all the bits it was waiting for were + * set then the returned value is the event group value before any bits were + * automatically cleared. + * + * Example usage: +
+ // Bits used by the three tasks.
+ #define TASK_0_BIT		( 1 << 0 )
+ #define TASK_1_BIT		( 1 << 1 )
+ #define TASK_2_BIT		( 1 << 2 )
+
+ #define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
+
+ // Use an event group to synchronise three tasks.  It is assumed this event
+ // group has already been created elsewhere.
+ xEventGroupHandle xEventBits;
+
+ void vTask0( void *pvParameters )
+ {
+ xEventBitsType uxReturn;
+ portTickType xBlockTime = 100 / portTICK_RATE_MS;
+
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 0 in the event flag to note this task has reached the
+		// sync point.  The other two tasks will set the other two bits defined
+		// by ALL_SYNC_BITS.  All three tasks have reached the synchronisation
+		// point when all the ALL_SYNC_BITS are set.  Wait a maximum of 100ms
+		// for this to happen.
+		uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xBlockTime );
+
+		if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
+		{
+			// All three tasks reached the synchronisation point before the call
+			// to xEventGroupSync() timed out.
+		}
+	}
+ }
+
+ void vTask1( void *pvParameters )
+ {
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 1 in the event flag to note this task has reached the
+		// synchronisation point.  The other two tasks will set the other two
+		// bits defined by ALL_SYNC_BITS.  All three tasks have reached the
+		// synchronisation point when all the ALL_SYNC_BITS are set.  Wait
+		// indefinitely for this to happen.
+		xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
+
+		// xEventGroupSync() was called with an indefinite block time, so
+		// this task will only reach here if the syncrhonisation was made by all
+		// three tasks, so there is no need to test the return value.
+	 }
+ }
+
+ void vTask2( void *pvParameters )
+ {
+	 for( ;; )
+	 {
+		// Perform task functionality here.
+
+		// Set bit 2 in the event flag to note this task has reached the
+		// synchronisation point.  The other two tasks will set the other two
+		// bits defined by ALL_SYNC_BITS.  All three tasks have reached the
+		// synchronisation point when all the ALL_SYNC_BITS are set.  Wait
+		// indefinitely for this to happen.
+		xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
+
+		// xEventGroupSync() was called with an indefinite block time, so
+		// this task will only reach here if the syncrhonisation was made by all
+		// three tasks, so there is no need to test the return value.
+	}
+ }
+
+ 
+ * \defgroup xEventGroupSync xEventGroupSync + * \ingroup EventGroup + */ +xEventBitsType xEventGroupSync( xEventGroupHandle xEventGroup, xEventBitsType uxBitsToSet, xEventBitsType uxBitsToWaitFor, portTickType xBlockTime ) PRIVILEGED_FUNCTION; + + +/** + * event_groups.h + *
+	xEventBitsType xEventGroupGetBits( xEventGroupHandle xEventGroup );
+ 
+ * + * Returns the current value of the bits in an event group. This function + * cannot be used from an interrupt. + * + * @param xEventGroup The event group being queried. + * + * @return The event group bits at the time xEventGroupGetBits() was called. + * + * \defgroup xEventGroupGetBits xEventGroupGetBits + * \ingroup EventGroup + */ +#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 ) + +/** + * event_groups.h + *
+	void xEventGroupDelete( xEventGroupHandle xEventGroup );
+ 
+ * + * Delete an event group that was previously created by a call to + * xEventGroupCreate(). Tasks that are blocked on the event group will be + * unblocked and obtain 0 as the event group's value. + * + * @param xEventGroup The event group being deleted. + */ +void vEventGroupDelete( xEventGroupHandle xEventGroup ); + +/* For internal use only. */ +void vEventGroupSetBitsCallback( void *pvEventGroup, unsigned long ulBitsToSet ); + + +#ifdef __cplusplus +} +#endif + +#endif /* EVENT_GROUPS_H */ + + diff --git a/FreeRTOS/Source/include/list.h b/FreeRTOS/Source/include/list.h index cc70e0689..a49368893 100644 --- a/FreeRTOS/Source/include/list.h +++ b/FreeRTOS/Source/include/list.h @@ -205,7 +205,31 @@ typedef struct xLIST * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE * \ingroup LinkedList */ -#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->xItemValue ) +#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext ) + +/* + * Return the list item at the head of the list. + * + * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY + * \ingroup LinkedList + */ +#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext ) + +/* + * Return the list item that marks the end of the list + * + * \page listGET_END_MARKER listGET_END_MARKER + * \ingroup LinkedList + */ +#define listGET_END_MARKER( pxList ) ( ( xListItem const * ) ( &( ( pxList )->xListEnd ) ) ) /* * Access macro to determine if a list contains any items. The macro will diff --git a/FreeRTOS/Source/include/portable.h b/FreeRTOS/Source/include/portable.h index 1240ecf60..9af5eb27d 100644 --- a/FreeRTOS/Source/include/portable.h +++ b/FreeRTOS/Source/include/portable.h @@ -368,6 +368,7 @@ void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION; void vPortFree( void *pv ) PRIVILEGED_FUNCTION; void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; +size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION; /* * Setup the hardware ready for the scheduler to take control. This generally diff --git a/FreeRTOS/Source/include/projdefs.h b/FreeRTOS/Source/include/projdefs.h index f292a0854..74aa84f0d 100644 --- a/FreeRTOS/Source/include/projdefs.h +++ b/FreeRTOS/Source/include/projdefs.h @@ -1,5 +1,5 @@ /* - FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. + FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -69,6 +69,10 @@ /* Defines the prototype to which task functions must conform. */ typedef void (*pdTASK_CODE)( void * ); +/* Defines the prototype to which callback functions called from the RTOS/timer +daemon task must conform. */ +typedef void (*pdAPPLICATION_CALLBACK_CODE)( void *, unsigned long ); + #define pdFALSE ( ( portBASE_TYPE ) 0 ) #define pdTRUE ( ( portBASE_TYPE ) 1 ) diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index ba7b32d7b..d7330a974 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -1378,15 +1378,26 @@ portBASE_TYPE xTaskIncrementTick( void ) PRIVILEGED_FUNCTION; * there be no higher priority tasks waiting on the same event) or * the delay period expires. * + * The 'unordered' version replaces the event list item value with the + * xItemValue value, and inserts the list item at the end of the list. + * + * The 'ordered' version uses the existing event list item value (which is the + * owning tasks priority) to insert the list item into the event list is task + * priority order. + * * @param pxEventList The list containing tasks that are blocked waiting * for the event to occur. * + * @param xItemValue The item value to use for the event list item when the + * event list is not ordered by task priority. + * * @param xTicksToWait The maximum amount of time that the task should wait * for the event to occur. This is specified in kernel ticks,the constant * portTICK_RATE_MS can be used to convert kernel ticks into a real time * period. */ void vTaskPlaceOnEventList( xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; +void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN @@ -1412,13 +1423,23 @@ void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xT * Removes a task from both the specified event list and the list of blocked * tasks, and places it on a ready queue. * - * xTaskRemoveFromEventList () will be called if either an event occurs to - * unblock a task, or the block timeout period expires. + * xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called + * if either an event occurs to unblock a task, or the block timeout period + * expires. + * + * xTaskRemoveFromEventList() is used when the event list is in task priority + * order. It removes the list item from the head of the event list as that will + * have the highest priority owning task of all the tasks on the event list. + * xTaskRemoveFromUnorderedEventList() is used when the event list is not + * ordered and the event list items hold something other than the owning tasks + * priority. In this case the event list item value is updated to the value + * passed in the xItemValue parameter. * * @return pdTRUE if the task being removed has a higher priority than the task * making the call, otherwise pdFALSE. */ signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) PRIVILEGED_FUNCTION; +signed portBASE_TYPE xTaskRemoveFromUnorderedEventList( xListItem * pxEventListItem, portTickType xItemValue ) PRIVILEGED_FUNCTION; /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY @@ -1430,6 +1451,12 @@ signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) */ void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION; +/* + * THESE FUNCTIONS MUST NOT BE USED FROM APPLICATION CODE. THEY ARE USED BY + * THE EVENT BITS MODULE. + */ +portTickType uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION; + /* * Return the handle of the calling task. */ @@ -1479,13 +1506,13 @@ signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed ch /* * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. */ -unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ); +unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ) PRIVILEGED_FUNCTION; /* * Set the uxTCBNumber of the task referenced by the xTask parameter to * ucHandle. */ -void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ); +void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ) PRIVILEGED_FUNCTION; /* * If tickless mode is being used, or a low power mode is implemented, then @@ -1494,7 +1521,7 @@ void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ); * to date with the actual execution time by being skipped forward by the by * a time equal to the idle period. */ -void vTaskStepTick( portTickType xTicksToJump ); +void vTaskStepTick( portTickType xTicksToJump ) PRIVILEGED_FUNCTION; /* * Provided for use within portSUPPRESS_TICKS_AND_SLEEP() to allow the port @@ -1509,7 +1536,7 @@ void vTaskStepTick( portTickType xTicksToJump ); * critical section between the timer being stopped and the sleep mode being * entered to ensure it is ok to proceed into the sleep mode. */ -eSleepModeStatus eTaskConfirmSleepModeStatus( void ); +eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION; #ifdef __cplusplus } diff --git a/FreeRTOS/Source/include/timers.h b/FreeRTOS/Source/include/timers.h index 01a09f371..f41ac583b 100644 --- a/FreeRTOS/Source/include/timers.h +++ b/FreeRTOS/Source/include/timers.h @@ -1,5 +1,5 @@ /* - FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. + FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -83,6 +83,7 @@ extern "C" { /* IDs for commands that can be sent/received on the timer queue. These are to be used solely through the macros that make up the public software timer API, as defined below. */ +#define tmrCOMMAND_EXECUTE_CALLBACK ( ( portBASE_TYPE ) -1 ) #define tmrCOMMAND_START ( ( portBASE_TYPE ) 0 ) #define tmrCOMMAND_STOP ( ( portBASE_TYPE ) 1 ) #define tmrCOMMAND_CHANGE_PERIOD ( ( portBASE_TYPE ) 2 ) @@ -170,7 +171,7 @@ typedef void (*tmrTIMER_CALLBACK)( xTimerHandle xTimer ); * * // Optionally do something if the pxTimer parameter is NULL. * configASSERT( pxTimer ); - * + * * // Which timer expired? * lArrayIndex = ( long ) pvTimerGetTimerID( pxTimer ); * @@ -293,7 +294,7 @@ void *pvTimerGetTimerID( xTimerHandle xTimer ) PRIVILEGED_FUNCTION; portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer ) PRIVILEGED_FUNCTION; /** - * xTimerGetTimerDaemonTaskHandle() is only available if + * xTimerGetTimerDaemonTaskHandle() is only available if * INCLUDE_xTimerGetTimerDaemonTaskHandle is set to 1 in FreeRTOSConfig.h. * * Simply returns the handle of the timer service/daemon task. It it not valid @@ -944,6 +945,95 @@ xTaskHandle xTimerGetTimerDaemonTaskHandle( void ); */ #define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U ) + +/** + * portBASE_TYPE xTimerPendCallbackFromISR( pdAPPLICATION_CALLBACK_CODE pvCallbackFunction, + * void *pvParameter1, + * unsigned long ulParameter2, + * portBASE_TYPE *pxHigherPriorityTaskWoken ); + * + * + * Can be used by interrupt service routines to request that a function (the + * callback function) is executed from a task context. + * + * Ideally an interrupt service routine (ISR) is kept as short as possible, but + * sometimes an ISR either has a lot of processing to do, or needs to perform + * processing that is not deterministic. In these cases the processing can be + * deferred to be performed in a task - allowing the ISR to exit. The timer + * daemon service/daemon task is already responsible for executing software + * timer callback functions, so is also used to executed callback functions that + * are pended from interrupts. + * + * A mechanism is provided that allows the interrupt to return directly to the + * task that will subsequently execute the pended callback function. This + * allows the callback function to execute contiguously in time with the + * interrupt - just as if the callback had executed in the interrupt itself. + * + * @param pvCallbackFunction The function to execute from the timer service/ + * daemon task. The function must conform to the pdAPPLICATION_CALLBACK_CODE + * prototype. + * + * @param pvParameter1 The value of the callback function's first parameter. + * The parameter has a void * type to allow it to be used to pass any type. + * For example, unsigned longs can be cast to a void *, or the void * can be + * used to point to a structure. + * + * @param ulParameter2 The value of the callback function's second parameter. + * + * @param pxHigherPriorityTaskWoken As mentioned above, calling this function + * will result in a message being sent to the timer daemon task. If the + * priority of the timer daemon task (which is set using + * configTIMER_TASK_PRIORITY in FreeRTOSConfig.h) is higher than the priority of + * the currently running task (the task the interrupt interrupted) then + * *pxHigherPriorityTaskWoken will be set to pdTRUE within + * xTimerPendCallbackFromISR(), indicating that a context switch should be + * requested before the interrupt exits. For that reason + * *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the + * example code below. + * + * Example usage: + * @verbatim + * + * // The callback function that will execute in the context of the daemon task. + * // Note callback functions must all use this same prototype. + * void vProcessInterface( void *pvParameter1, unsigned long ulParameter2 ) + * { + * portBASE_TYPE xInterfaceToService; + * + * // The interface that requires servicing is passed in the second + * // parameter. The first parameter is not used in this case. + * xInterfaceToService = ( portBASE_TYPE ) ulParameter2; + * + * // ...Perform the processing here... + * } + * + * // An ISR that receives data packets from multiple interfaces + * void vAnISR( void ) + * { + * portBASE_TYPE xInterfaceToService, xHigherPriorityTaskWoken; + * + * // Query the hardware to determine which interface needs processing. + * xInterfaceToService = prvCheckInterfaces(); + * + * // The actual processing is to be deferred to a task. Request the + * // vProcessInterface() callback function is executed, passing in the + * // number of the interface that needs processing. The interface to + * // service is passed in the second parameter. The first parameter is + * // not used in this case. + * xHigherPriorityTaskWoken = pdFALSE; + * xTimerPendCallbackFromISR( vProcessInterface, NULL, ( unsigned long ) xInterfaceToService, &xHigherPriorityTaskWoken ); + * + * // If xHigherPriorityTaskWoken is now set to pdTRUE then a context + * // switch should be requested. The macro used is port specific and will + * // be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - refer to + * // the documentation page for the port being used. + * portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + * + * } + * @endverbatim + */ +portBASE_TYPE xTimerPendCallbackFromISR( pdAPPLICATION_CALLBACK_CODE pvCallbackFunction, void *pvParameter1, unsigned long ulParameter2, portBASE_TYPE *pxHigherPriorityTaskWoken ); + /* * Functions beyond this part are not part of the public API and are intended * for use by the kernel only. diff --git a/FreeRTOS/Source/portable/MemMang/heap_4.c b/FreeRTOS/Source/portable/MemMang/heap_4.c index 21a202ee8..4ed42b8de 100644 --- a/FreeRTOS/Source/portable/MemMang/heap_4.c +++ b/FreeRTOS/Source/portable/MemMang/heap_4.c @@ -134,6 +134,7 @@ static xBlockLink xStart, *pxEnd = NULL; /* Keeps track of the number of free bytes remaining, but says nothing about fragmentation. */ static size_t xFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK ); +static size_t xMinimumEverFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK ); /* Gets set to the top bit of an size_t type. When this bit in the xBlockSize member of an xBlockLink structure is set then the block belongs to the @@ -223,6 +224,11 @@ void *pvReturn = NULL; xFreeBytesRemaining -= pxBlock->xBlockSize; + if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) + { + xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; + } + /* The block is being returned - it is allocated and owned by the application and has no "next" block. */ pxBlock->xBlockSize |= xBlockAllocatedBit; @@ -295,6 +301,12 @@ size_t xPortGetFreeHeapSize( void ) } /*-----------------------------------------------------------*/ +size_t xPortGetMinimumEverFreeHeapSize( void ) +{ + return xMinimumEverFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + void vPortInitialiseBlocks( void ) { /* This just exists to keep the linker quiet. */ diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index c0f151958..f23143271 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -169,7 +169,6 @@ typedef struct tskTaskControlBlock } tskTCB; - /* * Some kernel aware debuggers require the data the debugger needs access to to * be global, rather than file scope. @@ -1327,7 +1326,9 @@ void vTaskEndScheduler( void ) void vTaskSuspendAll( void ) { /* A critical section is not required as the variable is of type - portBASE_TYPE. */ + portBASE_TYPE. Please read Richard Barry's reply in the following link to a + post in the FreeRTOS support forum before reporting this as a bug! - + http://goo.gl/wu4acr */ ++uxSchedulerSuspended; } /*----------------------------------------------------------*/ @@ -1938,6 +1939,60 @@ portTickType xTimeToWake; } /*-----------------------------------------------------------*/ +void vTaskPlaceOnUnorderedEventList( xList * pxEventList, portTickType xItemValue, portTickType xTicksToWait ) +{ +portTickType xTimeToWake; + + configASSERT( pxEventList ); + + /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE + SCHEDULER SUSPENDED. */ + + /* Store the item value in the event list item. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), xItemValue ); + + /* Place the event list item of the TCB at the end of the appropriate event + list. */ + vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + + /* The task must be removed from the ready list before it is added to the + blocked list. Exclusive access can be assured to the ready list as the + scheduler is locked. */ + if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( unsigned portBASE_TYPE ) 0 ) + { + /* The current task must be in a ready list, so there is no need to + check, and the port reset macro can be called directly. */ + portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( xTicksToWait == portMAX_DELAY ) + { + /* Add the task to the suspended task list instead of a delayed task + list to ensure it is not woken by a timing event. It will block + indefinitely. */ + vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) ); + } + else + { + /* Calculate the time at which the task should be woken if the event does + not occur. This may overflow but this doesn't matter. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + } + #else /* INCLUDE_vTaskSuspend */ + { + /* Calculate the time at which the task should be woken if the event does + not occur. This may overflow but this doesn't matter. */ + xTimeToWake = xTickCount + xTicksToWait; + prvAddCurrentTaskToDelayedList( xTimeToWake ); + } + #endif /* INCLUDE_vTaskSuspend */ +} +/*-----------------------------------------------------------*/ + #if configUSE_TIMERS == 1 void vTaskPlaceOnEventListRestricted( xList * const pxEventList, portTickType xTicksToWait ) @@ -2034,6 +2089,56 @@ portBASE_TYPE xReturn; } /*-----------------------------------------------------------*/ +signed portBASE_TYPE xTaskRemoveFromUnorderedEventList( xListItem * pxEventListItem, portTickType xItemValue ) +{ +tskTCB *pxUnblockedTCB; +portBASE_TYPE xReturn; + + /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE + SCHEDULER SUSPENDED. It can also be called from within an ISR. */ + + /* Store the new item value in the event list. */ + listSET_LIST_ITEM_VALUE( pxEventListItem, xItemValue ); + + /* Remove the TCB from the delayed list, and add it to the ready list. */ + + pxUnblockedTCB = ( tskTCB * ) listGET_LIST_ITEM_OWNER( pxEventListItem ); + configASSERT( pxUnblockedTCB ); + ( void ) uxListRemove( pxEventListItem ); + + if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE ) + { + ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); + prvAddTaskToReadyList( pxUnblockedTCB ); + } + else + { + /* Cannot access the delayed or ready lists, so will hold this task + pending until the scheduler is resumed. */ + vListInsertEnd( &( xPendingReadyList ), pxEventListItem ); + } + + if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority ) + { + /* Return true if the task removed from the event list has + a higher priority than the calling task. This allows + the calling task to know if it should force a context + switch now. */ + xReturn = pdTRUE; + + /* Mark that a yield is pending in case the user is not using the + "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) { configASSERT( pxTimeOut ); @@ -2973,6 +3078,20 @@ tskTCB *pxNewTCB; } #endif /* configGENERATE_RUN_TIME_STATS */ +/*-----------------------------------------------------------*/ +portTickType uxTaskResetEventItemValue( void ) +{ +portTickType uxReturn; + + uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ) ); + + /* Reset the event list item to its normal value - so it can be used with + queues and semaphores. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xEventListItem ), ( ( portTickType ) configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + + return uxReturn; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index aeaae2f30..eebc99646 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -1,5 +1,5 @@ /* - FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. + FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -76,6 +76,10 @@ task.h is included from an application file. */ #include "queue.h" #include "timers.h" +#if ( INCLUDE_xTimerPendCallbackFromISR == 1 ) && ( configUSE_TIMERS == 0 ) + #error configUSE_TIMERS must be set to 1 to make the INCLUDE_xTimerPendCallbackFromISR() function available. +#endif + /* Lint e961 and e750 are suppressed as a MISRA exception justified because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the header files above, but not in this file, in order to generate the correct @@ -103,14 +107,41 @@ typedef struct tmrTimerControl 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 +/* The definition of messages that can be sent and received on the timer queue. +Two types of message can be queued - messages that manipulate a software timer, +and messages that request the execution of a non-timer related callback. The +two message types are defined in two separate structures, xTimerParametersType +and xCallbackParametersType respectively. */ +typedef struct tmrTimerParameters { - portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */ portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ xTIMER * pxTimer; /*<< The timer to which the command will be applied. */ -} xTIMER_MESSAGE; +} xTimerParametersType; + + +typedef struct tmrCallbackParameters +{ + pdAPPLICATION_CALLBACK_CODE pxCallbackFunction; /* << The callback function to execute. */ + void *pvParameter1; /* << The value that will be used as the callback functions first parameter. */ + unsigned long ulParameter2; /* << The value that will be used as the callback functions second parameter. */ +} xCallbackParametersType; + +/* The structure that contains the two message types, along with an identifier +that is used to determine which message type is valid. */ +typedef struct tmrTimerQueueMessage +{ + portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */ + union + { + xTimerParametersType xTimerParameters; + + /* Don't include xCallbackParameters if it is not going to be used as + it makes the structure (and therefore the timer queue) larger. */ + #if ( INCLUDE_xTimerPendCallbackFromISR == 1 ) + xCallbackParametersType xCallbackParameters; + #endif /* INCLUDE_xTimerPendCallbackFromISR */ + } u; +} xDAEMON_TASK_MESSAGE; /*lint -e956 A manual analysis and inspection has been used to determine which static variables must be declared volatile. */ @@ -270,7 +301,7 @@ xTIMER *pxNewTimer; portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, signed portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime ) { portBASE_TYPE xReturn = pdFAIL; -xTIMER_MESSAGE xMessage; +xDAEMON_TASK_MESSAGE xMessage; /* Send a message to the timer service task to perform a particular action on a particular timer definition. */ @@ -278,8 +309,8 @@ xTIMER_MESSAGE xMessage; { /* Send a command to the timer service task to start the xTimer timer. */ xMessage.xMessageID = xCommandID; - xMessage.xMessageValue = xOptionalValue; - xMessage.pxTimer = ( xTIMER * ) xTimer; + xMessage.u.xTimerParameters.xMessageValue = xOptionalValue; + xMessage.u.xTimerParameters.pxTimer = ( xTIMER * ) xTimer; if( pxHigherPriorityTaskWoken == NULL ) { @@ -518,77 +549,98 @@ portBASE_TYPE xProcessTimerNow = pdFALSE; static void prvProcessReceivedCommands( void ) { -xTIMER_MESSAGE xMessage; +xDAEMON_TASK_MESSAGE xMessage; xTIMER *pxTimer; portBASE_TYPE xTimerListsWereSwitched, xResult; portTickType xTimeNow; while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */ { - pxTimer = xMessage.pxTimer; - - if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) + #if ( INCLUDE_xTimerPendCallbackFromISR == 1 ) { - /* The timer is in a list, remove it. */ - ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); - } + if( xMessage.xMessageID == tmrCOMMAND_EXECUTE_CALLBACK ) + { + const xCallbackParametersType * const pxCallback = &( xMessage.u.xCallbackParameters ); - traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue ); + /* The timer uses the xCallbackParameters member to request a + callback be executed. Check the callback is not NULL. */ + configASSERT( pxCallback ); - /* In this case the xTimerListsWereSwitched parameter is not used, but - it must be present in the function call. prvSampleTimeNow() must be - called after the message is received from xTimerQueue so there is no - possibility of a higher priority task adding a message to the message - queue with a time that is ahead of the timer daemon task (because it - pre-empted the timer daemon task after the xTimeNow value was set). */ - xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + /* Call the function. */ + pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 ); + } + } + #endif /* INCLUDE_xTimerPendCallbackFromISR */ - switch( xMessage.xMessageID ) + if( xMessage.xMessageID != tmrCOMMAND_EXECUTE_CALLBACK ) { - case tmrCOMMAND_START : - /* Start or restart a timer. */ - if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE ) - { - /* The timer expired before it was added to the active timer - list. Process it now. */ - pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); + /* The messages uses the xTimerParameters member to work on a + software timer. */ + pxTimer = xMessage.u.xTimerParameters.pxTimer; + + if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) + { + /* The timer is in a list, remove it. */ + ( void ) uxListRemove( &( pxTimer->xTimerListItem ) ); + } + + traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue ); - if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + /* In this case the xTimerListsWereSwitched parameter is not used, but + it must be present in the function call. prvSampleTimeNow() must be + called after the message is received from xTimerQueue so there is no + possibility of a higher priority task adding a message to the message + queue with a time that is ahead of the timer daemon task (because it + pre-empted the timer daemon task after the xTimeNow value was set). */ + xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); + + switch( xMessage.xMessageID ) + { + case tmrCOMMAND_START : + /* Start or restart a timer. */ + if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) == pdTRUE ) { - xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); - configASSERT( xResult ); - ( void ) xResult; + /* The timer expired before it was added to the active timer + list. Process it now. */ + pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer ); + + if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE ) + { + xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY ); + configASSERT( xResult ); + ( void ) xResult; + } } - } - break; - - case tmrCOMMAND_STOP : - /* The timer has already been removed from the active list. - There is nothing to do here. */ - break; - - case tmrCOMMAND_CHANGE_PERIOD : - pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue; - configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); - - /* The new period does not really have a reference, and can be - longer or shorter than the old one. The command time is - therefore set to the current time, and as the period cannot be - zero the next expiry time can only be in the future, meaning - (unlike for the xTimerStart() case above) there is no fail case - that needs to be handled here. */ - ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); - break; - - case tmrCOMMAND_DELETE : - /* The timer has already been removed from the active list, - just free up the memory. */ - vPortFree( pxTimer ); - break; - - default : - /* Don't expect to get here. */ - break; + break; + + case tmrCOMMAND_STOP : + /* The timer has already been removed from the active list. + There is nothing to do here. */ + break; + + case tmrCOMMAND_CHANGE_PERIOD : + pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; + configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); + + /* The new period does not really have a reference, and can be + longer or shorter than the old one. The command time is + therefore set to the current time, and as the period cannot be + zero the next expiry time can only be in the future, meaning + (unlike for the xTimerStart() case above) there is no fail case + that needs to be handled here. */ + ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); + break; + + case tmrCOMMAND_DELETE : + /* The timer has already been removed from the active list, + just free up the memory. */ + vPortFree( pxTimer ); + break; + + default : + /* Don't expect to get here. */ + break; + } } } } @@ -664,7 +716,7 @@ static void prvCheckForValidListAndQueue( void ) vListInitialise( &xActiveTimerList2 ); pxCurrentTimerList = &xActiveTimerList1; pxOverflowTimerList = &xActiveTimerList2; - xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) ); + xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xDAEMON_TASK_MESSAGE ) ); } } taskEXIT_CRITICAL(); @@ -698,6 +750,28 @@ xTIMER *pxTimer = ( xTIMER * ) xTimer; } /*-----------------------------------------------------------*/ +#if( INCLUDE_xTimerPendCallbackFromISR == 1 ) + + portBASE_TYPE xTimerPendCallbackFromISR( pdAPPLICATION_CALLBACK_CODE pvCallbackFunction, void *pvParameter1, unsigned long ulParameter2, portBASE_TYPE *pxHigherPriorityTaskWoken ) + { + xDAEMON_TASK_MESSAGE xMessage; + portBASE_TYPE xReturn; + + /* Complete the message with the function parameters and post it to the + daemon task. */ + xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK; + xMessage.u.xCallbackParameters.pxCallbackFunction = pvCallbackFunction; + xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; + xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2; + + xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken ); + + return xReturn; + } + +#endif /* INCLUDE_xTimerPendCallbackFromISR */ +/*-----------------------------------------------------------*/ + /* This entire source file will be skipped if the application is not configured to include software timer functionality. If you want to include software timer functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ -- 2.39.2