[Back to COMM SWAG index]  [Back to Main SWAG index]  [Original]

{$B-} { Short circuit boolean ON }
{$I-} { I/O checking OFF }
{$R-} { Range checking OFF }
{$S-} { Stack checking OFF }
{$V-} { Var-str checking OFF}

UNIT ASYNC2;
  {PD async unit debugged and modified for doorgame use by Joel Bergen}
  {added com3 & com4 support and xon/xoff handshaking                 }
  {various bug fixes by Gary Gordon & Joel Bergen Jan 1990}
  {Last revised:  1/14/90}
  {still needs check for existance of comm port in Async_Open routine}

INTERFACE

USES DOS, CRT;

VAR
  Async_CheckCTS  : BOOLEAN;

PROCEDURE Async_Init;
  { initialize variables, call first to initialize }

PROCEDURE Async_Close;
  { reset the interrupt system when UART interrupts no longer needed }
  { Turn off the COM port interrupts.                                }
  { **MUST** BE CALLED BEFORE EXITING YOUR PROGRAM; otherwise you    }
  { will see some really strange errors and have to re-boot.         }

FUNCTION Async_Open(ComPort,BaudRate : WORD) : BOOLEAN;
  { open a communications port at 8/n/1 with supplied port & baud   }
  { Sets up interrupt vector, initialies the COM port for           }
  { processing, sets pointers to the buffer.  Returns FALSE if COM  }
  { port not installed.                                             }

FUNCTION Async_Buffer_Check : BOOLEAN;
  { see if a character has been received        }
  { If a character is available, returns TRUE   }
  { Otherwise, returns FALSE                    }

FUNCTION Async_Read : CHAR;
  { read a character, assuming it is ready}

PROCEDURE Async_Send(C : CHAR);
  { transmit a character }

PROCEDURE Async_Hangup;
  { drop carrier by dropping DTR}

FUNCTION Async_CarrierDetect : BOOLEAN;
  { true if carrier detected }

{----------------------------------------------------------------------------}

IMPLEMENTATION

CONST
  I8088_IMR = $21;   { port address of the Interrupt Mask Register }
  AsyncBasePort  : ARRAY[1..4] OF WORD = ($03F8,$02F8,$03E8,$02E8);
  AsyncIRQ       : ARRAY[1..4] OF WORD = (4,3,4,3);
  Async_Buffer_Max = 1024;          { size of input buffer }
  Ier = 1;
  Lcr = 3;
  Mcr = 4;
  Lsr = 5;
  Msr = 6;

VAR
  Async_OriginalVector : POINTER;
  Async_OriginalLcr    : INTEGER;
  Async_OriginalImr    : INTEGER;
  Async_OriginalIer    : INTEGER;

  Async_Buffer         : ARRAY[0..Async_Buffer_Max] OF CHAR;

  Async_Open_Flag      : BOOLEAN;   { true if Open but no Close }
  Async_Pause          : BOOLEAN;   { true if paused (Xoff received) }
  Async_Port           : INTEGER;   { current Open port number (1..4) }
  Async_Base           : INTEGER;   { base for current open port }
  Async_Irq            : INTEGER;   { irq for current open port }

  Async_Buffer_Overflow: BOOLEAN;   { True if buffer overflow has happened }
  Async_Buffer_Used    : WORD;      { number of characters in input buffer }

  { Async_Buffer is empty if Head = Tail }
  Async_Buffer_Head    : WORD;   { Locn in Async_Buffer to put next char }
  Async_Buffer_Tail    : WORD;   { Locn in Async_Buffer to get next char }

PROCEDURE DisableInterrupts; INLINE($FA {cli} );     {MACROS}
PROCEDURE EnableInterrupts;  INLINE($FB {sti} );

PROCEDURE Async_Isr;  INTERRUPT;
{ Interrupt Service Routine
  Invoked when the UART has received a byte of data from the
  communication line }
CONST
  Xon  = #17;  {^q resume}
  Xoff = #19;  {^s pause}
VAR
  c : CHAR;
BEGIN
  EnableInterrupts;
  IF Async_Buffer_Used < Async_Buffer_Max THEN BEGIN
    c := CHR(PORT[Async_Base]);
    CASE c OF
      Xoff : Async_Pause:=TRUE;
      Xon  : Async_Pause:=FALSE;
      ELSE BEGIN
        Async_Pause:=FALSE;
        Async_Buffer[Async_Buffer_Head] := c;
        IF Async_Buffer_Head < Async_Buffer_Max THEN
          INC(Async_Buffer_Head)
        ELSE
          Async_Buffer_Head := 0;
        INC(Async_Buffer_Used);
      END;
    END;
  END ELSE Async_Buffer_Overflow := TRUE;
  DisableInterrupts;
  PORT[$20] := $20;
END; { Async_Isr }

PROCEDURE Async_Init;
{ initialize variables }
BEGIN
  Async_Open_Flag       := FALSE;
  Async_Buffer_Head     := 0;
  Async_Buffer_Tail     := 0;
  Async_Buffer_Overflow := FALSE;
  Async_Buffer_Used     := 0;
  Async_Pause           := FALSE;
  Async_CheckCTS        := TRUE;
END; { Async_Init }

PROCEDURE Async_Close;
{ reset the interrupt system when UART interrupts no longer needed }
VAR
  i, m : INTEGER;
BEGIN
  IF Async_Open_Flag THEN BEGIN
    DisableInterrupts;             { disable IRQ on 8259 }
    PORT[Async_Base + Ier] := Async_OriginalIer;
    PORT[Async_Base+Lcr]   := Async_OriginalLcr;
    PORT[I8088_IMR]        := Async_OriginalImr;
    EnableInterrupts;
    SETINTVEC(Async_Irq + 8,Async_OriginalVector);
    Async_Open_Flag := FALSE     { flag port as closed }
  END
END; { Async_Close }

FUNCTION Async_Open(ComPort,BaudRate : WORD) : BOOLEAN;
VAR
  i, m : INTEGER;
  b    : BYTE;
BEGIN
    IF Async_Open_Flag THEN Async_Close;
    Async_Port := ComPort;
    Async_Base := AsyncBasePort[Async_Port];
    Async_Irq  := AsyncIRQ[Async_Port];
      { set comm parameters }
    Async_OriginalLcr := PORT[Async_Base+Lcr];

    PORT[Async_Base+Lcr] := $03;  {set 8/n/1. This shouldn't be hardcoded}
      { set ISR vector }
    GETINTVEC(Async_Irq+8, Async_OriginalVector);
    SETINTVEC(Async_Irq+8, @Async_Isr);
      { read the RBR and reset any possible pending error conditions }
      { first turn off the Divisor Access Latch Bit to allow access to RBR, etc. }
    DisableInterrupts;
    PORT[Async_Base+Lcr] := PORT[Async_Base+Lcr] AND $7F;
      { read the Line Status Register to reset any errors it indicates }
    i := PORT[Async_Base+Lsr];
      { read the Receiver Buffer Register in case it contains a character }
    i := PORT[Async_Base];
      { enable the irq on the 8259 controller }
    i := PORT[I8088_IMR];  { get the interrupt mask register }

    Async_OriginalImr := i;

    m := (1 shl Async_Irq) XOR $00FF;
    PORT[I8088_IMR] := i AND m;
      { enable the data ready interrupt on the 8250 }

    Async_OriginalIer := PORT[Async_Base + Ier];

    Port[Async_Base + Ier] := $01; { enable data ready interrupt }
      { enable OUT2 on 8250 }
    i := PORT[Async_Base + Mcr];
    PORT[Async_Base + Mcr] := i OR $08;
    EnableInterrupts;
      { Set baudrate}
    b := PORT[Async_Base+Lcr] OR 128;
    PORT[Async_Base+Lcr]:= b;
    PORT[Async_Base  ]  := LO(TRUNC(115200.0/BaudRate));
    PORT[Async_Base+1]  := HI(TRUNC(115200.0/BaudRate));
    PORT[Async_Base+Lcr]:= b AND 127;
      { set flags }
    Async_Open_Flag := TRUE;
    Async_Open := TRUE;
END; { Async_Open }

FUNCTION Async_Buffer_Check : BOOLEAN;
{ return true if character ready to receive }
BEGIN
  Async_Buffer_Check := (Async_Buffer_Used <> 0);
END; { Async_Buffer_Check }

FUNCTION Async_Read : CHAR;
{ return char, use Async_Buffer_Check first! }
BEGIN
  Async_Read := Async_Buffer[Async_Buffer_Tail];
  INC(Async_Buffer_Tail);
  IF Async_Buffer_Tail > Async_Buffer_Max THEN
    Async_Buffer_Tail := 0;
  DEC(Async_Buffer_Used);
END; { Async_Buffer_Check }

PROCEDURE Async_Send(c : CHAR);
{ transmit a character }
BEGIN
  PORT[Async_Base + Mcr] := $0B;                 {turn on OUT2, DTR, and RTS}
  IF Async_CheckCTS THEN
    WHILE (Port[Async_Base + Msr] AND $10) = 0 DO;  {wait for CTS}
  WHILE (Port[Async_Base + Lsr] AND $20) = 0 DO; {wait for Tx Holding Reg Empty}
  WHILE Async_Pause AND Async_CarrierDetect DO;  {wait for Xon}
  DisableInterrupts;
  PORT[Async_Base] := ORD(c);                    {send the character}
  EnableInterrupts;
END; { Async_Send }

PROCEDURE Async_Hangup;
BEGIN
  PORT[Async_Base+Mcr] := $00;  {dtr off}
  DELAY(1000);                  {wait 1 second}
  PORT[Async_Base+Mcr] := $03;  {dtr on}
END;

FUNCTION Async_CarrierDetect : BOOLEAN;
{true if carrier}
VAR
  b : BOOLEAN;
  w : WORD;
BEGIN
  w:=0; b:=TRUE;
  WHILE (w<500) AND b DO BEGIN              {make sure carrier stays down}
    INC(w);                                 {and is not just a fluke     }
    b:=(PORT[Async_Base+Msr] AND 128) <> 128; {true = no carrier};
  END;
  Async_CarrierDetect := NOT b;
END;

BEGIN
  Async_Init;
END. { ASYNC UNIT }

[Back to COMM SWAG index]  [Back to Main SWAG index]  [Original]