00001 /* 00002 FreeRTOS V6.0.0 - Copyright (C) 2009 Real Time Engineers Ltd. 00003 00004 *************************************************************************** 00005 * * 00006 * If you are: * 00007 * * 00008 * + New to FreeRTOS, * 00009 * + Wanting to learn FreeRTOS or multitasking in general quickly * 00010 * + Looking for basic training, * 00011 * + Wanting to improve your FreeRTOS skills and productivity * 00012 * * 00013 * then take a look at the FreeRTOS eBook * 00014 * * 00015 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * 00016 * http://www.FreeRTOS.org/Documentation * 00017 * * 00018 * A pdf reference manual is also available. Both are usually delivered * 00019 * to your inbox within 20 minutes to two hours when purchased between 8am * 00020 * and 8pm GMT (although please allow up to 24 hours in case of * 00021 * exceptional circumstances). Thank you for your support! * 00022 * * 00023 *************************************************************************** 00024 00025 This file is part of the FreeRTOS distribution. 00026 00027 FreeRTOS is free software; you can redistribute it and/or modify it under 00028 the terms of the GNU General Public License (version 2) as published by the 00029 Free Software Foundation AND MODIFIED BY the FreeRTOS exception. 00030 ***NOTE*** The exception to the GPL is included to allow you to distribute 00031 a combined work that includes FreeRTOS without being obliged to provide the 00032 source code for proprietary components outside of the FreeRTOS kernel. 00033 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT 00034 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00035 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00036 more details. You should have received a copy of the GNU General Public 00037 License and the FreeRTOS license exception along with FreeRTOS; if not it 00038 can be viewed here: http://www.freertos.org/a00114.html and also obtained 00039 by writing to Richard Barry, contact details for whom are available on the 00040 FreeRTOS WEB site. 00041 00042 1 tab == 4 spaces! 00043 00044 http://www.FreeRTOS.org - Documentation, latest information, license and 00045 contact details. 00046 00047 http://www.SafeRTOS.com - A version that is certified for use in safety 00048 critical systems. 00049 00050 http://www.OpenRTOS.com - Commercial support, development, porting, 00051 licensing and training services. 00052 */ 00053 00054 /* 00055 * This version of PollQ. c is for use on systems that have limited stack 00056 * space and no display facilities. The complete version can be found in 00057 * the Demo/Common/Full directory. 00058 * 00059 * Creates two tasks that communicate over a single queue. One task acts as a 00060 * producer, the other a consumer. 00061 * 00062 * The producer loops for three iteration, posting an incrementing number onto the 00063 * queue each cycle. It then delays for a fixed period before doing exactly the 00064 * same again. 00065 * 00066 * The consumer loops emptying the queue. Each item removed from the queue is 00067 * checked to ensure it contains the expected value. When the queue is empty it 00068 * blocks for a fixed period, then does the same again. 00069 * 00070 * All queue access is performed without blocking. The consumer completely empties 00071 * the queue each time it runs so the producer should never find the queue full. 00072 * 00073 * An error is flagged if the consumer obtains an unexpected value or the producer 00074 * find the queue is full. 00075 */ 00076 00077 /* 00078 Changes from V2.0.0 00079 00080 + Delay periods are now specified using variables and constants of 00081 portTickType rather than unsigned long. 00082 */ 00083 00084 #include <stdlib.h> 00085 00086 /* Scheduler include files. */ 00087 #include "FreeRTOS.h" 00088 #include "task.h" 00089 #include "queue.h" 00090 00091 /* Demo program include files. */ 00092 #include "PollQ.h" 00093 00094 #define pollqSTACK_SIZE configMINIMAL_STACK_SIZE 00095 #define pollqQUEUE_SIZE ( 10 ) 00096 #define pollqPRODUCER_DELAY ( ( portTickType ) 200 / portTICK_RATE_MS ) 00097 #define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( portTickType ) ( 20 / portTICK_RATE_MS ) ) 00098 #define pollqNO_DELAY ( ( portTickType ) 0 ) 00099 #define pollqVALUES_TO_PRODUCE ( ( signed portBASE_TYPE ) 3 ) 00100 #define pollqINITIAL_VALUE ( ( signed portBASE_TYPE ) 0 ) 00101 00102 /* The task that posts the incrementing number onto the queue. */ 00103 static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters ); 00104 00105 /* The task that empties the queue. */ 00106 static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters ); 00107 00108 /* Variables that are used to check that the tasks are still running with no 00109 errors. */ 00110 static volatile signed portBASE_TYPE xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE; 00111 00112 /*-----------------------------------------------------------*/ 00113 00114 void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority ) 00115 { 00116 static xQueueHandle xPolledQueue; 00117 00118 /* Create the queue used by the producer and consumer. */ 00119 xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) ); 00120 00121 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is 00122 in use. The queue registry is provided as a means for kernel aware 00123 debuggers to locate queues and has no purpose if a kernel aware debugger 00124 is not being used. The call to vQueueAddToRegistry() will be removed 00125 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 00126 defined to be less than 1. */ 00127 vQueueAddToRegistry( xPolledQueue, ( signed char * ) "Poll_Test_Queue" ); 00128 00129 /* Spawn the producer and consumer. */ 00130 xTaskCreate( vPolledQueueConsumer, ( signed char * ) "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL ); 00131 xTaskCreate( vPolledQueueProducer, ( signed char * ) "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL ); 00132 } 00133 /*-----------------------------------------------------------*/ 00134 00135 static portTASK_FUNCTION( vPolledQueueProducer, pvParameters ) 00136 { 00137 unsigned short usValue = ( unsigned short ) 0; 00138 signed portBASE_TYPE xError = pdFALSE, xLoop; 00139 00140 for( ;; ) 00141 { 00142 for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ ) 00143 { 00144 /* Send an incrementing number on the queue without blocking. */ 00145 if( xQueueSend( *( ( xQueueHandle * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS ) 00146 { 00147 /* We should never find the queue full so if we get here there 00148 has been an error. */ 00149 xError = pdTRUE; 00150 } 00151 else 00152 { 00153 if( xError == pdFALSE ) 00154 { 00155 /* If an error has ever been recorded we stop incrementing the 00156 check variable. */ 00157 portENTER_CRITICAL(); 00158 xPollingProducerCount++; 00159 portEXIT_CRITICAL(); 00160 } 00161 00162 /* Update the value we are going to post next time around. */ 00163 usValue++; 00164 } 00165 } 00166 00167 /* Wait before we start posting again to ensure the consumer runs and 00168 empties the queue. */ 00169 vTaskDelay( pollqPRODUCER_DELAY ); 00170 } 00171 } /*lint !e818 Function prototype must conform to API. */ 00172 /*-----------------------------------------------------------*/ 00173 00174 static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters ) 00175 { 00176 unsigned short usData, usExpectedValue = ( unsigned short ) 0; 00177 signed portBASE_TYPE xError = pdFALSE; 00178 00179 for( ;; ) 00180 { 00181 /* Loop until the queue is empty. */ 00182 while( uxQueueMessagesWaiting( *( ( xQueueHandle * ) pvParameters ) ) ) 00183 { 00184 if( xQueueReceive( *( ( xQueueHandle * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS ) 00185 { 00186 if( usData != usExpectedValue ) 00187 { 00188 /* This is not what we expected to receive so an error has 00189 occurred. */ 00190 xError = pdTRUE; 00191 00192 /* Catch-up to the value we received so our next expected 00193 value should again be correct. */ 00194 usExpectedValue = usData; 00195 } 00196 else 00197 { 00198 if( xError == pdFALSE ) 00199 { 00200 /* Only increment the check variable if no errors have 00201 occurred. */ 00202 portENTER_CRITICAL(); 00203 xPollingConsumerCount++; 00204 portEXIT_CRITICAL(); 00205 } 00206 } 00207 00208 /* Next time round we would expect the number to be one higher. */ 00209 usExpectedValue++; 00210 } 00211 } 00212 00213 /* Now the queue is empty we block, allowing the producer to place more 00214 items in the queue. */ 00215 vTaskDelay( pollqCONSUMER_DELAY ); 00216 } 00217 } /*lint !e818 Function prototype must conform to API. */ 00218 /*-----------------------------------------------------------*/ 00219 00220 /* This is called to check that all the created tasks are still running with no errors. */ 00221 portBASE_TYPE xArePollingQueuesStillRunning( void ) 00222 { 00223 portBASE_TYPE xReturn; 00224 00225 /* Check both the consumer and producer poll count to check they have both 00226 been changed since out last trip round. We do not need a critical section 00227 around the check variables as this is called from a higher priority than 00228 the other tasks that access the same variables. */ 00229 if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) || 00230 ( xPollingProducerCount == pollqINITIAL_VALUE ) 00231 ) 00232 { 00233 xReturn = pdFALSE; 00234 } 00235 else 00236 { 00237 xReturn = pdTRUE; 00238 } 00239 00240 /* Set the check variables back down so we know if they have been 00241 incremented the next time around. */ 00242 xPollingConsumerCount = pollqINITIAL_VALUE; 00243 xPollingProducerCount = pollqINITIAL_VALUE; 00244 00245 return xReturn; 00246 }