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