FreeRTOS
[armadillo_firmware.git] / FreeRTOS / Common / Full / events.c
blob0a3bfc88adccaa21a90c41df65864304a59bfc28
1 /*
2 FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd.
4 ***************************************************************************
5 * *
6 * If you are: *
7 * *
8 * + New to FreeRTOS, *
9 * + Wanting to learn FreeRTOS or multitasking in general quickly *
10 * + Looking for basic training, *
11 * + Wanting to improve your FreeRTOS skills and productivity *
12 * *
13 * then take a look at the FreeRTOS eBook *
14 * *
15 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
16 * http://www.FreeRTOS.org/Documentation *
17 * *
18 * A pdf reference manual is also available. Both are usually delivered *
19 * to your inbox within 20 minutes to two hours when purchased between 8am *
20 * and 8pm GMT (although please allow up to 24 hours in case of *
21 * exceptional circumstances). Thank you for your support! *
22 * *
23 ***************************************************************************
25 This file is part of the FreeRTOS distribution.
27 FreeRTOS is free software; you can redistribute it and/or modify it under
28 the terms of the GNU General Public License (version 2) as published by the
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30 ***NOTE*** The exception to the GPL is included to allow you to distribute
31 a combined work that includes FreeRTOS without being obliged to provide the
32 source code for proprietary components outside of the FreeRTOS kernel.
33 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
36 more details. You should have received a copy of the GNU General Public
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
39 by writing to Richard Barry, contact details for whom are available on the
40 FreeRTOS WEB site.
42 1 tab == 4 spaces!
44 http://www.FreeRTOS.org - Documentation, latest information, license and
45 contact details.
47 http://www.SafeRTOS.com - A version that is certified for use in safety
48 critical systems.
50 http://www.OpenRTOS.com - Commercial support, development, porting,
51 licensing and training services.
54 /**
55 * This file exercises the event mechanism whereby more than one task is
56 * blocked waiting for the same event.
58 * The demo creates five tasks - four 'event' tasks, and a controlling task.
59 * The event tasks have various different priorities and all block on reading
60 * the same queue. The controlling task writes data to the queue, then checks
61 * to see which of the event tasks read the data from the queue. The
62 * controlling task has the lowest priority of all the tasks so is guaranteed
63 * to always get preempted immediately upon writing to the queue.
65 * By selectively suspending and resuming the event tasks the controlling task
66 * can check that the highest priority task that is blocked on the queue is the
67 * task that reads the posted data from the queue.
69 * Two of the event tasks share the same priority. When neither of these tasks
70 * are suspended they should alternate - one reading one message from the queue,
71 * the other the next message, etc.
74 /* Standard includes. */
75 #include <stdlib.h>
76 #include <stdio.h>
77 #include <string.h>
79 /* Scheduler include files. */
80 #include "FreeRTOS.h"
81 #include "task.h"
82 #include "queue.h"
84 /* Demo program include files. */
85 #include "mevents.h"
86 #include "print.h"
88 /* Demo specific constants. */
89 #define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
90 #define evtNUM_TASKS ( 4 )
91 #define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 )
92 #define evtNO_DELAY 0
94 /* Just indexes used to uniquely identify the tasks. Note that two tasks are
95 'highest' priority. */
96 #define evtHIGHEST_PRIORITY_INDEX_2 3
97 #define evtHIGHEST_PRIORITY_INDEX_1 2
98 #define evtMEDIUM_PRIORITY_INDEX 1
99 #define evtLOWEST_PRIORITY_INDEX 0
101 /* Each event task increments one of these counters each time it reads data
102 from the queue. */
103 static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
105 /* Each time the controlling task posts onto the queue it increments the
106 expected count of the task that it expected to read the data from the queue
107 (i.e. the task with the highest priority that should be blocked on the queue).
109 xExpectedTaskCounters are incremented from the controlling task, and
110 xTaskCounters are incremented from the individual event tasks - therefore
111 comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
112 correct task was unblocked by the post. */
113 static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
115 /* Handles to the four event tasks. These are required to suspend and resume
116 the tasks. */
117 static xTaskHandle xCreatedTasks[ evtNUM_TASKS ];
119 /* The single queue onto which the controlling task posts, and the four event
120 tasks block. */
121 static xQueueHandle xQueue;
123 /* Flag used to indicate whether or not an error has occurred at any time.
124 An error is either the queue being full when not expected, or an unexpected
125 task reading data from the queue. */
126 static portBASE_TYPE xHealthStatus = pdPASS;
128 /*-----------------------------------------------------------*/
130 /* Function that implements the event task. This is created four times. */
131 static void prvMultiEventTask( void *pvParameters );
133 /* Function that implements the controlling task. */
134 static void prvEventControllerTask( void *pvParameters );
136 /* This is a utility function that posts data to the queue, then compares
137 xExpectedTaskCounters with xTaskCounters to ensure everything worked as
138 expected.
140 The event tasks all have higher priorities the controlling task. Therefore
141 the controlling task will always get preempted between writhing to the queue
142 and checking the task counters.
144 @param xExpectedTask The index to the task that the controlling task thinks
145 should be the highest priority task waiting for data, and
146 therefore the task that will unblock.
148 @param xIncrement The number of items that should be written to the queue.
150 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );
152 /* This is just incremented each cycle of the controlling tasks function so
153 the main application can ensure the test is still running. */
154 static portBASE_TYPE xCheckVariable = 0;
156 /*-----------------------------------------------------------*/
158 void vStartMultiEventTasks( void )
160 /* Create the queue to be used for all the communications. */
161 xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
163 /* Start the controlling task. This has the idle priority to ensure it is
164 always preempted by the event tasks. */
165 xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
167 /* Start the four event tasks. Note that two have priority 3, one
168 priority 2 and the other priority 1. */
169 xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
170 xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
171 xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
172 xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
174 /*-----------------------------------------------------------*/
176 static void prvMultiEventTask( void *pvParameters )
178 portBASE_TYPE *pxCounter;
179 unsigned portBASE_TYPE uxDummy;
180 const char * const pcTaskStartMsg = "Multi event task started.\r\n";
182 /* The variable this task will increment is passed in as a parameter. */
183 pxCounter = ( portBASE_TYPE * ) pvParameters;
185 vPrintDisplayMessage( &pcTaskStartMsg );
187 for( ;; )
189 /* Block on the queue. */
190 if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
192 /* We unblocked by reading the queue - so simply increment
193 the counter specific to this task instance. */
194 ( *pxCounter )++;
196 else
198 xHealthStatus = pdFAIL;
202 /*-----------------------------------------------------------*/
204 static void prvEventControllerTask( void *pvParameters )
206 const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";
207 portBASE_TYPE xDummy = 0;
209 /* Just to stop warnings. */
210 ( void ) pvParameters;
212 vPrintDisplayMessage( &pcTaskStartMsg );
214 for( ;; )
216 /* All tasks are blocked on the queue. When a message is posted one of
217 the two tasks that share the highest priority should unblock to read
218 the queue. The next message written should unblock the other task with
219 the same high priority, and so on in order. No other task should
220 unblock to read data as they have lower priorities. */
222 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
223 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
224 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
225 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
226 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
228 /* For the rest of these tests we don't need the second 'highest'
229 priority task - so it is suspended. */
230 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
234 /* Now suspend the other highest priority task. The medium priority
235 task will then be the task with the highest priority that remains
236 blocked on the queue. */
237 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
239 /* This time, when we post onto the queue we will expect the medium
240 priority task to unblock and preempt us. */
241 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
243 /* Now try resuming the highest priority task while the scheduler is
244 suspended. The task should start executing as soon as the scheduler
245 is resumed - therefore when we post to the queue again, the highest
246 priority task should again preempt us. */
247 vTaskSuspendAll();
248 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
249 xTaskResumeAll();
250 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
252 /* Now we are going to suspend the high and medium priority tasks. The
253 low priority task should then preempt us. Again the task suspension is
254 done with the whole scheduler suspended just for test purposes. */
255 vTaskSuspendAll();
256 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
257 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
258 xTaskResumeAll();
259 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
261 /* Do the same basic test another few times - selectively suspending
262 and resuming tasks and each time calling prvCheckTaskCounters() passing
263 to the function the number of the task we expected to be unblocked by
264 the post. */
266 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
267 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
269 vTaskSuspendAll(); /* Just for test. */
270 vTaskSuspendAll(); /* Just for test. */
271 vTaskSuspendAll(); /* Just for even more test. */
272 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
273 xTaskResumeAll();
274 xTaskResumeAll();
275 xTaskResumeAll();
276 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
278 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
279 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
281 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
282 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
284 /* Now a slight change, first suspend all tasks. */
285 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
286 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
287 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
289 /* Now when we resume the low priority task and write to the queue 3
290 times. We expect the low priority task to service the queue three
291 times. */
292 vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
293 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
295 /* Again suspend all tasks (only the low priority task is not suspended
296 already). */
297 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
299 /* This time we are going to suspend the scheduler, resume the low
300 priority task, then resume the high priority task. In this state we
301 will write to the queue three times. When the scheduler is resumed
302 we expect the high priority task to service all three messages. */
303 vTaskSuspendAll();
305 vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
306 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
308 for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
310 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
312 xHealthStatus = pdFAIL;
316 /* The queue should not have been serviced yet!. The scheduler
317 is still suspended. */
318 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
320 xHealthStatus = pdFAIL;
323 xTaskResumeAll();
325 /* We should have been preempted by resuming the scheduler - so by the
326 time we are running again we expect the high priority task to have
327 removed three items from the queue. */
328 xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
329 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
331 xHealthStatus = pdFAIL;
334 /* The medium priority and second high priority tasks are still
335 suspended. Make sure to resume them before starting again. */
336 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
337 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
339 /* Just keep incrementing to show the task is still executing. */
340 xCheckVariable++;
343 /*-----------------------------------------------------------*/
345 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )
347 portBASE_TYPE xDummy = 0;
349 /* Write to the queue the requested number of times. The data written is
350 not important. */
351 for( xDummy = 0; xDummy < xIncrement; xDummy++ )
353 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
355 /* Did not expect to ever find the queue full. */
356 xHealthStatus = pdFAIL;
360 /* All the tasks blocked on the queue have a priority higher than the
361 controlling task. Writing to the queue will therefore have caused this
362 task to be preempted. By the time this line executes the event task will
363 have executed and incremented its counter. Increment the expected counter
364 to the same value. */
365 ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
367 /* Check the actual counts and expected counts really are the same. */
368 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
370 /* The counters were not the same. This means a task we did not expect
371 to unblock actually did unblock. */
372 xHealthStatus = pdFAIL;
375 /*-----------------------------------------------------------*/
377 portBASE_TYPE xAreMultiEventTasksStillRunning( void )
379 static portBASE_TYPE xPreviousCheckVariable = 0;
381 /* Called externally to periodically check that this test is still
382 operational. */
384 if( xPreviousCheckVariable == xCheckVariable )
386 xHealthStatus = pdFAIL;
389 xPreviousCheckVariable = xCheckVariable;
391 return xHealthStatus;