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 /* 00056 * Simple demonstration of the usage of counting semaphore. 00057 */ 00058 00059 /* Scheduler include files. */ 00060 #include "FreeRTOS.h" 00061 #include "task.h" 00062 #include "semphr.h" 00063 00064 /* Demo program include files. */ 00065 #include "countsem.h" 00066 00067 /* The maximum count value that the semaphore used for the demo can hold. */ 00068 #define countMAX_COUNT_VALUE ( 200 ) 00069 00070 /* Constants used to indicate whether or not the semaphore should have been 00071 created with its maximum count value, or its minimum count value. These 00072 numbers are used to ensure that the pointers passed in as the task parameters 00073 are valid. */ 00074 #define countSTART_AT_MAX_COUNT ( 0xaa ) 00075 #define countSTART_AT_ZERO ( 0x55 ) 00076 00077 /* Two tasks are created for the test. One uses a semaphore created with its 00078 count value set to the maximum, and one with the count value set to zero. */ 00079 #define countNUM_TEST_TASKS ( 2 ) 00080 #define countDONT_BLOCK ( 0 ) 00081 00082 /*-----------------------------------------------------------*/ 00083 00084 /* Flag that will be latched to pdTRUE should any unexpected behaviour be 00085 detected in any of the tasks. */ 00086 static volatile portBASE_TYPE xErrorDetected = pdFALSE; 00087 00088 /*-----------------------------------------------------------*/ 00089 00090 /* 00091 * The demo task. This simply counts the semaphore up to its maximum value, 00092 * the counts it back down again. The result of each semaphore 'give' and 00093 * 'take' is inspected, with an error being flagged if it is found not to be 00094 * the expected result. 00095 */ 00096 static void prvCountingSemaphoreTask( void *pvParameters ); 00097 00098 /* 00099 * Utility function to increment the semaphore count value up from zero to 00100 * countMAX_COUNT_VALUE. 00101 */ 00102 static void prvIncrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter ); 00103 00104 /* 00105 * Utility function to decrement the semaphore count value up from 00106 * countMAX_COUNT_VALUE to zero. 00107 */ 00108 static void prvDecrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter ); 00109 00110 /*-----------------------------------------------------------*/ 00111 00112 /* The structure that is passed into the task as the task parameter. */ 00113 typedef struct COUNT_SEM_STRUCT 00114 { 00115 /* The semaphore to be used for the demo. */ 00116 xSemaphoreHandle xSemaphore; 00117 00118 /* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with 00119 its count value set to its max count value, or countSTART_AT_ZERO if it 00120 should have been created with its count value set to 0. */ 00121 unsigned portBASE_TYPE uxExpectedStartCount; 00122 00123 /* Incremented on each cycle of the demo task. Used to detect a stalled 00124 task. */ 00125 unsigned portBASE_TYPE uxLoopCounter; 00126 } xCountSemStruct; 00127 00128 /* Two structures are defined, one is passed to each test task. */ 00129 static volatile xCountSemStruct xParameters[ countNUM_TEST_TASKS ]; 00130 00131 /*-----------------------------------------------------------*/ 00132 00133 void vStartCountingSemaphoreTasks( void ) 00134 { 00135 /* Create the semaphores that we are going to use for the test/demo. The 00136 first should be created such that it starts at its maximum count value, 00137 the second should be created such that it starts with a count value of zero. */ 00138 xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE ); 00139 xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT; 00140 xParameters[ 0 ].uxLoopCounter = 0; 00141 00142 xParameters[ 1 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, 0 ); 00143 xParameters[ 1 ].uxExpectedStartCount = 0; 00144 xParameters[ 1 ].uxLoopCounter = 0; 00145 00146 /* vQueueAddToRegistry() adds the semaphore to the registry, if one is 00147 in use. The registry is provided as a means for kernel aware 00148 debuggers to locate semaphores and has no purpose if a kernel aware debugger 00149 is not being used. The call to vQueueAddToRegistry() will be removed 00150 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 00151 defined to be less than 1. */ 00152 vQueueAddToRegistry( ( xQueueHandle ) xParameters[ 0 ].xSemaphore, ( signed portCHAR * ) "Counting_Sem_1" ); 00153 vQueueAddToRegistry( ( xQueueHandle ) xParameters[ 1 ].xSemaphore, ( signed portCHAR * ) "Counting_Sem_2" ); 00154 00155 00156 /* Were the semaphores created? */ 00157 if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) ) 00158 { 00159 /* Create the demo tasks, passing in the semaphore to use as the parameter. */ 00160 xTaskCreate( prvCountingSemaphoreTask, ( signed portCHAR * ) "CNT1", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 0 ] ), tskIDLE_PRIORITY, NULL ); 00161 xTaskCreate( prvCountingSemaphoreTask, ( signed portCHAR * ) "CNT2", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 1 ] ), tskIDLE_PRIORITY, NULL ); 00162 } 00163 } 00164 /*-----------------------------------------------------------*/ 00165 00166 static void prvDecrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter ) 00167 { 00168 unsigned portBASE_TYPE ux; 00169 00170 /* If the semaphore count is at its maximum then we should not be able to 00171 'give' the semaphore. */ 00172 if( xSemaphoreGive( xSemaphore ) == pdPASS ) 00173 { 00174 xErrorDetected = pdTRUE; 00175 } 00176 00177 /* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */ 00178 for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ ) 00179 { 00180 if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS ) 00181 { 00182 /* We expected to be able to take the semaphore. */ 00183 xErrorDetected = pdTRUE; 00184 } 00185 00186 ( *puxLoopCounter )++; 00187 } 00188 00189 #if configUSE_PREEMPTION == 0 00190 taskYIELD(); 00191 #endif 00192 00193 /* If the semaphore count is zero then we should not be able to 'take' 00194 the semaphore. */ 00195 if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS ) 00196 { 00197 xErrorDetected = pdTRUE; 00198 } 00199 } 00200 /*-----------------------------------------------------------*/ 00201 00202 static void prvIncrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter ) 00203 { 00204 unsigned portBASE_TYPE ux; 00205 00206 /* If the semaphore count is zero then we should not be able to 'take' 00207 the semaphore. */ 00208 if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS ) 00209 { 00210 xErrorDetected = pdTRUE; 00211 } 00212 00213 /* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */ 00214 for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ ) 00215 { 00216 if( xSemaphoreGive( xSemaphore ) != pdPASS ) 00217 { 00218 /* We expected to be able to take the semaphore. */ 00219 xErrorDetected = pdTRUE; 00220 } 00221 00222 ( *puxLoopCounter )++; 00223 } 00224 00225 #if configUSE_PREEMPTION == 0 00226 taskYIELD(); 00227 #endif 00228 00229 /* If the semaphore count is at its maximum then we should not be able to 00230 'give' the semaphore. */ 00231 if( xSemaphoreGive( xSemaphore ) == pdPASS ) 00232 { 00233 xErrorDetected = pdTRUE; 00234 } 00235 } 00236 /*-----------------------------------------------------------*/ 00237 00238 static void prvCountingSemaphoreTask( void *pvParameters ) 00239 { 00240 xCountSemStruct *pxParameter; 00241 00242 #ifdef USE_STDIO 00243 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); 00244 00245 const portCHAR * const pcTaskStartMsg = "Counting semaphore demo started.\r\n"; 00246 00247 /* Queue a message for printing to say the task has started. */ 00248 vPrintDisplayMessage( &pcTaskStartMsg ); 00249 #endif 00250 00251 /* The semaphore to be used was passed as the parameter. */ 00252 pxParameter = ( xCountSemStruct * ) pvParameters; 00253 00254 /* Did we expect to find the semaphore already at its max count value, or 00255 at zero? */ 00256 if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT ) 00257 { 00258 prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) ); 00259 } 00260 00261 /* Now we expect the semaphore count to be 0, so this time there is an 00262 error if we can take the semaphore. */ 00263 if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS ) 00264 { 00265 xErrorDetected = pdTRUE; 00266 } 00267 00268 for( ;; ) 00269 { 00270 prvIncrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) ); 00271 prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) ); 00272 } 00273 } 00274 /*-----------------------------------------------------------*/ 00275 00276 portBASE_TYPE xAreCountingSemaphoreTasksStillRunning( void ) 00277 { 00278 static unsigned portBASE_TYPE uxLastCount0 = 0, uxLastCount1 = 0; 00279 portBASE_TYPE xReturn = pdPASS; 00280 00281 /* Return fail if any 'give' or 'take' did not result in the expected 00282 behaviour. */ 00283 if( xErrorDetected != pdFALSE ) 00284 { 00285 xReturn = pdFAIL; 00286 } 00287 00288 /* Return fail if either task is not still incrementing its loop counter. */ 00289 if( uxLastCount0 == xParameters[ 0 ].uxLoopCounter ) 00290 { 00291 xReturn = pdFAIL; 00292 } 00293 else 00294 { 00295 uxLastCount0 = xParameters[ 0 ].uxLoopCounter; 00296 } 00297 00298 if( uxLastCount1 == xParameters[ 1 ].uxLoopCounter ) 00299 { 00300 xReturn = pdFAIL; 00301 } 00302 else 00303 { 00304 uxLastCount1 = xParameters[ 1 ].uxLoopCounter; 00305 } 00306 00307 return xReturn; 00308 } 00309 00310