2 * FreeRTOS Kernel V10.1.1
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * http://www.FreeRTOS.org
23 * http://aws.amazon.com/freertos
28 /* Standard includes. */
32 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
33 all the API functions to use the MPU wrappers. That should only be done when
34 task.h is included from an application file. */
35 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
37 /* FreeRTOS includes. */
40 #include "stream_buffer.h"
42 #if( configUSE_TASK_NOTIFICATIONS != 1 )
43 #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c
46 /* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified
47 because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
48 for the header files above, but not in this file, in order to generate the
49 correct privileged Vs unprivileged linkage and placement. */
50 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
52 /* If the user has not provided application specific Rx notification macros,
53 or #defined the notification macros away, them provide default implementations
54 that uses task notifications. */
55 /*lint -save -e9026 Function like macros allowed and needed here so they can be overidden. */
56 #ifndef sbRECEIVE_COMPLETED
57 #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \
60 if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
62 ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \
65 ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
68 ( void ) xTaskResumeAll();
69 #endif /* sbRECEIVE_COMPLETED */
71 #ifndef sbRECEIVE_COMPLETED_FROM_ISR
72 #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \
73 pxHigherPriorityTaskWoken ) \
75 UBaseType_t uxSavedInterruptStatus; \
77 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
79 if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
81 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \
84 pxHigherPriorityTaskWoken ); \
85 ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
88 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
90 #endif /* sbRECEIVE_COMPLETED_FROM_ISR */
92 /* If the user has not provided an application specific Tx notification macro,
93 or #defined the notification macro away, them provide a default implementation
94 that uses task notifications. */
95 #ifndef sbSEND_COMPLETED
96 #define sbSEND_COMPLETED( pxStreamBuffer ) \
99 if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
101 ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \
104 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
107 ( void ) xTaskResumeAll();
108 #endif /* sbSEND_COMPLETED */
110 #ifndef sbSEND_COMPLETE_FROM_ISR
111 #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
113 UBaseType_t uxSavedInterruptStatus; \
115 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
117 if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
119 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \
122 pxHigherPriorityTaskWoken ); \
123 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
126 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
128 #endif /* sbSEND_COMPLETE_FROM_ISR */
129 /*lint -restore (9026) */
131 /* The number of bytes used to hold the length of a message in the buffer. */
132 #define sbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
134 /* Bits stored in the ucFlags field of the stream buffer. */
135 #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. */
136 #define sbFLAGS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */
138 /*-----------------------------------------------------------*/
140 /* Structure that hold state information on the buffer. */
141 typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
143 volatile size_t xTail; /* Index to the next item to read within the buffer. */
144 volatile size_t xHead; /* Index to the next item to write within the buffer. */
145 size_t xLength; /* The length of the buffer pointed to by pucBuffer. */
146 size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
147 volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
148 volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */
149 uint8_t *pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
152 #if ( configUSE_TRACE_FACILITY == 1 )
153 UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
158 * The number of bytes available to be read from the buffer.
160 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION;
163 * Add xCount bytes from pucData into the pxStreamBuffer message buffer.
164 * Returns the number of bytes written, which will either equal xCount in the
165 * success case, or 0 if there was not enough space in the buffer (in which case
166 * no data is written into the buffer).
168 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount ) PRIVILEGED_FUNCTION;
171 * If the stream buffer is being used as a message buffer, then reads an entire
172 * message out of the buffer. If the stream buffer is being used as a stream
173 * buffer then read as many bytes as possible from the buffer.
174 * prvReadBytesFromBuffer() is called to actually extract the bytes from the
175 * buffer's data storage area.
177 static size_t prvReadMessageFromBuffer( StreamBuffer_t *pxStreamBuffer,
179 size_t xBufferLengthBytes,
180 size_t xBytesAvailable,
181 size_t xBytesToStoreMessageLength ) PRIVILEGED_FUNCTION;
184 * If the stream buffer is being used as a message buffer, then writes an entire
185 * message to the buffer. If the stream buffer is being used as a stream
186 * buffer then write as many bytes as possible to the buffer.
187 * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's
190 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
191 const void * pvTxData,
192 size_t xDataLengthBytes,
194 size_t xRequiredSpace ) PRIVILEGED_FUNCTION;
197 * Read xMaxCount bytes from the pxStreamBuffer message buffer and write them
200 static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer,
203 size_t xBytesAvailable ) PRIVILEGED_FUNCTION;
206 * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to
207 * initialise the members of the newly created stream buffer structure.
209 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
210 uint8_t * const pucBuffer,
211 size_t xBufferSizeBytes,
212 size_t xTriggerLevelBytes,
213 uint8_t ucFlags ) PRIVILEGED_FUNCTION;
215 /*-----------------------------------------------------------*/
217 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
219 StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer )
221 uint8_t *pucAllocatedMemory;
224 /* In case the stream buffer is going to be used as a message buffer
225 (that is, it will hold discrete messages with a little meta data that
226 says how big the next message is) check the buffer will be large enough
227 to hold at least one message. */
228 if( xIsMessageBuffer == pdTRUE )
230 /* Is a message buffer but not statically allocated. */
231 ucFlags = sbFLAGS_IS_MESSAGE_BUFFER;
232 configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
236 /* Not a message buffer and not statically allocated. */
238 configASSERT( xBufferSizeBytes > 0 );
240 configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
242 /* A trigger level of 0 would cause a waiting task to unblock even when
243 the buffer was empty. */
244 if( xTriggerLevelBytes == ( size_t ) 0 )
246 xTriggerLevelBytes = ( size_t ) 1;
249 /* A stream buffer requires a StreamBuffer_t structure and a buffer.
250 Both are allocated in a single call to pvPortMalloc(). The
251 StreamBuffer_t structure is placed at the start of the allocated memory
252 and the buffer follows immediately after. The requested size is
253 incremented so the free space is returned as the user would expect -
254 this is a quirk of the implementation that means otherwise the free
255 space would be reported as one byte smaller than would be logically
258 pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */
260 if( pucAllocatedMemory != NULL )
262 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. */
263 pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */
268 traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );
272 traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );
275 return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */
278 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
279 /*-----------------------------------------------------------*/
281 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
283 StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
284 size_t xTriggerLevelBytes,
285 BaseType_t xIsMessageBuffer,
286 uint8_t * const pucStreamBufferStorageArea,
287 StaticStreamBuffer_t * const pxStaticStreamBuffer )
289 StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */
290 StreamBufferHandle_t xReturn;
293 configASSERT( pucStreamBufferStorageArea );
294 configASSERT( pxStaticStreamBuffer );
295 configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
297 /* A trigger level of 0 would cause a waiting task to unblock even when
298 the buffer was empty. */
299 if( xTriggerLevelBytes == ( size_t ) 0 )
301 xTriggerLevelBytes = ( size_t ) 1;
304 if( xIsMessageBuffer != pdFALSE )
306 /* Statically allocated message buffer. */
307 ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;
311 /* Statically allocated stream buffer. */
312 ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;
315 /* In case the stream buffer is going to be used as a message buffer
316 (that is, it will hold discrete messages with a little meta data that
317 says how big the next message is) check the buffer will be large enough
318 to hold at least one message. */
319 configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
321 #if( configASSERT_DEFINED == 1 )
323 /* Sanity check that the size of the structure used to declare a
324 variable of type StaticStreamBuffer_t equals the size of the real
325 message buffer structure. */
326 volatile size_t xSize = sizeof( StaticStreamBuffer_t );
327 configASSERT( xSize == sizeof( StreamBuffer_t ) );
328 } /*lint !e529 xSize is referenced is configASSERT() is defined. */
329 #endif /* configASSERT_DEFINED */
331 if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )
333 prvInitialiseNewStreamBuffer( pxStreamBuffer,
334 pucStreamBufferStorageArea,
339 /* Remember this was statically allocated in case it is ever deleted
341 pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;
343 traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );
345 xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */
350 traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );
356 #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
357 /*-----------------------------------------------------------*/
359 void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )
361 StreamBuffer_t * pxStreamBuffer = xStreamBuffer;
363 configASSERT( pxStreamBuffer );
365 traceSTREAM_BUFFER_DELETE( xStreamBuffer );
367 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )
369 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
371 /* Both the structure and the buffer were allocated using a single call
372 to pvPortMalloc(), hence only one call to vPortFree() is required. */
373 vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */
377 /* Should not be possible to get here, ucFlags must be corrupt.
379 configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );
385 /* The structure and buffer were not allocated dynamically and cannot be
386 freed - just scrub the structure so future use will assert. */
387 ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
390 /*-----------------------------------------------------------*/
392 BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
394 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
395 BaseType_t xReturn = pdFAIL;
397 #if( configUSE_TRACE_FACILITY == 1 )
398 UBaseType_t uxStreamBufferNumber;
401 configASSERT( pxStreamBuffer );
403 #if( configUSE_TRACE_FACILITY == 1 )
405 /* Store the stream buffer number so it can be restored after the
407 uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
411 /* Can only reset a message buffer if there are no tasks blocked on it. */
412 taskENTER_CRITICAL();
414 if( pxStreamBuffer->xTaskWaitingToReceive == NULL )
416 if( pxStreamBuffer->xTaskWaitingToSend == NULL )
418 prvInitialiseNewStreamBuffer( pxStreamBuffer,
419 pxStreamBuffer->pucBuffer,
420 pxStreamBuffer->xLength,
421 pxStreamBuffer->xTriggerLevelBytes,
422 pxStreamBuffer->ucFlags );
425 #if( configUSE_TRACE_FACILITY == 1 )
427 pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
431 traceSTREAM_BUFFER_RESET( xStreamBuffer );
439 /*-----------------------------------------------------------*/
441 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel )
443 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
446 configASSERT( pxStreamBuffer );
448 /* It is not valid for the trigger level to be 0. */
449 if( xTriggerLevel == ( size_t ) 0 )
451 xTriggerLevel = ( size_t ) 1;
454 /* The trigger level is the number of bytes that must be in the stream
455 buffer before a task that is waiting for data is unblocked. */
456 if( xTriggerLevel <= pxStreamBuffer->xLength )
458 pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
468 /*-----------------------------------------------------------*/
470 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )
472 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
475 configASSERT( pxStreamBuffer );
477 xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;
478 xSpace -= pxStreamBuffer->xHead;
479 xSpace -= ( size_t ) 1;
481 if( xSpace >= pxStreamBuffer->xLength )
483 xSpace -= pxStreamBuffer->xLength;
487 mtCOVERAGE_TEST_MARKER();
492 /*-----------------------------------------------------------*/
494 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )
496 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
499 configASSERT( pxStreamBuffer );
501 xReturn = prvBytesInBuffer( pxStreamBuffer );
504 /*-----------------------------------------------------------*/
506 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
507 const void *pvTxData,
508 size_t xDataLengthBytes,
509 TickType_t xTicksToWait )
511 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
512 size_t xReturn, xSpace = 0;
513 size_t xRequiredSpace = xDataLengthBytes;
516 configASSERT( pvTxData );
517 configASSERT( pxStreamBuffer );
519 /* This send function is used to write to both message buffers and stream
520 buffers. If this is a message buffer then the space needed must be
521 increased by the amount of bytes needed to store the length of the
523 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
525 xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
528 configASSERT( xRequiredSpace > xDataLengthBytes );
532 mtCOVERAGE_TEST_MARKER();
535 if( xTicksToWait != ( TickType_t ) 0 )
537 vTaskSetTimeOutState( &xTimeOut );
541 /* Wait until the required number of bytes are free in the message
543 taskENTER_CRITICAL();
545 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
547 if( xSpace < xRequiredSpace )
549 /* Clear notification state as going to wait for space. */
550 ( void ) xTaskNotifyStateClear( NULL );
552 /* Should only be one writer. */
553 configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
554 pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();
564 traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
565 ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
566 pxStreamBuffer->xTaskWaitingToSend = NULL;
568 } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
572 mtCOVERAGE_TEST_MARKER();
575 if( xSpace == ( size_t ) 0 )
577 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
581 mtCOVERAGE_TEST_MARKER();
584 xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
586 if( xReturn > ( size_t ) 0 )
588 traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );
590 /* Was a task waiting for the data? */
591 if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
593 sbSEND_COMPLETED( pxStreamBuffer );
597 mtCOVERAGE_TEST_MARKER();
602 mtCOVERAGE_TEST_MARKER();
603 traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );
608 /*-----------------------------------------------------------*/
610 size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
611 const void *pvTxData,
612 size_t xDataLengthBytes,
613 BaseType_t * const pxHigherPriorityTaskWoken )
615 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
616 size_t xReturn, xSpace;
617 size_t xRequiredSpace = xDataLengthBytes;
619 configASSERT( pvTxData );
620 configASSERT( pxStreamBuffer );
622 /* This send function is used to write to both message buffers and stream
623 buffers. If this is a message buffer then the space needed must be
624 increased by the amount of bytes needed to store the length of the
626 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
628 xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
632 mtCOVERAGE_TEST_MARKER();
635 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
636 xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
638 if( xReturn > ( size_t ) 0 )
640 /* Was a task waiting for the data? */
641 if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
643 sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
647 mtCOVERAGE_TEST_MARKER();
652 mtCOVERAGE_TEST_MARKER();
655 traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );
659 /*-----------------------------------------------------------*/
661 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
662 const void * pvTxData,
663 size_t xDataLengthBytes,
665 size_t xRequiredSpace )
667 BaseType_t xShouldWrite;
670 if( xSpace == ( size_t ) 0 )
672 /* Doesn't matter if this is a stream buffer or a message buffer, there
673 is no space to write. */
674 xShouldWrite = pdFALSE;
676 else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 )
678 /* This is a stream buffer, as opposed to a message buffer, so writing a
679 stream of bytes rather than discrete messages. Write as many bytes as
681 xShouldWrite = pdTRUE;
682 xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );
684 else if( xSpace >= xRequiredSpace )
686 /* This is a message buffer, as opposed to a stream buffer, and there
687 is enough space to write both the message length and the message itself
688 into the buffer. Start by writing the length of the data, the data
689 itself will be written later in this function. */
690 xShouldWrite = pdTRUE;
691 ( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH );
695 /* There is space available, but not enough space. */
696 xShouldWrite = pdFALSE;
699 if( xShouldWrite != pdFALSE )
701 /* Writes the data itself. */
702 xReturn = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alighment and access. */
711 /*-----------------------------------------------------------*/
713 size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
715 size_t xBufferLengthBytes,
716 TickType_t xTicksToWait )
718 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
719 size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
721 configASSERT( pvRxData );
722 configASSERT( pxStreamBuffer );
724 /* This receive function is used by both message buffers, which store
725 discrete messages, and stream buffers, which store a continuous stream of
726 bytes. Discrete messages include an additional
727 sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
729 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
731 xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
735 xBytesToStoreMessageLength = 0;
738 if( xTicksToWait != ( TickType_t ) 0 )
740 /* Checking if there is data and clearing the notification state must be
741 performed atomically. */
742 taskENTER_CRITICAL();
744 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
746 /* If this function was invoked by a message buffer read then
747 xBytesToStoreMessageLength holds the number of bytes used to hold
748 the length of the next discrete message. If this function was
749 invoked by a stream buffer read then xBytesToStoreMessageLength will
751 if( xBytesAvailable <= xBytesToStoreMessageLength )
753 /* Clear notification state as going to wait for data. */
754 ( void ) xTaskNotifyStateClear( NULL );
756 /* Should only be one reader. */
757 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
758 pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();
762 mtCOVERAGE_TEST_MARKER();
767 if( xBytesAvailable <= xBytesToStoreMessageLength )
769 /* Wait for data to be available. */
770 traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );
771 ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
772 pxStreamBuffer->xTaskWaitingToReceive = NULL;
774 /* Recheck the data available after blocking. */
775 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
779 mtCOVERAGE_TEST_MARKER();
784 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
787 /* Whether receiving a discrete message (where xBytesToStoreMessageLength
788 holds the number of bytes used to store the message length) or a stream of
789 bytes (where xBytesToStoreMessageLength is zero), the number of bytes
790 available must be greater than xBytesToStoreMessageLength to be able to
791 read bytes from the buffer. */
792 if( xBytesAvailable > xBytesToStoreMessageLength )
794 xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );
796 /* Was a task waiting for space in the buffer? */
797 if( xReceivedLength != ( size_t ) 0 )
799 traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );
800 sbRECEIVE_COMPLETED( pxStreamBuffer );
804 mtCOVERAGE_TEST_MARKER();
809 traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );
810 mtCOVERAGE_TEST_MARKER();
813 return xReceivedLength;
815 /*-----------------------------------------------------------*/
817 size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )
819 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
820 size_t xReturn, xBytesAvailable, xOriginalTail;
821 configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
823 configASSERT( pxStreamBuffer );
825 /* Ensure the stream buffer is being used as a message buffer. */
826 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
828 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
829 if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
831 /* The number of bytes available is greater than the number of bytes
832 required to hold the length of the next message, so another message
833 is available. Return its length without removing the length bytes
834 from the buffer. A copy of the tail is stored so the buffer can be
835 returned to its prior state as the message is not actually being
836 removed from the buffer. */
837 xOriginalTail = pxStreamBuffer->xTail;
838 ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable );
839 xReturn = ( size_t ) xTempReturn;
840 pxStreamBuffer->xTail = xOriginalTail;
844 /* The minimum amount of bytes in a message buffer is
845 ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is
846 less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
848 configASSERT( xBytesAvailable == 0 );
859 /*-----------------------------------------------------------*/
861 size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
863 size_t xBufferLengthBytes,
864 BaseType_t * const pxHigherPriorityTaskWoken )
866 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
867 size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
869 configASSERT( pvRxData );
870 configASSERT( pxStreamBuffer );
872 /* This receive function is used by both message buffers, which store
873 discrete messages, and stream buffers, which store a continuous stream of
874 bytes. Discrete messages include an additional
875 sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
877 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
879 xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
883 xBytesToStoreMessageLength = 0;
886 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
888 /* Whether receiving a discrete message (where xBytesToStoreMessageLength
889 holds the number of bytes used to store the message length) or a stream of
890 bytes (where xBytesToStoreMessageLength is zero), the number of bytes
891 available must be greater than xBytesToStoreMessageLength to be able to
892 read bytes from the buffer. */
893 if( xBytesAvailable > xBytesToStoreMessageLength )
895 xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );
897 /* Was a task waiting for space in the buffer? */
898 if( xReceivedLength != ( size_t ) 0 )
900 sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
904 mtCOVERAGE_TEST_MARKER();
909 mtCOVERAGE_TEST_MARKER();
912 traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );
914 return xReceivedLength;
916 /*-----------------------------------------------------------*/
918 static size_t prvReadMessageFromBuffer( StreamBuffer_t *pxStreamBuffer,
920 size_t xBufferLengthBytes,
921 size_t xBytesAvailable,
922 size_t xBytesToStoreMessageLength )
924 size_t xOriginalTail, xReceivedLength, xNextMessageLength;
925 configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
927 if( xBytesToStoreMessageLength != ( size_t ) 0 )
929 /* A discrete message is being received. First receive the length
930 of the message. A copy of the tail is stored so the buffer can be
931 returned to its prior state if the length of the message is too
932 large for the provided buffer. */
933 xOriginalTail = pxStreamBuffer->xTail;
934 ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable );
935 xNextMessageLength = ( size_t ) xTempNextMessageLength;
937 /* Reduce the number of bytes available by the number of bytes just
939 xBytesAvailable -= xBytesToStoreMessageLength;
941 /* Check there is enough space in the buffer provided by the
943 if( xNextMessageLength > xBufferLengthBytes )
945 /* The user has provided insufficient space to read the message
946 so return the buffer to its previous state (so the length of
947 the message is in the buffer again). */
948 pxStreamBuffer->xTail = xOriginalTail;
949 xNextMessageLength = 0;
953 mtCOVERAGE_TEST_MARKER();
958 /* A stream of bytes is being received (as opposed to a discrete
959 message), so read as many bytes as possible. */
960 xNextMessageLength = xBufferLengthBytes;
963 /* Read the actual data. */
964 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. */
966 return xReceivedLength;
968 /*-----------------------------------------------------------*/
970 BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )
972 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
976 configASSERT( pxStreamBuffer );
978 /* True if no bytes are available. */
979 xTail = pxStreamBuffer->xTail;
980 if( pxStreamBuffer->xHead == xTail )
991 /*-----------------------------------------------------------*/
993 BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )
996 size_t xBytesToStoreMessageLength;
997 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
999 configASSERT( pxStreamBuffer );
1001 /* This generic version of the receive function is used by both message
1002 buffers, which store discrete messages, and stream buffers, which store a
1003 continuous stream of bytes. Discrete messages include an additional
1004 sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */
1005 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1007 xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1011 xBytesToStoreMessageLength = 0;
1014 /* True if the available space equals zero. */
1015 if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )
1026 /*-----------------------------------------------------------*/
1028 BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken )
1030 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1032 UBaseType_t uxSavedInterruptStatus;
1034 configASSERT( pxStreamBuffer );
1036 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
1038 if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
1040 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
1043 pxHigherPriorityTaskWoken );
1044 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
1052 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1056 /*-----------------------------------------------------------*/
1058 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken )
1060 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1062 UBaseType_t uxSavedInterruptStatus;
1064 configASSERT( pxStreamBuffer );
1066 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
1068 if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
1070 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
1073 pxHigherPriorityTaskWoken );
1074 ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
1082 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1086 /*-----------------------------------------------------------*/
1088 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, const uint8_t *pucData, size_t xCount )
1090 size_t xNextHead, xFirstLength;
1092 configASSERT( xCount > ( size_t ) 0 );
1094 xNextHead = pxStreamBuffer->xHead;
1096 /* Calculate the number of bytes that can be added in the first write -
1097 which may be less than the total number of bytes that need to be added if
1098 the buffer will wrap back to the beginning. */
1099 xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount );
1101 /* Write as many bytes as can be written in the first write. */
1102 configASSERT( ( xNextHead + xFirstLength ) <= pxStreamBuffer->xLength );
1103 ( void ) memcpy( ( void* ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1105 /* If the number of bytes written was less than the number that could be
1106 written in the first write... */
1107 if( xCount > xFirstLength )
1109 /* ...then write the remaining bytes to the start of the buffer. */
1110 configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength );
1111 ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1115 mtCOVERAGE_TEST_MARKER();
1118 xNextHead += xCount;
1119 if( xNextHead >= pxStreamBuffer->xLength )
1121 xNextHead -= pxStreamBuffer->xLength;
1125 mtCOVERAGE_TEST_MARKER();
1128 pxStreamBuffer->xHead = xNextHead;
1132 /*-----------------------------------------------------------*/
1134 static size_t prvReadBytesFromBuffer( StreamBuffer_t *pxStreamBuffer, uint8_t *pucData, size_t xMaxCount, size_t xBytesAvailable )
1136 size_t xCount, xFirstLength, xNextTail;
1138 /* Use the minimum of the wanted bytes and the available bytes. */
1139 xCount = configMIN( xBytesAvailable, xMaxCount );
1141 if( xCount > ( size_t ) 0 )
1143 xNextTail = pxStreamBuffer->xTail;
1145 /* Calculate the number of bytes that can be read - which may be
1146 less than the number wanted if the data wraps around to the start of
1148 xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount );
1150 /* Obtain the number of bytes it is possible to obtain in the first
1151 read. Asserts check bounds of read and write. */
1152 configASSERT( xFirstLength <= xMaxCount );
1153 configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength );
1154 ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1156 /* If the total number of wanted bytes is greater than the number
1157 that could be read in the first read... */
1158 if( xCount > xFirstLength )
1160 /*...then read the remaining bytes from the start of the buffer. */
1161 configASSERT( xCount <= xMaxCount );
1162 ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1166 mtCOVERAGE_TEST_MARKER();
1169 /* Move the tail pointer to effectively remove the data read from
1171 xNextTail += xCount;
1173 if( xNextTail >= pxStreamBuffer->xLength )
1175 xNextTail -= pxStreamBuffer->xLength;
1178 pxStreamBuffer->xTail = xNextTail;
1182 mtCOVERAGE_TEST_MARKER();
1187 /*-----------------------------------------------------------*/
1189 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )
1191 /* Returns the distance between xTail and xHead. */
1194 xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
1195 xCount -= pxStreamBuffer->xTail;
1196 if ( xCount >= pxStreamBuffer->xLength )
1198 xCount -= pxStreamBuffer->xLength;
1202 mtCOVERAGE_TEST_MARKER();
1207 /*-----------------------------------------------------------*/
1209 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
1210 uint8_t * const pucBuffer,
1211 size_t xBufferSizeBytes,
1212 size_t xTriggerLevelBytes,
1215 /* Assert here is deliberately writing to the entire buffer to ensure it can
1216 be written to without generating exceptions, and is setting the buffer to a
1217 known value to assist in development/debugging. */
1218 #if( configASSERT_DEFINED == 1 )
1220 /* The value written just has to be identifiable when looking at the
1221 memory. Don't use 0xA5 as that is the stack fill value and could
1222 result in confusion as to what is actually being observed. */
1223 const BaseType_t xWriteValue = 0x55;
1224 configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );
1225 } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */
1228 ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */
1229 pxStreamBuffer->pucBuffer = pucBuffer;
1230 pxStreamBuffer->xLength = xBufferSizeBytes;
1231 pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
1232 pxStreamBuffer->ucFlags = ucFlags;
1235 #if ( configUSE_TRACE_FACILITY == 1 )
1237 UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )
1239 return xStreamBuffer->uxStreamBufferNumber;
1242 #endif /* configUSE_TRACE_FACILITY */
1243 /*-----------------------------------------------------------*/
1245 #if ( configUSE_TRACE_FACILITY == 1 )
1247 void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber )
1249 xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
1252 #endif /* configUSE_TRACE_FACILITY */
1253 /*-----------------------------------------------------------*/
1255 #if ( configUSE_TRACE_FACILITY == 1 )
1257 uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )
1259 return ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER );
1262 #endif /* configUSE_TRACE_FACILITY */
1263 /*-----------------------------------------------------------*/