FreeRTOS Real Time Operating System, Modified from Kenji Arai's initial port. See freertos.org for full documentation.
Fork of FreeRTOS_on_mbed_v1 by
GenQTest.c
00001 /* 00002 FreeRTOS V6.0.3 - Copyright (C) 2010 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 * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 - 00057 * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and 00058 * mutex behaviour. 00059 * 00060 * See the comments above the prvSendFrontAndBackTest() and 00061 * prvLowPriorityMutexTask() prototypes below for more information. 00062 */ 00063 00064 00065 #include <stdlib.h> 00066 00067 /* Scheduler include files. */ 00068 #include "FreeRTOS.h" 00069 #include "task.h" 00070 #include "queue.h" 00071 #include "semphr.h" 00072 00073 /* Demo program include files. */ 00074 #include "GenQTest.h" 00075 00076 #define genqQUEUE_LENGTH ( 5 ) 00077 #define genqNO_BLOCK ( 0 ) 00078 00079 #define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY ) 00080 #define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) 00081 #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 ) 00082 #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 ) 00083 00084 /*-----------------------------------------------------------*/ 00085 00086 /* 00087 * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack() 00088 * macros by using both to fill a queue, then reading from the queue to 00089 * check the resultant queue order is as expected. Queue data is also 00090 * peeked. 00091 */ 00092 static void prvSendFrontAndBackTest( void *pvParameters ); 00093 00094 /* 00095 * The following three tasks are used to demonstrate the mutex behaviour. 00096 * Each task is given a different priority to demonstrate the priority 00097 * inheritance mechanism. 00098 * 00099 * The low priority task obtains a mutex. After this a high priority task 00100 * attempts to obtain the same mutex, causing its priority to be inherited 00101 * by the low priority task. The task with the inherited high priority then 00102 * resumes a medium priority task to ensure it is not blocked by the medium 00103 * priority task while it holds the inherited high priority. Once the mutex 00104 * is returned the task with the inherited priority returns to its original 00105 * low priority, and is therefore immediately preempted by first the high 00106 * priority task and then the medium prioroity task before it can continue. 00107 */ 00108 static void prvLowPriorityMutexTask( void *pvParameters ); 00109 static void prvMediumPriorityMutexTask( void *pvParameters ); 00110 static void prvHighPriorityMutexTask( void *pvParameters ); 00111 00112 /*-----------------------------------------------------------*/ 00113 00114 /* Flag that will be latched to pdTRUE should any unexpected behaviour be 00115 detected in any of the tasks. */ 00116 static portBASE_TYPE xErrorDetected = pdFALSE; 00117 00118 /* Counters that are incremented on each cycle of a test. This is used to 00119 detect a stalled task - a test that is no longer running. */ 00120 static volatile unsigned portLONG ulLoopCounter = 0; 00121 static volatile unsigned portLONG ulLoopCounter2 = 0; 00122 00123 /* The variable that is guarded by the mutex in the mutex demo tasks. */ 00124 static volatile unsigned portLONG ulGuardedVariable = 0; 00125 00126 /* Handles used in the mutext test to suspend and resume the high and medium 00127 priority mutex test tasks. */ 00128 static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask; 00129 00130 /*-----------------------------------------------------------*/ 00131 00132 void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority ) 00133 { 00134 xQueueHandle xQueue; 00135 xSemaphoreHandle xMutex; 00136 00137 /* Create the queue that we are going to use for the 00138 prvSendFrontAndBackTest demo. */ 00139 xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) ); 00140 00141 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is 00142 in use. The queue registry is provided as a means for kernel aware 00143 debuggers to locate queues and has no purpose if a kernel aware debugger 00144 is not being used. The call to vQueueAddToRegistry() will be removed 00145 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 00146 defined to be less than 1. */ 00147 vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" ); 00148 00149 /* Create the demo task and pass it the queue just created. We are 00150 passing the queue handle by value so it does not matter that it is 00151 declared on the stack here. */ 00152 xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL ); 00153 00154 /* Create the mutex used by the prvMutexTest task. */ 00155 xMutex = xSemaphoreCreateMutex(); 00156 00157 /* vQueueAddToRegistry() adds the mutex to the registry, if one is 00158 in use. The registry is provided as a means for kernel aware 00159 debuggers to locate mutexes and has no purpose if a kernel aware debugger 00160 is not being used. The call to vQueueAddToRegistry() will be removed 00161 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 00162 defined to be less than 1. */ 00163 vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" ); 00164 00165 /* Create the mutex demo tasks and pass it the mutex just created. We are 00166 passing the mutex handle by value so it does not matter that it is declared 00167 on the stack here. */ 00168 xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL ); 00169 xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask ); 00170 xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask ); 00171 } 00172 /*-----------------------------------------------------------*/ 00173 00174 static void prvSendFrontAndBackTest( void *pvParameters ) 00175 { 00176 unsigned portLONG ulData, ulData2; 00177 xQueueHandle xQueue; 00178 00179 #ifdef USE_STDIO 00180 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); 00181 00182 const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n"; 00183 00184 /* Queue a message for printing to say the task has started. */ 00185 vPrintDisplayMessage( &pcTaskStartMsg ); 00186 #endif 00187 00188 xQueue = ( xQueueHandle ) pvParameters; 00189 00190 for( ;; ) 00191 { 00192 /* The queue is empty, so sending an item to the back of the queue 00193 should have the same efect as sending it to the front of the queue. 00194 00195 First send to the front and check everything is as expected. */ 00196 xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); 00197 00198 if( uxQueueMessagesWaiting( xQueue ) != 1 ) 00199 { 00200 xErrorDetected = pdTRUE; 00201 } 00202 00203 if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) 00204 { 00205 xErrorDetected = pdTRUE; 00206 } 00207 00208 /* The data we sent to the queue should equal the data we just received 00209 from the queue. */ 00210 if( ulLoopCounter != ulData ) 00211 { 00212 xErrorDetected = pdTRUE; 00213 } 00214 00215 /* Then do the same, sending the data to the back, checking everything 00216 is as expected. */ 00217 if( uxQueueMessagesWaiting( xQueue ) != 0 ) 00218 { 00219 xErrorDetected = pdTRUE; 00220 } 00221 00222 xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); 00223 00224 if( uxQueueMessagesWaiting( xQueue ) != 1 ) 00225 { 00226 xErrorDetected = pdTRUE; 00227 } 00228 00229 if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) 00230 { 00231 xErrorDetected = pdTRUE; 00232 } 00233 00234 if( uxQueueMessagesWaiting( xQueue ) != 0 ) 00235 { 00236 xErrorDetected = pdTRUE; 00237 } 00238 00239 /* The data we sent to the queue should equal the data we just received 00240 from the queue. */ 00241 if( ulLoopCounter != ulData ) 00242 { 00243 xErrorDetected = pdTRUE; 00244 } 00245 00246 #if configUSE_PREEMPTION == 0 00247 taskYIELD(); 00248 #endif 00249 00250 00251 00252 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */ 00253 for( ulData = 2; ulData < 5; ulData++ ) 00254 { 00255 xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ); 00256 } 00257 00258 /* Now the order in the queue should be 2, 3, 4, with 2 being the first 00259 thing to be read out. Now add 1 then 0 to the front of the queue. */ 00260 if( uxQueueMessagesWaiting( xQueue ) != 3 ) 00261 { 00262 xErrorDetected = pdTRUE; 00263 } 00264 ulData = 1; 00265 xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); 00266 ulData = 0; 00267 xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); 00268 00269 /* Now the queue should be full, and when we read the data out we 00270 should receive 0, 1, 2, 3, 4. */ 00271 if( uxQueueMessagesWaiting( xQueue ) != 5 ) 00272 { 00273 xErrorDetected = pdTRUE; 00274 } 00275 00276 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) 00277 { 00278 xErrorDetected = pdTRUE; 00279 } 00280 00281 if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) 00282 { 00283 xErrorDetected = pdTRUE; 00284 } 00285 00286 #if configUSE_PREEMPTION == 0 00287 taskYIELD(); 00288 #endif 00289 00290 /* Check the data we read out is in the expected order. */ 00291 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ ) 00292 { 00293 /* Try peeking the data first. */ 00294 if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) 00295 { 00296 xErrorDetected = pdTRUE; 00297 } 00298 00299 if( ulData != ulData2 ) 00300 { 00301 xErrorDetected = pdTRUE; 00302 } 00303 00304 00305 /* Now try receiving the data for real. The value should be the 00306 same. Clobber the value first so we know we really received it. */ 00307 ulData2 = ~ulData2; 00308 if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) 00309 { 00310 xErrorDetected = pdTRUE; 00311 } 00312 00313 if( ulData != ulData2 ) 00314 { 00315 xErrorDetected = pdTRUE; 00316 } 00317 } 00318 00319 /* The queue should now be empty again. */ 00320 if( uxQueueMessagesWaiting( xQueue ) != 0 ) 00321 { 00322 xErrorDetected = pdTRUE; 00323 } 00324 00325 #if configUSE_PREEMPTION == 0 00326 taskYIELD(); 00327 #endif 00328 00329 00330 /* Our queue is empty once more, add 10, 11 to the back. */ 00331 ulData = 10; 00332 if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) 00333 { 00334 xErrorDetected = pdTRUE; 00335 } 00336 ulData = 11; 00337 if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) 00338 { 00339 xErrorDetected = pdTRUE; 00340 } 00341 00342 if( uxQueueMessagesWaiting( xQueue ) != 2 ) 00343 { 00344 xErrorDetected = pdTRUE; 00345 } 00346 00347 /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the 00348 front. */ 00349 for( ulData = 9; ulData >= 7; ulData-- ) 00350 { 00351 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) 00352 { 00353 xErrorDetected = pdTRUE; 00354 } 00355 } 00356 00357 /* Now check that the queue is full, and that receiving data provides 00358 the expected sequence of 7, 8, 9, 10, 11. */ 00359 if( uxQueueMessagesWaiting( xQueue ) != 5 ) 00360 { 00361 xErrorDetected = pdTRUE; 00362 } 00363 00364 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) 00365 { 00366 xErrorDetected = pdTRUE; 00367 } 00368 00369 if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) 00370 { 00371 xErrorDetected = pdTRUE; 00372 } 00373 00374 #if configUSE_PREEMPTION == 0 00375 taskYIELD(); 00376 #endif 00377 00378 /* Check the data we read out is in the expected order. */ 00379 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ ) 00380 { 00381 if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) 00382 { 00383 xErrorDetected = pdTRUE; 00384 } 00385 00386 if( ulData != ulData2 ) 00387 { 00388 xErrorDetected = pdTRUE; 00389 } 00390 } 00391 00392 if( uxQueueMessagesWaiting( xQueue ) != 0 ) 00393 { 00394 xErrorDetected = pdTRUE; 00395 } 00396 00397 ulLoopCounter++; 00398 } 00399 } 00400 /*-----------------------------------------------------------*/ 00401 00402 static void prvLowPriorityMutexTask( void *pvParameters ) 00403 { 00404 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters; 00405 00406 #ifdef USE_STDIO 00407 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); 00408 00409 const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n"; 00410 00411 /* Queue a message for printing to say the task has started. */ 00412 vPrintDisplayMessage( &pcTaskStartMsg ); 00413 #endif 00414 00415 for( ;; ) 00416 { 00417 /* Take the mutex. It should be available now. */ 00418 if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS ) 00419 { 00420 xErrorDetected = pdTRUE; 00421 } 00422 00423 /* Set our guarded variable to a known start value. */ 00424 ulGuardedVariable = 0; 00425 00426 /* Our priority should be as per that assigned when the task was 00427 created. */ 00428 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) 00429 { 00430 xErrorDetected = pdTRUE; 00431 } 00432 00433 /* Now unsuspend the high priority task. This will attempt to take the 00434 mutex, and block when it finds it cannot obtain it. */ 00435 vTaskResume( xHighPriorityMutexTask ); 00436 00437 /* We should now have inherited the prioritoy of the high priority task, 00438 as by now it will have attempted to get the mutex. */ 00439 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) 00440 { 00441 xErrorDetected = pdTRUE; 00442 } 00443 00444 /* We can attempt to set our priority to the test priority - between the 00445 idle priority and the medium/high test priorities, but our actual 00446 prioroity should remain at the high priority. */ 00447 vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY ); 00448 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) 00449 { 00450 xErrorDetected = pdTRUE; 00451 } 00452 00453 /* Now unsuspend the medium priority task. This should not run as our 00454 inherited priority is above that of the medium priority task. */ 00455 vTaskResume( xMediumPriorityMutexTask ); 00456 00457 /* If the did run then it will have incremented our guarded variable. */ 00458 if( ulGuardedVariable != 0 ) 00459 { 00460 xErrorDetected = pdTRUE; 00461 } 00462 00463 /* When we give back the semaphore our priority should be disinherited 00464 back to the priority to which we attempted to set ourselves. This means 00465 that when the high priority task next blocks, the medium priority task 00466 should execute and increment the guarded variable. When we next run 00467 both the high and medium priority tasks will have been suspended again. */ 00468 if( xSemaphoreGive( xMutex ) != pdPASS ) 00469 { 00470 xErrorDetected = pdTRUE; 00471 } 00472 00473 /* Check that the guarded variable did indeed increment... */ 00474 if( ulGuardedVariable != 1 ) 00475 { 00476 xErrorDetected = pdTRUE; 00477 } 00478 00479 /* ... and that our priority has been disinherited to 00480 genqMUTEX_TEST_PRIORITY. */ 00481 if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY ) 00482 { 00483 xErrorDetected = pdTRUE; 00484 } 00485 00486 /* Set our priority back to our original priority ready for the next 00487 loop around this test. */ 00488 vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY ); 00489 00490 /* Just to show we are still running. */ 00491 ulLoopCounter2++; 00492 00493 #if configUSE_PREEMPTION == 0 00494 taskYIELD(); 00495 #endif 00496 } 00497 } 00498 /*-----------------------------------------------------------*/ 00499 00500 static void prvMediumPriorityMutexTask( void *pvParameters ) 00501 { 00502 ( void ) pvParameters; 00503 00504 for( ;; ) 00505 { 00506 /* The medium priority task starts by suspending itself. The low 00507 priority task will unsuspend this task when required. */ 00508 vTaskSuspend( NULL ); 00509 00510 /* When this task unsuspends all it does is increment the guarded 00511 variable, this is so the low priority task knows that it has 00512 executed. */ 00513 ulGuardedVariable++; 00514 } 00515 } 00516 /*-----------------------------------------------------------*/ 00517 00518 static void prvHighPriorityMutexTask( void *pvParameters ) 00519 { 00520 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters; 00521 00522 for( ;; ) 00523 { 00524 /* The high priority task starts by suspending itself. The low 00525 priority task will unsuspend this task when required. */ 00526 vTaskSuspend( NULL ); 00527 00528 /* When this task unsuspends all it does is attempt to obtain 00529 the mutex. It should find the mutex is not available so a 00530 block time is specified. */ 00531 if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS ) 00532 { 00533 xErrorDetected = pdTRUE; 00534 } 00535 00536 /* When we eventually obtain the mutex we just give it back then 00537 return to suspend ready for the next test. */ 00538 if( xSemaphoreGive( xMutex ) != pdPASS ) 00539 { 00540 xErrorDetected = pdTRUE; 00541 } 00542 } 00543 } 00544 /*-----------------------------------------------------------*/ 00545 00546 /* This is called to check that all the created tasks are still running. */ 00547 portBASE_TYPE xAreGenericQueueTasksStillRunning( void ) 00548 { 00549 static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0; 00550 00551 /* If the demo task is still running then we expect the loopcounters to 00552 have incremented since this function was last called. */ 00553 if( ulLastLoopCounter == ulLoopCounter ) 00554 { 00555 xErrorDetected = pdTRUE; 00556 } 00557 00558 if( ulLastLoopCounter2 == ulLoopCounter2 ) 00559 { 00560 xErrorDetected = pdTRUE; 00561 } 00562 00563 ulLastLoopCounter = ulLoopCounter; 00564 ulLastLoopCounter2 = ulLoopCounter2; 00565 00566 /* Errors detected in the task itself will have latched xErrorDetected 00567 to true. */ 00568 00569 return !xErrorDetected; 00570 } 00571 00572
Generated on Fri Jul 15 2022 10:21:25 by
1.7.2
