]> begriffs open source - freertos/blob - stream_buffer.c
Add IRQ safe API for message buffer reset (#1033)
[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 <string.h>
31
32 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
33  * all the API functions to use the MPU wrappers.  That should only be done when
34  * task.h is included from an application file. */
35 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
36
37 /* FreeRTOS includes. */
38 #include "FreeRTOS.h"
39 #include "task.h"
40 #include "stream_buffer.h"
41
42 #if ( configUSE_TASK_NOTIFICATIONS != 1 )
43     #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c
44 #endif
45
46 #if ( INCLUDE_xTaskGetCurrentTaskHandle != 1 )
47     #error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 to build stream_buffer.c
48 #endif
49
50 /* The MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
51  * for the header files above, but not in this file, in order to generate the
52  * correct privileged Vs unprivileged linkage and placement. */
53 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
54
55 /* This entire source file will be skipped if the application is not configured
56  * to include stream buffer functionality. This #if is closed at the very bottom
57  * of this file. If you want to include stream buffers then ensure
58  * configUSE_STREAM_BUFFERS is set to 1 in FreeRTOSConfig.h. */
59 #if ( configUSE_STREAM_BUFFERS == 1 )
60
61 /* If the user has not provided application specific Rx notification macros,
62  * or #defined the notification macros away, then provide default implementations
63  * that uses task notifications. */
64     #ifndef sbRECEIVE_COMPLETED
65         #define sbRECEIVE_COMPLETED( pxStreamBuffer )                                 \
66     do                                                                                \
67     {                                                                                 \
68         vTaskSuspendAll();                                                            \
69         {                                                                             \
70             if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                      \
71             {                                                                         \
72                 ( void ) xTaskNotifyIndexed( ( pxStreamBuffer )->xTaskWaitingToSend,  \
73                                              ( pxStreamBuffer )->uxNotificationIndex, \
74                                              ( uint32_t ) 0,                          \
75                                              eNoAction );                             \
76                 ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                        \
77             }                                                                         \
78         }                                                                             \
79         ( void ) xTaskResumeAll();                                                    \
80     } while( 0 )
81     #endif /* sbRECEIVE_COMPLETED */
82
83 /* If user has provided a per-instance receive complete callback, then
84  * invoke the callback else use the receive complete macro which is provided by default for all instances.
85  */
86     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
87         #define prvRECEIVE_COMPLETED( pxStreamBuffer )                                           \
88     do {                                                                                         \
89         if( ( pxStreamBuffer )->pxReceiveCompletedCallback != NULL )                             \
90         {                                                                                        \
91             ( pxStreamBuffer )->pxReceiveCompletedCallback( ( pxStreamBuffer ), pdFALSE, NULL ); \
92         }                                                                                        \
93         else                                                                                     \
94         {                                                                                        \
95             sbRECEIVE_COMPLETED( ( pxStreamBuffer ) );                                           \
96         }                                                                                        \
97     } while( 0 )
98     #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
99         #define prvRECEIVE_COMPLETED( pxStreamBuffer )    sbRECEIVE_COMPLETED( ( pxStreamBuffer ) )
100     #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
101
102     #ifndef sbRECEIVE_COMPLETED_FROM_ISR
103         #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                                \
104                                               pxHigherPriorityTaskWoken )                    \
105     do {                                                                                     \
106         UBaseType_t uxSavedInterruptStatus;                                                  \
107                                                                                              \
108         uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                              \
109         {                                                                                    \
110             if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                             \
111             {                                                                                \
112                 ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,  \
113                                                     ( pxStreamBuffer )->uxNotificationIndex, \
114                                                     ( uint32_t ) 0,                          \
115                                                     eNoAction,                               \
116                                                     ( pxHigherPriorityTaskWoken ) );         \
117                 ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                               \
118             }                                                                                \
119         }                                                                                    \
120         taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                                \
121     } while( 0 )
122     #endif /* sbRECEIVE_COMPLETED_FROM_ISR */
123
124     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
125         #define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                                                           \
126                                                pxHigherPriorityTaskWoken )                                               \
127     do {                                                                                                                 \
128         if( ( pxStreamBuffer )->pxReceiveCompletedCallback != NULL )                                                     \
129         {                                                                                                                \
130             ( pxStreamBuffer )->pxReceiveCompletedCallback( ( pxStreamBuffer ), pdTRUE, ( pxHigherPriorityTaskWoken ) ); \
131         }                                                                                                                \
132         else                                                                                                             \
133         {                                                                                                                \
134             sbRECEIVE_COMPLETED_FROM_ISR( ( pxStreamBuffer ), ( pxHigherPriorityTaskWoken ) );                           \
135         }                                                                                                                \
136     } while( 0 )
137     #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
138         #define prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
139     sbRECEIVE_COMPLETED_FROM_ISR( ( pxStreamBuffer ), ( pxHigherPriorityTaskWoken ) )
140     #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
141
142 /* If the user has not provided an application specific Tx notification macro,
143  * or #defined the notification macro away, then provide a default
144  * implementation that uses task notifications.
145  */
146     #ifndef sbSEND_COMPLETED
147         #define sbSEND_COMPLETED( pxStreamBuffer )                                  \
148     vTaskSuspendAll();                                                              \
149     {                                                                               \
150         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                     \
151         {                                                                           \
152             ( void ) xTaskNotifyIndexed( ( pxStreamBuffer )->xTaskWaitingToReceive, \
153                                          ( pxStreamBuffer )->uxNotificationIndex,   \
154                                          ( uint32_t ) 0,                            \
155                                          eNoAction );                               \
156             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                       \
157         }                                                                           \
158     }                                                                               \
159     ( void ) xTaskResumeAll()
160     #endif /* sbSEND_COMPLETED */
161
162 /* If user has provided a per-instance send completed callback, then
163  * invoke the callback else use the send complete macro which is provided by default for all instances.
164  */
165     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
166         #define prvSEND_COMPLETED( pxStreamBuffer )                                           \
167     do {                                                                                      \
168         if( ( pxStreamBuffer )->pxSendCompletedCallback != NULL )                             \
169         {                                                                                     \
170             ( pxStreamBuffer )->pxSendCompletedCallback( ( pxStreamBuffer ), pdFALSE, NULL ); \
171         }                                                                                     \
172         else                                                                                  \
173         {                                                                                     \
174             sbSEND_COMPLETED( ( pxStreamBuffer ) );                                           \
175         }                                                                                     \
176     } while( 0 )
177     #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
178         #define prvSEND_COMPLETED( pxStreamBuffer )    sbSEND_COMPLETED( ( pxStreamBuffer ) )
179     #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
180
181
182     #ifndef sbSEND_COMPLETE_FROM_ISR
183         #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )          \
184     do {                                                                                       \
185         UBaseType_t uxSavedInterruptStatus;                                                    \
186                                                                                                \
187         uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();                                \
188         {                                                                                      \
189             if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                            \
190             {                                                                                  \
191                 ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \
192                                                     ( pxStreamBuffer )->uxNotificationIndex,   \
193                                                     ( uint32_t ) 0,                            \
194                                                     eNoAction,                                 \
195                                                     ( pxHigherPriorityTaskWoken ) );           \
196                 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                              \
197             }                                                                                  \
198         }                                                                                      \
199         taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );                                  \
200     } while( 0 )
201     #endif /* sbSEND_COMPLETE_FROM_ISR */
202
203
204     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
205         #define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )                                \
206     do {                                                                                                              \
207         if( ( pxStreamBuffer )->pxSendCompletedCallback != NULL )                                                     \
208         {                                                                                                             \
209             ( pxStreamBuffer )->pxSendCompletedCallback( ( pxStreamBuffer ), pdTRUE, ( pxHigherPriorityTaskWoken ) ); \
210         }                                                                                                             \
211         else                                                                                                          \
212         {                                                                                                             \
213             sbSEND_COMPLETE_FROM_ISR( ( pxStreamBuffer ), ( pxHigherPriorityTaskWoken ) );                            \
214         }                                                                                                             \
215     } while( 0 )
216     #else /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
217         #define prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \
218     sbSEND_COMPLETE_FROM_ISR( ( pxStreamBuffer ), ( pxHigherPriorityTaskWoken ) )
219     #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
220
221 /* The number of bytes used to hold the length of a message in the buffer. */
222     #define sbBYTES_TO_STORE_MESSAGE_LENGTH    ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )
223
224 /* Bits stored in the ucFlags field of the stream buffer. */
225     #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. */
226     #define sbFLAGS_IS_STATICALLY_ALLOCATED    ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */
227
228 /*-----------------------------------------------------------*/
229
230 /* Structure that hold state information on the buffer. */
231 typedef struct StreamBufferDef_t
232 {
233     volatile size_t xTail;                       /* Index to the next item to read within the buffer. */
234     volatile size_t xHead;                       /* Index to the next item to write within the buffer. */
235     size_t xLength;                              /* The length of the buffer pointed to by pucBuffer. */
236     size_t xTriggerLevelBytes;                   /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */
237     volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */
238     volatile TaskHandle_t xTaskWaitingToSend;    /* Holds the handle of a task waiting to send data to a message buffer that is full. */
239     uint8_t * pucBuffer;                         /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */
240     uint8_t ucFlags;
241
242     #if ( configUSE_TRACE_FACILITY == 1 )
243         UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */
244     #endif
245
246     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
247         StreamBufferCallbackFunction_t pxSendCompletedCallback;    /* Optional callback called on send complete. sbSEND_COMPLETED is called if this is NULL. */
248         StreamBufferCallbackFunction_t pxReceiveCompletedCallback; /* Optional callback called on receive complete.  sbRECEIVE_COMPLETED is called if this is NULL. */
249     #endif
250     UBaseType_t uxNotificationIndex;                               /* The index we are using for notification, by default tskDEFAULT_INDEX_TO_NOTIFY. */
251 } StreamBuffer_t;
252
253 /*
254  * The number of bytes available to be read from the buffer.
255  */
256 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION;
257
258 /*
259  * Add xCount bytes from pucData into the pxStreamBuffer's data storage area.
260  * This function does not update the buffer's xHead pointer, so multiple writes
261  * may be chained together "atomically". This is useful for Message Buffers where
262  * the length and data bytes are written in two separate chunks, and we don't want
263  * the reader to see the buffer as having grown until after all data is copied over.
264  * This function takes a custom xHead value to indicate where to write to (necessary
265  * for chaining) and returns the the resulting xHead position.
266  * To mark the write as complete, manually set the buffer's xHead field with the
267  * returned xHead from this function.
268  */
269 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
270                                      const uint8_t * pucData,
271                                      size_t xCount,
272                                      size_t xHead ) PRIVILEGED_FUNCTION;
273
274 /*
275  * If the stream buffer is being used as a message buffer, then reads an entire
276  * message out of the buffer.  If the stream buffer is being used as a stream
277  * buffer then read as many bytes as possible from the buffer.
278  * prvReadBytesFromBuffer() is called to actually extract the bytes from the
279  * buffer's data storage area.
280  */
281 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
282                                         void * pvRxData,
283                                         size_t xBufferLengthBytes,
284                                         size_t xBytesAvailable ) PRIVILEGED_FUNCTION;
285
286 /*
287  * If the stream buffer is being used as a message buffer, then writes an entire
288  * message to the buffer.  If the stream buffer is being used as a stream
289  * buffer then write as many bytes as possible to the buffer.
290  * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's
291  * data storage area.
292  */
293 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
294                                        const void * pvTxData,
295                                        size_t xDataLengthBytes,
296                                        size_t xSpace,
297                                        size_t xRequiredSpace ) PRIVILEGED_FUNCTION;
298
299 /*
300  * Copies xCount bytes from the pxStreamBuffer's data storage area to pucData.
301  * This function does not update the buffer's xTail pointer, so multiple reads
302  * may be chained together "atomically". This is useful for Message Buffers where
303  * the length and data bytes are read in two separate chunks, and we don't want
304  * the writer to see the buffer as having more free space until after all data is
305  * copied over, especially if we have to abort the read due to insufficient receiving space.
306  * This function takes a custom xTail value to indicate where to read from (necessary
307  * for chaining) and returns the the resulting xTail position.
308  * To mark the read as complete, manually set the buffer's xTail field with the
309  * returned xTail from this function.
310  */
311 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
312                                       uint8_t * pucData,
313                                       size_t xCount,
314                                       size_t xTail ) PRIVILEGED_FUNCTION;
315
316 /*
317  * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to
318  * initialise the members of the newly created stream buffer structure.
319  */
320 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
321                                           uint8_t * const pucBuffer,
322                                           size_t xBufferSizeBytes,
323                                           size_t xTriggerLevelBytes,
324                                           uint8_t ucFlags,
325                                           StreamBufferCallbackFunction_t pxSendCompletedCallback,
326                                           StreamBufferCallbackFunction_t pxReceiveCompletedCallback ) PRIVILEGED_FUNCTION;
327
328 /*-----------------------------------------------------------*/
329     #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
330     StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
331                                                      size_t xTriggerLevelBytes,
332                                                      BaseType_t xIsMessageBuffer,
333                                                      StreamBufferCallbackFunction_t pxSendCompletedCallback,
334                                                      StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
335     {
336         void * pvAllocatedMemory;
337         uint8_t ucFlags;
338
339         traceENTER_xStreamBufferGenericCreate( xBufferSizeBytes, xTriggerLevelBytes, xIsMessageBuffer, pxSendCompletedCallback, pxReceiveCompletedCallback );
340
341         /* In case the stream buffer is going to be used as a message buffer
342          * (that is, it will hold discrete messages with a little meta data that
343          * says how big the next message is) check the buffer will be large enough
344          * to hold at least one message. */
345         if( xIsMessageBuffer == pdTRUE )
346         {
347             /* Is a message buffer but not statically allocated. */
348             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER;
349             configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
350         }
351         else
352         {
353             /* Not a message buffer and not statically allocated. */
354             ucFlags = 0;
355             configASSERT( xBufferSizeBytes > 0 );
356         }
357
358         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
359
360         /* A trigger level of 0 would cause a waiting task to unblock even when
361          * the buffer was empty. */
362         if( xTriggerLevelBytes == ( size_t ) 0 )
363         {
364             xTriggerLevelBytes = ( size_t ) 1;
365         }
366
367         /* A stream buffer requires a StreamBuffer_t structure and a buffer.
368          * Both are allocated in a single call to pvPortMalloc().  The
369          * StreamBuffer_t structure is placed at the start of the allocated memory
370          * and the buffer follows immediately after.  The requested size is
371          * incremented so the free space is returned as the user would expect -
372          * this is a quirk of the implementation that means otherwise the free
373          * space would be reported as one byte smaller than would be logically
374          * expected. */
375         if( xBufferSizeBytes < ( xBufferSizeBytes + 1U + sizeof( StreamBuffer_t ) ) )
376         {
377             xBufferSizeBytes++;
378             pvAllocatedMemory = pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) );
379         }
380         else
381         {
382             pvAllocatedMemory = NULL;
383         }
384
385         if( pvAllocatedMemory != NULL )
386         {
387             /* MISRA Ref 11.5.1 [Malloc memory assignment] */
388             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
389             /* coverity[misra_c_2012_rule_11_5_violation] */
390             prvInitialiseNewStreamBuffer( ( StreamBuffer_t * ) pvAllocatedMemory,                         /* Structure at the start of the allocated memory. */
391                                                                                                           /* MISRA Ref 11.5.1 [Malloc memory assignment] */
392                                                                                                           /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
393                                                                                                           /* coverity[misra_c_2012_rule_11_5_violation] */
394                                           ( ( uint8_t * ) pvAllocatedMemory ) + sizeof( StreamBuffer_t ), /* Storage area follows. */
395                                           xBufferSizeBytes,
396                                           xTriggerLevelBytes,
397                                           ucFlags,
398                                           pxSendCompletedCallback,
399                                           pxReceiveCompletedCallback );
400
401             traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pvAllocatedMemory ), xIsMessageBuffer );
402         }
403         else
404         {
405             traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );
406         }
407
408         traceRETURN_xStreamBufferGenericCreate( pvAllocatedMemory );
409
410         /* MISRA Ref 11.5.1 [Malloc memory assignment] */
411         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
412         /* coverity[misra_c_2012_rule_11_5_violation] */
413         return ( StreamBufferHandle_t ) pvAllocatedMemory;
414     }
415     #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
416 /*-----------------------------------------------------------*/
417
418     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
419
420     StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
421                                                            size_t xTriggerLevelBytes,
422                                                            BaseType_t xIsMessageBuffer,
423                                                            uint8_t * const pucStreamBufferStorageArea,
424                                                            StaticStreamBuffer_t * const pxStaticStreamBuffer,
425                                                            StreamBufferCallbackFunction_t pxSendCompletedCallback,
426                                                            StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
427     {
428         /* MISRA Ref 11.3.1 [Misaligned access] */
429         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
430         /* coverity[misra_c_2012_rule_11_3_violation] */
431         StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer;
432         StreamBufferHandle_t xReturn;
433         uint8_t ucFlags;
434
435         traceENTER_xStreamBufferGenericCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, xIsMessageBuffer, pucStreamBufferStorageArea, pxStaticStreamBuffer, pxSendCompletedCallback, pxReceiveCompletedCallback );
436
437         configASSERT( pucStreamBufferStorageArea );
438         configASSERT( pxStaticStreamBuffer );
439         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );
440
441         /* A trigger level of 0 would cause a waiting task to unblock even when
442          * the buffer was empty. */
443         if( xTriggerLevelBytes == ( size_t ) 0 )
444         {
445             xTriggerLevelBytes = ( size_t ) 1;
446         }
447
448         /* In case the stream buffer is going to be used as a message buffer
449          * (that is, it will hold discrete messages with a little meta data that
450          * says how big the next message is) check the buffer will be large enough
451          * to hold at least one message. */
452
453         if( xIsMessageBuffer != pdFALSE )
454         {
455             /* Statically allocated message buffer. */
456             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;
457             configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
458         }
459         else
460         {
461             /* Statically allocated stream buffer. */
462             ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;
463         }
464
465         #if ( configASSERT_DEFINED == 1 )
466         {
467             /* Sanity check that the size of the structure used to declare a
468              * variable of type StaticStreamBuffer_t equals the size of the real
469              * message buffer structure. */
470             volatile size_t xSize = sizeof( StaticStreamBuffer_t );
471             configASSERT( xSize == sizeof( StreamBuffer_t ) );
472         }
473         #endif /* configASSERT_DEFINED */
474
475         if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )
476         {
477             prvInitialiseNewStreamBuffer( pxStreamBuffer,
478                                           pucStreamBufferStorageArea,
479                                           xBufferSizeBytes,
480                                           xTriggerLevelBytes,
481                                           ucFlags,
482                                           pxSendCompletedCallback,
483                                           pxReceiveCompletedCallback );
484
485             /* Remember this was statically allocated in case it is ever deleted
486              * again. */
487             pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;
488
489             traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );
490
491             /* MISRA Ref 11.3.1 [Misaligned access] */
492             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
493             /* coverity[misra_c_2012_rule_11_3_violation] */
494             xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer;
495         }
496         else
497         {
498             xReturn = NULL;
499             traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );
500         }
501
502         traceRETURN_xStreamBufferGenericCreateStatic( xReturn );
503
504         return xReturn;
505     }
506     #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
507 /*-----------------------------------------------------------*/
508
509     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
510     BaseType_t xStreamBufferGetStaticBuffers( StreamBufferHandle_t xStreamBuffer,
511                                               uint8_t ** ppucStreamBufferStorageArea,
512                                               StaticStreamBuffer_t ** ppxStaticStreamBuffer )
513     {
514         BaseType_t xReturn;
515         StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
516
517         traceENTER_xStreamBufferGetStaticBuffers( xStreamBuffer, ppucStreamBufferStorageArea, ppxStaticStreamBuffer );
518
519         configASSERT( pxStreamBuffer );
520         configASSERT( ppucStreamBufferStorageArea );
521         configASSERT( ppxStaticStreamBuffer );
522
523         if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) != ( uint8_t ) 0 )
524         {
525             *ppucStreamBufferStorageArea = pxStreamBuffer->pucBuffer;
526             /* MISRA Ref 11.3.1 [Misaligned access] */
527             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-113 */
528             /* coverity[misra_c_2012_rule_11_3_violation] */
529             *ppxStaticStreamBuffer = ( StaticStreamBuffer_t * ) pxStreamBuffer;
530             xReturn = pdTRUE;
531         }
532         else
533         {
534             xReturn = pdFALSE;
535         }
536
537         traceRETURN_xStreamBufferGetStaticBuffers( xReturn );
538
539         return xReturn;
540     }
541     #endif /* configSUPPORT_STATIC_ALLOCATION */
542 /*-----------------------------------------------------------*/
543
544 void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )
545 {
546     StreamBuffer_t * pxStreamBuffer = xStreamBuffer;
547
548     traceENTER_vStreamBufferDelete( xStreamBuffer );
549
550     configASSERT( pxStreamBuffer );
551
552     traceSTREAM_BUFFER_DELETE( xStreamBuffer );
553
554     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )
555     {
556         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
557         {
558             /* Both the structure and the buffer were allocated using a single call
559             * to pvPortMalloc(), hence only one call to vPortFree() is required. */
560             vPortFree( ( void * ) pxStreamBuffer );
561         }
562         #else
563         {
564             /* Should not be possible to get here, ucFlags must be corrupt.
565              * Force an assert. */
566             configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );
567         }
568         #endif
569     }
570     else
571     {
572         /* The structure and buffer were not allocated dynamically and cannot be
573          * freed - just scrub the structure so future use will assert. */
574         ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
575     }
576
577     traceRETURN_vStreamBufferDelete();
578 }
579 /*-----------------------------------------------------------*/
580
581 BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
582 {
583     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
584     BaseType_t xReturn = pdFAIL;
585     StreamBufferCallbackFunction_t pxSendCallback = NULL, pxReceiveCallback = NULL;
586
587     #if ( configUSE_TRACE_FACILITY == 1 )
588         UBaseType_t uxStreamBufferNumber;
589     #endif
590
591     traceENTER_xStreamBufferReset( xStreamBuffer );
592
593     configASSERT( pxStreamBuffer );
594
595     #if ( configUSE_TRACE_FACILITY == 1 )
596     {
597         /* Store the stream buffer number so it can be restored after the
598          * reset. */
599         uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
600     }
601     #endif
602
603     /* Can only reset a message buffer if there are no tasks blocked on it. */
604     taskENTER_CRITICAL();
605     {
606         if( ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) )
607         {
608             #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
609             {
610                 pxSendCallback = pxStreamBuffer->pxSendCompletedCallback;
611                 pxReceiveCallback = pxStreamBuffer->pxReceiveCompletedCallback;
612             }
613             #endif
614
615             prvInitialiseNewStreamBuffer( pxStreamBuffer,
616                                           pxStreamBuffer->pucBuffer,
617                                           pxStreamBuffer->xLength,
618                                           pxStreamBuffer->xTriggerLevelBytes,
619                                           pxStreamBuffer->ucFlags,
620                                           pxSendCallback,
621                                           pxReceiveCallback );
622
623             #if ( configUSE_TRACE_FACILITY == 1 )
624             {
625                 pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
626             }
627             #endif
628
629             traceSTREAM_BUFFER_RESET( xStreamBuffer );
630
631             xReturn = pdPASS;
632         }
633     }
634     taskEXIT_CRITICAL();
635
636     traceRETURN_xStreamBufferReset( xReturn );
637
638     return xReturn;
639 }
640 /*-----------------------------------------------------------*/
641
642 BaseType_t xStreamBufferResetFromISR( StreamBufferHandle_t xStreamBuffer )
643 {
644     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
645     BaseType_t xReturn = pdFAIL;
646     StreamBufferCallbackFunction_t pxSendCallback = NULL, pxReceiveCallback = NULL;
647     UBaseType_t uxSavedInterruptStatus;
648
649     #if ( configUSE_TRACE_FACILITY == 1 )
650         UBaseType_t uxStreamBufferNumber;
651     #endif
652
653     traceENTER_xStreamBufferResetFromISR( xStreamBuffer );
654
655     configASSERT( pxStreamBuffer );
656
657     #if ( configUSE_TRACE_FACILITY == 1 )
658     {
659         /* Store the stream buffer number so it can be restored after the
660          * reset. */
661         uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
662     }
663     #endif
664
665     /* Can only reset a message buffer if there are no tasks blocked on it. */
666     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
667     {
668         if( ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) )
669         {
670             #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
671             {
672                 pxSendCallback = pxStreamBuffer->pxSendCompletedCallback;
673                 pxReceiveCallback = pxStreamBuffer->pxReceiveCompletedCallback;
674             }
675             #endif
676
677             prvInitialiseNewStreamBuffer( pxStreamBuffer,
678                                           pxStreamBuffer->pucBuffer,
679                                           pxStreamBuffer->xLength,
680                                           pxStreamBuffer->xTriggerLevelBytes,
681                                           pxStreamBuffer->ucFlags,
682                                           pxSendCallback,
683                                           pxReceiveCallback );
684
685             #if ( configUSE_TRACE_FACILITY == 1 )
686             {
687                 pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
688             }
689             #endif
690
691             traceSTREAM_BUFFER_RESET_FROM_ISR( xStreamBuffer );
692
693             xReturn = pdPASS;
694         }
695     }
696     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
697
698     traceRETURN_xStreamBufferResetFromISR( xReturn );
699
700     return xReturn;
701 }
702 /*-----------------------------------------------------------*/
703
704 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,
705                                          size_t xTriggerLevel )
706 {
707     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
708     BaseType_t xReturn;
709
710     traceENTER_xStreamBufferSetTriggerLevel( xStreamBuffer, xTriggerLevel );
711
712     configASSERT( pxStreamBuffer );
713
714     /* It is not valid for the trigger level to be 0. */
715     if( xTriggerLevel == ( size_t ) 0 )
716     {
717         xTriggerLevel = ( size_t ) 1;
718     }
719
720     /* The trigger level is the number of bytes that must be in the stream
721      * buffer before a task that is waiting for data is unblocked. */
722     if( xTriggerLevel < pxStreamBuffer->xLength )
723     {
724         pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
725         xReturn = pdPASS;
726     }
727     else
728     {
729         xReturn = pdFALSE;
730     }
731
732     traceRETURN_xStreamBufferSetTriggerLevel( xReturn );
733
734     return xReturn;
735 }
736 /*-----------------------------------------------------------*/
737
738 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )
739 {
740     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
741     size_t xSpace;
742     size_t xOriginalTail;
743
744     traceENTER_xStreamBufferSpacesAvailable( xStreamBuffer );
745
746     configASSERT( pxStreamBuffer );
747
748     /* The code below reads xTail and then xHead.  This is safe if the stream
749      * buffer is updated once between the two reads - but not if the stream buffer
750      * is updated more than once between the two reads - hence the loop. */
751     do
752     {
753         xOriginalTail = pxStreamBuffer->xTail;
754         xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;
755         xSpace -= pxStreamBuffer->xHead;
756     } while( xOriginalTail != pxStreamBuffer->xTail );
757
758     xSpace -= ( size_t ) 1;
759
760     if( xSpace >= pxStreamBuffer->xLength )
761     {
762         xSpace -= pxStreamBuffer->xLength;
763     }
764     else
765     {
766         mtCOVERAGE_TEST_MARKER();
767     }
768
769     traceRETURN_xStreamBufferSpacesAvailable( xSpace );
770
771     return xSpace;
772 }
773 /*-----------------------------------------------------------*/
774
775 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )
776 {
777     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
778     size_t xReturn;
779
780     traceENTER_xStreamBufferBytesAvailable( xStreamBuffer );
781
782     configASSERT( pxStreamBuffer );
783
784     xReturn = prvBytesInBuffer( pxStreamBuffer );
785
786     traceRETURN_xStreamBufferBytesAvailable( xReturn );
787
788     return xReturn;
789 }
790 /*-----------------------------------------------------------*/
791
792 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
793                           const void * pvTxData,
794                           size_t xDataLengthBytes,
795                           TickType_t xTicksToWait )
796 {
797     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
798     size_t xReturn, xSpace = 0;
799     size_t xRequiredSpace = xDataLengthBytes;
800     TimeOut_t xTimeOut;
801     size_t xMaxReportedSpace = 0;
802
803     traceENTER_xStreamBufferSend( xStreamBuffer, pvTxData, xDataLengthBytes, xTicksToWait );
804
805     configASSERT( pvTxData );
806     configASSERT( pxStreamBuffer );
807
808     /* The maximum amount of space a stream buffer will ever report is its length
809      * minus 1. */
810     xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;
811
812     /* This send function is used to write to both message buffers and stream
813      * buffers.  If this is a message buffer then the space needed must be
814      * increased by the amount of bytes needed to store the length of the
815      * message. */
816     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
817     {
818         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
819
820         /* Overflow? */
821         configASSERT( xRequiredSpace > xDataLengthBytes );
822
823         /* If this is a message buffer then it must be possible to write the
824          * whole message. */
825         if( xRequiredSpace > xMaxReportedSpace )
826         {
827             /* The message would not fit even if the entire buffer was empty,
828              * so don't wait for space. */
829             xTicksToWait = ( TickType_t ) 0;
830         }
831         else
832         {
833             mtCOVERAGE_TEST_MARKER();
834         }
835     }
836     else
837     {
838         /* If this is a stream buffer then it is acceptable to write only part
839          * of the message to the buffer.  Cap the length to the total length of
840          * the buffer. */
841         if( xRequiredSpace > xMaxReportedSpace )
842         {
843             xRequiredSpace = xMaxReportedSpace;
844         }
845         else
846         {
847             mtCOVERAGE_TEST_MARKER();
848         }
849     }
850
851     if( xTicksToWait != ( TickType_t ) 0 )
852     {
853         vTaskSetTimeOutState( &xTimeOut );
854
855         do
856         {
857             /* Wait until the required number of bytes are free in the message
858              * buffer. */
859             taskENTER_CRITICAL();
860             {
861                 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
862
863                 if( xSpace < xRequiredSpace )
864                 {
865                     /* Clear notification state as going to wait for space. */
866                     ( void ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex );
867
868                     /* Should only be one writer. */
869                     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
870                     pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();
871                 }
872                 else
873                 {
874                     taskEXIT_CRITICAL();
875                     break;
876                 }
877             }
878             taskEXIT_CRITICAL();
879
880             traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
881             ( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
882             pxStreamBuffer->xTaskWaitingToSend = NULL;
883         } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
884     }
885     else
886     {
887         mtCOVERAGE_TEST_MARKER();
888     }
889
890     if( xSpace == ( size_t ) 0 )
891     {
892         xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
893     }
894     else
895     {
896         mtCOVERAGE_TEST_MARKER();
897     }
898
899     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
900
901     if( xReturn > ( size_t ) 0 )
902     {
903         traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );
904
905         /* Was a task waiting for the data? */
906         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
907         {
908             prvSEND_COMPLETED( pxStreamBuffer );
909         }
910         else
911         {
912             mtCOVERAGE_TEST_MARKER();
913         }
914     }
915     else
916     {
917         mtCOVERAGE_TEST_MARKER();
918         traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );
919     }
920
921     traceRETURN_xStreamBufferSend( xReturn );
922
923     return xReturn;
924 }
925 /*-----------------------------------------------------------*/
926
927 size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
928                                  const void * pvTxData,
929                                  size_t xDataLengthBytes,
930                                  BaseType_t * const pxHigherPriorityTaskWoken )
931 {
932     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
933     size_t xReturn, xSpace;
934     size_t xRequiredSpace = xDataLengthBytes;
935
936     traceENTER_xStreamBufferSendFromISR( xStreamBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken );
937
938     configASSERT( pvTxData );
939     configASSERT( pxStreamBuffer );
940
941     /* This send function is used to write to both message buffers and stream
942      * buffers.  If this is a message buffer then the space needed must be
943      * increased by the amount of bytes needed to store the length of the
944      * message. */
945     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
946     {
947         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
948     }
949     else
950     {
951         mtCOVERAGE_TEST_MARKER();
952     }
953
954     xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
955     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
956
957     if( xReturn > ( size_t ) 0 )
958     {
959         /* Was a task waiting for the data? */
960         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
961         {
962             prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
963         }
964         else
965         {
966             mtCOVERAGE_TEST_MARKER();
967         }
968     }
969     else
970     {
971         mtCOVERAGE_TEST_MARKER();
972     }
973
974     traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );
975     traceRETURN_xStreamBufferSendFromISR( xReturn );
976
977     return xReturn;
978 }
979 /*-----------------------------------------------------------*/
980
981 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
982                                        const void * pvTxData,
983                                        size_t xDataLengthBytes,
984                                        size_t xSpace,
985                                        size_t xRequiredSpace )
986 {
987     size_t xNextHead = pxStreamBuffer->xHead;
988     configMESSAGE_BUFFER_LENGTH_TYPE xMessageLength;
989
990     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
991     {
992         /* This is a message buffer, as opposed to a stream buffer. */
993
994         /* Convert xDataLengthBytes to the message length type. */
995         xMessageLength = ( configMESSAGE_BUFFER_LENGTH_TYPE ) xDataLengthBytes;
996
997         /* Ensure the data length given fits within configMESSAGE_BUFFER_LENGTH_TYPE. */
998         configASSERT( ( size_t ) xMessageLength == xDataLengthBytes );
999
1000         if( xSpace >= xRequiredSpace )
1001         {
1002             /* There is enough space to write both the message length and the message
1003              * itself into the buffer.  Start by writing the length of the data, the data
1004              * itself will be written later in this function. */
1005             xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xMessageLength ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead );
1006         }
1007         else
1008         {
1009             /* Not enough space, so do not write data to the buffer. */
1010             xDataLengthBytes = 0;
1011         }
1012     }
1013     else
1014     {
1015         /* This is a stream buffer, as opposed to a message buffer, so writing a
1016          * stream of bytes rather than discrete messages.  Plan to write as many
1017          * bytes as possible. */
1018         xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );
1019     }
1020
1021     if( xDataLengthBytes != ( size_t ) 0 )
1022     {
1023         /* Write the data to the buffer. */
1024         /* MISRA Ref 11.5.5 [Void pointer assignment] */
1025         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
1026         /* coverity[misra_c_2012_rule_11_5_violation] */
1027         pxStreamBuffer->xHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes, xNextHead );
1028     }
1029
1030     return xDataLengthBytes;
1031 }
1032 /*-----------------------------------------------------------*/
1033
1034 size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1035                              void * pvRxData,
1036                              size_t xBufferLengthBytes,
1037                              TickType_t xTicksToWait )
1038 {
1039     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1040     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
1041
1042     traceENTER_xStreamBufferReceive( xStreamBuffer, pvRxData, xBufferLengthBytes, xTicksToWait );
1043
1044     configASSERT( pvRxData );
1045     configASSERT( pxStreamBuffer );
1046
1047     /* This receive function is used by both message buffers, which store
1048      * discrete messages, and stream buffers, which store a continuous stream of
1049      * bytes.  Discrete messages include an additional
1050      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
1051      * message. */
1052     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1053     {
1054         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1055     }
1056     else
1057     {
1058         xBytesToStoreMessageLength = 0;
1059     }
1060
1061     if( xTicksToWait != ( TickType_t ) 0 )
1062     {
1063         /* Checking if there is data and clearing the notification state must be
1064          * performed atomically. */
1065         taskENTER_CRITICAL();
1066         {
1067             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1068
1069             /* If this function was invoked by a message buffer read then
1070              * xBytesToStoreMessageLength holds the number of bytes used to hold
1071              * the length of the next discrete message.  If this function was
1072              * invoked by a stream buffer read then xBytesToStoreMessageLength will
1073              * be 0. */
1074             if( xBytesAvailable <= xBytesToStoreMessageLength )
1075             {
1076                 /* Clear notification state as going to wait for data. */
1077                 ( void ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex );
1078
1079                 /* Should only be one reader. */
1080                 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
1081                 pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();
1082             }
1083             else
1084             {
1085                 mtCOVERAGE_TEST_MARKER();
1086             }
1087         }
1088         taskEXIT_CRITICAL();
1089
1090         if( xBytesAvailable <= xBytesToStoreMessageLength )
1091         {
1092             /* Wait for data to be available. */
1093             traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );
1094             ( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
1095             pxStreamBuffer->xTaskWaitingToReceive = NULL;
1096
1097             /* Recheck the data available after blocking. */
1098             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1099         }
1100         else
1101         {
1102             mtCOVERAGE_TEST_MARKER();
1103         }
1104     }
1105     else
1106     {
1107         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1108     }
1109
1110     /* Whether receiving a discrete message (where xBytesToStoreMessageLength
1111      * holds the number of bytes used to store the message length) or a stream of
1112      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
1113      * available must be greater than xBytesToStoreMessageLength to be able to
1114      * read bytes from the buffer. */
1115     if( xBytesAvailable > xBytesToStoreMessageLength )
1116     {
1117         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
1118
1119         /* Was a task waiting for space in the buffer? */
1120         if( xReceivedLength != ( size_t ) 0 )
1121         {
1122             traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );
1123             prvRECEIVE_COMPLETED( xStreamBuffer );
1124         }
1125         else
1126         {
1127             mtCOVERAGE_TEST_MARKER();
1128         }
1129     }
1130     else
1131     {
1132         traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );
1133         mtCOVERAGE_TEST_MARKER();
1134     }
1135
1136     traceRETURN_xStreamBufferReceive( xReceivedLength );
1137
1138     return xReceivedLength;
1139 }
1140 /*-----------------------------------------------------------*/
1141
1142 size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )
1143 {
1144     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1145     size_t xReturn, xBytesAvailable;
1146     configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
1147
1148     traceENTER_xStreamBufferNextMessageLengthBytes( xStreamBuffer );
1149
1150     configASSERT( pxStreamBuffer );
1151
1152     /* Ensure the stream buffer is being used as a message buffer. */
1153     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1154     {
1155         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1156
1157         if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
1158         {
1159             /* The number of bytes available is greater than the number of bytes
1160              * required to hold the length of the next message, so another message
1161              * is available. */
1162             ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, pxStreamBuffer->xTail );
1163             xReturn = ( size_t ) xTempReturn;
1164         }
1165         else
1166         {
1167             /* The minimum amount of bytes in a message buffer is
1168              * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is
1169              * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
1170              * value is 0. */
1171             configASSERT( xBytesAvailable == 0 );
1172             xReturn = 0;
1173         }
1174     }
1175     else
1176     {
1177         xReturn = 0;
1178     }
1179
1180     traceRETURN_xStreamBufferNextMessageLengthBytes( xReturn );
1181
1182     return xReturn;
1183 }
1184 /*-----------------------------------------------------------*/
1185
1186 size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
1187                                     void * pvRxData,
1188                                     size_t xBufferLengthBytes,
1189                                     BaseType_t * const pxHigherPriorityTaskWoken )
1190 {
1191     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1192     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
1193
1194     traceENTER_xStreamBufferReceiveFromISR( xStreamBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken );
1195
1196     configASSERT( pvRxData );
1197     configASSERT( pxStreamBuffer );
1198
1199     /* This receive function is used by both message buffers, which store
1200      * discrete messages, and stream buffers, which store a continuous stream of
1201      * bytes.  Discrete messages include an additional
1202      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
1203      * message. */
1204     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1205     {
1206         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1207     }
1208     else
1209     {
1210         xBytesToStoreMessageLength = 0;
1211     }
1212
1213     xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1214
1215     /* Whether receiving a discrete message (where xBytesToStoreMessageLength
1216      * holds the number of bytes used to store the message length) or a stream of
1217      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
1218      * available must be greater than xBytesToStoreMessageLength to be able to
1219      * read bytes from the buffer. */
1220     if( xBytesAvailable > xBytesToStoreMessageLength )
1221     {
1222         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
1223
1224         /* Was a task waiting for space in the buffer? */
1225         if( xReceivedLength != ( size_t ) 0 )
1226         {
1227             prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
1228         }
1229         else
1230         {
1231             mtCOVERAGE_TEST_MARKER();
1232         }
1233     }
1234     else
1235     {
1236         mtCOVERAGE_TEST_MARKER();
1237     }
1238
1239     traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );
1240     traceRETURN_xStreamBufferReceiveFromISR( xReceivedLength );
1241
1242     return xReceivedLength;
1243 }
1244 /*-----------------------------------------------------------*/
1245
1246 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
1247                                         void * pvRxData,
1248                                         size_t xBufferLengthBytes,
1249                                         size_t xBytesAvailable )
1250 {
1251     size_t xCount, xNextMessageLength;
1252     configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
1253     size_t xNextTail = pxStreamBuffer->xTail;
1254
1255     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1256     {
1257         /* A discrete message is being received.  First receive the length
1258          * of the message. */
1259         xNextTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextTail );
1260         xNextMessageLength = ( size_t ) xTempNextMessageLength;
1261
1262         /* Reduce the number of bytes available by the number of bytes just
1263          * read out. */
1264         xBytesAvailable -= sbBYTES_TO_STORE_MESSAGE_LENGTH;
1265
1266         /* Check there is enough space in the buffer provided by the
1267          * user. */
1268         if( xNextMessageLength > xBufferLengthBytes )
1269         {
1270             /* The user has provided insufficient space to read the message. */
1271             xNextMessageLength = 0;
1272         }
1273         else
1274         {
1275             mtCOVERAGE_TEST_MARKER();
1276         }
1277     }
1278     else
1279     {
1280         /* A stream of bytes is being received (as opposed to a discrete
1281          * message), so read as many bytes as possible. */
1282         xNextMessageLength = xBufferLengthBytes;
1283     }
1284
1285     /* Use the minimum of the wanted bytes and the available bytes. */
1286     xCount = configMIN( xNextMessageLength, xBytesAvailable );
1287
1288     if( xCount != ( size_t ) 0 )
1289     {
1290         /* Read the actual data and update the tail to mark the data as officially consumed. */
1291         /* MISRA Ref 11.5.5 [Void pointer assignment] */
1292         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
1293         /* coverity[misra_c_2012_rule_11_5_violation] */
1294         pxStreamBuffer->xTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xCount, xNextTail );
1295     }
1296
1297     return xCount;
1298 }
1299 /*-----------------------------------------------------------*/
1300
1301 BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )
1302 {
1303     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1304     BaseType_t xReturn;
1305     size_t xTail;
1306
1307     traceENTER_xStreamBufferIsEmpty( xStreamBuffer );
1308
1309     configASSERT( pxStreamBuffer );
1310
1311     /* True if no bytes are available. */
1312     xTail = pxStreamBuffer->xTail;
1313
1314     if( pxStreamBuffer->xHead == xTail )
1315     {
1316         xReturn = pdTRUE;
1317     }
1318     else
1319     {
1320         xReturn = pdFALSE;
1321     }
1322
1323     traceRETURN_xStreamBufferIsEmpty( xReturn );
1324
1325     return xReturn;
1326 }
1327 /*-----------------------------------------------------------*/
1328
1329 BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )
1330 {
1331     BaseType_t xReturn;
1332     size_t xBytesToStoreMessageLength;
1333     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1334
1335     traceENTER_xStreamBufferIsFull( xStreamBuffer );
1336
1337     configASSERT( pxStreamBuffer );
1338
1339     /* This generic version of the receive function is used by both message
1340      * buffers, which store discrete messages, and stream buffers, which store a
1341      * continuous stream of bytes.  Discrete messages include an additional
1342      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */
1343     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1344     {
1345         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1346     }
1347     else
1348     {
1349         xBytesToStoreMessageLength = 0;
1350     }
1351
1352     /* True if the available space equals zero. */
1353     if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )
1354     {
1355         xReturn = pdTRUE;
1356     }
1357     else
1358     {
1359         xReturn = pdFALSE;
1360     }
1361
1362     traceRETURN_xStreamBufferIsFull( xReturn );
1363
1364     return xReturn;
1365 }
1366 /*-----------------------------------------------------------*/
1367
1368 BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1369                                               BaseType_t * pxHigherPriorityTaskWoken )
1370 {
1371     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1372     BaseType_t xReturn;
1373     UBaseType_t uxSavedInterruptStatus;
1374
1375     traceENTER_xStreamBufferSendCompletedFromISR( xStreamBuffer, pxHigherPriorityTaskWoken );
1376
1377     configASSERT( pxStreamBuffer );
1378
1379     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
1380     {
1381         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
1382         {
1383             ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
1384                                                 ( pxStreamBuffer )->uxNotificationIndex,
1385                                                 ( uint32_t ) 0,
1386                                                 eNoAction,
1387                                                 pxHigherPriorityTaskWoken );
1388             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
1389             xReturn = pdTRUE;
1390         }
1391         else
1392         {
1393             xReturn = pdFALSE;
1394         }
1395     }
1396     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
1397
1398     traceRETURN_xStreamBufferSendCompletedFromISR( xReturn );
1399
1400     return xReturn;
1401 }
1402 /*-----------------------------------------------------------*/
1403
1404 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1405                                                  BaseType_t * pxHigherPriorityTaskWoken )
1406 {
1407     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1408     BaseType_t xReturn;
1409     UBaseType_t uxSavedInterruptStatus;
1410
1411     traceENTER_xStreamBufferReceiveCompletedFromISR( xStreamBuffer, pxHigherPriorityTaskWoken );
1412
1413     configASSERT( pxStreamBuffer );
1414
1415     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
1416     {
1417         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
1418         {
1419             ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
1420                                                 ( pxStreamBuffer )->uxNotificationIndex,
1421                                                 ( uint32_t ) 0,
1422                                                 eNoAction,
1423                                                 pxHigherPriorityTaskWoken );
1424             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
1425             xReturn = pdTRUE;
1426         }
1427         else
1428         {
1429             xReturn = pdFALSE;
1430         }
1431     }
1432     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
1433
1434     traceRETURN_xStreamBufferReceiveCompletedFromISR( xReturn );
1435
1436     return xReturn;
1437 }
1438 /*-----------------------------------------------------------*/
1439
1440 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
1441                                      const uint8_t * pucData,
1442                                      size_t xCount,
1443                                      size_t xHead )
1444 {
1445     size_t xFirstLength;
1446
1447     configASSERT( xCount > ( size_t ) 0 );
1448
1449     /* Calculate the number of bytes that can be added in the first write -
1450      * which may be less than the total number of bytes that need to be added if
1451      * the buffer will wrap back to the beginning. */
1452     xFirstLength = configMIN( pxStreamBuffer->xLength - xHead, xCount );
1453
1454     /* Write as many bytes as can be written in the first write. */
1455     configASSERT( ( xHead + xFirstLength ) <= pxStreamBuffer->xLength );
1456     ( void ) memcpy( ( void * ) ( &( pxStreamBuffer->pucBuffer[ xHead ] ) ), ( const void * ) pucData, xFirstLength );
1457
1458     /* If the number of bytes written was less than the number that could be
1459      * written in the first write... */
1460     if( xCount > xFirstLength )
1461     {
1462         /* ...then write the remaining bytes to the start of the buffer. */
1463         configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength );
1464         ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength );
1465     }
1466     else
1467     {
1468         mtCOVERAGE_TEST_MARKER();
1469     }
1470
1471     xHead += xCount;
1472
1473     if( xHead >= pxStreamBuffer->xLength )
1474     {
1475         xHead -= pxStreamBuffer->xLength;
1476     }
1477     else
1478     {
1479         mtCOVERAGE_TEST_MARKER();
1480     }
1481
1482     return xHead;
1483 }
1484 /*-----------------------------------------------------------*/
1485
1486 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
1487                                       uint8_t * pucData,
1488                                       size_t xCount,
1489                                       size_t xTail )
1490 {
1491     size_t xFirstLength;
1492
1493     configASSERT( xCount != ( size_t ) 0 );
1494
1495     /* Calculate the number of bytes that can be read - which may be
1496      * less than the number wanted if the data wraps around to the start of
1497      * the buffer. */
1498     xFirstLength = configMIN( pxStreamBuffer->xLength - xTail, xCount );
1499
1500     /* Obtain the number of bytes it is possible to obtain in the first
1501      * read.  Asserts check bounds of read and write. */
1502     configASSERT( xFirstLength <= xCount );
1503     configASSERT( ( xTail + xFirstLength ) <= pxStreamBuffer->xLength );
1504     ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xTail ] ), xFirstLength );
1505
1506     /* If the total number of wanted bytes is greater than the number
1507      * that could be read in the first read... */
1508     if( xCount > xFirstLength )
1509     {
1510         /* ...then read the remaining bytes from the start of the buffer. */
1511         ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength );
1512     }
1513     else
1514     {
1515         mtCOVERAGE_TEST_MARKER();
1516     }
1517
1518     /* Move the tail pointer to effectively remove the data read from the buffer. */
1519     xTail += xCount;
1520
1521     if( xTail >= pxStreamBuffer->xLength )
1522     {
1523         xTail -= pxStreamBuffer->xLength;
1524     }
1525
1526     return xTail;
1527 }
1528 /*-----------------------------------------------------------*/
1529
1530 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )
1531 {
1532     /* Returns the distance between xTail and xHead. */
1533     size_t xCount;
1534
1535     xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
1536     xCount -= pxStreamBuffer->xTail;
1537
1538     if( xCount >= pxStreamBuffer->xLength )
1539     {
1540         xCount -= pxStreamBuffer->xLength;
1541     }
1542     else
1543     {
1544         mtCOVERAGE_TEST_MARKER();
1545     }
1546
1547     return xCount;
1548 }
1549 /*-----------------------------------------------------------*/
1550
1551 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
1552                                           uint8_t * const pucBuffer,
1553                                           size_t xBufferSizeBytes,
1554                                           size_t xTriggerLevelBytes,
1555                                           uint8_t ucFlags,
1556                                           StreamBufferCallbackFunction_t pxSendCompletedCallback,
1557                                           StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
1558 {
1559     /* Assert here is deliberately writing to the entire buffer to ensure it can
1560      * be written to without generating exceptions, and is setting the buffer to a
1561      * known value to assist in development/debugging. */
1562     #if ( configASSERT_DEFINED == 1 )
1563     {
1564         /* The value written just has to be identifiable when looking at the
1565          * memory.  Don't use 0xA5 as that is the stack fill value and could
1566          * result in confusion as to what is actually being observed. */
1567         #define STREAM_BUFFER_BUFFER_WRITE_VALUE    ( 0x55 )
1568         configASSERT( memset( pucBuffer, ( int ) STREAM_BUFFER_BUFFER_WRITE_VALUE, xBufferSizeBytes ) == pucBuffer );
1569     }
1570     #endif
1571
1572     ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
1573     pxStreamBuffer->pucBuffer = pucBuffer;
1574     pxStreamBuffer->xLength = xBufferSizeBytes;
1575     pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
1576     pxStreamBuffer->ucFlags = ucFlags;
1577     pxStreamBuffer->uxNotificationIndex = tskDEFAULT_INDEX_TO_NOTIFY;
1578     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
1579     {
1580         pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback;
1581         pxStreamBuffer->pxReceiveCompletedCallback = pxReceiveCompletedCallback;
1582     }
1583     #else
1584     {
1585         /* MISRA Ref 11.1.1 [Object type casting] */
1586         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-111 */
1587         /* coverity[misra_c_2012_rule_11_1_violation] */
1588         ( void ) pxSendCompletedCallback;
1589
1590         /* MISRA Ref 11.1.1 [Object type casting] */
1591         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-111 */
1592         /* coverity[misra_c_2012_rule_11_1_violation] */
1593         ( void ) pxReceiveCompletedCallback;
1594     }
1595     #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
1596 }
1597 /*-----------------------------------------------------------*/
1598
1599 UBaseType_t uxStreamBufferGetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer )
1600 {
1601     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1602
1603     traceENTER_uxStreamBufferGetStreamBufferNotificationIndex( xStreamBuffer );
1604
1605     configASSERT( pxStreamBuffer );
1606
1607     traceRETURN_uxStreamBufferGetStreamBufferNotificationIndex( pxStreamBuffer->uxNotificationIndex );
1608
1609     return pxStreamBuffer->uxNotificationIndex;
1610 }
1611 /*-----------------------------------------------------------*/
1612
1613 void vStreamBufferSetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer,
1614                                                     UBaseType_t uxNotificationIndex )
1615 {
1616     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1617
1618     traceENTER_vStreamBufferSetStreamBufferNotificationIndex( xStreamBuffer, uxNotificationIndex );
1619
1620     configASSERT( pxStreamBuffer );
1621
1622     /* There should be no task waiting otherwise we'd never resume them. */
1623     configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
1624     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
1625
1626     /* Check that the task notification index is valid. */
1627     configASSERT( uxNotificationIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES );
1628
1629     pxStreamBuffer->uxNotificationIndex = uxNotificationIndex;
1630
1631     traceRETURN_vStreamBufferSetStreamBufferNotificationIndex();
1632 }
1633 /*-----------------------------------------------------------*/
1634
1635     #if ( configUSE_TRACE_FACILITY == 1 )
1636
1637     UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )
1638     {
1639         traceENTER_uxStreamBufferGetStreamBufferNumber( xStreamBuffer );
1640
1641         traceRETURN_uxStreamBufferGetStreamBufferNumber( xStreamBuffer->uxStreamBufferNumber );
1642
1643         return xStreamBuffer->uxStreamBufferNumber;
1644     }
1645
1646     #endif /* configUSE_TRACE_FACILITY */
1647 /*-----------------------------------------------------------*/
1648
1649     #if ( configUSE_TRACE_FACILITY == 1 )
1650
1651     void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,
1652                                              UBaseType_t uxStreamBufferNumber )
1653     {
1654         traceENTER_vStreamBufferSetStreamBufferNumber( xStreamBuffer, uxStreamBufferNumber );
1655
1656         xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
1657
1658         traceRETURN_vStreamBufferSetStreamBufferNumber();
1659     }
1660
1661     #endif /* configUSE_TRACE_FACILITY */
1662 /*-----------------------------------------------------------*/
1663
1664     #if ( configUSE_TRACE_FACILITY == 1 )
1665
1666     uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )
1667     {
1668         traceENTER_ucStreamBufferGetStreamBufferType( xStreamBuffer );
1669
1670         traceRETURN_ucStreamBufferGetStreamBufferType( ( uint8_t ) ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) );
1671
1672         return( ( uint8_t ) ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) );
1673     }
1674
1675     #endif /* configUSE_TRACE_FACILITY */
1676 /*-----------------------------------------------------------*/
1677
1678 /* This entire source file will be skipped if the application is not configured
1679  * to include stream buffer functionality. This #if is closed at the very bottom
1680  * of this file. If you want to include stream buffers then ensure
1681  * configUSE_STREAM_BUFFERS is set to 1 in FreeRTOSConfig.h. */
1682 #endif /* configUSE_STREAM_BUFFERS == 1 */