;*****************************************************************************
; 	All rights reserved by Dipl.-Ing (FH) Andreas Hoeger
;	Ditzenbrunner Str. 64, 71254 Ditzingen, Germany
;	Telefon: (+497156)490980	Telefax: (+497156)490981
;	E-Mail: ingbuero@andreas-hoeger.de
;*****************************************************************************
;
;       8051- Programm fuer ATMEL Flash- Mikrocontroller AT89S53
;	
;	Teilprogrammfuer HSTG, wird durch INCLUDE eingebunden
;
;       Autor: Andreas Hoeger
;       Datum: 18.02.2002
;
;	Aenderungen:
;	16_02_02: initial version for HSTG
;       18_02_02: CAN-Mailboxzuordnung gemaess Spec
;	04_05_02: Error_ZSTG eingefuegt
;	06_05_02: CAN- Datenausgabe- Mailbox auf 6 umgestellt
;	26_07_02: DCF77 Plausibilisierung: keine Buchstaben (HEX) anzeigen
;		  Zehnerstellen begrenzen
;	08_08_02: Bugfix (Stack-Overflow in DCF77 Plausibilisierung)
;		  Plausi-Error-Meldung durch "-" Ausgabe ersetzt
;	21_08_02: Fehlerausgabe MSTG eingefuegt
;	08_09_02: Werteausgaben der Sensordaten eingefuegt
;	09_09_02: Messwertausgaben auf ASCII umgestellt
;	03_10_02: Wenn MSTG Powerdown dann andere Ausgaben
;	06_02_03: Ladedruckausgabe eingefuegt
;	27_07_03: Standby-Anzeige eingefuegt als Sonderausgabemode
;	tt_mm_yy: 
;			
;*****************************************************************************


        ;*********************************************************************
	; Unterprogramme fuer "Menue-Modus"
        ;*********************************************************************
	;	
	; Da nur ein DPTR zur Verfuegung steht, koennen keine 4 Adressen fuer
	; 4 Messages (4 LCD- Zeilen) gemerkt werden.
	; Diese Routinen laden daher die DPTR Werte in Zwischenspeicher um,
	; von denen sie der LCD- Ausgabetask wieder in DPTR holt.

	; Diese Routinen setzen das Update- Flag der entsprechenden Zeile.

	; Die Zwischenspeicher befinden sich im oberen RAM, d.h. "indirect 
	; adressing" muss verwendet werden mit R1

	; Eingangswert: DPTR (16- Bit)
	; Ausgangswert: LCD_LINEx_POINT_H und LCD_LINEx_POINT_L

save_dptr_line1:
	mov	R1,#MENU_LINE1_POINT_H
	mov	@R1, DPH
	mov	R1,#MENU_LINE1_POINT_L
	mov	@R1, DPL
	setb	LCD_MENU_CONTROL.4	; Update- Flag setzen um die neue
					; Zeile im Task auszugeben
	ret

save_dptr_line2:
	mov	R1,#MENU_LINE2_POINT_H
	mov	@R1, DPH
	mov	R1,#MENU_LINE2_POINT_L
	mov	@R1, DPL
	setb	LCD_MENU_CONTROL.4	; Update- Flag setzen um die neue
					; Zeile im Task auszugeben
	ret

save_dptr_line3:
	mov	R1,#MENU_LINE3_POINT_H
	mov	@R1, DPH
	mov	R1,#MENU_LINE3_POINT_L
	mov	@R1, DPL
	setb	LCD_MENU_CONTROL.4	; Update- Flag setzen um die neue
					; Zeile im Task auszugeben
	ret

save_dptr_line4:
	mov	R1,#MENU_LINE4_POINT_H
	mov	@R1, DPH
	mov	R1,#MENU_LINE4_POINT_L
	mov	@R1, DPL
	setb	LCD_MENU_CONTROL.4	; Update- Flag setzen um die neue
					; Zeile im Task auszugeben
	ret


task_lcd_menu:

	; Zeilen ausgeben deren DPTR in den Zwischenspeichern abgelegt sind
	; Den Cursor in der entsprechenden Zeile ausdrucken
	; Die Texte sind nur 18 Zeichen lang, damit passt Cursor und Luecke

	; Das Update-Flag des Menue- Modes muss wieder geloescht werden.
	; Dieses Flag "LCD_MENU_CONTROL.4" gilt fuer alle vier Zeilen

	jb	LCD_MENU_CONTROL.4,menu_line1	; Menu Mode Update Flag
	jmp	menu_line_end

menu_line1:	; Standardablauf: Pruefen ob Cursor oder Leerzeichen
		;		  Botschaft (MSG ...) aus Speicher nehmen

	mov	A,#LCD_LINE1		; Zeile 1 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	mov	A,#LCD_LINE1		; Zeile 1 Botschaft schreiben
	call	instr_out

	jb	LCD_MENU_CONTROL.0,set_c_line1	; Cursor in Zeile 1 ?

	mov	A,#20H
	call	char_out		; schreibe Leerzeichen in Zeile 1
	jmp	set_l_line1

set_c_line1:
	mov	A,#02H
	call	char_out		; schreibe Menuecursor in Zeile 1
	
set_l_line1:
	mov	A,#20H
	call	char_out		; schreibe zweites Zeichen
					; nach Pfeil oder Leerzeichen

	mov	R1,#MENU_LINE1_POINT_H	; Adresse der aktuellen Botschaft
	mov	DPH, @R1		; fuer Zeile 1 holen in DPTR
	mov	R1,#MENU_LINE1_POINT_L
	mov	DPL, @R1
	call	print_lcd

	;*****

menu_line2:	; Standardablauf: Pruefen ob Cursor oder Leerzeichen
		;		  Botschaft (MSG ...) aus Speicher nehmen

	mov	A,#LCD_LINE2		; Zeile 2 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	mov	A,#LCD_LINE2		; Zeile 2 Botschaft schreiben
	call	instr_out

	jb	LCD_MENU_CONTROL.1,set_c_line2	; Cursor in Zeile 2 ?

	mov	A,#20H
	call	char_out		; schreibe Leerzeichen in Zeile 2
	jmp	set_l_line2

set_c_line2:
	mov	A,#02H
	call	char_out		; schreibe Menuecursor in Zeile 2
	
set_l_line2:
	mov	A,#20H
	call	char_out		; schreibe zweites Zeichen
					; nach Pfeil oder Leerzeichen

	mov	R1,#MENU_LINE2_POINT_H	; Adresse der aktuellen Botschaft
	mov	DPH, @R1		; fuer Zeile 2 holen in DPTR
	mov	R1,#MENU_LINE2_POINT_L
	mov	DPL, @R1
	call	print_lcd

;*****

menu_line3:	; Standardablauf: Pruefen ob Cursor oder Leerzeichen
		;		  Botschaft (MSG ...) aus Speicher nehmen

	mov	A,#LCD_LINE3		; Zeile 3 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	mov	A,#LCD_LINE3		; Zeile 3 Botschaft schreiben
	call	instr_out

	jb	LCD_MENU_CONTROL.2,set_c_line3	; Cursor in Zeile 3 ?

	mov	A,#20H
	call	char_out		; schreibe Leerzeichen in Zeile 3
	jmp	set_l_line3

set_c_line3:
	mov	A,#02H
	call	char_out		; schreibe Menuecursor in Zeile 3
	
set_l_line3:
	mov	A,#20H
	call	char_out		; schreibe zweites Zeichen
					; nach Pfeil oder Leerzeichen

	mov	R1,#MENU_LINE3_POINT_H	; Adresse der aktuellen Botschaft
	mov	DPH, @R1		; fuer Zeile 3 holen in DPTR
	mov	R1,#MENU_LINE3_POINT_L
	mov	DPL, @R1
	call	print_lcd

;*****

menu_line4:	; Standardablauf: Pruefen ob Cursor oder Leerzeichen
		;		  Botschaft (MSG ...) aus Speicher nehmen

	mov	A,#LCD_LINE4		; Zeile 4 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	mov	A,#LCD_LINE4		; Zeile 4 Botschaft schreiben
	call	instr_out

	jb	LCD_MENU_CONTROL.3,set_c_line4	; Cursor in Zeile 4 ?

	mov	A,#20H
	call	char_out		; schreibe Leerzeichen in Zeile 4
	jmp	set_l_line4

set_c_line4:
	mov	A,#02H
	call	char_out		; schreibe Menuecursor in Zeile 4
	
set_l_line4:
	mov	A,#20H
	call	char_out		; schreibe zweites Zeichen
					; nach Pfeil oder Leerzeichen

	mov	R1,#MENU_LINE4_POINT_H	; Adresse der aktuellen Botschaft
	mov	DPH, @R1		; fuer Zeile 4 holen in DPTR
	mov	R1,#MENU_LINE4_POINT_L
	mov	DPL, @R1
	call	print_lcd

;*****

	clr	LCD_MENU_CONTROL.4	; Update- Flag wieder loeschen
					; fuer alle vier Zeilen

menu_line_end:

	ret

        ;*********************************************************************
	; Unterprogramme fuer Standard- Ausgabemodus "ShowData"
        ;*********************************************************************
	;	
	; Folgendes wird fuer jede Zeile gemacht:
	; - Nummer des für Zeile x aktuellen Tasks ermitteln 
	;   (LCD_DATA_TASK_Lx)
	; - Update- Flag pruefen; falls Null zur nächsten Zeile gehen
	;   sonst Cursor in Zeile setzen und entsprechendes Unterprogramm
	;   des Tasks aufrufen, in dem die Daten ausgegeben werden, bestehend
	;   aus Message und Werten, allerdings nur max. eine Zeile lang

task_lcd_standard:
	
std_line1:	; Task fuer Zeile 1 pruefen und ggf. neu ausgeben

	jnb	LCD_DATA_TASK_L1.7,std_line2	; MSB = Update-Flag
						; wenn nicht gesetzt weiter
std_t1:	clr	LCD_DATA_TASK_L1.7		; Update- Flag loeschen

	mov	A,#LCD_LINE1			; Zeile 1 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE1			; Zeile 1 Anfang
	call	instr_out
	; Message und Werte im UP ausgeben

	mov	A,LCD_DATA_TASK_L1		; Tasknummer Zeile 1 lesen
	call	std_tasks			; und vergleichen
	

std_line2:	; Task fuer Zeile 2 pruefen und ggf. neu ausgeben

	jnb	LCD_DATA_TASK_L2.7,std_line3	; MSB = Update-Flag
						; wenn nicht gesetzt weiter
std_t2:	clr	LCD_DATA_TASK_L2.7		; Update- Flag loeschen

	mov	A,#LCD_LINE2			; Zeile 2 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE2			; Zeile 2 Anfang
	call	instr_out
	; Message und Werte im UP ausgeben

	mov	A,LCD_DATA_TASK_L2		; Tasknummer Zeile 2 lesen
	call	std_tasks			; und vergleichen
	
std_line3:	; Task fuer Zeile 3 pruefen und ggf. neu ausgeben

	jnb	LCD_DATA_TASK_L3.7,std_line4	; MSB = Update-Flag
						; wenn nicht gesetzt weiter
std_t3:	clr	LCD_DATA_TASK_L3.7		; Update- Flag loeschen

	mov	A,#LCD_LINE3			; Zeile 3 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE3			; Zeile 3 Anfang
	call	instr_out
	; Message und Werte im UP ausgeben

	mov	A,LCD_DATA_TASK_L3		; Tasknummer Zeile 3 lesen
	call	std_tasks			; und vergleichen
	
std_line4:	; Task fuer Zeile 4 pruefen und ggf. neu ausgeben

	jnb	LCD_DATA_TASK_L4.7,std_end	; MSB = Update-Flag
						; wenn nicht gesetzt weiter

std_t4: clr	LCD_DATA_TASK_L4.7		; Update- Flag loeschen

	mov	A,#LCD_LINE4			; Zeile 4 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE4			; Zeile 4 Anfang
	call	instr_out
	; Message und Werte im UP ausgeben

	mov	A,LCD_DATA_TASK_L4		; Tasknummer Zeile 4 lesen
	call	std_tasks			; und vergleichen
	
std_end:	
	ret

        ;*********************************************************************
	; jetzt folgt der eigentliche Tasknummernvergleich 
	; (für alle vier Zeilen verwendet)
	; in A ist die aktuelle Tasknummer

std_tasks:
	cjne	A,#TASKNUMMER_TEMP,std_v2	; mit Temperatur-Task vergl.	
	call	t_temp				; (Innentemperatur)
	jmp	std_tasks_end
std_v2: cjne	A,#TASKNUMMER_ERROR,std_v3	; mit Error-Task vergleichen
	call	t_error
	jmp	std_tasks_end
std_v3: cjne	A,#TASKNUMMER_LEER,std_v4	; mit Leerzeilen-Task vergl.
	call	t_leer
	jmp	std_tasks_end
std_v4: cjne	A,#TASKNUMMER_TEMP_OUT,std_v5	; mit Aussentemp.-Task vergl.
	call	t_temp_out
	jmp	std_tasks_end
std_v5: cjne	A,#TASKNUMMER_VOLTAMP,std_v6	; mit Volt/Ampere-Task vergl.
	call	t_voltamp
	jmp	std_tasks_end
std_v6: cjne	A,#TASKNUMMER_LLK_TEMP,std_v7	; mit Ladelufttemp.-Task vergl.
	call	t_llk_temp
	jmp	std_tasks_end
std_v7: cjne	A,#TASKNUMMER_LLK_DRUCK,std_v8	; mit Ladedruck-Task vergl.
	call	t_llk_druck
	jmp	std_tasks_end
std_v8: cjne	A,#TASKNUMMER_OELTEMP,std_v9	; mit Oeltemp.-Task vergl.
	call	t_oeltemp
	jmp	std_tasks_end
std_v9: cjne	A,#TASKNUMMER_OELDRUCK,std_vA	; mit Oeldruck-Task vergl.
	call	t_oeldruck
	jmp	std_tasks_end
std_vA: cjne	A,#TASKNUMMER_ERROR_ZSTG,std_vB	; mit ZSTG-ERROR-Task vergl.
	call	t_error_zstg
	jmp	std_tasks_end
std_vB: cjne	A,#TASKNUMMER_ERROR_MSTG,std_vC	; mit MSTG-ERROR-Task vergl.
	call	t_error_mstg
	jmp	std_tasks_end
std_vC: cjne	A,#TASKNUMMER_DCF77,std_vx	; mit DCF77-Task vergl.
	call	t_dcf77
	jmp	std_tasks_end

std_vx:	nop
;	----- hier evtl. Fehlermeldung ungueltige Tasknummer -----
std_tasks_end:
	ret

        ;*********************************************************************
	; Task Leerzeilenausgabe

t_leer:	mov	DPTR,#MSG000		 
	call	print_lcd

	ret

        ;*********************************************************************
	; Task Aussentemperaturanzeige

t_temp_out:	
	mov	DPTR,#MSG800		 
	call	print_lcd

	ret

        ;*********************************************************************
	; Task Volt / Ampereanzeige

t_voltamp:	
	mov	DPTR,#MSG801	; Text ausgeben ohne Zahlenwerte	 
	call	print_lcd

	;****** Mailbox 8 nach Botschaft 5122 (Sensordaten ASCII) abfragen

	; die soeben eingelesene CAN_Botschaft in BOX 8 auswerten

	; BOX8_C: 	CAN Mailbox 8	Controlbyte
	; BOX8_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX8_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX8_0:	CAN Botschaft Mailbox --> Daten

	mov	R0,#BOX8_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 8
	inc	R0
	inc	R0			; zeigt auf Byte 0

	;****** ADC_VOLT ist in Byte 0,1,2 der Botschaft
	; - VOLT_ASCII_H = Zehner Vorkomma
	; - VOLT_ASCII_Z = Einer Vorkomma
	; - VOLT_ASCII_E = Nachkommastelle

	mov	ACC,@R0		; hole byte 0 in Akku, Zehner Vorkomma
	call	char_out
	inc	R0		; zeigt auf Byte 1
	mov	ACC,@R0		; hole byte 1 in Akku, Einer Vorkomma
	call	char_out

	mov	A,#2EH		; Kommapunkt ausgeben
	call	char_out

	inc	R0		; zeigt auf Byte 2
	mov	ACC,@R0		; hole byte 2 in Akku, Nachkomma
	call	char_out

	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out
	mov	A,#56H			; V für Einheit der Spannung
	call	char_out

	ret

        ;*********************************************************************
	; Task Ladelufttemperaturanzeige

t_llk_temp:	
	mov	DPTR,#MSG802	; Text ausgeben ohne Zahlenwerte	 
	call	print_lcd

	;****** Mailbox 7 nach Botschaft 513 (Sensordaten ASCII) abfragen

	; die soeben eingelesene CAN_Botschaft in BOX 7 auswerten

	; BOX7_C: 	CAN Mailbox 7	Controlbyte
	; BOX7_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX7_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX7_0:	CAN Botschaft Mailbox --> Daten

	mov	R0,#BOX7_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 7
	inc	R0
	inc	R0			; zeigt auf Byte 0

	;****** LLK_Temp ist in Byte 0,1 der Botschaft
	; - LLK_TEMP   Zehner
	; - LLK_TEMP   Einer
	; - OEL_TEMP   Hunderter
	; - OEL_TEMP   Zehner
	; - OEL_TEMP   Einer
	; - LLK_DRUCK  Hunderter
	; - LLK_DRUCK  Zehner
	; - LLK_DRUCK  Einer

	;****** wenn MSTG Powerdown aktiv (BIT04 == 1) dann
	;       Ausgabe loeschen sonst bleiben die letzten Werte stehen
	
	jb	BIT04,llk_temp_mstg_off

	mov	ACC,@R0		; hole byte 0 in Akku, Zehner
	call	char_out
	inc	R0		; zeigt auf Byte 1
	mov	ACC,@R0		; hole byte 1 in Akku, Einer
	call	char_out

	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out
	mov	A,#0DFH			; ° Symbol ausgeben
	call	char_out
	mov	A,#43H			; C für Einheit der Temperatur
	call	char_out

	ret

llk_temp_mstg_off:

	mov	A,#2DH		; Minuszeichen laden
	call	char_out
	mov	A,#2DH		; Minuszeichen laden
	call	char_out
	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out
	mov	A,#0DFH			; ° Symbol ausgeben
	call	char_out
	mov	A,#43H			; C für Einheit der Temperatur
	call	char_out

	ret
	
        ;*********************************************************************
	; Task Ladedruckanzeige

t_llk_druck:	
	mov	DPTR,#MSG803		 
	call	print_lcd

	;****** Mailbox 7 nach Botschaft 513 (Sensordaten ASCII) abfragen

	; die soeben eingelesene CAN_Botschaft in BOX 7 auswerten

	; BOX7_C: 	CAN Mailbox 7	Controlbyte
	; BOX7_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX7_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX7_0:	CAN Botschaft Mailbox --> Daten

	mov	R0,#BOX7_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 7
	inc	R0
	inc	R0			; zeigt auf Byte 0

	;****** LLK_Temp ist in Byte 0,1 der Botschaft
	; - LLK_TEMP   Zehner
	; - LLK_TEMP   Einer
	; - OEL_TEMP   Hunderter
	; - OEL_TEMP   Zehner
	; - OEL_TEMP   Einer
	; - LLK_DRUCK  Hunderter
	; - LLK_DRUCK  Zehner
	; - LLK_DRUCK  Einer

	;****** wenn MSTG Powerdown aktiv (BIT04 == 1) dann
	;       Ausgabe loeschen sonst bleiben die letzten Werte stehen
	
	jb	BIT04,llk_druck_mstg_off

	inc	R0		; zeigt auf Byte 1
	inc	R0		; zeigt auf Byte 2
	inc	R0		; zeigt auf Byte 3
	inc	R0		; zeigt auf Byte 4
	inc	R0		; zeigt auf Byte 5
	inc	R0		; zeigt auf Byte 6

	;Ausgabetext ist im Format 
	;Ladedruck 0.xx bar
	;mit maximalem Wert = 64h = 99dez = 0.99 bar

	mov	A,#30H			; Null ausgeben
	call	char_out
	mov	A,#2EH			; Punkt ausgeben
	call	char_out

	mov	ACC,@R0		; hole byte 6 in Akku, Zehner
	call	char_out
	inc	R0		; zeigt auf Byte 7
	mov	ACC,@R0		; hole byte 7 in Akku, Einer
	call	char_out

	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out
	mov	A,#62H			; b ausgeben
	call	char_out
	mov	A,#61H			; a ausgeben
	call	char_out
	mov	A,#72H			; r ausgeben
	call	char_out

	ret

llk_druck_mstg_off:

	mov	A,#2DH		; Minuszeichen laden fuer Nullstelle
	call	char_out
	mov	A,#2DH		; Minuszeichen laden fuer Komma
	call	char_out
	mov	A,#2DH		; Minuszeichen laden fuer Zehnerstelle
	call	char_out
	mov	A,#2DH		; Minuszeichen laden fuer Einerstelle
	call	char_out

	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out
	mov	A,#62H			; b ausgeben
	call	char_out
	mov	A,#61H			; a ausgeben
	call	char_out
	mov	A,#72H			; r ausgeben
	call	char_out

	ret

        ;*********************************************************************
	; Task Oeltemperaturanzeige

t_oeltemp:	
	mov	DPTR,#MSG804	; Text ausgeben ohne Zahlenwerte	 
	call	print_lcd

	;****** Mailbox 7 nach Botschaft 513 (Sensordaten ASCII) abfragen

	; die soeben eingelesene CAN_Botschaft in BOX 7 auswerten

	; BOX7_C: 	CAN Mailbox 7	Controlbyte
	; BOX7_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX7_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX7_0:	CAN Botschaft Mailbox --> Daten

	mov	R0,#BOX7_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 7
	inc	R0
	inc	R0			; zeigt auf Byte 0

	;****** OEL_Temp ist in Byte 2,3,4 der Botschaft
	; - LLK_TEMP   Zehner
	; - LLK_TEMP   Einer
	; - OEL_TEMP   Hunderter
	; - OEL_TEMP   Zehner
	; - OEL_TEMP   Einer
	; - LLK_DRUCK  Hunderter
	; - LLK_DRUCK  Zehner
	; - LLK_DRUCK  Einer

	;****** wenn MSTG Powerdown aktiv (BIT04 == 1) dann
	;       Ausgabe loeschen sonst bleiben die letzten Werte stehen
	
	jb	BIT04,oel_temp_mstg_off

	inc	R0		; zeigt auf Byte 1
	inc	R0		; zeigt auf Byte 2

	mov	ACC,@R0		; hole byte 2 in Akku, Hunderter
	call	char_out
	inc	R0		; zeigt auf Byte 3
	mov	ACC,@R0		; hole byte 3 in Akku, Zehner
	call	char_out
	inc	R0		; zeigt auf Byte 4
	mov	ACC,@R0		; hole byte 4 in Akku, Einer
	call	char_out

	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out
	mov	A,#0DFH			; ° Symbol ausgeben
	call	char_out
	mov	A,#43H			; C für Einheit der Temperatur
	call	char_out

	ret

oel_temp_mstg_off:

	mov	A,#2DH		; Minuszeichen laden
	call	char_out
	mov	A,#2DH		; Minuszeichen laden
	call	char_out
	mov	A,#2DH		; Minuszeichen laden
	call	char_out

	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out
	mov	A,#0DFH			; ° Symbol ausgeben
	call	char_out
	mov	A,#43H			; C für Einheit der Temperatur
	call	char_out

	ret

        ;*********************************************************************
	; Task Oeldruckanzeige

t_oeldruck:	
	mov	DPTR,#MSG805		 
	call	print_lcd

	ret

        ;*********************************************************************
	; Task Temperatur (alles was nach Zeile einstellen noch fehlt)
	; (Innentemperaturanzeige)

t_temp:	; dieses Unterprogramm fuer den Task Temperatur gibt die Werte hinter
	; der Botschaft auf die LCD- Anzeige aus.

	mov	DPTR,#MSX051		; Message Temperatur ausgeben		 
	call	print_lcd

	; TEMP_H sicherstellen, wird benutzt fuer Umwandlung
	call	hex_dez_ascii		; Umwandlung HEX/DEZ/ASCII
	
	jnb	Bit00,temp1		; wenn nicht gesetzt: positiv

	mov	A,#2DH			; Minuszeichen ausgeben
	jmp	temp3
			
temp1:	mov	A,#2BH			; Pluszeichen ausgeben
temp3:	call	char_out
	mov	A,TEMP_DEZ_H
	call	char_out		; Temp Hunderterstelle
	mov	A,TEMP_DEZ_Z
	call	char_out		; Temp Zehnerstelle 
	mov	A,TEMP_H		
	call	char_out		; Temp Einerstelle

	mov	A,#2EH			; Kommapunkt ausgeben
	call	char_out

	mov	A,TEMP_L		; nur MSB wichtig; gesetzt = .5
	rlc	A
	jc	pkt5

pkt0:	mov	A,#30H
	jmp	temp2

pkt5:	mov	A,#35H
	
temp2:	call	char_out

	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out

	mov	A,#0DFH			; ° Symbol ausgeben
	call	char_out

	mov	A,#43H			; C für Einheit der Temperatur
	call	char_out
	
	mov	A,#20H			; Leerzeichen ausgeben
	call	char_out

	; Tendenzpfeil ausgeben, abhängig von Bit 02
	; Bit 02 wird von der DS1621 Einleseroutine gesetzt bzw. geloescht
	; wenn diese den neuen Wert und den alten aus EEPROM vergleicht
	; Bit 02 = 0: Pfeil abwaerts, Temperatur fallend
	; Bit 02 = 1: Pfeil aufwaerts, Temperatur steigend

	jnb	Bit02,tempdown		; wenn nicht gesetzt: Pfeil ab

	mov	A,#01H			; Pfeil aufwaerts Sonderzeichen
	jmp	pfeilout
			
tempdown:	
	mov	A,#00H			; Pfeil abwaerts Sonderzeichen
pfeilout:	
	call	char_out

	ret

        ;*********************************************************************
	; Task DCF77 Wochentag, Datum und Zeit anzeigen 
	; (alles was nach Zeile einstellen noch fehlt).
	; Ausgewertet werden die CAN- Botschaft Bytes

t_dcf77:
	; dieses Unterprogramm fuer den Task DCF77 gibt die Datums und Zeit-
	; Werte hinter der Wochentags- Kennung auf die LCD- Anzeige aus.

	; Annahmen: - DCF77 Botschaft ist in sich konsistent, d.h. wurde nur
	;             gesendet wenn DCF77-Bit 59 aktiv
	;	    - CHKS der DCF77 Botschaft wurde sendeseitig geprueft

	; In Byte 0 der CAN Botschaft wird die Bitnummer uebertragen
	; zur Kontrolle der DCF Funktion auf CANalyzer.

	; Bei Bitnummer = FFh lag sendeseitig synchronisationsphase vor
	; Bei Bitnummer = FEh lag sendeseitig ein Checksummenfehler vor 

	; Es wird dann keine Zeit angezeigt sondern eine "Fehler"-Meldung. 
	; Hinweis: Dies ist kein Fehlerzustand mit Abbruch.

	;*********************************************************************

	; die soeben eingelesene CAN_Botschaft in BOX 4 auswerten

	; BOX4_C: 	CAN Mailbox 3	Controlbyte
	; BOX4_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX4_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX4_0:	CAN Botschaft Mailbox 4 	Datenbyte 0
	; BOX4_1:	CAN Botschaft Mailbox 4 	Datenbyte 1
	; BOX4_2:	CAN Botschaft Mailbox 4 	Datenbyte 2
	; BOX4_3:	CAN Botschaft Mailbox 4 	Datenbyte 3
	; BOX4_4:	CAN Botschaft Mailbox 4 	Datenbyte 4
	; BOX4_5:	CAN Botschaft Mailbox 4 	Datenbyte 5
	; BOX4_6:	CAN Botschaft Mailbox 4 	Datenbyte 6
	; BOX4_7:	CAN Botschaft Mailbox 4 	Datenbyte 7

	mov	R0,#BOX4_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 1
	inc	R0
	inc	R0			; zeigt auf Byte 0

;****** Pruefen ob Fehler oder noch nicht synchronisiert
	; auf Zeitsignal (Byte 0 = FFh)

	mov	ACC,@R0		; hole byte 0 in Akku
dcf_check_sync:
	cjne	A,#0FFH,dcf_check_chks
	jmp	dcf_sync_err	; Es ist FFh = SyncPhase
dcf_check_chks:
	cjne	A,#0FEh,dcf_ok
	jmp	dcf_chks_err
dcf_sync_err:
	mov	DPTR,#MSX077	; Message ausgeben "SYNC"		 
	call	print_lcd
	jmp	t_dcf77_end
dcf_chks_err:
	mov	DPTR,#MSX078	; Message ausgeben "CHKS"		 
	call	print_lcd
	jmp	t_dcf77_end


;****** Mit Auswertung beginnen; Byte 0 birgt keine Fehlerkennung

dcf_ok:
	inc	R0
	inc	R0
	inc	R0
	inc	R0
	inc	R0		; zeigt auf Byte 5

;****** Wochentag ermitteln und anzeigen	Byte 5 [4:2]

	mov	ACC,@R0		; hole Byte 5 in Akku
	rr	A
	rr	A
	anl	A,#DCF77_MASK_WEEKDAY

vgl_00h: 
	cjne	A,#00H,vgl_mo	; Meldung 'SYNC'
	mov	DPTR,#MSX077	; erscheint beim Booten
	call	print_lcd
	jmp	t_dcf77_end	; keine Nummern ausgeben
				; (Sonderfall)

vgl_mo:	cjne	A,#01H,vgl_di
	mov	DPTR,#MSX070	; 'MO  ' ausgeben		 
	call	print_lcd

vgl_di: cjne	A,#02H,vgl_mi
	mov	DPTR,#MSX071	; 'DI  ' ausgeben		 
	call	print_lcd

vgl_mi: cjne	A,#03H,vgl_do
	mov	DPTR,#MSX072	; 'MI  ' ausgeben		 
	call	print_lcd

vgl_do: cjne	A,#04H,vgl_fr
	mov	DPTR,#MSX073	; 'DO  ' ausgeben		 
	call	print_lcd

vgl_fr: cjne	A,#05H,vgl_sa
	mov	DPTR,#MSX074	; 'FR  ' ausgeben		 
	call	print_lcd

vgl_sa: cjne	A,#06H,vgl_so
	mov	DPTR,#MSX075	; 'SA  ' ausgeben		 
	call	print_lcd

vgl_so: cjne	A,#07H,vgl_weekday_end
	mov	DPTR,#MSX076	; 'SO  ' ausgeben		 
	call	print_lcd

vgl_weekday_end:

;****** Tag Zehner		; Byte 5 [1:0]

day_10: ; R0 steht auf Byte 5

	mov	ACC,@R0		; hole Byte 5 in Akku
	anl	A,#DCF77_MASK_DAY_10
	
	; Absichern dass nur 0, 1, 2, 3 moeglich 
	push	ACC			; sichern weil zerstoert
	jz	day_10_ok		; Null ist i.O.	
	dec	A
	jz	day_10_ok	; es war 1
	dec	A
	jz	day_10_ok	; es war 2
	dec	A
	jz	day_10_ok	; es war 3
day_10_err:
	pop	ACC		; avoid stack overflow !
	mov	A,#2DH		; overload "-" character
	jmp	day_10_out
day_10_ok:
	pop	ACC
day_10_out:
	call	hex_in_ascii
	mov	A,ASCII_L
	call	char_out	
	
;****** Tag Einer		; Byte 4 [7:4]

day_01:	; R0 steht auf Byte 5
	
	dec	R0		; zeigt auf Byte 4
	mov	ACC,@R0		; hole Byte 4 in Akku
	rr	A
	rr	A
	rr	A
	rr	A
	anl	A,#DCF77_MASK_DAY_01
	call	hex_in_ascii_dcf77	; wenn Buchstabe dann
					; Rückgabe NULL
	mov	A,ASCII_L
	jnz	day_01_ok		
	mov	A,#2DH		; Plausierror, load "-" char
day_01_ok:
	call	char_out	

;****** Punkt ausgeben		

	mov	A,#2EH		
	call	char_out
	
;****** Monat Zehner		; Byte 6 [1]

month_10:
	; R0 steht auf Byte 4
	
	inc	R0
	inc	R0		; zeigt auf Byte 6
	mov	ACC,@R0		; hole Byte 6 in Akku
	rr	A
	anl	A,#DCF77_MASK_MONTH_10

	; Absichern dass nur 0, 1 moeglich 
	push	ACC			; sichern weil zerstoert
	jz	month_10_ok		; Null ist i.O.	
	dec	A
	jz	month_10_ok	; es war 1
month_10_err:
	pop	ACC		; avoid stack overflow !
	mov	A,#2DH		; overload "-" character
	jmp	month_10_out
month_10_ok:
	pop	ACC
month_10_out:
	call	hex_in_ascii
	mov	A,ASCII_L
	call	char_out	

;****** Monat Einer		; LSB Byte 5 [7..5]
				; MSB Byte 6 [0]

month_01:
	; R0 steht auf Byte 6

	mov	ACC,@R0		; hole Byte 6 in Akku
	rrc	A		; hole Bit 0 in Carry

	dec	R0		; zeigt auf Byte 5
				; --> no flags affected
	mov	ACC,@R0		; hole Byte 5 in Akku
				; --> no flags affected

	rrc	A		; schiebe carry oben rein
	rr	A
	rr	A
	rr	A
	rr	A
	anl	A,#DCF77_MASK_MONTH_01
	call	hex_in_ascii_dcf77	; wenn Buchstabe dann
					; Rückgabe NULL
	mov	A,ASCII_L
	jnz	month_01_ok		
	mov	A,#2DH		; Plausierror, load "-" char
month_01_ok:
	call	char_out	

;****** Punkt ausgeben		

point2:
	mov	A,#2EH		
	call	char_out

;****** Jahr Zehner		; LSB Byte 6 [7:6]
				; MSB Byte 7 [1:0]
year_10:
	; R0 steht auf Byte 5
	inc	R0
	inc	R0		; zeigt auf Byte 7
	mov	ACC,@R0		; hole Byte 7 in Akku
				; --> no flags affected
	rrc	A
	dec	R0		; zeigt auf Byte 6
	mov	ACC,@R0		; hole Byte 6 in Akku
				; --> no flags affected
	rrc	A		; EX-Byte 7.0 an MSB rein

	mov	MERK,A		; sichern !!

	inc	R0		; zeigt auf Byte 7
	mov	ACC,@R0		; hole Byte 7 in Akku
				; --> no flags affected
	rrc	A
	rrc	A		; EX-Byte 7.1 jetzt in carry
	mov	A,MERK		; gesichertes Byte holen
	rrc	A		; EX-Byte 7.1 an MSB rein

	rr	A
	rr	A
	rr	A
	rr	A		
	anl	A,#DCF77_MASK_YEAR_10
	call	hex_in_ascii_dcf77	; wenn Buchstabe dann
					; Rückgabe NULL
	mov	A,ASCII_L
	jnz	year_10_ok		
	mov	A,#2DH		; Plausierror, load "-" char
year_10_ok:
	call	char_out	

;****** Jahr Einer		; Byte 6 [5:2]

year_01:
	; R0 steht auf Byte 7
	dec	R0		; zeigt auf Byte 6
	mov	ACC,@R0		; hole Byte 6 in Akku
	rr	A
	rr	A
	anl	A,#DCF77_MASK_YEAR_01
	call	hex_in_ascii_dcf77	; wenn Buchstabe dann
					; Rückgabe NULL
	mov	A,ASCII_L
	jnz	year_01_ok		
	mov	A,#2DH		; Plausierror, load "-" char
year_01_ok:
	call	char_out	

;****** zwei Leerstellen ausgeben

	mov	A,#20H		
	call	char_out
	mov	A,#20H		
	call	char_out

;****** Stunden Zehner		; Byte 4 [2:1]

hour_10:
	; R0 steht auf Byte 6
	dec	R0
	dec	R0		; zeigt auf Byte 4
	mov	ACC,@R0		; hole Byte 4 in Akku
	rr	A
	anl	A,#DCF77_MASK_HOUR_10

	; Absichern dass nur 0, 1, 2 moeglich 
	push	ACC			; sichern weil zerstoert
	jz	hour_10_ok		; Null ist i.O.	
	dec	A
	jz	hour_10_ok	; es war 1
	dec	A
	jz	hour_10_ok	; es war 2
hour_10_err:
	pop	ACC		; avoid stack overflow !
	mov	A,#2DH		; overload "-" character
	jmp	hour_10_out
hour_10_ok:
	pop	ACC
hour_10_out:
	call	hex_in_ascii
	mov	A,ASCII_L
	call	char_out	
	
;****** Stunden Einer		; LSB Byte 3 [7:5]
				; MSB Byte 4 [0]
hour_01:
	; R0 steht auf Byte 4

	mov	ACC,@R0		; hole Byte 4 in Akku
	rrc	A		; hole Bit 0 in Carry

	dec	R0		; zeigt auf Byte 3
				; --> no flags affected
	mov	ACC,@R0		; hole Byte 3 in Akku
				; --> no flags affected

	rrc	A		; schiebe carry oben rein
	rr	A
	rr	A
	rr	A
	rr	A
	anl	A,#DCF77_MASK_HOUR_01
	call	hex_in_ascii_dcf77	; wenn Buchstabe dann
					; Rückgabe NULL
	mov	A,ASCII_L
	jnz	hour_01_ok		
	mov	A,#2DH		; Plausierror, load "-" char
hour_01_ok:
	call	char_out	

;****** Doppelpunkt ausgeben

	mov	A,#3AH		; Doppelpunkt ausgeben
	call	char_out

;****** Minuten Zehner		; Byte 3 [3:1]

min_10:
	; R0 steht auf Byte 3

	mov	ACC,@R0		; hole Byte 3 in Akku
	rr	A
	anl	A,#DCF77_MASK_MIN_10

	; Absichern dass nur 0, 1, 2, 3, 4, 5 moeglich 
	push	ACC			; sichern weil zerstoert
	jz	min_10_ok		; Null ist i.O.	
	dec	A
	jz	min_10_ok	; es war 1
	dec	A
	jz	min_10_ok	; es war 2
	dec	A
	jz	min_10_ok	; es war 3
	dec	A
	jz	min_10_ok	; es war 4
	dec	A
	jz	min_10_ok	; es war 5
min_10_err:
	pop	ACC		; avoid stack overflow !
	mov	A,#2DH		; overload "-" character
	jmp	min_10_out
min_10_ok:
	pop	ACC
min_10_out:
	call	hex_in_ascii
	mov	A,ASCII_L
	call	char_out	

;****** Minuten Einer		; LSB Byte 2 [7:5]
				; MSB Byte 3 [0]
min_01:
	; R0 steht auf Byte 3

	mov	ACC,@R0		; hole Byte 3 in Akku
	rrc	A		; hole Bit 0 in Carry

	dec	R0		; zeigt auf Byte 2
				; --> no flags affected
	mov	ACC,@R0		; hole Byte 2 in Akku
				; --> no flags affected

	rrc	A		; schiebe carry oben rein
	rr	A
	rr	A
	rr	A
	rr	A
	anl	A,#DCF77_MASK_MIN_01
	call	hex_in_ascii_dcf77	; wenn Buchstabe dann
					; Rückgabe NULL
	mov	A,ASCII_L
	jnz	min_01_ok		
	mov	A,#2DH		; Plausierror, load "-" char
min_01_ok:
	call	char_out	

t_dcf77_end:

	ret

       ;*********************************************************************
	; Task Fehlermeldung (alles was nach Zeile einstellen noch fehlt)
	; Tasknummer wurde schon eingetragen in Zeile 1 und die anderen nach 
	; unten rotiert

t_error:
	mov	DPTR,#MSX060		 
	call	print_lcd

	mov	A,ERROR
	call	hex_in_ascii
	mov	A,ASCII_H
	call	char_out		; Fehler High Byte
	mov	A,ASCII_L
	call	char_out		; Fehler Low Byte 

	setb	BITS.7			; evtl. NOTSTOP am Anfang der 
					; Taskschleife
					; --> nicht hier weil zuerst noch die 
					; LCD- Ausgabe drankommen muss
	ret

        ;*********************************************************************
	; Task Fehlermeldung (alles was nach Zeile einstellen noch fehlt)
	; Tasknummer wurde schon eingetragen in Zeile 1 und die anderen nach 
	; unten rotiert

t_error_zstg:
	mov	DPTR,#MSX061		 
	call	print_lcd

	mov	A,ERROR
	call	hex_in_ascii
	mov	A,ASCII_H
	call	char_out		; Fehler High Byte
	mov	A,ASCII_L
	call	char_out		; Fehler Low Byte 

	setb	BITS.7			; evtl. NOTSTOP am Anfang der 
					; Taskschleife
					; --> nicht hier weil zuerst noch die 
					; LCD- Ausgabe drankommen muss
	ret

        ;*********************************************************************
	; Task Fehlermeldung (alles was nach Zeile einstellen noch fehlt)
	; Tasknummer wurde schon eingetragen in Zeile 1 und die anderen nach 
	; unten rotiert

t_error_mstg:
	mov	DPTR,#MSX062		 
	call	print_lcd

	mov	A,ERROR
	call	hex_in_ascii
	mov	A,ASCII_H
	call	char_out		; Fehler High Byte
	mov	A,ASCII_L
	call	char_out		; Fehler Low Byte 

	setb	BITS.7			; evtl. NOTSTOP am Anfang der 
					; Taskschleife
					; --> nicht hier weil zuerst noch die 
					; LCD- Ausgabe drankommen muss
	ret

        ;*********************************************************************
	; Unterprogramme fuer "Sonderausgabe-Modus"
        ;*********************************************************************
	;	
	; Folgendes wird gemacht:
	; Es wird geprueft, ob die aktuell am Display angegeben Tasknummer
	; das Update- Flag gesetzt hat.
	; Falls gesetzt, wird die entsprechende Botschaft neu ausgegeben.

task_lcd_sonder:

sonder:	; Updateflag fuer Sondermodus pruefen und ggf. neu ausgeben

	jnb	LCD_XDATA_TASK.7,sonder_end	; MSB = Update-Flag
						; wenn nicht gesetzt weiter
	
	clr	LCD_XDATA_TASK.7		; Update- Flag loeschen


	cjne	A,#TASKNUMMER_CANOUT,sonder_v2	; mit CAN-Task vergleichen	
	call	t_canout				
	jmp	sonder_end
sonder_v2: 
	cjne	A,#TASKNUMMER_STANDBY,sonder_v3	; mit Standbymode vergleichen
	call	t_standby
	jmp	sonder_end
sonder_v3:	
	nop
;	----- hier evtl. Fehlermeldung ungueltige Tasknummer -----

sonder_end:
	; falls im naechsten Zyklus wieder der Standardmodus dran ist
	; fuer diesen alle Updateflags setzen

	setb	LCD_DATA_TASK_L1.7
	setb	LCD_DATA_TASK_L2.7
	setb	LCD_DATA_TASK_L3.7
	setb	LCD_DATA_TASK_L4.7

	ret	

        ;*********************************************************************
	; Task CAN- Ausgabe (im Sondermodus, d.h. braucht ganzes Display)

t_canout:	; die soeben eingelesene CAN_Botschaft in BOX 6 ausgeben
		; an der LCD_Anzeige als HEX- Wert	

	mov	A,#LCD_LINE1		; Zeile 1 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE1		; Zeile 1 CAN_Botschaft
	call	instr_out
	mov	DPTR,#MSX030		 
	call	print_lcd

	mov	R0,#BOX6_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 6

	mov	CAN_DAT,@R0	; HighByte der Kennung anzeigen
	call	outword
	inc	R0

	mov	CAN_DAT,@R0	; LowByte der Kennung anzeigen
	call	outword
	inc	R0

	mov	A,#LCD_LINE2		; Zeile 2 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE2		; Zeile 2 Daten vom CAN
	call	instr_out

	mov	CAN_DAT,@R0	; D0-Register anzeigen
	call	out
	inc	R0

	mov	CAN_DAT,@R0	; D1-Register anzeigen
	call	out
	inc	R0

	mov	CAN_DAT,@R0	; D2-Register anzeigen
	call	out
	inc	R0

	mov	CAN_DAT,@R0	; D3-Register anzeigen
	call	out
	inc	R0

	mov	A,#LCD_LINE3		; Zeile 3 zuerst loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE3		; Zeile 3 Daten vom CAN
	call	instr_out

	mov	CAN_DAT,@R0	; D4-Register anzeigen
	call	out
	inc	R0

	mov	CAN_DAT,@R0	; D5-Register anzeigen
	call	out
	inc	R0

	mov	CAN_DAT,@R0	; D6-Register anzeigen
	call	out
	inc	R0

	mov	CAN_DAT,@R0	; D7-Register anzeigen
	call	out

	mov	A,#LCD_LINE4		; Zeile 4 loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd

	ret

        ;*********************************************************************
	; Task Standby- Ausgabe (im Sondermodus, d.h. braucht ganzes Display)

t_standby:	; am Display alle Zeilen löschen und an einer die Meldung
		; POWERDOWN ausgeben	

	mov	A,#LCD_LINE1		; Zeile 1 loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE2		; Zeile 2 Textausgabe POWERDOWN	
	call	instr_out
	mov	DPTR,#MSG001		 
	call	print_lcd
	
	mov	A,#LCD_LINE3		; Zeile 3 loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd
	
	mov	A,#LCD_LINE4		; Zeile 4 loeschen	
	call	instr_out
	mov	DPTR,#MSG000		 
	call	print_lcd

	ret

out:	mov	A,CAN_DAT
	call	hex_in_ascii
	mov	A,ASCII_H
	call	char_out		; High Byte
	mov	A,ASCII_L
	call	char_out		; Low Byte 
	mov	A,#0FEH
	call	char_out		; Leerzeichen 

	ret

outword:			; Ausgabe des HEXCODES der Botschaft
	mov	A,CAN_DAT	; 4 Zeichen ohne Luecke
	call	hex_in_ascii
	mov	A,ASCII_H
	call	char_out		; High Byte
	mov	A,ASCII_L
	call	char_out		; Low Byte 

	ret

;*****************************************************************************
; ENDE DES QUELLTEXTES
;*****************************************************************************

