]> begriffs open source - freertos/blob - stream_buffer.c
Merge github.com:FreeRTOS/FreeRTOS-Kernel into HEAD
[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, then 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         if( pucAllocatedMemory != NULL )\r
272         {\r
273             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
274                                           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
275                                           xBufferSizeBytes,\r
276                                           xTriggerLevelBytes,\r
277                                           ucFlags );\r
278 \r
279             traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer );\r
280         }\r
281         else\r
282         {\r
283             traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer );\r
284         }\r
285 \r
286         return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */\r
287     }\r
288 \r
289 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */\r
290 /*-----------------------------------------------------------*/\r
291 \r
292 #if ( configSUPPORT_STATIC_ALLOCATION == 1 )\r
293 \r
294     StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,\r
295                                                            size_t xTriggerLevelBytes,\r
296                                                            BaseType_t xIsMessageBuffer,\r
297                                                            uint8_t * const pucStreamBufferStorageArea,\r
298                                                            StaticStreamBuffer_t * const pxStaticStreamBuffer )\r
299     {\r
300         StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */\r
301         StreamBufferHandle_t xReturn;\r
302         uint8_t ucFlags;\r
303 \r
304         configASSERT( pucStreamBufferStorageArea );\r
305         configASSERT( pxStaticStreamBuffer );\r
306         configASSERT( xTriggerLevelBytes <= xBufferSizeBytes );\r
307 \r
308         /* A trigger level of 0 would cause a waiting task to unblock even when\r
309          * the buffer was empty. */\r
310         if( xTriggerLevelBytes == ( size_t ) 0 )\r
311         {\r
312             xTriggerLevelBytes = ( size_t ) 1;\r
313         }\r
314 \r
315         if( xIsMessageBuffer != pdFALSE )\r
316         {\r
317             /* Statically allocated message buffer. */\r
318             ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;\r
319         }\r
320         else\r
321         {\r
322             /* Statically allocated stream buffer. */\r
323             ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;\r
324         }\r
325 \r
326         /* In case the stream buffer is going to be used as a message buffer\r
327          * (that is, it will hold discrete messages with a little meta data that\r
328          * says how big the next message is) check the buffer will be large enough\r
329          * to hold at least one message. */\r
330         configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );\r
331 \r
332         #if ( configASSERT_DEFINED == 1 )\r
333             {\r
334                 /* Sanity check that the size of the structure used to declare a\r
335                  * variable of type StaticStreamBuffer_t equals the size of the real\r
336                  * message buffer structure. */\r
337                 volatile size_t xSize = sizeof( StaticStreamBuffer_t );\r
338                 configASSERT( xSize == sizeof( StreamBuffer_t ) );\r
339             } /*lint !e529 xSize is referenced is configASSERT() is defined. */\r
340         #endif /* configASSERT_DEFINED */\r
341 \r
342         if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )\r
343         {\r
344             prvInitialiseNewStreamBuffer( pxStreamBuffer,\r
345                                           pucStreamBufferStorageArea,\r
346                                           xBufferSizeBytes,\r
347                                           xTriggerLevelBytes,\r
348                                           ucFlags );\r
349 \r
350             /* Remember this was statically allocated in case it is ever deleted\r
351              * again. */\r
352             pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;\r
353 \r
354             traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );\r
355 \r
356             xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */\r
357         }\r
358         else\r
359         {\r
360             xReturn = NULL;\r
361             traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );\r
362         }\r
363 \r
364         return xReturn;\r
365     }\r
366 \r
367 #endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */\r
368 /*-----------------------------------------------------------*/\r
369 \r
370 void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )\r
371 {\r
372     StreamBuffer_t * pxStreamBuffer = xStreamBuffer;\r
373 \r
374     configASSERT( pxStreamBuffer );\r
375 \r
376     traceSTREAM_BUFFER_DELETE( xStreamBuffer );\r
377 \r
378     if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE )\r
379     {\r
380         #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )\r
381             {\r
382                 /* Both the structure and the buffer were allocated using a single call\r
383                 * to pvPortMalloc(), hence only one call to vPortFree() is required. */\r
384                 vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */\r
385             }\r
386         #else\r
387             {\r
388                 /* Should not be possible to get here, ucFlags must be corrupt.\r
389                  * Force an assert. */\r
390                 configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 );\r
391             }\r
392         #endif\r
393     }\r
394     else\r
395     {\r
396         /* The structure and buffer were not allocated dynamically and cannot be\r
397          * freed - just scrub the structure so future use will assert. */\r
398         ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) );\r
399     }\r
400 }\r
401 /*-----------------------------------------------------------*/\r
402 \r
403 BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )\r
404 {\r
405     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
406     BaseType_t xReturn = pdFAIL;\r
407 \r
408     #if ( configUSE_TRACE_FACILITY == 1 )\r
409         UBaseType_t uxStreamBufferNumber;\r
410     #endif\r
411 \r
412     configASSERT( pxStreamBuffer );\r
413 \r
414     #if ( configUSE_TRACE_FACILITY == 1 )\r
415         {\r
416             /* Store the stream buffer number so it can be restored after the\r
417              * reset. */\r
418             uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;\r
419         }\r
420     #endif\r
421 \r
422     /* Can only reset a message buffer if there are no tasks blocked on it. */\r
423     taskENTER_CRITICAL();\r
424     {\r
425         if( pxStreamBuffer->xTaskWaitingToReceive == NULL )\r
426         {\r
427             if( pxStreamBuffer->xTaskWaitingToSend == NULL )\r
428             {\r
429                 prvInitialiseNewStreamBuffer( pxStreamBuffer,\r
430                                               pxStreamBuffer->pucBuffer,\r
431                                               pxStreamBuffer->xLength,\r
432                                               pxStreamBuffer->xTriggerLevelBytes,\r
433                                               pxStreamBuffer->ucFlags );\r
434                 xReturn = pdPASS;\r
435 \r
436                 #if ( configUSE_TRACE_FACILITY == 1 )\r
437                     {\r
438                         pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;\r
439                     }\r
440                 #endif\r
441 \r
442                 traceSTREAM_BUFFER_RESET( xStreamBuffer );\r
443             }\r
444         }\r
445     }\r
446     taskEXIT_CRITICAL();\r
447 \r
448     return xReturn;\r
449 }\r
450 /*-----------------------------------------------------------*/\r
451 \r
452 BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer,\r
453                                          size_t xTriggerLevel )\r
454 {\r
455     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
456     BaseType_t xReturn;\r
457 \r
458     configASSERT( pxStreamBuffer );\r
459 \r
460     /* It is not valid for the trigger level to be 0. */\r
461     if( xTriggerLevel == ( size_t ) 0 )\r
462     {\r
463         xTriggerLevel = ( size_t ) 1;\r
464     }\r
465 \r
466     /* The trigger level is the number of bytes that must be in the stream\r
467      * buffer before a task that is waiting for data is unblocked. */\r
468     if( xTriggerLevel < pxStreamBuffer->xLength )\r
469     {\r
470         pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;\r
471         xReturn = pdPASS;\r
472     }\r
473     else\r
474     {\r
475         xReturn = pdFALSE;\r
476     }\r
477 \r
478     return xReturn;\r
479 }\r
480 /*-----------------------------------------------------------*/\r
481 \r
482 size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer )\r
483 {\r
484     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
485     size_t xSpace;\r
486 \r
487     configASSERT( pxStreamBuffer );\r
488 \r
489     xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail;\r
490     xSpace -= pxStreamBuffer->xHead;\r
491     xSpace -= ( size_t ) 1;\r
492 \r
493     if( xSpace >= pxStreamBuffer->xLength )\r
494     {\r
495         xSpace -= pxStreamBuffer->xLength;\r
496     }\r
497     else\r
498     {\r
499         mtCOVERAGE_TEST_MARKER();\r
500     }\r
501 \r
502     return xSpace;\r
503 }\r
504 /*-----------------------------------------------------------*/\r
505 \r
506 size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer )\r
507 {\r
508     const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
509     size_t xReturn;\r
510 \r
511     configASSERT( pxStreamBuffer );\r
512 \r
513     xReturn = prvBytesInBuffer( pxStreamBuffer );\r
514     return xReturn;\r
515 }\r
516 /*-----------------------------------------------------------*/\r
517 \r
518 size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,\r
519                           const void * pvTxData,\r
520                           size_t xDataLengthBytes,\r
521                           TickType_t xTicksToWait )\r
522 {\r
523     StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;\r
524     size_t xReturn, xSpace = 0;\r
525     size_t xRequiredSpace = xDataLengthBytes;\r
526     TimeOut_t xTimeOut;\r
527     size_t xMaxReportedSpace = 0;\r
528 \r
529     configASSERT( pvTxData );\r
530     configASSERT( pxStreamBuffer );\r
531 \r
532     /* The maximum amount of space a stream buffer will ever report is its length\r
533      * minus 1. */\r
534     xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1;\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