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