[Back to COMM SWAG index] [Back to Main SWAG index] [Original]
{$I-} { I/O hecking OFF }
{$R-} { Range checking OFF }
{$S-} { Stack checking OFF }
{$V-} { Var-str checking OFF}
{$B+} {Boolean complete evaluation on}
{$N-} {No numeric coprocessor}
Unit RS232INT;
Interface
Uses
Crt,
Dos;
{ global declarations for Async}
type
astr = String[160]; { generic string type for parameters }
const
buffer_max = 5120;
var
Async_OriginalVector : pointer;
buffer : Array[0..buffer_max] of char;
Async_Open_Flag : Boolean; { true if Open but no Close }
Async_Port : Integer; { current Open port number (1 or 2) }
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 : Integer;
Async_MaxBufferUsed : Integer;
{ buffer is empty if Head = Tail }
Buffer_head : Integer; { Locn in buffer to put next char }
Buffer_tail : Integer; { Locn in buffer to get next char }
Buffer_newtail : Integer;
{ End of Async declarations }
procedure async_isr; INTERRUPT;
procedure set_baud(r:integer);
function charin:char;
procedure charout(c:char);
function cdet:boolean;
procedure Async_Init;
procedure Async_Close;
Procedure Async_Open(ComPort : Integer;
BaudRate : Integer;
Parity : Char;
WordSize : Integer;
StopBits : Integer);
Implementation
const
UART_THR = $00;
UART_RBR = $00;
UART_IER = $01;
UART_IIR = $02;
UART_LCR = $03;
UART_MCR = $04;
UART_LSR = $05;
UART_MSR = $06;
I8088_IMR = $21; { port address of the Interrupt Mask Register }
var
Async_BIOS_Port_Table : Array[1..4] of Integer absolute $40:0;
const
Async_Num_Bauds = 8;
Async_Baud_Table : array [1..Async_Num_Bauds] of record
Baud, Bits : integer
end
= ((Baud:110; Bits:$00),
(Baud:150; Bits:$20),
(Baud:300; Bits:$40),
(Baud:600; Bits:$60),
(Baud:1200; Bits:$80),
(Baud:2400; Bits:$A0),
(Baud:4800; Bits:$C0),
(Baud:9600; Bits:$E0));
PROCEDURE DisableInterrupts; inline($FA {cli} ); {MACROS}
PROCEDURE EnableInterrupts; inline($FB {sti} );
procedure BIOS_RS232_Init(ComPort, ComParm : Integer);
var
Regs : registers;
begin
with Regs do
begin
ax := ComParm and $00FF; { AH=0; AL=ComParm }
dx := ComPort;
Intr($14, Regs)
end
end;
procedure Async_Isr; {INTERRUPT;}
begin
Inline(
$FB/ { STI }
{ get the incomming character }
{ buffer[Buffer_head] := Chr(Port[UART_RBR + base]); }
$8B/$16/base/ { MOV DX,base }
$EC/ { IN AL,DX }
$8B/$1E/Buffer_head/ { MOV BX,Buffer_head }
$88/$87/buffer/ { MOV buffer[BX],AL }
{ Async_Buffer_NewHead := Buffer_head + 1; }
$43/ { INC BX }
{ if Async_Buffer_NewHead > buffer_max then
Async_Buffer_NewHead := 0; }
$81/$FB/buffer_max/ { CMP BX,buffer_max }
$7E/$02/ { JLE L001 }
$33/$DB/ { XOR BX,BX }
{ if Async_Buffer_NewHead = Buffer_tail then
Async_Buffer_Overflow := TRUE
else }
{L001:}
$3B/$1E/Buffer_tail/ { CMP BX,Buffer_tail }
$75/$08/ { JNE L002 }
$C6/$06/Async_Buffer_Overflow/$01/ { MOV Async_Buffer_Overflow,1 }
$90/ { NOP generated by assembler for some reason }
$EB/$16/ { JMP SHORT L003 }
{ begin
Buffer_head := Async_Buffer_NewHead;
Async_Buffer_Used := Async_Buffer_Used + 1;
if Async_Buffer_Used > Async_MaxBufferUsed then
Async_MaxBufferUsed := Async_Buffer_Used
end; }
{L002:}
$89/$1E/Buffer_head/ { MOV Buffer_head,BX }
$FF/$06/Async_Buffer_Used/ { INC Async_Buffer_Used }
$8B/$1E/Async_Buffer_Used/ { MOV BX,Async_Buffer_Used }
$3B/$1E/Async_MaxBufferUsed/ { CMP BX,Async_MaxBufferUsed }
$7E/$04/ { JLE L003 }
$89/$1E/Async_MaxBufferUsed/ { MOV Async_MaxBufferUsed,BX }
{L003:}
{ disable interrupts }
$FA/ { CLI }
{ Port[$20] := $20; } { use non-specific EOI }
$B0/$20/ { MOV AL,20h }
$E6/$20 { OUT 20h,AL }
)
end; { Async_Isr }
procedure Async_Init;
begin
Async_Open_Flag := FALSE;
Async_Buffer_Overflow := FALSE;
Async_Buffer_Used := 0;
Async_MaxBufferUsed := 0;
end; { Async_Init }
procedure Async_Close;
var
i, m : Integer;
begin
if Async_Open_Flag then
begin
{ disable the IRQ on the 8259 }
DisableInterrupts;
i := Port[I8088_IMR]; { get the interrupt mask register }
m := 1 shl Async_Irq; { set mask to turn off interrupt }
Port[I8088_IMR] := i or m;
{ disable the 8250 data ready interrupt }
Port[UART_IER + base] := 0;
{ disable OUT2 on the 8250 }
Port[UART_MCR + base] := 0;
EnableInterrupts;
SetIntVec(Async_Irq + 8,Async_OriginalVector);
{ re-initialize our data areas so we know the port is closed }
Async_Open_Flag := FALSE
end
end; { Async_Close }
Procedure Async_Open(ComPort : Integer;
BaudRate : Integer;
Parity : Char;
WordSize : Integer;
StopBits : Integer);
{ open a communications port }
var
ComParm : Integer;
i, m : Integer;
begin
if Async_Open_Flag then Async_Close;
if (ComPort = 4) and (Async_BIOS_Port_Table[4] <> 0) then
Async_Port := 4;
if (ComPort = 3) and (Async_BIOS_Port_Table[3] <> 0) then
Async_Port := 3;
if (ComPort = 2) and (Async_BIOS_Port_Table[2] <> 0) then
Async_Port := 2;
if (ComPort = 1) and (Async_BIOS_Port_Table[1] <> 0) then
Async_Port := 1; { default to COM1 }
base := Async_BIOS_Port_Table[Async_Port];
Async_Irq := Hi(base) + 1;
if (Port[UART_IIR + base] and $00F8)=0
then
begin
Buffer_head := 0;
Buffer_tail := 0;
Async_Buffer_Overflow := FALSE;
{ Build the ComParm for RS232_Init }
{ See Technical Reference Manual for description }
ComParm := $0000;
{ Set up the bits for the baud rate }
i := 0;
repeat
i := i + 1
until (Async_Baud_Table[i].Baud = BaudRate) or (i = Async_Num_Bauds);
ComParm := ComParm or Async_Baud_Table[i].Bits;
if Parity in ['E', 'e'] then ComParm := ComParm or $0018
else if Parity in ['O', 'o'] then ComParm := ComParm or $0008
else ComParm := ComParm or $0000; { default to No parity }
if WordSize = 7 then ComParm := ComParm or $0002
else ComParm := ComParm or $0003; { default to 8 data bits }
if StopBits = 2 then ComParm := ComParm or $0004
else ComParm := ComParm or $0000; { default to 1 stop bit }
{ use the BIOS COM port initialization routine to save typing the code }
BIOS_RS232_Init(Async_Port - 1, ComParm);
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[UART_LCR + base] := Port[UART_LCR + base] and $7F;
{ read the Line Status Register to reset any errors it indicates }
i := Port[UART_LSR + base];
{ read the Receiver Buffer Register in case it contains a character }
i := Port[UART_RBR + base];
{ enable the irq on the 8259 controller }
i := Port[I8088_IMR]; { get the interrupt mask register }
m := (1 shl Async_Irq) xor $00FF;
Port[I8088_IMR] := i and m;
{ enable the data ready interrupt on the 8250 }
Port[UART_IER + base] := $01; { enable data ready interrupt }
{ enable OUT2 on 8250 }
i := Port[UART_MCR + base];
Port[UART_MCR + base] := i or $08;
EnableInterrupts;
Async_Open_Flag := TRUE;
{Async_Open := TRUE}
end
end; { Async_Open }
procedure set_baud(r:integer);
var rl:real; a:byte;
begin
if (r>=300) and (r<=9600) then begin
rl:=115200.0/r;
r:=trunc(rl);
a:=port[3+base] or 128;
port[base+3]:=a;
port[base]:=lo(r);
port[1+base]:=hi(r);
port[3+base]:=a and 127;
end;
end;
function charin:char;
var t:char;
begin
if buffer_Head = buffer_Tail Then
t:=#0
else begin
disableinterrupts;
t:=buffer[buffer_Tail];
buffer_Tail:=(buffer_Tail+1) mod (buffer_max+1);
enableinterrupts;
end;
charin := t;
end;
procedure charout(c:char);
begin
while (port[base+5] and 32)=0 do;
port[base]:=ord(c);
end;
function cdet:boolean;
begin
cdet:=(port[base+6] and 128)<>0;
end;
end.
[Back to COMM SWAG index] [Back to Main SWAG index] [Original]