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