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