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