mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-08-11 13:54:16 -04:00
Continue working on queue set implementation and testing.
This commit is contained in:
parent
4e5090e061
commit
232a5b3433
6 changed files with 329 additions and 103 deletions
|
@ -70,10 +70,13 @@
|
|||
* Demonstrates the creation an use of queue sets.
|
||||
*
|
||||
* A receive task creates a number of queues and adds them to a queue set before
|
||||
* blocking on a queue set receive. A transmit task repeatedly unblocks the
|
||||
* receive task by sending messages to the queues in a pseudo random order.
|
||||
* The receive task removes the messages from the queues and flags an error if
|
||||
* the received message does not match that expected.
|
||||
* blocking on the queue set receive. A transmit task and (optionally) an
|
||||
* interrupt repeatedly unblocks the receive task by sending messages to the
|
||||
* queues in a pseudo random order. The receive task removes the messages from
|
||||
* the queues and flags an error if the received message does not match that
|
||||
* expected. The task sends values in the range 0 to
|
||||
* queuesetINITIAL_ISR_TX_VALUE, and the ISR sends value in the range
|
||||
* queuesetINITIAL_ISR_TX_VALUE to 0xffffffffUL;
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
|
@ -94,6 +97,23 @@
|
|||
#define queuesetSHORT_DELAY 200
|
||||
#define queuesetDONT_BLOCK 0
|
||||
|
||||
/* Messages are sent in incrementing order from both a task and an interrupt.
|
||||
The task sends values in the range 0 to 0xfffe, and the interrupt sends values
|
||||
in the range of 0xffff to 0xffffffff; */
|
||||
#define queuesetINITIAL_ISR_TX_VALUE 0xffffUL
|
||||
|
||||
/* The priorities used in this demo. */
|
||||
#define queuesetLOW_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define queuesetMEDIUM_PRIORITY ( queuesetLOW_PRIORITY + 1 )
|
||||
#define queuesetHIGH_PRIORITY ( queuesetMEDIUM_PRIORITY + 1 )
|
||||
|
||||
/* For test purposes the priority of the sending task is changed after every
|
||||
queuesetPRIORITY_CHANGE_LOOPS number of values are sent to a queue. */
|
||||
#define queuesetPRIORITY_CHANGE_LOOPS 100UL
|
||||
|
||||
/* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */
|
||||
#define queuesetISR_TX_PERIOD ( 100UL )
|
||||
|
||||
/*
|
||||
* The task that periodically sends to the queue set.
|
||||
*/
|
||||
|
@ -107,6 +127,10 @@ static void prvQueueSetReceivingTask( void *pvParameters );
|
|||
/* The queues that are added to the set. */
|
||||
static xQueueHandle xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
|
||||
|
||||
/* Counts how many times each queue in the set is used to ensure all the
|
||||
queues are used. */
|
||||
static unsigned long ulQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
|
||||
|
||||
/* The handle of the queue set to which the queues are added. */
|
||||
static xQueueSetHandle xQueueSet;
|
||||
|
||||
|
@ -115,24 +139,32 @@ it increments ulCycleCounter on each iteration.
|
|||
xAreQueueSetTasksStillRunning() returns pdPASS if the value of
|
||||
ulCycleCounter has changed between consecutive calls, and pdFALSE if
|
||||
ulCycleCounter has stopped incrementing (indicating an error condition). */
|
||||
volatile unsigned long ulCycleCounter = 0UL;
|
||||
static volatile unsigned long ulCycleCounter = 0UL;
|
||||
|
||||
/* Set to pdFAIL if an error is detected by any queue set task.
|
||||
ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */
|
||||
volatile portBASE_TYPE xQueueSetTasksStatus = pdPASS;
|
||||
static volatile portBASE_TYPE xQueueSetTasksStatus = pdPASS;
|
||||
|
||||
/* Just a flag to let the function that writes to a queue from an ISR know that
|
||||
the queues are setup and can be used. */
|
||||
static volatile portBASE_TYPE xSetupComplete = pdFALSE;
|
||||
|
||||
/* The value sent to the queue from the ISR is file scope so the
|
||||
xAreQueeuSetTasksStillRunning() function can check it is incrementing as
|
||||
expected. */
|
||||
static volatile unsigned long ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueueSetTasks( unsigned portBASE_TYPE uxPriority )
|
||||
void vStartQueueSetTasks( void )
|
||||
{
|
||||
xTaskHandle xQueueSetSendingTask;
|
||||
|
||||
/* Create the two queues. The handle of the sending task is passed into
|
||||
the receiving task using the task parameter. The receiving task uses the
|
||||
handle to resume the sending task after it has created the queues. */
|
||||
xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xQueueSetSendingTask );
|
||||
xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, uxPriority, NULL );
|
||||
xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask );
|
||||
xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, NULL );
|
||||
|
||||
/* It is important that the sending task does not attempt to write to a
|
||||
queue before the queue has been created. It is therefore placed into the
|
||||
|
@ -145,8 +177,9 @@ xTaskHandle xQueueSetSendingTask;
|
|||
|
||||
portBASE_TYPE xAreQueueSetTasksStillRunning( void )
|
||||
{
|
||||
static unsigned long ulLastCycleCounter;
|
||||
portBASE_TYPE xReturn;
|
||||
static unsigned long ulLastCycleCounter, ulLastISRTxValue = 0;
|
||||
static unsigned long ulLastQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
|
||||
portBASE_TYPE xReturn = pdPASS, x;
|
||||
|
||||
if( ulLastCycleCounter == ulCycleCounter )
|
||||
{
|
||||
|
@ -154,44 +187,180 @@ portBASE_TYPE xReturn;
|
|||
tasks is stalled or an error has been detected. */
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
ulLastCycleCounter = ulCycleCounter;
|
||||
|
||||
/* Ensure that all the queues in the set have been used. This ensures the
|
||||
test is working as intended and guards against the rand() in the Tx task
|
||||
missing some values. */
|
||||
for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )
|
||||
{
|
||||
if( ulLastQueueUsedCounter[ x ] == ulQueueUsedCounter[ x ] )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
ulLastQueueUsedCounter[ x ] = ulQueueUsedCounter[ x ];
|
||||
}
|
||||
|
||||
/* Check the global status flag. */
|
||||
if( xQueueSetTasksStatus != pdPASS )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
/* Check that the ISR is still sending values to the queues too. */
|
||||
if( ulISRTxValue == ulLastISRTxValue )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdPASS;
|
||||
ulLastISRTxValue = ulISRTxValue;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vQueueSetWriteToQueueFromISR( void )
|
||||
{
|
||||
portBASE_TYPE x = 0;
|
||||
static unsigned long ulCallCount = 0;
|
||||
|
||||
/* xSetupComplete is set to pdTRUE when the queues have been created and
|
||||
are available for use. */
|
||||
if( xSetupComplete == pdTRUE )
|
||||
{
|
||||
/* It is intended that this function is called from the tick hook
|
||||
function, so each call is one tick period apart. */
|
||||
ulCallCount++;
|
||||
if( ulCallCount > queuesetISR_TX_PERIOD )
|
||||
{
|
||||
ulCallCount = 0;
|
||||
|
||||
/* Look for a queue that can be written to. */
|
||||
for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )
|
||||
{
|
||||
if( xQueues[ x ] != NULL )
|
||||
{
|
||||
/* xQueues[ x ] can be written to. Send the next value. */
|
||||
if( xQueueSendFromISR( xQueues[ x ], &ulISRTxValue, NULL ) == pdPASS )
|
||||
{
|
||||
ulISRTxValue++;
|
||||
|
||||
/* If the Tx value has wrapped then set it back to its
|
||||
initial value. */
|
||||
if( ulISRTxValue == 0UL )
|
||||
{
|
||||
ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSetSendingTask( void *pvParameters )
|
||||
{
|
||||
unsigned long ulTxValue = 0;
|
||||
unsigned long ulTaskTxValue = 0;
|
||||
portBASE_TYPE xQueueToWriteTo;
|
||||
xQueueHandle xQueueInUse;
|
||||
unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0;
|
||||
|
||||
/* Remove compiler warning about the unused parameter. */
|
||||
( void ) pvParameters;
|
||||
|
||||
srand( ( unsigned int ) &ulTxValue );
|
||||
srand( ( unsigned int ) &ulTaskTxValue );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Generate the index for the queue to which a value is to be sent. */
|
||||
xQueueToWriteTo = rand() % queuesetNUM_QUEUES_IN_SET;
|
||||
if( xQueueSendToBack( xQueues[ xQueueToWriteTo ], &ulTxValue, portMAX_DELAY ) != pdPASS )
|
||||
xQueueInUse = xQueues[ xQueueToWriteTo ];
|
||||
|
||||
/* Note which index is being written to to ensure all the queues are
|
||||
used. */
|
||||
( ulQueueUsedCounter[ xQueueToWriteTo ] )++;
|
||||
|
||||
/* Send to the queue to unblock the task that is waiting for data to
|
||||
arrive on a queue within the queue set to which this queue belongs. */
|
||||
if( xQueueSendToBack( xQueueInUse, &ulTaskTxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* The send should always pass as an infinite block time was
|
||||
used. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
ulTxValue++;
|
||||
/* Attempt to remove the queue from a queue set it does not belong
|
||||
to (NULL being passed as the queue set in this case). */
|
||||
if( xQueueRemoveFromQueueSet( xQueueInUse, NULL ) != pdFAIL )
|
||||
{
|
||||
/* It is not possible to successfully remove a queue from a queue
|
||||
set it does not belong to. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Mark the space in the array of queues as being empty before actually
|
||||
removing the queue from the queue set. This is to prevent the code
|
||||
that accesses the queue set from an interrupt from attempting to access
|
||||
a queue that is no longer in the set. */
|
||||
xQueues[ xQueueToWriteTo ] = 0;
|
||||
|
||||
/* Attempt to remove the queue from the queue set it does belong to. */
|
||||
if( xQueueRemoveFromQueueSet( xQueueInUse, xQueueSet ) != pdPASS )
|
||||
{
|
||||
/* It should be possible to remove the queue from the queue set it
|
||||
does belong to. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Add the queue back before cycling back to run again. */
|
||||
if( xQueueAddToQueueSet( xQueueInUse, xQueueSet ) != pdPASS )
|
||||
{
|
||||
/* If the queue was successfully removed from the queue set then it
|
||||
should be possible to add it back in again. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Now the queue is back in the set it is ok for the interrupt that
|
||||
writes to the queues to access it again. */
|
||||
xQueues[ xQueueToWriteTo ] = xQueueInUse;
|
||||
|
||||
ulTaskTxValue++;
|
||||
|
||||
/* If the Tx value has reached the range used by the ISR then set it
|
||||
back to 0. */
|
||||
if( ulTaskTxValue == queuesetINITIAL_ISR_TX_VALUE )
|
||||
{
|
||||
ulTaskTxValue = 0;
|
||||
}
|
||||
|
||||
/* Occasionally change the task priority relative to the priority of
|
||||
the receiving task. */
|
||||
ulLoops++;
|
||||
if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS )
|
||||
{
|
||||
ulLoops = 0;
|
||||
uxPriority++;
|
||||
if( uxPriority > queuesetHIGH_PRIORITY )
|
||||
{
|
||||
uxPriority = queuesetLOW_PRIORITY;
|
||||
}
|
||||
|
||||
vTaskPrioritySet( NULL, uxPriority );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSetReceivingTask( void *pvParameters )
|
||||
{
|
||||
unsigned long ulReceived, ulLastReceived = ~0UL;
|
||||
unsigned long ulReceived, ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;
|
||||
xQueueHandle xActivatedQueue;
|
||||
portBASE_TYPE x;
|
||||
xTaskHandle xQueueSetSendingTask;
|
||||
|
@ -208,7 +377,8 @@ xTaskHandle xQueueSetSendingTask;
|
|||
|
||||
for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )
|
||||
{
|
||||
/* Create the queue and add it to the set. */
|
||||
/* Create the queue and add it to the set. The queue is just holding
|
||||
unsigned long value. */
|
||||
xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( unsigned long ) );
|
||||
configASSERT( xQueues[ x ] );
|
||||
if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdPASS )
|
||||
|
@ -227,16 +397,19 @@ xTaskHandle xQueueSetSendingTask;
|
|||
/* The task that sends to the queues is not running yet, so attempting to
|
||||
read from the queue set should fail, resulting in xActivatedQueue being set
|
||||
to NULL. */
|
||||
xActivatedQueue = xQueueReadMultiple( xQueueSet, queuesetSHORT_DELAY );
|
||||
xActivatedQueue = xQueueBlockMultiple( xQueueSet, queuesetSHORT_DELAY );
|
||||
configASSERT( xActivatedQueue == NULL );
|
||||
|
||||
/* Resume the task that writes to the queues. */
|
||||
vTaskResume( xQueueSetSendingTask );
|
||||
|
||||
/* Let the ISR access the queues also. */
|
||||
xSetupComplete = pdTRUE;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait for a message to arrive on one of the queues in the set. */
|
||||
xActivatedQueue = xQueueReadMultiple( xQueueSet, portMAX_DELAY );
|
||||
xActivatedQueue = xQueueBlockMultiple( xQueueSet, portMAX_DELAY );
|
||||
configASSERT( xActivatedQueue );
|
||||
|
||||
if( xActivatedQueue == NULL )
|
||||
|
@ -254,16 +427,51 @@ xTaskHandle xQueueSetSendingTask;
|
|||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* It is always expected that the received value will be one
|
||||
greater than the previously received value. */
|
||||
configASSERT( ulReceived == ( ulLastReceived + 1 ) );
|
||||
if( ulReceived != ( ulLastReceived + 1 ) )
|
||||
/* If the received value is equal to or greater than
|
||||
queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */
|
||||
if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
/* The value was sent from the ISR. Check it against its
|
||||
expected value. */
|
||||
configASSERT( ulReceived == ulExpectedReceivedFromISR );
|
||||
if( ulReceived != ulExpectedReceivedFromISR )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It is expected to receive an incrementing value. */
|
||||
ulExpectedReceivedFromISR++;
|
||||
|
||||
/* If the expected value has wrapped then set it back to
|
||||
its initial value. */
|
||||
if( ulExpectedReceivedFromISR == 0 )
|
||||
{
|
||||
ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastReceived = ulReceived;
|
||||
/* The value was sent from the Tx task. Check it against its
|
||||
expected value. */
|
||||
configASSERT( ulReceived == ulExpectedReceivedFromTask );
|
||||
if( ulReceived != ulExpectedReceivedFromTask )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It is expected to receive an incrementing value. */
|
||||
ulExpectedReceivedFromTask++;
|
||||
|
||||
/* If the expected value has reached the range of values
|
||||
used by the ISR then set it back to 0. */
|
||||
if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE )
|
||||
{
|
||||
ulExpectedReceivedFromTask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue