root/webserver/example/freeRTOSexample/EnergyMeters/Common/Minimal/GenQTest.c

Revision 14, 17.9 kB (checked in by phil, 15 years ago)

added unmodified FreeRTOS package V5.4.1 with only web srv demo source for LPC2368 for CrossWorks?

Line 
1 /*
2         FreeRTOS V5.4.1 - Copyright (C) 2009 Real Time Engineers Ltd.
3
4         This file is part of the FreeRTOS distribution.
5
6         FreeRTOS is free software; you can redistribute it and/or modify it     under
7         the terms of the GNU General Public License (version 2) as published by the
8         Free Software Foundation and modified by the FreeRTOS exception.
9         **NOTE** The exception to the GPL is included to allow you to distribute a
10         combined work that includes FreeRTOS without being obliged to provide the
11         source code for proprietary components outside of the FreeRTOS kernel. 
12         Alternative commercial license and support terms are also available upon
13         request.  See the licensing section of http://www.FreeRTOS.org for full
14         license details.
15
16         FreeRTOS is distributed in the hope that it will be useful,     but WITHOUT
17         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19         more details.
20
21         You should have received a copy of the GNU General Public License along
22         with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
23         Temple Place, Suite 330, Boston, MA  02111-1307  USA.
24
25
26         ***************************************************************************
27         *                                                                         *
28         * Looking for a quick start?  Then check out the FreeRTOS eBook!          *
29         * See http://www.FreeRTOS.org/Documentation for details                   *
30         *                                                                         *
31         ***************************************************************************
32
33         1 tab == 4 spaces!
34
35         Please ensure to read the configuration and relevant port sections of the
36         online documentation.
37
38         http://www.FreeRTOS.org - Documentation, latest information, license and
39         contact details.
40
41         http://www.SafeRTOS.com - A version that is certified for use in safety
42         critical systems.
43
44         http://www.OpenRTOS.com - Commercial support, development, porting,
45         licensing and training services.
46 */
47
48
49 /*
50  * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
51  * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
52  * mutex behaviour.
53  *
54  * See the comments above the prvSendFrontAndBackTest() and
55  * prvLowPriorityMutexTask() prototypes below for more information.
56  */
57
58
59 #include <stdlib.h>
60
61 /* Scheduler include files. */
62 #include "FreeRTOS.h"
63 #include "task.h"
64 #include "queue.h"
65 #include "semphr.h"
66
67 /* Demo program include files. */
68 #include "GenQTest.h"
69
70 #define genqQUEUE_LENGTH                ( 5 )
71 #define genqNO_BLOCK                    ( 0 )
72
73 #define genqMUTEX_LOW_PRIORITY          ( tskIDLE_PRIORITY )
74 #define genqMUTEX_TEST_PRIORITY         ( tskIDLE_PRIORITY + 1 )
75 #define genqMUTEX_MEDIUM_PRIORITY       ( tskIDLE_PRIORITY + 2 )
76 #define genqMUTEX_HIGH_PRIORITY         ( tskIDLE_PRIORITY + 3 )
77
78 /*-----------------------------------------------------------*/
79
80 /*
81  * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
82  * macros by using both to fill a queue, then reading from the queue to
83  * check the resultant queue order is as expected.  Queue data is also
84  * peeked.
85  */
86 static void prvSendFrontAndBackTest( void *pvParameters );
87
88 /*
89  * The following three tasks are used to demonstrate the mutex behaviour.
90  * Each task is given a different priority to demonstrate the priority
91  * inheritance mechanism.
92  *
93  * The low priority task obtains a mutex.  After this a high priority task
94  * attempts to obtain the same mutex, causing its priority to be inherited
95  * by the low priority task.  The task with the inherited high priority then
96  * resumes a medium priority task to ensure it is not blocked by the medium
97  * priority task while it holds the inherited high priority.  Once the mutex
98  * is returned the task with the inherited priority returns to its original
99  * low priority, and is therefore immediately preempted by first the high
100  * priority task and then the medium prioroity task before it can continue.
101  */
102 static void prvLowPriorityMutexTask( void *pvParameters );
103 static void prvMediumPriorityMutexTask( void *pvParameters );
104 static void prvHighPriorityMutexTask( void *pvParameters );
105
106 /*-----------------------------------------------------------*/
107
108 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
109 detected in any of the tasks. */
110 static portBASE_TYPE xErrorDetected = pdFALSE;
111
112 /* Counters that are incremented on each cycle of a test.  This is used to
113 detect a stalled task - a test that is no longer running. */
114 static volatile unsigned portLONG ulLoopCounter = 0;
115 static volatile unsigned portLONG ulLoopCounter2 = 0;
116
117 /* The variable that is guarded by the mutex in the mutex demo tasks. */
118 static volatile unsigned portLONG ulGuardedVariable = 0;
119
120 /* Handles used in the mutext test to suspend and resume the high and medium
121 priority mutex test tasks. */
122 static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
123
124 /*-----------------------------------------------------------*/
125
126 void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
127 {
128 xQueueHandle xQueue;
129 xSemaphoreHandle xMutex;
130
131         /* Create the queue that we are going to use for the
132         prvSendFrontAndBackTest demo. */
133         xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
134
135         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
136         in use.  The queue registry is provided as a means for kernel aware
137         debuggers to locate queues and has no purpose if a kernel aware debugger
138         is not being used.  The call to vQueueAddToRegistry() will be removed
139         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
140         defined to be less than 1. */
141         vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" );
142
143         /* Create the demo task and pass it the queue just created.  We are
144         passing the queue handle by value so it does not matter that it is
145         declared on the stack here. */
146         xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
147
148         /* Create the mutex used by the prvMutexTest task. */
149         xMutex = xSemaphoreCreateMutex();
150
151         /* vQueueAddToRegistry() adds the mutex to the registry, if one is
152         in use.  The registry is provided as a means for kernel aware
153         debuggers to locate mutexes and has no purpose if a kernel aware debugger
154         is not being used.  The call to vQueueAddToRegistry() will be removed
155         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
156         defined to be less than 1. */
157         vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" );
158
159         /* Create the mutex demo tasks and pass it the mutex just created.  We are
160         passing the mutex handle by value so it does not matter that it is declared
161         on the stack here. */
162         xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
163         xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
164         xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
165 }
166 /*-----------------------------------------------------------*/
167
168 static void prvSendFrontAndBackTest( void *pvParameters )
169 {
170 unsigned portLONG ulData, ulData2;
171 xQueueHandle xQueue;
172
173         #ifdef USE_STDIO
174         void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
175        
176                 const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
177
178                 /* Queue a message for printing to say the task has started. */
179                 vPrintDisplayMessage( &pcTaskStartMsg );
180         #endif
181
182         xQueue = ( xQueueHandle ) pvParameters;
183
184         for( ;; )
185         {
186                 /* The queue is empty, so sending an item to the back of the queue
187                 should have the same efect as sending it to the front of the queue.
188
189                 First send to the front and check everything is as expected. */
190                 xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
191
192                 if( uxQueueMessagesWaiting( xQueue ) != 1 )
193                 {
194                         xErrorDetected = pdTRUE;
195                 }
196
197                 if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
198                 {
199                         xErrorDetected = pdTRUE;
200                 }
201
202                 /* The data we sent to the queue should equal the data we just received
203                 from the queue. */
204                 if( ulLoopCounter != ulData )
205                 {
206                         xErrorDetected = pdTRUE;
207                 }
208
209                 /* Then do the same, sending the data to the back, checking everything
210                 is as expected. */
211                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
212                 {
213                         xErrorDetected = pdTRUE;
214                 }
215
216                 xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
217
218                 if( uxQueueMessagesWaiting( xQueue ) != 1 )
219                 {
220                         xErrorDetected = pdTRUE;
221                 }
222
223                 if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
224                 {
225                         xErrorDetected = pdTRUE;
226                 }
227
228                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
229                 {
230                         xErrorDetected = pdTRUE;
231                 }
232
233                 /* The data we sent to the queue should equal the data we just received
234                 from the queue. */
235                 if( ulLoopCounter != ulData )
236                 {
237                         xErrorDetected = pdTRUE;
238                 }
239
240                 #if configUSE_PREEMPTION == 0
241                         taskYIELD();
242                 #endif
243
244
245
246                 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
247                 for( ulData = 2; ulData < 5; ulData++ )
248                 {
249                         xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
250                 }
251
252                 /* Now the order in the queue should be 2, 3, 4, with 2 being the first
253                 thing to be read out.  Now add 1 then 0 to the front of the queue. */
254                 if( uxQueueMessagesWaiting( xQueue ) != 3 )
255                 {
256                         xErrorDetected = pdTRUE;
257                 }
258                 ulData = 1;
259                 xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
260                 ulData = 0;
261                 xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
262
263                 /* Now the queue should be full, and when we read the data out we
264                 should receive 0, 1, 2, 3, 4. */
265                 if( uxQueueMessagesWaiting( xQueue ) != 5 )
266                 {
267                         xErrorDetected = pdTRUE;
268                 }
269
270                 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
271                 {
272                         xErrorDetected = pdTRUE;
273                 }
274
275                 if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
276                 {
277                         xErrorDetected = pdTRUE;
278                 }
279
280                 #if configUSE_PREEMPTION == 0
281                         taskYIELD();
282                 #endif
283
284                 /* Check the data we read out is in the expected order. */
285                 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
286                 {
287                         /* Try peeking the data first. */
288                         if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
289                         {
290                                 xErrorDetected = pdTRUE;
291                         }
292
293                         if( ulData != ulData2 )
294                         {
295                                 xErrorDetected = pdTRUE;
296                         }
297                        
298
299                         /* Now try receiving the data for real.  The value should be the
300                         same.  Clobber the value first so we know we really received it. */
301                         ulData2 = ~ulData2;
302                         if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
303                         {
304                                 xErrorDetected = pdTRUE;
305                         }
306
307                         if( ulData != ulData2 )
308                         {
309                                 xErrorDetected = pdTRUE;
310                         }
311                 }
312
313                 /* The queue should now be empty again. */
314                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
315                 {
316                         xErrorDetected = pdTRUE;
317                 }
318
319                 #if configUSE_PREEMPTION == 0
320                         taskYIELD();
321                 #endif
322
323
324                 /* Our queue is empty once more, add 10, 11 to the back. */
325                 ulData = 10;
326                 if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
327                 {
328                         xErrorDetected = pdTRUE;
329                 }
330                 ulData = 11;
331                 if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
332                 {
333                         xErrorDetected = pdTRUE;
334                 }
335
336                 if( uxQueueMessagesWaiting( xQueue ) != 2 )
337                 {
338                         xErrorDetected = pdTRUE;
339                 }
340
341                 /* Now we should have 10, 11 in the queue.  Add 7, 8, 9 to the
342                 front. */
343                 for( ulData = 9; ulData >= 7; ulData-- )
344                 {
345                         if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
346                         {
347                                 xErrorDetected = pdTRUE;
348                         }
349                 }
350
351                 /* Now check that the queue is full, and that receiving data provides
352                 the expected sequence of 7, 8, 9, 10, 11. */
353                 if( uxQueueMessagesWaiting( xQueue ) != 5 )
354                 {
355                         xErrorDetected = pdTRUE;
356                 }
357
358                 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
359                 {
360                         xErrorDetected = pdTRUE;
361                 }
362
363                 if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
364                 {
365                         xErrorDetected = pdTRUE;
366                 }
367
368                 #if configUSE_PREEMPTION == 0
369                         taskYIELD();
370                 #endif
371
372                 /* Check the data we read out is in the expected order. */
373                 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
374                 {
375                         if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
376                         {
377                                 xErrorDetected = pdTRUE;
378                         }
379
380                         if( ulData != ulData2 )
381                         {
382                                 xErrorDetected = pdTRUE;
383                         }
384                 }
385
386                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
387                 {
388                         xErrorDetected = pdTRUE;
389                 }
390
391                 ulLoopCounter++;
392         }
393 }
394 /*-----------------------------------------------------------*/
395
396 static void prvLowPriorityMutexTask( void *pvParameters )
397 {
398 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
399
400         #ifdef USE_STDIO
401         void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
402        
403                 const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
404
405                 /* Queue a message for printing to say the task has started. */
406                 vPrintDisplayMessage( &pcTaskStartMsg );
407         #endif
408
409         for( ;; )
410         {
411                 /* Take the mutex.  It should be available now. */
412                 if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )
413                 {
414                         xErrorDetected = pdTRUE;
415                 }
416
417                 /* Set our guarded variable to a known start value. */
418                 ulGuardedVariable = 0;
419
420                 /* Our priority should be as per that assigned when the task was
421                 created. */
422                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
423                 {
424                         xErrorDetected = pdTRUE;
425                 }
426
427                 /* Now unsuspend the high priority task.  This will attempt to take the
428                 mutex, and block when it finds it cannot obtain it. */
429                 vTaskResume( xHighPriorityMutexTask );
430
431                 /* We should now have inherited the prioritoy of the high priority task,
432                 as by now it will have attempted to get the mutex. */
433                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
434                 {
435                         xErrorDetected = pdTRUE;
436                 }
437
438                 /* We can attempt to set our priority to the test priority - between the
439                 idle priority and the medium/high test priorities, but our actual
440                 prioroity should remain at the high priority. */
441                 vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
442                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
443                 {
444                         xErrorDetected = pdTRUE;
445                 }
446
447                 /* Now unsuspend the medium priority task.  This should not run as our
448                 inherited priority is above that of the medium priority task. */
449                 vTaskResume( xMediumPriorityMutexTask );
450
451                 /* If the did run then it will have incremented our guarded variable. */
452                 if( ulGuardedVariable != 0 )
453                 {
454                         xErrorDetected = pdTRUE;
455                 }
456
457                 /* When we give back the semaphore our priority should be disinherited
458                 back to the priority to which we attempted to set ourselves.  This means
459                 that when the high priority task next blocks, the medium priority task
460                 should execute and increment the guarded variable.   When we next run
461                 both the high and medium priority tasks will have been suspended again. */
462                 if( xSemaphoreGive( xMutex ) != pdPASS )
463                 {
464                         xErrorDetected = pdTRUE;
465                 }
466
467                 /* Check that the guarded variable did indeed increment... */
468                 if( ulGuardedVariable != 1 )
469                 {
470                         xErrorDetected = pdTRUE;
471                 }
472
473                 /* ... and that our priority has been disinherited to
474                 genqMUTEX_TEST_PRIORITY. */
475                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
476                 {
477                         xErrorDetected = pdTRUE;
478                 }
479
480                 /* Set our priority back to our original priority ready for the next
481                 loop around this test. */
482                 vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
483
484                 /* Just to show we are still running. */
485                 ulLoopCounter2++;
486
487                 #if configUSE_PREEMPTION == 0
488                         taskYIELD();
489                 #endif         
490         }
491 }
492 /*-----------------------------------------------------------*/
493
494 static void prvMediumPriorityMutexTask( void *pvParameters )
495 {
496         ( void ) pvParameters;
497
498         for( ;; )
499         {
500                 /* The medium priority task starts by suspending itself.  The low
501                 priority task will unsuspend this task when required. */
502                 vTaskSuspend( NULL );
503
504                 /* When this task unsuspends all it does is increment the guarded
505                 variable, this is so the low priority task knows that it has
506                 executed. */
507                 ulGuardedVariable++;
508         }
509 }
510 /*-----------------------------------------------------------*/
511
512 static void prvHighPriorityMutexTask( void *pvParameters )
513 {
514 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
515
516         for( ;; )
517         {
518                 /* The high priority task starts by suspending itself.  The low
519                 priority task will unsuspend this task when required. */
520                 vTaskSuspend( NULL );
521
522                 /* When this task unsuspends all it does is attempt to obtain
523                 the mutex.  It should find the mutex is not available so a
524                 block time is specified. */
525                 if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
526                 {
527                         xErrorDetected = pdTRUE;
528                 }
529
530                 /* When we eventually obtain the mutex we just give it back then
531                 return to suspend ready for the next test. */
532                 if( xSemaphoreGive( xMutex ) != pdPASS )
533                 {
534                         xErrorDetected = pdTRUE;
535                 }               
536         }
537 }
538 /*-----------------------------------------------------------*/
539
540 /* This is called to check that all the created tasks are still running. */
541 portBASE_TYPE xAreGenericQueueTasksStillRunning( void )
542 {
543 static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
544
545         /* If the demo task is still running then we expect the loopcounters to
546         have incremented since this function was last called. */
547         if( ulLastLoopCounter == ulLoopCounter )
548         {
549                 xErrorDetected = pdTRUE;
550         }
551
552         if( ulLastLoopCounter2 == ulLoopCounter2 )
553         {
554                 xErrorDetected = pdTRUE;
555         }
556
557         ulLastLoopCounter = ulLoopCounter;
558         ulLastLoopCounter2 = ulLoopCounter2;   
559
560         /* Errors detected in the task itself will have latched xErrorDetected
561         to true. */
562
563         return !xErrorDetected;
564 }
565
566
Note: See TracBrowser for help on using the browser.