brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame^] | 1 | /* |
| 2 | FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd. |
| 3 | |
| 4 | *************************************************************************** |
| 5 | * * |
| 6 | * If you are: * |
| 7 | * * |
| 8 | * + New to FreeRTOS, * |
| 9 | * + Wanting to learn FreeRTOS or multitasking in general quickly * |
| 10 | * + Looking for basic training, * |
| 11 | * + Wanting to improve your FreeRTOS skills and productivity * |
| 12 | * * |
| 13 | * then take a look at the FreeRTOS eBook * |
| 14 | * * |
| 15 | * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * |
| 16 | * http://www.FreeRTOS.org/Documentation * |
| 17 | * * |
| 18 | * A pdf reference manual is also available. Both are usually delivered * |
| 19 | * to your inbox within 20 minutes to two hours when purchased between 8am * |
| 20 | * and 8pm GMT (although please allow up to 24 hours in case of * |
| 21 | * exceptional circumstances). Thank you for your support! * |
| 22 | * * |
| 23 | *************************************************************************** |
| 24 | |
| 25 | This file is part of the FreeRTOS distribution. |
| 26 | |
| 27 | FreeRTOS is free software; you can redistribute it and/or modify it under |
| 28 | the terms of the GNU General Public License (version 2) as published by the |
| 29 | Free Software Foundation AND MODIFIED BY the FreeRTOS exception. |
| 30 | ***NOTE*** The exception to the GPL is included to allow you to distribute |
| 31 | a combined work that includes FreeRTOS without being obliged to provide the |
| 32 | source code for proprietary components outside of the FreeRTOS kernel. |
| 33 | FreeRTOS is distributed in the hope that it will be useful, but WITHOUT |
| 34 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 35 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 36 | more details. You should have received a copy of the GNU General Public |
| 37 | License and the FreeRTOS license exception along with FreeRTOS; if not it |
| 38 | can be viewed here: http://www.freertos.org/a00114.html and also obtained |
| 39 | by writing to Richard Barry, contact details for whom are available on the |
| 40 | FreeRTOS WEB site. |
| 41 | |
| 42 | 1 tab == 4 spaces! |
| 43 | |
| 44 | http://www.FreeRTOS.org - Documentation, latest information, license and |
| 45 | contact details. |
| 46 | |
| 47 | http://www.SafeRTOS.com - A version that is certified for use in safety |
| 48 | critical systems. |
| 49 | |
| 50 | http://www.OpenRTOS.com - Commercial support, development, porting, |
| 51 | licensing and training services. |
| 52 | */ |
| 53 | |
| 54 | /* |
| 55 | * This version of PollQ. c is for use on systems that have limited stack |
| 56 | * space and no display facilities. The complete version can be found in |
| 57 | * the Demo/Common/Full directory. |
| 58 | * |
| 59 | * Creates two tasks that communicate over a single queue. One task acts as a |
| 60 | * producer, the other a consumer. |
| 61 | * |
| 62 | * The producer loops for three iteration, posting an incrementing number onto the |
| 63 | * queue each cycle. It then delays for a fixed period before doing exactly the |
| 64 | * same again. |
| 65 | * |
| 66 | * The consumer loops emptying the queue. Each item removed from the queue is |
| 67 | * checked to ensure it contains the expected value. When the queue is empty it |
| 68 | * blocks for a fixed period, then does the same again. |
| 69 | * |
| 70 | * All queue access is performed without blocking. The consumer completely empties |
| 71 | * the queue each time it runs so the producer should never find the queue full. |
| 72 | * |
| 73 | * An error is flagged if the consumer obtains an unexpected value or the producer |
| 74 | * find the queue is full. |
| 75 | */ |
| 76 | |
| 77 | /* |
| 78 | Changes from V2.0.0 |
| 79 | |
| 80 | + Delay periods are now specified using variables and constants of |
| 81 | portTickType rather than unsigned long. |
| 82 | */ |
| 83 | |
| 84 | #include <stdlib.h> |
| 85 | |
| 86 | /* Scheduler include files. */ |
| 87 | #include "FreeRTOS.h" |
| 88 | #include "task.h" |
| 89 | #include "queue.h" |
| 90 | |
| 91 | /* Demo program include files. */ |
| 92 | #include "PollQ.h" |
| 93 | |
| 94 | #define pollqSTACK_SIZE configMINIMAL_STACK_SIZE |
| 95 | #define pollqQUEUE_SIZE ( 10 ) |
| 96 | #define pollqPRODUCER_DELAY ( ( portTickType ) 200 / portTICK_RATE_MS ) |
| 97 | #define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( portTickType ) ( 20 / portTICK_RATE_MS ) ) |
| 98 | #define pollqNO_DELAY ( ( portTickType ) 0 ) |
| 99 | #define pollqVALUES_TO_PRODUCE ( ( signed portBASE_TYPE ) 3 ) |
| 100 | #define pollqINITIAL_VALUE ( ( signed portBASE_TYPE ) 0 ) |
| 101 | |
| 102 | /* The task that posts the incrementing number onto the queue. */ |
| 103 | static portTASK_FUNCTION_PROTO(vPolledQueueProducer, pvParameters); |
| 104 | |
| 105 | /* The task that empties the queue. */ |
| 106 | static portTASK_FUNCTION_PROTO(vPolledQueueConsumer, pvParameters); |
| 107 | |
| 108 | /* Variables that are used to check that the tasks are still running with no |
| 109 | errors. */ |
| 110 | static volatile signed portBASE_TYPE xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE; |
| 111 | |
| 112 | /*-----------------------------------------------------------*/ |
| 113 | |
| 114 | void vStartPolledQueueTasks(unsigned portBASE_TYPE uxPriority) |
| 115 | { |
| 116 | static xQueueHandle xPolledQueue; |
| 117 | |
| 118 | /* Create the queue used by the producer and consumer. */ |
| 119 | xPolledQueue = xQueueCreate(pollqQUEUE_SIZE, (unsigned portBASE_TYPE) sizeof(unsigned short)); |
| 120 | |
| 121 | /* vQueueAddToRegistry() adds the queue to the queue registry, if one is |
| 122 | in use. The queue registry is provided as a means for kernel aware |
| 123 | debuggers to locate queues and has no purpose if a kernel aware debugger |
| 124 | is not being used. The call to vQueueAddToRegistry() will be removed |
| 125 | by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is |
| 126 | defined to be less than 1. */ |
| 127 | vQueueAddToRegistry(xPolledQueue, (signed char *) "Poll_Test_Queue"); |
| 128 | |
| 129 | /* Spawn the producer and consumer. */ |
| 130 | xTaskCreate(vPolledQueueConsumer, (signed char *) "QConsNB", pollqSTACK_SIZE, (void *) &xPolledQueue, uxPriority, (xTaskHandle *) NULL); |
| 131 | xTaskCreate(vPolledQueueProducer, (signed char *) "QProdNB", pollqSTACK_SIZE, (void *) &xPolledQueue, uxPriority, (xTaskHandle *) NULL); |
| 132 | } |
| 133 | /*-----------------------------------------------------------*/ |
| 134 | |
| 135 | static portTASK_FUNCTION(vPolledQueueProducer, pvParameters) |
| 136 | { |
| 137 | unsigned short usValue = (unsigned short) 0; |
| 138 | signed portBASE_TYPE xError = pdFALSE, xLoop; |
| 139 | |
| 140 | for (;;) { |
| 141 | for (xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++) { |
| 142 | /* Send an incrementing number on the queue without blocking. */ |
| 143 | if (xQueueSend(*((xQueueHandle *) pvParameters), (void *) &usValue, pollqNO_DELAY) != pdPASS) { |
| 144 | /* We should never find the queue full so if we get here there |
| 145 | has been an error. */ |
| 146 | xError = pdTRUE; |
| 147 | } else { |
| 148 | if (xError == pdFALSE) { |
| 149 | /* If an error has ever been recorded we stop incrementing the |
| 150 | check variable. */ |
| 151 | portENTER_CRITICAL(); |
| 152 | xPollingProducerCount++; |
| 153 | portEXIT_CRITICAL(); |
| 154 | } |
| 155 | |
| 156 | /* Update the value we are going to post next time around. */ |
| 157 | usValue++; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | /* Wait before we start posting again to ensure the consumer runs and |
| 162 | empties the queue. */ |
| 163 | vTaskDelay(pollqPRODUCER_DELAY); |
| 164 | } |
| 165 | } /*lint !e818 Function prototype must conform to API. */ |
| 166 | /*-----------------------------------------------------------*/ |
| 167 | |
| 168 | static portTASK_FUNCTION(vPolledQueueConsumer, pvParameters) |
| 169 | { |
| 170 | unsigned short usData, usExpectedValue = (unsigned short) 0; |
| 171 | signed portBASE_TYPE xError = pdFALSE; |
| 172 | |
| 173 | for (;;) { |
| 174 | /* Loop until the queue is empty. */ |
| 175 | while (uxQueueMessagesWaiting(*((xQueueHandle *) pvParameters))) { |
| 176 | if (xQueueReceive(*((xQueueHandle *) pvParameters), &usData, pollqNO_DELAY) == pdPASS) { |
| 177 | if (usData != usExpectedValue) { |
| 178 | /* This is not what we expected to receive so an error has |
| 179 | occurred. */ |
| 180 | xError = pdTRUE; |
| 181 | |
| 182 | /* Catch-up to the value we received so our next expected |
| 183 | value should again be correct. */ |
| 184 | usExpectedValue = usData; |
| 185 | } else { |
| 186 | if (xError == pdFALSE) { |
| 187 | /* Only increment the check variable if no errors have |
| 188 | occurred. */ |
| 189 | portENTER_CRITICAL(); |
| 190 | xPollingConsumerCount++; |
| 191 | portEXIT_CRITICAL(); |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | /* Next time round we would expect the number to be one higher. */ |
| 196 | usExpectedValue++; |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | /* Now the queue is empty we block, allowing the producer to place more |
| 201 | items in the queue. */ |
| 202 | vTaskDelay(pollqCONSUMER_DELAY); |
| 203 | } |
| 204 | } /*lint !e818 Function prototype must conform to API. */ |
| 205 | /*-----------------------------------------------------------*/ |
| 206 | |
| 207 | /* This is called to check that all the created tasks are still running with no errors. */ |
| 208 | portBASE_TYPE xArePollingQueuesStillRunning(void) |
| 209 | { |
| 210 | portBASE_TYPE xReturn; |
| 211 | |
| 212 | /* Check both the consumer and producer poll count to check they have both |
| 213 | been changed since out last trip round. We do not need a critical section |
| 214 | around the check variables as this is called from a higher priority than |
| 215 | the other tasks that access the same variables. */ |
| 216 | if ((xPollingConsumerCount == pollqINITIAL_VALUE) || |
| 217 | (xPollingProducerCount == pollqINITIAL_VALUE) |
| 218 | ) { |
| 219 | xReturn = pdFALSE; |
| 220 | } else { |
| 221 | xReturn = pdTRUE; |
| 222 | } |
| 223 | |
| 224 | /* Set the check variables back down so we know if they have been |
| 225 | incremented the next time around. */ |
| 226 | xPollingConsumerCount = pollqINITIAL_VALUE; |
| 227 | xPollingProducerCount = pollqINITIAL_VALUE; |
| 228 | |
| 229 | return xReturn; |
| 230 | } |