home *** CD-ROM | disk | FTP | other *** search
- (*************************************************************************)
- (* RS 232 I/O Bufferung durch Interrupts 10/03/1987 *)
- (* Autor : K. Feller *)
- (* MS-DOS und Turbo-Pascal *)
- (*************************************************************************)
-
- CONST RS_Port = $03f8; (* Datenport des RS 232 Bausteins *)
- RS_Latch = $03f9; (* Interrupt & Baud Register *)
- RS_IntReg = $03fa; (* Interrupt Type Register *)
- RS_LinCtrl = $03fb; (* Wortlaenge und Parity Register *)
- RS_ModCmd = $03fc; (* RTS/DTR Register *)
- RS_StatReg = $03fd; (* Fehler Register *)
- RS_ModStat = $03fe; (* Modem Status Register *)
- RS_IntAkt = $100; (* Testbyte, ob Spooler vorhanden *)
- RS_InPtr = $103; (* Pointer auf n. freien Platz *)
- RS_BufOfs = $105; (* Start des Ringpuffers *)
- RS_ChCnt = $107; (* Anzahl der abzuholenden Char's *)
- RS_OutPtr = $109; (* Pointer auf naechstes Zeichen *)
- RS_BufRange = $10b; (* Groesse des Ringpuffers *)
- RS_FulFlg = $10d; (* Ueberlauf Flag des Ringpuffers *)
- RS_txready = $20; (* Maskenbit fuer Sendebereit *)
- RS_IntCtrl = $21; (* Interrupt Controler Adresse *)
- RS_IntFree = $20; (* Interrupt Controler freigabe *)
-
- VAR
- RS_Char : CHAR; (* RS-Zeichen-Puffer *)
- RS_NextPtr : INTEGER; (* Zeigerpuffer auf Zeichen *)
- RS_CodSeg : INTEGER; (* Codesegment des Spoolerprogr. *)
- RS_BufAdr : INTEGER; (* Ringpuffer Offset *)
- RS_BufSize : INTEGER; (* Ringpuffer Groesse *)
- RS_BufCnt : INTEGER; (* Zeichen im Ringpuffer, wird
- nur bei Pufferzugriff aktual.! *)
- RS_BufFull : BOOLEAN; (* Flag Ringpuffer-Ueberlauf
- = 0, wenn eingetreten! *)
-
- ende : BOOLEAN; (* Ende Flag des Hauptprogramms *)
- ch : CHAR; (* Tastatur-Zeichen-Puffer *)
-
- (* --------------------------------------------------------------------- *)
- (* Hole Adresse RS-232-C-Spooler Code, Puffer und dessen Groesse: *)
- (* Ist der Spooler aktiv, ist 'RS_FindSpooler' TRUE! Diese Funktion muss *)
- (* zu Beginn des Pascal-Programms einmal aufgerufen werden. *)
-
- FUNCTION RS_FindSpooler: BOOLEAN;
- TYPE register = RECORD (* Registersatz des Intel 8088/8086 *)
- ax,bx,cx,dx,bp,si,di,ds,es,flags: INTEGER;
- END;
- VAR msdos_register : register; (* MS-DOS Uebergaberegister Satz *)
- BEGIN
- WITH msdos_register DO
- BEGIN
- ax := $350c; msdos(msdos_register); RS_CodSeg := es;
- END;
- RS_BufAdr := memw[RS_CodSeg:RS_BufOfs];
- RS_BufSize := memw[RS_CodSeg:RS_BufRange];
- RS_BufCnt := memw[RS_CodSeg:RS_ChCnt];
- RS_BufFull := (mem[RS_CodSeg:RS_FulFlg] = 0);
- RS_FindSpooler := (mem[RS_CodSeg:RS_IntAkt] = $e9);
- END;
-
- (* --------------------------------------------------------------------- *)
- (* Fehler-Register lesen: *)
-
- FUNCTION RS_Status (mask: BYTE): BOOLEAN;
- BEGIN
- IF (Port[RS_StatReg] AND mask) = mask THEN RS_Status := TRUE
- ELSE RS_Status := FALSE;
- END;
-
- (* --------------------------------------------------------------------- *)
- (* Uebertragungsparameter setzen: *)
-
- PROCEDURE RS_SetLine (rate: INTEGER; parity: CHAR; stopbit, bits: BYTE);
- VAR temp : INTEGER;
- BEGIN
- CASE rate OF
- 50 : temp := $900; 75 : temp := $600;
- 110 : temp := $417; 134 : temp := $359;
- 150 : temp := $300; 300 : temp := $180;
- 600 : temp := $0c0; 1200 : temp := $060;
- 1800 : temp := $040; 2000 : temp := $03a;
- 2400 : temp := $030; 3600 : temp := $020;
- 4800 : temp := $018; 7200 : temp := $010;
- 9600 : temp := $00c;
- ELSE temp := $00c;
- END;
- Port[RS_LinCtrl] := $80;
- Port[RS_Port] := Lo(temp); Port[RS_Latch] := Hi(temp);
- CASE parity OF
- 'E','e' : temp := $18; 'O','o' : temp := 8;
- 'N','n' : temp := 0;
- ELSE temp := $18;
- END;
- CASE stopbit OF
- 1 : ; 2 : temp := temp+4;
- ELSE temp := temp+4;
- END;
- CASE bits OF
- 5 : ; 6 : temp := temp+1;
- 7 : temp := temp+2; 8 : temp := temp+3;
- ELSE temp := temp+3;
- END;
- Port[RS_LinCtrl] := temp;
- END;
-
- (* --------------------------------------------------------------------- *)
- (* Initialisiere RS-232-Interrupt und Ringpuffer-Parameter: *)
-
- PROCEDURE RS_Init (baudrate: INTEGER; parity: CHAR;
- stopbits, datenbits: BYTE);
- VAR dummy : INTEGER;
- BEGIN
- RS_SetLine(baudrate, parity, stopbits, datenbits);
- Port[RS_LinCtrl] := (Port[RS_LinCtrl] AND $7f);
- Port[RS_Latch] := 1; (* Enable Empfaenger Interrupt *)
- Port[RS_ModCmd] := $0b; (* Schalte Handshake Signale *)
- dummy := Port[RS_IntReg]; (* Dummy-Lesen zum bereinigen *)
- dummy := Port[RS_StatReg]; (* des Portbausteins. *)
- dummy := Port[RS_ModStat];
- dummy := Port[RS_Port];
- dummy := Port[RS_Port];
- Port[RS_IntCtrl] := (Port[RS_IntCtrl] AND $ef); (* Enable Interrupt *)
- END;
-
- (* --------------------------------------------------------------------- *)
- (* Spoolerpuffer 'gewaltsam' leeren: *)
-
- PROCEDURE RS_EmptyBuffer;
- BEGIN
- memw[RS_CodSeg:RS_InPtr] := 0;
- memw[RS_CodSeg:RS_ChCnt] := 0; RS_BufCnt := 0;
- memw[RS_CodSeg:RS_OutPtr] := 0;
- mem[RS_CodSeg:RS_FulFlg] := $FF; RS_BufFull := FALSE;
- END;
-
- (* --------------------------------------------------------------------- *)
- (* Hole ein Zeichen aus Ringpuffer, wenn vorhanden: *)
- (* Wenn vorhanden: RS_Char := Zeichen und RS_Getch := TRUE *)
-
- FUNCTION RS_Getch: BOOLEAN;
- BEGIN
- IF memw[RS_CodSeg:RS_ChCnt] = 0 THEN RS_Getch := FALSE
- ELSE
- BEGIN
- RS_Getch := TRUE;
- RS_NextPtr := memw[RS_CodSeg:RS_OutPtr];
- RS_Char := Chr(Mem[RS_CodSeg:RS_BufAdr+RS_NextPtr]);
- INLINE ($06/ (* push es *)
- $53/ (* push bx *)
- $a1/RS_CodSeg/ (* mov ax,[RS_CodSeg] *)
- $8e/$c0/ (* mov es,ax *)
- $bb/RS_ChCnt/ (* mov bx,RS_ChCnt *)
- $26/$FF/$0f/ (* dec word ptr es:[bx] *)
- $5b/ (* pop bx *)
- $07); (* pop es *)
- RS_NextPtr := Succ(RS_NextPtr);
- IF RS_NextPtr > RS_BufSize THEN RS_NextPtr := 0;
- memw[RS_CodSeg:RS_OutPtr] := RS_NextPtr;
- RS_BufFull := (memw[RS_CodSeg:RS_FulFlg] = 0);
- RS_BufCnt := memw[RS_CodSeg:RS_ChCnt];
- END;
- END;
-
- (* --------------------------------------------------------------------- *)
- (* Schreibe ein Zeichen an RS-232 mit Status und ohne warten: *)
-
- FUNCTION RS_Putch (ch: CHAR): BOOLEAN;
- BEGIN
- IF NOT (RS_Status(RS_txready)) THEN RS_Putch := FALSE
- ELSE
- BEGIN
- RS_Putch := TRUE; Port[RS_Port] := Ord(ch);
- END;
- END;
-
- (* --------------------------------------------------------------------- *)
-
- PROCEDURE Term_Stat;
- BEGIN
- WriteLn;
- WriteLn(' Puffergroesse: ', RS_BufSize:6,
- ' Zeichen im Puffer: ', RS_BufCnt:6,
- ' Pufferueberlauf: ', RS_BufFull);
- WriteLn;
- END;
-
- BEGIN
- ClrScr;
- ende := FALSE;
- IF RS_FindSpooler THEN (* Adresse und Groesse des Spoolers ermitteln *)
- BEGIN (* Spooler aktiv, weiter machen... *)
- (* Initial. der Schnittstelle: 300 Baud, keine Paritaet, 1 Stopbit *)
- RS_Init(300,'N',1,8); (* 8 Datenbits *)
- Term_Stat;
- REPEAT (* und einem ganz kleinen Terminal *)
- IF RS_Getch THEN Write (RS_Char); (* Zeichen wurde empfangen! *)
- IF KeyPressed THEN (* Taste wurde gedrueckt... *)
- BEGIN
- Read(Kbd, ch); (* Zeichen der Taste ermitteln *)
- IF ch = Chr(27) THEN
- ende := TRUE (* Ende bei ESC-Taste *)
- ELSE IF ch = Chr(1) THEN
- BEGIN
- RS_EmptyBuffer; (* Control-A setzt Puffer zurueck *)
- Term_Stat;
- END
- ELSE (* sonst Zeichen senden... *)
- BEGIN
- REPEAT UNTIL RS_Putch(ch);
- END;
- END;
- UNTIL ende;
- END
- ELSE
- BEGIN
- WriteLn; WriteLn;
- WriteLn('RS-232-Spooler ist nicht aktiv !!!');
- END;
- END.