]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/EventGroupsDemo.c
22b7fb81d659c5a39347bbbe63770dc4aca878c1
[freertos] / FreeRTOS / Demo / Common / Minimal / EventGroupsDemo.c
1 /*\r
2  * FreeRTOS Kernel V10.0.1\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 \r
29 \r
30 /*\r
31 * This file contains fairly comprehensive checks on the behaviour of event\r
32 * groups.  It is not intended to be a user friendly demonstration of the\r
33 * event groups API.\r
34 *\r
35 * NOTE:  The tests implemented in this file are informal 'sanity' tests\r
36 * only and are not part of the module tests that make use of the\r
37 * mtCOVERAGE_TEST_MARKER macro within the event groups implementation.\r
38 */\r
39 \r
40 \r
41 /* Scheduler include files. */\r
42 #include "FreeRTOS.h"\r
43 #include "task.h"\r
44 #include "event_groups.h"\r
45 \r
46 /* Demo app includes. */\r
47 #include "EventGroupsDemo.h"\r
48 \r
49 #if( INCLUDE_eTaskGetState != 1 )\r
50         #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file.\r
51 #endif\r
52 \r
53 /* Priorities used by the tasks. */\r
54 #define ebSET_BIT_TASK_PRIORITY         ( tskIDLE_PRIORITY )\r
55 #define ebWAIT_BIT_TASK_PRIORITY        ( tskIDLE_PRIORITY + 1 )\r
56 \r
57 /* Generic bit definitions. */\r
58 #define ebBIT_0         ( 0x01 )\r
59 #define ebBIT_1         ( 0x02 )\r
60 #define ebBIT_2         ( 0x04 )\r
61 #define ebBIT_3         ( 0x08 )\r
62 #define ebBIT_4         ( 0x10 )\r
63 #define ebBIT_5         ( 0x20 )\r
64 #define ebBIT_6         ( 0x40 )\r
65 #define ebBIT_7         ( 0x80 )\r
66 \r
67 /* Combinations of bits used in the demo. */\r
68 #define ebCOMBINED_BITS ( ebBIT_1 | ebBIT_5 | ebBIT_7 )\r
69 #define ebALL_BITS ( ebBIT_0 | ebBIT_1 | ebBIT_2 | ebBIT_3 | ebBIT_4 | ebBIT_5 | ebBIT_6 | ebBIT_7 )\r
70 \r
71 /* Associate a bit to each task.  These bits are used to identify all the tasks\r
72 that synchronise with the xEventGroupSync() function. */\r
73 #define ebSET_BIT_TASK_SYNC_BIT                 ebBIT_0\r
74 #define ebWAIT_BIT_TASK_SYNC_BIT                ebBIT_1\r
75 #define ebRENDESVOUS_TASK_1_SYNC_BIT    ebBIT_2\r
76 #define ebRENDESVOUS_TASK_2_SYNC_BIT    ebBIT_3\r
77 #define ebALL_SYNC_BITS ( ebSET_BIT_TASK_SYNC_BIT | ebWAIT_BIT_TASK_SYNC_BIT | ebRENDESVOUS_TASK_1_SYNC_BIT | ebRENDESVOUS_TASK_2_SYNC_BIT )\r
78 \r
79 /* A block time of zero simply means "don't block". */\r
80 #define ebDONT_BLOCK    ( 0 )\r
81 \r
82 /* A 5ms delay. */\r
83 #define ebSHORT_DELAY   pdMS_TO_TICKS( ( TickType_t ) 5 )\r
84 \r
85 /* Used in the selective bits test which checks no, one or both tasks blocked on\r
86 event bits in a group are unblocked as appropriate as different bits get set. */\r
87 #define ebSELECTIVE_BITS_1              0x03\r
88 #define ebSELECTIVE_BITS_2              0x05\r
89 \r
90 /*-----------------------------------------------------------*/\r
91 \r
92 /*\r
93  * NOTE:  The tests implemented in this function are informal 'sanity' tests\r
94  * only and are not part of the module tests that make use of the\r
95  * mtCOVERAGE_TEST_MARKER macro within the event groups implementation.\r
96  *\r
97  * The master test task.  This task:\r
98  *\r
99  * 1) Calls prvSelectiveBitsTestMasterFunction() to test the behaviour when two\r
100  *    tasks are blocked on different bits in an event group.  The counterpart of\r
101  *    this test is implemented by the prvSelectiveBitsTestSlaveFunction()\r
102  *    function (which is called by the two tasks that block on the event group).\r
103  *\r
104  * 2) Calls prvBitCombinationTestMasterFunction() to test the behaviour when\r
105  *    just one task is blocked on various combinations of bits within an event\r
106  *    group.  The counterpart of this test is implemented within the 'test\r
107  *    slave' task.\r
108  *\r
109  * 3) Calls prvPerformTaskSyncTests() to test task synchronisation behaviour.\r
110  */\r
111 static void prvTestMasterTask( void *pvParameters );\r
112 \r
113 /*\r
114  * A helper task that enables the 'test master' task to perform several\r
115  * behavioural tests.  See the comments above the prvTestMasterTask() prototype\r
116  * above.\r
117  */\r
118 static void prvTestSlaveTask( void *pvParameters );\r
119 \r
120 /*\r
121  * The part of the test that is performed between the 'test master' task and the\r
122  * 'test slave' task to test the behaviour when the slave blocks on various\r
123  * event bit combinations.\r
124  */\r
125 static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle );\r
126 \r
127 /*\r
128  * The part of the test that uses all the tasks to test the task synchronisation\r
129  * behaviour.\r
130  */\r
131 static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle );\r
132 \r
133 /*\r
134  * Two instances of prvSyncTask() are created.  They start by calling\r
135  * prvSelectiveBitsTestSlaveFunction() to act as slaves when the test master is\r
136  * executing the prvSelectiveBitsTestMasterFunction() function.  They then loop\r
137  * to test the task synchronisation (rendezvous) behaviour.\r
138  */\r
139 static void prvSyncTask( void *pvParameters );\r
140 \r
141 /*\r
142  * Functions used in a test that blocks two tasks on various different bits\r
143  * within an event group - then sets each bit in turn and checks that the\r
144  * correct tasks unblock at the correct times.\r
145  */\r
146 static BaseType_t prvSelectiveBitsTestMasterFunction( void );\r
147 static void prvSelectiveBitsTestSlaveFunction( void );\r
148 \r
149 /*-----------------------------------------------------------*/\r
150 \r
151 /* Variables that are incremented by the tasks on each cycle provided no errors\r
152 have been found.  Used to detect an error or stall in the test cycling. */\r
153 static volatile uint32_t ulTestMasterCycles = 0, ulTestSlaveCycles = 0, ulISRCycles = 0;\r
154 \r
155 /* The event group used by all the task based tests. */\r
156 static EventGroupHandle_t xEventGroup = NULL;\r
157 \r
158 /* The event group used by the interrupt based tests. */\r
159 static EventGroupHandle_t xISREventGroup = NULL;\r
160 \r
161 /* Handles to the tasks that only take part in the synchronisation calls. */\r
162 static TaskHandle_t xSyncTask1 = NULL, xSyncTask2 = NULL;\r
163 \r
164 /*-----------------------------------------------------------*/\r
165 \r
166 void vStartEventGroupTasks( void )\r
167 {\r
168 TaskHandle_t xTestSlaveTaskHandle;\r
169 \r
170         /*\r
171          * This file contains fairly comprehensive checks on the behaviour of event\r
172          * groups.  It is not intended to be a user friendly demonstration of the\r
173          * event groups API.\r
174          *\r
175          * NOTE:  The tests implemented in this file are informal 'sanity' tests\r
176          * only and are not part of the module tests that make use of the\r
177          * mtCOVERAGE_TEST_MARKER macro within the event groups implementation.\r
178          *\r
179          * Create the test tasks as described at the top of this file.\r
180          */\r
181         xTaskCreate( prvTestSlaveTask, "WaitO", configMINIMAL_STACK_SIZE, NULL, ebWAIT_BIT_TASK_PRIORITY, &xTestSlaveTaskHandle );\r
182         xTaskCreate( prvTestMasterTask, "SetB", configMINIMAL_STACK_SIZE, ( void * ) xTestSlaveTaskHandle, ebSET_BIT_TASK_PRIORITY, NULL );\r
183         xTaskCreate( prvSyncTask, "Rndv", configMINIMAL_STACK_SIZE, ( void * ) ebRENDESVOUS_TASK_1_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask1 );\r
184         xTaskCreate( prvSyncTask, "Rndv", configMINIMAL_STACK_SIZE, ( void * ) ebRENDESVOUS_TASK_2_SYNC_BIT, ebWAIT_BIT_TASK_PRIORITY, &xSyncTask2 );\r
185 \r
186         /* If the last task was created then the others will have been too. */\r
187         configASSERT( xSyncTask2 );\r
188 \r
189         /* Create the event group used by the ISR tests.  The event group used by\r
190         the tasks is created by the tasks themselves. */\r
191         xISREventGroup = xEventGroupCreate();\r
192         configASSERT( xISREventGroup );\r
193 }\r
194 /*-----------------------------------------------------------*/\r
195 \r
196 static void prvTestMasterTask( void *pvParameters )\r
197 {\r
198 BaseType_t xError;\r
199 \r
200 /* The handle to the slave task is passed in as the task parameter. */\r
201 TaskHandle_t xTestSlaveTaskHandle = ( TaskHandle_t ) pvParameters;\r
202 \r
203         /* Avoid compiler warnings. */\r
204         ( void ) pvParameters;\r
205 \r
206         /* Create the event group used by the tasks ready for the initial tests. */\r
207         xEventGroup = xEventGroupCreate();\r
208         configASSERT( xEventGroup );\r
209 \r
210         /* Perform the tests that block two tasks on different combinations of bits,\r
211         then set each bit in turn and check the correct tasks unblock at the correct\r
212         times. */\r
213         xError = prvSelectiveBitsTestMasterFunction();\r
214 \r
215         for( ;; )\r
216         {\r
217                 /* Recreate the event group ready for the next cycle. */\r
218                 xEventGroup = xEventGroupCreate();\r
219                 configASSERT( xEventGroup );\r
220 \r
221                 /* Perform the tests that check the behaviour when a single task is\r
222                 blocked on various combinations of event bits. */\r
223                 xError = prvBitCombinationTestMasterFunction( xError, xTestSlaveTaskHandle );\r
224 \r
225                 /* Perform the task synchronisation tests. */\r
226                 xError = prvPerformTaskSyncTests( xError, xTestSlaveTaskHandle );\r
227 \r
228                 /* Delete the event group. */\r
229                 vEventGroupDelete( xEventGroup );\r
230 \r
231                 /* Now all the other tasks should have completed and suspended\r
232                 themselves ready for the next go around the loop. */\r
233                 if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )\r
234                 {\r
235                         xError = pdTRUE;\r
236                 }\r
237 \r
238                 if( eTaskGetState( xSyncTask1 ) != eSuspended )\r
239                 {\r
240                         xError = pdTRUE;\r
241                 }\r
242 \r
243                 if( eTaskGetState( xSyncTask2 ) != eSuspended )\r
244                 {\r
245                         xError = pdTRUE;\r
246                 }\r
247 \r
248                 /* Only increment the cycle variable if no errors have been detected. */\r
249                 if( xError == pdFALSE )\r
250                 {\r
251                         ulTestMasterCycles++;\r
252                 }\r
253 \r
254                 configASSERT( xError == pdFALSE );\r
255         }\r
256 }\r
257 /*-----------------------------------------------------------*/\r
258 \r
259 static void prvSyncTask( void *pvParameters )\r
260 {\r
261 EventBits_t uxSynchronisationBit, uxReturned;\r
262 \r
263         /* A few tests that check the behaviour when two tasks are blocked on\r
264         various different bits within an event group are performed before this task\r
265         enters its infinite loop to carry out its main demo function. */\r
266         prvSelectiveBitsTestSlaveFunction();\r
267 \r
268         /* The bit to use to indicate this task is at the synchronisation point is\r
269         passed in as the task parameter. */\r
270         uxSynchronisationBit = ( EventBits_t ) pvParameters;\r
271 \r
272         for( ;; )\r
273         {\r
274                 /* Now this task takes part in a task synchronisation - sometimes known\r
275                 as a 'rendezvous'.  Its execution pattern is controlled by the 'test\r
276                 master' task, which is responsible for taking this task out of the\r
277                 Suspended state when it is time to test the synchronisation behaviour.\r
278                 See: http://www.freertos.org/xEventGroupSync.html. */\r
279                 vTaskSuspend( NULL );\r
280 \r
281                 /* Set the bit that indicates this task is at the synchronisation\r
282                 point.  The first time this is done the 'test master' task has a lower\r
283                 priority than this task so this task will get to the sync point before\r
284                 the set bits task. */\r
285                 uxReturned = xEventGroupSync( xEventGroup,      /* The event group used for the synchronisation. */\r
286                                                                         uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */\r
287                                                                         ebALL_SYNC_BITS,/* The bits to wait for - these bits are set by the other tasks taking part in the sync. */\r
288                                                                         portMAX_DELAY );/* The maximum time to wait for the sync condition to be met before giving up. */\r
289 \r
290                 /* A max delay was used, so this task should only exit the above\r
291                 function call when the sync condition is met.  Check this is the\r
292                 case. */\r
293                 configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS );\r
294 \r
295                 /* Remove compiler warning if configASSERT() is not defined. */\r
296                 ( void ) uxReturned;\r
297 \r
298                 /* Wait until the 'test master' task unsuspends this task again. */\r
299                 vTaskSuspend( NULL );\r
300 \r
301                 /* Set the bit that indicates this task is at the synchronisation\r
302                 point again.  This time the 'test master' task has a higher priority\r
303                 than this task so will get to the sync point before this task. */\r
304                 uxReturned = xEventGroupSync( xEventGroup, uxSynchronisationBit, ebALL_SYNC_BITS, portMAX_DELAY );\r
305 \r
306                 /* Again a max delay was used, so this task should only exit the above\r
307                 function call when the sync condition is met.  Check this is the\r
308                 case. */\r
309                 configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS );\r
310 \r
311                 /* Block on the event group again.  This time the event group is going\r
312                 to be deleted while this task is blocked on it so it is expected that 0\r
313                 be returned. */\r
314                 uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY );\r
315                 configASSERT( uxReturned == 0 );\r
316         }\r
317 }\r
318 /*-----------------------------------------------------------*/\r
319 \r
320 static void prvTestSlaveTask( void *pvParameters )\r
321 {\r
322 EventBits_t uxReturned;\r
323 BaseType_t xError = pdFALSE;\r
324 \r
325         /* Avoid compiler warnings. */\r
326         ( void ) pvParameters;\r
327 \r
328         for( ;; )\r
329         {\r
330                 /**********************************************************************\r
331                 * Part 1:  This section is the counterpart to the\r
332                 * prvBitCombinationTestMasterFunction() function which is called by the\r
333                 * test master task.\r
334                 ***********************************************************************\r
335 \r
336                 This task is controller by the 'test master' task (which is\r
337                 implemented by prvTestMasterTask()).  Suspend until resumed by the\r
338                 'test master' task. */\r
339                 vTaskSuspend( NULL );\r
340 \r
341                 /* Wait indefinitely for one of the bits in ebCOMBINED_BITS to get\r
342                 set.  Clear the bit on exit. */\r
343                 uxReturned = xEventGroupWaitBits( xEventGroup,  /* The event group that contains the event bits being queried. */\r
344                                                                                  ebBIT_1,               /* The bit to wait for. */\r
345                                                                                  pdTRUE,                /* Clear the bit on exit. */\r
346                                                                                  pdTRUE,                /* Wait for all the bits (only one in this case anyway). */\r
347                                                                                  portMAX_DELAY ); /* Block indefinitely to wait for the condition to be met. */\r
348 \r
349                 /* The 'test master' task set all the bits defined by ebCOMBINED_BITS,\r
350                 only one of which was being waited for by this task.  The return value\r
351                 shows the state of the event bits when the task was unblocked, however\r
352                 because the task was waiting for ebBIT_1 and 'clear on exit' was set to\r
353                 the current state of the event bits will have ebBIT_1 clear.  */\r
354                 if( uxReturned != ebCOMBINED_BITS )\r
355                 {\r
356                         xError = pdTRUE;\r
357                 }\r
358 \r
359                 /* Now call xEventGroupWaitBits() again, this time waiting for all the\r
360                 bits in ebCOMBINED_BITS to be set.  This call should block until the\r
361                 'test master' task sets ebBIT_1 - which was the bit cleared in the call\r
362                 to xEventGroupWaitBits() above. */\r
363                 uxReturned = xEventGroupWaitBits( xEventGroup,\r
364                                                                                  ebCOMBINED_BITS, /* The bits being waited on. */\r
365                                                                                  pdFALSE,                 /* Don't clear the bits on exit. */\r
366                                                                                  pdTRUE,                  /* All the bits must be set to unblock. */\r
367                                                                                  portMAX_DELAY );\r
368 \r
369                 /* Were all the bits set? */\r
370                 if( ( uxReturned & ebCOMBINED_BITS ) != ebCOMBINED_BITS )\r
371                 {\r
372                         xError = pdTRUE;\r
373                 }\r
374 \r
375                 /* Suspend again to wait for the 'test master' task. */\r
376                 vTaskSuspend( NULL );\r
377 \r
378                 /* Now call xEventGroupWaitBits() again, again waiting for all the bits\r
379                 in ebCOMBINED_BITS to be set, but this time clearing the bits when the\r
380                 task is unblocked. */\r
381                 uxReturned = xEventGroupWaitBits( xEventGroup,\r
382                                                                          ebCOMBINED_BITS, /* The bits being waited on. */\r
383                                                                          pdTRUE,                  /* Clear the bits on exit. */\r
384                                                                          pdTRUE,                  /* All the bits must be set to unblock. */\r
385                                                                          portMAX_DELAY );\r
386 \r
387                 /* The 'test master' task set all the bits in the event group, so that\r
388                 is the value that should have been returned.  The bits defined by\r
389                 ebCOMBINED_BITS will have been clear again in the current value though\r
390                 as 'clear on exit' was set to pdTRUE. */\r
391                 if( uxReturned != ebALL_BITS )\r
392                 {\r
393                         xError = pdTRUE;\r
394                 }\r
395 \r
396 \r
397 \r
398 \r
399 \r
400                 /**********************************************************************\r
401                 * Part 2:  This section is the counterpart to the\r
402                 * prvPerformTaskSyncTests() function which is called by the\r
403                 * test master task.\r
404                 ***********************************************************************\r
405 \r
406 \r
407                 Once again wait for the 'test master' task to unsuspend this task\r
408                 when it is time for the next test. */\r
409                 vTaskSuspend( NULL );\r
410 \r
411                 /* Now peform a synchronisation with all the other tasks.  At this point\r
412                 the 'test master' task has the lowest priority so will get to the sync\r
413                 point after all the other synchronising tasks. */\r
414                 uxReturned = xEventGroupSync( xEventGroup,              /* The event group used for the sync. */\r
415                                                                         ebWAIT_BIT_TASK_SYNC_BIT, /* The bit in the event group used to indicate this task is at the sync point. */\r
416                                                                         ebALL_SYNC_BITS,        /* The bits to wait for.  These bits are set by the other tasks taking part in the sync. */\r
417                                                                         portMAX_DELAY );        /* The maximum time to wait for the sync condition to be met before giving up. */\r
418 \r
419                 /* A sync with a max delay should only exit when all the synchronisation\r
420                 bits are set... */\r
421                 if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )\r
422                 {\r
423                         xError = pdTRUE;\r
424                 }\r
425 \r
426                 /* ...but now the synchronisation bits should be clear again.  Read back\r
427                 the current value of the bits within the event group to check that is\r
428                 the case.  Setting the bits to zero will return the bits previous value\r
429                 then leave all the bits clear. */\r
430                 if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 )\r
431                 {\r
432                         xError = pdTRUE;\r
433                 }\r
434 \r
435                 /* Check the bits are indeed 0 now by simply reading then. */\r
436                 if( xEventGroupGetBits( xEventGroup ) != 0 )\r
437                 {\r
438                         xError = pdTRUE;\r
439                 }\r
440 \r
441                 if( xError == pdFALSE )\r
442                 {\r
443                         /* This task is still cycling without finding an error. */\r
444                         ulTestSlaveCycles++;\r
445                 }\r
446 \r
447                 vTaskSuspend( NULL );\r
448 \r
449                 /* This time sync when the 'test master' task has the highest priority\r
450                 at the point where it sets its sync bit - so this time the 'test master'\r
451                 task will get to the sync point before this task. */\r
452                 uxReturned = xEventGroupSync( xEventGroup, ebWAIT_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY );\r
453 \r
454                 /* A sync with a max delay should only exit when all the synchronisation\r
455                 bits are set... */\r
456                 if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )\r
457                 {\r
458                         xError = pdTRUE;\r
459                 }\r
460 \r
461                 /* ...but now the sync bits should be clear again. */\r
462                 if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 )\r
463                 {\r
464                         xError = pdTRUE;\r
465                 }\r
466 \r
467                 /* Block on the event group again.  This time the event group is going\r
468                 to be deleted while this task is blocked on it, so it is expected that 0\r
469                 will be returned. */\r
470                 uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY );\r
471 \r
472                 if( uxReturned != 0 )\r
473                 {\r
474                         xError = pdTRUE;\r
475                 }\r
476 \r
477                 if( xError == pdFALSE )\r
478                 {\r
479                         /* This task is still cycling without finding an error. */\r
480                         ulTestSlaveCycles++;\r
481                 }\r
482 \r
483                 configASSERT( xError == pdFALSE );\r
484         }\r
485 }\r
486 /*-----------------------------------------------------------*/\r
487 \r
488 static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle )\r
489 {\r
490 EventBits_t uxBits;\r
491 \r
492         /* The three tasks that take part in the synchronisation (rendezvous) are\r
493         expected to be in the suspended state at the start of the test. */\r
494         if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )\r
495         {\r
496                 xError = pdTRUE;\r
497         }\r
498 \r
499         if( eTaskGetState( xSyncTask1 ) != eSuspended )\r
500         {\r
501                 xError = pdTRUE;\r
502         }\r
503 \r
504         if( eTaskGetState( xSyncTask2 ) != eSuspended )\r
505         {\r
506                 xError = pdTRUE;\r
507         }\r
508 \r
509         /* Try a synch with no other tasks involved.  First set all the bits other\r
510         than this task's bit. */\r
511         xEventGroupSetBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) );\r
512 \r
513         /* Then wait on just one bit - the bit that is being set. */\r
514         uxBits = xEventGroupSync( xEventGroup,                  /* The event group used for the synchronisation. */\r
515                                                         ebSET_BIT_TASK_SYNC_BIT,/* The bit set by this task when it reaches the sync point. */\r
516                                                         ebSET_BIT_TASK_SYNC_BIT,/* The bits to wait for - in this case it is just waiting for itself. */\r
517                                                         portMAX_DELAY );                /* The maximum time to wait for the sync condition to be met. */\r
518 \r
519         /* A sync with a max delay should only exit when all the synchronise\r
520         bits are set...check that is the case.  In this case there is only one\r
521         sync bit anyway. */\r
522         if( ( uxBits & ebSET_BIT_TASK_SYNC_BIT ) != ebSET_BIT_TASK_SYNC_BIT )\r
523         {\r
524                 xError = pdTRUE;\r
525         }\r
526 \r
527         /* ...but now the sync bits should be clear again, leaving all the other\r
528         bits set (as only one bit was being waited for). */\r
529         if( xEventGroupGetBits( xEventGroup ) != ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) )\r
530         {\r
531                 xError = pdTRUE;\r
532         }\r
533 \r
534         /* Clear all the bits to zero again. */\r
535         xEventGroupClearBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) );\r
536         if( xEventGroupGetBits( xEventGroup ) != 0 )\r
537         {\r
538                 xError = pdTRUE;\r
539         }\r
540 \r
541         /* Unsuspend the other tasks then check they have executed up to the\r
542         synchronisation point. */\r
543         vTaskResume( xTestSlaveTaskHandle );\r
544         vTaskResume( xSyncTask1 );\r
545         vTaskResume( xSyncTask2 );\r
546 \r
547         if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )\r
548         {\r
549                 xError = pdTRUE;\r
550         }\r
551 \r
552         if( eTaskGetState( xSyncTask1 ) != eBlocked )\r
553         {\r
554                 xError = pdTRUE;\r
555         }\r
556 \r
557         if( eTaskGetState( xSyncTask2 ) != eBlocked )\r
558         {\r
559                 xError = pdTRUE;\r
560         }\r
561 \r
562         /* Set this task's sync bit. */\r
563         uxBits = xEventGroupSync( xEventGroup,                  /* The event group used for the synchronisation. */\r
564                                                         ebSET_BIT_TASK_SYNC_BIT,/* The bit set by this task when it reaches the sync point. */\r
565                                                         ebALL_SYNC_BITS,                /* The bits to wait for - these bits are set by the other tasks that take part in the sync. */\r
566                                                         portMAX_DELAY );                /* The maximum time to wait for the sync condition to be met. */\r
567 \r
568         /* A sync with a max delay should only exit when all the synchronise\r
569         bits are set...check that is the case. */\r
570         if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )\r
571         {\r
572                 xError = pdTRUE;\r
573         }\r
574 \r
575         /* ...but now the sync bits should be clear again. */\r
576         if( xEventGroupGetBits( xEventGroup ) != 0 )\r
577         {\r
578                 xError = pdTRUE;\r
579         }\r
580 \r
581 \r
582         /* The other tasks should now all be suspended again, ready for the next\r
583         synchronisation. */\r
584         if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )\r
585         {\r
586                 xError = pdTRUE;\r
587         }\r
588 \r
589         if( eTaskGetState( xSyncTask1 ) != eSuspended )\r
590         {\r
591                 xError = pdTRUE;\r
592         }\r
593 \r
594         if( eTaskGetState( xSyncTask2 ) != eSuspended )\r
595         {\r
596                 xError = pdTRUE;\r
597         }\r
598 \r
599 \r
600         /* Sync again - but this time set the last necessary bit as the\r
601         highest priority task, rather than the lowest priority task.  Unsuspend\r
602         the other tasks then check they have executed up to the synchronisation\r
603         point. */\r
604         vTaskResume( xTestSlaveTaskHandle );\r
605         vTaskResume( xSyncTask1 );\r
606         vTaskResume( xSyncTask2 );\r
607 \r
608         if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )\r
609         {\r
610                 xError = pdTRUE;\r
611         }\r
612 \r
613         if( eTaskGetState( xSyncTask1 ) != eBlocked )\r
614         {\r
615                 xError = pdTRUE;\r
616         }\r
617 \r
618         if( eTaskGetState( xSyncTask2 ) != eBlocked )\r
619         {\r
620                 xError = pdTRUE;\r
621         }\r
622 \r
623         /* Raise the priority of this task above that of the other tasks. */\r
624         vTaskPrioritySet( NULL, ebWAIT_BIT_TASK_PRIORITY + 1 );\r
625 \r
626         /* Set this task's sync bit. */\r
627         uxBits = xEventGroupSync( xEventGroup, ebSET_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY );\r
628 \r
629         /* A sync with a max delay should only exit when all the synchronisation\r
630         bits are set... */\r
631         if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )\r
632         {\r
633                 xError = pdTRUE;\r
634         }\r
635 \r
636         /* ...but now the sync bits should be clear again. */\r
637         if( xEventGroupGetBits( xEventGroup ) != 0 )\r
638         {\r
639                 xError = pdTRUE;\r
640         }\r
641 \r
642 \r
643         /* The other tasks should now all be in the ready state again, but not\r
644         executed yet as this task still has a higher relative priority. */\r
645         if( eTaskGetState( xTestSlaveTaskHandle ) != eReady )\r
646         {\r
647                 xError = pdTRUE;\r
648         }\r
649 \r
650         if( eTaskGetState( xSyncTask1 ) != eReady )\r
651         {\r
652                 xError = pdTRUE;\r
653         }\r
654 \r
655         if( eTaskGetState( xSyncTask2 ) != eReady )\r
656         {\r
657                 xError = pdTRUE;\r
658         }\r
659 \r
660 \r
661         /* Reset the priority of this task back to its original value. */\r
662         vTaskPrioritySet( NULL, ebSET_BIT_TASK_PRIORITY );\r
663 \r
664         /* Now all the other tasks should have reblocked on the event bits\r
665         to test the behaviour when the event bits are deleted. */\r
666         if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )\r
667         {\r
668                 xError = pdTRUE;\r
669         }\r
670 \r
671         if( eTaskGetState( xSyncTask1 ) != eBlocked )\r
672         {\r
673                 xError = pdTRUE;\r
674         }\r
675 \r
676         if( eTaskGetState( xSyncTask2 ) != eBlocked )\r
677         {\r
678                 xError = pdTRUE;\r
679         }\r
680 \r
681         return xError;\r
682 }\r
683 /*-----------------------------------------------------------*/\r
684 \r
685 static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle )\r
686 {\r
687 EventBits_t uxBits;\r
688 \r
689         /* Resume the other task.  It will block, pending a single bit from\r
690         within ebCOMBINED_BITS. */\r
691         vTaskResume( xTestSlaveTaskHandle );\r
692 \r
693         /* Ensure the other task is blocked on the task. */\r
694         if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )\r
695         {\r
696                 xError = pdTRUE;\r
697         }\r
698 \r
699         /* Set all the bits in ebCOMBINED_BITS - the 'test slave' task is only\r
700         blocked waiting for one of them. */\r
701         xEventGroupSetBits( xEventGroup, ebCOMBINED_BITS );\r
702 \r
703         /* The 'test slave' task should now have executed, clearing ebBIT_1 (the\r
704         bit it was blocked on), then re-entered the Blocked state to wait for\r
705         all the other bits in ebCOMBINED_BITS to be set again.  First check\r
706         ebBIT_1 is clear. */\r
707         uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK );\r
708 \r
709         if( uxBits != ( ebCOMBINED_BITS & ~ebBIT_1 ) )\r
710         {\r
711                 xError = pdTRUE;\r
712         }\r
713 \r
714         /* Ensure the other task is still in the blocked state. */\r
715         if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )\r
716         {\r
717                 xError = pdTRUE;\r
718         }\r
719 \r
720         /* Set all the bits other than ebBIT_1 - which is the bit that must be\r
721         set before the other task unblocks. */\r
722         xEventGroupSetBits( xEventGroup, ebALL_BITS & ~ebBIT_1 );\r
723 \r
724         /* Ensure all the expected bits are still set. */\r
725         uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK );\r
726 \r
727         if( uxBits != ( ebALL_BITS & ~ebBIT_1 ) )\r
728         {\r
729                 xError = pdTRUE;\r
730         }\r
731 \r
732         /* Ensure the other task is still in the blocked state. */\r
733         if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )\r
734         {\r
735                 xError = pdTRUE;\r
736         }\r
737 \r
738         /* Now also set ebBIT_1, which should unblock the other task, which will\r
739         then suspend itself. */\r
740         xEventGroupSetBits( xEventGroup, ebBIT_1 );\r
741 \r
742         /* Ensure the other task is suspended. */\r
743         if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )\r
744         {\r
745                 xError = pdTRUE;\r
746         }\r
747 \r
748         /* The other task should not have cleared the bits - so all the bits\r
749         should still be set. */\r
750         if( xEventGroupSetBits( xEventGroup, 0x00 ) != ebALL_BITS )\r
751         {\r
752                 xError = pdTRUE;\r
753         }\r
754 \r
755         /* Clear ebBIT_1 again. */\r
756         if( xEventGroupClearBits( xEventGroup, ebBIT_1 ) != ebALL_BITS )\r
757         {\r
758                 xError = pdTRUE;\r
759         }\r
760 \r
761         /* Resume the other task - which will wait on all the ebCOMBINED_BITS\r
762         again - this time clearing the bits when it is unblocked. */\r
763         vTaskResume( xTestSlaveTaskHandle );\r
764 \r
765         /* Ensure the other task is blocked once again. */\r
766         if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )\r
767         {\r
768                 xError = pdTRUE;\r
769         }\r
770 \r
771         /* Set the bit the other task is waiting for. */\r
772         xEventGroupSetBits( xEventGroup, ebBIT_1 );\r
773 \r
774         /* Ensure the other task is suspended once again. */\r
775         if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )\r
776         {\r
777                 xError = pdTRUE;\r
778         }\r
779 \r
780         /* The other task should have cleared the bits in ebCOMBINED_BITS.\r
781         Clear the remaining bits. */\r
782         uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK );\r
783 \r
784         if( uxBits != ( ebALL_BITS & ~ebCOMBINED_BITS ) )\r
785         {\r
786                 xError = pdTRUE;\r
787         }\r
788 \r
789         /* Clear all bits ready for the sync with the other three tasks.  The\r
790         value returned is the value prior to the bits being cleared. */\r
791         if( xEventGroupClearBits( xEventGroup, ebALL_BITS ) != ( ebALL_BITS & ~ebCOMBINED_BITS ) )\r
792         {\r
793                 xError = pdTRUE;\r
794         }\r
795 \r
796         /* The bits should be clear now. */\r
797         if( xEventGroupGetBits( xEventGroup ) != 0x00 )\r
798         {\r
799                 xError = pdTRUE;\r
800         }\r
801 \r
802         return xError;\r
803 }\r
804 /*-----------------------------------------------------------*/\r
805 \r
806 static void prvSelectiveBitsTestSlaveFunction( void )\r
807 {\r
808 EventBits_t uxPendBits, uxReturned;\r
809 \r
810         /* Used in a test that blocks two tasks on various different bits within an\r
811         event group - then sets each bit in turn and checks that the correct tasks\r
812         unblock at the correct times.\r
813 \r
814         This function is called by two different tasks - each of which will use a\r
815         different bit.  Check the task handle to see which task the function was\r
816         called by. */\r
817         if( xTaskGetCurrentTaskHandle() == xSyncTask1 )\r
818         {\r
819                 uxPendBits = ebSELECTIVE_BITS_1;\r
820         }\r
821         else\r
822         {\r
823                 uxPendBits = ebSELECTIVE_BITS_2;\r
824         }\r
825 \r
826         for( ;; )\r
827         {\r
828                 /* Wait until it is time to perform the next cycle of the test.  The\r
829                 task is unsuspended by the tests implemented in the\r
830                 prvSelectiveBitsTestMasterFunction() function. */\r
831                 vTaskSuspend( NULL );\r
832                 uxReturned = xEventGroupWaitBits( xEventGroup, uxPendBits, pdTRUE, pdFALSE, portMAX_DELAY );\r
833 \r
834                 if( uxReturned == ( EventBits_t ) 0 )\r
835                 {\r
836                         break;\r
837                 }\r
838         }\r
839 }\r
840 /*-----------------------------------------------------------*/\r
841 \r
842 static BaseType_t prvSelectiveBitsTestMasterFunction( void )\r
843 {\r
844 BaseType_t xError = pdFALSE;\r
845 EventBits_t uxBit;\r
846 \r
847         /* Used in a test that blocks two tasks on various different bits within an\r
848         event group - then sets each bit in turn and checks that the correct tasks\r
849         unblock at the correct times.  The two other tasks (xSyncTask1 and\r
850         xSyncTask2) call prvSelectiveBitsTestSlaveFunction() to perform their parts in\r
851         this test.\r
852 \r
853         Both other tasks should start in the suspended state. */\r
854         if( eTaskGetState( xSyncTask1 ) != eSuspended )\r
855         {\r
856                 xError = pdTRUE;\r
857         }\r
858 \r
859         if( eTaskGetState( xSyncTask2 ) != eSuspended )\r
860         {\r
861                 xError = pdTRUE;\r
862         }\r
863 \r
864         /* Test each bit in the byte individually. */\r
865         for( uxBit = 0x01; uxBit < 0x100; uxBit <<= 1 )\r
866         {\r
867                 /* Resume both tasks. */\r
868                 vTaskResume( xSyncTask1 );\r
869                 vTaskResume( xSyncTask2 );\r
870 \r
871                 /* Now both tasks should be blocked on the event group. */\r
872                 if( eTaskGetState( xSyncTask1 ) != eBlocked )\r
873                 {\r
874                         xError = pdTRUE;\r
875                 }\r
876 \r
877                 if( eTaskGetState( xSyncTask2 ) != eBlocked )\r
878                 {\r
879                         xError = pdTRUE;\r
880                 }\r
881 \r
882                 /* Set one bit. */\r
883                 xEventGroupSetBits( xEventGroup, uxBit );\r
884 \r
885                 /* Is the bit set in the first set of selective bits?  If so the first\r
886                 sync task should have unblocked and returned to the suspended state. */\r
887                 if( ( uxBit & ebSELECTIVE_BITS_1 ) == 0 )\r
888                 {\r
889                         /* Task should not have unblocked. */\r
890                         if( eTaskGetState( xSyncTask1 ) != eBlocked )\r
891                         {\r
892                                 xError = pdTRUE;\r
893                         }\r
894                 }\r
895                 else\r
896                 {\r
897                         /* Task should have unblocked and returned to the suspended state. */\r
898                         if( eTaskGetState( xSyncTask1 ) != eSuspended )\r
899                         {\r
900                                 xError = pdTRUE;\r
901                         }\r
902                 }\r
903 \r
904                 /* Same checks for the second sync task. */\r
905                 if( ( uxBit & ebSELECTIVE_BITS_2 ) == 0 )\r
906                 {\r
907                         /* Task should not have unblocked. */\r
908                         if( eTaskGetState( xSyncTask2 ) != eBlocked )\r
909                         {\r
910                                 xError = pdTRUE;\r
911                         }\r
912                 }\r
913                 else\r
914                 {\r
915                         /* Task should have unblocked and returned to the suspended state. */\r
916                         if( eTaskGetState( xSyncTask2 ) != eSuspended )\r
917                         {\r
918                                 xError = pdTRUE;\r
919                         }\r
920                 }\r
921         }\r
922 \r
923         /* Ensure both tasks are blocked on the event group again, then delete the\r
924         event group so the other tasks leave this portion of the test. */\r
925         vTaskResume( xSyncTask1 );\r
926         vTaskResume( xSyncTask2 );\r
927 \r
928         /* Deleting the event group is the signal that the two other tasks should\r
929         leave the prvSelectiveBitsTestSlaveFunction() function and continue to the main\r
930         part of their functionality. */\r
931         vEventGroupDelete( xEventGroup );\r
932 \r
933         return xError;\r
934 }\r
935 /*-----------------------------------------------------------*/\r
936 \r
937 void vPeriodicEventGroupsProcessing( void )\r
938 {\r
939 static BaseType_t xCallCount = 0, xISRTestError = pdFALSE;\r
940 const BaseType_t xSetBitCount = 100, xGetBitsCount = 200, xClearBitsCount = 300;\r
941 const EventBits_t uxBitsToSet = 0x12U;\r
942 EventBits_t uxReturned;\r
943 BaseType_t xMessagePosted;\r
944 \r
945         /* Called periodically from the tick hook to exercise the "FromISR"\r
946         functions. */\r
947 \r
948         xCallCount++;\r
949 \r
950         if( xCallCount == xSetBitCount )\r
951         {\r
952                 /* All the event bits should start clear. */\r
953                 uxReturned = xEventGroupGetBitsFromISR( xISREventGroup );\r
954                 if( uxReturned != 0x00 )\r
955                 {\r
956                         xISRTestError = pdTRUE;\r
957                 }\r
958                 else\r
959                 {\r
960                         /* Set the bits.  This is called from the tick hook so it is not\r
961                         necessary to use the last parameter to ensure a context switch\r
962                         occurs immediately. */\r
963                         xMessagePosted = xEventGroupSetBitsFromISR( xISREventGroup, uxBitsToSet, NULL );\r
964                         if( xMessagePosted != pdPASS )\r
965                         {\r
966                                 xISRTestError = pdTRUE;\r
967                         }\r
968                 }\r
969         }\r
970         else if( xCallCount == xGetBitsCount )\r
971         {\r
972                 /* Check the bits were set as expected. */\r
973                 uxReturned = xEventGroupGetBitsFromISR( xISREventGroup );\r
974                 if( uxReturned != uxBitsToSet )\r
975                 {\r
976                         xISRTestError = pdTRUE;\r
977                 }\r
978         }\r
979         else if( xCallCount == xClearBitsCount )\r
980         {\r
981                 /* Clear the bits again. */\r
982                 uxReturned = ( EventBits_t ) xEventGroupClearBitsFromISR( xISREventGroup, uxBitsToSet );\r
983 \r
984                 /* Check the message was posted. */\r
985                 if( uxReturned != pdPASS )\r
986                 {\r
987                         xISRTestError = pdTRUE;\r
988                 }\r
989 \r
990                 /* Go back to the start. */\r
991                 xCallCount = 0;\r
992 \r
993                 /* If no errors have been detected then increment the count of test\r
994                 cycles. */\r
995                 if( xISRTestError == pdFALSE )\r
996                 {\r
997                         ulISRCycles++;\r
998                 }\r
999         }\r
1000         else\r
1001         {\r
1002                 /* Nothing else to do. */\r
1003         }\r
1004 }\r
1005 \r
1006 /*-----------------------------------------------------------*/\r
1007 /* This is called to check that all the created tasks are still running. */\r
1008 BaseType_t xAreEventGroupTasksStillRunning( void )\r
1009 {\r
1010 static uint32_t ulPreviousWaitBitCycles = 0, ulPreviousSetBitCycles = 0, ulPreviousISRCycles = 0;\r
1011 BaseType_t xStatus = pdPASS;\r
1012 \r
1013         /* Check the tasks are still cycling without finding any errors. */\r
1014         if( ulPreviousSetBitCycles == ulTestMasterCycles )\r
1015         {\r
1016                 xStatus = pdFAIL;\r
1017         }\r
1018         ulPreviousSetBitCycles = ulTestMasterCycles;\r
1019 \r
1020         if( ulPreviousWaitBitCycles == ulTestSlaveCycles )\r
1021         {\r
1022                 xStatus = pdFAIL;\r
1023         }\r
1024         ulPreviousWaitBitCycles = ulTestSlaveCycles;\r
1025 \r
1026         if( ulPreviousISRCycles == ulISRCycles )\r
1027         {\r
1028                 xStatus = pdFAIL;\r
1029         }\r
1030         ulPreviousISRCycles = ulISRCycles;\r
1031 \r
1032         return xStatus;\r
1033 }\r
1034 \r
1035 \r
1036 \r