|  | /* | 
|  | * FreeRTOS Kernel <DEVELOPMENT BRANCH> | 
|  | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. | 
|  | * | 
|  | * SPDX-License-Identifier: MIT | 
|  | * | 
|  | * 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 <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 | 
|  |  | 
|  | #if ( INCLUDE_xTaskGetCurrentTaskHandle != 1 ) | 
|  | #error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 to build stream_buffer.c | 
|  | #endif | 
|  |  | 
|  | /* 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 | 
|  |  | 
|  | /* 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. */ | 
|  | #ifndef sbRECEIVE_COMPLETED | 
|  | #define sbRECEIVE_COMPLETED( pxStreamBuffer )                                     \ | 
|  | do                                                                                \ | 
|  | {                                                                                 \ | 
|  | vTaskSuspendAll();                                                            \ | 
|  | {                                                                             \ | 
|  | if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                      \ | 
|  | {                                                                         \ | 
|  | ( void ) xTaskNotifyIndexed( ( pxStreamBuffer )->xTaskWaitingToSend,  \ | 
|  | ( pxStreamBuffer )->uxNotificationIndex, \ | 
|  | ( uint32_t ) 0,                          \ | 
|  | eNoAction );                             \ | 
|  | ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                        \ | 
|  | }                                                                         \ | 
|  | }                                                                             \ | 
|  | ( void ) xTaskResumeAll();                                                    \ | 
|  | } while( 0 ) | 
|  | #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 )                                               \ | 
|  | do {                                                                                         \ | 
|  | if( ( pxStreamBuffer )->pxReceiveCompletedCallback != NULL )                             \ | 
|  | {                                                                                        \ | 
|  | ( pxStreamBuffer )->pxReceiveCompletedCallback( ( pxStreamBuffer ), pdFALSE, NULL ); \ | 
|  | }                                                                                        \ | 
|  | else                                                                                     \ | 
|  | {                                                                                        \ | 
|  | sbRECEIVE_COMPLETED( ( pxStreamBuffer ) );                                           \ | 
|  | }                                                                                        \ | 
|  | } while( 0 ) | 
|  | #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 )                        \ | 
|  | do {                                                                                     \ | 
|  | UBaseType_t uxSavedInterruptStatus;                                                  \ | 
|  | \ | 
|  | uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                              \ | 
|  | {                                                                                    \ | 
|  | if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                             \ | 
|  | {                                                                                \ | 
|  | ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,  \ | 
|  | ( pxStreamBuffer )->uxNotificationIndex, \ | 
|  | ( uint32_t ) 0,                          \ | 
|  | eNoAction,                               \ | 
|  | ( pxHigherPriorityTaskWoken ) );         \ | 
|  | ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                               \ | 
|  | }                                                                                \ | 
|  | }                                                                                    \ | 
|  | taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                                \ | 
|  | } while( 0 ) | 
|  | #endif /* sbRECEIVE_COMPLETED_FROM_ISR */ | 
|  |  | 
|  | #if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) | 
|  | #define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                                                               \ | 
|  | pxHigherPriorityTaskWoken )                                                   \ | 
|  | do {                                                                                                                 \ | 
|  | if( ( pxStreamBuffer )->pxReceiveCompletedCallback != NULL )                                                     \ | 
|  | {                                                                                                                \ | 
|  | ( pxStreamBuffer )->pxReceiveCompletedCallback( ( pxStreamBuffer ), pdTRUE, ( pxHigherPriorityTaskWoken ) ); \ | 
|  | }                                                                                                                \ | 
|  | else                                                                                                             \ | 
|  | {                                                                                                                \ | 
|  | sbRECEIVE_COMPLETED_FROM_ISR( ( pxStreamBuffer ), ( pxHigherPriorityTaskWoken ) );                           \ | 
|  | }                                                                                                                \ | 
|  | } while( 0 ) | 
|  | #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 | 
|  | #define sbSEND_COMPLETED( pxStreamBuffer )                                      \ | 
|  | vTaskSuspendAll();                                                              \ | 
|  | {                                                                               \ | 
|  | if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                     \ | 
|  | {                                                                           \ | 
|  | ( void ) xTaskNotifyIndexed( ( pxStreamBuffer )->xTaskWaitingToReceive, \ | 
|  | ( pxStreamBuffer )->uxNotificationIndex,   \ | 
|  | ( uint32_t ) 0,                            \ | 
|  | eNoAction );                               \ | 
|  | ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                       \ | 
|  | }                                                                           \ | 
|  | }                                                                               \ | 
|  | ( void ) xTaskResumeAll() | 
|  | #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 )                                               \ | 
|  | do {                                                                                      \ | 
|  | if( ( pxStreamBuffer )->pxSendCompletedCallback != NULL )                             \ | 
|  | {                                                                                     \ | 
|  | ( pxStreamBuffer )->pxSendCompletedCallback( ( pxStreamBuffer ), pdFALSE, NULL ); \ | 
|  | }                                                                                     \ | 
|  | else                                                                                  \ | 
|  | {                                                                                     \ | 
|  | sbSEND_COMPLETED( ( pxStreamBuffer ) );                                           \ | 
|  | }                                                                                     \ | 
|  | } while( 0 ) | 
|  | #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 )              \ | 
|  | do {                                                                                       \ | 
|  | UBaseType_t uxSavedInterruptStatus;                                                    \ | 
|  | \ | 
|  | uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                                \ | 
|  | {                                                                                      \ | 
|  | if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                            \ | 
|  | {                                                                                  \ | 
|  | ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \ | 
|  | ( pxStreamBuffer )->uxNotificationIndex,   \ | 
|  | ( uint32_t ) 0,                            \ | 
|  | eNoAction,                                 \ | 
|  | ( pxHigherPriorityTaskWoken ) );           \ | 
|  | ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                              \ | 
|  | }                                                                                  \ | 
|  | }                                                                                      \ | 
|  | taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                                  \ | 
|  | } while( 0 ) | 
|  | #endif /* sbSEND_COMPLETE_FROM_ISR */ | 
|  |  | 
|  |  | 
|  | #if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) | 
|  | #define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )                                    \ | 
|  | do {                                                                                                              \ | 
|  | if( ( pxStreamBuffer )->pxSendCompletedCallback != NULL )                                                     \ | 
|  | {                                                                                                             \ | 
|  | ( pxStreamBuffer )->pxSendCompletedCallback( ( pxStreamBuffer ), pdTRUE, ( pxHigherPriorityTaskWoken ) ); \ | 
|  | }                                                                                                             \ | 
|  | else                                                                                                          \ | 
|  | {                                                                                                             \ | 
|  | sbSEND_COMPLETE_FROM_ISR( ( pxStreamBuffer ), ( pxHigherPriorityTaskWoken ) );                            \ | 
|  | }                                                                                                             \ | 
|  | } while( 0 ) | 
|  | #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 ) */ | 
|  |  | 
|  | /* 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 | 
|  | { | 
|  | 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 | 
|  | UBaseType_t uxNotificationIndex;                               /* The index we are using for notification, by default tskDEFAULT_INDEX_TO_NOTIFY. */ | 
|  | } 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 ) | 
|  | { | 
|  | void * pvAllocatedMemory; | 
|  | uint8_t ucFlags; | 
|  |  | 
|  | traceENTER_xStreamBufferGenericCreate( xBufferSizeBytes, xTriggerLevelBytes, xIsMessageBuffer, pxSendCompletedCallback, pxReceiveCompletedCallback ); | 
|  |  | 
|  | /* 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 + 1U + sizeof( StreamBuffer_t ) ) ) | 
|  | { | 
|  | xBufferSizeBytes++; | 
|  | pvAllocatedMemory = pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); | 
|  | } | 
|  | else | 
|  | { | 
|  | pvAllocatedMemory = NULL; | 
|  | } | 
|  |  | 
|  | if( pvAllocatedMemory != NULL ) | 
|  | { | 
|  | /* MISRA Ref 11.5.1 [Malloc memory assignment] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ | 
|  | /* coverity[misra_c_2012_rule_11_5_violation] */ | 
|  | prvInitialiseNewStreamBuffer( ( StreamBuffer_t * ) pvAllocatedMemory,                         /* Structure at the start of the allocated memory. */ | 
|  | /* MISRA Ref 11.5.1 [Malloc memory assignment] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ | 
|  | /* coverity[misra_c_2012_rule_11_5_violation] */ | 
|  | ( ( uint8_t * ) pvAllocatedMemory ) + sizeof( StreamBuffer_t ), /* Storage area follows. */ | 
|  | xBufferSizeBytes, | 
|  | xTriggerLevelBytes, | 
|  | ucFlags, | 
|  | pxSendCompletedCallback, | 
|  | pxReceiveCompletedCallback ); | 
|  |  | 
|  | traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pvAllocatedMemory ), xIsMessageBuffer ); | 
|  | } | 
|  | else | 
|  | { | 
|  | traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ); | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferGenericCreate( pvAllocatedMemory ); | 
|  |  | 
|  | /* MISRA Ref 11.5.1 [Malloc memory assignment] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ | 
|  | /* coverity[misra_c_2012_rule_11_5_violation] */ | 
|  | return ( StreamBufferHandle_t ) pvAllocatedMemory; | 
|  | } | 
|  | #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 ) | 
|  | { | 
|  | /* MISRA Ref 11.3.1 [Misaligned access] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */ | 
|  | /* coverity[misra_c_2012_rule_11_3_violation] */ | 
|  | StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; | 
|  | StreamBufferHandle_t xReturn; | 
|  | uint8_t ucFlags; | 
|  |  | 
|  | traceENTER_xStreamBufferGenericCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, xIsMessageBuffer, pucStreamBufferStorageArea, pxStaticStreamBuffer, pxSendCompletedCallback, pxReceiveCompletedCallback ); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /* 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 != pdFALSE ) | 
|  | { | 
|  | /* Statically allocated message buffer. */ | 
|  | ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED; | 
|  | configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Statically allocated stream buffer. */ | 
|  | ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED; | 
|  | } | 
|  |  | 
|  | #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 ) ); | 
|  | } | 
|  | #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; | 
|  |  | 
|  | traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ); | 
|  |  | 
|  | /* MISRA Ref 11.3.1 [Misaligned access] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */ | 
|  | /* coverity[misra_c_2012_rule_11_3_violation] */ | 
|  | xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; | 
|  | } | 
|  | else | 
|  | { | 
|  | xReturn = NULL; | 
|  | traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ); | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferGenericCreateStatic( xReturn ); | 
|  |  | 
|  | return xReturn; | 
|  | } | 
|  | #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) | 
|  | BaseType_t xStreamBufferGetStaticBuffers( StreamBufferHandle_t xStreamBuffer, | 
|  | uint8_t ** ppucStreamBufferStorageArea, | 
|  | StaticStreamBuffer_t ** ppxStaticStreamBuffer ) | 
|  | { | 
|  | BaseType_t xReturn; | 
|  | StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  |  | 
|  | traceENTER_xStreamBufferGetStaticBuffers( xStreamBuffer, ppucStreamBufferStorageArea, ppxStaticStreamBuffer ); | 
|  |  | 
|  | configASSERT( pxStreamBuffer ); | 
|  | configASSERT( ppucStreamBufferStorageArea ); | 
|  | configASSERT( ppxStaticStreamBuffer ); | 
|  |  | 
|  | if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) != ( uint8_t ) 0 ) | 
|  | { | 
|  | *ppucStreamBufferStorageArea = pxStreamBuffer->pucBuffer; | 
|  | /* MISRA Ref 11.3.1 [Misaligned access] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */ | 
|  | /* coverity[misra_c_2012_rule_11_3_violation] */ | 
|  | *ppxStaticStreamBuffer = ( StaticStreamBuffer_t * ) pxStreamBuffer; | 
|  | xReturn = pdTRUE; | 
|  | } | 
|  | else | 
|  | { | 
|  | xReturn = pdFALSE; | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferGetStaticBuffers( xReturn ); | 
|  |  | 
|  | return xReturn; | 
|  | } | 
|  | #endif /* configSUPPORT_STATIC_ALLOCATION */ | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | StreamBuffer_t * pxStreamBuffer = xStreamBuffer; | 
|  |  | 
|  | traceENTER_vStreamBufferDelete( 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 ); | 
|  | } | 
|  | #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 ) ); | 
|  | } | 
|  |  | 
|  | traceRETURN_vStreamBufferDelete(); | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | 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 | 
|  |  | 
|  | traceENTER_xStreamBufferReset( xStreamBuffer ); | 
|  |  | 
|  | 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 ) && ( 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; | 
|  | } | 
|  | } | 
|  | taskEXIT_CRITICAL(); | 
|  |  | 
|  | traceRETURN_xStreamBufferReset( xReturn ); | 
|  |  | 
|  | return xReturn; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, | 
|  | size_t xTriggerLevel ) | 
|  | { | 
|  | StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  | BaseType_t xReturn; | 
|  |  | 
|  | traceENTER_xStreamBufferSetTriggerLevel( xStreamBuffer, xTriggerLevel ); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferSetTriggerLevel( xReturn ); | 
|  |  | 
|  | return xReturn; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  | size_t xSpace; | 
|  | size_t xOriginalTail; | 
|  |  | 
|  | traceENTER_xStreamBufferSpacesAvailable( xStreamBuffer ); | 
|  |  | 
|  | 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(); | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferSpacesAvailable( xSpace ); | 
|  |  | 
|  | return xSpace; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  | size_t xReturn; | 
|  |  | 
|  | traceENTER_xStreamBufferBytesAvailable( xStreamBuffer ); | 
|  |  | 
|  | configASSERT( pxStreamBuffer ); | 
|  |  | 
|  | xReturn = prvBytesInBuffer( pxStreamBuffer ); | 
|  |  | 
|  | traceRETURN_xStreamBufferBytesAvailable( xReturn ); | 
|  |  | 
|  | 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; | 
|  |  | 
|  | traceENTER_xStreamBufferSend( xStreamBuffer, pvTxData, xDataLengthBytes, xTicksToWait ); | 
|  |  | 
|  | 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. */ | 
|  | taskENTER_CRITICAL(); | 
|  | { | 
|  | xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); | 
|  |  | 
|  | if( xSpace < xRequiredSpace ) | 
|  | { | 
|  | /* Clear notification state as going to wait for space. */ | 
|  | ( void ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex ); | 
|  |  | 
|  | /* 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 ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( 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 ); | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferSend( xReturn ); | 
|  |  | 
|  | 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; | 
|  |  | 
|  | traceENTER_xStreamBufferSendFromISR( xStreamBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ); | 
|  |  | 
|  | 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 ); | 
|  | traceRETURN_xStreamBufferSendFromISR( 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. */ | 
|  | /* MISRA Ref 11.5.5 [Void pointer assignment] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ | 
|  | /* coverity[misra_c_2012_rule_11_5_violation] */ | 
|  | pxStreamBuffer->xHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes, xNextHead ); | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | traceENTER_xStreamBufferReceive( xStreamBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ); | 
|  |  | 
|  | 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 ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex ); | 
|  |  | 
|  | /* 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 ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( 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(); | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferReceive( xReceivedLength ); | 
|  |  | 
|  | return xReceivedLength; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  | size_t xReturn, xBytesAvailable; | 
|  | configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn; | 
|  |  | 
|  | traceENTER_xStreamBufferNextMessageLengthBytes( xStreamBuffer ); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferNextMessageLengthBytes( xReturn ); | 
|  |  | 
|  | 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; | 
|  |  | 
|  | traceENTER_xStreamBufferReceiveFromISR( xStreamBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ); | 
|  |  | 
|  | 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 ); | 
|  | traceRETURN_xStreamBufferReceiveFromISR( 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. */ | 
|  | /* MISRA Ref 11.5.5 [Void pointer assignment] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ | 
|  | /* coverity[misra_c_2012_rule_11_5_violation] */ | 
|  | pxStreamBuffer->xTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xCount, xNextTail ); | 
|  | } | 
|  |  | 
|  | return xCount; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  | BaseType_t xReturn; | 
|  | size_t xTail; | 
|  |  | 
|  | traceENTER_xStreamBufferIsEmpty( xStreamBuffer ); | 
|  |  | 
|  | configASSERT( pxStreamBuffer ); | 
|  |  | 
|  | /* True if no bytes are available. */ | 
|  | xTail = pxStreamBuffer->xTail; | 
|  |  | 
|  | if( pxStreamBuffer->xHead == xTail ) | 
|  | { | 
|  | xReturn = pdTRUE; | 
|  | } | 
|  | else | 
|  | { | 
|  | xReturn = pdFALSE; | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferIsEmpty( xReturn ); | 
|  |  | 
|  | return xReturn; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | BaseType_t xReturn; | 
|  | size_t xBytesToStoreMessageLength; | 
|  | const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  |  | 
|  | traceENTER_xStreamBufferIsFull( 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; | 
|  | } | 
|  |  | 
|  | traceRETURN_xStreamBufferIsFull( xReturn ); | 
|  |  | 
|  | return xReturn; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, | 
|  | BaseType_t * pxHigherPriorityTaskWoken ) | 
|  | { | 
|  | StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  | BaseType_t xReturn; | 
|  | UBaseType_t uxSavedInterruptStatus; | 
|  |  | 
|  | traceENTER_xStreamBufferSendCompletedFromISR( xStreamBuffer, pxHigherPriorityTaskWoken ); | 
|  |  | 
|  | configASSERT( pxStreamBuffer ); | 
|  |  | 
|  | uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); | 
|  | { | 
|  | if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) | 
|  | { | 
|  | ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, | 
|  | ( pxStreamBuffer )->uxNotificationIndex, | 
|  | ( uint32_t ) 0, | 
|  | eNoAction, | 
|  | pxHigherPriorityTaskWoken ); | 
|  | ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; | 
|  | xReturn = pdTRUE; | 
|  | } | 
|  | else | 
|  | { | 
|  | xReturn = pdFALSE; | 
|  | } | 
|  | } | 
|  | taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); | 
|  |  | 
|  | traceRETURN_xStreamBufferSendCompletedFromISR( xReturn ); | 
|  |  | 
|  | return xReturn; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, | 
|  | BaseType_t * pxHigherPriorityTaskWoken ) | 
|  | { | 
|  | StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  | BaseType_t xReturn; | 
|  | UBaseType_t uxSavedInterruptStatus; | 
|  |  | 
|  | traceENTER_xStreamBufferReceiveCompletedFromISR( xStreamBuffer, pxHigherPriorityTaskWoken ); | 
|  |  | 
|  | configASSERT( pxStreamBuffer ); | 
|  |  | 
|  | uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); | 
|  | { | 
|  | if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) | 
|  | { | 
|  | ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, | 
|  | ( pxStreamBuffer )->uxNotificationIndex, | 
|  | ( uint32_t ) 0, | 
|  | eNoAction, | 
|  | pxHigherPriorityTaskWoken ); | 
|  | ( pxStreamBuffer )->xTaskWaitingToSend = NULL; | 
|  | xReturn = pdTRUE; | 
|  | } | 
|  | else | 
|  | { | 
|  | xReturn = pdFALSE; | 
|  | } | 
|  | } | 
|  | taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); | 
|  |  | 
|  | traceRETURN_xStreamBufferReceiveCompletedFromISR( xReturn ); | 
|  |  | 
|  | 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 ); | 
|  |  | 
|  | /* 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 ); | 
|  | } | 
|  | 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 ); | 
|  |  | 
|  | /* 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 ); | 
|  | } | 
|  | 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. */ | 
|  | #define STREAM_BUFFER_BUFFER_WRITE_VALUE    ( 0x55 ) | 
|  | configASSERT( memset( pucBuffer, ( int ) STREAM_BUFFER_BUFFER_WRITE_VALUE, xBufferSizeBytes ) == pucBuffer ); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); | 
|  | pxStreamBuffer->pucBuffer = pucBuffer; | 
|  | pxStreamBuffer->xLength = xBufferSizeBytes; | 
|  | pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes; | 
|  | pxStreamBuffer->ucFlags = ucFlags; | 
|  | pxStreamBuffer->uxNotificationIndex = tskDEFAULT_INDEX_TO_NOTIFY; | 
|  | #if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) | 
|  | { | 
|  | pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback; | 
|  | pxStreamBuffer->pxReceiveCompletedCallback = pxReceiveCompletedCallback; | 
|  | } | 
|  | #else | 
|  | { | 
|  | /* MISRA Ref 11.1.1 [Object type casting] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-111 */ | 
|  | /* coverity[misra_c_2012_rule_11_1_violation] */ | 
|  | ( void ) pxSendCompletedCallback; | 
|  |  | 
|  | /* MISRA Ref 11.1.1 [Object type casting] */ | 
|  | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-111 */ | 
|  | /* coverity[misra_c_2012_rule_11_1_violation] */ | 
|  | ( void ) pxReceiveCompletedCallback; | 
|  | } | 
|  | #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */ | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | UBaseType_t uxStreamBufferGetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  |  | 
|  | traceENTER_uxStreamBufferGetStreamBufferNotificationIndex( xStreamBuffer ); | 
|  |  | 
|  | configASSERT( pxStreamBuffer ); | 
|  |  | 
|  | traceRETURN_uxStreamBufferGetStreamBufferNotificationIndex( pxStreamBuffer->uxNotificationIndex ); | 
|  |  | 
|  | return pxStreamBuffer->uxNotificationIndex; | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | void vStreamBufferSetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer, | 
|  | UBaseType_t uxNotificationIndex ) | 
|  | { | 
|  | StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; | 
|  |  | 
|  | traceENTER_vStreamBufferSetStreamBufferNotificationIndex( xStreamBuffer, uxNotificationIndex ); | 
|  |  | 
|  | configASSERT( pxStreamBuffer ); | 
|  |  | 
|  | /* There should be no task waiting otherwise we'd never resume them. */ | 
|  | configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL ); | 
|  | configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL ); | 
|  |  | 
|  | /* Check that the task notification index is valid. */ | 
|  | configASSERT( uxNotificationIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES ); | 
|  |  | 
|  | pxStreamBuffer->uxNotificationIndex = uxNotificationIndex; | 
|  |  | 
|  | traceRETURN_vStreamBufferSetStreamBufferNotificationIndex(); | 
|  | } | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | #if ( configUSE_TRACE_FACILITY == 1 ) | 
|  |  | 
|  | UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | traceENTER_uxStreamBufferGetStreamBufferNumber( xStreamBuffer ); | 
|  |  | 
|  | traceRETURN_uxStreamBufferGetStreamBufferNumber( xStreamBuffer->uxStreamBufferNumber ); | 
|  |  | 
|  | return xStreamBuffer->uxStreamBufferNumber; | 
|  | } | 
|  |  | 
|  | #endif /* configUSE_TRACE_FACILITY */ | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | #if ( configUSE_TRACE_FACILITY == 1 ) | 
|  |  | 
|  | void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, | 
|  | UBaseType_t uxStreamBufferNumber ) | 
|  | { | 
|  | traceENTER_vStreamBufferSetStreamBufferNumber( xStreamBuffer, uxStreamBufferNumber ); | 
|  |  | 
|  | xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; | 
|  |  | 
|  | traceRETURN_vStreamBufferSetStreamBufferNumber(); | 
|  | } | 
|  |  | 
|  | #endif /* configUSE_TRACE_FACILITY */ | 
|  | /*-----------------------------------------------------------*/ | 
|  |  | 
|  | #if ( configUSE_TRACE_FACILITY == 1 ) | 
|  |  | 
|  | uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) | 
|  | { | 
|  | traceENTER_ucStreamBufferGetStreamBufferType( xStreamBuffer ); | 
|  |  | 
|  | traceRETURN_ucStreamBufferGetStreamBufferType( ( uint8_t ) ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ); | 
|  |  | 
|  | return( ( uint8_t ) ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) ); | 
|  | } | 
|  |  | 
|  | #endif /* configUSE_TRACE_FACILITY */ | 
|  | /*-----------------------------------------------------------*/ |