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