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