X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=FreeRTOS%2FDemo%2FCommon%2FMinimal%2FQueueSet.c;h=2b405d53a211746efd942b062690719afdc86e5d;hb=bb2faca82c580d60469d268594bdc3cb26a632b3;hp=d5f44e3ca4bb1ab97be685bbfc351b2d23e9d2e8;hpb=5027fc3607387a9d4ff4e75af681a2c0a1d318a1;p=freertos diff --git a/FreeRTOS/Demo/Common/Minimal/QueueSet.c b/FreeRTOS/Demo/Common/Minimal/QueueSet.c index d5f44e3ca..2b405d53a 100644 --- a/FreeRTOS/Demo/Common/Minimal/QueueSet.c +++ b/FreeRTOS/Demo/Common/Minimal/QueueSet.c @@ -1,45 +1,38 @@ /* - FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. + FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved - FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT - http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. *************************************************************************** * * - * FreeRTOS tutorial books are available in pdf and paperback. * - * Complete, revised, and edited pdf reference manuals are also * - * available. * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * * * - * Purchasing FreeRTOS documentation will not only help you, by * - * ensuring you get running as quickly as possible and with an * - * in-depth knowledge of how to use FreeRTOS, it will also help * - * the FreeRTOS project to continue with its mission of providing * - * professional grade, cross platform, de facto standard solutions * - * for microcontrollers - completely free of charge! * + * 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 * * * - * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * - * * - * Thank you for using FreeRTOS, and thank you for your support! * + * 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. See the GNU General Public License for - more details. You should have received a copy of the GNU General Public - License and the FreeRTOS license exception along with FreeRTOS; if not it - can be viewed here: http://www.freertos.org/a00114.html and also obtained - by writing to Richard Barry, contact details for whom are available on the - FreeRTOS WEB site. + 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! @@ -52,18 +45,22 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest versions, license - and contact details. + 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. + 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. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under - the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also - provide a safety engineered and independently SIL3 certified version under - the SafeRTOS brand: http://www.SafeRTOS.com. + 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! */ /* @@ -79,6 +76,7 @@ * queuesetINITIAL_ISR_TX_VALUE to ULONG_MAX. */ + /* Standard includes. */ #include #include @@ -109,15 +107,19 @@ in the range of 0xffff to ULONG_MAX. */ /* 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 +#define queuesetPRIORITY_CHANGE_LOOPS ( ( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ) * 2 ) /* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */ #define queuesetISR_TX_PERIOD ( 100UL ) +/* A delay inserted when the Tx task changes its priority to be above the idle +task priority to ensure the idle priority tasks get some CPU time before the +next iteration of the queue set Tx task. */ +#define queuesetTX_LOOP_DELAY ( 200 / portTICK_PERIOD_MS ) + /* The allowable maximum deviation between a received value and the expected received value. A deviation will occur when data is received from a queue inside an ISR in between a task receiving from a queue and the task checking @@ -128,6 +130,13 @@ the received value. */ testing of limits easier (don't have to deal with wrapping values). */ #define queuesetIGNORED_BOUNDARY ( queuesetALLOWABLE_RX_DEVIATION * 2 ) +typedef enum +{ + eEqualPriority = 0, /* Tx and Rx tasks have the same priority. */ + eTxHigherPriority, /* The priority of the Tx task is above that of the Rx task. */ + eTxLowerPriority /* The priority of the Tx task is below that of the Rx task. */ +} eRelativePriorities; + /* * The task that periodically sends to the queue set. */ @@ -157,7 +166,7 @@ static void prvSendToQueueInSetFromISR( void ); * Create the queues and add them to a queue set before resuming the Tx * task. */ -static void prvSetupTest( xTaskHandle xQueueSetSendingTask ); +static void prvSetupTest( void ); /* * Checks a value received from a queue falls within the range of expected @@ -165,17 +174,29 @@ static void prvSetupTest( xTaskHandle xQueueSetSendingTask ); */ static portBASE_TYPE prvCheckReceivedValueWithinExpectedRange( unsigned long ulReceived, unsigned long ulExpectedReceived ); +/* + * Increase test coverage by occasionally change the priorities of the two tasks + * relative to each other. */ +static void prvChangeRelativePriorities( void ); + +/* + * Local pseudo random number seed and return functions. Used to avoid calls + * to the standard library. + */ +static unsigned long prvRand( void ); +static void prvSRand( unsigned long ulSeed ); + /*-----------------------------------------------------------*/ /* The queues that are added to the set. */ -static xQueueHandle xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; +static QueueHandle_t 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; +static QueueSetHandle_t xQueueSet; /* If the prvQueueSetReceivingTask() task has not detected any errors then it increments ulCycleCounter on each iteration. @@ -197,17 +218,19 @@ xAreQueeuSetTasksStillRunning() function can check it is incrementing as expected. */ static volatile unsigned long ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE; +/* Used by the pseudo random number generator. */ +static unsigned long ulNextRand = 0; + +/* The task handles are stored so their priorities can be changed. */ +TaskHandle_t xQueueSetSendingTask, xQueueSetReceivingTask; + /*-----------------------------------------------------------*/ 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 * ) "SetTx", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask ); - xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "SetRx", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, NULL ); + /* Create the tasks. */ + xTaskCreate( prvQueueSetSendingTask, "SetTx", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask ); + xTaskCreate( prvQueueSetReceivingTask, "SetRx", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, &xQueueSetReceivingTask ); /* 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 @@ -268,25 +291,24 @@ portBASE_TYPE xReturn = pdPASS, x; static void prvQueueSetSendingTask( void *pvParameters ) { -unsigned long ulTaskTxValue = 0; -portBASE_TYPE xQueueToWriteTo; -xQueueHandle xQueueInUse; -unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0; +unsigned long ulTaskTxValue = 0, ulQueueToWriteTo; +QueueHandle_t xQueueInUse; /* Remove compiler warning about the unused parameter. */ ( void ) pvParameters; - srand( ( unsigned int ) &ulTaskTxValue ); + /* Seed mini pseudo random number generator. */ + prvSRand( ( unsigned long ) &ulTaskTxValue ); for( ;; ) { /* Generate the index for the queue to which a value is to be sent. */ - xQueueToWriteTo = rand() % queuesetNUM_QUEUES_IN_SET; - xQueueInUse = xQueues[ xQueueToWriteTo ]; + ulQueueToWriteTo = prvRand() % queuesetNUM_QUEUES_IN_SET; + xQueueInUse = xQueues[ ulQueueToWriteTo ]; /* Note which index is being written to to ensure all the queues are used. */ - ( ulQueueUsedCounter[ xQueueToWriteTo ] )++; + ( ulQueueUsedCounter[ ulQueueToWriteTo ] )++; /* 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. */ @@ -297,6 +319,10 @@ unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0; xQueueSetTasksStatus = pdFAIL; } + #if( configUSE_PREEMPTION == 0 ) + taskYIELD(); + #endif + ulTaskTxValue++; /* If the Tx value has reached the range used by the ISR then set it @@ -306,19 +332,56 @@ unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0; 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; - } + /* Increase test coverage by occasionally change the priorities of the + two tasks relative to each other. */ + prvChangeRelativePriorities(); + } +} +/*-----------------------------------------------------------*/ + +static void prvChangeRelativePriorities( void ) +{ +static unsigned portBASE_TYPE ulLoops = 0; +static eRelativePriorities ePriorities = eEqualPriority; + + /* Occasionally change the task priority relative to the priority of + the receiving task. */ + ulLoops++; + if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS ) + { + ulLoops = 0; - vTaskPrioritySet( NULL, uxPriority ); + switch( ePriorities ) + { + case eEqualPriority: + /* Both tasks are running with medium priority. Now lower the + priority of the receiving task so the Tx task has the higher + relative priority. */ + vTaskPrioritySet( xQueueSetReceivingTask, queuesetLOW_PRIORITY ); + ePriorities = eTxHigherPriority; + break; + + case eTxHigherPriority: + /* The Tx task is running with a higher priority than the Rx + task. Switch the priorities around so the Rx task has the + higher relative priority. */ + vTaskPrioritySet( xQueueSetReceivingTask, queuesetMEDIUM_PRIORITY ); + vTaskPrioritySet( xQueueSetSendingTask, queuesetLOW_PRIORITY ); + ePriorities = eTxLowerPriority; + break; + + case eTxLowerPriority: + /* The Tx task is running with a lower priority than the Rx + task. Make the priorities equal again. */ + vTaskPrioritySet( xQueueSetSendingTask, queuesetMEDIUM_PRIORITY ); + ePriorities = eEqualPriority; + + /* When both tasks are using a non-idle priority the queue set + tasks will starve idle priority tasks of execution time - so + relax a bit before the next iteration to minimise the impact. */ + vTaskDelay( queuesetTX_LOOP_DELAY ); + + break; } } } @@ -327,15 +390,14 @@ unsigned portBASE_TYPE uxPriority = queuesetMEDIUM_PRIORITY, ulLoops = 0; static void prvQueueSetReceivingTask( void *pvParameters ) { unsigned long ulReceived; -xQueueHandle xActivatedQueue; -xTaskHandle xQueueSetSendingTask; +QueueHandle_t xActivatedQueue; - /* The handle to the sending task is passed in using the task parameter. */ - xQueueSetSendingTask = ( xTaskHandle ) pvParameters; + /* Remove compiler warnings. */ + ( void ) pvParameters; /* Create the queues and add them to the queue set before resuming the Tx task. */ - prvSetupTest( xQueueSetSendingTask ); + prvSetupTest(); for( ;; ) { @@ -423,17 +485,11 @@ static unsigned long ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = { /* The value received is at the lower limit of the expected range. Don't test it and expect to receive one higher next time. */ - ulExpectedReceivedFromISR++; } else if( ( ULONG_MAX - ulReceived ) <= queuesetIGNORED_BOUNDARY ) { /* The value received is at the higher limit of the expected range. Don't test it and expect to wrap soon. */ - ulExpectedReceivedFromISR++; - if( ulExpectedReceivedFromISR == 0 ) - { - ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; - } } else { @@ -442,11 +498,15 @@ static unsigned long ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = { xQueueSetTasksStatus = pdFAIL; } - else - { - /* It is expected to receive an incrementing value. */ - ulExpectedReceivedFromISR++; - } + } + + configASSERT( xQueueSetTasksStatus ); + + /* It is expected to receive an incrementing number. */ + ulExpectedReceivedFromISR++; + if( ulExpectedReceivedFromISR == 0 ) + { + ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; } } else @@ -456,17 +516,11 @@ static unsigned long ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = { /* The value received is at the lower limit of the expected range. Don't test it, and expect to receive one higher next time. */ - ulExpectedReceivedFromTask++; } else if( ( ( queuesetINITIAL_ISR_TX_VALUE - 1 ) - ulReceived ) <= queuesetIGNORED_BOUNDARY ) { /* The value received is at the higher limit of the expected range. Don't test it and expect to wrap soon. */ - ulExpectedReceivedFromTask++; - if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE ) - { - ulExpectedReceivedFromTask = 0; - } } else { @@ -475,11 +529,15 @@ static unsigned long ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = { xQueueSetTasksStatus = pdFAIL; } - else - { - /* It is expected to receive an incrementing value. */ - ulExpectedReceivedFromTask++; - } + } + + configASSERT( xQueueSetTasksStatus ); + + /* It is expected to receive an incrementing number. */ + ulExpectedReceivedFromTask++; + if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE ) + { + ulExpectedReceivedFromTask = 0; } } } @@ -512,7 +570,7 @@ portBASE_TYPE xReturn = pdPASS; static void prvReceiveFromQueueInSetFromISR( void ) { -xQueueSetMemberHandle xActivatedQueue; +QueueSetMemberHandle_t xActivatedQueue; unsigned long ulReceived; /* See if any of the queues in the set contain data. */ @@ -559,9 +617,10 @@ static portBASE_TYPE xQueueToWriteTo = 0; } /*-----------------------------------------------------------*/ -static void prvSetupTest( xTaskHandle xQueueSetSendingTask ) +static void prvSetupTest( void ) { portBASE_TYPE x; +unsigned long ulValueToSend = 0; /* Ensure the queues are created and the queue set configured before the sending task is unsuspended. @@ -608,7 +667,18 @@ portBASE_TYPE x; xQueueSetTasksStatus = pdFAIL; } - /* Add the queue back again before starting the dynamic tests. */ + /* Add an item to the queue before attempting to add it back into the + set. */ + xQueueSend( xQueues[ 0 ], ( void * ) &ulValueToSend, 0 ); + if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdFAIL ) + { + /* Should not be able to add a non-empty queue to a set. */ + xQueueSetTasksStatus = pdFAIL; + } + + /* Remove the item from the queue before adding the queue back into the + set so the dynamic tests can begin. */ + xQueueReceive( xQueues[ 0 ], &ulValueToSend, 0 ); if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdPASS ) { /* If the queue was successfully removed from the queue set then it @@ -629,3 +699,17 @@ portBASE_TYPE x; /* Let the ISR access the queues also. */ xSetupComplete = pdTRUE; } +/*-----------------------------------------------------------*/ + +static unsigned long prvRand( void ) +{ + ulNextRand = ( ulNextRand * 1103515245UL ) + 12345UL; + return ( ulNextRand / 65536UL ) % 32768UL; +} +/*-----------------------------------------------------------*/ + +static void prvSRand( unsigned long ulSeed ) +{ + ulNextRand = ulSeed; +} +