--- /dev/null
+/*\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
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
#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
#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
--- /dev/null
+/*\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
* \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
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
/*\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
* 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
* 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
*/\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
/*\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
* 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
* 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
/*\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
/* 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
*\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
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
*/\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
/* 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
\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
}\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
\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
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
}\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
}\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
}\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
/*\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
#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
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
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
{\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
\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
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
}\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