]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Full/events.c
Update version numbers in preparation for V8.2.0 release candidate 1.
[freertos] / FreeRTOS / Demo / Common / Full / events.c
1 /*\r
2     FreeRTOS V8.2.0rc1 - Copyright (C) 2014 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
12 \r
13     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
14     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
15     >>!   obliged to provide the source code for proprietary components     !<<\r
16     >>!   outside of the FreeRTOS kernel.                                   !<<\r
17 \r
18     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
19     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
20     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
21     link: http://www.freertos.org/a00114.html\r
22 \r
23     1 tab == 4 spaces!\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    Having a problem?  Start by reading the FAQ "My application does   *\r
28      *    not run, what could be wrong?".  Have you defined configASSERT()?  *\r
29      *                                                                       *\r
30      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
31      *                                                                       *\r
32     ***************************************************************************\r
33 \r
34     ***************************************************************************\r
35      *                                                                       *\r
36      *    FreeRTOS provides completely free yet professionally developed,    *\r
37      *    robust, strictly quality controlled, supported, and cross          *\r
38      *    platform software that is more than just the market leader, it     *\r
39      *    is the industry's de facto standard.                               *\r
40      *                                                                       *\r
41      *    Help yourself get started quickly while simultaneously helping     *\r
42      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
43      *    tutorial book, reference manual, or both:                          *\r
44      *    http://www.FreeRTOS.org/Documentation                              *\r
45      *                                                                       *\r
46     ***************************************************************************\r
47 \r
48     ***************************************************************************\r
49      *                                                                       *\r
50      *   Investing in training allows your team to be as productive as       *\r
51      *   possible as early as possible, lowering your overall development    *\r
52      *   cost, and enabling you to bring a more robust product to market     *\r
53      *   earlier than would otherwise be possible.  Richard Barry is both    *\r
54      *   the architect and key author of FreeRTOS, and so also the world's   *\r
55      *   leading authority on what is the world's most popular real time     *\r
56      *   kernel for deeply embedded MCU designs.  Obtaining your training    *\r
57      *   from Richard ensures your team will gain directly from his in-depth *\r
58      *   product knowledge and years of usage experience.  Contact Real Time *\r
59      *   Engineers Ltd to enquire about the FreeRTOS Masterclass, presented  *\r
60      *   by Richard Barry:  http://www.FreeRTOS.org/contact\r
61      *                                                                       *\r
62     ***************************************************************************\r
63 \r
64     ***************************************************************************\r
65      *                                                                       *\r
66      *    You are receiving this top quality software for free.  Please play *\r
67      *    fair and reciprocate by reporting any suspected issues and         *\r
68      *    participating in the community forum:                              *\r
69      *    http://www.FreeRTOS.org/support                                    *\r
70      *                                                                       *\r
71      *    Thank you!                                                         *\r
72      *                                                                       *\r
73     ***************************************************************************\r
74 \r
75     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
76     license and Real Time Engineers Ltd. contact details.\r
77 \r
78     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
79     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
80     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
81 \r
82     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
83     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
84 \r
85     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
86     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
87     licenses offer ticketed support, indemnification and commercial middleware.\r
88 \r
89     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
90     engineered and independently SIL3 certified version for use in safety and\r
91     mission critical applications that require provable dependability.\r
92 \r
93     1 tab == 4 spaces!\r
94 */\r
95 \r
96 /**\r
97  * This file exercises the event mechanism whereby more than one task is\r
98  * blocked waiting for the same event.\r
99  *\r
100  * The demo creates five tasks - four 'event' tasks, and a controlling task.\r
101  * The event tasks have various different priorities and all block on reading\r
102  * the same queue.  The controlling task writes data to the queue, then checks\r
103  * to see which of the event tasks read the data from the queue.  The\r
104  * controlling task has the lowest priority of all the tasks so is guaranteed\r
105  * to always get preempted immediately upon writing to the queue.\r
106  *\r
107  * By selectively suspending and resuming the event tasks the controlling task\r
108  * can check that the highest priority task that is blocked on the queue is the\r
109  * task that reads the posted data from the queue.\r
110  *\r
111  * Two of the event tasks share the same priority.  When neither of these tasks\r
112  * are suspended they should alternate - one reading one message from the queue,\r
113  * the other the next message, etc.\r
114  */\r
115 \r
116 /* Standard includes. */\r
117 #include <stdlib.h>\r
118 #include <stdio.h>\r
119 #include <string.h>\r
120 \r
121 /* Scheduler include files. */\r
122 #include "FreeRTOS.h"\r
123 #include "task.h"\r
124 #include "queue.h"\r
125 \r
126 /* Demo program include files. */\r
127 #include "mevents.h"\r
128 #include "print.h"\r
129 \r
130 /* Demo specific constants. */\r
131 #define evtSTACK_SIZE           ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )\r
132 #define evtNUM_TASKS            ( 4 )\r
133 #define evtQUEUE_LENGTH         ( ( unsigned portBASE_TYPE ) 3 )\r
134 #define evtNO_DELAY                                             0\r
135 \r
136 /* Just indexes used to uniquely identify the tasks.  Note that two tasks are\r
137 'highest' priority. */\r
138 #define evtHIGHEST_PRIORITY_INDEX_2             3\r
139 #define evtHIGHEST_PRIORITY_INDEX_1             2\r
140 #define evtMEDIUM_PRIORITY_INDEX                1\r
141 #define evtLOWEST_PRIORITY_INDEX                0\r
142 \r
143 /* Each event task increments one of these counters each time it reads data\r
144 from the queue. */\r
145 static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };\r
146 \r
147 /* Each time the controlling task posts onto the queue it increments the \r
148 expected count of the task that it expected to read the data from the queue \r
149 (i.e. the task with the highest priority that should be blocked on the queue).  \r
150 \r
151 xExpectedTaskCounters are incremented from the controlling task, and \r
152 xTaskCounters are incremented from the individual event tasks - therefore\r
153 comparing xTaskCounters to xExpectedTaskCounters shows whether or not the \r
154 correct task was unblocked by the post. */\r
155 static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };\r
156 \r
157 /* Handles to the four event tasks.  These are required to suspend and resume\r
158 the tasks. */\r
159 static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ];\r
160 \r
161 /* The single queue onto which the controlling task posts, and the four event\r
162 tasks block. */\r
163 static QueueHandle_t xQueue;\r
164 \r
165 /* Flag used to indicate whether or not an error has occurred at any time.\r
166 An error is either the queue being full when not expected, or an unexpected\r
167 task reading data from the queue. */\r
168 static portBASE_TYPE xHealthStatus = pdPASS;\r
169 \r
170 /*-----------------------------------------------------------*/\r
171 \r
172 /* Function that implements the event task.  This is created four times. */\r
173 static void prvMultiEventTask( void *pvParameters );\r
174 \r
175 /* Function that implements the controlling task. */\r
176 static void prvEventControllerTask( void *pvParameters );\r
177 \r
178 /* This is a utility function that posts data to the queue, then compares \r
179 xExpectedTaskCounters with xTaskCounters to ensure everything worked as \r
180 expected.\r
181 \r
182 The event tasks all have higher priorities the controlling task.  Therefore\r
183 the controlling task will always get preempted between writhing to the queue\r
184 and checking the task counters. \r
185 \r
186 @param xExpectedTask  The index to the task that the controlling task thinks\r
187                       should be the highest priority task waiting for data, and\r
188                                           therefore the task that will unblock.\r
189                                           \r
190 @param  xIncrement    The number of items that should be written to the queue.\r
191 */\r
192 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );\r
193 \r
194 /* This is just incremented each cycle of the controlling tasks function so\r
195 the main application can ensure the test is still running. */\r
196 static portBASE_TYPE xCheckVariable = 0;\r
197 \r
198 /*-----------------------------------------------------------*/\r
199 \r
200 void vStartMultiEventTasks( void )\r
201 {\r
202         /* Create the queue to be used for all the communications. */\r
203         xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );\r
204 \r
205         /* Start the controlling task.  This has the idle priority to ensure it is\r
206         always preempted by the event tasks. */\r
207         xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
208 \r
209         /* Start the four event tasks.  Note that two have priority 3, one \r
210         priority 2 and the other priority 1. */\r
211         xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );\r
212         xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );\r
213         xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );\r
214         xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );\r
215 }\r
216 /*-----------------------------------------------------------*/\r
217 \r
218 static void prvMultiEventTask( void *pvParameters )\r
219 {\r
220 portBASE_TYPE *pxCounter;\r
221 unsigned portBASE_TYPE uxDummy;\r
222 const char * const pcTaskStartMsg = "Multi event task started.\r\n";\r
223 \r
224         /* The variable this task will increment is passed in as a parameter. */\r
225         pxCounter = ( portBASE_TYPE * ) pvParameters;\r
226 \r
227         vPrintDisplayMessage( &pcTaskStartMsg );\r
228 \r
229         for( ;; )\r
230         {\r
231                 /* Block on the queue. */\r
232                 if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )\r
233                 {\r
234                         /* We unblocked by reading the queue - so simply increment\r
235                         the counter specific to this task instance. */\r
236                         ( *pxCounter )++;\r
237                 }\r
238                 else\r
239                 {\r
240                         xHealthStatus = pdFAIL;\r
241                 }\r
242         }\r
243 }\r
244 /*-----------------------------------------------------------*/\r
245 \r
246 static void prvEventControllerTask( void *pvParameters )\r
247 {\r
248 const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";\r
249 portBASE_TYPE xDummy = 0;\r
250 \r
251         /* Just to stop warnings. */\r
252         ( void ) pvParameters;\r
253 \r
254         vPrintDisplayMessage( &pcTaskStartMsg );\r
255 \r
256         for( ;; )\r
257         {\r
258                 /* All tasks are blocked on the queue.  When a message is posted one of\r
259                 the two tasks that share the highest priority should unblock to read\r
260                 the queue.  The next message written should unblock the other task with\r
261                 the same high priority, and so on in order.   No other task should \r
262                 unblock to read data as they have lower priorities. */\r
263 \r
264                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
265                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );\r
266                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
267                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );\r
268                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
269 \r
270                 /* For the rest of these tests we don't need the second 'highest' \r
271                 priority task - so it is suspended. */\r
272                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );\r
273 \r
274 \r
275 \r
276                 /* Now suspend the other highest priority task.  The medium priority \r
277                 task will then be the task with the highest priority that remains \r
278                 blocked on the queue. */\r
279                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
280                 \r
281                 /* This time, when we post onto the queue we will expect the medium\r
282                 priority task to unblock and preempt us. */\r
283                 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );\r
284 \r
285                 /* Now try resuming the highest priority task while the scheduler is\r
286                 suspended.  The task should start executing as soon as the scheduler\r
287                 is resumed - therefore when we post to the queue again, the highest\r
288                 priority task should again preempt us. */\r
289                 vTaskSuspendAll();\r
290                         vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
291                 xTaskResumeAll();\r
292                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
293                 \r
294                 /* Now we are going to suspend the high and medium priority tasks.  The\r
295                 low priority task should then preempt us.  Again the task suspension is \r
296                 done with the whole scheduler suspended just for test purposes. */\r
297                 vTaskSuspendAll();\r
298                         vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
299                         vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
300                 xTaskResumeAll();\r
301                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );\r
302                 \r
303                 /* Do the same basic test another few times - selectively suspending\r
304                 and resuming tasks and each time calling prvCheckTaskCounters() passing\r
305                 to the function the number of the task we expected to be unblocked by \r
306                 the     post. */\r
307 \r
308                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
309                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
310                 \r
311                 vTaskSuspendAll(); /* Just for test. */\r
312                         vTaskSuspendAll(); /* Just for test. */\r
313                                 vTaskSuspendAll(); /* Just for even more test. */\r
314                                         vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
315                                 xTaskResumeAll();\r
316                         xTaskResumeAll();\r
317                 xTaskResumeAll();\r
318                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );\r
319                 \r
320                 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
321                 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );\r
322                 \r
323                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
324                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );\r
325 \r
326                 /* Now a slight change, first suspend all tasks. */\r
327                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
328                 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
329                 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
330                 \r
331                 /* Now when we resume the low priority task and write to the queue 3 \r
332                 times.  We expect the low priority task to service the queue three\r
333                 times. */\r
334                 vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
335                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );\r
336                 \r
337                 /* Again suspend all tasks (only the low priority task is not suspended\r
338                 already). */\r
339                 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
340                 \r
341                 /* This time we are going to suspend the scheduler, resume the low\r
342                 priority task, then resume the high priority task.  In this state we\r
343                 will write to the queue three times.  When the scheduler is resumed\r
344                 we expect the high priority task to service all three messages. */\r
345                 vTaskSuspendAll();\r
346                 {\r
347                         vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );\r
348                         vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );\r
349                         \r
350                         for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )\r
351                         {\r
352                                 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )\r
353                                 {\r
354                                         xHealthStatus = pdFAIL;\r
355                                 }\r
356                         }                       \r
357                         \r
358                         /* The queue should not have been serviced yet!.  The scheduler\r
359                         is still suspended. */\r
360                         if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )\r
361                         {\r
362                                 xHealthStatus = pdFAIL;\r
363                         }\r
364                 }\r
365                 xTaskResumeAll();\r
366 \r
367                 /* We should have been preempted by resuming the scheduler - so by the\r
368                 time we are running again we expect the high priority task to have \r
369                 removed three items from the queue. */\r
370                 xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;\r
371                 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )\r
372                 {\r
373                         xHealthStatus = pdFAIL;\r
374                 }\r
375                 \r
376                 /* The medium priority and second high priority tasks are still \r
377                 suspended.  Make sure to resume them before starting again. */\r
378                 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );\r
379                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );\r
380 \r
381                 /* Just keep incrementing to show the task is still executing. */\r
382                 xCheckVariable++;\r
383         }\r
384 }\r
385 /*-----------------------------------------------------------*/\r
386 \r
387 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )\r
388 {\r
389 portBASE_TYPE xDummy = 0;\r
390 \r
391         /* Write to the queue the requested number of times.  The data written is\r
392         not important. */\r
393         for( xDummy = 0; xDummy < xIncrement; xDummy++ )\r
394         {\r
395                 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )\r
396                 {\r
397                         /* Did not expect to ever find the queue full. */\r
398                         xHealthStatus = pdFAIL;\r
399                 }\r
400         }\r
401 \r
402         /* All the tasks blocked on the queue have a priority higher than the \r
403         controlling task.  Writing to the queue will therefore have caused this\r
404         task to be preempted.  By the time this line executes the event task will\r
405         have executed and incremented its counter.  Increment the expected counter\r
406         to the same value. */\r
407         ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;\r
408 \r
409         /* Check the actual counts and expected counts really are the same. */\r
410         if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )\r
411         {\r
412                 /* The counters were not the same.  This means a task we did not expect\r
413                 to unblock actually did unblock. */\r
414                 xHealthStatus = pdFAIL;\r
415         }\r
416 }\r
417 /*-----------------------------------------------------------*/\r
418 \r
419 portBASE_TYPE xAreMultiEventTasksStillRunning( void )\r
420 {\r
421 static portBASE_TYPE xPreviousCheckVariable = 0;\r
422 \r
423         /* Called externally to periodically check that this test is still\r
424         operational. */\r
425 \r
426         if( xPreviousCheckVariable == xCheckVariable )\r
427         {\r
428                 xHealthStatus = pdFAIL;\r
429         }\r
430         \r
431         xPreviousCheckVariable = xCheckVariable;\r
432         \r
433         return xHealthStatus;   \r
434 }\r
435 \r
436 \r