;	TITLE	'CLINK - COMMUNICATIONS LINK FOR CP/M - V 3.0'
 
;;;	CLINK - COMMUNICATIONS LINK - VERSION 3.0
;
;	LAWRENCE E. HUGHES	OCTOBER, 1978
;
;	PATCHED 2/9/80 - CONFIG DISPLAY - DICK SMITH
;	KILLED SMITH'S BUGS OF 2/9/80 -7/12/81  -DON EKSTEDT
;
;	REVISION HISTORY
;
;	10/19	0.0	INITIAL VERSION - BASIC LINK FACILITY,
;			CONFIGURATION FILE IMPLEMENTED. SITE,
;			PHONE, BAUD, PARITY, DBITS, SBITS, MODE,
;			DUPLEX, AUTOLF AND CAPS DIRECTIVES.
;
;	10/21	1.0	'LOCAL COMMANDS' IMPLEMENTED. ESCAPE,
;			DEBUG, ERROR, LIST, RETURN AND ABORT
;			DIRECTIVES ADDED.
;
;	10/22	2.0	ASR FILE TRANSMISSION IMPLEMENTED.
;			GARBAGE, EXPAND, READ, CAPTURE, WRITE
;			DIRECTIVES ADDED.
;
;	10/23	2.1	SAVE, BREAK, RESET, HELP DIRECTIVES.
;
;	10/29	2.2	ANSWER MODE CHECKED OUT, REMESC ADDED
;
;	10/30	2.3	BUGS FIXED, DIR COMMAND ADDED, HELP
;			COMMAND EXPANDED.
;
;	11/04	2.4	VARIOUS BUGS FIXED
;
;	11/18	2.5	ANSWER MODE TIMEOUT
;
;	01/12	3.0	PROTOCOL FILE TRANSFERS.
;
;	CLINK IS A CP/M TRANSIENT PROGRAM WHICH ALLOWS THE USER
;	TO ESTABLISH A COMMUNICATIONS LINK TO A REMOTE DEVICE
;	(TYPICALLY A REMOTE COMPUTER). ALL I/O IS DONE VIA THE
;	BDOS OR BIOS ENTRY POINTS. THE ASSUMPTION IS MADE THAT
;	THE BAUD RATE OF THE CONSOLE DEVICE IS MUCH GREATER (2X
;	OR MORE) THAN THE SELECTED BAUD RATE OF THE MODEM. THIS
;	IS ESPECIALLY IMPORTANT IF AUTO LINE-FEED IS SELECTED.
;
;	CLINK EXPECTS AS INPUT A FILE WITH ONE OR MORE DIRECTIVES
;	(ONE PER LINE) WHICH ALLOW THE USER TO 'PROGRAM' THE 
;	VARIOUS CONFIGURATION OPTIONS WHICH MIGHT VARY FROM DEVICE
;	TO DEVICE. IF A GIVEN OPTION IS NOT SPECIFIED, THE DEFAULT
;	VALUE WILL BE USED. THE SYNTAX OF THESE DIRECTIVES IS AS
;	FOLLOWS:
;
;		<KEYWORD> <DELIM> <VALUE>
;
;	WHERE <DELIM> IS ONE OR MORE SPACES AND/OR TABS, <KEYWORD>
;	IS ONE OF THE WORDS IN THE FOLLOWING TABLE, AND <VALUE> IS
;	ONE OF THE LEGAL VALUES SPECIFIED AFTER EACH KEYWORD.
;
;	KEYWD	POSSIBLE VALUE(S)		DEFAULT
;
;	SITE	(UP TO 80 ALPHANUMERIC CHARS)	NONE
;	PHONE	(UP TO 20 CHARACTERS)		NONE
;	BAUD	110,300				300
;	PARITY	EVEN,ODD,NONE			EVEN
;	DBITS	7,8				7
;	SBITS	1,2				1
;	MODE	ORIGINATE,ANSWER		ORIGINATE
;	DUPLEX	FULL,HALF			FULL
;	AUTOLF	ON,OFF				OFF
;	CAPS	ON,OFF				OFF
;	ESCAPE	(HEX VALUE, 00H=NONE)		1BH
;	REMESC	(HEX VALUE, 00H=NONE)		00H
;	DEBUG	ON,OFF				OFF
;	ERROR	SUMMARY,(HEX VALUE, 00H=NONE)	00H
;	GARBAGE	(HEX VALUE, 00H=NONE)		00H
;	EXPAND	ON,OFF				OFF
;	BREAK	(HEX VALUE, 00H=NONE)		00H
;
;	'SITE' IS USED ONLY BY THE LIST COMMAND, AND IS OPTIONAL.
;
;	THE 'PHONE' NUMBER MAY CONTAIN DIGITS, PARENTHESIS, DASHES,
;	BLANKS, AND/OR ASTERISKS. AN ASTERISK WILL CAUSE A ONE SECOND
;	PAUSE DURING DIALING. IF NO NUMBER IS SPECIFIED, IT IS ASSUMED
;	THAT A CONNECTION ALREADY EXISTS, AND THE DIALING CODE WILL BE
;	SKIPPED.
;
;	'BAUD' SELECTS BAUD RATE, EITHER 110 OR 300
;
;	'PARITY' MAY BE SPECIFIED AS ANY OF THE FOLLOWING:
;		EVEN - PARITY BIT CHOSEN TO GIVE EVEN # OF 'ON' BITS
;		ODD  - PARITY BIT CHOSEN TO GIVE ODD # OF 'ON' BITS
;		NONE - INHIBIT THE PARITY BIT ALTOGETHER
;
;	'DBITS' SELECTS THE NUMBER OF DATA BITS (7 OR 8)
;
;	'SBITS' SELECTS THE NUMBER OF STOP BITS (1 OR 2)
;
;	NOTE THAT THE TOTAL NUMBER OF BITS IN EACH ASYNCHRONOUS CHAR-
;	ACTER TO OR FROM THE MODEM WILL BE DBITS+SBITS+2 IF PARITY IS
;	SELECTED, OTHERWISE DBITS+SBITS+1 (START BIT ALWAYS PRESENT).
;
;	'MODE' MAY BE USED TO SELECT CARRIER FREQUENCY. THIS SHOULD
;	NORMALLY BE 'ORIGINATE', BUT MAY BE CHANGED TO 'ANSWER' TO
;	ALLOW LINKING TO A REMOTE MODEM RUNNING IN 'ORIGINATE' MODE
;	(SUCH AS ANOTHER CP/M USER RUNNING CLINK).
;
;	'DUPLEX' MAY BE SPECIFIED AS EITHER OF THE FOLLOWING:
;		FULL - DO NOT ECHO CONSOLE CHARACTERS LOCALLY
;		HALF - ECHO CONSOLE CHARACTERS LOCALLY
;
;	IF THE 'AUTOLF' IS SET TO 'ON', A LINE FEED CHARACTER
;	WILL BE SENT TO THE CONSOLE FOLLOWING ANY CARRIAGE RETURN.
;
;	THE 'CAPS' OPTION MAY BE USED TO TURN ON OR OFF THE AUTOMATIC
;	TRANSLATION OF LOWER CASE LETTERS (TO UPPER CASE) IN BOTH
;	DIRECTIONS (TO AND FROM MODEM).
;
;	'ESCAPE' ALLOWS THE USER TO SPECIFY WHICH (IF ANY) ASCII CODE
;	WILL BE USED TO TRAP INTO THE 'LOCAL COMMAND' MODE. THE VALUE
;	00H MEANS ALL CODES WILL BE TRANSMITTED TRANSPARENTLY. ANYTIME
;	THE SELECTED ESCAPE CODE IS TYPED (FROM THE CONSOLE), A LOCAL
;	PROMPT ( -> ) WILL BE DISPLAYED, AFTER WHICH A COMMAND MAY BE
;	ENTERED (ANY DIRECTIVE, PLUS 'ABORT' AND 'RETURN' FOR EXITING
;	TO CP/M WITH AND WITHOUT DISCONNECT, RESPECTIVELY). WHEN A CR
;	IS TYPED, THAT LOCAL COMMAND WILL BE EXECUTED AND CONTROL WILL
;	BE RETURNED TO THE MAIN LINK.
;
;	'REMESC' ALLOWS THE USER TO SPECIFY WHICH (IF ANY) ASCII CODE
;	WILL BE USED TO LET THE REMOTE USER TRAP INTO THE 'LOCAL
;	COMMAND' MODE (FROM HIS REMOTE TERMINAL). OTHERWISE SAME AS
;	THE 'ESCAPE' FUNCTION. NOTE THAT THIS FUNCTION IS CURRENLTY 
;	RESTRICTED TO ALLOWING AN ORIGINATE SYSTEM TO GENERATE A
;	REMOTE COMMAND, AND AN ANSWER SYSTEM TO RESPOND TO IT.
;
;	'DEBUG' MAY BE USED TO SWITCH ON AND OFF THE OPTION OF HAVING
;	ALL BYTES READ FROM THE MODEM BE DISPLAYED IN HEX, 16 PER LINE,
;	FOR PURPOSES OF DEBUGGING PROTOCOLS, DETERMINING LINE CHARAC-
;	TERISTICS, ETC.
;
;	'ERROR' MAY BE USED TO REQUEST A SUMMARY OF TRANSMISSION
;	ERRORS (PARITY, OVERRUN AND FRAME) BY USING THE PARAMETER
;	'SUMMARY'. BY SPECIFIYING A HEX VALUE, THE CORRESPONDING
;	ASCII CHARACTER WILL BE OUTPUT IN PLACE OF ANY CHARACTER
;	RECEIVED IN ERROR. THE VALUE 00H IS SPECIAL CASED TO MEAN
;	'OUTPUT THE RECEIVED CHARACTER ANYWAY'. THE ERROR COUNTS
;	WILL BE MAINTAINED REGARDLESS.
;
;	'GARBAGE' MAY BE USED TO SPECIFY THE NUMBER OF GARBAGE CHARS.
;	TO IGNORE AFTER ANY LINE FEED IS SENT FROM THE HOST. THIS IS
;	MOST USEFUL IN CONJUNCTION WITH THE 'SEND' COMMAND. NOTE THAT
;	THE 'DEBUG' OPTION MAY BE USED TO DETERMINE WHAT CONSTANT TO
;	USE IN THIS DIRECTIVE.
;
;	'LIST' MAY BE USED TO CAUSE THE CURRENT CONFIGURATION DETAILS
;	TO BE LISTED TO THE CONSOLE. IT IS PRIMARILY USEFUL FROM WITHIN
;	THE LINK (VIA ESCAPE CODE), BUT MAY BE USED IN A CONFIG. FILE.
;
;	'EXPAND' MAY BE USED TO SELECT OR DESELECT THE OPTION OF
;	EXPANDING TABS TO BLANKS DURING A 'SEND' OPERATION. IT DOES
;	NOT AFFECT TABS ANYWHERE ELSE.
;
;	'BREAK' MAY BE USED TO SPECIFY ANY ASCII CODE TO BE USED AS
;	A TRIGGER TO BREAK THE COMMUNICATIONS LINE FOR 150 MS. MANY
;	TIMESHARING SERVICES USE THIS CONDITION AS IF IT WERE A
;	CHARACTER, SO PROVISIONS HAVE BEEN MADE TO GENERATE IT.
;
;	IT IS SUGGESTED THAT THE USER DETERMINE THE LINE CHARACTER-
;	ISTICS FOR EACH POSSIBLE REMOTE SITE HE WILL BE DIALING INTO,
;	AND CREATE A SEPARATE CONFIGURATION FILE FOR EACH. A TYPICAL
;	FILE MIGHT BE AS FOLLOWS:
;
;		SITE	FSU CYBER 74, 300 BAUD ROTARY
;		PHONE	1-904-644-6566
;		PARITY	NONE
;		DBITS	8
;		ESCAPE	18H		(CTRL-X)
;
;	ALL UNSPECIFIED OPTIONS WILL DEFAULT TO THE VALUES LISTED IN
;	THE TABLE. IF THIS INFORMATION HAD BEEN WRITTEN TO THE FILE
;	'FSU74.CON', ONE COULD DIAL INTO THAT SITE WITH THE COMMAND:
;
;		CLINK FSU74.CON
;
;	IN ADDITION TO THE ABOVE DIRECTIVES, THE FOLLOWING DIRECTIVES
;	MAY BE USED FROM WITHIN THE LINK, VIA THE ESCAPE CODE:
;
;	RETURN			RETURN TO CP/M WITHOUT DISCONNECT
;	ABORT			DISCONNECT AND RETURN TO CP/M
;	READ	D:FN.FT		READ SPECIFIED FILE TO REMOTE HOST
;	CAPTURE			CAPTURE MODEM INPUT IN MEMORY BUFFER
;	WRITE	D:FN.FT		WRITE MEMORY BUFFER TO DISK FILE
;	SEND	D:FN.FT		SEND FILE USING PROTOCOL
;	RECV	D:FN.FT		RECEIVE FILE USING PROTOCOL
;	BLOCK	N		SET BLOCK SIZE TO N PAGES (SEND)
;	LIST			LIST CURRENT CONFIG. TO CONSOLE
;	SAVE	D:FN.FT		WRITE CURRENT CONFIG. TO DISK FILE
;	RESET			RESET ERROR COUNTS
;	DIR	AFN		SAME AS CP/M DIR COMMAND
;	HELP			REQUEST LIST OF ALL LOCAL COMMANDS
;
;	'READ' MAY BE USED TO SEND A FILE TO THE REMOTE DEVICE AS
;	IF IT WERE COMING FROM THE CONSOLE KEYBOARD. IF RUNNING IN
;	HALF DUPLEX, THE BYTES WILL JUST BE WRITTEN AS FAST AS THE
;	MODEM WILL ACCEPT THEM. IF RUNNING IN FUL DUPLEX, THE BYTES
;	ECHOED BY THE REMOTE DEVICE WILL BE COMPARED AGAINST THE
;	BYTES SENT, AND AN ERROR COUNT MAINTAINED. WHEN EOF IS READ
;	ON THE SPECIFIED FILE, AN ERROR SUMMARY WILL BE PRINTED (IN
;	FULL DUPLEX ONLY) A BELL WILL BE WRITTEN TO THE CONSOLE, AND
;	CONTROL WILL BE RETURNED TO THE MAIN LOOP.
;
;	'CAPTURE' MAY BE USED TO RESET THE MEMORY BUFFER POINTER AND
;	SET A FLAG SO THAT ALL BYTES INPUT FROM THE MODEM WILL ALSO
;	BE STORED SEQUENTIALLY IN MEMORY.
;
;	'WRITE' MAY BE USED TO WRITE 'CAPTURED' DATA TO A DISK FILE.
;	NOTE THAT THIS ALSO CLEARS THE 'CAPTURE' FLAG.
;
;	'SEND' MAY BE USED TO TRANSMIT ANY CP/M FILE, INCLUDING .COM
;	FILES (IF DATA PATH IS 8 BITS WIDE), USING AN ASYNCHRONOUS
;	PROTOCOL WHICH HAS FAIRLY ELABORATE ERROR DETECTION AND AUTO
;	RECOVERY (VIA RE-TRANSMISSION). AT PRESENT THIS WILL WORK
;	ONLY WITH ANOTHER CLINK 3.0 SYSTEM WHICH IS EXECUTING A RECV.
;
;	'RECV' MAY BE USED TO RECEIVE A FILE (DIRECTLY TO DISK) WHICH
;	IS BEING TRANSMITTED BY A CLINK 3.0 SYSTEM DOING A SEND.
;
;	'BLOCK' MAY BE USED TO SET THE BLOCK (MESSAGE) SIZE IN 'SEND',
;	IN TERMS OF 256 BYTE PAGES. DEFAULT VALUE IS 4 (1024 BYTES).
;
;	'LIST' MAY BE USED TO VIEW THE CURRENT CONFIGURATION DETAILS.
;
;	'SAVE' MAY BE USED TO WRITE THE CURRENT CONFIGURATION DETAILS
;	TO THE SPECIFIED DISK FILE, WHICH MAY LATER BE USED AS A
;	CONFIGURATION INPUT FILE.
;
;	'DIR' MAY BE USED TO DETERMINE WHICH FILES ARE CURRENTLY
;	ON ANY MOUNTED DISKETTE. THE RULES FOR THE PARAMETER ARE
;	THE SAME AS IN THE STANDARD CP/M DIR COMMAND.
;
;	'HELP' MAY BE USED AT ANY TIME TO REVIEW AVAILABLE COMMANDS
 
 
;	SYMBOL DEFINITIONS
 
ENTRY	EQU	0005H		;BDOS ENTRY POINT
 
RSFC	EQU	10		;READ STRING
OFFC	EQU	15		;OPEN FILE
CFFC	EQU	16		;CLOSE FILE
SFFC	EQU	17		;SEACH FIRST
SNFC	EQU	18		;SEARCH NEXT
DFFC	EQU	19		;DELETE FILE
RRFC	EQU	20		;READ RECORD
WRFC	EQU	21		;WRITE RECORD
MFFC	EQU	22		;MAKE FILE
SAFC	EQU	26		;SET ADDRESS
 
TFCB	EQU	005CH		;DEFAULT FILE CONTROL BLOCK
 
FN	EQU	01		;FILE NAME OFFSET
FT	EQU	09		;FILE TYPE OFFSET
EX	EQU	12		;EXTENT OFFSET
NR	EQU	32		;NEXT RECORD OFFSET
 
MDATA	EQU	80H		;MODEM DATA PORT
MSTAT	EQU	81H		;MODEM STATUS PORT
MCTRL	EQU	82H		;MODEM CONTROL PORT
 
;	MODEM STATUS INPUT PORT DEFINITIONS
 
RI	EQU	80H		;RING INDICATE
CD	EQU	40H		;CARRIER DETECT
OE	EQU	10H		;OVERRUN ERROR
FE	EQU	08H		;FRAMING ERROR
PE	EQU	04H		;PARITY ERROR
TRE	EQU	02H		;TRANSMIT REG. EMPTY
RRF	EQU	01H		;RECEIVER REG. FULL
 
;	MODEM STATUS OUTPUT PORT DEFINITIONS
 
PI	EQU	10H		;PARITY INHIBIT
SBS	EQU	08H		;STOP BIT SELECT
LS2	EQU	04H		;LENGTH SELECT 2
LS1	EQU	02H		;LENGTH SELECT 1
EPE	EQU	01H		;EVEN PARITY ENABLE
 
;	MODEM CONTROL OUTPUT PORT DEFINITIONS
 
OH	EQU	80H		;OFF HOOK
RID	EQU	20H		;RING INDICATE DISABLE
ST	EQU	10H		;SELF TEST
BK	EQU	08H		;BREAK
MS	EQU	04H		;MODE SELECT (1 = ORIGINATE)
TXE	EQU	02H		;TRANSMIT ENABLE
BRS	EQU	01H		;BIT RATE SELECT
 
;	ASCII CHARACTERS
 
NULL	EQU	00H		;NULL CHARACTER
SOH	EQU	01H		;START OF HEADER
STX	EQU	02H		;START OF TEXT
ETX	EQU	03H		;END OF TEXT
EOT	EQU	04H		;END OF TRANSMISSION
ENQ	EQU	05H		;ENQUIRE
ACK	EQU	06H		;ACKNOWLEDGE
BEL	EQU	07H		;BELL
BS	EQU	08H		;BACKSPACE
TAB	EQU	09H		;HORIZONTAL TAB
LF	EQU	0AH		;LINE FEED
CR	EQU	0DH		;CARRIAGE RETURN
DLE	EQU	10H		;DATA LINK ESCAPE
NAK	EQU	15H		;NEGATIVE ACKNOWLEDGE
SYN	EQU	16H		;SYNCH
ETB	EQU	17H		;END OF TEXT BLOCK
CAN	EQU	18H		;CANCEL
ESC	EQU	19H		;ESCAPE
 
CRCPOL	EQU	8005H		;CRC-16 POLYNOMIAL
 
	ORG	100H
CLINK:	LXI	H,0		;SAVE ENTRY STACK POINTER
	DAD	SP
	SHLD	OLDSP
	LXI	SP,STACK+128	;SETUP LOCAL STACK
	LHLD	ENTRY+1		;HL = FWA OF BDOS
	MOV	A,L		;ROUND DOWN TO NEAREST MULT. OF 128
	ANI	80H
	MOV	L,A
	SHLD	MAXADR		;SAVE AS MAX. ADDRESS
	LXI	D,-1024		;SUBTRACT 1024
	DAD	D
	SHLD	CCPADR		;SAVE AS CCP ADDRESS
	XRA	A		;CLEAR CCP OVERWRITE FLAG
	STA	CCPF
	CALL	CJV		;CREATE BIOS JUMP VECTOR
	XRA	A		;CLEAR CONTROL PORT BYTES
	STA	CR1
	STA	CR2
	MVI	A,IBUFL		;INITIALIZE IBUF
	STA	IBUF+0
	XRA	A		;DEFAULT TO NO SITE, NO PHONE
	STA	SITEL
	STA	PHONEL
	MVI	B,LS2+EPE	;EVEN PARITY, 7 DATA BITS, 1 STOP BIT
	CALL	CR1ON
	MVI	B,MS+BRS	;ORIGINATE, 300 BAUD
	IN	MSTAT		;IF INCOMING CARRIER IS ON...
	ANI	CD
	JZ	$+5
	MVI	B,OH+MS+BRS+TXE	;...THEN LEAVE OUR CARRIER ON
	CALL	CR2ON
	MVI	A,'O'
	STA	MODE
	XRA	A
	STA	COF		;DIRECT CONSOLE OUTPUT TO CONSOLE
	STA	ECHO		;DEFAULT TO FULL DUPLEX
	STA	AUTOLF		;DEFAULT TO NO AUTO LINE FEED
	STA	CAPS		;DEFAULT TO UPPER/LOWER CASE
	STA	DEBUG		;DEFAULT TO DEBUG OFF
	STA	ERROR		;DEFAULT TO NO ERROR CODE
	STA	GARBAGE		;DEFAULT TO NO GARBAGE CHARS.
	STA	EXPAND		;DEFAULT TO NO TAB EXPANSION
	STA	CAPTURE		;CLEAR CAPTURE FLAG
	STA	BREAK		;DEFAULT TO NO 'BREAK' TRIGGER
	MVI	A,11H		;DEFAULT TO CNTL Q REMESC
	STA	REMESC
	MVI	A,1BH		;DEFAULT TO ESCAPE CODE OF ESC
	STA	ESCAPE
	MVI	A,4		;DEFAULT TO 4 PAGE MESSAGES
	STA	BLKSZ
	LXI	H,0		;CLEAR ERROR COUNTS
	SHLD	PERR
	SHLD	OERR
	SHLD	FERR
	LXI	H,0FFFFH	;SETUP FOR INFINITE TIMEOUT
	SHLD	TIME
	LXI	H,MBUF		;CLEAR MEMORY BUFFER
	SHLD	MBUFP
	LXI	H,MSG0		;PRINT 'CLINK VX.X'
	CALL	WASC
	LDA	TFCB+FN		;JUMP IF NO FILE NAME
	CPI	' '
	JZ	CLINKH
	LXI	D,TFCB		;OPEN USER'S CONFIG. FILE
	CALL	OPEN
	CPI	255		;JUMP IF OK
	JNZ	CLINK0
	LXI	H,MSG1		;PRINT 'FILE NOT FOUND'
	CALL	WASC
	JMP	CLINKX		;EXIT
CLINK0:	XRA	A		;'REWIND' FILE
	STA	TFCB+NR
	STA	DIBUFC		;RESET DISK INPUT BUFFER
	CALL	WEOLC
CLINK1:	CALL	RASS		;READ LINE FROM FILE
	JC	CLINK2		;JUMP ON END OF FILE
	CALL	EASC		;ECHO ASCII STRING TO CONSOLE
	CALL	PCD		;PROCESS CONFIGURATION DIRECTIVE
	JC	DIRERR
	CNC 	MCD		;IF OK SEE IF MORE CD'S.
	CALL	PCD		;YES SO PROCESS
	JNC	CLINK1		;LOOP IF OK
DIRERR:	LXI	H,MSG2		;PRINT 'DIRECTIVE ERROR'
	CALL	WASC
	JMP	CLINKX		;EXIT

;

MCD:	CALL	GNC		;GET THE NEXT CHAR.
	JC	CLINK1		;CARRY SET SO NO MORE CHARS.
	CPI	' '		;SPACE ?
	JNZ	MCD		;NO SO LOOP
MCD1:	CALL	SNB		;YES SO GET RID OF SPACES
	JC	CLINK1		;OUT OF CHARS
	LHLD	IBUFP		;NOW WE GOT A CHAR.
	DCX	H		;SO MOVE POINTER BACK
	SHLD 	IBUFP		;AND STORE IT
	LDA	IBUFC		;GET THE COUNTER
	INR	A		;BACK IT UP TOO
	STA	IBUFC		;AND STORE IT
	RET			;RETURN SO WE CAN PCD AGAIN

CLINK2:	LXI	D,TFCB		;CLOSE CONFIG. FILE
	CALL	CLOSE
	CALL	WEOLC
CLINKH:	LXI	H,MSG14		;PRINT 'ENTER DIRECTIVES'
	CALL	WASC
CLINKF:	LXI	H,MSG10		;PRINT PROMPT
	CALL	WASC
	CALL	RASC
	CALL	WEOLC
	LDA	IBUFC
	ORA	A
	JZ	CLINKG
	CALL	PCD
	JNC	CLINKF
MODERR: LXI	H,MSG2		;PRINT 'DIRECTIVE ERROR'
	CALL	WASC
	JMP	CLINKF
CLINKG:	LDA	MODE		;JUMP IF ORIGINATE MODE
	CPI	'O'
	JZ	CLINKB
CLINK9:	IN	MSTAT		;WATCH FOR RING INDICATE
	ANI	RI
	JZ	CLINKM		;JUMP IF ACTIVE
	CALL	CCA		;CHECK FOR ESCAPE FROM CONSOLE
	JNC	CLINK9
	MOV	B,A
	LDA	ESCAPE
	CMP	B
	JZ	CLINKH		;JUMP IF PRESENT
	JMP	CLINK9
CLINKM:	MVI	B,OH+TXE	;GO OFF-HOOK AND BRING UP CARRIER
	CALL	CR2ON
	LXI	B,600
CLINKA:	IN	MSTAT		;CHECK FOR INCOMING CARRIER
	ANI	CD
	JNZ	CLINCA		;CARRIER DETECTED
	CALL	WAIT50
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	CLINKA
	LXI	H,MSG3		;NO CARRIER DETECTED
	CALL	WASC
	JMP	EXIT
CLINCA	MVI	A,1		;DIRECT CONSOLE OUTPUT TO MODEM
	STA	COF
	LXI	H,MSG0		;PRINT 'CLINK VX.X'
	CALL	WASC
	CALL	WEOLC
	LXI	H,KWTAB+0*10	;PRINT 'SITE    '
	CALL	W8CC
	LXI	H,SITE		;PRINT SITE NAME
	LDA	SITEL
	MOV	B,A
	INR	B
XXX1:	DCR	B
	JZ	XXX2
	MOV	A,M
	INX	H
	CALL	WACC
	JMP	XXX1
XXX2:	CALL	WEOLC
	LXI	H,KWTAB+25*10	;PRINT 'REMESC  '
	CALL	W8CC
	LDA	REMESC		;PRINT REMOTE ESCAPE CODE
	CALL	WHBC
	MVI	A,'H'
	CALL	WACC
	CALL	WEOLC
	CALL	WEOLC
	XRA	A		;REDIRECT CONSOLE OUTPUT TO CONSOLE
	STA	COF
	JMP	CLINK5		;JUMP INTO MAIN LOOP
CLINKB:	IN	MSTAT		;CHECK FOR CARRIER
	ANI	CD
	JZ	CLINK8		;JUMP IF NOT PRESENT
	LXI	H,MSG9		;PRINT 'CARRIER PRESENT, LINK RESUMED'
	CALL	WASC
	JMP	CLINK5
CLINK8:	MVI	B,OH		;GO OFF HOOK
	CALL	CR2ON
	MVI	B,40		;DELAY FOR 2 SECONDS
	CALL	WAIT50
	DCR	B
	JNZ	$-4
	CALL	DIAL		;DIAL NUMBER, IF PRESENT
	LXI	B,600		;SETUP FOR 30 SECOND TIMEOUT
CLINK3:	IN	MSTAT		;READ MODEM STATUS PORT
	ANI	CD		;BRANCH ON CARRIER DETECT
	JNZ	CLINK4
	CALL	WAIT50		;PAUSE FOR 50 MS
	DCX	B		;DECREMENT TIMEOUT COUNT
	MOV	A,B		;LOOP UNTIL ZERO
	ORA	C
	JNZ	CLINK3
	LXI	H,MSG3		;PRINT 'NO CARRIER DETECTED'
	CALL	WASC
	MVI	B,OH+TXE	;DISCONNECT
	CALL	CR2OFF
	JMP	CLINKX		;EXIT
CLINK4:	MVI	B,TXE		;TURN ON OUTGOING CARRIER
	CALL	CR2ON
	MVI	A,BEL		;RING BELL ON CONSOLE
	CALL	WACC
	CALL	WEOLC		;WRITE END OF LINE TO CONSOLE
CLINK5:	CALL	CCA		;CHECK FOR CONSOLE ACTIVITY
	JNC	CLINK6		;JUMP IF NONE
	STA	CCHAR
	LDA	BREAK		;IF 'BREAK' TRIGGER, SEND BREAK
	ORA	A
	JZ	CLINKE
	LXI	H,CCHAR
	CMP	M
	JNZ	CLINKE
	CALL	SBRK
	JMP	CLINK6
CLINKE:	LDA	ESCAPE		;JUMP IF NO ESCAPE CODE
	ORA	A
	JZ	CLINKC
	LXI	H,CCHAR
	CMP	M
	JNZ	CLINKC
	LXI	H,MSG10		;PRINT LOCAL PROMPT
	CALL	WASC
	CALL	RASC		;READ STRING FROM CONSOLE
	CALL	WEOLC
	CALL	PCD		;PROCESS DIRECTIVE
	JNC	CLINK6		;JUMP IF OK
	LXI	H,MSG2		;PRINT 'DIRECTIVE ERROR'
	CALL	WASC
	JMP	CLINK6		;CONTINUE
CLINKC:	LDA	CAPS		;CONVERT LOWER CASE IF CAPS LOCK ON
	ORA	A
	LDA	CCHAR
	CNZ	CLC
	OUT	MDATA		;WRITE CHAR TO MODEM
	LDA	ECHO		;JUMP IF FULL DUPLEX
	ORA	A
	JZ	CLINKI
	LDA	CCHAR		;ECHO CHARACTER TO CONSOLE
	CALL	WACC
CLINKI:	LDA	MODE		;JUMP IF ORIGINATE MODE
	CPI	'O'
	JZ	CLINK6
	LDA	CCHAR
	CPI	CR		;JUMP IF CHAR. NOT CR
	JNZ	CLINK6
	MVI	A,LF		;SEND A LINE FEED
	CALL	WACM
	CALL	WACC
CLINK6:	IN	MSTAT		;CHECK FOR MODEM RDA
	ANI	RRF
	JZ	CLINK7		;JUMP IF NONE
	IN	MDATA		;READ CHARACTER
	STA	MCHAR
	LDA	MODE		;JUMP IF WE'RE NOT IN ANSWER MODE
	CPI	'A'
	JNZ	CLINKL
	LDA	REMESC
	ORA	A
	JZ	CLINKL
	LXI	H,MCHAR
	CMP	M
	JNZ	CLINKL
	MVI	A,1		;REDIRECT CONSOLE OUTPUT TO MODEM
	STA	COF
	LXI	H,MSG10		;PRINT LOCAL PROMPT
	CALL	WASC
	CALL	RASM		;READ RESPONSE INTO IBUF
	CALL	WEOLC
	CALL	PCD		;PROCESS DIRECTIVE
	JNC	CLINKK		;JUMP IF OK
	LXI	H,MSG2		;PRINT 'DIRECTIVE ERROR'
	CALL	WASC
CLINKK:	MVI	A,0		;REDIRECT CONSOLE OUTPUT TO CONSOLE
	STA	COF
	JMP	CLINK5		;DO NOT ECHO REMESC CHAR
CLINKL:	LDA	MCHAR		;RESTORE MODEM CHAR
	CALL	CAPT		;CAPTURE DATA IF FLAG SET
	CALL	ERRCK		;CHECK FOR ERRORS
	LDA	MODE		;JUMP IF ORIGINATE MODE
	CPI	'O'
	JZ	CLINKJ
	LDA	MCHAR
	CALL	WACM		;ECHO CHARACTER TO REMOTE USER
	ANI	7FH
	CPI	CR		;JUMP IF NOT CARRIAGE RETURN
	JNZ	CLINKJ
	MVI	A,LF		;WRITE LINE FEED TO REMOTE USER
	CALL	WACM
	CALL	WACC		;ECHO TO LOCAL TERMINAL TOO
	CALL	CAPT		;CAPTURE GENERATED LINE FEED
CLINKJ:	LDA	DEBUG		;JUMP IF DEBUG NOT ON
	ORA	A
	JZ	CLINKD
	LDA	MCHAR
	CALL	WHBC		;WRITE BYTE TO CONSOLE IN HEX
	MVI	A,' '		;PRINT ONE SPACE
	CALL	WACC
	LDA	DEBUGC		;INCREMENT DEBUG COUNT
	INR	A
	STA	DEBUGC
	CPI	16		;CONTINUE IF DEBUGC < 16
	JC	CLINK7
	XRA	A		;RESET DEBUGC
	STA	DEBUGC
	CALL	WEOLC		;WRITE END OF LINE TO CONSOLE
	JMP	CLINK7		;CONTINUE
CLINKD:	LDA	CAPS		;CONVERT LOWER CASE IF CAPS LOCK ON
	ORA	A
	LDA	MCHAR
	CNZ	CLC
	CALL	WACC		;WRITE TO CONSOLE
	ANI	7FH		;JUMP IF NOT CARRAIGE RETURN
	CPI	CR
	JNZ	CLINK7
	LDA	AUTOLF		;JUMP IF AUTOLF NOT SET
	ORA	A
	JZ	CLINK7
	MVI	A,LF		;WRITE LINEFEED TO CONSOLE
	CALL	WACC
CLINK7:	IN	MSTAT		;CHECK INCOMING CARRIER
	ANI	CD
	JNZ	CLINK5		;LOOP IF STILL PRESENT
	CALL	WEOLC
	LXI	H,MSG4		;PRINT 'CARRIER LOST'
	CALL	WASC
EXIT:	MVI	B,OH+TXE	;... ELSE DISCONNECT
	CALL	CR2OFF
	LDA	MODE		;IF MODE = ANSWER,
	CPI	'A'
	JZ	CLINK9		;... THEN GO BACK TO IDLE STATE
CLINKX:	LDA	CCPF		;IF CCP OVERWRITE FLAG SET...
	ORA	A
	JNZ	0000H		;... THEN RELOAD CP/M
	LHLD	OLDSP		;ELSE JUST JUMP BACK INTO CCP
	SPHL
	RET			;RETURN TO CP/M
 
;;	DIAL - DIAL SPECIFIED PHONE NUMBER
;
;	ENTRY CONDITIONS
;
;		PHONEL	LENGTH OF PHONE NUMBER STRING
;
;		PHONE	PHONE NUMBER STRING
 
DIAL:	LDA	PHONEL		;RETURN IF STRING EMPTY
	ORA	A
	RZ
	LXI	H,MSG5		;PRINT 'NOW DIALING '
	CALL	WASC
	LXI	H,PHONE		;POINT TO PHONE NUMBER STRING
	LDA	PHONEL
	MOV	C,A
DIAL1:	MOV	A,M		;FETCH NEXT CHARACTER OF NUMBER
	INX	H
	CALL	WACC		;WRITE DIGIT TO CONSOLE
	CPI	'*'		;JUMP IF NOT ASTERISK
	JNZ	DIAL2
	MVI	B,20		;PAUSE FOR 1 SECOND
	CALL	WAIT50
	DCR	B
	JNZ	$-4
DIAL2:	SUI	'0'		;CONVERT, IGNORE NON-NUMERICS
	JC	DIAL4
	CPI	10
	JNC	DIAL4
	ORA	A		;JUMP IF NON-ZERO DIGIT
	JNZ	DIAL3
	MVI	A,10		;'0' REQUIRES 10 CLICKS
DIAL3:	MVI	B,OH		;GO BACK ON-HOOK
	CALL	CR2OFF
	CALL	WAIT50		;PAUSE 50 MS
	MVI	B,OH		;GO OFF-HOOK AGAIN
	CALL	CR2ON
	CALL	WAIT50		;PAUSE 50 MS
	DCR	A		;DECREMENT CLICK COUNT
	JNZ	DIAL3		;LOOP UNTIL ZERO
	MVI	B,10		;PAUSE FOR 500 MS
	CALL	WAIT50
	DCR	B
	JNZ	$-4
DIAL4:	DCR	C		;DECREMENT DIGIT COUNT
	JNZ	DIAL1		;LOOP UNTIL ZERO
	CALL	WEOLC		;WRITE END OF LINE TO CONSOLE
	RET			;EXIT
 
;;	CAPT - CAPTURE DATA IF FLAG SET
;
 
CAPT:	ORA	A		;DO NOT CAPTURE NULLS
	RZ
	PUSH	H
	PUSH	PSW
	LDA	CAPTURE		;EXIT IF FLAG NOT SET
	ORA	A
	JZ	CAPT1
	POP	PSW
	PUSH	PSW
	LHLD	MBUFP		;HL = MEMORY BUFFER POINTER
	MOV	M,A		;SAVE BYTE IN MEMORY BUFFER
	INX	H		;INCREMENT POINTER
	SHLD	MBUFP
	CMA
	OUT	0FFH
	CMA
	LDA	CCPADR+1	;JUMP IF MBUFP < CCPADR
	CMP	H
	JNC	CAPT1
	LDA	CCPADR
	CMP	L
	JNC	CAPT1
	MVI	A,1		;SET 'CCP OVERWRITE' FLAG
	STA	CCPF
	LDA	MAXADR+1	;RETURN IF MBUFP < MAXADR
	CMP	H
	JNC	CAPT1
	LDA	MAXADR
	CMP	L
	JNC	CAPT1
	LXI	H,MSG19		;PRINT 'MEMORY OVERFLOW'
	CALL	WASC
	XRA	A		;TURN OFF CAPTURE FLAG
	STA	CAPTURE
CAPT1:	POP	PSW
	POP	H
	RET
 
;;	ERRCK - ERROR CHECK
;
 
ERRCK:	PUSH	H
	PUSH	PSW
	IN	MSTAT		;CHECK FOR PARITY ERROR
	ANI	PE
	JZ	ERRCK1		;JUMP IF NOT PRESENT
	LHLD	PERR		;INCREMENT PARITY ERROR COUNT
	INX	H
	SHLD	PERR
	JMP	ERRCK4
ERRCK1:	IN	MSTAT		;JUMP IF NO OVERRUN ERROR
	ANI	OE
	JZ	ERRCK2
	LHLD	OERR		;INCREMENT OVERRUN ERROR COUNT
	INX	H
	SHLD	OERR
	JMP	ERRCK4
ERRCK2:	IN	MSTAT		;JUMP IF NO FRAME ERROR
	ANI	FE
	JZ	ERRCK5
	LHLD	FERR		;INCREMENT FRAME ERROR COUNT
	INX	H
	SHLD	FERR
ERRCK4:	LDA	ERROR		;CHECK ERROR CODE
	ORA	A
	JZ	ERRCK5		;JUMP IF 00H
	POP	H		;DISCARD TOP OF STACK (PSW/A)
	POP	H		;RESTORE REAL HL
	RET
ERRCK5:	POP	PSW		;RESTORE CHARACTER
	POP	H		;RESTORE HL
	RET
 
;;	SBRK - SEND BREAK
;
 
SBRK:	PUSH	B
	MVI	B,BK		;OPEN LINE
	CALL	CR2ON
	MVI	B,3		;WAIT 150 MS
SBRK1:	CALL	WAIT50
	DCR	B
	JNZ	SBRK1
	MVI	B,BK		;CLOSE LINE
	CALL	CR2OFF
	POP	B
	RET
 
;;	PCD - PROCESS CONFIGURATION DIRECTIVE
;
;	ENTRY CONDITIONS
;
;		IBUFC	NUMBER OF BYTES IN INPUT BUFFER
;
;		IBUFP	POINTER TO NEXT BYTE IN INPUT BUFFER
;
;	EXIT CONDITIONS
;
;		C-FLAG	SET IF ERROR
 
PCD:	LHLD	IBUFP		;CONVERT IBUF TO ALL UPPER CASE
	LDA	IBUFC
	MOV	B,A
PCD0:	MOV	A,M
	CALL	CLC
	MOV	M,A
	INX	H
	DCR	B
	JNZ	PCD0
	LXI	H,KWBUF		;BLANK FILL KEYWORD BUFFER
	MVI	B,8
PCD1:	MVI	M,' '
	INX	H
	DCR	B
	JNZ	PCD1
	LXI	H,KWBUF
	MVI	B,8
PCD2:	CALL	GNC		;GET NEXT CHAR FROM IBUF
	JC	PCD3		;BRANCH ON END OF LINE
	CPI	' '		;BRANCH ON BLANK
	JZ	PCD3
	CPI	TAB		;BRANCH ON TAB
	JZ	PCD3
	MOV	M,A		;STORE BYTE IN KWBUF
	INX	H
	DCR	B		;DECREMENT COUNT
	JP	PCD2		;LOOP IF STILL ROOM
	JMP	PCDX1		;FLAG ERROR AND EXIT
PCD3:	LXI	H,KWTAB		;POINT TO KEYWORD TABLE
PCD4:	LXI	D,KWBUF		;POINT TO KEYWORD
	MVI	B,8		;NUMBER OF BYTES TO COMPARE
	MVI	C,0		;START WITH NO DISCREPANCY
PCD5:	LDAX	D		;FETCH NEXT BYTE OF KWBUF
	XRA	M		;LOG. DIFF. WITH BYTE FROM TABLE
	ORA	C		;ACCUMULATE DISCREPANCY
	MOV	C,A
	INX	D		;INCREMENT POINTERS
	INX	H
	DCR	B		;DECREMENT COUNT
	JNZ	PCD5		;LOOP UNTIL ZERO
	INR	C		;JUMP IF NO DISCREPANCY
	DCR	C
	JZ	PCD6
	INX	H		;SKIP ADDRESS FIELD
	INX	H
	MOV	A,M		;LOOP IF NOT END OF TABLE
	ORA	A
	JNZ	PCD4
	JMP	PCDX1		;FLAG ERROR AND EXIT
PCD6:	MOV	E,M		;FETCH ADDRESS INTO DE
	INX	H
	MOV	D,M
	XCHG			;SWAP ADDRESS INTO HL
	PCHL			;AND AWAY WE GO!
PCDX1:	STC			;ERROR EXIT
	RET
PCDX2:	STC			;NORMAL EXIT
	CMC
	RET
 
KWTAB:	DB	'SITE    '
	DW	PCDA
	DB	'PHONE   '
	DW	PCDB
	DB	'PARITY  '
	DW	PCDC
	DB	'DBITS   '
	DW	PCDD
	DB	'SBITS   '
	DW	PCDE
	DB	'MODE    '
	DW	PCDF
	DB	'DUPLEX  '
	DW	PCDG
	DB	'AUTOLF  '
	DW	PCDH
	DB	'BAUD    '
	DW	PCDI
	DB	'CAPS    '
	DW	PCDJ
	DB	'ESCAPE  '
	DW	PCDK
	DB	'ABORT   '
	DW	PCDL
	DB	'RETURN  '
	DW	PCDM
	DB	'DEBUG   '
	DW	PCDN
	DB	'ERROR   '
	DW	PCDO
	DB	'READ    '
	DW	PCDP
	DB	'GARBAGE '
	DW	PCDQ
	DB	'LIST    '
	DW	PCDR
	DB	'EXPAND  '
	DW	PCDS
	DB	'CAPTURE '
	DW	PCDT
	DB	'WRITE   '
	DW	PCDU
	DB	'BREAK   '
	DW	PCDV
	DB	'SAVE    '
	DW	PCDW
	DB	'RESET   '
	DW	PCDX
	DB	'HELP    '
	DW	PCDY
	DB	'REMESC  '
	DW	PCDZ
	DB	'DIR     '
	DW	PCEA
	DB	'SEND    '
	DW	PCEB
	DB	'RECV    '
	DW	PCEC
	DB	'BLOCK   '
	DW	PCED
	DB	0
 
;	PCDA - PROCESS 'SITE' DIRECTIVE
 
PCDA:	XRA	A
	STA	SITEL
	CALL	SNB		;SCAN TO PARAMETER
	JC	PCDX2		;EXIT IF NO PARAMETER
	LXI	H,SITE		;POINT TO 'SITE' BUFFER
	MVI	B,60		;MAX LENGTH
PCDA1:	MOV	M,A		;STORE CHAR IN 'SITE' BUFFER
	INX	H
	LDA	SITEL		;INCREMENT 'SITE' LENGTH
	INR	A
	STA	SITEL
	CALL	GNC		;GET NEXT CHARACTER
	JC	PCDX2		;BRANCH ON END OF LINE
	DCR	B		;DECREMENT COUNT
	JP	PCDA1		;LOOP IF STILL ROOM
	JMP	PCDX1
 
;	PCDB - PROCESS 'PHONE' DIRECTIVE
 
PCDB:	XRA	A
	STA	PHONEL
	CALL	SNB		;SCAN TO PARAMETER
	JC	PCDX2		;EXIT IF NO PARAMETER
	LXI	H,PHONE		;POINT TO 'PHONE' BUFFER
	MVI	B,20		;MAX SIZE
PCDB1:	MOV	M,A		;STORE CHAR IN 'PHONE' BUFFER
	INX	H
	LDA	PHONEL		;INCREMENT 'PHONE' LENGTH
	INR	A
	STA	PHONEL
	CALL	GNC		;GET NEXT CHAR
	JC	PCDX2		;BRANCH ON END OF LINE
	DCR	B		;DECREMENT COUNT
	JP	PCDB1		;LOOP IF STILL ROOM
	JMP	PCDX1
 
;	PCDC - PROCESS 'PARITY' DIRECTIVE
 
PCDC:	CALL	SNB		;SKIP TO PARAMETER
	RC
	CPI	'E'		;JUMP IF NOT 'EVEN'
	JNZ	PCDC1
	MVI	B,EPE		;ENABLE EVEN PARITY
	CALL	CR1ON
	MVI	B,PI
	CALL	CR1OFF
	JMP	PCDX2		;EXIT
PCDC1:	CPI	'O'		;JUMP IF NOT 'ODD'
	JNZ	PCDC2
	MVI	B,EPE+PI	;ENABLE ODD PARITY
	CALL	CR1OFF
	JMP	PCDX2
PCDC2:	CPI	'N'		;JUMP IF NOT 'NONE'
	JNZ	PCDX1
	MVI	B,PI		;INHIBIT PARITY
	CALL	CR1ON
	JMP	PCDX2
 
;	PCDD - PROCESS 'DBITS' DIRECTIVE
 
PCDD:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'7'		;JUMP IF NOT '7'
	JNZ	PCDD1
	MVI	B,LS2		;SELECT 7 DATA BITS
	CALL	CR1ON
	MVI	B,LS1
	CALL	CR1OFF
	JMP	PCDX2
PCDD1:	CPI	'8'		;JUMP IF NOT '8'
	JNZ	PCDX1
	MVI	B,LS2+LS1	;SELECT 8 DATA BITS
	CALL	CR1ON
	JMP	PCDX2
 
;	PCDE - PROCESS 'SBITS' DIRECTIVE
 
PCDE:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'1'		;JUMP IF NOT '1'
	JNZ	PCDE1
	MVI	B,SBS		;SELECT 1 STOP BIT
	CALL	CR1OFF
	JMP	PCDX2
PCDE1:	CPI	'2'		;JUMP IF NOT '2'
	JNZ	PCDX1
	MVI	B,SBS		;SELECT 2 STOP BITS
	CALL	CR1ON
	JMP	PCDX2
 
;	PCDF - PROCESS 'MODE' DIRECTIVE
 
PCDF:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CALL	CLC
	STA	MODE
	CPI	'O'		;JUMP IF NOT 'ORIGINATE'
	JNZ	PCDF1
	MVI	B,MS		;SELECT ORIGINATE MODE
	CALL	CR2ON
	JMP	PCDX2
PCDF1:	CPI	'A'		;JUMP IF NOT 'ANSWER'
	JNZ	MODERR
	MVI	B,MS		;SELECT ANSWER MODE
	CALL	CR2OFF
	MVI	A,1		;FORCE HALF DUPLEX
	STA	ECHO
	JMP	PCDX2
 
;	PCDG - PROCESS 'DUPLEX' DIRECTIVE
 
PCDG:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'F'		;JUMP IF NOT 'FULL'
	JNZ	PCDG1
	XRA	A		;CLEAR ECHO FLAG
	STA	ECHO
	JMP	PCDX2
PCDG1:	CPI	'H'		;JUMP IF NOT 'HALF'
	JNZ	PCDX1
	MVI	A,1		;SET ECHO FLAG
	STA	ECHO
	JMP	PCDX2
 
;	PCDH - PROCESS 'AUTOLF' DIRECTIVE
 
PCDH:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'O'		;ERROR IF 1ST CHAR NOT 'O'
	JNZ	PCDX1
	CALL	GNC		;GET 2ND CHAR
	RC
	CPI	'N'		;JUMP IF NOT 'ON'
	JNZ	PCDH1
	MVI	A,1		;SET AUTOLF FLAG
	STA	AUTOLF
	JMP	PCDX2
PCDH1:	CPI	'F'		;JUMP IF NOT 'OFF'
	JNZ	PCDX1
	XRA	A		;CLEAR AUTOLF FLAG
	STA	AUTOLF
	JMP	PCDX2
 
;	PCDI - PROCESS 'BAUD' DIRECTIVE
 
PCDI:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'1'		;JUMP IF NOT '110'
	JNZ	PCDI1
	MVI	B,BRS		;SELECT 110 BAUD
	CALL	CR2OFF
	JMP	PCDX2
PCDI1:	CPI	'3'		;JUMP IF NOT '300'
	JNZ	PCDX1
	MVI	B,BRS		;SELECT 300 BAUD
	CALL	CR2ON
	JMP	PCDX2
 
;	PCDJ - PROCESS 'CAPS' DIRECTIVE
 
PCDJ:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'O'		;ERROR IF 1ST CHAR NOT 'O'
	JNZ	PCDX1
	CALL	GNC		;GET 2ND CHAR
	RC
	CPI	'N'		;JUMP IF NOT 'ON'
	JNZ	PCDJ1
	MVI	A,1		;TURN ON CAPS LOCK
	STA	CAPS
	JMP	PCDX2
PCDJ1:	CPI	'F'		;JUMP IF NOT 'OFF'
	JNZ	PCDX1
	XRA	A		;TURN OFF CAPS LOCK
	STA	CAPS
	JMP	PCDX2
 
;	PCDK - PROCESS 'ESCAPE' PARAMETER
 
PCDK:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CALL	DHD		;DECODE FIRST HEX DIGIT
	RC
	ADD	A		;LEFT SHIFT 4 (X 16)
	ADD	A
	ADD	A
	ADD	A
	MOV	B,A		;SAVE IT
	CALL	GNC		;DECODE SECIND HEX DIGIT
	RC
	CALL	DHD
	RC
	ADD	B		;ADD TO SHIFTED 1ST DIGIT
	STA	ESCAPE		;SAVE IT AS NEW ESCAPE CODE
	JMP	PCDX2		;NORMAL EXIT
 
;	PCDL - PROCESS 'ABORT' DIRECTIVE
 
PCDL:	LXI	H,MSG7		;PRINT 'LINK TERMINATED'
	CALL	WASC
	JMP	EXIT
 
;	PCDM - PROCESS 'RETURN' DIRECTIVE
 
PCDM:	LXI	H,MSG8		;PRINT 'LINK INTERUPPTED'
	CALL	WASC
	JMP	CLINKX
 
;	PCDN - PROCESS 'DEBUG' DIRECTIVE
 
PCDN:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'O'		;ERROR IF FIRST CHAR NOT 'O'
	JNZ	PCDX1
	CALL	GNC		;GET NEXT CHAR
	RC
	CPI	'N'		;JUMP IF NOT 'ON'
	JNZ	PCDN1
	MVI	A,1		;TURN ON DEBUG MODE
	STA	DEBUG
	XRA	A		;CLEAR DEBUG COUNT
	STA	DEBUGC
	JMP	PCDX2
PCDN1:	CPI	'F'		;JUMP IF NOT 'OFF'
	JNZ	PCDX1
	XRA	A		;TURN OFF DEBUG MODE
	STA	DEBUG
	JMP	PCDX2
 
;	PCDO - PROCESS 'ERROR' DIRECTIVE
 
PCDO:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'S'		;JUMP IF NOT 'SUMMARY'
	JNZ	PCDO1
	LHLD	PERR		;PRINT PARITY ERROR COUNT
	CALL	WDWC
	LXI	H,MSG11		;PRINT ' PARITY ERRORS'
	CALL	WASC
	LHLD	OERR		;PRINT OVERRUN COUNT
	CALL	WDWC
	LXI	H,MSG12		;PRINT ' OVERRUN ERRORS'
	CALL	WASC
	LHLD	FERR		;PRINT FRAME ERROR COUNT
	CALL	WDWC
	LXI	H,MSG13		;PRINT ' FRAME ERRORS'
	CALL	WASC
	JMP	PCDX2		;EXIT
PCDO1:	CALL	DHD		;DECODE 1ST HEX DIGIT
	RC
	ADD	A		;LEFT SHIFT 4
	ADD	A
	ADD	A
	ADD	A
	MOV	B,A		;SAVE IT
	CALL	GNC		;GET 2ND DIGIT
	RC
	CALL	DHD		;DECODE 2ND DIGIT
	RC
	ADD	B		;BUILD COMPLETE BYTE
	STA	ERROR		;SAVE AS ERROR CODE
	JMP	PCDX2		;EXIT
 
;	PCDP - PROCESS 'READ' DIRECTIVE
 
PCDP:	CALL	GFN		;GET FILE NAME INTO TFCB
	RC
	XRA	A
	STA	TFCB+EX
	LXI	D,TFCB		;TRY TO OPEN FILE
	CALL	OPEN
	CPI	255
	JNZ	PCDP1
	LXI	H,MSG1		;PRINT 'FILE NOT FOUND'
	CALL	WASC
	JMP	PCDX2		;NORMAL EXIT
PCDP1:	XRA	A
	STA	TFCB+NR
	STA	DIBUFC
	LXI	H,0		;CLEAR TRANSMISSION ERROR COUNT
	SHLD	TERR
PCDP2:	CALL	RASS		;READ NEXT LINE FROM FILE
	JC	PCDP6		;BRANCH ON EOF
	CALL	CCA		;CHECK FOR CONSOLE ACTIVITY
	JC	PCDP6		;ABORT TRANSMISSION IF PRESENT
	XRA	A		;CLEAR COLUMN COUNT FOR TAB EXPANSION
	STA	COL
PCDP3:	CALL	GNC		;GET NEXT CHAR
	JC	PCDP4		;BRANCH ON END OF LINE
	MOV	B,A
	LDA	CAPS		;CONVERT L.C. IF CAPS LOCK ON
	ORA	A
	MOV	A,B
	CNZ	CLC
	CPI	TAB		;JUMP IF NOT TAB
	JNZ	PCDP3C
	LDA	EXPAND		;JUMP IF EXPAND NOT SELECTED
	ORA	A
	MVI	A,TAB
	JZ	PCDP3C
PCDP3A:	MVI	A,' '		;SEND ANOTHER BLANK
	CALL	WACM
	MOV	B,A
	LDA	ECHO		;CHECK DUPLEX FLAG
	ORA	A
	MOV	A,B
	CZ	RACM		;AWAIT ECHO IF 'FULL'
	CALL	XWACC		;WRITE CHAR TO CONSOLE
	CMP	B		;COMPARE WITH CHAR WE SENT
	JZ	PCDP3B		;JUMP IF IDENTICAL
	LHLD	TERR		;ELSE INCREMENT TRANS. ERROR COUNT
	INX	H
	SHLD	TERR
PCDP3B:	LDA	COL		;INCREMENT COLUMN COUNT
	INR	A
	STA	COL
	ANI	07H		;LOOP UNTIL MOD(COL,8)=0
	JNZ	PCDP3A
	JMP	PCDP3		;GO GET NEXT CHAR FROM FILE
PCDP3C:	CALL	WACM		;WRITE CHAR TO MODEM
	MOV	B,A
	LDA	ECHO		;CHECK DUPLEX FLAG
	ORA	A
	MOV	A,B
	CZ	RACM		;AWAIT REMOTE ECHO IF 'FULL'
	CALL	XWACC		;WRITE CHAR TO CONSOLE
	CMP	B		;COMPARE WITH CHAR WE SENT
	JZ	PCDP3D		;JUMP IF IDENTICAL
	LHLD	TERR		;INCREMENT ERROR COUNT
	INX	H
	SHLD	TERR
PCDP3D:	LDA	COL		;INCREMENT COLUMN COUNT
	INR	A
	STA	COL
	JMP	PCDP3		;LOOP UNTIL EOF
PCDP4:	MVI	A,CR		;SEND CARRIAGE RETURN
	CALL	WACM
	MOV	B,A
	LDA	ECHO		;CHECK DUPLEX FLAG
	ORA	A
	MOV	A,B
	CZ	RACM		;AWAIT REMOTE ECHO IF 'FULL'
	CALL	XWACC		;WRITE CHAR TO CONSOLE
	CMP	B		;COMPARE WITH CHAR WE SENT
	JZ	PCDP9		;JUMP IF IDENTICAL
	LHLD	TERR		;ELSE INCREMENT ERROR COUNT
	INX	H
	SHLD	TERR
PCDP9:	LDA	MODE		;JUMP IF ORIGINATE MODE
	CPI	'O'
	JZ	PCDP5
	MVI	A,LF
	CALL	WACM		;SEND LF TO MODEM
	CALL	XWACC		;SEND LF TO CONSOLE
	JMP	PCDP2		;LOOP UNTIL EOF
PCDP5:	CALL	RACM		;AWAIT REMOTE LINE FEED
	ANI	7FH
	CPI	LF
	JNZ	PCDP5
	CALL	XWACC		;ECHO LF TO CONSOLE
	LXI	H,500		;SETUP FOR HALF-SECOND TIMEOUT
	SHLD	TIME
	LDA	GARBAGE		;GET GARBAGE COUNT
	MOV	B,A
	INR	B
PCDP8:	DCR	B		;DECREMENT COUNT
	JZ	PCDP7		;JUMP WHEN ZERO
	CALL	RACM		;DISCARD ANOTHER CHAR
	JMP	PCDP8		;LOOP UNTIL COUNT = 0
PCDP7:	LXI	H,0FFFFH	;RESET TO INF. TIMEOUT
	SHLD	TIME
	JMP	PCDP2		;LOOP UNTIL EOF
PCDP6:	LXI	D,TFCB		;CLOSE FILE
	CALL	CLOSE
	MVI	A,BEL		;RING BELL
	CALL	WACC
	CALL	WEOLC		;RETURN CARRIAGE
	LDA	ECHO		;RETURN IF HALF DUPLEX
	ORA	A
	JNZ	PCDX2
	LHLD	TERR		;PRINT TRANS. ERROR COUNT
	CALL	WDWC
	LXI	H,MSG15		;PRINT ' TRANSMISSION ERRORS'
	CALL	WASC
	JMP	PCDX2		;EXIT
 
;	PCDQ - PROCESS 'GARBAGE' DIRECTIVE
 
PCDQ:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CALL	DHD		;DECODE FIRST HEX DIGIT
	RC
	STA	GARBAGE
	ADD	A		;LEFT SHIFT 4
	ADD	A
	ADD	A
	ADD	A
	MOV	B,A		;SAVE IT
	CALL	GNC		;DECODE SECOND HEX DIGIT
	JC	PCDX2		;RETURN IF NO SECOND DIGIT
	CALL	DHD
	RC
	ADD	B		;ADD TO SHIFTED 1ST DIGIT
	STA	GARBAGE		;SAVE AS NEW GARBAGE COUNT
	JMP	PCDX2
 
;	PCDR - PROCESS 'LIST' DIRECTIVE
 
PCDR:	LXI	H,KWTAB+0*10	;PRINT 'SITE    '
	CALL	W8CC
	LXI	H,SITE		;PRINT SITE STRING
	LDA	SITEL
	MOV	B,A
	INR	B
PCDR1:	DCR	B
	JZ	PCDR2
	MOV	A,M
	INX	H
	CALL	WACC
	JMP	PCDR1
PCDR2:	CALL	WEOLC
	LXI	H,KWTAB+1*10	;PRINT 'PHONE   '
	CALL	W8CC
	LXI	H,PHONE		;PRINT PHONE NUMBER
	LDA	PHONEL
	MOV	B,A
	INR	B
PCDR3:	DCR	B
	JZ	PCDR4
	MOV	A,M
	INX	H
	CALL	WACC
	JMP	PCDR3
PCDR4:	CALL	WEOLC
	LXI	H,KWTAB+5*10	;PRINT 'MODE    '
	CALL	W8CC
	LDA	CR2		;JUMP IF NOT ORIGINATE
	ANI	MS
	JZ	PCDR5
	LXI	H,MSG24		;PRINT 'ORIGINATE'
	JMP	PCDR6
PCDR5:	LXI	H,MSG25		;PRINT 'ANSWER'
PCDR6:	CALL	WASC
	LXI	H,KWTAB+6*10	;PRINT 'DUPLEX  '
	CALL	W8CC
	LDA	ECHO		;JUMP IF HALF DUPLEX
	ORA	A
	JNZ	PCDR7
	LXI	H,MSG26		;PRINT 'FULL'
	JMP	PCDR8
PCDR7:	LXI	H,MSG27		;PRINT 'HALF'
PCDR8:	CALL	WASC
	MVI	B,9		;SPACE OVER 9
	CALL	WSPC
	LXI	H,KWTAB+2*10	;PRINT 'PARITY  '
	CALL	W8CC
	LDA	CR1		;JUMP IF NO PARITY INHIBIT
	ANI	PI
	JZ	PCDR9
	LXI	H,MSG21		;PRINT 'NONE'
	JMP	PCDRB
PCDR9:	LDA	CR1		;JUMP IF NOT EVEN
	ANI	EPE
	JZ	PCDRA
	LXI	H,MSG22		;PRINT 'EVEN'
	JMP	PCDRB
PCDRA:	LXI	H,MSG23
PCDRB:	CALL	WASC
	LXI	H,KWTAB+3*10	;PRINT 'DBITS   '
	CALL	W8CC
	LDA	CR1		;PRINT # OF DATA BITS
	ANI	LS2+LS1
	RRC
	ADI	'5'
	CALL	WACC
	MVI	B,12		;SPACE 12
	CALL	WSPC
	LXI	H,KWTAB+4*10	;PRINT 'SBITS   '
	CALL	W8CC
	LDA	CR1		;PRINT # OF STOP BITS
	ANI	SBS
	RRC
	RRC
	RRC
	ADI	'1'
	CALL	WACC
	CALL	WEOLC
	LXI	H,KWTAB+7*10	;PRINT 'AUTOLF  '
	CALL	W8CC
	LDA	AUTOLF		;PRINT STATE
	CALL	ONOFF
	MVI	B,10		;SPACE OVER 10
	CALL	WSPC
	LXI	H,KWTAB+8*10	;PRINT 'BAUD    '
	CALL	W8CC
	LDA	CR2		;JUMP IF 300
	ANI	BRS
	JNZ	PCDRC
	LXI	H,MSG28		;PRINT '110'
	JMP	PCDRD
PCDRC:	LXI	H,MSG29		;PRINT '300'
PCDRD:	CALL	WASC
	LXI	H,KWTAB+9*10	;PRINT 'CAPS    '
	CALL	W8CC
	LDA	CAPS		;PRINT STATE
	CALL	ONOFF
	MVI	B,10		;SPACE OVER 10
	CALL	WSPC
	LXI	H,KWTAB+10*10	;PRINT 'ESCAPE  '
	CALL	W8CC
	LDA	ESCAPE		;PRINT HEX VALUE
	CALL	WHBC
	MVI	A,'H'
	CALL	WACC
	CALL	WEOLC
	LXI	H,KWTAB+13*10	;PRINT 'DEBUG   '
	CALL	W8CC
	LDA	DEBUG		;PRINT STATE
	CALL	ONOFF
	MVI	B,10		;SPACE OVER 10
	CALL	WSPC
	LXI	H,KWTAB+14*10	;PRINT 'ERROR   '
	CALL	W8CC
	LDA	ERROR		;PRINT HEX VALUE
	CALL	WHBC
	MVI	A,'H'
	CALL	WACC
	CALL	WEOLC
	LXI	H,KWTAB+16*10	;PRINT 'GARBAGE '
	CALL	W8CC
	LDA	GARBAGE		;PRINT VALUE
	CALL	WHBC
	MVI	A,'H'
	CALL	WACC
	MVI	B,10		;SPACE OVER 10
	CALL	WSPC
	LXI	H,KWTAB+18*10	;PRINT 'EXPAND  '
	CALL	W8CC
	LDA	EXPAND		;PRINT STATE
	CALL	ONOFF
	CALL	WEOLC
	LXI	H,KWTAB+21*10	;PRINT 'BREAK   '
	CALL	W8CC
	LDA	BREAK
	CALL	WHBC
	MVI	A,'H'
	CALL	WACC
	MVI	B,10		;SPACE OVER 10
	CALL	WSPC
	LXI	H,KWTAB+25*10	;PRINT 'REMESC  '
	CALL	W8CC
	LDA	REMESC
	CALL	WHBC		;PRINT REMOTE ESCAPE CODE
	MVI	A,'H'
	CALL	WACC
	CALL	WEOLC
	LXI	H,KWTAB+29*10	;PRINT 'BLOCK   '
	CALL	W8CC
	LDA	BLKSZ		;PRINT BLOCK SIZE IN HEX
	CALL	WHBC
	MVI	A,'H'
	CALL	WACC
	CALL	WEOLC
	JMP	PCDX2		;NORMAL EXIT
 
;	PCDS - PROCESS 'EXPAND' DIRECTIVE
 
PCDS:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CPI	'O'		;ERROR IF 1ST CHAR NOT 'O'
	JNZ	PCDX1
	CALL	GNC		;GET 2ND CHAR
	RC
	CPI	'N'		;JUMP IF NOT 'ON'
	JNZ	PCDS1
	MVI	A,1		;TURN ON EXPAND FLAG
	STA	EXPAND
	JMP	PCDX2		;EXIT
PCDS1:	CPI	'F'		;ERROR IF NOT 'OFF'
	JNZ	PCDX1
	XRA	A		;TURN OFF EXPAND FLAG
	STA	EXPAND
	JMP	PCDX2		;EXIT
 
W8CC:	MVI	B,8
W8CC1:	MOV	A,M
	INX	H
	CALL	WACC
	DCR	B
	JNZ	W8CC1
	RET
 
ONOFF:	ORA	A		;JUMP IF OFF
	JZ	ONOFF1
	LXI	H,MSG30		;PRINT 'ON'
	JMP	ONOFF2
ONOFF1:	LXI	H,MSG31		;PRINT 'OFF'
ONOFF2:	CALL	WASC
	RET
 
;	PCDT - PROCESS 'CAPTURE' DIRECTIVE
 
PCDT:	MVI	A,1		;SET CAPTURE FLAG
	STA	CAPTURE
	LXI	H,MBUF		;RESET BUFFER POINTER
	SHLD	MBUFP
	JMP	PCDX2		;EXIT
 
;	PCDU - PROCESS 'WRITE' DIRECTIVE
 
PCDU:	XRA	A		;TURN OFF CAPTURE FLAG
	STA	CAPTURE
	LHLD	MBUFP		;HL = POINTER TO LAST DATA + 1
	LXI	D,MBUF		;DE = POINTER TO FIRST DATA
	MOV	A,L		;HL = HL - DE = DATA LENGTH
	SUB	E
	MOV	L,A
	MOV	A,H
	SBB	D
	MOV	H,A
	SHLD	SIZE
	ORA	L		;JUMP IF HL>0
	JNZ	PCDU1
	LXI	H,MSG16		;PRINT 'MEMORY BUFFER EMPTY'
	CALL	WASC
	JMP	PCDX2		;EXIT
PCDU1:	CALL	GFN		;GET USER'S FILE NAME
	RC
	XRA	A
	STA	TFCB+EX
	LXI	D,TFCB		;CREATE FILE
	CALL	DELETE
	CALL	MAKE
	CPI	255		;JUMP IF OK
	JNZ	PCDU2
	LXI	H,MSG17		;PRINT 'DISK FULL'
	CALL	WASC
	JMP	PCDX2		;EXIT
PCDU2:	XRA	A		;REWIND FILE
	STA	TFCB+NR
	STA	DOBUFC
	LXI	H,DOBUF
	SHLD	DOBUFP
	LHLD	SIZE		;DE = NUMBER OF BYTES TO SAVE
	XCHG
	LXI	H,MBUF		;HL = FWA OF DATA
PCDU3:	MOV	A,M		;FETCH NEXT CHAR FROM MBUF
	INX	H
	CALL	WACD		;WRITE ASCII CHAR TO DISK
	JNC	PCDU4		;JUMP IF OK
	LXI	H,MSG18		;PRINT 'WRITE ERROR'
	CALL	WASC
	JMP	PCDX2		;EXIT
PCDU4:	DCX	D		;DECREMENT SIZE
	MOV	A,D		;LOOP UNTIL ZERO
	ORA	E
	JNZ	PCDU3
	CALL	FLUSH		;FLUSH LAST OUTPUT BUFFER
	CALL	WEOLC		;RETURN CARRIAGE
	MVI	A,BEL		;RING BELL
	CALL	WACC
	JMP	PCDX2		;EXIT
 
;	PCDV - PROCESS 'BREAK' DIRECTIVE
 
PCDV:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CALL	DHD		;DECODE 1ST HEX DIGIT
	RC
	ADD	A		;LEFT SHIFT 4
	ADD	A
	ADD	A
	ADD	A
	MOV	B,A		;SAVE IT
	CALL	GNC		;GET 2ND DIGIT
	RC
	CALL	DHD		;DECODE IT
	RC
	ADD	B		;BUILD COMPLETE BYTE
	STA	BREAK		;SAVE AS NEW BREAK TRIGGER
	JMP	PCDX2
 
;	PCDW - PROCESS 'SAVE' DIRECTIVE
 
PCDW:	CALL	GFN		;GET FILE NAME
	RC
	XRA	A
	STA	TFCB+EX
	LXI	D,TFCB		;CREATE FILE
	CALL	DELETE
	CALL	MAKE
	CPI	255		;JUMP IF OK
	JNZ	PCDW2
	LXI	H,MSG17		;PRINT 'DISK FULL'
	CALL	WASC
	JMP	PCDX2
PCDW2:	XRA	A		;REWIND FILE
	STA	TFCB+NR
	STA	DOBUFC
	LXI	H,DOBUF
	SHLD	DOBUFP
	MVI	A,2		;REDIRECT CONSOLE OUTPUT TO DISK
	STA	COF
	CALL	PCDR		;WRITE CONFIG FILE
	CALL	FLUSH		;FLUSH BUFFER, CLOSE FILE
	XRA	A		;REDIRECT CONSOLE OUTPUT TO CONSOLE
	STA	COF
	JMP	PCDX2		;EXIT
 
;	PCDX - PROCESS 'RESET' DIRECTIVE
 
PCDX:	LXI	H,0
	SHLD	PERR
	SHLD	OERR
	SHLD	FERR
	JMP	PCDX2
 
;	PCDY - PROCESS 'HELP' DIRECTIVE
 
PCDY:	CALL	SNB		;SCAN TO PARAMETER
	JNC	PCDY1		;JUMP IF FOUND
	LXI	H,HMSG0		;ELSE PRINT HELP MESSAGE 0
	CALL	WASC
	JMP	PCDX2
PCDY1:	CPI	'1'		;JUMP IF NOT '1'
	JNZ	PCDY2
	LXI	H,HMSG1		;ELSE PRINT HELP MESSAGE 1
	CALL	WASC
	JMP	PCDX2
PCDY2:	CPI	'2'		;JUMP IF NOT '2'
	JNZ	PCDY3
	LXI	H,HMSG2		;ELSE PRINT HELP MESSAGE 2
	CALL	WASC
	JMP	PCDX2
PCDY3:	CPI	'3'		;JUMP IF NOT '3'
	JNZ	PCDY4
	LXI	H,HMSG3		;ELSE PRINT HELP MESSAGE 3
	CALL	WASC
	JMP	PCDX2
PCDY4:	JMP	PCDX1		;FOR NOW, FLAG ERROR
 
;	PCDZ - PROCESS 'REMESC' DIRECTIVE
 
PCDZ:	CALL	SNB		;SCAN TO PARAMETER
	RC
	CALL	DHD		;DECLARE 1ST HEX DIGIT
	RC
	ADD	A		;LEFT SHIFT 4 BITS
	ADD	A
	ADD	A
	ADD	A
	MOV	B,A
	CALL	GNC		;GET 2ND DIGIT
	RC
	CALL	DHD		;DECODE IT
	RC
	ADD	B		;ACCUMULATE BYTE
	STA	REMESC		;SAVE AS NEW REMOTE ESCAPE CODE
	JMP	PCDX2		;EXIT
 
;	PCEA - PROCESS 'DIR' DIRECTIVE
 
PCEA:	CALL	GFN		;GET FILE NAME
	RC
	LXI	H,TFCB+FN	;JUMP IF ANY NON-BLANK CHARS
	MVI	B,11
PCEA0:	MOV	A,M
	CPI	' '
	JNZ	PCEA6
	INX	H
	DCR	B
	JNZ	PCEA0
	LXI	H,TFCB+FN
	MVI	B,11		;ESLE FILL FN ANF FT WITH ?
PCEA5:	MVI	M,'?'
	INX	H
	DCR	B
	JNZ	PCEA5
PCEA6:	XRA	A		;CLEAR COLUMN COUNT
	STA	COL
	STA	TFCB+EX		;RESET TO EXTENT #0
	LXI	D,TFCB
	CALL	SRCHF		;SEARCH FOR 1ST OCCURANCE
	CPI	255
	JZ	PCEAX
PCEA1:	ANI	3		;MASK OFF LOW 2 BITS
	ADD	A		;MULTIPLY BY 32
	ADD	A
	ADD	A
	ADD	A
	ADD	A
	LXI	H,0080H		;ADD TO 80H
	ADD	L
	MOV	L,A
	INX	H		;SKIP 1ST BYTE
	MVI	B,11		;NUMBER OF BYTES
PCEA2:	MOV	A,M		;FETCH NEXT BYTE
	INX	H
	CALL	WACC		;WRITE TO CONSOLE
	DCR	B
	JNZ	PCEA2
	LXI	H,COL		;INCREMENT COLUMN COUNT
	INR	M
	MOV	A,M
	ANI	3		;JUMP IF DIVISIBLE BY 4
	JZ	PCEA3
	LXI	H,MSG20		;PRINT VERTICAL LINE
	CALL	WASC
	JMP	PCEA4		;LOOP
PCEA3:	CALL	WEOLC		;ISSUE END OF LINE
PCEA4:	LXI	D,TFCB
	CALL	SRCHN		;SEARCH FOR NEXT OCCURANCE
	CPI	255		;LOOP IF FOUND
	JNZ	PCEA1
	CALL	WEOLC		;ISSUE END OF LINE
	JMP	PCDX2		;EXIT
PCEAX:	LXI	H,MSG1		;PRINT 'FILE NOT FOUND'
	CALL	WASC
	JMP	PCDX2
 
;	PCEB - PROCESS 'SEND' DIRECTIVE
 
PCEB:	MVI	B,LS2+LS1	;FORCE 8 DATA BITS
	CALL	CR1ON
	CALL	GFN		;GET FILE NAME INTO TFCB
	RC
	XRA	A
	STA	TFCB+EX
	LXI	D,TFCB		;TRY TO OPEN FILE
	CALL	OPEN
	CPI	255
	JNZ	PCEB1
	LXI	H,MSG1		;PRINT 'FILE NOT FOUND'
	CALL	WASC
	JMP	PCDX2		;EXIT
PCEB1:	XRA	A
	STA	TFCB+NR		;REWIND FILE
	STA	EOF		;CLEAR END-OF-FILE FLAG
PCEB2:	LDA	EOF		;JUMP IF END-OF-FILE FLAG SET
	ORA	A
	JNZ	PCEB7
	CALL	CONST		;JUMP IF NO CONSOLE ACTIVITY
	ORA	A
	JZ	PCEB2A
	LXI	H,MSG38		;PRINT 'SEND ABORTED'
	CALL	WASC
	JMP	PCEB7		;GO SEND EOT
PCEB2A:	LXI	B,0		;COUNT = 0
	LXI	D,MBUF		;INITIAL MBUF POINTER
PCEB3:	CALL	RDREC2		;READ NEXT RECORD INTO MBUF
	CPI	1		;JUMP ON EOF
	JZ	PCEB3A
	MOV	A,E		;INCREMENT MBUF POINTER
	ADI	128
	MOV	E,A
	JNC	$+4
	INR	D
	MOV	A,C		;INCREMENT COUNT
	ADI	128
	MOV	C,A
	JNC	$+4
	INR	B
	MOV	A,B
	LXI	H,BLKSZ
	CMP	M
	JC	PCEB3
	JMP	PCEB3B		;GO SEND DATA MESSAGE
PCEB3A:	MVI	A,1		;SET END-OF-FILE FLAG
	STA	EOF
	MOV	A,B		;GO SEND EOT IF COUNT = 0
	ORA	C
	JZ	PCEB7
PCEB3B:	MOV	H,B		;SAVE COUNT
	MOV	L,C
	SHLD	OCNT
PCEB4:	MVI	A,NULL		;SEND DATA MESSAGE
	STA	OCODE
	CALL	SEND
PCEB5:	CALL	RECV
	JNC	PCEB5A		;JUMP IF OK
	LXI	H,MSG36		;PRINT 'INVALID CRC'
	CALL	WASC
	JMP	PCEB6
PCEB5A:	LHLD	TOC
	MOV	A,H
	ORA	L
	JNZ	PCEB5B
	LXI	H,MSG35		;PRINT 'TIMEOUT'
	CALL	WASC
	JMP	PCEB4
PCEB5B:	LDA	ICODE		;FETCH INPUT MESSAGE TYPE
	CPI	EOT		;JUMP IF ECHOED EOT
	JZ	PCEB8
	CPI	ACK		;CONTINUE TO NEXT MSG IF ACK
	JZ	PCEB2
	CPI	NAK		;RETRANSMIT IF NAK
	JNZ	PCEB5C
	LXI	H,MSG34		;PRINT 'RETRANSMITTING'
	CALL	WASC
	LDA	OCODE		;JUMP IF LAST MSG WAS EOT
	CPI	EOT
	JZ	PCEB7
	JMP	PCEB4		;ELSE RETRANS. DATA MESSAGE
PCEB5C:	LXI	H,MSG37		;PRINT 'UNKNOWN MESSAGE'
	CALL	WASC
PCEB6:	MVI	A,NAK		;SEND NAK
	STA	OCODE
	CALL	SEND
	JMP	PCEB5
PCEB7:	MVI	A,EOT		;SEND EOT
	STA	OCODE
	CALL	SEND
	JMP	PCEB5		;AWAIT EOT ECHO
PCEB8:	LXI	D,TFCB		;CLOSE FILE
	CALL	CLOSE
	LXI	H,MSG32		;PRINT 'FILE SENT'
	CALL	WASC
	JMP	PCDX2		;NORMAL EXIT
 
;	PCEC - PROCESS 'RECV' DIRECTIVE
 
PCEC:	MVI	B,LS2+LS1	;FORCE 8 DATA BITS
	CALL	CR1ON
	CALL	GFN		;GET FILE NAME
	RC
	XRA	A
	STA	TFCB+EX
	LXI	D,TFCB
	CALL	DELETE		;DELETE EXISTING FILE, IF ANY
	CALL	MAKE		;MAKE NEW ONE
	CPI	255		;JUMP IF OK
	JNZ	PCEC1
	LXI	H,MSG17		;PRINT 'DISK FULL'
	CALL	WASC
	JMP	PCDX2
PCEC1:	XRA	A
	STA	TFCB+NR
	MVI	A,0FFH		;'AWAITING FIRST MSG' CODE
	STA	OCODE
PCEC2:	CALL	RECV		;RECEIVE MESSAGE
	JNC	PCEC2A		;JUMP IF OK
	LXI	H,MSG36		;PRINT 'INVALID CRC'
	CALL	WASC
	JMP	PCEC3
PCEC2A:	LHLD	TOC		;BRANCH IF NO TIMEOUT
	MOV	A,H
	ORA	L
	JNZ	PCEC2B
	LDA	OCODE		;LOOP IF AWAITING FIRST MSG
	INR	A
	JZ	PCEC2
	LXI	H,MSG35		;PRINT 'TIMEOUT' AND SEND NAK
	CALL	WASC
	JMP	PCEC3
PCEC2B:	LDA	ICODE		;FETCH MESSAGE CODE
	CPI	NAK		;JUMP IF NAK
	JNZ	PCEC2C
	LXI	H,MSG34		;PRINT 'RETRANSMITTING'
	CALL	WASC
	JMP	PCEC6
PCEC2C:	CPI	EOT		;JUMP IF EOT
	JZ	PCEC9
	CPI	NULL		;JUMP IF DATA MESSAGE
	JZ	PCEC7
	LXI	H,MSG37		;PRINT 'UNKNOWN MESSAGE'
	CALL	WASC
PCEC3:	MVI	A,NAK		;SEND NAK
	JMP	PCEC5
PCEC4:	MVI	A,ACK		;SEND ACK
PCEC5:	STA	OCODE
PCEC6:	CALL	SEND		;SEND MESSAGE
	JMP	PCEC2		;GO READ RESPONSE
PCEC7:	LXI	D,MBUF2		;FWA OF INPUT BUFFER
	LHLD	ICNT		;HL = # OF BYTES READ
PCEC8:	CALL	WRREC2		;WRITE NEXT RECORD FROM MBUF
	MOV	A,E		;ADD 128 TO POINTER
	ADI	128
	MOV	E,A
	JNC	$+4
	INR	D
	MOV	A,L		;SUBTRACT 128 FROM COUNT
	SUI	128
	MOV	L,A
	JNC	$+4
	DCR	H
	MOV	A,H		;LOOP UNTIL COUNT = 0
	ORA	L
	JNZ	PCEC8
	JMP	PCEC4		;GO SEND ACK, LOOP UNTIL EOF
PCEC9:	MVI	A,EOT
	STA	OCODE
	CALL	SEND
	LXI	D,TFCB
	CALL	CLOSE
	LXI	H,MSG33		;PRINT 'FILE RECEIVED'
	CALL	WASC
	JMP	PCDX2
 
;	PCED - PROCESS 'BLOCK' DIRECTIVE
 
PCED:	CALL	SNB
	RC
	CALL	DHD
	RC
	STA	BLKSZ
	ADD	A
	ADD	A
	ADD	A
	ADD	A
	MOV	B,A
	CALL	GNC
	JC	PCDX2
	CALL	DHD
	RC
	ADD	B
	STA	BLKSZ
	JMP	PCDX2
 
;;	SEND - SEND MESSAGE USING PROTOCOL
;
;	ENTRY CONDITIONS
;
;		OCODE	MESSAGE TYPE (ACK,NAK,EOT,NUL)
;
;		OCNT	MESSAGE LENGTH (IF OCODE=NUL)
;
;		MBUF	MESSAGE (IF OCODE=NUL)
 
SEND:	MVI	A,SOH		;SEND START OF HEADER
	CALL	WACM
	LXI	H,0		;CLEAR CRC
	SHLD	CRC
	LDA	OCODE		;SEND MESSAGE TYPE
	CALL	WACMC
	CPI	NULL		;JUMP IF NOT DATA MESSAGE
	JNZ	SEND2
	LHLD	OCNT		;FETCH MESSAGE LENGTH
	MOV	A,H		;SEND HIGH BYTE
	CALL	WACMC
	MOV	A,L		;SEND LOW BYTE
	CALL	WACMC
	MVI	A,STX		;SEND START OF TEXT
	CALL	WACMC
	MOV	B,H		;BC=COUNT
	MOV	C,L
	LXI	H,MBUF		;HL = FWA OF MESSAGE
SEND1:	MOV	A,M		;FETCH NEXT BYTE OF MESSAGE
	INX	H
	CALL	WACMC		;SEND NEXT DATA BYTE
	DCX	B		;DECREMENT COUNT
	MOV	A,B		;LOOP UNTIL ZERO
	ORA	C
	JNZ	SEND1
	MVI	A,ETX		;SEND END OF TEXT
	CALL	WACMC
SEND2:	LDA	CRC+1		;SEND HIGH BYTE OF CRC
	CALL	WACM
	LDA	CRC		;SEND LOW BYTE OF CRC
	CALL	WACM
	RET			;EXIT
 
;;	RECV - RECEIVE MESSAGE USING PROTOCOL
;
;	ENTRY CONDITIONS
;
;		TIME	TIMEOUT COUNT (IN MILLISECONDS)
;
;	EXIT CONDITIONS
;
;		TOC	REMAINING TIME (ZERO IF TIMED OUT)
;
;		C-FLAG	SET IF ERROR DETECTED
;
;		ICODE	INPUT MESSAGE TYPE (ACK/NAK/EOT/NUL)
;
;		ICNT	INPUT MESSAGE COUNT (IF ICODE=NUL)
;
;		MBUF2	INPUT MESSAGE (IF ICODE=NUL)
 
RECV:	LXI	H,1000		;SETUP FOR 1 SECOND TIMEOUT
	SHLD	TIME
	MVI	B,10		;TRY 10 TIMES FOR SOH
RECV0:	CALL	RACM		;READ CHARACTER
	CPI	SOH		;JUMP IF SOH
	JZ	RECV1
	DCR	B		;NON-SOH OR TIMEOUT,
	JNZ	RECV0		;TRY AGAIN
	LXI	H,0		;FAKE TIMEOUT
	SHLD	TOC
	JMP	RECVX		;AND EXIT
RECV1:	LXI	H,0		;CLEAR CRC
	SHLD	CRC
	LXI	H,500		;SETUP FOR HALF-SECOND TIMEOUT
	SHLD	TIME
	CALL	RACMC		;READ MESSAGE TYPE
	JC	RECVX
	STA	ICODE
	CPI	NULL		;JUMP IF NOT DATA MESSAGE
	JNZ	RECV4
	CALL	RACMC		;READ HIGH BYTE OF COUNT
	JC	RECVX
	MOV	H,A
	CALL	RACMC		;READ LOW BYTE OF COUNT
	JC	RECVX
	MOV	L,A
	SHLD	ICNT		;SAVE COUNT
	MOV	B,H		;BC = COUNT
	MOV	C,L
RECV2:	CALL	RACMC		;LOOP UNTIL STX READ
	JC	RECVX
	CPI	STX
	JNZ	RECV2
	LXI	H,MBUF2		;FWA OF INPUT BUFFER
RECV3:	CALL	RACMC		;READ DATA BYTE
	JC	RECVX
	MOV	M,A		;STORE IN BUFFER
	INX	H
	DCX	B		;DECREMENT COUNT
	MOV	A,B		;LOOP UNTIL ZERO
	ORA	C
	JNZ	RECV3
	CALL	RACMC		;ERROR IF NEXT BYTE NOT ETX
	JC	RECVX
	CPI	ETX
	JNZ	RECVE
RECV4:	CALL	RACM		;READ TRANSMITTED CRC INTO DE
	JC	RECVX
	MOV	D,A
	CALL	RACM
	JC	RECVX
	MOV	E,A
	LHLD	CRC		;FETCH COMPUTED CRC INTO HL
	MOV	A,E		;ERROR IF NOT SAME
	CMP	L
	JNZ	RECVE
	MOV	A,D
	CMP	H
	JNZ	RECVE
RECVX:	LXI	H,0FFFFH	;RETURN TO INF. TIMEOUT
	SHLD	TIME
	STC
	CMC
	RET
RECVE:	LXI	H,0FFFFH	;RETURN TO INF. TIMEOUT
	SHLD	TIME
	STC			;ERROR EXIT
	RET
 
;;	WACMC - WRITE ASCII CHARACTER TO MODEM (WITH CRC)
;
 
WACMC:	CALL	WACM		;WRITE CHAR TO MODEM
	CALL	UCRC		;UPDATE CRC
	CMA			;DISPLAY ON LIGHTS
	OUT	0FFH
	CMA
	RET
 
;;	RACMC - READ ASCII CHARACTER FROM MODEM (WITH CRC)
;
 
RACMC:	CALL	RACM		;READ CHARACTER FROM MODEM
	PUSH	PSW
	CALL	UCRC		;UPDATE CRC
	CMA			;DISPLAY ON LIGHTS
	OUT	0FFH
	POP	PSW
	RET
 
;;	UCRC - UPDATE CRC
;
 
UCRC:	PUSH	PSW		;SAVE REGS
	PUSH	B
	PUSH	H
	MOV	B,A		;SAVE DATA BYTE
	MVI	C,8		;# BITS PER BYTE
UCRC1:	ANI	80H		;GET MOST SIG. BIT
	LHLD	CRC		;HL = CRC
	XRA	H		;XOR M.S.B. INTO CRC
	MOV	H,A
	DAD	H		;LEFT SHIFT CRC 1 BIT
	JNC	UCRC2		;JUMP IF M.S.B. ZERO
	MOV	A,H		;HL = HL XOR CRC POLYNOMIAL
	XRI	CRCPOL SHR 8
	MOV	H,A
	MOV	A,L
	XRI	CRCPOL AND 0FFH
	MOV	L,A
UCRC2:	SHLD	CRC		;REPLACE CRC
	DCR	C		;EXIT WHEN DONE
	JZ	UCRC3
	MOV	A,B		;SHIFT DATA BYTE LEFT 1 BIT
	ADD	A
	MOV	B,A
	JMP	UCRC1		;LOOP
UCRC3:	POP	H		;RESTORE REGS, RETURN
	POP	B
	POP	PSW
	RET
 
;;	SNB - SCAN TO NON-BLANK (AND NON-TAB)
;
 
SNB:	CALL	GNC		;GET NEXT CHAR
	RC			;RETURN IF END OF LINE
	CPI	' '		;LOOP IF BLANK
	JZ	SNB
	CPI	TAB		;LOOP IF TAB
	JZ	SNB
	STC			;NORMAL EXIT
	CMC
	RET
 
;;	DHD - DECODE HEX DIGIT
;
 
DHD:	CPI	'A'		;JUMP IF <A OR >F
	JC	DHD1
	CPI	'F'+1
	JNC	DHD1
	SUI	'A'-10		;DECODE A THRU F
	JMP	DHD2		;EXIT
DHD1:	CPI	'0'		;ERROR IF <0 OR >9
	RC
	CPI	'9'+1
	CMC
	RC
	SUI	'0'		;DECODE 0 THRU 9
DHD2:	STC			;EXIT
	CMC
	RET
 
;;	EASC - ECHO ASCII STRING TO CONSOLE
;
 
EASC:	LDA	IBUF+1		;FETCH STRING LENGTH
	ORA	A		;RETURN IF EMPTY
	RZ
	MOV	B,A		;B = LENGTH
	LXI	H,IBUF+2	;HL = FWA OF STRING
	MVI	C,0		;C = COLUMN COUNT
EASC1:	MOV	A,M		;FETCH NEXT CHAR FROM IBUF
	INX	H
	CPI	TAB		;JUMP IF NOT TAB
	JNZ	EASC3
EASC2:	MVI	A,' '		;EXPAND TAB
	CALL	WACC
	INR	C
	MOV	A,C
	ANI	07H
	JNZ	EASC2
	JMP	EASC4		;CONTINUE
EASC3:	CALL	WACC		;WRITE CHAR
	INR	C		;INCREMENT COLUMN COUNT
EASC4:	DCR	B		;DECREMENT COUNT
	JNZ	EASC1		;LOOP THRU ENTIRE BUFFER
	CALL	WEOLC		;WRITE END OF LINE TO CONSOLE
	RET			;EXIT
 
;;	GFN - GET FILE NAME INTO TFCB
;
 
GFN:	LXI	H,TFCB		;AREA TO STORE NAME
	MVI	M,0		;DEFAULT TO CURRENT DRIVE
	INX	H
	MVI	B,11		;BLANK FILL FN AND FT
GFN1:	MVI	M,' '
	INX	H
	DCR	B
	JNZ	GFN1
	CALL	SNB		;SCAN TO FILE NAME
	JC	GFNX
	MVI	B,8		;MAX CHARS IN NAME
	LXI	H,TFCB+FN	;START SCANNING FN
	JMP	GFN2A
GFN1A:	LXI	H,TFCB+FN	;OOPS - THAT WAS A DRIVE NAME
	MOV	A,M
	SUI	'A'-1
	STA	TFCB+0
	MVI	M,' '
	MVI	B,8
GFN2:	CALL	GNC		;GET NEXT CHAR
	JC	GFNX
GFN2A:	CPI	'*'		;JUMP IF ASTERISK
	JZ	GFN2B
	CPI	'.'		;JUMP IF END OF FN
	JZ	GFN3
	CPI	' '
	JZ	GFNX
	CPI	':'		;THIS IS NO FN, ITS A DRIVE ID!
	JZ	GFN1A
	CALL	CLC		;CONVERT LOWER CASE
	MOV	M,A		;SAVE IN FN
	INX	H
	DCR	B		;DECREMENT COUNT
	JP	GFN2		;LOOP IF STILL ROOM
	JMP	GFNE		;ELSE ERROR
GFN2B:	DCR	B		;FILL REST OF FN WITH '?'
GFN2C:	MVI	M,'?'
	INX	H
	DCR	B
	JNZ	GFN2C
	CALL	GNC		;GET NEXT CHAR
	JC	GFNX		;EXIT IF END OF NAME
	CPI	'.'		;ERROR IF NOT PERIOD
	JNZ	GFNE
GFN3:	LXI	H,TFCB+FT	;SCAN OFF FT FIELD
GFN4:	MVI	B,3		;MAX CHARS IN FT
GFN5:	CALL	GNC		;GET CHAR
	JC	GFNX		;EXIT IF END OF NAME
	CPI	'*'		;JUMP IF ASTERISK
	JZ	GFN5B
	CPI	' '		;EXIT IF END OF NAME
	JZ	GFNX
	CALL	CLC		;CONVERT LOWER CASE
	MOV	M,A		;SAVE IN FT
	INX	H
	DCR	B		;DECREMENT COUNT
	JP	GFN5		;LOOP IF STILL ROOM
	JMP	GFNE		;ELSE ERROR
GFN5B:	DCR	B		;FILL REST OF FT WITH '?'
GFN5C:	MVI	M,'?'
	INX	H
	DCR	B
	JP	GFN5C
	CALL	GNC		;EXIT IF END OF NAME
	JC	GFNX
	CPI	' '
	JNZ	GFNE		;ELSE ERROR
GFNX:	STC			;NORMAL EXIT
	CMC
	RET
GFNE:	STC			;ERROR EXIT
	RET
 
;;	OPEN - OPEN SPECIFIED FILE
;
;	ENTRY CONDITIONS:
;
;		DE	FWA OF FCB OF FILE
;
;	EXIT CONDITIONS:
;
;		A	255 IF FILE NOT FOUND
 
OPEN:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,OFFC
	CALL	ENTRY
	POP	B
	POP	D
	POP	H
	RET
 
;;	CLOSE - CLOSE SPECIFIED FILE
;
;	ENTRY CONDITIONS:
;
;		DE	FWA OF FCB OF FILE
;
;	EXIT CONDITIONS
;
;		A	255 IF UNABLE TO CLOSE
 
CLOSE:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,CFFC
	CALL	ENTRY
	POP	B
	POP	D
	POP	H
	RET
 
;;	SRCHF - SEARCH FOR FIRST OCCURANCE (OF AFN IN DIRECTORY)
;
 
SRCHF:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,SFFC
	CALL	ENTRY
	POP	B
	POP	D
	POP	H
	RET
 
;;	SRCHN - SEARCH FOR NEXT OCCURANCE (OF AFN IN DIRECTORY)
;
 
SRCHN:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,SNFC
	CALL	ENTRY
	POP	B
	POP	D
	POP	H
	RET
 
;;	RASS - READ ASCII STRING FROM SOURCE FILE
;
;	EXIT CONDITIONS
;
;		IBUFC	NUMBER OF CHARS READ
;
;		IBUFP	POINTER TO 1ST CHAR
;
;		C-FLAG	SET IF EOF READ
 
RASS:	PUSH	H
	PUSH	B
	LXI	H,IBUF
	MOV	B,M		;B = MAX CHAR COUNT
	INX	H
	MVI	M,0
	INX	H
	SHLD	IBUFP		;SET IBUF POINTER
RASS1:	CALL	RACS		;READ NEXT CHAR FROM SOURCE
	JC	RASS3		;JUMP ON PHYSICAL EOF
	CPI	'Z'-40H		;JUMP ON LOGICAL EOF
	JZ	RASS3
	CPI	LF		;IGNORE LINE FEEDS
	JZ	RASS1
	CPI	CR		;JUMP ON END-OF-LINE
	JZ	RASS2
	INR	B		;LOOP IF NO ROOM IN IBUF
	DCR	B
	JZ	RASS1
	MOV	M,A		;STORE IN IBUF
	INX	H
	LDA	IBUFC		;INCREMENT IBUF COUNT
	INR	A
	STA	IBUFC
	DCR	B		;DECREMENT MAX COUNT
	JMP	RASS1		;LOOP
RASS2:	STC			;NORMAL EXIT
	CMC
	JMP	RASS4
RASS3:	STC			;EOF EXIT
RASS4:	POP	B
	POP	H
	RET
 
;;	RACS - READ ASCII CHARACTER FROM SOURCE
;
;	EXIT CONDITIONS
;
;		A	CHARACTER READ
;
;		C-FLAG	SET IF PHYSICAL EOF
 
RACS:	PUSH	H
	LDA	DIBUFC		;JUMP IF DISK INPUT BUFFER NOT EMPTY
	ORA	A
	JNZ	RACS1
	CALL	RDREC		;READ NEXT RECORD INTO DIBUF
	CPI	1		;BRANCH ON PHYSICAL EOF
	JZ	RACS2
	LXI	H,DIBUF		;RESET DIBUF POINTER
	SHLD	DIBUFP
	MVI	A,80H		;RESET DIBUF COUNT
RACS1:	DCR	A		;DECREMENT COUNT
	STA	DIBUFC
	LHLD	DIBUFP		;FETCH CHAR AT POINTER
	MOV	A,M
	INX	H		;INCREMENT POINTER
	SHLD	DIBUFP
	POP	H		;NORMAL EXIT
	STC
	CMC
	RET
RACS2:	POP	H		;EOF EXIT
	STC
	RET
 
;;	RDREC - READ RECORD FROM SOURCE FILE
;
 
RDREC2:	PUSH	H
	PUSH	D
	PUSH	B
	JMP	RDREC1
RDREC:	PUSH	H
	PUSH	D
	PUSH	B
	LXI	D,DIBUF
RDREC1:	MVI	C,SAFC
	CALL	ENTRY
	LXI	D,TFCB
	MVI	C,RRFC
	CALL	ENTRY
	PUSH	PSW
	LXI	D,80H
	MVI	C,SAFC
	CALL	ENTRY
	POP	PSW
	POP	B
	POP	D
	POP	H
	RET
 
;;	DELETE - DELETE EXISTING FILE
;
 
DELETE:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,DFFC
	CALL	ENTRY
	POP	B
	POP	D
	POP	H
	RET
 
;;	MAKE - MAKE NEW FILE
;
;	ENTRY CONDITIONS
;
;		DE	FWA OF FILE CONTROL BLOCK
 
MAKE:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,MFFC
	CALL	ENTRY
	POP	B
	POP	D
	POP	H
	RET
 
;;	WACD - WRITE ASCII CHARACTER TO DEST. FILE
;
;	ENTRY CONDITIONS
;
;		A	CHARACTER TO WRITE
 
WACD:	PUSH	H
	PUSH	PSW
	LDA	DOBUFC		;JUMP IF BUFFER NOT YET FULL
	CPI	128
	JC	WACD1
	CALL	WRREC		;WRITE BUFFER TO FILE
	LXI	H,DOBUF		;RESET BUFFER POINTER
	SHLD	DOBUFP
	XRA	A		;RESET BUFFER COUNT
WACD1:	INR	A		;INCREMENT BUFFER COUNT
	STA	DOBUFC
	POP	PSW		;GET CHAR BACK
	LHLD	DOBUFP		;STORE CHAR AT POINTER
	MOV	M,A
	INX	H		;INCREMENT POINTER
	SHLD	DOBUFP
	POP	H
	RET
 
;;	FLUSH - FLUSH BUFFER TO DEST. FILE
;
 
FLUSH:	PUSH	H
	PUSH	D
	MVI	A,1AH		;INSURE AT LEAST ONE EOF CHAR
	CALL	WACD
	LHLD	DOBUFP		;FETCH POINTER
	LDA	DOBUFC		;FETCH COUNT
FLUSH1:	CPI	128		;JUMP IF BUFFER FILL
	JZ	FLUSH2
	MVI	M,1AH		;INSERT ANOTHER EOF CHAR
	INX	H		;BUMP POINTER
	INR	A		;INCREMENT COUNT
	JMP	FLUSH1		;LOOP
FLUSH2:	CALL	WRREC		;WRITE BUFFER TO FILE
	LXI	D,TFCB		;CLOSE FILE
	CALL	CLOSE
	POP	D		;EXIT
	POP	H
	RET
 
;;	WRREC - WRITE NEXT RECORD TO DEST. FILE
;
 
WRREC2:	PUSH	H
	PUSH	D
	PUSH	B
	JMP	WRREC1
WRREC:	PUSH	H
	PUSH	D
	PUSH	B
	LXI	D,DOBUF
WRREC1:	MVI	C,SAFC
	CALL	ENTRY
	LXI	D,TFCB
	MVI	C,WRFC
	CALL	ENTRY
	PUSH	PSW
	LXI	D,80H
	MVI	C,SAFC
	CALL	ENTRY
	POP	PSW
	POP	B
	POP	D
	POP	H
	RET
 
;;	RASM - READ ASCII STRING FROM MODEM
;
 
RASM:	PUSH	H
	PUSH	D
	PUSH	B
	LDA	IBUF
	MOV	B,A
	MVI	C,0		;CLEAR CURRENT STRING LENGTH
	LXI	H,IBUF+2
RASM1:	CALL	RACM		;READ ASCII CHAR FROM MODEM
	CALL	WACM
	ANI	7FH
	CALL	XWACC
	CALL	CLC
	CPI	CR		;JUMP IF CR
	JZ	RASM4
	CPI	'H'-40H		;JUMP IF NOT BACKSPACE
	JNZ	RASM2
	INR	C		;IGNORE IF AT START OF LINE
	DCR	C
	JZ	RASM1
	DCR	C		;DECREMENT COUNT
	DCX	H		;DECREMENT POINTER
	CALL	WACM		;ECHO BS TO MODEM
	CALL	XWACC
	JMP	RASM1		;LOOP UNTIL CR
RASM2:	CPI	'U'-40H		;JUMP IF NOT CTRL-U
	JNZ	RASM3
	MVI	A,CR		;WRITE END OF LINE TO MODEM
	CALL	WACM
	CALL	XWACC
	MVI	A,LF
	CALL	WACM
	CALL	XWACC
	LXI	H,IBUF+2	;RESET INPUT BUFFER
	MVI	C,0
	JMP	RASM1
RASM3:	MOV	M,A		;STORE CHAR IN BUFFER
	INX	H		;INCREMENT POINTER
	INR	C		;INCREMENT COUNT
	MOV	A,C
	CMP	B		;LOOP IF STILL ROOM
	JC	RASM1
RASM4:	MOV	A,C		;SAVE BUFFER COUNT
	STA	IBUF+1
	LXI	H,IBUF+2	;RESET INPUT BUFFER POINTER
	SHLD	IBUFP
	POP	B
	POP	D
	POP	H
	RET
 
;;	RASC - READ ASCII STRING FROM CONSOLE
;
 
RASC:	PUSH	H
	PUSH	D
	PUSH	B
	LXI	D,IBUF
	MVI	C,RSFC
	CALL	ENTRY
	LXI	H,IBUF+2	;RESET INPUT BUFFER POINTER
	SHLD	IBUFP
	POP	B
	POP	D
	POP	H
	RET
 
;;	GNC - GET NEXT CHARACTER FROM IBUF
;
;	ENTRY CONDITIONS
;
;		IBUFP	POINTS TO NEXT CHAR IN IBUF
;
;		IBUFC	CONTAINS # OF CHARS LEFT
;
;	EXIT CONDITIONS
;
;		IBUFP	INCREMENTED BY ONE
;
;		IBUFC	DECREMENTED BY ONE
;
;		A	RETURNED CHARACTER
;
;		C-FLAG	SET IF END OF LINE
 
GNC:	LDA	IBUFC		;JUMP IF IBUFC > 0
	ORA	A
	JNZ	GNC1
	STC			;ELSE SET EOL FLAG, EXIT
	RET
GNC1:	DCR	A		;DECREMENT IBUFC
	STA	IBUFC
	PUSH	H
	LHLD	IBUFP		;FETCH POINTER
	MOV	A,M		;GET CHAR AT POINTER
	INX	H		;INCREMENT POINTER
	SHLD	IBUFP
	POP	H
	STC			;CLEAR EOL FLAG, EXIT
	CMC
	RET
 
;;	CCA - CHECK FOR CONSOLE ACTIVITY
;
;	EXIT CONDITIONS
;
;		A	CHARACTER READ, IF ANY
;
;		C-FLAG	SET IF CHARACTER FOUND
 
CCA:	PUSH	H
	PUSH	D
	PUSH	B
	CALL	CONST
	RRC
	JNC	CCAX
	CALL	CONIN
	STC
CCAX:	POP	B
	POP	D
	POP	H
	RET
 
;;	WDWC - WRITE DECIMAL WORD TO CONSOLE
;
;	ENTRY CONDITIONS
;
;		HL	VALUE TO WRITE IN DECIMAL
 
WDWC:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,0		;CLEAR 'DIGIT PRINTED' FLAG
	LXI	D,10000		;WRITE TEN THOUSANDS DIGIT
	CALL	WNDC
	LXI	D,1000		;WRITE THOUSANDS DIGIT
	CALL	WNDC
	LXI	D,100		;WRITE HUNDREDS DIGIT
	CALL	WNDC
	LXI	D,10		;WRITE TENS DIGIT
	CALL	WNDC
	LXI	D,1		;WRITE UNITS DIGIT
	MVI	C,1		;FORCE UNITS DIGIT TO PRINT
	CALL	WNDC
	POP	B
	POP	D
	POP	H
	RET
 
;;	WNDC - WRITE NEXT DIGIT TO CONSOLE
;
;	ENTRY CONDITIONS
;
;		HL	VALUE TO PRINT NEXT DIGIT OF
;
;		DE	DECIMAL ORDER OF MAGNITUDE
;
;		C	ZERO MEAN LEADING DIGIT NOT YET PRINTED
;
;	EXIT CONDITIONS
;
;		HL	OLD.HL - (OLD.HL / DE) * DE
;
;		C	SET IF DIGIT PRINTED
 
WNDC:	MVI	B,0		;CLEAR COUNT
WNDC1:	MOV	A,L		;HL = HL - DE
	SUB	E
	MOV	L,A
	MOV	A,H
	SBB	D
	MOV	H,A
	JC	WNDC2		;BRANCH IF HL < 0
	INR	B		;ELSE INCREMENT COUNT
	JMP	WNDC1		;AND LOOP
WNDC2:	DAD	D		;ADD DE BACK IN ONCE
	MOV	A,B		;GET COUNT
	ORA	A
	JNZ	WNDC3		;JUMP IF NON-ZERO
	INR	C		;JUMP IF DIGIT PRINTED ALREADY
	DCR	C
	JNZ	WNDC3
	MVI	A,' '		;PRINT A BLANK AND EXIT
	JMP	WACC
WNDC3:	MVI	C,1		;SET 'DIGIT PRINTED' FLAG
	ADI	'0'		;WRITE DIGIT IN ASCII
	JMP	WACC
 
;;	WHBC - WRITE HEX BYTE TO CONSOLE
;
;	ENTRY CONDITIONS
;
;		A	BYTE TO WRITE IN HEX
 
WHBC:	PUSH	PSW
	RRC
	RRC
	RRC
	RRC
	CALL	WHDC
	POP	PSW
WHDC:	PUSH	PSW
	ANI	0FH
	CPI	10
	JC	$+5
	ADI	7
	ADI	'0'
	CALL	WACC
	POP	PSW
	RET
 
;;	WASC - WRITE ASCII STRING TO CONSOLE
;
;	ENTRY CONDITIONS
;
;		HL	FWA OF STRING, TERM. BY ZERO BYTE
 
WASC:	MVI	C,0
WASC1:	MOV	A,M
	ORA	A
	RZ
	INX	H
	CPI	TAB
	JNZ	WASC3
WASC2:	MVI	A,' '
	CALL	WACC
	INR	C
	MOV	A,C
	ANI	7
	JNZ	WASC2
	JMP	WASC1
WASC3:	CALL	WACC
	INR	C
	CPI	LF
	JNZ	WASC1
	MVI	C,0
	JMP	WASC1
 
;;	WEOLC - WRITE END OF LINE TO CONSOLE
;
 
WEOLC:	MVI	A,CR
	CALL	WACC
	MVI	A,LF
	JMP	WACC
 
;;      WSPC - WRITE SPACES TO CONSOLE
;

WSPC:	MVI	A,' '		;BLANK
WSPCS:	CALL	WACC
	DCR	B
	JNZ	WSPCS
	RET

;;	WACC - WRITE ASCII CHARACTER TO CONSOLE
;
;	ENTRY CONDITIONS
;
;		A	CHARACTER TO WRITE
 
WACC:	PUSH	H
	PUSH	D
	PUSH	B
	PUSH	PSW
	MOV	B,A
	LDA	COF
	ORA	A
	JNZ	WACC1
	MOV	C,B
	CALL	CONOUT
	JMP	WACC3
WACC1:	DCR	A
	JNZ	WACC2
	MOV	A,B
	CALL	WACM
	MOV	C,B
	CALL	CONOUT
	JMP	WACC3
WACC2:	DCR	A
	JNZ	WACC3
	MOV	A,B
	CALL	WACD
WACC3:	POP	PSW
	POP	B
	POP	D
	POP	H
	RET
 
;;	XWACC - GO DIRECTLY TO CONSOLE
;
 
XWACC:	PUSH	H
	PUSH	D
	PUSH	B
	PUSH	PSW
	MOV	C,A
	CALL	CONOUT
	POP	PSW
	POP	B
	POP	D
	POP	H
	RET
 
;;	RACM - READ ASCII CHAR FROM MODEM (WITH OPTIONAL TIMEOUT)
;
;	ENTRY CONDITIONS
;
;		TIME	MILLISECONDS BEFORE TIMEOUT (FFFF=INF.)
;
;	EXIT CONDITIONS
;
;		A	CHARACTER READ (ALL 8 BITS)
;
;		C-FLAG	SET IF TIMEOUT
;
;		TOC	NUMBER OF MILLISECONDS REMAINING
 
RACM:	PUSH	H
	LHLD	TIME		;RESET TIMEOUT COUNT
	SHLD	TOC
RACM1:	IN	MSTAT		;JUMP IF DATA AVAILABLE
	ANI	RRF
	JNZ	RACM2
	LHLD	TOC		;LOOP IF INF. TIMEOUT
	INX	H
	MOV	A,H
	ORA	L
	JZ	RACM1
	DCX	H
	CALL	WAIT1		;WAIT ANOTHER MILLISECOND
	DCX	H		;DECREMENT COUNT
	SHLD	TOC
	MOV	A,H		;LOOP IF STILL NON-ZERO
	ORA	L
	JNZ	RACM1
	POP	H
	XRA	A		;RETURN NULL CHAR
	STC			;SET TIMEOUT FLAG
	RET
RACM2:	IN	MDATA		;READ DATA FROM MODEM
	POP	H
	STC			;CLEAR TIMEOUT FLAG
	CMC
	RET
 
;;	WACM - WRITE ASCII CHAR TO MODEM
;
;	ENTRY CONDITIONS
;
;		A	CHARACTER TO WRITE (ALL 8 BITS)
 
WACM:	PUSH	PSW
WACM1:	IN	MSTAT
	ANI	TRE
	JZ	WACM1
	POP	PSW
	OUT	MDATA
	RET
 
;;	CJV - CREATE (BIOS) JUMP VECTOR
;
 
CJV:	LHLD	0001H		;HL = FWA OF REAL VECTOR
	DCX	H
	DCX	H
	DCX	H
	LXI	D,BOOT		;FWA OF LOCAL VECTOR
	LXI	B,13*3		;NUMBER OF BYTES TO MOVE
	JMP	MOVE		;COPY REAL VECTOR INTO LOCAL ONE
 
;;	MOVE - MOVE BLOCK OF MEMORY
;
;	ENTRY CONDITIONS
;
;		HL	FWA OF SOURCE BLOCK
;
;		DE	FWA OF DESTINATION AREA
;
;		BC	NUMBER OF BYTES TO MOVE
 
MOVE:	MOV	A,B
	ORA	C
	RZ
	MOV	A,M
	INX	H
	STAX	D
	INX	D
	DCX	B
	JMP	MOVE
 
;;	WAIT50 - WAIT 50 MS
;
 
WAIT50:	PUSH	PSW
	PUSH	H
	LXI	H,2776
WAIT51:	DCX	H
	MOV	A,H
	ORA	L
	JNZ	WAIT51
	POP	H
	POP	PSW
	RET
 
;;	WAIT1 - WAIT 1 MS
;
 
WAIT1:	PUSH	PSW
	PUSH	H
	LXI	H,55
WAIT11:	DCX	H
	MOV	A,H
	ORA	L
	JNZ	WAIT11
	POP	H
	POP	PSW
	RET
 
;;	CR1ON - TURN ON BIT(S) ON MODEM CONTROL REG. ONE
;
;	ENTRY CONDITIONS
;
;		B	ONES IN POSITIONS TO TURN ON
 
CR1ON:	PUSH	PSW
	LDA	CR1
	ORA	B
	STA	CR1
	OUT	MSTAT
	POP	PSW
	RET
 
;;	CR1OFF - TURN BIT(S) OFF ON MODEM CONTROL REG. ONE
;
;	ENTRY CONDITIONS
;
;		B	ONES IN POSITIONS TO TURN OFF
 
CR1OFF:	PUSH	PSW
	MOV	A,B
	CMA
	MOV	B,A
	LDA	CR1
	ANA	B
	STA	CR1
	OUT	MSTAT
	POP	PSW
	RET
 
;;	CR2ON - TURN ON BIT(S) ON MODEM CONTROL REG. TWO
;
;	ENTRY CONDITIONS
;
;		B	ONES IN POSITIONS TO TURN ON
 
CR2ON:	PUSH	PSW
	LDA	CR2
	ORA	B
	STA	CR2
	OUT	MCTRL
	POP	PSW
	RET
 
;;	CR2OFF - TURN BIT(S) OFF ON MODEM CONTROL REG. TWO
;
;	ENTRY CONDITIONS
;
;		B	ONES IN POSITIONS TO TURN OFF
 
CR2OFF:	PUSH	PSW
	MOV	A,B
	CMA
	MOV	B,A
	LDA	CR2
	ANA	B
	STA	CR2
	OUT	MCTRL
	POP	PSW
	RET
 
;;	CLC - CONVERT LOWER CASE (TO UPPER CASE)
;
;	ENTRY CONDITIONS
;
;		A	CHARACTER TO CONVERT
 
CLC:	CPI	'A'+20H
	RC
	CPI	'Z'+20H+1
	RNC
	SUI	20H
	RET
 
MSG0:	DB	'CLINK V3.0',CR,LF,0
MSG1:	DB	'FILE NOT FOUND',CR,LF,0
MSG2:	DB	'DIRECTIVE ERROR',CR,LF,0
MSG3:	DB	'NO CARRIER DETECTED',CR,LF,0
MSG4:	DB	'CARRIER LOST',CR,LF,0
MSG5:	DB	'NOW DIALING ',0
MSG7:	DB	'LINK TERMINATED',CR,LF,0
MSG8:	DB	'LINK INTERRUPTED, CARRIER STILL PRESENT',CR,LF,0
MSG9:	DB	'CARRIER ALREADY PRESENT, LINK RESUMED',CR,LF,0
MSG10:	DB	CR,LF,'COMMAND>',0
MSG11:	DB	' PARITY ERRORS',CR,LF,0
MSG12:	DB	' OVERRUN ERRORS',CR,LF,0
MSG13:	DB	' FRAME ERRORS',CR,LF,0
MSG14:	DB	'ENTER DIRECTIVES - END WITH EMPTY LINE',CR,LF,0
MSG15:	DB	' TRANSMISSION ERRORS',CR,LF,0
MSG16:	DB	'MEMORY BUFFER EMPTY',CR,LF,0
MSG17:	DB	'DISK FULL',CR,LF,0
MSG18:	DB	'WRITE ERROR',CR,LF,0
MSG19:	DB	BEL,BEL,BEL,CR,LF,'*** MEMORY OVERFLOW ***',CR,LF,0
MSG20:	DB	'  |  ',0
MSG21:	DB	'NONE',CR,LF,0
MSG22:	DB	'EVEN',CR,LF,0
MSG23:	DB	'ODD ',CR,LF,0
MSG24:	DB	'ORIGINATE',CR,LF,0
MSG25:	DB	'ANSWER',CR,LF,0
MSG26:	DB	'FULL',0
MSG27:	DB	'HALF',0
MSG28:	DB	'110',CR,LF,0
MSG29:	DB	'300',CR,LF,0
MSG30:	DB	'ON ',0
MSG31:	DB	'OFF',0
MSG32:	DB	'FILE TRANSMITTED',CR,LF,0
MSG33:	DB	'FILE RECEIVED',CR,LF,0
MSG34:	DB	'RETRANSMITTING',CR,LF,0
MSG35:	DB	'TIMEOUT OCCURED',CR,LF,0
MSG36:	DB	'INVALID CRC',CR,LF,0
MSG37:	DB	'UNKNOWN MESSAGE TYPE',CR,LF,0
MSG38:	DB	'SEND ABORTED',CR,LF,0
 
HMSG0:	DB	'HELP FOR CLINK IS AVAILABLE UNDER 3 HEADINGS,',CR,LF
	DB	'AND MAY BE ACCESSED BY THE COMMAND    HELP N ',CR,LF
	DB	'WHERE N IS AN INTEGER FROM 1 TO 3 AS FOLLOWS:',CR,LF
	DB	CR,LF
	DB	'     1 - TERMINAL CONFIGURATION DIRECTIVES',CR,LF
	DB	'     2 - LOCAL COMMANDS',CR,LF
	DB	'     3 - ASR FILE TRANSMISSION/RECEPTION',CR,LF
	DB	0
 
HMSG1:	DB	'SITE			NAME OF REMOTE SITE',CR,LF
	DB	'PHONE			NUMBER OF REMOTE SITE',CR,LF
	DB	'BAUD	300,110		SET BAUD RATE',CR,LF
	DB	'PARITY	EVEN,ODD,NONE	SET PARITY',CR,LF
	DB	'DBITS	7,8		SET # OF DATA BITS',CR,LF
	DB	'SBITS	1,2		SET NUMBER OF STOP BITS',CR,LF
	DB	'MODE	ORIG,ANS	SET CARRIER FREQS, ETC.',CR,LF
	DB	'DUPLEX	FULL,HALF	REMOTE/LOCAL ECHO',CR,LF
	DB	'AUTOLF	OFF,ON		AUTO LF AFTER RCVD CR',CR,LF
	DB	'CAPS	OFF,ON		AUTO LC TO UC TRANSLATION',CR,LF
	DB	'ESCAPE	(HEX VALUE)	SET LOCAL ESCAPE CODE',CR,LF
	DB	'REMESC	(HEX VALUE)	SET REMOTE ESCAPE CODE',CR,LF
	DB	'ERROR	(HEX VALUE)	SET ERROR SUBST. CODE',CR,LF
	DB	'BREAK	(HEX VALUE)	SET BREAK TRIGGER CODE',CR,LF
	DB	0
 
HMSG2:	DB	'RETURN			RETURN TO CP/M',CR,LF
	DB	'ABORT			DISCONNECT, RETURN TO CP/M',CR,LF
	DB	'ERROR	SUMMARY		REQUEST ERROR SUMMARY',CR,LF
	DB	'RESET			CLEAR ERROR COUNTS',CR,LF
	DB	'DEBUG	OFF,ON		HEX DISPLAY OF RCVD DATA',CR,LF
	DB	'LIST			LIST CURRENT CONFIGURATION',CR,LF
	DB	'SAVE	D:FN.FT		SAVE CONFIGURATION ON FILE',CR,LF
	DB	'DIR	AFN		SAME AS CP/M DIR COMMAND',CR,LF
	DB	0
 
HMSG3:	DB     'CAPTURE			START CAPTURING RCVD DATA',CR,LF
	DB     'WRITE	D:FN.FT		WRITE CAPTURED DATA TO FILE',CR,LF
	DB     'READ	D:FN.FT		READ FILE, SEND TO MODEM',CR,LF
	DB     'GARBAGE	(HEX VALUE)	IGNORE N CHARS AFTER LF',CR,LF
	DB     'EXPAND	OFF,ON		EXPAND TABS DURING READ',CR,LF
	DB     'SEND	D:FN.FT		TRANSMIT FILE WITH PROTOCOL',CR,LF
	DB     'RECV	D:FN.FT		RECEIVE FILE WITH PROTOCOL',CR,LF
	DB     'BLOCK	N		SET MESSAGE SIZE IN PAGES',CR,LF
	DB	0
 
;	LOCAL BIOS JUMP VECTOR
 
BOOT:	DS	3		;COLD BOOT
WBOOT:	DS	3		;WARM BOOT
CONST:	DS	3		;CONSOLE STATUS
CONIN:	DS	3		;CONSOLE INPUT
CONOUT:	DS	3		;CONSOLE OUTPUT
LIST:	DS	3		;LIST OUTPUT
PUNCH:	DS	3		;PUNCH OUTPUT
READER:	DS	3		;READER INPUT
HOME:	DS	3		;HOME DISK DRIVE
SELDSK:	DS	3		;SELECT DISK DRIVE
SETTRK:	DS	3		;SET DMA ADDRESS
READ:	DS	3		;READ SECTOR
WRITE:	DS	3		;WRITE SECTOR
 
;	SCRATCH RAM AREA
 
OLDSP:	DS	2		;ENTRY STACK POINTER
STACK:	DS	128		;LOCAL STACK
 
SIZE:	DS	2		;SCRATCH LOCATION
CCPF:	DS	1		;CCP OVERWRITE FLAG
COF:	DS	1		;CONSOLE OUTPUT FLAG (FOR WACC)
 
CR1:	DS	1		;CONTROL REGISTER ONE (BUFFER)
CR2:	DS	1		;CONTROL REGISTER TWO (BUFFER)
 
CCHAR:	DS	1		;CONSOLE CHARACTER BUFFER
MCHAR:	DS	1		;MODEM CHARACTER BUFFER
 
DIBUFC:	DS	1		;DISK INPUT BUFFER COUNT
DIBUFP:	DS	2		;DISK INPUT BUFFER POINTER
DIBUF:	DS	128		;DISK INPUT BUFFER
 
DOBUFC:	DS	1		;DISK OUTPUT BUFFER COUNT
DOBUFP:	DS	2		;DISK OUTPUT BUFFER POINTER
DOBUF:	DS	128		;DISK OUTPUT BUFFER
 
SITEL:	DS	1		;LENGTH OF 'SITE' STRING
SITE:	DS	80		;SITE STRING
PHONEL:	DS	1		;LENGTH OF PHONE STRING
PHONE:	DS	20		;PHONE STRING
MODE:	DS	1		;MODE - 'A'=ANSWER 'O'=ORIGINATE
ECHO:	DS	1		;FULL/HALF DUPLEX FLAG
AUTOLF:	DS	1		;AUTO LINE-FEED FLAG
CAPS:	DS	1		;CAPS LOCK FLAG
ESCAPE:	DS	1		;ESCAPE CODE
REMESC:	DS	1		;REMOTE ESCAPE CODE
DEBUG:	DS	1		;DEBUG FLAG
DEBUGC:	DS	1		;DEBUG COUNT
ERROR:	DS	1		;ERROR CODE
GARBAGE: DS	1		;NUMBER OF GARBAGE CHARS TO IGNORE
EXPAND:	DS	1		;TAB EXPANSION FLAG
CAPTURE: DS	1		;CAPTURE FLAG
BREAK:	DS	1		;BREAK TRIGGER
 
COL:	DS	1		;COLUMN COUNTER FOR TAB EXPANSION
 
PERR:	DS	2		;PARITY ERROR COUNT
OERR:	DS	2		;OVERRUN ERROR COUNT
FERR:	DS	2		;FRAME ERROR COUNT
TERR:	DS	2		;TRANSMISSION ERROR COUNT
 
IBUFL	EQU	150		;INPUT BUFFER LENGTH
IBUFP:	DS	2		;INPUT BUFFER POINTER
IBUF:	DS	IBUFL+2		;INPUT BUFFER
IBUFC:	EQU	IBUF+1		;INPUT BUFFER COUNT
 
KWBUF:	DS	10		;KEYWORD BUFFER
 
MBUFP:	DS	2		;MEMORY BUFFER POINTER
MAXADR:	DS	2		;MAX MEMORY BUFFER ADDRESS
CCPADR:	DS	2		;FIRST WORD ADDRESS OF CCP
 
EOF:	DS	1		;END OF FILE FLAG
OCNT:	DS	2		;OUTPUT MESSAGE COUNT
OCODE:	DS	1		;OUTPUT MESSAGE TYPE
ICNT:	DS	2		;INPUT MESSAGE COUNT
ICODE:	DS	1		;INPUT MESSAGE TYPE
CRC:	DS	2		;CYCLIC REDUNDANY CHECK
BLKSZ:	DS	1		;BLOCK SIZE FOR SEND
TOC:	DS	2		;TIMEOUT COUNTER
TIME:	DS	2		;TIMEOUT INITIAL VALUE
 
	ORG	($+127)/128*128
MBUF	EQU	$			;START OF MEMORY BUFFER
MBUF2	EQU	MBUF+1024		;START OF SECOND BUFFER

	END	CLINK
