You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1263 lines
43 KiB
1263 lines
43 KiB
/* |
|
* FreeRTOS Kernel V10.3.1 |
|
* 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 |
|
* 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. |
|
* |
|
* http://www.FreeRTOS.org |
|
* http://aws.amazon.com/freertos |
|
* |
|
* 1 tab == 4 spaces! |
|
*/ |
|
|
|
/* 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" |
|
|
|
#if( configUSE_TASK_NOTIFICATIONS != 1 ) |
|
#error configUSE_TASK_NOTIFICATIONS 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, them provide default implementations |
|
that uses task notifications. */ |
|
/*lint -save -e9026 Function like macros allowed and needed here so they can be overidden. */ |
|
#ifndef sbRECEIVE_COMPLETED |
|
#define sbRECEIVE_COMPLETED( pxStreamBuffer ) \ |
|
vTaskSuspendAll(); \ |
|
{ \ |
|
if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ |
|
{ \ |
|
( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \ |
|
( uint32_t ) 0, \ |
|
eNoAction ); \ |
|
( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ |
|
} \ |
|
} \ |
|
( void ) xTaskResumeAll(); |
|
#endif /* sbRECEIVE_COMPLETED */ |
|
|
|
#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 the user has not provided an application specific Tx notification macro, |
|
or #defined the notification macro away, them provide a default implementation |
|
that uses task notifications. */ |
|
#ifndef sbSEND_COMPLETED |
|
#define sbSEND_COMPLETED( pxStreamBuffer ) \ |
|
vTaskSuspendAll(); \ |
|
{ \ |
|
if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ |
|
{ \ |
|
( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \ |
|
( uint32_t ) 0, \ |
|
eNoAction ); \ |
|
( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ |
|
} \ |
|
} \ |
|
( void ) xTaskResumeAll(); |
|
#endif /* sbSEND_COMPLETED */ |
|
|
|
#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 */ |
|
/*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 |
|
} 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 message buffer. |
|
* Returns the number of bytes written, which will either equal xCount in the |
|
* success case, or 0 if there was not enough space in the buffer (in which case |
|
* no data is written into the buffer). |
|
*/ |
|
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 |
|
* 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, |
|
size_t xBytesToStoreMessageLength ) 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; |
|
|
|
/* |
|
* Read xMaxCount bytes from the pxStreamBuffer message buffer and write them |
|
* to pucData. |
|
*/ |
|
static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer, |
|
uint8_t *pucData, |
|
size_t xMaxCount, |
|
size_t xBytesAvailable ) 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 ) PRIVILEGED_FUNCTION; |
|
|
|
/*-----------------------------------------------------------*/ |
|
|
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) |
|
|
|
StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer ) |
|
{ |
|
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. */ |
|
xBufferSizeBytes++; |
|
pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */ |
|
|
|
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 ); |
|
|
|
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 ) |
|
{ |
|
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 ) ); |
|
} /*lint !e529 xSize is referenced is configASSERT() is defined. */ |
|
#endif /* configASSERT_DEFINED */ |
|
|
|
if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) ) |
|
{ |
|
prvInitialiseNewStreamBuffer( pxStreamBuffer, |
|
pucStreamBufferStorageArea, |
|
xBufferSizeBytes, |
|
xTriggerLevelBytes, |
|
ucFlags ); |
|
|
|
/* Remember this was statically allocated in case it is ever deleted |
|
again. */ |
|
pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED; |
|
|
|
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 ) */ |
|
/*-----------------------------------------------------------*/ |
|
|
|
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; |
|
|
|
#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. */ |
|
taskENTER_CRITICAL(); |
|
{ |
|
if( pxStreamBuffer->xTaskWaitingToReceive == NULL ) |
|
{ |
|
if( pxStreamBuffer->xTaskWaitingToSend == NULL ) |
|
{ |
|
prvInitialiseNewStreamBuffer( pxStreamBuffer, |
|
pxStreamBuffer->pucBuffer, |
|
pxStreamBuffer->xLength, |
|
pxStreamBuffer->xTriggerLevelBytes, |
|
pxStreamBuffer->ucFlags ); |
|
xReturn = pdPASS; |
|
|
|
#if( configUSE_TRACE_FACILITY == 1 ) |
|
{ |
|
pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; |
|
} |
|
#endif |
|
|
|
traceSTREAM_BUFFER_RESET( xStreamBuffer ); |
|
} |
|
} |
|
} |
|
taskEXIT_CRITICAL(); |
|
|
|
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; |
|
|
|
configASSERT( pxStreamBuffer ); |
|
|
|
xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail; |
|
xSpace -= pxStreamBuffer->xHead; |
|
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; |
|
|
|
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; |
|
|
|
/* Overflow? */ |
|
configASSERT( xRequiredSpace > xDataLengthBytes ); |
|
} |
|
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. */ |
|
taskENTER_CRITICAL(); |
|
{ |
|
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 |
|
{ |
|
taskEXIT_CRITICAL(); |
|
break; |
|
} |
|
} |
|
taskEXIT_CRITICAL(); |
|
|
|
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 ) |
|
{ |
|
sbSEND_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 ) |
|
{ |
|
sbSEND_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 ) |
|
{ |
|
BaseType_t xShouldWrite; |
|
size_t xReturn; |
|
|
|
if( xSpace == ( size_t ) 0 ) |
|
{ |
|
/* Doesn't matter if this is a stream buffer or a message buffer, there |
|
is no space to write. */ |
|
xShouldWrite = pdFALSE; |
|
} |
|
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 |
|
stream of bytes rather than discrete messages. Write as many bytes as |
|
possible. */ |
|
xShouldWrite = pdTRUE; |
|
xDataLengthBytes = configMIN( xDataLengthBytes, xSpace ); |
|
} |
|
else if( xSpace >= xRequiredSpace ) |
|
{ |
|
/* 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 |
|
into the buffer. Start by writing the length of the data, the data |
|
itself will be written later in this function. */ |
|
xShouldWrite = pdTRUE; |
|
( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH ); |
|
} |
|
else |
|
{ |
|
/* There is space available, but not enough space. */ |
|
xShouldWrite = pdFALSE; |
|
} |
|
|
|
if( xShouldWrite != pdFALSE ) |
|
{ |
|
/* Writes the data itself. */ |
|
xReturn = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alighment and access. */ |
|
} |
|
else |
|
{ |
|
xReturn = 0; |
|
} |
|
|
|
return xReturn; |
|
} |
|
/*-----------------------------------------------------------*/ |
|
|
|
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. */ |
|
taskENTER_CRITICAL(); |
|
{ |
|
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(); |
|
} |
|
} |
|
taskEXIT_CRITICAL(); |
|
|
|
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, xBytesToStoreMessageLength ); |
|
|
|
/* Was a task waiting for space in the buffer? */ |
|
if( xReceivedLength != ( size_t ) 0 ) |
|
{ |
|
traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ); |
|
sbRECEIVE_COMPLETED( pxStreamBuffer ); |
|
} |
|
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, xOriginalTail; |
|
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. Return its length without removing the length bytes |
|
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 |
|
removed from the buffer. */ |
|
xOriginalTail = pxStreamBuffer->xTail; |
|
( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable ); |
|
xReturn = ( size_t ) xTempReturn; |
|
pxStreamBuffer->xTail = xOriginalTail; |
|
} |
|
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, xBytesToStoreMessageLength ); |
|
|
|
/* Was a task waiting for space in the buffer? */ |
|
if( xReceivedLength != ( size_t ) 0 ) |
|
{ |
|
sbRECEIVE_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 xBytesToStoreMessageLength ) |
|
{ |
|
size_t xOriginalTail, xReceivedLength, xNextMessageLength; |
|
configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength; |
|
|
|
if( xBytesToStoreMessageLength != ( size_t ) 0 ) |
|
{ |
|
/* 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 |
|
returned to its prior state if the length of the message is too |
|
large for the provided buffer. */ |
|
xOriginalTail = pxStreamBuffer->xTail; |
|
( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable ); |
|
xNextMessageLength = ( size_t ) xTempNextMessageLength; |
|
|
|
/* Reduce the number of bytes available by the number of bytes just |
|
read out. */ |
|
xBytesAvailable -= xBytesToStoreMessageLength; |
|
|
|
/* 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 |
|
so return the buffer to its previous state (so the length of |
|
the message is in the buffer again). */ |
|
pxStreamBuffer->xTail = xOriginalTail; |
|
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; |
|
} |
|
|
|
/* Read the actual data. */ |
|
xReceivedLength = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xNextMessageLength, xBytesAvailable ); /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */ |
|
|
|
return xReceivedLength; |
|
} |
|
/*-----------------------------------------------------------*/ |
|
|
|
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 xNextHead, xFirstLength; |
|
|
|
configASSERT( xCount > ( size_t ) 0 ); |
|
|
|
xNextHead = pxStreamBuffer->xHead; |
|
|
|
/* 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 - xNextHead, xCount ); |
|
|
|
/* Write as many bytes as can be written in the first write. */ |
|
configASSERT( ( xNextHead + xFirstLength ) <= pxStreamBuffer->xLength ); |
|
( 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 |
|
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(); |
|
} |
|
|
|
xNextHead += xCount; |
|
if( xNextHead >= pxStreamBuffer->xLength ) |
|
{ |
|
xNextHead -= pxStreamBuffer->xLength; |
|
} |
|
else |
|
{ |
|
mtCOVERAGE_TEST_MARKER(); |
|
} |
|
|
|
pxStreamBuffer->xHead = xNextHead; |
|
|
|
return xCount; |
|
} |
|
/*-----------------------------------------------------------*/ |
|
|
|
static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer, uint8_t *pucData, size_t xMaxCount, size_t xBytesAvailable ) |
|
{ |
|
size_t xCount, xFirstLength, xNextTail; |
|
|
|
/* Use the minimum of the wanted bytes and the available bytes. */ |
|
xCount = configMIN( xBytesAvailable, xMaxCount ); |
|
|
|
if( xCount > ( size_t ) 0 ) |
|
{ |
|
xNextTail = pxStreamBuffer->xTail; |
|
|
|
/* 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 - xNextTail, xCount ); |
|
|
|
/* Obtain the number of bytes it is possible to obtain in the first |
|
read. Asserts check bounds of read and write. */ |
|
configASSERT( xFirstLength <= xMaxCount ); |
|
configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength ); |
|
( 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 |
|
that could be read in the first read... */ |
|
if( xCount > xFirstLength ) |
|
{ |
|
/*...then read the remaining bytes from the start of the buffer. */ |
|
configASSERT( xCount <= xMaxCount ); |
|
( 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. */ |
|
xNextTail += xCount; |
|
|
|
if( xNextTail >= pxStreamBuffer->xLength ) |
|
{ |
|
xNextTail -= pxStreamBuffer->xLength; |
|
} |
|
|
|
pxStreamBuffer->xTail = xNextTail; |
|
} |
|
else |
|
{ |
|
mtCOVERAGE_TEST_MARKER(); |
|
} |
|
|
|
return xCount; |
|
} |
|
/*-----------------------------------------------------------*/ |
|
|
|
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 ) |
|
{ |
|
/* 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 ); |
|
} /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */ |
|
#endif |
|
|
|
( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */ |
|
pxStreamBuffer->pucBuffer = pucBuffer; |
|
pxStreamBuffer->xLength = xBufferSizeBytes; |
|
pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes; |
|
pxStreamBuffer->ucFlags = ucFlags; |
|
} |
|
|
|
#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 */ |
|
/*-----------------------------------------------------------*/
|
|
|