2 * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
29 /* Standard includes. */
33 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
34 * all the API functions to use the MPU wrappers. That should only be done when
35 * task.h is included from an application file. */
36 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
38 /* FreeRTOS includes. */
41 #include "stream_buffer.h"
43 #if ( configUSE_TASK_NOTIFICATIONS != 1 )
44 #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c
47 /* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified
48 * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
49 * for the header files above, but not in this file, in order to generate the
50 * correct privileged Vs unprivileged linkage and placement. */
51 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
53 /* If the user has not provided application specific Rx notification macros,
54 * or #defined the notification macros away, then provide default implementations
55 * that uses task notifications. */
56 /*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */
57 #ifndef sbRECEIVE_COMPLETED
58 #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \
61 if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
63 ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \
66 ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
69 ( void ) xTaskResumeAll();
70 #endif /* sbRECEIVE_COMPLETED */
72 /* If user has provided a per-instance receive complete callback, then
73 * invoke the callback else use the receive complete macro which is provided by default for all instances.
75 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
76 #define prvRECEIVE_COMPLETED( pxStreamBuffer ) \
78 if( pxStreamBuffer->pxReceiveCompletedCallback != NULL ) \
80 pxStreamBuffer->pxReceiveCompletedCallback( pxStreamBuffer, pdFALSE, NULL ); \
84 sbRECEIVE_COMPLETED( pxStreamBuffer ); \
87 #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
88 #define prvRECEIVE_COMPLETED( pxStreamBuffer ) sbRECEIVE_COMPLETED( pxStreamBuffer )
89 #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
91 #ifndef sbRECEIVE_COMPLETED_FROM_ISR
92 #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \
93 pxHigherPriorityTaskWoken ) \
95 UBaseType_t uxSavedInterruptStatus; \
97 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
99 if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \
101 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \
104 pxHigherPriorityTaskWoken ); \
105 ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \
108 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
110 #endif /* sbRECEIVE_COMPLETED_FROM_ISR */
112 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
113 #define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \
114 pxHigherPriorityTaskWoken ) \
116 if( pxStreamBuffer->pxReceiveCompletedCallback != NULL ) \
118 pxStreamBuffer->pxReceiveCompletedCallback( pxStreamBuffer, pdTRUE, pxHigherPriorityTaskWoken ); \
122 sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); \
125 #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
126 #define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
127 sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )
128 #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
130 /* If the user has not provided an application specific Tx notification macro,
131 * or #defined the notification macro away, then provide a default
132 * implementation that uses task notifications.
134 #ifndef sbSEND_COMPLETED
135 #define sbSEND_COMPLETED( pxStreamBuffer ) \
138 if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
140 ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \
143 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
146 ( void ) xTaskResumeAll();
147 #endif /* sbSEND_COMPLETED */
149 /* If user has provided a per-instance send completed callback, then
150 * invoke the callback else use the send complete macro which is provided by default for all instances.
152 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
153 #define prvSEND_COMPLETED( pxStreamBuffer ) \
155 if( pxStreamBuffer->pxSendCompletedCallback != NULL ) \
157 pxStreamBuffer->pxSendCompletedCallback( pxStreamBuffer, pdFALSE, NULL ); \
161 sbSEND_COMPLETED( pxStreamBuffer ); \
164 #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
165 #define prvSEND_COMPLETED( pxStreamBuffer ) sbSEND_COMPLETED( pxStreamBuffer )
166 #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
169 #ifndef sbSEND_COMPLETE_FROM_ISR
170 #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
172 UBaseType_t uxSavedInterruptStatus; \
174 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
176 if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \
178 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \
181 pxHigherPriorityTaskWoken ); \
182 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \
185 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
187 #endif /* sbSEND_COMPLETE_FROM_ISR */
190 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
191 #define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
193 if( pxStreamBuffer->pxSendCompletedCallback != NULL ) \
195 pxStreamBuffer->pxSendCompletedCallback( pxStreamBuffer, pdTRUE, pxHigherPriorityTaskWoken ); \
199 sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); \
202 #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
203 #define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
204 sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )
205 #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
207 /*lint -restore (9026) */
209 /* The number of bytes used to hold the length of a message in the buffer. */
210 #define sbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
212 /* Bits stored in the ucFlags field of the stream buffer. */
213 #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. */
214 #define sbFLAGS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */
216 /*-----------------------------------------------------------*/
218 /* Structure that hold state information on the buffer. */
219 typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
221 volatile size_t xTail; /* Index to the next item to read within the buffer. */
222 volatile size_t xHead; /* Index to the next item to write within the buffer. */
223 size_t xLength; /* The length of the buffer pointed to by pucBuffer. */
224 size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
225 volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
226 volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */
227 uint8_t * pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
230 #if ( configUSE_TRACE_FACILITY == 1 )
231 UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
234 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
235 StreamBufferCallbackFunction_t pxSendCompletedCallback; /* Optional callback called on send complete. sbSEND_COMPLETED is called if this is NULL. */
236 StreamBufferCallbackFunction_t pxReceiveCompletedCallback; /* Optional callback called on receive complete. sbRECEIVE_COMPLETED is called if this is NULL. */
241 * The number of bytes available to be read from the buffer.
243 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION;
246 * Add xCount bytes from pucData into the pxStreamBuffer's data storage area.
247 * This function does not update the buffer's xHead pointer, so multiple writes
248 * may be chained together "atomically". This is useful for Message Buffers where
249 * the length and data bytes are written in two separate chunks, and we don't want
250 * the reader to see the buffer as having grown until after all data is copied over.
251 * This function takes a custom xHead value to indicate where to write to (necessary
252 * for chaining) and returns the the resulting xHead position.
253 * To mark the write as complete, manually set the buffer's xHead field with the
254 * returned xHead from this function.
256 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
257 const uint8_t * pucData,
259 size_t xHead ) PRIVILEGED_FUNCTION;
262 * If the stream buffer is being used as a message buffer, then reads an entire
263 * message out of the buffer. If the stream buffer is being used as a stream
264 * buffer then read as many bytes as possible from the buffer.
265 * prvReadBytesFromBuffer() is called to actually extract the bytes from the
266 * buffer's data storage area.
268 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
270 size_t xBufferLengthBytes,
271 size_t xBytesAvailable ) PRIVILEGED_FUNCTION;
274 * If the stream buffer is being used as a message buffer, then writes an entire
275 * message to the buffer. If the stream buffer is being used as a stream
276 * buffer then write as many bytes as possible to the buffer.
277 * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's
280 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
281 const void * pvTxData,
282 size_t xDataLengthBytes,
284 size_t xRequiredSpace ) PRIVILEGED_FUNCTION;
287 * Copies xCount bytes from the pxStreamBuffer's data storage area to pucData.
288 * This function does not update the buffer's xTail pointer, so multiple reads
289 * may be chained together "atomically". This is useful for Message Buffers where
290 * the length and data bytes are read in two separate chunks, and we don't want
291 * the writer to see the buffer as having more free space until after all data is
292 * copied over, especially if we have to abort the read due to insufficient receiving space.
293 * This function takes a custom xTail value to indicate where to read from (necessary
294 * for chaining) and returns the the resulting xTail position.
295 * To mark the read as complete, manually set the buffer's xTail field with the
296 * returned xTail from this function.
298 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
301 size_t xTail ) PRIVILEGED_FUNCTION;
304 * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to
305 * initialise the members of the newly created stream buffer structure.
307 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
308 uint8_t * const pucBuffer,
309 size_t xBufferSizeBytes,
310 size_t xTriggerLevelBytes,
312 StreamBufferCallbackFunction_t pxSendCompletedCallback,
313 StreamBufferCallbackFunction_t pxReceiveCompletedCallback ) PRIVILEGED_FUNCTION;
315 /*-----------------------------------------------------------*/
316 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
317 StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
318 size_t xTriggerLevelBytes,
319 BaseType_t xIsMessageBuffer,
320 StreamBufferCallbackFunction_t pxSendCompletedCallback,
321 StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
323 uint8_t * pucAllocatedMemory;
326 /* In case the stream buffer is going to be used as a message buffer
327 * (that is, it will hold discrete messages with a little meta data that
328 * says how big the next message is) check the buffer will be large enough
329 * to hold at least one message. */
330 if( xIsMessageBuffer == pdTRUE )
332 /* Is a message buffer but not statically allocated. */
333 ucFlags = sbFLAGS_IS_MESSAGE_BUFFER;
334 configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
338 /* Not a message buffer and not statically allocated. */
340 configASSERT( xBufferSizeBytes > 0 );
343 configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
345 /* A trigger level of 0 would cause a waiting task to unblock even when
346 * the buffer was empty. */
347 if( xTriggerLevelBytes == ( size_t ) 0 )
349 xTriggerLevelBytes = ( size_t ) 1;
352 /* A stream buffer requires a StreamBuffer_t structure and a buffer.
353 * Both are allocated in a single call to pvPortMalloc(). The
354 * StreamBuffer_t structure is placed at the start of the allocated memory
355 * and the buffer follows immediately after. The requested size is
356 * incremented so the free space is returned as the user would expect -
357 * this is a quirk of the implementation that means otherwise the free
358 * space would be reported as one byte smaller than would be logically
360 if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) )
363 pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */
367 pucAllocatedMemory = NULL;
370 if( pucAllocatedMemory != NULL )
372 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. */
373 pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */
377 pxSendCompletedCallback,
378 pxReceiveCompletedCallback );
380 traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );
384 traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );
387 return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */
389 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
390 /*-----------------------------------------------------------*/
392 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
394 StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
395 size_t xTriggerLevelBytes,
396 BaseType_t xIsMessageBuffer,
397 uint8_t * const pucStreamBufferStorageArea,
398 StaticStreamBuffer_t * const pxStaticStreamBuffer,
399 StreamBufferCallbackFunction_t pxSendCompletedCallback,
400 StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
402 StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */
403 StreamBufferHandle_t xReturn;
406 configASSERT( pucStreamBufferStorageArea );
407 configASSERT( pxStaticStreamBuffer );
408 configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
410 /* A trigger level of 0 would cause a waiting task to unblock even when
411 * the buffer was empty. */
412 if( xTriggerLevelBytes == ( size_t ) 0 )
414 xTriggerLevelBytes = ( size_t ) 1;
417 if( xIsMessageBuffer != pdFALSE )
419 /* Statically allocated message buffer. */
420 ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;
424 /* Statically allocated stream buffer. */
425 ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;
428 /* In case the stream buffer is going to be used as a message buffer
429 * (that is, it will hold discrete messages with a little meta data that
430 * says how big the next message is) check the buffer will be large enough
431 * to hold at least one message. */
432 configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
434 #if ( configASSERT_DEFINED == 1 )
436 /* Sanity check that the size of the structure used to declare a
437 * variable of type StaticStreamBuffer_t equals the size of the real
438 * message buffer structure. */
439 volatile size_t xSize = sizeof( StaticStreamBuffer_t );
440 configASSERT( xSize == sizeof( StreamBuffer_t ) );
441 } /*lint !e529 xSize is referenced is configASSERT() is defined. */
442 #endif /* configASSERT_DEFINED */
444 if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )
446 prvInitialiseNewStreamBuffer( pxStreamBuffer,
447 pucStreamBufferStorageArea,
451 pxSendCompletedCallback,
452 pxReceiveCompletedCallback );
454 /* Remember this was statically allocated in case it is ever deleted
456 pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;
458 traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );
460 xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */
465 traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );
470 #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
471 /*-----------------------------------------------------------*/
473 void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )
475 StreamBuffer_t * pxStreamBuffer = xStreamBuffer;
477 configASSERT( pxStreamBuffer );
479 traceSTREAM_BUFFER_DELETE( xStreamBuffer );
481 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )
483 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
485 /* Both the structure and the buffer were allocated using a single call
486 * to pvPortMalloc(), hence only one call to vPortFree() is required. */
487 vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */
491 /* Should not be possible to get here, ucFlags must be corrupt.
492 * Force an assert. */
493 configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );
499 /* The structure and buffer were not allocated dynamically and cannot be
500 * freed - just scrub the structure so future use will assert. */
501 ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
504 /*-----------------------------------------------------------*/
506 BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
508 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
509 BaseType_t xReturn = pdFAIL;
510 StreamBufferCallbackFunction_t pxSendCallback = NULL, pxReceiveCallback = NULL;
512 #if ( configUSE_TRACE_FACILITY == 1 )
513 UBaseType_t uxStreamBufferNumber;
516 configASSERT( pxStreamBuffer );
518 #if ( configUSE_TRACE_FACILITY == 1 )
520 /* Store the stream buffer number so it can be restored after the
522 uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
526 /* Can only reset a message buffer if there are no tasks blocked on it. */
527 taskENTER_CRITICAL();
529 if( ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) )
531 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
533 pxSendCallback = pxStreamBuffer->pxSendCompletedCallback;
534 pxReceiveCallback = pxStreamBuffer->pxReceiveCompletedCallback;
538 prvInitialiseNewStreamBuffer( pxStreamBuffer,
539 pxStreamBuffer->pucBuffer,
540 pxStreamBuffer->xLength,
541 pxStreamBuffer->xTriggerLevelBytes,
542 pxStreamBuffer->ucFlags,
546 #if ( configUSE_TRACE_FACILITY == 1 )
548 pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
552 traceSTREAM_BUFFER_RESET( xStreamBuffer );
561 /*-----------------------------------------------------------*/
563 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,
564 size_t xTriggerLevel )
566 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
569 configASSERT( pxStreamBuffer );
571 /* It is not valid for the trigger level to be 0. */
572 if( xTriggerLevel == ( size_t ) 0 )
574 xTriggerLevel = ( size_t ) 1;
577 /* The trigger level is the number of bytes that must be in the stream
578 * buffer before a task that is waiting for data is unblocked. */
579 if( xTriggerLevel < pxStreamBuffer->xLength )
581 pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
591 /*-----------------------------------------------------------*/
593 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )
595 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
597 size_t xOriginalTail;
599 configASSERT( pxStreamBuffer );
601 /* The code below reads xTail and then xHead. This is safe if the stream
602 * buffer is updated once between the two reads - but not if the stream buffer
603 * is updated more than once between the two reads - hence the loop. */
606 xOriginalTail = pxStreamBuffer->xTail;
607 xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;
608 xSpace -= pxStreamBuffer->xHead;
609 } while( xOriginalTail != pxStreamBuffer->xTail );
611 xSpace -= ( size_t ) 1;
613 if( xSpace >= pxStreamBuffer->xLength )
615 xSpace -= pxStreamBuffer->xLength;
619 mtCOVERAGE_TEST_MARKER();
624 /*-----------------------------------------------------------*/
626 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )
628 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
631 configASSERT( pxStreamBuffer );
633 xReturn = prvBytesInBuffer( pxStreamBuffer );
636 /*-----------------------------------------------------------*/
638 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
639 const void * pvTxData,
640 size_t xDataLengthBytes,
641 TickType_t xTicksToWait )
643 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
644 size_t xReturn, xSpace = 0;
645 size_t xRequiredSpace = xDataLengthBytes;
647 size_t xMaxReportedSpace = 0;
649 configASSERT( pvTxData );
650 configASSERT( pxStreamBuffer );
652 /* The maximum amount of space a stream buffer will ever report is its length
654 xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;
656 /* This send function is used to write to both message buffers and stream
657 * buffers. If this is a message buffer then the space needed must be
658 * increased by the amount of bytes needed to store the length of the
660 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
662 xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
665 configASSERT( xRequiredSpace > xDataLengthBytes );
667 /* If this is a message buffer then it must be possible to write the
669 if( xRequiredSpace > xMaxReportedSpace )
671 /* The message would not fit even if the entire buffer was empty,
672 * so don't wait for space. */
673 xTicksToWait = ( TickType_t ) 0;
677 mtCOVERAGE_TEST_MARKER();
682 /* If this is a stream buffer then it is acceptable to write only part
683 * of the message to the buffer. Cap the length to the total length of
685 if( xRequiredSpace > xMaxReportedSpace )
687 xRequiredSpace = xMaxReportedSpace;
691 mtCOVERAGE_TEST_MARKER();
695 if( xTicksToWait != ( TickType_t ) 0 )
697 vTaskSetTimeOutState( &xTimeOut );
701 /* Wait until the required number of bytes are free in the message
703 taskENTER_CRITICAL();
705 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
707 if( xSpace < xRequiredSpace )
709 /* Clear notification state as going to wait for space. */
710 ( void ) xTaskNotifyStateClear( NULL );
712 /* Should only be one writer. */
713 configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
714 pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();
724 traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
725 ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
726 pxStreamBuffer->xTaskWaitingToSend = NULL;
727 } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
731 mtCOVERAGE_TEST_MARKER();
734 if( xSpace == ( size_t ) 0 )
736 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
740 mtCOVERAGE_TEST_MARKER();
743 xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
745 if( xReturn > ( size_t ) 0 )
747 traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );
749 /* Was a task waiting for the data? */
750 if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
752 prvSEND_COMPLETED( pxStreamBuffer );
756 mtCOVERAGE_TEST_MARKER();
761 mtCOVERAGE_TEST_MARKER();
762 traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );
767 /*-----------------------------------------------------------*/
769 size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
770 const void * pvTxData,
771 size_t xDataLengthBytes,
772 BaseType_t * const pxHigherPriorityTaskWoken )
774 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
775 size_t xReturn, xSpace;
776 size_t xRequiredSpace = xDataLengthBytes;
778 configASSERT( pvTxData );
779 configASSERT( pxStreamBuffer );
781 /* This send function is used to write to both message buffers and stream
782 * buffers. If this is a message buffer then the space needed must be
783 * increased by the amount of bytes needed to store the length of the
785 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
787 xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
791 mtCOVERAGE_TEST_MARKER();
794 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
795 xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
797 if( xReturn > ( size_t ) 0 )
799 /* Was a task waiting for the data? */
800 if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
802 prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
806 mtCOVERAGE_TEST_MARKER();
811 mtCOVERAGE_TEST_MARKER();
814 traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );
818 /*-----------------------------------------------------------*/
820 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
821 const void * pvTxData,
822 size_t xDataLengthBytes,
824 size_t xRequiredSpace )
826 size_t xNextHead = pxStreamBuffer->xHead;
827 configMESSAGE_BUFFER_LENGTH_TYPE xMessageLength;
829 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
831 /* This is a message buffer, as opposed to a stream buffer. */
833 /* Convert xDataLengthBytes to the message length type. */
834 xMessageLength = ( configMESSAGE_BUFFER_LENGTH_TYPE ) xDataLengthBytes;
836 /* Ensure the data length given fits within configMESSAGE_BUFFER_LENGTH_TYPE. */
837 configASSERT( ( size_t ) xMessageLength == xDataLengthBytes );
839 if( xSpace >= xRequiredSpace )
841 /* There is enough space to write both the message length and the message
842 * itself into the buffer. Start by writing the length of the data, the data
843 * itself will be written later in this function. */
844 xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xMessageLength ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead );
848 /* Not enough space, so do not write data to the buffer. */
849 xDataLengthBytes = 0;
854 /* This is a stream buffer, as opposed to a message buffer, so writing a
855 * stream of bytes rather than discrete messages. Plan to write as many
856 * bytes as possible. */
857 xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );
860 if( xDataLengthBytes != ( size_t ) 0 )
862 /* Write the data to the buffer. */
863 pxStreamBuffer->xHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes, xNextHead ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alignment and access. */
866 return xDataLengthBytes;
868 /*-----------------------------------------------------------*/
870 size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
872 size_t xBufferLengthBytes,
873 TickType_t xTicksToWait )
875 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
876 size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
878 configASSERT( pvRxData );
879 configASSERT( pxStreamBuffer );
881 /* This receive function is used by both message buffers, which store
882 * discrete messages, and stream buffers, which store a continuous stream of
883 * bytes. Discrete messages include an additional
884 * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
886 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
888 xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
892 xBytesToStoreMessageLength = 0;
895 if( xTicksToWait != ( TickType_t ) 0 )
897 /* Checking if there is data and clearing the notification state must be
898 * performed atomically. */
899 taskENTER_CRITICAL();
901 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
903 /* If this function was invoked by a message buffer read then
904 * xBytesToStoreMessageLength holds the number of bytes used to hold
905 * the length of the next discrete message. If this function was
906 * invoked by a stream buffer read then xBytesToStoreMessageLength will
908 if( xBytesAvailable <= xBytesToStoreMessageLength )
910 /* Clear notification state as going to wait for data. */
911 ( void ) xTaskNotifyStateClear( NULL );
913 /* Should only be one reader. */
914 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
915 pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();
919 mtCOVERAGE_TEST_MARKER();
924 if( xBytesAvailable <= xBytesToStoreMessageLength )
926 /* Wait for data to be available. */
927 traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );
928 ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
929 pxStreamBuffer->xTaskWaitingToReceive = NULL;
931 /* Recheck the data available after blocking. */
932 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
936 mtCOVERAGE_TEST_MARKER();
941 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
944 /* Whether receiving a discrete message (where xBytesToStoreMessageLength
945 * holds the number of bytes used to store the message length) or a stream of
946 * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
947 * available must be greater than xBytesToStoreMessageLength to be able to
948 * read bytes from the buffer. */
949 if( xBytesAvailable > xBytesToStoreMessageLength )
951 xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
953 /* Was a task waiting for space in the buffer? */
954 if( xReceivedLength != ( size_t ) 0 )
956 traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );
957 prvRECEIVE_COMPLETED( xStreamBuffer );
961 mtCOVERAGE_TEST_MARKER();
966 traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );
967 mtCOVERAGE_TEST_MARKER();
970 return xReceivedLength;
972 /*-----------------------------------------------------------*/
974 size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )
976 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
977 size_t xReturn, xBytesAvailable;
978 configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
980 configASSERT( pxStreamBuffer );
982 /* Ensure the stream buffer is being used as a message buffer. */
983 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
985 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
987 if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
989 /* The number of bytes available is greater than the number of bytes
990 * required to hold the length of the next message, so another message
992 ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, pxStreamBuffer->xTail );
993 xReturn = ( size_t ) xTempReturn;
997 /* The minimum amount of bytes in a message buffer is
998 * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is
999 * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
1001 configASSERT( xBytesAvailable == 0 );
1012 /*-----------------------------------------------------------*/
1014 size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
1016 size_t xBufferLengthBytes,
1017 BaseType_t * const pxHigherPriorityTaskWoken )
1019 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1020 size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
1022 configASSERT( pvRxData );
1023 configASSERT( pxStreamBuffer );
1025 /* This receive function is used by both message buffers, which store
1026 * discrete messages, and stream buffers, which store a continuous stream of
1027 * bytes. Discrete messages include an additional
1028 * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
1030 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1032 xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1036 xBytesToStoreMessageLength = 0;
1039 xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1041 /* Whether receiving a discrete message (where xBytesToStoreMessageLength
1042 * holds the number of bytes used to store the message length) or a stream of
1043 * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
1044 * available must be greater than xBytesToStoreMessageLength to be able to
1045 * read bytes from the buffer. */
1046 if( xBytesAvailable > xBytesToStoreMessageLength )
1048 xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
1050 /* Was a task waiting for space in the buffer? */
1051 if( xReceivedLength != ( size_t ) 0 )
1053 prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
1057 mtCOVERAGE_TEST_MARKER();
1062 mtCOVERAGE_TEST_MARKER();
1065 traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );
1067 return xReceivedLength;
1069 /*-----------------------------------------------------------*/
1071 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
1073 size_t xBufferLengthBytes,
1074 size_t xBytesAvailable )
1076 size_t xCount, xNextMessageLength;
1077 configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
1078 size_t xNextTail = pxStreamBuffer->xTail;
1080 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1082 /* A discrete message is being received. First receive the length
1083 * of the message. */
1084 xNextTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextTail );
1085 xNextMessageLength = ( size_t ) xTempNextMessageLength;
1087 /* Reduce the number of bytes available by the number of bytes just
1089 xBytesAvailable -= sbBYTES_TO_STORE_MESSAGE_LENGTH;
1091 /* Check there is enough space in the buffer provided by the
1093 if( xNextMessageLength > xBufferLengthBytes )
1095 /* The user has provided insufficient space to read the message. */
1096 xNextMessageLength = 0;
1100 mtCOVERAGE_TEST_MARKER();
1105 /* A stream of bytes is being received (as opposed to a discrete
1106 * message), so read as many bytes as possible. */
1107 xNextMessageLength = xBufferLengthBytes;
1110 /* Use the minimum of the wanted bytes and the available bytes. */
1111 xCount = configMIN( xNextMessageLength, xBytesAvailable );
1113 if( xCount != ( size_t ) 0 )
1115 /* Read the actual data and update the tail to mark the data as officially consumed. */
1116 pxStreamBuffer->xTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xCount, xNextTail ); /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */
1121 /*-----------------------------------------------------------*/
1123 BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )
1125 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1129 configASSERT( pxStreamBuffer );
1131 /* True if no bytes are available. */
1132 xTail = pxStreamBuffer->xTail;
1134 if( pxStreamBuffer->xHead == xTail )
1145 /*-----------------------------------------------------------*/
1147 BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )
1150 size_t xBytesToStoreMessageLength;
1151 const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1153 configASSERT( pxStreamBuffer );
1155 /* This generic version of the receive function is used by both message
1156 * buffers, which store discrete messages, and stream buffers, which store a
1157 * continuous stream of bytes. Discrete messages include an additional
1158 * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */
1159 if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1161 xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1165 xBytesToStoreMessageLength = 0;
1168 /* True if the available space equals zero. */
1169 if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )
1180 /*-----------------------------------------------------------*/
1182 BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1183 BaseType_t * pxHigherPriorityTaskWoken )
1185 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1187 UBaseType_t uxSavedInterruptStatus;
1189 configASSERT( pxStreamBuffer );
1191 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
1193 if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
1195 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
1198 pxHigherPriorityTaskWoken );
1199 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
1207 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1211 /*-----------------------------------------------------------*/
1213 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1214 BaseType_t * pxHigherPriorityTaskWoken )
1216 StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1218 UBaseType_t uxSavedInterruptStatus;
1220 configASSERT( pxStreamBuffer );
1222 uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
1224 if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
1226 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
1229 pxHigherPriorityTaskWoken );
1230 ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
1238 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1242 /*-----------------------------------------------------------*/
1244 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
1245 const uint8_t * pucData,
1249 size_t xFirstLength;
1251 configASSERT( xCount > ( size_t ) 0 );
1253 /* Calculate the number of bytes that can be added in the first write -
1254 * which may be less than the total number of bytes that need to be added if
1255 * the buffer will wrap back to the beginning. */
1256 xFirstLength = configMIN( pxStreamBuffer->xLength - xHead, xCount );
1258 /* Write as many bytes as can be written in the first write. */
1259 configASSERT( ( xHead + xFirstLength ) <= pxStreamBuffer->xLength );
1260 ( void ) memcpy( ( void * ) ( &( pxStreamBuffer->pucBuffer[ xHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1262 /* If the number of bytes written was less than the number that could be
1263 * written in the first write... */
1264 if( xCount > xFirstLength )
1266 /* ...then write the remaining bytes to the start of the buffer. */
1267 configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength );
1268 ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1272 mtCOVERAGE_TEST_MARKER();
1277 if( xHead >= pxStreamBuffer->xLength )
1279 xHead -= pxStreamBuffer->xLength;
1283 mtCOVERAGE_TEST_MARKER();
1288 /*-----------------------------------------------------------*/
1290 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
1295 size_t xFirstLength;
1297 configASSERT( xCount != ( size_t ) 0 );
1299 /* Calculate the number of bytes that can be read - which may be
1300 * less than the number wanted if the data wraps around to the start of
1302 xFirstLength = configMIN( pxStreamBuffer->xLength - xTail, xCount );
1304 /* Obtain the number of bytes it is possible to obtain in the first
1305 * read. Asserts check bounds of read and write. */
1306 configASSERT( xFirstLength <= xCount );
1307 configASSERT( ( xTail + xFirstLength ) <= pxStreamBuffer->xLength );
1308 ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1310 /* If the total number of wanted bytes is greater than the number
1311 * that could be read in the first read... */
1312 if( xCount > xFirstLength )
1314 /* ...then read the remaining bytes from the start of the buffer. */
1315 ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */
1319 mtCOVERAGE_TEST_MARKER();
1322 /* Move the tail pointer to effectively remove the data read from the buffer. */
1325 if( xTail >= pxStreamBuffer->xLength )
1327 xTail -= pxStreamBuffer->xLength;
1332 /*-----------------------------------------------------------*/
1334 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )
1336 /* Returns the distance between xTail and xHead. */
1339 xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
1340 xCount -= pxStreamBuffer->xTail;
1342 if( xCount >= pxStreamBuffer->xLength )
1344 xCount -= pxStreamBuffer->xLength;
1348 mtCOVERAGE_TEST_MARKER();
1353 /*-----------------------------------------------------------*/
1355 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
1356 uint8_t * const pucBuffer,
1357 size_t xBufferSizeBytes,
1358 size_t xTriggerLevelBytes,
1360 StreamBufferCallbackFunction_t pxSendCompletedCallback,
1361 StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
1363 /* Assert here is deliberately writing to the entire buffer to ensure it can
1364 * be written to without generating exceptions, and is setting the buffer to a
1365 * known value to assist in development/debugging. */
1366 #if ( configASSERT_DEFINED == 1 )
1368 /* The value written just has to be identifiable when looking at the
1369 * memory. Don't use 0xA5 as that is the stack fill value and could
1370 * result in confusion as to what is actually being observed. */
1371 const BaseType_t xWriteValue = 0x55;
1372 configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );
1373 } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */
1376 ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */
1377 pxStreamBuffer->pucBuffer = pucBuffer;
1378 pxStreamBuffer->xLength = xBufferSizeBytes;
1379 pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
1380 pxStreamBuffer->ucFlags = ucFlags;
1381 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
1383 pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback;
1384 pxStreamBuffer->pxReceiveCompletedCallback = pxReceiveCompletedCallback;
1388 ( void ) pxSendCompletedCallback;
1389 ( void ) pxReceiveCompletedCallback;
1394 #if ( configUSE_TRACE_FACILITY == 1 )
1396 UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )
1398 return xStreamBuffer->uxStreamBufferNumber;
1401 #endif /* configUSE_TRACE_FACILITY */
1402 /*-----------------------------------------------------------*/
1404 #if ( configUSE_TRACE_FACILITY == 1 )
1406 void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,
1407 UBaseType_t uxStreamBufferNumber )
1409 xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
1412 #endif /* configUSE_TRACE_FACILITY */
1413 /*-----------------------------------------------------------*/
1415 #if ( configUSE_TRACE_FACILITY == 1 )
1417 uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )
1419 return( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER );
1422 #endif /* configUSE_TRACE_FACILITY */
1423 /*-----------------------------------------------------------*/