UNIT Y767COMM; (* Interrupt driven Serial Comm routines - D. J. Wilke 10/18/89 *)

INTERFACE

USES CRT, DOS, Y767GLO;

PROCEDURE EnableInterrupts;
PROCEDURE CommExitProc;
PROCEDURE SetupSerialPort(ComPort : INTEGER; ComVec : WORD; ComBase,IRQM : INTEGER);
FUNCTION InStat : Boolean;
PROCEDURE FlushBuffer;
FUNCTION InChar : Char;
PROCEDURE OutChar(Ch : Char);
PROCEDURE SendString(Inst : STRING5; SUS : INTEGER);

IMPLEMENTATION

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE EnableInterrupts;
BEGIN
    INLINE($FB);                             (* Interrupt Service Routine *)
END;

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE Incoming(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : Word);
INTERRUPT;

VAR
    RBR : INTEGER;

BEGIN
    EnableInterrupts;                        (* Enable ints during the ISR: *)
    RBR               := ComBase;            (* 8250 Receive Buffer Register *)
    IF LastSaved >= 1023 THEN                (* Make 1024-byte circ buffer *)
        LastSaved     := 0
    ELSE Inc(LastSaved);
    Buffer[LastSaved] := Char(Port[RBR]);    (* Read incoming character *)
    Port[OCW2]        := $20;                (* Send EOI byte to 8259 *)
END;

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
{$F+}
PROCEDURE CommExitProc;

VAR
    RBR,IER,MCR : INTEGER;

BEGIN
    RBR        := ComBase;                   (* 8250 Receive Buffer Register *)
    IER        := ComBase + 1;               (* 8250 Interrupt Enable Register *)
    MCR        := ComBase + 4;               (* 8250 Modem Control Register *)
    Port[IER]  := 0;                         (* Disable interrupts at 8250 *)
    Port[OCW1] := Port[OCW1] OR IRQM;        (* Disable IRQ_ at 8259 *)
    Port[MCR]  := 0;                         (* Bring the comm line down *)
    SETINTVEC(ComVec,OldComVec);             (* Restore prev saved vector *)
END;
{$F-}

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE SetupSerialPort(ComPort      : INTEGER;
                          ComVec       : WORD;
                          ComBase,IRQM : INTEGER);

VAR
    RBR,THR,DLL,DLM,IER,IIR,LCR,MCR,LSR,MSR : INTEGER;

BEGIN
    RBR        := ComBase;                   (* 8250 Receive Buffer Register *)
    THR        := ComBase;                   (* 8250 Transmit Holding Register *)
    DLL        := ComBase;                   (* 8250 Divisor Latch LSB *)
    DLM        := ComBase + 1;               (* 8250 Divisor Latch MSB *)
    IER        := ComBase + 1;               (* 8250 Interrupt Enable Register *)
    IIR        := ComBase + 2;               (* 8250 Interrupt Ident Register *)
    LCR        := ComBase + 3;               (* 8250 Line Control Register *)
    MCR        := ComBase + 4;               (* 8250 Modem Control Register *)
    LSR        := ComBase + 5;               (* 8250 Line Status Register *)
    MSR        := ComBase + 6;               (* 8250 Modem Status Register *)
    LastRead   := 0;                         (* Initialize circ buf pointers *)
    LastSaved  := 0;
    Port[IER]  := 0;                         (* Disable ints while setting up *)
    GETINTVEC(ComVec,OldComVec);             (* Save old IRQ vector *)
    ExitProc   := @CommExitProc;             (* Hook exit proc into chain *)
    SETINTVEC(ComVec,@Incoming);             (* Put ISR addr into vector table *)
    Port[LCR]  := Port[LCR] OR DLAB;         (* Set up 8250 for baud rate *)
    Port[DLL]  := Lo(Divisor);               (* Set baud rate divisor *)
    Port[DLM]  := Hi(Divisor);
    Port[LCR]  := DataBits OR StopBits;      (* Set word length and stop bits *)
    Port[LCR]  := Port[LCR] OR Parity;       (* Set parity *)
    Port[MCR]  := DTR OR RTS OR OUT2;        (* Enable DTR, RTS & adapter *)
    Port[OCW1] := Port[OCW1] AND (NOT IRQM); (* Turn on 8259 IRQ_ ints *)
    Clearit    := Port[RBR];                 (* Clear any garbage from RBR *)
    Clearit    := Port[LSR];                 (* Clear any garbage from LSR *)
    Port[IER]  := $01;                       (* Enable int on received char *)
END;

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
FUNCTION InStat : Boolean;

BEGIN
    IF LastSaved <> LastRead THEN
        InStat  := True
    ELSE InStat := False;
END;

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE FlushBuffer;

VAR
    RBR : INTEGER;

BEGIN
    RBR        := ComBase;                   (* 8250 Receive Buffer Register *)
    LastRead   := 0;
    LastSaved  := 0;
    Clearit    := Port[RBR];                 (* Clear any garbage from RBR *)
    FILLCHAR(Buffer,SIZEOF(Buffer),0);
END;

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
FUNCTION InChar : Char;                      (* Bring in next char from ring buf *)

BEGIN
    IF LastRead >= 1023 THEN
        LastRead  := 0
    ELSE LastRead := Succ(LastRead);
    InChar := Buffer[LastRead];
END;

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE OutChar(Ch : Char);                (* Send a char to the comm port *)

VAR
    THR : INTEGER;

BEGIN
    THR       := ComBase;                    (* 8250 Transmit Holding Register *)
    Port[THR] := Byte(Ch)                    (* Put char into THR *)
END;

(*²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²*)
PROCEDURE SendString(Inst : STRING5; SUS : INTEGER);

VAR
    Index : INTEGER;

BEGIN
    FOR Index := 1 to LENGTH(Inst) DO BEGIN
        OutChar(Inst[Index]);
        DELAY(10);
    END;
    DELAY(SUS * 3);
END;

END. (* UNIT Y767COMM *)
