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