]> git.sur5r.net Git - freertos/commitdiff
Add event_groups.c and associated functions in other core files.
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Thu, 21 Nov 2013 21:46:08 +0000 (21:46 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Thu, 21 Nov 2013 21:46:08 +0000 (21:46 +0000)
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 [new file with mode: 0644]
FreeRTOS/Source/include/FreeRTOS.h
FreeRTOS/Source/include/event_groups.h [new file with mode: 0644]
FreeRTOS/Source/include/list.h
FreeRTOS/Source/include/portable.h
FreeRTOS/Source/include/projdefs.h
FreeRTOS/Source/include/task.h
FreeRTOS/Source/include/timers.h
FreeRTOS/Source/portable/MemMang/heap_4.c
FreeRTOS/Source/tasks.c
FreeRTOS/Source/timers.c

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