[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]