]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/Common/Minimal/QueueSet.c
Update version number ready for release.
[freertos] / FreeRTOS / Demo / Common / Minimal / QueueSet.c
index 809aff1ed416147fa9f666685eb48a046abdc38e..2b405d53a211746efd942b062690719afdc86e5d 100644 (file)
@@ -1,45 +1,38 @@
 /*\r
-    FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd.\r
+    FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd. \r
+    All rights reserved\r
 \r
-    FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
-    http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
+    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
 \r
     ***************************************************************************\r
      *                                                                       *\r
-     *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
-     *    Complete, revised, and edited pdf reference manuals are also       *\r
-     *    available.                                                         *\r
+     *    FreeRTOS provides completely free yet professionally developed,    *\r
+     *    robust, strictly quality controlled, supported, and cross          *\r
+     *    platform software that has become a de facto standard.             *\r
      *                                                                       *\r
-     *    Purchasing FreeRTOS documentation will not only help you, by       *\r
-     *    ensuring you get running as quickly as possible and with an        *\r
-     *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
-     *    the FreeRTOS project to continue with its mission of providing     *\r
-     *    professional grade, cross platform, de facto standard solutions    *\r
-     *    for microcontrollers - completely free of charge!                  *\r
+     *    Help yourself get started quickly and support the FreeRTOS         *\r
+     *    project by purchasing a FreeRTOS tutorial book, reference          *\r
+     *    manual, or both from: http://www.FreeRTOS.org/Documentation        *\r
      *                                                                       *\r
-     *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
-     *                                                                       *\r
-     *    Thank you for using FreeRTOS, and thank you for your support!      *\r
+     *    Thank you!                                                         *\r
      *                                                                       *\r
     ***************************************************************************\r
 \r
-\r
     This file is part of the FreeRTOS distribution.\r
 \r
     FreeRTOS is free software; you can redistribute it and/or modify it under\r
     the terms of the GNU General Public License (version 2) as published by the\r
-    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
-    >>>NOTE<<< The modification to the GPL is included to allow you to\r
-    distribute a combined work that includes FreeRTOS without being obliged to\r
-    provide the source code for proprietary components outside of the FreeRTOS\r
-    kernel.  FreeRTOS is distributed in the hope that it will be useful, but\r
-    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
-    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
-    more details. You should have received a copy of the GNU General Public\r
-    License and the FreeRTOS license exception along with FreeRTOS; if not it\r
-    can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
-    by writing to Richard Barry, contact details for whom are available on the\r
-    FreeRTOS WEB site.\r
+    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
+\r
+    >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
+    >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
+    >>!   obliged to provide the source code for proprietary components     !<<\r
+    >>!   outside of the FreeRTOS kernel.                                   !<<\r
+\r
+    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
+    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+    FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
+    link: http://www.freertos.org/a00114.html\r
 \r
     1 tab == 4 spaces!\r
 \r
      *                                                                       *\r
     ***************************************************************************\r
 \r
-\r
-    http://www.FreeRTOS.org - Documentation, training, latest versions, license\r
-    and contact details.\r
+    http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
+    license and Real Time Engineers Ltd. contact details.\r
 \r
     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
-    including FreeRTOS+Trace - an indispensable productivity tool.\r
+    including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
+    compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
 \r
-    Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell\r
-    the code with commercial support, indemnification, and middleware, under\r
-    the OpenRTOS brand: http://www.OpenRTOS.com.  High Integrity Systems also\r
-    provide a safety engineered and independently SIL3 certified version under\r
-    the SafeRTOS brand: http://www.SafeRTOS.com.\r
+    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
+    Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
+    licenses offer ticketed support, indemnification and middleware.\r
+\r
+    http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
+    engineered and independently SIL3 certified version for use in safety and\r
+    mission critical applications that require provable dependability.\r
+\r
+    1 tab == 4 spaces!\r
 */\r
 \r
 /*\r
- * Demonstrates the creation an use of queue sets.\r
+ * Tests the use of queue sets.\r
  *\r
  * A receive task creates a number of queues and adds them to a queue set before\r
  * blocking on the queue set receive.  A transmit task and (optionally) an\r
  * the queues and flags an error if the received message does not match that\r
  * expected.  The task sends values in the range 0 to\r
  * queuesetINITIAL_ISR_TX_VALUE, and the ISR sends value in the range\r
- * queuesetINITIAL_ISR_TX_VALUE to 0xffffffffUL;\r
+ * queuesetINITIAL_ISR_TX_VALUE to ULONG_MAX.\r
  */\r
 \r
+\r
 /* Standard includes. */\r
 #include <stdlib.h>\r
+#include <limits.h>\r
 \r
 /* Kernel includes. */\r
 #include "FreeRTOS.h"\r
 \r
 /* Messages are sent in incrementing order from both a task and an interrupt.\r
 The task sends values in the range 0 to 0xfffe, and the interrupt sends values\r
-in the range of 0xffff to 0xffffffff; */\r
+in the range of 0xffff to ULONG_MAX. */\r
 #define queuesetINITIAL_ISR_TX_VALUE 0xffffUL\r
 \r
 /* The priorities used in this demo. */\r
 #define queuesetLOW_PRIORITY   ( tskIDLE_PRIORITY )\r
 #define queuesetMEDIUM_PRIORITY ( queuesetLOW_PRIORITY + 1 )\r
-#define queuesetHIGH_PRIORITY  ( queuesetMEDIUM_PRIORITY + 1 )\r
 \r
 /* For test purposes the priority of the sending task is changed after every\r
 queuesetPRIORITY_CHANGE_LOOPS number of values are sent to a queue. */\r
-#define queuesetPRIORITY_CHANGE_LOOPS  100UL\r
+#define queuesetPRIORITY_CHANGE_LOOPS  ( ( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ) * 2 )\r
 \r
 /* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */\r
 #define queuesetISR_TX_PERIOD  ( 100UL )\r
 \r
+/* A delay inserted when the Tx task changes its priority to be above the idle\r
+task priority to ensure the idle priority tasks get some CPU time before the\r
+next iteration of the queue set Tx task. */\r
+#define queuesetTX_LOOP_DELAY  ( 200 / portTICK_PERIOD_MS )\r
+\r
+/* The allowable maximum deviation between a received value and the expected\r
+received value.  A deviation will occur when data is received from a queue\r
+inside an ISR in between a task receiving from a queue and the task checking\r
+the received value. */\r
+#define queuesetALLOWABLE_RX_DEVIATION 3\r
+\r
+/* Ignore values that are at the boundaries of allowable values to make the\r
+testing of limits easier (don't have to deal with wrapping values). */\r
+#define queuesetIGNORED_BOUNDARY       ( queuesetALLOWABLE_RX_DEVIATION * 2 )\r
+\r
+typedef enum\r
+{\r
+       eEqualPriority = 0,     /* Tx and Rx tasks have the same priority. */\r
+       eTxHigherPriority,      /* The priority of the Tx task is above that of the Rx task. */\r
+       eTxLowerPriority        /* The priority of the Tx task is below that of the Rx task. */\r
+} eRelativePriorities;\r
+\r
 /*\r
  * The task that periodically sends to the queue set.\r
  */\r
@@ -127,15 +147,56 @@ static void prvQueueSetSendingTask( void *pvParameters );
  */\r
 static void prvQueueSetReceivingTask( void *pvParameters );\r
 \r
+/*\r
+ * Check the value received from a queue is the expected value.  Some values\r
+ * originate from the send task, some values originate from the ISR, with the\r
+ * range of the value being used to distinguish between the two message\r
+ * sources.\r
+ */\r
+static void prvCheckReceivedValue( unsigned long ulReceived );\r
+\r
+/*\r
+ * For purposes of test coverage, functions that read from and write to a\r
+ * queue set from an ISR respectively.\r
+ */\r
+static void prvReceiveFromQueueInSetFromISR( void );\r
+static void prvSendToQueueInSetFromISR( void );\r
+\r
+/*\r
+ * Create the queues and add them to a queue set before resuming the Tx\r
+ * task.\r
+ */\r
+static void prvSetupTest( void );\r
+\r
+/*\r
+ * Checks a value received from a queue falls within the range of expected\r
+ * values.\r
+ */\r
+static portBASE_TYPE prvCheckReceivedValueWithinExpectedRange( unsigned long ulReceived, unsigned long ulExpectedReceived );\r
+\r
+/*\r
+ * Increase test coverage by occasionally change the priorities of the two tasks\r
+ * relative to each other. */\r
+static void prvChangeRelativePriorities( void );\r
+\r
+/*\r
+ * Local pseudo random number seed and return functions.  Used to avoid calls\r
+ * to the standard library.\r
+ */\r
+static unsigned long prvRand( void );\r
+static void prvSRand( unsigned long ulSeed );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
 /* The queues that are added to the set. */\r
-static xQueueHandle xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 };\r
+static QueueHandle_t xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 };\r
 \r
 /* Counts how many times each queue in the set is used to ensure all the\r
 queues are used. */\r
 static unsigned long ulQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 };\r
 \r
 /* The handle of the queue set to which the queues are added. */\r
-static xQueueSetHandle xQueueSet;\r
+static QueueSetHandle_t xQueueSet;\r
 \r
 /* If the prvQueueSetReceivingTask() task has not detected any errors then\r
 it increments ulCycleCounter on each iteration.\r
@@ -157,17 +218,19 @@ xAreQueeuSetTasksStillRunning() function can check it is incrementing as
 expected. */\r
 static volatile unsigned long ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;\r
 \r
+/* Used by the pseudo random number generator. */\r
+static unsigned long ulNextRand = 0;\r
+\r
+/* The task handles are stored so their priorities can be changed. */\r
+TaskHandle_t xQueueSetSendingTask, xQueueSetReceivingTask;\r
+\r
 /*-----------------------------------------------------------*/\r
 \r
 void vStartQueueSetTasks( void )\r
 {\r
-xTaskHandle xQueueSetSendingTask;\r
-\r
-       /* Create the two queues.  The handle of the sending task is passed into\r
-       the receiving task using the task parameter.  The receiving task uses the\r
-       handle to resume the sending task after it has created the queues. */\r
-       xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask );\r
-       xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, NULL );\r
+       /* Create the tasks. */\r
+       xTaskCreate( prvQueueSetSendingTask, "SetTx", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask );\r
+       xTaskCreate( prvQueueSetReceivingTask, "SetRx", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, &xQueueSetReceivingTask );\r
 \r
        /* It is important that the sending task does not attempt to write to a\r
        queue before the queue has been created.  It is therefore placed into the\r
@@ -226,69 +289,26 @@ portBASE_TYPE xReturn = pdPASS, x;
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-void vQueueSetWriteToQueueFromISR( void )\r
-{\r
-portBASE_TYPE x = 0;\r
-static unsigned long ulCallCount = 0;\r
-\r
-       /* xSetupComplete is set to pdTRUE when the queues have been created and\r
-       are available for use. */\r
-       if( xSetupComplete == pdTRUE )\r
-       {\r
-               /* It is intended that this function is called from the tick hook\r
-               function, so each call is one tick period apart. */\r
-               ulCallCount++;\r
-               if( ulCallCount > queuesetISR_TX_PERIOD )\r
-               {\r
-                       ulCallCount = 0;\r
-\r
-                       /* Look for a queue that can be written to. */\r
-                       for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )\r
-                       {\r
-                               if( xQueues[ x ] != NULL )\r
-                               {\r
-                                       /* xQueues[ x ] can be written to.  Send the next value. */\r
-                                       if( xQueueSendFromISR( xQueues[ x ], ( void * ) &ulISRTxValue, NULL ) == pdPASS )\r
-                                       {\r
-                                               ulISRTxValue++;\r
-\r
-                                               /* If the Tx value has wrapped then set it back to its\r
-                                               initial value. */\r
-                                               if( ulISRTxValue == 0UL )\r
-                                               {\r
-                                                       ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;\r
-                                               }\r
-                                       }\r
-\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
 static void prvQueueSetSendingTask( void *pvParameters )\r
 {\r
-unsigned long ulTaskTxValue = 0;\r
-portBASE_TYPE xQueueToWriteTo;\r
-xQueueHandle xQueueInUse;\r
-unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0;\r
+unsigned long ulTaskTxValue = 0, ulQueueToWriteTo;\r
+QueueHandle_t xQueueInUse;\r
 \r
        /* Remove compiler warning about the unused parameter. */\r
        ( void ) pvParameters;\r
 \r
-       srand( ( unsigned int ) &ulTaskTxValue );\r
+       /* Seed mini pseudo random number generator. */\r
+       prvSRand( ( unsigned long ) &ulTaskTxValue );\r
 \r
        for( ;; )\r
        {\r
                /* Generate the index for the queue to which a value is to be sent. */\r
-               xQueueToWriteTo = rand() % queuesetNUM_QUEUES_IN_SET;\r
-               xQueueInUse = xQueues[ xQueueToWriteTo ];\r
+               ulQueueToWriteTo = prvRand() % queuesetNUM_QUEUES_IN_SET;\r
+               xQueueInUse = xQueues[ ulQueueToWriteTo ];\r
 \r
                /* Note which index is being written to to ensure all the queues are\r
                used. */\r
-               ( ulQueueUsedCounter[ xQueueToWriteTo ] )++;\r
+               ( ulQueueUsedCounter[ ulQueueToWriteTo ] )++;\r
 \r
                /* Send to the queue to unblock the task that is waiting for data to\r
                arrive on a queue within the queue set to which this queue belongs. */\r
@@ -299,84 +319,315 @@ unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0;
                        xQueueSetTasksStatus = pdFAIL;\r
                }\r
 \r
-               /* Attempt to remove the queue from a queue set it does not belong\r
-               to (NULL being passed as the queue set in this case). */\r
-               if( xQueueRemoveFromQueueSet( xQueueInUse, NULL ) != pdFAIL )\r
+               #if( configUSE_PREEMPTION == 0 )\r
+                       taskYIELD();\r
+               #endif\r
+\r
+               ulTaskTxValue++;\r
+\r
+               /* If the Tx value has reached the range used by the ISR then set it\r
+               back to 0. */\r
+               if( ulTaskTxValue == queuesetINITIAL_ISR_TX_VALUE )\r
                {\r
-                       /* It is not possible to successfully remove a queue from a queue\r
-                       set it does not belong to. */\r
-                       xQueueSetTasksStatus = pdFAIL;\r
+                       ulTaskTxValue = 0;\r
                }\r
 \r
-               /* Mark the space in the array of queues as being empty before actually\r
-               removing the queue from the queue set.  This is to prevent the code\r
-               that accesses the queue set from an interrupt from attempting to access\r
-               a queue that is no longer in the set. */\r
-               xQueues[ xQueueToWriteTo ] = 0;\r
+               /* Increase test coverage by occasionally change the priorities of the\r
+               two tasks relative to each other. */\r
+               prvChangeRelativePriorities();\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvChangeRelativePriorities( void )\r
+{\r
+static unsigned portBASE_TYPE ulLoops = 0;\r
+static eRelativePriorities ePriorities = eEqualPriority;\r
+\r
+       /* Occasionally change the task priority relative to the priority of\r
+       the receiving task. */\r
+       ulLoops++;\r
+       if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS )\r
+       {\r
+               ulLoops = 0;\r
 \r
-               /* Attempt to remove the queue from the queue set it does belong to. */\r
-               if( xQueueRemoveFromQueueSet( xQueueInUse, xQueueSet ) != pdPASS )\r
+               switch( ePriorities )\r
                {\r
-                       /* It should be possible to remove the queue from the queue set it\r
-                       does belong to. */\r
-                       xQueueSetTasksStatus = pdFAIL;\r
+                       case eEqualPriority:\r
+                               /* Both tasks are running with medium priority.  Now lower the\r
+                               priority of the receiving task so the Tx task has the higher\r
+                               relative priority. */\r
+                               vTaskPrioritySet( xQueueSetReceivingTask, queuesetLOW_PRIORITY );\r
+                               ePriorities = eTxHigherPriority;\r
+                               break;\r
+\r
+                       case eTxHigherPriority:\r
+                               /* The Tx task is running with a higher priority than the Rx\r
+                               task.  Switch the priorities around so the Rx task has the\r
+                               higher relative priority. */\r
+                               vTaskPrioritySet( xQueueSetReceivingTask, queuesetMEDIUM_PRIORITY );\r
+                               vTaskPrioritySet( xQueueSetSendingTask, queuesetLOW_PRIORITY );\r
+                               ePriorities = eTxLowerPriority;\r
+                               break;\r
+\r
+                       case eTxLowerPriority:\r
+                               /* The Tx task is running with a lower priority than the Rx\r
+                               task.  Make the priorities equal again. */\r
+                               vTaskPrioritySet( xQueueSetSendingTask, queuesetMEDIUM_PRIORITY );\r
+                               ePriorities = eEqualPriority;\r
+\r
+                               /* When both tasks are using a non-idle priority the queue set\r
+                               tasks will starve idle priority tasks of execution time - so\r
+                               relax a bit before the next iteration to minimise the impact. */\r
+                               vTaskDelay( queuesetTX_LOOP_DELAY );\r
+\r
+                               break;\r
                }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvQueueSetReceivingTask( void *pvParameters )\r
+{\r
+unsigned long ulReceived;\r
+QueueHandle_t xActivatedQueue;\r
+\r
+       /* Remove compiler warnings. */\r
+       ( void ) pvParameters;\r
 \r
-               /* Add the queue back before cycling back to run again. */\r
-               if( xQueueAddToQueueSet( xQueueInUse, xQueueSet ) != pdPASS )\r
+       /* Create the queues and add them to the queue set before resuming the Tx\r
+       task. */\r
+       prvSetupTest();\r
+\r
+       for( ;; )\r
+       {\r
+               /* Wait for a message to arrive on one of the queues in the set. */\r
+               xActivatedQueue = xQueueSelectFromSet( xQueueSet, portMAX_DELAY );\r
+               configASSERT( xActivatedQueue );\r
+\r
+               if( xActivatedQueue == NULL )\r
                {\r
-                       /* If the queue was successfully removed from the queue set then it\r
-                       should be possible to add it back in again. */\r
+                       /* This should not happen as an infinite delay was used. */\r
                        xQueueSetTasksStatus = pdFAIL;\r
                }\r
+               else\r
+               {\r
+                       /* Reading from the queue should pass with a zero block time as\r
+                       this task will only run when something has been posted to a task\r
+                       in the queue set. */\r
+                       if( xQueueReceive( xActivatedQueue, &ulReceived, queuesetDONT_BLOCK ) != pdPASS )\r
+                       {\r
+                               xQueueSetTasksStatus = pdFAIL;\r
+                       }\r
+\r
+                       /* Ensure the value received was the value expected.  This function\r
+                       manipulates file scope data and is also called from an ISR, hence\r
+                       the critical section. */\r
+                       taskENTER_CRITICAL();\r
+                       {\r
+                               prvCheckReceivedValue( ulReceived );\r
+                       }\r
+                       taskEXIT_CRITICAL();\r
+               }\r
 \r
-               /* Now the queue is back in the set it is ok for the interrupt that\r
-               writes to the queues to access it again. */\r
-               xQueues[ xQueueToWriteTo ] = xQueueInUse;\r
+               if( xQueueSetTasksStatus == pdPASS )\r
+               {\r
+                       ulCycleCounter++;\r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
 \r
-               ulTaskTxValue++;\r
+void vQueueSetAccessQueueSetFromISR( void )\r
+{\r
+static unsigned long ulCallCount = 0;\r
 \r
-               /* If the Tx value has reached the range used by the ISR then set it\r
-               back to 0. */\r
-               if( ulTaskTxValue == queuesetINITIAL_ISR_TX_VALUE )\r
+       /* xSetupComplete is set to pdTRUE when the queues have been created and\r
+       are available for use. */\r
+       if( xSetupComplete == pdTRUE )\r
+       {\r
+               /* It is intended that this function is called from the tick hook\r
+               function, so each call is one tick period apart. */\r
+               ulCallCount++;\r
+               if( ulCallCount > queuesetISR_TX_PERIOD )\r
                {\r
-                       ulTaskTxValue = 0;\r
+                       ulCallCount = 0;\r
+\r
+                       /* First attempt to read from the queue set. */\r
+                       prvReceiveFromQueueInSetFromISR();\r
+\r
+                       /* Then write to the queue set. */\r
+                       prvSendToQueueInSetFromISR();\r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCheckReceivedValue( unsigned long ulReceived )\r
+{\r
+static unsigned long ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;\r
+\r
+       /* Values are received in tasks and interrupts.  It is likely that the\r
+       receiving task will sometimes get preempted by the receiving interrupt\r
+       between reading a value from the queue and calling this function.  When\r
+       that happens, if the receiving interrupt calls this function the values\r
+       will get passed into this function slightly out of order.  For that\r
+       reason the value passed in is tested against a small range of expected\r
+       values, rather than a single absolute value.  To make the range testing\r
+       easier values in the range limits are ignored. */\r
+\r
+       /* If the received value is equal to or greater than\r
+       queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */\r
+       if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE )\r
+       {\r
+               /* The value was sent from the ISR. */\r
+               if( ( ulReceived - queuesetINITIAL_ISR_TX_VALUE ) < queuesetIGNORED_BOUNDARY )\r
+               {\r
+                       /* The value received is at the lower limit of the expected range.\r
+                       Don't test it and expect to receive one higher next time. */\r
+               }\r
+               else if( ( ULONG_MAX - ulReceived ) <= queuesetIGNORED_BOUNDARY )\r
+               {\r
+                       /* The value received is at the higher limit of the expected range.\r
+                       Don't test it and expect to wrap soon. */\r
+               }\r
+               else\r
+               {\r
+                       /* Check the value against its expected value range. */\r
+                       if( prvCheckReceivedValueWithinExpectedRange( ulReceived, ulExpectedReceivedFromISR ) != pdPASS )\r
+                       {\r
+                               xQueueSetTasksStatus = pdFAIL;\r
+                       }\r
                }\r
 \r
-               /* Occasionally change the task priority relative to the priority of\r
-               the receiving task. */\r
-               ulLoops++;\r
-               if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS )\r
+               configASSERT( xQueueSetTasksStatus );\r
+\r
+               /* It is expected to receive an incrementing number. */\r
+               ulExpectedReceivedFromISR++;\r
+               if( ulExpectedReceivedFromISR == 0 )\r
+               {\r
+                       ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               /* The value was sent from the Tx task. */\r
+               if( ulReceived < queuesetIGNORED_BOUNDARY )\r
+               {\r
+                       /* The value received is at the lower limit of the expected range.\r
+                       Don't test it, and expect to receive one higher next time. */\r
+               }\r
+               else if( ( ( queuesetINITIAL_ISR_TX_VALUE - 1 ) - ulReceived ) <= queuesetIGNORED_BOUNDARY )\r
+               {\r
+                       /* The value received is at the higher limit of the expected range.\r
+                       Don't test it and expect to wrap soon. */\r
+               }\r
+               else\r
                {\r
-                       ulLoops = 0;\r
-                       uxPriority++;\r
-                       if( uxPriority > queuesetHIGH_PRIORITY )\r
+                       /* Check the value against its expected value range. */\r
+                       if( prvCheckReceivedValueWithinExpectedRange( ulReceived, ulExpectedReceivedFromTask ) != pdPASS )\r
                        {\r
-                               uxPriority = queuesetLOW_PRIORITY;\r
+                               xQueueSetTasksStatus = pdFAIL;\r
                        }\r
+               }\r
+\r
+               configASSERT( xQueueSetTasksStatus );\r
 \r
-                       vTaskPrioritySet( NULL, uxPriority );\r
+               /* It is expected to receive an incrementing number. */\r
+               ulExpectedReceivedFromTask++;\r
+               if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE )\r
+               {\r
+                       ulExpectedReceivedFromTask = 0;\r
                }\r
        }\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-static void prvQueueSetReceivingTask( void *pvParameters )\r
+static portBASE_TYPE prvCheckReceivedValueWithinExpectedRange( unsigned long ulReceived, unsigned long ulExpectedReceived )\r
 {\r
-unsigned long ulReceived, ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;\r
-xQueueHandle xActivatedQueue;\r
-portBASE_TYPE x;\r
-xTaskHandle xQueueSetSendingTask;\r
+portBASE_TYPE xReturn = pdPASS;\r
+\r
+       if( ulReceived > ulExpectedReceived )\r
+       {\r
+               configASSERT( ( ulReceived - ulExpectedReceived ) <= queuesetALLOWABLE_RX_DEVIATION );\r
+               if( ( ulReceived - ulExpectedReceived ) > queuesetALLOWABLE_RX_DEVIATION )\r
+               {\r
+                       xReturn = pdFALSE;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               configASSERT( ( ulExpectedReceived - ulReceived ) <= queuesetALLOWABLE_RX_DEVIATION );\r
+               if( ( ulExpectedReceived - ulReceived ) > queuesetALLOWABLE_RX_DEVIATION )\r
+               {\r
+                       xReturn = pdFALSE;\r
+               }\r
+       }\r
+\r
+       return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvReceiveFromQueueInSetFromISR( void )\r
+{\r
+QueueSetMemberHandle_t xActivatedQueue;\r
+unsigned long ulReceived;\r
+\r
+       /* See if any of the queues in the set contain data. */\r
+       xActivatedQueue = xQueueSelectFromSetFromISR( xQueueSet );\r
+\r
+       if( xActivatedQueue != NULL )\r
+       {\r
+               /* Reading from the queue for test purposes only. */\r
+               if( xQueueReceiveFromISR( xActivatedQueue, &ulReceived, NULL ) != pdPASS )\r
+               {\r
+                       /* Data should have been available as the handle was returned from\r
+                       xQueueSelectFromSetFromISR(). */\r
+                       xQueueSetTasksStatus = pdFAIL;\r
+               }\r
+\r
+               /* Ensure the value received was the value expected. */\r
+               prvCheckReceivedValue( ulReceived );\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSendToQueueInSetFromISR( void )\r
+{\r
+static portBASE_TYPE xQueueToWriteTo = 0;\r
+\r
+       if( xQueueSendFromISR( xQueues[ xQueueToWriteTo ], ( void * ) &ulISRTxValue, NULL ) == pdPASS )\r
+       {\r
+               ulISRTxValue++;\r
+\r
+               /* If the Tx value has wrapped then set it back to its\r
+               initial value. */\r
+               if( ulISRTxValue == 0UL )\r
+               {\r
+                       ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;\r
+               }\r
 \r
-       /* The handle to the sending task is passed in using the task parameter. */\r
-       xQueueSetSendingTask = ( xTaskHandle ) pvParameters;\r
+               /* Use a different queue next time. */\r
+               xQueueToWriteTo++;\r
+               if( xQueueToWriteTo >= queuesetNUM_QUEUES_IN_SET )\r
+               {\r
+                       xQueueToWriteTo = 0;\r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSetupTest( void )\r
+{\r
+portBASE_TYPE x;\r
+unsigned long ulValueToSend = 0;\r
 \r
        /* Ensure the queues are created and the queue set configured before the\r
        sending task is unsuspended.\r
 \r
        First Create the queue set such that it will be able to hold a message for\r
        every space in every queue in the set. */\r
-       xQueueSet = xQueueSetCreate( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH );\r
+       xQueueSet = xQueueCreateSet( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH );\r
 \r
        for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )\r
        {\r
@@ -384,104 +635,81 @@ xTaskHandle xQueueSetSendingTask;
                unsigned long value. */\r
                xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( unsigned long ) );\r
                configASSERT( xQueues[ x ] );\r
-               if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdPASS )\r
+               if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdPASS )\r
                {\r
                        xQueueSetTasksStatus = pdFAIL;\r
                }\r
-\r
-               /* The queue has now been added to the queue set and cannot be added to\r
-               another. */\r
-               if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdFAIL )\r
+               else\r
                {\r
-                       xQueueSetTasksStatus = pdFAIL;\r
+                       /* The queue has now been added to the queue set and cannot be added to\r
+                       another. */\r
+                       if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdFAIL )\r
+                       {\r
+                               xQueueSetTasksStatus = pdFAIL;\r
+                       }\r
                }\r
        }\r
 \r
+       /* Attempt to remove a queue from a queue set it does not belong\r
+       to (NULL being passed as the queue set in this case). */\r
+       if( xQueueRemoveFromSet( xQueues[ 0 ], NULL ) != pdFAIL )\r
+       {\r
+               /* It is not possible to successfully remove a queue from a queue\r
+               set it does not belong to. */\r
+               xQueueSetTasksStatus = pdFAIL;\r
+       }\r
+\r
+       /* Attempt to remove a queue from the queue set it does belong to. */\r
+       if( xQueueRemoveFromSet( xQueues[ 0 ], xQueueSet ) != pdPASS )\r
+       {\r
+               /* It should be possible to remove the queue from the queue set it\r
+               does belong to. */\r
+               xQueueSetTasksStatus = pdFAIL;\r
+       }\r
+\r
+       /* Add an item to the queue before attempting to add it back into the\r
+       set. */\r
+       xQueueSend( xQueues[ 0 ], ( void * ) &ulValueToSend, 0 );\r
+       if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdFAIL )\r
+       {\r
+               /* Should not be able to add a non-empty queue to a set. */\r
+               xQueueSetTasksStatus = pdFAIL;\r
+       }\r
+\r
+       /* Remove the item from the queue before adding the queue back into the\r
+       set so the dynamic tests can begin. */\r
+       xQueueReceive( xQueues[ 0 ], &ulValueToSend, 0 );\r
+       if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdPASS )\r
+       {\r
+               /* If the queue was successfully removed from the queue set then it\r
+               should be possible to add it back in again. */\r
+               xQueueSetTasksStatus = pdFAIL;\r
+       }\r
+\r
        /* The task that sends to the queues is not running yet, so attempting to\r
-       read from the queue set should fail, resulting in xActivatedQueue being set\r
-       to NULL. */\r
-       xActivatedQueue = xQueueBlockMultiple( xQueueSet, queuesetSHORT_DELAY );\r
-       configASSERT( xActivatedQueue == NULL );\r
+       read from the queue set should fail. */\r
+       if( xQueueSelectFromSet( xQueueSet, queuesetSHORT_DELAY ) != NULL )\r
+       {\r
+               xQueueSetTasksStatus = pdFAIL;\r
+       }\r
 \r
        /* Resume the task that writes to the queues. */\r
        vTaskResume( xQueueSetSendingTask );\r
 \r
        /* Let the ISR access the queues also. */\r
        xSetupComplete = pdTRUE;\r
+}\r
+/*-----------------------------------------------------------*/\r
 \r
-       for( ;; )\r
-       {\r
-               /* Wait for a message to arrive on one of the queues in the set. */\r
-               xActivatedQueue = xQueueBlockMultiple( xQueueSet, portMAX_DELAY );\r
-               configASSERT( xActivatedQueue );\r
-\r
-               if( xActivatedQueue == NULL )\r
-               {\r
-                       /* This should not happen as an infinite delay was used. */\r
-                       xQueueSetTasksStatus = pdFAIL;\r
-               }\r
-               else\r
-               {\r
-                       /* Reading from the queue should pass with a zero block time as\r
-                       this task will only run when something has been posted to a task\r
-                       in the queue set. */\r
-                       if( xQueueReceive( xActivatedQueue, &ulReceived, queuesetDONT_BLOCK ) != pdPASS )\r
-                       {\r
-                               xQueueSetTasksStatus = pdFAIL;\r
-                       }\r
-\r
-                       /* If the received value is equal to or greater than\r
-                       queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */\r
-                       if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE )\r
-                       {\r
-                               /* The value was sent from the ISR.  Check it against its\r
-                               expected value. */\r
-                               configASSERT( ulReceived == ulExpectedReceivedFromISR );\r
-                               if( ulReceived != ulExpectedReceivedFromISR )\r
-                               {\r
-                                       xQueueSetTasksStatus = pdFAIL;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* It is expected to receive an incrementing value. */\r
-                                       ulExpectedReceivedFromISR++;\r
-\r
-                                       /* If the expected value has wrapped then set it back to\r
-                                       its initial value. */\r
-                                       if( ulExpectedReceivedFromISR == 0 )\r
-                                       {\r
-                                               ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;\r
-                                       }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               /* The value was sent from the Tx task.  Check it against its\r
-                               expected value. */\r
-                               configASSERT( ulReceived == ulExpectedReceivedFromTask );\r
-                               if( ulReceived != ulExpectedReceivedFromTask )\r
-                               {\r
-                                       xQueueSetTasksStatus = pdFAIL;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* It is expected to receive an incrementing value. */\r
-                                       ulExpectedReceivedFromTask++;\r
-\r
-                                       /* If the expected value has reached the range of values\r
-                                       used by the ISR then set it back to 0. */\r
-                                       if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE )\r
-                                       {\r
-                                               ulExpectedReceivedFromTask = 0;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
+static unsigned long prvRand( void )\r
+{\r
+       ulNextRand = ( ulNextRand * 1103515245UL ) + 12345UL;\r
+    return ( ulNextRand / 65536UL ) % 32768UL;\r
+}\r
+/*-----------------------------------------------------------*/\r
 \r
-               if( xQueueSetTasksStatus == pdPASS )\r
-               {\r
-                       ulCycleCounter++;\r
-               }\r
-       }\r
+static void prvSRand( unsigned long ulSeed )\r
+{\r
+    ulNextRand = ulSeed;\r
 }\r
 \r