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