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