diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h index 2cfcbbfd56..965dabad9d 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h @@ -1253,8 +1253,8 @@ extern void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t si trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCFAILED, TASK, pxCurrentTCB, xTicksToWait); \ } #else /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ -#define traceTASK_NOTIFY_TAKE() \ - if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED){ \ +#define traceTASK_NOTIFY_TAKE( index ) \ + if (pxCurrentTCB->ucNotifyState[ ( index ) ] == taskNOTIFICATION_RECEIVED){ \ trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE, TASK, pxCurrentTCB, xTicksToWait); \ }else{ \ trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCFAILED, TASK, pxCurrentTCB, xTicksToWait);} @@ -1276,10 +1276,10 @@ extern void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t si prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCFAILED, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ } #else /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ -#define traceTASK_NOTIFY_WAIT() \ +#define traceTASK_NOTIFY_WAIT( index ) \ if (TRACE_GET_OBJECT_FILTER(TASK, pxCurrentTCB) & CurrentFilterMask) \ { \ - if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED) \ + if (pxCurrentTCB->ucNotifyState[ ( index ) ] == taskNOTIFICATION_RECEIVED) \ prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ else \ prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCFAILED, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ diff --git a/FreeRTOS/Demo/Common/Minimal/TaskNotifyArray.c b/FreeRTOS/Demo/Common/Minimal/TaskNotifyArray.c new file mode 100644 index 0000000000..a8789e3018 --- /dev/null +++ b/FreeRTOS/Demo/Common/Minimal/TaskNotifyArray.c @@ -0,0 +1,1234 @@ +/* + * FreeRTOS Kernel V10.3.1 + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/* + * Tests the behaviour of arrays of task notifications per task. The tests in this + * file are additive to those implemented in FreeRTOS/Demo/Common/Minimal/TaskNotify.c. + */ + +/* Standard includes. */ +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" + +/* Demo program include files. */ +#include "TaskNotifyArray.h" + +#if( configTASK_NOTIFICATION_ARRAY_ENTRIES < 3 ) + #error This file tests direct to task notification arrays and needs configTASK_NOTIFICATION_ARRAY_ENTRIES to be at least 3. +#endif + +/* Allow parameters to be overridden on a demo by demo basis. */ +#ifndef notifyNOTIFY_ARRAY_TASK_STACK_SIZE + #define notifyNOTIFY_ARRAY_TASK_STACK_SIZE configMINIMAL_STACK_SIZE +#endif + +#define notifyTASK_PRIORITY ( tskIDLE_PRIORITY ) + +/* Constants used in tests when setting/clearing bits. */ +#define notifyUINT32_MAX ( ( uint32_t ) 0xffffffff ) +#define notifyUINT32_HIGH_BYTE ( ( uint32_t ) 0xff000000 ) +#define notifyUINT32_LOW_BYTE ( ( uint32_t ) 0x000000ff ) + +/*-----------------------------------------------------------*/ + +/* + * Implementation of the task that runs the tests - the task runs some tests + * itself, and others where notifications are sent from a software timer or + * an interrupt (specifically the tick hook function). + */ +static void prvNotifiedTask( void *pvParameters ); + +/* + * Performs the tests that don't require notifications to be sent from a + * remote source. + */ +static void prvSingleTaskTests( void ); + +/* + * Uses a software timer to send notifications to the task while the task is + * suspended. + */ +static void prvTestNotifyTaskWhileSuspended( void ); + +/* + * Uses a software timer to send notifications to the index within the array of + * task notifications on which the task is blocked. The task should unblock and + * the state of all the other task notifications within the array should remain + * unchanged. + */ +static void prvBlockOnTheNotifiedIndexed( void ); + +/* + * As per prvBlockOnTheNotifiedIndexed(), but this time the notification comes from + * the tick hook function, so from an interrupt rather than from a software timer. + */ +static void prvBlockOnNotificationsComingFromInterrupts( void ); + +/* + * As per prvBlockOnTheNotifiedIndexed(), except this time the notification is + * sent to an index within the task notification array on which the task is not + * blocked, so this time the task should not unblock and the state of all the + * task notifications other than the one to which the notification was actually + * sent should remain unchanged. + */ +static void prvBlockOnANonNotifiedIndexed( void ); + +/* + * Callback of the software timer used to send notifications for the + * prvBlockOnTheNotifiedIndexed() and prvBlockOnANonNotifiedIndexed() tests. + */ +static void prvNotifyingTimerCallback( TimerHandle_t xTimer ); + +/* + * Callback for a timer that is used by the prvTestNotifyTaskWhileSuspended() + * test. + */ +static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer ); + +/* + * Utility function to create pseudo random numbers. + */ +static UBaseType_t prvRand( void ); + + +/*-----------------------------------------------------------*/ + +/* Counters used to check the task has not stalled. ulFineCycleCount is +incremented within each test. ulCourseCycleCounter is incremented one every +loop of all the tests to ensure each test is actually executing. The check task +calls xAreTaskNotificationArrayTasksStillRunning() (implemented within this +file) to check both counters are changing. */ +static volatile uint32_t ulFineCycleCount = 0, ulCourseCycleCounter = 0; + +/* The handle of the task that runs the tests and receives the notifications +from the software timers and interrupts. */ +static TaskHandle_t xTaskToNotify = NULL; + +/* The software timers used to send notifications to the main test task. */ +static TimerHandle_t xIncrementingIndexTimer = NULL; +static TimerHandle_t xNotifyWhileSuspendedTimer = NULL; + +/* Used by the pseudo random number generating function. */ +static size_t uxNextRand = 0; + +/* Used to communicate when to send a task notification to the tick hook tests. */ +static volatile BaseType_t xSendNotificationFromISR = pdFALSE; + +/*-----------------------------------------------------------*/ + +void vStartTaskNotifyArrayTask( void ) +{ +const TickType_t xIncrementingIndexTimerPeriod = pdMS_TO_TICKS( 100 ); +const TickType_t xSuspendTimerPeriod = pdMS_TO_TICKS( 50 ); + + /* Create the software timers used for these tests. The timer callbacks send + notifications to this task. */ + xNotifyWhileSuspendedTimer = xTimerCreate( "SingleNotify", xSuspendTimerPeriod, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback ); + xIncrementingIndexTimer = xTimerCreate( "Notifier", xIncrementingIndexTimerPeriod, pdFALSE, NULL, prvNotifyingTimerCallback ); + configASSERT( xNotifyWhileSuspendedTimer ); + configASSERT( xIncrementingIndexTimer ); + + /* Create the task that performs some tests by itself, then loops around + being notified by both a software timer and an interrupt. */ + xTaskCreate( prvNotifiedTask, /* Function that implements the task. */ + "ArrayNotifed", /* Text name for the task - for debugging only - not used by the kernel. */ + notifyNOTIFY_ARRAY_TASK_STACK_SIZE, /* Task's stack size in words, not bytes!. */ + NULL, /* Task parameter, not used in this case. */ + notifyTASK_PRIORITY, /* Task priority, 0 is the lowest. */ + &xTaskToNotify ); /* Used to pass a handle to the task out if needed, otherwise set to NULL. */ + + /* Pseudo seed the random number generator. */ + uxNextRand = ( size_t ) prvRand; +} +/*-----------------------------------------------------------*/ + +static void prvNotifiedTask( void *pvParameters ) +{ + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* Loop through each set of test functions in turn. See the comments above + the respective function prototypes above for more details. */ + for( ;; ) + { + prvSingleTaskTests(); + prvTestNotifyTaskWhileSuspended(); + prvBlockOnTheNotifiedIndexed(); + prvBlockOnANonNotifiedIndexed(); + prvBlockOnNotificationsComingFromInterrupts(); + ulCourseCycleCounter++; + } +} +/*-----------------------------------------------------------*/ + +static void prvSingleTaskTests( void ) +{ +const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL ); +BaseType_t xReturned; +uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue, ulPreviousValue, ulExpectedValue; +TickType_t xTimeOnEntering; +const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL; +const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL; +UBaseType_t uxIndexToTest, uxOtherIndexes; + + + /* ------------------------------------------------------------------------ + Check blocking when there are no notifications. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* Send notifications to the task notification in each index of the + task notification array other than the one on which this task will + block. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes != uxIndexToTest ) + { + xTaskNotifyIndexed( xTaskToNotify, uxOtherIndexes, 0, eNoAction ); + } + } + + xTimeOnEntering = xTaskGetTickCount(); + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* Should have blocked for the entire block time. */ + configASSERT( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait ); + configASSERT( xReturned == pdFAIL ); + configASSERT( ulNotifiedValue == 0UL ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) ulNotifiedValue; + + /* Clear all the other notifications within the array of task + notifications again ready for the next round. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes != uxIndexToTest ) + { + xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes ); + + /* The notification state was set above so expect it to still be + set. */ + configASSERT( xReturned == pdTRUE ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + } + + + + /* ------------------------------------------------------------------------ + Check no blocking when notifications are pending. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* First notify the task notification at index uxIndexToTest within this + task's own array of task notifications - this would not be a normal + thing to do and is done here for test purposes only. */ + xReturned = xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue ); + + /* Even through the 'without overwrite' action was used the update should + have been successful. */ + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* No bits should have been pending previously. */ + configASSERT( ulPreviousValue == 0 ); + ( void ) ulPreviousValue; + + /* The task should now have a notification pending in the task + notification at index uxIndexToTest within the task notification array, + and so not time out. */ + xTimeOnEntering = xTaskGetTickCount(); + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait ); + configASSERT( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait ); + + /* The task should have been notified, and the notified value should + be equal to ulFirstNotifiedConst. */ + configASSERT( xReturned == pdPASS ); + configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) ulNotifiedValue; + } + + + + + /*------------------------------------------------------------------------- + Check the non-overwriting functionality. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* Send notifications to all indexes with the array of task + notificaitons other than the one on which this task will block. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes != uxIndexToTest ) + { + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxOtherIndexes, ulFirstNotifiedConst, eSetValueWithOverwrite ); + configASSERT(xReturned == pdPASS); + (void)xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + + /* The notification is performed twice using two different notification + values. The action says don't overwrite so only the first notification + should pass and the value read back should also be that used with the + first notification. The notification is sent to the task notification at + index uxIndexToTest within the array of task notifications. */ + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite ); + configASSERT( xReturned == pdFAIL ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* Waiting for the notification should now return immediately so a block + time of zero is used. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, 0 ); + + configASSERT( xReturned == pdPASS ); + configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) ulNotifiedValue; + + /* Clear all the other task notifications within the array of task + notifications again ready for the next round. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes != uxIndexToTest ) + { + xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes ); + configASSERT( xReturned == pdTRUE ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + ulNotifiedValue = ulTaskNotifyValueClearIndexed( xTaskToNotify, uxOtherIndexes, notifyUINT32_MAX ); + + /* The notification value was set to ulFirstNotifiedConst in all + the other indexes, so expect it to still have that value. */ + configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + } + + + + + /*------------------------------------------------------------------------- + Do the same again, only this time use the overwriting version. This time + both notifications should pass, and the value written the second time should + overwrite the value written the first time, and so be the value that is read + back. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes != uxIndexToTest ) + { + xTaskNotifyIndexed( xTaskToNotify, uxOtherIndexes, ulFirstNotifiedConst, eSetValueWithOverwrite ); + } + } + + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithOverwrite ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithOverwrite ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, notifyUINT32_MAX, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst ); + ( void ) ulNotifiedValue; + + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes != uxIndexToTest ) + { + xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes ); + configASSERT( xReturned == pdTRUE ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + ulNotifiedValue = ulTaskNotifyValueClearIndexed( xTaskToNotify, uxOtherIndexes, notifyUINT32_MAX ); + configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + } + + + + + /*------------------------------------------------------------------------- + For each task notification within the array of task notifications, check + notifications with no action pass without updating the value. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* First set the notification values of the task notification at index + uxIndexToTest of the array of task notification to + ulSecondNotifiedValueConst. */ + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithOverwrite ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* Even though ulFirstNotifiedConst is used as the value next, the value + read back should remain at ulSecondNotifiedConst as the action is set + to eNoAction. */ + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eNoAction ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* All task notifications in the array of task notifications up to and + including index uxIndexToTest should still contain the same value. */ + for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) + { + /* First zero is bits to clear on entry, the second is bits to clear on + exist, the last 0 is the block time. */ + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); + configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + + /* All array indexes in the array of task notifications after index + uxIndexToTest should still contain 0 as they have not been set in this + loop yet. This time use ulTaskNotifyValueClearIndexed() instead of + xTaskNotifyWaitIndexed(), just for test coverage. */ + for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + /* This time 0 is the bits to clear parameter - so clearing no bits. */ + ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 ); + configASSERT( ulNotifiedValue == 0 ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + + + + + /*------------------------------------------------------------------------- + Check incrementing values. For each task notification in the array of task + notifications in turn, send ulMaxLoop increment notifications, then ensure + the received value is as expected - which should be + ulSecondNotificationValueConst plus how ever many times to loop iterated. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ ) + { + /* Increment the value of the task notification at index + uxIndexToTest within the array of task notifications. */ + xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eIncrement ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + + /* All array indexes up to and including uxIndexToTest should still + contain the updated value. */ + for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) + { + /* First zero is bits to clear on entry, the second is bits to clear on + exist, the last 0 is the block time. */ + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); + configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + + /* Should not be any notifications pending now. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdFAIL ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) ulNotifiedValue; + + /* All notifications values in the array of task notifications after + index uxIndexToTest should still contain the un-incremented + ulSecondNotifiedValueConst as they have not been set in this loop yet. + This time use ulTaskNotifyValueClearIndexed() instead of xTaskNotifyWaitIndexed(), + just for test coverage. */ + for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + /* This time 0 is the bits to clear parameter - so clearing no bits. */ + ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 ); + configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + + /* Clear all bits ready for next test. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* Start with all bits clear. */ + ulTaskNotifyValueClearIndexed( NULL, uxIndexToTest, notifyUINT32_MAX ); + } + + + + /*------------------------------------------------------------------------- + For each task notification in the array of task notifications in turn, check + all bits in the notification's value can be set by notifying the task with + one additional bit set on each notification, and exiting the loop when all + the bits are found to be set. As there are 32-bits the loop should execute + 32 times before all the bits are found to be set. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + ulNotifyingValue = 0x01; + ulLoop = 0; + + do + { + /* Set the next bit in the value of the task notification at index + uxIndexToTest within the array of task notifications. */ + xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulNotifyingValue, eSetBits ); + + /* Wait for the notified value - which of course will already be + available. Don't clear the bits on entry or exit as this loop is + exited when all the bits are set. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + ulLoop++; + + /* Use the next bit on the next iteration around this loop. */ + ulNotifyingValue <<= 1UL; + + } while ( ulNotifiedValue != notifyUINT32_MAX ); + + /* As a 32-bit value was used the loop should have executed 32 times before + all the bits were set. */ + configASSERT( ulLoop == 32 ); + + /* The value of each task notification within the array of task + notifications up to and including index uxIndexToTest should still have + all bits set. */ + for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) + { + /* First zero is bits to clear on entry, the second is bits to clear on + exist, the last 0 is the block time. */ + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); + configASSERT( ulNotifiedValue == notifyUINT32_MAX ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + + /* The value of each task notification within the array of task + notifications after index uxIndexToTest should still contain 0 as they + have not been set in this loop yet. This time use ulTaskNotifyValueClearIndexed() + instead of xTaskNotifyWaitIndexed(), just for test coverage. */ + for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + /* This time 0 is the bits to clear parameter - so clearing no bits. */ + ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 ); + configASSERT( ulNotifiedValue == 0 ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + + + + /*------------------------------------------------------------------------- + For each task notification within the array of task notifications in turn, + check bits are cleared on entry but not on exit when a notification fails + to arrive before timing out - both with and without a timeout value. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* Wait for the notification - but this time it is not given by anything + and should return pdFAIL. The parameters are set to clear bit zero on + entry and bit one on exit. As no notification was received only the bit + cleared on entry should actually get cleared. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait ); + configASSERT( xReturned == pdFAIL ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* Send a notification with no action to the task notification at index + uxIndexToTest within the array of task notifications. This should not + update the bits even though notifyUINT32_MAX is used as the notification + value. */ + xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eNoAction ); + + /* All array indexes up to and including uxIndexToTest within the array + of task notifications should have the modified value. */ + for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) + { + /* Reading back the value should find bit 0 is clear, as this was cleared + on entry, but bit 1 is not clear as it will not have been cleared on exit + as no notification was received. */ + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0x00UL, 0x00UL, &ulNotifiedValue, 0 ); + if( uxOtherIndexes == uxIndexToTest ) + { + /* This is the index being used this time round the loop and its + notification state was set immediately above. */ + configASSERT( xReturned == pdPASS ); + } + else + { + /* Nothing should have set this index's notification state again. */ + configASSERT( xReturned == pdFAIL ); + } + + configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + + /* All array indexes after uxIndexToTest should still contain notifyUINT32_MAX + left over from the previous test. This time use xTaskNotifyValueClear() + instead of xTaskNotifyWaitIndexed(), just for test coverage. */ + for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + /* This time 0 is the bits to clear parameter - so clearing no bits. */ + ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 ); + configASSERT( ulNotifiedValue == notifyUINT32_MAX ); + ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + + + + + /*------------------------------------------------------------------------- + Now try clearing the bit on exit. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* The task is notified first using the task notification at index + uxIndexToTest within the array of task notifications. */ + xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eNoAction ); + xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, ulBit1, &ulNotifiedValue, 0 ); + + /* However as the bit is cleared on exit, after the returned notification + value is set, the returned notification value should not have the bit + cleared... */ + configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) ); + + /* ...but reading the value back again should find that the bit was indeed + cleared internally. The returned value should be pdFAIL however as nothing + has notified the task in the mean time. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, 0x00, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdFAIL ); + configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* No other indexes should have a notification pending. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes != uxIndexToTest ) + { + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0x00UL, 0x00UL, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdFAIL ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + } + } + + + + /*------------------------------------------------------------------------- + For each task notification within the array of task notifications, try + querying the previous value while notifying a task. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, 0x00, eSetBits, &ulPreviousValue ); + configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) ); + + /* Clear all bits. */ + xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 ); + xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, 0x00, eSetBits, &ulPreviousValue ); + configASSERT( ulPreviousValue == 0 ); + + ulExpectedValue = 0; + for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL ) + { + /* Set the next bit up, and expect to receive the last bits set (so + the previous value will not yet have the bit being set this time + around). */ + xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulLoop, eSetBits, &ulPreviousValue ); + configASSERT( ulExpectedValue == ulPreviousValue ); + ulExpectedValue |= ulLoop; + } + } + + + /* ---------------------------------------------------------------------- */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* Clear the previous notifications. */ + xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, 0 ); + } + + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* No task notification within the array of task notifications should + have any notification pending, so an attempt to clear the notification + state should fail. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdFALSE ); + } + + /* Get the task to notify itself using the task notification at index + uxIndexToTest within the array of task notifications. This is not a + normal thing to do, and is only done here for test purposes. */ + xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue ); + + /* Now the notification state should be eNotified, so it should now be + possible to clear the notification state. Other indexes should still + not have a notification pending - likewise uxIndexToTest should not have + a notification pending once it has been cleared. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + if( uxOtherIndexes == uxIndexToTest ) + { + configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdTRUE ); + } + + configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdFALSE ); + } + } + + + /* ------------------------------------------------------------------------ + For each task notification within the array of task notifications, clear + bits in the notification value. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* Get the task to set all bits in its task notification at index + uxIndexToTest within its array of task notifications. This is not a + normal thing to do, and is only done here for test purposes. */ + xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eSetBits ); + + /* Now clear the top bytes - the returned value from the first call + should indicate that previously all bits were set. */ + configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX ); + + /* Next clear the bottom bytes - the returned value this time should + indicate that the top byte was clear (before the bottom byte was + cleared. */ + configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) ); + + /* Next clear all bytes - the returned value should indicate that previously the + high and low bytes were clear. */ + configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) ); + + /* Now all bits should be clear. */ + configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == 0 ); + configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, 0UL ) == 0 ); + configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == 0 ); + + /* Now the notification state should be eNotified, so it should now be + possible to clear the notification state. */ + configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdTRUE ); + configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdFALSE ); + } + + + + + /* Incremented to show the task is still running. */ + ulFineCycleCount++; + + /* Leave all bits cleared. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, NULL, 0 ); + } +} +/*-----------------------------------------------------------*/ + +static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer ) +{ +static uint32_t ulCallCount = 0; +static UBaseType_t uxIndexToNotify = 0; + + /* Remove compiler warnings about unused parameters. */ + ( void ) xExpiredTimer; + + /* Callback for a timer that is used to send notifications to a task while + it is suspended. The timer tests the behaviour when 1: a task waiting for a + notification is suspended and then resumed without ever receiving a + notification, and 2: when a task waiting for a notification receives a + notification while it is suspended. Run one of two tests on every other + invocation of this callback. The notification is sent to the task + notification at index uxIndexToNotify. */ + if( ( ulCallCount & 0x01 ) == 0 ) + { + vTaskSuspend( xTaskToNotify ); + configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended ); + vTaskResume( xTaskToNotify ); + } + else + { + vTaskSuspend( xTaskToNotify ); + + /* Sending a notification while the task is suspended should pass, but + not cause the task to resume. */ + xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 1, eSetValueWithOverwrite ); + + /* Use the next task notification within the array of task notifications + the next time around. */ + uxIndexToNotify++; + if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES ) + { + uxIndexToNotify = 0; + } + + /* Make sure giving the notification didn't resume the task. */ + configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended ); + + vTaskResume( xTaskToNotify ); + } + + ulCallCount++; +} +/*-----------------------------------------------------------*/ + +static void prvNotifyingTimerCallback( TimerHandle_t xNotUsed ) +{ +static BaseType_t uxIndexToNotify = 0; + + ( void ) xNotUsed; + + /* "Give" the task notification (which increments the target task + notification value) at index uxIndexToNotify within the array of task + notifications. */ + xTaskNotifyGiveIndexed( xTaskToNotify, uxIndexToNotify ); + + /* Use the next task notification within the array of task notifications the + next time around. */ + uxIndexToNotify++; + if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES ) + { + uxIndexToNotify = 0; + } +} +/*-----------------------------------------------------------*/ + +static void prvTestNotifyTaskWhileSuspended( void ) +{ +UBaseType_t uxIndexToTest, uxOtherIndexes; +BaseType_t xReturned; +uint32_t ulNotifiedValue; + + /* Raise the task's priority so it can suspend itself before the timer + expires. */ + vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); + + /* Perform the test on each task notification within the array or task + notifications. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + /* Ensure no notifications within the array of task notifications are + pending. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, NULL, 0 ); + configASSERT( xReturned == pdFALSE ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + + /* Start the timer that will try notifying this task while it is + suspended, then wait for a notification. The first time the callback + executes the timer will suspend the task, then resume the task, without + ever sending a notification to the task. */ + ulNotifiedValue = 0; + xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY ); + + /* Check a notification is not received on the task notification at + index uxIndexToTest within the array of task notifications. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY ); + configASSERT( xReturned == pdFALSE ); + configASSERT( ulNotifiedValue == 0 ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* Check none of the task notifications within the array of task + notifications as been notified. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdFALSE ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + } + + /* Start the timer that will try notifying this task while it is + suspended, then wait for a notification at index uxIndexToTest within + the array of task notifications. The second time the callback executes + the timer will suspend the task, notify the task, then resume the task + (previously it was suspended and resumed without being notified). */ + xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY ); + + /* Check a notification is only received in the index within the array + of task notifications under test. */ + xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY ); + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + configASSERT( ulNotifiedValue != 0 ); + + /* Check a notification is not received in any index within the array + of task notifications at and below the index being tested have a notification + value, and that indexes above the index being tested to not have + notification values. */ + for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) + { + xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); + configASSERT( xReturned == pdFALSE ); + + if( uxOtherIndexes <= uxIndexToTest ) + { + configASSERT( ulNotifiedValue == 1 ); + } + else + { + configASSERT( ulNotifiedValue == 0 ); + } + ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) ulNotifiedValue; + } + } + + /* Return the task to its proper priority */ + vTaskPrioritySet( NULL, notifyTASK_PRIORITY ); + + /* Incremented to show the task is still running. */ + ulFineCycleCount++; + + /* Leave all bits cleared. */ + for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) + { + xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, NULL, 0 ); + } +} +/* ------------------------------------------------------------------------ */ + +static void prvBlockOnTheNotifiedIndexed( void ) +{ +const TickType_t xTimerPeriod = pdMS_TO_TICKS( 100 ), xMargin = pdMS_TO_TICKS( 50 ), xDontBlock = 0; +UBaseType_t uxIndex, uxIndexToNotify; +uint32_t ulReceivedValue; +BaseType_t xReturned; + + /* Set the value of each notification in the array of task notifications to + the value of its index position plus 1 so everything starts in a known + state, then clear the notification state ready for the next test. Plus 1 is + used because the index under test will use 0. */ + for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) + { + xTaskNotifyIndexed( xTaskToNotify, uxIndex, uxIndex + 1, eSetValueWithOverwrite ); + xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndex ); + } + + /* Peform the test on each task notification within the array of task + notifications. */ + for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) + { + /* Set the notification value of the index being tested to 0 so the + notification value increment/decrement functions can be tested. */ + xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 0, eSetValueWithOverwrite ); + xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify ); + + /* Start the software timer then wait for it to notify this task. Block + on the notification index we expect to receive the notification on. The + margin is to ensure the task blocks longer than the timer period. */ + xTimerStart( xIncrementingIndexTimer, portMAX_DELAY ); + ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdFALSE, xTimerPeriod + xMargin ); + + /* The notification value was initially zero, and should have been + incremented by the software timer, so now one. It will also have been + decremented again by the call to ulTaskNotifyTakeIndexed() so gone back + to 0. */ + configASSERT( ulReceivedValue == 1UL ); + ( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* No other notification indexes should have changed, and therefore should + still have their value set to their index plus 1 within the array of + notifications. */ + for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) + { + if( uxIndex != uxIndexToNotify ) + { + xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xDontBlock ); + configASSERT( xReturned == pdFALSE ); + configASSERT( ulReceivedValue == ( uxIndex + 1 ) ); + ( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) xReturned; + } + } + + /* Reset the notification value for the index just tested back to the + index value plus 1 ready for the next iteration around this loop. */ + xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, uxIndexToNotify + 1, eSetValueWithOverwrite ); + xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify ); + + /* Incremented to show the task is still running. */ + ulFineCycleCount++; + } +} +/* ------------------------------------------------------------------------ */ + +static void prvBlockOnANonNotifiedIndexed( void ) +{ +const TickType_t xTimerPeriod = pdMS_TO_TICKS( 100 ), xMargin = pdMS_TO_TICKS( 50 ), xDontBlock = 0; +UBaseType_t uxIndex, uxIndexToNotify; +uint32_t ulReceivedValue; +BaseType_t xReturned; +TickType_t xTimeBeforeBlocking; + + /* Set all notify values within the array of tasks notifications to zero + ready for the next test. */ + for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) + { + ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToNotify, notifyUINT32_MAX ); + } + + /* Perform the test for each notification within the array of task + notifications. */ + for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) + { + /* Start the software timer then wait for it to notify this task. Block + on a notification index that we do not expect to receive the notification + on. The margin is to ensure the task blocks longer than the timer period. */ + xTimerStart( xIncrementingIndexTimer, portMAX_DELAY ); + xTimeBeforeBlocking = xTaskGetTickCount(); + + + if( uxIndexToNotify == ( configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 ) ) + { + /* configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 is to be notified, so + block on index 0. */ + uxIndex = 0; + } + else + { + /* The next index to get notified will be uxIndexToNotify, so block + on uxIndexToNotify + 1 */ + uxIndex = uxIndexToNotify + 1; + } + + xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xTimerPeriod + xMargin ); + + /* The notification will have been sent to task notification at index + uxIndexToNotify in this task by the timer callback after xTimerPeriodTicks. + The notification should not have woken this task, so xReturned should + be false and at least xTimerPeriod + xMargin ticks should have passed. */ + configASSERT( xReturned == pdFALSE ); + configASSERT( ( xTaskGetTickCount() - xTimeBeforeBlocking ) >= ( xTimerPeriod + xMargin ) ); + ( void ) xReturned; /* Remove compiler warnings if configASSERT() is not defined. */ + ( void ) xTimeBeforeBlocking; + + /* Only the notification at index position uxIndexToNotify should be + set. Calling this function will clear it again. */ + for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) + { + xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xDontBlock ); + + if( uxIndex == uxIndexToNotify ) + { + /* Expect the notification state to be set and the notification + value to have been incremented. */ + configASSERT( xReturned == pdTRUE ); + configASSERT( ulReceivedValue == 1 ); + + /* Set the notification value for this array index back to 0. */ + ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndex, notifyUINT32_MAX ); + } + else + { + /* Expect the notification state to be clear and the notification + value to remain at zer0. */ + configASSERT( xReturned == pdFALSE ); + configASSERT( ulReceivedValue == 0 ); + } + } + + /* Incremented to show the task is still running. */ + ulFineCycleCount++; + } +} +/* ------------------------------------------------------------------------ */ + +static void prvBlockOnNotificationsComingFromInterrupts( void ) +{ +UBaseType_t uxIndex, uxIndexToNotify; +uint32_t ulReceivedValue; +BaseType_t xReturned; +const TickType_t xDontBlock = 0; + + /* Set the value of each notification within the array of task notifications + to zero so the task can block on xTaskNotifyTake(). */ + for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) + { + xTaskNotifyIndexed( xTaskToNotify, uxIndex, 0, eSetValueWithOverwrite ); + xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndex ); + } + + /* Perform the test on each task notification within the array of task + notifications. */ + for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) + { + /* Tell the interrupt to send the next notification. */ + taskENTER_CRITICAL(); + { + /* Don't expect to find xSendNotificationFromISR set at this time as + the interrupt should have cleared it back to pdFALSE last time it + executed. */ + configASSERT( xSendNotificationFromISR == pdFALSE ); + xSendNotificationFromISR = pdTRUE; + } + taskEXIT_CRITICAL(); + + /* Wait for a notification on the task notification at index + uxIndexToNotify within the array of task notifications. */ + ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdTRUE, portMAX_DELAY ); + + /* Interrupt should have reset xSendNotificationFromISR after it sent + the notificatino. */ + configASSERT( xSendNotificationFromISR == pdFALSE ); + + /* The notification value was initially zero, and should have been + incremented by the interrupt, so now one. */ + configASSERT( ulReceivedValue == 1UL ); + ( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + + /* No other notification indexes should have changed, and therefore should + still have their value set to 0. The value in array index uxIndexToNotify + should also have been decremented back to zero by the call to + ulTaskNotifyTakeIndexed(). */ + for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) + { + xReturned = xTaskNotifyWaitIndexed( uxIndexToNotify, 0, 0, &ulReceivedValue, xDontBlock ); + configASSERT( xReturned == pdFALSE ); + configASSERT( ulReceivedValue == 0 ); + ( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ + ( void ) xReturned; + } + + /* Incremented to show the task is still running. */ + ulFineCycleCount++; + } +} +/*-----------------------------------------------------------*/ + +void xNotifyArrayTaskFromISR( void ) +{ +static BaseType_t xCallCount = 0, xAPIToUse = 0; +uint32_t ulPreviousValue; +const uint32_t ulUnexpectedValue = 0xff; +static UBaseType_t uxIndexToNotify = 0; + + /* Check the task notification demo task was actually created. */ + configASSERT( xTaskToNotify ); + + /* The task sets xSendNotificationFromISR to pdTRUE each time it wants this + interrupt (this function runs in the RTOS tick hook) to send the next + notification. */ + if( xSendNotificationFromISR == pdTRUE ) + { + xSendNotificationFromISR = pdFALSE; + + /* It is time to 'give' the notification again. */ + xCallCount = 0; + + /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR() + and xTaskNotifyAndQueryFromISR(). The notification is set to the task + notification at index uxIndexToNotify within the array of task + notifications. */ + switch( xAPIToUse ) + { + case 0: vTaskNotifyGiveIndexedFromISR( xTaskToNotify, uxIndexToNotify, NULL ); + xAPIToUse++; + break; + + case 1: xTaskNotifyIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, NULL ); + xAPIToUse++; + break; + + case 2: ulPreviousValue = ulUnexpectedValue; + xTaskNotifyAndQueryIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, &ulPreviousValue, NULL ); + configASSERT( ulPreviousValue == 0 ); + xAPIToUse = 0; + break; + + default:/* Should never get here!. */ + break; + } + + /* Use the next index in the array of task notifications the next time + around. */ + uxIndexToNotify++; + if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES ) + { + uxIndexToNotify = 0; + } + } +} +/*-----------------------------------------------------------*/ + +/* This is called to check the created tasks are still running and have not +detected any errors. */ +BaseType_t xAreTaskNotificationArrayTasksStillRunning( void ) +{ +static uint32_t ulLastFineCycleCount = 0, ulLastCourseCycleCount = 0, ulCallCount = 0; +const uint32_t ulCallsBetweenCourseCycleCountChecks = 3UL; +static BaseType_t xErrorStatus = pdPASS; + + /* Check the cycle count is still incrementing to ensure the task is still + actually running. The fine counter is incremented within individual test + functions. The course counter is incremented one each time all the test + functions have been executed to ensure all the tests are running. */ + if( ulLastFineCycleCount == ulFineCycleCount ) + { + xErrorStatus = pdFAIL; + } + else + { + ulLastFineCycleCount = ulFineCycleCount; + } + + ulCallCount++; + if( ulCallCount >= ulCallsBetweenCourseCycleCountChecks ) + { + ulCallCount = 0; + if( ulLastCourseCycleCount == ulCourseCycleCounter ) + { + xErrorStatus = pdFAIL; + } + else + { + ulLastCourseCycleCount = ulCourseCycleCounter; + } + } + + return xErrorStatus; +} +/*-----------------------------------------------------------*/ + +static UBaseType_t prvRand( void ) +{ +const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1; + + /* Utility function to generate a pseudo random number. */ + uxNextRand = ( uxMultiplier * uxNextRand ) + uxIncrement; + return( ( uxNextRand >> 16 ) & ( ( size_t ) 0x7fff ) ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/Common/include/TaskNotifyArray.h b/FreeRTOS/Demo/Common/include/TaskNotifyArray.h new file mode 100644 index 0000000000..aa0320ea2e --- /dev/null +++ b/FreeRTOS/Demo/Common/include/TaskNotifyArray.h @@ -0,0 +1,38 @@ +/* + * FreeRTOS Kernel V10.3.0 + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef TASK_NOTIFY_ARRAY_H +#define TASK_NOTIFY_ARRAY_H + +void vStartTaskNotifyArrayTask( void ); +BaseType_t xAreTaskNotificationArrayTasksStillRunning( void ); +void xNotifyArrayTaskFromISR( void ); + +#endif /* TASK_NOTIFY_ARRAY_H */ + + + diff --git a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h index ff78188fdc..a70d8fb61d 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h @@ -62,6 +62,7 @@ #define configUSE_ALTERNATIVE_API 0 #define configUSE_QUEUE_SETS 1 #define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 5 #define configSUPPORT_STATIC_ALLOCATION 1 #define configINITIAL_TICK_COUNT ( ( TickType_t ) 0 ) /* For test. */ #define configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN 1 /* As there are a lot of tasks running. */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj index a972826128..69148ec42b 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj @@ -105,6 +105,7 @@ + %(AdditionalIncludeDirectories) diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters index ae43ea7508..cf09e0db42 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters @@ -160,6 +160,9 @@ Demo App Source\Full_Demo\Common Demo Tasks + + Demo App Source\Full_Demo\Common Demo Tasks + diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index c26b641dd2..6a45e98494 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -44,7 +44,6 @@ * port for further information: * http://www.freertos.org/FreeRTOS-Windows-Simulator-Emulator-for-Visual-Studio-and-Eclipse-MingW.html * - * ******************************************************************************* */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/main_full.c b/FreeRTOS/Demo/WIN32-MSVC/main_full.c index a73e6459e6..7637ae636e 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main_full.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main_full.c @@ -97,6 +97,7 @@ #include "EventGroupsDemo.h" #include "IntSemTest.h" #include "TaskNotify.h" +#include "TaskNotifyArray.h" #include "QueueSetPolling.h" #include "StaticAllocation.h" #include "blocktim.h" @@ -183,6 +184,7 @@ int main_full( void ) /* Create the standard demo tasks. */ vStartTaskNotifyTask(); + vStartTaskNotifyArrayTask(); vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY ); vStartSemaphoreTasks( mainSEM_TEST_PRIORITY ); vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); @@ -286,6 +288,10 @@ HeapStats_t xHeapStats; { pcStatusMessage = "Error: Notification"; } + else if( xAreTaskNotificationArrayTasksStillRunning() != pdTRUE ) + { + pcStatusMessage = "Error: NotificationArray"; + } else if( xAreInterruptSemaphoreTasksStillRunning() != pdTRUE ) { pcStatusMessage = "Error: IntSem"; @@ -496,6 +502,7 @@ TaskHandle_t xTimerTask; /* Exercise using task notifications from an interrupt. */ xNotifyTaskFromISR(); + xNotifyArrayTaskFromISR(); /* Writes to stream buffer byte by byte to test the stream buffer trigger level functionality. */ diff --git a/FreeRTOS/Demo/WIN32-MingW/main.c b/FreeRTOS/Demo/WIN32-MingW/main.c index bd136f6287..6ec43e13dc 100644 --- a/FreeRTOS/Demo/WIN32-MingW/main.c +++ b/FreeRTOS/Demo/WIN32-MingW/main.c @@ -370,7 +370,6 @@ const HeapRegion_t xHeapRegions[] = /* The heap has not been initialised yet so expect stats to all be zero. */ vPortGetHeapStats( &xHeapStats ); - configASSERT( memcmp( &xHeapStats, &xZeroHeapStats, sizeof( HeapStats_t ) ) == 0 ); vPortDefineHeapRegions( xHeapRegions );