;********************************************************
;*							*
;*	    BI-DIRECTIONAL PRINTING DRIVER 		*
;*	      FOR DIABLO 1620 OR SIMILAR		*
;*		  DAISYWHEEL PRINTER			*
;*							*
;********************************************************
;
;	VERSION:	1.00
;
;	DATE:		03/Mar/1980
;
;	HISTORY:	Modified for CP/M use 
;			from PTDOS program
;			originally published by PROTEUS
;
;	Modifications by:
;			Bill Bolton
;			Software Tools
;			P.O. Box 80,
;			Newport Beach,
;			NSW, 2106,
;			Australia
;
NULL	EQU	000H		;ASCII NULL
DEL	EQU	07FH		;ASCII DELETE
CR	EQU	00DH		;ASCII CARRIAGE RETURN
LF	EQU	00AH		;ASCII LINE FEED
FF	EQU	00CH		;ASCII FORM FEED
ESC	EQU	01BH		;ASCII ESCAPE
HTAB	EQU	009H		;ASCII HORIZONTAL TAB
SPACE	EQU	020H		;ASCII ' '
BACKSP	EQU	008H		;ASCII BACKSPACE
ACK	EQU	006H		;ASCII ACKNOWLEDGE
ETX	EQU	003H		;ASCII END OF TEXT
STPORT	EQU	003H		;HORIZON 1ST SERIAL STATUS
DPORT	EQU	STPORT-1	;HORIZON 1ST SERIAL DATA
OUTMASK	EQU	001H		;OUTPUT STATUS MASK
INMASK	EQU	002H		;INPUT STATUS MASK
COUNT	EQU	150		;DIABLO BUFFER LENGTH
;
	ORG	0F200H		;Or wherever suits
;
PROCESS:
	MOV	A,C
	CPI	CR		;CARRIAGE RETURN ?
	JZ	PRINT		;YES, PRINT OUT THE BUFFER
	CPI	LF		;LINE FEED ?
	JZ	PUTC		;YES, SEND IT
	CPI	FF		;FORM FEED ?
	JZ	PUTC		;YES, SEND IT
	CPI	DEL		;DELETE ?
	RZ			;YES, IGNORE IT
	CPI	NULL		;NULL ?
	RZ			;IGNORE IT
;
PRO2:
	LDA	EOLINE		;INCREMENT END OF LINE
	INR	A
	STA	EOLINE
	LHLD	TXTPT		;GET TEXT POINTER
	MOV	M,C		;CHARACTER WAS IN C
	INX	H		;BUMP POINTER
	MVI	M,0		;BUFFER END MARK IS 0
	SHLD	TXTPT		;STORE POINTER
	RET
;
;*	This routine strips leading and lagging blanks from
;*	the buffer before sending the buffer out to the printer.
;
;*	Strip the leading blanks
;
PRINT:
	LXI	H,BUFFER+1	;POINT TO 1ST CHARACTER POSITION
	MVI	D,0		;BLANKS COUNTER
	MVI	A,SPACE		;BLANK FOR COMPARISION
P1:
	CMP	M		;BLANK ?
	JNZ	P2		;NO, STOP COUNTING
	INR	D
	INX	H
	JMP	P1
;
P2:
	DCX	H		;POINT TO CHAR-1
	MVI	M,0		;PUT IN A MARKER
	MOV	A,D		;GET BLANK COUNT
	STA	BOLINE		;AND SAVE IT
;
;*	Strip the lagging blanks
;
	LHLD	TXTPT		;POINT TO BUFFER END MARK
	LDA	EOLINE		;GET CHARACTER COUNT
	MOV	D,A
	MVI	A,SPACE		;GET A SPACE
;
P3:
	DCX	H
	DCR	D		;BLANK COUNTER
	CMP	M		;IS IT A SPACE ?
	JZ	P3		;YES, KEEP COUNTING
;
P4:
	INX	H		;NO, BACK UP THE POINTER
	MVI	M,0		;STORE END MARKER
	MOV	A,D
	STA	EOLINE		;STORE NEW COUNT
	SHLD	TXTPT		;STORE NEW BUFER END
;
;*	Calculate the most efficient direction to print
;*	(logic seeking).
; 
DRCTN:
	LDA	HDPOS		;GET PRINT HEAD POSITION
	PUSH	PSW		;SAVE IT
	LXI	H,BOLINE	;POINT TO BEGINNING OF LINE
	SUB	M		;FIND THE DIFFERENCE
	CM	ABSVAL		;TAKE THE ABSOLUTE VALUE
	MOV	B,A		;SAVE IT IN B
	INX	H		;GET THE END OF LINE
	POP	PSW		;GET HEAD POSITION
	SUB	M		;FIND THE DIFFERENCE
	CM	ABSVAL		;TAKE THE ABSOLUTE VALUE
	SUB	B		;COMPARE DISTANCE TO BOL AND EOL
	JP	MFWRD		;IF PLUS FORWARD IS FASTER
;
;*	Print backwards
;
MBWRD:
	MVI	D,'6'		;DIABLO BACKWARD PRINT CODE
	LDA	EOLINE		;GET END OF LINE
	CALL	ALIGN		;PROCESS THE DATA
	LDA	BOLINE		;POSITION OF 1ST BUFFER CHARACTER
	ORA	A		;IS IT THE ZERO POSITION
	JZ	MB2		;YES, CANT TAB LEFT OF MARGIN
	DCR	A
;
MB2:
	STA	HDPOS		;UPDATE HEAD POSITION
	LXI	D,-1
	LHLD	TXTPT		;POINT TO END OF BUFFER
	JMP	PRLINE		;PRINT THE BUFFER
;
;*	Print forwards
;
MFWRD:
	MVI	D,'5'		;DIABLO FORWARD PRINT CODE
	LDA	BOLINE		;GET BEGINNING OF LINE
	CALL	ALIGN
	LDA	EOLINE		;GET LAST CHARACTER POSITION
	INR	A
	STA	HDPOS		;SAVE NEW HEAD POSITION
	LXI	H,BUFFER	;POINT TO BUFFER START
	LDA	BOLINE		;COMPUTE POSITION OF 1ST NON BLANK
	MVI	D,0
	MOV	E,A
	DAD	D
	LXI	D,1		;SET UP TO READ BUFFER FORWARD
;
;*	Print the buffer
;
PRLINE:
	DAD	D		;BUMP	HL
	MOV	A,M		;MOVE CHARACTER IN BUFFER TO A
	ORA	A		;END OF BUFFER ?
	JZ	CLRBUF		;YES, GO CLEAN UP
	CALL	PUTC		;PRINT THE CHARACTER
	JMP	PRLINE
;
;*		Align the Print Head to the correct position
;*		to start printing
;
;*		NOTE: The diablo 1610/1620 can only do an
;*		"absolute tab" to the first 126 character
;*		positions.
;
;*		D = Direction of printing
;*		A = BOLINE or EOLINE
;
ALIGN:
	MOV	E,A		;SAVE BOLINE/EOLINE
	MVI	A,ESC		;GET "COMMAND" CODE
	CALL	PUTC		;SEND IT
	MOV	A,D		;GET THE DIRECTION CODE
	CALL	PUTC		;SEND IT
;
	MVI	A,ESC		;GET "COMMAND" CODE
	CALL	PUTC		;SEND IT
	MVI	A,HTAB		;GET ABSOLUTE TAB CODE
	CALL	PUTC		;SEND IT
	MOV	A,E		;GET LOCATION TO TAB TO
	ADI	1		;ADD TO SATISFY DIABLO
	JMP	PUTC		;SEND IT AND RETURN
;
CLRBUF:
	LXI	H,BUFFER+1	;CLEAR BUFFER
	SHLD	TXTPT
	XRA	A
	STA	EOLINE		;RESET COUNTERS
	STA	BOLINE
	STA	BUFFER+1
	RET
;
ABSVAL:
	CMA			;TAKE THE ABSOLUTE VALUE
	INR	A
	RET
;
PUTC:
	MOV	C,A
	CALL	OUTPUT		;SEND THE CHARACTER
	CPI	ESC		;WAS IT AN ESCAPE?
	JZ	ESCSEQ		;YES, NEEDS SPECIAL TREATMENT
	LDA	OUTCNT		;CHARS SENT SINCE O/P COUNT RESET
	DCR	A
STORE:
	STA	OUTCNT		;SAVE UPDATED COUNT
	RNZ			;NO, RETURN
	MVI	A,COUNT		;SET COUNT
	STA	OUTCNT
	MVI	C,ETX		;YES, GET ETX
	CALL	OUTPUT		;SEND IT
ACKLOOP:
	CALL	INPUT		;GET CHARACTER FROM PRINTER
	CPI	ACK		;DIABLO SENDS ACK WHEN IT GETS ETX
				;FROM ITS CHARACTER BUFFER
	JNZ	ACKLOOP		;NOT FOUND, KEEP LOOKING
	RET
;
ESCSEQ:
	LDA	OUTCNT		;GET OUTPUT COUNT
	ADI	2		;MAKE SURE NEXT TWO CHARS,
	JMP	STORE		;GET SENT BEFORE ETX
;
OUTPUT:
	IN	STPORT		;1ST SERIAL PORT
	ANI	OUTMASK
	JZ	OUTPUT
	MOV	A,C
	OUT	DPORT
	RET
;
INPUT:
	IN	STPORT
	ANI	INMASK
	JZ	INPUT
	IN	DPORT
	ANI	07FH
	RET
;
;
HDPOS	DB	0		;CURRENT HEAD POSITION
BOLINE	DB	0		;BEGINNING OF LINE POINTER
EOLINE	DB	0		;END OF LINE POINTER
TXTPT	DW	BUFFER+1	;BUFFER POINTER
OUTCNT	DB	COUNT		;CHARACTERS SENT TO PRINTER
;
BUFFER	DW	0000H
	DS	160		;CHARACTER BUFFER
;
	END	PROCESS
		