;********************************************************
;*                                                      *
;*          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