]> git.sur5r.net Git - freertos/blob - Demo/Cygnal/main.c
Ready for V5.2.0 release.
[freertos] / Demo / Cygnal / main.c
1 /*\r
2         FreeRTOS.org V5.2.0 - Copyright (C) 2003-2009 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \r
6         FreeRTOS.org is free software; you can redistribute it and/or modify it \r
7         under the terms of the GNU General Public License (version 2) as published\r
8         by the Free Software Foundation and modified by the FreeRTOS exception.\r
9 \r
10         FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT\r
11         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \r
12         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for \r
13         more details.\r
14 \r
15         You should have received a copy of the GNU General Public License along \r
16         with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59 \r
17         Temple Place, Suite 330, Boston, MA  02111-1307  USA.\r
18 \r
19         A special exception to the GPL is included to allow you to distribute a \r
20         combined work that includes FreeRTOS.org without being obliged to provide\r
21         the source code for any proprietary components.  See the licensing section\r
22         of http://www.FreeRTOS.org for full details.\r
23 \r
24 \r
25         ***************************************************************************\r
26         *                                                                         *\r
27         * Get the FreeRTOS eBook!  See http://www.FreeRTOS.org/Documentation      *\r
28         *                                                                         *\r
29         * This is a concise, step by step, 'hands on' guide that describes both   *\r
30         * general multitasking concepts and FreeRTOS specifics. It presents and   *\r
31         * explains numerous examples that are written using the FreeRTOS API.     *\r
32         * Full source code for all the examples is provided in an accompanying    *\r
33         * .zip file.                                                              *\r
34         *                                                                         *\r
35         ***************************************************************************\r
36 \r
37         1 tab == 4 spaces!\r
38 \r
39         Please ensure to read the configuration and relevant port sections of the\r
40         online documentation.\r
41 \r
42         http://www.FreeRTOS.org - Documentation, latest information, license and\r
43         contact details.\r
44 \r
45         http://www.SafeRTOS.com - A version that is certified for use in safety\r
46         critical systems.\r
47 \r
48         http://www.OpenRTOS.com - Commercial support, development, porting,\r
49         licensing and training services.\r
50 */\r
51 \r
52 /*\r
53  * Creates the demo application tasks, then starts the scheduler.  The WEB\r
54  * documentation provides more details of the demo application tasks.\r
55  * \r
56  * Main. c also creates four other tasks:\r
57  * \r
58  * 1) vErrorChecks()\r
59  * This only executes every few seconds but has the highest priority so is \r
60  * guaranteed to get processor time.  Its main function is to check that all \r
61  * the standard demo application tasks are still operational and have not\r
62  * experienced any errors.  vErrorChecks() will toggle the on board LED\r
63  * every mainNO_ERROR_FLASH_PERIOD milliseconds if none of the demo application\r
64  * tasks have reported an error.  Should any task report an error at any time\r
65  * the rate at which the on board LED is toggled is increased to \r
66  * mainERROR_FLASH_PERIOD - providing visual feedback that something has gone\r
67  * wrong.\r
68  *\r
69  * 2) vRegisterCheck()\r
70  * This is a very simple task that checks that all the registers are always\r
71  * in their expected state.  The task only makes use of the A register, so\r
72  * all the other registers should always contain their initial values.\r
73  * An incorrect value indicates an error in the context switch mechanism.\r
74  * The task operates at the idle priority so will be preempted regularly.\r
75  * Any error will cause the toggle rate of the on board LED to increase to\r
76  * mainERROR_FLASH_PERIOD milliseconds.\r
77  *\r
78  * 3 and 4) vFLOPCheck1() and vFLOPCheck2()\r
79  * These are very basic versions of the standard FLOP tasks.  They are good\r
80  * at detecting errors in the context switch mechanism, and also check that\r
81  * the floating point libraries are correctly built to be re-enterant.  The\r
82  * stack restrictions of the 8051 prevent the use of the standard FLOP demo\r
83  * tasks.\r
84  */\r
85 \r
86 /* Standard includes. */\r
87 #include <stdlib.h>\r
88 \r
89 /* Scheduler includes. */\r
90 #include "FreeRTOS.h"\r
91 #include "task.h"\r
92 \r
93 /* Demo application includes. */\r
94 #include "partest.h"\r
95 #include "flash.h"\r
96 #include "integer.h"\r
97 #include "PollQ.h"\r
98 #include "comtest2.h"\r
99 #include "semtest.h"\r
100 \r
101 /* Demo task priorities. */\r
102 #define mainLED_TASK_PRIORITY           ( tskIDLE_PRIORITY + 1 )\r
103 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 2 )\r
104 #define mainCOM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 2 )\r
105 #define mainCHECK_TASK_PRIORITY         ( tskIDLE_PRIORITY + 3 )\r
106 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 2 )\r
107 #define mainINTEGER_PRIORITY            tskIDLE_PRIORITY\r
108 \r
109 /* Constants required to disable the watchdog. */\r
110 #define mainDISABLE_BYTE_1                      ( ( unsigned portCHAR ) 0xde )\r
111 #define mainDISABLE_BYTE_2                      ( ( unsigned portCHAR ) 0xad )\r
112 \r
113 /* Constants to setup and use the on board LED. */\r
114 #define ucLED_BIT                                       ( ( unsigned portCHAR ) 0x40 )\r
115 #define mainPORT_1_BIT_6                        ( ( unsigned portCHAR ) 0x40 )\r
116 #define mainENABLE_CROSS_BAR            ( ( unsigned portCHAR ) 0x40 )\r
117 \r
118 /* Constants to set the clock frequency. */\r
119 #define mainSELECT_INTERNAL_OSC         ( ( unsigned portCHAR ) 0x80 )\r
120 #define mainDIVIDE_CLOCK_BY_1           ( ( unsigned portCHAR ) 0x03 )\r
121 #define mainPLL_USES_INTERNAL_OSC       ( ( unsigned portCHAR ) 0x04 )\r
122 #define mainFLASH_READ_TIMING           ( ( unsigned portCHAR ) 0x30 )\r
123 #define mainPLL_POWER_ON                        ( ( unsigned portCHAR ) 0x01 )\r
124 #define mainPLL_NO_PREDIVIDE            ( ( unsigned portCHAR ) 0x01 )\r
125 #define mainPLL_FILTER                          ( ( unsigned portCHAR ) 0x01 )\r
126 #define mainPLL_MULTIPLICATION          ( ( unsigned portCHAR ) 0x04 )\r
127 #define mainENABLE_PLL                          ( ( unsigned portCHAR ) 0x02 )\r
128 #define mainPLL_LOCKED                          ( ( unsigned portCHAR ) 0x10 )\r
129 #define mainSELECT_PLL_AS_SOURCE        ( ( unsigned portCHAR ) 0x02 )\r
130 \r
131 /* Toggle rate for the on board LED - which is dependent on whether or not\r
132 an error has been detected. */\r
133 #define mainNO_ERROR_FLASH_PERIOD       ( ( portTickType ) 5000 )\r
134 #define mainERROR_FLASH_PERIOD          ( ( portTickType ) 250 )\r
135 \r
136 /* Baud rate used by the serial port tasks. */\r
137 #define mainCOM_TEST_BAUD_RATE          ( ( unsigned portLONG ) 115200 )\r
138 \r
139 /* Pass an invalid LED number to the COM test task as we don't want it to flash\r
140 an LED.  There are only 8 LEDs (excluding the on board LED) wired in and these\r
141 are all used by the flash tasks. */\r
142 #define mainCOM_TEST_LED                        ( 200 )\r
143 \r
144 /* We want the Cygnal to act as much as possible as a standard 8052. */\r
145 #define mainAUTO_SFR_OFF                        ( ( unsigned portCHAR ) 0 )\r
146 \r
147 /* Constants required to setup the IO pins for serial comms. */\r
148 #define mainENABLE_COMS                         ( ( unsigned portCHAR ) 0x04 )\r
149 #define mainCOMS_LINES_TO_PUSH_PULL ( ( unsigned portCHAR ) 0x03 )\r
150 \r
151 /* Pointer passed as a parameter to vRegisterCheck() just so it has some know\r
152 values to check for in the DPH, DPL and B registers. */\r
153 #define mainDUMMY_POINTER               ( ( xdata void * ) 0xabcd )\r
154 \r
155 /* Macro that lets vErrorChecks() know that one of the tasks defined in\r
156 main. c has detected an error.  A critical region is used around xLatchError\r
157 as it is accessed from vErrorChecks(), which has a higher priority. */ \r
158 #define mainLATCH_ERROR()                       \\r
159 {                                                                       \\r
160         portENTER_CRITICAL();                   \\r
161                 xLatchedError = pdTRUE;         \\r
162         portEXIT_CRITICAL();                    \\r
163 }\r
164 \r
165 /*\r
166  * Setup the Cygnal microcontroller for its fastest operation. \r
167  */\r
168 static void prvSetupSystemClock( void );\r
169 \r
170 /*\r
171  * Setup the peripherals, including the on board LED. \r
172  */\r
173 static void prvSetupHardware( void );\r
174 \r
175 /*\r
176  * Toggle the state of the on board LED. \r
177  */\r
178 static void prvToggleOnBoardLED( void );\r
179 \r
180 /*\r
181  * See comments at the top of the file for details. \r
182  */\r
183 static void vErrorChecks( void *pvParameters );\r
184 \r
185 /*\r
186  * See comments at the top of the file for details. \r
187  */\r
188 static void vRegisterCheck( void *pvParameters );\r
189 \r
190 /*\r
191  * See comments at the top of the file for details. \r
192  */\r
193 static void vFLOPCheck1( void *pvParameters );\r
194 \r
195 /*\r
196  * See comments at the top of the file for details. \r
197  */\r
198 static void vFLOPCheck2( void *pvParameters );\r
199 \r
200 /* File scope variable used to communicate the occurrence of an error between\r
201 tasks. */\r
202 static portBASE_TYPE xLatchedError = pdFALSE;\r
203 \r
204 /*-----------------------------------------------------------*/\r
205 \r
206 /*\r
207  * Starts all the other tasks, then starts the scheduler. \r
208  */\r
209 void main( void )\r
210 {\r
211         /* Initialise the hardware including the system clock and on board\r
212         LED. */\r
213         prvSetupHardware();\r
214 \r
215         /* Initialise the port that controls the external LED's utilized by the\r
216         flash tasks. */\r
217         vParTestInitialise();\r
218 \r
219         /* Start the used standard demo tasks. */\r
220         vStartLEDFlashTasks( mainLED_TASK_PRIORITY );\r
221         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );\r
222         vStartIntegerMathTasks( mainINTEGER_PRIORITY );\r
223         vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );\r
224         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );\r
225 \r
226         /* Start the tasks defined in this file.  The first three never block so\r
227         must not be used with the co-operative scheduler. */\r
228         #if configUSE_PREEMPTION == 1\r
229         {\r
230                 xTaskCreate( vRegisterCheck, "RegChck", configMINIMAL_STACK_SIZE, mainDUMMY_POINTER, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
231                 xTaskCreate( vFLOPCheck1, "FLOP", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
232                 xTaskCreate( vFLOPCheck2, "FLOP", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );\r
233         }\r
234         #endif \r
235 \r
236         xTaskCreate( vErrorChecks, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, ( xTaskHandle * ) NULL );\r
237 \r
238         /* Finally kick off the scheduler.  This function should never return. */\r
239         vTaskStartScheduler();\r
240 \r
241         /* Should never reach here as the tasks will now be executing under control\r
242         of the scheduler. */\r
243 }\r
244 /*-----------------------------------------------------------*/\r
245 \r
246 /*\r
247  * Setup the hardware prior to using the scheduler.  Most of the Cygnal\r
248  * specific initialisation is performed here leaving standard 8052 setup\r
249  * only in the driver code.\r
250  */\r
251 static void prvSetupHardware( void )\r
252 {\r
253 unsigned portCHAR ucOriginalSFRPage;\r
254 \r
255         /* Remember the SFR page before it is changed so it can get set back\r
256         before the function exits. */\r
257         ucOriginalSFRPage = SFRPAGE;\r
258 \r
259         /* Setup the SFR page to access the config SFR's. */\r
260         SFRPAGE = CONFIG_PAGE;\r
261 \r
262         /* Don't allow the microcontroller to automatically switch SFR page, as the\r
263         SFR page is not stored as part of the task context. */\r
264         SFRPGCN = mainAUTO_SFR_OFF;\r
265 \r
266         /* Disable the watchdog. */\r
267         WDTCN = mainDISABLE_BYTE_1;\r
268         WDTCN = mainDISABLE_BYTE_2;\r
269 \r
270         /* Set the on board LED to push pull. */\r
271         P1MDOUT |= mainPORT_1_BIT_6;\r
272 \r
273         /* Setup the cross bar to enable serial comms here as it is not part of the \r
274         standard 8051 setup and therefore is not in the driver code. */\r
275         XBR0 |= mainENABLE_COMS;\r
276         P0MDOUT |= mainCOMS_LINES_TO_PUSH_PULL;\r
277 \r
278         /* Enable the cross bar so our hardware setup takes effect. */\r
279         XBR2 = mainENABLE_CROSS_BAR;\r
280 \r
281         /* Setup a fast system clock. */\r
282         prvSetupSystemClock();\r
283 \r
284         /* Return the SFR page. */\r
285         SFRPAGE = ucOriginalSFRPage;\r
286 }\r
287 /*-----------------------------------------------------------*/\r
288 \r
289 static void prvSetupSystemClock( void )\r
290 {\r
291 volatile unsigned portSHORT usWait;\r
292 const unsigned portSHORT usWaitTime = ( unsigned portSHORT ) 0x2ff;\r
293 unsigned portCHAR ucOriginalSFRPage;\r
294 \r
295         /* Remember the SFR page so we can set it back at the end. */\r
296         ucOriginalSFRPage = SFRPAGE;\r
297         SFRPAGE = CONFIG_PAGE;\r
298 \r
299         /* Use the internal oscillator set to its fasted frequency. */\r
300         OSCICN = mainSELECT_INTERNAL_OSC | mainDIVIDE_CLOCK_BY_1;\r
301 \r
302         /* Ensure the clock is stable. */\r
303         for( usWait = 0; usWait < usWaitTime; usWait++ );\r
304 \r
305         /* Setup the clock source for the PLL. */\r
306         PLL0CN &= ~mainPLL_USES_INTERNAL_OSC;\r
307 \r
308         /* Change the read timing for the flash ready for the fast clock. */\r
309         SFRPAGE = LEGACY_PAGE;\r
310         FLSCL |= mainFLASH_READ_TIMING;\r
311 \r
312         /* Turn on the PLL power. */\r
313         SFRPAGE = CONFIG_PAGE;\r
314         PLL0CN |= mainPLL_POWER_ON;\r
315 \r
316         /* Don't predivide the clock. */\r
317         PLL0DIV = mainPLL_NO_PREDIVIDE;\r
318 \r
319         /* Set filter for fastest clock. */\r
320         PLL0FLT = mainPLL_FILTER;\r
321         PLL0MUL = mainPLL_MULTIPLICATION;\r
322 \r
323         /* Ensure the clock is stable. */\r
324         for( usWait = 0; usWait < usWaitTime; usWait++ );\r
325 \r
326         /* Enable the PLL and wait for it to lock. */\r
327         PLL0CN |= mainENABLE_PLL;\r
328         for( usWait = 0; usWait < usWaitTime; usWait++ )\r
329         {\r
330                 if( PLL0CN & mainPLL_LOCKED )\r
331                 {\r
332                         break;\r
333                 }\r
334         }\r
335 \r
336         /* Select the PLL as the clock source. */\r
337         CLKSEL |= mainSELECT_PLL_AS_SOURCE;\r
338 \r
339         /* Return the SFR back to its original value. */\r
340         SFRPAGE = ucOriginalSFRPage;\r
341 }\r
342 /*-----------------------------------------------------------*/\r
343 \r
344 static void prvToggleOnBoardLED( void )\r
345 {\r
346         /* If the on board LED is on, turn it off and visa versa. */\r
347         if( P1 & ucLED_BIT )\r
348         {\r
349                 P1 &= ~ucLED_BIT;\r
350         }\r
351         else\r
352         {\r
353                 P1 |= ucLED_BIT;\r
354         }\r
355 }\r
356 /*-----------------------------------------------------------*/\r
357 \r
358 /*\r
359  * See the documentation at the top of this file. \r
360  */\r
361 static void vErrorChecks( void *pvParameters )\r
362 {\r
363 portBASE_TYPE xErrorHasOccurred = pdFALSE;\r
364         \r
365         /* Just to prevent compiler warnings. */\r
366         ( void ) pvParameters;\r
367         \r
368         /* Cycle for ever, delaying then checking all the other tasks are still\r
369         operating without error.   The delay period depends on whether an error\r
370         has ever been detected. */\r
371         for( ;; )\r
372         {\r
373                 if( xLatchedError == pdFALSE )\r
374                 {               \r
375                         /* No errors have been detected so delay for a longer period.  The\r
376                         on board LED will get toggled every mainNO_ERROR_FLASH_PERIOD ms. */\r
377                         vTaskDelay( mainNO_ERROR_FLASH_PERIOD );\r
378                 }\r
379                 else\r
380                 {\r
381                         /* We have at some time recognised an error in one of the demo\r
382                         application tasks, delay for a shorter period.  The on board LED\r
383                         will get toggled every mainERROR_FLASH_PERIOD ms. */\r
384                         vTaskDelay( mainERROR_FLASH_PERIOD );\r
385                 }\r
386 \r
387                 \r
388                 \r
389                 /* Check the demo application tasks for errors. */\r
390 \r
391                 if( xAreIntegerMathsTaskStillRunning() != pdTRUE )\r
392                 {\r
393                         xErrorHasOccurred = pdTRUE;\r
394                 }\r
395 \r
396                 if( xArePollingQueuesStillRunning() != pdTRUE )\r
397                 {\r
398                         xErrorHasOccurred = pdTRUE;\r
399                 }\r
400 \r
401                 if( xAreComTestTasksStillRunning() != pdTRUE )\r
402                 {\r
403                         xErrorHasOccurred = pdTRUE;\r
404                 }\r
405 \r
406                 if( xAreSemaphoreTasksStillRunning() != pdTRUE )\r
407                 {\r
408                         xErrorHasOccurred = pdTRUE;\r
409                 }\r
410 \r
411                 /* If an error has occurred, latch it to cause the LED flash rate to \r
412                 increase. */\r
413                 if( xErrorHasOccurred == pdTRUE )\r
414                 {\r
415                         xLatchedError = pdTRUE;\r
416                 }\r
417 \r
418                 /* Toggle the LED to indicate the completion of a check cycle.  The\r
419                 frequency of check cycles is dependent on whether or not we have \r
420                 latched an error. */\r
421                 prvToggleOnBoardLED();\r
422         }\r
423 }\r
424 /*-----------------------------------------------------------*/\r
425 \r
426 /*\r
427  * See the documentation at the top of this file.  Also see the standard FLOP\r
428  * demo task documentation for the rationale of these tasks.\r
429  */\r
430 static void vFLOPCheck1( void *pvParameters )\r
431 {\r
432 volatile portFLOAT fVal1, fVal2, fResult;\r
433 \r
434         ( void ) pvParameters;\r
435 \r
436         for( ;; )\r
437         {\r
438                 fVal1 = ( portFLOAT ) -1234.5678;\r
439                 fVal2 = ( portFLOAT ) 2345.6789;\r
440 \r
441                 fResult = fVal1 + fVal2;\r
442                 if( ( fResult > ( portFLOAT )  1111.15 ) || ( fResult < ( portFLOAT ) 1111.05 ) )\r
443                 {\r
444                         mainLATCH_ERROR();\r
445                 }\r
446 \r
447                 fResult = fVal1 / fVal2;\r
448                 if( ( fResult > ( portFLOAT ) -0.51 ) || ( fResult < ( portFLOAT ) -0.53 ) )\r
449                 {\r
450                         mainLATCH_ERROR();\r
451                 }\r
452         }\r
453 }\r
454 /*-----------------------------------------------------------*/\r
455 \r
456 /*\r
457  * See the documentation at the top of this file.\r
458  */\r
459 static void vFLOPCheck2( void *pvParameters )\r
460 {\r
461 volatile portFLOAT fVal1, fVal2, fResult;\r
462 \r
463         ( void ) pvParameters;\r
464 \r
465         for( ;; )\r
466         {\r
467                 fVal1 = ( portFLOAT ) -12340.5678;\r
468                 fVal2 = ( portFLOAT ) 23450.6789;\r
469 \r
470                 fResult = fVal1 + fVal2;\r
471                 if( ( fResult > ( portFLOAT ) 11110.15 ) || ( fResult < ( portFLOAT ) 11110.05 ) )\r
472                 {\r
473                         mainLATCH_ERROR();\r
474                 }\r
475 \r
476                 fResult = fVal1 / -fVal2;\r
477                 if( ( fResult > ( portFLOAT ) 0.53 ) || ( fResult < ( portFLOAT ) 0.51 ) )\r
478                 {\r
479                         mainLATCH_ERROR();\r
480                 }\r
481         }\r
482 }\r
483 /*-----------------------------------------------------------*/\r
484 \r
485 /*\r
486  * See the documentation at the top of this file. \r
487  */\r
488 static void vRegisterCheck( void *pvParameters )\r
489 {\r
490         ( void ) pvParameters;\r
491 \r
492         for( ;; )\r
493         {\r
494                 if( SP != configSTACK_START )\r
495                 {\r
496                         mainLATCH_ERROR();\r
497                 }\r
498 \r
499                 _asm\r
500                         MOV ACC, ar0\r
501                 _endasm;\r
502 \r
503                 if( ACC != 0 )\r
504                 {\r
505                         mainLATCH_ERROR();\r
506                 }\r
507 \r
508                 _asm\r
509                         MOV ACC, ar1\r
510                 _endasm;\r
511 \r
512                 if( ACC != 1 )\r
513                 {\r
514                         mainLATCH_ERROR();\r
515                 }\r
516                 _asm\r
517                         MOV ACC, ar2\r
518                 _endasm;\r
519 \r
520                 if( ACC != 2 )\r
521                 {\r
522                         mainLATCH_ERROR();\r
523                 }\r
524                 _asm\r
525                         MOV ACC, ar3\r
526                 _endasm;\r
527 \r
528                 if( ACC != 3 )\r
529                 {\r
530                         mainLATCH_ERROR();\r
531                 }\r
532                 _asm\r
533                         MOV ACC, ar4\r
534                 _endasm;\r
535 \r
536                 if( ACC != 4 )\r
537                 {\r
538                         mainLATCH_ERROR();\r
539                 }\r
540                 _asm\r
541                         MOV ACC, ar5\r
542                 _endasm;\r
543 \r
544                 if( ACC != 5 )\r
545                 {\r
546                         mainLATCH_ERROR();\r
547                 }\r
548                 _asm\r
549                         MOV ACC, ar6\r
550                 _endasm;\r
551 \r
552                 if( ACC != 6 )\r
553                 {\r
554                         mainLATCH_ERROR();\r
555                 }\r
556                 _asm\r
557                         MOV ACC, ar7\r
558                 _endasm;\r
559 \r
560                 if( ACC != 7 )\r
561                 {\r
562                         mainLATCH_ERROR();\r
563                 }\r
564 \r
565                 if( DPL != 0xcd )\r
566                 {\r
567                         mainLATCH_ERROR();\r
568                 }\r
569 \r
570                 if( DPH != 0xab )\r
571                 {\r
572                         mainLATCH_ERROR();\r
573                 }\r
574 \r
575                 if( B != 0x01 )\r
576                 {\r
577                         mainLATCH_ERROR();\r
578                 }                       \r
579         }\r
580 }\r
581 \r
582 \r