	TITLE  'MICROMODEM 100 TERMINAL PROGRAM VER. 1.2'
;COPYRIGHT 1979, HAYES MICROCOMPUTER PRODUCTS, INC.
;NOTE: MICROMODEM 100 IS A TRADEMARK OF
;      HAYES MICROCOMPUTER PRODUCTS, INC.
;
;


;	VER. 1.2	12-21-79
;
;PRINTER ON/OFF ROUTINES ADDED  12-21-79
;CAPTURE BUFFER USAGE GRAPH     1-3-80
;BUG IN "CRECV" FIXED	        12-21-79
;BUG IN "CONOUT" FIXED FOR SOL  12-21-79

;WRITTEN BY DALE A. HEATHERINGTON

	ORG	100H

CPM	EQU	1	;SET FOR CPM ASSEMBLY

BDOS	EQU	5	;CPM ENTRY
REBOOT	EQU	0	;CPM WARM BOOT


CR	EQU	0DH	;CARRIAGE RETURN
LF	EQU	0AH	;LINE FEED
BELL	EQU	7	;ASCII BELL


;MODEM I/O PORTS ARE DEFINED IN MODEM I/O SECTION.


START:	LXI	SP,STACK
	CALL	INIT		;SET UP CP/M I/O VECTORS
	LXI	D,PROMPT	;PUSH A RETURN ADDRESS ON STACK
	PUSH	D		;IN CASE CARRIER IS PRESENT
	CALL	CDSTAT		;SEE IF WE GOT CARRIER
	ORA	A
	JZ	STR1		;NO, DO INITIALIZATION
	CALL	CKRAM		;GET CHECKSUM OF RAM AREA
	MOV	C,A
	LDA	CKSUM		;GET OLD CHECKSUM
	CMP	C		;SAME?
	JZ	TALK		;RAM OK, JUMP TO COMM LOOP
	CALL	PRINT
	DB	'REENTRY NOT POSSIBLE, RAM OVERWRITTEN',CR
STR1:	CALL	RESET		;ELSE CLEAR MODEM
	LDA	7		;GET PAGE ADDRESS OF CP/M 
	SUI	1		;1 PAGE BELOW IT
	STA	MTOP		;TOP OF USER MEMORY
	XRA	A
	STA	PRNSW		;PRINTER OFF
	CALL	CRLF
	CALL	PRINT
	DB	'    Hayes Microcomputer Products, Inc.',CR
	CALL	PRINT
	DB	'Micromodem 100 Terminal program  ver. 1.2',CR
	XRA	A		;A=0
	STA	NMBR		;SET PHONE NUMBER BUFFER EMPTY
	LXI	H,DFAULT	;POINT TO COMMAND STRING
	SHLD	BUFPNT		;OF DEFAULT OPTIONS
	CALL	DEC1		;EXECUTE THE COMMANDS
	POP	D		;CLEAN UP STACK

PROMPT:	CALL	CMND		;GET AND EXECUTE COMMANDS
	JMP	PROMPT		;LOOP FOREVER


;THIS IS A COMMAND LINE THAT SETS THE DEFAULT OPTIONS.
;8 DATA BITS, 1 STOP BIT, NO PARITY, 300 BAUD, FULL DUPLEX,
;CLEAR CAPTURE BUFFER. SET DEBUG MODE OFF.

DFAULT:	DB	'L8,S1,PN,B3,F,C0,?0',CR

;DOES A CHECKSUM OF THE SCRATCH PAD RAM LOCATIONS

CKRAM:	MVI	B,EOR-SOR	;END OF RAM MINUS START OF RAM = COUNT
	LXI	H,SOR		;START OF RAM POINTER
	MVI	A,0		;A IS CHECKSUM
CKR1:	ADD	M		;ADD MEMORY BYTE
	INX	H		;INC. POINTER
	DCR	B		;COUNT 'EM
	JNZ	CKR1		;LOOP IF NOT DONE
	RET			;CHECKSUM IN REG A




;THIS ROUTINE FILLS THE COMMAND BUFFER WITH
;A COMMAND STRING FROM THE CONSOLE THEN
;DECODES AND EXECUTES THEM.

CMND:	CALL	CRLF
	CALL	PRINT
	DB	'COMMAND:@'
	CALL	FILBUF		;GET COMMANDS TO BUFFER
	ORA	A		;TEST FOR NO COMMANDS
	RZ			;RETURN IF NONE IN BUFFER

DECODE:	LXI	H,BUF		;POINT TO COMMAND BUFFER
	SHLD	BUFPNT		;SAVE POINTER
DEC1:	CALL	NEXT		;GET A COMMAND
	CPI	CR		;END OF LINE?
	RZ
	ORA	A		;DELIMITER?
	JZ	DEC1
	LXI	H,TABLE		;POINT TO DECODE TABLE
	MOV	C,A		;STORE COMMAND IN C
SRCH:	MOV	A,M		;GET BYTE FROM TABLE
	CMP	C		;DOES IT MATCH?
	JZ	FOUND		;YES, JUMP
	INX	H		;NO, ADVANCE POINTERS
	INX	H
	INX	H
	ORA	A		;TEST FOR END OF TABLE
	JNZ	SRCH
	CALL	CONOUT		;ECHO BAD COMMAND
	CALL	PRINT
	DB	' = BAD COMMAND',CR
	RET

FOUND:	LXI	D,DEC1		;RETURN ADDRESS
	PUSH	D		;PUT IT ON STACK
	INX	H
	MOV	E,M		;GET LOW BYTE OF COMMAND ADR.
	INX	H
	MOV	D,M		;GET HIGH BYTE
	XCHG			;ADDRESS TO HL
	PCHL			;CALL ROUTINE



;THIS ROUTINE GETS CHARACTERS FROM THE CONSOLE
; AND PUTS THEM IN A BUFFER.  RUBOUT WILL DELETE
; THE LAST CHARACTER TYPED. CONTROL U WILL KILL
; THE WHOLE LINE.  THE BUFFER IS 64 CHARACTERS
; LONG.


FILBUF:	LXI 	H,BUF
	MVI	B,0		;CHARACTER COUNTER
FIL1:	CALL	CONIN		;GET ONE
	CPI	7FH		;IS IT A RUBOUT?
FIL2:	JNZ	FIL3		;JUMP IF NOT
	MOV	A,B
	ORA	A		;SEE IF BUFFER EMPTY
	JZ	FILBUF
	DCX	H
	DCR	B		;BACK UP EVERYTHING
	MVI	C,5FH		;BACK ARROW CHARACTER
	CALL	CONOUT
	JMP	FIL1

FIL3:	CPI	15H		;CONTROL U?
	JNZ	FIL4
	MVI	C,'#'
	CALL	CONOUT		;ECHO #
	CALL	CRLF
	XRA	A
	RET			;RETURN A=0

FIL4:	CPI	CR		;CARRIAGE RETURN
	JNZ	FIL5
	MOV	M,A		;PUT IT IN BUFFER
	MOV	A,B		;GET COUNT
	CALL	CRLF
	RET

FIL5:	CALL	UCASE		;CONVERT TO UPPER CASE
	MOV	M,A		;PUT IT IN MEMORY
	MOV	C,A
	MVI	A,64		;MAX. LENGTH OF BUFFER
	CMP	B
	JNZ	FIL6		;JUMP IF NOT FULL
	MVI	C,'#'
	JMP	FIL7
FIL6:	INX	H
	INR	B		;ADVANCE POINTER AND COUNTER
FIL7:	CALL	CONOUT		;ECHO CHARACTER
	JMP	FIL1

;LOWER TO UPPER CASE CONVERSION ROUTINE.

UCASE:	CPI	60H
	RC			;RETURN IF ALREADY UPPER CASE
	SUI	20H		;ELSE CONVERT TO UPPER
	RET



;THIS ROUTINE GETS THE NEXT CHARACTER FROM THE BUFFER.
;IT RETURNS A=0 IF A COMMA OR SPACE IS ENCOUNTERED.

NEXT:	LHLD	BUFPNT		;GET ADDRESS OF BUFFER
	MOV	A,M		;GET A BYTE
	INX	H
	SHLD	BUFPNT		;INCREMENT AND SAVE POINTER
	CPI	20H		;SPACE?
	JZ	DELM
	CPI	','		;COMMA?
	JZ	DELM
	CPI	CR		;CARRIAGE RETURN?
	RNZ			;RETURN IF NOT
	DCX	H
	SHLD	BUFPNT
	RET
DELM:	XRA	A
	RET

;THIS ROUTINE ADVANCES THE BUFFER POINTER TO THE
;NEXT COMMAND OR DIGIT STRING.
;IF NO MORE CHARACTERS WERE FOUND IT WILL RETURN
;WITH A=0.  OTHERWISE A=1

NXTCHR:	CALL	NEXT
	MVI	C,0
	CPI	CR		;TEST FOR END OF BUFFER
	JZ	NXT1
	ORA	A		;TEST FOR DELIMITER
	JZ	NXTCHR		;JUMP IF SPACE OR COMMA
	INR	C		;C = 1
	LHLD	BUFPNT		;GET BUFFER POINTER
	DCX	H		;BACK UP ONE
	SHLD	BUFPNT		;STORE IT
NXT1:	MOV	A,C		;A=0 NONE FOUND
	RET			;A=1 CHARACTER FOUND




;GET A HEX DIGIT STRING FROM BUFFER AND
;CONVERT IT TO A 16 BIT BINARY NUMBER IN DE.


GETHEX:	LXI	H,0
GH1:	XCHG			;NUMBER TO DE
	CALL	NEXT		;GET A DIGIT
	CPI	'0'		;SEE IF IT'S HEX
	RC			;RETURN ON FIRST NON HEX CHAR.
	CPI	'G'
	RNC
	CPI	'A'
	JNC	GH2
	CPI	':'
	RNC
GH2:	SUI	30H		;REMOVE ASCII BIAS
	CPI	10
	JC	GH3		;JUMP IF DIGIT 0-9
	SUI	7		;ELSE REMOVE A-F BIAS
GH3:	XCHG			;NUMBER TO HL
	DAD	H		;SHIFT LEFT 4 BITS
	DAD	H
	DAD	H
	DAD	H
	ADD	L		;ADD IN THIS DIGIT
	MOV	L,A
	JMP	GH1



;SEND CARRIAGE RETURN-LINE FEED TO CONSOLE

CRLF:	CALL	PRINT
	DB	CR
	RET


;PRINTS A STRING POINTED TO BY CONTENTS OF TOP
; OF STACK. CARRIAGE RET. OR "@" TERMINATES THE STRING.
; "@" WILL PRINT STRING WITH NO CR-LF SEQUENCE AT END.


PRINT:	XTHL			;TOP OF STACK TO HL
	PUSH	PSW		;SAVE REGISTERS
	PUSH	B
PRN1:	MOV	A,M		;GET A CHARACTER
	INX	H
	CPI	'@'		;END?
	JZ	PRN2		;JUMP IF END, NO CRLF
	MOV	C,A
	CALL	CONOUT		;PRINT THE CHAR.
	CPI	CR		;WAS IT A CARRIAGE RET.?
	JNZ	PRN1		;NO, GO BACK FOR MORE
	CALL	PRINT		;CALL OURSELF
	DB	LF,0,0,0,'@'	;LINE FEED AND 3 NULLS
PRN2:	POP	B		;RESTORE REGISTERS
	POP	PSW
	XTHL			;RETURN ADDRESS TO STACK
	RET



;RETURNS TO USERS OPERATING SYSTEM


QUIT:	CALL	CRLF
	CALL	SHSTAT	;GET SWITCH-HOOK STATUS
	ORA	A
	JZ	REBOOT
	CALL	PRINT
	DB	'DO YOU WANT TO HANG UP FIRST? (Y OR N)@'
	CALL	CONIN
	CALL	UCASE
	MOV	C,A
	CALL	CONOUT
	MOV	A,C
	CPI	'N'
	JNZ	QUIT1
	CALL	CKRAM		;GET CURRENT RAM CHECKSUM
	STA	CKSUM		;SAVE IT
	JMP	REBOOT		;BACK TO CPM
QUIT1:	CALL	HANGUP
	JMP	REBOOT


;THIS ROUTINE DIALS A PHONE NUMBER THEN JUMPS TO
;THE COMMUNICATION ROUTINE.
;IF NO PHONE NUMBER FOLLOWS THE "D" COMMAND THE
;LAST NUMBER DIALED WILL BE RE-DIALED.

DIAL:	CALL	PRINT
	DB	'DIALING-@'
	CALL	DLTONE		;GET A DIAL TONE
	CALL	NXTCHR		;FIND PHONE NO. IN BUFFER
	ORA	A
	JZ	DL1		;PHONE NUMBER NOT PRESENT
	LXI	D,NMBR-1	;POINT TO PHONE NO. BUFFER
DL0:	CALL	NEXT		;GET A DIGIT
	INX	D		;ADVANCE POINTER
	STAX	D		;PUT IT IN BUFFER
	ORA	A
	JZ	DL1
	CPI	CR
	JNZ	DL0		;IF NOT END, LOOP BACK
	XRA	A		;A=0
	STAX	D		;ZERO MARKS END OF NUMBER
DL1:	LXI	H,NMBR		;POINT TO NUMBER BUFFER
DL2:	MOV	A,M		;GET A DIGIT
	INX	H		;ADVANCE POINTER
	ORA	A		;TEST FOR END
	JZ	COMM		;GO TRY TO COMMUNICATE
	MOV	C,A
	CALL	CONOUT		;ECHO DIGIT WE'RE DIALING
	MOV	A,C
	MVI	C,40
	CPI	'*'		;2 SECOND DELAY?
	PUSH	PSW
	CZ	DELAY		;YES, WAIT 2 SEC.
	POP	PSW
	JZ	DL2
	CPI	3AH		;IGNORE ALL XCEPT DIGITS
	JNC	DL2
	CPI	'0'
	JC	DL2
	MOV	C,A
	CALL	PULSE		;DIAL THE DIGIT
	JMP	DL2		;LOOP BACK FOR MORE


;THIS ROUTINE WAITS FOR THE PHONE TO RING.
;IT THEN ANSWERS ON THE FIRST RING, TURNS ON
;THE CARRIER, THEN JUMPS TO "COMM1" AND WAITS
;FOR A RECEIVE CARRIER.

ANSWR:	CALL	NEXT		;GET NEXT CHARACTER
	CPI	'A'		;A=ANSWER WITHOUT A RING
	JZ	ANS2		;IN ANSWER MODE
	CPI	'O'		;O=ANSWER WITHOUT A RING
	JZ	COMM		;IN ORIGINATE MODE
	CALL	PRINT		;ELSE WAIT FOR RING
	DB	'WAITING FOR RING. PRESS ANY KEY TO ABORT.',CR
ANS1:	CALL	RISTAT		;CHECK FOR PHONE RINGING
	ORA	A
	JNZ	ANS2		;IF YES THEN ANSWER IT
	CALL	CONST		;ABORT?
	ORA	A
	JZ	ANS1		;NO, LOOP BACK
	CALL	CONIN		;GET CHARACTER
	RET			;ABORT
ANS2:	CALL	PRINT
	DB	BELL,'ANSWERING CALL',CR
	MVI	C,1
	CALL	SWHOOK		;ANSWER PHONE
	MVI	A,0		;A=0 FOR ANSWER MODE
	STA	MFLAG
	MOV	C,A
	CALL	MODE		;SET TO ANSWER MODE
	MVI	C,1
	CALL	TXON		;TURN ON TRANSMIT CARRIER
	JMP	COMM1




;THIS ROUTINE WAITS FOR A CARRIER THEN GOES INTO
;THE TELETYPE MODE FOR COMMUNICATIONS.

COMM:	CALL	CRLF
	MVI	A,1		;ORIGINATE MODE
	STA	MFLAG		;SET TO  MODE
	MOV	C,A
	CALL	MODE
COMM1:	MVI	E,30		;SET FOR 30 SECONDS
	CALL	PRINT
	DB	'WAITING FOR CARRIER, PRESS ANY KEY TO ABORT.',CR
CM1:	MVI	C,20		;FOR 1 SECOND DELAY
	CALL	DELAY		;WAIT A SECOND
	CALL	CDSTAT		;LOOK FOR A CARRIER
	ORA	A		;SET FLAGS
	JNZ	TALK
	CALL	CONST		;CHECK CONSOLE
	ORA	A
	JNZ	CM2		;ABORT IF ANY KEY PRESSED
	DCR	E		;COUNT SECONDS
	JNZ	CM1		;LOOP 30 TIMES
CM2:	CALL	PRINT
	DB	'NO CARRIER RECEIVED',BELL,CR
	CALL	CONST		;CHECK CONSOLE
	ORA	A
	CNZ	CONIN		;THROW AWAY CHARACTER
	JMP	HANGUP

;THIS IS THE COMMUNICATIONS LOOP. CHARACTERS FROM THE
;LINE ARE SENT TO THE CONSOLE.  CHRACTERS FROM THE
;CONSOLE ARE SENT TO THE PHONE LINE.


TALK:	CALL	CDSTAT
	ORA	A
	JZ	TLK2
	MVI	C,1
	CALL	TXON		;TURN ON CARRIER
	CALL	PRINT
	DB	'CONNECTION ESTABLISHED',CR
TLK1:	CALL	CONST		;CHECK FOR CONSOLE CHAR.
	ORA	A
	CNZ	CSEND		;SEND IT IF PRESENT
	CALL	RXSTAT		;SEE IF MODEM HAS A CHARn
	ORA	A
	CNZ	CRECV		;GET IT IF PRESENT
	CALL	CDSTAT		;CHECK FOR CARRIER
	ORA	A
	JNZ	TLK1		;IF CARRIER, CONTINUE
TLK2:	CALL	CRLF
	CALL	PRINT
	DB	'[* LOST CARRIER *]',BELL,CR
	JMP	HANGUP


;SEND A CHARACTER TO MODEM.
;CONSOLE CHARACTERS ARE CHECKED FOR 2 CONTROL CODES.
;CONTROL A WILL ESCAPE TO THE COMMAND MODE.
;CONTROL B WILL CAUSE A BREAK TO BE TRANSMITTED.
;NOTE THAT CONTROL A OR B CAN'T BE SENT TO THE MODEM.


CSEND:	CALL	CONIN		;GET CHAR. FROM CONSOLE
	CPI	1		;CONTROL A?
	JZ	CMND		;BACK TO COMMAND MODE
	MVI	C,3		;PREPARE FOR 150 MS BREAK
	CPI	17H		;CONTROL W?
	JZ	BREAK		;YES, SEND BREAK
	MOV	C,A
XMIT:	CALL	TXCHR		;SEND TO MODEM
	LDA	MFLAG		;GET MODE 0=ANS 1=ORG
	ORA	A
	JZ	CONOUT		;ECHO IF ANSWER MODE
	LDA	DPLX		;GET DUPLEX FLAG 1=FULL
	ORA	A
	JZ	CONOUT		;ECHO IF HALF DUPLEX
	RET


;RECEIVES CHARACTERS FROM THE MODEM AND SENDS THEM
; TO THE CONSOLE.  IF IN FULL DUPLEX ANSWER MODE THE
; CHARACTERS WILL BE ECHOED BACK TO THE MODEM.  IN
; ORIGINATE MODE OR HALF DUPLEX CHARACTERS WILL NOT
;BE ECHOED BACK.
;IT ALSO CALLS THE CAPTURE ROUTINE WHICH WILL PUT
;THE RECEIVED CHARACTERS IN THE BUFFER IF IT IS ENABLED.


CRECV:	CALL	RXCHR		;GET CHARACTER FROM MODEM
	MOV	C,A
	LDA	BUGFLAG		;SEE IF WE PRINT IT IN HEX
	ORA	A
	JZ	REC1		;JUMP IF NOT HEX DISP. MODE
	PUSH	B		;SAVE CHARACTER IN C
	CALL	PRNHEX
	MVI	C,20H		;ASCII SPACE
	CALL	CONOUT		;SPACE BETWEEN HEX NUMBERS
	LDA	BUGCOUNT
	DCR	A
	STA	BUGCOUNT
	ANI	0FH
	CZ	CRLF
	POP	B		;RESTORE CHARACTER IN C
	JMP	REC2
REC1:	CALL	ERFLG		;GER __T ERROR FLAGS
	ANI	1
	JZ 	REC3
	MVI	C,'#'		;# SUBS FOR CHAR. WITH PARITY ERROR
REC3:
	MOV	A,C
	ANI	7FH		;KILL MSB
	MOV	C,A
	CALL	CONOUT		;SEND TO CONSOLE
REC2:	CALL	CPBFIL		;ALSO TO CAPTURE BUFFER
	LDA	MFLAG		;GET MODE  1=ORG 0=ANS
	ORA	A
	RNZ			;DON'T ECHO TO LINE IF ORIG.
	LDA	DPLX		;GET DUPLEX FLAG  1=FULL
	ORA	A
	JNZ	TXCHR		;ECHO BACK TO SENDER
	RET


;PRINTS INCOMMING CHARACTERS IN HEX WITH THE MODEM STATUS WORD.

PRNHEX:	PUSH	B	;CHARACTER IS IN C, SAVE IT
	MOV	A,C
	RRC
	RRC
	RRC
	RRC
	CALL	PRNH1
	POP	B	;RESTORE CHARACTER
	PUSH	B	;SAVE AGAIN
	MOV	A,C
	CALL	PRNH1	;PRINT LOW NIBBLE
	POP	B
	RET

PRNH1:	ANI	0FH	;KEEP LOW 4 BITS
	ADI	30H	;ASCII BIAS ADDED
	MOV	C,A
	CPI	3AH
	JC	CONOUT
	MVI	A,7
	ADD	C	;MAKE LETTER A-F
	MOV	C,A
	JMP	CONOUT





;THIS ROUTINE HANGS UP AND TURNS OFF THE TX CARRIER.

HANGUP:	MVI	C,0
	CALL	TXON		;TRANSMIT CARRIER OFF
	MVI	C,0
	CALL	SWHOOK		;GO ON-HOOK
	CALL	PRINT
	DB	'[ HUNG UP ]',BELL,CR
	MVI	C,20		;SET FOR 1 SECOND DELAY
	CALL	DELAY		;WAIT FOR THINGS TO DISCONNECT
	RET


;***** THE FOLLOWING ROUTINES SET OPTIONS ******

;NOTE THAT MOST DON'T CHECK FOR VALID RANGE OF VARIABLES.
;IT IS POSSIBLE FOR EXAMPLE TO SET THE STOP BITS TO 7 OR 9
;OR OTHER IMPOSSIBLE NUMBER.  IN THIS CASE 1 OR 2 STOP BITS
;WOULD ACTUALLY BE SET EVEN THOUGH NO ERROR MESSAGE WAS
;GENERATED.



;THIS ROUTINE LETS THE USER CHANGE THE BAUD RATE.

BRATE:	CALL	GETHEX		;GET A DIGIT
	MOV	A,E
	CPI	1		;110 BAUD?
	JZ	BR110
	CPI	3
	JNZ	BADBR		;BAD IF NOT 110 OR 300
	CALL	PRINT
	DB	'300 BAUD',CR
	MVI	C,1
	JMP	BAUD		;SET RATE

BR110:	CALL	PRINT
	DB	'110 BAUD',CR
	MVI	C,0
	JMP	BAUD

BADBR:	CALL	PRINT
	DB	'BAD BAUD RATE',CR
	RET

;SETS DATA WORD LENGTH TO 5 6 7 OR 8 BITS.

LENGTH:	CALL	GETHEX		;GET LENGTH
	CALL	PDIGIT		;PRINT IT
	CALL	PRINT
	DB	' DATA BITS',CR
	MOV	C,E
	JMP	WLS		;SET MODEM BOARD


PDIGIT:	MVI	A,30H
	ADD	E		;MAKE NUMBER IN E ASCII
	MOV	C,A
	CALL	CONOUT		;PRINT IT
	RET


;SET NUMBER OF STOP BITS ( 1 OR 2).

SBITS:	CALL	GETHEX
	CALL	PDIGIT
	CALL	PRINT
	DB	' STOP BITS',CR
	MOV	C,E
	JMP	NSTOP		;SET THE MODEM


;SETS FULL DUPLEX MODE  ( F COMMAND)

FULL:	MVI	A,1
	STA	DPLX		;SET FLAG
	CALL	PRINT
	DB	'FULL DUPLEX',CR
	RET

;SET HALF DUPLEX MODE  (H COMMAND)

HALF:	XRA	A
	STA	DPLX		;CLEAR FLAG
	CALL	PRINT
	DB	'HALF DUPLEX',CR
	RET


;SET PARITY,  N=NO PARITY   E=EVEN PARITY  O=ODD PARITY


PARTYP:	CALL	NXTCHR		;FIND NEXT CHARACTER IN BUFF.
	CALL	NEXT		;GET IT
	CPI	'N'
	JZ	NPAR
	CPI	'E'
	JZ	EPAR
	CPI	'O'
	JZ	OPAR
	RET

NPAR:	CALL	PRINT
	DB	'NO PARITY',CR
	MVI	C,0
	JMP	PARITY

EPAR:	CALL	PRINT
	DB	'EVEN PARITY',CR
	MVI	C,2
	JMP	PARITY

OPAR:	CALL	PRINT
	DB	'ODD PARITY',CR
	MVI	C,1
	JMP	PARITY

;THIS ROUTINE ALLOWS THE USER TO JUMP TO
;AN EXTERNAL PROGRAM AND EXECUTE IT.
;FOR EXAMPLE, IF YOU HAD A ROM MONITOR
;AT F000 HEX, YOU WOULD ENTER THE COMMAND: J F000
;

JUMP:	CALL	NXTCHR		;FIND ADDRESS
	CALL	GETHEX		;CONVERT TO BINARY IN DE
	PUSH	D		;SAVE JUMP ADDRESS
	CALL	CKRAM		;GET RAM CHECKSUM
	STA	CKSUM		;STORE IT
	POP	H		;GET JUMP ADDRESS TO HL
	LXI	D,XRET		;A RETURN ADDRESS
	PUSH	D		;PUT IN ON STACK
	PCHL			;CALL EXTERNAL ROUTINE 
XRET:	RET			;

;THIS ROUTINE SETS UP THE THE CAPTURE FUNCTION
;COMMAND FORMAT:   C0  RESETS THE BUFFER POINTER
;AND DISABLES CAPTURE.
;C1   ENABLES CAPTURE AT CURRENT BUFFER ADDRESS
;C2   STOPS CAPTURE AT CURRENT ADDRESS.
;C?   PRINTS A BAR GRAPH OF BUFFER USAGE.


CAPTURE:
	CALL	NXTCHR		;FIND DIGIT
	ORA	A
	RZ			;RETURN IF NO ARG.
	CALL	NEXT		;GET DIGIT
	CPI	'?'		;WANT STATUS?
	JZ	SEECAP
	CPI	'0'
	JZ	RSBUF		;IF ZERO, RESET
	CPI	'1'		
	JZ	STRT		;IF 1 START CAPTURE MODE
	CPI	'2'		
	RNZ			;IF 2 STOP CAPTURE
	XRA	A
	STA	CPFLAG		;CLEAR CAPTURE FLAG
	CALL	PRINT
	DB	'CAPTURE STOPED',CR
	RET

STRT:	MVI	A,1
	STA	CPFLAG		;SET CAPTURE FLAG
	CALL	PRINT
	DB	'CAPTURE ENABLED',CR
	RET

RSBUF:	LXI	H,CPBUF		;START OF CAPTURE BUFFER
	SHLD	CBUFP		;STORE POINTER
	XRA	A
	STA	CPFLAG		;CLEAR FLAG
	STA	CPCNT		;CLEAR BYTE COUNTER
	STA	CPCNT+1
	CALL	PRINT
	DB	'CAPTURE BUFFER CLEARED',CR
	RET

;THIS ROUTINE FILLS THE CAPTURE BUFFER WITH CHARACTERS
;FROM THE MODEM IF THE "CPFLAG" IS SET TO A 1.
;THE BUFFER POINTER IS STORED AT "CBUFP".

CPBFIL:	LDA	CPFLAG		;GET FLAG
	ORA	A
	RZ			;RETURN IF NOT ENABLED
	PUSH	H		;SAVE HL
	LHLD	CBUFP		;GET BUFFER POINTER
	MOV	M,C		;PUT CHARACTER IN BUFFER
	INX	H		;ADVANCE POINTER
	LDA	MTOP		;TOP OF MEMORY
	CMP	H		;CHECK FOR "OUT OF MEMORY"
	JZ	OUTMEM
	SHLD	CBUFP		;SAVE POINTER
	LHLD	CPCNT		;GET CHARACTER COUNTER
	INX	H		;INCREMENT IT
	SHLD	CPCNT		;STORE IT
	POP	H
	RET

OUTMEM:	CALL	CRLF
	CALL	PRINT
	DB	'CAPTURE BUFFER FULL',BELL,CR
	XRA	A
	STA	CPFLAG		;DISABLE CAPTURE MODE
	POP	H
	RET


;TYPES THE CAPTURE BUFFER TO THE CONSOLE.


;T   WILL TYPE STARTING AT THE BEGINNING
;T FOLLOWED BY A HEX NUMBER WILL CAUSE PRINTING TO
;START AT A POINT SPECFIED BY THE NUMBER. FOR EXAMPLE
;T 100   WILL START TYPING AT A POINT 100 HEX
;CHARACTERS INTO THE BUFFER.  S STARTS
;AND STOPS THE PRINTING. CARRIAGE RETURN ABORTS
;THIS FUNCTION.

TYPE:	CALL	GETHEX
	LXI	H,CPBUF		;STARTING ADDRESS OF BUFFER
	DAD	D		;ADD USERS COUNT TO STARTING ADR.
TY1:	LDA	CPCNT		;SEE IF WE'RE AT END 
	CMP	E
	JNZ	TY0
	LDA	CPCNT+1
	CMP	D
	RZ			;QUIT AT END OF BUFFER
TY0:	MOV	C,M		;GET A CHARACTER
	CALL	CONOUT		;PRINT IT
	CALL	CONST		;CHECK FOR CONSOLE INPUT
	ORA	A
	JZ	TY2
	CALL	CONIN		;GET CONSOLE
	CPI	CR		;WANT TO ABORT?
	RZ			;IF YES THEN RETURN
	CPI	'S'		;WANT TO STOP?
	JNZ	TY2
TY3:	CALL	CONST
	ORA	A
	JZ	TY3		;WAIT FOR ANOTHER S
	CALL	CONIN
	CPI	CR
	RZ
	CPI	'S'
	JNZ	TY3
TY2:	INX	H		;ADVANCE POINTERS
	INX	D
	JMP	TY1		;LOOP BACK FOR MORE


DEBUG:	CALL	NEXT
	CPI	'0'
	JZ	DBOFF
	CPI	'1'		;DEBUG ON?
	RNZ
	CALL	PRINT
	DB	'DEBUG MODE ON',CR
	MVI	A,1
	STA	BUGFLAG
	DCR	A
	STA	BUGCOUNT
	RET
DBOFF:	CALL	PRINT
	DB	'DEBUG MODE OFF',CR
	XRA	A
	STA	BUGFLAG
	RET
;
;THIS TURNS THE LIST DEVICE ON OR OFF. 
; Q1 TURNS IT ON   Q0 TURNS IT OFF.
;
LSTONOFF:
	CALL	NEXT
	CPI	'0'		;OFF
	JZ	LSTOFF
	CPI	'1'		;ON
	RNZ
	CALL	PRINT
	DB	'PRINTER ON',CR
	MVI	A,1
	STA	PRNSW
	RET
LSTOFF:	XRA	A
	STA	PRNSW
	CALL	PRINT
	DB	'PRINTER OFF',CR
	RET

;THIS ROUTINE PRINTS A HORZ. BAR GRAPH OF THE CAPTURE
;BUFFER USAGE.  EACH "-" IS A KILOBYTE.

SEECAP:	LDA	MTOP	;GET TOP OF RAM PAGE
	LXI	B,CPBUF		;GET START OF CAPTURE BUFFER
	SUB	B		;TOTAL PAGES AVALABLE NOW IN A
	RAR			;DIVIDE BY 4 TO GET K BYTES
	RAR
	ANI	3FH
	MOV	B,A		;K BYTES IN B
	CALL	PRINT
	DB	'AVALABLE:@'
	CALL	BARGRAF
	LHLD	CPCNT		;GET BYTES USED
	MOV	A,H		;PAGES USED TO A
	RAR			;DIVIDE BY 4 TO GET K BYTES
	RAR
	ANI	3FH
	MOV	B,A		;K BYTES USED IN B
	CALL	PRINT
	DB	'    USED:@'
BARGRAF:
	MOV	A,B
	ORA	A
	RZ			;RETURN IF ZERO
BG1:	CALL	PRINT
	DB	'-@'
	DCR	B		;COUNT K
	JNZ	BG1
	JMP	CRLF

;


;THIS IS THE COMMAND DECODING TABLE.

;EACH ENTRY IS AN ASCII LETTER FOLLOWED BY AN ADDRESS
;OF THE ROUTINE WHICH IS CALLED TO EXECUTE THAT COMMAND.
;THE END OF THE TABLE IS MARKED WITH A ZERO.



TABLE:	DB	'X'		;EXIT TO CP/M
	DW	QUIT
	DB	'D'		;DIAL A NUMBER
	DW	DIAL
	DB	'A'		;ANSWER CALLS
	DW	ANSWR
	DB	'G'		;"GOODBYE" HANG UP PHONE
	DW	HANGUP
	DB	'B'		;CHANGE BAUD RATE
	DW	BRATE
	DB	'S'		;SET STOP BITS
	DW	SBITS
	DB	'L'		;SET DATA WORD LENGTH
	DW	LENGTH
	DB	'P'		;SET PARITY MODE
	DW	PARTYP
	DB	'F'		;SET FULL DUPLEX
	DW	FULL
	DB	'H'		;HALF DUPLEX
	DW	HALF
	DB	'J'		;JUMP TO ADDRESS
	DW	JUMP
	DB	'C'		;CAPTURE
	DW	CAPTURE
	DB	'T'		;TYPE BUFFER TO CONSOLE
	DW	TYPE
	DB	'W'		;WRITE CAPTURE BUFFER TO DISK
	DW	SAVE
	DB	'R'		;READ AND TRANSMIT DISK FILE
	DW	READ
	DB	'?'		;SET TO DEBUG MODE
	DW	DEBUG
	DB	'Q'		;PRINTER ENABLE/DISABLE
	DW	LSTONOFF
	DB	0		;END OF TABLE
;*********** OPTIONAL DISK I/O AREA ************************


;THESE ROUTINES ALLOW YOU TO SAVE THE CONTENTS OF
;THE CAPTURE BUFFER ON THE DISK.  IF YOU DON'T HAVE
;THE CP/M DISK OPERATING SYSTEM THEY WON'T WORK.


;DISK I/O ROUTINES

DELETE:	LXI	D,FCB
	MVI	C,19
	JMP	BDOS

MAKE:	LXI	D,FCB
	MVI	C,22
	JMP	BDOS

SETDMA:	PUSH	H
	MVI	C,26
	CALL	BDOS
	POP	H
	RET

WRITENR:
	PUSH	H
	LXI	D,FCB
	MVI	C,21
	CALL	BDOS
	POP	H
	RET

READNR:
	PUSH	H
	LXI	D,FCB
	MVI	C,20
	CALL	BDOS
	POP	H
	RET

CLOSE:	LXI	D,FCB
	MVI	C,16
	JMP	BDOS

OPEN:	LXI	D,FCB
	MVI	C,15
	JMP	BDOS


;GET NAME OF FILE FROM CONSOLE BUFFER TO FILE CONTTROL BLOCK

GETNAME:
	CALL	NXTCHR		;SET BUFFER POINTER TO FILE NAME
	ORA	A		;TEST FOR NO FILE NAME
	RZ			;RETURN IF NONE ENTERED
	LXI	H,ET	;POINT TO ENTRY TYPE
	XRA	A		;ZERO A
	MVI	B,12		;LOAD COPUTER
G1:	MOV	M,A		;FILL FCB AREA WITH 0 + 11 SPACES
	MVI	A,20H		;A SPACE
	INX	H		;BUMP POINTER
	DCR	B		;COUNT'EM
	JNZ	G1
MVI	B,8			;MAX OF 8 CHARS. IN FILE NAME
	LXI	D,FNAME		;POINT TO FCB FILE NAME AREA
	CALL	MVNAM		;MOVE NAME FROM BUFFER TO FCB
	CPI	'.'
	JNZ	G2		;IF NO PERIOD THEN NO FILE TYPE
	LXI	D,FTYPE		;POINT TO FILE TYPE AREA
	MVI	B,3		;MAX OF 3 CHARS. IN FILE TYPE
	CALL	MVNAM		;MOVE TYPE INTO FCB AREA
G2:	LXI	H,EX		;FILL REST OF FCB WITH ZEROS
	MVI	B,(NR+1)-EX	;COUNTER
GG3:	MVI	M,0
	INX	H
	DCR	B
	JNZ	GG3
	LXI	D,80H		;SET DMA ADDRESS TO 80H
	CALL	SETDMA
	RET


;MOVES STRINGS FROM CONSOLE BUFFER TO FCB AREA
;DE POINT TO DESTINATION
;B HAS NUMBER OF CHARACTERS TO MOVE

MVNAM:	CALL	NEXT		;GET NEXT CHARACTER
	CPI	'.'		;END OF FILE NAME?
	RZ
	CPI	CR		;END OF LINE?
	RZ
	CPI	0		;DELIMITER?
	RZ
	STAX	D		;PUT CAHRACTER IN FCB
	INX	D		;ADVANCE POINTER
	DCR	B
	JNZ	MVNAM		;LOOP IF MORE CHARACTERS
	JMP	NEXT		;GET NEXT CHARACTER AND RETURN



;DISK FILE TRANSMIT ROUTINE

READ:	CALL	GETNAME		;GET FILE NAME
	CALL	OPEN
	CPI	255	;OK?
	JNZ	R1		;JUMP IF OPEN IS OK
	CALL	PRINT
	DB	'NOT FOUND',CR
	RET
R1:	CALL	READNR		;READ 128 BYTES INTO 80H BUFFER
	CALL	TXBUF		;TRANSMIT THE BUFFER CONTENTS
	CPI	1AH		;CONTROL Z (END OF FILE)
	JNZ	R1
	CALL	CLOSE
	RET

;TRANSMITS THE CONTENTS OF THE DISK BUFFER

TXBUF:	LXI	H,80H
	MVI	B,128
TXB1:	MOV	C,M		;GET A CHARACTER
	CALL	XMIT		;TRANSMIT IT
	MOV	A,C
	CPI	1AH		;END OF FILE?
	RZ			;YES RETURN
	CPI	CR		;END OF LINE?
	CZ	WTRPLY		;WAIT FOR POSSIBLE PROMPT
	CALL	RXSTAT		;SEE IF CHAR. HAS BEEN RECEIVED
	ORA	A
	CNZ	CRECV		;GET IT AND SEND TO CONSOLE
	CALL	CDSTAT		;CHECK FOR CARRIER
	ORA	A
	JZ	ABRT		;ABORT IF NO CARRIER
	CALL	CONST		;WANT TO ABORT?
	ORA	A
	JZ	TXB2		;JUMP IF NOT
	CALL	CONIN		;ABORT ON ANY KEY PRESSED
ABRT:	MVI	A,1AH		;FAKE OUT THE CALLING ROUTINE
	RET

TXB2:	INX	H		;BUMP BUFFER POINTER
	DCR	B		;COUNT BYTES
	JNZ	TXB1
	RET

;THIS ROUTINE WAITS FOR 150 MS AFTER THE LAST
;CHARACTER IS RECEIVED BY THE MODEM.

WTRPLY:	PUSH	B
	CALL	RXSTAT
	ORA	A
	CNZ	RXCHR		;FLUSH UART
WTRP1:	MVI	B,3		;150 MS
WTRP2:	CALL	STIME		;START TIMER
WTRP3:	CALL	RXSTAT		;MODEM CHAR. RECEIVED?
	ORA	A
	PUSH	PSW		;SAVE STATUS
	CNZ	CRECV		;GET AND SEND TO CONSOLE
	POP	PSW		;POP FLAGS AGAIN
	JNZ	WTRP1		;IF CHARACTER REC. LOOP BACK
	CALL	CKTIME		;TIME UP?
	ORA	A
	JZ	WTRP3		;NO, LOOP BACK
	DCR	B		;COUNT LOOPS
	JNZ	WTRP2		;LOOP IF NOT 150 MS
	POP	B		;RESTORE BC
	RET



;THIS ROUTINE STORES THE CONTENTS OF THE CAPTURE
;BUFFER ON THE DISK.



SAVE:	CALL	GETNAME
	CALL	DELETE	;ERASE OLD FILE OF SAME NAME
	CALL	MAKE	;MAKE NEW FILE
	CPI	255
	JNZ	S1
	CALL	PRINT
	DB	'NO DIRECTORY SPACE',CR
	RET

S1:	CALL	OPEN
	LHLD	CBUFP		;CAPTURE BUFFER POINTER
	XCHG			;POINTER TO DE
	LHLD	CPCNT		;BUFFER CAHRACTER COUNT
S2:	MVI	A,1AH		;END OF FILE MARKER
	STAX	D
	INX	D
	INX	H		;FILL OUT WITH 1A'S TILL
	MOV	A,L		;EVEN WITH 128 BYTE BOUNDRY
	ANI	7FH
	JNZ	S2
	DAD	H		;SHIFT HL LEFT 1 BIT
	ACI	0		;SHIFT CARRY INTO REG. A
	MOV	B,A		;MSB OF RECORD COUNT TO B
	MOV	C,H		;LSB OF RECORD COUNT IN C
	INX	B		;ADD 1 MORE
	LXI	D,CPBUF		;CAPTURE BUFFER START ADDRESS
S3:	PUSH	B		;SAVE RECORD COUNT
	PUSH	D		;SAVE BUFFER POINTER
	CALL	SETDMA		;DMA=BUFFER
	CALL	WRITENR		;WRITE A RECORD TO DISK
	ORA	A		;CHECK FOR ERROR
	JNZ	ERRR
	POP	D		;GET CAPTURE BUFFER POINTER
	LXI	H,128
	DAD	D		;ADVANCE IT 128 BYTES
	XCHG
	POP	B		;GET RECORD COUNT
	DCX	B		;COUNT 1
	MOV	A,B
	ORA	C		;TEST FOR ZERO
	JNZ	S3		;IF NOT ZERO, LOOP BACK
	LXI	D,80H		;RESET DMA TO 80H
	CALL	SETDMA
	CALL	CLOSE
	CPI	255
	JNZ	RSBUF		;CLEAR CAPTURE BUFFER 
	CALL	PRINT
	DB	'CANNOT CLOSE FILE',CR
	RET


ERRR:	POP	H
	POP	H	;CLEAN UP STACK
	CALL	PRINT
	DB	'OUT OF SPACE',CR
	RET








;******* CONSOLE I/O AREA FOR CP/M ******************



;CONSOLE INPUT
;IT RETURNS THE CHARACTER IN REGISTER A



CONIN:	PUSH	H
	PUSH	D
	PUSH	B
	CALL	XCONIN
	ANI	7FH		;KILL MSB
	POP	B
	POP	D
	POP	H
	RET


;CONSOLE STATUS CHECK
;RETURNS WITH A=0 IF NO CHARACTER TYPED
;OR A=1 IF CHARACTER HAS BEEN TYPED (OR A= NOT ZERO)

CONST:	PUSH	H
	PUSH	D
	PUSH	B
	CALL	XCONST
	POP	B
	POP	D
	POP	H
	RET


;CONSOLE OUTPUT.  CHARACTER TO BE PRINTED MUST BE IN
; REG. C


CONOUT:	PUSH	H
	PUSH	D
	PUSH	B
	CALL	XCONOT
	POP	B
	POP	D
	POP	H
	LDA	PRNSW		;GET PRINTER SWITCH
	CPI	1
	MOV	A,C		;RECOVER CHARACTER
	RNZ			;RETURN IF PRINTER NOT ENABLED
				;ELSE FALL INTO LIST BELOW
;
;
;SEND DATA TO LIST DEVICE
;
LIST:	PUSH	H
	PUSH	D
	PUSH	B
	MOV	E,C	;CHARACTER TO REG. E
	MVI	C,5	;LIST CODE FOR BDOS
	CALL	BDOS	;SEND IT TO LIST DEVICE
	POP	B
	POP	D
	POP	H
	MOV	A,C	;RETURN WITH CHAR IN A
	RET
;
;
	RET

;INITIALIZATION ROUTINE FOR USER HARDWARE AND SOFTWARE.
;PUT YOUR OWN SPECIAL INITIALIZATION ROUTINES HERE.

;THIS ROUTINE MOVES THE CP/M CBIOS JUMP TABLE TO
;"JTAB" IN RAM.


INIT:	LHLD	1		;GET ADDRESS OF CBIOS
	LXI	D,JTAB		;DESTINATION ADDRESS
	MVI	B,4*3		;NO. OF BYTES TO MOVE
MOVE:	MOV	A,M		;GET A BYTE
	STAX	D		;MOVE IT
	INX	H		;ADVANCE POINTERS
	INX	D
	DCR	B
	JNZ	MOVE		;COUNT BYTES
	RET

	PAGE			;PRINTER TOP OF FORM




;********* MODEM I/O AREA ***********

;  ALL MODEM I/O AND CONTROL ARE HERE.


;	MODEM I/O SYSTEM	5-10-79


;	WRITTEN BY DALE A. HEATHERINGTON
;	COPYRIGHT 1979 HAYES MICROCOMPUTER PRODUCTS, INC.


;	PORT EQUATES

DATA	EQU	80H
STATUS	EQU	DATA+1
CR1	EQU	DATA+1
CR2	EQU	DATA+2
CR3	EQU	DATA+3


;	BIT FUNCTIONS

;STATUS REGISTER

RRF	EQU	1	;RECEIVE REGISTER FULL
TRE	EQU	2	;TRANSMITER HOLDING REGISTER EMPTY
PE	EQU	4	;PARITY ERROR
FE	EQU	8	;FRAMMING ERROR
OE	EQU	10H	;OVERRUN ERROR
TMR	EQU	20H	;TIMER STATUS
CD	EQU	40H	;CARRIER PRESENT
RI	EQU	80H	;NOT RING INDICATOR (LOW TRUE)

;CONTROL REGISTER 1  (CR1)

EPE	EQU	1	;EVEN PARITY ENABLE
LS1	EQU	2	;WORD LENGTH SELECT BIT 1
LS2	EQU	4	;WORD LENGTH SELECT BIT 2
SBS	EQU	8	;STOP BITS
PI	EQU	10H	;PARITY INHIBIT
TMIE	EQU	20H	;TIMER INTERUPTS ENABLE


;CONTROL REGISTER 2  (CR2)

BRS	EQU	1	;BAUD RATE CONTROL
TXE	EQU	2	;TRANSMIT CARRIER ENABLE
MS	EQU	4	;MODE (0=ANSWER 1=ORIGINATE)
BRK	EQU	8	;SEND BREAK
ST	EQU	10H	;SELF TEST
TIE	EQU	20H	;TRANSMITTER INTERUPT ENABLE
RIE	EQU	40H	;RECEIVER INTERUPT ENABLE
OH	EQU	80H	;OFF-HOOK

;CONTROL REGISTER 3  (CR3)

;WRITING ANYTHING TO CR3 STARTS THE 50 MS TIMER.



;THIS ROUTINE CLEARS ALL THE CONTROL REGISTERS

RESET:	XRA	A	;ZERO A
	OUT	CR1
	OUT	CR2
	STA	MICR2	;CLEAR MEMORY IMAGES TOO
	STA	MICR1
	RET


;THIS ROUTINE SENDS A BYTE IN REGISTER C TO THE MODEM
;TRANSMITTER. ONLY REGISTER A IS DISTURBED

TXCHR:	IN	STATUS	;GET MODEM STATUS
	ANI	TXE	;CHECK FOR TRANSMITER EMPTY
	JZ	TXCHR	;LOOP IF NOT
	MOV	A,C
	OUT	DATA	;SEND THE BYTE
	RET


;GETS A BYTE FROM THE MODEM RECEIVER IN REGISTER A

RXCHR:	IN	STATUS
	ANI	RRF
	JZ	RXCHR	;LOOP IF NO CHARACTER REC.
	IN	DATA
	RET		;CHARACTER IN A


;THIS ROUTINE RETURNS WITH A=1 IF A RECEIVED
;CHARACTER IS WAITING OR A=0 IF NOT.

RXSTAT:	IN	STATUS	;GET MODEM STATUS
	ANI	RRF	;CHECK RECEIVER FLAG
	RET		;A=1 IF CHARACTER PRESENT


;CARRIER STATUS CHECK. A=1 IF CARRIER IS PRESENT

CDSTAT:	IN	STATUS
	ANI	CD	;TEST CARRIER DETECT FLAG
	MVI	A,0	;ASSUME 0
	RZ
	INR	A	;MAKE A=1 IF CARRIER PRESENT
	RET

;RING INDICATOR STATUS CHECK.  A=1 IF PHONE RINGING

RISTAT:	IN	STATUS
	ANI	RI
	MVI	A,1	;ASSUME RINGING
	RZ		;RETURN IF IT IS (LOW TRUE BIT)
	DCR	A	;ELSE MAKE A=0
	RET

;GET THE ERROR FLAGS. ERROR BITS ARE RETURNED IN REG. A.
;A=0 IF NO ERRORS WERE DETECTED ON LAST CHARACTER RECEIVED.
;BIT 0=PARITY ERROR   BIT 1=FRAMMING ERROR
;BIT 2=OVERRUN ERROR

ERFLG:	IN	STATUS
	RAR		;SHIFT BITS RIGHT 2 PLACES
	RAR
	ANI	7	;KILL UNWANTED BITS
	RET		;LOW 3 BITS ARE ERROR FLAGS

;TRANSMIT CARRIER CONTROL.
;ENTER WITH REG. C=0 FOR CARRIER OFF 
; OR REG. C=1 FOR TRANSMIT CARRIER ON

TXON:	MOV	A,C	
	ORA	A
	MVI	A,TXE	;PUT TXE BIT IN A
	JZ	CLR2	;CLEAR IT IF 0
	JMP	SET2	;SET IT IF A 1

;SET THE BAUD RATE.  C=0 FOR LOW BAUD RATE (110)
; C=1 FOR HIGH BAUD RATE (300)

BAUD:	MOV	A,C
	ORA	A
	MVI	A,BRS	;BAUD RATE BIT IN A
	JZ	CLR2	;RESET BIT IF 0
	JMP	SET2	;SET IF 1




;GO ON/OFF HOOK.   C=0 FOR ON-HOOK (IDLE)
;   C=1 FOR OFF-HOOK.


SWHOOK:	MOV	A,C
	ORA	A
	MVI	A,OH	;SWITCH-HOOK BIT
	JZ	CLR2
	JMP	SET2


;GET SWITCH HOOK STATUS.
; A=0 ON HOOK    A=1 OFF HOOK


SHSTAT:	LDA	MICR2		;GET CR2
	ANI	OH		;MASK FOR OFF HOOK
	MVI	A,1
	RNZ			;RET. IF OFF HOOK A=1
	DCR	A
	RET			;ELSE A=0

;SET THE MODE.	C=0 FOR ANSWER MODE
;  C=1 FOR ORGINATE MODE

MODE:	MOV	A,C
	ORA	A
	MVI	A,MS	;MODE SELECT BIT
	JZ	CLR2
	JMP	SET2


;SET OR CLEAR SELF-TEST MODE.
;C=1 FOR SELF TEST     C=0 FOR NORMAL

SELFT:	MOV	A,C
	ORA	A
	MVI	A,ST	;SELF-TEST BIT
	JZ	CLR2	;CLEAR IT
	JMP	SET2	;OR SET IT



;SEND A BREAK CONSISTING OF SENDING A SPACE (LOW TONE) FOR
; A NUMBER OF 50 MS INTERVALS SPECIFIED IN THE REG. C.

BREAK:	PUSH	B	;SAVE BREAK DURATION VALUE
	MVI	C,2
	CALL	DELAY	;WAIT 100 MS
	POP	B	;RESTORE BREAK DURATION VALUE
	PUSH	H
	LXI	H,MICR2
	MVI	A,BRK	;SET THE BREAK BIT
	ORA	M
	OUT	CR2
	CALL	DELAY	;C=50 MS INTERVALS TO WAIT
	MVI	A,BRK
	CMA
	ANA	M	;CLEAR BREAK BIT
	OUT	CR2	;WRITE IT TO MODEM
	POP	H
	RET


;SETS THE PARITY.   C=0 FOR NO PARITY
;  C=1 FOR ODD PARITY    C=2 FOR EVEN PARITY

PARITY:	MOV	A,C
	ORA	A	;TEST FOR NO PARITY
	JZ	PAROFF
	MVI	A,PI
	CALL	CLR1	;CLEAR PARITY INHIBIT BIT
	MOV	A,C
	RAR		;LSB IS NOW EVEN/ODD PARITY
	ANI	1
	MVI	A,EPE
	JZ	CLR1	;CLEAR EPE IF ODD
	JMP	SET1	;SET EPE IF EVEN

PAROFF:	MVI	A,PI
	JMP	SET1	;INHIBIT PARITY

; SELECT WORD LENGTH.
LSBITS	EQU	LS1+LS2

WLS:	MOV	A,C
	SUI	5	;REMOVE BIAS
	ADD	A	;SHIFT LEFT 1 PLACE
	ANI	6	;KILL ANY STRAY BITS
	MOV	C,A	;SAVE RESULT IN C
	LDA	MICR1	;GET MEMORY IMAGE
	ANI	(NOT LSBITS) AND 255 ;CLEAR WORD LENGTH BITS
	ORA	C	;PUT IN NEW ONES
	STA	MICR1	;UPDATE MEMORY
	OUT	CR1	;WRITE TO MODEM
	RET

;SET NUMBER OF STOP BITS
;C=STOP BITS  (1 OR 2)

NSTOP:	MOV	A,C
	SUI	1
	MVI	A,SBS	;STOP BIT SELECT BIT
	JZ	CLR1	;CLEAR IT
	JMP	SET1	;ELSE SET IT


;DELAY ROUTINE.
;WAITS 50 MS TIMES THE VALUE IN REGISTER C.

DELAY:	MOV	A,C
	ORA	A
	RZ		;WAIT ZERO TIME IF C=0
	PUSH	B	;SAVE CONTENTS OF C
DLY1:	OUT	CR3	;START TIMER
DLY2:	IN	STATUS	;WAIT TILL IT TIMES OUT
	ANI	TMR	;LOOK AT TIMER BIT
	JZ	DLY2	;LOOP BACK IF ZERO
	DCR	C	;COUNT DOWN
	JNZ	DLY1	;DO AGAIN IF NOT ZERO
	POP	B
	RET


;STARTS THE 50 MS TIMER

STIME:	OUT	CR3	;START TIMER
	RET

;CHECKS THE STATUS OF THE TIMER.
; RETURNS WITH  A=1 IF TIMED OUT OR  A=0 IF NOT.


CKTIME:	IN	STATUS
	ANI	TMR	;MASK IN TIMER BIT
	MVI	A,1
	RNZ		;RET.  A=1 IF TIMED OUT
	DCR	A
	RET		;RET.  A=0 IF TIME NOT UP


;GOES OFF-HOOK AND WAITS FOR A DIAL TONE.  SINCE THE
;MICROMODEM HAS NO DIAL TONE DETECTOR WE JUST GO
;OFF-HOOK, WAIT 2 SECONDS, ASSUME A DIAL TONE IS 
;PRESENT, THEN RETURN.


DLTONE:	PUSH	B
	MVI	C,1
	CALL	SWHOOK	;GO OFF-HOOK
	MVI	C,40	;40*50MS=2 SECONDS
	CALL	DELAY	;WAIT 2 SECONDS
	POP	B	;RESTORE BC
	RET



;DIAL PULSE ROUTINE. DIALS THE DIGIT IN REGISTER C.
;IF C=0 THEN 10 PULSES WILL BE PRODUCED. THE DIGIT IN
;THE C REGISTER CAN BE BINARY OR ASCII.  AFTER THE
;DIGIT IS OUT-PULSED THIS ROUTINE WILL PAUSE FOR 600 MS
;FOR INTER-DIGIT SPACING.


PULSE:	PUSH	B	;SAVE BC
	MOV	A,C
	MVI	B,10	;PRE-LOAD PULSE COUNTER
	ANI	0FH	;KILL POSSIBLE ASCII BIAS
	CPI	0	;SEE IF WE'RE DOING 10 PULSES
	JZ	PULS1
	MOV	B,A	;PULSE COUNT TO B
PULS1:	MVI	C,0	;GO ON HOOK
	CALL	SWHOOK
	MVI	C,1
	CALL	DELAY	;WAIT 50 MS
	MVI	C,1
	CALL	SWHOOK	;OFF HOOK AGAIN
	MVI	C,1
	CALL	DELAY	;WAIT 50 MS
	DCR	B	;WE MADE 1 PULSE, COUNT IT
	JNZ	PULS1	;IF NOT ZERO, MAKE SOME MORE
	MVI	C,11	;11*50 MS=550 MS
	CALL	DELAY	;INTER-DIGIT DELAY
	POP	B	;RESTORE BC REGISTERS
	RET



;SETS BITS IN CONTROL REGISTER 2.
;ENTER WITH REG. A CONTAINING 1'S WHERE BITS ARE TO BE
;SET.

SET2:	PUSH	H	;SAVE HL
	LXI	H,MICR2
	ORA	M	;OR IN BITS TO BE SET
	MOV	M,A
	OUT	CR2	;SET THE MODEM
	POP	H
	RET


;CLEAR BITS IN CONTROL REGISTER 2.
;REG. A HAS 1'S FOR BITS TO BE CLEARED.

CLR2:	PUSH	H
	LXI	H,MICR2	;MEMORY IMAGE OF CR2
	CMA
	ANA	M	;TURN OFF THE BIT
	MOV	M,A	;UPDATE MEMORY
	OUT	CR2	;WRITE TO CRL. REG. 2
	POP	H	;RESTORE HL
	RET


;SET BITS IN CONTROL REGISTER 1.
;REG. A HAS 1'S IN BITS TO BE SET.

SET1:	PUSH	H
	LXI	H,MICR1	;POINT TO MEMORY IMAGE
	ORA	M	;OR IN THE BITS
	MOV	M,A	;UPDATE MEMORY
	OUT	CR1	;WRITE TO MODEM
	POP	H
	RET

 
;CLEAR BITS IN CONTROL REGISTER 1
;REG. A HAS 1'S IN BITS TO BE CLEARED.

CLR1:	PUSH	H
	LXI	H,MICR1	;POINT TO MEMORY IMAGE
	CMA		;INVERT A
	ANA	M	;CLEAR BITS
	MOV	M,A	;UPDATE MEMORY
	OUT	CR1
	POP	H
	RET




;THIS AREA MUST BE R/W MEMORY.

	ORG	1000H		;RAM MEMORY AREA
SOR:				;START OF RAM

MICR1:	DS	1	;MEMORY IMAGE OF CONTROL REG. 1
MICR2:	DS	1	;MEMORY IMAGE OF CONTROL REG. 2
DPLX:	DS	1	;FULL DUPLEX FLAG 1=FULL  0=HALF
MFLAG:	DS	1	;0=ANSWER    1=ORIGINATE

JTAB:	DS	3	;CBIOS JUMP TABLE IS MOVED HERE
XCONST:	DS	3	;CONSOLE STATUS
XCONIN:	DS	3	;CONSOLE INPUT
XCONOT:	DS	3	;CONSOLE OUTPUT

NMBR:	DS	32	;32 BYTES PHONE NUMBER STORAGE
BUFPNT:	DS	2	;BUFFER POINTER STORAGE

CPFLAG:	DS	1		;CAPTURE FLAG 1=ON  0=OFF
BUGFLAG:DS	1		;1=DEBUG MODE  0= NORMAL
BUGCOUNT: DS	1		;COUNTS HEX BYTES PER LINE
MTOP:	DS	1		;TOP OF MEMORY (PAGE)
PRNSW:	DS	1		;1=PRINTER ON  0=OFF
CBUFP:	DS	2		;CAPTURE BUFFER POINTER
CPCNT:	DS	2		;CAPTURED CHARACTER COUNTER
EOR:				;END OF RAM CHECKED BY CHECKSUM
CKSUM:	DS	1		;CHECKSUM STORED HERE

	DS	64
STACK:	DS	1	;64 BYTES FOR STACK

BUF:	DS	65	;CONSOLE BUFFER

;CPM FILE CONTROL BLOCK

FCB:
ET:	DS	1		;ENTRY TYPE
FNAME:	DS	8		;FILE NAME
FTYPE:	DS	3		;FILE TYPE
EX:	DS	3		;EXTENT
RCC:	DS	1		;RECORD COUNT
DM:	DS	16		;DISK MAP
NR:	DS	1		;NEXT RECORD

CPBUF:	DS	1		;CAPTURE BUFFER

	END	START	;THATS ALL
