]> begriffs open source - freertos/blob - stream_buffer.c
RP2040: Remove incorrect assertion (#508)
[freertos] / stream_buffer.c
1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
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.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29 /* Standard includes. */
30 #include <stdint.h>
31 #include <string.h>
32
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
37
38 /* FreeRTOS includes. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 #include "stream_buffer.h"
42
43 #if ( configUSE_TASK_NOTIFICATIONS != 1 )
44     #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c
45 #endif
46
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. */
52
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 )                         \
59     vTaskSuspendAll();                                                    \
60     {                                                                     \
61         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )              \
62         {                                                                 \
63             ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \
64                                   ( uint32_t ) 0,                         \
65                                   eNoAction );                            \
66             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                \
67         }                                                                 \
68     }                                                                     \
69     ( void ) xTaskResumeAll();
70 #endif /* sbRECEIVE_COMPLETED */
71
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.
74  */
75 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
76     #define prvRECEIVE_COMPLETED( pxStreamBuffer )                                       \
77     {                                                                                    \
78         if( pxStreamBuffer->pxReceiveCompletedCallback != NULL )                         \
79         {                                                                                \
80             pxStreamBuffer->pxReceiveCompletedCallback( pxStreamBuffer, pdFALSE, NULL ); \
81         }                                                                                \
82         else                                                                             \
83         {                                                                                \
84             sbRECEIVE_COMPLETED( pxStreamBuffer );                                       \
85         }                                                                                \
86     }
87 #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
88     #define prvRECEIVE_COMPLETED( pxStreamBuffer )    sbRECEIVE_COMPLETED( pxStreamBuffer )
89 #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
90
91 #ifndef sbRECEIVE_COMPLETED_FROM_ISR
92     #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                            \
93                                           pxHigherPriorityTaskWoken )                \
94     {                                                                                \
95         UBaseType_t uxSavedInterruptStatus;                                          \
96                                                                                      \
97         uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();  \
98         {                                                                            \
99             if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                     \
100             {                                                                        \
101                 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \
102                                              ( uint32_t ) 0,                         \
103                                              eNoAction,                              \
104                                              pxHigherPriorityTaskWoken );            \
105                 ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                       \
106             }                                                                        \
107         }                                                                            \
108         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                 \
109     }
110 #endif /* sbRECEIVE_COMPLETED_FROM_ISR */
111
112 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
113     #define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                                                   \
114                                            pxHigherPriorityTaskWoken )                                       \
115     {                                                                                                        \
116         if( pxStreamBuffer->pxReceiveCompletedCallback != NULL )                                             \
117         {                                                                                                    \
118             pxStreamBuffer->pxReceiveCompletedCallback( pxStreamBuffer, pdTRUE, pxHigherPriorityTaskWoken ); \
119         }                                                                                                    \
120         else                                                                                                 \
121         {                                                                                                    \
122             sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );                       \
123         }                                                                                                    \
124     }
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 ) */
129
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.
133  */
134 #ifndef sbSEND_COMPLETED
135     #define sbSEND_COMPLETED( pxStreamBuffer )                               \
136     vTaskSuspendAll();                                                       \
137     {                                                                        \
138         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )              \
139         {                                                                    \
140             ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \
141                                   ( uint32_t ) 0,                            \
142                                   eNoAction );                               \
143             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                \
144         }                                                                    \
145     }                                                                        \
146     ( void ) xTaskResumeAll();
147 #endif /* sbSEND_COMPLETED */
148
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.
151  */
152 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
153     #define prvSEND_COMPLETED( pxStreamBuffer )                                       \
154     {                                                                                 \
155         if( pxStreamBuffer->pxSendCompletedCallback != NULL )                         \
156         {                                                                             \
157             pxStreamBuffer->pxSendCompletedCallback( pxStreamBuffer, pdFALSE, NULL ); \
158         }                                                                             \
159         else                                                                          \
160         {                                                                             \
161             sbSEND_COMPLETED( pxStreamBuffer );                                       \
162         }                                                                             \
163     }
164 #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
165     #define prvSEND_COMPLETED( pxStreamBuffer )    sbSEND_COMPLETED( pxStreamBuffer )
166 #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
167
168
169 #ifndef sbSEND_COMPLETE_FROM_ISR
170     #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )       \
171     {                                                                                   \
172         UBaseType_t uxSavedInterruptStatus;                                             \
173                                                                                         \
174         uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();     \
175         {                                                                               \
176             if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                     \
177             {                                                                           \
178                 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \
179                                              ( uint32_t ) 0,                            \
180                                              eNoAction,                                 \
181                                              pxHigherPriorityTaskWoken );               \
182                 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                       \
183             }                                                                           \
184         }                                                                               \
185         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                    \
186     }
187 #endif /* sbSEND_COMPLETE_FROM_ISR */
188
189
190 #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
191     #define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )                        \
192     {                                                                                                     \
193         if( pxStreamBuffer->pxSendCompletedCallback != NULL )                                             \
194         {                                                                                                 \
195             pxStreamBuffer->pxSendCompletedCallback( pxStreamBuffer, pdTRUE, pxHigherPriorityTaskWoken ); \
196         }                                                                                                 \
197         else                                                                                              \
198         {                                                                                                 \
199             sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );                        \
200         }                                                                                                 \
201     }
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 ) */
206
207 /*lint -restore (9026) */
208
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 ) )
211
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. */
215
216 /*-----------------------------------------------------------*/
217
218 /* Structure that hold state information on the buffer. */
219 typedef struct StreamBufferDef_t                 /*lint !e9058 Style convention uses tag. */
220 {
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. */
228     uint8_t ucFlags;
229
230     #if ( configUSE_TRACE_FACILITY == 1 )
231         UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
232     #endif
233
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. */
237     #endif
238 } StreamBuffer_t;
239
240 /*
241  * The number of bytes available to be read from the buffer.
242  */
243 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION;
244
245 /*
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.
255  */
256 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
257                                      const uint8_t * pucData,
258                                      size_t xCount,
259                                      size_t xHead ) PRIVILEGED_FUNCTION;
260
261 /*
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.
267  */
268 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
269                                         void * pvRxData,
270                                         size_t xBufferLengthBytes,
271                                         size_t xBytesAvailable ) PRIVILEGED_FUNCTION;
272
273 /*
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
278  * data storage area.
279  */
280 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
281                                        const void * pvTxData,
282                                        size_t xDataLengthBytes,
283                                        size_t xSpace,
284                                        size_t xRequiredSpace ) PRIVILEGED_FUNCTION;
285
286 /*
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.
297  */
298 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
299                                       uint8_t * pucData,
300                                       size_t xCount,
301                                       size_t xTail ) PRIVILEGED_FUNCTION;
302
303 /*
304  * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to
305  * initialise the members of the newly created stream buffer structure.
306  */
307 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
308                                           uint8_t * const pucBuffer,
309                                           size_t xBufferSizeBytes,
310                                           size_t xTriggerLevelBytes,
311                                           uint8_t ucFlags,
312                                           StreamBufferCallbackFunction_t pxSendCompletedCallback,
313                                           StreamBufferCallbackFunction_t pxReceiveCompletedCallback ) PRIVILEGED_FUNCTION;
314
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 )
322     {
323         uint8_t * pucAllocatedMemory;
324         uint8_t ucFlags;
325
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 )
331         {
332             /* Is a message buffer but not statically allocated. */
333             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER;
334             configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
335         }
336         else
337         {
338             /* Not a message buffer and not statically allocated. */
339             ucFlags = 0;
340             configASSERT( xBufferSizeBytes > 0 );
341         }
342
343         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
344
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 )
348         {
349             xTriggerLevelBytes = ( size_t ) 1;
350         }
351
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
359          * expected. */
360         if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) )
361         {
362             xBufferSizeBytes++;
363             pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */
364         }
365         else
366         {
367             pucAllocatedMemory = NULL;
368         }
369
370         if( pucAllocatedMemory != NULL )
371         {
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. */
374                                           xBufferSizeBytes,
375                                           xTriggerLevelBytes,
376                                           ucFlags,
377                                           pxSendCompletedCallback,
378                                           pxReceiveCompletedCallback );
379
380             traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );
381         }
382         else
383         {
384             traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );
385         }
386
387         return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */
388     }
389 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
390 /*-----------------------------------------------------------*/
391
392 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
393
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 )
401     {
402         StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */
403         StreamBufferHandle_t xReturn;
404         uint8_t ucFlags;
405
406         configASSERT( pucStreamBufferStorageArea );
407         configASSERT( pxStaticStreamBuffer );
408         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
409
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 )
413         {
414             xTriggerLevelBytes = ( size_t ) 1;
415         }
416
417         if( xIsMessageBuffer != pdFALSE )
418         {
419             /* Statically allocated message buffer. */
420             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;
421         }
422         else
423         {
424             /* Statically allocated stream buffer. */
425             ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;
426         }
427
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 );
433
434         #if ( configASSERT_DEFINED == 1 )
435         {
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 */
443
444         if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )
445         {
446             prvInitialiseNewStreamBuffer( pxStreamBuffer,
447                                           pucStreamBufferStorageArea,
448                                           xBufferSizeBytes,
449                                           xTriggerLevelBytes,
450                                           ucFlags,
451                                           pxSendCompletedCallback,
452                                           pxReceiveCompletedCallback );
453
454             /* Remember this was statically allocated in case it is ever deleted
455              * again. */
456             pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;
457
458             traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );
459
460             xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */
461         }
462         else
463         {
464             xReturn = NULL;
465             traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );
466         }
467
468         return xReturn;
469     }
470 #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
471 /*-----------------------------------------------------------*/
472
473 void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )
474 {
475     StreamBuffer_t * pxStreamBuffer = xStreamBuffer;
476
477     configASSERT( pxStreamBuffer );
478
479     traceSTREAM_BUFFER_DELETE( xStreamBuffer );
480
481     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )
482     {
483         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
484         {
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(). */
488         }
489         #else
490         {
491             /* Should not be possible to get here, ucFlags must be corrupt.
492              * Force an assert. */
493             configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );
494         }
495         #endif
496     }
497     else
498     {
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 ) );
502     }
503 }
504 /*-----------------------------------------------------------*/
505
506 BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
507 {
508     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
509     BaseType_t xReturn = pdFAIL;
510     StreamBufferCallbackFunction_t pxSendCallback = NULL, pxReceiveCallback = NULL;
511
512     #if ( configUSE_TRACE_FACILITY == 1 )
513         UBaseType_t uxStreamBufferNumber;
514     #endif
515
516     configASSERT( pxStreamBuffer );
517
518     #if ( configUSE_TRACE_FACILITY == 1 )
519     {
520         /* Store the stream buffer number so it can be restored after the
521          * reset. */
522         uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
523     }
524     #endif
525
526     /* Can only reset a message buffer if there are no tasks blocked on it. */
527     taskENTER_CRITICAL();
528     {
529         if( ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) )
530         {
531             #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
532             {
533                 pxSendCallback = pxStreamBuffer->pxSendCompletedCallback;
534                 pxReceiveCallback = pxStreamBuffer->pxReceiveCompletedCallback;
535             }
536             #endif
537
538             prvInitialiseNewStreamBuffer( pxStreamBuffer,
539                                           pxStreamBuffer->pucBuffer,
540                                           pxStreamBuffer->xLength,
541                                           pxStreamBuffer->xTriggerLevelBytes,
542                                           pxStreamBuffer->ucFlags,
543                                           pxSendCallback,
544                                           pxReceiveCallback );
545
546             #if ( configUSE_TRACE_FACILITY == 1 )
547             {
548                 pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
549             }
550             #endif
551
552             traceSTREAM_BUFFER_RESET( xStreamBuffer );
553
554             xReturn = pdPASS;
555         }
556     }
557     taskEXIT_CRITICAL();
558
559     return xReturn;
560 }
561 /*-----------------------------------------------------------*/
562
563 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,
564                                          size_t xTriggerLevel )
565 {
566     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
567     BaseType_t xReturn;
568
569     configASSERT( pxStreamBuffer );
570
571     /* It is not valid for the trigger level to be 0. */
572     if( xTriggerLevel == ( size_t ) 0 )
573     {
574         xTriggerLevel = ( size_t ) 1;
575     }
576
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 )
580     {
581         pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
582         xReturn = pdPASS;
583     }
584     else
585     {
586         xReturn = pdFALSE;
587     }
588
589     return xReturn;
590 }
591 /*-----------------------------------------------------------*/
592
593 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )
594 {
595     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
596     size_t xSpace;
597     size_t xOriginalTail;
598
599     configASSERT( pxStreamBuffer );
600
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. */
604     do
605     {
606         xOriginalTail = pxStreamBuffer->xTail;
607         xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;
608         xSpace -= pxStreamBuffer->xHead;
609     } while( xOriginalTail != pxStreamBuffer->xTail );
610
611     xSpace -= ( size_t ) 1;
612
613     if( xSpace >= pxStreamBuffer->xLength )
614     {
615         xSpace -= pxStreamBuffer->xLength;
616     }
617     else
618     {
619         mtCOVERAGE_TEST_MARKER();
620     }
621
622     return xSpace;
623 }
624 /*-----------------------------------------------------------*/
625
626 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )
627 {
628     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
629     size_t xReturn;
630
631     configASSERT( pxStreamBuffer );
632
633     xReturn = prvBytesInBuffer( pxStreamBuffer );
634     return xReturn;
635 }
636 /*-----------------------------------------------------------*/
637
638 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
639                           const void * pvTxData,
640                           size_t xDataLengthBytes,
641                           TickType_t xTicksToWait )
642 {
643     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
644     size_t xReturn, xSpace = 0;
645     size_t xRequiredSpace = xDataLengthBytes;
646     TimeOut_t xTimeOut;
647     size_t xMaxReportedSpace = 0;
648
649     configASSERT( pvTxData );
650     configASSERT( pxStreamBuffer );
651
652     /* The maximum amount of space a stream buffer will ever report is its length
653      * minus 1. */
654     xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;
655
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
659      * message. */
660     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
661     {
662         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
663
664         /* Overflow? */
665         configASSERT( xRequiredSpace > xDataLengthBytes );
666
667         /* If this is a message buffer then it must be possible to write the
668          * whole message. */
669         if( xRequiredSpace > xMaxReportedSpace )
670         {
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;
674         }
675         else
676         {
677             mtCOVERAGE_TEST_MARKER();
678         }
679     }
680     else
681     {
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
684          * the buffer. */
685         if( xRequiredSpace > xMaxReportedSpace )
686         {
687             xRequiredSpace = xMaxReportedSpace;
688         }
689         else
690         {
691             mtCOVERAGE_TEST_MARKER();
692         }
693     }
694
695     if( xTicksToWait != ( TickType_t ) 0 )
696     {
697         vTaskSetTimeOutState( &xTimeOut );
698
699         do
700         {
701             /* Wait until the required number of bytes are free in the message
702              * buffer. */
703             taskENTER_CRITICAL();
704             {
705                 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
706
707                 if( xSpace < xRequiredSpace )
708                 {
709                     /* Clear notification state as going to wait for space. */
710                     ( void ) xTaskNotifyStateClear( NULL );
711
712                     /* Should only be one writer. */
713                     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
714                     pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();
715                 }
716                 else
717                 {
718                     taskEXIT_CRITICAL();
719                     break;
720                 }
721             }
722             taskEXIT_CRITICAL();
723
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 );
728     }
729     else
730     {
731         mtCOVERAGE_TEST_MARKER();
732     }
733
734     if( xSpace == ( size_t ) 0 )
735     {
736         xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
737     }
738     else
739     {
740         mtCOVERAGE_TEST_MARKER();
741     }
742
743     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
744
745     if( xReturn > ( size_t ) 0 )
746     {
747         traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );
748
749         /* Was a task waiting for the data? */
750         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
751         {
752             prvSEND_COMPLETED( pxStreamBuffer );
753         }
754         else
755         {
756             mtCOVERAGE_TEST_MARKER();
757         }
758     }
759     else
760     {
761         mtCOVERAGE_TEST_MARKER();
762         traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );
763     }
764
765     return xReturn;
766 }
767 /*-----------------------------------------------------------*/
768
769 size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
770                                  const void * pvTxData,
771                                  size_t xDataLengthBytes,
772                                  BaseType_t * const pxHigherPriorityTaskWoken )
773 {
774     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
775     size_t xReturn, xSpace;
776     size_t xRequiredSpace = xDataLengthBytes;
777
778     configASSERT( pvTxData );
779     configASSERT( pxStreamBuffer );
780
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
784      * message. */
785     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
786     {
787         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
788     }
789     else
790     {
791         mtCOVERAGE_TEST_MARKER();
792     }
793
794     xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
795     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
796
797     if( xReturn > ( size_t ) 0 )
798     {
799         /* Was a task waiting for the data? */
800         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
801         {
802             prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
803         }
804         else
805         {
806             mtCOVERAGE_TEST_MARKER();
807         }
808     }
809     else
810     {
811         mtCOVERAGE_TEST_MARKER();
812     }
813
814     traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );
815
816     return xReturn;
817 }
818 /*-----------------------------------------------------------*/
819
820 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
821                                        const void * pvTxData,
822                                        size_t xDataLengthBytes,
823                                        size_t xSpace,
824                                        size_t xRequiredSpace )
825 {
826     size_t xNextHead = pxStreamBuffer->xHead;
827     configMESSAGE_BUFFER_LENGTH_TYPE xMessageLength;
828
829     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
830     {
831         /* This is a message buffer, as opposed to a stream buffer. */
832
833         /* Convert xDataLengthBytes to the message length type. */
834         xMessageLength = ( configMESSAGE_BUFFER_LENGTH_TYPE ) xDataLengthBytes;
835
836         /* Ensure the data length given fits within configMESSAGE_BUFFER_LENGTH_TYPE. */
837         configASSERT( ( size_t ) xMessageLength == xDataLengthBytes );
838
839         if( xSpace >= xRequiredSpace )
840         {
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 );
845         }
846         else
847         {
848             /* Not enough space, so do not write data to the buffer. */
849             xDataLengthBytes = 0;
850         }
851     }
852     else
853     {
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 );
858     }
859
860     if( xDataLengthBytes != ( size_t ) 0 )
861     {
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. */
864     }
865
866     return xDataLengthBytes;
867 }
868 /*-----------------------------------------------------------*/
869
870 size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
871                              void * pvRxData,
872                              size_t xBufferLengthBytes,
873                              TickType_t xTicksToWait )
874 {
875     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
876     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
877
878     configASSERT( pvRxData );
879     configASSERT( pxStreamBuffer );
880
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
885      * message. */
886     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
887     {
888         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
889     }
890     else
891     {
892         xBytesToStoreMessageLength = 0;
893     }
894
895     if( xTicksToWait != ( TickType_t ) 0 )
896     {
897         /* Checking if there is data and clearing the notification state must be
898          * performed atomically. */
899         taskENTER_CRITICAL();
900         {
901             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
902
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
907              * be 0. */
908             if( xBytesAvailable <= xBytesToStoreMessageLength )
909             {
910                 /* Clear notification state as going to wait for data. */
911                 ( void ) xTaskNotifyStateClear( NULL );
912
913                 /* Should only be one reader. */
914                 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
915                 pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();
916             }
917             else
918             {
919                 mtCOVERAGE_TEST_MARKER();
920             }
921         }
922         taskEXIT_CRITICAL();
923
924         if( xBytesAvailable <= xBytesToStoreMessageLength )
925         {
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;
930
931             /* Recheck the data available after blocking. */
932             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
933         }
934         else
935         {
936             mtCOVERAGE_TEST_MARKER();
937         }
938     }
939     else
940     {
941         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
942     }
943
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 )
950     {
951         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
952
953         /* Was a task waiting for space in the buffer? */
954         if( xReceivedLength != ( size_t ) 0 )
955         {
956             traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );
957             prvRECEIVE_COMPLETED( xStreamBuffer );
958         }
959         else
960         {
961             mtCOVERAGE_TEST_MARKER();
962         }
963     }
964     else
965     {
966         traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );
967         mtCOVERAGE_TEST_MARKER();
968     }
969
970     return xReceivedLength;
971 }
972 /*-----------------------------------------------------------*/
973
974 size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )
975 {
976     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
977     size_t xReturn, xBytesAvailable;
978     configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
979
980     configASSERT( pxStreamBuffer );
981
982     /* Ensure the stream buffer is being used as a message buffer. */
983     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
984     {
985         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
986
987         if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
988         {
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
991              * is available. */
992             ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, pxStreamBuffer->xTail );
993             xReturn = ( size_t ) xTempReturn;
994         }
995         else
996         {
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
1000              * value is 0. */
1001             configASSERT( xBytesAvailable == 0 );
1002             xReturn = 0;
1003         }
1004     }
1005     else
1006     {
1007         xReturn = 0;
1008     }
1009
1010     return xReturn;
1011 }
1012 /*-----------------------------------------------------------*/
1013
1014 size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
1015                                     void * pvRxData,
1016                                     size_t xBufferLengthBytes,
1017                                     BaseType_t * const pxHigherPriorityTaskWoken )
1018 {
1019     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1020     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
1021
1022     configASSERT( pvRxData );
1023     configASSERT( pxStreamBuffer );
1024
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
1029      * message. */
1030     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1031     {
1032         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1033     }
1034     else
1035     {
1036         xBytesToStoreMessageLength = 0;
1037     }
1038
1039     xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1040
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 )
1047     {
1048         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
1049
1050         /* Was a task waiting for space in the buffer? */
1051         if( xReceivedLength != ( size_t ) 0 )
1052         {
1053             prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
1054         }
1055         else
1056         {
1057             mtCOVERAGE_TEST_MARKER();
1058         }
1059     }
1060     else
1061     {
1062         mtCOVERAGE_TEST_MARKER();
1063     }
1064
1065     traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );
1066
1067     return xReceivedLength;
1068 }
1069 /*-----------------------------------------------------------*/
1070
1071 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
1072                                         void * pvRxData,
1073                                         size_t xBufferLengthBytes,
1074                                         size_t xBytesAvailable )
1075 {
1076     size_t xCount, xNextMessageLength;
1077     configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
1078     size_t xNextTail = pxStreamBuffer->xTail;
1079
1080     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1081     {
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;
1086
1087         /* Reduce the number of bytes available by the number of bytes just
1088          * read out. */
1089         xBytesAvailable -= sbBYTES_TO_STORE_MESSAGE_LENGTH;
1090
1091         /* Check there is enough space in the buffer provided by the
1092          * user. */
1093         if( xNextMessageLength > xBufferLengthBytes )
1094         {
1095             /* The user has provided insufficient space to read the message. */
1096             xNextMessageLength = 0;
1097         }
1098         else
1099         {
1100             mtCOVERAGE_TEST_MARKER();
1101         }
1102     }
1103     else
1104     {
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;
1108     }
1109
1110     /* Use the minimum of the wanted bytes and the available bytes. */
1111     xCount = configMIN( xNextMessageLength, xBytesAvailable );
1112
1113     if( xCount != ( size_t ) 0 )
1114     {
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. */
1117     }
1118
1119     return xCount;
1120 }
1121 /*-----------------------------------------------------------*/
1122
1123 BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )
1124 {
1125     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1126     BaseType_t xReturn;
1127     size_t xTail;
1128
1129     configASSERT( pxStreamBuffer );
1130
1131     /* True if no bytes are available. */
1132     xTail = pxStreamBuffer->xTail;
1133
1134     if( pxStreamBuffer->xHead == xTail )
1135     {
1136         xReturn = pdTRUE;
1137     }
1138     else
1139     {
1140         xReturn = pdFALSE;
1141     }
1142
1143     return xReturn;
1144 }
1145 /*-----------------------------------------------------------*/
1146
1147 BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )
1148 {
1149     BaseType_t xReturn;
1150     size_t xBytesToStoreMessageLength;
1151     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1152
1153     configASSERT( pxStreamBuffer );
1154
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 )
1160     {
1161         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1162     }
1163     else
1164     {
1165         xBytesToStoreMessageLength = 0;
1166     }
1167
1168     /* True if the available space equals zero. */
1169     if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )
1170     {
1171         xReturn = pdTRUE;
1172     }
1173     else
1174     {
1175         xReturn = pdFALSE;
1176     }
1177
1178     return xReturn;
1179 }
1180 /*-----------------------------------------------------------*/
1181
1182 BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1183                                               BaseType_t * pxHigherPriorityTaskWoken )
1184 {
1185     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1186     BaseType_t xReturn;
1187     UBaseType_t uxSavedInterruptStatus;
1188
1189     configASSERT( pxStreamBuffer );
1190
1191     uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
1192     {
1193         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
1194         {
1195             ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
1196                                          ( uint32_t ) 0,
1197                                          eNoAction,
1198                                          pxHigherPriorityTaskWoken );
1199             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
1200             xReturn = pdTRUE;
1201         }
1202         else
1203         {
1204             xReturn = pdFALSE;
1205         }
1206     }
1207     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1208
1209     return xReturn;
1210 }
1211 /*-----------------------------------------------------------*/
1212
1213 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1214                                                  BaseType_t * pxHigherPriorityTaskWoken )
1215 {
1216     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1217     BaseType_t xReturn;
1218     UBaseType_t uxSavedInterruptStatus;
1219
1220     configASSERT( pxStreamBuffer );
1221
1222     uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();
1223     {
1224         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
1225         {
1226             ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
1227                                          ( uint32_t ) 0,
1228                                          eNoAction,
1229                                          pxHigherPriorityTaskWoken );
1230             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
1231             xReturn = pdTRUE;
1232         }
1233         else
1234         {
1235             xReturn = pdFALSE;
1236         }
1237     }
1238     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
1239
1240     return xReturn;
1241 }
1242 /*-----------------------------------------------------------*/
1243
1244 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
1245                                      const uint8_t * pucData,
1246                                      size_t xCount,
1247                                      size_t xHead )
1248 {
1249     size_t xFirstLength;
1250
1251     configASSERT( xCount > ( size_t ) 0 );
1252
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 );
1257
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 *. */
1261
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 )
1265     {
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 *. */
1269     }
1270     else
1271     {
1272         mtCOVERAGE_TEST_MARKER();
1273     }
1274
1275     xHead += xCount;
1276
1277     if( xHead >= pxStreamBuffer->xLength )
1278     {
1279         xHead -= pxStreamBuffer->xLength;
1280     }
1281     else
1282     {
1283         mtCOVERAGE_TEST_MARKER();
1284     }
1285
1286     return xHead;
1287 }
1288 /*-----------------------------------------------------------*/
1289
1290 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
1291                                       uint8_t * pucData,
1292                                       size_t xCount,
1293                                       size_t xTail )
1294 {
1295     size_t xFirstLength;
1296
1297     configASSERT( xCount != ( size_t ) 0 );
1298
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
1301      * the buffer. */
1302     xFirstLength = configMIN( pxStreamBuffer->xLength - xTail, xCount );
1303
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 *. */
1309
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 )
1313     {
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 *. */
1316     }
1317     else
1318     {
1319         mtCOVERAGE_TEST_MARKER();
1320     }
1321
1322     /* Move the tail pointer to effectively remove the data read from the buffer. */
1323     xTail += xCount;
1324
1325     if( xTail >= pxStreamBuffer->xLength )
1326     {
1327         xTail -= pxStreamBuffer->xLength;
1328     }
1329
1330     return xTail;
1331 }
1332 /*-----------------------------------------------------------*/
1333
1334 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )
1335 {
1336 /* Returns the distance between xTail and xHead. */
1337     size_t xCount;
1338
1339     xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
1340     xCount -= pxStreamBuffer->xTail;
1341
1342     if( xCount >= pxStreamBuffer->xLength )
1343     {
1344         xCount -= pxStreamBuffer->xLength;
1345     }
1346     else
1347     {
1348         mtCOVERAGE_TEST_MARKER();
1349     }
1350
1351     return xCount;
1352 }
1353 /*-----------------------------------------------------------*/
1354
1355 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
1356                                           uint8_t * const pucBuffer,
1357                                           size_t xBufferSizeBytes,
1358                                           size_t xTriggerLevelBytes,
1359                                           uint8_t ucFlags,
1360                                           StreamBufferCallbackFunction_t pxSendCompletedCallback,
1361                                           StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
1362 {
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 )
1367     {
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. */
1374     #endif
1375
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 )
1382     {
1383         pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback;
1384         pxStreamBuffer->pxReceiveCompletedCallback = pxReceiveCompletedCallback;
1385     }
1386     #else
1387     {
1388         ( void ) pxSendCompletedCallback;
1389         ( void ) pxReceiveCompletedCallback;
1390     }
1391     #endif
1392 }
1393
1394 #if ( configUSE_TRACE_FACILITY == 1 )
1395
1396     UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )
1397     {
1398         return xStreamBuffer->uxStreamBufferNumber;
1399     }
1400
1401 #endif /* configUSE_TRACE_FACILITY */
1402 /*-----------------------------------------------------------*/
1403
1404 #if ( configUSE_TRACE_FACILITY == 1 )
1405
1406     void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,
1407                                              UBaseType_t uxStreamBufferNumber )
1408     {
1409         xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
1410     }
1411
1412 #endif /* configUSE_TRACE_FACILITY */
1413 /*-----------------------------------------------------------*/
1414
1415 #if ( configUSE_TRACE_FACILITY == 1 )
1416
1417     uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )
1418     {
1419         return( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER );
1420     }
1421
1422 #endif /* configUSE_TRACE_FACILITY */
1423 /*-----------------------------------------------------------*/