]> begriffs open source - freertos/blob - stream_buffer.c
[AUTO][RELEASE]: Bump file header version to "10.4.2"
[freertos] / stream_buffer.c
1 /*\r
2  * FreeRTOS Kernel V10.4.2\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         xBufferSizeBytes++;\r
262         pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */\r
263 \r
264         if( pucAllocatedMemory != NULL )\r
265         {\r
266             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
267                                           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
268                                           xBufferSizeBytes,\r
269                                           xTriggerLevelBytes,\r
270                                           ucFlags );\r
271 \r
272             traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );\r
273         }\r
274         else\r
275         {\r
276             traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );\r
277         }\r
278 \r
279         return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */\r
280     }\r
281 \r
282 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
283 /*-----------------------------------------------------------*/\r
284 \r
285 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )\r
286 \r
287     StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,\r
288                                                            size_t xTriggerLevelBytes,\r
289                                                            BaseType_t xIsMessageBuffer,\r
290                                                            uint8_t * const pucStreamBufferStorageArea,\r
291                                                            StaticStreamBuffer_t * const pxStaticStreamBuffer )\r
292     {\r
293         StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */\r
294         StreamBufferHandle_t xReturn;\r
295         uint8_t ucFlags;\r
296 \r
297         configASSERT( pucStreamBufferStorageArea );\r
298         configASSERT( pxStaticStreamBuffer );\r
299         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );\r
300 \r
301         /* A trigger level of 0 would cause a waiting task to unblock even when\r
302          * the buffer was empty. */\r
303         if( xTriggerLevelBytes == ( size_t ) 0 )\r
304         {\r
305             xTriggerLevelBytes = ( size_t ) 1;\r
306         }\r
307 \r
308         if( xIsMessageBuffer != pdFALSE )\r
309         {\r
310             /* Statically allocated message buffer. */\r
311             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;\r
312         }\r
313         else\r
314         {\r
315             /* Statically allocated stream buffer. */\r
316             ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;\r
317         }\r
318 \r
319         /* In case the stream buffer is going to be used as a message buffer\r
320          * (that is, it will hold discrete messages with a little meta data that\r
321          * says how big the next message is) check the buffer will be large enough\r
322          * to hold at least one message. */\r
323         configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );\r
324 \r
325         #if ( configASSERT_DEFINED == 1 )\r
326             {\r
327                 /* Sanity check that the size of the structure used to declare a\r
328                  * variable of type StaticStreamBuffer_t equals the size of the real\r
329                  * message buffer structure. */\r
330                 volatile size_t xSize = sizeof( StaticStreamBuffer_t );\r
331                 configASSERT( xSize == sizeof( StreamBuffer_t ) );\r
332             } /*lint !e529 xSize is referenced is configASSERT() is defined. */\r
333         #endif /* configASSERT_DEFINED */\r
334 \r
335         if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )\r
336         {\r
337             prvInitialiseNewStreamBuffer( pxStreamBuffer,\r
338                                           pucStreamBufferStorageArea,\r
339                                           xBufferSizeBytes,\r
340                                           xTriggerLevelBytes,\r
341                                           ucFlags );\r
342 \r
343             /* Remember this was statically allocated in case it is ever deleted\r
344              * again. */\r
345             pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;\r
346 \r
347             traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );\r
348 \r
349             xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */\r
350         }\r
351         else\r
352         {\r
353             xReturn = NULL;\r
354             traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );\r
355         }\r
356 \r
357         return xReturn;\r
358     }\r
359 \r
360 #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )\r
364 {\r
365     StreamBuffer_t * pxStreamBuffer = xStreamBuffer;\r
366 \r
367     configASSERT( pxStreamBuffer );\r
368 \r
369     traceSTREAM_BUFFER_DELETE( xStreamBuffer );\r
370 \r
371     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )\r
372     {\r
373         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
374             {\r
375                 /* Both the structure and the buffer were allocated using a single call\r
376                 * to pvPortMalloc(), hence only one call to vPortFree() is required. */\r
377                 vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */\r
378             }\r
379         #else\r
380             {\r
381                 /* Should not be possible to get here, ucFlags must be corrupt.\r
382                  * Force an assert. */\r
383                 configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );\r
384             }\r
385         #endif\r
386     }\r
387     else\r
388     {\r
389         /* The structure and buffer were not allocated dynamically and cannot be\r
390          * freed - just scrub the structure so future use will assert. */\r
391         ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );\r
392     }\r
393 }\r
394 /*-----------------------------------------------------------*/\r
395 \r
396 BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )\r
397 {\r
398     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
399     BaseType_t xReturn = pdFAIL;\r
400 \r
401     #if ( configUSE_TRACE_FACILITY == 1 )\r
402         UBaseType_t uxStreamBufferNumber;\r
403     #endif\r
404 \r
405     configASSERT( pxStreamBuffer );\r
406 \r
407     #if ( configUSE_TRACE_FACILITY == 1 )\r
408         {\r
409             /* Store the stream buffer number so it can be restored after the\r
410              * reset. */\r
411             uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;\r
412         }\r
413     #endif\r
414 \r
415     /* Can only reset a message buffer if there are no tasks blocked on it. */\r
416     taskENTER_CRITICAL();\r
417     {\r
418         if( pxStreamBuffer->xTaskWaitingToReceive == NULL )\r
419         {\r
420             if( pxStreamBuffer->xTaskWaitingToSend == NULL )\r
421             {\r
422                 prvInitialiseNewStreamBuffer( pxStreamBuffer,\r
423                                               pxStreamBuffer->pucBuffer,\r
424                                               pxStreamBuffer->xLength,\r
425                                               pxStreamBuffer->xTriggerLevelBytes,\r
426                                               pxStreamBuffer->ucFlags );\r
427                 xReturn = pdPASS;\r
428 \r
429                 #if ( configUSE_TRACE_FACILITY == 1 )\r
430                     {\r
431                         pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;\r
432                     }\r
433                 #endif\r
434 \r
435                 traceSTREAM_BUFFER_RESET( xStreamBuffer );\r
436             }\r
437         }\r
438     }\r
439     taskEXIT_CRITICAL();\r
440 \r
441     return xReturn;\r
442 }\r
443 /*-----------------------------------------------------------*/\r
444 \r
445 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,\r
446                                          size_t xTriggerLevel )\r
447 {\r
448     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
449     BaseType_t xReturn;\r
450 \r
451     configASSERT( pxStreamBuffer );\r
452 \r
453     /* It is not valid for the trigger level to be 0. */\r
454     if( xTriggerLevel == ( size_t ) 0 )\r
455     {\r
456         xTriggerLevel = ( size_t ) 1;\r
457     }\r
458 \r
459     /* The trigger level is the number of bytes that must be in the stream\r
460      * buffer before a task that is waiting for data is unblocked. */\r
461     if( xTriggerLevel <= pxStreamBuffer->xLength )\r
462     {\r
463         pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;\r
464         xReturn = pdPASS;\r
465     }\r
466     else\r
467     {\r
468         xReturn = pdFALSE;\r
469     }\r
470 \r
471     return xReturn;\r
472 }\r
473 /*-----------------------------------------------------------*/\r
474 \r
475 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )\r
476 {\r
477     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
478     size_t xSpace;\r
479 \r
480     configASSERT( pxStreamBuffer );\r
481 \r
482     xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;\r
483     xSpace -= pxStreamBuffer->xHead;\r
484     xSpace -= ( size_t ) 1;\r
485 \r
486     if( xSpace >= pxStreamBuffer->xLength )\r
487     {\r
488         xSpace -= pxStreamBuffer->xLength;\r
489     }\r
490     else\r
491     {\r
492         mtCOVERAGE_TEST_MARKER();\r
493     }\r
494 \r
495     return xSpace;\r
496 }\r
497 /*-----------------------------------------------------------*/\r
498 \r
499 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )\r
500 {\r
501     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
502     size_t xReturn;\r
503 \r
504     configASSERT( pxStreamBuffer );\r
505 \r
506     xReturn = prvBytesInBuffer( pxStreamBuffer );\r
507     return xReturn;\r
508 }\r
509 /*-----------------------------------------------------------*/\r
510 \r
511 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,\r
512                           const void * pvTxData,\r
513                           size_t xDataLengthBytes,\r
514                           TickType_t xTicksToWait )\r
515 {\r
516     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
517     size_t xReturn, xSpace = 0;\r
518     size_t xRequiredSpace = xDataLengthBytes;\r
519     TimeOut_t xTimeOut;\r
520 \r
521     /* The maximum amount of space a stream buffer will ever report is its length\r
522      * minus 1. */\r
523     const size_t xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;\r
524 \r
525     configASSERT( pvTxData );\r
526     configASSERT( pxStreamBuffer );\r
527 \r
528     /* This send function is used to write to both message buffers and stream\r
529      * buffers.  If this is a message buffer then the space needed must be\r
530      * increased by the amount of bytes needed to store the length of the\r
531      * message. */\r
532     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
533     {\r
534         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
535 \r
536         /* Overflow? */\r
537         configASSERT( xRequiredSpace > xDataLengthBytes );\r
538 \r
539         /* If this is a message buffer then it must be possible to write the\r
540          * whole message. */\r
541         if( xRequiredSpace > xMaxReportedSpace )\r
542         {\r
543             /* The message would not fit even if the entire buffer was empty,\r
544              * so don't wait for space. */\r
545             xTicksToWait = ( TickType_t ) 0;\r
546         }\r
547         else\r
548         {\r
549             mtCOVERAGE_TEST_MARKER();\r
550         }\r
551     }\r
552     else\r
553     {\r
554         /* If this is a stream buffer then it is acceptable to write only part\r
555          * of the message to the buffer.  Cap the length to the total length of\r
556          * the buffer. */\r
557         if( xRequiredSpace > xMaxReportedSpace )\r
558         {\r
559             xRequiredSpace = xMaxReportedSpace;\r
560         }\r
561         else\r
562         {\r
563             mtCOVERAGE_TEST_MARKER();\r
564         }\r
565     }\r
566 \r
567     if( xTicksToWait != ( TickType_t ) 0 )\r
568     {\r
569         vTaskSetTimeOutState( &xTimeOut );\r
570 \r
571         do\r
572         {\r
573             /* Wait until the required number of bytes are free in the message\r
574              * buffer. */\r
575             taskENTER_CRITICAL();\r
576             {\r
577                 xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );\r
578 \r
579                 if( xSpace < xRequiredSpace )\r
580                 {\r
581                     /* Clear notification state as going to wait for space. */\r
582                     ( void ) xTaskNotifyStateClear( NULL );\r
583 \r
584                     /* Should only be one writer. */\r
585                     configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL );\r
586                     pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle();\r
587                 }\r
588                 else\r
589                 {\r
590                     taskEXIT_CRITICAL();\r
591                     break;\r
592                 }\r
593             }\r
594             taskEXIT_CRITICAL();\r
595 \r
596             traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer );\r
597             ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );\r
598             pxStreamBuffer->xTaskWaitingToSend = NULL;\r
599         } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE );\r
600     }\r
601     else\r
602     {\r
603         mtCOVERAGE_TEST_MARKER();\r
604     }\r
605 \r
606     if( xSpace == ( size_t ) 0 )\r
607     {\r
608         xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );\r
609     }\r
610     else\r
611     {\r
612         mtCOVERAGE_TEST_MARKER();\r
613     }\r
614 \r
615     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );\r
616 \r
617     if( xReturn > ( size_t ) 0 )\r
618     {\r
619         traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn );\r
620 \r
621         /* Was a task waiting for the data? */\r
622         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )\r
623         {\r
624             sbSEND_COMPLETED( pxStreamBuffer );\r
625         }\r
626         else\r
627         {\r
628             mtCOVERAGE_TEST_MARKER();\r
629         }\r
630     }\r
631     else\r
632     {\r
633         mtCOVERAGE_TEST_MARKER();\r
634         traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer );\r
635     }\r
636 \r
637     return xReturn;\r
638 }\r
639 /*-----------------------------------------------------------*/\r
640 \r
641 size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,\r
642                                  const void * pvTxData,\r
643                                  size_t xDataLengthBytes,\r
644                                  BaseType_t * const pxHigherPriorityTaskWoken )\r
645 {\r
646     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
647     size_t xReturn, xSpace;\r
648     size_t xRequiredSpace = xDataLengthBytes;\r
649 \r
650     configASSERT( pvTxData );\r
651     configASSERT( pxStreamBuffer );\r
652 \r
653     /* This send function is used to write to both message buffers and stream\r
654      * buffers.  If this is a message buffer then the space needed must be\r
655      * increased by the amount of bytes needed to store the length of the\r
656      * message. */\r
657     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
658     {\r
659         xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
660     }\r
661     else\r
662     {\r
663         mtCOVERAGE_TEST_MARKER();\r
664     }\r
665 \r
666     xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer );\r
667     xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace );\r
668 \r
669     if( xReturn > ( size_t ) 0 )\r
670     {\r
671         /* Was a task waiting for the data? */\r
672         if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes )\r
673         {\r
674             sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );\r
675         }\r
676         else\r
677         {\r
678             mtCOVERAGE_TEST_MARKER();\r
679         }\r
680     }\r
681     else\r
682     {\r
683         mtCOVERAGE_TEST_MARKER();\r
684     }\r
685 \r
686     traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn );\r
687 \r
688     return xReturn;\r
689 }\r
690 /*-----------------------------------------------------------*/\r
691 \r
692 static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer,\r
693                                        const void * pvTxData,\r
694                                        size_t xDataLengthBytes,\r
695                                        size_t xSpace,\r
696                                        size_t xRequiredSpace )\r
697 {\r
698     BaseType_t xShouldWrite;\r
699     size_t xReturn;\r
700 \r
701     if( xSpace == ( size_t ) 0 )\r
702     {\r
703         /* Doesn't matter if this is a stream buffer or a message buffer, there\r
704          * is no space to write. */\r
705         xShouldWrite = pdFALSE;\r
706     }\r
707     else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 )\r
708     {\r
709         /* This is a stream buffer, as opposed to a message buffer, so writing a\r
710          * stream of bytes rather than discrete messages.  Write as many bytes as\r
711          * possible. */\r
712         xShouldWrite = pdTRUE;\r
713         xDataLengthBytes = configMIN( xDataLengthBytes, xSpace );\r
714     }\r
715     else if( xSpace >= xRequiredSpace )\r
716     {\r
717         /* This is a message buffer, as opposed to a stream buffer, and there\r
718          * is enough space to write both the message length and the message itself\r
719          * into the buffer.  Start by writing the length of the data, the data\r
720          * itself will be written later in this function. */\r
721         xShouldWrite = pdTRUE;\r
722         ( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH );\r
723     }\r
724     else\r
725     {\r
726         /* There is space available, but not enough space. */\r
727         xShouldWrite = pdFALSE;\r
728     }\r
729 \r
730     if( xShouldWrite != pdFALSE )\r
731     {\r
732         /* Writes the data itself. */\r
733         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
734     }\r
735     else\r
736     {\r
737         xReturn = 0;\r
738     }\r
739 \r
740     return xReturn;\r
741 }\r
742 /*-----------------------------------------------------------*/\r
743 \r
744 size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,\r
745                              void * pvRxData,\r
746                              size_t xBufferLengthBytes,\r
747                              TickType_t xTicksToWait )\r
748 {\r
749     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
750     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;\r
751 \r
752     configASSERT( pvRxData );\r
753     configASSERT( pxStreamBuffer );\r
754 \r
755     /* This receive function is used by both message buffers, which store\r
756      * discrete messages, and stream buffers, which store a continuous stream of\r
757      * bytes.  Discrete messages include an additional\r
758      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the\r
759      * message. */\r
760     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
761     {\r
762         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
763     }\r
764     else\r
765     {\r
766         xBytesToStoreMessageLength = 0;\r
767     }\r
768 \r
769     if( xTicksToWait != ( TickType_t ) 0 )\r
770     {\r
771         /* Checking if there is data and clearing the notification state must be\r
772          * performed atomically. */\r
773         taskENTER_CRITICAL();\r
774         {\r
775             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
776 \r
777             /* If this function was invoked by a message buffer read then\r
778              * xBytesToStoreMessageLength holds the number of bytes used to hold\r
779              * the length of the next discrete message.  If this function was\r
780              * invoked by a stream buffer read then xBytesToStoreMessageLength will\r
781              * be 0. */\r
782             if( xBytesAvailable <= xBytesToStoreMessageLength )\r
783             {\r
784                 /* Clear notification state as going to wait for data. */\r
785                 ( void ) xTaskNotifyStateClear( NULL );\r
786 \r
787                 /* Should only be one reader. */\r
788                 configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL );\r
789                 pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle();\r
790             }\r
791             else\r
792             {\r
793                 mtCOVERAGE_TEST_MARKER();\r
794             }\r
795         }\r
796         taskEXIT_CRITICAL();\r
797 \r
798         if( xBytesAvailable <= xBytesToStoreMessageLength )\r
799         {\r
800             /* Wait for data to be available. */\r
801             traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer );\r
802             ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait );\r
803             pxStreamBuffer->xTaskWaitingToReceive = NULL;\r
804 \r
805             /* Recheck the data available after blocking. */\r
806             xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
807         }\r
808         else\r
809         {\r
810             mtCOVERAGE_TEST_MARKER();\r
811         }\r
812     }\r
813     else\r
814     {\r
815         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
816     }\r
817 \r
818     /* Whether receiving a discrete message (where xBytesToStoreMessageLength\r
819      * holds the number of bytes used to store the message length) or a stream of\r
820      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes\r
821      * available must be greater than xBytesToStoreMessageLength to be able to\r
822      * read bytes from the buffer. */\r
823     if( xBytesAvailable > xBytesToStoreMessageLength )\r
824     {\r
825         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );\r
826 \r
827         /* Was a task waiting for space in the buffer? */\r
828         if( xReceivedLength != ( size_t ) 0 )\r
829         {\r
830             traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength );\r
831             sbRECEIVE_COMPLETED( pxStreamBuffer );\r
832         }\r
833         else\r
834         {\r
835             mtCOVERAGE_TEST_MARKER();\r
836         }\r
837     }\r
838     else\r
839     {\r
840         traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer );\r
841         mtCOVERAGE_TEST_MARKER();\r
842     }\r
843 \r
844     return xReceivedLength;\r
845 }\r
846 /*-----------------------------------------------------------*/\r
847 \r
848 size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer )\r
849 {\r
850     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
851     size_t xReturn, xBytesAvailable, xOriginalTail;\r
852     configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn;\r
853 \r
854     configASSERT( pxStreamBuffer );\r
855 \r
856     /* Ensure the stream buffer is being used as a message buffer. */\r
857     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
858     {\r
859         xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
860 \r
861         if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH )\r
862         {\r
863             /* The number of bytes available is greater than the number of bytes\r
864              * required to hold the length of the next message, so another message\r
865              * is available.  Return its length without removing the length bytes\r
866              * from the buffer.  A copy of the tail is stored so the buffer can be\r
867              * returned to its prior state as the message is not actually being\r
868              * removed from the buffer. */\r
869             xOriginalTail = pxStreamBuffer->xTail;\r
870             ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable );\r
871             xReturn = ( size_t ) xTempReturn;\r
872             pxStreamBuffer->xTail = xOriginalTail;\r
873         }\r
874         else\r
875         {\r
876             /* The minimum amount of bytes in a message buffer is\r
877              * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is\r
878              * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid\r
879              * value is 0. */\r
880             configASSERT( xBytesAvailable == 0 );\r
881             xReturn = 0;\r
882         }\r
883     }\r
884     else\r
885     {\r
886         xReturn = 0;\r
887     }\r
888 \r
889     return xReturn;\r
890 }\r
891 /*-----------------------------------------------------------*/\r
892 \r
893 size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,\r
894                                     void * pvRxData,\r
895                                     size_t xBufferLengthBytes,\r
896                                     BaseType_t * const pxHigherPriorityTaskWoken )\r
897 {\r
898     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
899     size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength;\r
900 \r
901     configASSERT( pvRxData );\r
902     configASSERT( pxStreamBuffer );\r
903 \r
904     /* This receive function is used by both message buffers, which store\r
905      * discrete messages, and stream buffers, which store a continuous stream of\r
906      * bytes.  Discrete messages include an additional\r
907      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the\r
908      * message. */\r
909     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
910     {\r
911         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
912     }\r
913     else\r
914     {\r
915         xBytesToStoreMessageLength = 0;\r
916     }\r
917 \r
918     xBytesAvailable = prvBytesInBuffer( pxStreamBuffer );\r
919 \r
920     /* Whether receiving a discrete message (where xBytesToStoreMessageLength\r
921      * holds the number of bytes used to store the message length) or a stream of\r
922      * bytes (where xBytesToStoreMessageLength is zero), the number of bytes\r
923      * available must be greater than xBytesToStoreMessageLength to be able to\r
924      * read bytes from the buffer. */\r
925     if( xBytesAvailable > xBytesToStoreMessageLength )\r
926     {\r
927         xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength );\r
928 \r
929         /* Was a task waiting for space in the buffer? */\r
930         if( xReceivedLength != ( size_t ) 0 )\r
931         {\r
932             sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken );\r
933         }\r
934         else\r
935         {\r
936             mtCOVERAGE_TEST_MARKER();\r
937         }\r
938     }\r
939     else\r
940     {\r
941         mtCOVERAGE_TEST_MARKER();\r
942     }\r
943 \r
944     traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength );\r
945 \r
946     return xReceivedLength;\r
947 }\r
948 /*-----------------------------------------------------------*/\r
949 \r
950 static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer,\r
951                                         void * pvRxData,\r
952                                         size_t xBufferLengthBytes,\r
953                                         size_t xBytesAvailable,\r
954                                         size_t xBytesToStoreMessageLength )\r
955 {\r
956     size_t xOriginalTail, xReceivedLength, xNextMessageLength;\r
957     configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength;\r
958 \r
959     if( xBytesToStoreMessageLength != ( size_t ) 0 )\r
960     {\r
961         /* A discrete message is being received.  First receive the length\r
962          * of the message.  A copy of the tail is stored so the buffer can be\r
963          * returned to its prior state if the length of the message is too\r
964          * large for the provided buffer. */\r
965         xOriginalTail = pxStreamBuffer->xTail;\r
966         ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable );\r
967         xNextMessageLength = ( size_t ) xTempNextMessageLength;\r
968 \r
969         /* Reduce the number of bytes available by the number of bytes just\r
970          * read out. */\r
971         xBytesAvailable -= xBytesToStoreMessageLength;\r
972 \r
973         /* Check there is enough space in the buffer provided by the\r
974          * user. */\r
975         if( xNextMessageLength > xBufferLengthBytes )\r
976         {\r
977             /* The user has provided insufficient space to read the message\r
978              * so return the buffer to its previous state (so the length of\r
979              * the message is in the buffer again). */\r
980             pxStreamBuffer->xTail = xOriginalTail;\r
981             xNextMessageLength = 0;\r
982         }\r
983         else\r
984         {\r
985             mtCOVERAGE_TEST_MARKER();\r
986         }\r
987     }\r
988     else\r
989     {\r
990         /* A stream of bytes is being received (as opposed to a discrete\r
991          * message), so read as many bytes as possible. */\r
992         xNextMessageLength = xBufferLengthBytes;\r
993     }\r
994 \r
995     /* Read the actual data. */\r
996     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
997 \r
998     return xReceivedLength;\r
999 }\r
1000 /*-----------------------------------------------------------*/\r
1001 \r
1002 BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer )\r
1003 {\r
1004     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1005     BaseType_t xReturn;\r
1006     size_t xTail;\r
1007 \r
1008     configASSERT( pxStreamBuffer );\r
1009 \r
1010     /* True if no bytes are available. */\r
1011     xTail = pxStreamBuffer->xTail;\r
1012 \r
1013     if( pxStreamBuffer->xHead == xTail )\r
1014     {\r
1015         xReturn = pdTRUE;\r
1016     }\r
1017     else\r
1018     {\r
1019         xReturn = pdFALSE;\r
1020     }\r
1021 \r
1022     return xReturn;\r
1023 }\r
1024 /*-----------------------------------------------------------*/\r
1025 \r
1026 BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer )\r
1027 {\r
1028     BaseType_t xReturn;\r
1029     size_t xBytesToStoreMessageLength;\r
1030     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1031 \r
1032     configASSERT( pxStreamBuffer );\r
1033 \r
1034     /* This generic version of the receive function is used by both message\r
1035      * buffers, which store discrete messages, and stream buffers, which store a\r
1036      * continuous stream of bytes.  Discrete messages include an additional\r
1037      * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */\r
1038     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 )\r
1039     {\r
1040         xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH;\r
1041     }\r
1042     else\r
1043     {\r
1044         xBytesToStoreMessageLength = 0;\r
1045     }\r
1046 \r
1047     /* True if the available space equals zero. */\r
1048     if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength )\r
1049     {\r
1050         xReturn = pdTRUE;\r
1051     }\r
1052     else\r
1053     {\r
1054         xReturn = pdFALSE;\r
1055     }\r
1056 \r
1057     return xReturn;\r
1058 }\r
1059 /*-----------------------------------------------------------*/\r
1060 \r
1061 BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer,\r
1062                                               BaseType_t * pxHigherPriorityTaskWoken )\r
1063 {\r
1064     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1065     BaseType_t xReturn;\r
1066     UBaseType_t uxSavedInterruptStatus;\r
1067 \r
1068     configASSERT( pxStreamBuffer );\r
1069 \r
1070     uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();\r
1071     {\r
1072         if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL )\r
1073         {\r
1074             ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive,\r
1075                                          ( uint32_t ) 0,\r
1076                                          eNoAction,\r
1077                                          pxHigherPriorityTaskWoken );\r
1078             ( pxStreamBuffer )->xTaskWaitingToReceive = NULL;\r
1079             xReturn = pdTRUE;\r
1080         }\r
1081         else\r
1082         {\r
1083             xReturn = pdFALSE;\r
1084         }\r
1085     }\r
1086     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1087 \r
1088     return xReturn;\r
1089 }\r
1090 /*-----------------------------------------------------------*/\r
1091 \r
1092 BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer,\r
1093                                                  BaseType_t * pxHigherPriorityTaskWoken )\r
1094 {\r
1095     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
1096     BaseType_t xReturn;\r
1097     UBaseType_t uxSavedInterruptStatus;\r
1098 \r
1099     configASSERT( pxStreamBuffer );\r
1100 \r
1101     uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR();\r
1102     {\r
1103         if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL )\r
1104         {\r
1105             ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend,\r
1106                                          ( uint32_t ) 0,\r
1107                                          eNoAction,\r
1108                                          pxHigherPriorityTaskWoken );\r
1109             ( pxStreamBuffer )->xTaskWaitingToSend = NULL;\r
1110             xReturn = pdTRUE;\r
1111         }\r
1112         else\r
1113         {\r
1114             xReturn = pdFALSE;\r
1115         }\r
1116     }\r
1117     portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );\r
1118 \r
1119     return xReturn;\r
1120 }\r
1121 /*-----------------------------------------------------------*/\r
1122 \r
1123 static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer,\r
1124                                      const uint8_t * pucData,\r
1125                                      size_t xCount )\r
1126 {\r
1127     size_t xNextHead, xFirstLength;\r
1128 \r
1129     configASSERT( xCount > ( size_t ) 0 );\r
1130 \r
1131     xNextHead = pxStreamBuffer->xHead;\r
1132 \r
1133     /* Calculate the number of bytes that can be added in the first write -\r
1134      * which may be less than the total number of bytes that need to be added if\r
1135      * the buffer will wrap back to the beginning. */\r
1136     xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount );\r
1137 \r
1138     /* Write as many bytes as can be written in the first write. */\r
1139     configASSERT( ( xNextHead + xFirstLength ) <= pxStreamBuffer->xLength );\r
1140     ( void ) memcpy( ( void * ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1141 \r
1142     /* If the number of bytes written was less than the number that could be\r
1143      * written in the first write... */\r
1144     if( xCount > xFirstLength )\r
1145     {\r
1146         /* ...then write the remaining bytes to the start of the buffer. */\r
1147         configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength );\r
1148         ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1149     }\r
1150     else\r
1151     {\r
1152         mtCOVERAGE_TEST_MARKER();\r
1153     }\r
1154 \r
1155     xNextHead += xCount;\r
1156 \r
1157     if( xNextHead >= pxStreamBuffer->xLength )\r
1158     {\r
1159         xNextHead -= pxStreamBuffer->xLength;\r
1160     }\r
1161     else\r
1162     {\r
1163         mtCOVERAGE_TEST_MARKER();\r
1164     }\r
1165 \r
1166     pxStreamBuffer->xHead = xNextHead;\r
1167 \r
1168     return xCount;\r
1169 }\r
1170 /*-----------------------------------------------------------*/\r
1171 \r
1172 static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer,\r
1173                                       uint8_t * pucData,\r
1174                                       size_t xMaxCount,\r
1175                                       size_t xBytesAvailable )\r
1176 {\r
1177     size_t xCount, xFirstLength, xNextTail;\r
1178 \r
1179     /* Use the minimum of the wanted bytes and the available bytes. */\r
1180     xCount = configMIN( xBytesAvailable, xMaxCount );\r
1181 \r
1182     if( xCount > ( size_t ) 0 )\r
1183     {\r
1184         xNextTail = pxStreamBuffer->xTail;\r
1185 \r
1186         /* Calculate the number of bytes that can be read - which may be\r
1187          * less than the number wanted if the data wraps around to the start of\r
1188          * the buffer. */\r
1189         xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount );\r
1190 \r
1191         /* Obtain the number of bytes it is possible to obtain in the first\r
1192          * read.  Asserts check bounds of read and write. */\r
1193         configASSERT( xFirstLength <= xMaxCount );\r
1194         configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength );\r
1195         ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1196 \r
1197         /* If the total number of wanted bytes is greater than the number\r
1198          * that could be read in the first read... */\r
1199         if( xCount > xFirstLength )\r
1200         {\r
1201             /*...then read the remaining bytes from the start of the buffer. */\r
1202             configASSERT( xCount <= xMaxCount );\r
1203             ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */\r
1204         }\r
1205         else\r
1206         {\r
1207             mtCOVERAGE_TEST_MARKER();\r
1208         }\r
1209 \r
1210         /* Move the tail pointer to effectively remove the data read from\r
1211          * the buffer. */\r
1212         xNextTail += xCount;\r
1213 \r
1214         if( xNextTail >= pxStreamBuffer->xLength )\r
1215         {\r
1216             xNextTail -= pxStreamBuffer->xLength;\r
1217         }\r
1218 \r
1219         pxStreamBuffer->xTail = xNextTail;\r
1220     }\r
1221     else\r
1222     {\r
1223         mtCOVERAGE_TEST_MARKER();\r
1224     }\r
1225 \r
1226     return xCount;\r
1227 }\r
1228 /*-----------------------------------------------------------*/\r
1229 \r
1230 static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer )\r
1231 {\r
1232 /* Returns the distance between xTail and xHead. */\r
1233     size_t xCount;\r
1234 \r
1235     xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead;\r
1236     xCount -= pxStreamBuffer->xTail;\r
1237 \r
1238     if( xCount >= pxStreamBuffer->xLength )\r
1239     {\r
1240         xCount -= pxStreamBuffer->xLength;\r
1241     }\r
1242     else\r
1243     {\r
1244         mtCOVERAGE_TEST_MARKER();\r
1245     }\r
1246 \r
1247     return xCount;\r
1248 }\r
1249 /*-----------------------------------------------------------*/\r
1250 \r
1251 static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,\r
1252                                           uint8_t * const pucBuffer,\r
1253                                           size_t xBufferSizeBytes,\r
1254                                           size_t xTriggerLevelBytes,\r
1255                                           uint8_t ucFlags )\r
1256 {\r
1257     /* Assert here is deliberately writing to the entire buffer to ensure it can\r
1258      * be written to without generating exceptions, and is setting the buffer to a\r
1259      * known value to assist in development/debugging. */\r
1260     #if ( configASSERT_DEFINED == 1 )\r
1261         {\r
1262             /* The value written just has to be identifiable when looking at the\r
1263              * memory.  Don't use 0xA5 as that is the stack fill value and could\r
1264              * result in confusion as to what is actually being observed. */\r
1265             const BaseType_t xWriteValue = 0x55;\r
1266             configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );\r
1267         } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */\r
1268     #endif\r
1269 \r
1270     ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */\r
1271     pxStreamBuffer->pucBuffer = pucBuffer;\r
1272     pxStreamBuffer->xLength = xBufferSizeBytes;\r
1273     pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;\r
1274     pxStreamBuffer->ucFlags = ucFlags;\r
1275 }\r
1276 \r
1277 #if ( configUSE_TRACE_FACILITY == 1 )\r
1278 \r
1279     UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer )\r
1280     {\r
1281         return xStreamBuffer->uxStreamBufferNumber;\r
1282     }\r
1283 \r
1284 #endif /* configUSE_TRACE_FACILITY */\r
1285 /*-----------------------------------------------------------*/\r
1286 \r
1287 #if ( configUSE_TRACE_FACILITY == 1 )\r
1288 \r
1289     void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer,\r
1290                                              UBaseType_t uxStreamBufferNumber )\r
1291     {\r
1292         xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;\r
1293     }\r
1294 \r
1295 #endif /* configUSE_TRACE_FACILITY */\r
1296 /*-----------------------------------------------------------*/\r
1297 \r
1298 #if ( configUSE_TRACE_FACILITY == 1 )\r
1299 \r
1300     uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer )\r
1301     {\r
1302         return( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER );\r
1303     }\r
1304 \r
1305 #endif /* configUSE_TRACE_FACILITY */\r
1306 /*-----------------------------------------------------------*/\r