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