home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1987 / 07 / rs232 / rsspldem.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1987-04-29  |  9.4 KB  |  220 lines

  1. (*************************************************************************)
  2. (*     RS 232 I/O Bufferung durch Interrupts              10/03/1987     *)
  3. (*                        Autor : K. Feller                              *)
  4. (*                     MS-DOS und Turbo-Pascal                           *)
  5. (*************************************************************************)
  6.  
  7. CONST RS_Port     = $03f8;             (* Datenport des RS 232 Bausteins *)
  8.       RS_Latch    = $03f9;             (* Interrupt & Baud Register      *)
  9.       RS_IntReg   = $03fa;             (* Interrupt Type  Register       *)
  10.       RS_LinCtrl  = $03fb;             (* Wortlaenge und Parity Register *)
  11.       RS_ModCmd   = $03fc;             (* RTS/DTR Register               *)
  12.       RS_StatReg  = $03fd;             (* Fehler Register                *)
  13.       RS_ModStat  = $03fe;             (* Modem Status Register          *)
  14.       RS_IntAkt   = $100;              (* Testbyte, ob Spooler vorhanden *)
  15.       RS_InPtr    = $103;              (* Pointer auf n. freien Platz    *)
  16.       RS_BufOfs   = $105;              (* Start des Ringpuffers          *)
  17.       RS_ChCnt    = $107;              (* Anzahl der abzuholenden Char's *)
  18.       RS_OutPtr   = $109;              (* Pointer auf naechstes Zeichen  *)
  19.       RS_BufRange = $10b;              (* Groesse des Ringpuffers        *)
  20.       RS_FulFlg   = $10d;              (* Ueberlauf Flag des Ringpuffers *)
  21.       RS_txready  = $20;               (* Maskenbit fuer Sendebereit     *)
  22.       RS_IntCtrl  = $21;               (* Interrupt Controler Adresse    *)
  23.       RS_IntFree  = $20;               (* Interrupt Controler freigabe   *)
  24.  
  25. VAR
  26.     RS_Char        : CHAR;             (* RS-Zeichen-Puffer              *)
  27.     RS_NextPtr     : INTEGER;          (* Zeigerpuffer auf Zeichen       *)
  28.     RS_CodSeg      : INTEGER;          (* Codesegment des Spoolerprogr.  *)
  29.     RS_BufAdr      : INTEGER;          (* Ringpuffer Offset              *)
  30.     RS_BufSize     : INTEGER;          (* Ringpuffer Groesse             *)
  31.     RS_BufCnt      : INTEGER;          (* Zeichen im Ringpuffer, wird
  32.                                           nur bei Pufferzugriff aktual.! *)
  33.     RS_BufFull     : BOOLEAN;          (* Flag Ringpuffer-Ueberlauf
  34.                                           = 0, wenn eingetreten!         *)
  35.  
  36.     ende           : BOOLEAN;          (* Ende Flag des Hauptprogramms   *)
  37.     ch             : CHAR;             (* Tastatur-Zeichen-Puffer        *)
  38.  
  39. (* --------------------------------------------------------------------- *)
  40. (*    Hole Adresse RS-232-C-Spooler Code, Puffer und dessen Groesse:     *)
  41. (* Ist der Spooler aktiv, ist 'RS_FindSpooler' TRUE! Diese Funktion muss *)
  42. (* zu Beginn des Pascal-Programms einmal aufgerufen werden.              *)
  43.  
  44. FUNCTION RS_FindSpooler: BOOLEAN;
  45. TYPE register = RECORD               (* Registersatz des Intel 8088/8086 *)
  46.                   ax,bx,cx,dx,bp,si,di,ds,es,flags: INTEGER;
  47.                 END;
  48. VAR msdos_register : register;         (* MS-DOS Uebergaberegister Satz  *)
  49.   BEGIN
  50.     WITH msdos_register DO
  51.     BEGIN
  52.       ax := $350c;  msdos(msdos_register);  RS_CodSeg := es;
  53.     END;
  54.     RS_BufAdr := memw[RS_CodSeg:RS_BufOfs];
  55.     RS_BufSize := memw[RS_CodSeg:RS_BufRange];
  56.     RS_BufCnt := memw[RS_CodSeg:RS_ChCnt];
  57.     RS_BufFull := (mem[RS_CodSeg:RS_FulFlg] = 0);
  58.     RS_FindSpooler := (mem[RS_CodSeg:RS_IntAkt] = $e9);
  59.   END;
  60.  
  61. (* --------------------------------------------------------------------- *)
  62. (*                      Fehler-Register lesen:                           *)
  63.  
  64. FUNCTION RS_Status (mask: BYTE): BOOLEAN;
  65.   BEGIN
  66.     IF (Port[RS_StatReg] AND mask) = mask THEN  RS_Status := TRUE
  67.     ELSE  RS_Status := FALSE;
  68.   END;
  69.  
  70. (* --------------------------------------------------------------------- *)
  71. (*                  Uebertragungsparameter setzen:                       *)
  72.  
  73. PROCEDURE RS_SetLine (rate: INTEGER; parity: CHAR; stopbit, bits: BYTE);
  74.   VAR temp : INTEGER;
  75.   BEGIN
  76.     CASE rate OF
  77.         50 : temp := $900;      75 : temp := $600;
  78.        110 : temp := $417;     134 : temp := $359;
  79.        150 : temp := $300;     300 : temp := $180;
  80.        600 : temp := $0c0;    1200 : temp := $060;
  81.       1800 : temp := $040;    2000 : temp := $03a;
  82.       2400 : temp := $030;    3600 : temp := $020;
  83.       4800 : temp := $018;    7200 : temp := $010;
  84.       9600 : temp := $00c;
  85.       ELSE temp := $00c;
  86.     END;
  87.     Port[RS_LinCtrl] := $80;
  88.     Port[RS_Port] := Lo(temp);  Port[RS_Latch] := Hi(temp);
  89.     CASE parity OF
  90.       'E','e' : temp := $18;   'O','o' : temp := 8;
  91.       'N','n' : temp := 0;
  92.       ELSE temp := $18;
  93.     END;
  94.     CASE stopbit OF
  95.       1 : ;                     2 : temp := temp+4;
  96.       ELSE temp := temp+4;
  97.     END;
  98.     CASE bits OF
  99.       5 : ;                     6 : temp := temp+1;
  100.       7 : temp := temp+2;       8 : temp := temp+3;
  101.       ELSE temp := temp+3;
  102.     END;
  103.     Port[RS_LinCtrl] := temp;
  104.   END;
  105.  
  106. (* --------------------------------------------------------------------- *)
  107. (*       Initialisiere RS-232-Interrupt und Ringpuffer-Parameter:        *)
  108.  
  109. PROCEDURE RS_Init (baudrate: INTEGER; parity: CHAR;
  110.                    stopbits, datenbits: BYTE);
  111.   VAR dummy : INTEGER;
  112.   BEGIN
  113.     RS_SetLine(baudrate, parity, stopbits, datenbits);
  114.     Port[RS_LinCtrl] := (Port[RS_LinCtrl] AND $7f);
  115.     Port[RS_Latch] := 1;               (* Enable Empfaenger Interrupt    *)
  116.     Port[RS_ModCmd] := $0b;            (* Schalte Handshake Signale      *)
  117.     dummy := Port[RS_IntReg];          (* Dummy-Lesen zum bereinigen     *)
  118.     dummy := Port[RS_StatReg];         (* des Portbausteins.             *)
  119.     dummy := Port[RS_ModStat];
  120.     dummy := Port[RS_Port];
  121.     dummy := Port[RS_Port];
  122.     Port[RS_IntCtrl] := (Port[RS_IntCtrl] AND $ef); (* Enable Interrupt  *)
  123.   END;
  124.  
  125. (* --------------------------------------------------------------------- *)
  126. (*                Spoolerpuffer 'gewaltsam' leeren:                      *)
  127.  
  128. PROCEDURE RS_EmptyBuffer;
  129.   BEGIN
  130.     memw[RS_CodSeg:RS_InPtr] := 0;
  131.     memw[RS_CodSeg:RS_ChCnt] := 0;    RS_BufCnt := 0;
  132.     memw[RS_CodSeg:RS_OutPtr] := 0;
  133.     mem[RS_CodSeg:RS_FulFlg] := $FF;  RS_BufFull := FALSE;
  134.   END;
  135.  
  136. (* --------------------------------------------------------------------- *)
  137. (*          Hole ein Zeichen aus Ringpuffer, wenn vorhanden:             *)
  138. (*       Wenn vorhanden: RS_Char := Zeichen und RS_Getch := TRUE         *)
  139.  
  140. FUNCTION RS_Getch: BOOLEAN;
  141.   BEGIN
  142.     IF memw[RS_CodSeg:RS_ChCnt] = 0 THEN  RS_Getch := FALSE
  143.     ELSE
  144.       BEGIN
  145.         RS_Getch := TRUE;
  146.         RS_NextPtr := memw[RS_CodSeg:RS_OutPtr];
  147.         RS_Char := Chr(Mem[RS_CodSeg:RS_BufAdr+RS_NextPtr]);
  148.         INLINE ($06/              (* push  es                    *)
  149.                 $53/              (* push  bx                    *)
  150.                 $a1/RS_CodSeg/    (* mov   ax,[RS_CodSeg]        *)
  151.                 $8e/$c0/          (* mov   es,ax                 *)
  152.                 $bb/RS_ChCnt/     (* mov   bx,RS_ChCnt           *)
  153.                 $26/$FF/$0f/      (* dec   word ptr es:[bx]      *)
  154.                 $5b/              (* pop   bx                    *)
  155.                 $07);             (* pop   es                    *)
  156.         RS_NextPtr := Succ(RS_NextPtr);
  157.         IF RS_NextPtr > RS_BufSize THEN RS_NextPtr := 0;
  158.         memw[RS_CodSeg:RS_OutPtr] := RS_NextPtr;
  159.         RS_BufFull := (memw[RS_CodSeg:RS_FulFlg] = 0);
  160.         RS_BufCnt := memw[RS_CodSeg:RS_ChCnt];
  161.       END;
  162.     END;
  163.  
  164. (* --------------------------------------------------------------------- *)
  165. (*      Schreibe ein Zeichen an RS-232 mit Status und ohne warten:       *)
  166.  
  167. FUNCTION RS_Putch (ch: CHAR): BOOLEAN;
  168.   BEGIN
  169.     IF NOT (RS_Status(RS_txready)) THEN  RS_Putch := FALSE
  170.     ELSE
  171.       BEGIN
  172.         RS_Putch := TRUE;  Port[RS_Port] := Ord(ch);
  173.       END;
  174.   END;
  175.  
  176. (* --------------------------------------------------------------------- *)
  177.  
  178. PROCEDURE Term_Stat;
  179.   BEGIN
  180.     WriteLn;
  181.     WriteLn('  Puffergroesse: ', RS_BufSize:6,
  182.             '  Zeichen im Puffer: ', RS_BufCnt:6,
  183.             '  Pufferueberlauf: ', RS_BufFull);
  184.     WriteLn;
  185.   END;
  186.  
  187. BEGIN
  188.   ClrScr;
  189.   ende := FALSE;
  190.   IF RS_FindSpooler THEN   (* Adresse und Groesse des Spoolers ermitteln *)
  191.     BEGIN                             (* Spooler aktiv, weiter machen... *)
  192.       (* Initial. der Schnittstelle: 300 Baud, keine Paritaet, 1 Stopbit *)
  193.       RS_Init(300,'N',1,8);                               (* 8 Datenbits *)
  194.       Term_Stat;
  195.       REPEAT                          (* und einem ganz kleinen Terminal *)
  196.         IF RS_Getch THEN Write (RS_Char);    (* Zeichen wurde empfangen! *)
  197.         IF KeyPressed THEN                   (* Taste wurde gedrueckt... *)
  198.         BEGIN
  199.           Read(Kbd, ch);                  (* Zeichen der Taste ermitteln *)
  200.           IF ch = Chr(27) THEN
  201.             ende := TRUE                           (* Ende bei ESC-Taste *)
  202.           ELSE IF ch = Chr(1) THEN
  203.             BEGIN
  204.               RS_EmptyBuffer;          (* Control-A setzt Puffer zurueck *)
  205.               Term_Stat;
  206.             END
  207.           ELSE                                (* sonst Zeichen senden... *)
  208.             BEGIN
  209.               REPEAT UNTIL RS_Putch(ch);
  210.             END;
  211.         END;
  212.       UNTIL ende;
  213.     END
  214.   ELSE
  215.     BEGIN
  216.       WriteLn; WriteLn;
  217.       WriteLn('RS-232-Spooler ist nicht aktiv !!!');
  218.     END;
  219. END.
  220.