home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
pascal
/
library
/
dos
/
multtsk
/
cpmult
/
source
/
v24.pas
< prev
Wrap
Pascal/Delphi Source File
|
1990-04-07
|
12KB
|
259 lines
(*////////////////////////////////////////////////////////////////////////////
/// ///
/// T U R B O - P A S C A L V24-Interrupt-Handler V2.00 ///
/// (c) Copyright Juni 1988 by C.Philipps ///
/// ///
/// (Turbo Pascal V4.0 or higher required) ///
/// ///
//////////////////////////////////////////////////////////////////////////////
/// ///
/// Low-Level Interrupt-Routinen für die Behandlung der ///
/// seriellen Schnittstellen Com1 und Com2 mit Geschwindig- ///
/// keiten von bis zu 115200 bps. ///
/// Teile der Grundidee sind dem Modul ASYNC von Mike Halli- ///
/// day entnommen, das im Shuttle unter dem Namen ASYNC.ARC ///
/// verfügbar ist. ///
/// ///
/// Dieses Modul stelle ich hiermit allen interessierten Turbo- ///
/// Pascal-Anwendern zur freien Verfügung. ///
/// Es darf ohne Bedenken an andere Benutzer weitergegeben ///
/// werden, vorausgesetzt, dies geschieht unentgeldlich und in sei- ///
/// ner ursprünglichen, unveränderten Form. ///
/// Es steht Ihnen frei, die Routinen in Ihre eigenen Programme zu ///
/// integrieren oder sie zu erweitern/verändern. Ich wäre Ihnen je- ///
/// doch dankbar, wenn Sie die daraus entstehende neue Version wie- ///
/// derum der Allgemeinheit zur Verfügung stellten. ///
/// ///
/// Christian Philipps ///
/// Düsseldorfer Str. 316 ///
/// 4130 Moers 1 ///
/// ///
/// Stand: 07/89 ///
/// ///
////////////////////////////////////////////////////////////////////////////*)
{$R-,S-,I-,D-,F-,V-,B-,N-,L- }
UNIT V24;
INTERFACE
USES DOS;
TYPE ComType = (Com1,Com2,Com3,Com4,Com5,Com6);
BaudType = (b110,b150,b300,b600,b1200,b2400,b4800,b9600,b19200,
b38400,b57600,b115200);
ParityType = (Space,Odd,Mark,Even,None);
DataBitsType = (d5,d6,d7,d8);
StopBitsType = (s1,s2);
CONST V24Timeout : BOOLEAN = FALSE; {SendByte-Timeout}
IntMasks : ARRAY[Com1..Com6] OF WORD = ($EF,$F7,$EF,$F7,$EF,$F7);
IntVect : ARRAY[Com1..Com6] OF BYTE = ($0C,$0B,$0C,$0B,$0C,$0B);
VAR V24TP : WORD; {Buffer Tail-Pointer
Im Interface-Teil, da zur Ereignis-
steuerung im Multi-Tasking benötigt.}
ComBaseAdr : ARRAY[Com1..Com6] OF WORD;
FUNCTION V24DataAvail:BOOLEAN;
FUNCTION V24GetByte:BYTE;
PROCEDURE InitCom(ComPort:ComType;Baudrate:BaudType;Parity:ParityType;
Bits:DataBitsType;Stop:StopBitsType);
PROCEDURE DisableCom;
PROCEDURE SendByte(Data:BYTE);
{=============================================================================}
IMPLEMENTATION
CONST Regs : Registers =
(AX:0;BX:0;CX:0;DX:0;BP:0;SI:0;DI:0;DS:0;ES:0;FLAGS:0);
RBR = $00; {xF8 Receive Buffer Register }
THR = $00; {xF8 Transmitter Holding Register }
IER = $01; {xF9 Interrupt Enable Register }
IIR = $02; {xFA Interrupt Identification Register }
LCR = $03; {xFB Line Control Register }
MCR = $04; {xFC Modem Control Register }
LSR = $05; {xFD Line Status Register }
MSR = $06; {xFE Modem Status Register }
{--- if LCR Bit 7 = 1 --- }
DLL = $00; {xF8 Divisor Latch Low Byte }
DLH = $01; {xF9 Divisor Latch Hi Byte }
CMD8259 = $20; {Interrupt Controller Command Register }
IMR8259 = $21; {Interrupt Controller Mask Register }
{Should be evaluated by any higher-level
send-routine}
LoopLimit = 1000; {When does a timeout-error occur }
V24BuffSize= 2048; { Ringpuffer 2 KB }
VAR BiosComBaseAdr : ARRAY[Com1..Com2] OF WORD ABSOLUTE $0040:$0000;
ActivePort : ComType;
{ The Com-Port base adresses are taken from the BIOS data area }
ComBase : WORD; {Hardware Com-Port Base Adress }
OldV24 : Pointer;
V24HP : WORD; {Buffer Head-Pointer }
V24BuffEnd : WORD; {Buffer End-Adress }
V24Buff : ARRAY[0..V24BuffSize] OF BYTE;
OExitHandler : Pointer; {Save-Area für Zeiger auf Org.-Exit-Proc}
{============================ lokale Routinen ================================}
PROCEDURE V24Int; external;
{$L v24.obj}
{-----------------------------------------------------------------------------}
PROCEDURE ClearPendingInterrupts;
VAR N : BYTE;
BEGIN {ClearPendingInterrupts}
WHILE (PORT[ComBase+IIR] AND 1) = 0 DO {While Interrupts are pending}
BEGIN
N := PORT[ComBase+LSR]; {Read Line Status}
N := PORT[ComBase+MSR]; {Read Modem Status}
N := PORT[ComBase+RBR]; {Read Receive Buffer Register}
PORT[CMD8259] := $20; {End of Interrupt}
END;
END; {ClearPendingInterrupts}
{======================== extern verfügbare Routinen =========================}
FUNCTION V24DataAvail:BOOLEAN;
{ Diese Funktion überprüft, ob Daten im Ringpuffer vorliegen }
BEGIN {V24DataAvail}
V24DataAvail := (V24HP <> V24TP);
END; {V24DataAvail}
{-----------------------------------------------------------------------------}
FUNCTION V24GetByte:BYTE;
{ Diese Funktion holt ein Byte aus dem Ringpuffer. Es wird vorausgesetzt,
das über V24DataAvail zuvor sichergestellt wurde, daß auch ein Zeichen
zum Auslesen bereitsteht!!!!!
Da die Interruptroutine auf den Head-Pointer nur lesend zugreift,
brauchen beim Update des Pointers die Interrupts nicht gesperrt zu
werden! }
BEGIN {V24GetByte}
V24GetByte := Mem[DSeg:V24HP];
Inc(V24HP);
IF V24HP > V24BuffEnd
THEN V24HP := Ofs(V24Buff);
END; {V24GetByte}
{-----------------------------------------------------------------------------}
PROCEDURE SendByte(Data:BYTE);
VAR Count:BYTE;
BEGIN {SendByte}
Count := 0;
V24Timeout := FALSE;
IF ComBase > 0
THEN BEGIN
REPEAT
Count := SUCC(Count);
UNTIL ((PORT[ComBase+LSR] AND $20) <> 0) OR (Count > LoopLimit);
IF Count > LoopLimit
THEN V24Timeout := TRUE
ELSE PORT[ComBase+THR] := Data;
END;
END; {SendByte}
{-----------------------------------------------------------------------------}
PROCEDURE InitCom(ComPort:ComType;Baudrate:BaudType;Parity:ParityType;
Bits:DataBitsType;Stop:StopBitsType);
CONST BaudConst : ARRAY[b110..b115200] OF WORD =
($417,$300,$180,$C0,$60,$30,$18,$0C,$06,$03,$02,$01);
ParityConst : ARRAY[Space..None] OF BYTE =
($38,$08,$28,$18,$00);
BitsConst : ARRAY[d5..d8] OF BYTE =
($00,$01,$02,$03);
StopConst : ARRAY[s1..s2] OF BYTE =
($00,$04);
BEGIN {InitCom}
V24HP := Ofs(V24Buff);
V24TP := V24HP;
V24BuffEnd := V24HP+V24BuffSize;
FillChar(V24Buff,Succ(V24BuffSize),#0);
V24Timeout := FALSE; {Reset Timeout-Marker}
ComBase := ComBaseAdr[ComPort]; {Get Com-Port base adress}
ActivePort := ComPort; {Keep Active-Port for EOI}
ClearPendingInterrupts;
GetIntVec(IntVect[ComPort],OldV24);
SetIntVec(IntVect[ComPort],@V24Int);
{Install interrupt routine}
INLINE($FA); {CLI}
PORT[ComBase+LCR] := $80; {Adress Divisor Latch}
PORT[ComBase+DLH] := Hi(BaudConst[Baudrate]); {Set Baud rate}
PORT[COMBase+DLL] := Lo(BaudConst[Baudrate]);
PORT[ComBase+LCR] := ($00 OR ParityConst[Parity] {Setup Parity}
OR BitsConst[Bits] {Setup number of databits}
OR StopConst[Stop]); {Setup number of stopbits}
PORT[ComBase+MCR] := $0B; {Set RTS,DTR,OUT2}
(*
PORT[ComBase+MCR] := $1B; {Set RTS,DTR,OUT2,Loop}
*)
PORT[ComBase+IER] := $01; {Enable Data-Available Interrupts}
PORT[IMR8259] := PORT[IMR8259] AND IntMasks[ComPort]; {Enable V24-Interrups}
INLINE($FB); {STI}
END; {InitCom}
{-----------------------------------------------------------------------------}
PROCEDURE DisableCom;
BEGIN {DisableCom}
IF ComBase = 0
THEN Exit;
INLINE($FA); {CLI}
PORT[ComBase+MCR] := 00; {Disable Interrupts, Reset MCR}
PORT[IMR8259] := PORT[IMR8259] OR $18; {Disable Interrupt Level 3 and 4}
PORT[ComBase+IER] := 0; {Disable 8250-Interrupts}
ClearPendingInterrupts; {Clean up}
ComBase := 0; {Reset Combase}
SetIntVec(IntVect[ActivePort],OldV24); {Reset old IV}
INLINE($FB); {STI}
END; {DisableCom}
{-----------------------------------------------------------------------------}
{$F+}
PROCEDURE V24ExitProc;
BEGIN {V24ExitProc}
DisableCom;
ExitProc := OExitHandler; { alten Exit-Handler reaktivieren }
END; {V24ExitProc}
{$F-}
{-----------------------------------------------------------------------------}
BEGIN {Initialisierung}
{Grund-Init, damit irrtümliche Aufrufe von V24DataAvail nicht zu
endlosen Ausgaben von Speicherschrott führen!}
Move(BiosComBaseAdr,ComBaseAdr[Com1],SizeOf(BiosComBaseAdr));
Move(BiosComBaseAdr,ComBaseAdr[Com3],SizeOf(BiosComBaseAdr));
Move(BiosComBaseAdr,ComBaseAdr[Com5],SizeOf(BiosComBaseAdr));
ComBase := 0;
V24HP := Ofs(V24Buff);
V24TP := V24HP;
V24BuffEnd := V24HP+V24BuffSize;
OExitHandler := ExitProc; {eigene Exit-Prozedur aktivieren}
ExitProc := @V24ExitProc;
END. {Initialisierung}
(*////////////////////////////////////////////////////////////////////////////
/// E N D O F M O D U L E ///
////////////////////////////////////////////////////////////////////////////*)