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