{Here's a unit for sending and receiving async commands } { ======================= SERIAL COMMUNICATIONS ============================ } UNIT Async; {$D-,V-,B-,S-,R-} INTERFACE USES Dos, Crt; TYPE BAUD = (B110,B150,B300,B600,B1200,B2400,B4800,B9600); PARITY = (PNONE, PODD, PNOTHING, PEVEN); VAR AsyncInstalled : BOOLEAN; AsyncActive : BOOLEAN; PROCEDURE InitAsync(Com :BYTE; Speed :BAUD; Par :PARITY; Stop :BYTE; Dbits :BYTE); PROCEDURE TermAsync; FUNCTION CheckAsync :WORD; PROCEDURE HangUp; PROCEDURE Send(Buffer :STRING); PROCEDURE Receive(VAR Buffer :STRING); IMPLEMENTATION CONST THR = 0; RBR = 0; IER = 1; IIR = 2; LCR = 3; MCR = 4; LSR = 5; MSR = 6; BUFFSIZE = 255; TIMOUT = 60000; EOI : BYTE = $20; IRQ4low : BYTE = $EF; IRQ4high : BYTE = $10; IRQ3low : BYTE = $F7; IRQ3high : BYTE = $08; ErrorMask : BYTE = $0E; DSRready : BYTE = $20; OUT2 : BYTE = $08; DTR : BYTE = $01; RTS : BYTE = $02; VAR Regs : REGISTERS; OldVector : POINTER; AsyncStatus : WORD; IntType : BYTE; AsyncDisable : BYTE; AsyncEnable : BYTE; AsyncBuff : ARRAY [0..BUFFSIZE] OF BYTE; Front : INTEGER; Rear : INTEGER; ComPort : BYTE; ComBase : WORD; {//////////////////////////////////////////////////////////////////////////} PROCEDURE ZeroDlab; { -- zero divisor latch access bit allowing access to THR, RBR and IER } BEGIN PORT[ComBase+LCR]:= PORT[ComBase+LCR] AND $7F; END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE SetDTR; { -- enable interrupts and set DTR } BEGIN PORT[ComBase+MCR]:= OUT2 + DTR + RTS; DELAY(1000) END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE ReadPorts; { -- read UART values } VAR Temp : BYTE; BEGIN Temp:= PORT[ComBase]; Temp:= PORT[ComBase+IIR]; Temp:= PORT[ComBase+LSR]; Temp:= PORT[ComBase+MSR]; END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE HangUp; { -- hang up phone } BEGIN ReadPorts; PORT[ComBase+MCR]:= 0; DELAY(1000); END; {//////////////////////////////////////////////////////////////////////////} FUNCTION CheckAsync; { -- return status MB = Line Status, LB = Modem Status } VAR LSReg : WORD; BEGIN LSReg:= PORT[ComBase+LSR]; CheckAsync:= (LSReg SHL 8) OR PORT[ComBase+MSR]; END; {//////////////////////////////////////////////////////////////////////////} {$F+} PROCEDURE AsyncISR; INTERRUPT; { -- serial port interrupt routine } BEGIN PORT[$21]:= PORT[$21] AND AsyncDisable; INLINE($FB); { enable interrupts } IntType:= PORT[ComBase+IIR] AND 6; IF IntType = 4 THEN BEGIN ZeroDlab; AsyncBuff[Rear]:= PORT[ComBase+RBR]; Rear:= SUCC(Rear) MOD BUFFSIZE END; AsyncStatus:= (PORT[ComBase+LSR] SHL 8) + PORT[ComBase+MSR]; INLINE($FA); { disable interrupts } PORT[$20]:= EOI; PORT[$21]:= PORT[$21] AND AsyncEnable END; {$F-} {//////////////////////////////////////////////////////////////////////////} PROCEDURE InstallAsync; { -- replaces interrupt vector by user routine } BEGIN IF NOT(AsyncInstalled) THEN BEGIN GetIntVec($0C-ComPort,OldVector); SetIntVec($0C-ComPort,@AsyncISR); AsyncInstalled:=TRUE; END; END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE DeinstallAsync; { -- restores interrupt vector } BEGIN IF AsyncInstalled THEN BEGIN SetIntVec($0C-ComPort,OldVector); AsyncInstalled:=FALSE; END; END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE InitAsync(Com : BYTE; Speed : BAUD; Par : PARITY; Stop : BYTE; Dbits : BYTE); { -- initialize serial port communications } BEGIN WITH Regs DO BEGIN IF NOT(AsyncActive) THEN BEGIN ComPort := Com-1; MEMW[0:$400] := $3F8; { to prevent a BIOS bug } MEMW[0:$402] := $2F8; { to prevent a BIOS bug } IF ComPort = 0 THEN BEGIN ComBase := $3F8; AsyncEnable := IRQ4low; AsyncDisable:= IRQ4high; END ELSE BEGIN ComBase := $2F8; AsyncEnable := IRQ3low; AsyncDisable:= IRQ3high END; Front := 0; Rear := 0; AsyncStatus := 0; InstallAsync; DX :=ComPort; AX :=ORD(Speed)*32 + ORD(Par)*8 + (Stop-1)*4 + Dbits-5; INTR($14,Regs); ReadPorts; ZeroDlab; PORT[ComBase+IER]:= $05; INLINE($FA); { disable interrupts } PORT[$21] :=PORT[$21] AND AsyncEnable; INLINE($FB); { enable interrupts } SetDTR; AsyncActive := TRUE; END ELSE BEGIN HangUp; SetDTR; END; END; END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE Receive; { -- get characters from circular buffer } VAR Ch : CHAR; NbrChrs : INTEGER; Count : LONGINT; BEGIN Buffer := ''; Count := TIMOUT; NbrChrs := 0; WHILE Count>0 DO BEGIN DEC(Count); IF Front <> Rear THEN BEGIN REPEAT Ch := CHAR(AsyncBuff[Front]); Front := SUCC(Front) MOD BUFFSIZE; IF Ch IN [#0..#31] THEN Ch:= #32; Buffer := Buffer + Ch; INC(NbrChrs); UNTIL (Front = Rear) OR (NbrChrs = BUFFSIZE); Count:= TIMOUT; END; END; END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE Send; VAR Ptr : INTEGER; TH : BYTE; CH : CHAR; BEGIN IF LENGTH(Buffer)>0 THEN BEGIN SetDTR; FOR Ptr:=1 TO LENGTH(Buffer) DO BEGIN REPEAT TH:= PORT[ComBase+LSR] AND DSRready UNTIL TH<>0; CH:= Buffer[Ptr]; IF (CH = '%') THEN BEGIN DELAY(1000); EXIT; END; IF (CH = '|') THEN CH:= #13; IF (CH = '~') THEN DELAY(2000) ELSE PORT[ComBase+THR]:= BYTE(CH); END; DELAY(1000); END; END; {//////////////////////////////////////////////////////////////////////////} PROCEDURE TermAsync; { -- terminate communications } BEGIN IF AsyncActive THEN BEGIN HangUp; INLINE($FA); { disable interrupts } PORT[$21] := PORT[$21] OR (IRQ4high + IRQ3high); INLINE($FB); { enable interrupts } ZeroDlab; PORT[ComBase+IER]:= 0; DELAY(1000); DeinstallAsync; AsyncActive := FALSE; END; END; {//////////////////////////////////////////////////////////////////////////} BEGIN AsyncInstalled := FALSE; AsyncActive := FALSE; END. It's a old unit from tp4 but it works well for me. I think it will not support the fifo buffers and the specials of the 16550 uart because they wern't available at that time but maybe somebody can modify it Greetings from: Niko van Hagen Monday, 25 March 1996, 10:19. The Haghe, Holland Fido : 2:281/909.11 Internet : nvhagen@worldonline.nl PGP KEYID : 6CF49689