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