EBIKE-FreeRTOS/Common/Minimal/EventGroupsDemo.c
2024-04-14 18:38:39 +08:00

1059 lines
39 KiB
C

/*
* 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;
}