From 5e45472d6ec29d89eb677c8588cfab2038837636 Mon Sep 17 00:00:00 2001 From: Joseph Julicher Date: Wed, 3 Mar 2021 10:38:12 -0700 Subject: [PATCH 01/20] fixed documentation for ulTaskNotifyTake() and ulTaskNotifyTakeIndexed() (#269) --- include/task.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/task.h b/include/task.h index 181ed70fd..d17bef8e7 100644 --- a/include/task.h +++ b/include/task.h @@ -1934,9 +1934,8 @@ uint32_t ulTaskGetIdleRunTimeCounter( void ) PRIVILEGED_FUNCTION; * that way task notifications can be used to send data to a task, or be used as * light weight and fast binary or counting semaphores. * - * A task can use xTaskNotifyWaitIndexed() to [optionally] block to wait for a - * notification to be pending, or ulTaskNotifyTakeIndexed() to [optionally] block - * to wait for a notification value to have a non-zero value. The task does + * A task can use xTaskNotifyWaitIndexed() or ulTaskNotifyTakeIndexed() to + * [optionally] block to wait for a notification to be pending. The task does * not consume any CPU time while it is in the Blocked state. * * A notification sent to a task will remain pending until it is cleared by the @@ -2522,8 +2521,8 @@ void vTaskGenericNotifyGiveFromISR( TaskHandle_t xTaskToNotify, * value acts like a counting semaphore. * * A task can use ulTaskNotifyTakeIndexed() to [optionally] block to wait for - * the task's notification value to be non-zero. The task does not consume any - * CPU time while it is in the Blocked state. + * a notification. The task does not consume any CPU time while it is in the + * Blocked state. * * Where as xTaskNotifyWaitIndexed() will return when a notification is pending, * ulTaskNotifyTakeIndexed() will return when the task's notification value is From 98eba938e2defa4eca516517113e5bfb0c38969f Mon Sep 17 00:00:00 2001 From: xuelix <33909469+xuelix@users.noreply.github.com> Date: Thu, 4 Mar 2021 21:00:22 +0000 Subject: [PATCH 02/20] Added git-secrets check to Github Actions (#270) Co-authored-by: Gary Wicker <14828980+gkwicker@users.noreply.github.com> --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5ff4eefb..cb689b7d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,3 +44,23 @@ jobs: - name: URL Checker run: | bash kernel/.github/actions/url_verifier.sh kernel + + git-secrets: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Checkout awslabs/git-secrets + uses: actions/checkout@v2 + with: + repository: awslabs/git-secrets + ref: master + path: git-secrets + - name: Install git-secrets + run: cd git-secrets && sudo make install && cd .. + - name: Run git-secrets + run: | + git-secrets --register-aws + git-secrets --scan + From 4b5d1e43959e5f4e245c3af708056f6b4b324862 Mon Sep 17 00:00:00 2001 From: alfred gedeon <28123637+alfred2g@users.noreply.github.com> Date: Fri, 5 Mar 2021 09:13:03 -0800 Subject: [PATCH 03/20] Comment: fix code comment for xTaskAbortDelay (#272) --- tasks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks.c b/tasks.c index a994ec908..fd3c25744 100644 --- a/tasks.c +++ b/tasks.c @@ -2694,8 +2694,8 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) #if ( configUSE_PREEMPTION == 1 ) { /* Preemption is on, but a context switch should only be - * performed if the unblocked task has a priority that is - * equal to or higher than the currently executing task. */ + * performed if the unblocked task has a priority that is + * higher than the currently executing task. */ if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) { /* Pend the yield to be performed when the scheduler From de19eeb7d343531496a7e46ca36e10abe3874f02 Mon Sep 17 00:00:00 2001 From: xuelix <33909469+xuelix@users.noreply.github.com> Date: Fri, 5 Mar 2021 22:00:57 +0000 Subject: [PATCH 04/20] Moved git-secrets check to a different workflow (#271) git-secrets check is now performed on all PR branches --- .github/workflows/ci.yml | 19 ------------------- .github/workflows/git-secrets.yml | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/git-secrets.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb689b7d4..50c1b1871 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,22 +45,3 @@ jobs: run: | bash kernel/.github/actions/url_verifier.sh kernel - git-secrets: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Checkout awslabs/git-secrets - uses: actions/checkout@v2 - with: - repository: awslabs/git-secrets - ref: master - path: git-secrets - - name: Install git-secrets - run: cd git-secrets && sudo make install && cd .. - - name: Run git-secrets - run: | - git-secrets --register-aws - git-secrets --scan - diff --git a/.github/workflows/git-secrets.yml b/.github/workflows/git-secrets.yml new file mode 100644 index 000000000..b78a79c45 --- /dev/null +++ b/.github/workflows/git-secrets.yml @@ -0,0 +1,24 @@ +name: git-secrets Check +on: + push: + pull_request: + workflow_dispatch: +jobs: + git-secrets: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Checkout awslabs/git-secrets + uses: actions/checkout@v2 + with: + repository: awslabs/git-secrets + ref: master + path: git-secrets + - name: Install git-secrets + run: cd git-secrets && sudo make install && cd .. + - name: Run git-secrets + run: | + git-secrets --register-aws + git-secrets --scan From 18d4ba9c0792278a4e6351508e3410bdabe98275 Mon Sep 17 00:00:00 2001 From: Paul Bartell Date: Fri, 5 Mar 2021 18:46:49 -0800 Subject: [PATCH 05/20] Add some assertions and coverage exceptions to queue.c (#273) * Add an LCOV_BRANCH exception for the check that sizeof( StaticQueue_t ) == sizeof( Queue_t ) * Add LCOV_BRANCH coverage exception for a configASSERT on pxQueueSetContainer with a condition that is unreachable. * Add configASSERTs to alert when invalid parameters are passed into Queue Registry related functions. * Assert that the semaphore handle passed into xQueueGetMutexHolder is not NULL. * Correct some typos in queue.c * Update lexicon.txt --- .github/lexicon.txt | 6 ++++-- queue.c | 30 ++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/lexicon.txt b/.github/lexicon.txt index 9ffef9ac6..800def74d 100644 --- a/.github/lexicon.txt +++ b/.github/lexicon.txt @@ -1529,6 +1529,7 @@ prvinitialisenewstreambuffer prvinitialisenewtimer prvinsertblockintofreelist prvlockqueue +prvnotifyqueuesetcontainer prvportmalloc prvportresetpic prvprocesssimulatedinterrupts @@ -1631,7 +1632,6 @@ pvyieldevent pwdtc pwm pwmc -pxtaskcode pxblock pxblocktoinsert pxcallbackfunction @@ -1688,6 +1688,7 @@ pxprevious pxpreviouswaketime pxqueue pxqueuebuffer +pxqueuesetcontainer pxramstack pxreadycoroutinelists pxreadytaskslists @@ -1707,6 +1708,7 @@ pxstreambuffercreatestatic pxtagvalue pxtask pxtaskbuffer +pxtaskcode pxtaskdefinition pxtaskstatus pxtaskstatusarray @@ -2653,7 +2655,6 @@ wu www wwwfreertos wxr -xtasktodelete xa xaa xaaaa @@ -3020,6 +3021,7 @@ xtaskswaitingforbits xtaskswaitingtermination xtaskswaitingtoreceive xtaskswaitingtosend +xtasktodelete xtasktonotify xtasktoquery xtasktoresume diff --git a/queue.c b/queue.c index 7ed8e9878..6805cd050 100644 --- a/queue.c +++ b/queue.c @@ -342,8 +342,10 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, * variable of type StaticQueue_t or StaticSemaphore_t equals the size of * the real queue and semaphore structures. */ volatile size_t xSize = sizeof( StaticQueue_t ); - configASSERT( xSize == sizeof( Queue_t ) ); - ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ + + /* This assertion cannot be branch covered in unit tests */ + configASSERT( xSize == sizeof( Queue_t ) ); /* LCOV_EXCL_BR_LINE */ + ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ } #endif /* configASSERT_DEFINED */ @@ -398,7 +400,7 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue, configASSERT( ( uxItemSize == 0 ) || ( uxQueueLength == ( xQueueSizeInBytes / uxItemSize ) ) ); /* Check for addition overflow. */ - configASSERT( ( sizeof( Queue_t ) + xQueueSizeInBytes ) > xQueueSizeInBytes ); + configASSERT( ( sizeof( Queue_t ) + xQueueSizeInBytes ) > xQueueSizeInBytes ); /* Allocate the queue and storage area. Justification for MISRA * deviation as follows: pvPortMalloc() always ensures returned memory @@ -561,6 +563,8 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, TaskHandle_t pxReturn; Queue_t * const pxSemaphore = ( Queue_t * ) xSemaphore; + configASSERT( xSemaphore ); + /* This function is called by xSemaphoreGetMutexHolder(), and should not * be called directly. Note: This is a good way of determining if the * calling task is the mutex holder, but not a good way of determining the @@ -944,15 +948,15 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); /* Unlocking the queue means queue events can effect the - * event list. It is possible that interrupts occurring now + * event list. It is possible that interrupts occurring now * remove this task from the event list again - but as the * scheduler is suspended the task will go onto the pending - * ready last instead of the actual ready list. */ + * ready list instead of the actual ready list. */ prvUnlockQueue( pxQueue ); /* Resuming the scheduler will move tasks from the pending * ready list into the ready list - so it is feasible that this - * task is already in a ready list before it yields - in which + * task is already in the ready list before it yields - in which * case the yield will not cause a context switch unless there * is also a higher priority task in the pending ready list. */ if( xTaskResumeAll() == pdFALSE ) @@ -1774,7 +1778,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue, taskEXIT_CRITICAL(); /* Interrupts and other tasks can send to and receive from the queue - * now the critical section has been exited. */ + * now that the critical section has been exited. */ vTaskSuspendAll(); prvLockQueue( pxQueue ); @@ -2723,6 +2727,9 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) { UBaseType_t ux; + configASSERT( xQueue ); + configASSERT( pcQueueName ); + /* See if there is an empty space in the registry. A NULL name denotes * a free slot. */ for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) @@ -2753,6 +2760,8 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) UBaseType_t ux; const char * pcReturn = NULL; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + configASSERT( xQueue ); + /* Note there is nothing here to protect against another task adding or * removing entries from the registry while it is being searched. */ @@ -2781,6 +2790,8 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) { UBaseType_t ux; + configASSERT( xQueue ); + /* See if the handle of the queue being unregistered in actually in the * registry. */ for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ ) @@ -2967,7 +2978,10 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue ) /* This function must be called form a critical section. */ - configASSERT( pxQueueSetContainer ); + /* The following line is not reachable in unit tests because every call + * to prvNotifyQueueSetContainer is preceded by a check that + * pxQueueSetContainer != NULL */ + configASSERT( pxQueueSetContainer ); /* LCOV_EXCL_BR_LINE */ configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ); if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) From 66b3f908df957ab2fc6ccd40dc309465ec4ec267 Mon Sep 17 00:00:00 2001 From: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Fri, 12 Mar 2021 12:11:19 -0800 Subject: [PATCH 06/20] Update comment in list.c (#276) The tick interrupt priority must be configured to ensure that it cannot interrupt a critical section. This change updates the comment to help the application writer while debugging. Signed-off-by: Gaurav Aggarwal --- list.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/list.c b/list.c index 17a4e903e..d1a59649e 100644 --- a/list.c +++ b/list.c @@ -158,6 +158,9 @@ void vListInsert( List_t * const pxList, * 4) Using a queue or semaphore before it has been initialised or * before the scheduler has been started (are interrupts firing * before vTaskStartScheduler() has been called?). + * 5) If the FreeRTOS port supports interrupt nesting then ensure that + * the priority of the tick interrupt is at or below + * configMAX_SYSCALL_INTERRUPT_PRIORITY. **********************************************************************/ for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */ From 755daad276d349496100fe542a6978e152f6964e Mon Sep 17 00:00:00 2001 From: Ravishankar Bhagavandas Date: Mon, 15 Mar 2021 18:01:42 -0700 Subject: [PATCH 07/20] Improve comments and assertions in stream buffer (#277) * Improve comments and assertions in stream buffer * Add back null check instead of assert * Adding config assert back --- stream_buffer.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stream_buffer.c b/stream_buffer.c index 5c6a47e2c..0c4f429ce 100644 --- a/stream_buffer.c +++ b/stream_buffer.c @@ -49,7 +49,7 @@ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ /* If the user has not provided application specific Rx notification macros, - * or #defined the notification macros away, them provide default implementations + * or #defined the notification macros away, then provide default implementations * that uses task notifications. */ /*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */ #ifndef sbRECEIVE_COMPLETED @@ -267,7 +267,6 @@ static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, { pucAllocatedMemory = NULL; } - if( pucAllocatedMemory != NULL ) { @@ -466,7 +465,7 @@ BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, /* The trigger level is the number of bytes that must be in the stream * buffer before a task that is waiting for data is unblocked. */ - if( xTriggerLevel <= pxStreamBuffer->xLength ) + if( xTriggerLevel < pxStreamBuffer->xLength ) { pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel; xReturn = pdPASS; @@ -525,14 +524,15 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, size_t xReturn, xSpace = 0; size_t xRequiredSpace = xDataLengthBytes; TimeOut_t xTimeOut; - - /* The maximum amount of space a stream buffer will ever report is its length - * minus 1. */ - const size_t xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1; + size_t xMaxReportedSpace = 0; configASSERT( pvTxData ); configASSERT( pxStreamBuffer ); + /* The maximum amount of space a stream buffer will ever report is its length + * minus 1. */ + xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1; + /* This send function is used to write to both message buffers and stream * buffers. If this is a message buffer then the space needed must be * increased by the amount of bytes needed to store the length of the From 95433d02848af0d274648ae4cdd846f6eff76dde Mon Sep 17 00:00:00 2001 From: Paul Bartell Date: Tue, 16 Mar 2021 18:31:37 -0700 Subject: [PATCH 08/20] Run CMock unit tests on each pull request with a github action. (#279) Run CMock unit tests on each pull request with a github action. Include coverage information reported by codecov.io --- .github/workflows/unit-tests.yml | 56 ++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/unit-tests.yml diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 000000000..7c4fa8ffb --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,56 @@ +name: CMock Unit Tests +on: [push] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - name: Checkout Parent Repo + uses: actions/checkout@v2 + with: + ref: master + repository: FreeRTOS/FreeRTOS + submodules: 'recursive' + fetch-depth: 1 + - name: Clone This Repo + uses: actions/checkout@v2 + with: + path: ./FreeRTOS/Source + + - name: Setup Python + uses: actions/setup-python@master + with: + python-version: 3.8 + + - name: Install packages + run: | + sudo apt-get install lcov cflow ruby doxygen build-essential + - name: Run Unit Tests with ENABLE_SANITIZER=1 + run: | + make -C FreeRTOS/Test/CMock clean + make -C FreeRTOS/Test/CMock ENABLE_SANITIZER=1 run_col_formatted + - name: Run Unit Tests for coverage + run: | + make -C FreeRTOS/Test/CMock clean + make -C FreeRTOS/Test/CMock lcovhtml + lcov --config-file FreeRTOS/Test/CMock/lcovrc --summary FreeRTOS/Test/CMock/build/cmock_test.info > FreeRTOS/Test/CMock/build/cmock_test_summary.txt + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + files: FreeRTOS/Test/CMock/build/cmock_test.info + working-directory: . + root_dir: FreeRTOS/Source + flags: unittests + fail_ci_if_error: false + path_to_write_report: coverage/codecov_report.txt + verbose: false + - name: Archive code coverage data + uses: actions/upload-artifact@v2 + with: + name: coverage-data + path: FreeRTOS/Test/CMock/build/cmock_test* + - name: Archive code coverage html report + uses: actions/upload-artifact@v2 + with: + name: coverage-report + path: FreeRTOS/Test/CMock/build/coverage From 1059b35838f2cf47599960b104ab416c535b3eb4 Mon Sep 17 00:00:00 2001 From: alfred gedeon <28123637+alfred2g@users.noreply.github.com> Date: Fri, 19 Mar 2021 10:36:17 -0700 Subject: [PATCH 09/20] Comment: xTaskResumeAll: comment: doesn't match the code (#281) --- tasks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks.c b/tasks.c index fd3c25744..988e32bdb 100644 --- a/tasks.c +++ b/tasks.c @@ -2238,8 +2238,8 @@ BaseType_t xTaskResumeAll( void ) ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); - /* If the moved task has a priority higher than the current - * task then a yield must be performed. */ + /* If the moved task has a priority higher than or equal to + * the current task then a yield must be performed. */ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ) { xYieldPending = pdTRUE; From 49c38f08deaec3204c46555679abdd1bb95a5ce4 Mon Sep 17 00:00:00 2001 From: carlo-dev-git <79503870+carlo-dev-git@users.noreply.github.com> Date: Fri, 19 Mar 2021 23:22:22 +0100 Subject: [PATCH 10/20] Update port.c (#283) --- portable/RVDS/ARM_CM7/r0p1/port.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/portable/RVDS/ARM_CM7/r0p1/port.c b/portable/RVDS/ARM_CM7/r0p1/port.c index 25e5f5aad..93c8bd59b 100644 --- a/portable/RVDS/ARM_CM7/r0p1/port.c +++ b/portable/RVDS/ARM_CM7/r0p1/port.c @@ -762,10 +762,10 @@ __asm uint32_t vPortGetIPSR( void ) * be set to a value equal to or numerically *higher* than * configMAX_SYSCALL_INTERRUPT_PRIORITY. * - * Interrupts that use the FreeRTOS API must not be left at their - * default priority of zero as that is the highest possible priority, + * Interrupts that use the FreeRTOS API must not be left at their + * default priority of zero as that is the highest possible priority, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, - * and therefore also guaranteed to be invalid. + * and therefore also guaranteed to be invalid. * * FreeRTOS maintains separate thread and ISR API functions to ensure * interrupt entry is as fast and simple as possible. From cb7bef09f2e9d9b891737828a598ee5eec8ef118 Mon Sep 17 00:00:00 2001 From: Tobias Schulte Date: Fri, 19 Mar 2021 23:35:21 +0100 Subject: [PATCH 11/20] Adjust portPOINTER_SIZE_TYPE to correct size (#275) * Adjust portPOINTER_SIZE_TYPE to correct size portPOINTER_SIZE_TYPE wasn't yet set correctly to be 16 bit * Fixed FreeRTOS file header to comply with automatic checks Co-authored-by: Cobus van Eeden <35851496+cobusve@users.noreply.github.com> --- portable/GCC/ATMega323/portmacro.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/portable/GCC/ATMega323/portmacro.h b/portable/GCC/ATMega323/portmacro.h index 482fc8ea6..d02e39ea0 100644 --- a/portable/GCC/ATMega323/portmacro.h +++ b/portable/GCC/ATMega323/portmacro.h @@ -22,7 +22,6 @@ * https://www.FreeRTOS.org * https://github.com/FreeRTOS * - * 1 tab == 4 spaces! */ /* @@ -58,6 +57,8 @@ extern "C" { #define portSTACK_TYPE uint8_t #define portBASE_TYPE char +#define portPOINTER_SIZE_TYPE uint16_t + typedef portSTACK_TYPE StackType_t; typedef signed char BaseType_t; typedef unsigned char UBaseType_t; From 9706a69850031c3f4152601152593460a13ff96c Mon Sep 17 00:00:00 2001 From: alfred gedeon <28123637+alfred2g@users.noreply.github.com> Date: Fri, 19 Mar 2021 17:44:12 -0700 Subject: [PATCH 12/20] Fix: testing for mpu wrapers to be equal to 1 (#285) --- include/mpu_wrappers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mpu_wrappers.h b/include/mpu_wrappers.h index a5c081ff7..6550c1e6a 100644 --- a/include/mpu_wrappers.h +++ b/include/mpu_wrappers.h @@ -29,7 +29,7 @@ /* This file redefines API functions to be called through a wrapper macro, but * only for ports that are using the MPU. */ -#ifdef portUSING_MPU_WRAPPERS +#if ( portUSING_MPU_WRAPPERS == 1 ) /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is * included from queue.c or task.c to prevent it from having an effect within From 086d52f9d31677986c9df7721b488fdff86ade69 Mon Sep 17 00:00:00 2001 From: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Sat, 20 Mar 2021 11:58:07 -0700 Subject: [PATCH 13/20] A recent change in the FreeRTOS/FreeRTOS hub repo (which submodules this repo) introduced use of a new compile time constant configRUN_ADDITIONAL_TESTS. This check in adds a default for the constant that will be used in builds to which it does not apply. (#266) --- include/FreeRTOS.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h index 957325875..6c3e82646 100644 --- a/include/FreeRTOS.h +++ b/include/FreeRTOS.h @@ -1059,6 +1059,11 @@ #define configRUN_FREERTOS_SECURE_ONLY 0 #endif +#ifndef configRUN_ADDITIONAL_TESTS + #define configRUN_ADDITIONAL_TESTS 0 +#endif + + /* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using * dynamically allocated RAM, in which case when any task is deleted it is known * that both the task's stack and TCB need to be freed. Sometimes the From 6685c042cb3b3811e2965d3dce59c42e4566648f Mon Sep 17 00:00:00 2001 From: milesfrain Date: Sat, 20 Mar 2021 12:03:27 -0700 Subject: [PATCH 14/20] Fix race condition bugs when reading and writing to message buffers (#264) * Fix inaccuracies in prvWriteBytesToBuffer description * Perform atomic message write in prvWriteMessageToBuffer * Remove unnecessary length arg from prvReadMessageFromBuffer * Perform atomic message read in prvReadBytesFromBuffer * Apply SpacesAvailable() fix Original author: RichardBarry * Apply review feedback * Edit some prv functions for simplicity and consistency - prvWriteMessageToBuffer - prvReadMessageFromBuffer - prvWriteBytesToBuffer - prvReadBytesFromBuffer * Significant simplification of prvWriteMessageToBuffer * fixup off-by-one comment indentation Co-authored-by: alfred gedeon <28123637+alfred2g@users.noreply.github.com> Co-authored-by: RichardBarry <3073890+RichardBarry@users.noreply.github.com> --- stream_buffer.c | 2619 +++++++++++++++++++++++------------------------ 1 file changed, 1305 insertions(+), 1314 deletions(-) diff --git a/stream_buffer.c b/stream_buffer.c index 0c4f429ce..382dd08e6 100644 --- a/stream_buffer.c +++ b/stream_buffer.c @@ -1,1314 +1,1305 @@ -/* - * FreeRTOS Kernel V10.4.3 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * https://www.FreeRTOS.org - * https://github.com/FreeRTOS - * - */ - -/* Standard includes. */ -#include -#include - -/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining - * all the API functions to use the MPU wrappers. That should only be done when - * task.h is included from an application file. */ -#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE - -/* FreeRTOS includes. */ -#include "FreeRTOS.h" -#include "task.h" -#include "stream_buffer.h" - -#if ( configUSE_TASK_NOTIFICATIONS != 1 ) - #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c -#endif - -/* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified - * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined - * for the header files above, but not in this file, in order to generate the - * correct privileged Vs unprivileged linkage and placement. */ -#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ - -/* If the user has not provided application specific Rx notification macros, - * or #defined the notification macros away, then provide default implementations - * that uses task notifications. */ -/*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */ -#ifndef sbRECEIVE_COMPLETED - #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \ - vTaskSuspendAll(); \ - { \ - if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ - { \ - ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \ - ( uint32_t ) 0, \ - eNoAction ); \ - ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ - } \ - } \ - ( void ) xTaskResumeAll(); -#endif /* sbRECEIVE_COMPLETED */ - -#ifndef sbRECEIVE_COMPLETED_FROM_ISR - #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \ - pxHigherPriorityTaskWoken ) \ - { \ - UBaseType_t uxSavedInterruptStatus; \ - \ - uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ - { \ - if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ - { \ - ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \ - ( uint32_t ) 0, \ - eNoAction, \ - pxHigherPriorityTaskWoken ); \ - ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ - } \ - } \ - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ - } -#endif /* sbRECEIVE_COMPLETED_FROM_ISR */ - -/* If the user has not provided an application specific Tx notification macro, - * or #defined the notification macro away, them provide a default implementation - * that uses task notifications. */ -#ifndef sbSEND_COMPLETED - #define sbSEND_COMPLETED( pxStreamBuffer ) \ - vTaskSuspendAll(); \ - { \ - if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ - { \ - ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \ - ( uint32_t ) 0, \ - eNoAction ); \ - ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ - } \ - } \ - ( void ) xTaskResumeAll(); -#endif /* sbSEND_COMPLETED */ - -#ifndef sbSEND_COMPLETE_FROM_ISR - #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \ - { \ - UBaseType_t uxSavedInterruptStatus; \ - \ - uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ - { \ - if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ - { \ - ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \ - ( uint32_t ) 0, \ - eNoAction, \ - pxHigherPriorityTaskWoken ); \ - ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ - } \ - } \ - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ - } -#endif /* sbSEND_COMPLETE_FROM_ISR */ -/*lint -restore (9026) */ - -/* The number of bytes used to hold the length of a message in the buffer. */ -#define sbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) ) - -/* Bits stored in the ucFlags field of the stream buffer. */ -#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. */ -#define sbFLAGS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */ - -/*-----------------------------------------------------------*/ - -/* Structure that hold state information on the buffer. */ -typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */ -{ - volatile size_t xTail; /* Index to the next item to read within the buffer. */ - volatile size_t xHead; /* Index to the next item to write within the buffer. */ - size_t xLength; /* The length of the buffer pointed to by pucBuffer. */ - size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */ - volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */ - volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */ - uint8_t * pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */ - uint8_t ucFlags; - - #if ( configUSE_TRACE_FACILITY == 1 ) - UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */ - #endif -} StreamBuffer_t; - -/* - * The number of bytes available to be read from the buffer. - */ -static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION; - -/* - * Add xCount bytes from pucData into the pxStreamBuffer message buffer. - * Returns the number of bytes written, which will either equal xCount in the - * success case, or 0 if there was not enough space in the buffer (in which case - * no data is written into the buffer). - */ -static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, - const uint8_t * pucData, - size_t xCount ) PRIVILEGED_FUNCTION; - -/* - * If the stream buffer is being used as a message buffer, then reads an entire - * message out of the buffer. If the stream buffer is being used as a stream - * buffer then read as many bytes as possible from the buffer. - * prvReadBytesFromBuffer() is called to actually extract the bytes from the - * buffer's data storage area. - */ -static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer, - void * pvRxData, - size_t xBufferLengthBytes, - size_t xBytesAvailable, - size_t xBytesToStoreMessageLength ) PRIVILEGED_FUNCTION; - -/* - * If the stream buffer is being used as a message buffer, then writes an entire - * message to the buffer. If the stream buffer is being used as a stream - * buffer then write as many bytes as possible to the buffer. - * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's - * data storage area. - */ -static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, - const void * pvTxData, - size_t xDataLengthBytes, - size_t xSpace, - size_t xRequiredSpace ) PRIVILEGED_FUNCTION; - -/* - * Read xMaxCount bytes from the pxStreamBuffer message buffer and write them - * to pucData. - */ -static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer, - uint8_t * pucData, - size_t xMaxCount, - size_t xBytesAvailable ) PRIVILEGED_FUNCTION; - -/* - * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to - * initialise the members of the newly created stream buffer structure. - */ -static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, - uint8_t * const pucBuffer, - size_t xBufferSizeBytes, - size_t xTriggerLevelBytes, - uint8_t ucFlags ) PRIVILEGED_FUNCTION; - -/*-----------------------------------------------------------*/ - -#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - - StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, - size_t xTriggerLevelBytes, - BaseType_t xIsMessageBuffer ) - { - uint8_t * pucAllocatedMemory; - uint8_t ucFlags; - - /* In case the stream buffer is going to be used as a message buffer - * (that is, it will hold discrete messages with a little meta data that - * says how big the next message is) check the buffer will be large enough - * to hold at least one message. */ - if( xIsMessageBuffer == pdTRUE ) - { - /* Is a message buffer but not statically allocated. */ - ucFlags = sbFLAGS_IS_MESSAGE_BUFFER; - configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); - } - else - { - /* Not a message buffer and not statically allocated. */ - ucFlags = 0; - configASSERT( xBufferSizeBytes > 0 ); - } - - configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); - - /* A trigger level of 0 would cause a waiting task to unblock even when - * the buffer was empty. */ - if( xTriggerLevelBytes == ( size_t ) 0 ) - { - xTriggerLevelBytes = ( size_t ) 1; - } - - /* A stream buffer requires a StreamBuffer_t structure and a buffer. - * Both are allocated in a single call to pvPortMalloc(). The - * StreamBuffer_t structure is placed at the start of the allocated memory - * and the buffer follows immediately after. The requested size is - * incremented so the free space is returned as the user would expect - - * this is a quirk of the implementation that means otherwise the free - * space would be reported as one byte smaller than would be logically - * expected. */ - if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) ) - { - xBufferSizeBytes++; - pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */ - } - else - { - pucAllocatedMemory = NULL; - } - - if( pucAllocatedMemory != NULL ) - { - 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. */ - pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */ - xBufferSizeBytes, - xTriggerLevelBytes, - ucFlags ); - - traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer ); - } - else - { - traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ); - } - - return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */ - } - -#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ -/*-----------------------------------------------------------*/ - -#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - - StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, - size_t xTriggerLevelBytes, - BaseType_t xIsMessageBuffer, - uint8_t * const pucStreamBufferStorageArea, - StaticStreamBuffer_t * const pxStaticStreamBuffer ) - { - StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */ - StreamBufferHandle_t xReturn; - uint8_t ucFlags; - - configASSERT( pucStreamBufferStorageArea ); - configASSERT( pxStaticStreamBuffer ); - configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); - - /* A trigger level of 0 would cause a waiting task to unblock even when - * the buffer was empty. */ - if( xTriggerLevelBytes == ( size_t ) 0 ) - { - xTriggerLevelBytes = ( size_t ) 1; - } - - if( xIsMessageBuffer != pdFALSE ) - { - /* Statically allocated message buffer. */ - ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED; - } - else - { - /* Statically allocated stream buffer. */ - ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED; - } - - /* In case the stream buffer is going to be used as a message buffer - * (that is, it will hold discrete messages with a little meta data that - * says how big the next message is) check the buffer will be large enough - * to hold at least one message. */ - configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); - - #if ( configASSERT_DEFINED == 1 ) - { - /* Sanity check that the size of the structure used to declare a - * variable of type StaticStreamBuffer_t equals the size of the real - * message buffer structure. */ - volatile size_t xSize = sizeof( StaticStreamBuffer_t ); - configASSERT( xSize == sizeof( StreamBuffer_t ) ); - } /*lint !e529 xSize is referenced is configASSERT() is defined. */ - #endif /* configASSERT_DEFINED */ - - if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) ) - { - prvInitialiseNewStreamBuffer( pxStreamBuffer, - pucStreamBufferStorageArea, - xBufferSizeBytes, - xTriggerLevelBytes, - ucFlags ); - - /* Remember this was statically allocated in case it is ever deleted - * again. */ - pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED; - - traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ); - - xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */ - } - else - { - xReturn = NULL; - traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ); - } - - return xReturn; - } - -#endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ -/*-----------------------------------------------------------*/ - -void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) -{ - StreamBuffer_t * pxStreamBuffer = xStreamBuffer; - - configASSERT( pxStreamBuffer ); - - traceSTREAM_BUFFER_DELETE( xStreamBuffer ); - - if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE ) - { - #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - { - /* Both the structure and the buffer were allocated using a single call - * to pvPortMalloc(), hence only one call to vPortFree() is required. */ - vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */ - } - #else - { - /* Should not be possible to get here, ucFlags must be corrupt. - * Force an assert. */ - configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 ); - } - #endif - } - else - { - /* The structure and buffer were not allocated dynamically and cannot be - * freed - just scrub the structure so future use will assert. */ - ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); - } -} -/*-----------------------------------------------------------*/ - -BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - BaseType_t xReturn = pdFAIL; - - #if ( configUSE_TRACE_FACILITY == 1 ) - UBaseType_t uxStreamBufferNumber; - #endif - - configASSERT( pxStreamBuffer ); - - #if ( configUSE_TRACE_FACILITY == 1 ) - { - /* Store the stream buffer number so it can be restored after the - * reset. */ - uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber; - } - #endif - - /* Can only reset a message buffer if there are no tasks blocked on it. */ - taskENTER_CRITICAL(); - { - if( pxStreamBuffer->xTaskWaitingToReceive == NULL ) - { - if( pxStreamBuffer->xTaskWaitingToSend == NULL ) - { - prvInitialiseNewStreamBuffer( pxStreamBuffer, - pxStreamBuffer->pucBuffer, - pxStreamBuffer->xLength, - pxStreamBuffer->xTriggerLevelBytes, - pxStreamBuffer->ucFlags ); - xReturn = pdPASS; - - #if ( configUSE_TRACE_FACILITY == 1 ) - { - pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; - } - #endif - - traceSTREAM_BUFFER_RESET( xStreamBuffer ); - } - } - } - taskEXIT_CRITICAL(); - - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, - size_t xTriggerLevel ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - BaseType_t xReturn; - - configASSERT( pxStreamBuffer ); - - /* It is not valid for the trigger level to be 0. */ - if( xTriggerLevel == ( size_t ) 0 ) - { - xTriggerLevel = ( size_t ) 1; - } - - /* The trigger level is the number of bytes that must be in the stream - * buffer before a task that is waiting for data is unblocked. */ - if( xTriggerLevel < pxStreamBuffer->xLength ) - { - pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel; - xReturn = pdPASS; - } - else - { - xReturn = pdFALSE; - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) -{ - const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - size_t xSpace; - - configASSERT( pxStreamBuffer ); - - xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail; - xSpace -= pxStreamBuffer->xHead; - xSpace -= ( size_t ) 1; - - if( xSpace >= pxStreamBuffer->xLength ) - { - xSpace -= pxStreamBuffer->xLength; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - return xSpace; -} -/*-----------------------------------------------------------*/ - -size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) -{ - const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - size_t xReturn; - - configASSERT( pxStreamBuffer ); - - xReturn = prvBytesInBuffer( pxStreamBuffer ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, - const void * pvTxData, - size_t xDataLengthBytes, - TickType_t xTicksToWait ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - size_t xReturn, xSpace = 0; - size_t xRequiredSpace = xDataLengthBytes; - TimeOut_t xTimeOut; - size_t xMaxReportedSpace = 0; - - configASSERT( pvTxData ); - configASSERT( pxStreamBuffer ); - - /* The maximum amount of space a stream buffer will ever report is its length - * minus 1. */ - xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1; - - /* This send function is used to write to both message buffers and stream - * buffers. If this is a message buffer then the space needed must be - * increased by the amount of bytes needed to store the length of the - * message. */ - if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) - { - xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; - - /* Overflow? */ - configASSERT( xRequiredSpace > xDataLengthBytes ); - - /* If this is a message buffer then it must be possible to write the - * whole message. */ - if( xRequiredSpace > xMaxReportedSpace ) - { - /* The message would not fit even if the entire buffer was empty, - * so don't wait for space. */ - xTicksToWait = ( TickType_t ) 0; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - /* If this is a stream buffer then it is acceptable to write only part - * of the message to the buffer. Cap the length to the total length of - * the buffer. */ - if( xRequiredSpace > xMaxReportedSpace ) - { - xRequiredSpace = xMaxReportedSpace; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - - if( xTicksToWait != ( TickType_t ) 0 ) - { - vTaskSetTimeOutState( &xTimeOut ); - - do - { - /* Wait until the required number of bytes are free in the message - * buffer. */ - taskENTER_CRITICAL(); - { - xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); - - if( xSpace < xRequiredSpace ) - { - /* Clear notification state as going to wait for space. */ - ( void ) xTaskNotifyStateClear( NULL ); - - /* Should only be one writer. */ - configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL ); - pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle(); - } - else - { - taskEXIT_CRITICAL(); - break; - } - } - taskEXIT_CRITICAL(); - - traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ); - ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); - pxStreamBuffer->xTaskWaitingToSend = NULL; - } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - if( xSpace == ( size_t ) 0 ) - { - xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); - - if( xReturn > ( size_t ) 0 ) - { - traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ); - - /* Was a task waiting for the data? */ - if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) - { - sbSEND_COMPLETED( pxStreamBuffer ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ); - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer, - const void * pvTxData, - size_t xDataLengthBytes, - BaseType_t * const pxHigherPriorityTaskWoken ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - size_t xReturn, xSpace; - size_t xRequiredSpace = xDataLengthBytes; - - configASSERT( pvTxData ); - configASSERT( pxStreamBuffer ); - - /* This send function is used to write to both message buffers and stream - * buffers. If this is a message buffer then the space needed must be - * increased by the amount of bytes needed to store the length of the - * message. */ - if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) - { - xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); - xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); - - if( xReturn > ( size_t ) 0 ) - { - /* Was a task waiting for the data? */ - if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) - { - sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn ); - - return xReturn; -} -/*-----------------------------------------------------------*/ - -static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, - const void * pvTxData, - size_t xDataLengthBytes, - size_t xSpace, - size_t xRequiredSpace ) -{ - BaseType_t xShouldWrite; - size_t xReturn; - - if( xSpace == ( size_t ) 0 ) - { - /* Doesn't matter if this is a stream buffer or a message buffer, there - * is no space to write. */ - xShouldWrite = pdFALSE; - } - else if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) == ( uint8_t ) 0 ) - { - /* This is a stream buffer, as opposed to a message buffer, so writing a - * stream of bytes rather than discrete messages. Write as many bytes as - * possible. */ - xShouldWrite = pdTRUE; - xDataLengthBytes = configMIN( xDataLengthBytes, xSpace ); - } - else if( xSpace >= xRequiredSpace ) - { - /* This is a message buffer, as opposed to a stream buffer, and there - * is enough space to write both the message length and the message itself - * into the buffer. Start by writing the length of the data, the data - * itself will be written later in this function. */ - xShouldWrite = pdTRUE; - ( void ) prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH ); - } - else - { - /* There is space available, but not enough space. */ - xShouldWrite = pdFALSE; - } - - if( xShouldWrite != pdFALSE ) - { - /* Writes the data itself. */ - xReturn = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alignment and access. */ - } - else - { - xReturn = 0; - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, - void * pvRxData, - size_t xBufferLengthBytes, - TickType_t xTicksToWait ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength; - - configASSERT( pvRxData ); - configASSERT( pxStreamBuffer ); - - /* This receive function is used by both message buffers, which store - * discrete messages, and stream buffers, which store a continuous stream of - * bytes. Discrete messages include an additional - * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the - * message. */ - if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) - { - xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; - } - else - { - xBytesToStoreMessageLength = 0; - } - - if( xTicksToWait != ( TickType_t ) 0 ) - { - /* Checking if there is data and clearing the notification state must be - * performed atomically. */ - taskENTER_CRITICAL(); - { - xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); - - /* If this function was invoked by a message buffer read then - * xBytesToStoreMessageLength holds the number of bytes used to hold - * the length of the next discrete message. If this function was - * invoked by a stream buffer read then xBytesToStoreMessageLength will - * be 0. */ - if( xBytesAvailable <= xBytesToStoreMessageLength ) - { - /* Clear notification state as going to wait for data. */ - ( void ) xTaskNotifyStateClear( NULL ); - - /* Should only be one reader. */ - configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL ); - pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - taskEXIT_CRITICAL(); - - if( xBytesAvailable <= xBytesToStoreMessageLength ) - { - /* Wait for data to be available. */ - traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ); - ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); - pxStreamBuffer->xTaskWaitingToReceive = NULL; - - /* Recheck the data available after blocking. */ - xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); - } - - /* Whether receiving a discrete message (where xBytesToStoreMessageLength - * holds the number of bytes used to store the message length) or a stream of - * bytes (where xBytesToStoreMessageLength is zero), the number of bytes - * available must be greater than xBytesToStoreMessageLength to be able to - * read bytes from the buffer. */ - if( xBytesAvailable > xBytesToStoreMessageLength ) - { - xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength ); - - /* Was a task waiting for space in the buffer? */ - if( xReceivedLength != ( size_t ) 0 ) - { - traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ); - sbRECEIVE_COMPLETED( pxStreamBuffer ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ); - mtCOVERAGE_TEST_MARKER(); - } - - return xReceivedLength; -} -/*-----------------------------------------------------------*/ - -size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - size_t xReturn, xBytesAvailable, xOriginalTail; - configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn; - - configASSERT( pxStreamBuffer ); - - /* Ensure the stream buffer is being used as a message buffer. */ - if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) - { - xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); - - if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH ) - { - /* The number of bytes available is greater than the number of bytes - * required to hold the length of the next message, so another message - * is available. Return its length without removing the length bytes - * from the buffer. A copy of the tail is stored so the buffer can be - * returned to its prior state as the message is not actually being - * removed from the buffer. */ - xOriginalTail = pxStreamBuffer->xTail; - ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, xBytesAvailable ); - xReturn = ( size_t ) xTempReturn; - pxStreamBuffer->xTail = xOriginalTail; - } - else - { - /* The minimum amount of bytes in a message buffer is - * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is - * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid - * value is 0. */ - configASSERT( xBytesAvailable == 0 ); - xReturn = 0; - } - } - else - { - xReturn = 0; - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, - void * pvRxData, - size_t xBufferLengthBytes, - BaseType_t * const pxHigherPriorityTaskWoken ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength; - - configASSERT( pvRxData ); - configASSERT( pxStreamBuffer ); - - /* This receive function is used by both message buffers, which store - * discrete messages, and stream buffers, which store a continuous stream of - * bytes. Discrete messages include an additional - * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the - * message. */ - if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) - { - xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; - } - else - { - xBytesToStoreMessageLength = 0; - } - - xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); - - /* Whether receiving a discrete message (where xBytesToStoreMessageLength - * holds the number of bytes used to store the message length) or a stream of - * bytes (where xBytesToStoreMessageLength is zero), the number of bytes - * available must be greater than xBytesToStoreMessageLength to be able to - * read bytes from the buffer. */ - if( xBytesAvailable > xBytesToStoreMessageLength ) - { - xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable, xBytesToStoreMessageLength ); - - /* Was a task waiting for space in the buffer? */ - if( xReceivedLength != ( size_t ) 0 ) - { - sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ); - - return xReceivedLength; -} -/*-----------------------------------------------------------*/ - -static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer, - void * pvRxData, - size_t xBufferLengthBytes, - size_t xBytesAvailable, - size_t xBytesToStoreMessageLength ) -{ - size_t xOriginalTail, xReceivedLength, xNextMessageLength; - configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength; - - if( xBytesToStoreMessageLength != ( size_t ) 0 ) - { - /* A discrete message is being received. First receive the length - * of the message. A copy of the tail is stored so the buffer can be - * returned to its prior state if the length of the message is too - * large for the provided buffer. */ - xOriginalTail = pxStreamBuffer->xTail; - ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, xBytesToStoreMessageLength, xBytesAvailable ); - xNextMessageLength = ( size_t ) xTempNextMessageLength; - - /* Reduce the number of bytes available by the number of bytes just - * read out. */ - xBytesAvailable -= xBytesToStoreMessageLength; - - /* Check there is enough space in the buffer provided by the - * user. */ - if( xNextMessageLength > xBufferLengthBytes ) - { - /* The user has provided insufficient space to read the message - * so return the buffer to its previous state (so the length of - * the message is in the buffer again). */ - pxStreamBuffer->xTail = xOriginalTail; - xNextMessageLength = 0; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - /* A stream of bytes is being received (as opposed to a discrete - * message), so read as many bytes as possible. */ - xNextMessageLength = xBufferLengthBytes; - } - - /* Read the actual data. */ - 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. */ - - return xReceivedLength; -} -/*-----------------------------------------------------------*/ - -BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) -{ - const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - BaseType_t xReturn; - size_t xTail; - - configASSERT( pxStreamBuffer ); - - /* True if no bytes are available. */ - xTail = pxStreamBuffer->xTail; - - if( pxStreamBuffer->xHead == xTail ) - { - xReturn = pdTRUE; - } - else - { - xReturn = pdFALSE; - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) -{ - BaseType_t xReturn; - size_t xBytesToStoreMessageLength; - const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - - configASSERT( pxStreamBuffer ); - - /* This generic version of the receive function is used by both message - * buffers, which store discrete messages, and stream buffers, which store a - * continuous stream of bytes. Discrete messages include an additional - * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */ - if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) - { - xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; - } - else - { - xBytesToStoreMessageLength = 0; - } - - /* True if the available space equals zero. */ - if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength ) - { - xReturn = pdTRUE; - } - else - { - xReturn = pdFALSE; - } - - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, - BaseType_t * pxHigherPriorityTaskWoken ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - BaseType_t xReturn; - UBaseType_t uxSavedInterruptStatus; - - configASSERT( pxStreamBuffer ); - - uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); - { - if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) - { - ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, - ( uint32_t ) 0, - eNoAction, - pxHigherPriorityTaskWoken ); - ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; - xReturn = pdTRUE; - } - else - { - xReturn = pdFALSE; - } - } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); - - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, - BaseType_t * pxHigherPriorityTaskWoken ) -{ - StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; - BaseType_t xReturn; - UBaseType_t uxSavedInterruptStatus; - - configASSERT( pxStreamBuffer ); - - uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); - { - if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) - { - ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, - ( uint32_t ) 0, - eNoAction, - pxHigherPriorityTaskWoken ); - ( pxStreamBuffer )->xTaskWaitingToSend = NULL; - xReturn = pdTRUE; - } - else - { - xReturn = pdFALSE; - } - } - portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); - - return xReturn; -} -/*-----------------------------------------------------------*/ - -static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, - const uint8_t * pucData, - size_t xCount ) -{ - size_t xNextHead, xFirstLength; - - configASSERT( xCount > ( size_t ) 0 ); - - xNextHead = pxStreamBuffer->xHead; - - /* Calculate the number of bytes that can be added in the first write - - * which may be less than the total number of bytes that need to be added if - * the buffer will wrap back to the beginning. */ - xFirstLength = configMIN( pxStreamBuffer->xLength - xNextHead, xCount ); - - /* Write as many bytes as can be written in the first write. */ - configASSERT( ( xNextHead + xFirstLength ) <= pxStreamBuffer->xLength ); - ( void ) memcpy( ( void * ) ( &( pxStreamBuffer->pucBuffer[ xNextHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */ - - /* If the number of bytes written was less than the number that could be - * written in the first write... */ - if( xCount > xFirstLength ) - { - /* ...then write the remaining bytes to the start of the buffer. */ - configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength ); - ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */ - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - xNextHead += xCount; - - if( xNextHead >= pxStreamBuffer->xLength ) - { - xNextHead -= pxStreamBuffer->xLength; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - pxStreamBuffer->xHead = xNextHead; - - return xCount; -} -/*-----------------------------------------------------------*/ - -static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer, - uint8_t * pucData, - size_t xMaxCount, - size_t xBytesAvailable ) -{ - size_t xCount, xFirstLength, xNextTail; - - /* Use the minimum of the wanted bytes and the available bytes. */ - xCount = configMIN( xBytesAvailable, xMaxCount ); - - if( xCount > ( size_t ) 0 ) - { - xNextTail = pxStreamBuffer->xTail; - - /* Calculate the number of bytes that can be read - which may be - * less than the number wanted if the data wraps around to the start of - * the buffer. */ - xFirstLength = configMIN( pxStreamBuffer->xLength - xNextTail, xCount ); - - /* Obtain the number of bytes it is possible to obtain in the first - * read. Asserts check bounds of read and write. */ - configASSERT( xFirstLength <= xMaxCount ); - configASSERT( ( xNextTail + xFirstLength ) <= pxStreamBuffer->xLength ); - ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xNextTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */ - - /* If the total number of wanted bytes is greater than the number - * that could be read in the first read... */ - if( xCount > xFirstLength ) - { - /*...then read the remaining bytes from the start of the buffer. */ - configASSERT( xCount <= xMaxCount ); - ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */ - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - /* Move the tail pointer to effectively remove the data read from - * the buffer. */ - xNextTail += xCount; - - if( xNextTail >= pxStreamBuffer->xLength ) - { - xNextTail -= pxStreamBuffer->xLength; - } - - pxStreamBuffer->xTail = xNextTail; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - return xCount; -} -/*-----------------------------------------------------------*/ - -static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) -{ -/* Returns the distance between xTail and xHead. */ - size_t xCount; - - xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead; - xCount -= pxStreamBuffer->xTail; - - if( xCount >= pxStreamBuffer->xLength ) - { - xCount -= pxStreamBuffer->xLength; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - return xCount; -} -/*-----------------------------------------------------------*/ - -static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, - uint8_t * const pucBuffer, - size_t xBufferSizeBytes, - size_t xTriggerLevelBytes, - uint8_t ucFlags ) -{ - /* Assert here is deliberately writing to the entire buffer to ensure it can - * be written to without generating exceptions, and is setting the buffer to a - * known value to assist in development/debugging. */ - #if ( configASSERT_DEFINED == 1 ) - { - /* The value written just has to be identifiable when looking at the - * memory. Don't use 0xA5 as that is the stack fill value and could - * result in confusion as to what is actually being observed. */ - const BaseType_t xWriteValue = 0x55; - configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer ); - } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */ - #endif - - ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */ - pxStreamBuffer->pucBuffer = pucBuffer; - pxStreamBuffer->xLength = xBufferSizeBytes; - pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes; - pxStreamBuffer->ucFlags = ucFlags; -} - -#if ( configUSE_TRACE_FACILITY == 1 ) - - UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) - { - return xStreamBuffer->uxStreamBufferNumber; - } - -#endif /* configUSE_TRACE_FACILITY */ -/*-----------------------------------------------------------*/ - -#if ( configUSE_TRACE_FACILITY == 1 ) - - void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, - UBaseType_t uxStreamBufferNumber ) - { - xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; - } - -#endif /* configUSE_TRACE_FACILITY */ -/*-----------------------------------------------------------*/ - -#if ( configUSE_TRACE_FACILITY == 1 ) - - uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) - { - return( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ); - } - -#endif /* configUSE_TRACE_FACILITY */ -/*-----------------------------------------------------------*/ +/* + * FreeRTOS Kernel V10.4.3 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* Standard includes. */ +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining + * all the API functions to use the MPU wrappers. That should only be done when + * task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "stream_buffer.h" + +#if ( configUSE_TASK_NOTIFICATIONS != 1 ) + #error configUSE_TASK_NOTIFICATIONS must be set to 1 to build stream_buffer.c +#endif + +/* Lint e961, e9021 and e750 are suppressed as a MISRA exception justified + * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined + * for the header files above, but not in this file, in order to generate the + * correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */ + +/* If the user has not provided application specific Rx notification macros, + * or #defined the notification macros away, then provide default implementations + * that uses task notifications. */ +/*lint -save -e9026 Function like macros allowed and needed here so they can be overridden. */ +#ifndef sbRECEIVE_COMPLETED + #define sbRECEIVE_COMPLETED( pxStreamBuffer ) \ + vTaskSuspendAll(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ + { \ + ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToSend, \ + ( uint32_t ) 0, \ + eNoAction ); \ + ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ + } \ + } \ + ( void ) xTaskResumeAll(); +#endif /* sbRECEIVE_COMPLETED */ + +#ifndef sbRECEIVE_COMPLETED_FROM_ISR + #define sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, \ + pxHigherPriorityTaskWoken ) \ + { \ + UBaseType_t uxSavedInterruptStatus; \ + \ + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) \ + { \ + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, \ + ( uint32_t ) 0, \ + eNoAction, \ + pxHigherPriorityTaskWoken ); \ + ( pxStreamBuffer )->xTaskWaitingToSend = NULL; \ + } \ + } \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ + } +#endif /* sbRECEIVE_COMPLETED_FROM_ISR */ + +/* If the user has not provided an application specific Tx notification macro, + * or #defined the notification macro away, them provide a default implementation + * that uses task notifications. */ +#ifndef sbSEND_COMPLETED + #define sbSEND_COMPLETED( pxStreamBuffer ) \ + vTaskSuspendAll(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ + { \ + ( void ) xTaskNotify( ( pxStreamBuffer )->xTaskWaitingToReceive, \ + ( uint32_t ) 0, \ + eNoAction ); \ + ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ + } \ + } \ + ( void ) xTaskResumeAll(); +#endif /* sbSEND_COMPLETED */ + +#ifndef sbSEND_COMPLETE_FROM_ISR + #define sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ) \ + { \ + UBaseType_t uxSavedInterruptStatus; \ + \ + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ + { \ + if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) \ + { \ + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, \ + ( uint32_t ) 0, \ + eNoAction, \ + pxHigherPriorityTaskWoken ); \ + ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; \ + } \ + } \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ + } +#endif /* sbSEND_COMPLETE_FROM_ISR */ +/*lint -restore (9026) */ + +/* The number of bytes used to hold the length of a message in the buffer. */ +#define sbBYTES_TO_STORE_MESSAGE_LENGTH ( sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) ) + +/* Bits stored in the ucFlags field of the stream buffer. */ +#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. */ +#define sbFLAGS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 2 ) /* Set if the stream buffer was created using statically allocated memory. */ + +/*-----------------------------------------------------------*/ + +/* Structure that hold state information on the buffer. */ +typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */ +{ + volatile size_t xTail; /* Index to the next item to read within the buffer. */ + volatile size_t xHead; /* Index to the next item to write within the buffer. */ + size_t xLength; /* The length of the buffer pointed to by pucBuffer. */ + size_t xTriggerLevelBytes; /* The number of bytes that must be in the stream buffer before a task that is waiting for data is unblocked. */ + volatile TaskHandle_t xTaskWaitingToReceive; /* Holds the handle of a task waiting for data, or NULL if no tasks are waiting. */ + volatile TaskHandle_t xTaskWaitingToSend; /* Holds the handle of a task waiting to send data to a message buffer that is full. */ + uint8_t * pucBuffer; /* Points to the buffer itself - that is - the RAM that stores the data passed through the buffer. */ + uint8_t ucFlags; + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxStreamBufferNumber; /* Used for tracing purposes. */ + #endif +} StreamBuffer_t; + +/* + * The number of bytes available to be read from the buffer. + */ +static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) PRIVILEGED_FUNCTION; + +/* + * Add xCount bytes from pucData into the pxStreamBuffer's data storage area. + * This function does not update the buffer's xHead pointer, so multiple writes + * may be chained together "atomically". This is useful for Message Buffers where + * the length and data bytes are written in two separate chunks, and we don't want + * the reader to see the buffer as having grown until after all data is copied over. + * This function takes a custom xHead value to indicate where to write to (necessary + * for chaining) and returns the the resulting xHead position. + * To mark the write as complete, manually set the buffer's xHead field with the + * returned xHead from this function. + */ +static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, + const uint8_t * pucData, + size_t xCount, + size_t xHead ) PRIVILEGED_FUNCTION; + +/* + * If the stream buffer is being used as a message buffer, then reads an entire + * message out of the buffer. If the stream buffer is being used as a stream + * buffer then read as many bytes as possible from the buffer. + * prvReadBytesFromBuffer() is called to actually extract the bytes from the + * buffer's data storage area. + */ +static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer, + void * pvRxData, + size_t xBufferLengthBytes, + size_t xBytesAvailable ) PRIVILEGED_FUNCTION; + +/* + * If the stream buffer is being used as a message buffer, then writes an entire + * message to the buffer. If the stream buffer is being used as a stream + * buffer then write as many bytes as possible to the buffer. + * prvWriteBytestoBuffer() is called to actually send the bytes to the buffer's + * data storage area. + */ +static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, + const void * pvTxData, + size_t xDataLengthBytes, + size_t xSpace, + size_t xRequiredSpace ) PRIVILEGED_FUNCTION; + +/* + * Copies xCount bytes from the pxStreamBuffer's data storage area to pucData. + * This function does not update the buffer's xTail pointer, so multiple reads + * may be chained together "atomically". This is useful for Message Buffers where + * the length and data bytes are read in two separate chunks, and we don't want + * the writer to see the buffer as having more free space until after all data is + * copied over, especially if we have to abort the read due to insufficient receiving space. + * This function takes a custom xTail value to indicate where to read from (necessary + * for chaining) and returns the the resulting xTail position. + * To mark the read as complete, manually set the buffer's xTail field with the + * returned xTail from this function. + */ +static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer, + uint8_t * pucData, + size_t xCount, + size_t xTail ) PRIVILEGED_FUNCTION; + +/* + * Called by both pxStreamBufferCreate() and pxStreamBufferCreateStatic() to + * initialise the members of the newly created stream buffer structure. + */ +static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, + uint8_t * const pucBuffer, + size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + uint8_t ucFlags ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ + +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + + StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + BaseType_t xIsMessageBuffer ) + { + uint8_t * pucAllocatedMemory; + uint8_t ucFlags; + + /* In case the stream buffer is going to be used as a message buffer + * (that is, it will hold discrete messages with a little meta data that + * says how big the next message is) check the buffer will be large enough + * to hold at least one message. */ + if( xIsMessageBuffer == pdTRUE ) + { + /* Is a message buffer but not statically allocated. */ + ucFlags = sbFLAGS_IS_MESSAGE_BUFFER; + configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); + } + else + { + /* Not a message buffer and not statically allocated. */ + ucFlags = 0; + configASSERT( xBufferSizeBytes > 0 ); + } + + configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); + + /* A trigger level of 0 would cause a waiting task to unblock even when + * the buffer was empty. */ + if( xTriggerLevelBytes == ( size_t ) 0 ) + { + xTriggerLevelBytes = ( size_t ) 1; + } + + /* A stream buffer requires a StreamBuffer_t structure and a buffer. + * Both are allocated in a single call to pvPortMalloc(). The + * StreamBuffer_t structure is placed at the start of the allocated memory + * and the buffer follows immediately after. The requested size is + * incremented so the free space is returned as the user would expect - + * this is a quirk of the implementation that means otherwise the free + * space would be reported as one byte smaller than would be logically + * expected. */ + if( xBufferSizeBytes < ( xBufferSizeBytes + 1 + sizeof( StreamBuffer_t ) ) ) + { + xBufferSizeBytes++; + pucAllocatedMemory = ( uint8_t * ) pvPortMalloc( xBufferSizeBytes + sizeof( StreamBuffer_t ) ); /*lint !e9079 malloc() only returns void*. */ + } + else + { + pucAllocatedMemory = NULL; + } + + if( pucAllocatedMemory != NULL ) + { + 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. */ + pucAllocatedMemory + sizeof( StreamBuffer_t ), /* Storage area follows. */ /*lint !e9016 Indexing past structure valid for uint8_t pointer, also storage area has no alignment requirement. */ + xBufferSizeBytes, + xTriggerLevelBytes, + ucFlags ); + + traceSTREAM_BUFFER_CREATE( ( ( StreamBuffer_t * ) pucAllocatedMemory ), xIsMessageBuffer ); + } + else + { + traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ); + } + + return ( StreamBufferHandle_t ) pucAllocatedMemory; /*lint !e9087 !e826 Safe cast as allocated memory is aligned. */ + } + +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + + StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + BaseType_t xIsMessageBuffer, + uint8_t * const pucStreamBufferStorageArea, + StaticStreamBuffer_t * const pxStaticStreamBuffer ) + { + StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */ + StreamBufferHandle_t xReturn; + uint8_t ucFlags; + + configASSERT( pucStreamBufferStorageArea ); + configASSERT( pxStaticStreamBuffer ); + configASSERT( xTriggerLevelBytes <= xBufferSizeBytes ); + + /* A trigger level of 0 would cause a waiting task to unblock even when + * the buffer was empty. */ + if( xTriggerLevelBytes == ( size_t ) 0 ) + { + xTriggerLevelBytes = ( size_t ) 1; + } + + if( xIsMessageBuffer != pdFALSE ) + { + /* Statically allocated message buffer. */ + ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED; + } + else + { + /* Statically allocated stream buffer. */ + ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED; + } + + /* In case the stream buffer is going to be used as a message buffer + * (that is, it will hold discrete messages with a little meta data that + * says how big the next message is) check the buffer will be large enough + * to hold at least one message. */ + configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH ); + + #if ( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + * variable of type StaticStreamBuffer_t equals the size of the real + * message buffer structure. */ + volatile size_t xSize = sizeof( StaticStreamBuffer_t ); + configASSERT( xSize == sizeof( StreamBuffer_t ) ); + } /*lint !e529 xSize is referenced is configASSERT() is defined. */ + #endif /* configASSERT_DEFINED */ + + if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) ) + { + prvInitialiseNewStreamBuffer( pxStreamBuffer, + pucStreamBufferStorageArea, + xBufferSizeBytes, + xTriggerLevelBytes, + ucFlags ); + + /* Remember this was statically allocated in case it is ever deleted + * again. */ + pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED; + + traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ); + + xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */ + } + else + { + xReturn = NULL; + traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ); + } + + return xReturn; + } + +#endif /* ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ +/*-----------------------------------------------------------*/ + +void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) +{ + StreamBuffer_t * pxStreamBuffer = xStreamBuffer; + + configASSERT( pxStreamBuffer ); + + traceSTREAM_BUFFER_DELETE( xStreamBuffer ); + + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) pdFALSE ) + { + #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + { + /* Both the structure and the buffer were allocated using a single call + * to pvPortMalloc(), hence only one call to vPortFree() is required. */ + vPortFree( ( void * ) pxStreamBuffer ); /*lint !e9087 Standard free() semantics require void *, plus pxStreamBuffer was allocated by pvPortMalloc(). */ + } + #else + { + /* Should not be possible to get here, ucFlags must be corrupt. + * Force an assert. */ + configASSERT( xStreamBuffer == ( StreamBufferHandle_t ) ~0 ); + } + #endif + } + else + { + /* The structure and buffer were not allocated dynamically and cannot be + * freed - just scrub the structure so future use will assert. */ + ( void ) memset( pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + BaseType_t xReturn = pdFAIL; + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxStreamBufferNumber; + #endif + + configASSERT( pxStreamBuffer ); + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + /* Store the stream buffer number so it can be restored after the + * reset. */ + uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber; + } + #endif + + /* Can only reset a message buffer if there are no tasks blocked on it. */ + taskENTER_CRITICAL(); + { + if( pxStreamBuffer->xTaskWaitingToReceive == NULL ) + { + if( pxStreamBuffer->xTaskWaitingToSend == NULL ) + { + prvInitialiseNewStreamBuffer( pxStreamBuffer, + pxStreamBuffer->pucBuffer, + pxStreamBuffer->xLength, + pxStreamBuffer->xTriggerLevelBytes, + pxStreamBuffer->ucFlags ); + xReturn = pdPASS; + + #if ( configUSE_TRACE_FACILITY == 1 ) + { + pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; + } + #endif + + traceSTREAM_BUFFER_RESET( xStreamBuffer ); + } + } + } + taskEXIT_CRITICAL(); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, + size_t xTriggerLevel ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + BaseType_t xReturn; + + configASSERT( pxStreamBuffer ); + + /* It is not valid for the trigger level to be 0. */ + if( xTriggerLevel == ( size_t ) 0 ) + { + xTriggerLevel = ( size_t ) 1; + } + + /* The trigger level is the number of bytes that must be in the stream + * buffer before a task that is waiting for data is unblocked. */ + if( xTriggerLevel < pxStreamBuffer->xLength ) + { + pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel; + xReturn = pdPASS; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) +{ + const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + size_t xSpace; + volatile size_t xOriginalTail; + + configASSERT( pxStreamBuffer ); + + /* The code below reads xTail and then xHead. This is safe if the stream + buffer is updated once between the two reads - but not if the stream buffer + is updated more than once between the two reads - hence the loop. */ + do + { + xOriginalTail = pxStreamBuffer->xTail; + xSpace = pxStreamBuffer->xLength + pxStreamBuffer->xTail; + xSpace -= pxStreamBuffer->xHead; + } while( xOriginalTail != pxStreamBuffer->xTail ); + xSpace -= ( size_t ) 1; + + if( xSpace >= pxStreamBuffer->xLength ) + { + xSpace -= pxStreamBuffer->xLength; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xSpace; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) +{ + const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + size_t xReturn; + + configASSERT( pxStreamBuffer ); + + xReturn = prvBytesInBuffer( pxStreamBuffer ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, + const void * pvTxData, + size_t xDataLengthBytes, + TickType_t xTicksToWait ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + size_t xReturn, xSpace = 0; + size_t xRequiredSpace = xDataLengthBytes; + TimeOut_t xTimeOut; + size_t xMaxReportedSpace = 0; + + configASSERT( pvTxData ); + configASSERT( pxStreamBuffer ); + + /* The maximum amount of space a stream buffer will ever report is its length + * minus 1. */ + xMaxReportedSpace = pxStreamBuffer->xLength - ( size_t ) 1; + + /* This send function is used to write to both message buffers and stream + * buffers. If this is a message buffer then the space needed must be + * increased by the amount of bytes needed to store the length of the + * message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; + + /* Overflow? */ + configASSERT( xRequiredSpace > xDataLengthBytes ); + + /* If this is a message buffer then it must be possible to write the + * whole message. */ + if( xRequiredSpace > xMaxReportedSpace ) + { + /* The message would not fit even if the entire buffer was empty, + * so don't wait for space. */ + xTicksToWait = ( TickType_t ) 0; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* If this is a stream buffer then it is acceptable to write only part + * of the message to the buffer. Cap the length to the total length of + * the buffer. */ + if( xRequiredSpace > xMaxReportedSpace ) + { + xRequiredSpace = xMaxReportedSpace; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + + if( xTicksToWait != ( TickType_t ) 0 ) + { + vTaskSetTimeOutState( &xTimeOut ); + + do + { + /* Wait until the required number of bytes are free in the message + * buffer. */ + taskENTER_CRITICAL(); + { + xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); + + if( xSpace < xRequiredSpace ) + { + /* Clear notification state as going to wait for space. */ + ( void ) xTaskNotifyStateClear( NULL ); + + /* Should only be one writer. */ + configASSERT( pxStreamBuffer->xTaskWaitingToSend == NULL ); + pxStreamBuffer->xTaskWaitingToSend = xTaskGetCurrentTaskHandle(); + } + else + { + taskEXIT_CRITICAL(); + break; + } + } + taskEXIT_CRITICAL(); + + traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ); + ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); + pxStreamBuffer->xTaskWaitingToSend = NULL; + } while( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xSpace == ( size_t ) 0 ) + { + xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); + + if( xReturn > ( size_t ) 0 ) + { + traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ); + + /* Was a task waiting for the data? */ + if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) + { + sbSEND_COMPLETED( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer, + const void * pvTxData, + size_t xDataLengthBytes, + BaseType_t * const pxHigherPriorityTaskWoken ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + size_t xReturn, xSpace; + size_t xRequiredSpace = xDataLengthBytes; + + configASSERT( pvTxData ); + configASSERT( pxStreamBuffer ); + + /* This send function is used to write to both message buffers and stream + * buffers. If this is a message buffer then the space needed must be + * increased by the amount of bytes needed to store the length of the + * message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xRequiredSpace += sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xSpace = xStreamBufferSpacesAvailable( pxStreamBuffer ); + xReturn = prvWriteMessageToBuffer( pxStreamBuffer, pvTxData, xDataLengthBytes, xSpace, xRequiredSpace ); + + if( xReturn > ( size_t ) 0 ) + { + /* Was a task waiting for the data? */ + if( prvBytesInBuffer( pxStreamBuffer ) >= pxStreamBuffer->xTriggerLevelBytes ) + { + sbSEND_COMPLETE_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, + const void * pvTxData, + size_t xDataLengthBytes, + size_t xSpace, + size_t xRequiredSpace ) +{ + size_t xNextHead = pxStreamBuffer->xHead; + + if( xDataLengthBytes != xRequiredSpace ) + { + /* This is a message buffer, as opposed to a stream buffer. */ + + if( xSpace >= xRequiredSpace ) + { + /* There is enough space to write both the message length and the message + * itself into the buffer. Start by writing the length of the data, the data + * itself will be written later in this function. */ + xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead); + } + else + { + /* Not enough space, so do not write data to the buffer. */ + xDataLengthBytes = 0; + } + } + else + { + /* This is a stream buffer, as opposed to a message buffer, so writing a + * stream of bytes rather than discrete messages. Plan to write as many + * bytes as possible. */ + xDataLengthBytes = configMIN( xDataLengthBytes, xSpace ); + } + + if( xDataLengthBytes != ( size_t ) 0 ) + { + /* Write the data to the buffer. */ + pxStreamBuffer->xHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) pvTxData, xDataLengthBytes, xNextHead ); /*lint !e9079 Storage buffer is implemented as uint8_t for ease of sizing, alignment and access. */ + } + + return xDataLengthBytes; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, + void * pvRxData, + size_t xBufferLengthBytes, + TickType_t xTicksToWait ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength; + + configASSERT( pvRxData ); + configASSERT( pxStreamBuffer ); + + /* This receive function is used by both message buffers, which store + * discrete messages, and stream buffers, which store a continuous stream of + * bytes. Discrete messages include an additional + * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the + * message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + xBytesToStoreMessageLength = 0; + } + + if( xTicksToWait != ( TickType_t ) 0 ) + { + /* Checking if there is data and clearing the notification state must be + * performed atomically. */ + taskENTER_CRITICAL(); + { + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + + /* If this function was invoked by a message buffer read then + * xBytesToStoreMessageLength holds the number of bytes used to hold + * the length of the next discrete message. If this function was + * invoked by a stream buffer read then xBytesToStoreMessageLength will + * be 0. */ + if( xBytesAvailable <= xBytesToStoreMessageLength ) + { + /* Clear notification state as going to wait for data. */ + ( void ) xTaskNotifyStateClear( NULL ); + + /* Should only be one reader. */ + configASSERT( pxStreamBuffer->xTaskWaitingToReceive == NULL ); + pxStreamBuffer->xTaskWaitingToReceive = xTaskGetCurrentTaskHandle(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + taskEXIT_CRITICAL(); + + if( xBytesAvailable <= xBytesToStoreMessageLength ) + { + /* Wait for data to be available. */ + traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ); + ( void ) xTaskNotifyWait( ( uint32_t ) 0, ( uint32_t ) 0, NULL, xTicksToWait ); + pxStreamBuffer->xTaskWaitingToReceive = NULL; + + /* Recheck the data available after blocking. */ + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + } + + /* Whether receiving a discrete message (where xBytesToStoreMessageLength + * holds the number of bytes used to store the message length) or a stream of + * bytes (where xBytesToStoreMessageLength is zero), the number of bytes + * available must be greater than xBytesToStoreMessageLength to be able to + * read bytes from the buffer. */ + if( xBytesAvailable > xBytesToStoreMessageLength ) + { + xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable ); + + /* Was a task waiting for space in the buffer? */ + if( xReceivedLength != ( size_t ) 0 ) + { + traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ); + sbRECEIVE_COMPLETED( pxStreamBuffer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ); + mtCOVERAGE_TEST_MARKER(); + } + + return xReceivedLength; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + size_t xReturn, xBytesAvailable; + configMESSAGE_BUFFER_LENGTH_TYPE xTempReturn; + + configASSERT( pxStreamBuffer ); + + /* Ensure the stream buffer is being used as a message buffer. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + + if( xBytesAvailable > sbBYTES_TO_STORE_MESSAGE_LENGTH ) + { + /* The number of bytes available is greater than the number of bytes + * required to hold the length of the next message, so another message + * is available. */ + ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, pxStreamBuffer->xTail); + xReturn = ( size_t ) xTempReturn; + } + else + { + /* The minimum amount of bytes in a message buffer is + * ( sbBYTES_TO_STORE_MESSAGE_LENGTH + 1 ), so if xBytesAvailable is + * less than sbBYTES_TO_STORE_MESSAGE_LENGTH the only other valid + * value is 0. */ + configASSERT( xBytesAvailable == 0 ); + xReturn = 0; + } + } + else + { + xReturn = 0; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, + void * pvRxData, + size_t xBufferLengthBytes, + BaseType_t * const pxHigherPriorityTaskWoken ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + size_t xReceivedLength = 0, xBytesAvailable, xBytesToStoreMessageLength; + + configASSERT( pvRxData ); + configASSERT( pxStreamBuffer ); + + /* This receive function is used by both message buffers, which store + * discrete messages, and stream buffers, which store a continuous stream of + * bytes. Discrete messages include an additional + * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the + * message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + xBytesToStoreMessageLength = 0; + } + + xBytesAvailable = prvBytesInBuffer( pxStreamBuffer ); + + /* Whether receiving a discrete message (where xBytesToStoreMessageLength + * holds the number of bytes used to store the message length) or a stream of + * bytes (where xBytesToStoreMessageLength is zero), the number of bytes + * available must be greater than xBytesToStoreMessageLength to be able to + * read bytes from the buffer. */ + if( xBytesAvailable > xBytesToStoreMessageLength ) + { + xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable); + + /* Was a task waiting for space in the buffer? */ + if( xReceivedLength != ( size_t ) 0 ) + { + sbRECEIVE_COMPLETED_FROM_ISR( pxStreamBuffer, pxHigherPriorityTaskWoken ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ); + + return xReceivedLength; +} +/*-----------------------------------------------------------*/ + +static size_t prvReadMessageFromBuffer( StreamBuffer_t * pxStreamBuffer, + void * pvRxData, + size_t xBufferLengthBytes, + size_t xBytesAvailable ) +{ + size_t xCount, xNextMessageLength; + configMESSAGE_BUFFER_LENGTH_TYPE xTempNextMessageLength; + size_t xNextTail = pxStreamBuffer->xTail; + + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + /* A discrete message is being received. First receive the length + * of the message. */ + xNextTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempNextMessageLength, sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextTail ); + xNextMessageLength = ( size_t ) xTempNextMessageLength; + + /* Reduce the number of bytes available by the number of bytes just + * read out. */ + xBytesAvailable -= sbBYTES_TO_STORE_MESSAGE_LENGTH; + + /* Check there is enough space in the buffer provided by the + * user. */ + if( xNextMessageLength > xBufferLengthBytes ) + { + /* The user has provided insufficient space to read the message. */ + xNextMessageLength = 0; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* A stream of bytes is being received (as opposed to a discrete + * message), so read as many bytes as possible. */ + xNextMessageLength = xBufferLengthBytes; + } + + /* Use the minimum of the wanted bytes and the available bytes. */ + xCount = configMIN( xNextMessageLength, xBytesAvailable ); + + if( xCount != ( size_t ) 0 ) + { + /* Read the actual data and update the tail to mark the data as officially consumed. */ + pxStreamBuffer->xTail = prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) pvRxData, xCount, xNextTail); /*lint !e9079 Data storage area is implemented as uint8_t array for ease of sizing, indexing and alignment. */ + } + + return xCount; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) +{ + const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + BaseType_t xReturn; + size_t xTail; + + configASSERT( pxStreamBuffer ); + + /* True if no bytes are available. */ + xTail = pxStreamBuffer->xTail; + + if( pxStreamBuffer->xHead == xTail ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) +{ + BaseType_t xReturn; + size_t xBytesToStoreMessageLength; + const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + + configASSERT( pxStreamBuffer ); + + /* This generic version of the receive function is used by both message + * buffers, which store discrete messages, and stream buffers, which store a + * continuous stream of bytes. Discrete messages include an additional + * sbBYTES_TO_STORE_MESSAGE_LENGTH bytes that hold the length of the message. */ + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) + { + xBytesToStoreMessageLength = sbBYTES_TO_STORE_MESSAGE_LENGTH; + } + else + { + xBytesToStoreMessageLength = 0; + } + + /* True if the available space equals zero. */ + if( xStreamBufferSpacesAvailable( xStreamBuffer ) <= xBytesToStoreMessageLength ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, + BaseType_t * pxHigherPriorityTaskWoken ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + BaseType_t xReturn; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( pxStreamBuffer ); + + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( ( pxStreamBuffer )->xTaskWaitingToReceive != NULL ) + { + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToReceive, + ( uint32_t ) 0, + eNoAction, + pxHigherPriorityTaskWoken ); + ( pxStreamBuffer )->xTaskWaitingToReceive = NULL; + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, + BaseType_t * pxHigherPriorityTaskWoken ) +{ + StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; + BaseType_t xReturn; + UBaseType_t uxSavedInterruptStatus; + + configASSERT( pxStreamBuffer ); + + uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); + { + if( ( pxStreamBuffer )->xTaskWaitingToSend != NULL ) + { + ( void ) xTaskNotifyFromISR( ( pxStreamBuffer )->xTaskWaitingToSend, + ( uint32_t ) 0, + eNoAction, + pxHigherPriorityTaskWoken ); + ( pxStreamBuffer )->xTaskWaitingToSend = NULL; + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static size_t prvWriteBytesToBuffer( StreamBuffer_t * const pxStreamBuffer, + const uint8_t * pucData, + size_t xCount, + size_t xHead ) +{ + size_t xFirstLength; + + configASSERT( xCount > ( size_t ) 0 ); + + /* Calculate the number of bytes that can be added in the first write - + * which may be less than the total number of bytes that need to be added if + * the buffer will wrap back to the beginning. */ + xFirstLength = configMIN( pxStreamBuffer->xLength - xHead, xCount ); + + /* Write as many bytes as can be written in the first write. */ + configASSERT( ( xHead + xFirstLength ) <= pxStreamBuffer->xLength ); + ( void ) memcpy( ( void * ) ( &( pxStreamBuffer->pucBuffer[ xHead ] ) ), ( const void * ) pucData, xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + + /* If the number of bytes written was less than the number that could be + * written in the first write... */ + if( xCount > xFirstLength ) + { + /* ...then write the remaining bytes to the start of the buffer. */ + configASSERT( ( xCount - xFirstLength ) <= pxStreamBuffer->xLength ); + ( void ) memcpy( ( void * ) pxStreamBuffer->pucBuffer, ( const void * ) &( pucData[ xFirstLength ] ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + xHead += xCount; + + if( xHead >= pxStreamBuffer->xLength ) + { + xHead -= pxStreamBuffer->xLength; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xHead; +} +/*-----------------------------------------------------------*/ + +static size_t prvReadBytesFromBuffer( StreamBuffer_t * pxStreamBuffer, + uint8_t * pucData, + size_t xCount, + size_t xTail ) +{ + size_t xFirstLength; + + configASSERT( xCount != ( size_t ) 0 ); + + /* Calculate the number of bytes that can be read - which may be + * less than the number wanted if the data wraps around to the start of + * the buffer. */ + xFirstLength = configMIN( pxStreamBuffer->xLength - xTail, xCount ); + + /* Obtain the number of bytes it is possible to obtain in the first + * read. Asserts check bounds of read and write. */ + configASSERT( xFirstLength <= xCount ); + configASSERT( ( xTail + xFirstLength ) <= pxStreamBuffer->xLength ); + ( void ) memcpy( ( void * ) pucData, ( const void * ) &( pxStreamBuffer->pucBuffer[ xTail ] ), xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + + /* If the total number of wanted bytes is greater than the number + * that could be read in the first read... */ + if( xCount > xFirstLength ) + { + /* ...then read the remaining bytes from the start of the buffer. */ + configASSERT( xCount <= xCount ); + ( void ) memcpy( ( void * ) &( pucData[ xFirstLength ] ), ( void * ) ( pxStreamBuffer->pucBuffer ), xCount - xFirstLength ); /*lint !e9087 memcpy() requires void *. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Move the tail pointer to effectively remove the data read from the buffer. */ + xTail += xCount; + + if( xTail >= pxStreamBuffer->xLength ) + { + xTail -= pxStreamBuffer->xLength; + } + + return xTail; +} +/*-----------------------------------------------------------*/ + +static size_t prvBytesInBuffer( const StreamBuffer_t * const pxStreamBuffer ) +{ +/* Returns the distance between xTail and xHead. */ + size_t xCount; + + xCount = pxStreamBuffer->xLength + pxStreamBuffer->xHead; + xCount -= pxStreamBuffer->xTail; + + if( xCount >= pxStreamBuffer->xLength ) + { + xCount -= pxStreamBuffer->xLength; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + return xCount; +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer, + uint8_t * const pucBuffer, + size_t xBufferSizeBytes, + size_t xTriggerLevelBytes, + uint8_t ucFlags ) +{ + /* Assert here is deliberately writing to the entire buffer to ensure it can + * be written to without generating exceptions, and is setting the buffer to a + * known value to assist in development/debugging. */ + #if ( configASSERT_DEFINED == 1 ) + { + /* The value written just has to be identifiable when looking at the + * memory. Don't use 0xA5 as that is the stack fill value and could + * result in confusion as to what is actually being observed. */ + const BaseType_t xWriteValue = 0x55; + configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer ); + } /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */ + #endif + + ( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */ + pxStreamBuffer->pucBuffer = pucBuffer; + pxStreamBuffer->xLength = xBufferSizeBytes; + pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes; + pxStreamBuffer->ucFlags = ucFlags; +} + +#if ( configUSE_TRACE_FACILITY == 1 ) + + UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) + { + return xStreamBuffer->uxStreamBufferNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, + UBaseType_t uxStreamBufferNumber ) + { + xStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber; + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_TRACE_FACILITY == 1 ) + + uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) + { + return( xStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ); + } + +#endif /* configUSE_TRACE_FACILITY */ +/*-----------------------------------------------------------*/ From 6b72419c789dfee9070186f18bd145a2516d9e28 Mon Sep 17 00:00:00 2001 From: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Sat, 20 Mar 2021 12:59:51 -0700 Subject: [PATCH 15/20] Fix error introduced when merging #264. (#286) --- stream_buffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stream_buffer.c b/stream_buffer.c index 382dd08e6..531cd4c6e 100644 --- a/stream_buffer.c +++ b/stream_buffer.c @@ -496,7 +496,7 @@ size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) { const StreamBuffer_t * const pxStreamBuffer = xStreamBuffer; size_t xSpace; - volatile size_t xOriginalTail; + size_t xOriginalTail; configASSERT( pxStreamBuffer ); @@ -726,7 +726,7 @@ static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, { size_t xNextHead = pxStreamBuffer->xHead; - if( xDataLengthBytes != xRequiredSpace ) + if( ( pxStreamBuffer->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER ) != ( uint8_t ) 0 ) { /* This is a message buffer, as opposed to a stream buffer. */ @@ -735,7 +735,7 @@ static size_t prvWriteMessageToBuffer( StreamBuffer_t * const pxStreamBuffer, /* There is enough space to write both the message length and the message * itself into the buffer. Start by writing the length of the data, the data * itself will be written later in this function. */ - xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead); + xNextHead = prvWriteBytesToBuffer( pxStreamBuffer, ( const uint8_t * ) &( xDataLengthBytes ), sbBYTES_TO_STORE_MESSAGE_LENGTH, xNextHead ); } else { @@ -883,7 +883,7 @@ size_t xStreamBufferNextMessageLengthBytes( StreamBufferHandle_t xStreamBuffer ) /* The number of bytes available is greater than the number of bytes * required to hold the length of the next message, so another message * is available. */ - ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, pxStreamBuffer->xTail); + ( void ) prvReadBytesFromBuffer( pxStreamBuffer, ( uint8_t * ) &xTempReturn, sbBYTES_TO_STORE_MESSAGE_LENGTH, pxStreamBuffer->xTail ); xReturn = ( size_t ) xTempReturn; } else @@ -939,7 +939,7 @@ size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, * read bytes from the buffer. */ if( xBytesAvailable > xBytesToStoreMessageLength ) { - xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable); + xReceivedLength = prvReadMessageFromBuffer( pxStreamBuffer, pvRxData, xBufferLengthBytes, xBytesAvailable ); /* Was a task waiting for space in the buffer? */ if( xReceivedLength != ( size_t ) 0 ) From 9cd19603e8c055e22105e28c2dace4d55b1e420b Mon Sep 17 00:00:00 2001 From: alfred gedeon <28123637+alfred2g@users.noreply.github.com> Date: Sun, 21 Mar 2021 09:03:38 -0700 Subject: [PATCH 16/20] Code: Remove redundant check (#287) --- timers.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/timers.c b/timers.c index eb4229695..203a07778 100644 --- a/timers.c +++ b/timers.c @@ -350,27 +350,24 @@ /* 0 is not a valid value for xTimerPeriodInTicks. */ configASSERT( ( xTimerPeriodInTicks > 0 ) ); - if( pxNewTimer != NULL ) + /* Ensure the infrastructure used by the timer service task has been + * created/initialised. */ + prvCheckForValidListAndQueue(); + + /* Initialise the timer structure members using the function + * parameters. */ + pxNewTimer->pcTimerName = pcTimerName; + pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; + pxNewTimer->pvTimerID = pvTimerID; + pxNewTimer->pxCallbackFunction = pxCallbackFunction; + vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + + if( uxAutoReload != pdFALSE ) { - /* Ensure the infrastructure used by the timer service task has been - * created/initialised. */ - prvCheckForValidListAndQueue(); - - /* Initialise the timer structure members using the function - * parameters. */ - pxNewTimer->pcTimerName = pcTimerName; - pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; - pxNewTimer->pvTimerID = pvTimerID; - pxNewTimer->pxCallbackFunction = pxCallbackFunction; - vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); - - if( uxAutoReload != pdFALSE ) - { - pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; - } - - traceTIMER_CREATE( pxNewTimer ); + pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; } + + traceTIMER_CREATE( pxNewTimer ); } /*-----------------------------------------------------------*/ From 4ad84923a0279a93d579957171b286c56d66b5d0 Mon Sep 17 00:00:00 2001 From: Paul Bartell Date: Tue, 23 Mar 2021 10:33:47 -0700 Subject: [PATCH 17/20] Build the posix port on pushes and PRs to the Kernel repository (#290) * Run posix build action when new commits are pushed to the FreeRTOS/Kernel repository * Run kernel unit tests on push and pull_request actions --- .github/workflows/kernel-checks.yml | 27 ++++++++++++++++++++++++++- .github/workflows/unit-tests.yml | 4 ++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/workflows/kernel-checks.yml b/.github/workflows/kernel-checks.yml index df2563e98..e17276048 100644 --- a/.github/workflows/kernel-checks.yml +++ b/.github/workflows/kernel-checks.yml @@ -1,6 +1,6 @@ name: Kernel-Checker -on: [pull_request] +on: [push, pull_request] jobs: kernel-checker: @@ -45,3 +45,28 @@ jobs: cd inspect .github/scripts/kernel_checker.py --json ${HOME}/files_modified.json ${HOME}/files_added.json ${HOME}/files_renamed.json exit $? + build-checker: + name: FreeRTOS Posix Build Check + runs-on: ubuntu-latest + steps: + - name: Checkout the parent repository + uses: actions/checkout@v2 + with: + ref: master + repository: FreeRTOS/FreeRTOS + submodules: 'recursive' + fetch-depth: 1 + path: ./workspace + - name: Checkout the current repository + uses: actions/checkout@v2 + with: + path: ./workspace/FreeRTOS/Source + - name: Posix Build Checker + run: | + bash workspace/.github/scripts/posix_build_checker.sh workspace + - name: Install lib pcap dev + run: | + sudo apt-get install libpcap-dev + - name: Posix Network Build Checker + run: | + bash workspace/.github/scripts/posix_network_build_checker.sh workspace diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 7c4fa8ffb..3a498d6ee 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -1,11 +1,11 @@ name: CMock Unit Tests -on: [push] +on: [push, pull_request] jobs: run: runs-on: ubuntu-latest steps: - - name: Checkout Parent Repo + - name: Checkout Parent Repository uses: actions/checkout@v2 with: ref: master From 9efe10b805e3516974dd5eba2d61bfa071ff8392 Mon Sep 17 00:00:00 2001 From: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Wed, 24 Mar 2021 17:04:20 -0700 Subject: [PATCH 18/20] Add assert to catch invalid task priority (#292) * Add assert to catch invalid task priority Signed-off-by: Gaurav Aggarwal --- tasks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasks.c b/tasks.c index 988e32bdb..a1a6aaca0 100644 --- a/tasks.c +++ b/tasks.c @@ -913,8 +913,8 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, pxNewTCB->pcTaskName[ 0 ] = 0x00; } - /* This is used as an array index so must ensure it's not too large. First - * remove the privilege bit if one is present. */ + /* This is used as an array index so must ensure it's not too large. */ + configASSERT( uxPriority < configMAX_PRIORITIES ); if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) { uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; @@ -1544,7 +1544,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry; BaseType_t xYieldRequired = pdFALSE; - configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); + configASSERT( uxNewPriority < configMAX_PRIORITIES ); /* Ensure the new priority is valid. */ if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) From 9b679c347c9df320afca71ed137ff38906b3d203 Mon Sep 17 00:00:00 2001 From: Paul Bartell Date: Thu, 25 Mar 2021 12:39:08 -0700 Subject: [PATCH 19/20] Fix comments in list.h and clarify list usage in xTaskRemoveFromEventList (#289) * Change instances of "descending" to "ascending" to match implementation. * Uncrustify * Clarify list usage in xTaskRemoveFromEventList --- include/list.h | 32 ++++++++++++++++---------------- tasks.c | 12 +++++++++--- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/include/list.h b/include/list.h index d8a498841..6f5d15dc7 100644 --- a/include/list.h +++ b/include/list.h @@ -31,7 +31,7 @@ * * list_ts can only store pointers to list_item_ts. Each ListItem_t contains a * numeric value (xItemValue). Most of the time the lists are sorted in - * descending item value order. + * ascending item value order. * * Lists are created already containing one list item. The value of this * item is the maximum possible that can be stored, it is therefore always at @@ -141,19 +141,19 @@ struct xLIST; struct xLIST_ITEM { - listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ - configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ - struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ - struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ - void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ - struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */ - listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in ascending order. */ + struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ + struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ + void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */ + struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */ + listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ }; -typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */ +typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */ struct xMINI_LIST_ITEM { - listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE TickType_t xItemValue; struct xLIST_ITEM * configLIST_VOLATILE pxNext; struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; @@ -165,11 +165,11 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t; */ typedef struct xLIST { - listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ volatile UBaseType_t uxNumberOfItems; - ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ - MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ - listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ + ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ + MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ + listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ } List_t; /* @@ -192,7 +192,7 @@ typedef struct xLIST /* * Access macro to set the value of the list item. In most cases the value is - * used to sort the list in descending order. + * used to sort the list in ascending order. * * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE * \ingroup LinkedList @@ -359,7 +359,7 @@ void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION; /* * Insert a list item into a list. The item will be inserted into the list in - * a position determined by its item value (descending item value order). + * a position determined by its item value (ascending item value order). * * @param pxList The list into which the item is to be inserted. * diff --git a/tasks.c b/tasks.c index a1a6aaca0..c7be57cb2 100644 --- a/tasks.c +++ b/tasks.c @@ -295,7 +295,6 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to #endif #if ( configUSE_NEWLIB_REENTRANT == 1 ) - /* Allocate a Newlib reent structure that is specific to this task. * Note Newlib support has been included by popular demand, but is not * used by the FreeRTOS maintainers themselves. FreeRTOS is not @@ -3093,8 +3092,15 @@ void vTaskPlaceOnEventList( List_t * const pxEventList, /* Place the event list item of the TCB in the appropriate event list. * This is placed in the list in priority order so the highest priority task - * is the first to be woken by the event. The queue that contains the event - * list is locked, preventing simultaneous access from interrupts. */ + * is the first to be woken by the event. + * + * Note: Lists are sorted in ascending order by ListItem_t.xItemValue. + * Normally, the xItemValue of a TCB's ListItem_t members is: + * xItemValue = ( configMAX_PRIORITIES - uxPriority ) + * Therefore, the event list is sorted in descending priority order. + * + * The queue that contains the event list is locked, preventing + * simultaneous access from interrupts. */ vListInsert( pxEventList, &( pxCurrentTCB->xEventListItem ) ); prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); From 534eba66ce4a5bda45d5edeeb81ac5a3cf6d0df8 Mon Sep 17 00:00:00 2001 From: Ming Yue Date: Thu, 25 Mar 2021 15:57:42 -0700 Subject: [PATCH 20/20] Check NULL pointer input for vEventGroupDelete. (#293) * Check NULL pointer input for vEventGroupDelete. * Change the input parameter check with assertion. Co-authored-by: Cobus van Eeden <35851496+cobusve@users.noreply.github.com> --- event_groups.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/event_groups.c b/event_groups.c index 0ee799067..4a12430c1 100644 --- a/event_groups.c +++ b/event_groups.c @@ -625,6 +625,8 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, void vEventGroupDelete( EventGroupHandle_t xEventGroup ) { + configASSERT( xEventGroup ); + EventGroup_t * pxEventBits = xEventGroup; const List_t * pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );