2 FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
28 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
29 >>! the source code for proprietary components outside of the FreeRTOS
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
67 * This file exercises the event mechanism whereby more than one task is
\r
68 * blocked waiting for the same event.
\r
70 * The demo creates five tasks - four 'event' tasks, and a controlling task.
\r
71 * The event tasks have various different priorities and all block on reading
\r
72 * the same queue. The controlling task writes data to the queue, then checks
\r
73 * to see which of the event tasks read the data from the queue. The
\r
74 * controlling task has the lowest priority of all the tasks so is guaranteed
\r
75 * to always get preempted immediately upon writing to the queue.
\r
77 * By selectively suspending and resuming the event tasks the controlling task
\r
78 * can check that the highest priority task that is blocked on the queue is the
\r
79 * task that reads the posted data from the queue.
\r
81 * Two of the event tasks share the same priority. When neither of these tasks
\r
82 * are suspended they should alternate - one reading one message from the queue,
\r
83 * the other the next message, etc.
\r
86 /* Standard includes. */
\r
91 /* Scheduler include files. */
\r
92 #include "FreeRTOS.h"
\r
96 /* Demo program include files. */
\r
97 #include "mevents.h"
\r
100 /* Demo specific constants. */
\r
101 #define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
\r
102 #define evtNUM_TASKS ( 4 )
\r
103 #define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 )
\r
104 #define evtNO_DELAY 0
\r
106 /* Just indexes used to uniquely identify the tasks. Note that two tasks are
\r
107 'highest' priority. */
\r
108 #define evtHIGHEST_PRIORITY_INDEX_2 3
\r
109 #define evtHIGHEST_PRIORITY_INDEX_1 2
\r
110 #define evtMEDIUM_PRIORITY_INDEX 1
\r
111 #define evtLOWEST_PRIORITY_INDEX 0
\r
113 /* Each event task increments one of these counters each time it reads data
\r
115 static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
\r
117 /* Each time the controlling task posts onto the queue it increments the
\r
118 expected count of the task that it expected to read the data from the queue
\r
119 (i.e. the task with the highest priority that should be blocked on the queue).
\r
121 xExpectedTaskCounters are incremented from the controlling task, and
\r
122 xTaskCounters are incremented from the individual event tasks - therefore
\r
123 comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
\r
124 correct task was unblocked by the post. */
\r
125 static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
\r
127 /* Handles to the four event tasks. These are required to suspend and resume
\r
129 static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ];
\r
131 /* The single queue onto which the controlling task posts, and the four event
\r
133 static QueueHandle_t xQueue;
\r
135 /* Flag used to indicate whether or not an error has occurred at any time.
\r
136 An error is either the queue being full when not expected, or an unexpected
\r
137 task reading data from the queue. */
\r
138 static portBASE_TYPE xHealthStatus = pdPASS;
\r
140 /*-----------------------------------------------------------*/
\r
142 /* Function that implements the event task. This is created four times. */
\r
143 static void prvMultiEventTask( void *pvParameters );
\r
145 /* Function that implements the controlling task. */
\r
146 static void prvEventControllerTask( void *pvParameters );
\r
148 /* This is a utility function that posts data to the queue, then compares
\r
149 xExpectedTaskCounters with xTaskCounters to ensure everything worked as
\r
152 The event tasks all have higher priorities the controlling task. Therefore
\r
153 the controlling task will always get preempted between writhing to the queue
\r
154 and checking the task counters.
\r
156 @param xExpectedTask The index to the task that the controlling task thinks
\r
157 should be the highest priority task waiting for data, and
\r
158 therefore the task that will unblock.
\r
160 @param xIncrement The number of items that should be written to the queue.
\r
162 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );
\r
164 /* This is just incremented each cycle of the controlling tasks function so
\r
165 the main application can ensure the test is still running. */
\r
166 static portBASE_TYPE xCheckVariable = 0;
\r
168 /*-----------------------------------------------------------*/
\r
170 void vStartMultiEventTasks( void )
\r
172 /* Create the queue to be used for all the communications. */
\r
173 xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
\r
175 /* Start the controlling task. This has the idle priority to ensure it is
\r
176 always preempted by the event tasks. */
\r
177 xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
\r
179 /* Start the four event tasks. Note that two have priority 3, one
\r
180 priority 2 and the other priority 1. */
\r
181 xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
\r
182 xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
\r
183 xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
\r
184 xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
\r
186 /*-----------------------------------------------------------*/
\r
188 static void prvMultiEventTask( void *pvParameters )
\r
190 portBASE_TYPE *pxCounter;
\r
191 unsigned portBASE_TYPE uxDummy;
\r
192 const char * const pcTaskStartMsg = "Multi event task started.\r\n";
\r
194 /* The variable this task will increment is passed in as a parameter. */
\r
195 pxCounter = ( portBASE_TYPE * ) pvParameters;
\r
197 vPrintDisplayMessage( &pcTaskStartMsg );
\r
201 /* Block on the queue. */
\r
202 if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
\r
204 /* We unblocked by reading the queue - so simply increment
\r
205 the counter specific to this task instance. */
\r
210 xHealthStatus = pdFAIL;
\r
214 /*-----------------------------------------------------------*/
\r
216 static void prvEventControllerTask( void *pvParameters )
\r
218 const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";
\r
219 portBASE_TYPE xDummy = 0;
\r
221 /* Just to stop warnings. */
\r
222 ( void ) pvParameters;
\r
224 vPrintDisplayMessage( &pcTaskStartMsg );
\r
228 /* All tasks are blocked on the queue. When a message is posted one of
\r
229 the two tasks that share the highest priority should unblock to read
\r
230 the queue. The next message written should unblock the other task with
\r
231 the same high priority, and so on in order. No other task should
\r
232 unblock to read data as they have lower priorities. */
\r
234 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
\r
235 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
\r
236 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
\r
237 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
\r
238 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
\r
240 /* For the rest of these tests we don't need the second 'highest'
\r
241 priority task - so it is suspended. */
\r
242 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
\r
246 /* Now suspend the other highest priority task. The medium priority
\r
247 task will then be the task with the highest priority that remains
\r
248 blocked on the queue. */
\r
249 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
251 /* This time, when we post onto the queue we will expect the medium
\r
252 priority task to unblock and preempt us. */
\r
253 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
\r
255 /* Now try resuming the highest priority task while the scheduler is
\r
256 suspended. The task should start executing as soon as the scheduler
\r
257 is resumed - therefore when we post to the queue again, the highest
\r
258 priority task should again preempt us. */
\r
260 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
262 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
\r
264 /* Now we are going to suspend the high and medium priority tasks. The
\r
265 low priority task should then preempt us. Again the task suspension is
\r
266 done with the whole scheduler suspended just for test purposes. */
\r
268 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
269 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
\r
271 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
\r
273 /* Do the same basic test another few times - selectively suspending
\r
274 and resuming tasks and each time calling prvCheckTaskCounters() passing
\r
275 to the function the number of the task we expected to be unblocked by
\r
278 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
279 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
\r
281 vTaskSuspendAll(); /* Just for test. */
\r
282 vTaskSuspendAll(); /* Just for test. */
\r
283 vTaskSuspendAll(); /* Just for even more test. */
\r
284 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
288 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
\r
290 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
\r
291 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
\r
293 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
294 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
\r
296 /* Now a slight change, first suspend all tasks. */
\r
297 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
298 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
\r
299 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
\r
301 /* Now when we resume the low priority task and write to the queue 3
\r
302 times. We expect the low priority task to service the queue three
\r
304 vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
\r
305 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
\r
307 /* Again suspend all tasks (only the low priority task is not suspended
\r
309 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
\r
311 /* This time we are going to suspend the scheduler, resume the low
\r
312 priority task, then resume the high priority task. In this state we
\r
313 will write to the queue three times. When the scheduler is resumed
\r
314 we expect the high priority task to service all three messages. */
\r
317 vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
\r
318 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
\r
320 for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
\r
322 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
\r
324 xHealthStatus = pdFAIL;
\r
328 /* The queue should not have been serviced yet!. The scheduler
\r
329 is still suspended. */
\r
330 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
\r
332 xHealthStatus = pdFAIL;
\r
337 /* We should have been preempted by resuming the scheduler - so by the
\r
338 time we are running again we expect the high priority task to have
\r
339 removed three items from the queue. */
\r
340 xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
\r
341 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
\r
343 xHealthStatus = pdFAIL;
\r
346 /* The medium priority and second high priority tasks are still
\r
347 suspended. Make sure to resume them before starting again. */
\r
348 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
\r
349 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
\r
351 /* Just keep incrementing to show the task is still executing. */
\r
355 /*-----------------------------------------------------------*/
\r
357 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )
\r
359 portBASE_TYPE xDummy = 0;
\r
361 /* Write to the queue the requested number of times. The data written is
\r
363 for( xDummy = 0; xDummy < xIncrement; xDummy++ )
\r
365 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
\r
367 /* Did not expect to ever find the queue full. */
\r
368 xHealthStatus = pdFAIL;
\r
372 /* All the tasks blocked on the queue have a priority higher than the
\r
373 controlling task. Writing to the queue will therefore have caused this
\r
374 task to be preempted. By the time this line executes the event task will
\r
375 have executed and incremented its counter. Increment the expected counter
\r
376 to the same value. */
\r
377 ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
\r
379 /* Check the actual counts and expected counts really are the same. */
\r
380 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
\r
382 /* The counters were not the same. This means a task we did not expect
\r
383 to unblock actually did unblock. */
\r
384 xHealthStatus = pdFAIL;
\r
387 /*-----------------------------------------------------------*/
\r
389 portBASE_TYPE xAreMultiEventTasksStillRunning( void )
\r
391 static portBASE_TYPE xPreviousCheckVariable = 0;
\r
393 /* Called externally to periodically check that this test is still
\r
396 if( xPreviousCheckVariable == xCheckVariable )
\r
398 xHealthStatus = pdFAIL;
\r
401 xPreviousCheckVariable = xCheckVariable;
\r
403 return xHealthStatus;
\r