;*****************************************************************************
; 	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
;
;       Projekt: HSTG	 		Version Software: V0.16
;					Version Hardware: V1.00
;       
;       Autor: Andreas Hoeger		Build:11_08_03
;
;       --> zusätzlich aendern: 
;	Softwareversion bei den LCD- Ausgabetexten (am Fileende)
;
;	Timing ausgelegt fuer Systemtakt mit 16 MHz Quarz
; 	Speicherauslegung für 12k (3000H)
;
;	Aenderungen:
;	11_02_02: Initial version (=1.18)
;	15_02_02: CAN- Botschaften gemaess neuer Spec 
;	28_02_02: LOOPCNT auf CAN, HSTG_BITS auf CAN
;	03_03_02: neues Taskschema eingefuegt mit TASK_BITS,
;		  Stackueberwachung, ZSTG-Ueberwachung in INIT und zyklisch
;	04_03_02: Menue angepasst und erweitert
;	12_03_02: COMMAND_ZSTG_1 auf CAN ausgeben fuer Schaltkommandos
;	21_04_02: In Init die Standardanzeige-Vorgabe aus EEPROM holen
;		  Standardanzeige-Tasks eingefuegt
;	23_04_02: Aufruf der EEPROM-Erstinbetriebnahmefunktionen eingefuegt
;	30_04_02: MSG606 eingefuegt
;	04_05_02: Errormanagement ZSTG, Applikationsdatenuebertragung
;	10_06_02: Ausgabe Errors ZSTG und MSTG auf CAN eingefuegt
;	11_06_02: Optokopplersignale auswerten eingefuegt
;	18_07_02: EEPROM Ersteinstellungs-Switch zusammengefasst
;		  fuer Bugfix Pageumschaltung, EE_DEBUG_CAN_OUT eingefuegt
;		  Ausgabe EEPROM Inhalte auf neuer CAN Botschaft
;	20_07_02: CAN Rx Routine mit dynamischer Aufrufanzahl
;	20_07_02: CAN Rx in zwei Teile gesplittet
;	26_07_02: Plausi Text für DCF77 eingefuegt
;	21_08_02: Error-Ausgabe MSTG eingefuegt
;		  Netzwerkinit MSTG eingefuegt
;	07_09_02: Bugfix Task Standheizung: Ziel von JMP falsch
;	09_09_02: ADC Texte angepasst
;	27_09_02: ADC Text Spannungsmessung angepasst, ADC Messung eingefuegt
;	28_09_02: Task Powerdown eingefuehrt (MSTG Stromverbrauchsreduzierung)
;		  Zykluszeit erhoeht wegen ZSTG 71 Fehler
;	30_09_02: neue Timeouterkennung fuer ZSTG (robuster)
;		  CAN Botschaft 502h auskommentiert
;	02_10_02: EW_GEBLAESE_PLAUSI eingefuehrt
;	03_10_02: POWERDOWN_MSTG_CNT eingefuehrt in Verbindung mit BIT04
;	          zur Verzoegerung MSTG Abschaltvorgang
;		  MSTG ALIVE Ueberwachung entfernt
;		  CAN_Powerdown in Botschaft 505h eingefuegt
;	01_11_02: Wartezeit bei ERROR_STOP = 0 entfernt
;	10_11_02: Bugfixe: - POWERDOWN_MSTG_CNT,#00H beim ausschalten MSTG 
;		           - #EW_GEBLAESE_PLAUSI deaktiviert
;			   - EEPROM_NEU Switch deaktiviert
;		  Innentemperatur in HSTG Temperatur umbenannt (Menue)
;		  CAN- Datenausgabe Menue angepasst und ergaenzt
;	22_12_02: POWERDOWN_MSTG_CNT auf CAN; Delay MSTG abschalten groesser
;	02_03_03: ueberspringen bei PowerDown eingefuegt und groessere
;		  Zykluszeit bei PowerDown
;	04_03_03: Im PowerDown Sekundenzyklus alle Tasks ausfuehren
;		  Bei PowerDown keine Partnersteuergeraeteueberwachungen
;	27_07_03: Power-Down Anzeige im Display begonnen
;		  Bugfix Kommentar LCD_MENU_CONTROL.6 und .7 bei Umschaltung
;	09_08_03: Power-Down Anzeige im Display: setzen des Update-Bits 
;                 eingefuegt, Ablauf der Anzeige-Umschaltung geändert
;	10_08_03: PD_BIT 07 eingefuehrt fuer Flankenerkennung Klemme 15 0->1
;	11_08_03: Bugfix: PowerDown Umschaltung aus Menuemode
;	xx_yy_zz:
;			
;*****************************************************************************

        $MOD51                	; use 8051 predefined symbols
        $SYMBOLS               	; append symbol table to listing

	;****** Compilerschalter *********************************************

LCD_2x20_4x20	EQU	1	; 1=einbinden, 0=weglassen

NO_CAN		EQU	0	; 1= Betrieb ohne physikalischen CAN,
			        ;    erzeugt keine Fehlermeldungen
				; 0= CAN-Bus angeschlossen mit Gegenstelle,
				;    CAN-Ausfall erzeugt Fehlermeldung

ERROR_STOP	EQU	0	; 1= Fehlermeldung ausgeben, LED blinken
				;    und in diesem Zustand bleiben
				; 0= Fehlermeldung kurz ausgeben und dann
				;    fortfahren

EEPOT_NEU 	EQU 	0	; 0= EEPOT schonmal sinnvoll eingestellt
				; 1= EEPOT neu einstellen auf default

EEPROM_NEU 	EQU 	0	; 0= EEPROM enthaelt schon die Daten
				; 1= Defaultwerte einspeichern in Page 0

				; und von sys_ini in Page 1 kopieren lassen

		; * Hardwareversion
		; * Defaultwerte fuer die Standardanzeige (Auswahl)
		; * Defaultwert fuer CAN- Datenausgabe Identifier
		; * Trennrelaisschaltverhalten

;*****************************************************************************
;	Einbinden der Speicher- Segmentierung und Konstantendefinitionen	
;*****************************************************************************

	$INCLUDE (dseg_equ.asm)	; enthält die ORG, DS und EQU- Anweisungen

;*****************************************************************************
        
        CSEG

        ;*********************************************************************
        ; Interrupt- Vectortabelle
        ;*********************************************************************

        ORG     0000h				;power on / reset vector
        jmp     on_reset

	ORG	0003h				;external interrupt 0 vector
	reti

        ORG     000Bh                           ;timer 0 overflow vector
	reti
        
	ORG     0013h                           ;external interrupt 1 vector
	reti

        ORG     001Bh                           ;timer 1 overflow vector
	reti

        org     0023h                           ;serial I/O interrupt vector
	reti                          

        ORG     002Bh                           ;timer 2 overflow vector
	reti

	ORG	0033h				;?? reserved ??
	reti

        ;*********************************************************************
        ; Beginn Anwendungs- Programmcode
        ;*********************************************************************
        
        ORG     0100H

on_reset:  

	;****** min. 500 ms Wartezeit wegen Errata-Sheet AT89S53 *************
	;****** ISP sonst ab dem zweiten mal blockiert ***********************

	call	sek_1

	;****** System-Initialisierung ***************************************

	mov     IE,#00H			; Interrupts nicht freigeben

	mov     SP,#STACK		; Stackpointer auf Stackbereich 
					; setzen

        mov     BITS,#00H		; Merkerbits loeschen

	setb	BIT05			; Merker fuer "Initphase"
					; 1 = in Init, 0 = Init vorbei
					; wird spaeter geloescht

	call	ini_system		; erst aufrufen, wenn der Stack 
					; aufgesetzt ist !
					; meldet "power on self check"
					; meldet SW / HW- Versionen
					; EEPROM Page Vergleich

	;****** Initialisierung Stack ****************************************

	mov	CNT0,#20H		; Stacklaenge 20H
	mov	R0,#STACK		; indirect adressing
initstack:
	mov	@R0,#STACK_INIT_VALUE		
	inc	R0
	djnz	CNT0,initstack

	mov	STACK_END_MARK,#STACK_END_VALUE	; Endemarkierung fuer 
						; Stackoverflow Erkennung

	;****** Unterprogramm für Ersteinstellungen neuer EEPROMs ************

	; Komponenten werden nur aufgerufen wenn die entsprechenden Switches 
	; aktiviert sind !

	call	ee_new

	;****** Initialisierung zyklischer Ablauf ****************************

	mov     LOOPCNT,#00H		; Zaehler initialisieren fuer 
	mov	TASK_BITS,#00H		; zyklischen Ablauf

	mov	PD_BITS,#00H		; PowerDownManager Kontrollbits

	mov	LCD_XDATA_TASK,#00H	; Tasknummer im "SonderdatenModus"
					; mit Update-Flag (MSB)

	mov	PRELL_COUNT,#00H	; fuer Tastatur- Entprellung
	mov	PRELL_BITS,#00H		; fuer Tastatur- Entprellung

;	mov	LCD_MENU_CONTROL,#00H	; Kontrollwort Menue (Anzeigemodus)
					; Update Flags fuer "MenueModus"

	mov	LCD_MENU_CONTROL,#01H	; Kontrollwort Menue (Anzeigemodus)
					; Standard- Datenausgabe einstellen
					; Menuemode Cursor Zeile 1 default
	mov	LCD_MENU_MODE_NR,#10H	; Grundeinstellung MenueMode Anzeige
					; beim ersten Aufruf Mode 10 
					; --> Texte von Mode 00

	; vier LCD- Zeilen eintragen fuer Menuemodus 00
	; --> das Update-Flag fuer die Menuezeilen wird automatisch gesetzt
	; bei "save_dptr_linex"

	mov	DPTR,#MSG610		; Schaltfunktionen
	call	save_dptr_line1	
	mov	DPTR,#MSG620		; Sondermodus
	call	save_dptr_line2
	mov	DPTR,#MSG630		; Einstellungen
	call	save_dptr_line3
	mov	DPTR,#MSG640		; Anzeigen- Auswahl
	call	save_dptr_line4


	call	set_cursor_line1	; Cursor auf Zeile 1 initialisieren	

	; ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

	call	task_std_from_EEPROM	; aus dem EEPROM die SOLL- Anzeige
					; Tasks holen fuer 
					; Standardanzeige-Mode

	call	task_can_box_switch_from_EE	; aus dem EEPROM den
						; Identifier fuer die CAN-
						; Datenausgabe holen

	; ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

	mov	LCD_XDATA_TASK,#70H	; Task "CAN-Daten" vorgeben
					; für Sonderausgabemodus
	; ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

	mov	EE_DEBUG_CAN_OUT,#00H	; erste EE_Zelle fuer CAN Ausgabe
					; der EEPROM Page 0 Inhalte

	; ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

	mov	OUT_SHIFT,#00H		; Initwert fuer Schieberegister-
					; ausgabe (IC16)

	mov	HZG_COMMAND,#00H	; Kommando an Standheizung

	mov	COMMAND_ZSTG_1,#00H	; Schaltkommandos an ZSTG

	mov	POWERDOWN_CNT,#00H ; Abschaltverzoegerung MSTG

	mov	ERROR,#00H

	;*********************************************************************
	;****** Beginn zyklischer Ablauf - Taskschema ************************
	;*********************************************************************

	clr	BIT05		; Merker fuer "Init-Phase" loeschen
				; da Init jetzt vorbei und alle 
				; Fehlermeldungen anzeigbar sind
				; --> beeinflusst Fehlermeldungen / EE-eintrag

	;****** Initialisierung XSTG Netzwerk ********************************
	;****** --> Unterschied zu oben: mit CAN-RX **************************

	call 	ini_network

	;*********************************************************************
	; CAN RX Buffer Data Overrun Flag loeschen nach Init
	; Flag ist in Status Register SR.1; loeschen in Command Register CMR.3

	mov	CAN_ADR,#CAN_ADR_CMR		; CMR "Clear Data Overrun"
	mov	CAN_DAT,#CAN_CMR_CLROVR
	call	can_write
	;*********************************************************************

start_loop:

	;****** Normalbetriebsverzoegerung
	call	zehn_ms		; !! Aufpassen wegen Zykluszeitverhaeltnissen
	call	zehn_ms		; sonst schlaegt Timeoutzeit ZSTG zu wenn HSTG
	call	zehn_ms		; zu schnell ist
	call	zehn_ms

	;****** NUR BEI POWERDOWN damit ZSTG nicht so oft aufwacht
	jnb	PD_BIT03,timeloopadd_end

	call	sek_1

timeloopadd_end:
	;******

;--> nur zum Test von HSTG Base Relais
;	call	heizluft_ein
;	call	io_shift		; liest Schiebereg. von 
;	call	sek_1

;	call	heizluft_aus
;	call	io_shift		; liest Schiebereg. von 
;	call	sek_1
;--> bis hier Test

	;****** NOTSTOP fuer Fehlerausgabe abfragen

notstop:
	jnb	BITS.7,notstop_end	; dieses Bit wurde bei Fehlermeldung
					; gesetzt. Dort kann aber nicht 
					; gestoppt werden da erst noch die
	IF ERROR_STOP			; LCD- Ausgabe drankommen muss

	jmp	blinkledstop		; verzweige in die
					; Endlosschleife mit Blink- LED
	ELSE

;	call	sek_3			; lange genug anzeigen
;	call	sek_3			; und weitermachen

	ENDIF

notstop_end:

	;****** Taskzaehler erhoehen

	inc	LOOPCNT			; Zaehler fuer Schleifendurchlaufe
					; erhoehen; bei 17 auf 1 zurücksetzen

	mov	TASK_BITS,#00H		; default: zunaechst kein Task aktiv

	;****** Taskmaske berechnen	
	;****** Tasks koennen in jedem zweiten, vierten, achten oder sechzehnten
	;****** Durchlauf aktiviert werden

	mov	A,#11H	
	cjne	A,LOOPCNT,no_overflow
overflow:
	mov	LOOPCNT,#01
no_overflow:
	mov	A,#02
	cjne	A,LOOPCNT,check04
	jmp	set2			
check04:mov	A,#04
	cjne	A,LOOPCNT,check06
	jmp	set24	
check06:mov	A,#06
	cjne	A,LOOPCNT,check08
	jmp	set2	
check08:mov	A,#08
	cjne	A,LOOPCNT,check10
	jmp	set248	
check10:mov	A,#0AH
	cjne	A,LOOPCNT,check12
	jmp	set2	
check12:mov	A,#0CH
	cjne	A,LOOPCNT,check14
	jmp	set24	
check14:mov	A,#0EH
	cjne	A,LOOPCNT,check16
	jmp	set2	
check16:mov	A,#10H
	cjne	A,LOOPCNT,checkend
	jmp	set24816	
checkend:jmp	task_calc_end		; no active task

set2:	mov	TASK_BITS,#01H
	jmp	task_calc_end
set24:	mov	TASK_BITS,#03H
	jmp	task_calc_end
set248: mov	TASK_BITS,#07H
	jmp	task_calc_end
set24816: mov	TASK_BITS,#0FH

	;****** Nur bei PowerDown: wegen Ein-Sekunden-Zyklus alle 
	;	verbliebenen Tasks aktivieren
	jnb	PD_BIT03,alltaskactive_end

	mov	TASK_BITS,#0FH

alltaskactive_end:


task_calc_end:


task_menu:
;	clr	LCD_MENU_CONTROL.7	; Grundzustand Standardausgabe
;	clr	LCD_MENU_CONTROL.6	; zunaechst default einstellen
					; am Zyklusanfang und dann
					; LCD_MENU_CONTROL pruefen

	call	io_shift		; liest Schiebereg. von 
					; Tastatur ein, Ergebnis in
					; IN_TAST und IN_OPTO
					; beidesmal invertiert

					; gibt OUT_SHIFT zerstoerungsfrei
					; an Ausgangsschiebregister

; Ausgaberelais:	; Bit 0 (LSB): Relais 08: Wegfahrsperre
; OUT_SHIFT		; Bit 1      : Relais 07: Servomotor Ascher
			; Bit 2      : Relais 06: Geblaese WT hinten
			; Bit 3	     : Relais 05: Geblaese Stufe 1 Webasto
			; Bit 4      : Relais 04: ---
			; Bit 5	     : Relais 03: Powerlicht Fern
			; Bit 6	     : Relais 02: Powerlicht Abblend
			; Bit 7	(MSB): Relais 01: Powerlicht NSW

	call	tast_invert		; Tastaturergebnis
					; (IN_TAST) invertieren, damit
					; "gedrueckt = high"

	call	entprell		; Tastaturzustand pruefen und
					; bestimmte Anzahl gleicher
					; Zustaende fordern bis Taste gilt
	
	; Ergebnis von Entprellung: gültige Taste in PRELL_BITS[7:4] und 
	;		            LCD_MENU_CONTROL.5 gesetzt
	;		  ODER	    kein gueltiger Zustand,
	;		            LCD_MENU_CONTROL.5 geloescht					
					 
	jnb	LCD_MENU_CONTROL.5,task_menu_end	; keine gueltige
							; Taste erkannt

	call	menu	; Aufruf Menueverzweigungen da gueltige Taste
			; Die Taste kann in PRELL_BITS[7:4] gelesen werden
			; Es wird der Menue-Mode entsprechend umgeschaltet
			; und die Cursorzeile gesetzt

task_menu_end:


task_optokopp:
	;****** Task "Optokoppler Signale auswerten"

; Optokoppler (inv.)	; Bit 0 (LSB): Stecker 09: Standheizung Schaltuhr
; IN_OPTO		; Bit 1      : Stecker 11: Wegsignal Tacho 
			; Bit 2	     : Stecker 13: WAECO Komfortfuktion
			; Bit 3	     : Stecker 15: Powerlicht Schalter
			; Bit 4	     : Stecker 16: Klemme 58 Licht
			; Bit 5	     : Stecker 14: Klemme 15
			; Bit 6	     : Stecker 12: Spritzwasserstand vorn
			; Bit 7 (MSB): Stecker 10: D+ erfassen

	; Hinweis: Klemme 58, 15 und D+ werden von ZSTG aus dem Signal
	; 	   entnommen und ausgewertet

	; AM OPTOKOPPLER SIND ALLE SIGNALE INVERTIERT !!!
	; ABER IN DER FOLGENDEN AUSWERTUNG LOGISCH UMGEDREHT !!!

	;****** Standheizung Schaltuhr
opto_bit0:
	mov	A,IN_OPTO
	rrc	A
	jc	bit0_isOff
bit0_isSet:
	call	schaltuhr_hzg_ein
	jmp	opto_bit2
bit0_isOff:
	call	schaltuhr_hzg_aus

	;****** WAECO Komfortfunktion
opto_bit2:
	mov	A,IN_OPTO
	rrc	A
	rrc	A
	rrc	A
	jc	bit2_isOff
bit2_isSet:
	call	waeco_hzg_ein
	jmp	opto_bit4
bit2_isOff:
	call	waeco_hzg_aus

	;****** WAECO Komfortfunktion
opto_bit4:
	mov	A,IN_OPTO
	rlc	A
	rlc	A
	rlc	A
	rlc	A
	jc	bit4_isOff
bit4_isSet:
	call	displaybel_58_ein
	jmp	task_optokopp_end
bit4_isOff:
	call	displaybel_58_aus

task_optokopp_end:


task_pd_manager:

	jnb	TASK_BITS.2,task_pd_manager_end	; wie Botschaft 504h und 505h
						; weil dort Kommandos an MSTG
						; und ZSTG gesendet werden

	;****** MSTG wegen Stromverbrauch nur einschalten wenn Klemme 15 aktiv

	;****** Ausnahme: Wenn Standheizung eingeschaltet wurde, dann muss MSTG
	;	gebootet werden damit die Standheizungs-Lueftungsanforderung
	;       vom CAN aufgenommen werden kann.

	;****** Optokoppler Bit 5 betrachten = Klemme 15; ACHTUNG invertiert !

	mov	A,IN_OPTO
	rlc	A
	rlc	A
	rlc	A
	jc	bit5_isOff
bit5_isSet:

	;****** Flankenerkennung Klemme 15 0->1 um beim Beenden des Standby
	;	Modes die LCD- Anzeige wieder zu beleben (Mode umschalten und
	;	update Bits)

	jnb	PD_BIT07,bit5_notInitialActive 	; es ist keine Rückkehr aus Standby
			
	; Bit 07 ist gesetzt, also erste Rückkehr aus Standby (Klemme 15 0->1). Daher
	; - LCD Mode umschalten
	; - Bit 07 wieder loeschen
	
	clr	LCD_MENU_CONTROL.6	; Sondermode ausschalten
		
	clr	LCD_MENU_CONTROL.7	; auch Bit 7 in Menuemode zuruecksetzen
					; weil Sondermode beendet wird
	clr	PD_BIT07		; loesche Merker fuer Flanke Klemme 15-->1
					; Erkennung
	;mov	LCD_MENU_MODE_NR,#00H	; Menuemode zuruecksetzen
					; falls man aus Menue in Standby kam
	;call	set_cursor_line1

bit5_notInitialActive:

	;****** Kl. 15 an, daher alle PowerDown Bits ruecksetzen
	call	mstg12v_ein		; auf jeden Fall einschalten, beenden

	clr	PD_BIT01	; clear PD_BIT01: = MSTG BIT04
				;		  = ZSTG BIT04
				;                 = HSTG Partnerstg.Ueberw off
	clr	PD_BIT02	; clear PD_BIT02: = HSTG Debug Info off
				;		  = MSTG ausschalten an ZSTG
				;    		  = ZSTG IDLE, CAN sleep mode
	clr	PD_BIT03	; clear PD_BIT03: = HSTG CAN Sleep mode
				;		  = HSTG no can tx
	mov	POWERDOWN_CNT,#00H	; setze Abschaltverzoegerung
					; zurueck
	jmp	task_pd_manager_end

bit5_isOff:

	;****** Kl. 15 aus, aber wegen Standheizung evtl. doch einschalten

	mov 	A,HZG_COMMAND		; wenn !=0 dann hat mind. eine
					; Quelle die Standheizung aktiviert
	jz	pd_mstgoff	
pd_mstgon:
	call	mstg12v_ein		; nicht Null --> einschalten MSTG
					; fuer Standheizung
	clr	PD_BIT01	; siehe Kommentar oben
	clr	PD_BIT02	; siehe Kommentar oben
	clr	PD_BIT03	; siehe Kommentar oben
	mov	POWERDOWN_CNT,#00H	; setzte Abschaltverzoegerung
					; zurueck
	jmp	task_pd_manager_end

pd_mstgoff:
	
	;****** send CAN message to MSTG first to stop it from sending on CAN
	;       before power of MSTG is really switched off by ZSTG

	setb	PD_BIT01		; Vorbereitungsphase PowerDown
					; MSTG wird aufgefordert CAN einzustellen
					; erst verzoegert tatsaechlich 
					; MSTG abschalten anfordern
	;****** begin or continue incrementing PowerDown counter

	jb	PD_BIT03,increment_end	; do not count higher than needed
	mov	A,POWERDOWN_CNT		; because then the overflow will
	inc	A			; destroy everything !
	mov	POWERDOWN_CNT,A
increment_end:

	;****** compare counter and set PD_BIT02 if delay reached

cmp_delay_cycles_pdbit02:

	mov	A,POWERDOWN_CNT		; Zaehler zum auswerten laden
	jz	cmp_delay_cycles_pdbit02_end	; Sicherheitsabfrage
	mov	CNT0,#PDBIT02_DELAY_CYCLES	; Vergleichswert laden
pdbit02_cmp:
	dec	A
	jz	cmp_delay_cycles_pdbit02_end	; Counter < Vergleichswert
	djnz	CNT0,pdbit02_cmp		; loop PDBIT02_DELAY_CYCLES
						
	setb	PD_BIT02			; setze PD_BIT02 weil
						; Vergleichswert ueberschritten
cmp_delay_cycles_pdbit02_end:

	;****** compare counter and set PD_BIT03 if delay reached

cmp_delay_cycles_pdbit03:

	mov	A,POWERDOWN_CNT		; Zaehler zum auswerten laden
	jz	cmp_delay_cycles_pdbit03_end	; Sicherheitsabfrage
	mov	CNT0,#PDBIT03_DELAY_CYCLES	; Vergleichswert laden
pdbit03_cmp:
	dec	A
	jz	cmp_delay_cycles_pdbit03_end	; Counter < Vergleichswert
	djnz	CNT0,pdbit03_cmp		; loop PDBIT03_DELAY_CYCLES
						
	setb	PD_BIT03			; setze PD_BIT03 weil
						; Vergleichswert ueberschritten
cmp_delay_cycles_pdbit03_end:

	;****** ZSTG veranlassen MSTG abzuschalten wenn notwendig

switchoff:
	jnb	PD_BIT02,notswitchoffyet	
	call	mstg12v_aus	; sendet Abschaltanforderung fuer MSTG 
				; an ZSTG zur Umsetzung
notswitchoffyet:

task_pd_manager_end:


task_temp:

	;****** nicht ausfuehren bei PowerDown
	jb	PD_BIT03,task_temp_end_uml	
	;****** Task "Temperatur messen"

	jb	TASK_BITS.2,temp_einlesen
	; Achtung ! Wenn Temperatur in CAN- Botschaft 500 immer ausgegeben 
	; wird muss auch immer gemessen werden, sonst falsche Werte dazwischen
	jmp	temp_einlesen

task_temp_end_uml:

	jmp	task_temp_end

temp_einlesen:

	;**** Temperatur einlesen

	mov	I2C_ADR_H,#00H		
	mov	I2C_ADR_L,#DS_READ_TEMP	; Command: read temperature
	mov	I2C_ID,#DS_ID	

	call	read_ds_random_2byte	; Ergebnis in TEMP_H und TEMP_L

	;**** Tendenzanzeige
	; vergleich mit altem Wert im EEPROM: 	EE_TEMP_H_OLD
	
	; SPAETER EVTL NOCH EINBAUEN:
	; vergleich mit seitherigen Maxima:	EE_TEMP_MAX
	; vergleich mit seitherigem Minima:	EE_TEMP_MIN
	
	; alte Temperatur holen und vergleichen, Bit02 entsprechend setzen
	; als Kennzeichnung fuer Uebergabe an LCD-Anzeige
	; Bit02 = 0 bei fallender Temperatur (bei LCD Ausgabe Pfeil ab)
	; Bit02 = 1 bei steigender Temperatur (bei LCD Ausgabe Pfeil auf)

	; Positive / negative Werte werden an dieser Stelle noch durch
	; das MSB unterschieden; spaeter nach Konvertiertung fuer LCD
	; wird ein Merkerbit benutzt fuer positiv / negativ Kennzeichnung

	; Die folgenden Vergleichsalgorithmen ergeben bei gleichem Wert
	; immer Pfeil up; daher bei gleichen Werten alt/neu Vergleichs-
	; routinen ueberspringen

	mov	I2C_ADR_H,#00H			; Page 0
	mov	I2C_ADR_L,#EE_TEMP_H_OLD	; Adresse des Nutzbytes
	mov	I2C_ID,#EE_ID
	call	read_random			; Ergebnis in I2C_DATA

	; jetzt ist I2C_DATA = alter Temperaturwert TEMP_H
	; jetzt ist TEMP_H = aktueller Temperaturwert

;	mov	CAN_D4,I2C_DATA		; EEPROM_Temperaturwert auf CAN_D4

	; zuerst pruefen ob Werte gleich sind; dann gleich weitergehen
	; und Bit02 nicht veraendern

	mov	A,TEMP_H
	cjne	A,I2C_DATA,start_temp_vgl	; vergleichen und Bit entsprechend 
						; setzen
	jmp	temp_restlich			; Vergleichsroutinen ueberspringen,
						; nur TEMP- Ausgabe CAN und LCD
	
start_temp_vgl:

	; Achtung: Beim nun folgenden Vergleich darf TEMP_H nicht veraendert werden
 	
	mov	CNT2,TEMP_H			; sichern, wegen neg/neg Vergleich

test_pol_old:
	mov	ACC,I2C_DATA		; laden zum Polaritaet ermitteln
	rlc	A
	jc	test_pol_new1		; alter Wert ist negativ
	jmp	test_pol_new2		; alter Wert ist positiv

test_pol_new1:		; alter Wert negativ, neuer positiv ?

	mov	ACC,TEMP_H
	rlc	A
	jnc	pfeil_up		; neuer Wert ist positiv
	jmp	vgl_neg_neg		; neuer Wert auch negativ

test_pol_new2:		; alter Wert positiv, neuer positiv ?

	mov	ACC,TEMP_H
	rlc	A
	jc	pfeil_down
	jmp	vgl_pos_pos

vgl_neg_neg:		; es sind sicher zwei negative Werte
			; daher zuerst MSBs loeschen

	mov	ACC,TEMP_H
	rlc	A
	clr	C
	rrc	A	; das hat das MSB geloescht

	mov	ACC,I2C_DATA
	rlc	A
	clr	C
	rrc	A	; das hat das MSB geloescht

	mov	ACC,TEMP_H		; zum runterzaehlen
	mov	CNT0,I2C_DATA		; Vergleichswert laden

vgl_neg_loop:

	; DS1621: wenig kalt = FF !

	dec	A
	jz	pfeil_down	; Betrag von TEMP_H war kleiner
				; als Vergleichwert I2C
				; also pfeil_down, kaelter
	djnz	CNT0,vgl_neg_loop
	jmp	pfeil_up	; Betrag von TEMP_H war groesser
				; als Vergleichswert
				; also pfeil_up, waermer

vgl_pos_pos:
	mov	ACC,TEMP_H		; zum runterzaehlen
	mov	CNT0,I2C_DATA		; Vergleichswert laden
vgl_pos_loop:
	dec	A
	jz	pfeil_down	; TEMP_H war kleiner als Vergleichwert I2C
				; also pfeil_down
	djnz	CNT0,vgl_pos_loop
	jmp	pfeil_up	; TEMP_H war groesser als Vergleichswert
				; also pfeil_up
	
pfeil_up:	

	setb	bit02		; Kennzeichen fuer LCD
	jmp	tendenz_end

pfeil_down:	

	clr	bit02		; Kennzeichen fuer LCD

tendenz_end:
	mov	TEMP_H,CNT2		; Sicherungskopie zurueckholen

	; TEMP_H (neuer Wert) im EEPROM ablegen als EE_TEMP_H_OLD

	;mov	I2C_ADR_H,#00H			; Page 0
	mov	I2C_ADR_L,#EE_TEMP_H_OLD	; Adresse des Nutzbytes
	mov	I2C_ID,#EE_ID
	mov	I2C_DATA,TEMP_H			; aktueller Temperaturwert
	call	write_byte
	
temp_restlich:

	;**** Ausgabe auf LCD- Anzeige 

	jnb	TASK_BITS.3,task_temp_end	; nicht jedesmal ausfuehren
						; abhaengig von TASK_BITS

	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen
	; Hinweis: Dieser Task hat Nummer 10H

	mov	A,#TASKNUMMER_TEMP	; entspricht 10H
	call	task_check_update	; durchsucht und setzt ggf. Flag

	;**** Ausgabe Temperatur auf CAN erfolgt unten

	;mov	CAN_D1,TEMP_H		; in Sendepuffer schreiben
	;mov	CAN_D2,TEMP_L
	
task_temp_end:

task_temp_out:	
	;****** Task "Aussentemperatur ausgeben"

	jnb	TASK_BITS.3,task_temp_out_end

	; fuer Ausgabe auf LCD- Anzeige 
	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen

	mov	A,#TASKNUMMER_TEMP_OUT
	call	task_check_update	; durchsucht und setzt ggf. Flag
	
task_temp_out_end:

task_dcf77:	
	;****** Task "DCF77_Signal ausgeben"

	jnb	TASK_BITS.3,task_dcf77_end

	; fuer Ausgabe auf LCD- Anzeige 
	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen

	mov	A,#TASKNUMMER_DCF77
	call	task_check_update	; durchsucht und setzt ggf. Flag
	
task_dcf77_end:

task_canrx1:
	;****** Task "CAN_Botschaften empfangen"
	;****** und Inhalte in Mailboxen verteilen

	jnb	TASK_BITS.2,task_canrx1_end

	mov	CAN_RX_CNT_1,#CAN_RX_CALL_TO	; maximale Anzahl

rx1_again:	
	call	can_rx	        ; pruefen ob Botschaft im Empfangspuffer
				; des SJA1000 ist; ggf. Identifier lesen 
				; und Botschaft in Mailbox uebertragen

	; Rückgabewerte in Akku: 0 = war nix
	;			 1 = Botschaft war da

	jnz	enter_rx1_again

	jmp	task_canrx1_end	; Rx Buffer is empty, go on

enter_rx1_again:
	djnz	CAN_RX_CNT_1,rx1_again 
	
	; number of calls too high (counter == zero)	

	mov	ERROR,#EW_CAN_RX_OVERLOAD
	call	errorcode_out		; Fehlermeldung generieren

task_canrx1_end:


task_voltamp:	
	;****** Task "Volt / Ampere ausgeben"

	jnb	TASK_BITS.3,task_voltamp_end

	; fuer Ausgabe auf LCD- Anzeige 
	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen

	mov	A,#TASKNUMMER_VOLTAMP
	call	task_check_update	; durchsucht und setzt ggf. Flag
	
task_voltamp_end:

task_llk_temp:	
	;****** Task "Ladelufttemperatur ausgeben"

	jnb	TASK_BITS.3,task_llk_temp_end

	; fuer Ausgabe auf LCD- Anzeige 
	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen

	mov	A,#TASKNUMMER_LLK_TEMP
	call	task_check_update	; durchsucht und setzt ggf. Flag
	
task_llk_temp_end:

task_llk_druck:	
	;****** Task "Ladedruck ausgeben"

	jnb	TASK_BITS.3,task_llk_druck_end

	; fuer Ausgabe auf LCD- Anzeige 
	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen

	mov	A,#TASKNUMMER_LLK_DRUCK
	call	task_check_update	; durchsucht und setzt ggf. Flag
	
task_llk_druck_end:

task_oeltemp:	
	;****** Task "Oeltemperatur ausgeben"

	jnb	TASK_BITS.3,task_oeltemp_end

	; fuer Ausgabe auf LCD- Anzeige 
	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen

	mov	A,#TASKNUMMER_OELTEMP
	call	task_check_update	; durchsucht und setzt ggf. Flag
	
task_oeltemp_end:

task_oeldruck:	
	;****** Task "Oeldruck ausgeben"

	jnb	TASK_BITS.3,task_oeldruck_end

	; fuer Ausgabe auf LCD- Anzeige 
	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen

	mov	A,#TASKNUMMER_OELDRUCK
	call	task_check_update	; durchsucht und setzt ggf. Flag
	
task_oeldruck_end:


task_cantx_1:
	;****** Task "CAN Grunddaten Botschaften senden"

	;**** zyklische CAN- Botschaftsausgabe 500 (Status 1 HSTG)
	;**** immer abschicken ausser bei CAN-Sleep-Mode
	jb	PD_BIT03,task_cantx_1_end

	mov	CAN_I1,#0A0H		; Botschaft definieren
	mov	CAN_I2,#08H		; 500h senden

	mov	CAN_D0,LOOPCNT		; Zykluszaehler
	mov	CAN_D1,TEMP_H		; TEMP_H und
	mov	CAN_D2,TEMP_L		; TEMP_L
	mov	CAN_D3,PD_BITS		; Einzelbits fuer PowerDownManagement		
	mov	CAN_D4,IN_OPTO		; Optokopplereingang		
	mov	CAN_D5,#00H
	mov	CAN_D6,#00H
	mov	CAN_D7,#00H
					
	call	can_tx

	;**** zyklische CAN- Botschaftsausgabe 501 (Applikationsdaten ZSTG)

	jnb	TASK_BITS.1,task_cantx_1_end

	mov	CAN_I1,#0A0H		; Botschaft definieren
	mov	CAN_I2,#28H		; 501h senden

	mov	I2C_ID,#EE_ID
	mov	I2C_ADR_L,#EE_DPLUS_SOWI	; Sommer/Winter D+ Charakt.
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D0,I2C_DATA	

	mov	CAN_D1,#00H 
	mov	CAN_D2,#00H
	mov	CAN_D3,#00H
	mov	CAN_D4,#00H
	mov	CAN_D5,#00H
	mov	CAN_D6,#00H
	mov	CAN_D7,#00H
					
	call	can_tx

	;**** zyklische CAN- Botschaftsausgabe 502 (Applikationsdaten MSTG)

;	jnb	TASK_BITS.1,task_cantx_1_end

;	mov	CAN_I1,#0A0H		; Botschaft definieren
;	mov	CAN_I2,#48H		; 502h senden

;	mov	CAN_D0,#11H		; 
;	mov	CAN_D1,#22H		; 
;	mov	CAN_D2,#33H
;	mov	CAN_D3,#44H
;	mov	CAN_D4,#55H
;	mov	CAN_D5,#66H
;	mov	CAN_D6,#77H
;	mov	CAN_D7,#88H
					
;	call	can_tx

task_cantx_1_end:

task_cantx_2:

	;****** Task "CAN Kommando-Botschaften senden"

	jnb	TASK_BITS.2,task_cantx_2_end

	;**** zyklische CAN- Botschaftsausgabe 503 (Standheizung HSTG Data)
	;**** immer abschicken ausser bei CAN-Sleep-Mode
	jb	PD_BIT03,task_cantx_2_end

	mov	CAN_I1,#0A0H		; Botschaft definieren
	mov	CAN_I2,#68H		; 503h senden

	mov	CAN_D0,HZG_COMMAND	; Kommando an Standheizung 
	mov	CAN_D1,IN_OPTO		; Optokopplereingang

	mov	A,CAN_D1		; ausmaskieren aller Bits die nicht 
	anl	A,#03H			; fuer Standheizung relevant sind
	mov	CAN_D1,A		; Bit A = Schaltuhr, Bit B = Waeco
 
	mov	CAN_D2,#00H
	mov	CAN_D3,#00H
	mov	CAN_D4,#00H
	mov	CAN_D5,#00H
	mov	CAN_D6,#00H
	mov	CAN_D7,#00H
					
	call	can_tx

	;**** zyklische CAN- Botschaftsausgabe 504 (Kommandos an ZSTG)

	mov	CAN_I1,#0A0H		; Botschaft definieren
	mov	CAN_I2,#88H		; 504h senden

	mov	CAN_D0,COMMAND_ZSTG_1	; Schaltkommandos an ZSTG 
	mov	CAN_D1,POWERDOWN_CNT 	; Abschaltcounter PowerDown
					
	mov	CAN_D2,#33H
	mov	CAN_D3,#44H
	mov	CAN_D4,#55H
	mov	CAN_D5,#66H
	mov	CAN_D6,CAN_RX_CNT_1	; preliminary
	mov	CAN_D7,CAN_RX_CNT_2	; preliminary		
	call	can_tx

	;**** zyklische CAN- Botschaftsausgabe 505 (Kommandos an MSTG)

	mov	CAN_I1,#0A0H		; Botschaft definieren
	mov	CAN_I2,#0A8H		; 505h senden

;	CAN_D0 siehe unten
	mov	CAN_D1,STACK		;Stack Overflow 
	mov	CAN_D2,STACK_1		;preliminary 
	mov	CAN_D3,STACK_2
	mov	CAN_D4,STACK_3
	mov	CAN_D5,STACK_END_MARK
	mov	CAN_D6,OLD_ZSTG_CNT
	mov	CAN_D7,#00H

	;****** Abhaengig von Powerdown-Manager-Bit PD_BIT01
	;	MSTG dazu veranlassen CAN einzustellen

	jnb	PD_BIT01,CAN_nopowerdown
CAN_powerdown:
	mov	CAN_D0,#01H		; MSTG soll CAN einstellen
	jmp	CAN_powerdown_end
CAN_nopowerdown:
	mov	CAN_D0,#00H		; MSTG soll weitersenden
CAN_powerdown_end:
					
	call	can_tx

task_cantx_2_end:

task_cantx_3:

	;****** bei PowerDown keine Debugging Info auf CAN ! *****
	jb	PD_BIT02,task_cantx_3_end	

	;****** Task "CAN Debugging Botschaften senden"

	jnb	TASK_BITS.1,task_cantx_3_end

	;**** zyklische CAN- Botschaftsausgabe 506 (EEPROM Page 0 Inhalte)

	mov	CAN_I1,#0A0H		; Botschaft definieren
	mov	CAN_I2,#0C8H		; 506h senden

	mov	I2C_ID,#EE_ID
	mov	I2C_ADR_H,#00H		; Page 0 
	
	; !! hier immer Page 0 ausgeben

	mov	I2C_ADR_L,EE_DEBUG_CAN_OUT	; Adresse Ausgabebyte holen
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D0,I2C_DATA	

	inc	I2C_ADR_L
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D1,I2C_DATA	

	inc	I2C_ADR_L
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D2,I2C_DATA	

	inc	I2C_ADR_L
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D3,I2C_DATA	

	inc	I2C_ADR_L
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D4,I2C_DATA	

	inc	I2C_ADR_L
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D5,I2C_DATA	

	inc	I2C_ADR_L
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D6,I2C_DATA	

	inc	I2C_ADR_L
	call	read_random_internal		; Ergebnis in I2C_DATA
	mov	CAN_D7,I2C_DATA	

	inc	I2C_ADR_L
	mov	EE_DEBUG_CAN_OUT,I2C_ADR_L	; Adresse EE-Ausgabebyte
						; sichern fuer naechsten Zyklus
	call	can_tx

task_cantx_3_end:

task_cantx_4:

	;****** bei PowerDown keine Debugging Info auf CAN ! *****
	jb	PD_BIT02,task_cantx_4_end	

	;****** Task "CAN Debugging Botschaften senden"

	jnb	TASK_BITS.1,task_cantx_4_end

	;**** zyklische CAN- Botschaftsausgabe 507 (Fehlerspeicher Partner-STG)

	mov	CAN_I1,#0A0H		; Botschaft definieren
	mov	CAN_I2,#0E8H		; 507h senden

	mov	I2C_ID,#EE_ID

	mov	I2C_ADR_L,#EE_ERRORMEM_ZSTG_0	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D0,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_ZSTG_1	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D1,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_ZSTG_2	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D2,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_ZSTG_3	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D3,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_MSTG_0	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D4,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_MSTG_1	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D5,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_MSTG_2	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D6,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_MSTG_3	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D7,I2C_DATA	
					
	call	can_tx

task_cantx_4_end:

task_cantx_5:

	;****** bei PowerDown keine Debugging Info auf CAN ! *****
	jb	PD_BIT02,task_cantx_5_end	

	;****** Task "CAN Debugging Botschaften senden"

	jnb	TASK_BITS.1,task_cantx_5_end

	;**** zyklische CAN- Botschaftsausgabe 508 (Fehlerspeicher)

	mov	CAN_I1,#0A1H		; Botschaft definieren
	mov	CAN_I2,#08H		; 508h senden

	mov	I2C_ID,#EE_ID

	mov	I2C_ADR_L,#EE_ERRORMEM_0	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D0,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_1	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D1,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_2	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D2,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_3	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D3,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_4	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D4,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_5	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D5,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_6	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D6,I2C_DATA	

	mov	I2C_ADR_L,#EE_ERRORMEM_7	; Adresse Fehlerspeicherbyte
	call	read_random		        ; Ergebnis in I2C_DATA
	mov	CAN_D7,I2C_DATA	
					
	call	can_tx

	;**** zyklische CAN- Botschaftsausgabe 509 (Debugging Botschaft)

	mov	CAN_I1,#0A1H		; Botschaft definieren
	mov	CAN_I2,#28H		; 509h senden

	mov	CAN_D0,IN_TAST		; Tastatureingabe (invertiert)
	mov	CAN_D1,IN_OPTO		; Optokopplereingang
	mov	CAN_D2,LCD_MENU_MODE_NR ; Menue-Modes
	mov	CAN_D3,LCD_MENU_CONTROL ; Menuesteuerung Kontrollwort
	mov	CAN_D4,BITS		; Merkerbyte
	mov	CAN_D5,PRELL_BITS	; entprelltes Tastenergebnis
	mov	CAN_D6,PRELL_COUNT	; Zaehler fuer Tastenentprellung
	mov	CAN_D7,OUT_SHIFT	; Ausgangsschieberegister
					
	call	can_tx

task_cantx_5_end:

task_canrx2:
	;****** Task "CAN_Botschaften empfangen"
	;****** und Inhalte in Mailboxen verteilen

	jnb	TASK_BITS.2,task_canrx2_end

	mov	CAN_RX_CNT_2,#CAN_RX_CALL_TO	; maximale Anzahl

rx2_again:	
	call	can_rx    	; pruefen ob Botschaft im Empfangspuffer
				; des SJA1000 ist; ggf. Identifier lesen 
				; und Botschaft in Mailbox uebertragen

	; Rückgabewerte in Akku: 0 = war nix
	;			 1 = Botschaft war da

	jnz	enter_rx2_again

	jmp	task_canrx2_end	; Rx Buffer is empty, go on

enter_rx2_again:
	djnz	CAN_RX_CNT_2,rx2_again 
	
	; number of calls too high (counter == zero)	

	mov	ERROR,#EW_CAN_RX_OVERLOAD
	call	errorcode_out		; Fehlermeldung generieren

task_canrx2_end:


task_standheizung:

	;****** Pruefen ob Luftgeblaese Stufe 1 eingeschaltet werden
	;       muss weil Webasto es anfordert ueber CAN
	;       Botschaft 511h in Mailbox 2 auswerten;
	;       Byte 0: 41h = ein / 40h und 00h = aus

	jnb	TASK_BITS.2,task_standheizung_end	; wie CAN_RX !!

	;****** Mailbox 2, Botschaft 511 (Standh. MSTG Data) abfragen

	; die soeben eingelesene CAN_Botschaft in BOX 2 auswerten

	; BOX2_C: 	CAN Mailbox 2	Controlbyte
	; BOX2_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX2_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX2_0:	CAN Botschaft Mailbox --> Nutzdaten Geblaese

	mov	R0,#BOX2_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 2
	inc	R0
	inc	R0			; zeigt auf Byte 0

	mov	ACC,@R0		; hole byte 0 in Akku
	
	cjne	A,#GEBLAESE_SET,geblaese_aus

geblaese_ein:
	
	; Plausibilisieren: nur einschalten wenn auch eine 
	; Heizung-Anforderung vorliegt

	mov	A,HZG_COMMAND
	jnz	geblaese_really_ein
	
;	mov	ERROR,#EW_GEBLAESE_PLAUSI
;	call	errorcode_out		; Fehlermeldung generieren
;	--> deaktiviert weil Ausschalten schiefgeht:
;	    HZG_COMMAND sofort weg, aber Lueftung verspaetet
	jmp	geblaese_aus

geblaese_really_ein:
	call	heizluft_ein		; Maskierung auf "OUT_SHIFT"
	jmp	task_standheizung_end

geblaese_aus:

	call	heizluft_aus

task_standheizung_end:


task_partner_stgx:
zstg_alive_check:

	;****** nicht ausfuehren bei POWERDOWN

	jb	PD_BIT01,task_partner_stgx_end

	;****** Pruefen ob Zaehler ZSTG in Statusbotschaft noch zaehlt

	jnb	TASK_BITS.2,task_partner_stgx_end	; wie CAN_RX !!

	;****** Mailbox 3 nach Botschaft 520 (ZSTG Status) abfragen

	; die soeben eingelesene CAN_Botschaft in BOX 3 auswerten

	; BOX3_C: 	CAN Mailbox 3	Controlbyte
	; BOX3_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX3_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX3_0:	CAN Botschaft Mailbox --> ALIVE-Counter ZSTG

	mov	R0,#BOX3_C		; indirect adressing
	inc	R0			; Basisadresse Mailbox 3
	inc	R0
	inc	R0			; zeigt auf Byte 0

	;****** Pruefen ob ZSTG noch laufenden Zaehler in Statusmeldung sendet

	mov	ACC,@R0		; hole byte 0 in Akku

	cjne	A,OLD_ZSTG_CNT,zstg_alive
	cjne	A,OLD_ZSTG_CNT_1,zstg_alive
	cjne	A,OLD_ZSTG_CNT_2,zstg_alive

	mov	ERROR,#EW_ZSTG_MISSING_ZYKL
;	call	errorcode_out		; Fehlermeldung generieren
	jmp	zstg_error

zstg_alive:
	;****** Zaehlerstaende durch "Schieberegister" schieben
	;       immer drei aeltere Werte sichern
	mov	OLD_ZSTG_CNT_2,OLD_ZSTG_CNT_1	; oldest = xxx_2
	mov	OLD_ZSTG_CNT_1,OLD_ZSTG_CNT	; older  = xxx_1
	mov	OLD_ZSTG_CNT,A

	;****** Pruefen ob ZSTG in Statusbotschaft ERROR sendet
	;	Falls ja, dann in EEPROM eintragen und anzeigen am Display
zstg_error:
	inc	R0	
	inc	R0	
	inc	R0	
	inc	R0
	inc	R0
	inc	R0
	inc	R0		; zeige auf Byte 7 (ERROR)
	mov	ACC,@R0		; hole byte 7 in Akku

	cjne	A,#00H,zstg_error_eintrag
	jmp	zstg_error_end

zstg_error_eintrag:

	mov	ERROR,ACC
	call	zstg_errorcode_out		; Fehlermeldung generieren
						; und in EE eintragen
zstg_error_end:	

	;****** Mailbox 3 nach Botschaft 510 (MSTG Status) abfragen

	; die soeben eingelesene CAN_Botschaft in BOX 1 auswerten

	; BOX1_C: 	CAN Mailbox 1	Controlbyte
	; BOX1_IH: 	CAN High Byte Botschaftsnumer [HEX]
	; BOX1_IL: 	CAN Low Byte Botschaftsnumer [HEX]
	; BOX1_0:	CAN Botschaft Mailbox --> ALIVE-Counter MSTG

	;****** --> nur wenn MSTG nicht POWERDOWN ist !
	jb	PD_BIT01,task_partner_stgx_end

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

	;****** Pruefen ob MSTG noch laufenden Zaehler in Statusmeldung sendet

	mov	ACC,@R0		; hole byte 0 in Akku

	cjne	A,OLD_MSTG_CNT,mstg_alive
	cjne	A,OLD_MSTG_CNT_1,mstg_alive
	cjne	A,OLD_MSTG_CNT_2,mstg_alive

	mov	ERROR,#EW_MSTG_MISSING_ZYKL
;	call	errorcode_out		; Fehlermeldung generieren
	jmp	mstg_error

mstg_alive:
	;****** Zaehlerstaende durch "Schieberegister" schieben
	;       immer drei aeltere Werte sichern
	mov	OLD_MSTG_CNT_2,OLD_MSTG_CNT_1	; oldest = xxx_2
	mov	OLD_MSTG_CNT_1,OLD_MSTG_CNT	; older  = xxx_1
	mov	OLD_MSTG_CNT,A

	;****** Pruefen ob MSTG in Statusbotschaft ERROR sendet
	;	Falls ja, dann in EEPROM eintragen und anzeigen am Display
mstg_error:
	inc	R0	
	inc	R0	
	inc	R0	
	inc	R0
	inc	R0
	inc	R0
	inc	R0		; zeige auf Byte 7 (ERROR)
	mov	ACC,@R0		; hole byte 7 in Akku

	cjne	A,#00H,mstg_error_eintrag
	jmp	mstg_error_end

mstg_error_eintrag:

	mov	ERROR,ACC
	call	mstg_errorcode_out		; Fehlermeldung generieren
						; und in EE eintragen
mstg_error_end:	

task_partner_stgx_end:


task_stack_overflo:

	;****** Pruefen Stack- Endemarkierung (Init-Wert 55h) noch da ist

	mov	A,#55h
	cjne	A,STACK_END_MARK,stack_error
	jmp	task_stack_overflow_end
stack_error:	
	mov	ERROR,#EW_STACK_OVERFLOW
	call	errorcode_out		; Fehlermeldung generieren

task_stack_overflow_end:


task_LCDsaypowerdown:
	;****** Im Fall des Ueberganges in den PowerDown Modus soll 
        ;       am Display "POWERDOWN" ausgegeben werden.
	;	Dies ist als LCD Sondermodus realisiert. 	
	
	jnb	PD_BIT02,task_LCDsaypowerdown_end
	setb	LCD_MENU_CONTROL.6	; Sondermode einschalten
	clr	LCD_MENU_CONTROL.7

	mov	LCD_XDATA_TASK,#TASKNUMMER_STANDBY	; Task "PowerDownAnzeige" vorgeben
					                ; für Sonderausgabemodus
	; Updateflag wird von TASK-CAN-OUT gesetzt !

	mov	A,#TASKNUMMER_STANDBY	; entspricht 71H
	call	taskx_check_update	; vergleicht und setzt ggf. Flag

	setb	PD_BIT07		; setze Merker auf "aktiv" um die Flanke Klemme 15-->1
					; erkennen zu koennen und den Menuemode wieder 
					; zurueckzuschalten ohne dass das immer im 
					; Normalbetrieb (Klemme 15 = 1) geschieht.
	
task_LCDsaypowerdown_end:


task_can_out:
	;****** Task "CAN_Botschaften am LCD anzeigen"

	jnb	TASK_BITS.1,task_can_out_end

	; pruefen ob Task momentan auf LCD ist, evtl. Update Flag setzen
	; Hinweis: Dieser Task hat Nummer 70H und ist eine Sonderausgabe

	mov	A,#TASKNUMMER_CANOUT	; entspricht 70H
	call	taskx_check_update	; vergleicht und setzt ggf. Flag

task_can_out_end:

task_lcd:	
	;****** Task "Ausgabe auf LCD- Anzeige"
	;****** abhaengig vom eingestellten LCD- Modus 
	;****** (LCD_MENU_CONTROL Bit 7 und 6)
	; - Bit 7 (MSB): 1 = Menue- Modus
	;		 0 = Data-Modus, weiter unterscheiden mit Bit 6
	; - Bit 6:       0 = normaler Datenausgabemodus (ShowData)
	;		 1 = Sonderausgabemodus

	jb	LCD_MENU_CONTROL.7,menumode
	jnb	LCD_MENU_CONTROL.6,standardmode

sondermode:
	call	task_lcd_sonder
	jmp	task_lcd_end

standardmode:
	call	task_lcd_standard
	jmp	task_lcd_end

menumode:
	call	task_lcd_menu
	jmp	task_lcd_end

task_lcd_end:
	
	nop


;****** Activation of CAN sleep in case of POWER DOWN

task_can_sleep:	

	jnb	PD_BIT03,disactivate_sleep

	;read all CAN-RX-FIFO contents and ensure that CAN-controller does not
	;keep Int-line on LOW, then read IR to clear all interrupt flags,
	;then activate GO TO SLEEP bit.

task_canrx_pd:
	;****** Task "CAN_Botschaften empfangen"

	mov	CAN_RX_CNT_2,#CAN_RX_CALL_TO_PD	; maximale Anzahl laden

rx_pd_again:	
	call	can_rx    	; pruefen ob Botschaft im Empfangspuffer
				; des SJA1000 ist; ggf. Identifier lesen 
				; und Botschaft in Mailbox uebertragen

	; Rückgabewerte in Akku: 0 = war nix
	;			 1 = Botschaft war da

	jnz	enter_rx_pd_again

	jmp	task_canrx_pd_end	; Rx Buffer is empty, go on

enter_rx_pd_again:

	djnz	CAN_RX_CNT_2,rx_pd_again 
	
	; number of calls too high (counter == zero)	

	mov	ERROR,#EW_CAN_RX_PD_OVERLOAD
	call	errorcode_out		; Fehlermeldung generieren
	jmp	task_can_sleep_end	; und kein powerdown weil
					; Fehlern sonst nicht gesendet
					; werden kann
task_canrx_pd_end:

task_read_canIR:
	mov	CAN_ADR,#CAN_ADR_IR
	call	can_read			; Ergebnis in CAN_DAT
						; aber nicht gebraucht
task_read_canIR_end:

activate_sleep:
	;****** Task "CAN Controller in Sleep mode versetzen"
	; NOTE: Wakeup automatically when bus-activity detected by SJA

	mov	CAN_ADR,#CAN_ADR_CMR		; CMR "GoToSleep" Bit
						; setzen
	mov	CAN_DAT,#CAN_CMR_SLEEP
	call	can_write

	jmp	task_can_sleep_end

disactivate_sleep:
	;****** Task "CAN Controller aus Sleep mode zurückholen"
	; NOTE: Da das ZSTG auch im Sleep mode ist wird keine Busaktivität
	;	den Sleep mode beenden, daher manuell rücksetzen

	mov	CAN_ADR,#CAN_ADR_CMR		; CMR "GoToSleep" Bit
						; zurücksetzen
	mov	CAN_DAT,#CAN_CMR_SLEEP_END
	call	can_write

disactivate_sleep_end:
task_can_sleep_end:


end_loop:
	jmp	start_loop		; zum Anfang der zyklischen 
					; Abarbeitung zurueckspringen

	;****** Blink- LED als NOT-STOP ************************************** 
	; kann nicht mit normaler Fehlerausgabe gemacht werden da 
	; ausserhalb der Main-Routine

blinkstopend:	
	mov	CNT0,#0FFH		; Pulsdauer FF/FF = 150 ms
stop0:	nop				; Pulsdauer C0/FF = 115 ms
	mov	CNT1,#0FFH		; Pulsdauer 90/FF =  80 ms
stop1:	nop				; Pulsdauer 60/FF =  55 ms
	djnz	CNT1,stop1		; Pulsdauer 33/FF =  30 ms
	djnz	CNT0,stop0		; Pulsdauer 11/FF =  10 ms
					; Pulsdauer 10/1A =   1 ms
	cpl	LED
	jmp	blinkstopend		; LED toggeln

;*****************************************************************************
;	Einbinden der Unterprogramme / Treiber im Anschluss an den Main-Code	
;*****************************************************************************

	$INCLUDE (sys_ini.asm)	; Systeminitialisierung
	$INCLUDE (basiccan.asm)	; Treiber fuer Basic CAN
	$INCLUDE (convert.asm)	; Unterprogramme zur Datenumwandlung
	$INCLUDE (ds1621.asm)	; Unterprogramme fuer Temperaturmessbaustein
	$INCLUDE (ee_iic.asm)	; Treiber fuer IIC- Bus, noetig fuer EEPROM
	$INCLUDE (lcdbasis.asm)	; Treiber fuer LCD
	$INCLUDE (lcd_out.asm)	; LCD- Daten-Ausgabe
	$INCLUDE (shift.asm)	; Unterprogramme zum Einlesen der digital I/O
	$INCLUDE (timeloop.asm)	; Zeitschleifen
	$INCLUDE (errorman.asm)	; Fehlermanagement
	$INCLUDE (eepot.asm)	; Treiber fuer EEPOT
	$INCLUDE (menue.asm)	; Menuesteuerung
	$INCLUDE (entprell.asm) ; Tastaturentprellung
	$INCLUDE (switch.asm)   ; Schaltfunktionen- Unterprogramme
	$INCLUDE (ee_new.asm)   ; EEPROM-Erstinbetriebnahme-Routinen
	$INCLUDE (net_ini.asm)  ; Netzwerk- Initialisierung

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

        ;*********************************************************************
        ; Datensatzdefinitionen 
        ;*********************************************************************
	; Texte enthalten 20 Zeichen und zusätzlich die Endemarke
	; Endemarke = 16 weil das kein darstellbares Zeichen ist
	; MSG = Message = Text ohne einzufuegende Werte
	; MSX = Message X = Text an den Werte aus Variablen angehaengt werden
	;		    -> komplette Zeile sollte vorher geloescht werden
	; MSC = Message Custom = Definition Sonderzeichen (kundenspezifisch)	

        ORG     2900H           

	;****** Allgemeine Systemmeldungen ***********************************

MSG000:	DB	'                    ',16
MSG001: DB      '     POWER DOWN     ',16	; wird fuer Anzeige verwendet
MSG002:	DB	'POWER-ON SELF CHECK ',16	; wird fuer Anzeige verwendet
MSG003: DB	'... RUNNING         ',16	; wird fuer Anzeige verwendet
MSG004: DB	'... PASSED          ',16	; wird fuer Anzeige verwendet

MSG005:	DB	'Software  V 0.16    ',16	; wird fuer Anzeige verwendet
MSG006:	DB	'C 2000/2003 BY ANDI ',16	; wird fuer Anzeige verwendet
MSG008: DB	'Andreas Hoeger 08/03',16
MSG009: DB      'Build 11_08_03      ',16

MSX010: DB      'Hardware  V',16		; wird fuer Anzeige verwendet

	;****** oben lesbare Texte fuer HEX Code *****************************

MSG020:	DB	'<--     <OK>     -->',16

MSX030: DB	'CAN-IDENT: 0x',16
;MSX040:	DB	'Q2:',16
;MSX050: DB	'TEMPERATUR: ',16
MSX051: DB	'HSTG: ',16		; Temperatur im Hauptsteuergeraet
;MSX052: DB	'TEMP IN: ',16
;MSX053: DB      'TEMP OUT: ',16

MSX060: DB      'FEHLER: 0x ',16
MSX061: DB      'FEHLER_ZSTG: 0x '  ,16
MSX062: DB      'FEHLER_MSTG: 0x '  ,16


MSX070: DB      'MO  ',16		; für DCF77 Anzeige 
MSX071: DB      'DI  ',16
MSX072: DB      'MI  ',16
MSX073: DB      'DO  ',16
MSX074: DB      'FR  ',16
MSX075: DB      'SA  ',16
MSX076: DB      'SO  ',16
MSX077: DB      'DCF77_SYNC     ',16
MSX078: DB      'DCF77_CHKS     ',16

	;****** Messwertausgaben *********************************************

;MSG100:	DB	'DREHZAHL  xxxx U/min',16
;MSG105:	DB	'DREHMOMENT    xxx Nm',16
;MSG110: DB	'INNENTEMP    xxx.x C',16
;MSG115: DB	'AUSSENTEMP   xxx.x C',16
;MSG120: DB	'xxx.x Volt  yyy.yy A',16

	;****** Motor ********************************************************

;MSG200:	DB	'MOTOROEL     PRUEFEN',16
;MSG205:	DB	'WISCHWASSER VORN    ',16
;MSG210: DB	'WISCHWASSER HINTEN  ',16

	;****** Lampen *******************************************************

;MSG300: 	DB	'KENNZEICHENBEL.     ',16

;MSG310: 	DB	'BREMSLICHT LINKS    ',16
;MSG311: 	DB	'BREMSLICHT RECHTS   ',16
;MSG312: 	DB	'BREMSLICHT MITTE    ',16
;MSG313:	DB	'BREMSLICHT ANHAENGER',16

;MSG320: 	DB	'RUECKLICHT LINKS    ',16
;MSG321: 	DB	'RUECKLICHT RECHTS   ',16
;MSG322: 	DB	'RUECKLICHT ANHAENGER',16

;MSG330:	DB	'BLINKER RECHTS VORN ',16
;MSG331:	DB	'BLINKER RECHTS HECK ',16
;MSG332:	DB	'BLINKER LINKS VORN  ',16
;MSG333:	DB	'BLINKER LINKS HECK  ',16
;MSG334:	DB	'BLINKER ANHAENGER   ',16

	;****** Sonderfunktionen *********************************************

;MSG400:	DB	'DIESELVORWAERMUNG   ',16
;MSG410: 	DB	'SCHIEBETUERE OFFEN  ',16
;MSG420: 	DB	'HECKKLAPPE OFFEN    ',16
;MSG421:	DB	'FLUEGELTUERE OFFEN  ',16

;MSG430: 	DB	'DACHFENSTER VORN    ',16
;MSG431: 	DB	'DACHFENSTER HINTEN  ',16

;MSG440: 	DB	'STANDHEIZUNG AKTIV  ',16
;MSG441: 	DB	'STANDHEIZUNG REST   ',16

;MSG450:	DB	'TURBO LIGHT AKTIV   ',16
;MSG460: 	DB	'NOTSTART ZWEITBATT. ',16
;MSG461: 	DB	'BATTERIEN GEBRUECKT ',16

	;****** CAN- Diagnose ************************************************

;MSG500: DB	'CAN-BOTSCHAFT xxx   ',16
;MSG501: DB	'00112233 44556677   ',16

	;****** Menuetexte ***************************************************

	; Achtung ! Diese Texte duerfen max. 18 Zeichen lang sein
	; damit vorne noch der Cursor und das Leerzeichen anzeigbar ist.
	; max.  '------------------'  so lang

MSG600: DB      '...               ',16
MSG601: DB      '--> zurueck       ',16

MSG605: DB      ' -      OK      + ',16		; Fuer Einstellung der
						; CAN- Botschaft

MSG606: DB      'Sommer      Winter',16		; Fuer Einstellung D+
						; Charakteristik

MSG607: DB      'ein            aus',16		; Fuer Schaltfunktionen

MSG608: DB	'hell   OK   dunkel',16		; Fuer Kontrastverstellung 
						; LCD
MSG609: DB      'up     OK     down',16

MSG610: DB	'SCHALTFUNKTIONEN  ',16
MSG611: DB	'Beleuchtung LCD   ',16
MSG612: DB	'Standheizung      ',16
MSG613: DB	'Innenbeleuchtung  ',16
MSG614: DB	'Steckdose         ',16
MSG615: DB	'Powerlicht        ',16
MSG616: DB	'Klemme 15         ',16
MSG617: DB	'Notstart Trennrel.',16

MSG620: DB	'SONDERMODUS       ',16
MSG621: DB      'CAN- Datenausgabe ',16

MSG630: DB      'EINSTELLUNGEN     ',16
MSG631: DB	'LCD-Kontrast	   ',16
MSG632: DB	'Defaultanzeige LCD',16
MSG633: DB	'Fehlersp. loeschen',16
MSG634: DB	'D+ Sommer/Winter  ',16
MSG635: DB	'CAN- Botschaft Nr.',16

MSG640: DB      'ANZEIGEN-AUSWAHL  ',16		; Wahl der im Standardmodus
						; angezeigten Zeilen	
MSG641: DB      'Uhrzeit und Datum ',16 
MSG642: DB      'Temperatur aussen ',16
MSG643: DB      'Temperatur HSTG   ',16
MSG644: DB      'Batteriespannung  ',16
MSG645: DB      'Ladelufttemperatur',16
MSG646: DB      'Ladedruck         ',16
MSG647: DB      'Oeltemperatur     ',16
MSG648: DB      'Oeldruck          ',16

	;****** Netzwerk-Init ************************************************

MSG700:	DB	'ZSTG erkannt      ',16
MSG701: DB	'ZSTG nicht am CAN ',16
;MSG702: DB	'ZSTG Appdata o.k. ',16
;MSG703: DB	'ZSTG Appdata fehlt',16

MSG710: DB	'MSTG erkannt      ',16
MSG711: DB	'MSTG nicht am CAN ',16

	;****** ADC Werte ****************************************************

MSG800:	DB	'DUMMY Temp aussen ',16
MSG801:	DB	'Batterie    ',16
MSG802:	DB	'LLK Temp     ',16
MSG803:	DB	'Ladedruck ',16
MSG804:	DB	'OEL Temp    ',16
MSG805:	DB	'DUMMY Oeldruck    ',16

	;****** CAN- Datenausgabe- Wahl **************************************

MSG850: DB	'500 h (StatusHSTG)',16
MSG851: DB      '501 h (Appd. ZSTG)',16
MSG852: DB      '502 h (Appd. MSTG)',16
MSG853: DB      '503 h (Hzg.  HSTG)',16
MSG854: DB      '504 h (Komm. ZSTG)',16
MSG855: DB      '505 h (Komm. MSTG)',16
MSG856: DB      '506 h (EEPROM PG0)',16
MSG857: DB      '507 h (Error Z/M )',16
MSG858: DB      '508 h (Error HSTG)',16
MSG859: DB      '509 h (Debug HSTG)',16

MSG860: DB      '510 h (StatusMSTG)',16
MSG861: DB      '511 h (Hzg.  MSTG)',16
MSG862: DB      '512 h (SensorMSTG)',16
MSG863: DB      '513 h (Sens M ASC)',16
MSG867: DB      '517 h (1-wire ID1)',16
MSG868: DB      '518 h (1-wire ID2)',16
MSG869: DB      '519 h (Debug MSTG)',16

MSG870: DB      '520 h (StatusZSTG)',16
MSG871: DB      '521 h (DCF77 Data)',16
MSG872: DB      '522 h (Sens Z ASC)',16
MSG877: DB      '527 h (1-wire ID1)',16
MSG878: DB      '528 h (DCF77 Plus)',16
MSG879: DB      '529 h (Debug ZSTG)',16

	;****** Sonderzeichen ************************************************

	; Zeichen Nummer Null

MSC000: DB	00000100b		;  *
	DB	00000100b		;  *
	DB	00000100b		;  *
	DB	00000100b		;  *
	DB	00010101b		;* * *
	DB	00001110b		; ***
	DB	00000100b		;  *
	DB	00000000b		;


	; Zeichen Nummer Eins

MSC001: DB	00000100b		;  *
	DB	00001110b		; ***
	DB	00010101b		;* * *
	DB	00000100b		;  *
	DB	00000100b		;  * 
	DB	00000100b		;  *
	DB	00000100b		;  *
	DB	00000000b		;

	; Zeichen Nummer Zwei

MSC002: DB	00010000b		;*  
	DB	00011000b		;**
	DB	00011100b		;***
	DB	00011110b		;****
	DB	00011100b		;*** 
	DB	00011000b		;**
	DB	00010000b		;*
	DB	00000000b		;

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

        END

