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