/* * FreeRTOS V202212.00 * 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 * */ /* * This file contains fairly comprehensive checks on the behaviour of event * groups. It is not intended to be a user friendly demonstration of the * event groups API. * * NOTE: The tests implemented in this file are informal 'sanity' tests * only and are not part of the module tests that make use of the * mtCOVERAGE_TEST_MARKER macro within the event groups implementation. */ /* Scheduler include files. */ #include "FreeRTOS.h" #include "task.h" #include "event_groups.h" /* Demo app includes. */ #include "EventGroupsDemo.h" #if ( INCLUDE_eTaskGetState != 1 ) #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file. #endif /* Priorities used by the tasks. */ #define ebSET_BIT_TASK_PRIORITY ( tskIDLE_PRIORITY ) #define ebWAIT_BIT_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) /* Generic bit definitions. */ #define ebBIT_0 ( 0x01 ) #define ebBIT_1 ( 0x02 ) #define ebBIT_2 ( 0x04 ) #define ebBIT_3 ( 0x08 ) #define ebBIT_4 ( 0x10 ) #define ebBIT_5 ( 0x20 ) #define ebBIT_6 ( 0x40 ) #define ebBIT_7 ( 0x80 ) /* Combinations of bits used in the demo. */ #define ebCOMBINED_BITS ( ebBIT_1 | ebBIT_5 | ebBIT_7 ) #define ebALL_BITS ( ebBIT_0 | ebBIT_1 | ebBIT_2 | ebBIT_3 | ebBIT_4 | ebBIT_5 | ebBIT_6 | ebBIT_7 ) /* Associate a bit to each task. These bits are used to identify all the tasks * that synchronise with the xEventGroupSync() function. */ #define ebSET_BIT_TASK_SYNC_BIT ebBIT_0 #define ebWAIT_BIT_TASK_SYNC_BIT ebBIT_1 #define ebRENDEZVOUS_TASK_1_SYNC_BIT ebBIT_2 #define ebRENDEZVOUS_TASK_2_SYNC_BIT ebBIT_3 #define ebALL_SYNC_BITS ( ebSET_BIT_TASK_SYNC_BIT | ebWAIT_BIT_TASK_SYNC_BIT | ebRENDEZVOUS_TASK_1_SYNC_BIT | ebRENDEZVOUS_TASK_2_SYNC_BIT ) /* A block time of zero simply means "don't block". */ #define ebDONT_BLOCK ( 0 ) /* A 5ms delay. */ #define ebSHORT_DELAY pdMS_TO_TICKS( ( TickType_t ) 5 ) /* Used in the selective bits test which checks no, one or both tasks blocked on * event bits in a group are unblocked as appropriate as different bits get set. */ #define ebSELECTIVE_BITS_1 0x03 #define ebSELECTIVE_BITS_2 0x05 #ifndef ebRENDEZVOUS_TEST_TASK_STACK_SIZE #define ebRENDEZVOUS_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE #endif #ifndef ebEVENT_GROUP_SET_BITS_TEST_TASK_STACK_SIZE #define ebEVENT_GROUP_SET_BITS_TEST_TASK_STACK_SIZE configMINIMAL_STACK_SIZE #endif /*-----------------------------------------------------------*/ /* * NOTE: The tests implemented in this function are informal 'sanity' tests * only and are not part of the module tests that make use of the * mtCOVERAGE_TEST_MARKER macro within the event groups implementation. * * The master test task. This task: * * 1) Calls prvSelectiveBitsTestMasterFunction() to test the behaviour when two * tasks are blocked on different bits in an event group. The counterpart of * this test is implemented by the prvSelectiveBitsTestSlaveFunction() * function (which is called by the two tasks that block on the event group). * * 2) Calls prvBitCombinationTestMasterFunction() to test the behaviour when * just one task is blocked on various combinations of bits within an event * group. The counterpart of this test is implemented within the 'test * slave' task. * * 3) Calls prvPerformTaskSyncTests() to test task synchronisation behaviour. */ static void prvTestMasterTask( void * pvParameters ); /* * A helper task that enables the 'test master' task to perform several * behavioural tests. See the comments above the prvTestMasterTask() prototype * above. */ static void prvTestSlaveTask( void * pvParameters ); /* * The part of the test that is performed between the 'test master' task and the * 'test slave' task to test the behaviour when the slave blocks on various * event bit combinations. */ static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ); /* * The part of the test that uses all the tasks to test the task synchronisation * behaviour. */ static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ); /* * Two instances of prvSyncTask() are created. They start by calling * prvSelectiveBitsTestSlaveFunction() to act as slaves when the test master is * executing the prvSelectiveBitsTestMasterFunction() function. They then loop * to test the task synchronisation (rendezvous) behaviour. */ static void prvSyncTask( void * pvParameters ); /* * Functions used in a test that blocks two tasks on various different bits * within an event group - then sets each bit in turn and checks that the * correct tasks unblock at the correct times. */ static BaseType_t prvSelectiveBitsTestMasterFunction( void ); static void prvSelectiveBitsTestSlaveFunction( void ); /*-----------------------------------------------------------*/ /* Variables that are incremented by the tasks on each cycle provided no errors * have been found. Used to detect an error or stall in the test cycling. */ static volatile uint32_t ulTestMasterCycles = 0, ulTestSlaveCycles = 0, ulISRCycles = 0; /* The event group used by all the task based tests. */ static EventGroupHandle_t xEventGroup = NULL; /* The event group used by the interrupt based tests. */ static EventGroupHandle_t xISREventGroup = NULL; /* Handles to the tasks that only take part in the synchronisation calls. */ static TaskHandle_t xSyncTask1 = NULL, xSyncTask2 = NULL; /*-----------------------------------------------------------*/ void vStartEventGroupTasks( void ) { TaskHandle_t xTestSlaveTaskHandle; /* * This file contains fairly comprehensive checks on the behaviour of event * groups. It is not intended to be a user friendly demonstration of the * event groups API. * * NOTE: The tests implemented in this file are informal 'sanity' tests * only and are not part of the module tests that make use of the * mtCOVERAGE_TEST_MARKER macro within the event groups implementation. * * Create the test tasks as described at the top of this file. */ xTaskCreate( prvTestSlaveTask, "WaitO", ebRENDEZVOUS_TEST_TASK_STACK_SIZE, NULL, ebWAIT_BIT_TASK_PRIORITY, &xTestSlaveTaskHandle ); xTaskCreate( prvTestMasterTask, "SetB", ebEVENT_GROUP_SET_BITS_TEST_TASK_STACK_SIZE, ( void * ) xTestSlaveTaskHandle, ebSET_BIT_TASK_PRIORITY, NULL ); xTaskCreate( prvSyncTask, "Rndv", ebRENDEZVOUS_TEST_TASK_STACK_SIZE, ( void * ) ebRENDEZVOUS_TASK_1_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask1 ); xTaskCreate( prvSyncTask, "Rndv", ebRENDEZVOUS_TEST_TASK_STACK_SIZE, ( void * ) ebRENDEZVOUS_TASK_2_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask2 ); /* If the last task was created then the others will have been too. */ configASSERT( xSyncTask2 ); /* Create the event group used by the ISR tests. The event group used by * the tasks is created by the tasks themselves. */ xISREventGroup = xEventGroupCreate(); configASSERT( xISREventGroup ); } /*-----------------------------------------------------------*/ static void prvTestMasterTask( void * pvParameters ) { BaseType_t xError; /* The handle to the slave task is passed in as the task parameter. */ TaskHandle_t xTestSlaveTaskHandle = ( TaskHandle_t ) pvParameters; /* Avoid compiler warnings. */ ( void ) pvParameters; /* Create the event group used by the tasks ready for the initial tests. */ xEventGroup = xEventGroupCreate(); configASSERT( xEventGroup ); /* Perform the tests that block two tasks on different combinations of bits, * then set each bit in turn and check the correct tasks unblock at the correct * times. */ xError = prvSelectiveBitsTestMasterFunction(); for( ; ; ) { /* Recreate the event group ready for the next cycle. */ xEventGroup = xEventGroupCreate(); configASSERT( xEventGroup ); /* Perform the tests that check the behaviour when a single task is * blocked on various combinations of event bits. */ xError = prvBitCombinationTestMasterFunction( xError, xTestSlaveTaskHandle ); /* Perform the task synchronisation tests. */ xError = prvPerformTaskSyncTests( xError, xTestSlaveTaskHandle ); /* Delete the event group. */ vEventGroupDelete( xEventGroup ); /* Now all the other tasks should have completed and suspended * themselves ready for the next go around the loop. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask1 ) != eSuspended ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eSuspended ) { xError = pdTRUE; } /* Only increment the cycle variable if no errors have been detected. */ if( xError == pdFALSE ) { ulTestMasterCycles++; } configASSERT( xError == pdFALSE ); } } /*-----------------------------------------------------------*/ static void prvSyncTask( void * pvParameters ) { EventBits_t uxSynchronisationBit, uxReturned; /* A few tests that check the behaviour when two tasks are blocked on * various different bits within an event group are performed before this task * enters its infinite loop to carry out its main demo function. */ prvSelectiveBitsTestSlaveFunction(); /* The bit to use to indicate this task is at the synchronisation point is * passed in as the task parameter. */ uxSynchronisationBit = ( EventBits_t ) pvParameters; for( ; ; ) { /* Now this task takes part in a task synchronisation - sometimes known * as a 'rendezvous'. Its execution pattern is controlled by the 'test * master' task, which is responsible for taking this task out of the * Suspended state when it is time to test the synchronisation behaviour. * See: http://www.freertos.org/xEventGroupSync.html. */ vTaskSuspend( NULL ); /* Set the bit that indicates this task is at the synchronisation * point. The first time this is done the 'test master' task has a lower * priority than this task so this task will get to the sync point before * the set bits task - test this by calling xEventGroupSync() with a zero * block time before calling again with a max delay - the first call should * return before the rendezvous completes, the second only after the * rendezvous is complete. */ uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */ ebALL_SYNC_BITS, /* The bits to wait for - these bits are set by the other tasks taking part in the sync. */ ebDONT_BLOCK ); /* The maximum time to wait for the sync condition to be met before giving up. */ /* No block time was specified, so as per the comments above, the * rendezvous is not expected to have completed yet. */ configASSERT( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ); uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */ ebALL_SYNC_BITS, /* The bits to wait for - these bits are set by the other tasks taking part in the sync. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met before giving up. */ /* A max delay was used, so this task should only exit the above * function call when the sync condition is met. Check this is the * case. */ configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS ); /* Remove compiler warning if configASSERT() is not defined. */ ( void ) uxReturned; /* Wait until the 'test master' task unsuspends this task again. */ vTaskSuspend( NULL ); /* Set the bit that indicates this task is at the synchronisation * point again. This time the 'test master' task has a higher priority * than this task so will get to the sync point before this task. */ uxReturned = xEventGroupSync( xEventGroup, uxSynchronisationBit, ebALL_SYNC_BITS, portMAX_DELAY ); /* Again a max delay was used, so this task should only exit the above * function call when the sync condition is met. Check this is the * case. */ configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS ); /* Block on the event group again. This time the event group is going * to be deleted while this task is blocked on it so it is expected that 0 * be returned. */ uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); configASSERT( uxReturned == 0 ); } } /*-----------------------------------------------------------*/ static void prvTestSlaveTask( void * pvParameters ) { EventBits_t uxReturned; BaseType_t xError = pdFALSE; /* Avoid compiler warnings. */ ( void ) pvParameters; for( ; ; ) { /********************************************************************** * Part 1: This section is the counterpart to the * prvBitCombinationTestMasterFunction() function which is called by the * test master task. *********************************************************************** * * This task is controller by the 'test master' task (which is * implemented by prvTestMasterTask()). Suspend until resumed by the * 'test master' task. */ vTaskSuspend( NULL ); /* Wait indefinitely for one of the bits in ebCOMBINED_BITS to get * set. Clear the bit on exit. */ uxReturned = xEventGroupWaitBits( xEventGroup, /* The event group that contains the event bits being queried. */ ebBIT_1, /* The bit to wait for. */ pdTRUE, /* Clear the bit on exit. */ pdTRUE, /* Wait for all the bits (only one in this case anyway). */ portMAX_DELAY ); /* Block indefinitely to wait for the condition to be met. */ /* The 'test master' task set all the bits defined by ebCOMBINED_BITS, * only one of which was being waited for by this task. The return value * shows the state of the event bits when the task was unblocked, however * because the task was waiting for ebBIT_1 and 'clear on exit' was set to * the current state of the event bits will have ebBIT_1 clear. */ if( uxReturned != ebCOMBINED_BITS ) { xError = pdTRUE; } /* Now call xEventGroupWaitBits() again, this time waiting for all the * bits in ebCOMBINED_BITS to be set. This call should block until the * 'test master' task sets ebBIT_1 - which was the bit cleared in the call * to xEventGroupWaitBits() above. */ uxReturned = xEventGroupWaitBits( xEventGroup, ebCOMBINED_BITS, /* The bits being waited on. */ pdFALSE, /* Don't clear the bits on exit. */ pdTRUE, /* All the bits must be set to unblock. */ portMAX_DELAY ); /* Were all the bits set? */ if( ( uxReturned & ebCOMBINED_BITS ) != ebCOMBINED_BITS ) { xError = pdTRUE; } /* Suspend again to wait for the 'test master' task. */ vTaskSuspend( NULL ); /* Now call xEventGroupWaitBits() again, again waiting for all the bits * in ebCOMBINED_BITS to be set, but this time clearing the bits when the * task is unblocked. */ uxReturned = xEventGroupWaitBits( xEventGroup, ebCOMBINED_BITS, /* The bits being waited on. */ pdTRUE, /* Clear the bits on exit. */ pdTRUE, /* All the bits must be set to unblock. */ portMAX_DELAY ); /* The 'test master' task set all the bits in the event group, so that * is the value that should have been returned. The bits defined by * ebCOMBINED_BITS will have been clear again in the current value though * as 'clear on exit' was set to pdTRUE. */ if( uxReturned != ebALL_BITS ) { xError = pdTRUE; } /********************************************************************** * Part 2: This section is the counterpart to the * prvPerformTaskSyncTests() function which is called by the * test master task. *********************************************************************** * * * Once again wait for the 'test master' task to unsuspend this task * when it is time for the next test. */ vTaskSuspend( NULL ); /* Now perform a synchronisation with all the other tasks. At this point * the 'test master' task has the lowest priority so will get to the sync * point after all the other synchronising tasks. */ uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the sync. */ ebWAIT_BIT_TASK_SYNC_BIT, /* The bit in the event group used to indicate this task is at the sync point. */ ebALL_SYNC_BITS, /* The bits to wait for. These bits are set by the other tasks taking part in the sync. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met before giving up. */ /* A sync with a max delay should only exit when all the synchronisation * bits are set... */ if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) { xError = pdTRUE; } /* ...but now the synchronisation bits should be clear again. Read back * the current value of the bits within the event group to check that is * the case. Setting the bits to zero will return the bits previous value * then leave all the bits clear. */ if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 ) { xError = pdTRUE; } /* Check the bits are indeed 0 now by simply reading then. */ if( xEventGroupGetBits( xEventGroup ) != 0 ) { xError = pdTRUE; } if( xError == pdFALSE ) { /* This task is still cycling without finding an error. */ ulTestSlaveCycles++; } vTaskSuspend( NULL ); /* This time sync when the 'test master' task has the highest priority * at the point where it sets its sync bit - so this time the 'test master' * task will get to the sync point before this task. */ uxReturned = xEventGroupSync( xEventGroup, ebWAIT_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); /* A sync with a max delay should only exit when all the synchronisation * bits are set... */ if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) { xError = pdTRUE; } /* ...but now the sync bits should be clear again. */ if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 ) { xError = pdTRUE; } /* Block on the event group again. This time the event group is going * to be deleted while this task is blocked on it, so it is expected that 0 * will be returned. */ uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); if( uxReturned != 0 ) { xError = pdTRUE; } if( xError == pdFALSE ) { /* This task is still cycling without finding an error. */ ulTestSlaveCycles++; } configASSERT( xError == pdFALSE ); } } /*-----------------------------------------------------------*/ static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ) { EventBits_t uxBits; /* The three tasks that take part in the synchronisation (rendezvous) are * expected to be in the suspended state at the start of the test. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask1 ) != eSuspended ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eSuspended ) { xError = pdTRUE; } /* Try a synch with no other tasks involved. First set all the bits other * than this task's bit. */ xEventGroupSetBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ); /* Then wait on just one bit - the bit that is being set. */ uxBits = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ ebSET_BIT_TASK_SYNC_BIT, /* The bit set by this task when it reaches the sync point. */ ebSET_BIT_TASK_SYNC_BIT, /* The bits to wait for - in this case it is just waiting for itself. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */ /* A sync with a max delay should only exit when all the synchronise * bits are set...check that is the case. In this case there is only one * sync bit anyway. */ if( ( uxBits & ebSET_BIT_TASK_SYNC_BIT ) != ebSET_BIT_TASK_SYNC_BIT ) { xError = pdTRUE; } /* ...but now the sync bits should be clear again, leaving all the other * bits set (as only one bit was being waited for). */ if( xEventGroupGetBits( xEventGroup ) != ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ) { xError = pdTRUE; } /* Clear all the bits to zero again. */ xEventGroupClearBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ); if( xEventGroupGetBits( xEventGroup ) != 0 ) { xError = pdTRUE; } /* Unsuspend the other tasks then check they have executed up to the * synchronisation point. */ vTaskResume( xTestSlaveTaskHandle ); vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask2 ); if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask1 ) != eBlocked ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eBlocked ) { xError = pdTRUE; } /* Set this task's sync bit. */ uxBits = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ ebSET_BIT_TASK_SYNC_BIT, /* The bit set by this task when it reaches the sync point. */ ebALL_SYNC_BITS, /* The bits to wait for - these bits are set by the other tasks that take part in the sync. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */ /* A sync with a max delay should only exit when all the synchronise * bits are set...check that is the case. */ if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) { xError = pdTRUE; } /* ...but now the sync bits should be clear again. */ if( xEventGroupGetBits( xEventGroup ) != 0 ) { xError = pdTRUE; } /* The other tasks should now all be suspended again, ready for the next * synchronisation. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask1 ) != eSuspended ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eSuspended ) { xError = pdTRUE; } /* Sync again - but this time set the last necessary bit as the * highest priority task, rather than the lowest priority task. Unsuspend * the other tasks then check they have executed up to the synchronisation * point. */ vTaskResume( xTestSlaveTaskHandle ); vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask2 ); if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask1 ) != eBlocked ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eBlocked ) { xError = pdTRUE; } /* Raise the priority of this task above that of the other tasks. */ vTaskPrioritySet( NULL, ebWAIT_BIT_TASK_PRIORITY + 1 ); /* Set this task's sync bit. */ uxBits = xEventGroupSync( xEventGroup, ebSET_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); /* A sync with a max delay should only exit when all the synchronisation * bits are set... */ if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) { xError = pdTRUE; } /* ...but now the sync bits should be clear again. */ if( xEventGroupGetBits( xEventGroup ) != 0 ) { xError = pdTRUE; } /* The other tasks should now all be in the ready state again, but not * executed yet as this task still has a higher relative priority. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eReady ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask1 ) != eReady ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eReady ) { xError = pdTRUE; } /* Reset the priority of this task back to its original value. */ vTaskPrioritySet( NULL, ebSET_BIT_TASK_PRIORITY ); /* Now all the other tasks should have reblocked on the event bits * to test the behaviour when the event bits are deleted. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask1 ) != eBlocked ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eBlocked ) { xError = pdTRUE; } return xError; } /*-----------------------------------------------------------*/ static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ) { EventBits_t uxBits; /* Resume the other task. It will block, pending a single bit from * within ebCOMBINED_BITS. */ vTaskResume( xTestSlaveTaskHandle ); /* Ensure the other task is blocked on the task. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) { xError = pdTRUE; } /* Set all the bits in ebCOMBINED_BITS - the 'test slave' task is only * blocked waiting for one of them. */ xEventGroupSetBits( xEventGroup, ebCOMBINED_BITS ); /* The 'test slave' task should now have executed, clearing ebBIT_1 (the * bit it was blocked on), then re-entered the Blocked state to wait for * all the other bits in ebCOMBINED_BITS to be set again. First check * ebBIT_1 is clear. */ uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); if( uxBits != ( ebCOMBINED_BITS & ~ebBIT_1 ) ) { xError = pdTRUE; } /* Ensure the other task is still in the blocked state. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) { xError = pdTRUE; } /* Set all the bits other than ebBIT_1 - which is the bit that must be * set before the other task unblocks. */ xEventGroupSetBits( xEventGroup, ebALL_BITS & ~ebBIT_1 ); /* Ensure all the expected bits are still set. */ uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); if( uxBits != ( ebALL_BITS & ~ebBIT_1 ) ) { xError = pdTRUE; } /* Ensure the other task is still in the blocked state. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) { xError = pdTRUE; } /* Now also set ebBIT_1, which should unblock the other task, which will * then suspend itself. */ xEventGroupSetBits( xEventGroup, ebBIT_1 ); /* Ensure the other task is suspended. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) { xError = pdTRUE; } /* The other task should not have cleared the bits - so all the bits * should still be set. */ if( xEventGroupSetBits( xEventGroup, 0x00 ) != ebALL_BITS ) { xError = pdTRUE; } /* Clear ebBIT_1 again. */ if( xEventGroupClearBits( xEventGroup, ebBIT_1 ) != ebALL_BITS ) { xError = pdTRUE; } /* Resume the other task - which will wait on all the ebCOMBINED_BITS * again - this time clearing the bits when it is unblocked. */ vTaskResume( xTestSlaveTaskHandle ); /* Ensure the other task is blocked once again. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) { xError = pdTRUE; } /* Set the bit the other task is waiting for. */ xEventGroupSetBits( xEventGroup, ebBIT_1 ); /* Ensure the other task is suspended once again. */ if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) { xError = pdTRUE; } /* The other task should have cleared the bits in ebCOMBINED_BITS. * Clear the remaining bits. */ uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); if( uxBits != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) { xError = pdTRUE; } /* Clear all bits ready for the sync with the other three tasks. The * value returned is the value prior to the bits being cleared. */ if( xEventGroupClearBits( xEventGroup, ebALL_BITS ) != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) { xError = pdTRUE; } /* The bits should be clear now. */ if( xEventGroupGetBits( xEventGroup ) != 0x00 ) { xError = pdTRUE; } return xError; } /*-----------------------------------------------------------*/ static void prvSelectiveBitsTestSlaveFunction( void ) { EventBits_t uxPendBits, uxReturned; /* Used in a test that blocks two tasks on various different bits within an * event group - then sets each bit in turn and checks that the correct tasks * unblock at the correct times. * * This function is called by two different tasks - each of which will use a * different bit. Check the task handle to see which task the function was * called by. */ if( xTaskGetCurrentTaskHandle() == xSyncTask1 ) { uxPendBits = ebSELECTIVE_BITS_1; } else { uxPendBits = ebSELECTIVE_BITS_2; } for( ; ; ) { /* Wait until it is time to perform the next cycle of the test. The * task is unsuspended by the tests implemented in the * prvSelectiveBitsTestMasterFunction() function. */ vTaskSuspend( NULL ); uxReturned = xEventGroupWaitBits( xEventGroup, uxPendBits, pdTRUE, pdFALSE, portMAX_DELAY ); if( uxReturned == ( EventBits_t ) 0 ) { break; } } } /*-----------------------------------------------------------*/ static BaseType_t prvSelectiveBitsTestMasterFunction( void ) { BaseType_t xError = pdFALSE; EventBits_t uxBit; /* Used in a test that blocks two tasks on various different bits within an * event group - then sets each bit in turn and checks that the correct tasks * unblock at the correct times. The two other tasks (xSyncTask1 and * xSyncTask2) call prvSelectiveBitsTestSlaveFunction() to perform their parts in * this test. * * Both other tasks should start in the suspended state. */ if( eTaskGetState( xSyncTask1 ) != eSuspended ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eSuspended ) { xError = pdTRUE; } /* Test each bit in the byte individually. */ for( uxBit = 0x01; uxBit < 0x100; uxBit <<= 1 ) { /* Resume both tasks. */ vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask2 ); /* Now both tasks should be blocked on the event group. */ if( eTaskGetState( xSyncTask1 ) != eBlocked ) { xError = pdTRUE; } if( eTaskGetState( xSyncTask2 ) != eBlocked ) { xError = pdTRUE; } /* Set one bit. */ xEventGroupSetBits( xEventGroup, uxBit ); /* Is the bit set in the first set of selective bits? If so the first * sync task should have unblocked and returned to the suspended state. */ if( ( uxBit & ebSELECTIVE_BITS_1 ) == 0 ) { /* Task should not have unblocked. */ if( eTaskGetState( xSyncTask1 ) != eBlocked ) { xError = pdTRUE; } } else { /* Task should have unblocked and returned to the suspended state. */ if( eTaskGetState( xSyncTask1 ) != eSuspended ) { xError = pdTRUE; } } /* Same checks for the second sync task. */ if( ( uxBit & ebSELECTIVE_BITS_2 ) == 0 ) { /* Task should not have unblocked. */ if( eTaskGetState( xSyncTask2 ) != eBlocked ) { xError = pdTRUE; } } else { /* Task should have unblocked and returned to the suspended state. */ if( eTaskGetState( xSyncTask2 ) != eSuspended ) { xError = pdTRUE; } } } /* Ensure both tasks are blocked on the event group again, then delete the * event group so the other tasks leave this portion of the test. */ vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask2 ); /* Deleting the event group is the signal that the two other tasks should * leave the prvSelectiveBitsTestSlaveFunction() function and continue to the main * part of their functionality. */ vEventGroupDelete( xEventGroup ); return xError; } /*-----------------------------------------------------------*/ void vPeriodicEventGroupsProcessing( void ) { static BaseType_t xCallCount = 0, xISRTestError = pdFALSE; const BaseType_t xSetBitCount = 100, xGetBitsCount = 200, xClearBitsCount = 300; const EventBits_t uxBitsToSet = 0x12U; EventBits_t uxReturned; BaseType_t xMessagePosted; /* Called periodically from the tick hook to exercise the "FromISR" * functions. */ /* Check the even group tasks were actually created. */ configASSERT( xISREventGroup ); xCallCount++; if( xCallCount == xSetBitCount ) { /* All the event bits should start clear. */ uxReturned = xEventGroupGetBitsFromISR( xISREventGroup ); if( uxReturned != 0x00 ) { xISRTestError = pdTRUE; } else { /* Set the bits. This is called from the tick hook so it is not * necessary to use the last parameter to ensure a context switch * occurs immediately. */ xMessagePosted = xEventGroupSetBitsFromISR( xISREventGroup, uxBitsToSet, NULL ); if( xMessagePosted != pdPASS ) { xISRTestError = pdTRUE; } } } else if( xCallCount == xGetBitsCount ) { /* Check the bits were set as expected. */ uxReturned = xEventGroupGetBitsFromISR( xISREventGroup ); if( uxReturned != uxBitsToSet ) { xISRTestError = pdTRUE; } } else if( xCallCount == xClearBitsCount ) { /* Clear the bits again. */ uxReturned = ( EventBits_t ) xEventGroupClearBitsFromISR( xISREventGroup, uxBitsToSet ); /* Check the message was posted. */ if( uxReturned != pdPASS ) { xISRTestError = pdTRUE; } /* Go back to the start. */ xCallCount = 0; /* If no errors have been detected then increment the count of test * cycles. */ if( xISRTestError == pdFALSE ) { ulISRCycles++; } } else { /* Nothing else to do. */ } } /*-----------------------------------------------------------*/ /* This is called to check that all the created tasks are still running. */ BaseType_t xAreEventGroupTasksStillRunning( void ) { static uint32_t ulPreviousWaitBitCycles = 0, ulPreviousSetBitCycles = 0, ulPreviousISRCycles = 0; BaseType_t xStatus = pdPASS; /* Check the tasks are still cycling without finding any errors. */ if( ulPreviousSetBitCycles == ulTestMasterCycles ) { xStatus = pdFAIL; } ulPreviousSetBitCycles = ulTestMasterCycles; if( ulPreviousWaitBitCycles == ulTestSlaveCycles ) { xStatus = pdFAIL; } ulPreviousWaitBitCycles = ulTestSlaveCycles; if( ulPreviousISRCycles == ulISRCycles ) { xStatus = pdFAIL; } ulPreviousISRCycles = ulISRCycles; return xStatus; }