| /* | |
| FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd. | |
| All rights reserved | |
| VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. | |
| *************************************************************************** | |
| * * | |
| * FreeRTOS provides completely free yet professionally developed, * | |
| * robust, strictly quality controlled, supported, and cross * | |
| * platform software that has become a de facto standard. * | |
| * * | |
| * Help yourself get started quickly and support the FreeRTOS * | |
| * project by purchasing a FreeRTOS tutorial book, reference * | |
| * manual, or both from: http://www.FreeRTOS.org/Documentation * | |
| * * | |
| * Thank you! * | |
| * * | |
| *************************************************************************** | |
| This file is part of the FreeRTOS distribution. | |
| FreeRTOS is free software; you can redistribute it and/or modify it under | |
| the terms of the GNU General Public License (version 2) as published by the | |
| Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. | |
| >>! NOTE: The modification to the GPL is included to allow you to !<< | |
| >>! distribute a combined work that includes FreeRTOS without being !<< | |
| >>! obliged to provide the source code for proprietary components !<< | |
| >>! outside of the FreeRTOS kernel. !<< | |
| FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY | |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| FOR A PARTICULAR PURPOSE. Full license text is available from the following | |
| link: http://www.freertos.org/a00114.html | |
| 1 tab == 4 spaces! | |
| *************************************************************************** | |
| * * | |
| * Having a problem? Start by reading the FAQ "My application does * | |
| * not run, what could be wrong?" * | |
| * * | |
| * http://www.FreeRTOS.org/FAQHelp.html * | |
| * * | |
| *************************************************************************** | |
| http://www.FreeRTOS.org - Documentation, books, training, latest versions, | |
| license and Real Time Engineers Ltd. contact details. | |
| http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, | |
| including FreeRTOS+Trace - an indispensable productivity tool, a DOS | |
| compatible FAT file system, and our tiny thread aware UDP/IP stack. | |
| http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High | |
| Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS | |
| licenses offer ticketed support, indemnification and middleware. | |
| http://www.SafeRTOS.com - High Integrity Systems also provide a safety | |
| engineered and independently SIL3 certified version for use in safety and | |
| mission critical applications that require provable dependability. | |
| 1 tab == 4 spaces! | |
| */ | |
| /* | |
| * 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 ( 0x01UL ) | |
| #define ebBIT_1 ( 0x02UL ) | |
| #define ebBIT_2 ( 0x04UL ) | |
| #define ebBIT_3 ( 0x08UL ) | |
| #define ebBIT_4 ( 0x10UL ) | |
| #define ebBIT_5 ( 0x20UL ) | |
| #define ebBIT_6 ( 0x40UL ) | |
| #define ebBIT_7 ( 0x80UL ) | |
| /* 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 ebRENDESVOUS_TASK_1_SYNC_BIT ebBIT_2 | |
| #define ebRENDESVOUS_TASK_2_SYNC_BIT ebBIT_3 | |
| #define ebALL_SYNC_BITS ( ebSET_BIT_TASK_SYNC_BIT | ebWAIT_BIT_TASK_SYNC_BIT | ebRENDESVOUS_TASK_1_SYNC_BIT | ebRENDESVOUS_TASK_2_SYNC_BIT ) | |
| /* A block time of zero simply means "don't block". */ | |
| #define ebDONT_BLOCK ( 0 ) | |
| /* A 5ms delay. */ | |
| #define ebSHORT_DELAY ( 5 / portTICK_PERIOD_MS ) | |
| /* 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 | |
| /*-----------------------------------------------------------*/ | |
| /* | |
| * 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 unsigned long 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", configMINIMAL_STACK_SIZE, NULL, ebWAIT_BIT_TASK_PRIORITY, &xTestSlaveTaskHandle ); | |
| xTaskCreate( prvTestMasterTask, "SetB", configMINIMAL_STACK_SIZE, ( void * ) xTestSlaveTaskHandle, ebSET_BIT_TASK_PRIORITY, NULL ); | |
| xTaskCreate( prvSyncTask, "Rndv", configMINIMAL_STACK_SIZE, ( void * ) ebRENDESVOUS_TASK_1_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask1 ); | |
| xTaskCreate( prvSyncTask, "Rndv", configMINIMAL_STACK_SIZE, ( void * ) ebRENDESVOUS_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. */ | |
| 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 peform 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. */ | |
| 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 = 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 unsigned long 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; | |
| } | |