	TITLE  'CP/M MODEM PROGRAM Version 7.98  12/31/82'
;
;THE FOLLOWING IS AN EXTENSIVE REVISION OF THE CP/M MODEM PROGRAM
;CREATED BY WARD CHRISTENSEN FOR THE CP/M USERS LIBRARY.  IT ALSO
;INCORPORATES ROUTINES FOUND IN THE POTOMAC MICRO-MAGIC MODEM
;MANUAL WHICH MAY BE USED IF YOU HAVE A PMMI MODEM BOARD.
;
;	     ********* N O T I C E S *********
;
;	Revisers releasing new versions should only
;	change the version number by 1 digit in the
;	last place.
;
;	Except for PMMI routines, revisers should
;	only make nonspecialized changes for
;	distribution. Please make configuration files,
;	such as MCNFG7xx.ASM and MCOSB7xx.ASM, for
;	particular computers, uarts or modems.
;
;	     **********************************
;
;##### This file requires MODEM797.LIB and MAC.COM to assemble. #####
;
;##### The file MCNFG797.ASM can be used to overlay the HEX #####
;##### or COM file versions with your own modem routines and #####
;##### configuration options. The file MODEM797.SET can be used #####
;##### as a reference for directly setting the modem equates #####
;##### and configuration options with the S command in DDT. #####
;
;Fix log in MODEM797.HIS
;
;
          MACLIB MODEM797	;Contains the CMDLINE, INBUF, INLNCOMP,
				;DIRLIST, SENDTIME, PRTBAUD, and MFACCESS
				;routines.
;
;Note that the library has not been changed since version 7.97.
;
;
TRUE	EQU	0FFH
FALSE	EQU	0
;
CPM2X	EQU	TRUE	;TRUE IF CP/M 2.X
DBUFSIZ	EQU	16	;BUFFER SIZE FOR FILE TRANSFER IN KBYTES
;
ERRCRC	EQU	6	;NUMBER OF TIMES TO TRY CRC MODE BEFORE
			;SWITCHING TO CHECKSUM
ERRLIM	EQU	10	;NUMBER OF TIMES TO RETRY
			;SEND/RECEIVE ERRORS BEFORE QUIT
;
; PMMI EQUATES
PORT	EQU	0C0H	;PMMI BASE ADDRESS
;
MODCTLP	 EQU	PORT	;MODEM CONTROL PORT
MODDATP	 EQU	PORT+1	;MODEM DATA PORT
BAUDRP	 EQU	PORT+2	;BAUD RATE PORT
MODCTL2	 EQU	PORT+3	;2ND MODEM CONTROL PORT
MODRCVB	 EQU	02H	;MODEM RECEIVE BIT (DAV)
MODRCVR	 EQU	02H	;MODEM RECEIVE READY
MODSNDB	 EQU	01H	;MODEM SEND BIT (XMIT BUFF EMPTY)
MODSNDR	 EQU	01H	;MODEM SEND READY
NOPARMSK EQU	10H	;MASK TO RESET TO NO PARITY
EVPARMSK EQU	20H	;MASK TO SET EVEN PARITY
ODPARMSK EQU	0CFH	;MASK TO SET ODD PARITY
BRKMSK	 EQU	0FBH	;MASK TO SET BREAK
ERRCDMSK EQU	38H	;MASK TO BLOCK ALL BITS EXCEPT ERROR CODES
FRMER	 EQU	20H     ;FRAMING ERROR MASK
ORUNER	 EQU	10H	;OVERRUN ERROR MASK
PARER	 EQU	08H	;PARITY ERROR MASK
ANSWMOD	 EQU	1EH	;ANSWER MODE
ORIGMOD	 EQU	1DH	;ORIGINATE MODE
WAITCTS	 EQU	255	;NUMBER OF SECONDS X 10 TO WAIT FOR COMPUTER
			;TONE AFTER PMMI AUTO-DIAL FUNCTION 255 MAX.
;
CRC       EQU   'C'         ;USED TO REQUEST 'CRC' INSTEAD OF 'CKSUM'
ESC	  EQU	'['-40H	    ; ^[ = ESCAPE
SOH       EQU   'A'-40H     ; ^A = START OF HEADER
EOT       EQU   'D'-40H     ; ^D = END OF TEXT
ACK       EQU   'F'-40H     ; ^F = ACKNOWLEDGE
OKNMCH    EQU   'F'-40H     ; ^F = OKAY NAME MATCH
BELL      EQU   'G'-40H     ; ^G = BELL CHARACTER
BKSP	  EQU	'H'-40H     ; ^H = BACKSPACE
LF        EQU   'J'-40H     ; ^J = LINEFEED
CR        EQU   'M'-40H     ; ^M = CARRIAGE RETURN
XON       EQU   'Q'-40H     ; ^Q = XON CHARACTER
XOFF      EQU   'S'-40H     ; ^S = XOFF CHARACTER
NAK       EQU   'U'-40H     ; ^U = NOT ACKNOWLEDGE
CAN       EQU   'X'-40H     ; ^X = CANCEL SEND/RECEIVE
EOFCHAR   EQU   'Z'-40H     ; ^Z = END OF FILE
BDNMCH    EQU   75H         ; BAD NAME MATCH
RUB	  EQU	7FH	    ; RUB
;
BOTTRAM   SET   LAST+100H AND 0FF00H
;
          ORG   0100H
;
          JMP   START
;
;THESE ROUTINES AND EQUATES ARE AT THE BEGINNING OF THE PROGRAM SO
;THEY CAN BE PATCHED BY A MONITOR OR OVERLAY FILE WITHOUT RE-ASSEMBLING
;THE PROGRAM.
;
PMMIBYTE:	DB	TRUE	;true=PMMI modem
SETUPTST:	DB	FALSE	;true=non-PMMI setup routine
SCRNTEST:	DB	FALSE	;true=if home cursor and clear screen
				;routine at CLRSCRN
CLOCK:		DB	4	;clock speed in MHz, 8 MHz maximum
BAKUPBYTE:	DB	FALSE	;true=make .BAK file
CKSUMDFLT:	DB	FALSE	;true=default to Checksum checking
				;false=default to CRC checking
TOGGLECRC:	DB	TRUE	;true=allow toggling of Checksum to CRC
CONVBKSP:	DB	FALSE	;true=convert backspace to rub
TOGGLEBK:	DB	TRUE	;true=allow toggling of bksp to rub
ADDLF:		DB	FALSE	;true=add LF after CR
TOGGLELF:	DB	TRUE	;true=allow toggling of LF after CR
TRANLOGON:	DB	FALSE	;true=allow transmission of logon
				;write logon sequence at location LOGON
SAVCCP:		DB	TRUE	;true=do not overwrite CCP
LOCONEXTCHR:	DB	FALSE	;true=local command if EXTCHR precedes
				;false=not local command if EXTCHR precedes
TOGGLELOC:	DB	TRUE	;true=allow toggling of LOCONEXTCHR
LSTTST:		DB	TRUE	;true=allow toggling of printer on/off
				;in terminal mode. Set to false if your
				;printer can't keep up with the modem
XOFFTST:	DB	FALSE	;true=allow testing of XOFF from remote
				;while transmitting a file in terminal mode
XONWAIT:	DB	FALSE	;true=wait for XON after sending CR while
				;transmitting a file in terminal mode
TOGXOFF:	DB	TRUE	;true=allow toggling of XOFF/XON testing
MSPEED:		DB	1	;sets the display time to send a file
				;0=110 1=300 2=450 3=600 4=710 5=1200
				;6=2400 7=4800 8=9600
BYTDLY:		DB	0	;default time to send character in
				;terminal mode file transfer
				;0=0 delay, 1=0.02 sec, -- ,9=0.18 sec
CRDLY:		DB	0	;default time for extra wait after CR
				;in terminal mode file transfer
				;0=0 delay, 1=0.02 sec, -- ,9=0.18 sec
BELRPT:		DB	30	;bell repeat time = value*0.03 sec
EXITCHR:	DB	'E'-40H	; ^E = Exit without disconnect
LOGCHR:		DB	'O'-40H	; ^O = Send logon
LSTCHR:		DB	'P'-40H	; ^P = Toggle printer
UNSAVECHR:	DB	'R'-40H	; ^R = Close input text buffer
TRANCHR:	DB	'T'-40H ; ^T = Transmit file to remote
SAVECHR:	DB	'Y'-40H	; ^Y = Open input text buffer
EXTCHR:		DB	'^'-40H	; ^^ = Send next character
;
;Equates used only by PMMI routines grouped together here.
PULSERATE:	DB	125	;125 for 20pps, 250 for 10pps on PMMI
				;not used if PMMI FALSE
CLDBOOT:	DW	00000H	;currently set to warm boot with
				;BYE routine for PMMI, put your cold
				;boot entry here if you have one and
				;desire to do on BYE
BRKCHR:		DB	'@'-40H ; ^@ = Transmit "BREAK" with PMMI
CHGBAUD:	DB	'B'-40H	; ^B = Used with PMMI in terminal
				;  mode to change baud rate on fly
DISCCHR:	DB	'D'-40H	; ^D = PMMI Disconnect
;
;
IN$MODCTLP:	IN	MODCTLP ! RET	;in modem control port
OUT$MODDATP:	OUT	MODDATP ! RET	;out modem data port
IN$MODDATP:	IN	MODDATP ! RET	;in modem data port
ANI$MODSNDB:	ANI	MODSNDB ! RET	;bit to test for send ready
CPI$MODSNDR:	CPI	MODSNDR ! RET	;value of send bit when ready
ANI$MODRCVB:	ANI	MODRCVB ! RET	;bit to test for receive ready
CPI$MODRCVR:	CPI	MODRCVR ! RET	;value of receive bit when ready
;
;THE FOLLOWING ARE TYPICALLY USED ONLY BY PMMI
IN$BAUDRP:	IN	BAUDRP	! RET	;in baudrate port
OUT$BAUDRP:	OUT	BAUDRP	! RET	;out baudrate port
OUT$MODCTL2:	OUT	MODCTL2	! RET	;out modem control port #2
OUT$MODCTLP:	OUT	MODCTLP		;out modem control port
		STA UARTCTLB	! RET	;and store control byte
;
LOGONPTR:	DW	LOGON
JMP$INITMOD:	JMP	INITMOD
JMP$SETUPR:	JMP	SETUPR
;Clear sequences are for H19.  Change to yours.
CLREOS:		CALL	JMP$ILPRT
		DB	ESC,'J',0,0,0
		RET
CLRSCRN:	CALL	JMP$ILPRT
		DB	ESC,'E',0,0,0
		RET
;
;NEXT THREE LINES SHOULD NOT BE CHANGED BY USER OVERLAY
JMP$ILPRT:	JMP	ILPRT
JMP$ILCOMP:	JMP	ILCOMP
JMP$INBUFF:	JMP	INBUFF
JMP$SYSVER:	JMP	SYSVER
JMP$DIALPL:	JMP	DIALPL
JMP$DISCONNT:	JMP	DISCONNT
;
SYSVER:
	LDA	PMMIBYTE	;USING THE PMMI S-100 MODEM?
	ORA	A
	JZ	SYSVER1		;GO IF NOT
	CALL	ILPRT
	DB	'Version for: PMMI S-100 MODEM Starting at Port ',0
	LDA	IN$MODCTLP+1
	CALL	HEXO
	CALL	ILPRT
	DB	'H',CR,LF,0
	RET
;
SYSVER1:
	CALL	ILPRT	;IF NOT USING THE PMMI S-100 BOARD
	DB	'Version for: Non-PMMI MODEM',CR,LF,0
	RET
;
;INSERT YOUR LOGON HERE, MUST END IN 0.
LOGON:	DB	0
;
;INSERT YOUR INITIALIZATION ROUTINE HERE IF NEEDED.
;CAN REPLACE THE FOLLOWING SECTION WHICH IS PRESENTLY
;USED FOR THE PMMI BOARD.
;
INITMOD:
	LDA	PMMIBYTE
	ORA	A
	RZ
	LDA	ANSWFLG	;IF ANSWER OR ORIGINATE MODE..
	ORA	A	;..IS NOT REQUESTED OR NO..
	JNZ	SKIPB1	;..BAUDRATE SPECIFIED, THEN..
	CALL	GETBAUD	;..ROUTINE RETURNS WITH CHANGE..
	JMP	FIXBAUD	;..OF BAUD. IF OPT REQUESTED,..
;
SKIPB1:	LDA	ORIGFLG	;..A BLANK FORCES 300 BAUD..
	ORA	A	;..ELSE A 0 FROM NEWBAUD..
	RNZ		;..FORCES 300 BAUD.
	CALL	GETBAUD
FIXBAUD:
	CALL	OUT$BAUDRP
	CALL	CHGMSPD
	MOV	A,C
	STA	MSPEED
	MOV	A,B
	CPI	52
	MVI	A,5FH
	JC	GT300
	MVI	A,7FH
GT300:	CALL	OUT$MODCTL2
	STA	MODCTLB	;SAVE MODEM CONTROL BYTE
	LDA	ORIGFLG
	ORA	A
	MVI	A,ORIGMOD
	JZ	OFFHOOK
	LDA	ANSWFLG
	ORA	A
	MVI	A,ANSWMOD
	RNZ
OFFHOOK:
	LXI	H,4000
OFFDLY:	DCR	L
	JNZ	OFFDLY
	DCR	H
	JNZ	OFFDLY
	CALL	OUT$MODCTLP
	RET
;
GETBAUD:
	LDA	FCB+9
	CPI	' '
	MVI	A,52
	RZ
	LDA	FCB+9
	CPI	0
	MVI	A,52
	RZ
	LXI	D,FCB+9
	LXI	H,0
DECLP:	LDAX	D
	INX	D
	CPI	' '
	JZ	DECLP
	CPI	'0'
	JC	BADRATE
	CPI	'9'+1
	JNC	BADRATE
	SUI	'0'
	MOV	B,H
	MOV	C,L
	DAD	H
	DAD	H
	DAD	B
	DAD	H
	ADD	L
	MOV	L,A
	JNZ	DIGNC
	INR	H
DIGNC:	MOV	A,E
	CPI	FCB+12
	JNZ	DECLP
	MOV	A,H
	CMA
	MOV	D,A
	MOV	A,L
	CMA
	MOV	E,A
	INX	D
	LXI	H,15625
	LXI	B,-1
DIVLP:	INX	B
	DAD	D
	JC	DIVLP
	MOV	A,B
	ORA	A
	MOV	A,C
	RZ
BADRATE:
	CALL	ERXIT
	DB	'++ Invalid baud rate ++$'
;
CHGMSPD:		;CHANGES MSPEED FOR 110-710 BAUD
	MVI	C,0	;CONTAINS MSPEED
	MOV	B,A	;SAVE BAUD RATE DIVISOR
	CPI	100	; < 300 BAUD
	RNC
	INR	C
	CPI	40	; < 450 BAUD
	RNC
	INR	C
	CPI	30	; < 600 BAUD
	RNC
	INR	C
	CPI	24	; < 710 BAUD
	RNC
	INR	C	;MUST BE 710 BAUD
	RET
;
;DIALING ROUTINES TAKEN (AND GREATLY MODIFIED) FROM PMMI MANUAL.
;MODEM CONTROL COMMAND WORDS
;
CLEAR	EQU 3FH	;IDLE MODE
MAKEM	EQU 1	;TELE LINE MAKE (OFF HOOK)
BRKM	EQU 0	;TELE LINE ON HOOK (BREAK DURING DIALING)
DTMSK	EQU 1	;DIAL TONE MASK
RBLMT	EQU 70	;# OF SEC*10 TO WAIT BEFORE GIVING NO RING HEARD MSG
RBWAIT	EQU 50	;# OF SEC*10 DELAY BEFORE REDIALING NUMBER
TMPUL	EQU 80H	;TIMER PULSES MASK BIT
TRATE	EQU 250	;VALUE FOR 0.1 SECOND
;
DIALPL:
	LDA	PMMIBYTE   ;FLAG FOR PMMI OPERATION
	ORA	A          ;SET FLAGS
	RZ                 ;PMMI FALSE, RETURN
	XRA	A          ;0
	STA	CRFLAG     ;CONTINUOUS REDIAL FLAG
DPL1:	LXI	H,CMDBUF+1 ;POINT # OF CHARS IN BUFF
	MOV	A,M        ;GET # OF CHARS
	CPI	4          ;4 OR MORE CHARS TYPED BEFORE <CR>?
	JC	ENTNUM     ;NO, ASK FOR NUMBER
	LXI	H,CMDBUF+6 ;POINT TO NUMBER TO DIAL
	JMP	DIAL10     ;CHECK IF LIB #, & DIAL
;
DIALPL0:
	CALL	DISCONNT
	CALL	ILPRT
	DB	CR,LF,'Waiting for dial tone',CR,LF,0
	MVI	A,MAKEM     ;MAKE MAKE (OFF-HOOK)
	CALL	OUT$MODCTLP ;DO IT
	MVI	D,DTMSK     ;DIAL TONE MASK
	MVI	C,100       ;10 SECOND WAIT
	CALL	WAIT        ;WAIT FOR DIAL TONE
	NOP                 ;DELAY
;
; WAIT SUBROUTINE WILL RETURN WITH CARRY SET IF UNABLE TO
; GET DIALTONE, ELSE CARRY NOT SET MEANS DIALTONE RECEIVED
;
	RNC		;IF DIAL TONE WITHIN 10 SECONDS
	CALL	ILPRT	;ELSE, MESSAGE AND RETURN WITH CARRY SET
	DB	CR,LF,'<< No dial tone >>',CR,LF,0
	CALL	DISCONNT
	STC
	RET
;
;THIS IS ALL THE SET-UP FOR THE PRINT AT 'ENTNUM2'.
;
ENTNUM:
	MVI	C,13       ;NUMBER OF LINES TO MOVE
	LXI	H,NUMBLIB  ;ADDRESS OF SOURCE MEMORY
	LXI	D,DBUF     ;ADDRESS OF TARGET MEMORY
	CALL	NEWLINE    ;START WITH CRLF
	STAX	D          ;+LF
	INX	D          ;AND BUMP IT
ENTNUM1:
	MVI	B,32	;NUMBER OF BYTES TO MOVE
	CALL	MOVE	;MOVE TO BUFFER
	CALL	SPACES	;2 ENTRIES + 3 SPACES = 67 CHARACTERS
	MVI	B,32
	CALL	MOVE
	CALL	NEWLINE
	DCR	C	;NUMBER OF LINES TO PRINT
	JZ	ENTNUM2
	JMP	ENTNUM1
;
ENTNUM2:
	MVI	A,'$'
	STAX	D
	CALL	CLRTST
	MVI	C,PRINT
	LXI	D,DBUF	;POINT TO TABLE OF NUMBERS TO PRINT
	CALL	BDOS
	CALL	ILPRT
	DB	CR,LF,'Enter number or library letter - <CR> when finished,'
	DB	CR,LF,'Ctrl-X cancels while dialing: ',0
	LXI	D,CMDBUF
	CALL	INBUFF
DIALLP1:
	LDA	CMDBUF+1
	ORA	A	;NULL MEANS <CR> WAS TYPED
	JZ	BORTIT	;ABORT DIALING, RETURN TO MENU
	LXI	H,CMDBUF+2 ;FIRST TYPED CHAR OF NUMBER TO DIAL
;
; ENTER THIS ROUTINE WITH HL POINTING TO NUMBER TO DIAL
;
DIAL10:
	PUSH	H	;SAVE HL
	CALL	DIALPL0	;DISCONNECT, RECONNECT, WAIT FOR DIAL TONE
	POP	H	;GET HL
	JC	DILAGN	;NO DIALTONE?, ASK RETRY
	MVI	B,'A'	;FIRST LETTER OF ALPHABET
	MVI	E,0	;COUNTS NUMBER OF LETTERS TO MATCH
	MVI	C,26	;NUMBER OF LETTERS IN ALPHABET
	MOV	A,M	;GET CHAR BUFFER
DIAL11:
	CMP	B	;NUMBER FROM TABLE?
	JZ	LIBSET
	INR	B	;MAKE NEXT LETTER (A-Z)
	INR	E	;COUNT UP
	DCR	C	;COUNT DOWN
	JZ	DIALLPX	;NOT A LETTER
	JMP	DIAL11	;LOOP
;
LIBSET:
	LXI	H,NUMBLIB ;PHONE NUMBER LIBRARY
	LXI	B,32	;LENGTH OF LIBRARY ENTRY
	MOV	A,E	;NUMBER OF TIMES TO ADD 32 TO HL
	ORA	A	;SET FLAGS
	JZ	DIAL13
DIAL12:
	MOV	A,M	;GET FIRST CHAR OF SELECTED LIB ENTRY
	ORA	A	;SET FLAGS
	JZ	DIALLPA	;SEND BAD LIBRARY MSG AND ABORT
	DAD	B	;INCREMENT HL BY 32
	DCR	E	;COUNTDOWN
	JNZ	DIAL12	;NOT THERE YET, LOOP
DIAL13:
	MVI	B,32	;NUMBER OF CHARACTERS TO GET FROM TABLE
	LXI	D,CMDBUF+1 ;POINT TO BUFFER
	XCHG		;HL POINTS TO CMDBUF+1
	MOV	M,B	;STORE # OF BYTES IN A TABLE ENTRY
	XCHG		;RESTORE REG.
	INX	D	;POINT TO FIRST CHAR POSITION IN BUFFER
	CALL	MOVE	;MOVE TABLE ENTRY TO BUFFER
DIALLPX:
	LDA	CMDBUF+1
	MOV	E,A	;NUMBER OF CHARS IN BUFF
	LXI	H,CMDBUF+2 ;POINT FIRST CHAR
DIALLP2:
	MOV	A,M	;GET FIRST # FROM BUFFER
	ORA	A	;SET FLAGS
	JNZ	NOBLMSG
;
; PRINT BAD LIBRARY MESSAGE AND ABORT IF NULL ENCOUNTERED
DIALLPA:
	CALL	ILPRT
	DB	CR,LF,'++ Bad library number called ++',CR,LF,0
	JMP	BORTIT	;ABORT
;
; DIAL A DIGIT, CHECK KBD FOR ABORT
;
NOBLMSG:
	CALL	DIAL	;DIAL IT
	CALL	STAT	; KEYPRESS?
	ORA	A	;SET FLAGS
	CNZ	KEYIN	;YES, GO GET IT
	CPI	CAN	;^X?
	JZ	BORTIT	;YES, ABORT
	INX	H	;BUMP POINTER
	PUSH	D	;SAVE DE
	PUSH	H	;SAVE HL
	MVI	B,1	;WAIT 1 TIME INTERVAL
	CALL	TIMER
	POP	H	;RESTORE HL
	POP	D	;RESTORE DE
	DCR	E	;COUNT DOWN CHARS IN BUFF
	JNZ	DIALLP2	;NOT DONE, LOOP
	JZ	DIALDN	;DIALING DONE
DISCONNT:
	XRA	A	;0
	CALL	OUT$MODCTL2 ;CLEAR DAV, ESD, ETC
	CALL	OUT$MODCTLP ;HANG-UP
	PUSH	B
	MVI	B,8	;WAIT FOR PMMI TO DISCONNECT
	CALL	TIMER
	POP	B
	RET
TIMER:
	MVI	A,TRATE    ;TRATE 250, VALUE FOR .1 SEC INTERVAL
	CALL	OUT$BAUDRP ;B-REG CONTAINS NUMBER OF .1 SEC INTERVALS
TIMES:
	CALL	IN$BAUDRP  ;TO COUNT
	ANI	TMPUL
	JZ	TIMES      ;WAIT FOR TIMER TO GO HIGH
TIMEE:
	CALL	IN$BAUDRP
	ANI	TMPUL
	JNZ	TIMEE      ;WAIT FOR TIMER TO GO LOW
	DCR	B
	JNZ	TIMES
	RET
BORTIT:
	CALL	DISCONNT
	CALL	CRLF
	JMP	MENU
;
;AUTO DIALER
;
DIAL:
	CALL	TYPE	;PRINT WHATEVER CHARACTER, DASHES, ETC.
	CPI	30H
	RC		;DIGIT MUST BE AT LEAST 0..
	CPI	'R'	;COULD IT BE A RINGBACK CHARACTER
	JNZ	DIAL1	;NO? - JUMP
	PUSH	PSW	;SAVE ACCUMULATOR & FLAGS
	MOV	A,E	;GET # OF CHAR LEFT INTO ACC.
	CPI	01H	;IS THIS THE LAST CHARACTER?
	JZ	RINGBK	;IF SO, IT MUST BE RINGBACK CHAR - DO RINGBACK
	POP	PSW	;EVERYTHING BACK AS IT WAS
DIAL1:	CPI	3AH
	RNC		;..AND NOT MORE THAN 9
	ANI	0FH	;STRIP ASCII -- COULD ALSO DO SUI 30H ('0')
	JNZ	DIALS
	MVI	A,10	;CONVERT ZERO TO 10 PULSES
DIALS:	MOV	C,A
	LDA	PULSERATE ;CONTAINS VALUE FOR DIAL SPEED
	CALL	OUT$BAUDRP
DIALC:	CALL	IN$BAUDRP
	ANI	TMPUL
	JNZ	DIALC
DIALB:	CALL	IN$BAUDRP
	ANI	TMPUL
	JZ	DIALB
MAKEP:	MVI	A,MAKEM
	CALL	OUT$MODCTLP
TIMEM:	CALL	IN$BAUDRP
	ANI	TMPUL
	JNZ	TIMEM
	MVI	A,BRKM
	CALL	OUT$MODCTLP
TIMEB:	CALL	IN$BAUDRP
	ANI	TMPUL
	JZ	TIMEB
	DCR	C
	JNZ	MAKEP
	MVI	A,MAKEM
	CALL	OUT$MODCTLP
	MVI	B,2
	CALL	TIMER
	RET
;
RINGBK:
	POP	PSW       ;TO GET IT OFF THE STACK
	LDA	CMDBUF+1  ;GET # OF CHAR IN BUFFER
	SUI	01H       ;SUBTRACT 1 TO AVOID THE RINGBACK CHAR
	STA	CMDBUF+1  ;STORE THE NEW VALUE
	MVI	D,DTMSK   ;LOAD TONE DETECT MASK
	MVI	C,RBLMT   ;SET TIMER FOR RBLMT NUMBER OF SECONDS
	CALL	WAIT
	JC	RBTIME    ;JUMP IF NO RING DETECTED
	MVI	B,25      ;WAIT 2.5 SEC
	CALL	TIMER
	CALL	IN$BAUDRP ;IS TONE STILL PRESENT?
	ANA	D
	JNZ	RNGBK1
	JMP	DILAGN    ;YES, MUST BE BUSY
;
RNGBK1:
	CALL	HANGP     ;HANG UP THE PHONE
	MVI	B,RBWAIT  ;WAIT X SEC
	CALL	TIMER
	CALL	DIALPL0   ;GO OFF HOOK & LISTEN FOR DIAL TONE
	JNC	DIALLPX   ;GO REDIAL NUMBER
	JMP	DILAGN    ;NO DIAL TONE HEARD
;
RBTIME:
	CALL	CRLF
	JMP	RNGBK1    ;HANGUP, REDIAL, & LISTEN FOR CARRIER
;
;TIME OUT ROUTINE. MUST BE CALLED WITH MASK IN D REG FOR INPUT
;AT RELATIVE PORT 2 AND NUMBER OF SECONDS * 10 IN C REG.
;
WAIT:
	MVI	B,1	
	CALL	TIMER	;WAIT FOR TIMER TO GO HIGH THEN LOW
	CALL	IN$BAUDRP ;PMMIADDR+2 (MODEM STATUS PORT)
	ANA	D	;(CTS or DIALTONE MASK)
	RZ		;ACTIVE LOW, SO RETURN ON 0
	PUSH	B	;SAVE..
	PUSH	D	;..ACTIVE REG'S
	CALL	STAT	;KEYPRESS?
	ORA	A	;SET FLAGS
	CNZ	KEYIN	;YES, GET CHAR
	CPI	CAN	;^X?
	JZ	WAIT1	;YES, DISCONNECT, JMP TO MENU
	POP D		;RESTORE..
	POP B		;..REGS
	DCR C		;COUNT-DOWN
	JNZ	WAIT
	STC		;SET CARRY TO INDICATE MASK NOT SET
	RET
;
WAIT1:
	POP	D	;RESET..
	POP	B	;..STACK
	JMP	DISCON1	;DISCONNECT
;
HANGP:
	MVI	A,CLEAR
	CALL	OUT$MODCTL2
	MVI	A,0
	CALL	OUT$MODCTLP
	RET
;
DIALDN:
	CALL	CRLF
	MVI	A,07FH       ;TURN ON DTR
	CALL	OUT$MODCTL2  ;TIMER RATE?
	MVI	B,1
	CALL	TIMER        ;WAIT FOR MODEM TO TURN ON DTR
	MVI	A,5DH        ;2 STOP BITS, NO PARITY, 8 DATA BITS
	CALL	OUT$MODCTLP
	MVI	D,4          ;CLEAR TO SEND MASK
	MVI	C,WAITCTS    ;WQAIT TIME FOR CTS (25.5 SEC MAX)
	CALL	WAIT
	JNC	CONMADE      ;CONNECTION MADE
	CALL	DISCONNT
DILAGN:	LDA	CRFLAG       ;CONTINUOUS REDIAL FLAG
	ORA	A
	JNZ	DILAGN0
	CALL	ILPRT
	DB	CR,LF,'No answer after time-out.  Redial? (Y/N/C): ',BELL,0
	CALL	KEYIN	;GET RESPONSE
	CALL	TYPE	;ECHO IT
	CALL	UCASE	;ANI 5FH
	CALL	CRLF	;NEW LINE
	CPI	'N'	;REDIAL?
	JZ	MENU	;NO, GO MENU
	CPI	'Y'	;REDIAL?
	JZ	DILAGN0	;YES, REDIAL
	CPI	'C'	;CONTINUOUS REDIAL?
	JNZ	DILAGN	;INVALID RESPONSE, ASK AGAIN
	XRA	A
	CMA		;0FFH
	STA	CRFLAG	;CONTINUOUS REDIAL FLAG
 DILAGN0:
	MVI	B,70	;7 SECONDS WAIT FOR PMMI RESET
	CALL	TIMER	;ELSE BUSY TONE MAY BE SENSED AS DIALTONE
	LXI	H,CMDBUF+1	;CHECK IF 'CAL LIBNUM'
	MOV	A,M
	CPI	4	;MORE THAN 4 CHARACTERS TYPED
	JC	DIALLP1	;NO, THEN GET MENU CHOICE
	JMP	DPL1	;YES, THEN USE CAL LETTER
;
CONMADE:
	CALL	ILPRT
	DB	CR,LF,'Connection established - Select options: ',BELL,0
DILAGN1:
	CALL	STAT	;KEYPRESS?
	ORA	A	;SET FLAGS
	JNZ	GETCMD	;KEY PRESSED, GO GET OPTIONS
	MVI	A,BELL
	CALL	TYPE	;RING BELL
	LXI	B,2000H
DILAGN2:
	DCR	C
	JNZ	DILAGN2	;KILL SOME TIME FOR TERMINAL TO PROCESS BELL
	DCR	B
	JNZ	DILAGN2
	JMP	DILAGN1	;LOOP
;
CRFLAG:		DB	0		;CONTINUOUS REDIAL FLAG
;
; END OF PMMI ROUTINES
;
;
;THE NON PMMI SETUP ROUTINES ARE INTENDED TO COME FROM
;THE USER OVERLAY. THE FOLLOWING IS A SAFETY NET
;
SETUPR:		RET
;
; PHONE NUMBER LIBRARY TABLE FOR DIALING FROM LIBRARY
; OF NUMBERS STORED IN THESE DB'S AT ASSEMBLY-TIME.
; EACH DB MUST BE 32 CHARACTERS LONG FOR PROPER OPERATION.
; A 'DB 0' INDICATES NO DIALING, PROGRAM WILL DISCONNECT
; AND RETURN TO COMMAND MODE.  LAST DB MUST BE DB 0. UP TO
; 26 NUMBERS ARE ALLOWED.
;
NUMBLIB:
;	'----5---10---15---20---25-----32'
DB	'A=Amrad           1-703-734-1387'	;'A'
DB	'B=Ben Bronson     1-312-955-4493'	;'B'
DB	'C=CBBS Pasadena   1-213-799-1632'	;'C'
DB	'D=PMMI            1-703-379-0303'	;'D'
DB	'E=Tech. CBBS      1-313-846-6127'	;'E'
DB	'F=Ron Fowler     1-313-729-1905R'	;'F'
DB	'G=Gasnet NASA     1-301-344-9156'	;'G'
DB	'H=Dave Hardy      1-313-846-6127'	;'H'
DB	'I=Wayne Hammerly  1-301-953-3753'	;'I'
DB	'J=RBBS Pasadena   1-213-356-1034'	;'J'
DB	'K=David Kozinn    1-216-334-4604'	;'K'
DB	'L=Program Store   1-202-337-4694'	;'L'
DB	'M=Kelly Smith     1-805-527-9321'	;'M'
DB	'N=SuperBrain Sys  1-617-862-0781'	;'N'
DB	'O=R.L.Plouffe     1-703-524-2549'	;'O'
DB	'P=K.Petersen     1-313-759-6569R'	;'P'
DB	'Q=Bruce Ratoff    1-201-272-1874'	;'Q'
DB	'R=Mark Pulver     1-312-789-0499'	;'R'
DB	'S=                              '	;'S'
DB	'T=                              '	;'T'
DB	'U=                              '	;'U'
DB	'V=                              '	;'V'
DB	'W=                              '	;'W'
DB	'X=                              '	;'X'
DB	'Y=                              '	;'Y'
DB	'Z=                              '	;'Z'
DB	0					; end
;	'----5---10---15---20---25-----32'
;
START:
	LXI	H,0
	DAD	SP	;GET CP/M'S STACK
	SHLD	STACK	;SAVE IT
	LXI	SP,STACK	;START LOCAL STACK
	CALL	ILPRT
	DB	CR,LF,'MODEM 7.98 - 12/31/82',CR,LF,0
	CALL	INITADR	;INITIALIZE ADDRESSES
	CALL	JMP$SYSVER	;GIVE CONFIGURATION MESSAGE
	CALL	GETUSR	;GET USER
	STA	SAVUSR	;SAVE FOR EXIT
	MVI	A,TRUE	;0FFH
	STA	NFILFLG
	CMA		;0
	STA	SAVEFLG
	LDA	FCB+1		;IS THERE A COMMAND TAIL?
	STA	OPTION
	CPI	' '
	JNZ	START0		;IF YES, DIGEST IT
	SUB	A
	STA	EXITFLG		;ELSE SAY WE WANT MENU
	JMP	START1
START0:
	LXI	H,80H		;SIMULATE COMMAND LINE INPUT FROM MENU
	MOV	B,M		;SAVE CHAR CNT
STARTA:
	INX	H
	MOV	A,M		;SKIP OVER LEADING SPACES IN COMMAND TAIL
	CPI	' '
	JNZ	STARTB
	DCR	B
	JMP	STARTA
STARTB:
	MOV	A,B
	STA	CMDBUF+1	;STORE COMMAND CHAR COUNT LESS LEADING SPACES
	INR	B		;MOVE 1 EXTRA BYTE (SHOULD BE A NULL)
	LXI	D,CMDBUF+2
	CALL	MOVE
	CALL	SETFCB		;DIGEST COMMAND LINE AND OPTIONS
START1:
	LDA	UARTFLG
	ORA	A
	MVI	A,ANSWMOD
	STA	UARTCTLB
	JNZ	RESTART
	MVI	A,ORIGMOD
	STA	UARTCTLB
;
RESTART:
	LXI	SP,STACK;MAKE SURE WE HAVE A CLEAN STACK
	LXI	D,CMDBUF+1	;MAY BE USEFUL WHERE WE ARE GOING
	LDA	OPTION	;GET MAIN OPTION
	MOV	B,A	;SAVE IT
	LDA	PMMIBYTE ;PMMI?
	ORA	A	;SET FLAGS
	MOV	A,B	;GET OPTION BACK
	JZ	S1	;NOT PMMI
	CPI	'C'	;CALL (DIAL) FUNCTION?
	JZ	JMP$DIALPL	;YES, GO TO IT
	CPI	'D'	;DISCONNECT?
	JZ	DISCON1	;YES, DISCONNECT & GO MENU
S1:	CPI	' '	;NO OPTION SPEC'D?
	JZ	MENU	;TRUE, GO MENU
	CPI	'H'	;MENU ASKED FOR?
	JZ	MENU2	;YES, GO MENU2
	CALL	JMP$INITMOD
	CALL	MOVEFCB
	CALL	IN$MODDATP ;GOBBLE UP GARBAGE..
	CALL	IN$MODDATP ;..CHARACTERS ON LINE
	XRA	A
	STA	ECHOFLG	;RESET ECHO FLAG
	STA	LOCFLG	;RESET LOCAL FLAG
	LDA	OPTION	;PROCESS MAIN OPTION
	CPI	'E'	;ECHO MODE?
	JNZ	NOECH	;JUMP IF NOT
	MVI	A,TRUE	;SET ECHO TO TRUE
	STA	ECHOFLG
	JMP	DSKSAVE
NOECH:	CPI	'L'	;LOCAL ECHO MODE
	JNZ	NOLOC
	MVI	A,TRUE
	STA	LOCFLG
	JMP	DSKSAVE
NOLOC:	CPI	'T'	;TERMINAL MODE?
	JZ	DSKSAVE	;YES
	CPI	'S'	;SEND A FILE?
	JZ	SENDFIL	;YES
	CPI	'R'	;RECEIVE A FILE?
	JZ	RCVFIL	;YES
	CALL	NOTVLDMSG	;SAY NOT A VALID OPTION
	JMP	MENU	;NO VALID OPTION SPEC'D, GO MENU
;
;REVISED TERMINAL ROUTINE ALLOWING MEMORY SAVE
;
DSKSAVE:
	LDA	FCB+1	;FIRST CHAR OF FILENAME
	CPI	' '	;FILE SPEC'D
	JNZ	GOODNM	;YES, GOOD NAME
	MVI	A,TRUE	;0FFH
	STA	NFILFLG
	CMA		;0
	STA	SAVEFLG
	JMP	TERM
;
GOODNM:
	CALL	ERASFIL
	CALL	MOVE2
	LXI	D,FCB3
	MVI	C,MAKE
	CALL	BDOS
	LXI	D,FCB3
	MVI	C,OPEN
	CALL	BDOS
	LXI	H,BOTTRAM
	SHLD	HLSAVE
	XRA	A
	STA	NFILFLG
	STA	LISTMOR		;STOP ANY BUFFERED PRINTER OUTPUT
TERM:	LDA	UARTFLG
	STA	ORIGSAV
	ORA	A
	MVI	A,ANSWMOD
	STA	UARTCTLB
	JNZ	TERM2
	MVI	A,ORIGMOD
	STA	UARTCTLB
TERM2:	LDA	LISTMOR		;ANY BUFFERED PRINTER OUTPUT?
	ORA	A
	CNZ	GOLIST		;GO IF SO
	CALL	STAT	;KEYPRESS?
	JZ	TERML	;NO, CHECK LINE
	CALL	KEYIN	;GET CHAR FROM KBD
	CPI	' '
	JNC	NOTOG	;GO IF NOT CONTROL CHARACTER
	MOV	B,A	;SAVE
	CPI	BKSP	;TEST FOR BACKSPACE
	JNZ	NOBKSP
	LDA	CONVBKSP  ;CONVERT BACKSPACE TO RUB?
	ORA	A
	JZ	NOBKSP	;GO IF NO CONVERSION
	MVI	A,RUB
	JMP	NOTOG
NOBKSP:	LDA	EXACFLG
	ORA	A	;EXACT?
	MVI	A,0
	STA	EXACFLG		;CLR FOR NEXT TIME
	JZ	NOTEXAFLG	;GO OF EXAFLG FALSE
	LDA	LOCONEXTCHR
	ORA	A	;SHOULD WE SEND ON EXAFLG?
	MOV	A,B
	JZ	NOTOG	;YES, IF LOCONEXTCHR FALSE
	LDA	EXTCHR	;WE WANT TO SEND EXTCHR IN ANY CASE
	CMP	B
	MOV	A,B
	JZ	NOTOG	;SEND IF EXTCHR
	JMP	LOCCHK	;OTHERWISE DO LOCAL STUFF
NOTEXAFLG:
	LDA	EXTCHR	;TREAT NEXT CHARACTER IN SPECIAL WAY?
	CMP	B
	JZ	EXTFLG	;YES, SET EXAFLG FOR NEXT CHAR
	LDA	LOCONEXTCHR
	ORA	A	;SHOULD WE SEND IF NOT EXAFLG
	MOV	A,B
	JNZ	NOTOG	;YES, IF LOCONEXTCHR TRUE
LOCCHK:	LDA	EXITCHR	;RETURN TO MENU?
	CMP	B
	JZ	EXITMEN	;YES, RETURN TO MENU
	LDA	TRANCHR	;OUTPUT TEXT FILE TO REMOTE?
	CMP	B
	CZ	TRANSFER  ;SEND-A-FILE (BLIND SEND)
	JZ	TERM2	  ;LOOP
	LDA	TRANLOGON
	ORA	A
	JZ	SKPLOGON
	LDA	LOGCHR	;SEND LOGON?
	CMP	B
	JZ	SENDLOG
SKPLOGON:
	LDA	LSTTST
	ORA	A
	JZ	NOLST
	LDA	LSTCHR
	CMP	B
	JNZ	NOLST
	LDA	LISTFLG
	CMA
	STA	LISTFLG
	CALL	CRLF
	CALL	CRLF
	CALL	LSTMSG
	CALL	CRLF
	JMP	TERML
NOLST:	LDA	PMMIBYTE
	ORA	A
	JZ	S2
	LDA	DISCCHR	;PMMI DISCONNECT?
	CMP	B
	JZ	DISCON1	;YES, DISCONNECT & RETURN TO MENU
	LDA	BRKCHR	;PMMI BREAK?
	CMP	B
	JZ	BREAK
	LDA	CHGBAUD	;PMMI CHANGE BAUD?
	CMP	B
	PUSH	PSW
	PUSH	H
	CZ	NEWBAUD
	POP	H
	POP	PSW
	JZ	TERML
S2:	LDA	UNSAVECHR	;CLOSE INPUT BUFFER?
	CMP	B
	JZ	S2A	;IF YES, DISABLE COPY
	LDA	SAVECHR	;OPEN INPUT BUFFER?
	CMP	B
	MOV	A,B	;RESTORE CHARACTER TYPED
	JNZ	NOTOG
	LDA	NFILFLG	;DO NOT ALLOW SAVE IF..
	CPI	TRUE	;..THIS FLAG IS SET.
	JZ	TERML
	MVI	A,TRUE	;0FFH -- ALLOW COPY INTO FILE
	JMP	S2B
S2A:	MVI	A,FALSE	;0 -- STOP COPY INTO FILE
S2B:	STA	SAVEFLG
	CALL	BUFMSG
	JMP	TERML
;
BUFMSG:	CALL	ILPRT
	DB	CR,LF,LF,'** Memory buffer ',0
	LDA	SAVEFLG
	ORA	A
	JZ	BUFMSG2
	CALL	ILPRT
	DB	'open **',CR,LF,LF,':',BELL,0
	RET
;
BUFMSG2:
	CALL	ILPRT
	DB	'closed **',CR,LF,LF,BELL,0
	RET
;
EXITMEN:
	CALL	CRLF
	CALL	CLREOS	;CLEAR TO END OF SCREEN TO CLEAN UP ANY MESS
	JMP	MENU0
;
SENDREADY:
	CALL	IN$MODCTLP
	CALL	ANI$MODSNDB
	JMP	CPI$MODSNDR
;
SENDLF:	CALL	SENDREADY
	JNZ	NOLFYET		;GO IF NOT READY FOR OUTPUT YET
	MVI	A,LF
	JMP	NOTOG		;SEND LF
NOLFYET:
	CALL	EXITTEST
	JNC	EXITMEN		;GO IF SO, SO DON'T GET HUNG UP
	JMP	SENDLF		;ELSE KEEP TRYING TO SEND LF
;
SENDLOG:
	PUSH	H
	LHLD	LOGONPTR	;HL POINTS TO START OF LOGON MESSAGE
LOGLP:	CALL	SENDREADY
	JNZ	NOSENDLOG	;GO IF NOT READY
	MOV	A,M		;GET LOGON BYTE
	INX	H
	CPI	0		;IS IT THE END?
	JZ	ENDLOG		;GO IF SO
	CALL	OUT$MODDATP
	JMP	LOGLP
NOSENDLOG:
	CALL	EXITTEST	;TEST SO DON'T GET HUNG UP
	JNC	EXITLOG		;GO IF OPERATOR WANTS EXIT
	JMP	LOGLP
;
ENDLOG:	POP	H
	JMP	TERML
;
EXITLOG:
	POP	H
	JMP	EXITMEN
;
EXITTEST:
	CALL	STAT	;KEYPRESS?
	JZ	NOKEY
	CALL	KEYIN	
	MOV	B,A
	LDA	EXITCHR	;SEE IF OPERATOR WANTS EXIT
	CMP	B
	JNZ	NOKEY	;GO IF WRONG KEY		
	STC
	CMC		;RESET FOR EXIT
	RET
NOKEY:	STC		;SET FOR NO KEY OR WRONG KEY
	RET
;
EXTFLG:	MVI	A,TRUE
	STA	EXACFLG
	JMP	TERML
;
RCVREADY:
	CALL	IN$MODCTLP
	CALL	ANI$MODRCVB
	JMP	CPI$MODRCVR
;
LSTMSG:	LDA	LISTFLG
	ORA	A
	JZ	LSTMSG2
	CALL	ILPRT
	DB	'Printer is on',CR,LF,0
	RET
LSTMSG2:
	CALL	ILPRT
	DB	'Printer is off',CR,LF,0
	RET
;
NOTOG:	CALL	OUT$MODDATP
	MOV	B,A
	LDA	LOCFLG
	ORA	A
	JNZ	LTYPE
	LDA	ECHOFLG
	ORA	A
	JZ	CHKCR
LTYPE:	MOV	A,B
	CALL	TYPE
	CALL	CHKSAVE		;TO STORE LOCAL IF BUFFER OPEN
	CALL	CHKPRNT
CHKCR:	MVI	A,CR
	CMP	B
	JNZ	TERML
	LDA	ADDLF
	ORA	A
	JZ	TERML
	JMP	SENDLF
;
TERML:	CALL	RCVREADY	;TEST FOR RECEIVED CHARACTER
	JNZ	TERM2
	CALL	IN$MODDATP
	ANI	7FH	;STRIP PARITY
	JZ	TERM2		
GIVLF:	CALL	TYPE
	MOV	B,A
	CALL	CHKSAVE
	CALL	CHKPRNT
	LDA	ECHOFLG
	ORA	A
	JZ	NOECHO
	MOV	A,B
	CALL	OUT$MODDATP
NOECHO:	MVI	A,CR
	CMP	B
	JNZ	TERM2
	LDA	ADDLF
	JZ	TERM2
	LDA	ECHOFLG
	ORA	A
	JNZ	SENDLF
	MVI	A,LF
	JMP	GIVLF
;
CHKSAVE:
	LDA	SAVEFLG
	ORA	A
	RZ
	MOV	M,B
	INX	H
	SHLD	HLSAVE	;MENU COMMAND DESTROYS HL-REG..
	MVI	A,LF
	CMP	B
	JNZ	NOCOLON	;..TYPE ":" AFTER EACH LINE FEED..
	MVI	A,':'	;..WHEN MEMORY SAVE ACTIVE.
	CALL	TYPE
NOCOLON:
	CALL	GETMAX
	CMP	H
	PUSH	B
	CZ	INTDSKSV
	POP	B
	RET
;
GETMAX:	LDA	SAVCCP
	ORA	A
	LDA	7
	JZ	SUB1
	SBI	8	;..PAGE BELOW CCP ..
SUB1:	DCR	A	;..OR BDOS HAS BEEN..
	RET		;..REACHED AND DISKSAVE IS NEEDED.
;
CHKPRNT:
	LDA	LISTFLG	;OUT TO PRINTER?
	ORA	A
	RZ		;RETURN IF NOT
	LDA	NFILFLG	;IS BUFFER USED FOR FILE?
	ORA	A
	JZ	NOBUFF	;DON'T BUFFER PRINTER IF SO, HOWEVER CHARACTERS
			;WILL BE LOST IF PRINTER IS SLOWER THAN MODEM
	CALL	GETMAX	;GET MAXIMUM FOR BUFFER
	LHLD	HLSAVE1	
	CMP	H	;ARE WE THERE?
	JNZ	NOTMAX	;GO IF NOT
	LXI	H,BOTTRAM	;FLUSH BUFFER
	SHLD	HLSAVE1
	SHLD	HLSAVE2
NOTMAX:	
	MOV	M,B	;SAVE CHARACTER IN BUFFER
	INX	H	;INCREMENT END OF BUFFER
	SHLD	HLSAVE1
	MVI	A,TRUE	;SET FLAG FOR PRINTER OUTPUT
	STA	LISTMOR
	RET
;
NOBUFF:
	CALL	LSTSTAT	
	RZ		;RETURN IF PRINTER BUSY
	MOV	C,B	;ELSE PRINT CHARACTER
	JMP	LISTER
;
GOLIST:
	CALL	LSTSTAT
	RZ		;RETURN IF PRINTER BUSY
	LHLD	HLSAVE2	;GET LOCATION OF NEXT CHARACTER TO PRINT
	MOV	C,M	;GET CHARACTER
	INX	H	;INCREMENT POINTER
	SHLD	HLSAVE2
	CALL	CMPBUFF	;CHECK FOR END OF BUFFER
	JMP	LISTER	;PRINT
;
;ROUTINE CHECKS FOR END OF BUFFER, RESETS BUFFER IF SO AND STOPS
;PRINTER OUTPUT
;
CMPBUFF:
	LHLD	HLSAVE2
	XCHG
	LHLD	HLSAVE1
	MOV	A,L
	SUB	E
	MOV	L,A
	MOV	A,H
	SBB	D
	ORA	L
	RNZ
	LXI	H,BOTTRAM
	SHLD	HLSAVE1
	SHLD	HLSAVE2
	XRA	A
	STA	LISTMOR
	RET
;
INTDSKSV:
	MVI	A,XOFF       ;SEND A CTRL-S TO STOP..
	CALL	OUT$MODDATP  ;..REMOTE COMPUTER OUTPUT.
	MVI	D,0          ;D IS THE BUFFER COUNT
	CALL	INMODEM      ;GET LAST BYTES SENT..
	STA	LASTBYT1     ;..AFTER CTRL-S.
	CALL	INMODEM      ;ADD MORE CALLS TO INMODEM..
	STA	LASTBYT2     ;..AND STA LASTBYT# IF YOU ARE..
	PUSH	D
	CALL	NUMREC1
	CALL	WRTDSK       ;WRITE THE RECORDS
	POP	D
	LXI	H,BOTTRAM
	INR	D
	DCR	D            ;TEST BUFFER COUNT FOR ZERO
	JZ	CTRLQ
	LDA	LASTBYT1     ;GET THE LAST BYTES THAT WERE..
	MOV	M,A          ;..SAVED AND PUT THEM IN..
	INX	H            ;..BOTTRAM.
	CALL	TYPE
	DCR	D
	JZ	CTRLQ
	LDA	LASTBYT2
	MOV	M,A
	INX	H
	CALL	TYPE
CTRLQ:
	MVI	A,XON        ;SEND START CHARACTER..
	JMP	OUT$MODDATP  ;..TO REMOTE COMPUTER.
;
BREAK:
	PUSH	D	;SAVE IT
	LXI	D,0	;ZERO IT
	LDA	MODCTLB	;GET THE LAST MODEM CONTROL BYTE
	ANI	0FBH	;SET THE TRANSMIT BREAK BIT LOW - ACTIVE LOW
	CALL	OUT$MODCTL2 ;SEND IT TO THE MODEM
	PUSH	H
	LXI	H,225
	CALL	FIXCNT
	PUSH	H
	POP	B
	POP	H
BRK1:	CALL	TIMERL
	JZ	BRK2	;IF TIME IS UP RESET BREAK
	CPI	0	;CHECK FOR NULLS
	JZ	BRK1	;DON'T PROCESS THEM
	ANI	7FH	;STRIP PARITY
	CALL	TYPE
	PUSH	PSW
	LDA	SAVEFLG
	CPI	FALSE
	JZ	NOSAVEB
	POP	PSW
	MOV	M,A
	INX	H
	SHLD	HLSAVE	;MENU COMMAND DESTROYS HL-REG..
			;..GET	HL WHEN ENTERING VIA 'NOL' CMD.
COLONB:
	CPI	LF
	JNZ	BRK1	;..TYPE ":" AFTER EACH LINE FEED..
	MVI	A,':'	;..WHEN MEMORY SAVE ACTIVE.
	CALL	TYPE
	JMP	BRK1
;
NOSAVEB:
	POP	PSW	;RESTORE IT
	JMP	BRK1
;
BRK2:
	LDA	MODCTLB	;GET MODEM CONTROL BYTE
	CALL	OUT$MODCTL2
	POP	D
	LHLD	HLSAVE	;LAST ADDRESS WRITTEN IF DATA BEING SAVED
	LDA	SAVCCP
	ORA	A
	JZ	SUB2
	LDA	7	;CHECK TO SEE IF..
	SBI	8	;..PAGE BELOW CCP ..
	JMP	SUB2A
;
SUB2:
	LDA	7
SUB2A:
	DCR	A	;..OR BDOS HAS BEEN ..
	CMP	H	;..REACHED AND DISKSAVE IS NEEDED.
	JNZ	TERM2	;NO PROBLEM - GO BACK TO NORMAL ROUTINE
	CALL	ILPRT
	DB	CR,LF,'Memory save buffer full',CR,LF,BELL,0
	JMP	TERM2
;
;THIS SUBROUTINE WILL LOOP UNTIL THE MODEM RECEIVES A CHARACTER
;OR 100 MILLISECONDS. IF A CHARACTER IS RECEIVED, A FLAG IS SET
;TO STORE THE CHARACTER. A MAXIMUM OF TWO CHARACTERS ARE STORED,
;BUT MORE MAY BE STORED IF DESIRED (SEE COMMENT IN "INTDSKSV"
;ABOVE).
;
INMODEM:
	PUSH	H
	LXI	H,625
	CALL	FIXCNT
	PUSH	H
	POP	B
	POP	H
TIMERL:
	CALL	RCVREADY
	JZ	GETBYTE
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	TIMERL
	RET
;
GETBYTE:
	CALL	IN$MODDATP
	INR	D
	RET
;
NUMRECS:
	MVI	M,EOFCHAR
	INX	H
	LXI	D,127
	DAD	D
NUMREC1:
	LXI	D,-(BOTTRAM)
	DAD	D
	MOV	A,L	;DIVIDE HL BY 128..
	ORA	A
	RAL		;..TO GET THE..
	MOV	L,H	;..NUMBER OF SECTORS
	MVI	H,0
	PUSH	PSW
	DAD	H
	POP	PSW
	MVI	A,0
	ADC	L
	MOV	L,A	;RETURNS WITH NUMBER OF..
	RET		;..128 BYTE RECORDS IN HL.
;
WRTDSK:	LXI	D,BOTTRAM
NEXTWRT:
	MVI	C,STDMA
	CALL	BDOSRT
	PUSH	D
	LXI	D,FCB3
	MVI	C,WRITE
	CALL	BDOSRT
	POP	D
	XCHG
	PUSH	D
	LXI	D,128
	DAD	D
	POP	D
	XCHG
	DCX	H
	MOV	A,H
	ORA	L
	JNZ	NEXTWRT
	RET
;
CLOSE3:	LXI	D,FCB3
	MVI	C,CLOSE
	JMP	BDOS
;
BDOSRT:
	PUSH	B
	PUSH	D
	PUSH	H
	PUSH	PSW
	CALL	BDOS
	POP	PSW
	POP	H
	POP	D
	POP	B
	RET
;
MOVE2:
	LXI	H,FCB3
	CALL	INITFCBS
	LXI	H,FCB
	LXI	D,FCB3
	MVI	B,12
	JMP	MOVE
;
;FILE TRANSFER ROUTINE - CALLED WITH 
;CONTROL-T FROM TERMINAL ROUTINE.
;TRANSFER MAY BE CANCELLED WHILE SENDING BY USING CONTROL-X.
;
TRANSFER:
	PUSH	H
	PUSH	D
	PUSH	B
	PUSH	PSW
	LXI	H,FCB4
	CALL	INITFCBS ;INITIALIZES FCBS POINTED..
	LXI	H,FCB+16 ;..TO BY HL REG.
	CALL	INITFCBS
GET:
	CALL	GETNAME
	LDA	CMDBUF+2 ;WAS FILE ENTERED
	CPI	20H
	JZ	TRANSL2
	CALL	MOVE4
	CALL	OPEN4
	CPI	0FFH	;RETURN WITH 0FFH MEANS
	JNZ	CONTIN	;FILE DOES NOT EXIST
TRANSL1:
	CALL	ILPRT
	DB	CR,LF,'++File does not exist++',CR,LF,0
TRANSL2:
	CALL	ILPRT
	DB	'Type "R" to return to modem',CR,LF
	DB	'Type "A" to re-enter name: ',BELL,0
	CALL	KEYIN
	CALL	UCASE
	CALL	TYPE	;ECHO RESPONSE
	CALL	CRLF
	CPI	'A'
	JZ	GET
	CPI	'R'
	JZ	RETURN
	JMP	TRANSL2
;
CONTIN:
	LXI	D,80H
	MVI	C,STDMA
	CALL	BDOS
READMR:
	CALL	READ80
	CPI	1	;END OF FILE
	JZ	RETURNS
	CPI	2	;BAD READ
	JZ	RETURNU
	CALL	SEND80C
	CPI	EOFCHAR	;END OF FILE - OMIT IF OBJECT..
	JZ	RETURNS	;..CODE IS TO BE SENT.
	CPI	CAN	;CANCELLATION?
	JZ	TRANCAN
	JMP	READMR
;
RETURNS:
	CALL	ILPRT
	DB	CR,LF,'++File transfer completed++',CR,LF,BELL,0
	JMP	RETURN
;
RETURNU:
	CALL	ILPRT
	DB	CR,LF,'++File transfer unsuccessful++',CR,LF,BELL,0
	JMP	RETURN
;
TRANCAN:
	CALL	ILPRT
	DB	CR,LF,LF,'++ Transfer cancelled ++',CR,LF,BELL,0
RETURN:
	POP	PSW
	POP	B
	POP	D
	POP	H
	RET
;
INITFCBS:		;ENTRY AT +2 WILL LEAVE..
	MVI	M,0	;..DRIVE NO. INTACT.
	INX	H	;WILL INITIALIZE AN FCB..
	MVI	B,11	;..POINTED TO BY HL-REG. FILLS 1ST POS
LOOP10:
	MVI	M,' '	;..WITH 0, NEXT 11 WITH..
	INX	H	;..WITH BLANKS, AND LAST..
	DCR	B	;..21 WITH NULLS.
	JNZ	LOOP10
	MVI	B,21
LOOP11:
	MVI	M,0
	INX	H
	DCR	B
	JNZ	LOOP11
	RET
;
GETNAME:
	CALL	ILPRT
	DB	CR,LF,'Enter file name to be transferred -  C/R TO QUIT: ',0
	LXI	D,CMDBUF
	CALL	INBUFF
	JMP	CRLF
;
MOVE4:
	LXI	D,CMDBUF
	LXI	H,FCB4
	JMP	CPMLINE
;
OPEN4:
	LXI	D,FCB4
	MVI	C,OPEN
	JMP	BDOS
;
READ80:
	LXI	D,FCB4
	MVI	C,READ
	JMP	BDOS
;
SEND80C:
	MVI	B,80H
	LXI	H,80H
SENDCH1:
	PUSH	D
	CALL	SPEED
	POP	D
	MOV	A,M
	CALL	MODOUT
	CPI	EOFCHAR
	RZ
	CALL	STAT	;TEST TO SEE IF
	ORA	A	;CANCELLATION REQUESTED
	JZ	SKIP12
	CALL	KEYIN
	CPI	CAN
	RZ
SKIP12:
	INX	H
	DCR	B
	JNZ	SENDCH1
	RET
;
MODOUT:
	PUSH	PSW
MODOUTL:
	LDA	XOFFTST
	ORA	A
	CNZ	TXOFF
	CALL	SENDREADY
	JNZ	MODOUTL
	POP	PSW
	CALL	OUT$MODDATP
	CALL	TYPE
	CPI	CR
	JZ	DLYCR
	RET
;
DLYCR:	INX	H	;ALWAYS DISPLAY LF AFTER CR
	MVI	A,LF
	CMP	M
	DCX	H
	JZ	LFSKIP
	CALL	TYPE
LFSKIP:	LDA	XONWAIT	;WAIT FOR XON AFTER CR?
	ORA	A
	JNZ	WAITXON
	LDA	CRDLY	;EXTRA DELAY AFTER CR
	JMP	DLYCR2
;
SPEED:	LDA	BYTDLY	;GET SPEED VALUE (0-9)
			;DELAY IS FROM 0.02 SEC FOR SPDVAL = 1
			;TO 0.18 SEC FOR SPDVAL	= 9
DLYCR2:	ORA	A
	RZ		;RETURN IF 0
	MOV	C,A
SPDLP:	CALL	SPD1	;OUTER LOOP
	DCR	C
	RZ
	JMP	SPDLP
;
SPD1:	PUSH	H
	LXI	H,357	;ABOUT 0.02 SEC AT 2 MHZ
	LDA	XOFFTST
	ORA	A
	JZ	SPD2
	LXI	H,102	;ADJUST FOR XOFF TESTING
	LDA	ECHOFLG
	ORA	A
	JZ	SPD2
	LDA	LOCFLG
	ORA	A
	JZ	SPD2
	LXI	H,76	;ADJUST AGAIN FOR REMOTE ECHO
SPD2:	CALL	FIXCNT
	PUSH	H
	POP	D
	POP	H
SPDLP1:	DCX	D	;INNER LOOP
	LDA	XOFFTST
	ORA	A
	CNZ	TXOFF
	MOV	A,E
	ORA	D
	RZ
	JMP	SPDLP1
;
TXOFF:	CALL	RCVREADY
	RNZ
	CALL	IN$MODDATP
	ANI	7FH
	CPI	XOFF
	CZ	WAITXON
	RET
;
WAITXON:
	CALL	RCVREADY
	JNZ	WTXON2
	CALL	IN$MODDATP
	ANI	7FH
	CPI	XON
	RZ
WTXON2:	CALL	STAT	;TEST TO SEE IF
	ORA	A	;CANCELLATION REQUESTED
	JZ	WAITXON ;SO DON'T GET HUNG UP
	CALL	KEYIN
	CPI	CAN
	RZ
	JMP	WAITXON
;
;SEND A CP/M FILE
;
SENDFIL:
	MVI	A,TRUE	;ALWAYS FORCE CHECKSUM MODE INITIALLY ON SEND
	STA	CKSUMFLG
SENDFIL1:
	CALL	PARITY	;SET PARITY IF REQUESTED
	LDA	BATCHFLG  ;CHECK IF MULTIPLE FILE..
	ORA	A	;..MODE IS SET.
	JNZ	SENDC1
	MVI	A,TRUE	;INDICATE SEND FOR BATCH MODE
	STA	SENDFLG
	LDA	FSTFLG	;IF FIRST TIME THRU..
	ORA	A	;..SCAN THE COMMAND LINE..
	CNZ	TNMBUF	;..FOR MULTIPLE NAMES.
	CALL	SENDFN	;SENDS FILE NAME TO RECEIVER
	JNC	SENDC2	;CARRY SET MEANS NO MORE FILES.
	MVI	A,'B'	;STOP BATCH..
	STA	BATCHFLG  ;..MODE OPTION.
	MVI	A,EOT	;FINAL XFER END
	CALL	SEND
	JMP	DONE
;
SENDC1:
	LDA	FCB+1
	CPI	' '
	JZ	BLKFILE
SENDC2:
	CALL	CNREC	;GET NUMBER OF RECORDS
	CALL	OPENFIL
	MVI	E,80
	CALL	WAITNAK
SENDLP:
	CALL	RDSECT
	JC	SENDEOF
	CALL	INCRSNO
	MVI	A,1
	STA	ERRCT
SENDRPT:
	CALL	SENDHDR
	CALL	SENDSEC
	LDA	CKSUMFLG
	ORA	A
	CZ	SENDCRC
	CNZ	SENDCKS
	CALL	GETACK
	JC	SENDRPT
	JMP	SENDLP
;
SENDEOF:
	MVI	A,EOT
	CALL	SEND
	CALL	GETACK
	JC	SENDEOF
	JMP	DONE
;
;RECEIVE A FILE
;
RCVFIL:
	LDA	CKSUMDFLT	;GET MODE REQUESTED BY OPERATOR
	STA	CKSUMFLG	;STORE IT
RCVFIL1:
	CALL	PARITY	;SET PARITY IF REQUESTED
	LDA	BATCHFLG ;CHECK IF MULT..
	ORA	A	;..FILE MODE.
	JNZ	RCVC1
	MVI	A,FALSE	;FLAG WHERE TO RETURN..
	STA	SENDFLG	;..FOR NEXT FILE TRANS.
	CALL	GETFN	;GET THE FILE NAME.
	JNC	RCVC2	;CARRY SET MEANS NO MORE FILES.
	MVI	A,'B'	;STOP BATCH..
	STA	BATCHFLG ;..MODE OPTION.
	JMP	DONE
;
RCVC1:
	LDA	FCB+1	;MAKE SURE FILE IS NAMED
	CPI	' '
	JZ	BLKFILE
;
RCVC2:
	CALL	CKCPM2
	CALL	CKBAKUP
RCVC3:
	CALL	ERASFIL
	CALL	MAKEFIL
	LDA	BATCHFLG
	ORA	A	;DON'T PRINT MSG IF..
	JZ	RCVFST	;..IN BATCH
	CALL	ILPRT
	DB	'File open, ready to receive',CR,LF,0
RCVFST:
	LDA	CKSUMFLG
	ORA	A
	MVI	A,NAK
	JNZ	RCVFIL2
	MVI	A,CRC
RCVFIL2:
	CALL	SEND
	LDA	QFLG
	ORA	A
	JZ	RCVLP
	LDA	CKSUMFLG
	ORA	A
	JNZ	RCVNAKM		;IF IN CRC MODE
	CALL	ILPRT		;THEN SAY SO
	DB	'CRC in effect',CR,LF,0
	JMP	RCVLP
RCVNAKM:
	CALL	ILPRT		;ELSE SAY CHECKSUM MODE
	DB	'Checksum in effect',CR,LF,0
RCVLP:
	CALL	RCVSECT
	JC	RCVEOT
	CALL	WRSECT
	CALL	INCRSNO
	CALL	SENDACK
	JMP	RCVLP
;
RCVEOT:
	CALL	WRBLOCK
	CALL	SENDACK
	CALL	CLOSFIL
	JMP	DONE
;	
;SUBROUTINES
;
SENDFN:
	LDA	QFLG
	ORA	A
	JZ	SWNAK
	CALL	ILPRT
	DB	'Awaiting name NAK',CR,LF,0
SWNAK:
	MVI	E,80
	CALL	WAITNLP
	MVI	A,ACK	;GOT NAK, SEND ACK
	CALL	SEND
	LXI	H,FILECT
	DCR	M
	JM	NOMRNM
	LHLD	NBSAVE	;GET FILE NAME..
	LXI	D,FCB	;..IN FCB
	MVI	B,12
	CALL	MOVE
	SHLD	NBSAVE
	CALL	SENDNM	;SEND IT
	ORA	A	;CLEAR CARRY
	RET
;
NOMRNM:	MVI A,EOT
	CALL SEND
	STC
	RET
;
SENDNM:	PUSH	H
SENDNM1:
	MVI	D,11	;COUNT CHARS IN NAME
	MVI	C,0	;INIT CHECKSUM
	MOV	A,C
	STA	FTYCNT	;INITIATE FILE TYPE COUNT
	LXI	H,FCB+1	;ADDRESS NAME
NAMLPS:	MOV	A,M	;SEND NAME
	ANI	7FH	;STRIP HIGH ORDER BIT SO CP/M 2..
	CALL	SEND	;..WON'T SEND R/O FILE DESIGNATION.
	LDA	QFLG	;SHOW NAME IF..
	ORA	A	;..QFLG NOT SET.
	MOV	A,M
	JZ	ACKLP
	CALL	FTYTST	;TYPE CHARACTER ETC.
ACKLP:	PUSH	B	;SAVE CKSUM
	MVI	B,1	;WAIT FOR RECEIVER..
	CALL	RECV	;..TO ACKNOWLEDGE..
	POP	B	;..GETTING LETTER.
	JC	SCKSER
	CPI	ACK
	JNZ	ACKLP
	INX	H	;NEXT CHAR
	DCR	D
	JNZ	NAMLPS
	MVI	A,EOFCHAR ;TELL RECEIVER END OF NAME
	CALL	SEND
	LDA	QFLG
	ORA	A
	CNZ	CRLF
	MOV	D,C	;SAVE CHECKSUM
	MVI	B,1
	CALL	RECV	;GET CHECKSUM..
	CMP	D	;..FROM RECEIVER.
	JZ	NAMEOK
SCKSER:	MVI	A,BDNMCH ;BAD NAME-TELL RECEIVER
	CALL	SEND
	LDA	QFLG
	ORA	A
	JZ	SKCSER1
	CALL	ILPRT
	DB	'Checksum error',CR,LF,0
SKCSER1:
	MVI	E,80	;DO HANDSHAKING OVER
	CALL	WAITNLP	;DON'T PRINT "AWAITING NAK" MSG
	MVI	A,ACK
	CALL	SEND
	JMP	SENDNM1
;
NAMEOK:
	MVI	A,OKNMCH ;GOOD NAME-TELL RECEIVER
	CALL	SEND
	POP	H
	RET	
;
GETFN:	LXI	H,FCB
	CALL	INITFCBS+2 ;DOES NOT INITIALIZE DRIVE
	LDA	QFLG
	ORA	A
	JZ	GNAMELP
	CALL	ILPRT
	DB	'Awaiting file name',CR,LF,0
GNAMELP:
	CALL	HSNAK
	JC	GNAMELP
	CALL	GETNM	;GET THE NAME
	CPI	EOT	;IF EOT, THEN NO MORE FILES
	JZ	NOMRNMG
	ORA	A	;CLEAR CARRY
	RET
;
NOMRNMG:
	STC
	RET
;
GETNM:
	PUSH	H
GETNM1:
	MVI	C,0	;INIT CHECKSUM
	MOV	A,C
	STA	FTYCNT	;INITIATE COUNT FOR FILE TYPE
	LXI	H,FCB+1
NAMELPG:
	MVI	B,5
	CALL	RECV	;GET CHAR
	JNC	GETNM3
	LDA	QFLG
	ORA	A
	JZ	GETNM2
	CALL	ILPRT
	DB	'Time out receiving filename',CR,LF,0
GETNM2:	JMP	GCKSER
;
GETNM3:
	CPI	EOT	;IF EOT, THEN NO MORE FILES
	JZ	GNRET
	CPI	EOFCHAR	;GOT END OF NAME
	JZ	ENDNAME
	MOV	M,A	;PUT NAME IN FCB
	LDA	QFLG	;CAN TYPE IT IF NO QFLG
	ORA	A
	JZ	SKPTYP
	CALL	FTYTST
SKPTYP:	PUSH	B	;SAVE CKSUM
	MVI	A,ACK	;ACK GETTING LETTER
	CALL	SEND
	POP	B
	INX	H	;GET NEXT CHAR
	MOV	A,L	;DON'T LET NOISE...
	CPI	7FH	;..CAUSE OVERFLOW..
	JZ	GCKSER	;..INTO PROGRAM AREA.
	JMP	NAMELPG
;
FTYTST:
	LDA	FTYCNT
	INR	A
	STA	FTYCNT
	CPI	9	;ARE WE AT THE FILE TYPE?
	JZ	SPCTST	;GO IF SO
ENDSPT:	MOV	A,M
	CPI	' '	;TEST FOR SPACE
	CNZ	TYPE	;TYPE IF NOT
	RET
;
SPCTST:	MOV	A,M
	CPI	' '	;TEST FOR SPACE IN FIRST FILE TYPE BYTE
	RZ		;DON'T OUTPUT PERIOD IF SPACE
	MVI	A,'.'	
	CALL	TYPE
	JMP	ENDSPT	;OUTPUT FIRST FILE TYPE BYTE
;
ENDNAME:
	LDA	QFLG
	ORA	A
	CNZ	CRLF
	MOV	A,C	;SEND CHECKSUM
	CALL	SEND
	MVI	B,1
	CALL	RECV	;CHECKSUM GOOD?
	CPI	OKNMCH	;YES IF OKNMCH SENT..
	JZ	GNRET	;..ELSE DO OVER.
GCKSER:	LXI	H,FCB	;CLEAR FCB (EXCEPT DRIVE)..
	CALL	INITFCBS+2 ;..SINCE IT MIGHT BE DAMAGED..
	LDA	QFLG	;..BY TOO MANY CHARS.
	ORA	A
	JZ	GCKSER1
	CALL	ILPRT
	DB	'Checksum error',CR,LF,0
GCKSER1:
	CALL	HSNAK	;DO HANDSHAKING OVER
	JC	GCKSER1
	JMP	GETNM1
;
GNRET:	POP	H
	RET
;
HSNAK:	MVI	A,NAK	;SEND NAK UNTIL..
	CALL	SEND	;..RECEIVING ACK.
	CALL	CKABORT	;DON'T GET HUNG UP HERE
	MVI	B,2	;WAIT 2 SECONDS..
	CALL	RECV	;..IN RECEIVE.
	CPI	ACK	;IF ACK,RETURN WITH..
	RZ		;..CARRY CLEAR.
	STC
	RET
;
TNMBUF:	MVI	A,FALSE	;CALL FROM SENDFIL ONLY ONCE.
	STA	FSTFLG
	STA	FILECT
	CALL	SCAN
	LXI	H,NAMEBUF
	SHLD	NBSAVE	;SAVE ADDR OF 1ST NAME
TNLP1:	CALL	TRTOBUF
	LXI	H,FCB
	LXI	D,FCBBUF
	CALL	CPMLINE	;PARSE NAME TO CP/M FORMAT
TNLP2:	CALL	MFNAME	;SEARCH FOR NAMES (* FORMAT)
	JC	NEXTNM
	LDA	FCB+10	;IF CP/M 2 $SYS FILE..
	ANI	80H	;..DON'T SEND
	JNZ	TNLP2
	LHLD	NBSAVE	;GET NAME
	LXI	D,FCB	;MOVE IT TO FCB
	XCHG
	MVI	B,12
	CALL	MOVE
	XCHG
	SHLD	NBSAVE	;ADDR OF NEXT NAME
	LXI	H,FILECT	;COUNT FILES FOUND
	INR	M
	JMP	TNLP2
;
NEXTNM:	LXI	H,NAMECT ;COUNT NAMES FOUND
	DCR	M
	JNZ	TNLP1
	LXI	H,NAMEBUF  ;SAVE START OF BUFFER
	SHLD	NBSAVE
	LDA	FILECT
	CPI	65	;NO MORE THAN 64 TRANSFERS
	RC
	MVI	A,64	;ONLY X'FER FIRST 64
	STA	FILECT
	RET
;
;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE)
;AFTER LAST NAME
;
SCAN:	PUSH	H
	LXI	H,NAMECT
	MVI	M,0
	LXI	H,CMDBUF+1  ;FIND END OF CMD LINE..
	MOV	C,M         ;..AND PUT SPACE THERE.
	MVI	B,0
	LXI	H,CMDBUF+2
	DAD	B
	MVI	M,20H
	LXI	H,CMDBUF+1
	MOV	B,M
	INR	B
	INR	B
SCANLP1:
	INX	H
	DCR	B
	JZ	DNSCAN
	MOV	A,M
	CPI	20H
	JNZ	SCANLP1
SCANLP2:
	INX	H	;EAT EXTRA SPACES
	DCR	B
	JZ	DNSCAN
	MOV	A,M
	CPI	20H
	JZ	SCANLP2
	SHLD	BGNMS	;SAVE START OF NAMES IN CMDBUF
	INR	B
	DCX	H
SCANLP3:
	INX	H
	DCR	B
	JZ	DNSCAN
	MOV	A,M
	CPI	20H
	JNZ	SCANLP3
	LDA	NAMECT	;COUNTS NAMES
	INR	A
	STA	NAMECT
SCANLP4:
	INX	H	;EAT SPACES
	DCR	B
	JZ	DNSCAN
	MOV	A,M
	CPI	20H
	JZ	SCANLP4
	JMP	SCANLP3
;
DNSCAN:
	MVI	M,20H	;SPACE AFTER LAST CHAR
	POP	H
	RET
;
;PLACES NEXT NAME IN BUFFER SO 'CPMLINE' MAY PARSE IT
;
TRTOBUF:
	LHLD	BGNMS
	MVI	B,0
	LXI	D,FCBBUF+2
TBLP:
	MOV	A,M
	CPI	20H
	JZ	TRBFEND
	STAX	D
	INX	H
	INX	D
	INR	B	;COUNT CHARS IN NAME
	JMP	TBLP
;
TRBFEND:
	INX	H
	MOV	A,M	;EAT EXTRA SPACES
	CPI	20H
	JZ	TRBFEND
	SHLD	BGNMS
	LXI	H,FCBBUF+1 ;PUT # CHARS BEFORE NAME
	MOV	M,B
	RET
;
;IN CP/M V.2, IF FILE IS R/O OR SYS, IT IS CHANGED TO 'BAK'.
;
CKCPM2:
	MVI	C,12
	CALL	BDOS
	ORA	A	;RETURN 0 MEANS CP/M 1
	RZ
	MVI	C,STDMA
	LXI	D,80H
	CALL	BDOS
	MVI	C,SRCHF	;SEARCH FOR FILE
	LXI	D,FCB
	CALL	BDOS
	CPI	0FFH
	RZ
	ADD	A
	ADD	A	;MULT A-REG BY..
	ADD	A
	ADD	A	;..32 TO FIND..
	ADD	A	;..NAME IN DMA.
	LXI	H,80H
	ADD	L
	MOV	L,A	;HL POINTS TO DIR NAME
	LXI	D,9
	DAD	D	;POINT TO R/O ATTRIB BYTE
	MOV	A,M
	ANI	80H	;TEST MSB
	JNZ	MKCHG	;IF SET, MAKE CHANGE
	INX	H	;CHECK SYSTEM ATTRIB BYTE
	MOV	A,M
	ANI	80H
	RZ		;NOT $SYS OR $R/O
	DCX	H
MKCHG:	LXI	D,-8
	DAD	D	;POINT HL TO FILENAME + 1
	LXI	D,FCB+1	;MOVE DIR NAME TO FCB..
	MVI	B,11	;..WITHOUT CHANGING DRIVE.
	CALL	MOVE
	LXI	H,FCB+9	;R/O ATTRIB
	MOV	A,M
	ANI	7FH	;STRIP R/O ATTRIB
	MOV	M,A
	INX	H	;SYS ATTRIB
	MOV	A,M
	ANI	7FH
	MOV	M,A
	LXI	D,FCB
	MVI	C,30	;SET NEW ATTRIBS IN DIR
	CALL	BDOS
;
;MAY BE CALLED BY CKBAKUP BELOW. ITS RETURN DONE HERE
;
PLANCHG:
	LXI	H,FCB	;CHANGE NAME TO TYPE "BAK"
	LXI	D,6CH
	MVI	B,9	;MOVE DRIVE AND NAME (NOT TYPE)
	CALL	MOVE
	LXI	H,75H	;START OF TYPE IN FCB2
	MVI	M,'B'
	INX	H
	MVI	M,'A'
	INX	H
	MVI	M,'K'
	LXI	D,6CH
	MVI	C,ERASE	;ERASE ANY PREV BACKUPS
	CALL	BDOS
	LXI	H,6CH	;FCB2 DR FIELD SHOULD..
	MVI	M,0	;..0 FOR RENAME.
	LXI	D,FCB
	MVI	C,23	;RENAME
	JMP	BDOS
;
CKBAKUP:
	LDA	BAKUPBYTE
	ORA	A
	RZ
	MVI	C,SRCHF
	LXI	D,FCB
	CALL	BDOS
	INR	A
	RZ	;FILE NOT FOUND
	JMP	PLANCHG	;IN "CKCPM2" - RET DONE THERE
;
;MULTI-FILE ACCESS SUBROUTINE FROM CP/M USER'S GROUP
;FIXED BY MARK ZEIGER 8/17/80
;CARRY IS SET IF NO MORE NAMES CAN BE FOUND
;
MFNAME:
	MFACCESS	;A MACRO IN MACROS.LIB
;
RCVSECT:
	MVI	A,1
	STA	ERRCT
RCVRPT:
	XRA	A	;ZERO ACCUM
	STA	ERRCDE	;CLEAR RECEIVE ERROR CODE
	LDA	QFLG
	ORA	A
	JZ	RCVSQ
	CALL	ILPRT
	DB	CR,'Awaiting # ',0
	PUSH	H	;SAVE IT
	LHLD	SECTNO	;GET SECTOR NUMBER
	INX	H	;BUMP IT
	CALL	DECOUT	;PRINT SECTOR NUMBER IN DECIMAL
	CALL	ILPRT
	DB	' (', 0
	CALL	DHXOUT	;16 BIT HEX CONVERSION & OUTPUT
	CALL	ILPRT
	DB	'H)',0
	MOV	A,L	;ONLY LOW BYTE USED BY PROGRAM
	POP	H	;RESTORE IT
;
RCVSQ:			;WAIT FOR SOH OR EOT
	MVI	B,10	;10 SECONDS
	CALL	RECV
	JC	RCVSTOT
	CALL	RCVERR	;CHECK FOR ERRORS
	JC	RCVDERR	;JUMP IF THERE WAS AN ERROR
	CPI	SOH
	JZ	RCVSOH
	ORA	A
	JZ	RCVSQ
	CPI	EOT
	STC
	RZ
	MOV	B,A
	LDA	QFLG
	ORA	A
	JZ	RCVSERR
RCVSEH:
	MOV	A,B
	CALL	CRLF
	CALL	HEXO
	CALL	ILPRT
	DB	'H recv''d, not SOH',CR,LF,0
RCVSERR:
	MVI	B,1	;WAIT FOR 1 SEC..
	CALL	RECV	;..WITH NO CHARS
	JNC	RCVSERR ;LOOP UNTIL SENDER DONE
	LDA	CKSUMFLG	;GET CHECKSUM FLAG
	ORA	A	;CRC IN EFFECT?
	MVI	A,NAK	;PUT NAK IN ACCUM
	JNZ	RCVSER2	;NO, SEND THE NAK
	LDA	FIRSTME ;GET FIRST TIME SWITCH
	ORA	A	;HAS FIRST SOH BEEN RECEIVED?
	MVI	A,NAK	;PUT NAK IN ACCUM
	JZ	RCVSER2	;YES, THEN SEND NAK
	MVI	A,CRC	;TELL SENDER CRC IS IN EFFECT
RCVSER2:
	CALL	SEND	;..THE NAK or CRC request
	LDA	ERRCT	;ABORT IF..
	INR	A	;..WE HAVE REACHED..
	STA	ERRCT	;..THE ERROR..
	CPI	ERRLIM	;..LIMIT?
	JC	RCVRPT	;..NO, TRY AGAIN
	LDA	QFLG
	ORA	A
	JZ	RCVSABT
RCVCKQ:	CALL	CKQUIT
	JZ	RCVSECT
RCVSABT:
	CALL	CLOSFIL
	CALL	ERXIT
	DB	CR,LF,'++ Unable to receive block - Aborting ++',CR,LF,'$'
;
RCVSTOT:
	LDA	QFLG
	ORA	A
	JZ	RCVSCRC
RCVSPT:	CALL	ILPRT
	DB	CR,LF,'++ Timeout ++ ',0
RCVPRN:	LDA	ERRCT
	PUSH	H
	MVI	H,0
	MOV	L,A
	CALL	DECOUT
	POP	H
	CALL	CRLF
RCVSCRC:
	CALL	RCVSCRC2
	JMP	RCVSERR
;
;ROUTINE WILL SWITCH FROM CRC TO CHECKSUM IF ERCNT REACHES ERRCRC
;AND FIRSTME IS TRUE
;
RCVSCRC2:
	LDA	ERRCT
	CPI	ERRCRC
	RNZ
	LDA	FIRSTME
	ORA	A
	RZ
	LDA	CKSUMFLG
	ORA	A
	RNZ
	CMA
	STA	CKSUMFLG
	STA	CKSUMDFLT
	LDA	QFLG
	ORA	A
	RZ
	CALL	ILPRT
	DB	'++ Switching to Checksum mode ++',CR,LF
	DB	'++ Sender may not be CRC capable ++',CR,LF,BELL,0
	RET
;
;---->	RCVERR:
;
;	Checks for framing, overrun, and parity errors. Parity errors
;	cannot be detected unless the parity option has been selected.
;	1.Error code (ERRCDE) was set in RECV routine.
;	2.ERRCDE=0 for no errors, ERRCDE<>0 for errors.
;	3.If there is an error, routine returns with carry flag set.
;
RCVERR:	PUSH	PSW	;SAVE CHAR TRANSMITTED
	LDA	ERRCDE	;GET RECEIVE ERROR CODE
	ANA	A	;IS IT ZERO?
	JZ	RCVERR2	;YES, NO RECEIVE ERROR
	POP	PSW	;RESTORE CHAR TRANSMITTED
	STC		;SET CARRY ON TO INDICATE AN ERROR
	RET
RCVERR2:
	POP	PSW	;RESTORE CHAR TRANSMITTED
	RET
;
;---->	RCVDERR: Checks for a receive error and displays appropriate
;                error message.  Then goes to RCVSERR to purge the line
;                and send a NAK.
;
RCVDERR:
	LDA	QFLG	;QUIET...
	ORA	A	;...MODE?
	JZ	RCVSERR	;YES, NO MSG
RCVDERRP:
	CALL ILPRT
	DB	CR,LF,0
	LDA	ERRCDE	;GET RECEIVE ERR CODE
	ANI	FRMER	;WAS THERE A FRAMING ERROR?
	JZ	RCVDERR2 ;NO, GO CHECK FOR OVERRUN
	CALL	ILPRT
	DB	'++ Framing error ++ ',0
	CALL	RCVDERR5 ;PRINT # OF ERROR

RCVDERR2:
	LDA	ERRCDE	;GET RECEIVE ERR CODE
	ANI	ORUNER	;WAS THERE AN OVERRUN
	JZ	RCVDERR3 ;NO, GO CHECK FOR PARITY ERROR
	CALL	ILPRT
	DB	'++ Overrun error ++ ',0
	CALL	RCVDERR5
RCVDERR3:
	LDA	ERRCDE	;GET RECEIVE ERR CODE
	ANI	PARER	;WAS THERE A PARITY ERROR?
	JZ	RCVDERR4 ;NO, GO PURGE LINE
	CALL	ILPRT
	DB	'++ Parity error ++ ',0
	CALL	RCVDERR5
RCVDERR4:
	JMP	RCVSERR	;GO PURGE LINE, SEND NAK
;
;Display the number of the error, do a carriage return and line feed.
;
RCVDERR5:
	LDA	ERRCT	;GET ERROR NUMBER
	PUSH	H
	MVI	H,0
	MOV	L,A
	CALL	DECOUT	;DISPLAY IT
	POP	H
	JMP	CRLF	;DO CR, LF
;
;Got SOH - get block #, block # complemented
;
RCVSOH:	XRA	A	;ZERO ACCUM
	STA	FIRSTME ;INDICATE FIRST SOH RECV'D
	MVI	B,1	;TIMEOUT = 1 SEC
	CALL	RECV	;GET SECTOR
	JC	RCVSTOT ;GOT TIMEOUT
	CALL	RCVERR	;CHECK FOR RECEIVE ERROR
	JC	RCVDERR
	MOV	D,A
	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	CALL	RCVERR	;CHECK FOR RECEIVE ERROR
	JC	RCVDERR
	CMA
	CMP	D
	JZ	RCVDATA
	LDA	QFLG
	ORA	A
	JZ	RCVSERR
RCVBSE:
	CALL	ILPRT
	DB	CR,LF,'++  Bad sector # in Hdr',CR,LF,0
	JMP	RCVSERR
;
RCVDATA:
	MOV	A,D
	STA	RCVSNO
	MVI	A,1
	STA	DATAFLG
	MVI	C,0
	CALL	CLRCRC	;CLEAR CRC COUNTER
	LXI	H,80H
RCVCHR:
	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	CALL	RCVERR	;CHECK FOR RECEIVE ERROR
	JC	RCVDERR
	MOV	M,A
	INR	L
	JNZ	RCVCHR
	LDA	CKSUMFLG
	ORA	A
	JZ	RCVCRC
	MOV	D,C
	XRA	A
	STA	DATAFLG
	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	CALL	RCVERR	;CHECK FOR RECEIVE ERROR
	JC	RCVDERR
	CMP	D
	JNZ	RCVCERR
CHKSNUM:
	LDA	RCVSNO
	MOV	B,A
	LDA	SECTNO
	CMP	B
	JZ	RECVACK
	INR	A
	CMP	B
	JNZ	ABORT
	RET
;
RCVCRC:
	MVI	E,2	;NUMBER OF CRC BYTES
RCVCRC2:
	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	CALL	RCVERR
	JC	RCVDERR
	DCR	E
	JNZ	RCVCRC2
	CALL	CHKCRC
	ORA	A
	JZ	CHKSNUM
	LDA	QFLG
	ORA	A
	JZ	RCVSERR
RCVCRER:
	CALL	ILPRT
	DB	CR,LF,'++ CRC error ++',0
	JMP	RCVPRN
;
RCVCERR:
	LDA	QFLG
	ORA	A
	JZ	RCVSERR
RCVCPR:
	CALL	ILPRT
	DB	CR,LF,'++ Checksum error ++ ',0
	JMP	RCVPRN
;
RECVACK:
	CALL	SENDACK
	JMP	RCVSECT
;
SENDACK:
	MVI	A,ACK
	JMP	SEND
;
SENDHDR:
	LDA	QFLG
	ORA	A
	JZ	SENDHNM
	CALL	ILPRT
	DB	CR,'Sending # ',0
	PUSH	H
	LHLD	SECTNO	;GET SECTOR NUMBER
	CALL	DECOUT	;PRINT IT IN DECIMAL
	CALL	ILPRT
	DB	' (',0
	CALL	DHXOUT	;16 BIT HEX CONVERSION & OUTPUT
	CALL	ILPRT
	DB	'H)',0
	POP	H
SENDHNM:
	MVI	A,SOH
	CALL	SEND
	LDA	SECTNO
	CALL	SEND
	LDA	SECTNO
	CMA
	JMP	SEND
;
SENDSEC:
	MVI	A,1
	STA	DATAFLG
	MVI	C,0
	CALL	CLRCRC
	LXI	H,80H
SENDC:
	MOV	A,M
	CALL	SEND
	INR	L
	JNZ	SENDC
	XRA	A
	STA	DATAFLG
	RET
;
SENDCKS:
	MOV	A,C
	JMP	SEND
;
SENDCRC:
	CALL	FINCRC
	MOV	A,D
	CALL	SEND
	MOV	A,E
	CALL	SEND
	XRA	A
	RET
;
GETACK:	MVI	B,10		;10 SECONDS
	CALL	RECVDG
	JC	GETATOT
	CPI	ACK
	RZ
	MOV	B,A
	LDA	QFLG
	ORA	A
	JZ	ACKERR
	MOV	A,B
	CALL	CRLF
	CALL	HEXO
	CALL	ILPRT
	DB	'H Recv''d, not ACK',CR,LF,0
ACKERR:	LDA	ERRCT
	INR	A
	STA	ERRCT
	DCR	A
	CPI	ERRLIM
	RC
	LDA	QFLG
	ORA	A
	JZ	CSABORT
GACKV:	CALL	CKQUIT
	STC
	RZ
CSABORT:
	CALL	ERXIT
	DB	CR,LF,'Can''t send sector -- Aborting',CR,LF,'$'
GETATOT:
	LDA	QFLG
	ORA	A
	JZ	ACKERR
	CALL	ILPRT
	DB	CR,LF,'Timeout on ACK',CR,LF,0
	JMP ACKERR
;
CKABORT:
	LDA	QFLG
	ORA	A
	RZ	
CKABGO:
	CALL	STAT
	RZ
	CALL	KEYIN
	CPI	CAN
	RNZ
ABORT:
	LXI	SP,STACK
ABORTL:
	MVI	B,1
	CALL	RECV
	JNC	ABORTL
	MVI	A,CAN
	CALL	SEND
ABORTW:
	MVI	B,1
	CALL	RECV
	JNC	ABORTW
	MVI	A,' '
	CALL	SEND
	CALL	ILPRT
	DB	CR,LF,'Routine cancelled',CR,LF,BELL,0
	MVI	A,'B'     ;TURN MULTI-FILE MODE..
	STA	BATCHFLG  ;..OFF SO ROUTINE ENDS.
	JMP	DONETCE
;
INCRSNO:
	PUSH	H
	LHLD	SECTNO	;GET SECTOR NUMBER
	INX	H	;BUMP IT
	SHLD	SECTNO	;STORE IT
	MOV	A,L
	POP	H
	RET
;
ERASFIL:
	LDA	BATCHFLG ;DON'T ASK FOR ERASE..
	ORA	A	;..IN MULTI-FILE MODE,..
	JZ	NOASK	;..JUST DO IT.
	LXI	D,FCB
	MVI	C,SRCHF
	CALL	BDOS
	INR	A
	RZ
	CALL	ILPRT
	DB	'File exists -- Type ''Y'' to erase: ',BELL,0
	CALL	KEYIN
	PUSH	PSW
	CALL	TYPE
	POP	PSW
	CALL	UCASE
	CPI	'Y'
	JNZ	MENU
	CALL	CRLF
NOASK:	LXI	D,FCB
	MVI	C,ERASE
	JMP	BDOS
;
BLKFILE:
	CALL	ILPRT	;ROUTINE IF NO FILE IS NAMED FOR "SEND" OR "RECEIVE"
	DB	CR,LF,'No file specified',CR,LF,BELL,0
	JMP	MENU

MAKEFIL:
	LXI	D,FCB
	MVI	C,MAKE
	CALL	BDOS
	INR	A
	RNZ
	CALL	ERXIT
	DB	'Error - Can''t make file',CR,LF
	DB	'Directory is likely full',CR,LF,'$'
;
	IF	CPM2X
;
CNREC:	MVI	C,FILSIZ ;COMPUTE FILE SIZE FUNCTION IN CP/M 2.x
	LXI	D,FCB	;POINT TO FILE CONTROL BLOCK
	CALL	BDOS
	LHLD	FCB+33	;GET RECORD COUNT
	SHLD	RCNT	;STORE IT
	LXI	H,0	;ZERO HL
	SHLD	FCB+33	;RESET RANDOM RECORD IN FCB
	RET
;
	ENDIF	;CPM2X
;
	IF	NOT CPM2X
;
CNREC:	MVI	A,'?'	;MATCH ALL EXTENTS
	STA	FCBEXT
	MVI	A,0FFH
	STA	MAXEXT	;INIT MAX EXT NO.
	MVI	C,SRCHF	;GET 'SEARCH FIRST' FNC
	LXI	D,FCB
	CALL	BDOS	;READ FIRST
	INR	A	;WERE THERE ANY?
	JNZ	SOME	;GOT SOME
	CALL	ERXIT
	DB	'++ File not found ++$'
;
;READ MORE DIRECTORY ENTRIES
;
MOREDIR:
	MVI	C,SRCHN	;SEARCH NEXT
	LXI	D,FCB
	CALL	BDOS	;READ DIR ENTRY
	INR	A	;CHECK FOR END (0FFH)
	JNZ	SOME	;NOT END OF DIR...PROCESS EXTENT
	LDA	MAXEXT	;HIT END...GET HIGHEST EXTENT NO. SEEN
	MOV	L,A	;WHICH GIVES EXTENT COUNT -1
	MVI	H,0
	MOV	D,H
	LDA	RCNT	;GET RECORD COUNT OF MAX EXTENT SEEN
	MOV	E,A	;SAVE IT IN DE
	DAD	H
	DAD	H	;MULTIPLY # OF EXTENTS -1
	DAD	H	; TIMES 128
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	D	;ADD IN SIZE OF LAST EXTENT
	SHLD	RCNT	;SAVE TOTAL RECORD COUNT
	RET		;AND EXIT
;
;POINT TO DIRECTORY ENTRY
;
SOME:	DCR	A	;UNDO PREV 'INR A'
	ANI	3	;MAKE MODULUS 4
	ADD	A	;MULTIPLY...
	ADD	A	;..BY 32 BECAUSE
	ADD	A	;..EACH DIRECTORY
	ADD	A	;..ENTRY IS 32
	ADD	A	;..BYTES LONG
	LXI	H,80H	POINT TO BUFFER
	ADD	L	;POINT TO ENTRY
	ADI	15	;OFFSET TO RECORD COUNT
	MOV	L,A	;HL NOW POINTS TO REC COUNT
	MOV	B,M	;GET RECORD COUNT
	DCX	H
	DCX	H	;BACK DOWN TO EXTENT NUMBER
	DCX	H
	LDA	MAXEXT	;COMPARE WITH CURRENT MAX.
	ORA	A	;IF NO MAX YET
	JM	BIGGER	;THEN SAVE RECORD COUNT ANYWAY
	CMP	M
	JNC	MOREDIR
BIGGER:	MOV	A,B	;SAVE NEW RECORD COUNT
	STA	RCNT
	MOV	A,M	;SAVE NEW MAX. EXTENT NO.
	STA	MAXEXT
	JMP	MOREDIR	;GO FIND MORE EXTENTS
;
	ENDIF	;NOT CPM2X
;
OPENFIL:
	XRA	A
	STA	FCBEXT
	LXI	D,FCB
	MVI	C,OPEN
	CALL	BDOS
	INR	A
	JNZ	OPENOK
	CALL	ERXIT
	DB	'Can''t open file$'
OPENOK:
	LDA	BATCHFLG
	ORA	A		;ONLY IF SINGLE FILE...
	RZ
	JMP	SENDTIM		;A LIB MACRO SHOWS TIME TO SEND	
;
CLOSFIL:
	LXI	D,FCB
	MVI	C,CLOSE
	CALL	BDOS
	INR	A
	RNZ
	CALL	ERXIT
	DB	'Can''t close file$'
RDSECT:
	LDA	SECINBF
	DCR	A
	STA	SECINBF
	JM	RDBLOCK
	LHLD	SECPTR
	LXI	D,80H
	CALL	MOVE128
	SHLD	SECPTR
	RET
;
RDBLOCK:
	LDA	EOFLG
	CPI	1
	STC
	RZ
	MVI	C,0
	LXI	D,DBUF
RDSECLP:
	PUSH	B
	PUSH	D
	MVI	C,STDMA
	CALL	BDOS
	LXI	D,FCB
	MVI	C,READ
	CALL	BDOS
	POP	D
	POP	B
	ORA	A
	JZ	RDSECOK
	DCR	A
	JZ	REOF
	CALL	ERXIT
	DB	'++ File read error ++$'
RDSECOK:
	LXI	H,80H
	DAD	D
	XCHG
	INR	C
	MOV	A,C
	CPI	DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS
	JZ	RDBFULL
	JMP	RDSECLP
;
REOF:	MVI	A,1
	STA	EOFLG
	MOV	A,C
RDBFULL:
	STA	SECINBF
	LXI	H,DBUF
	SHLD	SECPTR
	LXI	D,80H
	MVI	C,STDMA
	CALL	BDOS
	JMP	RDSECT
;
WRSECT:
	LHLD	SECPTR
	XCHG
	LXI	H,80H
	CALL	MOVE128
	XCHG
	SHLD	SECPTR
	LDA	SECINBF
	INR	A
	STA	SECINBF
	CPI	DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS
	RNZ
WRBLOCK:
	LDA	SECINBF
	ORA	A
	RZ
	MOV	C,A
	LXI	D,DBUF
DKWRLP:
	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,STDMA
	CALL	BDOS
	LXI	D,FCB
	MVI	C,WRITE
	CALL	BDOS
	POP	B
	POP	D
	POP	H
	ORA	A
	JNZ	WRERR
	LXI	H,80H
	DAD	D
	XCHG
	DCR	C
	JNZ	DKWRLP
	XRA	A
	STA	SECINBF
	LXI	H,DBUF
	SHLD	SECPTR
	RET
;
WRERR:	MVI	C,CAN
	CALL	SEND
	CALL	ERXIT
	DB	CR,LF,'Error writing file',CR,LF,'$'
;
;---->	RECV: Receive a character
;
;Timeout time is in B, in seconds. Entry via 'RECVDG' deletes garbage
;characters on the line. For example, having just sent a sector, calling
;RECVDG will delete any line noise induced characters LONG before the
;ACK/NAK would be received.
;
RECVDG:	EQU $
	CALL	IN$MODDATP
	CALL	IN$MODDATP
RECV:	PUSH	D
MSEC:	PUSH	H
	LXI	H,7500
	CALL	FIXCNT
	PUSH	H
	POP	D
	POP	H
	CALL	CKABORT
MWTI:
	CALL	RCVREADY
	JZ	MCHAR
	DCR	E
	JNZ	MWTI
	DCR	D
	JNZ	MWTI
	DCR	B
	JNZ	MSEC
	POP	D
	STC
	RET
;
MCHAR:
	LDA	PMMIBYTE    ;IS THE MODEM A PMMI?
	ORA	A           ;SET FLAGS
	JZ	MCHAR1      ;YES, JUMP
	CALL	IN$MODCTLP  ;GET ERROR-STATUS BYTE
	ANI	ERRCDMSK    ;MASK OUT ALL EXCEPT ERROR BITS (3-5)
	STA	ERRCDE      ;SAVE THE ERROR CODE
MCHAR1:
	CALL	IN$MODDATP
	POP	D
	PUSH	PSW
	CALL	UPDCRC      ;CALCULATE CRC
	ADD	C	
	MOV	C,A
	LDA	RSEEFLG
	ORA	A
	JZ	MONIN
	LDA	VSEEFLG
	ORA	A
	JNZ	NOMONIN
	LDA	DATAFLG
	ORA	A
	JZ	NOMONIN
MONIN:	POP	PSW
	PUSH	PSW
	CALL	SHOW
NOMONIN:
	POP	PSW
	ORA	A
	RET
;
SEND:	PUSH	PSW
	LDA	SSEEFLG
	ORA	A
	JZ	MONOUT
	LDA	VSEEFLG
	ORA	A
	JNZ	NOMONOT
	LDA	DATAFLG
	ORA	A
	JZ	NOMONOT
MONOUT:	POP	PSW
	PUSH	PSW
	CALL	SHOW
NOMONOT:
	POP	PSW
	PUSH	PSW
	CALL	UPDCRC	;CALCULATE CRC
	ADD	C
	MOV	C,A
SENDW:	CALL	SENDREADY
	JNZ	SENDW
	POP	PSW
	JMP	OUT$MODDATP
;
WAITNAK:
	LDA	QFLG
	ORA	A
	JZ	WAITNLP
	CALL	ILPRT
	DB	'Awaiting initial NAK',CR,LF,0
WAITNLP:
	CALL	CKABORT
	MVI	B,1
	CALL	RECV
	CPI	NAK
	RZ
	CPI	CRC	;CRC REQUEST?
	JZ	WAITCRC	;YES, GO SET CRC FLAG
	CPI	CAN	;CANCEL?
	JZ	ABORT
	DCR	E
	JZ	ABORT
	JMP	WAITNLP
;
WAITCRC:
	LDA	QFLG
	ORA	A
	JZ	WAITCRC1
	CALL	ILPRT
	DB	'CRC request received',CR,LF,0
WAITCRC1:
	XRA	A
	STA	CKSUMFLG
	RET
;
;--->PARITY: Routine to setup PMMI for odd/even parity.
;
PARITY:
	LDA	PMMIBYTE ;IS MODEM A PMMI?
	ORA	A	;SET FLAGS
	RZ		;NO, RETURN
	LDA	OPARITY	;GET ODD PARITY REQUEST BYTE
	ORA	A	;SET FLAGS
	JNZ	EVENPAR	;IF NOT ODD SEE IF IT IS EVEN
	LDA	UARTCTLB ;GET UART/MODEM CONTROL BYTE
	ANI	ODPARMSK
	JMP	PARITY1
;
EVENPAR:
	LDA	EPARITY   ;GET EVEN PARITY REQUEST BYTE
	ORA	A         ;SET FLAGS
	RNZ               ;IF EVEN PARITY NOT SPECIFIED RETURN
	LDA	UARTCTLB  ;GET UART/MODEM CONTROL BYTE
	ANI	ODPARMSK  ;SET FOR PARITY
	ORI	EVPARMSK  ;NOW SET FOR EVEN PARITY
PARITY1:
	JMP	OUT$MODCTLP  ;SEND TO PMMI -
			     ;WHEN OUT$MODCTLP DOES RET IT
			     ;WILL GO BACK TO CALLING ROUTINE
;
NOPARIT:
	LDA	PMMIBYTE
	ORA	A
	RZ
	LDA	UARTCTLB     ;GET UART/MODEM CONTROL BYTE
	ORI	NOPARMSK     ;RESET PARITY BIT ON PMMI
	JMP	OUT$MODCTLP
;
INITADR:
	LHLD	1
	LXI	D,3
	DAD	D
	SHLD	VSTAT+1
	DAD	D
	SHLD	VKEYIN+1
	DAD	D
	SHLD	VTYPE+1
	DAD	D
	SHLD	VLIST+1
	LXI	D,30
	DAD	D
	SHLD	VLSTAT+1
	LDA	PMMIBYTE
	ORA	A
	RZ			;RETURN DONE FROM THIS ROUTINE..
	LDA	IN$MODCTLP+1	;..IF NOT PMMI
	STA	OUT$MODCTLP+1
	INR	A
	STA	OUT$MODDATP+1
	STA	IN$MODDATP+1
	INR	A
	STA	IN$BAUDRP+1
	STA	OUT$BAUDRP+1
	INR	A
	STA	OUT$MODCTL2+1
	RET
;
; CHECK OPTIONS, PUT 0 IN APPROPRIATE PLACES IN OPTION TABLE
; IF OPTION SELECTED
;
PROCOPT:
	LXI	D,FCB+1
	LDAX	D
	STA	OPTION
OPTLP:	INX	D
	LDAX	D
	CPI	' '
	JZ	ENDOPT
	LXI	H,OPTBL
	MVI	B,OPTBE-OPTBL
OPTCK:	CMP	M
	JNZ	OPTNO
	CPI	'O'
	JNZ	OPTCK1
	XRA	A
	STA	UARTFLG
	JMP	OPTCK2
;
OPTCK1:	CPI	'A'
	JNZ	OPTCK2
	MVI	A,TRUE
	STA	UARTFLG
OPTCK2:	MVI	M,0
	JMP	OPTLP
;
OPTNO:	INX	H
	DCR	B
	JNZ	OPTCK
	CALL	NOTVLDMSG
	POP	PSW	;PRESERVE STACK
	JMP	MENU
;
ENDOPT:	LDA	VSEEFLG	
	ORA	A
	RNZ
	STA	QFLG	;IF VIEWING SUPPRESS ALL ELSE
	RET
;
DONE:
	LDA	BATCHFLG
	ORA	A
	JNZ	DONETC
	LDA	QFLG
	ORA	A
	JZ	NMSTRNS
	MVI	B,12		;ZERO OUT FTRNMSG
	LXI	H,FTRNMSG
	MVI	A,0
ZEROLP:	MOV	M,A
	INX	H
	DCR	B
	JNZ	ZEROLP
	MVI	B,12		;PUT FILE NAME IN FTRNMSG
	LXI	H,FCB+1		
	LXI	D,FTRNMSG
LOADMSG:
	MVI	A,4	;START OF FILE TYPE?
	CMP	B
	JZ	PERIOD	;PUT IN PERIOD IF SO
	MOV	A,M	
	CPI	' '	;DON'T PUT IN SPACE
	JZ	SKPSP	
	STAX	D	;STORE IN FTRNMSG
	INX	D
SKPSP:	INX	H
	DCR	B
	MOV	A,B
	ORA	A		;END OF FILE NAME?
	JZ	FTRNMSG0	;DISPLAY FILE NAME
	JMP	LOADMSG		;LOOP FOR ANOTHER CHARACTER
;
PERIOD:
	MOV	A,M
	CPI	' '		;IS FILE TYPE EMPTY?
	JZ	FTRNMSG0	;GO IF SO
	MVI	A,'.'		;ELSE PUT PERIOD IN MESSAGE
	STAX	D
	INX	D
	DCR	B
	JMP	LOADMSG	
;
FTRNMSG0:
	CALL	ILPRT
	DB	CR,LF
FTRNMSG:
	DS	12
	DB	0
	CALL	ILPRT
	DB	' Transferred',CR,LF,LF,0
NMSTRNS:
	LDA	FCB	;SAVE DRIVE NO.
	STA	DISKNO
	LXI	H,FCB	;BLANK OUT FILE CONTROL BLOCKS
	CALL	INITFCBS
	LDA	DISKNO	;PUT DRIVE NUMBER BACK
	STA	FCB
	LXI	H,RESTSN ;RESTORE SECTORE NUMBERS..
	LXI	D,SECTNOB ;..FOR NEW FILE TRANSFER.
	MVI	B,SECTNOE-SECTNOB ;ROUTINE ALSO DONE IN MENU.
	CALL	MOVE
	LDA	SENDFLG	;GOES TO EITHER SEND OR..
	ORA	A	;..RECEIVE FILE, DEPENDING..
	JNZ	SENDFIL1	;..UPON WHICH ROUTINE SET..
	JMP	RCVFIL1	;..THE FLAG IN MULTI-FILE MODE.
;
DONETC:
	CALL	ILPRT
	DB	CR,LF,'Transfer completed',CR,LF,BELL,0
DONETCA:
	LDA	DISCFLG	;SEE IF DISCONNECT WHEN THROUGH
	ORA	A
	JNZ	DONETCE	;NO, DON'T DISCONNECT
DONETCB:
	CALL	ILPRT
	DB	CR,LF,'Press RETURN to disconnect',BELL,CR,LF,0
	MVI	C,RDCON
	CALL	BDOS	;WAIT FOR RESPONSE
	CPI	0DH	;CARRIAGE RETURN
	JNZ	DONETCB	;NOPE
	CALL	ILPRT
	DB	CR,LF,'Disconnected',CR,LF,0
	CALL	JMP$DISCONNT  ;HANG-UP THE PMMI
	JMP	EXIT	;GO TO CP/M
;
DONETCE:
	CALL	NOPARIT	;RESET TO NO PARITY
	MVI	A,TRUE
	STA	FIRSTME	;SET FIRST-TIME FLAG
	STA	FSTFLG	;RESET MULTIFILE TRANS
	STA	NFILFLG	;..USED IN TERMINAL ROUTINE
	CMA
	STA	SAVEFLG	;STOP MEMORY SAVE IN TERM ROUTINE
	STA	LISTMOR	;STOP ANY BUFFERED OUTPUT TO PRINTER
	LXI	H,BOTTRAM	;RESET PRINTER BUFFER POINTERS
	SHLD	HLSAVE1
	SHLD	HLSAVE2
	LDA	TERMFLG	;SEE IF RETURN TO..
	ORA	A	;..TERMINAL MODE..
	JNZ	MENU	;..AFTER X'FER.
	CALL	CRLF
	JMP	TERM
;
MOVEFCB:
	LXI	H,FCB+16
	LXI	D,FCB
	MVI	B,16
	CALL	MOVE
	XRA	A
	STA	FCBSNO
	STA	FCBEXT
	RET
;
SHOW:	CPI	LF
	JZ	CTYPE
	CPI	CR
	JZ	CTYPE
	CPI	9
	JZ	CTYPE
	CPI	' '
	JC	SHOWHEX
	CPI	7FH
	JC	CTYPE
SHOWHEX:
	PUSH	PSW
	MVI	A,'('
	CALL	CTYPE
	POP	PSW
	CALL	HEXO
	MVI	A,')'
	JMP	CTYPE
;
CTYPE:	PUSH	B
	PUSH	D
	PUSH	H
	MOV	E,A
	MVI	C,WRCON
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;
CRLF:	PUSH	PSW
	MVI	A,CR
	CALL	TYPE
	MVI	A,LF
	CALL	TYPE
	POP	PSW
	RET
;
TYPE:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	MOV	C,A
VTYPE:	CALL	$-$
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;
STAT:
	PUSH	B
	PUSH	D
	PUSH	H
;
VSTAT:	CALL	$-$
	POP	H
	POP	D
	POP	B
	ORA	A
	RET
;
KEYIN:
	PUSH	B
	PUSH	D
	PUSH	H
VKEYIN:	CALL	$-$
	POP	H
	POP	D
	POP	B
	RET
;
LISTER:
	PUSH	B
	PUSH	D
	PUSH	H
VLIST:	CALL	$-$
	POP	H
	POP	D
	POP	B
	RET
;
LSTSTAT:
	PUSH	B
	PUSH	D
	PUSH	H
VLSTAT:	CALL	$-$
	POP	H
	POP	D
	POP	B
	ORA	A
	RET
;
UCASE:
	CPI	61H	;CHANGES LOWER CASE CHARACTER..
	RC		;..IN A-REG TO UPPER CASE.
	CPI	7BH
	RNC
	ANI	5FH
	RET
;
DECOUT:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	LXI	B,-10
	LXI	D,-1
DECOU2:	DAD	B
	INX	D
	JC	DECOU2
	LXI	B,10
	DAD	B
	XCHG
	MOV	A,H
	ORA	L
	CNZ	DECOUT
	MOV	A,E
	ADI	'0'
	CALL	CTYPE
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;
;---->	DHXOUT: - DOUBLE PRECISION HEX OUTPUT ROUTINE.
;
DHXOUT:
	PUSH	H
	PUSH	PSW
	MOV	A,H	;GET MS BYTE
	CALL	HEXO	;OUTPUT HIGH ORDER BYTE
	MOV	A,L	;GET LS BYTE
	CALL	HEXO	;OUTPUT LOW ORDER BYTE
	POP	PSW
	POP	H
	RET
;
HEXO:
	PUSH	PSW
	RAR
	RAR
	RAR
	RAR
	CALL	NIBBL
	POP	PSW
NIBBL:
	ANI	0FH
	CPI	10
	JC	ISNUM
	ADI	7
ISNUM:
	ADI	'0'
	JMP	TYPE
;
;RETURNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN
;NO QUESTIONS ASKED, JUST QUIT
;
CKQUIT:
	LDA	BATCHFLG
	ORA	A
	JNZ	CKQTASK	;ASK FOR RETRY
	INR	A	;RESET ZERO FLG
	RET
;
CKQTASK:
	MVI	A,1
	STA	ERRCT
	CALL	ILPRT
	DB	CR,LF,'Multiple errors encountered.',CR,LF
	DB	'Type Q to quit, R to retry:  ',BELL,0
	CALL	KEYIN
	PUSH	PSW
	CALL	CRLF
	POP	PSW
	CALL	UCASE	;INSTEAD OF "ANI 5FH"
	CPI	'R'
	RZ
	CPI	'Q'
	JNZ	CKQUIT
	ORA	A
	RET
;
SHFTYPE:
	PUSH	PSW
	CALL	ILPRT
	DB	'ctrl-',0
	POP	PSW
	ADI	40H
	CALL	TYPE
;
;WRITE A STRING OF CHARACTERS
;
ILPRT:
	XTHL
ILPLP:
	MOV	A,M
	ORA	A
	JZ	ILPRET
	CALL	CTYPE
	INX	H
	JMP	ILPLP
ILPRET:
	XTHL
	RET
;
PRTMSG:
	MVI	C,PRINT
	JMP	BDOS
;
ERXIT:
	POP	D
	CALL	PRTMSG
	MVI	A,BELL
	CALL	TYPE
	LDA	BATCHFLG
	ORA	A
	JNZ	DONETCE
	MVI	A,'Q'	;RESET QFLG
	STA	QFLG
	JMP	ABORT	;ABORT OTHER COMPUTER
;
EXIT:
	CALL	ILPRT
	DB	'%%% Exiting MODEM %%%',0
	LDA	SAVUSR
	MOV	E,A
	CALL	SETUSR
	LXI	D,80H
	MVI	C,STDMA
	CALL	BDOS
	LHLD	STACK
	SPHL
	LDA	SAVCCP
	ORA	A
	JZ	0	;WARM BOOT
	RET
;
MOVE128:
	MVI	B,128
MOVE:	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVE
	RET
;
;INITIALIZES CP/M FILE CONTROL BLOCKS AT 5CH AND 6CH
;
SETFCB:
	LXI	D,CMDBUF
	LXI	H,FCB
	CALL	CPMLINE
	CALL	PROCOPT
CHECKNM:
	LDA	FCB+1	;CHECK ON THE PRIMARY OPTION
	CPI	'E'	;RETURN IF ECHO OPTION
	RZ
	CPI	'H'	;RETURN IF HELP OPTION
	RZ
	CPI	'L'	;RETURN IF LOCAL ECHO OPTION
	RZ
	MOV	B,A
	LDA	PMMIBYTE
	ORA	A
	MOV	A,B
	JZ	S4
	CPI	'C'
	RZ
S4:	CPI	'T'
	JZ	TERMSEL
	CPI	'S'
	JZ	CKFILE
	CPI	'R'
	JNZ	BDOPT
	LDA	BATCHFLG ;IF MULT FILE MODE, THEN..
	ORA	A	 ;..RECV OPT DOES NOT NEED..
	RZ		 ;..NAME.
	JMP	CKFILE
BDOPT:	CALL	ILPRT
	DB	CR,LF,'++ Bad Option ++',CR,LF,0
	JMP	REENT
CKFILE:	LDA	FCB+17	;IF OPTION THAT NEEDS FILE NAME,..
	CPI	' '	;..THEN CHECK TO SEE IF NAME..
	RNZ		;..EXISTS. IF NOT..
REENT:	CALL	ILPRT	;..DO EVERYTHING OVER.
	DB	CR,LF,'Re-enter PRIMARY option and file name only: ',BELL,0
	LXI	D,CMDBUF
	CALL	INBUFF
	JMP	SETFCB
;
TERMSEL:
	LDA	FCB+17
	CPI	' '
	JNZ	SAVAGN
	MVI	A,FALSE
	STA	SAVEFLG
	MVI	A,TRUE
	STA	NFILFLG
	RET
;
SAVAGN:
	MVI	A,FALSE
	STA	NFILFLG
	RET
;
NEWBAUD:
	LDA	PMMIBYTE
	ORA	A
	RZ
	CALL	ILPRT
	DB	CR,LF,'Enter New Baudrate: ',0
	LXI	H,FCB+9
	MVI	M,0	;PUTS A ZERO IN FIRST POSITION SO AS TO
LOOP5:
	CALL	KEYIN	;FORCE THE DEFAULT OPTION OF 300 BAUD.
	CPI	CR	;CARRIAGE RET ENTERS BAUD RATE
	JNZ	CONNEWB	;GOES TO THE ESTABLISHED ROUTINE - RETURN TO MAIN
	CALL	CRLF	;PROGRAM IS DONE THERE.
	JMP	JMP$INITMOD
;
CONNEWB:
	CPI	30H	;MAKE SURE IT'S..
	JC	LOOP5	;..A DIGIT, ELSE..
	CPI	3AH	;..DON'T ACCEPT IT.
	JNC	LOOP5
	MOV	M,A
	MOV	C,A
	CALL	TYPE	;ECHO THE CHARACTER ENTERED
	INX	H
	JMP	LOOP5
;
;****************************************************************
;*								*
;*   CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20	*
;*   8080 Mnemonics						*
;*								*
;*     These subroutines will compute and check a true 16-bit	*
;*   Cyclic Redundancy Code for a message of arbitrary length.	*
;*								*
;*     The use of this scheme will guarantee detection of all	*
;*   single and double bit errors, all  errors  with  an  odd	*
;*   number  of  error bits, all burst errors of length 16 or	*
;*   less, 99.9969% of all 17-bit error bursts, and  99.9984%	*
;*   of  all  possible  longer  error bursts.  (Ref: Computer	*
;*   Networks, Andrew S.  Tanenbaum, Prentiss-Hall, 1981)	*
;*								*
;*   Designed & coded by Paul Hansknecht, June 13, 1981		*
;*								*
;*   Copyright (c) 1981, Carpenter Associates			*
;*		    Box 451					*
;*		    Bloomfield Hills, MI 48013			*
;*		    313/855-3074				*
;*								*
;*   This program may be freely reproduced for non-profit use.	*
;*								*
;****************************************************************
;
;	ENTRY	CLRCRC,UPDCRC,FINCRC,CHKCRC
;
CLRCRC:	EQU	$	;RESET CRC ACCUMULATOR FOR A NEW MESSAGE.
	PUSH	H
	LXI	H,0
	SHLD	CRCVAL
	POP	H
	RET
;
UPDCRC:	EQU	$	;UPDATE CRC ACCUMULATOR USING BYTE IN (A).
	PUSH	PSW
	PUSH	B
	PUSH	H
	MVI	B,8
	MOV	C,A
	LHLD	CRCVAL
UPDLOOP:
	MOV	A,C
	RLC
	MOV	C,A
	MOV	A,L
	RAL
	MOV	L,A
	MOV	A,H
	RAL
	MOV	H,A
	JNC	SKIPIT
	MOV	A,H	;THE GENERATOR IS X^16 + X^12 + X^5 + 1
	XRI	10H	;AS RECOMMENDED BY CCITT.
	MOV	H,A	;AN ALTERNATE GENERATOR WHICH IS OFTEN
	MOV	A,L	;USED IN SYNCHRONOUS TRANSMISSION PROTOCOLS
	XRI	21H	;IS X^16 + X^15 + X^2 + 1. THIS MAY BE
	MOV	L,A	;USED BY SUBSTITUTING XOR 80H FOR XOR 10H
SKIPIT:	DCR	B	;AND XOR 05H FOR XOR 21H IN THE ADJACENT CODE
	JNZ	UPDLOOP
	SHLD	CRCVAL
	POP	H
	POP	B
	POP	PSW
	RET
;
FINCRC:	EQU	$	;FINISH CRC CALCULATION FOR OUTPUT MESSAGE
	PUSH	PSW
	XRA	A
	CALL	UPDCRC
	CALL	UPDCRC
	PUSH	H
	LHLD	CRCVAL
	MOV	D,H
	MOV	E,L
	POP	H
	POP	PSW
	RET
;
CHKCRC:	EQU	$	;CHECK CRC BYTES OF RECEIVED MESSAGE
	PUSH	H
	LHLD	CRCVAL
	MOV	A,H
	ORA	L
	POP	H
	RZ
	MVI	A,0FFH
	RET
;
CRCVAL:
	DW	0
;
MENU0:
	LDA	NFILFLG
	ORA	A
	JNZ	MENU	;GO IF NO FILE ACTIVE
	CALL	ILPRT	;ELSE PRINT MESSAGE
	DB	CR,LF,LF
	DB	'** There may be text in the memory buffer **',CR,LF
	DB	'** It will be lost unless NOL or WRT commands are used **'
	DB	CR,LF,BELL,0
	MVI	B,2	;2 MORE BELLS
BLOOP:	LDA	BELRPT	;GET TIME
	MOV	C,A
BCLOOP:	LXI	H,1000	;ABOUT 0.03 SECONDS
	CALL	FIXCNT
BILOOP:	MOV	A,L
	ORA	H
	DCX	H
	JNZ	BILOOP
	DCR	C
	JNZ	BCLOOP
	MVI	A,BELL
	CALL	TYPE
	DCR	B
	JNZ	BLOOP
	JMP	MENU1
;
MENU:
	LDA	EXITFLG
	ORA	A
	JNZ	EXIT
MENU1:
	LXI	H,RESTSN  ;RESTORE SECTOR NUMBERS..
	LXI	D,SECTNOB ;..FOR NEW FILE TRANSFER.
	MVI	B,SECTNOE-SECTNOB
	CALL	MOVE
	LXI	H,RESTROPT ;RESTORE OPTION TABLE
	LXI	D,OPTBL
	MVI	B,OPTBE-OPTBL
	CALL	MOVE
	MVI	A,0
	STA	MFFLG1	;RESET MFACCESS ROUTINE..
	CMA		;..AND MULTI TRANS IN CASE..
	STA	FSTFLG	;..OF ABORT.
	JMP	XPRT
;
MENU2:
	CALL	CLRTST
	CALL    ILPRT
	DB	'               Single Letter Commands',CR,LF,LF
	DB	' H  - Display this information',CR,LF
	DB	' ?  - Display current settings',CR,LF,LF
	DB      ' T  - Terminal mode',CR,LF
	DB      ' E  - Terminal mode with echo',CR,LF
	DB	' L  - Terminal mode with local echo',CR,LF
	DB	'     For capturing text use T(or E or L) FILENAME.TYP and'
	DB	CR,LF
	DB	'     Start & Stop toggles described on subsequent screen.'
	DB	CR,LF,LF
	DB      ' R  - Receive file using Christensen Protocol',CR,LF
	DB      ' S  - Send file using Christensen Protocol',CR,LF
	DB	'     Command is: R(or S) FILENAME.TYP',CR,LF
	DB	'     R and S can use the following subcommands:',CR,LF
	DB	'          B  - Bulk transfer using wildcards (e.g. *.*)',CR,LF
	DB	'          Q  - Quiet mode (no messages to console)',CR,LF
	DB	'          T  - Return to terminal mode after transfer',CR,LF
	DB	'          V  - View bytes transferred on console',CR,LF,LF
	DB	'The single letter commands may also be used on the',CR,LF
	DB	'command line when the program is initially executed.'
	DB	CR,LF,LF,0
;
	CALL	NXTSCRN
;
	LDA	PMMIBYTE
	ORA	A
	JZ	THREELTR
	CALL	ILPRT
	DB	'       Additional Subcommands for PMMI Modem',CR,LF,LF
	DB	'  Modem control:',CR,LF
	DB	'      O - Send or receive on Originate tone',CR,LF
	DB	'      A - Send or receive on Answer tone',CR,LF
	DB	'      D - Disconnect option',CR,LF,LF
	DB	'  Parity options:',CR,LF
	DB	'      1 - Set and check for odd parity',CR,LF
	DB	'      0 - Set and check for even parity',CR,LF
	DB	'          Both ends must be capable of these options',CR,LF
	DB	'          which are available only in S and R modes.',CR,LF
	DB	'          The parity checking will be part of the',CR,LF
	DB	'          file transfer protocol.',CR,LF,LF
	DB	'  Speed Options:',CR,LF
	DB	'      After entering your primary and secondary options,'
	DB	CR,LF
	DB	'      you can set the modem speed by placing a "." after'
	DB	CR,LF
	DB	'      the options followed by the speed e.g. 110, 300.',CR,LF
	DB	'      For example:  SBO1T.600 will set the modem to run',CR,LF
	DB	'      at 600 baud.',CR,LF,LF,0
;
	CALL	NXTSCRN
;
THREELTR:
	CALL	ILPRT
	DB	'               Three Letter Commands',CR,LF,LF
	DB      'DIR - List directory and space free (may specify drive)'
	DB	CR,LF
	DB	'END - Exit from this program',CR,LF
	DB	'ERA - Erase file (may specify drive)',CR,LF
	DB	'LOG - Change default drive/user (specify drive/user)'
	DB	CR,LF
	DB	'      and reset disks.  e.g. LOG A0, LOG B (user unchanged)'
	DB	CR,LF
	DB	'SPD - Set speed of file output in terminal mode',CR,LF,0
;
	CALL	SORPTST
	JNZ	NOTIME
	CALL	ILPRT
	DB	'TIM - Set S mode time-to-send message',CR,LF,0
;
NOTIME:
	LDA	TOGGLECRC
	ORA	A
	JZ	NOTOGCRC
	CALL	ILPRT
	DB	'TCC - Toggle Checksum/CRC mode on receive',CR,LF,0
;
NOTOGCRC:
	LDA	TOGGLEBK
	ORA	A
	JZ	NOTOGBK
	CALL	ILPRT
	DB	'TBR - Toggle backspace to rub conversion',CR,LF,0
;
NOTOGBK:
	LDA	TOGGLELOC
	ORA	A
	JZ	NOTOGLOC
	CALL	ILPRT
	DB	'TLC - Toggle  1) local command immediate',CR,LF
	DB	'              2) local command after ',0
	LDA	EXTCHR
	CALL	SHFTYPE
	DB	CR,LF,0
;
NOTOGLOC:
	LDA	TOGGLELF
	ORA	A
	JZ	NOTOGLF
	CALL	ILPRT
	DB	'TLF - Toggle send linefeed after carriage return',CR,LF,0
;
NOTOGLF:
	LDA	TOGXOFF
	ORA	A
	JZ	NOTOGXOFF
	CALL	ILPRT
	DB	'TXO - Toggle XOFF/XON testing in terminal mode file output'
	DB	CR,LF,0
;
NOTOGXOFF:
	LDA	PMMIBYTE
	ORA	A
	JNZ	NONUM
	CALL	ILPRT
	DB	'NUM - List remote systems',CR,LF,0
	LDA	SETUPTST
	ORA	A
	JZ	NOSETUP
	CALL	ILPRT
	DB	'SET - Set communication ports',CR,LF,0
;
NOSETUP:
	MVI	A,LF
	CALL	TYPE
	JMP	NOPMMI
;
NONUM:
	CALL    ILPRT
	DB      'CAL - Dial number',CR,LF
	DB      'DSC - Disconnect',CR,LF
	DB	'BYE - Disconnect and reboot',CR,LF,LF,0
;
NOPMMI:
	CALL	ILPRT
	DB	'    The following are terminal text buffer commands:'
	DB	CR,LF,0
	LDA	PMMIBYTE
	ORA	A
	JNZ	SKIPLF
	MVI	A,LF
	CALL	TYPE
SKIPLF:
	CALL	ILPRT
	DB      'DEL - Delete memory buffer and file',CR,LF
	DB      'NOL - Return to terminal mode - no loss of data in buffer'
	DB	CR,LF
	DB      'WRT - Write memory buffer to disk file',CR,LF,LF,0
	CALL	NXTSCRN
;
	CALL	ILPRT
	DB	'      Local Commands while in Terminal Mode',CR,LF,LF,0
	LDA	EXITCHR
	CALL	SHFTYPE
	DB	'  - Exit to command mode',CR,LF,LF,0
;
	LDA     PMMIBYTE
	ORA     A
	JZ      S5A
;
	LDA	DISCCHR
	CALL	SHFTYPE
	DB	'  - Disconnect',CR,LF,0
	LDA	BRKCHR
	CALL	SHFTYPE
	DB	'  - Send break',CR,LF,0
	LDA	CHGBAUD
	CALL	SHFTYPE
	DB	'  - Change baud rate',CR,LF,0
;
S5A:
	LDA	TRANLOGON
	ORA	A
	JZ	NOTRANLOG
	LDA	LOGCHR
	CALL	SHFTYPE
	DB	'  - Transmit logon',CR,LF,0
;
NOTRANLOG:
	LDA	LSTTST
	ORA	A
	JZ	NOLST2
	LDA	LSTCHR
	CALL	SHFTYPE
	DB	'  - Toggle printer',CR,LF,0
;
NOLST2:
	MVI	A,LF
	CALL	TYPE
	LDA	SAVECHR
	CALL	SHFTYPE
	DB	'  - Start copy into buffer',CR,LF,0
	LDA	UNSAVECHR
	CALL	SHFTYPE
	DB      '  - Stop copy into buffer',CR,LF
	DB	'     Start & Stop may be toggled as often as desired.',CR,LF
	DB	'     A ":" at start of line indicates buffer is open.',CR,LF
	DB	'     XOFF automatically used to stop input when writing',CR,LF
	DB	'     full buffer to disk, XON sent to resume.',CR,LF,LF,0
	LDA	TRANCHR
	CALL	SHFTYPE
	DB	'  - Transfer ASCII file to remote',CR,LF,LF,0
	LDA	LOCONEXTCHR
	ORA	A
	LDA	EXTCHR
	JNZ	REMDFLT
	CALL	SHFTYPE
	DB	'  - Send local control character to remote',CR,LF,0
	JMP	XPRT
REMDFLT:
	CALL	SHFTYPE
	DB	'  - Next character will be used for local control',CR,LF,0
;
XPRT:
	CALL	ILPRT
	DB	CR,LF,'Drive ',0
	MVI	C,CURDSK	;CURRENT DISK FUNCTION
	CALL	BDOS
	ADI	'A'		;MAKE ASCII
	CALL	TYPE
;
	IF  CPM2X	;IF CPM VER 2.X
;
	CALL	GETUSR	;GET CURRENT USER NUMBER
	CPI	0
	JZ	SR3B	;SKIP IF USER 0
	PUSH	PSW
	CALL	ILPRT
	DB	', User ',0
	POP	PSW
	MVI	H,0
	MOV	L,A
	CALL	DECOUT	;REPORT USER
;
	ENDIF	;CPM2X
;
SR3B:	CALL	CRLF
	LDA	NFILFLG
	ORA	A
	JNZ	NOBUFMSG
	CALL	GETSPC
	CALL	ILPRT
	DB	' bytes of buffer free',CR,LF,0
NOBUFMSG:	
	CALL	ILPRT
	DB	'COMMAND (H for Help): ',0
GETCMD:
	LXI	D,CMDBUF	;ENTER COMMAND
	CALL	INBUFF
	CALL	CRLF
	LXI	D,CMDBUF+2 ;POINT TO COMMAND
	CALL	ILCOMP
	DB	'END',0
	JNC	EXIT
	CALL	ILCOMP
	DB	'LOG',0
	JNC	LOGNEW
	CALL	ILCOMP
	DB	'DIR',0
	JNC	DIR
	CALL	ILCOMP
	DB	'ERA',0
	JNC	ERASEF
	CALL	ILCOMP
	DB	'?',0
	JNC	CURPAR
	CALL	ILCOMP
	DB	'SPD',0
	JNC	SETSPD
	CALL	ILCOMP
	DB	'TIM',0
	JNC	SETTIM
	CALL	ILCOMP
	DB	'TCC',0
	JNC	TOGCRC
	CALL	ILCOMP
	DB	'TBR',0
	JNC	TOGBKSP
	CALL	ILCOMP
	DB	'TLC',0
	JNC	TOGLOC
	CALL	ILCOMP
	DB	'TLF',0
	JNC	TOGLF
	CALL	ILCOMP
	DB	'TXO',0
	JNC	TOGTXOFF
	LDA	PMMIBYTE
	ORA	A
	JNZ	NONUM2
	CALL	ILCOMP
	DB	'NUM',0
	JNC	NUMPRN
NONUM2:	LDA	SETUPTST
	ORA	A
	JZ	NOSETUP2
	CALL	ILCOMP
	DB	'SET',0
	JNC	SETUPENT
NOSETUP2:
	CALL	ILCOMP
	DB	'NOL',0
	JC	NXTOPT1		;CARRY SET = NO MATCH
	LDA	NFILFLG
	ORA	A
	JNZ	NOFILOPN	;GO TELL OPERATOR IF NO FILE OPEN
	LDA	ORIGSAV
	STA	ORIGFLG
	CALL	BUFMSG
	LHLD	HLSAVE	;RETURN TO TERMINAL..
	JMP	TERM	;..MODE WITH SAVE OPTION..
			;..IF PREVIOUSLY ENABLED.
;
NXTOPT1:
	CALL	ILCOMP
	DB	'WRT',0
	JNC	WRTFIL
	CALL	ILCOMP
	DB	'DEL',0
	JNC	NEWFILE
	LDA	PMMIBYTE
	ORA	A
	JZ	S6
	CALL	ILCOMP	;DE SET FROM 1ST ILCOMP CALL
	DB	'DSC',0
	JNC	DISCON1
	CALL	ILCOMP
	DB	'BYE',0
	JNC	BYEBYE
	CALL	ILCOMP
	DB	'CAL',0
	JC	S6
	MVI	A,20H		;FOOL THE SYSTEM
	STA	CMDBUF+4	;..CMDBUF SO THAT IT..
	JMP	DOOPT		;..LOOKS AT OPTION FOR DIAL
S6:	PUSH	H
	LDA	CMDBUF+2
	LXI	H,COMPLIST
	CALL	COMPARE	;COMPARES LIST POINTED TO BY HL..
	POP	H	;..TO CHAR IN A-REG.
	JC	NOTVLD	;CARRY SET = NO MATCH
DOOPT:	PUSH	H	;LOAD ORIGINAL FCB WITH TRANSFER..
	CALL	SETFCB	;..CMDS AND GO TO BEGINNING OF..
	POP	H	;..PROGRAM. WILL FOLLOW SAME LOGIC..
	JMP	RESTART	;..AS IF PROGRAM WERE CALLED WITH..
			;..CP/M COMMAND LINE.
;
NOTVLD:
	CALL	NOTVLDMSG
	JMP	XPRT
;
NOTVLDMSG:
	CALL	ILPRT
	DB	'++ Invalid Command ++',CR,LF,BELL,0
	RET
;
DISCON1:
	CALL	JMP$DISCONNT
	CALL	ILPRT
	DB	CR,LF,'<< Disconnected >>',CR,LF,BELL,0
	JMP	EXITMEN
;
BYEBYE:
	CALL	ILPRT
	DB	CR,LF,'Goodbye...',CR,LF,0
	XRA	A
	CALL	OUT$MODCTLP
	CALL	OUT$MODCTL2
	LDA	SAVUSR
	MOV	E,A
	CALL	SETUSR
	LHLD	CLDBOOT	;GET COLD BOOT PROM ADDRESS OR WARM BOOT
	PCHL		;JUMP TO IT
;
DIR:
	MVI	C,CURDSK
	CALL	BDOS
	STA	DISKSAV
	CALL	DIRLST
	LDA	DISKSAV
	MOV	E,A
	MVI	C,SELDSK
	CALL	BDOS
	JMP	XPRT
;
LOGNEW:	LDA	NFILFLG
	ORA	A
	JZ	NORESET
	LDA	CMDBUF+6
	CPI	' '
	JNZ	SPECIFD
	MVI	C,CURDSK
	CALL	BDOS
	ADI	'A'
SPECIFD:
	SUI	'A'
	STA	DISKSAV
	CPI	16
	JNC	NOTVLD
;
	IF	CPM2X		;IF CPM VER. 2.X
;
	CALL	GETUSR		;PICK UP CURRENT USER NUMBER
	MOV	B,A		;SAVE IT
	LDA	CMDBUF+7	;GET NEW USER NUMBER
	CPI	' '		;CHECK FOR SPACE
	JZ	SR7B		;EXIT IF NO NEW USER NUMBER SPECIFIED
	CALL	NUMCHK		;CHECK TO SEE IF IT IS A NUMBER
	MOV	B,A		;SAVE
	LDA	CMDBUF+8	;GET SECOND DIGIT
	CPI	' '
	JZ	SR7B		;GO IF SPACE
	CALL	NUMCHK
	MOV	C,A		;SAVE
	MOV	A,B		;GET SAVED FIRST DIGIT
	ADD	A		; X2
	ADD	A		; X4
	ADD	A		; X8
	ADD	B		; X9
	ADD	B		; X10
	ADD	C
	MOV	B,A		;SAVE
	LDA	CMDBUF+9	;GET THIRD DIGIT
	CPI	' '
	JZ	SR7B		;GO IF SPACE
	CALL	NUMCHK
	MOV	C,A		;SAVE
	MOV	A,B		;GET SAVED FIRST & SECOND DIGIT
	ADD	A		; X2
	ADD	A		; X4
	ADD	A		; X8
	ADD	B		; X9
	ADD	B		; X10
	ADD	C
;	CPI	16		;CHECK FOR < 16
;	JNC	NOTVLD		;GO IF NOT
	MOV	B,A
SR7B:	MOV	A,B
	STA	SAVUSR
;
	ENDIF	;CPM2X
;
	CALL	ILPRT
	DB	'Insert disk for drive ',0
	LDA	DISKSAV
	ADI	'A'
	CALL	TYPE
NOTCR:	CALL	ILPRT
	DB	CR,LF,'Hit return when ready',0
	CALL	KEYIN
	CPI	3	;CTL-C ABORTS LOGIN
	JZ	XPRT
	CPI	CR
	JNZ	NOTCR
	CALL	CRLF
	MVI	C,RESET
	CALL	BDOS	
	LDA	DISKSAV
	MOV	E,A
	MVI	C,SELDSK
	CALL	BDOS
;
	IF	CPM2X
	LDA	SAVUSR
	MOV	E,A
	CALL	SETUSR
	ENDIF
;
	JMP	XPRT
;
	IF	CPM2X
;
GETUSR:	MVI	E,0FFH		;GET CURRENT USER
SETUSR:	MVI	C,USER		;SET-UP FUNCTION CALL
	JMP	BDOS		;NUMBER IN RETURNED IN A
;
	ENDIF	;CPM2X
;
NORESET:
	CALL	ILPRT
	DB	'++      Terminal mode file open      ++',CR,LF
	DB	'++ Use WRT or DEL before LOG command ++',CR,LF
	DB	CR,LF,LF,BELL,0
	XRA	A
	JMP	XPRT
;
ERASEF:	LXI	D,CMDBUF ;PUT CMD LINE INTO FCB AT HL
	LXI	H,FCB
	CALL	CPMLINE
	CALL	MOVEFCB	;MOVE FCB+16 TO FCB
	LDA	FCB+1
	CPI	' '
	JZ	NOTVLD	;GO IF NO FILE SPECIFIED
	LXI	D,FCB
	MVI	C,SRCHF
	CALL	BDOS
	INR	A	;0 IF FILE NOT FOUND
	JNZ	ERAFILE ;OK, GO ERASE
	CALL	ILPRT
	DB	'++ File not found ++',CR,LF,BELL,0
	JMP	XPRT
;
ERAFILE:
	LXI	D,FCB
	MVI	C,ERASE
	CALL	BDOS
	CALL	ILPRT
	DB	'File erased',CR,LF,0
	JMP	XPRT
;
SETSPD:
	CALL	ILPRT
	DB	'Enter character output delay [0(none) - 9(longest delay)]: ',0
	CALL	NUMGET
	JNC	NOCHG1
	STA	BYTDLY
NOCHG1:	CALL	SPDMSG
	CALL	ILPRT
	DB	CR,LF,'Enter additional delay after <CR> [0-9]: ',0
	CALL	NUMGET
	JNC	NOCHG2
	RLC		;X2
	RLC		;X4
	STA	CRDLY
NOCHG2:	CALL	CRDLYMSG
	JMP	XPRT
;
NUMGET:	LXI	D,CMDBUF
	CALL	INBUFF
	LDA	CMDBUF+2 	;GET NUMBER
	CPI	' '
	RZ
NUMCHK:	SUI	'0'
	CPI	10
	RC
	POP	PSW		;PRESERVE STACK
	JMP	NOTVLD
;
SPDMSG:	CALL	ILPRT
	DB	'Terminal mode file output delay is 0.',0
	LDA	BYTDLY
	CALL	GIVNUM
	CALL	ILPRT
	DB	' seconds per character',CR,LF,0
	RET
;
CRDLYMSG:
	CALL	ILPRT
	DB	'Additional delay after <CR> is 0.',0
	LDA	CRDLY
	CALL	GIVNUM
	CALL	ILPRT
	DB	' seconds',CR,LF,0
	RET
;
GIVNUM:	ADD	A	;2X
	CPI	10
	MOV	B,A
	JNC	NOZERO
	MVI	A,'0'
	CALL	TYPE
	MOV	A,B
NOZERO:	PUSH	H
	MOV	L,A
	MVI	H,0
	CALL	DECOUT
	POP	H
	RET
;
SETTIM:
	CALL	SORPTST
	JNZ	NOTVLD
	CALL	ILPRT
	DB	'Use 0-8 to give baud rate for S mode time-to-send message,'
	DB	CR,LF
	DB	'where 0=110, 1=300, 2=450, 3=600, 4=710, 5=1200, 6=2400,'
	DB	CR,LF
	DB	'      7=4800, and 8=9600 Baud.'
	DB	CR,LF,LF,'Enter value: ',0
	CALL	NUMGET
	CPI	9
	JNC	NOTVLD
	STA	MSPEED
	CALL	SETTIM2
	JMP	XPRT
;
SETTIM2:
	CALL	SORPTST
	JNZ	SETTIM3
	CALL	ILPRT
	DB	'Rate for the S mode time-to-send message is set to ',0
	JMP	SETTIM4
SETTIM3:
	CALL	ILPRT
	DB	'Modem speed is ',0
SETTIM4:
	JMP	BAUDPRT
;
SORPTST:
	LDA	SETUPTST
	MOV	B,A
	LDA	PMMIBYTE
	ORA	B
	RET
;
TOGCRC:
	LDA	TOGGLECRC
	ORA	A
	JZ	NOTVLD
	LDA	CKSUMDFLT
	CMA
	STA	CKSUMDFLT
	CALL	TOGCRC2
	JMP	XPRT
;
TOGCRC2:
	ORA	A
	JNZ	CHEKMSG
	CALL	ILPRT
	DB	'CRC mode set',CR,LF,0
	RET
;
CHEKMSG:
	CALL	ILPRT
	DB	'Checksum mode set',CR,LF,0
	RET
;
TOGBKSP:
	LDA	TOGGLEBK
	ORA	A
	JZ	NOTVLD
	LDA	CONVBKSP
	CMA
	STA	CONVBKSP
	CALL	TOGBKSP2
	JMP	XPRT
;
TOGBKSP2:
	LDA	CONVBKSP
	ORA	A
	JZ	NORUBMSG
	CALL	ILPRT
	DB	'Backspace is rub',CR,LF,0
	RET
;
NORUBMSG:
	CALL	ILPRT
	DB	'Backspace is backspace',CR,LF,0
	RET
;
TOGLOC:	LDA	TOGGLELOC
	ORA	A
	JZ	NOTVLD
	LDA	LOCONEXTCHR
	CMA
	STA	LOCONEXTCHR
	CALL	TOGLOC2
	JMP	XPRT
;
TOGLOC2:
	CALL	ILPRT
	DB	'Use ',0
	LDA	LOCONEXTCHR
	ORA	A
	LDA	EXTCHR
	JZ	LOCMSG
	CALL	SHFTYPE
	DB	' before local command',CR,LF,0
	RET
;
LOCMSG: CALL	SHFTYPE
	DB	' to send local command to remote',CR,LF,0
	RET
;
TOGLF:	LDA	TOGGLELF
	ORA	A
	JZ	NOTVLD
	LDA	ADDLF
	CMA
	STA	ADDLF
	CALL	TOGLF2
	JMP	XPRT
;
TOGLF2:
	CALL	ILPRT
	DB	'Linefeed ',0
	LDA	ADDLF
	ORA	A
	JNZ	LFMSG
	CALL	ILPRT
	DB	'NOT ',0
LFMSG:	CALL	ILPRT
	DB	'sent after <CR>',CR,LF,0
	RET
;
TOGTXOFF:
	LDA	TOGXOFF
	ORA	A
	JZ	NOTVLD
	CALL	ILPRT
	DB	'Use XOFF testing? (Y/N): ',0
	CALL	GETANS
	JC	NOCHG3
	STA	XOFFTST
NOCHG3:	CALL	XOFFMSG
	CALL	ILPRT
	DB	CR,LF,'Use XON waiting after <CR> (Y/N): ',0
	CALL	GETANS
	JC	NOCHG4
	STA	XONWAIT
NOCHG4:	CALL	XONMSG
	LDA	XONWAIT
	ORA	A
	JZ	XPRT
	CMA
	STA	XOFFTST		;DON'T ALLOW BOTH
	CALL	ILPRT
	DB	'Therefore ',0
	CALL	XOFFMSG
	JMP	XPRT
;
GETANS:
	LXI	D,CMDBUF
	CALL	INBUFF
	LDA	CMDBUF+2 	;GET ANSWER
	CPI	' '
	CMC
	RZ
	MOV	B,A
	CPI	'N'
	MVI	A,FALSE
	RZ
	MOV	A,B
	CPI	'Y'
	MVI	A,TRUE
	RZ
	POP	PSW		;PRESERVE STACK
	JMP	NOTVLD
;
XOFFMSG:
	CALL	ILPRT
	DB	'XOFF testing ',0
	LDA	XOFFTST
	ORA	A
	JNZ	XOTSTON
	CALL	ILPRT
	DB	'NOT ',0
XOTSTON:
	CALL	ILPRT
	DB	'used',0
XONMSG3:
	CALL	ILPRT
	DB	' in terminal mode file output',CR,LF,0
	RET
;
XONMSG:
	CALL	ILPRT
	DB	'XON ',0
	LDA	XONWAIT
	ORA	A
	JNZ	XONMSG2
	CALL	ILPRT
	DB	'NOT ',0
XONMSG2:
	CALL	ILPRT
	DB	'automatically tested after <CR>',0
	JMP	XONMSG3
;
SETUPENT:
	LDA	SETUPTST
	ORA	A
	JZ	NOTVLD
	LXI	D,CMDBUF+1
	CALL	JMP$SETUPR
	JMP	XPRT
;
NEWFILE:
	LDA	NFILFLG
	ORA	A
	JNZ	NOFILOPN	
	LDA	FCB3+1		;CHECK THAT FILE WAS REQUESTED
	CPI	' '
	JZ	NOFILOPN	;IF NO FILE, DON'T ERASE
	LXI	D,FCB3
	MVI	C,ERASE
	CALL	BDOSRT
	MVI	A,TRUE	;DO NOT ALLOW TERMINAL..
	STA	NFILFLG	;..SAVE SINCE NO FILE..
	CMA		;..SPECIFIED.
	STA	SAVEFLG
	LXI	H,FCB3
	CALL	INITFCBS
	LXI	H,BOTTRAM
	SHLD	HLSAVE
	JMP	XPRT
;
WRTFIL:
	LDA	NFILFLG
	CPI	TRUE
	JZ	NOFILOPN
	LDA	FCB3+1	;CHECK THAT FILE WAS REQUESTED
	CPI	' '
	JZ	NOFILOPN
	LHLD	HLSAVE
	CALL	NUMRECS	;DISK WRITE ROUTINE AS USED IN..
	CALL	WRTDSK	;..IN THE INTDSKSV ROUTINE.
	CALL	CLOSE3
	MVI	A,TRUE
	STA	NFILFLG
	CMA
	STA	SAVEFLG
	LXI	H,FCB3
	CALL	INITFCBS ;BLANK OUT FCB SO WRITTEN FILE CAN'T BE ERASED.
	LXI	H,BOTTRAM
	SHLD	HLSAVE
	JMP	XPRT
;
NOFILOPN:
	CALL	ILPRT
	DB	'++ No File Open ++',CR,LF,BELL,0
	JMP	XPRT
;
;THIS ROUTINE DISPLAYS THE PHONE NUMBERS IN THE LIBRARY
;
NUMPRN:
	PUSH	H
	CALL	CLRTST
	CALL	ILPRT
	DB	'           Library of Phone Numbers of Remote Systems',0
	MVI	C,13       ;NUMBER OF LINES TO MOVE
	LXI	H,NUMBLIB  ;ADDRESS OF SOURCE MEMORY
	LXI	D,DBUF     ;ADDRESS OF TARGET MEMORY
	CALL	NEWLINE    ;START WITH CRLF
	STAX	D          ;+LF
	INX	D          ;AND BUMP IT
NUMPRN1:
	INX	H	;SKIP PMMI DIALING LETTER
	INX	H	;AND EQUAL SIGN
	MVI	B,30	;NUMBER OF BYTES TO MOVE
	CALL	MOVE	;MOVE TO BUFFER
	CALL	SPACES	;2 ENTRIES + 3 SPACES = 63 CHARACTERS
	INX	H
	INX	H
	MVI	B,30
	CALL	MOVE
	CALL	NEWLINE
	DCR	C	;NUMBER OF LINES TO PRINT
	JZ	NUMPRN2
	JMP	NUMPRN1
;
NEWLINE:		;PUTS CR-LF AT MEMORY POINTED BY 'DE'
	MVI	A,CR	;CR
	STAX	D	;STORE IT
	MVI	A,LF	;LF
	INX	D	;BUMP POINTER
	STAX	D	;STORE LF
	INX	D	;BUMP POINTER
	RET
;
SPACES:
	MVI	A,20H	;SPACE
	STAX	D
	INX	D	;1
	STAX	D
	INX	D	;2
	STAX	D
	INX	D	;3
	RET
;
NUMPRN2:
	MVI	A,'$'
	STAX	D
	MVI	C,PRINT
	LXI	D,DBUF	;POINT TO TABLE OF NUMBERS TO PRINT
	CALL	BDOS
	CALL	CRLF
	CALL	CRLF
	POP	H
	JMP	XPRT
;
COMPARE:
	MOV	B,M	;COMPARES A-REG WITH LIST..
COMPLP:
	INX	H	;..ADDRESSED BY HL. FIRST ELEMENT..
	CMP	M	;..OF LIST MUST BE NUMBER OF ELEMENTS..
	JZ	VALID	;..BEING COMPARED. RETURNS WITH..
	DCR	B	;..CARRY SET IF A-REG DOES NOT..
	JNZ	COMPLP	;.. CONTAIN AN ELEMENT IN LIST.
	STC
VALID:
	RET
;
NXTSCRN:
	CALL    ILPRT
	DB	'HIT any KEY to CONTINUE',0
NOKEY1:	CALL	STAT	;GET KEYBOARD STATUS
	JZ	NOKEY1	;KEEP LOOPING UNTIL KEYPRESS
	CALL	KEYIN	;GOBBLE UP KEYPRESS
	CPI	3	;QUIT?
	JNZ	CLRTST
	POP	PSW	;CLEAN RETURN ADR OFF OF STACK
	JMP	XPRT
;
CLRTST:	LDA	SCRNTEST
	ORA	A
	JNZ	CLRSCRN
;
LOTSALF:
	MVI	A,CR
	CALL	TYPE
	MVI	B,12
	MVI	A,LF
LFLOOP:	CALL	TYPE
	DCR	B
	JNZ	LFLOOP
	RET	
;
CURPAR:
	CALL	CLRTST
	CALL	ILPRT
	DB	'                Current Settings',CR,LF,LF,LF,0
	LDA	CKSUMDFLT
	CALL	TOGCRC2
	LDA	LSTTST
	ORA	A
	JZ	NOLST3
	CALL	LSTMSG
NOLST3:
	CALL	SETTIM2
	CALL	TOGBKSP2
	CALL	TOGLF2
	CALL	TOGLOC2
	CALL	ILPRT
	DB	'Terminal mode file buffer is ',0
	LDA	NFILFLG
	ORA	A
	JZ	ACTIVE
	CALL	ILPRT
	DB	'in',0
ACTIVE:
	CALL	ILPRT
	DB	'active',CR,LF,'Unused portion of buffer is ',0
	CALL	GETSPC
	CALL	ILPRT
	DB	' bytes',CR,LF,0
	CALL	XOFFMSG
	CALL	XONMSG
	CALL	SPDMSG
	CALL	CRDLYMSG
	CALL	CRLF
	JMP	XPRT
;
GETSPC:	CALL	GETMAX
	MOV	B,A
	LHLD	HLSAVE
	STC
	CMC
	MVI	A,0
	SBB	L
	MOV	L,A
	MOV	A,B
	SBB	H
	MOV	H,A
	JMP	DECOUT
;
;ADJUSTS LOOP COUNTERS FOR VARIOUS CLOCK SPEEDS
;
FIXCNT:	LDA	CLOCK
	CPI	1
	RZ
	PUSH	D
	PUSH	H
	POP	D
CNTMUL:	DAD	D
	DCR	A
	JNZ	CNTMUL
	POP	D
	RET
;
COMPLIST:
	DB	 6, 'S', 'R', 'T', 'E', 'H', 'L'
ILCOMP:
	INLNCOMP	;A LIB MACRO
INBUFF:
	INBUF		;A LIB MACRO
;
;IF ABOVE ROUTINE DOES NOT LET YOU EDIT IN A PROPER MANNER,
;THEN THE MACRO MAY BE SUBSTITUTED FOR THE FOLLOWING ROUTINE:
;
;INBUFF:
;	MVI	C,RDBUF
;	JMP	BDOSRT	;BUT BE CAREFUL OF CONTROL-C
;
CPMLINE:
	CMDLINE		;A LIB MACRO
DIRLST:
	DIRLIST		;A LIB MACRO
SENDTIM:
	SENDTIME	;A LIB MACRO
BAUDPRT:
	PRTBAUD		;A LIB MACRO
NFILFLG:
	DB	FALSE	;NORMALLY SET TO FALSE. ALLOWS WRITE TO..
;			;..MEMORY IN TERMINAL MODE.
OPTION:
	DB	0
;
OPTBL	EQU	$
;
ANSWFLG:
	DB	'A'
DISCFLG:
	DB	'D'
ORIGFLG:
	DB	'O'
QFLG:
	DB	'Q'
RSEEFLG:
	DB	'R'
SSEEFLG:
	DB	'S'
VSEEFLG:
	DB	'V'
TERMFLG:
	DB	'T'
LOCCHFLG:
	DB	'L'
EPARITY:
	DB	'0'	;EVEN PARITY SUB-OPTION
			;ONLY AVAILABLE IN 'S' AND 'R' MODES
OPARITY:
	DB	'1'	;ODD PARITY SUB-OPTION
			;ONLY AVAILABLE IN 'S' AND 'R' MODES
BATCHFLG:
	DB	'B'	;BATCH FLAG (WHY WAS THIS DISABLED IN EARLIER VERS?)
OPTBE	EQU	$

RESTROPT:		;MUST BE IN SAME ORDER AS TABLE ABOVE
	DB	'A','D','O','Q','R','S','V','T','L'
	DB	'0','1','B'
;
;THE NEXT 13 BYTES EQUAL THE NUMBER OF BYTES BETWEEN SECTNOB AND SECTNOE
RESTSN:
	DB	0,0,0,0,0,0
	DW	DBUF
	DB	0,0,0,0,0
;
SECTNOB   EQU	$	;START OF TABLE MARKER
RCVSNO:   DB	0	;\
SECTNO:   DW	0	; \
ERRCT:    DB	0	;  \
ERRCDE:   DB	0	;   \
EOFLG:    DB	0	;    \	13 BYTES BETWEEN TABLE MARKERS
SECPTR:   DW	DBUF	;    /
SECINBF:  DB	0	;   /
MAXEXT:   DB	0	;  /
RCNT:     DW	0 	; /
DATAFLG:  DB	0	;/
SECTNOE   EQU	$	;END OF TABLE MARKER
;
MODCTLB:  DB	07FH
UARTFLG:  DB	TRUE
UARTCTLB: DB	ANSWMOD	;(WAS PREVIOUSLY ORIGMOD)
SAVEFLG:  DB	FALSE
LASTBYT1: DB	0
LASTBYT2: DB	0
EXACFLG:  DB	0
ECHOFLG:  DB	FALSE
LOCFLG:	  DB	FALSE
CKSUMFLG: DB	TRUE
LISTFLG:  DB	FALSE
LISTMOR:  DB	FALSE
FSTFLG:	  DB	TRUE
FIRSTME:  DB	TRUE	;FIRST SOH RECEIVED SWITCH (ZERO AFTER 1ST SOH)
EXITFLG:  DB	TRUE
HLSAVE:	  DW	BOTTRAM
HLSAVE1:  DW	BOTTRAM
HLSAVE2:  DW	BOTTRAM
CMDBUF:	  DB	80H,0
	  DS	80H
DISKNO:	  DS	1
DISKSAV:  DS	1
SAVUSR:  DS	1
SENDFLG:  DS	1
NBSAVE:	  DS	2
BGNMS:	  DS	2
FILECT:	  DS	1
NAMECT:	  DS	1
ORIGSAV:  DS	1
FTYCNT:	  DS	1
          DS	100
STACK:	  DS	2
FCB3:	  DS	33
FCB4:	  DS	33
FCBBUF:	  DS	15
DBUF	  EQU	$	
NAMEBUF	  EQU	DBUF+(DBUFSIZ*1024)	;BUFFER FOR NAMES IN BATCH MODE.
;					;OVERFLOWS ABOVE PROGRAM CODE.
;
;	BDOS EQUATES
;
RDCON	EQU	1
WRCON	EQU	2
LSTOUT	EQU	5
PRINT	EQU	9
RDBUF	EQU	10
CONST	EQU	11
RESET	EQU	13
SELDSK	EQU	14
OPEN	EQU	15
CLOSE	EQU	16
SRCHF	EQU	17
SRCHN	EQU	18
ERASE	EQU	19
READ	EQU	20
WRITE	EQU	21
MAKE	EQU	22
REN	EQU	23
CURDSK	EQU	25
STDMA	EQU	26
USER	EQU	32
FILSIZ	EQU	35
BDOS	EQU	5
REIPL	EQU	0
FCB	EQU	5CH
FCBEXT	EQU	FCB+12
FCBSNO	EQU	FCB+32
FCBRNO	EQU	FCB+32
FCB2	EQU	6CH
;
LAST	END	100H
