]> begriffs open source - freertos/blob - stream_buffer.c
[AUTO][RELEASE]: Bump task.h version macros to "10.4.3 LTS Patch 1"
[freertos] / stream_buffer.c
1 /*\r
2  * FreeRTOS Kernel V10.4.3\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * https://www.FreeRTOS.org\r
23  * https://github.com/FreeRTOS\r
24  *\r
25  */\r
26 \r
27 /* Standard includes. */\r
28 #include <stdint.h>\r
29 #include <string.h>\r
30 \r
31 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
32  * all the API functions to use the MPU wrappers.  That should only be done when\r
33  * task.h is included from an application file. */\r
34 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
35 \r
36 /* FreeRTOS includes. */\r
37 #include "FreeRTOS.h"\r
38 #include "task.h"\r
39 #include "stream_buffer.h"\r
40 \r
41 #if ( configUSE_TASK_NOTIFICATIONS != 1 )\r
42     #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c\r
43 #endif\r
44 \r
45 /* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified\r
46  * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined\r
47  * for the header files above, but not in this file, in order to generate the\r
48  * correct privileged Vs unprivileged linkage and placement. */\r
49 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */\r
50 \r
51 /* If the user has not provided application specific Rx notification macros,\r
52  * or #defined the notification macros away, them provide default implementations\r
53  * that uses task notifications. */\r
54 /*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */\r
55 #ifndef sbRECEIVE_COMPLETED\r
56     #define sbRECEIVE_COMPLETED( pxStreamBuffer )                         \\r
57     vTaskSuspendAll();                                                    \\r
58     {                                                                     \\r
59         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )              \\r
60         {                                                                 \\r
61             ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \\r
62                                   ( uint32_t ) 0,                         \\r
63                                   eNoAction );                            \\r
64             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                \\r
65         }                                                                 \\r
66     }                                                                     \\r
67     ( void ) xTaskResumeAll();\r
68 #endif /* sbRECEIVE_COMPLETED */\r
69 \r
70 #ifndef sbRECEIVE_COMPLETED_FROM_ISR\r
71     #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer,                            \\r
72                                           pxHigherPriorityTaskWoken )                \\r
73     {                                                                                \\r
74         UBaseType_t uxSavedInterruptStatus;                                          \\r
75                                                                                      \\r
76         uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();  \\r
77         {                                                                            \\r
78             if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )                     \\r
79             {                                                                        \\r
80                 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \\r
81                                              ( uint32_t ) 0,                         \\r
82                                              eNoAction,                              \\r
83                                              pxHigherPriorityTaskWoken );            \\r
84                 ( pxStreamBuffer )->xTaskWaitingToSend = NULL;                       \\r
85             }                                                                        \\r
86         }                                                                            \\r
87         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                 \\r
88     }\r
89 #endif /* sbRECEIVE_COMPLETED_FROM_ISR */\r
90 \r
91 /* If the user has not provided an application specific Tx notification macro,\r
92  * or #defined the notification macro away, them provide a default implementation\r
93  * that uses task notifications. */\r
94 #ifndef sbSEND_COMPLETED\r
95     #define sbSEND_COMPLETED( pxStreamBuffer )                               \\r
96     vTaskSuspendAll();                                                       \\r
97     {                                                                        \\r
98         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )              \\r
99         {                                                                    \\r
100             ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \\r
101                                   ( uint32_t ) 0,                            \\r
102                                   eNoAction );                               \\r
103             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                \\r
104         }                                                                    \\r
105     }                                                                        \\r
106     ( void ) xTaskResumeAll();\r
107 #endif /* sbSEND_COMPLETED */\r
108 \r
109 #ifndef sbSEND_COMPLETE_FROM_ISR\r
110     #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken )       \\r
111     {                                                                                   \\r
112         UBaseType_t uxSavedInterruptStatus;                                             \\r
113                                                                                         \\r
114         uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();     \\r
115         {                                                                               \\r
116             if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )                     \\r
117             {                                                                           \\r
118                 ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \\r
119                                              ( uint32_t ) 0,                            \\r
120                                              eNoAction,                                 \\r
121                                              pxHigherPriorityTaskWoken );               \\r
122                 ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;                       \\r
123             }                                                                           \\r
124         }                                                                               \\r
125         portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                    \\r
126     }\r
127 #endif /* sbSEND_COMPLETE_FROM_ISR */\r
128 /*lint -restore (9026) */\r
129 \r
130 /* The number of bytes used to hold the length of a message in the buffer. */\r
131 #define sbBYTES_TO_STORE_MESSAGE_LENGTH    ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) )\r
132 \r
133 /* Bits stored in the ucFlags field of the stream buffer. */\r
134 #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. */\r
135 #define sbFLAGS_IS_STATICALLY_ALLOCATED    ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */\r
136 \r
137 /*-----------------------------------------------------------*/\r
138 \r
139 /* Structure that hold state information on the buffer. */\r
140 typedef struct StreamBufferDef_t                 /*lint !e9058 Style convention uses tag. */\r
141 {\r
142     volatile size_t xTail;                       /* Index to the next item to read within the buffer. */\r
143     volatile size_t xHead;                       /* Index to the next item to write within the buffer. */\r
144     size_t xLength;                              /* The length of the buffer pointed to by pucBuffer. */\r
145     size_t xTriggerLevelBytes;                   /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */\r
146     volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */\r
147     volatile TaskHandle_t xTaskWaitingToSend;    /* Holds the handle of a task waiting to send data to a message buffer that is full. */\r
148     uint8_t * pucBuffer;                         /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */\r
149     uint8_t ucFlags;\r
150 \r
151     #if ( configUSE_TRACE_FACILITY == 1 )\r
152         UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */\r
153     #endif\r
154 } StreamBuffer_t;\r
155 \r
156 /*\r
157  * The number of bytes available to be read from the buffer.\r
158  */\r
159 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION;\r
160 \r
161 /*\r
162  * Add xCount bytes from pucData into the pxStreamBuffer message buffer.\r
163  * Returns the number of bytes written, which will either equal xCount in the\r
164  * success case, or 0 if there was not enough space in the buffer (in which case\r
165  * no data is written into the buffer).\r
166  */\r
167 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,\r
168                                      const uint8_t * pucData,\r
169                                      size_t xCount ) PRIVILEGED_FUNCTION;\r
170 \r
171 /*\r
172  * If the stream buffer is being used as a message buffer, then reads an entire\r
173  * message out of the buffer.  If the stream buffer is being used as a stream\r
174  * buffer then read as many bytes as possible from the buffer.\r
175  * prvReadBytesFromBuffer() is called to actually extract the bytes from the\r
176  * buffer's data storage area.\r
177  */\r
178 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,\r
179                                         void * pvRxData,\r
180                                         size_t xBufferLengthBytes,\r
181                                         size_t xBytesAvailable,\r
182                                         size_t xBytesToStoreMessageLength ) PRIVILEGED_FUNCTION;\r
183 \r
184 /*\r
185  * If the stream buffer is being used as a message buffer, then writes an entire\r
186  * message to the buffer.  If the stream buffer is being used as a stream\r
187  * buffer then write as many bytes as possible to the buffer.\r
188  * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's\r
189  * data storage area.\r
190  */\r
191 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,\r
192                                        const void * pvTxData,\r
193                                        size_t xDataLengthBytes,\r
194                                        size_t xSpace,\r
195                                        size_t xRequiredSpace ) PRIVILEGED_FUNCTION;\r
196 \r
197 /*\r
198  * Read xMaxCount bytes from the pxStreamBuffer message buffer and write them\r
199  * to pucData.\r
200  */\r
201 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,\r
202                                       uint8_t * pucData,\r
203                                       size_t xMaxCount,\r
204                                       size_t xBytesAvailable ) PRIVILEGED_FUNCTION;\r
205 \r
206 /*\r
207  * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to\r
208  * initialise the members of the newly created stream buffer structure.\r
209  */\r
210 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,\r
211                                           uint8_t * const pucBuffer,\r
212                                           size_t xBufferSizeBytes,\r
213                                           size_t xTriggerLevelBytes,\r
214                                           uint8_t ucFlags ) PRIVILEGED_FUNCTION;\r
215 \r
216 /*-----------------------------------------------------------*/\r
217 \r
218 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
219 \r
220     StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,\r
221                                                      size_t xTriggerLevelBytes,\r
222                                                      BaseType_t xIsMessageBuffer )\r
223     {\r
224         uint8_t * pucAllocatedMemory;\r
225         uint8_t ucFlags;\r
226 \r
227         /* In case the stream buffer is going to be used as a message buffer\r
228          * (that is, it will hold discrete messages with a little meta data that\r
229          * says how big the next message is) check the buffer will be large enough\r
230          * to hold at least one message. */\r
231         if( xIsMessageBuffer == pdTRUE )\r
232         {\r
233             /* Is a message buffer but not statically allocated. */\r
234             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER;\r
235             configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );\r
236         }\r
237         else\r
238         {\r
239             /* Not a message buffer and not statically allocated. */\r
240             ucFlags = 0;\r
241             configASSERT( xBufferSizeBytes > 0 );\r
242         }\r
243 \r
244         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );\r
245 \r
246         /* A trigger level of 0 would cause a waiting task to unblock even when\r
247          * the buffer was empty. */\r
248         if( xTriggerLevelBytes == ( size_t ) 0 )\r
249         {\r
250             xTriggerLevelBytes = ( size_t ) 1;\r
251         }\r
252 \r
253         /* A stream buffer requires a StreamBuffer_t structure and a buffer.\r
254          * Both are allocated in a single call to pvPortMalloc().  The\r
255          * StreamBuffer_t structure is placed at the start of the allocated memory\r
256          * and the buffer follows immediately after.  The requested size is\r
257          * incremented so the free space is returned as the user would expect -\r
258          * this is a quirk of the implementation that means otherwise the free\r
259          * space would be reported as one byte smaller than would be logically\r
260          * expected. */\r
261         if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) )\r
262         {\r
263             xBufferSizeBytes++;\r
264             pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */\r
265         }\r
266         else\r
267         {\r
268             pucAllocatedMemory = NULL;\r
269         }\r
270         \r
271 \r
272         if( pucAllocatedMemory != NULL )\r
273         {\r
274             prvInitialiseNewStreamBuffer( ( StreamBuffer_t * ) pucAllocatedMemory,       /* Structure at the start of the allocated memory. */ /*lint !e9087 Safe cast as allocated memory is aligned. */ /*lint !e826 Area is not too small and alignment is guaranteed provided malloc() behaves as expected and returns aligned buffer. */\r
275                                           pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */\r
276                                           xBufferSizeBytes,\r
277                                           xTriggerLevelBytes,\r
278                                           ucFlags );\r
279 \r
280             traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );\r
281         }\r
282         else\r
283         {\r
284             traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );\r
285         }\r
286 \r
287         return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */\r
288     }\r
289 \r
290 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
291 /*-----------------------------------------------------------*/\r
292 \r
293 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )\r
294 \r
295     StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,\r
296                                                            size_t xTriggerLevelBytes,\r
297                                                            BaseType_t xIsMessageBuffer,\r
298                                                            uint8_t * const pucStreamBufferStorageArea,\r
299                                                            StaticStreamBuffer_t * const pxStaticStreamBuffer )\r
300     {\r
301         StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */\r
302         StreamBufferHandle_t xReturn;\r
303         uint8_t ucFlags;\r
304 \r
305         configASSERT( pucStreamBufferStorageArea );\r
306         configASSERT( pxStaticStreamBuffer );\r
307         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );\r
308 \r
309         /* A trigger level of 0 would cause a waiting task to unblock even when\r
310          * the buffer was empty. */\r
311         if( xTriggerLevelBytes == ( size_t ) 0 )\r
312         {\r
313             xTriggerLevelBytes = ( size_t ) 1;\r
314         }\r
315 \r
316         if( xIsMessageBuffer != pdFALSE )\r
317         {\r
318             /* Statically allocated message buffer. */\r
319             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;\r
320         }\r
321         else\r
322         {\r
323             /* Statically allocated stream buffer. */\r
324             ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;\r
325         }\r
326 \r
327         /* In case the stream buffer is going to be used as a message buffer\r
328          * (that is, it will hold discrete messages with a little meta data that\r
329          * says how big the next message is) check the buffer will be large enough\r
330          * to hold at least one message. */\r
331         configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );\r
332 \r
333         #if ( configASSERT_DEFINED == 1 )\r
334             {\r
335                 /* Sanity check that the size of the structure used to declare a\r
336                  * variable of type StaticStreamBuffer_t equals the size of the real\r
337                  * message buffer structure. */\r
338                 volatile size_t xSize = sizeof( StaticStreamBuffer_t );\r
339                 configASSERT( xSize == sizeof( StreamBuffer_t ) );\r
340             } /*lint !e529 xSize is referenced is configASSERT() is defined. */\r
341         #endif /* configASSERT_DEFINED */\r
342 \r
343         if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )\r
344         {\r
345             prvInitialiseNewStreamBuffer( pxStreamBuffer,\r
346                                           pucStreamBufferStorageArea,\r
347                                           xBufferSizeBytes,\r
348                                           xTriggerLevelBytes,\r
349                                           ucFlags );\r
350 \r
351             /* Remember this was statically allocated in case it is ever deleted\r
352              * again. */\r
353             pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;\r
354 \r
355             traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );\r
356 \r
357             xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */\r
358         }\r
359         else\r
360         {\r
361             xReturn = NULL;\r
362             traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );\r
363         }\r
364 \r
365         return xReturn;\r
366     }\r
367 \r
368 #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */\r
369 /*-----------------------------------------------------------*/\r
370 \r
371 void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )\r
372 {\r
373     StreamBuffer_t * pxStreamBuffer = xStreamBuffer;\r
374 \r
375     configASSERT( pxStreamBuffer );\r
376 \r
377     traceSTREAM_BUFFER_DELETE( xStreamBuffer );\r
378 \r
379     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )\r
380     {\r
381         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
382             {\r
383                 /* Both the structure and the buffer were allocated using a single call\r
384                 * to pvPortMalloc(), hence only one call to vPortFree() is required. */\r
385                 vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */\r
386             }\r
387         #else\r
388             {\r
389                 /* Should not be possible to get here, ucFlags must be corrupt.\r
390                  * Force an assert. */\r
391                 configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );\r
392             }\r
393         #endif\r
394     }\r
395     else\r
396     {\r
397         /* The structure and buffer were not allocated dynamically and cannot be\r
398          * freed - just scrub the structure so future use will assert. */\r
399         ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );\r
400     }\r
401 }\r
402 /*-----------------------------------------------------------*/\r
403 \r
404 BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )\r
405 {\r
406     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
407     BaseType_t xReturn = pdFAIL;\r
408 \r
409     #if ( configUSE_TRACE_FACILITY == 1 )\r
410         UBaseType_t uxStreamBufferNumber;\r
411     #endif\r
412 \r
413     configASSERT( pxStreamBuffer );\r
414 \r
415     #if ( configUSE_TRACE_FACILITY == 1 )\r
416         {\r
417             /* Store the stream buffer number so it can be restored after the\r
418              * reset. */\r
419             uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;\r
420         }\r
421     #endif\r
422 \r
423     /* Can only reset a message buffer if there are no tasks blocked on it. */\r
424     taskENTER_CRITICAL();\r
425     {\r
426         if( pxStreamBuffer->xTaskWaitingToReceive == NULL )\r
427         {\r
428             if( pxStreamBuffer->xTaskWaitingToSend == NULL )\r
429             {\r
430                 prvInitialiseNewStreamBuffer( pxStreamBuffer,\r
431                                               pxStreamBuffer->pucBuffer,\r
432                                               pxStreamBuffer->xLength,\r
433                                               pxStreamBuffer->xTriggerLevelBytes,\r
434                                               pxStreamBuffer->ucFlags );\r
435                 xReturn = pdPASS;\r
436 \r
437                 #if ( configUSE_TRACE_FACILITY == 1 )\r
438                     {\r
439                         pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;\r
440                     }\r
441                 #endif\r
442 \r
443                 traceSTREAM_BUFFER_RESET( xStreamBuffer );\r
444             }\r
445         }\r
446     }\r
447     taskEXIT_CRITICAL();\r
448 \r
449     return xReturn;\r
450 }\r
451 /*-----------------------------------------------------------*/\r
452 \r
453 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,\r
454                                          size_t xTriggerLevel )\r
455 {\r
456     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
457     BaseType_t xReturn;\r
458 \r
459     configASSERT( pxStreamBuffer );\r
460 \r
461     /* It is not valid for the trigger level to be 0. */\r
462     if( xTriggerLevel == ( size_t ) 0 )\r
463     {\r
464         xTriggerLevel = ( size_t ) 1;\r
465     }\r
466 \r
467     /* The trigger level is the number of bytes that must be in the stream\r
468      * buffer before a task that is waiting for data is unblocked. */\r
469     if( xTriggerLevel <= pxStreamBuffer->xLength )\r
470     {\r
471         pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;\r
472         xReturn = pdPASS;\r
473     }\r
474     else\r
475     {\r
476         xReturn = pdFALSE;\r
477     }\r
478 \r
479     return xReturn;\r
480 }\r
481 /*-----------------------------------------------------------*/\r
482 \r
483 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )\r
484 {\r
485     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
486     size_t xSpace;\r
487 \r
488     configASSERT( pxStreamBuffer );\r
489 \r
490     xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;\r
491     xSpace -= pxStreamBuffer->xHead;\r
492     xSpace -= ( size_t ) 1;\r
493 \r
494     if( xSpace >= pxStreamBuffer->xLength )\r
495     {\r
496         xSpace -= pxStreamBuffer->xLength;\r
497     }\r
498     else\r
499     {\r
500         mtCOVERAGE_TEST_MARKER();\r
501     }\r
502 \r
503     return xSpace;\r
504 }\r
505 /*-----------------------------------------------------------*/\r
506 \r
507 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )\r
508 {\r
509     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
510     size_t xReturn;\r
511 \r
512     configASSERT( pxStreamBuffer );\r
513 \r
514     xReturn = prvBytesInBuffer( pxStreamBuffer );\r
515     return xReturn;\r
516 }\r
517 /*-----------------------------------------------------------*/\r
518 \r
519 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,\r
520                           const void * pvTxData,\r
521                           size_t xDataLengthBytes,\r
522                           TickType_t xTicksToWait )\r
523 {\r
524     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
525     size_t xReturn, xSpace = 0;\r
526     size_t xRequiredSpace = xDataLengthBytes;\r
527     TimeOut_t xTimeOut;\r
528 \r
529     /* The maximum amount of space a stream buffer will ever report is its length\r
530      * minus 1. */\r
531     const size_t xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;\r
532 \r
533     configASSERT( pvTxData );\r
534     configASSERT( pxStreamBuffer );\r
535 \r
536     /* This send function is used to write to both message buffers and stream\r
537      * buffers.  If this is a message buffer then the space needed must be\r
538      * increased by the amount of bytes needed to store the length of the\r
539      * message. */\r
540     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
541     {\r
542         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
543 \r
544         /* Overflow? */\r
545         configASSERT( xRequiredSpace > xDataLengthBytes );\r
546 \r
547         /* If this is a message buffer then it must be possible to write the\r
548          * whole message. */\r
549         if( xRequiredSpace > xMaxReportedSpace )\r
550         {\r
551             /* The message would not fit even if the entire buffer was empty,\r
552              * so don't wait for space. */\r
553             xTicksToWait = ( TickType_t ) 0;\r
554         }\r
555         else\r
556         {\r
557             mtCOVERAGE_TEST_MARKER();\r
558         }\r
559     }\r
560     else\r
561     {\r
562         /* If this is a stream buffer then it is acceptable to write only part\r
563          * of the message to the buffer.  Cap the length to the total length of\r
564          * the buffer. */\r
565         if( xRequiredSpace > xMaxReportedSpace )\r
566         {\r
567             xRequiredSpace = xMaxReportedSpace;\r
568         }\r
569         else\r
570         {\r
571             mtCOVERAGE_TEST_MARKER();\r
572         }\r
573     }\r
574 \r
575     if( xTicksToWait != ( TickType_t ) 0 )\r
576     {\r
577         vTaskSetTimeOutState( &xTimeOut );\r
578 \r
579         do\r
580         {\r
581             /* Wait until the required number of bytes are free in the message\r
582              * buffer. */\r
583             taskENTER_CRITICAL();\r
584             {\r
585                 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );\r
586 \r
587                 if( xSpace < xRequiredSpace )\r
588                 {\r
589                     /* Clear notification state as going to wait for space. */\r
590                     ( void ) xTaskNotifyStateClear( NULL );\r
591 \r
592                     /* Should only be one writer. */\r
593                     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );\r
594                     pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();\r
595                 }\r
596                 else\r
597                 {\r
598                     taskEXIT_CRITICAL();\r
599                     break;\r
600                 }\r
601             }\r
602             taskEXIT_CRITICAL();\r
603 \r
604             traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );\r
605             ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );\r
606             pxStreamBuffer->xTaskWaitingToSend = NULL;\r
607         } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );\r
608     }\r
609     else\r
610     {\r
611         mtCOVERAGE_TEST_MARKER();\r
612     }\r
613 \r
614     if( xSpace == ( size_t ) 0 )\r
615     {\r
616         xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );\r
617     }\r
618     else\r
619     {\r
620         mtCOVERAGE_TEST_MARKER();\r
621     }\r
622 \r
623     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );\r
624 \r
625     if( xReturn > ( size_t ) 0 )\r
626     {\r
627         traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );\r
628 \r
629         /* Was a task waiting for the data? */\r
630         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )\r
631         {\r
632             sbSEND_COMPLETED( pxStreamBuffer );\r
633         }\r
634         else\r
635         {\r
636             mtCOVERAGE_TEST_MARKER();\r
637         }\r
638     }\r
639     else\r
640     {\r
641         mtCOVERAGE_TEST_MARKER();\r
642         traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );\r
643     }\r
644 \r
645     return xReturn;\r
646 }\r
647 /*-----------------------------------------------------------*/\r
648 \r
649 size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,\r
650                                  const void * pvTxData,\r
651                                  size_t xDataLengthBytes,\r
652                                  BaseType_t * const pxHigherPriorityTaskWoken )\r
653 {\r
654     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
655     size_t xReturn, xSpace;\r
656     size_t xRequiredSpace = xDataLengthBytes;\r
657 \r
658     configASSERT( pvTxData );\r
659     configASSERT( pxStreamBuffer );\r
660 \r
661     /* This send function is used to write to both message buffers and stream\r
662      * buffers.  If this is a message buffer then the space needed must be\r
663      * increased by the amount of bytes needed to store the length of the\r
664      * message. */\r
665     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
666     {\r
667         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
668     }\r
669     else\r
670     {\r
671         mtCOVERAGE_TEST_MARKER();\r
672     }\r
673 \r
674     xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );\r
675     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );\r
676 \r
677     if( xReturn > ( size_t ) 0 )\r
678     {\r
679         /* Was a task waiting for the data? */\r
680         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )\r
681         {\r
682             sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );\r
683         }\r
684         else\r
685         {\r
686             mtCOVERAGE_TEST_MARKER();\r
687         }\r
688     }\r
689     else\r
690     {\r
691         mtCOVERAGE_TEST_MARKER();\r
692     }\r
693 \r
694     traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );\r
695 \r
696     return xReturn;\r
697 }\r
698 /*-----------------------------------------------------------*/\r
699 \r
700 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,\r
701                                        const void * pvTxData,\r
702                                        size_t xDataLengthBytes,\r
703                                        size_t xSpace,\r
704                                        size_t xRequiredSpace )\r
705 {\r
706     BaseType_t xShouldWrite;\r
707     size_t xReturn;\r
708 \r
709     if( xSpace == ( size_t ) 0 )\r
710     {\r
711         /* Doesn't matter if this is a stream buffer or a message buffer, there\r
712          * is no space to write. */\r
713         xShouldWrite = pdFALSE;\r
714     }\r
715     else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 )\r
716     {\r
717         /* This is a stream buffer, as opposed to a message buffer, so writing a\r
718          * stream of bytes rather than discrete messages.  Write as many bytes as\r
719          * possible. */\r
720         xShouldWrite = pdTRUE;\r
721         xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );\r
722     }\r
723     else if( xSpace >= xRequiredSpace )\r
724     {\r
725         /* This is a message buffer, as opposed to a stream buffer, and there\r
726          * is enough space to write both the message length and the message itself\r
727          * into the buffer.  Start by writing the length of the data, the data\r
728          * itself will be written later in this function. */\r
729         xShouldWrite = pdTRUE;\r
730         ( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH );\r
731     }\r
732     else\r
733     {\r
734         /* There is space available, but not enough space. */\r
735         xShouldWrite = pdFALSE;\r
736     }\r
737 \r
738     if( xShouldWrite != pdFALSE )\r
739     {\r
740         /* Writes the data itself. */\r
741         xReturn = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alignment and access. */\r
742     }\r
743     else\r
744     {\r
745         xReturn = 0;\r
746     }\r
747 \r
748     return xReturn;\r
749 }\r
750 /*-----------------------------------------------------------*/\r
751 \r
752 size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,\r
753                              void * pvRxData,\r
754                              size_t xBufferLengthBytes,\r
755                              TickType_t xTicksToWait )\r
756 {\r
757     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
758     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;\r
759 \r
760     configASSERT( pvRxData );\r
761     configASSERT( pxStreamBuffer );\r
762 \r
763     /* This receive function is used by both message buffers, which store\r
764      * discrete messages, and stream buffers, which store a continuous stream of\r
765      * bytes.  Discrete messages include an additional\r
766      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the\r
767      * message. */\r
768     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
769     {\r
770         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
771     }\r
772     else\r
773     {\r
774         xBytesToStoreMessageLength = 0;\r
775     }\r
776 \r
777     if( xTicksToWait != ( TickType_t ) 0 )\r
778     {\r
779         /* Checking if there is data and clearing the notification state must be\r
780          * performed atomically. */\r
781         taskENTER_CRITICAL();\r
782         {\r
783             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
784 \r
785             /* If this function was invoked by a message buffer read then\r
786              * xBytesToStoreMessageLength holds the number of bytes used to hold\r
787              * the length of the next discrete message.  If this function was\r
788              * invoked by a stream buffer read then xBytesToStoreMessageLength will\r
789              * be 0. */\r
790             if( xBytesAvailable <= xBytesToStoreMessageLength )\r
791             {\r
792                 /* Clear notification state as going to wait for data. */\r
793                 ( void ) xTaskNotifyStateClear( NULL );\r
794 \r
795                 /* Should only be one reader. */\r
796                 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );\r
797                 pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();\r
798             }\r
799             else\r
800             {\r
801                 mtCOVERAGE_TEST_MARKER();\r
802             }\r
803         }\r
804         taskEXIT_CRITICAL();\r
805 \r
806         if( xBytesAvailable <= xBytesToStoreMessageLength )\r
807         {\r
808             /* Wait for data to be available. */\r
809             traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );\r
810             ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );\r
811             pxStreamBuffer->xTaskWaitingToReceive = NULL;\r
812 \r
813             /* Recheck the data available after blocking. */\r
814             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
815         }\r
816         else\r
817         {\r
818             mtCOVERAGE_TEST_MARKER();\r
819         }\r
820     }\r
821     else\r
822     {\r
823         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
824     }\r
825 \r
826     /* Whether receiving a discrete message (where xBytesToStoreMessageLength\r
827      * holds the number of bytes used to store the message length) or a stream of\r
828      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes\r
829      * available must be greater than xBytesToStoreMessageLength to be able to\r
830      * read bytes from the buffer. */\r
831     if( xBytesAvailable > xBytesToStoreMessageLength )\r
832     {\r
833         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );\r
834 \r
835         /* Was a task waiting for space in the buffer? */\r
836         if( xReceivedLength != ( size_t ) 0 )\r
837         {\r
838             traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );\r
839             sbRECEIVE_COMPLETED( pxStreamBuffer );\r
840         }\r
841         else\r
842         {\r
843             mtCOVERAGE_TEST_MARKER();\r
844         }\r
845     }\r
846     else\r
847     {\r
848         traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );\r
849         mtCOVERAGE_TEST_MARKER();\r
850     }\r
851 \r
852     return xReceivedLength;\r
853 }\r
854 /*-----------------------------------------------------------*/\r
855 \r
856 size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )\r
857 {\r
858     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
859     size_t xReturn, xBytesAvailable, xOriginalTail;\r
860     configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;\r
861 \r
862     configASSERT( pxStreamBuffer );\r
863 \r
864     /* Ensure the stream buffer is being used as a message buffer. */\r
865     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
866     {\r
867         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
868 \r
869         if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )\r
870         {\r
871             /* The number of bytes available is greater than the number of bytes\r
872              * required to hold the length of the next message, so another message\r
873              * is available.  Return its length without removing the length bytes\r
874              * from the buffer.  A copy of the tail is stored so the buffer can be\r
875              * returned to its prior state as the message is not actually being\r
876              * removed from the buffer. */\r
877             xOriginalTail = pxStreamBuffer->xTail;\r
878             ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable );\r
879             xReturn = ( size_t ) xTempReturn;\r
880             pxStreamBuffer->xTail = xOriginalTail;\r
881         }\r
882         else\r
883         {\r
884             /* The minimum amount of bytes in a message buffer is\r
885              * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is\r
886              * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid\r
887              * value is 0. */\r
888             configASSERT( xBytesAvailable == 0 );\r
889             xReturn = 0;\r
890         }\r
891     }\r
892     else\r
893     {\r
894         xReturn = 0;\r
895     }\r
896 \r
897     return xReturn;\r
898 }\r
899 /*-----------------------------------------------------------*/\r
900 \r
901 size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,\r
902                                     void * pvRxData,\r
903                                     size_t xBufferLengthBytes,\r
904                                     BaseType_t * const pxHigherPriorityTaskWoken )\r
905 {\r
906     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
907     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;\r
908 \r
909     configASSERT( pvRxData );\r
910     configASSERT( pxStreamBuffer );\r
911 \r
912     /* This receive function is used by both message buffers, which store\r
913      * discrete messages, and stream buffers, which store a continuous stream of\r
914      * bytes.  Discrete messages include an additional\r
915      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the\r
916      * message. */\r
917     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
918     {\r
919         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
920     }\r
921     else\r
922     {\r
923         xBytesToStoreMessageLength = 0;\r
924     }\r
925 \r
926     xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
927 \r
928     /* Whether receiving a discrete message (where xBytesToStoreMessageLength\r
929      * holds the number of bytes used to store the message length) or a stream of\r
930      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes\r
931      * available must be greater than xBytesToStoreMessageLength to be able to\r
932      * read bytes from the buffer. */\r
933     if( xBytesAvailable > xBytesToStoreMessageLength )\r
934     {\r
935         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );\r
936 \r
937         /* Was a task waiting for space in the buffer? */\r
938         if( xReceivedLength != ( size_t ) 0 )\r
939         {\r
940             sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );\r
941         }\r
942         else\r
943         {\r
944             mtCOVERAGE_TEST_MARKER();\r
945         }\r
946     }\r
947     else\r
948     {\r
949         mtCOVERAGE_TEST_MARKER();\r
950     }\r
951 \r
952     traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );\r
953 \r
954     return xReceivedLength;\r
955 }\r
956 /*-----------------------------------------------------------*/\r
957 \r
958 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,\r
959                                         void * pvRxData,\r
960                                         size_t xBufferLengthBytes,\r
961                                         size_t xBytesAvailable,\r
962                                         size_t xBytesToStoreMessageLength )\r
963 {\r
964     size_t xOriginalTail, xReceivedLength, xNextMessageLength;\r
965     configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;\r
966 \r
967     if( xBytesToStoreMessageLength != ( size_t ) 0 )\r
968     {\r
969         /* A discrete message is being received.  First receive the length\r
970          * of the message.  A copy of the tail is stored so the buffer can be\r
971          * returned to its prior state if the length of the message is too\r
972          * large for the provided buffer. */\r
973         xOriginalTail = pxStreamBuffer->xTail;\r
974         ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable );\r
975         xNextMessageLength = ( size_t ) xTempNextMessageLength;\r
976 \r
977         /* Reduce the number of bytes available by the number of bytes just\r
978          * read out. */\r
979         xBytesAvailable -= xBytesToStoreMessageLength;\r
980 \r
981         /* Check there is enough space in the buffer provided by the\r
982          * user. */\r
983         if( xNextMessageLength > xBufferLengthBytes )\r
984         {\r
985             /* The user has provided insufficient space to read the message\r
986              * so return the buffer to its previous state (so the length of\r
987              * the message is in the buffer again). */\r
988             pxStreamBuffer->xTail = xOriginalTail;\r
989             xNextMessageLength = 0;\r
990         }\r
991         else\r
992         {\r
993             mtCOVERAGE_TEST_MARKER();\r
994         }\r
995     }\r
996     else\r
997     {\r
998         /* A stream of bytes is being received (as opposed to a discrete\r
999          * message), so read as many bytes as possible. */\r
1000         xNextMessageLength = xBufferLengthBytes;\r
1001     }\r
1002 \r
1003     /* Read the actual data. */\r
1004     xReceivedLength = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xNextMessageLength, xBytesAvailable ); /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */\r
1005 \r
1006     return xReceivedLength;\r
1007 }\r
1008 /*-----------------------------------------------------------*/\r
1009 \r
1010 BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )\r
1011 {\r
1012     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1013     BaseType_t xReturn;\r
1014     size_t xTail;\r
1015 \r
1016     configASSERT( pxStreamBuffer );\r
1017 \r
1018     /* True if no bytes are available. */\r
1019     xTail = pxStreamBuffer->xTail;\r
1020 \r
1021     if( pxStreamBuffer->xHead == xTail )\r
1022     {\r
1023         xReturn = pdTRUE;\r
1024     }\r
1025     else\r
1026     {\r
1027         xReturn = pdFALSE;\r
1028     }\r
1029 \r
1030     return xReturn;\r
1031 }\r
1032 /*-----------------------------------------------------------*/\r
1033 \r
1034 BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )\r
1035 {\r
1036     BaseType_t xReturn;\r
1037     size_t xBytesToStoreMessageLength;\r
1038     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1039 \r
1040     configASSERT( pxStreamBuffer );\r
1041 \r
1042     /* This generic version of the receive function is used by both message\r
1043      * buffers, which store discrete messages, and stream buffers, which store a\r
1044      * continuous stream of bytes.  Discrete messages include an additional\r
1045      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */\r
1046     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
1047     {\r
1048         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
1049     }\r
1050     else\r
1051     {\r
1052         xBytesToStoreMessageLength = 0;\r
1053     }\r
1054 \r
1055     /* True if the available space equals zero. */\r
1056     if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )\r
1057     {\r
1058         xReturn = pdTRUE;\r
1059     }\r
1060     else\r
1061     {\r
1062         xReturn = pdFALSE;\r
1063     }\r
1064 \r
1065     return xReturn;\r
1066 }\r
1067 /*-----------------------------------------------------------*/\r
1068 \r
1069 BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,\r
1070                                               BaseType_t * pxHigherPriorityTaskWoken )\r
1071 {\r
1072     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1073     BaseType_t xReturn;\r
1074     UBaseType_t uxSavedInterruptStatus;\r
1075 \r
1076     configASSERT( pxStreamBuffer );\r
1077 \r
1078     uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();\r
1079     {\r
1080         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )\r
1081         {\r
1082             ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,\r
1083                                          ( uint32_t ) 0,\r
1084                                          eNoAction,\r
1085                                          pxHigherPriorityTaskWoken );\r
1086             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;\r
1087             xReturn = pdTRUE;\r
1088         }\r
1089         else\r
1090         {\r
1091             xReturn = pdFALSE;\r
1092         }\r
1093     }\r
1094     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1095 \r
1096     return xReturn;\r
1097 }\r
1098 /*-----------------------------------------------------------*/\r
1099 \r
1100 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,\r
1101                                                  BaseType_t * pxHigherPriorityTaskWoken )\r
1102 {\r
1103     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1104     BaseType_t xReturn;\r
1105     UBaseType_t uxSavedInterruptStatus;\r
1106 \r
1107     configASSERT( pxStreamBuffer );\r
1108 \r
1109     uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();\r
1110     {\r
1111         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )\r
1112         {\r
1113             ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,\r
1114                                          ( uint32_t ) 0,\r
1115                                          eNoAction,\r
1116                                          pxHigherPriorityTaskWoken );\r
1117             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;\r
1118             xReturn = pdTRUE;\r
1119         }\r
1120         else\r
1121         {\r
1122             xReturn = pdFALSE;\r
1123         }\r
1124     }\r
1125     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1126 \r
1127     return xReturn;\r
1128 }\r
1129 /*-----------------------------------------------------------*/\r
1130 \r
1131 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,\r
1132                                      const uint8_t * pucData,\r
1133                                      size_t xCount )\r
1134 {\r
1135     size_t xNextHead, xFirstLength;\r
1136 \r
1137     configASSERT( xCount > ( size_t ) 0 );\r
1138 \r
1139     xNextHead = pxStreamBuffer->xHead;\r
1140 \r
1141     /* Calculate the number of bytes that can be added in the first write -\r
1142      * which may be less than the total number of bytes that need to be added if\r
1143      * the buffer will wrap back to the beginning. */\r
1144     xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount );\r
1145 \r
1146     /* Write as many bytes as can be written in the first write. */\r
1147     configASSERT( ( xNextHead + xFirstLength ) <= pxStreamBuffer->xLength );\r
1148     ( void ) memcpy( ( void * ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1149 \r
1150     /* If the number of bytes written was less than the number that could be\r
1151      * written in the first write... */\r
1152     if( xCount > xFirstLength )\r
1153     {\r
1154         /* ...then write the remaining bytes to the start of the buffer. */\r
1155         configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength );\r
1156         ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1157     }\r
1158     else\r
1159     {\r
1160         mtCOVERAGE_TEST_MARKER();\r
1161     }\r
1162 \r
1163     xNextHead += xCount;\r
1164 \r
1165     if( xNextHead >= pxStreamBuffer->xLength )\r
1166     {\r
1167         xNextHead -= pxStreamBuffer->xLength;\r
1168     }\r
1169     else\r
1170     {\r
1171         mtCOVERAGE_TEST_MARKER();\r
1172     }\r
1173 \r
1174     pxStreamBuffer->xHead = xNextHead;\r
1175 \r
1176     return xCount;\r
1177 }\r
1178 /*-----------------------------------------------------------*/\r
1179 \r
1180 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,\r
1181                                       uint8_t * pucData,\r
1182                                       size_t xMaxCount,\r
1183                                       size_t xBytesAvailable )\r
1184 {\r
1185     size_t xCount, xFirstLength, xNextTail;\r
1186 \r
1187     /* Use the minimum of the wanted bytes and the available bytes. */\r
1188     xCount = configMIN( xBytesAvailable, xMaxCount );\r
1189 \r
1190     if( xCount > ( size_t ) 0 )\r
1191     {\r
1192         xNextTail = pxStreamBuffer->xTail;\r
1193 \r
1194         /* Calculate the number of bytes that can be read - which may be\r
1195          * less than the number wanted if the data wraps around to the start of\r
1196          * the buffer. */\r
1197         xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount );\r
1198 \r
1199         /* Obtain the number of bytes it is possible to obtain in the first\r
1200          * read.  Asserts check bounds of read and write. */\r
1201         configASSERT( xFirstLength <= xMaxCount );\r
1202         configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength );\r
1203         ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1204 \r
1205         /* If the total number of wanted bytes is greater than the number\r
1206          * that could be read in the first read... */\r
1207         if( xCount > xFirstLength )\r
1208         {\r
1209             /*...then read the remaining bytes from the start of the buffer. */\r
1210             configASSERT( xCount <= xMaxCount );\r
1211             ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1212         }\r
1213         else\r
1214         {\r
1215             mtCOVERAGE_TEST_MARKER();\r
1216         }\r
1217 \r
1218         /* Move the tail pointer to effectively remove the data read from\r
1219          * the buffer. */\r
1220         xNextTail += xCount;\r
1221 \r
1222         if( xNextTail >= pxStreamBuffer->xLength )\r
1223         {\r
1224             xNextTail -= pxStreamBuffer->xLength;\r
1225         }\r
1226 \r
1227         pxStreamBuffer->xTail = xNextTail;\r
1228     }\r
1229     else\r
1230     {\r
1231         mtCOVERAGE_TEST_MARKER();\r
1232     }\r
1233 \r
1234     return xCount;\r
1235 }\r
1236 /*-----------------------------------------------------------*/\r
1237 \r
1238 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )\r
1239 {\r
1240 /* Returns the distance between xTail and xHead. */\r
1241     size_t xCount;\r
1242 \r
1243     xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;\r
1244     xCount -= pxStreamBuffer->xTail;\r
1245 \r
1246     if( xCount >= pxStreamBuffer->xLength )\r
1247     {\r
1248         xCount -= pxStreamBuffer->xLength;\r
1249     }\r
1250     else\r
1251     {\r
1252         mtCOVERAGE_TEST_MARKER();\r
1253     }\r
1254 \r
1255     return xCount;\r
1256 }\r
1257 /*-----------------------------------------------------------*/\r
1258 \r
1259 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,\r
1260                                           uint8_t * const pucBuffer,\r
1261                                           size_t xBufferSizeBytes,\r
1262                                           size_t xTriggerLevelBytes,\r
1263                                           uint8_t ucFlags )\r
1264 {\r
1265     /* Assert here is deliberately writing to the entire buffer to ensure it can\r
1266      * be written to without generating exceptions, and is setting the buffer to a\r
1267      * known value to assist in development/debugging. */\r
1268     #if ( configASSERT_DEFINED == 1 )\r
1269         {\r
1270             /* The value written just has to be identifiable when looking at the\r
1271              * memory.  Don't use 0xA5 as that is the stack fill value and could\r
1272              * result in confusion as to what is actually being observed. */\r
1273             const BaseType_t xWriteValue = 0x55;\r
1274             configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );\r
1275         } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */\r
1276     #endif\r
1277 \r
1278     ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */\r
1279     pxStreamBuffer->pucBuffer = pucBuffer;\r
1280     pxStreamBuffer->xLength = xBufferSizeBytes;\r
1281     pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;\r
1282     pxStreamBuffer->ucFlags = ucFlags;\r
1283 }\r
1284 \r
1285 #if ( configUSE_TRACE_FACILITY == 1 )\r
1286 \r
1287     UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )\r
1288     {\r
1289         return xStreamBuffer->uxStreamBufferNumber;\r
1290     }\r
1291 \r
1292 #endif /* configUSE_TRACE_FACILITY */\r
1293 /*-----------------------------------------------------------*/\r
1294 \r
1295 #if ( configUSE_TRACE_FACILITY == 1 )\r
1296 \r
1297     void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,\r
1298                                              UBaseType_t uxStreamBufferNumber )\r
1299     {\r
1300         xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;\r
1301     }\r
1302 \r
1303 #endif /* configUSE_TRACE_FACILITY */\r
1304 /*-----------------------------------------------------------*/\r
1305 \r
1306 #if ( configUSE_TRACE_FACILITY == 1 )\r
1307 \r
1308     uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )\r
1309     {\r
1310         return( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER );\r
1311     }\r
1312 \r
1313 #endif /* configUSE_TRACE_FACILITY */\r
1314 /*-----------------------------------------------------------*/\r