freertos: Sync safe changes from Amazon SMP branch

This commit is contained in:
Zim Kalinowski
2021-08-10 05:13:43 +08:00
parent 03b361c5a6
commit afc77dbc5a
7 changed files with 9689 additions and 9538 deletions

View File

@@ -1,6 +1,6 @@
/* /*
* FreeRTOS Kernel V10.2.1 * FreeRTOS Kernel V10.2.1
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of * Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in * this software and associated documentation files (the "Software"), to deal in
@@ -19,10 +19,9 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* http://www.FreeRTOS.org * https://www.FreeRTOS.org
* http://aws.amazon.com/freertos * https://github.com/FreeRTOS
* *
* 1 tab == 4 spaces!
*/ */
#include "FreeRTOS.h" #include "FreeRTOS.h"
@@ -45,8 +44,8 @@
static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */ static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */ static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */
static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */ static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */ static List_t * pxDelayedCoRoutineList = NULL; /*< Points to the delayed co-routine list currently being used. */
static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */ static List_t * pxOverflowDelayedCoRoutineList = NULL; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */ static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
/* Other file private variables. --------------------------------*/ /* Other file private variables. --------------------------------*/
@@ -99,17 +98,20 @@ static void prvCheckDelayedList( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex ) BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode,
UBaseType_t uxPriority,
UBaseType_t uxIndex )
{ {
BaseType_t xReturn; BaseType_t xReturn;
CRCB_t * pxCoRoutine; CRCB_t * pxCoRoutine;
/* Allocate the memory that will store the co-routine control block. */ /* Allocate the memory that will store the co-routine control block. */
pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) ); pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
if( pxCoRoutine ) if( pxCoRoutine )
{ {
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
be created and the co-routine data structures need initialising. */ * be created and the co-routine data structures need initialising. */
if( pxCurrentCoRoutine == NULL ) if( pxCurrentCoRoutine == NULL )
{ {
pxCurrentCoRoutine = pxCoRoutine; pxCurrentCoRoutine = pxCoRoutine;
@@ -133,8 +135,8 @@ CRCB_t *pxCoRoutine;
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) ); vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
/* Set the co-routine control block as a link back from the ListItem_t. /* Set the co-routine control block as a link back from the ListItem_t.
This is so we can get back to the containing CRCB from a generic item * This is so we can get back to the containing CRCB from a generic item
in a list. */ * in a list. */
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine ); listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine ); listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
@@ -142,7 +144,7 @@ CRCB_t *pxCoRoutine;
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) ); listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) );
/* Now the co-routine has been initialised it can be added to the ready /* Now the co-routine has been initialised it can be added to the ready
list at the correct priority. */ * list at the correct priority. */
prvAddCoRoutineToReadyQueue( pxCoRoutine ); prvAddCoRoutineToReadyQueue( pxCoRoutine );
xReturn = pdPASS; xReturn = pdPASS;
@@ -156,17 +158,18 @@ CRCB_t *pxCoRoutine;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList ) void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay,
List_t * pxEventList )
{ {
TickType_t xTimeToWake; TickType_t xTimeToWake;
/* Calculate the time to wake - this may overflow but this is /* Calculate the time to wake - this may overflow but this is
not a problem. */ * not a problem. */
xTimeToWake = xCoRoutineTickCount + xTicksToDelay; xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
/* We must remove ourselves from the ready list before adding /* We must remove ourselves from the ready list before adding
ourselves to the blocked list as the same list item is used for * ourselves to the blocked list as the same list item is used for
both lists. */ * both lists. */
( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); ( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
/* The list item will be inserted in wake time order. */ /* The list item will be inserted in wake time order. */
@@ -175,20 +178,20 @@ TickType_t xTimeToWake;
if( xTimeToWake < xCoRoutineTickCount ) if( xTimeToWake < xCoRoutineTickCount )
{ {
/* Wake time has overflowed. Place this item in the /* Wake time has overflowed. Place this item in the
overflow list. */ * overflow list. */
vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
} }
else else
{ {
/* The wake time has not overflowed, so we can use the /* The wake time has not overflowed, so we can use the
current block list. */ * current block list. */
vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) ); vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
} }
if( pxEventList ) if( pxEventList )
{ {
/* Also add the co-routine to an event list. If this is done then the /* Also add the co-routine to an event list. If this is done then the
function must be called with interrupts disabled. */ * function must be called with interrupts disabled. */
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) ); vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
} }
} }
@@ -197,8 +200,8 @@ TickType_t xTimeToWake;
static void prvCheckPendingReadyList( void ) static void prvCheckPendingReadyList( void )
{ {
/* Are there any co-routines waiting to get moved to the ready list? These /* Are there any co-routines waiting to get moved to the ready list? These
are co-routines that have been readied by an ISR. The ISR cannot access * are co-routines that have been readied by an ISR. The ISR cannot access
the ready lists itself. */ * the ready lists itself. */
while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE ) while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
{ {
CRCB_t * pxUnblockedCRCB; CRCB_t * pxUnblockedCRCB;
@@ -222,6 +225,7 @@ static void prvCheckDelayedList( void )
CRCB_t * pxCRCB; CRCB_t * pxCRCB;
xPassedTicks = xTaskGetTickCount() - xLastTickCount; xPassedTicks = xTaskGetTickCount() - xLastTickCount;
while( xPassedTicks ) while( xPassedTicks )
{ {
xCoRoutineTickCount++; xCoRoutineTickCount++;
@@ -233,7 +237,7 @@ CRCB_t *pxCRCB;
List_t * pxTemp; List_t * pxTemp;
/* Tick count has overflowed so we need to swap the delay lists. If there are /* Tick count has overflowed so we need to swap the delay lists. If there are
any items in pxDelayedCoRoutineList here then there is an error! */ * any items in pxDelayedCoRoutineList here then there is an error! */
pxTemp = pxDelayedCoRoutineList; pxTemp = pxDelayedCoRoutineList;
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList; pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
pxOverflowDelayedCoRoutineList = pxTemp; pxOverflowDelayedCoRoutineList = pxTemp;
@@ -253,10 +257,10 @@ CRCB_t *pxCRCB;
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
{ {
/* The event could have occurred just before this critical /* The event could have occurred just before this critical
section. If this is the case then the generic list item will * section. If this is the case then the generic list item will
have been moved to the pending ready list and the following * have been moved to the pending ready list and the following
line is still valid. Also the pvContainer parameter will have * line is still valid. Also the pvContainer parameter will have
been set to NULL so the following lines are also valid. */ * been set to NULL so the following lines are also valid. */
( void ) uxListRemove( &( pxCRCB->xGenericListItem ) ); ( void ) uxListRemove( &( pxCRCB->xGenericListItem ) );
/* Is the co-routine waiting on an event also? */ /* Is the co-routine waiting on an event also? */
@@ -295,7 +299,7 @@ void vCoRoutineSchedule( void )
} }
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
of the same priority get an equal share of the processor time. */ * of the same priority get an equal share of the processor time. */
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ); listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
/* Call the co-routine. */ /* Call the co-routine. */
@@ -319,7 +323,7 @@ UBaseType_t uxPriority;
vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList ); vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList );
/* Start with pxDelayedCoRoutineList using list1 and the /* Start with pxDelayedCoRoutineList using list1 and the
pxOverflowDelayedCoRoutineList using list2. */ * pxOverflowDelayedCoRoutineList using list2. */
pxDelayedCoRoutineList = &xDelayedCoRoutineList1; pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2; pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
} }
@@ -331,8 +335,8 @@ CRCB_t *pxUnblockedCRCB;
BaseType_t xReturn; BaseType_t xReturn;
/* This function is called from within an interrupt. It can only access /* This function is called from within an interrupt. It can only access
event lists and the pending ready list. This function assumes that a * event lists and the pending ready list. This function assumes that a
check has already been made to ensure pxEventList is not empty. */ * check has already been made to ensure pxEventList is not empty. */
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) ); ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) ); vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );

View File

@@ -1,6 +1,6 @@
/* /*
* FreeRTOS Kernel V10.2.1 * FreeRTOS Kernel V10.2.1
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of * Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in * this software and associated documentation files (the "Software"), to deal in
@@ -19,18 +19,17 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* http://www.FreeRTOS.org * https://www.FreeRTOS.org
* http://aws.amazon.com/freertos * https://github.com/FreeRTOS
* *
* 1 tab == 4 spaces!
*/ */
/* Standard includes. */ /* Standard includes. */
#include <stdlib.h> #include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* 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 * all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */ * task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */ /* FreeRTOS includes. */
@@ -40,14 +39,14 @@ task.h is included from an application file. */
#include "event_groups.h" #include "event_groups.h"
/* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified /* Lint e961, e750 and e9021 are suppressed as a MISRA exception justified
because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined * 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 * for the header files above, but not in this file, in order to generate the
correct privileged Vs unprivileged linkage and placement. */ * correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021 See comment above. */
/* The following bit fields convey control information in a task's event list /* The following bit fields convey control information in a task's event list
item value. It is important they don't clash with the * item value. It is important they don't clash with the
taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */ * taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */
#if configUSE_16_BIT_TICKS == 1 #if configUSE_16_BIT_TICKS == 1
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U #define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U #define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U
@@ -86,7 +85,9 @@ typedef struct EventGroupDef_t
* wait condition is met if any of the bits set in uxBitsToWait for are also set * wait condition is met if any of the bits set in uxBitsToWait for are also set
* in uxCurrentEventBits. * in uxCurrentEventBits.
*/ */
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION; static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@@ -102,8 +103,8 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
#if ( configASSERT_DEFINED == 1 ) #if ( configASSERT_DEFINED == 1 )
{ {
/* Sanity check that the size of the structure used to declare a /* Sanity check that the size of the structure used to declare a
variable of type StaticEventGroup_t equals the size of the real * variable of type StaticEventGroup_t equals the size of the real
event group structure. */ * event group structure. */
volatile size_t xSize = sizeof( StaticEventGroup_t ); volatile size_t xSize = sizeof( StaticEventGroup_t );
configASSERT( xSize == sizeof( EventGroup_t ) ); configASSERT( xSize == sizeof( EventGroup_t ) );
} /*lint !e529 xSize is referenced if configASSERT() is defined. */ } /*lint !e529 xSize is referenced if configASSERT() is defined. */
@@ -120,8 +121,8 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
/* Both static and dynamic allocation can be used, so note that /* Both static and dynamic allocation can be used, so note that
this event group was created statically in case the event group * this event group was created statically in case the event group
is later deleted. */ * is later deleted. */
pxEventBits->ucStaticallyAllocated = pdTRUE; pxEventBits->ucStaticallyAllocated = pdTRUE;
} }
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
@@ -133,8 +134,8 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
else else
{ {
/* xEventGroupCreateStatic should only ever be called with /* xEventGroupCreateStatic should only ever be called with
pxEventGroupBuffer pointing to a pre-allocated (compile time * pxEventGroupBuffer pointing to a pre-allocated (compile time
allocated) StaticEventGroup_t variable. */ * allocated) StaticEventGroup_t variable. */
traceEVENT_GROUP_CREATE_FAILED(); traceEVENT_GROUP_CREATE_FAILED();
} }
@@ -151,18 +152,18 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
EventGroup_t * pxEventBits; EventGroup_t * pxEventBits;
/* Allocate the event group. Justification for MISRA deviation as /* Allocate the event group. Justification for MISRA deviation as
follows: pvPortMalloc() always ensures returned memory blocks are * follows: pvPortMalloc() always ensures returned memory blocks are
aligned per the requirements of the MCU stack. In this case * aligned per the requirements of the MCU stack. In this case
pvPortMalloc() must return a pointer that is guaranteed to meet the * pvPortMalloc() must return a pointer that is guaranteed to meet the
alignment requirements of the EventGroup_t structure - which (if you * alignment requirements of the EventGroup_t structure - which (if you
follow it through) is the alignment requirements of the TickType_t type * follow it through) is the alignment requirements of the TickType_t type
(EventBits_t being of TickType_t itself). Therefore, whenever the * (EventBits_t being of TickType_t itself). Therefore, whenever the
stack alignment requirements are greater than or equal to the * stack alignment requirements are greater than or equal to the
TickType_t alignment requirements the cast is safe. In other cases, * TickType_t alignment requirements the cast is safe. In other cases,
where the natural word size of the architecture is less than * where the natural word size of the architecture is less than
sizeof( TickType_t ), the TickType_t variables will be accessed in two * sizeof( TickType_t ), the TickType_t variables will be accessed in two
or more reads operations, and the alignment requirements is only that * or more reads operations, and the alignment requirements is only that
of each individual read. */ * of each individual read. */
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */ pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); /*lint !e9087 !e9079 see comment above. */
if( pxEventBits != NULL ) if( pxEventBits != NULL )
@@ -173,8 +174,8 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{ {
/* Both static and dynamic allocation can be used, so note this /* Both static and dynamic allocation can be used, so note this
event group was allocated statically in case the event group is * event group was allocated statically in case the event group is
later deleted. */ * later deleted. */
pxEventBits->ucStaticallyAllocated = pdFALSE; pxEventBits->ucStaticallyAllocated = pdFALSE;
} }
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
@@ -194,7 +195,10 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait )
{ {
EventBits_t uxOriginalBitValue, uxReturn; EventBits_t uxOriginalBitValue, uxReturn;
EventGroup_t * pxEventBits = xEventGroup; EventGroup_t * pxEventBits = xEventGroup;
@@ -220,7 +224,7 @@ BaseType_t xTimeoutOccurred = pdFALSE;
uxReturn = ( uxOriginalBitValue | uxBitsToSet ); uxReturn = ( uxOriginalBitValue | uxBitsToSet );
/* Rendezvous always clear the bits. They will have been cleared /* Rendezvous always clear the bits. They will have been cleared
already unless this is the only task in the rendezvous. */ * already unless this is the only task in the rendezvous. */
pxEventBits->uxEventBits &= ~uxBitsToWaitFor; pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
xTicksToWait = 0; xTicksToWait = 0;
@@ -232,20 +236,20 @@ BaseType_t xTimeoutOccurred = pdFALSE;
traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor ); traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
/* Store the bits that the calling task is waiting for in the /* 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 * task's event list item so the kernel knows when a match is
found. Then enter the blocked state. */ * found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait ); vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
/* This assignment is obsolete as uxReturn will get set after /* This assignment is obsolete as uxReturn will get set after
the task unblocks, but some compilers mistakenly generate a * the task unblocks, but some compilers mistakenly generate a
warning about uxReturn being returned without being set if the * warning about uxReturn being returned without being set if the
assignment is omitted. */ * assignment is omitted. */
uxReturn = 0; uxReturn = 0;
} }
else else
{ {
/* The rendezvous bits were not set, but no block time was /* The rendezvous bits were not set, but no block time was
specified - just return the current event bit value. */ * specified - just return the current event bit value. */
uxReturn = pxEventBits->uxEventBits; uxReturn = pxEventBits->uxEventBits;
xTimeoutOccurred = pdTRUE; xTimeoutOccurred = pdTRUE;
} }
@@ -259,9 +263,9 @@ BaseType_t xTimeoutOccurred = pdFALSE;
portYIELD_WITHIN_API(); portYIELD_WITHIN_API();
/* The task blocked to wait for its required bits to be set - at this /* 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 * 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 * 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. */ * event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue(); uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
@@ -272,9 +276,9 @@ BaseType_t xTimeoutOccurred = pdFALSE;
uxReturn = pxEventBits->uxEventBits; uxReturn = pxEventBits->uxEventBits;
/* Although the task got here because it timed out before the /* Although the task got here because it timed out before the
bits it was waiting for were set, it is possible that since it * bits it was waiting for were set, it is possible that since it
unblocked another task has set the bits. If this is the case * unblocked another task has set the bits. If this is the case
then it needs to clear the bits before exiting. */ * then it needs to clear the bits before exiting. */
if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor ) if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
{ {
pxEventBits->uxEventBits &= ~uxBitsToWaitFor; pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
@@ -294,7 +298,7 @@ BaseType_t xTimeoutOccurred = pdFALSE;
} }
/* Control bits might be set as the task had blocked should not be /* Control bits might be set as the task had blocked should not be
returned. */ * returned. */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
} }
@@ -307,7 +311,11 @@ BaseType_t xTimeoutOccurred = pdFALSE;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait )
{ {
EventGroup_t * pxEventBits = xEventGroup; EventGroup_t * pxEventBits = xEventGroup;
EventBits_t uxReturn, uxControlBits = 0; EventBits_t uxReturn, uxControlBits = 0;
@@ -315,7 +323,7 @@ BaseType_t xWaitConditionMet;
BaseType_t xTimeoutOccurred = pdFALSE; BaseType_t xTimeoutOccurred = pdFALSE;
/* Check the user is not attempting to wait on the bits used by the kernel /* 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. */ * itself, and that at least one bit is being requested. */
configASSERT( xEventGroup ); configASSERT( xEventGroup );
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
configASSERT( uxBitsToWaitFor != 0 ); configASSERT( uxBitsToWaitFor != 0 );
@@ -335,7 +343,7 @@ BaseType_t xTimeoutOccurred = pdFALSE;
if( xWaitConditionMet != pdFALSE ) if( xWaitConditionMet != pdFALSE )
{ {
/* The wait condition has already been met so there is no need to /* The wait condition has already been met so there is no need to
block. */ * block. */
uxReturn = uxCurrentEventBits; uxReturn = uxCurrentEventBits;
xTicksToWait = ( TickType_t ) 0; xTicksToWait = ( TickType_t ) 0;
@@ -352,16 +360,16 @@ BaseType_t xTimeoutOccurred = pdFALSE;
else if( xTicksToWait == ( TickType_t ) 0 ) else if( xTicksToWait == ( TickType_t ) 0 )
{ {
/* The wait condition has not been met, but no block time was /* The wait condition has not been met, but no block time was
specified, so just return the current value. */ * specified, so just return the current value. */
uxReturn = uxCurrentEventBits; uxReturn = uxCurrentEventBits;
xTimeoutOccurred = pdTRUE; xTimeoutOccurred = pdTRUE;
} }
else else
{ {
/* The task is going to block to wait for its required bits to be /* The task is going to block to wait for its required bits to be
set. uxControlBits are used to remember the specified behaviour of * set. uxControlBits are used to remember the specified behaviour of
this call to xEventGroupWaitBits() - for use when the event bits * this call to xEventGroupWaitBits() - for use when the event bits
unblock the task. */ * unblock the task. */
if( xClearOnExit != pdFALSE ) if( xClearOnExit != pdFALSE )
{ {
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT; uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
@@ -381,13 +389,13 @@ BaseType_t xTimeoutOccurred = pdFALSE;
} }
/* Store the bits that the calling task is waiting for in the /* 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 * task's event list item so the kernel knows when a match is
found. Then enter the blocked state. */ * found. Then enter the blocked state. */
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait ); vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
/* This is obsolete as it will get set after the task unblocks, but /* This is obsolete as it will get set after the task unblocks, but
some compilers mistakenly generate a warning about the variable * some compilers mistakenly generate a warning about the variable
being returned without being set if it is not done. */ * being returned without being set if it is not done. */
uxReturn = 0; uxReturn = 0;
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor ); traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
@@ -401,9 +409,9 @@ BaseType_t xTimeoutOccurred = pdFALSE;
portYIELD_WITHIN_API(); portYIELD_WITHIN_API();
/* The task blocked to wait for its required bits to be set - at this /* 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 * 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 * 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. */ * event list item, and they should now be retrieved then cleared. */
uxReturn = uxTaskResetEventItemValue(); uxReturn = uxTaskResetEventItemValue();
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
@@ -414,7 +422,7 @@ BaseType_t xTimeoutOccurred = pdFALSE;
uxReturn = pxEventBits->uxEventBits; uxReturn = pxEventBits->uxEventBits;
/* It is possible that the event bits were updated between this /* It is possible that the event bits were updated between this
task leaving the Blocked state and running again. */ * task leaving the Blocked state and running again. */
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE ) if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
{ {
if( xClearOnExit != pdFALSE ) if( xClearOnExit != pdFALSE )
@@ -430,6 +438,7 @@ BaseType_t xTimeoutOccurred = pdFALSE;
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
xTimeoutOccurred = pdTRUE; xTimeoutOccurred = pdTRUE;
} }
taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); taskEXIT_CRITICAL( &pxEventBits->eventGroupMux );
@@ -442,6 +451,7 @@ BaseType_t xTimeoutOccurred = pdFALSE;
/* The task blocked so control bits may have been set. */ /* The task blocked so control bits may have been set. */
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
} }
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred ); traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
/* Prevent compiler warnings when trace macros are not used. */ /* Prevent compiler warnings when trace macros are not used. */
@@ -451,13 +461,14 @@ BaseType_t xTimeoutOccurred = pdFALSE;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
{ {
EventGroup_t * pxEventBits = xEventGroup; EventGroup_t * pxEventBits = xEventGroup;
EventBits_t uxReturn; EventBits_t uxReturn;
/* Check the user is not attempting to clear the bits used by the kernel /* Check the user is not attempting to clear the bits used by the kernel
itself. */ * itself. */
configASSERT( xEventGroup ); configASSERT( xEventGroup );
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
@@ -466,7 +477,7 @@ EventBits_t uxReturn;
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear ); traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
/* The value returned is the event group value prior to the bits being /* The value returned is the event group value prior to the bits being
cleared. */ * cleared. */
uxReturn = pxEventBits->uxEventBits; uxReturn = pxEventBits->uxEventBits;
/* Clear the bits. */ /* Clear the bits. */
@@ -480,7 +491,8 @@ EventBits_t uxReturn;
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
{ {
BaseType_t xReturn; BaseType_t xReturn;
@@ -490,7 +502,7 @@ EventBits_t uxReturn;
return xReturn; return xReturn;
} }
#endif #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
@@ -509,7 +521,8 @@ EventBits_t uxReturn;
} /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */ } /*lint !e818 EventGroupHandle_t is a typedef used in other functions to so can't be pointer to const. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet )
{ {
ListItem_t * pxListItem, * pxNext; ListItem_t * pxListItem, * pxNext;
ListItem_t const * pxListEnd; ListItem_t const * pxListEnd;
@@ -519,7 +532,7 @@ EventGroup_t *pxEventBits = xEventGroup;
BaseType_t xMatchFound = pdFALSE; BaseType_t xMatchFound = pdFALSE;
/* Check the user is not attempting to set the bits used by the kernel /* Check the user is not attempting to set the bits used by the kernel
itself. */ * itself. */
configASSERT( xEventGroup ); configASSERT( xEventGroup );
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
@@ -581,21 +594,21 @@ BaseType_t xMatchFound = pdFALSE;
} }
/* Store the actual event flag value in the task's event list /* Store the actual event flag value in the task's event list
item before removing the task from the event list. The * item before removing the task from the event list. The
eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows * eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
that is was unblocked due to its required bits matching, rather * that is was unblocked due to its required bits matching, rather
than because it timed out. */ * than because it timed out. */
xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
} }
/* Move onto the next list item. Note pxListItem->pxNext is not /* 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 * used here as the list item may have been removed from the event list
and inserted into the ready/pending reading list. */ * and inserted into the ready/pending reading list. */
pxListItem = pxNext; pxListItem = pxNext;
} }
/* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT /* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT
bit was set in the control word. */ * bit was set in the control word. */
pxEventBits->uxEventBits &= ~uxBitsToClear; pxEventBits->uxEventBits &= ~uxBitsToClear;
} }
taskEXIT_CRITICAL( &pxEventBits->eventGroupMux ); taskEXIT_CRITICAL( &pxEventBits->eventGroupMux );
@@ -616,7 +629,7 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 ) while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
{ {
/* Unblock the task, returning 0 as the event list is being deleted /* Unblock the task, returning 0 as the event list is being deleted
and cannot therefore have any bits set. */ * and cannot therefore have any bits set. */
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
} }
@@ -626,13 +639,13 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
#if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
{ {
/* The event group can only have been allocated dynamically - free /* The event group can only have been allocated dynamically - free
it again. */ * it again. */
vPortFree( pxEventBits ); vPortFree( pxEventBits );
} }
#elif ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) #elif ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
{ {
/* The event group could have been allocated statically or /* The event group could have been allocated statically or
dynamically, so check before attempting to free the memory. */ * dynamically, so check before attempting to free the memory. */
if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
{ {
vPortFree( pxEventBits ); vPortFree( pxEventBits );
@@ -647,29 +660,33 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* For internal use only - execute a 'set bits' command that was pended from /* For internal use only - execute a 'set bits' command that was pended from
an interrupt. */ * an interrupt. */
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) void vEventGroupSetBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToSet )
{ {
( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */ ( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* For internal use only - execute a 'clear bits' command that was pended from /* For internal use only - execute a 'clear bits' command that was pended from
an interrupt. */ * an interrupt. */
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) void vEventGroupClearBitsCallback( void * pvEventGroup,
const uint32_t ulBitsToClear )
{ {
( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */ ( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear ); /*lint !e9079 Can't avoid cast to void* as a generic timer callback prototype. Callback casts back to original type so safe. */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xWaitForAllBits )
{ {
BaseType_t xWaitConditionMet = pdFALSE; BaseType_t xWaitConditionMet = pdFALSE;
if( xWaitForAllBits == pdFALSE ) if( xWaitForAllBits == pdFALSE )
{ {
/* Task only has to wait for one bit within uxBitsToWaitFor to be /* Task only has to wait for one bit within uxBitsToWaitFor to be
set. Is one already set? */ * set. Is one already set? */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 ) if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
{ {
xWaitConditionMet = pdTRUE; xWaitConditionMet = pdTRUE;
@@ -682,7 +699,7 @@ BaseType_t xWaitConditionMet = pdFALSE;
else else
{ {
/* Task has to wait for all the bits in uxBitsToWaitFor to be set. /* Task has to wait for all the bits in uxBitsToWaitFor to be set.
Are they set already? */ * Are they set already? */
if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor ) if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
{ {
xWaitConditionMet = pdTRUE; xWaitConditionMet = pdTRUE;
@@ -699,7 +716,9 @@ BaseType_t xWaitConditionMet = pdFALSE;
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t * pxHigherPriorityTaskWoken )
{ {
BaseType_t xReturn; BaseType_t xReturn;
@@ -709,7 +728,7 @@ BaseType_t xWaitConditionMet = pdFALSE;
return xReturn; return xReturn;
} }
#endif #endif /* if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
@@ -736,7 +755,8 @@ BaseType_t xWaitConditionMet = pdFALSE;
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
void vEventGroupSetNumber( void * xEventGroup, UBaseType_t uxEventGroupNumber ) void vEventGroupSetNumber( void * xEventGroup,
UBaseType_t uxEventGroupNumber )
{ {
( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */ ( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber; /*lint !e9087 !e9079 EventGroupHandle_t is a pointer to an EventGroup_t, but EventGroupHandle_t is kept opaque outside of this file for data hiding purposes. */
} }

View File

@@ -1,6 +1,6 @@
/* /*
* FreeRTOS Kernel V10.2.1 * FreeRTOS Kernel V10.4.3
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of * Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in * this software and associated documentation files (the "Software"), to deal in
@@ -19,10 +19,9 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* http://www.FreeRTOS.org * https://www.FreeRTOS.org
* http://aws.amazon.com/freertos * https://github.com/FreeRTOS
* *
* 1 tab == 4 spaces!
*/ */
@@ -38,23 +37,23 @@
void vListInitialise( List_t * const pxList ) void vListInitialise( List_t * const pxList )
{ {
/* The list structure contains a list item which is used to mark the /* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted * end of the list. To initialise the list the list end is inserted
as the only list entry. */ * as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
/* The list end value is the highest possible value in the list to /* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */ * ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY; pxList->xListEnd.xItemValue = portMAX_DELAY;
/* The list end next and previous pointers point to itself so we know /* The list end next and previous pointers point to itself so we know
when the list is empty. */ * when the list is empty. */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->uxNumberOfItems = ( UBaseType_t ) 0U; pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
/* Write known values into the list if /* Write known values into the list if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ * configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
} }
@@ -66,25 +65,26 @@ void vListInitialiseItem( ListItem_t * const pxItem )
pxItem->pxContainer = NULL; pxItem->pxContainer = NULL;
/* Write known values into the list item if /* Write known values into the list item if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ * configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) void vListInsertEnd( List_t * const pxList,
ListItem_t * const pxNewListItem )
{ {
ListItem_t * const pxIndex = pxList->pxIndex; ListItem_t * const pxIndex = pxList->pxIndex;
/* Only effective when configASSERT() is also defined, these tests may catch /* Only effective when configASSERT() is also defined, these tests may catch
the list data structures being overwritten in memory. They will not catch * the list data structures being overwritten in memory. They will not catch
data errors caused by incorrect configuration or use of FreeRTOS. */ * data errors caused by incorrect configuration or use of FreeRTOS. */
listTEST_LIST_INTEGRITY( pxList ); listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* Insert a new list item into pxList, but rather than sort the list, /* Insert a new list item into pxList, but rather than sort the list,
makes the new list item the last item to be removed by a call to * makes the new list item the last item to be removed by a call to
listGET_OWNER_OF_NEXT_ENTRY(). */ * listGET_OWNER_OF_NEXT_ENTRY(). */
pxNewListItem->pxNext = pxIndex; pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious; pxNewListItem->pxPrevious = pxIndex->pxPrevious;
@@ -101,25 +101,26 @@ ListItem_t * const pxIndex = pxList->pxIndex;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) void vListInsert( List_t * const pxList,
ListItem_t * const pxNewListItem )
{ {
ListItem_t * pxIterator; ListItem_t * pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
/* Only effective when configASSERT() is also defined, these tests may catch /* Only effective when configASSERT() is also defined, these tests may catch
the list data structures being overwritten in memory. They will not catch * the list data structures being overwritten in memory. They will not catch
data errors caused by incorrect configuration or use of FreeRTOS. */ * data errors caused by incorrect configuration or use of FreeRTOS. */
listTEST_LIST_INTEGRITY( pxList ); listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* Insert the new list item into the list, sorted in xItemValue order. /* Insert the new list item into the list, sorted in xItemValue order.
*
If the list already contains a list item with the same item value then the * If the list already contains a list item with the same item value then the
new list item should be placed after it. This ensures that TCBs which are * new list item should be placed after it. This ensures that TCBs which are
stored in ready lists (all of which have the same xItemValue value) get a * stored in ready lists (all of which have the same xItemValue value) get a
share of the CPU. However, if the xItemValue is the same as the back marker * share of the CPU. However, if the xItemValue is the same as the back marker
the iteration loop below will not end. Therefore the value is checked * the iteration loop below will not end. Therefore the value is checked
first, and the algorithm slightly modified if necessary. */ * first, and the algorithm slightly modified if necessary. */
if( xValueOfInsertion == portMAX_DELAY ) if( xValueOfInsertion == portMAX_DELAY )
{ {
pxIterator = pxList->xListEnd.pxPrevious; pxIterator = pxList->xListEnd.pxPrevious;
@@ -127,31 +128,34 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
else else
{ {
/* *** NOTE *********************************************************** /* *** NOTE ***********************************************************
If you find your application is crashing here then likely causes are * If you find your application is crashing here then likely causes are
listed below. In addition see https://www.freertos.org/FAQHelp.html for * listed below. In addition see https://www.freertos.org/FAQHelp.html for
more tips, and ensure configASSERT() is defined! * more tips, and ensure configASSERT() is defined!
https://www.freertos.org/a00110.html#configASSERT * https://www.freertos.org/a00110.html#configASSERT
*
1) Stack overflow - * 1) Stack overflow -
see https://www.freertos.org/Stacks-and-stack-overflow-checking.html * see https://www.freertos.org/Stacks-and-stack-overflow-checking.html
2) Incorrect interrupt priority assignment, especially on Cortex-M * 2) Incorrect interrupt priority assignment, especially on Cortex-M
parts where numerically high priority values denote low actual * parts where numerically high priority values denote low actual
interrupt priorities, which can seem counter intuitive. See * interrupt priorities, which can seem counter intuitive. See
https://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition * https://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
of configMAX_SYSCALL_INTERRUPT_PRIORITY on * of configMAX_SYSCALL_INTERRUPT_PRIORITY on
https://www.freertos.org/a00110.html * https://www.freertos.org/a00110.html
3) Calling an API function from within a critical section or when * 3) Calling an API function from within a critical section or when
the scheduler is suspended, or calling an API function that does * the scheduler is suspended, or calling an API function that does
not end in "FromISR" from an interrupt. * not end in "FromISR" from an interrupt.
4) Using a queue or semaphore before it has been initialised or * 4) Using a queue or semaphore before it has been initialised or
before the scheduler has been started (are interrupts firing * before the scheduler has been started (are interrupts firing
before vTaskStartScheduler() has been called?). * before vTaskStartScheduler() has been called?).
* 5) If the FreeRTOS port supports interrupt nesting then ensure that
* the priority of the tick interrupt is at or below
* configMAX_SYSCALL_INTERRUPT_PRIORITY.
**********************************************************************/ **********************************************************************/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */ for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */
{ {
/* There is nothing to do here, just iterating to the wanted /* There is nothing to do here, just iterating to the wanted
insertion position. */ * insertion position. */
} }
} }
@@ -161,7 +165,7 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
pxIterator->pxNext = pxNewListItem; pxIterator->pxNext = pxNewListItem;
/* Remember which list the item is in. This allows fast removal of the /* Remember which list the item is in. This allows fast removal of the
item later. */ * item later. */
pxNewListItem->pxContainer = pxList; pxNewListItem->pxContainer = pxList;
( pxList->uxNumberOfItems )++; ( pxList->uxNumberOfItems )++;
@@ -171,7 +175,7 @@ const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{ {
/* The list item knows which list it is in. Obtain the list from the list /* The list item knows which list it is in. Obtain the list from the list
item. */ * item. */
List_t * const pxList = pxItemToRemove->pxContainer; List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* /*
* FreeRTOS Kernel V10.2.1 * FreeRTOS Kernel V10.4.3
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of * Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in * this software and associated documentation files (the "Software"), to deal in
@@ -19,10 +19,9 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* http://www.FreeRTOS.org * https://www.FreeRTOS.org
* http://aws.amazon.com/freertos * https://github.com/FreeRTOS
* *
* 1 tab == 4 spaces!
*/ */
/* Standard includes. */ /* Standard includes. */
@@ -30,8 +29,8 @@
#include <string.h> #include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* 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 * all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */ * task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */ /* FreeRTOS includes. */
@@ -44,15 +43,15 @@ task.h is included from an application file. */
#endif #endif
/* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified /* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified
because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined * 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 * for the header files above, but not in this file, in order to generate the
correct privileged Vs unprivileged linkage and placement. */ * correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
/* If the user has not provided application specific Rx notification macros, /* If the user has not provided application specific Rx notification macros,
or #defined the notification macros away, them provide default implementations * or #defined the notification macros away, then provide default implementations
that uses task notifications. */ * that uses task notifications. */
/*lint -save -e9026 Function like macros allowed and needed here so they can be overidden. */ /*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */
#ifndef sbRECEIVE_COMPLETED #ifndef sbRECEIVE_COMPLETED
#define sbRECEIVE_COMPLETED( pxStreamBuffer ) \ #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \
taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); \ taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); \
@@ -90,8 +89,8 @@ that uses task notifications. */
#endif /* sbRECEIVE_COMPLETED_FROM_ISR */ #endif /* sbRECEIVE_COMPLETED_FROM_ISR */
/* If the user has not provided an application specific Tx notification macro, /* If the user has not provided an application specific Tx notification macro,
or #defined the notification macro away, them provide a default implementation * or #defined the notification macro away, them provide a default implementation
that uses task notifications. */ * that uses task notifications. */
#ifndef sbSEND_COMPLETED #ifndef sbSEND_COMPLETED
#define sbSEND_COMPLETED( pxStreamBuffer ) \ #define sbSEND_COMPLETED( pxStreamBuffer ) \
taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); \ taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); \
@@ -152,7 +151,6 @@ typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */ UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
#endif #endif
portMUX_TYPE xStreamBufferMux; //Mutex required due to SMP portMUX_TYPE xStreamBufferMux; //Mutex required due to SMP
} StreamBuffer_t; } StreamBuffer_t;
@@ -167,7 +165,9 @@ static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PR
* success case, or 0 if there was not enough space in the buffer (in which case * success case, or 0 if there was not enough space in the buffer (in which case
* no data is written into the buffer). * no data is written into the buffer).
*/ */
static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount ) PRIVILEGED_FUNCTION; static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
const uint8_t *pucData,
size_t xCount ) PRIVILEGED_FUNCTION;
/* /*
* If the stream buffer is being used as a message buffer, then reads an entire * If the stream buffer is being used as a message buffer, then reads an entire
@@ -218,15 +218,17 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer ) StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
size_t xTriggerLevelBytes,
BaseType_t xIsMessageBuffer )
{ {
uint8_t * pucAllocatedMemory; uint8_t * pucAllocatedMemory;
uint8_t ucFlags; uint8_t ucFlags;
/* In case the stream buffer is going to be used as a message buffer /* In case the stream buffer is going to be used as a message buffer
(that is, it will hold discrete messages with a little meta data that * (that is, it will hold discrete messages with a little meta data that
says how big the next message is) check the buffer will be large enough * says how big the next message is) check the buffer will be large enough
to hold at least one message. */ * to hold at least one message. */
if( xIsMessageBuffer == pdTRUE ) if( xIsMessageBuffer == pdTRUE )
{ {
/* Is a message buffer but not statically allocated. */ /* Is a message buffer but not statically allocated. */
@@ -239,23 +241,24 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
ucFlags = 0; ucFlags = 0;
configASSERT( xBufferSizeBytes > 0 ); configASSERT( xBufferSizeBytes > 0 );
} }
configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
/* A trigger level of 0 would cause a waiting task to unblock even when /* A trigger level of 0 would cause a waiting task to unblock even when
the buffer was empty. */ * the buffer was empty. */
if( xTriggerLevelBytes == ( size_t ) 0 ) if( xTriggerLevelBytes == ( size_t ) 0 )
{ {
xTriggerLevelBytes = ( size_t ) 1; xTriggerLevelBytes = ( size_t ) 1;
} }
/* A stream buffer requires a StreamBuffer_t structure and a buffer. /* A stream buffer requires a StreamBuffer_t structure and a buffer.
Both are allocated in a single call to pvPortMalloc(). The * Both are allocated in a single call to pvPortMalloc(). The
StreamBuffer_t structure is placed at the start of the allocated memory * StreamBuffer_t structure is placed at the start of the allocated memory
and the buffer follows immediately after. The requested size is * and the buffer follows immediately after. The requested size is
incremented so the free space is returned as the user would expect - * incremented so the free space is returned as the user would expect -
this is a quirk of the implementation that means otherwise the free * this is a quirk of the implementation that means otherwise the free
space would be reported as one byte smaller than would be logically * space would be reported as one byte smaller than would be logically
expected. */ * expected. */
if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) ) if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) )
{ {
xBufferSizeBytes++; xBufferSizeBytes++;
@@ -304,7 +307,7 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
/* A trigger level of 0 would cause a waiting task to unblock even when /* A trigger level of 0 would cause a waiting task to unblock even when
the buffer was empty. */ * the buffer was empty. */
if( xTriggerLevelBytes == ( size_t ) 0 ) if( xTriggerLevelBytes == ( size_t ) 0 )
{ {
xTriggerLevelBytes = ( size_t ) 1; xTriggerLevelBytes = ( size_t ) 1;
@@ -322,16 +325,16 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
} }
/* In case the stream buffer is going to be used as a message buffer /* In case the stream buffer is going to be used as a message buffer
(that is, it will hold discrete messages with a little meta data that * (that is, it will hold discrete messages with a little meta data that
says how big the next message is) check the buffer will be large enough * says how big the next message is) check the buffer will be large enough
to hold at least one message. */ * to hold at least one message. */
configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
#if ( configASSERT_DEFINED == 1 ) #if ( configASSERT_DEFINED == 1 )
{ {
/* Sanity check that the size of the structure used to declare a /* Sanity check that the size of the structure used to declare a
variable of type StaticStreamBuffer_t equals the size of the real * variable of type StaticStreamBuffer_t equals the size of the real
message buffer structure. */ * message buffer structure. */
volatile size_t xSize = sizeof( StaticStreamBuffer_t ); volatile size_t xSize = sizeof( StaticStreamBuffer_t );
configASSERT( xSize == sizeof( StreamBuffer_t ) ); configASSERT( xSize == sizeof( StreamBuffer_t ) );
} /*lint !e529 xSize is referenced is configASSERT() is defined. */ } /*lint !e529 xSize is referenced is configASSERT() is defined. */
@@ -344,8 +347,9 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
xBufferSizeBytes, xBufferSizeBytes,
xTriggerLevelBytes, xTriggerLevelBytes,
ucFlags ); ucFlags );
/* Remember this was statically allocated in case it is ever deleted /* Remember this was statically allocated in case it is ever deleted
again. */ * again. */
pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED; pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;
traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ); traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );
@@ -377,13 +381,13 @@ StreamBuffer_t * pxStreamBuffer = xStreamBuffer;
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
/* Both the structure and the buffer were allocated using a single call /* Both the structure and the buffer were allocated using a single call
to pvPortMalloc(), hence only one call to vPortFree() is required. */ * to pvPortMalloc(), hence only one call to vPortFree() is required. */
vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */ vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */
} }
#else #else
{ {
/* Should not be possible to get here, ucFlags must be corrupt. /* Should not be possible to get here, ucFlags must be corrupt.
Force an assert. */ * Force an assert. */
configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 ); configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );
} }
#endif #endif
@@ -391,7 +395,7 @@ StreamBuffer_t * pxStreamBuffer = xStreamBuffer;
else else
{ {
/* The structure and buffer were not allocated dynamically and cannot be /* The structure and buffer were not allocated dynamically and cannot be
freed - just scrub the structure so future use will assert. */ * freed - just scrub the structure so future use will assert. */
( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
} }
} }
@@ -411,7 +415,7 @@ BaseType_t xReturn = pdFAIL;
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
{ {
/* Store the stream buffer number so it can be restored after the /* Store the stream buffer number so it can be restored after the
reset. */ * reset. */
uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber; uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
} }
#endif #endif
@@ -446,7 +450,8 @@ BaseType_t xReturn = pdFAIL;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,
size_t xTriggerLevel )
{ {
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
BaseType_t xReturn; BaseType_t xReturn;
@@ -460,7 +465,7 @@ BaseType_t xReturn;
} }
/* The trigger level is the number of bytes that must be in the stream /* The trigger level is the number of bytes that must be in the stream
buffer before a task that is waiting for data is unblocked. */ * buffer before a task that is waiting for data is unblocked. */
if( xTriggerLevel <= pxStreamBuffer->xLength ) if( xTriggerLevel <= pxStreamBuffer->xLength )
{ {
pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel; pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
@@ -525,9 +530,9 @@ TimeOut_t xTimeOut;
configASSERT( pxStreamBuffer ); configASSERT( pxStreamBuffer );
/* This send function is used to write to both message buffers and stream /* This send function is used to write to both message buffers and stream
buffers. If this is a message buffer then the space needed must be * buffers. If this is a message buffer then the space needed must be
increased by the amount of bytes needed to store the length of the * increased by the amount of bytes needed to store the length of the
message. */ * message. */
if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
{ {
xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
@@ -547,7 +552,7 @@ TimeOut_t xTimeOut;
do do
{ {
/* Wait until the required number of bytes are free in the message /* Wait until the required number of bytes are free in the message
buffer. */ * buffer. */
taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
{ {
xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
@@ -572,7 +577,6 @@ TimeOut_t xTimeOut;
traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ); traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
pxStreamBuffer->xTaskWaitingToSend = NULL; pxStreamBuffer->xTaskWaitingToSend = NULL;
} while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ); } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
} }
else else
@@ -628,9 +632,9 @@ size_t xRequiredSpace = xDataLengthBytes;
configASSERT( pxStreamBuffer ); configASSERT( pxStreamBuffer );
/* This send function is used to write to both message buffers and stream /* This send function is used to write to both message buffers and stream
buffers. If this is a message buffer then the space needed must be * buffers. If this is a message buffer then the space needed must be
increased by the amount of bytes needed to store the length of the * increased by the amount of bytes needed to store the length of the
message. */ * message. */
if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
{ {
xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
@@ -678,23 +682,23 @@ static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
if( xSpace == ( size_t ) 0 ) if( xSpace == ( size_t ) 0 )
{ {
/* Doesn't matter if this is a stream buffer or a message buffer, there /* Doesn't matter if this is a stream buffer or a message buffer, there
is no space to write. */ * is no space to write. */
xShouldWrite = pdFALSE; xShouldWrite = pdFALSE;
} }
else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 ) else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 )
{ {
/* This is a stream buffer, as opposed to a message buffer, so writing a /* This is a stream buffer, as opposed to a message buffer, so writing a
stream of bytes rather than discrete messages. Write as many bytes as * stream of bytes rather than discrete messages. Write as many bytes as
possible. */ * possible. */
xShouldWrite = pdTRUE; xShouldWrite = pdTRUE;
xDataLengthBytes = configMIN( xDataLengthBytes, xSpace ); xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );
} }
else if( xSpace >= xRequiredSpace ) else if( xSpace >= xRequiredSpace )
{ {
/* This is a message buffer, as opposed to a stream buffer, and there /* This is a message buffer, as opposed to a stream buffer, and there
is enough space to write both the message length and the message itself * is enough space to write both the message length and the message itself
into the buffer. Start by writing the length of the data, the data * into the buffer. Start by writing the length of the data, the data
itself will be written later in this function. */ * itself will be written later in this function. */
xShouldWrite = pdTRUE; xShouldWrite = pdTRUE;
( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH ); ( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH );
} }
@@ -730,10 +734,10 @@ size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
configASSERT( pxStreamBuffer ); configASSERT( pxStreamBuffer );
/* This receive function is used by both message buffers, which store /* This receive function is used by both message buffers, which store
discrete messages, and stream buffers, which store a continuous stream of * discrete messages, and stream buffers, which store a continuous stream of
bytes. Discrete messages include an additional * bytes. Discrete messages include an additional
sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
message. */ * message. */
if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
{ {
xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
@@ -746,16 +750,16 @@ size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
if( xTicksToWait != ( TickType_t ) 0 ) if( xTicksToWait != ( TickType_t ) 0 )
{ {
/* Checking if there is data and clearing the notification state must be /* Checking if there is data and clearing the notification state must be
performed atomically. */ * performed atomically. */
taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux ); taskENTER_CRITICAL( &pxStreamBuffer->xStreamBufferMux );
{ {
xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
/* If this function was invoked by a message buffer read then /* If this function was invoked by a message buffer read then
xBytesToStoreMessageLength holds the number of bytes used to hold * xBytesToStoreMessageLength holds the number of bytes used to hold
the length of the next discrete message. If this function was * the length of the next discrete message. If this function was
invoked by a stream buffer read then xBytesToStoreMessageLength will * invoked by a stream buffer read then xBytesToStoreMessageLength will
be 0. */ * be 0. */
if( xBytesAvailable <= xBytesToStoreMessageLength ) if( xBytesAvailable <= xBytesToStoreMessageLength )
{ {
/* Clear notification state as going to wait for data. */ /* Clear notification state as going to wait for data. */
@@ -793,10 +797,10 @@ size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
} }
/* Whether receiving a discrete message (where xBytesToStoreMessageLength /* Whether receiving a discrete message (where xBytesToStoreMessageLength
holds the number of bytes used to store the message length) or a stream of * holds the number of bytes used to store the message length) or a stream of
bytes (where xBytesToStoreMessageLength is zero), the number of bytes * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
available must be greater than xBytesToStoreMessageLength to be able to * available must be greater than xBytesToStoreMessageLength to be able to
read bytes from the buffer. */ * read bytes from the buffer. */
if( xBytesAvailable > xBytesToStoreMessageLength ) if( xBytesAvailable > xBytesToStoreMessageLength )
{ {
xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength ); xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );
@@ -834,14 +838,15 @@ configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
{ {
xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH ) if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
{ {
/* The number of bytes available is greater than the number of bytes /* The number of bytes available is greater than the number of bytes
required to hold the length of the next message, so another message * required to hold the length of the next message, so another message
is available. Return its length without removing the length bytes * is available. Return its length without removing the length bytes
from the buffer. A copy of the tail is stored so the buffer can be * from the buffer. A copy of the tail is stored so the buffer can be
returned to its prior state as the message is not actually being * returned to its prior state as the message is not actually being
removed from the buffer. */ * removed from the buffer. */
xOriginalTail = pxStreamBuffer->xTail; xOriginalTail = pxStreamBuffer->xTail;
( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable ); ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable );
xReturn = ( size_t ) xTempReturn; xReturn = ( size_t ) xTempReturn;
@@ -850,9 +855,9 @@ configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
else else
{ {
/* The minimum amount of bytes in a message buffer is /* The minimum amount of bytes in a message buffer is
( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is
less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
value is 0. */ * value is 0. */
configASSERT( xBytesAvailable == 0 ); configASSERT( xBytesAvailable == 0 );
xReturn = 0; xReturn = 0;
} }
@@ -878,10 +883,10 @@ size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
configASSERT( pxStreamBuffer ); configASSERT( pxStreamBuffer );
/* This receive function is used by both message buffers, which store /* This receive function is used by both message buffers, which store
discrete messages, and stream buffers, which store a continuous stream of * discrete messages, and stream buffers, which store a continuous stream of
bytes. Discrete messages include an additional * bytes. Discrete messages include an additional
sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
message. */ * message. */
if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
{ {
xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
@@ -894,10 +899,10 @@ size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
/* Whether receiving a discrete message (where xBytesToStoreMessageLength /* Whether receiving a discrete message (where xBytesToStoreMessageLength
holds the number of bytes used to store the message length) or a stream of * holds the number of bytes used to store the message length) or a stream of
bytes (where xBytesToStoreMessageLength is zero), the number of bytes * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
available must be greater than xBytesToStoreMessageLength to be able to * available must be greater than xBytesToStoreMessageLength to be able to
read bytes from the buffer. */ * read bytes from the buffer. */
if( xBytesAvailable > xBytesToStoreMessageLength ) if( xBytesAvailable > xBytesToStoreMessageLength )
{ {
xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength ); xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );
@@ -935,24 +940,24 @@ configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
if( xBytesToStoreMessageLength != ( size_t ) 0 ) if( xBytesToStoreMessageLength != ( size_t ) 0 )
{ {
/* A discrete message is being received. First receive the length /* A discrete message is being received. First receive the length
of the message. A copy of the tail is stored so the buffer can be * of the message. A copy of the tail is stored so the buffer can be
returned to its prior state if the length of the message is too * returned to its prior state if the length of the message is too
large for the provided buffer. */ * large for the provided buffer. */
xOriginalTail = pxStreamBuffer->xTail; xOriginalTail = pxStreamBuffer->xTail;
( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable ); ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable );
xNextMessageLength = ( size_t ) xTempNextMessageLength; xNextMessageLength = ( size_t ) xTempNextMessageLength;
/* Reduce the number of bytes available by the number of bytes just /* Reduce the number of bytes available by the number of bytes just
read out. */ * read out. */
xBytesAvailable -= xBytesToStoreMessageLength; xBytesAvailable -= xBytesToStoreMessageLength;
/* Check there is enough space in the buffer provided by the /* Check there is enough space in the buffer provided by the
user. */ * user. */
if( xNextMessageLength > xBufferLengthBytes ) if( xNextMessageLength > xBufferLengthBytes )
{ {
/* The user has provided insufficient space to read the message /* The user has provided insufficient space to read the message
so return the buffer to its previous state (so the length of * so return the buffer to its previous state (so the length of
the message is in the buffer again). */ * the message is in the buffer again). */
pxStreamBuffer->xTail = xOriginalTail; pxStreamBuffer->xTail = xOriginalTail;
xNextMessageLength = 0; xNextMessageLength = 0;
} }
@@ -964,7 +969,7 @@ configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
else else
{ {
/* A stream of bytes is being received (as opposed to a discrete /* A stream of bytes is being received (as opposed to a discrete
message), so read as many bytes as possible. */ * message), so read as many bytes as possible. */
xNextMessageLength = xBufferLengthBytes; xNextMessageLength = xBufferLengthBytes;
} }
@@ -985,6 +990,7 @@ size_t xTail;
/* True if no bytes are available. */ /* True if no bytes are available. */
xTail = pxStreamBuffer->xTail; xTail = pxStreamBuffer->xTail;
if( pxStreamBuffer->xHead == xTail ) if( pxStreamBuffer->xHead == xTail )
{ {
xReturn = pdTRUE; xReturn = pdTRUE;
@@ -1007,9 +1013,9 @@ const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
configASSERT( pxStreamBuffer ); configASSERT( pxStreamBuffer );
/* This generic version of the receive function is used by both message /* This generic version of the receive function is used by both message
buffers, which store discrete messages, and stream buffers, which store a * buffers, which store discrete messages, and stream buffers, which store a
continuous stream of bytes. Discrete messages include an additional * continuous stream of bytes. Discrete messages include an additional
sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */ * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */
if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
{ {
xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
@@ -1033,7 +1039,8 @@ const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
BaseType_t * pxHigherPriorityTaskWoken )
{ {
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
BaseType_t xReturn; BaseType_t xReturn;
@@ -1063,7 +1070,8 @@ UBaseType_t uxSavedInterruptStatus;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
BaseType_t * pxHigherPriorityTaskWoken )
{ {
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
BaseType_t xReturn; BaseType_t xReturn;
@@ -1093,7 +1101,9 @@ UBaseType_t uxSavedInterruptStatus;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount ) static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
const uint8_t * pucData,
size_t xCount )
{ {
size_t xNextHead, xFirstLength; size_t xNextHead, xFirstLength;
@@ -1102,8 +1112,8 @@ size_t xNextHead, xFirstLength;
xNextHead = pxStreamBuffer->xHead; xNextHead = pxStreamBuffer->xHead;
/* Calculate the number of bytes that can be added in the first write - /* Calculate the number of bytes that can be added in the first write -
which may be less than the total number of bytes that need to be added if * which may be less than the total number of bytes that need to be added if
the buffer will wrap back to the beginning. */ * the buffer will wrap back to the beginning. */
xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount ); xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount );
/* Write as many bytes as can be written in the first write. */ /* Write as many bytes as can be written in the first write. */
@@ -1111,7 +1121,7 @@ size_t xNextHead, xFirstLength;
( void ) memcpy( ( void* ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */ ( void ) memcpy( ( void* ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */
/* If the number of bytes written was less than the number that could be /* If the number of bytes written was less than the number that could be
written in the first write... */ * written in the first write... */
if( xCount > xFirstLength ) if( xCount > xFirstLength )
{ {
/* ...then write the remaining bytes to the start of the buffer. */ /* ...then write the remaining bytes to the start of the buffer. */
@@ -1124,6 +1134,7 @@ size_t xNextHead, xFirstLength;
} }
xNextHead += xCount; xNextHead += xCount;
if( xNextHead >= pxStreamBuffer->xLength ) if( xNextHead >= pxStreamBuffer->xLength )
{ {
xNextHead -= pxStreamBuffer->xLength; xNextHead -= pxStreamBuffer->xLength;
@@ -1139,7 +1150,10 @@ size_t xNextHead, xFirstLength;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer, uint8_t *pucData, size_t xMaxCount, size_t xBytesAvailable ) static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
uint8_t * pucData,
size_t xMaxCount,
size_t xBytesAvailable )
{ {
size_t xCount, xFirstLength, xNextTail; size_t xCount, xFirstLength, xNextTail;
@@ -1151,18 +1165,18 @@ size_t xCount, xFirstLength, xNextTail;
xNextTail = pxStreamBuffer->xTail; xNextTail = pxStreamBuffer->xTail;
/* Calculate the number of bytes that can be read - which may be /* Calculate the number of bytes that can be read - which may be
less than the number wanted if the data wraps around to the start of * less than the number wanted if the data wraps around to the start of
the buffer. */ * the buffer. */
xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount ); xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount );
/* Obtain the number of bytes it is possible to obtain in the first /* Obtain the number of bytes it is possible to obtain in the first
read. Asserts check bounds of read and write. */ * read. Asserts check bounds of read and write. */
configASSERT( xFirstLength <= xMaxCount ); configASSERT( xFirstLength <= xMaxCount );
configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength ); configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength );
( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */ ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */
/* If the total number of wanted bytes is greater than the number /* If the total number of wanted bytes is greater than the number
that could be read in the first read... */ * that could be read in the first read... */
if( xCount > xFirstLength ) if( xCount > xFirstLength )
{ {
/*...then read the remaining bytes from the start of the buffer. */ /*...then read the remaining bytes from the start of the buffer. */
@@ -1175,7 +1189,7 @@ size_t xCount, xFirstLength, xNextTail;
} }
/* Move the tail pointer to effectively remove the data read from /* Move the tail pointer to effectively remove the data read from
the buffer. */ * the buffer. */
xNextTail += xCount; xNextTail += xCount;
if( xNextTail >= pxStreamBuffer->xLength ) if( xNextTail >= pxStreamBuffer->xLength )
@@ -1201,6 +1215,7 @@ size_t xCount;
xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead; xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
xCount -= pxStreamBuffer->xTail; xCount -= pxStreamBuffer->xTail;
if( xCount >= pxStreamBuffer->xLength ) if( xCount >= pxStreamBuffer->xLength )
{ {
xCount -= pxStreamBuffer->xLength; xCount -= pxStreamBuffer->xLength;
@@ -1221,13 +1236,13 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
uint8_t ucFlags ) uint8_t ucFlags )
{ {
/* Assert here is deliberately writing to the entire buffer to ensure it can /* Assert here is deliberately writing to the entire buffer to ensure it can
be written to without generating exceptions, and is setting the buffer to a * be written to without generating exceptions, and is setting the buffer to a
known value to assist in development/debugging. */ * known value to assist in development/debugging. */
#if ( configASSERT_DEFINED == 1 ) #if ( configASSERT_DEFINED == 1 )
{ {
/* The value written just has to be identifiable when looking at the /* The value written just has to be identifiable when looking at the
memory. Don't use 0xA5 as that is the stack fill value and could * memory. Don't use 0xA5 as that is the stack fill value and could
result in confusion as to what is actually being observed. */ * result in confusion as to what is actually being observed. */
const BaseType_t xWriteValue = 0x55; const BaseType_t xWriteValue = 0x55;
configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer ); configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );
} /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */ } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */
@@ -1253,7 +1268,8 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber ) void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,
UBaseType_t uxStreamBufferNumber )
{ {
xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* /*
* FreeRTOS Kernel V10.2.1 * FreeRTOS Kernel V10.2.1
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of * Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in * this software and associated documentation files (the "Software"), to deal in
@@ -19,18 +19,17 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
* http://www.FreeRTOS.org * https://www.FreeRTOS.org
* http://aws.amazon.com/freertos * https://github.com/FreeRTOS
* *
* 1 tab == 4 spaces!
*/ */
/* Standard includes. */ /* Standard includes. */
#include <stdlib.h> #include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* 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 * all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */ * task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h" #include "FreeRTOS.h"
@@ -43,23 +42,23 @@ task.h is included from an application file. */
#endif #endif
/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified /* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined * 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 * for the header files above, but not in this file, in order to generate the
correct privileged Vs unprivileged linkage and placement. */ * correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */
/* This entire source file will be skipped if the application is not configured /* This entire source file will be skipped if the application is not configured
to include software timer functionality. This #if is closed at the very bottom * to include software timer functionality. This #if is closed at the very bottom
of this file. If you want to include software timer functionality then ensure * of this file. If you want to include software timer functionality then ensure
configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ * configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
#if ( configUSE_TIMERS == 1 ) #if ( configUSE_TIMERS == 1 )
/* Misc definitions. */ /* Misc definitions. */
#define tmrNO_DELAY ( TickType_t ) 0U #define tmrNO_DELAY ( TickType_t ) 0U
/* The name assigned to the timer service task. This can be overridden by /* The name assigned to the timer service task. This can be overridden by
defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */ * defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
#ifndef configTIMER_SERVICE_TASK_NAME #ifndef configTIMER_SERVICE_TASK_NAME
#define configTIMER_SERVICE_TASK_NAME "Tmr Svc" #define configTIMER_SERVICE_TASK_NAME "Tmr Svc"
#endif #endif
@@ -84,14 +83,14 @@ typedef struct tmrTimerControl /* The old naming convention is used to prevent b
} xTIMER; } xTIMER;
/* The old xTIMER name is maintained above then typedefed to the new Timer_t /* The old xTIMER name is maintained above then typedefed to the new Timer_t
name below to enable the use of older kernel aware debuggers. */ * name below to enable the use of older kernel aware debuggers. */
typedef xTIMER Timer_t; typedef xTIMER Timer_t;
/* 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, * 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 * and messages that request the execution of a non-timer related callback. The
two message types are defined in two separate structures, xTimerParametersType * two message types are defined in two separate structures, xTimerParametersType
and xCallbackParametersType respectively. */ * and xCallbackParametersType respectively. */
typedef struct tmrTimerParameters typedef struct tmrTimerParameters
{ {
TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */ TickType_t xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
@@ -107,7 +106,7 @@ typedef struct tmrCallbackParameters
} CallbackParameters_t; } CallbackParameters_t;
/* The structure that contains the two message types, along with an identifier /* The structure that contains the two message types, along with an identifier
that is used to determine which message type is valid. */ * that is used to determine which message type is valid. */
typedef struct tmrTimerQueueMessage typedef struct tmrTimerQueueMessage
{ {
BaseType_t xMessageID; /*<< The command being sent to the timer service task. */ BaseType_t xMessageID; /*<< The command being sent to the timer service task. */
@@ -116,7 +115,7 @@ typedef struct tmrTimerQueueMessage
TimerParameter_t xTimerParameters; TimerParameter_t xTimerParameters;
/* Don't include xCallbackParameters if it is not going to be used as /* Don't include xCallbackParameters if it is not going to be used as
it makes the structure (and therefore the timer queue) larger. */ * it makes the structure (and therefore the timer queue) larger. */
#if ( INCLUDE_xTimerPendFunctionCall == 1 ) #if ( INCLUDE_xTimerPendFunctionCall == 1 )
CallbackParameters_t xCallbackParameters; CallbackParameters_t xCallbackParameters;
#endif /* INCLUDE_xTimerPendFunctionCall */ #endif /* INCLUDE_xTimerPendFunctionCall */
@@ -124,14 +123,14 @@ typedef struct tmrTimerQueueMessage
} DaemonTaskMessage_t; } DaemonTaskMessage_t;
/*lint -save -e956 A manual analysis and inspection has been used to determine /*lint -save -e956 A manual analysis and inspection has been used to determine
which static variables must be declared volatile. */ * which static variables must be declared volatile. */
/* The list in which active timers are stored. Timers are referenced in expire /* The list in which active timers are stored. Timers are referenced in expire
time order, with the nearest expiry time at the front of the list. Only the * time order, with the nearest expiry time at the front of the list. Only the
timer service task is allowed to access these lists. * timer service task is allowed to access these lists.
xActiveTimerList1 and xActiveTimerList2 could be at function scope but that * xActiveTimerList1 and xActiveTimerList2 could be at function scope but that
breaks some kernel aware debuggers, and debuggers that reply on removing the * breaks some kernel aware debuggers, and debuggers that reply on removing the
static qualifier. */ * static qualifier. */
PRIVILEGED_DATA static List_t xActiveTimerList1; PRIVILEGED_DATA static List_t xActiveTimerList1;
PRIVILEGED_DATA static List_t xActiveTimerList2; PRIVILEGED_DATA static List_t xActiveTimerList2;
PRIVILEGED_DATA static List_t * pxCurrentTimerList; PRIVILEGED_DATA static List_t * pxCurrentTimerList;
@@ -151,9 +150,9 @@ PRIVILEGED_DATA portMUX_TYPE xTimerMux = portMUX_INITIALIZER_UNLOCKED;
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
/* If static allocation is supported then the application must provide the /* If static allocation is supported then the application must provide the
following callback function - which enables the application to optionally * following callback function - which enables the application to optionally
provide the memory that will be used by the timer task as the task's stack * provide the memory that will be used by the timer task as the task's stack
and TCB. */ * and TCB. */
extern void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ); extern void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize );
#endif #endif
@@ -181,13 +180,17 @@ static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
* Insert the timer into either xActiveTimerList1, or xActiveTimerList2, * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
* depending on if the expire time causes a timer counter overflow. * depending on if the expire time causes a timer counter overflow.
*/ */
static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime ) PRIVILEGED_FUNCTION; static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer,
const TickType_t xNextExpiryTime,
const TickType_t xTimeNow,
const TickType_t xCommandTime ) PRIVILEGED_FUNCTION;
/* /*
* An active timer has reached its expire time. Reload the timer if it is an * An active timer has reached its expire time. Reload the timer if it is an
* auto reload timer, then call its callback. * auto-reload timer, then call its callback.
*/ */
static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) PRIVILEGED_FUNCTION; static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
/* /*
* The tick count has overflowed. Switch the timer lists after ensuring the * The tick count has overflowed. Switch the timer lists after ensuring the
@@ -213,7 +216,8 @@ static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty ) PRIV
* If a timer has expired, process it. Otherwise, block the timer service task * If a timer has expired, process it. Otherwise, block the timer service task
* until either a timer does expire or a command is received. * until either a timer does expire or a command is received.
*/ */
static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION; static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime,
BaseType_t xListWasEmpty ) PRIVILEGED_FUNCTION;
/* /*
* Called after a Timer_t structure has been allocated either statically or * Called after a Timer_t structure has been allocated either statically or
@@ -232,9 +236,9 @@ BaseType_t xTimerCreateTimerTask( void )
BaseType_t xReturn = pdFAIL; BaseType_t xReturn = pdFAIL;
/* This function is called when the scheduler is started if /* This function is called when the scheduler is started if
configUSE_TIMERS is set to 1. Check that the infrastructure used by the * configUSE_TIMERS is set to 1. Check that the infrastructure used by the
timer service task has been created/initialised. If timers have already * timer service task has been created/initialised. If timers have already
been created then the initialisation will already have been performed. */ * been created then the initialisation will already have been performed. */
prvCheckForValidListAndQueue(); prvCheckForValidListAndQueue();
if( xTimerQueue != NULL ) if( xTimerQueue != NULL )
@@ -260,7 +264,7 @@ BaseType_t xReturn = pdFAIL;
xReturn = pdPASS; xReturn = pdPASS;
} }
} }
#else #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
{ {
xReturn = xTaskCreatePinnedToCore( prvTimerTask, xReturn = xTaskCreatePinnedToCore( prvTimerTask,
configTIMER_SERVICE_TASK_NAME, configTIMER_SERVICE_TASK_NAME,
@@ -296,8 +300,8 @@ BaseType_t xReturn = pdFAIL;
if( pxNewTimer != NULL ) if( pxNewTimer != NULL )
{ {
/* Status is thus far zero as the timer is not created statically /* Status is thus far zero as the timer is not created statically
and has not been started. The autoreload bit may get set in * and has not been started. The auto-reload bit may get set in
prvInitialiseNewTimer. */ * prvInitialiseNewTimer. */
pxNewTimer->ucStatus = 0x00; pxNewTimer->ucStatus = 0x00;
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
} }
@@ -322,8 +326,8 @@ BaseType_t xReturn = pdFAIL;
#if ( configASSERT_DEFINED == 1 ) #if ( configASSERT_DEFINED == 1 )
{ {
/* Sanity check that the size of the structure used to declare a /* Sanity check that the size of the structure used to declare a
variable of type StaticTimer_t equals the size of the real timer * variable of type StaticTimer_t equals the size of the real timer
structure. */ * structure. */
volatile size_t xSize = sizeof( StaticTimer_t ); volatile size_t xSize = sizeof( StaticTimer_t );
configASSERT( xSize == sizeof( Timer_t ) ); configASSERT( xSize == sizeof( Timer_t ) );
( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */
@@ -337,8 +341,8 @@ BaseType_t xReturn = pdFAIL;
if( pxNewTimer != NULL ) if( pxNewTimer != NULL )
{ {
/* Timers can be created statically or dynamically so note this /* Timers can be created statically or dynamically so note this
timer was created statically in case it is later deleted. The * timer was created statically in case it is later deleted. The
autoreload bit may get set in prvInitialiseNewTimer(). */ * auto-reload bit may get set in prvInitialiseNewTimer(). */
pxNewTimer->ucStatus = tmrSTATUS_IS_STATICALLY_ALLOCATED; pxNewTimer->ucStatus = tmrSTATUS_IS_STATICALLY_ALLOCATED;
prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer );
@@ -363,26 +367,32 @@ static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e97
if( pxNewTimer != NULL ) if( pxNewTimer != NULL )
{ {
/* Ensure the infrastructure used by the timer service task has been /* Ensure the infrastructure used by the timer service task has been
created/initialised. */ * created/initialised. */
prvCheckForValidListAndQueue(); prvCheckForValidListAndQueue();
/* Initialise the timer structure members using the function /* Initialise the timer structure members using the function
parameters. */ * parameters. */
pxNewTimer->pcTimerName = pcTimerName; pxNewTimer->pcTimerName = pcTimerName;
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
pxNewTimer->pvTimerID = pvTimerID; pxNewTimer->pvTimerID = pvTimerID;
pxNewTimer->pxCallbackFunction = pxCallbackFunction; pxNewTimer->pxCallbackFunction = pxCallbackFunction;
vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
if( uxAutoReload != pdFALSE ) if( uxAutoReload != pdFALSE )
{ {
pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD;
} }
traceTIMER_CREATE( pxNewTimer ); traceTIMER_CREATE( pxNewTimer );
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) BaseType_t xTimerGenericCommand( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
BaseType_t * const pxHigherPriorityTaskWoken,
const TickType_t xTicksToWait )
{ {
BaseType_t xReturn = pdFAIL; BaseType_t xReturn = pdFAIL;
DaemonTaskMessage_t xMessage; DaemonTaskMessage_t xMessage;
@@ -390,7 +400,7 @@ DaemonTaskMessage_t xMessage;
configASSERT( xTimer ); configASSERT( xTimer );
/* Send a message to the timer service task to perform a particular action /* Send a message to the timer service task to perform a particular action
on a particular timer definition. */ * on a particular timer definition. */
if( xTimerQueue != NULL ) if( xTimerQueue != NULL )
{ {
/* Send a command to the timer service task to start the xTimer timer. */ /* Send a command to the timer service task to start the xTimer timer. */
@@ -428,7 +438,7 @@ DaemonTaskMessage_t xMessage;
TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) TaskHandle_t xTimerGetTimerDaemonTaskHandle( void )
{ {
/* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been /* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
started, then xTimerTaskHandle will be NULL. */ * started, then xTimerTaskHandle will be NULL. */
configASSERT( ( xTimerTaskHandle != NULL ) ); configASSERT( ( xTimerTaskHandle != NULL ) );
return xTimerTaskHandle; return xTimerTaskHandle;
} }
@@ -443,7 +453,8 @@ Timer_t *pxTimer = xTimer;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) void vTimerSetReloadMode( TimerHandle_t xTimer,
const UBaseType_t uxAutoReload )
{ {
Timer_t * pxTimer = xTimer; Timer_t * pxTimer = xTimer;
@@ -758,11 +769,11 @@ TickType_t xTimeNow;
traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue ); traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );
/* In this case the xTimerListsWereSwitched parameter is not used, but /* In this case the xTimerListsWereSwitched parameter is not used, but
it must be present in the function call. prvSampleTimeNow() must be * it must be present in the function call. prvSampleTimeNow() must be
called after the message is received from xTimerQueue so there is no * called after the message is received from xTimerQueue so there is no
possibility of a higher priority task adding a message to the message * 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 * 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). */ * pre-empted the timer daemon task after the xTimeNow value was set). */
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
switch( xMessage.xMessageID ) switch( xMessage.xMessageID )
@@ -774,10 +785,11 @@ TickType_t xTimeNow;
case tmrCOMMAND_START_DONT_TRACE: case tmrCOMMAND_START_DONT_TRACE:
/* Start or restart a timer. */ /* Start or restart a timer. */
pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE; pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )
{ {
/* The timer expired before it was added to the active /* The timer expired before it was added to the active
timer list. Process it now. */ * timer list. Process it now. */
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
traceTIMER_EXPIRED( pxTimer ); traceTIMER_EXPIRED( pxTimer );
@@ -796,6 +808,7 @@ TickType_t xTimeNow;
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
break; break;
case tmrCOMMAND_STOP: case tmrCOMMAND_STOP:
@@ -811,11 +824,11 @@ TickType_t xTimeNow;
configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
/* The new period does not really have a reference, and can /* The new period does not really have a reference, and can
be longer or shorter than the old one. The command time is * be longer or shorter than the old one. The command time is
therefore set to the current time, and as the period cannot * therefore set to the current time, and as the period cannot
be zero the next expiry time can only be in the future, * be zero the next expiry time can only be in the future,
meaning (unlike for the xTimerStart() case above) there is * meaning (unlike for the xTimerStart() case above) there is
no fail case that needs to be handled here. */ * no fail case that needs to be handled here. */
( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
break; break;
@@ -823,8 +836,8 @@ TickType_t xTimeNow;
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
/* The timer has already been removed from the active list, /* The timer has already been removed from the active list,
just free up the memory if the memory was dynamically * just free up the memory if the memory was dynamically
allocated. */ * allocated. */
if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 ) if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 )
{ {
vPortFree( pxTimer ); vPortFree( pxTimer );
@@ -834,12 +847,12 @@ TickType_t xTimeNow;
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
} }
} }
#else #else /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
{ {
/* If dynamic allocation is not enabled, the memory /* If dynamic allocation is not enabled, the memory
could not have been dynamically allocated. So there is * could not have been dynamically allocated. So there is
no need to free the memory - just mark the timer as * no need to free the memory - just mark the timer as
"not active". */ * "not active". */
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
} }
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
@@ -862,9 +875,9 @@ Timer_t *pxTimer;
BaseType_t xResult; BaseType_t xResult;
/* The tick count has overflowed. The timer lists must be switched. /* The tick count has overflowed. The timer lists must be switched.
If there are any timers still referenced from the current timer list * If there are any timers still referenced from the current timer list
then they must have expired and should be processed before the lists * then they must have expired and should be processed before the lists
are switched. */ * are switched. */
while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
{ {
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
@@ -875,19 +888,20 @@ BaseType_t xResult;
traceTIMER_EXPIRED( pxTimer ); traceTIMER_EXPIRED( pxTimer );
/* Execute its callback, then send a command to restart the timer if /* Execute its callback, then send a command to restart the timer if
it is an auto-reload timer. It cannot be restarted here as the lists * it is an auto-reload timer. It cannot be restarted here as the lists
have not yet been switched. */ * have not yet been switched. */
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 ) if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
{ {
/* Calculate the reload value, and if the reload value results in /* Calculate the reload value, and if the reload value results in
the timer going into the same timer list then it has already expired * the timer going into the same timer list then it has already expired
and the timer should be re-inserted into the current list so it is * and the timer should be re-inserted into the current list so it is
processed again within this loop. Otherwise a command should be sent * processed again within this loop. Otherwise a command should be sent
to restart the timer to ensure it is only inserted into a list after * to restart the timer to ensure it is only inserted into a list after
the lists have been swapped. */ * the lists have been swapped. */
xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ); xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
if( xReloadTime > xNextExpireTime ) if( xReloadTime > xNextExpireTime )
{ {
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime ); listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
@@ -916,8 +930,8 @@ BaseType_t xResult;
static void prvCheckForValidListAndQueue( void ) static void prvCheckForValidListAndQueue( void )
{ {
/* Check that the list from which active timers are referenced, and the /* Check that the list from which active timers are referenced, and the
queue used to communicate with the timer service, have been * queue used to communicate with the timer service, have been
initialised. */ * initialised. */
if( xTimerQueue == NULL ) vPortCPUInitializeMutex( &xTimerMux ); if( xTimerQueue == NULL ) vPortCPUInitializeMutex( &xTimerMux );
@@ -933,7 +947,7 @@ static void prvCheckForValidListAndQueue( void )
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{ {
/* The timer queue is allocated statically in case /* The timer queue is allocated statically in case
configSUPPORT_DYNAMIC_ALLOCATION is 0. */ * configSUPPORT_DYNAMIC_ALLOCATION is 0. */
static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */ static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */ static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
@@ -943,7 +957,7 @@ static void prvCheckForValidListAndQueue( void )
{ {
xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) ); xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );
} }
#endif #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
#if ( configQUEUE_REGISTRY_SIZE > 0 ) #if ( configQUEUE_REGISTRY_SIZE > 0 )
{ {
@@ -1009,7 +1023,8 @@ void *pvReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) void vTimerSetTimerID( TimerHandle_t xTimer,
void * pvNewID )
{ {
Timer_t * const pxTimer = xTimer; Timer_t * const pxTimer = xTimer;
@@ -1025,13 +1040,16 @@ Timer_t * const pxTimer = xTimer;
#if ( INCLUDE_xTimerPendFunctionCall == 1 ) #if ( INCLUDE_xTimerPendFunctionCall == 1 )
BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken ) BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend,
void * pvParameter1,
uint32_t ulParameter2,
BaseType_t * pxHigherPriorityTaskWoken )
{ {
DaemonTaskMessage_t xMessage; DaemonTaskMessage_t xMessage;
BaseType_t xReturn; BaseType_t xReturn;
/* Complete the message with the function parameters and post it to the /* Complete the message with the function parameters and post it to the
daemon task. */ * daemon task. */
xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR; xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
@@ -1049,18 +1067,21 @@ Timer_t * const pxTimer = xTimer;
#if ( INCLUDE_xTimerPendFunctionCall == 1 ) #if ( INCLUDE_xTimerPendFunctionCall == 1 )
BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait ) BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend,
void * pvParameter1,
uint32_t ulParameter2,
TickType_t xTicksToWait )
{ {
DaemonTaskMessage_t xMessage; DaemonTaskMessage_t xMessage;
BaseType_t xReturn; BaseType_t xReturn;
/* This function can only be called after a timer has been created or /* This function can only be called after a timer has been created or
after the scheduler has been started because, until then, the timer * after the scheduler has been started because, until then, the timer
queue does not exist. */ * queue does not exist. */
configASSERT( xTimerQueue ); configASSERT( xTimerQueue );
/* Complete the message with the function parameters and post it to the /* Complete the message with the function parameters and post it to the
daemon task. */ * daemon task. */
xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK; xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK;
xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend; xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1; xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
@@ -1088,7 +1109,8 @@ Timer_t * const pxTimer = xTimer;
#if ( configUSE_TRACE_FACILITY == 1 ) #if ( configUSE_TRACE_FACILITY == 1 )
void vTimerSetTimerNumber( TimerHandle_t xTimer, UBaseType_t uxTimerNumber ) void vTimerSetTimerNumber( TimerHandle_t xTimer,
UBaseType_t uxTimerNumber )
{ {
( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber; ( ( Timer_t * ) xTimer )->uxTimerNumber = uxTimerNumber;
} }
@@ -1097,6 +1119,6 @@ Timer_t * const pxTimer = xTimer;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This entire source file will be skipped if the application is not configured /* 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 * to include software timer functionality. If you want to include software timer
functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */ * functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
#endif /* configUSE_TIMERS == 1 */ #endif /* configUSE_TIMERS == 1 */