	PAGE 70

;	RCVFILE.MAC
;	empfaengt Files ueber die SIO-A des VIDEOPLAN,
;	speichert sie zunaechst im Hauptspeicher
;	und legt sie anschliessend auf Diskette ab.
;
;	Der Empfang wird bei Tastendruck abgebrochen. 
;
;	HL zeigt anschliessend hinter das letzte Zeichen. 
;
;	A.Herrmann	22.11.84
;
	.Z80
	ENTRY RCVFIL

RCVFIL:	JP START

;--------------- Konstanten und Variablen ---------

RTS	EQU 01H		;REQUEST TO SEND CHAR.
EOF	EQU 1AH		;END OF FILE MARKER
BDOS	EQU 5		;BDOS EINSPRUNG
FBASE	EQU 6		;FDOS BASIS ADRESSE
SIOC	EQU 7		;SIO CONTROL PORT
SIOD	EQU 5		;SIO DATA PORT
EXK00	EQU 0		;EXIT KRITERIUM DOUBLE ZERO
EXKEOF	EQU 1		;               HEX 1A
EXKKEY	EQU 2		;               KEY HIT


SIOREG:	DB 11011000B	;RESET
	DB 1,00000000B	;NO INTERRUPTS
	DB 3,11000001B	;RCV 8 BIT/CHAR 
	DB 4,01000100B	;x16 CLOCK, 1 STOP BIT
	DB 5,11101000B	;DTR, TSM 8 BIT/CHAR, TRANSMIT ENABLE
SIOLEN	EQU $-SIOREG

DRIVE:	DB 0		;OUTPUT DISK DRIVE
EXKRIT:	DB 0		;EXIT-KRITERIUM
ZERFLG:	DB 0		;ZERO FLAG, GESETZT BEI ERSTER NULL
FNFLAG:	DB 0		;0=ENTER / 1=RECEIVE FILENAME
RTSFLG:	DB 0		;RTS SENDEN, WENN FLAG = 1

BUFANF:	DW 0		;BUFFER-ANFANG
BUFEND:	DW 0		;BUFFER-ENDE
DATEND:	DW 0		;DATA ENDE

INPBUF:	DB 12		;INPUT BUFFER
	DB 0		;TATSAECHL.LAENGE
	DS 12		;12 ZEICHEN

STRING:	DW 0		;OUTPUT STRING
	DW 0		;5 ZEICHEN
	DB 0
CRLF:	DB 0DH,0AH,'$'

FCB:	DS 33		;FILE CONTROL BLOCK
FCBLEN	EQU $-FCB

;--------------- Ausgabe-Strings ------------------

HEADER:	DB 0CH
	DB 'RCVFILE - Version 1.1   22.11.84   (C) A.Herrmann'
	DB 0DH,0AH,0AH,'$'

BUFMSG:	DB 'Buffer Length = '
	DB '$'

SIOMSG: DB 0DH,0AH
	DB 'SIO-A (Ports 05/07) set to 4800 Bd, '
	DB '8 Bit/Char, 1 StopBit, No Parity, DTR, RTS'
	DB 0DH,0AH,0AH,'$'

EXTMSG:	DB 'Exit Receive Loop on :',0DH,0AH
	DB '- Double Zero  0',0DH,0AH
	DB '- Hex 1A       1',0DH,0AH
	DB '- Key Hit      2    '
	DB '$'

DRVMSG:	DB 0DH,0AH,0AH
	DB 'Write Files to Drive (A/B)  '
	DB '$'

FILMSG:	DB 0DH,0AH
	DB 'Filename',0DH,0AH
	DB '- to enter    E',0DH,0AH
	DB '- to receive  R   '
	DB '$'

RTSMSG:	DB 0DH,0AH,0AH
	DB 'Send RTS prior to receive (Y/N)  '
	DB '$'

ENTMSG:	DB 0DH,0AH,0AH
	DB 'Enter Filename (filename.ext)  '
	DB '$'

RCVMSG:	DB 0DH,0AH,0AH
	DB 'Receiving Filename (11 Chars)  '
	DB '$'

DATMSG:	DB 'Receiving Data...  '
	DB '$'

LENMSG:	DB 'Data Length = '
	DB '$'

DSKMSG:	DB 'File stored on Disk'
	DB '$'

EMPMSG:	DB 'File empty - not stored on Disk'
	DB '$'

ERRMSG:	DB 0DH,0AH,0AH
	DB '*** Disk Write Error ***'
	DB '$'

SERMSG:	DB 0DH,0AH,0AH
	DB '*** SIO Rcv Error ***'
	DB '$'

OFLMSG: DB 0DH,0AH,0AH
	DB '*** Buffer Overflow ***'
	DB '$'

ABOMSG:	DB 0DH,0AH,0AH
	DB '*** Program aborted ***'
	DB '$'

RSTMSG:	DB 0DH,0AH,0AH
	DB 'Restart ? (Y/N)  '
	DB '$'

;--------------- PROGRAMM-ANFANG ------------------
		
START:	LD DE,HEADER	;MELDUNG
	CALL PRINT

	LD HL,PRGEND	;BUFFER-ANFANG BESTIMMEN
	LD L,0
	INC H
	LD (BUFANF),HL
	EX DE,HL

	LD HL,(FBASE)	;BUFFER-ENDE BESTIMMEN
	LD (BUFEND),HL	;BUFFER LAENGE BERECHNEN
	SCF
	SBC HL,DE
	CALL CONVRT	;HL-WERT NACH STRING KONVERTIEREN
	LD DE,BUFMSG
	CALL PRINT	;UND AUSGEBEN
	LD DE,STRING
	CALL PRINT

	LD HL,SIOREG	;SIO INIT.
	LD B,SIOLEN
	LD C,SIOC
	OTIR
	LD DE,SIOMSG
	CALL PRINT

EXSPEZ:	LD DE,EXTMSG	;EXIT-KRITERIUM SPEZ.
	CALL PRINT
	LD C,1
	CALL BDOS
	SUB '0'
	JR C,EXSPEZ
	CP 3
	JR NC,EXSPEZ
	LD (EXKRIT),A

DRSPEZ:	LD DE,DRVMSG	;DRIVE SPEZ.
	CALL PRINT
	CALL INPUT
	SUB 40H
	JR C,DRSPEZ
	CP 4
	JR NC,DRSPEZ
	LD (DRIVE),A

FISPEZ:	LD DE,FILMSG	;FILE NAME EINGABE SPEZ.
	CALL PRINT
	CALL INPUT
	SUB 'E'
	JR Z,FISPE1
	SUB 'R'-'E'
	JR NZ,FISPEZ
	INC A
FISPE1:	LD (FNFLAG),A

RTSPEZ:	LD DE,RTSMSG
	CALL PRINT
	CALL INPUT
	SUB 'N'
	JR Z,RTSPE1
	SUB 'Y'-'N'
	JR NZ,RTSPEZ
	INC A
RTSPE1:	LD (RTSFLG),A

;--------------- MAIN LOOP ------------------------

MLOOP:	LD B,FCBLEN	;NAECHSTEN FILE EMPFANGEN
	LD HL,FCB	;FILE CONTROL BLOCK INIT.
	XOR A
FLOOP:	LD (HL),A
	INC HL
	DJNZ FLOOP

	LD A,(DRIVE)	;DRIVE IN FCB
	LD (FCB),A

FILNAM:	LD A,(FNFLAG)	;WOHER FILENAME?
	OR A
	JR NZ,RCVNAM

	LD DE,ENTMSG	;VON CONSOLE
	CALL PRINT
	LD C,10
	LD DE,INPBUF
	CALL BDOS

	LD A,(INPBUF+1)	;STRING LAENGE
	OR A
	JP Z,ABORT	;=0 ?

	LD HL,FCB+1	;NAME IN FCB MIT
	LD A,' '	;BLANKS INIT.
	LD B,12
BLOOP:	LD (HL),A
	INC HL
	DJNZ BLOOP

	LD A,(INPBUF+1)	;NAME IN FCB KOPIEREN
	LD C,A
	LD B,0
	LD HL,INPBUF+2
	LD DE,FCB+1
SLOOP:	LD A,'.'	;BIS PUNKT
	CP (HL)
	JR Z,FILEXT
	LDI
	LD A,C
	OR A
	JR NZ,SLOOP
	JP RTSNAM

FILEXT:	LD DE,FCB+9	;FILE EXTENSION
	INC HL
	DEC C
XLOOP:	LD A,C
	OR A
	JP Z,RTSNAM
	LDI
	JR XLOOP

RTSNAM:	LD A,(RTSFLG)
	OR A
	JP Z,RCVDAT	;VORHER RTS SENDEN?

	LD A,RTS
	OUT (SIOD),A
	JP RCVDAT

RCVNAM:	LD DE,RCVMSG	;FILE NAME EMPFANGEN
	CALL PRINT	;FORMAT MIT GENAU 8+3 ZEICHEN
	LD B,11		;ALSO:  filenameext (OHNE PUNKT!)
	LD HL,FCB+1	;

	LD A,(RTSFLG)
	OR A
	JR Z,NLOOP	;VORHER RTS SENDEN?

	LD A,RTS
	OUT (SIOD),A

NLOOP:	IN A,(SIOC)	;ZEICHEN DA?
	AND 1
	JR NZ,GETNCH

	PUSH HL		;FALLS NICHT,
	PUSH BC
	LD C,11		;CONSOLE ABFRAGEN
	CALL BDOS
	POP BC
	POP HL
	OR A
	JR Z,NLOOP
	JP ABORT

GETNCH:	IN A,(SIOD)	;SONST ZEICHEN
	LD (HL),A	;UEBERNEHMEN
	INC HL		;UND ABLEGEN
	DJNZ NLOOP

	LD A,'$'	;FILE NAME AUSGEBEN
	LD (FCB+12),A
	LD DE,FCB
	CALL PRINT
	XOR A
	LD (FCB+12),A

;--------------- Empfang der Daten ---------------

RCVDAT:	LD DE,CRLF
	CALL PRINT
	LD DE,DATMSG	;DATEN EMPFANGEN
	CALL PRINT

	XOR A
	LD (ZERFLG),A	;ZERO FLAG LOESCHEN
	LD HL,(BUFANF)	;POINTER AUF BUFFER-ANFANG

DLOOP:	IN A,(SIOC)	;ZEICHEN DA?
	AND 1
	JR NZ,GETDCH
	
	LD A,1		;CHECK READ REG.1
	OUT (SIOC),A	;FOR ERRORS
	IN A,(SIOC)
	AND 70H
	JP Z,EXIT?

	LD DE,SERMSG	;SIO ERROR
	CALL PRINT
	JP ABORT

EXIT?:	LD A,(EXKRIT)	;FALLS NICHT:
	CP EXKKEY	;EXIT ON KEY HIT?
	JP Z,EXKEY
	PUSH HL		;NEIN,
	LD C,11		;ABORT ON KEY HIT?
	CALL BDOS
	POP HL
	OR A
	JP Z,DLOOP
	JP ABORT

GETDCH:	IN A,(SIOD)	;SONST ZEICHEN
	LD (HL),A	;UEBERNEHMEN
	INC HL		;UND ABLEGEN

	EX DE,HL	;BUFFER-ENDE ERREICHT?
	LD HL,(BUFEND)
	SCF
	SBC HL,DE
	EX DE,HL
	JP C,OVRFLW

	LD B,A		;EXIT?
	LD A,(EXKRIT)
	CP EXK00
	JP Z,EX00
	CP EXKEOF
	JP Z,EXEOF

EXKEY:	PUSH HL		;BEI EXIT ON KEY HIT
	LD C,11		;CONSOLE ABFRAGEN
	CALL BDOS
	POP HL
	OR A
	JP Z,DLOOP
	JP READY

EX00:	XOR A		;EXIT, FALLS DOPPEL-NULL
	CP B
	JP Z,EX001
	LD (ZERFLG),A
	JP DLOOP

EX001:	LD A,(ZERFLG)	;ZEICHEN IST NULL
	OR A
	JP NZ,READY	;ZWEITE NULL?
	INC A
	LD (ZERFLG),A	;NEIN, ERSTE NULL
	JP DLOOP

EXEOF:	LD A,B		;EXIT, FALLS END OF FILE
	CP EOF
	JP Z,READY
	JP DLOOP

;--------------- File ablegen --------------------

READY:	XOR A		;REST BIS ..FF
	SUB L		;MIT 0 AUFFUELLEN
	JR Z,OKAY
	LD B,A
	XOR A
FILL:	LD (HL),A
	INC HL
	DJNZ FILL

OKAY:	LD (DATEND),HL	;FILE IST EMPFANGEN
	LD DE,(BUFANF)
	XOR A
	SBC HL,DE	;LAENGE BERECHNEN
	PUSH AF
	CALL CONVRT	;UND IN STRING KONVERTIEREN
	LD DE,LENMSG
	CALL PRINT
	LD DE,STRING
	CALL PRINT
	POP AF
	JR Z,EMPTY	;LEERER FILE?

	LD C,19		;FILE LOESCHEN
	LD DE,FCB
	CALL BDOS

	LD C,22		;FILE OEFFNEN
	LD DE,FCB
	CALL BDOS

	LD DE,(BUFANF)	;ERSTE WRITE ADRESSE

WLOOP:	PUSH DE		;WRITE LOOP
	LD C,26		;SET DMA AUF DE
	CALL BDOS
	LD DE,FCB
	LD C,21		;RECORD SCHREIBEN
	CALL BDOS
	POP DE
	OR A		;ERROR?
	JR NZ,DSKERR

	LD HL,128	;NEIN, 
	ADD HL,DE	;NAECHSTEN RECORD ANFANG BEST.
	EX DE,HL
	LD HL,(DATEND)	;DATA ENDE ERREICHT?
	SCF
	SBC HL,DE
	JR NC,WLOOP

	LD C,16		;JA, DATEI SCHLIESSEN
	LD DE,FCB
	CALL BDOS
	CP 0FFH
	JR Z,DSKERR
	
	LD DE,DSKMSG	;FILE IST AUF DISK
	CALL PRINT
	JP MLOOP	;WEITER MIT NAECHSTEM FILE

EMPTY:	LD DE,EMPMSG	;LEERER FILE WIRD NICHT
	CALL PRINT	;ABGELEGT
	JP MLOOP

;--------------- MAIN LOOP ENDE -------------------

DSKERR:	LD DE,ERRMSG	;DISK WRITE ERROR
	CALL PRINT
	JP ABORT

OVRFLW:	LD DE,OFLMSG	;BUFFER OVERFLOW
	CALL PRINT

ABORT:	LD DE,ABOMSG	;PROGRAMM-ABBRUCH
	CALL PRINT

RESTRT:	LD DE,RSTMSG	;RESTART?
	CALL PRINT
	CALL INPUT
	CP 'Y'
	JP Z,START
	CP 'N'
	JP Z,EXIT
	JR RESTRT

;--------------- SUBROUTINEN ----------------------

INPUT:	PUSH BC		;1 BUCHSTABEN VON CONSOLE
	PUSH DE
	PUSH HL
	LD C,1
	CALL BDOS
	AND 01011111B	;ZU GROSSBUCHST. MASKIEREN
	POP HL
	POP DE
	POP BC
	RET

PRINT:	LD C,9		;STRING OUTPUT AUF CONSOLE
	CALL BDOS
	RET

CONVRT:	LD DE,STRING	;INTEGER IN HL 5-STELLIG
	LD BC,5		;NACH STRING KONVERTIEREN

	EX DE,HL
	ADD HL,BC
	DEC HL
	EX DE,HL
	LD B,C

	PUSH DE		;HL GROESSER GLEICH HEX A000 ?
	EX DE,HL
	LD HL,0A000H
	SCF
	SBC HL,DE
	JR NC,CONVR0

	EX DE,HL	;JA, ERSTMAL A000H = 40960 ABZIEHEN
	LD DE,0A000H
	CCF
	SBC HL,DE
	CALL DIV10	;UND DIE DIFFERENZ ALLEIN TEILEN
	POP DE
	CALL RCODE	;REST CODIEREN
	DEC B		;1 STELLE WENIGER
	PUSH DE
	LD DE,1000H	;AUF DEN QUOTIENTEN 1000H = 4096
	ADD HL,DE	;WIEDER DRAUF
	POP DE
	JR CONVR1	;UND NORMAL WEITER

CONVR0:	EX DE,HL	;NEIN
	POP DE

CONVR1: CALL DIV10	;HL DURCH 10 DIVIDIEREN
	CALL RCODE	;REST CODIEREN
	DJNZ CONVR1	;ALLE STELLEN GENERIERT ?
	RET

DIV10:	PUSH BC		;DIVIDIERT HL DURCH 10.
	PUSH DE
	LD B,12		;DIVIDEND HAT 12+4 BITS.
	LD D,0A0H	;DIVISOR (=10) IM OBEREN HALBBYTE VON D
	LD E,0
DIVBIT:	XOR A		;CLEAR CARRY FLAG
	ADD HL,HL	;HL 1 BIT NACH LINKS
	PUSH AF		;SAVE CARRY FLAG
	XOR A		;CLEAR CARRY FLAG
	SBC HL,DE	;"GEHT DE IN HL"?
	INC HL		;ANGENOMMEN, JA.
	JR NC,DIVCNT	;FALLS NICHT
	POP AF		;UND FALLS VORHER
	JR C,DIVNXT	;KEIN CARRY,
	ADD HL,DE	;SUBTRAKTION UND
	DEC HL		;QUOTIENTEN-STELLE
	JR DIVNXT	;ZURUECKNEHMEN.
DIVCNT:	POP AF
DIVNXT:	DJNZ DIVBIT
	POP DE
	POP BC
	RET

RCODE:	LD A,H		;REST AUS DEM OBEREN HALBBYTE
	RR A		;VON H INS UNTERE SCHIEBEN,
	RR A
	RR A
	RR A
	AND 0FH		;HERAUSMASKIEREN,
	OR 30H		;ALS ASCII-ZEICHEN CODIEREN
	LD (DE),A	;UND ABSPEICHERN.
	LD A,H		;QUOTIENT STEHT IN L UND 
	AND 0FH		;UNTEREM HALBBYTE VON H
	LD H,A
	DEC DE
	RET

;--------------- PROGRAMM-ENDE --------------------

EXIT:	JP 0		;WARMBOOT

PRGEND	EQU $

	END
