1 /*
2  * FreeRTOS Kernel V11.1.0
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 )
xStreamBufferGenericCreate(size_t xBufferSizeBytes,size_t xTriggerLevelBytes,BaseType_t xStreamBufferType,StreamBufferCallbackFunction_t pxSendCompletedCallback,StreamBufferCallbackFunction_t pxReceiveCompletedCallback)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 
xStreamBufferGenericCreateStatic(size_t xBufferSizeBytes,size_t xTriggerLevelBytes,BaseType_t xStreamBufferType,uint8_t * const pucStreamBufferStorageArea,StaticStreamBuffer_t * const pxStaticStreamBuffer,StreamBufferCallbackFunction_t pxSendCompletedCallback,StreamBufferCallbackFunction_t pxReceiveCompletedCallback)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 )
xStreamBufferGetStaticBuffers(StreamBufferHandle_t xStreamBuffer,uint8_t ** ppucStreamBufferStorageArea,StaticStreamBuffer_t ** ppxStaticStreamBuffer)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 
vStreamBufferDelete(StreamBufferHandle_t xStreamBuffer)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 
xStreamBufferReset(StreamBufferHandle_t xStreamBuffer)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 
xStreamBufferResetFromISR(StreamBufferHandle_t xStreamBuffer)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     /* MISRA Ref 4.7.1 [Return value shall be checked] */
680     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
681     /* coverity[misra_c_2012_directive_4_7_violation] */
682     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
683     {
684         if( ( pxStreamBuffer->xTaskWaitingToReceive == NULL ) && ( pxStreamBuffer->xTaskWaitingToSend == NULL ) )
685         {
686             #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
687             {
688                 pxSendCallback = pxStreamBuffer->pxSendCompletedCallback;
689                 pxReceiveCallback = pxStreamBuffer->pxReceiveCompletedCallback;
690             }
691             #endif
692 
693             prvInitialiseNewStreamBuffer( pxStreamBuffer,
694                                           pxStreamBuffer->pucBuffer,
695                                           pxStreamBuffer->xLength,
696                                           pxStreamBuffer->xTriggerLevelBytes,
697                                           pxStreamBuffer->ucFlags,
698                                           pxSendCallback,
699                                           pxReceiveCallback );
700 
701             #if ( configUSE_TRACE_FACILITY == 1 )
702             {
703                 pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
704             }
705             #endif
706 
707             traceSTREAM_BUFFER_RESET_FROM_ISR( xStreamBuffer );
708 
709             xReturn = pdPASS;
710         }
711     }
712     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
713 
714     traceRETURN_xStreamBufferResetFromISR( xReturn );
715 
716     return xReturn;
717 }
718 /*-----------------------------------------------------------*/
719 
xStreamBufferSetTriggerLevel(StreamBufferHandle_t xStreamBuffer,size_t xTriggerLevel)720 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,
721                                          size_t xTriggerLevel )
722 {
723     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
724     BaseType_t xReturn;
725 
726     traceENTER_xStreamBufferSetTriggerLevel( xStreamBuffer, xTriggerLevel );
727 
728     configASSERT( pxStreamBuffer );
729 
730     /* It is not valid for the trigger level to be 0. */
731     if( xTriggerLevel == ( size_t ) 0 )
732     {
733         xTriggerLevel = ( size_t ) 1;
734     }
735 
736     /* The trigger level is the number of bytes that must be in the stream
737      * buffer before a task that is waiting for data is unblocked. */
738     if( xTriggerLevel < pxStreamBuffer->xLength )
739     {
740         pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
741         xReturn = pdPASS;
742     }
743     else
744     {
745         xReturn = pdFALSE;
746     }
747 
748     traceRETURN_xStreamBufferSetTriggerLevel( xReturn );
749 
750     return xReturn;
751 }
752 /*-----------------------------------------------------------*/
753 
xStreamBufferSpacesAvailable(StreamBufferHandle_t xStreamBuffer)754 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )
755 {
756     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
757     size_t xSpace;
758     size_t xOriginalTail;
759 
760     traceENTER_xStreamBufferSpacesAvailable( xStreamBuffer );
761 
762     configASSERT( pxStreamBuffer );
763 
764     /* The code below reads xTail and then xHead.  This is safe if the stream
765      * buffer is updated once between the two reads - but not if the stream buffer
766      * is updated more than once between the two reads - hence the loop. */
767     do
768     {
769         xOriginalTail = pxStreamBuffer->xTail;
770         xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;
771         xSpace -= pxStreamBuffer->xHead;
772     } while( xOriginalTail != pxStreamBuffer->xTail );
773 
774     xSpace -= ( size_t ) 1;
775 
776     if( xSpace >= pxStreamBuffer->xLength )
777     {
778         xSpace -= pxStreamBuffer->xLength;
779     }
780     else
781     {
782         mtCOVERAGE_TEST_MARKER();
783     }
784 
785     traceRETURN_xStreamBufferSpacesAvailable( xSpace );
786 
787     return xSpace;
788 }
789 /*-----------------------------------------------------------*/
790 
xStreamBufferBytesAvailable(StreamBufferHandle_t xStreamBuffer)791 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )
792 {
793     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
794     size_t xReturn;
795 
796     traceENTER_xStreamBufferBytesAvailable( xStreamBuffer );
797 
798     configASSERT( pxStreamBuffer );
799 
800     xReturn = prvBytesInBuffer( pxStreamBuffer );
801 
802     traceRETURN_xStreamBufferBytesAvailable( xReturn );
803 
804     return xReturn;
805 }
806 /*-----------------------------------------------------------*/
807 
xStreamBufferSend(StreamBufferHandle_t xStreamBuffer,const void * pvTxData,size_t xDataLengthBytes,TickType_t xTicksToWait)808 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
809                           const void * pvTxData,
810                           size_t xDataLengthBytes,
811                           TickType_t xTicksToWait )
812 {
813     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
814     size_t xReturn, xSpace = 0;
815     size_t xRequiredSpace = xDataLengthBytes;
816     TimeOut_t xTimeOut;
817     size_t xMaxReportedSpace = 0;
818 
819     traceENTER_xStreamBufferSend( xStreamBuffer, pvTxData, xDataLengthBytes, xTicksToWait );
820 
821     configASSERT( pvTxData );
822     configASSERT( pxStreamBuffer );
823 
824     /* The maximum amount of space a stream buffer will ever report is its length
825      * minus 1. */
826     xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;
827 
828     /* This send function is used to write to both message buffers and stream
829      * buffers.  If this is a message buffer then the space needed must be
830      * increased by the amount of bytes needed to store the length of the
831      * message. */
832     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
833     {
834         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
835 
836         /* Overflow? */
837         configASSERT( xRequiredSpace > xDataLengthBytes );
838 
839         /* If this is a message buffer then it must be possible to write the
840          * whole message. */
841         if( xRequiredSpace > xMaxReportedSpace )
842         {
843             /* The message would not fit even if the entire buffer was empty,
844              * so don't wait for space. */
845             xTicksToWait = ( TickType_t ) 0;
846         }
847         else
848         {
849             mtCOVERAGE_TEST_MARKER();
850         }
851     }
852     else
853     {
854         /* If this is a stream buffer then it is acceptable to write only part
855          * of the message to the buffer.  Cap the length to the total length of
856          * the buffer. */
857         if( xRequiredSpace > xMaxReportedSpace )
858         {
859             xRequiredSpace = xMaxReportedSpace;
860         }
861         else
862         {
863             mtCOVERAGE_TEST_MARKER();
864         }
865     }
866 
867     if( xTicksToWait != ( TickType_t ) 0 )
868     {
869         vTaskSetTimeOutState( &xTimeOut );
870 
871         do
872         {
873             /* Wait until the required number of bytes are free in the message
874              * buffer. */
875             taskENTER_CRITICAL();
876             {
877                 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
878 
879                 if( xSpace < xRequiredSpace )
880                 {
881                     /* Clear notification state as going to wait for space. */
882                     ( void ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex );
883 
884                     /* Should only be one writer. */
885                     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
886                     pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();
887                 }
888                 else
889                 {
890                     taskEXIT_CRITICAL();
891                     break;
892                 }
893             }
894             taskEXIT_CRITICAL();
895 
896             traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );
897             ( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
898             pxStreamBuffer->xTaskWaitingToSend = NULL;
899         } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );
900     }
901     else
902     {
903         mtCOVERAGE_TEST_MARKER();
904     }
905 
906     if( xSpace == ( size_t ) 0 )
907     {
908         xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
909     }
910     else
911     {
912         mtCOVERAGE_TEST_MARKER();
913     }
914 
915     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
916 
917     if( xReturn > ( size_t ) 0 )
918     {
919         traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );
920 
921         /* Was a task waiting for the data? */
922         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
923         {
924             prvSEND_COMPLETED( pxStreamBuffer );
925         }
926         else
927         {
928             mtCOVERAGE_TEST_MARKER();
929         }
930     }
931     else
932     {
933         mtCOVERAGE_TEST_MARKER();
934         traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );
935     }
936 
937     traceRETURN_xStreamBufferSend( xReturn );
938 
939     return xReturn;
940 }
941 /*-----------------------------------------------------------*/
942 
xStreamBufferSendFromISR(StreamBufferHandle_t xStreamBuffer,const void * pvTxData,size_t xDataLengthBytes,BaseType_t * const pxHigherPriorityTaskWoken)943 size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
944                                  const void * pvTxData,
945                                  size_t xDataLengthBytes,
946                                  BaseType_t * const pxHigherPriorityTaskWoken )
947 {
948     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
949     size_t xReturn, xSpace;
950     size_t xRequiredSpace = xDataLengthBytes;
951 
952     traceENTER_xStreamBufferSendFromISR( xStreamBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken );
953 
954     configASSERT( pvTxData );
955     configASSERT( pxStreamBuffer );
956 
957     /* This send function is used to write to both message buffers and stream
958      * buffers.  If this is a message buffer then the space needed must be
959      * increased by the amount of bytes needed to store the length of the
960      * message. */
961     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
962     {
963         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;
964     }
965     else
966     {
967         mtCOVERAGE_TEST_MARKER();
968     }
969 
970     xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );
971     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );
972 
973     if( xReturn > ( size_t ) 0 )
974     {
975         /* Was a task waiting for the data? */
976         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )
977         {
978             /* MISRA Ref 4.7.1 [Return value shall be checked] */
979             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
980             /* coverity[misra_c_2012_directive_4_7_violation] */
981             prvSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
982         }
983         else
984         {
985             mtCOVERAGE_TEST_MARKER();
986         }
987     }
988     else
989     {
990         mtCOVERAGE_TEST_MARKER();
991     }
992 
993     traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );
994     traceRETURN_xStreamBufferSendFromISR( xReturn );
995 
996     return xReturn;
997 }
998 /*-----------------------------------------------------------*/
999 
prvWriteMessageToBuffer(StreamBuffer_t * const pxStreamBuffer,const void * pvTxData,size_t xDataLengthBytes,size_t xSpace,size_t xRequiredSpace)1000 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,
1001                                        const void * pvTxData,
1002                                        size_t xDataLengthBytes,
1003                                        size_t xSpace,
1004                                        size_t xRequiredSpace )
1005 {
1006     size_t xNextHead = pxStreamBuffer->xHead;
1007     configMESSAGE_BUFFER_LENGTH_TYPE xMessageLength;
1008 
1009     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1010     {
1011         /* This is a message buffer, as opposed to a stream buffer. */
1012 
1013         /* Convert xDataLengthBytes to the message length type. */
1014         xMessageLength = ( configMESSAGE_BUFFER_LENGTH_TYPE ) xDataLengthBytes;
1015 
1016         /* Ensure the data length given fits within configMESSAGE_BUFFER_LENGTH_TYPE. */
1017         configASSERT( ( size_t ) xMessageLength == xDataLengthBytes );
1018 
1019         if( xSpace >= xRequiredSpace )
1020         {
1021             /* There is enough space to write both the message length and the message
1022              * itself into the buffer.  Start by writing the length of the data, the data
1023              * itself will be written later in this function. */
1024             xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xMessageLength ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead );
1025         }
1026         else
1027         {
1028             /* Not enough space, so do not write data to the buffer. */
1029             xDataLengthBytes = 0;
1030         }
1031     }
1032     else
1033     {
1034         /* This is a stream buffer, as opposed to a message buffer, so writing a
1035          * stream of bytes rather than discrete messages.  Plan to write as many
1036          * bytes as possible. */
1037         xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );
1038     }
1039 
1040     if( xDataLengthBytes != ( size_t ) 0 )
1041     {
1042         /* Write the data to the buffer. */
1043         /* MISRA Ref 11.5.5 [Void pointer assignment] */
1044         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
1045         /* coverity[misra_c_2012_rule_11_5_violation] */
1046         pxStreamBuffer->xHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes, xNextHead );
1047     }
1048 
1049     return xDataLengthBytes;
1050 }
1051 /*-----------------------------------------------------------*/
1052 
xStreamBufferReceive(StreamBufferHandle_t xStreamBuffer,void * pvRxData,size_t xBufferLengthBytes,TickType_t xTicksToWait)1053 size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
1054                              void * pvRxData,
1055                              size_t xBufferLengthBytes,
1056                              TickType_t xTicksToWait )
1057 {
1058     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1059     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
1060 
1061     traceENTER_xStreamBufferReceive( xStreamBuffer, pvRxData, xBufferLengthBytes, xTicksToWait );
1062 
1063     configASSERT( pvRxData );
1064     configASSERT( pxStreamBuffer );
1065 
1066     /* This receive function is used by both message buffers, which store
1067      * discrete messages, and stream buffers, which store a continuous stream of
1068      * bytes.  Discrete messages include an additional
1069      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
1070      * message. */
1071     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1072     {
1073         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1074     }
1075     else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_BATCHING_BUFFER ) != ( uint8_t ) 0 )
1076     {
1077         /* Force task to block if the batching buffer contains less bytes than
1078          * the trigger level. */
1079         xBytesToStoreMessageLength = pxStreamBuffer->xTriggerLevelBytes;
1080     }
1081     else
1082     {
1083         xBytesToStoreMessageLength = 0;
1084     }
1085 
1086     if( xTicksToWait != ( TickType_t ) 0 )
1087     {
1088         /* Checking if there is data and clearing the notification state must be
1089          * performed atomically. */
1090         taskENTER_CRITICAL();
1091         {
1092             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1093 
1094             /* If this function was invoked by a message buffer read then
1095              * xBytesToStoreMessageLength holds the number of bytes used to hold
1096              * the length of the next discrete message.  If this function was
1097              * invoked by a stream buffer read then xBytesToStoreMessageLength will
1098              * be 0. If this function was invoked by a stream batch buffer read
1099              * then xBytesToStoreMessageLength will be xTriggerLevelBytes value
1100              * for the buffer.*/
1101             if( xBytesAvailable <= xBytesToStoreMessageLength )
1102             {
1103                 /* Clear notification state as going to wait for data. */
1104                 ( void ) xTaskNotifyStateClearIndexed( NULL, pxStreamBuffer->uxNotificationIndex );
1105 
1106                 /* Should only be one reader. */
1107                 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
1108                 pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();
1109             }
1110             else
1111             {
1112                 mtCOVERAGE_TEST_MARKER();
1113             }
1114         }
1115         taskEXIT_CRITICAL();
1116 
1117         if( xBytesAvailable <= xBytesToStoreMessageLength )
1118         {
1119             /* Wait for data to be available. */
1120             traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );
1121             ( void ) xTaskNotifyWaitIndexed( pxStreamBuffer->uxNotificationIndex, ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );
1122             pxStreamBuffer->xTaskWaitingToReceive = NULL;
1123 
1124             /* Recheck the data available after blocking. */
1125             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1126         }
1127         else
1128         {
1129             mtCOVERAGE_TEST_MARKER();
1130         }
1131     }
1132     else
1133     {
1134         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1135     }
1136 
1137     /* Whether receiving a discrete message (where xBytesToStoreMessageLength
1138      * holds the number of bytes used to store the message length) or a stream of
1139      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
1140      * available must be greater than xBytesToStoreMessageLength to be able to
1141      * read bytes from the buffer. */
1142     if( xBytesAvailable > xBytesToStoreMessageLength )
1143     {
1144         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
1145 
1146         /* Was a task waiting for space in the buffer? */
1147         if( xReceivedLength != ( size_t ) 0 )
1148         {
1149             traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );
1150             prvRECEIVE_COMPLETED( xStreamBuffer );
1151         }
1152         else
1153         {
1154             mtCOVERAGE_TEST_MARKER();
1155         }
1156     }
1157     else
1158     {
1159         traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );
1160         mtCOVERAGE_TEST_MARKER();
1161     }
1162 
1163     traceRETURN_xStreamBufferReceive( xReceivedLength );
1164 
1165     return xReceivedLength;
1166 }
1167 /*-----------------------------------------------------------*/
1168 
xStreamBufferNextMessageLengthBytes(StreamBufferHandle_t xStreamBuffer)1169 size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )
1170 {
1171     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1172     size_t xReturn, xBytesAvailable;
1173     configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;
1174 
1175     traceENTER_xStreamBufferNextMessageLengthBytes( xStreamBuffer );
1176 
1177     configASSERT( pxStreamBuffer );
1178 
1179     /* Ensure the stream buffer is being used as a message buffer. */
1180     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1181     {
1182         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1183 
1184         if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )
1185         {
1186             /* The number of bytes available is greater than the number of bytes
1187              * required to hold the length of the next message, so another message
1188              * is available. */
1189             ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, pxStreamBuffer->xTail );
1190             xReturn = ( size_t ) xTempReturn;
1191         }
1192         else
1193         {
1194             /* The minimum amount of bytes in a message buffer is
1195              * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is
1196              * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid
1197              * value is 0. */
1198             configASSERT( xBytesAvailable == 0 );
1199             xReturn = 0;
1200         }
1201     }
1202     else
1203     {
1204         xReturn = 0;
1205     }
1206 
1207     traceRETURN_xStreamBufferNextMessageLengthBytes( xReturn );
1208 
1209     return xReturn;
1210 }
1211 /*-----------------------------------------------------------*/
1212 
xStreamBufferReceiveFromISR(StreamBufferHandle_t xStreamBuffer,void * pvRxData,size_t xBufferLengthBytes,BaseType_t * const pxHigherPriorityTaskWoken)1213 size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
1214                                     void * pvRxData,
1215                                     size_t xBufferLengthBytes,
1216                                     BaseType_t * const pxHigherPriorityTaskWoken )
1217 {
1218     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1219     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;
1220 
1221     traceENTER_xStreamBufferReceiveFromISR( xStreamBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken );
1222 
1223     configASSERT( pvRxData );
1224     configASSERT( pxStreamBuffer );
1225 
1226     /* This receive function is used by both message buffers, which store
1227      * discrete messages, and stream buffers, which store a continuous stream of
1228      * bytes.  Discrete messages include an additional
1229      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the
1230      * message. */
1231     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1232     {
1233         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1234     }
1235     else
1236     {
1237         xBytesToStoreMessageLength = 0;
1238     }
1239 
1240     xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );
1241 
1242     /* Whether receiving a discrete message (where xBytesToStoreMessageLength
1243      * holds the number of bytes used to store the message length) or a stream of
1244      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes
1245      * available must be greater than xBytesToStoreMessageLength to be able to
1246      * read bytes from the buffer. */
1247     if( xBytesAvailable > xBytesToStoreMessageLength )
1248     {
1249         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable );
1250 
1251         /* Was a task waiting for space in the buffer? */
1252         if( xReceivedLength != ( size_t ) 0 )
1253         {
1254             /* MISRA Ref 4.7.1 [Return value shall be checked] */
1255             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1256             /* coverity[misra_c_2012_directive_4_7_violation] */
1257             prvRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );
1258         }
1259         else
1260         {
1261             mtCOVERAGE_TEST_MARKER();
1262         }
1263     }
1264     else
1265     {
1266         mtCOVERAGE_TEST_MARKER();
1267     }
1268 
1269     traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );
1270     traceRETURN_xStreamBufferReceiveFromISR( xReceivedLength );
1271 
1272     return xReceivedLength;
1273 }
1274 /*-----------------------------------------------------------*/
1275 
prvReadMessageFromBuffer(StreamBuffer_t * pxStreamBuffer,void * pvRxData,size_t xBufferLengthBytes,size_t xBytesAvailable)1276 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,
1277                                         void * pvRxData,
1278                                         size_t xBufferLengthBytes,
1279                                         size_t xBytesAvailable )
1280 {
1281     size_t xCount, xNextMessageLength;
1282     configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;
1283     size_t xNextTail = pxStreamBuffer->xTail;
1284 
1285     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1286     {
1287         /* A discrete message is being received.  First receive the length
1288          * of the message. */
1289         xNextTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextTail );
1290         xNextMessageLength = ( size_t ) xTempNextMessageLength;
1291 
1292         /* Reduce the number of bytes available by the number of bytes just
1293          * read out. */
1294         xBytesAvailable -= sbBYTES_TO_STORE_MESSAGE_LENGTH;
1295 
1296         /* Check there is enough space in the buffer provided by the
1297          * user. */
1298         if( xNextMessageLength > xBufferLengthBytes )
1299         {
1300             /* The user has provided insufficient space to read the message. */
1301             xNextMessageLength = 0;
1302         }
1303         else
1304         {
1305             mtCOVERAGE_TEST_MARKER();
1306         }
1307     }
1308     else
1309     {
1310         /* A stream of bytes is being received (as opposed to a discrete
1311          * message), so read as many bytes as possible. */
1312         xNextMessageLength = xBufferLengthBytes;
1313     }
1314 
1315     /* Use the minimum of the wanted bytes and the available bytes. */
1316     xCount = configMIN( xNextMessageLength, xBytesAvailable );
1317 
1318     if( xCount != ( size_t ) 0 )
1319     {
1320         /* Read the actual data and update the tail to mark the data as officially consumed. */
1321         /* MISRA Ref 11.5.5 [Void pointer assignment] */
1322         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */
1323         /* coverity[misra_c_2012_rule_11_5_violation] */
1324         pxStreamBuffer->xTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xCount, xNextTail );
1325     }
1326 
1327     return xCount;
1328 }
1329 /*-----------------------------------------------------------*/
1330 
xStreamBufferIsEmpty(StreamBufferHandle_t xStreamBuffer)1331 BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )
1332 {
1333     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1334     BaseType_t xReturn;
1335     size_t xTail;
1336 
1337     traceENTER_xStreamBufferIsEmpty( xStreamBuffer );
1338 
1339     configASSERT( pxStreamBuffer );
1340 
1341     /* True if no bytes are available. */
1342     xTail = pxStreamBuffer->xTail;
1343 
1344     if( pxStreamBuffer->xHead == xTail )
1345     {
1346         xReturn = pdTRUE;
1347     }
1348     else
1349     {
1350         xReturn = pdFALSE;
1351     }
1352 
1353     traceRETURN_xStreamBufferIsEmpty( xReturn );
1354 
1355     return xReturn;
1356 }
1357 /*-----------------------------------------------------------*/
1358 
xStreamBufferIsFull(StreamBufferHandle_t xStreamBuffer)1359 BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )
1360 {
1361     BaseType_t xReturn;
1362     size_t xBytesToStoreMessageLength;
1363     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1364 
1365     traceENTER_xStreamBufferIsFull( xStreamBuffer );
1366 
1367     configASSERT( pxStreamBuffer );
1368 
1369     /* This generic version of the receive function is used by both message
1370      * buffers, which store discrete messages, and stream buffers, which store a
1371      * continuous stream of bytes.  Discrete messages include an additional
1372      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */
1373     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )
1374     {
1375         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;
1376     }
1377     else
1378     {
1379         xBytesToStoreMessageLength = 0;
1380     }
1381 
1382     /* True if the available space equals zero. */
1383     if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )
1384     {
1385         xReturn = pdTRUE;
1386     }
1387     else
1388     {
1389         xReturn = pdFALSE;
1390     }
1391 
1392     traceRETURN_xStreamBufferIsFull( xReturn );
1393 
1394     return xReturn;
1395 }
1396 /*-----------------------------------------------------------*/
1397 
xStreamBufferSendCompletedFromISR(StreamBufferHandle_t xStreamBuffer,BaseType_t * pxHigherPriorityTaskWoken)1398 BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1399                                               BaseType_t * pxHigherPriorityTaskWoken )
1400 {
1401     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1402     BaseType_t xReturn;
1403     UBaseType_t uxSavedInterruptStatus;
1404 
1405     traceENTER_xStreamBufferSendCompletedFromISR( xStreamBuffer, pxHigherPriorityTaskWoken );
1406 
1407     configASSERT( pxStreamBuffer );
1408 
1409     /* MISRA Ref 4.7.1 [Return value shall be checked] */
1410     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1411     /* coverity[misra_c_2012_directive_4_7_violation] */
1412     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
1413     {
1414         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )
1415         {
1416             ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,
1417                                                 ( pxStreamBuffer )->uxNotificationIndex,
1418                                                 ( uint32_t ) 0,
1419                                                 eNoAction,
1420                                                 pxHigherPriorityTaskWoken );
1421             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;
1422             xReturn = pdTRUE;
1423         }
1424         else
1425         {
1426             xReturn = pdFALSE;
1427         }
1428     }
1429     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
1430 
1431     traceRETURN_xStreamBufferSendCompletedFromISR( xReturn );
1432 
1433     return xReturn;
1434 }
1435 /*-----------------------------------------------------------*/
1436 
xStreamBufferReceiveCompletedFromISR(StreamBufferHandle_t xStreamBuffer,BaseType_t * pxHigherPriorityTaskWoken)1437 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,
1438                                                  BaseType_t * pxHigherPriorityTaskWoken )
1439 {
1440     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1441     BaseType_t xReturn;
1442     UBaseType_t uxSavedInterruptStatus;
1443 
1444     traceENTER_xStreamBufferReceiveCompletedFromISR( xStreamBuffer, pxHigherPriorityTaskWoken );
1445 
1446     configASSERT( pxStreamBuffer );
1447 
1448     /* MISRA Ref 4.7.1 [Return value shall be checked] */
1449     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
1450     /* coverity[misra_c_2012_directive_4_7_violation] */
1451     uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
1452     {
1453         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )
1454         {
1455             ( void ) xTaskNotifyIndexedFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,
1456                                                 ( pxStreamBuffer )->uxNotificationIndex,
1457                                                 ( uint32_t ) 0,
1458                                                 eNoAction,
1459                                                 pxHigherPriorityTaskWoken );
1460             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;
1461             xReturn = pdTRUE;
1462         }
1463         else
1464         {
1465             xReturn = pdFALSE;
1466         }
1467     }
1468     taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
1469 
1470     traceRETURN_xStreamBufferReceiveCompletedFromISR( xReturn );
1471 
1472     return xReturn;
1473 }
1474 /*-----------------------------------------------------------*/
1475 
prvWriteBytesToBuffer(StreamBuffer_t * const pxStreamBuffer,const uint8_t * pucData,size_t xCount,size_t xHead)1476 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,
1477                                      const uint8_t * pucData,
1478                                      size_t xCount,
1479                                      size_t xHead )
1480 {
1481     size_t xFirstLength;
1482 
1483     configASSERT( xCount > ( size_t ) 0 );
1484 
1485     /* Calculate the number of bytes that can be added in the first write -
1486      * which may be less than the total number of bytes that need to be added if
1487      * the buffer will wrap back to the beginning. */
1488     xFirstLength = configMIN( pxStreamBuffer->xLength - xHead, xCount );
1489 
1490     /* Write as many bytes as can be written in the first write. */
1491     configASSERT( ( xHead + xFirstLength ) <= pxStreamBuffer->xLength );
1492     ( void ) memcpy( ( void * ) ( &( pxStreamBuffer->pucBuffer[ xHead ] ) ), ( const void * ) pucData, xFirstLength );
1493 
1494     /* If the number of bytes written was less than the number that could be
1495      * written in the first write... */
1496     if( xCount > xFirstLength )
1497     {
1498         /* ...then write the remaining bytes to the start of the buffer. */
1499         configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength );
1500         ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength );
1501     }
1502     else
1503     {
1504         mtCOVERAGE_TEST_MARKER();
1505     }
1506 
1507     xHead += xCount;
1508 
1509     if( xHead >= pxStreamBuffer->xLength )
1510     {
1511         xHead -= pxStreamBuffer->xLength;
1512     }
1513     else
1514     {
1515         mtCOVERAGE_TEST_MARKER();
1516     }
1517 
1518     return xHead;
1519 }
1520 /*-----------------------------------------------------------*/
1521 
prvReadBytesFromBuffer(StreamBuffer_t * pxStreamBuffer,uint8_t * pucData,size_t xCount,size_t xTail)1522 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,
1523                                       uint8_t * pucData,
1524                                       size_t xCount,
1525                                       size_t xTail )
1526 {
1527     size_t xFirstLength;
1528 
1529     configASSERT( xCount != ( size_t ) 0 );
1530 
1531     /* Calculate the number of bytes that can be read - which may be
1532      * less than the number wanted if the data wraps around to the start of
1533      * the buffer. */
1534     xFirstLength = configMIN( pxStreamBuffer->xLength - xTail, xCount );
1535 
1536     /* Obtain the number of bytes it is possible to obtain in the first
1537      * read.  Asserts check bounds of read and write. */
1538     configASSERT( xFirstLength <= xCount );
1539     configASSERT( ( xTail + xFirstLength ) <= pxStreamBuffer->xLength );
1540     ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xTail ] ), xFirstLength );
1541 
1542     /* If the total number of wanted bytes is greater than the number
1543      * that could be read in the first read... */
1544     if( xCount > xFirstLength )
1545     {
1546         /* ...then read the remaining bytes from the start of the buffer. */
1547         ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength );
1548     }
1549     else
1550     {
1551         mtCOVERAGE_TEST_MARKER();
1552     }
1553 
1554     /* Move the tail pointer to effectively remove the data read from the buffer. */
1555     xTail += xCount;
1556 
1557     if( xTail >= pxStreamBuffer->xLength )
1558     {
1559         xTail -= pxStreamBuffer->xLength;
1560     }
1561 
1562     return xTail;
1563 }
1564 /*-----------------------------------------------------------*/
1565 
prvBytesInBuffer(const StreamBuffer_t * const pxStreamBuffer)1566 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )
1567 {
1568     /* Returns the distance between xTail and xHead. */
1569     size_t xCount;
1570 
1571     xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;
1572     xCount -= pxStreamBuffer->xTail;
1573 
1574     if( xCount >= pxStreamBuffer->xLength )
1575     {
1576         xCount -= pxStreamBuffer->xLength;
1577     }
1578     else
1579     {
1580         mtCOVERAGE_TEST_MARKER();
1581     }
1582 
1583     return xCount;
1584 }
1585 /*-----------------------------------------------------------*/
1586 
prvInitialiseNewStreamBuffer(StreamBuffer_t * const pxStreamBuffer,uint8_t * const pucBuffer,size_t xBufferSizeBytes,size_t xTriggerLevelBytes,uint8_t ucFlags,StreamBufferCallbackFunction_t pxSendCompletedCallback,StreamBufferCallbackFunction_t pxReceiveCompletedCallback)1587 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
1588                                           uint8_t * const pucBuffer,
1589                                           size_t xBufferSizeBytes,
1590                                           size_t xTriggerLevelBytes,
1591                                           uint8_t ucFlags,
1592                                           StreamBufferCallbackFunction_t pxSendCompletedCallback,
1593                                           StreamBufferCallbackFunction_t pxReceiveCompletedCallback )
1594 {
1595     /* Assert here is deliberately writing to the entire buffer to ensure it can
1596      * be written to without generating exceptions, and is setting the buffer to a
1597      * known value to assist in development/debugging. */
1598     #if ( configASSERT_DEFINED == 1 )
1599     {
1600         /* The value written just has to be identifiable when looking at the
1601          * memory.  Don't use 0xA5 as that is the stack fill value and could
1602          * result in confusion as to what is actually being observed. */
1603         #define STREAM_BUFFER_BUFFER_WRITE_VALUE    ( 0x55 )
1604         configASSERT( memset( pucBuffer, ( int ) STREAM_BUFFER_BUFFER_WRITE_VALUE, xBufferSizeBytes ) == pucBuffer );
1605     }
1606     #endif
1607 
1608     ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );
1609     pxStreamBuffer->pucBuffer = pucBuffer;
1610     pxStreamBuffer->xLength = xBufferSizeBytes;
1611     pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
1612     pxStreamBuffer->ucFlags = ucFlags;
1613     pxStreamBuffer->uxNotificationIndex = tskDEFAULT_INDEX_TO_NOTIFY;
1614     #if ( configUSE_SB_COMPLETED_CALLBACK == 1 )
1615     {
1616         pxStreamBuffer->pxSendCompletedCallback = pxSendCompletedCallback;
1617         pxStreamBuffer->pxReceiveCompletedCallback = pxReceiveCompletedCallback;
1618     }
1619     #else
1620     {
1621         /* MISRA Ref 11.1.1 [Object type casting] */
1622         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-111 */
1623         /* coverity[misra_c_2012_rule_11_1_violation] */
1624         ( void ) pxSendCompletedCallback;
1625 
1626         /* MISRA Ref 11.1.1 [Object type casting] */
1627         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-111 */
1628         /* coverity[misra_c_2012_rule_11_1_violation] */
1629         ( void ) pxReceiveCompletedCallback;
1630     }
1631     #endif /* if ( configUSE_SB_COMPLETED_CALLBACK == 1 ) */
1632 }
1633 /*-----------------------------------------------------------*/
1634 
uxStreamBufferGetStreamBufferNotificationIndex(StreamBufferHandle_t xStreamBuffer)1635 UBaseType_t uxStreamBufferGetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer )
1636 {
1637     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1638 
1639     traceENTER_uxStreamBufferGetStreamBufferNotificationIndex( xStreamBuffer );
1640 
1641     configASSERT( pxStreamBuffer );
1642 
1643     traceRETURN_uxStreamBufferGetStreamBufferNotificationIndex( pxStreamBuffer->uxNotificationIndex );
1644 
1645     return pxStreamBuffer->uxNotificationIndex;
1646 }
1647 /*-----------------------------------------------------------*/
1648 
vStreamBufferSetStreamBufferNotificationIndex(StreamBufferHandle_t xStreamBuffer,UBaseType_t uxNotificationIndex)1649 void vStreamBufferSetStreamBufferNotificationIndex( StreamBufferHandle_t xStreamBuffer,
1650                                                     UBaseType_t uxNotificationIndex )
1651 {
1652     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
1653 
1654     traceENTER_vStreamBufferSetStreamBufferNotificationIndex( xStreamBuffer, uxNotificationIndex );
1655 
1656     configASSERT( pxStreamBuffer );
1657 
1658     /* There should be no task waiting otherwise we'd never resume them. */
1659     configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );
1660     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );
1661 
1662     /* Check that the task notification index is valid. */
1663     configASSERT( uxNotificationIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES );
1664 
1665     pxStreamBuffer->uxNotificationIndex = uxNotificationIndex;
1666 
1667     traceRETURN_vStreamBufferSetStreamBufferNotificationIndex();
1668 }
1669 /*-----------------------------------------------------------*/
1670 
1671     #if ( configUSE_TRACE_FACILITY == 1 )
1672 
uxStreamBufferGetStreamBufferNumber(StreamBufferHandle_t xStreamBuffer)1673     UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )
1674     {
1675         traceENTER_uxStreamBufferGetStreamBufferNumber( xStreamBuffer );
1676 
1677         traceRETURN_uxStreamBufferGetStreamBufferNumber( xStreamBuffer->uxStreamBufferNumber );
1678 
1679         return xStreamBuffer->uxStreamBufferNumber;
1680     }
1681 
1682     #endif /* configUSE_TRACE_FACILITY */
1683 /*-----------------------------------------------------------*/
1684 
1685     #if ( configUSE_TRACE_FACILITY == 1 )
1686 
vStreamBufferSetStreamBufferNumber(StreamBufferHandle_t xStreamBuffer,UBaseType_t uxStreamBufferNumber)1687     void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,
1688                                              UBaseType_t uxStreamBufferNumber )
1689     {
1690         traceENTER_vStreamBufferSetStreamBufferNumber( xStreamBuffer, uxStreamBufferNumber );
1691 
1692         xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
1693 
1694         traceRETURN_vStreamBufferSetStreamBufferNumber();
1695     }
1696 
1697     #endif /* configUSE_TRACE_FACILITY */
1698 /*-----------------------------------------------------------*/
1699 
1700     #if ( configUSE_TRACE_FACILITY == 1 )
1701 
ucStreamBufferGetStreamBufferType(StreamBufferHandle_t xStreamBuffer)1702     uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )
1703     {
1704         traceENTER_ucStreamBufferGetStreamBufferType( xStreamBuffer );
1705 
1706         traceRETURN_ucStreamBufferGetStreamBufferType( ( uint8_t ) ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) );
1707 
1708         return( ( uint8_t ) ( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) );
1709     }
1710 
1711     #endif /* configUSE_TRACE_FACILITY */
1712 /*-----------------------------------------------------------*/
1713 
1714 /* This entire source file will be skipped if the application is not configured
1715  * to include stream buffer functionality. This #if is closed at the very bottom
1716  * of this file. If you want to include stream buffers then ensure
1717  * configUSE_STREAM_BUFFERS is set to 1 in FreeRTOSConfig.h. */
1718 #endif /* configUSE_STREAM_BUFFERS == 1 */
1719