;-----------------------------------------------------------------------------
; INDUSTROLOGIC, INC.		WWW.INDUSTROLOGIC.COM
; FILE NAME	DIO51MON.ASM	COPYRIGHT 2008
;
; MONITOR PROGRAM FOR THE INDUSTROLOGIC DIO51 SINGLE BOARD COMPUTER
;
; VERSION	LAST UPDATE	DESCRIPTION
; 1.0		12/16/07	ORIGINAL VERSION
;
;-----------------------------------------------------------------------------

PCON	EQU	87H		;IN CASE ASSEMBLER DOESN'T KNOW THIS

CMDFLAG	BIT	20H.0		;COMMAND COMPLETED WITH CARRIAGE RETURN
CHRFLAG	BIT	20H.1		;CHARACTER RECEIVED AND STORED
ESCFLAG	BIT	20H.2		;ESCAPE RECEIVED
CHARERR	BIT	20H.3		;FOR ATOB ROUTINE

LASTCH	EQU	21H		;LAST CHARACTER RECEIVED
RXPTR	EQU	22H		;SERIAL RECEIVE BUFFER POINTER

CNT0MSB	EQU	23H		;COUNTER VALUE FOR INT0
CNT0LSB	EQU	24H
CNT1MSB	EQU	25H		;COUNTER VALUE FOR INT1
CNT1LSB	EQU	26H

RXBUF	EQU	30H		;RECEIVE BUFFER


;-----------------------------------------------------------------------------
; CODE

	ORG	0		;RESTART VECTOR
	JMP	INIT		;JUMP AROUND INTERRUPT VECTORS

	ORG	3		;EXTERNAL INTERRUPT 0 VECTOR
	JMP	EI0VEC

	ORG	13H		;EXTERNAL INTERRUPT 1 VECTOR
	JMP	EI1VEC

	ORG	23H		;SERIAL INTERRUPT VECTOR
	JMP	SERVEC

;-----------------------------------------------------------------------------
;INITIALIZATION


INIT:	MOV	R0,#8H		;CLEAR RAM
	MOV	R1,#78H		;7F-08 BANK 0 REGISTERS
INIT1:	MOV	@R0,#0
	INC	R0
	DJNZ	R1,INIT1

	MOV	RXPTR,#RXBUF	;START OF RECEIVE BUFFER

	SETB	IT0		;EXTERNAL INTERRUPT 0 PIN LOW GOING EDGE TRIGGERED
	SETB	EX0		;ENABLE EXTERNAL INTERRUPT 0
	SETB	IT1		;EXTERNAL INTERRUPT 1 PIN LOW GOING EDGE TRIGGERED
	SETB	EX1		;ENABLE EXTERNAL INTERRUPT 1

	MOV	TMOD,#21H	;T1=BAUD TIMER, T0=16 BIT
	MOV	SCON,#50H	;MODE 1, 8 BIT UART, VAR. BAUD RATE USING T1

;22.1184 MHZ CRYSTAL, 040H=300, 0E8H=2400, 0FAH=9600, 0FDH=19200, 0FDH=38400 WITH SMOD HIGH
;11.0592 MHZ CRYSTAL, 0A0H=300, 0F4H=2400, 0FAH=4800, 0FDH=9600,  0FDH=19200 WITH SMOD HIGH
;	ORL	PCON,#80H	;SET SMOD BIT HIGH TO DOUBLE THE BAUD RATE
	MOV	A,#0FAH		;BAUD RATE TO 9600
	MOV	TH1,A		;TIMER 1 IS FOR BAUD RATE
	MOV	TL1,A
	SETB	TR1		;START THE BAUD RATE TIMER
	SETB	ES		;ENABLE SERIAL INTERRUPT

	SETB	EA		;ENABLE ALL INTERRUPTS MASTER BIT

;-----------------------------------------------------------------------------
; MAIN LOOP

MENU:	MOV	DPTR,#MENUMSG	;POINT TO MESSAGE
	CALL	TXMSG		;TRANSMIT MESSAGE POINTED TO BY DPTR

PROM:	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED

PROMPT:	MOV	DPTR,#PROMPTMSG	;POINT TO MESSAGE
	CALL	TXMSG		;TRANSMIT MESSAGE POINTED TO BY DPTR


MAIN:	JNB	CHRFLAG,MAIN	;SKIP IF CHARACTER NOT RECEIVED LATELY
	CALL	RXCHAR		;PROCESS RECEIVED CHARACTER
	JB	ESCFLAG,PROM	;BACK TO PROMPT IF ESCAPE HIT
	JNB	CMDFLAG,MAIN	;NOT A COMPLETE COMMAND YET
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN/LINE FEED
	JMP	RXCMD		;RECEIVED A COMPLETE COMMAND


;-----------------------------------------------------------------------------

MENUMSG:
DB 13,10
DB 13,10
DB 'Industrologic, Inc. DIO51 Monitor Program, version 1.0',13,10
DB 13,10
DB 'Function:           Commands:                       Responses:',13,10
DB 'Read Port           P0      P1      P2              hh',13,10
DB 'Write Port          P0=hh   P1=hh   P2=hh',13,10
DB 'Read Bit            I0      I1      T0      T1      b',13,10
DB 'Write Bit           I0=b    I1=b    T0=b    T1=b',13,10
DB 'Read/Reset Counter  C0      C1                      hhhh',13,10
DB 'Read All            A                               hh,hh,hh,b,b,b,b,hhhh,hhhh',13,10
DB 'Read All/Test       R                               Displays inputs',13,10
DB 'Write All/Test      W                               Cycles outputs',13,10
DB 'Display RAM         M',13,10
DB 13,10
DB 'Counters C0 and C1 are pulses counted on INT0 and INT1',13,10
DB 'hh=2 character hex value 00 to FF, hhhh=4 character hex value 0000-FFFF',13,10
DB 'b=1 character bit value 0 or 1',13,10
DB 'hh,hh,hh,b,b,b,b,hhhh,hhhh=values for P0,P1,P2,INT0,INT1,T0,T1,C0,C1',13,10
DB '<CR>=carriage return, 0D hex [Enter key], <LF>=line feed, 0A hex',13,10
DB '<ESC>=escape, 1B hex [Escape key]',13,10
DB 13,10
DB 'Commands followed by <CR> (<LF> ignored), responses followed by <CR><LF>',13,10
DB '<ESC> aborts command in progress, <CR> by itself re-displays menu',13,10
DB 0

ERRORMSG:	DB	'Command Error',13,10,0
PROMPTMSG:	DB	'DIO51>',0


; ----------------------------------------------------------------------------
; PROCESS CHARACTER RECEIVED FROM SERIAL PORT WHILE AT PROMPT
; R0 USED AS A POINTER IN THIS ROUTINE BUT NOT BEFORE OR AFTER

RXCHAR:	CLR	CMDFLAG		;INDICATE NOT A COMPLETE COMMAND
	CLR	ESCFLAG		;INDICATE NO ESCAPE TO EXIT INPUT INSTRUCTION
	MOV	R0,RXPTR	;GET RECEIVE BUFFER POINTER
	MOV	A,LASTCH	;GET THE LAST CHARACTER RECEIVED
	CLR	CHRFLAG		;CLEAR THE CHARACTER RECEIVED FLAG

	CJNE	A,#10,RXCH1	;CHECK FOR LINE FEED
	RET			;IGNORE LINE FEEDS ENTIRELY

RXCH1:	CJNE	A,#13,RXCH2	;CHECK FOR CARRIAGE RETURN
	SETB	CMDFLAG		;INDICATE A COMPLETE COMMAND RECEIVED
	MOV	@R0,A		;STORE IN BUFFER AT POINTER LOCATION
	SJMP	RXCH3

RXCH2:	CJNE	A,#27,RXCH5	;CONTINUE IF NOT AN ESCAPE
	SETB	ESCFLAG		;INDICATE ESCAPE ENTERED
RXCH3:	MOV	RXPTR,#RXBUF	;POINT BACK TO START OF RECEIVE BUFFER
	RET

RXCH5:	CJNE	A,#8,RXCH6	;CONTINUE IF NOT A BACKSPACE
	DEC	R0		;BACK UP ONE BUFFER LOCATION
	CJNE	R0,#RXBUF-1,RXCH7	;CONTINUE IF NOT BEFORE START OF BUFFER
	MOV	RXPTR,#RXBUF	;POINT BACK TO START OF RECEIVE BUFFER
	RET

RXCH7:	MOV	RXPTR,R0	;SAVE RECEIVE BUFFER POINTER
	MOV	DPTR,#BSMSG	;POINT TO BACKSPACE MESSAGE
	CALL	TXMSG		;SEND MESSAGE
	RET

BSMSG:	DB	8,32,8,0	;BACKSPACE, SPACE, BACKSPACE

RXCH6:	CJNE	R0,#RXBUF+0FH,RXCH8	;CHECK FOR PAST END OF BUFFER
	RET
				;CONVERT ALL LOWER CASE TO UPPER
RXCH8:	CJNE	A,#'a',RXCH9	;CHECK FOR BELOW LOWER CASE ALPHABETIC
RXCH9:	JC	RXCH10		;BELOW, CONTINUE
	CJNE	A,#'z'+1,RXCH11	;CHECK FOR ABOVE LOWER CASE ALPHABETIC
RXCH11:	JNC	RXCH10		;ABOVE, CONTINUE
	ANL	A,#0DFH		;CONVERT LOWER CASE TO UPPER CASE

RXCH10:	MOV	@R0,A		;STORE THE CHARACTER
	CALL	TXCHAR		;TRANSMIT CHARACTER IN A, ECHO CHARACTER
	INC	R0		;POINT TO NEXT BUFFER LOCATION
	MOV	RXPTR,R0	;SAVE RECEIVE BUFFER POINTER

	RET


; ----------------------------------------------------------------------------
; PROCESS A COMPLETE COMMAND IN RECEIVE BUFFER ONCE ENTERED.
; CHECK THE FIRST CHARACTER THEN JUMP TO OTHER ROUTINES TO TEST FURTHER

RXCMD:	CLR	CMDFLAG		;CLEAR THE COMMAND RECEIVED FLAG
	MOV	A,RXBUF		;GET FIRST CHARACTER OF COMMAND

RXCR:	CJNE	A,#13,RXP	;CHECK FOR MENU COMMAND
	JMP	MENU

RXP:	CJNE	A,#'P',RXI	;CHECK FOR PORT COMMAND
	JMP	PCMD

RXI:	CJNE	A,#'I',RXT	;CHECK FOR INTERRUPT PIN COMMAND
	JMP	ICMD

RXT:	CJNE	A,#'T',RXC	;CHECK FOR TIMER PIN COMMAND
	JMP	TCMD

RXC:	CJNE	A,#'C',RXM	;CHECK FOR COUNTER COMMAND
	JMP	CCMD

RXM:	CJNE	A,#'M',RXA	;CHECK FOR DISPLAY INTERNAL RAM COMMAND
	JMP	MCMD

RXA:	CJNE	A,#'A',RXR	;CHECK FOR READ ALL COMMAND
	JMP	ACMD

RXR:	CJNE	A,#'R',RXW	;CHECK FOR READ/TEST OUTPUTS COMMAND
	JMP	RCMD

RXW:	CJNE	A,#'W',RXBAD	;CHECK FOR WRITE/TEST INPUTS COMMAND
	JMP	WCMD

RXBAD:	MOV	DPTR,#ERRORMSG	;BAD COMMAND
	CALL	TXMSG		;SEND MESSAGE
	JMP	PROMPT


;-----------------------------------------------------------------------------
; COMMANDS

PCMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND

PCMD0:	CJNE	A,#'0',PCMD1	;CHECK FOR PORT 0
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,PC09	;CHECK FOR CARRIAGE RETURN
				;P0
	CALL	GETP0		;READ BYTE VALUE FROM INPUT PINS OF P0
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT
				;P0=hh
PC09:	CALL	BYTE45		;FORM BYTE FROM 4TH AND 5TH CHARACTER
	JC	PCMDX		;INVALID CHARACTERS IF CARRY SET
	MOV	P0,A		;WRITE VALUE TO PORT
	JMP	PROMPT



PCMD1:	CJNE	A,#'1',PCMD2
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,PC19	;CHECK FOR CARRIAGE RETURN
				;P1
	CALL	GETP1		;READ BYTE VALUE FROM INPUT PINS OF P1
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT
				;P1=hh
PC19:	CALL	BYTE45		;FORM BYTE FROM 4TH AND 5TH CHARACTER
	JC	PCMDX		;INVALID CHARACTERS IF CARRY SET
	MOV	P1,A		;WRITE VALUE TO PORT
	JMP	PROMPT



PCMD2:	CJNE	A,#'2',PCMD3
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,PC29	;CHECK FOR CARRIAGE RETURN
				;P2
	CALL	GETP2		;READ BYTE VALUE FROM INPUT PINS OF P2
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT
				;P2=hh
PC29:	CALL	BYTE45		;FORM BYTE FROM 4TH AND 5TH CHARACTER
	JC	PCMDX		;INVALID CHARACTERS IF CARRY SET
	MOV	P2,A		;WRITE VALUE TO PORT
	JMP	PROMPT


PCMD3:
PCMDX:	JMP	RXBAD


;-------------------------------

ICMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND

ICMD0:	CJNE	A,#'0',ICMD1	;CHECK FOR INT 0
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,IC09	;CHECK FOR CARRIAGE RETURN
				;I0
	MOV	A,#0		;CLEAR BYTE
	MOV	C,INT0		;READ INT0 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT

				;I0=b
IC09:	CJNE	A,#'=',ICMDX	;CHECK FOR EQUAL SIGN
	MOV	A,RXBUF+4	;GET FIFTH CHARACTER
	CJNE	A,#13,ICMDX	;BAD COMMAND IF NOT CARRIAGE RETURN

	MOV	A,RXBUF+3	;GET FOURTH CHARACTER
	CJNE	A,#'0',IC091	;ZERO
	CLR	INT0		;CLEAR INT0 PIN
	JMP	PROMPT
IC091:	CJNE	A,#'1',IC092	;ONE
	SETB	INT0		;SET INT0 PIN
	JMP	PROMPT
IC092:	JMP	ICMDX		;ERROR IF NOT 0 OR 1



ICMD1:	CJNE	A,#'1',ICMD2    ;CHECK FOR INT 1
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
				;I1
	CJNE	A,#13,IC19	;CHECK FOR CARRIAGE RETURN
	MOV	A,#0		;CLEAR BYTE
	MOV	C,INT1		;READ INT1 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT

				;I1=b
IC19:	CJNE	A,#'=',ICMDX	;CHECK FOR EQUAL SIGN
	MOV	A,RXBUF+4	;GET FIFTH CHARACTER
	CJNE	A,#13,ICMDX	;BAD COMMAND IF NOT CARRIAGE RETURN

	MOV	A,RXBUF+3	;GET FOURTH CHARACTER
	CJNE	A,#'0',IC191	;ZERO
	CLR	INT1		;CLEAR INT1 PIN
	JMP	PROMPT
IC191:	CJNE	A,#'1',IC192	;ONE
	SETB	INT1		;SET INT1 PIN
	JMP	PROMPT
IC192:				;ERROR IF NOT 0 OR 1


ICMD2:
ICMDX:	JMP	RXBAD


;-------------------------------

TCMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND

TCMD0:	CJNE	A,#'0',TCMD1	;CHECK FOR T0
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,TC09	;CHECK FOR CARRIAGE RETURN
				;T0
	MOV	A,#0		;CLEAR BYTE
	MOV	C,T0		;READ T0 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT

				;T0=b
TC09:	CJNE	A,#'=',ICMDX	;CHECK FOR EQUAL SIGN
	MOV	A,RXBUF+4	;GET FIFTH CHARACTER
	CJNE	A,#13,ICMDX	;BAD COMMAND IF NOT CARRIAGE RETURN

	MOV	A,RXBUF+3	;GET FOURTH CHARACTER
	CJNE	A,#'0',TC091	;ZERO
	CLR	T0		;CLEAR T0 PIN
	JMP	PROMPT
TC091:	CJNE	A,#'1',TC092	;ONE
	SETB	T0		;SET T0 PIN
	JMP	PROMPT
TC092:	JMP	ICMDX		;ERROR IF NOT 0 OR 1



TCMD1:	CJNE	A,#'1',TCMD2    ;CHECK FOR T1
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,TC19	;CHECK FOR CARRIAGE RETURN
				;T1
	MOV	A,#0		;CLEAR BYTE
	MOV	C,T1		;READ T1 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT

				;T1=b
TC19:	CJNE	A,#'=',TCMDX	;CHECK FOR EQUAL SIGN
	MOV	A,RXBUF+4	;GET FIFTH CHARACTER
	CJNE	A,#13,TCMDX	;BAD COMMAND IF NOT CARRIAGE RETURN

	MOV	A,RXBUF+3	;GET FOURTH CHARACTER
	CJNE	A,#'0',TC191	;ZERO
	CLR	T1		;CLEAR T1 PIN
	JMP	PROMPT
TC191:	CJNE	A,#'1',TC192	;ONE
	SETB	T1		;SET T1 PIN
	JMP	PROMPT
TC192:				;ERROR IF NOT 0 OR 1


TCMD2:
TCMDX:	JMP	RXBAD


;-------------------------------

CCMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND

CCMD0:	CJNE	A,#'0',CCMD1	;CHECK FOR COUNTER 0
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,CCMDX	;CHECK FOR CARRIAGE RETURN
				;C0
	MOV	A,CNT0LSB	;GET THE COUNT FOR INT0/LSB
	MOV	CNT0LSB,#0	;CLEAR IT IMMEDIATELY
	PUSH	ACC
	MOV	A,CNT0MSB	;GET THE COUNT FOR INT0/MSB
	MOV	CNT0MSB,#0	;CLEAR IT IMMEDIATELY
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	POP	ACC
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT

CCMD1:	CJNE	A,#'1',CCMD2    ;CHECK FOR COUNTER 1
	MOV	A,RXBUF+2	;GET THIRD CHARACTER OF COMMAND
	CJNE	A,#13,CCMDX	;CHECK FOR CARRIAGE RETURN
				;C1
	MOV	A,CNT1LSB	;GET THE COUNT FOR INT1/LSB
	MOV	CNT1LSB,#0	;CLEAR IT IMMEDIATELY
	PUSH	ACC
	MOV	A,CNT1MSB	;GET THE COUNT FOR INT1/MSB
	MOV	CNT1MSB,#0	;CLEAR IT IMMEDIATELY
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	POP	ACC
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT

CCMD2:
CCMDX:	JMP	RXBAD		;SECOND CHARACTER DID NOT MATCH


;-------------------------------

ACMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND
	CJNE	A,#13,ACMDX	;CHECK FOR CARRIAGE RETURN
				;A
	CALL	RDALL		;READ AND DISPLAY ALL PORTS, BITS
				;DO COUNTERS SEPARATELY, CLEAR COUNTS

	MOV	A,CNT0LSB	;GET THE COUNT FOR INT0/LSB
	MOV	CNT0LSB,#0	;CLEAR IT IMMEDIATELY
	PUSH	ACC
	MOV	A,CNT0MSB	;GET THE COUNT FOR INT0/MSB
	MOV	CNT0MSB,#0	;CLEAR IT IMMEDIATELY
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	POP	ACC
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS

	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC

	MOV	A,CNT1LSB	;GET THE COUNT FOR INT1/LSB
	MOV	CNT1LSB,#0	;CLEAR IT IMMEDIATELY
	PUSH	ACC
	MOV	A,CNT1MSB	;GET THE COUNT FOR INT1/MSB
	MOV	CNT1MSB,#0	;CLEAR IT IMMEDIATELY
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	POP	ACC
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS

	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED

	JMP	PROMPT

ACMDX:	JMP	RXBAD



;-------------------------------

RCMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND
	CJNE	A,#13,RCMDX	;CHECK FOR CARRIAGE RETURN
				;R
RCMD1:	CALL	RDALL		;READ AND DISPLAY ALL PORTS, BITS
				;DO COUNTERS SEPARATELY, DO NOT CLEAR COUNTS
	MOV	A,CNT0MSB	;GET THE COUNT FOR INT0/LSB
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	MOV	A,CNT0LSB	;GET THE COUNT FOR INT0/MSB
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS

	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC

	MOV	A,CNT1MSB	;GET THE COUNT FOR INT1/LSB
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	MOV	A,CNT1LSB	;GET THE COUNT FOR INT1/MSB
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS

	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED

	JB	CHRFLAG,RCMD2	;IF CHARACTER RECEIVED
	CALL	TSDELAY		;SHORT DELAY
	JMP	RCMD1

RCMD2:	CLR	CHRFLAG		;CLEAR FLAG
	JMP	PROMPT

RCMDX:	JMP	RXBAD


;-------------------------------

WCMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND
	CJNE	A,#13,WCMDX	;CHECK FOR CARRIAGE RETURN
				;W
	MOV	A,#1		;INITIAL VALUE
WCMD1:	MOV	P0,A		;WRITE VALUE TO PORT
	MOV	P1,A		;WRITE VALUE TO PORT
	MOV	P2,A		;WRITE VALUE TO PORT
	MOV	C,ACC.0		;GET LOWEST BIT FROM VALUE
	MOV	INT0,C		;SEND IT TO PIN
	MOV	INT1,C		;SEND IT TO PIN
	MOV	T0,C		;SEND IT TO PIN
	MOV	T1,C		;SEND IT TO PIN
	JB	CHRFLAG,WCMD2	;IF CHARACTER RECEIVED
	CALL	TSDELAY		;SHORT DELAY
	RL	A		;ROTATE TO NEXT VALUE
	JMP	WCMD1

WCMD2:	CLR	CHRFLAG		;CLEAR FLAG
	MOV	P0,#0FFH	;SET TO POWER UP VALUE
	MOV	P1,#0FFH	;SET TO POWER UP VALUE
	MOV	P2,#0FFH	;SET TO POWER UP VALUE
	SETB	INT0		;SET TO POWER UP VALUE
	SETB	INT1		;SET TO POWER UP VALUE
	SETB	T0		;SET TO POWER UP VALUE
	SETB	T1		;SET TO POWER UP VALUE
	JMP	PROMPT

WCMDX:	JMP	RXBAD


;-------------------------------
; SUBROUTINES FOR COMMANDS

				;READ AND DISPLAY ALL PORTS AND BITS
				;BUT NOT THE COUNTERS, THEY MIGHT NEED CLEARING
RDALL:	CALL	GETP0		;READ BYTE VALUE FROM INPUT PINS OF P0
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	CALL	GETP1		;READ BYTE VALUE FROM INPUT PINS OF P1
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	CALL	GETP2		;READ BYTE VALUE FROM INPUT PINS OF P2
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	MOV	A,#0		;CLEAR BYTE
	MOV	C,INT0		;READ INT0 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	MOV	A,#0		;CLEAR BYTE
	MOV	C,INT1		;READ INT1 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	MOV	A,#0		;CLEAR BYTE
	MOV	C,T0		;READ T0 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	MOV	A,#0		;CLEAR BYTE
	MOV	C,T1		;READ T1 PIN INTO CARRY
	MOV	ACC.0,C		;THEN PLACE IN LOWEST BIT OF ACC
	CALL	TXASC		;TRANSMIT CHARACTER IN ACC WITH ASCII OFFSET
	MOV	A,#','		;COMMA
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	RET



; NEEDED BECAUSE "MOV A,P0" READS THE OUTPUT LATCHES, NOT THE PINS

GETP0:	MOV	A,#0		;CLEAR VALUE
GP00:	JNB	P0.0,GP01	;BIT 0 NOT ON, SKIP
	ORL	A,#01H		;BIT 0 ON, ADD THIS TO VALUE
GP01:	JNB	P0.1,GP02	;BIT 1 NOT ON, SKIP
	ORL	A,#02H		;BIT 1 ON, ADD THIS TO VALUE
GP02:	JNB	P0.2,GP03	;BIT 2 NOT ON, SKIP
	ORL	A,#04H		;BIT 2 ON, ADD THIS TO VALUE
GP03:	JNB	P0.3,GP04	;BIT 3 NOT ON, SKIP
	ORL	A,#08H		;BIT 3 ON, ADD THIS TO VALUE
GP04:	JNB	P0.4,GP05	;BIT 4 NOT ON, SKIP
	ORL	A,#10H		;BIT 4 ON, ADD THIS TO VALUE
GP05:	JNB	P0.5,GP06	;BIT 5 NOT ON, SKIP
	ORL	A,#20H		;BIT 5 ON, ADD THIS TO VALUE
GP06:	JNB	P0.6,GP07	;BIT 6 NOT ON, SKIP
	ORL	A,#40H		;BIT 6 ON, ADD THIS TO VALUE
GP07:	JNB	P0.7,GP08	;BIT 7 NOT ON, SKIP
	ORL	A,#80H		;BIT 7 ON, ADD THIS TO VALUE
GP08:	RET


; NEEDED BECAUSE "MOV A,P1" READS THE OUTPUT LATCHES, NOT THE PINS

GETP1:	MOV	A,#0		;CLEAR VALUE
GP10:	JNB	P1.0,GP11	;BIT 0 NOT ON, SKIP
	ORL	A,#01H		;BIT 0 ON, ADD THIS TO VALUE
GP11:	JNB	P1.1,GP12	;BIT 1 NOT ON, SKIP
	ORL	A,#02H		;BIT 1 ON, ADD THIS TO VALUE
GP12:	JNB	P1.2,GP13	;BIT 2 NOT ON, SKIP
	ORL	A,#04H		;BIT 2 ON, ADD THIS TO VALUE
GP13:	JNB	P1.3,GP14	;BIT 3 NOT ON, SKIP
	ORL	A,#08H		;BIT 3 ON, ADD THIS TO VALUE
GP14:	JNB	P1.4,GP15	;BIT 4 NOT ON, SKIP
	ORL	A,#10H		;BIT 4 ON, ADD THIS TO VALUE
GP15:	JNB	P1.5,GP16	;BIT 5 NOT ON, SKIP
	ORL	A,#20H		;BIT 5 ON, ADD THIS TO VALUE
GP16:	JNB	P1.6,GP17	;BIT 6 NOT ON, SKIP
	ORL	A,#40H		;BIT 6 ON, ADD THIS TO VALUE
GP17:	JNB	P1.7,GP18	;BIT 7 NOT ON, SKIP
	ORL	A,#80H		;BIT 7 ON, ADD THIS TO VALUE
GP18:	RET

; NEEDED BECAUSE "MOV A,P2" READS THE OUTPUT LATCHES, NOT THE PINS

GETP2:	MOV	A,#0		;CLEAR VALUE
GP20:	JNB	P2.0,GP21	;BIT 0 NOT ON, SKIP
	ORL	A,#01H		;BIT 0 ON, ADD THIS TO VALUE
GP21:	JNB	P2.1,GP22	;BIT 1 NOT ON, SKIP
	ORL	A,#02H		;BIT 1 ON, ADD THIS TO VALUE
GP22:	JNB	P2.2,GP23	;BIT 2 NOT ON, SKIP
	ORL	A,#04H		;BIT 2 ON, ADD THIS TO VALUE
GP23:	JNB	P2.3,GP24	;BIT 3 NOT ON, SKIP
	ORL	A,#08H		;BIT 3 ON, ADD THIS TO VALUE
GP24:	JNB	P2.4,GP25	;BIT 4 NOT ON, SKIP
	ORL	A,#10H		;BIT 4 ON, ADD THIS TO VALUE
GP25:	JNB	P2.5,GP26	;BIT 5 NOT ON, SKIP
	ORL	A,#20H		;BIT 5 ON, ADD THIS TO VALUE
GP26:	JNB	P2.6,GP27	;BIT 6 NOT ON, SKIP
	ORL	A,#40H		;BIT 6 ON, ADD THIS TO VALUE
GP27:	JNB	P2.7,GP28	;BIT 7 NOT ON, SKIP
	ORL	A,#80H		;BIT 7 ON, ADD THIS TO VALUE
GP28:	RET



; FORM A BYTE VALUE FROM THE FOURTH AND FIFTH CHARACTER OF THE RECEIVE BUFFER
; EXIT WITH CARRY CLEAR IF VALID CHARACTERS, CARRY SET IF NOT

BYTE45:	MOV	A,RXBUF+3	;GET FOURTH CHARACTER, UPPER NIBBLE
	CALL	HTOB		;CONVERT ASCII CHARACTER 0-F TO BINARY VALUE
	CJNE	A,#0FFH,B451	;CHECK FOR VALID CHARACTER
	SETB	C		;BAD COMMAND IF NOT
	RET			;RETURN WITH CARRY SET
B451:	RL	A		;MOVE THIS UPPER NIBBLE TO ITS PROPER BITS
	RL	A
	RL	A
	RL	A
	MOV	R1,A		;SAVE THE UPPER NIBBLE FOR NOW
	MOV	A,RXBUF+4	;GET FIFTH CHARACTER, LOWER NIBBLE
	CALL	HTOB		;CONVERT ASCII CHARACTER 0-F TO BINARY VALUE
	CJNE	A,#0FFH,B452	;CHECK FOR VALID CHARACTER
	SETB	C		;BAD COMMAND IF NOT
	RET			;RETURN WITH CARRY SET
B452:	ADD	A,R1		;ADD THE UPPER NIBBLE TO THE LOWER
	CLR	C		;RETURN WITH CARRY CLEAR
	RET




SECDELAY:			;ONE SECOND DELAY
	MOV	R7,#20
	JMP	SEC10
TSDELAY:MOV	R7,#2		;1/10 SECOND DELAY


				;FOR 22.1184MHZ CRYSTAL
SEC10:	MOV	R6,#200		;.05 SEC
SEC500U:MOV	R5,#229		;250 uS
	DJNZ	R5,$
	DJNZ	R6,SEC500U
	DJNZ	R7,SEC10
	RET


;SECDELAY:			;ONE SECOND DELAY
;	MOV	R7,#10
;	JMP	SEC10
;TSDELAY:MOV	R7,#1		;1/10 SECOND DELAY

				;FOR 11.0592MHZ CRYSTAL
;SEC10:	MOV	R6,#200		;.100256sec?, 99820us+436 us IN LOOP
;SEC500U:MOV	R5,#229		;499.1us?
;	DJNZ	R5,$
;	DJNZ	R6,SEC500U
;	DJNZ	R7,SEC10
;	RET


;-------------------------------
; TRANSMIT CONTENTS OF INTERNAL RAM
; USES REGISTERS ACC, R1, R2, R3, DPTR
; USES SUBROUTINES TXMSG, TXHEX, TXCHAR, TXCRLF

MCMD:	MOV	A,RXBUF+1	;GET SECOND CHARACTER OF COMMAND
	CJNE	A,#13,MCMDX	;CHECK FOR CARRIAGE RETURN
	CALL	TXRAM
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED
	JMP	PROMPT

MCMDX:	JMP	RXBAD


RAMMSG:	DB	'Contents of Internal RAM',13,10,0

TXRAM:	MOV	DPTR,#RAMMSG	;POINT TO MESSAGE
	CALL	TXMSG		;TRANSMIT MESSAGE
	MOV	R1,#0		;STARTING MEMORY LOCATION
	MOV	R3,#8		;NUMBER OF LINES ---------------------+
TXRAML:	MOV	A,R1		;GET LINE'S STARTING LOCATION         |
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS  |
	MOV	A,#' '		;SPACE                                |
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC            |
	MOV	A,#' '		;SPACE                                |
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC            |
	MOV	R2,#16		;NUMBER OF BYTES IN LINE -------------+
TXRAM8:	MOV	A,@R1		;GET A BYTE FROM MEMORY
	CALL	TXHEX		;TRANSMIT BYTE VALUE AS 2 HEX DIGITS
	MOV	A,#' '		;SPACE
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	INC	R1		;INCREMENT LOCATION POINTER
	DJNZ	R2,TXRAM8	;DO ANOTHER BYTE
	CALL	TXCRLF		;TRANSMIT CARRIAGE RETURN AND LINE FEED

	DJNZ	R3,TXRAML	;DO ANOTHER LINE
	RET

;-----------------------------------------------------------------------------
; TRANSMIT ROUTINES


;---------------------------------------
; TRANSMIT CARRIAGE RETURN AND LINE FEED
; USES REGISTER A, USES SUBROUTINE TXCHAR

				;TRANSMIT CARRIAGE RETURN AND LINE FEED
TXCRLF:	MOV	A,#13		;CARRIAGE RETURN
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	MOV	A,#10		;LINE FEED
	CALL	TXCHAR		;TRANSMIT CHARACTER IN ACC
	RET

;-------------------------------
; TRANSMIT MESSAGE IN CODE MEMORY POINTED TO BY DPTR
; USES REGISTER A, DPTR, USES SUBROUTINES TXCHAR

TXMSG:	CLR	A		;POINT TO FIRST CHARACTER
	MOVC	A,@A+DPTR	;GET NEXT CHARACTER IN STRING
	JZ	TXMSG1		;EXIT IF TERMINATING ZERO
	CALL	TXCHAR		;TRANSMIT CHARACTER IN A
	INC	DPTR		;POINT TO NEXT CHARACTER
	SJMP	TXMSG		;AND REPEAT
TXMSG1:	RET


;----------------------------------------------------
; TRANSMIT CONTENTS OF ACCUMULATOR IN HEX AS 2 DIGITS
; USES REGISTER A, USES SUBROUTINES TXCHAR, HTOA

TXHEX:	PUSH	ACC		;SAVE LOWER NIBBLE
	SWAP	A		;SWAP NIBBLES
	CALL	HTOA		;CONVERT LOWER NIBBLE TO A HEX CHARACTER
	CALL	TXCHAR		;TRANSMIT CHARACTER IN A
	POP	ACC		;RESTORE LOWER NIBBLE
	CALL	HTOA		;CONVERT LOWER NIBBLE TO A HEX CHARACTER
	CALL	TXCHAR		;TRANSMIT CHARACTER IN A
	RET


TXASC:	ADD	A,#30H		;ADD THE ASCII CHARACTER OFFSET

				;TRANSMIT CHARACTER IN ACC
TXCHAR:	MOV	SBUF,A		;PUT CHARACTER IN TRANSMIT BUFFER
	JNB	TI,$		;LOOP UNTIL (ALMOST) FINISHED TRANSMITTING
	CLR	TI		;TI IS SET AT THE BEGINNING OF THE STOP BIT
	RET			;SO WE NEED TO WAIT THAT MUCH LONGER


;-----------------------------------------------------------------------------
; CONVERSION ROUTINES

;----------------------------------------------------------------
; CONVERT AN ASCII CHARACTER 0-F IN ACC TO A BINARY VALUE IN ACC
; RETURNS 0FFH IF CHARACTER DOES NOT REPRESENT A VALID VALUE
; USES REGISTERS A, B, DPTR

HTOB:	MOV	DPTR,#HEXTBL	;POINT TO TABLE OF HEX CHARACTERS
	MOV	B,A		;SAVE CHARACTER
	MOV	A,#0		;CLEAR VALUE
	PUSH	ACC		;SAVE VALUE
ATOB2:	CLR	A		;CLEAR POINTER
	MOVC	A,@A+DPTR	;GET CHARACTER FROM TABLE
	JZ	ATOBE		;END OF TABLE, NO MATCH, ERROR
	CJNE	A,B,ATOB1	;NOT A MATCHING CHARACTER
	POP	ACC		;RESTORE THE VALUE
	RET

ATOB1:	INC	DPTR		;POINT TO NEXT CHARACTER
	POP	ACC		;RESTORE VALUE
	INC	A		;INCREMENT VALUE
	PUSH	ACC		;SAVE IT AGAIN
	SJMP	ATOB2		;ANOTHER CHECK FOR MATCH

ATOBE:	POP	ACC		;CLEAN UP STACK POINTER
	MOV	A,#0FFH		;FLAG AN INVALID CHARACTER

	RET

HEXTBL:	DB	'0123456789ABCDEF',0


;-------------------------------------------------------------------
; CONVERT HEX VALUE IN LOWER NIBBLE OF ACC TO ASCII CHARACTER IN ACC

HTOA:	PUSH	DPH
	PUSH	DPL
	ANL	A,#0FH		;USE ONLY LOWER NIBBLE
	MOV	DPTR,#HEXTBL	;POINT TO TABLE OF HEX VALUES
	MOVC	A,@A+DPTR	;GET CHARACTER REPRESENTING VALUE
	POP	DPL
	POP	DPH
	RET


;-----------------------------------------------------------------------------
; INTERRUPT ROUTINES


EI0VEC:	CLR	EA		;DISABLE INTERRUPTS
	PUSH	ACC
	PUSH	PSW
	INC	CNT0LSB		;INCREMENT THE LOWER BYTE OF COUNT
	MOV	A,CNT0LSB	;NEEDED FOR THE JNZ
	JNZ	CNT0		;SKIP IF LOWER BYTE HAS NOT ROLLED OVER
	INC	CNT0MSB		;INCREMENT THE UPPER BYTE OF COUNT
CNT0:	POP	PSW
	POP	ACC
	SETB	EA		;RE-ENABLE INTERRUPTS
	RETI


EI1VEC:	CLR	EA		;DISABLE INTERRUPTS
	PUSH	ACC
	PUSH	PSW
	INC	CNT1LSB		;INCREMENT THE LOWER BYTE OF COUNT
	MOV	A,CNT1LSB	;NEEDED FOR THE JNZ
	JNZ	CNT1		;SKIP IF LOWER BYTE HAS NOT ROLLED OVER
	INC	CNT1MSB		;INCREMENT THE UPPER BYTE OF COUNT
CNT1:	POP	PSW
	POP	ACC
	SETB	EA		;RE-ENABLE INTERRUPTS
	RETI


SERVEC:	CLR	EA		;DISABLE INTERRUPTS
	PUSH	ACC
	PUSH	PSW
	JNB	RI,SEREX	;IF NOT AN RX INTERRUPT THEN EXIT

	CLR	RI		;RESET RECEIVE INTERRUPT FLAG
	MOV	A,SBUF		;GET THE CHARACTER
	MOV	LASTCH,A	;SAVE LAST CHARACTER RECEIVED IN STORAGE
	SETB	CHRFLAG		;FLAG A CHARACTER RECEIVED

SEREX:	POP	PSW
	POP	ACC
	SETB	EA		;RE-ENABLE INTERRUPTS
	RETI



	END
