]> git.sur5r.net Git - freertos/blob - Demo/Common/Full/events.c
Comment the command line interpreter and lwIP sockets based server code.
[freertos] / Demo / Common / Full / events.c
1 /*\r
2     FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
3         \r
4 \r
5     ***************************************************************************\r
6      *                                                                       *\r
7      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
8      *    Complete, revised, and edited pdf reference manuals are also       *\r
9      *    available.                                                         *\r
10      *                                                                       *\r
11      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
12      *    ensuring you get running as quickly as possible and with an        *\r
13      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
14      *    the FreeRTOS project to continue with its mission of providing     *\r
15      *    professional grade, cross platform, de facto standard solutions    *\r
16      *    for microcontrollers - completely free of charge!                  *\r
17      *                                                                       *\r
18      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
19      *                                                                       *\r
20      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
21      *                                                                       *\r
22     ***************************************************************************\r
23 \r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \r
27     FreeRTOS is free software; you can redistribute it and/or modify it under\r
28     the terms of the GNU General Public License (version 2) as published by the\r
29     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
30     >>>NOTE<<< The modification to the GPL is included to allow you to\r
31     distribute a combined work that includes FreeRTOS without being obliged to\r
32     provide the source code for proprietary components outside of the FreeRTOS\r
33     kernel.  FreeRTOS is distributed in the hope that it will be useful, but\r
34     WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
35     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
36     more details. You should have received a copy of the GNU General Public\r
37     License and the FreeRTOS license exception along with FreeRTOS; if not it\r
38     can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
39     by writing to Richard Barry, contact details for whom are available on the\r
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43 \r
44     http://www.FreeRTOS.org - Documentation, latest information, license and\r
45     contact details.\r
46 \r
47     http://www.SafeRTOS.com - A version that is certified for use in safety\r
48     critical systems.\r
49 \r
50     http://www.OpenRTOS.com - Commercial support, development, porting,\r
51     licensing and training services.\r
52 */\r
53 \r
54 /**\r
55  * This file exercises the event mechanism whereby more than one task is\r
56  * blocked waiting for the same event.\r
57  *\r
58  * The demo creates five tasks - four 'event' tasks, and a controlling task.\r
59  * The event tasks have various different priorities and all block on reading\r
60  * the same queue.  The controlling task writes data to the queue, then checks\r
61  * to see which of the event tasks read the data from the queue.  The\r
62  * controlling task has the lowest priority of all the tasks so is guaranteed\r
63  * to always get preempted immediately upon writing to the queue.\r
64  *\r
65  * By selectively suspending and resuming the event tasks the controlling task\r
66  * can check that the highest priority task that is blocked on the queue is the\r
67  * task that reads the posted data from the queue.\r
68  *\r
69  * Two of the event tasks share the same priority.  When neither of these tasks\r
70  * are suspended they should alternate - one reading one message from the queue,\r
71  * the other the next message, etc.\r
72  */\r
73 \r
74 /* Standard includes. */\r
75 #include <stdlib.h>\r
76 #include <stdio.h>\r
77 #include <string.h>\r
78 \r
79 /* Scheduler include files. */\r
80 #include "FreeRTOS.h"\r
81 #include "task.h"\r
82 #include "queue.h"\r
83 \r
84 /* Demo program include files. */\r
85 #include "mevents.h"\r
86 #include "print.h"\r
87 \r
88 /* Demo specific constants. */\r
89 #define evtSTACK_SIZE           ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )\r
90 #define evtNUM_TASKS            ( 4 )\r
91 #define evtQUEUE_LENGTH         ( ( unsigned portBASE_TYPE ) 3 )\r
92 #define evtNO_DELAY                                             0\r
93 \r
94 /* Just indexes used to uniquely identify the tasks.  Note that two tasks are\r
95 'highest' priority. */\r
96 #define evtHIGHEST_PRIORITY_INDEX_2             3\r
97 #define evtHIGHEST_PRIORITY_INDEX_1             2\r
98 #define evtMEDIUM_PRIORITY_INDEX                1\r
99 #define evtLOWEST_PRIORITY_INDEX                0\r
100 \r
101 /* Each event task increments one of these counters each time it reads data\r
102 from the queue. */\r
103 static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };\r
104 \r
105 /* Each time the controlling task posts onto the queue it increments the \r
106 expected count of the task that it expected to read the data from the queue \r
107 (i.e. the task with the highest priority that should be blocked on the queue).  \r
108 \r
109 xExpectedTaskCounters are incremented from the controlling task, and \r
110 xTaskCounters are incremented from the individual event tasks - therefore\r
111 comparing xTaskCounters to xExpectedTaskCounters shows whether or not the \r
112 correct task was unblocked by the post. */\r
113 static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };\r
114 \r
115 /* Handles to the four event tasks.  These are required to suspend and resume\r
116 the tasks. */\r
117 static xTaskHandle xCreatedTasks[ evtNUM_TASKS ];\r
118 \r
119 /* The single queue onto which the controlling task posts, and the four event\r
120 tasks block. */\r
121 static xQueueHandle xQueue;\r
122 \r
123 /* Flag used to indicate whether or not an error has occurred at any time.\r
124 An error is either the queue being full when not expected, or an unexpected\r
125 task reading data from the queue. */\r
126 static portBASE_TYPE xHealthStatus = pdPASS;\r
127 \r
128 /*-----------------------------------------------------------*/\r
129 \r
130 /* Function that implements the event task.  This is created four times. */\r
131 static void prvMultiEventTask( void *pvParameters );\r
132 \r
133 /* Function that implements the controlling task. */\r
134 static void prvEventControllerTask( void *pvParameters );\r
135 \r
136 /* This is a utility function that posts data to the queue, then compares \r
137 xExpectedTaskCounters with xTaskCounters to ensure everything worked as \r
138 expected.\r
139 \r
140 The event tasks all have higher priorities the controlling task.  Therefore\r
141 the controlling task will always get preempted between writhing to the queue\r
142 and checking the task counters. \r
143 \r
144 @param xExpectedTask  The index to the task that the controlling task thinks\r
145                       should be the highest priority task waiting for data, and\r
146                                           therefore the task that will unblock.\r
147                                           \r
148 @param  xIncrement    The number of items that should be written to the queue.\r
149 */\r
150 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );\r
151 \r
152 /* This is just incremented each cycle of the controlling tasks function so\r
153 the main application can ensure the test is still running. */\r
154 static portBASE_TYPE xCheckVariable = 0;\r
155 \r
156 /*-----------------------------------------------------------*/\r
157 \r
158 void vStartMultiEventTasks( void )\r
159 {\r
160         /* Create the queue to be used for all the communications. */\r
161         xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );\r
162 \r
163         /* Start the controlling task.  This has the idle priority to ensure it is\r
164         always preempted by the event tasks. */\r
165         xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
166 \r
167         /* Start the four event tasks.  Note that two have priority 3, one \r
168         priority 2 and the other priority 1. */\r
169         xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );\r
170         xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );\r
171         xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );\r
172         xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );\r
173 }\r
174 /*-----------------------------------------------------------*/\r
175 \r
176 static void prvMultiEventTask( void *pvParameters )\r
177 {\r
178 portBASE_TYPE *pxCounter;\r
179 unsigned portBASE_TYPE uxDummy;\r
180 const char * const pcTaskStartMsg = "Multi event task started.\r\n";\r
181 \r
182         /* The variable this task will increment is passed in as a parameter. */\r
183         pxCounter = ( portBASE_TYPE * ) pvParameters;\r
184 \r
185         vPrintDisplayMessage( &pcTaskStartMsg );\r
186 \r
187         for( ;; )\r
188         {\r
189                 /* Block on the queue. */\r
190                 if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )\r
191                 {\r
192                         /* We unblocked by reading the queue - so simply increment\r
193                         the counter specific to this task instance. */\r
194                         ( *pxCounter )++;\r
195                 }\r
196                 else\r
197                 {\r
198                         xHealthStatus = pdFAIL;\r
199                 }\r
200         }\r
201 }\r
202 /*-----------------------------------------------------------*/\r
203 \r
204 static void prvEventControllerTask( void *pvParameters )\r
205 {\r
206 const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";\r
207 portBASE_TYPE xDummy = 0;\r
208 \r
209         /* Just to stop warnings. */\r
210         ( void ) pvParameters;\r
211 \r
212         vPrintDisplayMessage( &pcTaskStartMsg );\r
213 \r
214         for( ;; )\r
215         {\r
216                 /* All tasks are blocked on the queue.  When a message is posted one of\r
217                 the two tasks that share the highest priority should unblock to read\r
218                 the queue.  The next message written should unblock the other task with\r
219                 the same high priority, and so on in order.   No other task should \r
220                 unblock to read data as they have lower priorities. */\r
221 \r
222                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
223                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );\r
224                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
225                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );\r
226                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
227 \r
228                 /* For the rest of these tests we don't need the second 'highest' \r
229                 priority task - so it is suspended. */\r
230                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );\r
231 \r
232 \r
233 \r
234                 /* Now suspend the other highest priority task.  The medium priority \r
235                 task will then be the task with the highest priority that remains \r
236                 blocked on the queue. */\r
237                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
238                 \r
239                 /* This time, when we post onto the queue we will expect the medium\r
240                 priority task to unblock and preempt us. */\r
241                 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );\r
242 \r
243                 /* Now try resuming the highest priority task while the scheduler is\r
244                 suspended.  The task should start executing as soon as the scheduler\r
245                 is resumed - therefore when we post to the queue again, the highest\r
246                 priority task should again preempt us. */\r
247                 vTaskSuspendAll();\r
248                         vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
249                 xTaskResumeAll();\r
250                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
251                 \r
252                 /* Now we are going to suspend the high and medium priority tasks.  The\r
253                 low priority task should then preempt us.  Again the task suspension is \r
254                 done with the whole scheduler suspended just for test purposes. */\r
255                 vTaskSuspendAll();\r
256                         vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
257                         vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
258                 xTaskResumeAll();\r
259                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );\r
260                 \r
261                 /* Do the same basic test another few times - selectively suspending\r
262                 and resuming tasks and each time calling prvCheckTaskCounters() passing\r
263                 to the function the number of the task we expected to be unblocked by \r
264                 the     post. */\r
265 \r
266                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
267                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
268                 \r
269                 vTaskSuspendAll(); /* Just for test. */\r
270                         vTaskSuspendAll(); /* Just for test. */\r
271                                 vTaskSuspendAll(); /* Just for even more test. */\r
272                                         vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
273                                 xTaskResumeAll();\r
274                         xTaskResumeAll();\r
275                 xTaskResumeAll();\r
276                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );\r
277                 \r
278                 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
279                 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );\r
280                 \r
281                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
282                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
283 \r
284                 /* Now a slight change, first suspend all tasks. */\r
285                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
286                 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
287                 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
288                 \r
289                 /* Now when we resume the low priority task and write to the queue 3 \r
290                 times.  We expect the low priority task to service the queue three\r
291                 times. */\r
292                 vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
293                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );\r
294                 \r
295                 /* Again suspend all tasks (only the low priority task is not suspended\r
296                 already). */\r
297                 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
298                 \r
299                 /* This time we are going to suspend the scheduler, resume the low\r
300                 priority task, then resume the high priority task.  In this state we\r
301                 will write to the queue three times.  When the scheduler is resumed\r
302                 we expect the high priority task to service all three messages. */\r
303                 vTaskSuspendAll();\r
304                 {\r
305                         vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
306                         vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
307                         \r
308                         for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )\r
309                         {\r
310                                 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )\r
311                                 {\r
312                                         xHealthStatus = pdFAIL;\r
313                                 }\r
314                         }                       \r
315                         \r
316                         /* The queue should not have been serviced yet!.  The scheduler\r
317                         is still suspended. */\r
318                         if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )\r
319                         {\r
320                                 xHealthStatus = pdFAIL;\r
321                         }\r
322                 }\r
323                 xTaskResumeAll();\r
324 \r
325                 /* We should have been preempted by resuming the scheduler - so by the\r
326                 time we are running again we expect the high priority task to have \r
327                 removed three items from the queue. */\r
328                 xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;\r
329                 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )\r
330                 {\r
331                         xHealthStatus = pdFAIL;\r
332                 }\r
333                 \r
334                 /* The medium priority and second high priority tasks are still \r
335                 suspended.  Make sure to resume them before starting again. */\r
336                 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
337                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );\r
338 \r
339                 /* Just keep incrementing to show the task is still executing. */\r
340                 xCheckVariable++;\r
341         }\r
342 }\r
343 /*-----------------------------------------------------------*/\r
344 \r
345 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )\r
346 {\r
347 portBASE_TYPE xDummy = 0;\r
348 \r
349         /* Write to the queue the requested number of times.  The data written is\r
350         not important. */\r
351         for( xDummy = 0; xDummy < xIncrement; xDummy++ )\r
352         {\r
353                 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )\r
354                 {\r
355                         /* Did not expect to ever find the queue full. */\r
356                         xHealthStatus = pdFAIL;\r
357                 }\r
358         }\r
359 \r
360         /* All the tasks blocked on the queue have a priority higher than the \r
361         controlling task.  Writing to the queue will therefore have caused this\r
362         task to be preempted.  By the time this line executes the event task will\r
363         have executed and incremented its counter.  Increment the expected counter\r
364         to the same value. */\r
365         ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;\r
366 \r
367         /* Check the actual counts and expected counts really are the same. */\r
368         if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )\r
369         {\r
370                 /* The counters were not the same.  This means a task we did not expect\r
371                 to unblock actually did unblock. */\r
372                 xHealthStatus = pdFAIL;\r
373         }\r
374 }\r
375 /*-----------------------------------------------------------*/\r
376 \r
377 portBASE_TYPE xAreMultiEventTasksStillRunning( void )\r
378 {\r
379 static portBASE_TYPE xPreviousCheckVariable = 0;\r
380 \r
381         /* Called externally to periodically check that this test is still\r
382         operational. */\r
383 \r
384         if( xPreviousCheckVariable == xCheckVariable )\r
385         {\r
386                 xHealthStatus = pdFAIL;\r
387         }\r
388         \r
389         xPreviousCheckVariable = xCheckVariable;\r
390         \r
391         return xHealthStatus;   \r
392 }\r
393 \r
394 \r