2023-05-10 04:22:41 -04:00
/*
2023-05-10 04:51:13 -04:00
* FreeRTOS Kernel V10 .5 .1 ( ESP - IDF SMP modified )
2023-05-10 04:22:41 -04:00
* Copyright ( C ) 2021 Amazon . com , Inc . or its affiliates . All Rights Reserved .
*
* SPDX - FileCopyrightText : 2021 Amazon . com , Inc . or its affiliates
*
* SPDX - License - Identifier : MIT
*
* SPDX - FileContributor : 2023 Espressif Systems ( Shanghai ) CO LTD
*
* 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
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of
* the Software , and to permit persons to whom the Software is furnished to do so ,
* subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER
* 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 .
*
* https : //www.FreeRTOS.org
* https : //github.com/FreeRTOS
*
*/
/* Standard includes. */
# include <stdint.h>
# include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers . That should only be done when
* task . h is included from an application file . */
# define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
# include "FreeRTOS.h"
# include "task.h"
# include "stream_buffer.h"
2023-09-07 12:29:57 -04:00
/* Include private IDF API additions for critical thread safety macros */
# include "esp_private/freertos_idf_additions_priv.h"
2023-05-10 04:22:41 -04:00
# if ( configUSE_TASK_NOTIFICATIONS != 1 )
# error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c
# endif
# if ( INCLUDE_xTaskGetCurrentTaskHandle != 1 )
# error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 to build stream_buffer.c
# endif
/* 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
* for the header files above , but not in this file , in order to generate the
* correct privileged Vs unprivileged linkage and placement . */
# undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
/* If the user has not provided application specific Rx notification macros,
* or # defined the notification macros away , then provide default implementations
* that uses task notifications . */
/*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */
# ifndef sbRECEIVE_COMPLETED
2023-09-07 12:29:57 -04:00
# define sbRECEIVE_COMPLETED( pxStreamBuffer ) \
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ; \
{ \
if ( ( pxStreamBuffer ) - > xTaskWaitingToSend ! = NULL ) \
{ \
( void ) xTaskNotify ( ( pxStreamBuffer ) - > xTaskWaitingToSend , \
( uint32_t ) 0 , \
eNoAction ) ; \
( pxStreamBuffer ) - > xTaskWaitingToSend = NULL ; \
} \
} \
( void ) prvEXIT_CRITICAL_OR_RESUME_ALL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
# endif /* sbRECEIVE_COMPLETED */
/* If user has provided a per-instance receive complete callback, then
* invoke the callback else use the receive complete macro which is provided by default for all instances .
*/
# if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
# define prvRECEIVE_COMPLETED( pxStreamBuffer ) \
{ \
if ( ( pxStreamBuffer ) - > pxReceiveCompletedCallback ! = NULL ) \
{ \
( pxStreamBuffer ) - > pxReceiveCompletedCallback ( ( pxStreamBuffer ) , pdFALSE , NULL ) ; \
} \
else \
{ \
sbRECEIVE_COMPLETED ( ( pxStreamBuffer ) ) ; \
} \
}
# else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
# define prvRECEIVE_COMPLETED( pxStreamBuffer ) sbRECEIVE_COMPLETED( ( pxStreamBuffer ) )
# endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
# ifndef sbRECEIVE_COMPLETED_FROM_ISR
# define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \
pxHigherPriorityTaskWoken ) \
{ \
UBaseType_t uxSavedInterruptStatus ; \
\
uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR ( ) ; \
{ \
if ( ( pxStreamBuffer ) - > xTaskWaitingToSend ! = NULL ) \
{ \
( void ) xTaskNotifyFromISR ( ( pxStreamBuffer ) - > xTaskWaitingToSend , \
( uint32_t ) 0 , \
eNoAction , \
( pxHigherPriorityTaskWoken ) ) ; \
( pxStreamBuffer ) - > xTaskWaitingToSend = NULL ; \
} \
} \
portCLEAR_INTERRUPT_MASK_FROM_ISR ( uxSavedInterruptStatus ) ; \
}
# endif /* sbRECEIVE_COMPLETED_FROM_ISR */
# if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
# define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \
pxHigherPriorityTaskWoken ) \
{ \
if ( ( pxStreamBuffer ) - > pxReceiveCompletedCallback ! = NULL ) \
{ \
( pxStreamBuffer ) - > pxReceiveCompletedCallback ( ( pxStreamBuffer ) , pdTRUE , ( pxHigherPriorityTaskWoken ) ) ; \
} \
else \
{ \
sbRECEIVE_COMPLETED_FROM_ISR ( ( pxStreamBuffer ) , ( pxHigherPriorityTaskWoken ) ) ; \
} \
}
# else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
# define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
sbRECEIVE_COMPLETED_FROM_ISR ( ( pxStreamBuffer ) , ( pxHigherPriorityTaskWoken ) )
# endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
/* If the user has not provided an application specific Tx notification macro,
* or # defined the notification macro away , then provide a default
* implementation that uses task notifications .
*/
# ifndef sbSEND_COMPLETED
2023-09-07 12:29:57 -04:00
# define sbSEND_COMPLETED( pxStreamBuffer ) \
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ; \
{ \
if ( ( pxStreamBuffer ) - > xTaskWaitingToReceive ! = NULL ) \
{ \
( void ) xTaskNotify ( ( pxStreamBuffer ) - > xTaskWaitingToReceive , \
( uint32_t ) 0 , \
eNoAction ) ; \
( pxStreamBuffer ) - > xTaskWaitingToReceive = NULL ; \
} \
} \
( void ) prvEXIT_CRITICAL_OR_RESUME_ALL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
# endif /* sbSEND_COMPLETED */
/* If user has provided a per-instance send completed callback, then
* invoke the callback else use the send complete macro which is provided by default for all instances .
*/
# if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
# define prvSEND_COMPLETED( pxStreamBuffer ) \
{ \
if ( ( pxStreamBuffer ) - > pxSendCompletedCallback ! = NULL ) \
{ \
pxStreamBuffer - > pxSendCompletedCallback ( ( pxStreamBuffer ) , pdFALSE , NULL ) ; \
} \
else \
{ \
sbSEND_COMPLETED ( ( pxStreamBuffer ) ) ; \
} \
}
# else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
# define prvSEND_COMPLETED( pxStreamBuffer ) sbSEND_COMPLETED( ( pxStreamBuffer ) )
# endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
# ifndef sbSEND_COMPLETE_FROM_ISR
# define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
{ \
UBaseType_t uxSavedInterruptStatus ; \
\
uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR ( ) ; \
{ \
if ( ( pxStreamBuffer ) - > xTaskWaitingToReceive ! = NULL ) \
{ \
( void ) xTaskNotifyFromISR ( ( pxStreamBuffer ) - > xTaskWaitingToReceive , \
( uint32_t ) 0 , \
eNoAction , \
( pxHigherPriorityTaskWoken ) ) ; \
( pxStreamBuffer ) - > xTaskWaitingToReceive = NULL ; \
} \
} \
portCLEAR_INTERRUPT_MASK_FROM_ISR ( uxSavedInterruptStatus ) ; \
}
# endif /* sbSEND_COMPLETE_FROM_ISR */
# if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
# define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
{ \
if ( ( pxStreamBuffer ) - > pxSendCompletedCallback ! = NULL ) \
{ \
( pxStreamBuffer ) - > pxSendCompletedCallback ( ( pxStreamBuffer ) , pdTRUE , ( pxHigherPriorityTaskWoken ) ) ; \
} \
else \
{ \
sbSEND_COMPLETE_FROM_ISR ( ( pxStreamBuffer ) , ( pxHigherPriorityTaskWoken ) ) ; \
} \
}
# else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
# define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
sbSEND_COMPLETE_FROM_ISR ( ( pxStreamBuffer ) , ( pxHigherPriorityTaskWoken ) )
# endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
/*lint -restore (9026) */
/* The number of bytes used to hold the length of a message in the buffer. */
# define sbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
/* Bits stored in the ucFlags field of the stream buffer. */
# define sbFLAGS_IS_MESSAGE_BUFFER ( ( uint8_t ) 1 ) /* Set if the stream buffer was created as a message buffer, in which case it holds discrete messages rather than a stream. */
# define sbFLAGS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */
/*-----------------------------------------------------------*/
/* Structure that hold state information on the buffer. */
typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
{
volatile size_t xTail ; /* Index to the next item to read within the buffer. */
volatile size_t xHead ; /* Index to the next item to write within the buffer. */
size_t xLength ; /* The length of the buffer pointed to by pucBuffer. */
size_t xTriggerLevelBytes ; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
volatile TaskHandle_t xTaskWaitingToReceive ; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
volatile TaskHandle_t xTaskWaitingToSend ; /* Holds the handle of a task waiting to send data to a message buffer that is full. */
uint8_t * pucBuffer ; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
uint8_t ucFlags ;
# if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxStreamBufferNumber ; /* Used for tracing purposes. */
# endif
# if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
StreamBufferCallbackFunction_t pxSendCompletedCallback ; /* Optional callback called on send complete. sbSEND_COMPLETED is called if this is NULL. */
StreamBufferCallbackFunction_t pxReceiveCompletedCallback ; /* Optional callback called on receive complete. sbRECEIVE_COMPLETED is called if this is NULL. */
# endif
2023-09-07 12:29:57 -04:00
portMUX_TYPE xStreamBufferLock ; /* Spinlock required for SMP critical sections */
2023-05-10 04:22:41 -04:00
} StreamBuffer_t ;
/*
* The number of bytes available to be read from the buffer .
*/
static size_t prvBytesInBuffer ( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION ;
/*
* Add xCount bytes from pucData into the pxStreamBuffer ' s data storage area .
* This function does not update the buffer ' s xHead pointer , so multiple writes
* may be chained together " atomically " . This is useful for Message Buffers where
* the length and data bytes are written in two separate chunks , and we don ' t want
* the reader to see the buffer as having grown until after all data is copied over .
* This function takes a custom xHead value to indicate where to write to ( necessary
* for chaining ) and returns the the resulting xHead position .
* To mark the write as complete , manually set the buffer ' s xHead field with the
* returned xHead from this function .
*/
static size_t prvWriteBytesToBuffer ( StreamBuffer_t * const pxStreamBuffer ,
const uint8_t * pucData ,
size_t xCount ,
size_t xHead ) PRIVILEGED_FUNCTION ;
/*
* If the stream buffer is being used as a message buffer , then reads an entire
* message out of the buffer . If the stream buffer is being used as a stream
* buffer then read as many bytes as possible from the buffer .
* prvReadBytesFromBuffer ( ) is called to actually extract the bytes from the
* buffer ' s data storage area .
*/
static size_t prvReadMessageFromBuffer ( StreamBuffer_t * pxStreamBuffer ,
void * pvRxData ,
size_t xBufferLengthBytes ,
size_t xBytesAvailable ) PRIVILEGED_FUNCTION ;
/*
* If the stream buffer is being used as a message buffer , then writes an entire
* message to the buffer . If the stream buffer is being used as a stream
* buffer then write as many bytes as possible to the buffer .
* prvWriteBytestoBuffer ( ) is called to actually send the bytes to the buffer ' s
* data storage area .
*/
static size_t prvWriteMessageToBuffer ( StreamBuffer_t * const pxStreamBuffer ,
const void * pvTxData ,
size_t xDataLengthBytes ,
size_t xSpace ,
size_t xRequiredSpace ) PRIVILEGED_FUNCTION ;
/*
* Copies xCount bytes from the pxStreamBuffer ' s data storage area to pucData .
* This function does not update the buffer ' s xTail pointer , so multiple reads
* may be chained together " atomically " . This is useful for Message Buffers where
* the length and data bytes are read in two separate chunks , and we don ' t want
* the writer to see the buffer as having more free space until after all data is
* copied over , especially if we have to abort the read due to insufficient receiving space .
* This function takes a custom xTail value to indicate where to read from ( necessary
* for chaining ) and returns the the resulting xTail position .
* To mark the read as complete , manually set the buffer ' s xTail field with the
* returned xTail from this function .
*/
static size_t prvReadBytesFromBuffer ( StreamBuffer_t * pxStreamBuffer ,
uint8_t * pucData ,
size_t xCount ,
size_t xTail ) PRIVILEGED_FUNCTION ;
/*
* Called by both pxStreamBufferCreate ( ) and pxStreamBufferCreateStatic ( ) to
* initialise the members of the newly created stream buffer structure .
*/
static void prvInitialiseNewStreamBuffer ( StreamBuffer_t * const pxStreamBuffer ,
uint8_t * const pucBuffer ,
size_t xBufferSizeBytes ,
size_t xTriggerLevelBytes ,
uint8_t ucFlags ,
StreamBufferCallbackFunction_t pxSendCompletedCallback ,
StreamBufferCallbackFunction_t pxReceiveCompletedCallback ) PRIVILEGED_FUNCTION ;
/*-----------------------------------------------------------*/
# if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
StreamBufferHandle_t xStreamBufferGenericCreate ( size_t xBufferSizeBytes ,
size_t xTriggerLevelBytes ,
BaseType_t xIsMessageBuffer ,
StreamBufferCallbackFunction_t pxSendCompletedCallback ,
StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
{
uint8_t * pucAllocatedMemory ;
uint8_t ucFlags ;
/* 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
* says how big the next message is ) check the buffer will be large enough
* to hold at least one message . */
if ( xIsMessageBuffer = = pdTRUE )
{
/* Is a message buffer but not statically allocated. */
ucFlags = sbFLAGS_IS_MESSAGE_BUFFER ;
configASSERT ( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ) ;
}
else
{
/* Not a message buffer and not statically allocated. */
ucFlags = 0 ;
configASSERT ( xBufferSizeBytes > 0 ) ;
}
configASSERT ( xTriggerLevelBytes < = xBufferSizeBytes ) ;
/* A trigger level of 0 would cause a waiting task to unblock even when
* the buffer was empty . */
if ( xTriggerLevelBytes = = ( size_t ) 0 )
{
xTriggerLevelBytes = ( size_t ) 1 ;
}
/* A stream buffer requires a StreamBuffer_t structure and a buffer.
* Both are allocated in a single call to pvPortMalloc ( ) . The
* StreamBuffer_t structure is placed at the start of the allocated memory
* and the buffer follows immediately after . The requested size is
* incremented so the free space is returned as the user would expect -
* this is a quirk of the implementation that means otherwise the free
* space would be reported as one byte smaller than would be logically
* expected . */
if ( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof ( StreamBuffer_t ) ) )
{
xBufferSizeBytes + + ;
pucAllocatedMemory = ( uint8_t * ) pvPortMalloc ( xBufferSizeBytes + sizeof ( StreamBuffer_t ) ) ; /*lint !e9079 malloc() only returns void*. */
}
else
{
pucAllocatedMemory = NULL ;
}
if ( pucAllocatedMemory ! = NULL )
{
prvInitialiseNewStreamBuffer ( ( StreamBuffer_t * ) pucAllocatedMemory , /* Structure at the start of the allocated memory. */ /*lint !e9087 Safe cast as allocated memory is aligned. */ /*lint !e826 Area is not too small and alignment is guaranteed provided malloc() behaves as expected and returns aligned buffer. */
pucAllocatedMemory + sizeof ( StreamBuffer_t ) , /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */
xBufferSizeBytes ,
xTriggerLevelBytes ,
ucFlags ,
pxSendCompletedCallback ,
pxReceiveCompletedCallback ) ;
2023-09-07 12:29:57 -04:00
/* Initialize the stream buffer's spinlock separately, as
* prvInitialiseNewStreamBuffer ( ) is also called from
* xStreamBufferReset ( ) . */
portMUX_INITIALIZE ( & ( ( ( StreamBuffer_t * ) pucAllocatedMemory ) - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
traceSTREAM_BUFFER_CREATE ( ( ( StreamBuffer_t * ) pucAllocatedMemory ) , xIsMessageBuffer ) ;
}
else
{
traceSTREAM_BUFFER_CREATE_FAILED ( xIsMessageBuffer ) ;
}
return ( StreamBufferHandle_t ) pucAllocatedMemory ; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */
}
# endif /* configSUPPORT_DYNAMIC_ALLOCATION */
/*-----------------------------------------------------------*/
# if ( configSUPPORT_STATIC_ALLOCATION == 1 )
StreamBufferHandle_t xStreamBufferGenericCreateStatic ( size_t xBufferSizeBytes ,
size_t xTriggerLevelBytes ,
BaseType_t xIsMessageBuffer ,
uint8_t * const pucStreamBufferStorageArea ,
StaticStreamBuffer_t * const pxStaticStreamBuffer ,
StreamBufferCallbackFunction_t pxSendCompletedCallback ,
StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
{
StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer ; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */
StreamBufferHandle_t xReturn ;
uint8_t ucFlags ;
configASSERT ( pucStreamBufferStorageArea ) ;
configASSERT ( pxStaticStreamBuffer ) ;
configASSERT ( xTriggerLevelBytes < = xBufferSizeBytes ) ;
/* A trigger level of 0 would cause a waiting task to unblock even when
* the buffer was empty . */
if ( xTriggerLevelBytes = = ( size_t ) 0 )
{
xTriggerLevelBytes = ( size_t ) 1 ;
}
if ( xIsMessageBuffer ! = pdFALSE )
{
/* Statically allocated message buffer. */
ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED ;
}
else
{
/* Statically allocated stream buffer. */
ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED ;
}
/* 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
* says how big the next message is ) check the buffer will be large enough
* to hold at least one message . */
configASSERT ( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ) ;
# if ( configASSERT_DEFINED == 1 )
{
/* Sanity check that the size of the structure used to declare a
* variable of type StaticStreamBuffer_t equals the size of the real
* message buffer structure . */
volatile size_t xSize = sizeof ( StaticStreamBuffer_t ) ;
configASSERT ( xSize = = sizeof ( StreamBuffer_t ) ) ;
2024-08-19 00:02:03 -04:00
( void ) xSize ; /* Prevent unused variable warning when configASSERT() is not used. */
2023-05-10 04:22:41 -04:00
} /*lint !e529 xSize is referenced is configASSERT() is defined. */
# endif /* configASSERT_DEFINED */
if ( ( pucStreamBufferStorageArea ! = NULL ) & & ( pxStaticStreamBuffer ! = NULL ) )
{
prvInitialiseNewStreamBuffer ( pxStreamBuffer ,
pucStreamBufferStorageArea ,
xBufferSizeBytes ,
xTriggerLevelBytes ,
ucFlags ,
pxSendCompletedCallback ,
pxReceiveCompletedCallback ) ;
/* Remember this was statically allocated in case it is ever deleted
* again . */
pxStreamBuffer - > ucFlags | = sbFLAGS_IS_STATICALLY_ALLOCATED ;
2023-09-07 12:29:57 -04:00
/* Initialize the stream buffer's spinlock separately, as
* prvInitialiseNewStreamBuffer ( ) is also called from
* xStreamBufferReset ( ) . */
portMUX_INITIALIZE ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
traceSTREAM_BUFFER_CREATE ( pxStreamBuffer , xIsMessageBuffer ) ;
xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer ; /*lint !e9087 Data hiding requires cast to opaque type. */
}
else
{
xReturn = NULL ;
traceSTREAM_BUFFER_CREATE_STATIC_FAILED ( xReturn , xIsMessageBuffer ) ;
}
return xReturn ;
}
# endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
/*-----------------------------------------------------------*/
2023-07-13 07:01:20 -04:00
# if ( configSUPPORT_STATIC_ALLOCATION == 1 )
BaseType_t xStreamBufferGetStaticBuffers ( StreamBufferHandle_t xStreamBuffer ,
uint8_t * * ppucStreamBufferStorageArea ,
StaticStreamBuffer_t * * ppxStaticStreamBuffer )
{
BaseType_t xReturn ;
const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
configASSERT ( pxStreamBuffer ) ;
configASSERT ( ppucStreamBufferStorageArea ) ;
configASSERT ( ppxStaticStreamBuffer ) ;
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) ! = ( uint8_t ) 0 )
{
* ppucStreamBufferStorageArea = pxStreamBuffer - > pucBuffer ;
* ppxStaticStreamBuffer = ( StaticStreamBuffer_t * ) pxStreamBuffer ;
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
return xReturn ;
}
# endif /* configSUPPORT_STATIC_ALLOCATION */
/*-----------------------------------------------------------*/
2023-05-10 04:22:41 -04:00
void vStreamBufferDelete ( StreamBufferHandle_t xStreamBuffer )
{
StreamBuffer_t * pxStreamBuffer = xStreamBuffer ;
configASSERT ( pxStreamBuffer ) ;
traceSTREAM_BUFFER_DELETE ( xStreamBuffer ) ;
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) = = ( uint8_t ) pdFALSE )
{
# if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
/* Both the structure and the buffer were allocated using a single call
* 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(). */
}
# else
{
/* Should not be possible to get here, ucFlags must be corrupt.
* Force an assert . */
configASSERT ( xStreamBuffer = = ( StreamBufferHandle_t ) ~ 0 ) ;
}
# endif
}
else
{
/* The structure and buffer were not allocated dynamically and cannot be
* freed - just scrub the structure so future use will assert . */
( void ) memset ( pxStreamBuffer , 0x00 , sizeof ( StreamBuffer_t ) ) ;
}
}
/*-----------------------------------------------------------*/
BaseType_t xStreamBufferReset ( StreamBufferHandle_t xStreamBuffer )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
BaseType_t xReturn = pdFAIL ;
StreamBufferCallbackFunction_t pxSendCallback = NULL , pxReceiveCallback = NULL ;
# if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxStreamBufferNumber ;
# endif
configASSERT ( pxStreamBuffer ) ;
# if ( configUSE_TRACE_FACILITY == 1 )
{
/* Store the stream buffer number so it can be restored after the
* reset . */
uxStreamBufferNumber = pxStreamBuffer - > uxStreamBufferNumber ;
}
# endif
/* Can only reset a message buffer if there are no tasks blocked on it. */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
{
if ( ( pxStreamBuffer - > xTaskWaitingToReceive = = NULL ) & & ( pxStreamBuffer - > xTaskWaitingToSend = = NULL ) )
{
# if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
{
pxSendCallback = pxStreamBuffer - > pxSendCompletedCallback ;
pxReceiveCallback = pxStreamBuffer - > pxReceiveCompletedCallback ;
}
# endif
prvInitialiseNewStreamBuffer ( pxStreamBuffer ,
pxStreamBuffer - > pucBuffer ,
pxStreamBuffer - > xLength ,
pxStreamBuffer - > xTriggerLevelBytes ,
pxStreamBuffer - > ucFlags ,
pxSendCallback ,
pxReceiveCallback ) ;
# if ( configUSE_TRACE_FACILITY == 1 )
{
pxStreamBuffer - > uxStreamBufferNumber = uxStreamBufferNumber ;
}
# endif
traceSTREAM_BUFFER_RESET ( xStreamBuffer ) ;
xReturn = pdPASS ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
/*-----------------------------------------------------------*/
BaseType_t xStreamBufferSetTriggerLevel ( StreamBufferHandle_t xStreamBuffer ,
size_t xTriggerLevel )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
BaseType_t xReturn ;
configASSERT ( pxStreamBuffer ) ;
/* It is not valid for the trigger level to be 0. */
if ( xTriggerLevel = = ( size_t ) 0 )
{
xTriggerLevel = ( size_t ) 1 ;
}
/* 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 . */
if ( xTriggerLevel < pxStreamBuffer - > xLength )
{
pxStreamBuffer - > xTriggerLevelBytes = xTriggerLevel ;
xReturn = pdPASS ;
}
else
{
xReturn = pdFALSE ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
size_t xStreamBufferSpacesAvailable ( StreamBufferHandle_t xStreamBuffer )
{
const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
size_t xSpace ;
size_t xOriginalTail ;
configASSERT ( pxStreamBuffer ) ;
/* The code below reads xTail and then xHead. This is safe if the stream
* buffer is updated once between the two reads - but not if the stream buffer
* is updated more than once between the two reads - hence the loop . */
do
{
xOriginalTail = pxStreamBuffer - > xTail ;
xSpace = pxStreamBuffer - > xLength + pxStreamBuffer - > xTail ;
xSpace - = pxStreamBuffer - > xHead ;
} while ( xOriginalTail ! = pxStreamBuffer - > xTail ) ;
xSpace - = ( size_t ) 1 ;
if ( xSpace > = pxStreamBuffer - > xLength )
{
xSpace - = pxStreamBuffer - > xLength ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return xSpace ;
}
/*-----------------------------------------------------------*/
size_t xStreamBufferBytesAvailable ( StreamBufferHandle_t xStreamBuffer )
{
const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
size_t xReturn ;
configASSERT ( pxStreamBuffer ) ;
xReturn = prvBytesInBuffer ( pxStreamBuffer ) ;
return xReturn ;
}
/*-----------------------------------------------------------*/
size_t xStreamBufferSend ( StreamBufferHandle_t xStreamBuffer ,
const void * pvTxData ,
size_t xDataLengthBytes ,
TickType_t xTicksToWait )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
size_t xReturn , xSpace = 0 ;
size_t xRequiredSpace = xDataLengthBytes ;
TimeOut_t xTimeOut ;
size_t xMaxReportedSpace = 0 ;
configASSERT ( pvTxData ) ;
configASSERT ( pxStreamBuffer ) ;
/* The maximum amount of space a stream buffer will ever report is its length
* minus 1. */
xMaxReportedSpace = pxStreamBuffer - > xLength - ( size_t ) 1 ;
/* 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
* increased by the amount of bytes needed to store the length of the
* message . */
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
xRequiredSpace + = sbBYTES_TO_STORE_MESSAGE_LENGTH ;
/* Overflow? */
configASSERT ( xRequiredSpace > xDataLengthBytes ) ;
/* If this is a message buffer then it must be possible to write the
* whole message . */
if ( xRequiredSpace > xMaxReportedSpace )
{
/* The message would not fit even if the entire buffer was empty,
* so don ' t wait for space . */
xTicksToWait = ( TickType_t ) 0 ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
/* If this is a stream buffer then it is acceptable to write only part
* of the message to the buffer . Cap the length to the total length of
* the buffer . */
if ( xRequiredSpace > xMaxReportedSpace )
{
xRequiredSpace = xMaxReportedSpace ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
if ( xTicksToWait ! = ( TickType_t ) 0 )
{
vTaskSetTimeOutState ( & xTimeOut ) ;
do
{
/* Wait until the required number of bytes are free in the message
* buffer . */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
{
xSpace = xStreamBufferSpacesAvailable ( pxStreamBuffer ) ;
if ( xSpace < xRequiredSpace )
{
/* Clear notification state as going to wait for space. */
( void ) xTaskNotifyStateClear ( NULL ) ;
/* Should only be one writer. */
configASSERT ( pxStreamBuffer - > xTaskWaitingToSend = = NULL ) ;
pxStreamBuffer - > xTaskWaitingToSend = xTaskGetCurrentTaskHandle ( ) ;
}
else
{
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
break ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
traceBLOCKING_ON_STREAM_BUFFER_SEND ( xStreamBuffer ) ;
( void ) xTaskNotifyWait ( ( uint32_t ) 0 , ( uint32_t ) 0 , NULL , xTicksToWait ) ;
pxStreamBuffer - > xTaskWaitingToSend = NULL ;
} while ( xTaskCheckForTimeOut ( & xTimeOut , & xTicksToWait ) = = pdFALSE ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
if ( xSpace = = ( size_t ) 0 )
{
xSpace = xStreamBufferSpacesAvailable ( pxStreamBuffer ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
xReturn = prvWriteMessageToBuffer ( pxStreamBuffer , pvTxData , xDataLengthBytes , xSpace , xRequiredSpace ) ;
if ( xReturn > ( size_t ) 0 )
{
traceSTREAM_BUFFER_SEND ( xStreamBuffer , xReturn ) ;
/* Was a task waiting for the data? */
if ( prvBytesInBuffer ( pxStreamBuffer ) > = pxStreamBuffer - > xTriggerLevelBytes )
{
prvSEND_COMPLETED ( pxStreamBuffer ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
traceSTREAM_BUFFER_SEND_FAILED ( xStreamBuffer ) ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
size_t xStreamBufferSendFromISR ( StreamBufferHandle_t xStreamBuffer ,
const void * pvTxData ,
size_t xDataLengthBytes ,
BaseType_t * const pxHigherPriorityTaskWoken )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
size_t xReturn , xSpace ;
size_t xRequiredSpace = xDataLengthBytes ;
configASSERT ( pvTxData ) ;
configASSERT ( pxStreamBuffer ) ;
/* 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
* increased by the amount of bytes needed to store the length of the
* message . */
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
xRequiredSpace + = sbBYTES_TO_STORE_MESSAGE_LENGTH ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
xSpace = xStreamBufferSpacesAvailable ( pxStreamBuffer ) ;
xReturn = prvWriteMessageToBuffer ( pxStreamBuffer , pvTxData , xDataLengthBytes , xSpace , xRequiredSpace ) ;
if ( xReturn > ( size_t ) 0 )
{
/* Was a task waiting for the data? */
if ( prvBytesInBuffer ( pxStreamBuffer ) > = pxStreamBuffer - > xTriggerLevelBytes )
{
prvSEND_COMPLETE_FROM_ISR ( pxStreamBuffer , pxHigherPriorityTaskWoken ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
traceSTREAM_BUFFER_SEND_FROM_ISR ( xStreamBuffer , xReturn ) ;
return xReturn ;
}
/*-----------------------------------------------------------*/
static size_t prvWriteMessageToBuffer ( StreamBuffer_t * const pxStreamBuffer ,
const void * pvTxData ,
size_t xDataLengthBytes ,
size_t xSpace ,
size_t xRequiredSpace )
{
size_t xNextHead = pxStreamBuffer - > xHead ;
configMESSAGE_BUFFER_LENGTH_TYPE xMessageLength ;
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
/* This is a message buffer, as opposed to a stream buffer. */
/* Convert xDataLengthBytes to the message length type. */
xMessageLength = ( configMESSAGE_BUFFER_LENGTH_TYPE ) xDataLengthBytes ;
/* Ensure the data length given fits within configMESSAGE_BUFFER_LENGTH_TYPE. */
configASSERT ( ( size_t ) xMessageLength = = xDataLengthBytes ) ;
if ( xSpace > = xRequiredSpace )
{
/* There 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
* itself will be written later in this function . */
xNextHead = prvWriteBytesToBuffer ( pxStreamBuffer , ( const uint8_t * ) & ( xMessageLength ) , sbBYTES_TO_STORE_MESSAGE_LENGTH , xNextHead ) ;
}
else
{
/* Not enough space, so do not write data to the buffer. */
xDataLengthBytes = 0 ;
}
}
else
{
/* This is a stream buffer, as opposed to a message buffer, so writing a
* stream of bytes rather than discrete messages . Plan to write as many
* bytes as possible . */
xDataLengthBytes = configMIN ( xDataLengthBytes , xSpace ) ;
}
if ( xDataLengthBytes ! = ( size_t ) 0 )
{
/* Write the data to the buffer. */
pxStreamBuffer - > xHead = prvWriteBytesToBuffer ( pxStreamBuffer , ( const uint8_t * ) pvTxData , xDataLengthBytes , xNextHead ) ; /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alignment and access. */
}
return xDataLengthBytes ;
}
/*-----------------------------------------------------------*/
size_t xStreamBufferReceive ( StreamBufferHandle_t xStreamBuffer ,
void * pvRxData ,
size_t xBufferLengthBytes ,
TickType_t xTicksToWait )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
size_t xReceivedLength = 0 , xBytesAvailable , xBytesToStoreMessageLength ;
configASSERT ( pvRxData ) ;
configASSERT ( pxStreamBuffer ) ;
/* This receive function is used by both message buffers, which store
* discrete messages , and stream buffers , which store a continuous stream of
* bytes . Discrete messages include an additional
* sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
* message . */
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH ;
}
else
{
xBytesToStoreMessageLength = 0 ;
}
if ( xTicksToWait ! = ( TickType_t ) 0 )
{
/* Checking if there is data and clearing the notification state must be
* performed atomically . */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
{
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer ) ;
/* If this function was invoked by a message buffer read then
* xBytesToStoreMessageLength holds the number of bytes used to hold
* the length of the next discrete message . If this function was
* invoked by a stream buffer read then xBytesToStoreMessageLength will
* be 0. */
if ( xBytesAvailable < = xBytesToStoreMessageLength )
{
/* Clear notification state as going to wait for data. */
( void ) xTaskNotifyStateClear ( NULL ) ;
/* Should only be one reader. */
configASSERT ( pxStreamBuffer - > xTaskWaitingToReceive = = NULL ) ;
pxStreamBuffer - > xTaskWaitingToReceive = xTaskGetCurrentTaskHandle ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & ( pxStreamBuffer - > xStreamBufferLock ) ) ;
2023-05-10 04:22:41 -04:00
if ( xBytesAvailable < = xBytesToStoreMessageLength )
{
/* Wait for data to be available. */
traceBLOCKING_ON_STREAM_BUFFER_RECEIVE ( xStreamBuffer ) ;
( void ) xTaskNotifyWait ( ( uint32_t ) 0 , ( uint32_t ) 0 , NULL , xTicksToWait ) ;
pxStreamBuffer - > xTaskWaitingToReceive = NULL ;
/* Recheck the data available after blocking. */
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer ) ;
}
/* Whether receiving a discrete message (where xBytesToStoreMessageLength
* holds the number of bytes used to store the message length ) or a stream of
* bytes ( where xBytesToStoreMessageLength is zero ) , the number of bytes
* available must be greater than xBytesToStoreMessageLength to be able to
* read bytes from the buffer . */
if ( xBytesAvailable > xBytesToStoreMessageLength )
{
xReceivedLength = prvReadMessageFromBuffer ( pxStreamBuffer , pvRxData , xBufferLengthBytes , xBytesAvailable ) ;
/* Was a task waiting for space in the buffer? */
if ( xReceivedLength ! = ( size_t ) 0 )
{
traceSTREAM_BUFFER_RECEIVE ( xStreamBuffer , xReceivedLength ) ;
prvRECEIVE_COMPLETED ( xStreamBuffer ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
traceSTREAM_BUFFER_RECEIVE_FAILED ( xStreamBuffer ) ;
mtCOVERAGE_TEST_MARKER ( ) ;
}
return xReceivedLength ;
}
/*-----------------------------------------------------------*/
size_t xStreamBufferNextMessageLengthBytes ( StreamBufferHandle_t xStreamBuffer )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
size_t xReturn , xBytesAvailable ;
configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn ;
configASSERT ( pxStreamBuffer ) ;
/* Ensure the stream buffer is being used as a message buffer. */
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer ) ;
if ( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
{
/* The number of bytes available is greater than the number of bytes
* required to hold the length of the next message , so another message
* is available . */
( void ) prvReadBytesFromBuffer ( pxStreamBuffer , ( uint8_t * ) & xTempReturn , sbBYTES_TO_STORE_MESSAGE_LENGTH , pxStreamBuffer - > xTail ) ;
xReturn = ( size_t ) xTempReturn ;
}
else
{
/* The minimum amount of bytes in a message buffer is
* ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ) , so if xBytesAvailable is
* less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
* value is 0. */
configASSERT ( xBytesAvailable = = 0 ) ;
xReturn = 0 ;
}
}
else
{
xReturn = 0 ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
size_t xStreamBufferReceiveFromISR ( StreamBufferHandle_t xStreamBuffer ,
void * pvRxData ,
size_t xBufferLengthBytes ,
BaseType_t * const pxHigherPriorityTaskWoken )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
size_t xReceivedLength = 0 , xBytesAvailable , xBytesToStoreMessageLength ;
configASSERT ( pvRxData ) ;
configASSERT ( pxStreamBuffer ) ;
/* This receive function is used by both message buffers, which store
* discrete messages , and stream buffers , which store a continuous stream of
* bytes . Discrete messages include an additional
* sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
* message . */
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH ;
}
else
{
xBytesToStoreMessageLength = 0 ;
}
xBytesAvailable = prvBytesInBuffer ( pxStreamBuffer ) ;
/* Whether receiving a discrete message (where xBytesToStoreMessageLength
* holds the number of bytes used to store the message length ) or a stream of
* bytes ( where xBytesToStoreMessageLength is zero ) , the number of bytes
* available must be greater than xBytesToStoreMessageLength to be able to
* read bytes from the buffer . */
if ( xBytesAvailable > xBytesToStoreMessageLength )
{
xReceivedLength = prvReadMessageFromBuffer ( pxStreamBuffer , pvRxData , xBufferLengthBytes , xBytesAvailable ) ;
/* Was a task waiting for space in the buffer? */
if ( xReceivedLength ! = ( size_t ) 0 )
{
prvRECEIVE_COMPLETED_FROM_ISR ( pxStreamBuffer , pxHigherPriorityTaskWoken ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
traceSTREAM_BUFFER_RECEIVE_FROM_ISR ( xStreamBuffer , xReceivedLength ) ;
return xReceivedLength ;
}
/*-----------------------------------------------------------*/
static size_t prvReadMessageFromBuffer ( StreamBuffer_t * pxStreamBuffer ,
void * pvRxData ,
size_t xBufferLengthBytes ,
size_t xBytesAvailable )
{
size_t xCount , xNextMessageLength ;
configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength ;
size_t xNextTail = pxStreamBuffer - > xTail ;
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
/* A discrete message is being received. First receive the length
* of the message . */
xNextTail = prvReadBytesFromBuffer ( pxStreamBuffer , ( uint8_t * ) & xTempNextMessageLength , sbBYTES_TO_STORE_MESSAGE_LENGTH , xNextTail ) ;
xNextMessageLength = ( size_t ) xTempNextMessageLength ;
/* Reduce the number of bytes available by the number of bytes just
* read out . */
xBytesAvailable - = sbBYTES_TO_STORE_MESSAGE_LENGTH ;
/* Check there is enough space in the buffer provided by the
* user . */
if ( xNextMessageLength > xBufferLengthBytes )
{
/* The user has provided insufficient space to read the message. */
xNextMessageLength = 0 ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
/* A stream of bytes is being received (as opposed to a discrete
* message ) , so read as many bytes as possible . */
xNextMessageLength = xBufferLengthBytes ;
}
/* Use the minimum of the wanted bytes and the available bytes. */
xCount = configMIN ( xNextMessageLength , xBytesAvailable ) ;
if ( xCount ! = ( size_t ) 0 )
{
/* Read the actual data and update the tail to mark the data as officially consumed. */
pxStreamBuffer - > xTail = prvReadBytesFromBuffer ( pxStreamBuffer , ( uint8_t * ) pvRxData , xCount , xNextTail ) ; /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */
}
return xCount ;
}
/*-----------------------------------------------------------*/
BaseType_t xStreamBufferIsEmpty ( StreamBufferHandle_t xStreamBuffer )
{
const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
BaseType_t xReturn ;
size_t xTail ;
configASSERT ( pxStreamBuffer ) ;
/* True if no bytes are available. */
xTail = pxStreamBuffer - > xTail ;
if ( pxStreamBuffer - > xHead = = xTail )
{
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
BaseType_t xStreamBufferIsFull ( StreamBufferHandle_t xStreamBuffer )
{
BaseType_t xReturn ;
size_t xBytesToStoreMessageLength ;
const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
configASSERT ( pxStreamBuffer ) ;
/* This generic version of the receive function is used by both message
* buffers , which store discrete messages , and stream buffers , which store a
* continuous stream of bytes . Discrete messages include an additional
* sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message . */
if ( ( pxStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ! = ( uint8_t ) 0 )
{
xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH ;
}
else
{
xBytesToStoreMessageLength = 0 ;
}
/* True if the available space equals zero. */
if ( xStreamBufferSpacesAvailable ( xStreamBuffer ) < = xBytesToStoreMessageLength )
{
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
BaseType_t xStreamBufferSendCompletedFromISR ( StreamBufferHandle_t xStreamBuffer ,
BaseType_t * pxHigherPriorityTaskWoken )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
BaseType_t xReturn ;
UBaseType_t uxSavedInterruptStatus ;
configASSERT ( pxStreamBuffer ) ;
uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR ( ) ;
{
if ( ( pxStreamBuffer ) - > xTaskWaitingToReceive ! = NULL )
{
( void ) xTaskNotifyFromISR ( ( pxStreamBuffer ) - > xTaskWaitingToReceive ,
( uint32_t ) 0 ,
eNoAction ,
pxHigherPriorityTaskWoken ) ;
( pxStreamBuffer ) - > xTaskWaitingToReceive = NULL ;
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR ( uxSavedInterruptStatus ) ;
return xReturn ;
}
/*-----------------------------------------------------------*/
BaseType_t xStreamBufferReceiveCompletedFromISR ( StreamBufferHandle_t xStreamBuffer ,
BaseType_t * pxHigherPriorityTaskWoken )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer ;
BaseType_t xReturn ;
UBaseType_t uxSavedInterruptStatus ;
configASSERT ( pxStreamBuffer ) ;
uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR ( ) ;
{
if ( ( pxStreamBuffer ) - > xTaskWaitingToSend ! = NULL )
{
( void ) xTaskNotifyFromISR ( ( pxStreamBuffer ) - > xTaskWaitingToSend ,
( uint32_t ) 0 ,
eNoAction ,
pxHigherPriorityTaskWoken ) ;
( pxStreamBuffer ) - > xTaskWaitingToSend = NULL ;
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
}
portCLEAR_INTERRUPT_MASK_FROM_ISR ( uxSavedInterruptStatus ) ;
return xReturn ;
}
/*-----------------------------------------------------------*/
static size_t prvWriteBytesToBuffer ( StreamBuffer_t * const pxStreamBuffer ,
const uint8_t * pucData ,
size_t xCount ,
size_t xHead )
{
size_t xFirstLength ;
configASSERT ( xCount > ( size_t ) 0 ) ;
/* 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
* the buffer will wrap back to the beginning . */
xFirstLength = configMIN ( pxStreamBuffer - > xLength - xHead , xCount ) ;
/* Write as many bytes as can be written in the first write. */
configASSERT ( ( xHead + xFirstLength ) < = pxStreamBuffer - > xLength ) ;
( void ) memcpy ( ( void * ) ( & ( pxStreamBuffer - > pucBuffer [ xHead ] ) ) , ( const void * ) pucData , xFirstLength ) ; /*lint !e9087 memcpy() requires void *. */
/* If the number of bytes written was less than the number that could be
* written in the first write . . . */
if ( xCount > xFirstLength )
{
/* ...then write the remaining bytes to the start of the buffer. */
configASSERT ( ( xCount - xFirstLength ) < = pxStreamBuffer - > xLength ) ;
( void ) memcpy ( ( void * ) pxStreamBuffer - > pucBuffer , ( const void * ) & ( pucData [ xFirstLength ] ) , xCount - xFirstLength ) ; /*lint !e9087 memcpy() requires void *. */
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
xHead + = xCount ;
if ( xHead > = pxStreamBuffer - > xLength )
{
xHead - = pxStreamBuffer - > xLength ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return xHead ;
}
/*-----------------------------------------------------------*/
static size_t prvReadBytesFromBuffer ( StreamBuffer_t * pxStreamBuffer ,
uint8_t * pucData ,
size_t xCount ,
size_t xTail )
{
size_t xFirstLength ;
configASSERT ( xCount ! = ( size_t ) 0 ) ;
/* 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
* the buffer . */
xFirstLength = configMIN ( pxStreamBuffer - > xLength - xTail , xCount ) ;
/* Obtain the number of bytes it is possible to obtain in the first
* read . Asserts check bounds of read and write . */
configASSERT ( xFirstLength < = xCount ) ;
configASSERT ( ( xTail + xFirstLength ) < = pxStreamBuffer - > xLength ) ;
( void ) memcpy ( ( void * ) pucData , ( const void * ) & ( pxStreamBuffer - > pucBuffer [ xTail ] ) , xFirstLength ) ; /*lint !e9087 memcpy() requires void *. */
/* If the total number of wanted bytes is greater than the number
* that could be read in the first read . . . */
if ( xCount > xFirstLength )
{
/* ...then read the remaining bytes from the start of the buffer. */
( void ) memcpy ( ( void * ) & ( pucData [ xFirstLength ] ) , ( void * ) ( pxStreamBuffer - > pucBuffer ) , xCount - xFirstLength ) ; /*lint !e9087 memcpy() requires void *. */
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Move the tail pointer to effectively remove the data read from the buffer. */
xTail + = xCount ;
if ( xTail > = pxStreamBuffer - > xLength )
{
xTail - = pxStreamBuffer - > xLength ;
}
return xTail ;
}
/*-----------------------------------------------------------*/
static size_t prvBytesInBuffer ( const StreamBuffer_t * const pxStreamBuffer )
{
/* Returns the distance between xTail and xHead. */
size_t xCount ;
xCount = pxStreamBuffer - > xLength + pxStreamBuffer - > xHead ;
xCount - = pxStreamBuffer - > xTail ;
if ( xCount > = pxStreamBuffer - > xLength )
{
xCount - = pxStreamBuffer - > xLength ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return xCount ;
}
/*-----------------------------------------------------------*/
static void prvInitialiseNewStreamBuffer ( StreamBuffer_t * const pxStreamBuffer ,
uint8_t * const pucBuffer ,
size_t xBufferSizeBytes ,
size_t xTriggerLevelBytes ,
uint8_t ucFlags ,
StreamBufferCallbackFunction_t pxSendCompletedCallback ,
StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
{
/* 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
* known value to assist in development / debugging . */
# if ( configASSERT_DEFINED == 1 )
{
/* 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
* result in confusion as to what is actually being observed . */
const BaseType_t xWriteValue = 0x55 ;
configASSERT ( memset ( pucBuffer , ( int ) xWriteValue , xBufferSizeBytes ) = = pucBuffer ) ;
2024-08-19 00:02:03 -04:00
( void ) xWriteValue ;
2023-05-10 04:22:41 -04:00
} /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */
# endif
2023-09-07 12:29:57 -04:00
/* This function could be called from xStreamBufferReset(), so we reset the
* stream buffer fields manually in order to avoid clearing
* xStreamBufferLock . The xStreamBufferLock is initialized separately on
* stream buffer creation . */
pxStreamBuffer - > xTail = ( size_t ) 0 ;
pxStreamBuffer - > xHead = ( size_t ) 0 ;
pxStreamBuffer - > xTaskWaitingToReceive = ( TaskHandle_t ) 0 ;
pxStreamBuffer - > xTaskWaitingToSend = ( TaskHandle_t ) 0 ;
# if ( configUSE_TRACE_FACILITY == 1 )
pxStreamBuffer - > uxStreamBufferNumber = ( UBaseType_t ) 0 ;
# endif
2023-05-10 04:22:41 -04:00
pxStreamBuffer - > pucBuffer = pucBuffer ;
pxStreamBuffer - > xLength = xBufferSizeBytes ;
pxStreamBuffer - > xTriggerLevelBytes = xTriggerLevelBytes ;
pxStreamBuffer - > ucFlags = ucFlags ;
# if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
{
pxStreamBuffer - > pxSendCompletedCallback = pxSendCompletedCallback ;
pxStreamBuffer - > pxReceiveCompletedCallback = pxReceiveCompletedCallback ;
}
# else
{
( void ) pxSendCompletedCallback ;
( void ) pxReceiveCompletedCallback ;
}
# endif
}
# if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxStreamBufferGetStreamBufferNumber ( StreamBufferHandle_t xStreamBuffer )
{
return xStreamBuffer - > uxStreamBufferNumber ;
}
# endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
# if ( configUSE_TRACE_FACILITY == 1 )
void vStreamBufferSetStreamBufferNumber ( StreamBufferHandle_t xStreamBuffer ,
UBaseType_t uxStreamBufferNumber )
{
xStreamBuffer - > uxStreamBufferNumber = uxStreamBufferNumber ;
}
# endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
# if ( configUSE_TRACE_FACILITY == 1 )
uint8_t ucStreamBufferGetStreamBufferType ( StreamBufferHandle_t xStreamBuffer )
{
return ( xStreamBuffer - > ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ;
}
# endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/