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

Revision 14, 15.3 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  * The first test creates three tasks - two counter tasks (one continuous count
50  * and one limited count) and one controller.  A "count" variable is shared
51  * between all three tasks.  The two counter tasks should never be in a "ready"
52  * state at the same time.  The controller task runs at the same priority as
53  * the continuous count task, and at a lower priority than the limited count
54  * task.
55  *
56  * One counter task loops indefinitely, incrementing the shared count variable
57  * on each iteration.  To ensure it has exclusive access to the variable it
58  * raises it's priority above that of the controller task before each
59  * increment, lowering it again to it's original priority before starting the
60  * next iteration.
61  *
62  * The other counter task increments the shared count variable on each
63  * iteration of it's loop until the count has reached a limit of 0xff - at
64  * which point it suspends itself.  It will not start a new loop until the
65  * controller task has made it "ready" again by calling vTaskResume (). 
66  * This second counter task operates at a higher priority than controller
67  * task so does not need to worry about mutual exclusion of the counter
68  * variable.
69  *
70  * The controller task is in two sections.  The first section controls and
71  * monitors the continuous count task.  When this section is operational the
72  * limited count task is suspended.  Likewise, the second section controls
73  * and monitors the limited count task.  When this section is operational the
74  * continuous count task is suspended.
75  *
76  * In the first section the controller task first takes a copy of the shared
77  * count variable.  To ensure mutual exclusion on the count variable it
78  * suspends the continuous count task, resuming it again when the copy has been
79  * taken.  The controller task then sleeps for a fixed period - during which
80  * the continuous count task will execute and increment the shared variable.
81  * When the controller task wakes it checks that the continuous count task
82  * has executed by comparing the copy of the shared variable with its current
83  * value.  This time, to ensure mutual exclusion, the scheduler itself is
84  * suspended with a call to vTaskSuspendAll ().  This is for demonstration
85  * purposes only and is not a recommended technique due to its inefficiency.
86  *
87  * After a fixed number of iterations the controller task suspends the
88  * continuous count task, and moves on to its second section.
89  *
90  * At the start of the second section the shared variable is cleared to zero.
91  * The limited count task is then woken from it's suspension by a call to
92  * vTaskResume ().  As this counter task operates at a higher priority than
93  * the controller task the controller task should not run again until the
94  * shared variable has been counted up to the limited value causing the counter
95  * task to suspend itself.  The next line after vTaskResume () is therefore
96  * a check on the shared variable to ensure everything is as expected.
97  *
98  *
99  * The second test consists of a couple of very simple tasks that post onto a
100  * queue while the scheduler is suspended.  This test was added to test parts
101  * of the scheduler not exercised by the first test.
102  *
103  */
104
105 #include <stdlib.h>
106
107 /* Scheduler include files. */
108 #include "FreeRTOS.h"
109 #include "task.h"
110 #include "semphr.h"
111
112 /* Demo app include files. */
113 #include "dynamic.h"
114
115 /* Function that implements the "limited count" task as described above. */
116 static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters );
117
118 /* Function that implements the "continuous count" task as described above. */
119 static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters );
120
121 /* Function that implements the controller task as described above. */
122 static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters );
123
124 static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters );
125 static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
126
127 /* Demo task specific constants. */
128 #define priSTACK_SIZE                           ( configMINIMAL_STACK_SIZE )
129 #define priSLEEP_TIME                           ( ( portTickType ) 128 / portTICK_RATE_MS )
130 #define priLOOPS                                        ( 5 )
131 #define priMAX_COUNT                            ( ( unsigned portLONG ) 0xff )
132 #define priNO_BLOCK                                     ( ( portTickType ) 0 )
133 #define priSUSPENDED_QUEUE_LENGTH       ( 1 )
134
135 /*-----------------------------------------------------------*/
136
137 /* Handles to the two counter tasks.  These could be passed in as parameters
138 to the controller task to prevent them having to be file scope. */
139 static xTaskHandle xContinousIncrementHandle, xLimitedIncrementHandle;
140
141 /* The shared counter variable.  This is passed in as a parameter to the two
142 counter variables for demonstration purposes. */
143 static unsigned portLONG ulCounter;
144
145 /* Variables used to check that the tasks are still operating without error.
146 Each complete iteration of the controller task increments this variable
147 provided no errors have been found.  The variable maintaining the same value
148 is therefore indication of an error. */
149 static volatile unsigned portSHORT usCheckVariable = ( unsigned portSHORT ) 0;
150 static volatile portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
151 static volatile portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
152
153 /* Queue used by the second test. */
154 xQueueHandle xSuspendedTestQueue;
155
156 /*-----------------------------------------------------------*/
157 /*
158  * Start the three tasks as described at the top of the file.
159  * Note that the limited count task is given a higher priority.
160  */
161 void vStartDynamicPriorityTasks( void )
162 {
163         xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned portLONG ) );
164
165         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
166         in use.  The queue registry is provided as a means for kernel aware
167         debuggers to locate queues and has no purpose if a kernel aware debugger
168         is not being used.  The call to vQueueAddToRegistry() will be removed
169         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
170         defined to be less than 1. */
171         vQueueAddToRegistry( xSuspendedTestQueue, ( signed portCHAR * ) "Suspended_Test_Queue" );
172
173         xTaskCreate( vContinuousIncrementTask, ( signed portCHAR * ) "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinousIncrementHandle );
174         xTaskCreate( vLimitedIncrementTask, ( signed portCHAR * ) "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
175         xTaskCreate( vCounterControlTask, ( signed portCHAR * ) "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
176         xTaskCreate( vQueueSendWhenSuspendedTask, ( signed portCHAR * ) "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
177         xTaskCreate( vQueueReceiveWhenSuspendedTask, ( signed portCHAR * ) "SUSP_RX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
178 }
179 /*-----------------------------------------------------------*/
180
181 /*
182  * Just loops around incrementing the shared variable until the limit has been
183  * reached.  Once the limit has been reached it suspends itself.
184  */
185 static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
186 {
187 unsigned portLONG *pulCounter;
188
189         /* Take a pointer to the shared variable from the parameters passed into
190         the task. */
191         pulCounter = ( unsigned portLONG * ) pvParameters;
192
193         /* This will run before the control task, so the first thing it does is
194         suspend - the control task will resume it when ready. */
195         vTaskSuspend( NULL );
196
197         for( ;; )
198         {
199                 /* Just count up to a value then suspend. */
200                 ( *pulCounter )++;     
201                
202                 if( *pulCounter >= priMAX_COUNT )
203                 {
204                         vTaskSuspend( NULL );
205                 }       
206         }
207 }
208 /*-----------------------------------------------------------*/
209
210 /*
211  * Just keep counting the shared variable up.  The control task will suspend
212  * this task when it wants.
213  */
214 static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )
215 {
216 unsigned portLONG *pulCounter;
217 unsigned portBASE_TYPE uxOurPriority;
218
219         /* Take a pointer to the shared variable from the parameters passed into
220         the task. */
221         pulCounter = ( unsigned portLONG * ) pvParameters;
222
223         /* Query our priority so we can raise it when exclusive access to the
224         shared variable is required. */
225         uxOurPriority = uxTaskPriorityGet( NULL );
226
227         for( ;; )
228         {
229                 /* Raise our priority above the controller task to ensure a context
230                 switch does not occur while we are accessing this variable. */
231                 vTaskPrioritySet( NULL, uxOurPriority + 1 );
232                         ( *pulCounter )++;             
233                 vTaskPrioritySet( NULL, uxOurPriority );
234         }
235 }
236 /*-----------------------------------------------------------*/
237
238 /*
239  * Controller task as described above.
240  */
241 static portTASK_FUNCTION( vCounterControlTask, pvParameters )
242 {
243 unsigned portLONG ulLastCounter;
244 portSHORT sLoops;
245 portSHORT sError = pdFALSE;
246
247         /* Just to stop warning messages. */
248         ( void ) pvParameters;
249
250         for( ;; )
251         {
252                 /* Start with the counter at zero. */
253                 ulCounter = ( unsigned portLONG ) 0;
254
255                 /* First section : */
256
257                 /* Check the continuous count task is running. */
258                 for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
259                 {
260                         /* Suspend the continuous count task so we can take a mirror of the
261                         shared variable without risk of corruption. */
262                         vTaskSuspend( xContinousIncrementHandle );
263                                 ulLastCounter = ulCounter;
264                         vTaskResume( xContinousIncrementHandle );
265                        
266                         /* Now delay to ensure the other task has processor time. */
267                         vTaskDelay( priSLEEP_TIME );
268
269                         /* Check the shared variable again.  This time to ensure mutual
270                         exclusion the whole scheduler will be locked.  This is just for
271                         demo purposes! */
272                         vTaskSuspendAll();
273                         {
274                                 if( ulLastCounter == ulCounter )
275                                 {
276                                         /* The shared variable has not changed.  There is a problem
277                                         with the continuous count task so flag an error. */
278                                         sError = pdTRUE;
279                                 }
280                         }
281                         xTaskResumeAll();
282                 }
283
284
285                 /* Second section: */
286
287                 /* Suspend the continuous counter task so it stops accessing the shared variable. */
288                 vTaskSuspend( xContinousIncrementHandle );
289
290                 /* Reset the variable. */
291                 ulCounter = ( unsigned portLONG ) 0;
292
293                 /* Resume the limited count task which has a higher priority than us.
294                 We should therefore not return from this call until the limited count
295                 task has suspended itself with a known value in the counter variable. */
296                 vTaskResume( xLimitedIncrementHandle );
297
298                 /* Does the counter variable have the expected value? */
299                 if( ulCounter != priMAX_COUNT )
300                 {
301                         sError = pdTRUE;
302                 }
303
304                 if( sError == pdFALSE )
305                 {
306                         /* If no errors have occurred then increment the check variable. */
307                         portENTER_CRITICAL();
308                                 usCheckVariable++;
309                         portEXIT_CRITICAL();
310                 }
311
312                 /* Resume the continuous count task and do it all again. */
313                 vTaskResume( xContinousIncrementHandle );
314         }
315 }
316 /*-----------------------------------------------------------*/
317
318 static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )
319 {
320 static unsigned portLONG ulValueToSend = ( unsigned portLONG ) 0;
321
322         /* Just to stop warning messages. */
323         ( void ) pvParameters;
324
325         for( ;; )
326         {
327                 vTaskSuspendAll();
328                 {
329                         /* We must not block while the scheduler is suspended! */
330                         if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
331                         {
332                                 xSuspendedQueueSendError = pdTRUE;
333                         }
334                 }
335                 xTaskResumeAll();
336
337                 vTaskDelay( priSLEEP_TIME );
338
339                 ++ulValueToSend;
340         }
341 }
342 /*-----------------------------------------------------------*/
343
344 static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )
345 {
346 static unsigned portLONG ulExpectedValue = ( unsigned portLONG ) 0, ulReceivedValue;
347 portBASE_TYPE xGotValue;
348
349         /* Just to stop warning messages. */
350         ( void ) pvParameters;
351
352         for( ;; )
353         {
354                 do
355                 {
356                         /* Suspending the scheduler here is fairly pointless and
357                         undesirable for a normal application.  It is done here purely
358                         to test the scheduler.  The inner xTaskResumeAll() should
359                         never return pdTRUE as the scheduler is still locked by the
360                         outer call. */
361                         vTaskSuspendAll();
362                         {
363                                 vTaskSuspendAll();
364                                 {
365                                         xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
366                                 }
367                                 if( xTaskResumeAll() )
368                                 {
369                                         xSuspendedQueueReceiveError = pdTRUE;
370                                 }
371                         }
372                         xTaskResumeAll();
373
374                         #if configUSE_PREEMPTION == 0
375                         {
376                                 taskYIELD();
377                         }
378                         #endif
379
380                 } while( xGotValue == pdFALSE );
381
382                 if( ulReceivedValue != ulExpectedValue )
383                 {
384                         xSuspendedQueueReceiveError = pdTRUE;
385                 }
386
387                 ++ulExpectedValue;
388         }
389 }
390 /*-----------------------------------------------------------*/
391
392 /* Called to check that all the created tasks are still running without error. */
393 portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
394 {
395 /* Keep a history of the check variables so we know if it has been incremented
396 since the last call. */
397 static unsigned portSHORT usLastTaskCheck = ( unsigned portSHORT ) 0;
398 portBASE_TYPE xReturn = pdTRUE;
399
400         /* Check the tasks are still running by ensuring the check variable
401         is still incrementing. */
402
403         if( usCheckVariable == usLastTaskCheck )
404         {
405                 /* The check has not incremented so an error exists. */
406                 xReturn = pdFALSE;
407         }
408
409         if( xSuspendedQueueSendError == pdTRUE )
410         {
411                 xReturn = pdFALSE;
412         }
413
414         if( xSuspendedQueueReceiveError == pdTRUE )
415         {
416                 xReturn = pdFALSE;
417         }
418
419         usLastTaskCheck = usCheckVariable;
420         return xReturn;
421 }
Note: See TracBrowser for help on using the browser.