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