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