		;********************************
		;*				*
		;*  Setup Epson Printer		*
		;*  For a CPM system            *
		;*  Written by M.M. Hessel	*
		;*  2/15/82 			*
		;*				*
		;********************************
		;
	ORG 0100H
	JMP START	; START IN THE MAIN PROGRAM
		;
		;   DATA STORAGE AREA
		;
NTRY	EQU	0005H	; CPM OUTPUT SUBROUTINE
PSTR	EQU	09	; PRINT BUFFER FUNCTION
GSTR	EQU	0AH	; READ BUFFER FUNCTION
PRTR    EQU	05	; PRINTER WRITE CHAR FUNCTION
RFUNC	EQU	01	; CONSOLE READ CHAR FUNCTION
WFUNC	EQU	02	; CONSOLE WRITE CHAR FUNCTION
CS	EQU	1AH	; ^Z, CLEAR SCREEN (HARDWARE DEPENDENT)
CR	EQU	0DH	; CARRIAGE RETURN
LF	EQU	0AH	; LINE FEED
		;
		;   WRITTEN DATA STORAGE
		;
PRINON	DB	0DH
	DB	'       *****EPSON PRINTER PROGRAM*****'
	DB	0AH,0AH,0AH,0AH,07H,0DH
	DB 	' !!!!! Load the PAPER FIRST!',0DH,0AH,0AH,0AH
	DB	' ***** Then TURNON the PRINTER****',0DH,0AH,0AH,0AH,07H
        DB	' Hit Any Key To Start The Program $'
		;
HLP     DB	0DH
	DB	'*****HELP INFORMATION*****',0DH,0AH,0AH,0AH
	DB	'This program will setup your Epson printer until you',0DH,0AH
	DB	'turn on it off or select a new set of options.',0DH,0AH,0AH
	DB      'The enlarged print option was not included since',0DH,0AH 
	DB	'it resets to normal size after each line printed',0DH,0AH,0AH
	DB	'You can select emphasized and then doublestrike',0DH,0AH
	DB      'to get boldface type.',0DH,0AH,0AH,0AH,0AH 
	DB      'HIT ANY KEY TO CONTINUE $'
		;
SETUP   DB	0DH
	DB 	'   ***SETUP PRINTER***',0DH,0AH,0AH
	DB	'   1. Select Typesize',0DH,0AH,0AH
	DB	'   2. Select Line Spacing',0DH,0AH,0AH	
	DB	'   3. Select Paper Out Mode',0DH,0AH,0AH
	DB	'   4. Select International Font',0DH,0AH,0AH
	DB	'   5. Help Information',0DH,0AH,0AH
	DB	'   6. Exit Program',0DH,0AH,0AH
	DB	'   Enter Your Selection $'
		;
SLINSP	DB	'   ***SELECT LINE SPACING',0DH,0AH,0AH
	DB	'   1. 6 lines/inch (Default)',0DH,0AH,0AH
	DB	'   2. 8 lines/inch',0DH,0AH,0AH
	DB	'   3. Choose special spacing!',0DH,0AH,0AH
	DB	'   Enter Your Selection $'
		;
SPSPC	DB	'   ***VARIABLE LINE SPACING***',0DH,0AH,0AH
	DB	'   You can set line spacing between 1/72 to',0DH,0AH
	DB	'   85/72 of an inch',0DH,0AH,0AH,07H
	DB	'   Enter a number between 1 and 85 ',0DH,0AH,0AH,'$'
		;
TSIZE	DB 	'   ***SELECT TYPEFACE***',0DH,0AH,0AH
        DB	'   1. Emphasized Print On',0DH,0AH,0AH
	DB	'   2. Condensed Print On',0DH,0AH,0AH
	DB	'   3. Emphasized Print Off',0DH,0AH,0AH
	DB	'   4. Condensed Print Off',0DH,0AH,0AH
	DB	'   5. Double Strike On',0DH,0AH,0AH
	DB	'   6. Double Strike Off',0DH,0AH,0AH
	DB	'   7. No change',0DH,0AH,0AH
	DB 	' Enter your Selection  $'
		;
PSEL	DB	'   ***SELECT PAPER OUT MODE***',0DH,0AH,0AH
	DB	'   1. Select Paper End Detector',0DH,0AH,0AH
	DB	'   2. Deselects Paper End Detector',0DH,0AH,0AH
	DB	'  Enter your Selection $'
		;
INTFONT	DB	'   ***SELECT CHARACTER SET***',0DH,0AH,0AH
	DB	'   0. U.S.A.',0DH,0AH,0AH
	DB	'   1. France',0DH,0AH,0AH
	DB	'   2. Germany',0DH,0AH,0AH
	DB	'   3. England',0DH,0AH,0AH
	DB	'   4. Denmark',0DH,0AH,0AH
	DB	'   5. Sweden',0DH,0AH,0AH
	DB	'   6. Italy',0DH,0AH,0AH
	DB	'   7. Spain',0DH,0AH,0AH
	DB	' Enter Your Selection $'
		;
ERRMSG	DB	07H,'  DEFAULT USED $'
		;
SPCNG	DS 4	; Stores line spacing
OLDSTK	DS 2
	DS 60
STACK	EQU $	; Allows 30 items on the stack
		;
		;********************************
		;*   Subroutine "Savstk"        *
		;*   Saves CPM registers/stack	*
		;*   Define SP			*
		;********************************
SAVSTK	POP B
	LXI H,0000	; Clear HL
	DAD SP		; Get Stack Pointer
	SHLD OLDSTK	; Save SP
	LXI H,STACK	; Set HL with address of SP
	SPHL		; Set new Stack Pointer
	PUSH B		; Return address set
	RET
		;
		;********************************
		;*   Subroutine "Restor"	*
		;*   Restores stack to CPM	*
		;********************************
		;
RESTOR	LHLD OLDSTK	; Get old Stack Pointer
	SPHL		; Put it in the register
	RET		; This returns to CPM
			;
		;********************************
		;* Subroutine "TURNON" reminds  *
		;* you to turn on the printer   *
		;********************************
		;
TURNON	CALL CLEAR
	CALL CRLF
	LXI D,PRINON
	CALL PRINT
	CALL READ
	RET
		;
		;********************************
		;* Subroutine "Menu" the main   *
		;* selection menu. Program      *
		;* returns to this menu after   *
		;* selecting option. Exit goes  *
		;* back to CPM			*
		;********************************
		;
MENU	CALL CLEAR
	CALL CRLF
	MVI E,CR
	CALL PCHAR
	LXI D,SETUP
	CALL PRINT
	CALL READ
	MVI B,36H
	CMP B
	JZ EXIT		; EXIT TO CPM
	DCR B
	CMP B
	JZ HELP		; TO WRITE HELP INFORMATION
	DCR B
	CMP B
	JZ CHARSET	; CHARACTER SET FONT
	DCR B
	CMP B
	JZ PSMODE	; PAPER SELECTOR
	DCR B
	CMP B
	JZ LINESP	; LINE SPACING
	DCR B
	CMP B
	JZ TYPE		; TYPESIZE
	JMP MENU	; INCORRECT NUMBER SELECTED
EXIT	RET		; RETURN TO CPM
		;
		;********************************
		;* Subroutine "HELP" prints     *
		;* information about program    *
		;********************************
HELP	CALL CLEAR
	CALL CRLF
	LXI D,HLP
	CALL PRINT
	CALL READ
	JMP MENU
		;
		;********************************
		;* Subroutine "CHARSET" selects *
		;* one of an eight possible     *
		;* character sets U.S.A.,France,*
		;* Germany,etc.                 *
		;********************************
		;
CHARSET	CALL CLEAR
	CALL CRLF
	LXI D,INTFONT
	CALL PRINT
	CALL READ
	MVI E,1BH
	CALL PCHAR		; Escape to Printer
	MVI E,52H
	CALL PCHAR		; "R" to Printer
	SUI 30H			; Convert console input fom ASCII to Binary
	CMP B			; Is input < 0 ?
	JC INCORR		; If yes invalid
	MVI B,08H
	CMP B			; Is input > 7 ?
	JZ SKIP			
	JNC INCORR		; If yes invalid
SKIP	MOV E,A	
	CALL PCHAR		; "Character Set" to printer
	JMP FIN
INCORR	MVI E,00H		
	CALL PCHAR		; Default Set is USA
FIN	JMP MENU		; End of Character Set!!
		;
		;********************************
		;*   Subroutine "PSMODE" turn   *
		;*   the paper end detector off *
		;*   or on. Default is on	*
		;********************************
PSMODE	CALL CLEAR
	CALL CRLF
	LXI D,PSEL
	CALL PRINT 
	CALL READ
	MVI E,1BH
	CALL PCHAR
	MVI B,32H
	CMP B
	JNZ SELECT
	MVI E,38H
	CALL PCHAR
	JMP MENU
SELECT	MVI E,39H
	CALL PCHAR
	JMP MENU	
		;
		;********************************
		;*   Subroutine "TYPE" sets the *
		;*   typeface		        *
		;********************************
		;
TYPE 	CALL CLEAR
	CALL CRLF
	LXI D,TSIZE
	CALL PRINT
	CALL READ
	MVI B,37H	; Test the selection
	CMP B
	JZ MENU  	; No change
	DCR B
	CMP B
	JZ DSOFF	; Doublestrike off 
	DCR B
	CMP B
	JZ DSON		; Doublestrike on
	DCR B
	CMP B
	JZ CNOFF	; Condensed printing off
	DCR B
	CMP B
	JZ EMOFF	; Emphasized printing off
	DCR B
	CMP B
	JZ CNON		; Condensed printing on
	DCR B
	CMP B
	JZ EMON		; Emphasized printing on
	JMP MENU 	; To Menu
DSOFF	MVI E,1BH	
	CALL PCHAR
	MVI E,48H	; Doublestrike off
	JMP PTR
DSON    MVI E,1BH
	CALL PCHAR
	MVI E,47H	; Doublestrike on	
	JMP PTR
CNOFF	MVI E,12H	; ^R Condensed off
	JMP PTR
EMOFF   MVI E,1BH	; Escape to printer
	CALL PCHAR
	MVI E,46H	; "F" emphasized off
	JMP PTR
CNON	MVI E,0FH	; ^O Condensed on
	JMP PTR
EMON	MVI E,1BH	; Escape to printer
	CALL PCHAR
	MVI E,45H	; "E" emphasized on
PTR	CALL PCHAR
NOCHG   JMP MENU
		;
		;********************************
		; Subroutine "LINESP" provides a*
		; choice of 1 - 85/72 of an inch*
		; spacing on the Epson.         *
		;********************************
LINESP	CALL CLEAR
	CALL CRLF
	LXI D,SLINSP
	CALL PRINT	; Your choice line of spacing
	MVI E,1BH	
	CALL PCHAR	; Send escape to the printer
	CALL READ
	MVI B,32H
	CMP B
	JNZ SPSP	
	MVI E,30H	; 8 Lines/inch
	CALL PCHAR	; To the printer
	JMP MENU
SPSP	MVI B,33H
	CMP B
	JZ SPECL
DFL	MVI E,31H
	CALL PCHAR	; 6 Lines/inch (Default)
	JMP  MENU
SPECL	CALL CLEAR	; Variable line spacing
	CALL CRLF
	LXI D,SPSPC
	CALL PRINT
	MVI E,41H
	CALL PCHAR	; Send "A" to printer(Esc A)
	LXI H,SPCNG     ; Address of console buffer
	MOV D,H   	; Put H & L in 
	MOV E,L		; D & E registers	
	MVI M,02	; Maximum buffer length = 2
	INX H		; Point to character count byte
	MVI M,00	; Zero charcter count
	CALL CHRSTR	; Console buffer read subroutine
CKCHR	LXI H,SPCNG+1	; This routine checks input is it 1 to 85?
	MOV A,M		; Character counter
	CPI 02H		; Two characters?
	INX H
	INX H		; Point to units digit
	JZ CTES		; If yes process two digits
	CPI 1		; One character?
	JZ SHIFT	; If yes shift tens to unit position
	JMP DEF		; If 0 set default
CTES	MOV A,M		; Put units digit in A
    	CALL TEST	; Test if it is in the range 0 to 9
TENS	DCX H		; Point to tens digit
	MOV A,M
	CALL BLANK	; Is it blank?
	CALL TEST	; Test for 0 to 9
	CALL CONV	; Convert to hex from decimal
	JMP MENU	; Done!
TEST	SUI 30H		; Tests for digit
	JC DEF		; <0
	CPI 0AH		
	JNC DEF		; >9
	MOV M,A		; Store digit
	RET
CONV	MOV A,M		; Converts tens input to hex
	ADD A		; *2
	ADD A		; *4
	ADD M		; *5
	ADD A		; *10
	INX H		; point M to units
	ADD M		; Conversion complete
	CPI 0		; Is it 0
	JZ DEF		
	CPI 86		; Is it >85
	JNC DEF
	MOV E,A
	CALL PCHAR	; Send spacing to printer
	RET
SHIFT	DCX H		; Point to tens digit
	MOV A,M		; Move it to accumulator
	MVI M,30H	; Store ASCII 0 in tens
	INX H		; Point to units digit
	MOV M,A		; Put tens in unit place
	JMP CTES
BLANK 	CPI 20H		; Is it blank?
	RNZ
	MVI A,30H	; Yes put an ASCII 0 in A.
	MOV M,A		; Store it
	RET
DEF     POP D
DEFLT 	MVI E,0CH
	CALL PCHAR	; Send 12/72 to printer 6 lines/inch
	LXI D,ERRMSG
	CALL PRINT
	JMP MENU
			;
		;********************************	
		;* Subroutine "Print" a string  *
		;* on the console. String must  *
		;* end with a $ sign            *
		;********************************
		;
PRINT	PUSH H	; PRESERVE REGISTERS
	PUSH D
	PUSH B
	PUSH PSW
	MVI C,PSTR
	CALL NTRY
	POP PSW
	POP B
	POP D
	POP H
	RET
		;
		;*******************************
		;*  Subroutine "Clear Screen"  *
		;*  for Osborne ^Z =1AH        *
		;*******************************
		;
CLEAR	PUSH PSW
	MVI A,CS
	CALL WCHAR
	POP PSW
	RET
		;
		;*******************************
		;*   Subroutine "Write" one    *
		;*   character to the console  *
		;*******************************
		;
WCHAR	PUSH H
	PUSH D
	PUSH B
	PUSH PSW
	MOV E,A		; PUT CHAR IN THE E REGISTER
	MVI C,WFUNC	; WRITE CHARACTER FUNCTION
	CALL NTRY
	POP PSW
	POP B
	POP D
	POP H
	RET
		;
		;*******************************
		;*   Subroutine CRLF           *
		;*******************************
		;
CRLF	PUSH PSW
	MVI A,CR	; Carriage return
	CALL WCHAR
	MVI A,LF	; Line Feed
	CALL WCHAR
	POP PSW
	RET
		;
		;********************************
		;*   Subroutine "READ" character*
		;*   from the console	        *
		;********************************
		;
READ	EQU $		; REGISTERS NOT SAVED
	MVI C,RFUNC
	CALL NTRY	; STORES THE CHARACTER IN A
	RET
		;
		;********************************
		;*  Subroutine "CHRSTR" reads a *
		;*  string of characters from   *
		;*  the console			*
		;********************************
		;
CHRSTR	MVI C,GSTR	
	CALL NTRY
	RET
		;
		;********************************
		;   Subroutine "PCHAR" lists a  *
		;   character on the printer    *
		;********************************
		;
PCHAR	PUSH PSW
	MVI C,PRTR
	CALL NTRY
	POP PSW
	RET
		;
		;********************************
		;*   MAIN PROGRAM		*
		;********************************
		;
START

	CALL SAVSTK		; Preserves CPM registers/stack
	CALL TURNON		; Reminds you to turn on printer
	CALL MENU
	MVI E,0AH		; Send CR to printer
	CALL PCHAR
	CALL RESTOR		; Returns to CPM
	END 0100H