home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / ASYNCH.ZIP / ASYNCH.PAS
Encoding:
Pascal/Delphi Source File  |  1988-02-11  |  11.6 KB  |  379 lines

  1. {$R+}    {Range checking off}
  2. {$B-}    {Boolean short circuiting off}
  3. {$S-}    {Stack checking on}
  4. {$I-}    {I/O checking on}
  5. {$N-}    {No numeric coprocessor}
  6.  
  7. (**********************************************************************)
  8. (*                                                                    *)
  9. (*    Unit for communications for the IBM PC and compatibles          *)
  10. (*                                                                    *)
  11. (*                 Version 1.0      February 2, 1988                  *)
  12. (*                                                                    *)
  13. (*    This unit supports only Com 1 and 2 at this time and has not    *)
  14. (*    been fully ported over to Turbo 4.0.  If you make improvements  *)
  15. (*    on this code, please send me a message or a copy of the fix     *)
  16. (*    to the below address:                                           *)
  17. (*                                                                    *)
  18. (*                  Dale Barnes                                       *)
  19. (*                  127 Post Oak Place                                *)
  20. (*                  Shalimar, FL  32579                               *)
  21. (*                  (904) 651-6125                                    *)
  22. (*                  CIS 76530,1441                                    *)
  23. (*                                                                    *)
  24. (**********************************************************************)
  25.  
  26. Unit Asynch;
  27.  
  28. Interface
  29.  
  30. Uses
  31.   Dos,
  32.   Crt;
  33.  
  34.  
  35. CONST
  36.   BuffSize = 4096;
  37.   Cr       = #13;
  38.   Lf       = #10;
  39.  
  40. TYPE
  41.   Buffer_Type = 0..BuffSize;
  42.   ComType     = (Com1, Com2);
  43.   ByteChar = RECORD CASE Boolean OF
  44.                True  : (O : Byte);
  45.                False : (C : Char)
  46.              END;
  47.  
  48. VAR
  49.   C              : Char;
  50.   Local          : Boolean;
  51.   Prt            : Boolean;
  52.   Comp           : Comtype;
  53.   Head, Tail     : Buffer_Type;
  54.   CPort          : Byte;
  55.   Tbyte          : Byte;
  56.   LByte          : Byte;
  57.   EightBits      : Byte;
  58.   IntBuffer      : ARRAY[0..BuffSize] OF ByteChar;
  59.   ModemWait      : integer;
  60.  
  61.  
  62. PROCEDURE IntHandler;                            (* Comm interrupt handler *)
  63.  
  64. PROCEDURE SetRate(R : Integer);                           (* set baud rate *)
  65.  
  66. PROCEDURE Clear_Buffer;                        (* empties the buffer queue *)
  67.  
  68. PROCEDURE IntOn(Com : ComType);    (* turns on interrupts -- handles int24 *)
  69.  
  70. PROCEDURE IntOff;                (* turns interrupts off -- handles int 24 *)
  71.  
  72. FUNCTION ReadCom : Char; (* reads [if one is avaiable] a char from the modem *)
  73.  
  74. PROCEDURE Drop;
  75.  
  76. PROCEDURE On_Hook(On : boolean);
  77.  
  78. PROCEDURE Raise;
  79.  
  80. PROCEDURE Drop_DTR;
  81.  
  82. PROCEDURE WriteCom(Ch : Char; screen : Boolean);      (* write Ch to modem *)
  83.  
  84. FUNCTION ModemInput : Boolean; (* returns true is a character is available *)
  85.  
  86. FUNCTION Online : Boolean;       (* returns true if caller or sysop online *)
  87.  
  88. FUNCTION Ringing : Boolean;            (* returns true if phone is ringing *)
  89.  
  90. PROCEDURE Determine_Bits;                    (* determines the parity bits *)
  91.  
  92. PROCEDURE SendString(Txt : String; Crs : Integer); (* sends a string with CRS *)
  93.  
  94. PROCEDURE Send(Txt : String);     (* sends a string with NO screen echo *)
  95.  
  96. PROCEDURE Check_Ring;                    (* if modem is ringing, sends ATA *)
  97.  
  98.  
  99. {===========================================================================}
  100.  
  101. Implementation
  102.  
  103. (*-------------------------------------------------------------------*)
  104. (*                    Low Level Asynch Routines                      *)
  105. (*-------------------------------------------------------------------*)
  106.  
  107.  
  108. Const
  109.  
  110.   Com1Base  = $03F8;
  111.   Com2Base  = $02F8;
  112.   Irq4      = $30;
  113.   Irq3      = $2C;
  114.   LineCtrl  = 3;
  115.   LineStat  = 5;
  116.   IntenReg  = 1;
  117.   ModemStat = 6;
  118.   ModemCtrl = 4;
  119.  
  120.  
  121. Var
  122.  
  123. Regs     : Registers;
  124. ComPort  : Integer;
  125.  
  126. MSR        : Integer;
  127. LSR        : Integer;
  128. LCR        : Integer;
  129. MCR        : Integer;
  130. OldVecSeg  : Integer;
  131. OldVecOff  : Integer;
  132. CdMask     : Integer;
  133.  
  134. procedure CommIntOn; inline($FB);
  135. procedure CommIntOff; inline($FA);
  136.  
  137. PROCEDURE IntHandler;                            (* Comm interrupt handler *)
  138. BEGIN
  139.     INLINE
  140.      ($50/                                           {   PUSH    AX           }
  141.       $53/                                           {   PUSH    BX           }
  142.       $51/                                           {   PUSH    CX           }
  143.       $52/                                           {   PUSH    DX           }
  144.       $57/                                           {   PUSH    DI           }
  145.       $56/                                           {   PUSH    SI           }
  146.       $06/                                           {   PUSH    ES           }
  147.       $1E/                                           {   PUSH    DS           }
  148.       $2E/$A1/$A0/$00/                               {   MOV     AX,CS:[00A0] }
  149.       $50/                                           {   PUSH    AX           }
  150.       $1F);                                          {   POP     DS           }
  151.     TByte := Port[Comport];
  152.     LByte := Port[LSR];
  153.     Head := (Head+1) MOD BuffSize;
  154.     IntBuffer[head].O := Tbyte;
  155.     Port[$20] := $20;
  156.     INLINE
  157.      ($1F/                                           {   POP     DS           }
  158.       $07/                                           {   POP     ES           }
  159.       $5E/                                           {   POP     SI           }
  160.       $5F/                                           {   POP     DI           }
  161.       $5A/                                           {   POP     DX           }
  162.       $59/                                           {   POP     CX           }
  163.       $5B/                                           {   POP     BX           }
  164.       $58/                                           {   POP     AX           }
  165.       $5D/                                           {   POP     BP           }
  166.       $89/$EC/                                       {   MOV     SP,BP        }
  167.       $5D/                                           {   POP     BP           }
  168.       $CF);                                          {   IRET                 }
  169.   END;
  170.  
  171. PROCEDURE IntOn(Com : ComType);    (* turns on interrupts -- handles int24 *)
  172. VAR TByte : Byte;                  (* i.e. IntOn(Com1) or IntOn(Com2);     *)
  173. BEGIN
  174.   CommIntOff;
  175.   Head := 0;
  176.   Tail := 0;
  177.   CASE Com OF
  178.     Com1 : ComPort := Com1Base;
  179.     Com2 : Comport := Com2Base;
  180.   END;
  181.   MCR := ComPort+ModemCtrl;
  182.   MSR := ComPort+ModemStat;
  183.   LCR := ComPort+LineCtrl;
  184.   LSR := ComPort+LineStat;
  185.   TByte := Port[LSR];
  186.   Port[LCR] := 3;
  187.   Port[MCR] := 11;
  188.   Port[Comport+IntenReg] := 1;
  189.   TByte := Port[$21];
  190.   Regs.Ax := $2500;
  191.   Regs.DS := CSeg;
  192.   Regs.DX := Ofs(IntHandler);
  193.   CASE Com OF
  194.     Com1 : BEGIN
  195.              OldVecOff := MemW[0000 : Irq4];
  196.              OldVecSeg := MemW[0000 : Irq4+2];
  197.              Regs.AX   := Regs.AX+12;
  198.              Intr($21, Regs);
  199.              Port[$21] := TByte AND $EF;
  200.            END;
  201.     Com2 : BEGIN
  202.              OldVecOff := MemW[0000 : Irq3];
  203.              OldVecSeg := MemW[0000 : Irq3+2];
  204.              Regs.AX := Regs.AX+11;
  205.              Intr($21, Regs);
  206.              Port[$21] := TByte AND $F7;
  207.            END;
  208.   END;
  209.    CommIntOn;
  210. END;
  211.  
  212.  
  213. PROCEDURE IntOff;                (* turns interrupts off -- handles int 24 *)
  214. VAR Tbyte : Byte;
  215.   BEGIN
  216.     TByte := Port[$21];
  217.     Port[Comport+IntEnReg] := 0;
  218.     IF Comport = $3F8 THEN
  219.       BEGIN
  220.         Port[$21] := TByte OR 16;
  221.         MemW[0000:Irq4]   := OldVecOff;
  222.         MemW[0000:Irq4+2] := OldVecSeg;
  223.     END ELSE
  224.       BEGIN
  225.         MemW[0000:Irq3]   := OldVecOff;
  226.         MemW[0000:Irq3+2] := OldVecSeg;
  227.         Port[$21] := TByte OR 8;
  228.       END;
  229.   END;
  230.  
  231. PROCEDURE SetRate(R : Integer);                           (* set baud rate *)
  232. VAR TdlMsb, TdlLsb : Byte;
  233. BEGIN
  234.   CommIntOff;
  235.   TdlMsb := 0;
  236.   CASE R OF
  237.     300 : BEGIN                                                 { 300  Baud }
  238.             TdlMsb := 1;
  239.             TdlLsb := $80;
  240.           END;
  241.     1200 : TdlLsb := $60;                                      {  1200 Baud }
  242.     2400 : TdlLsb := $30;                                      {  2400 Baud }
  243.     4800 : TdlLsb := $18;                                      {  4800 Baud }
  244.     7200 : TdlLsb := $10;                                      {  7200 Baud }
  245.     9600 : TdlLsb := $0C;                                      {  9600 Baud }
  246.    19200 : TdlLsb := $06;                                      { 19200 Baud }
  247.   END;
  248.    Port[LCR] := $80;
  249.    Port[ComPort] := TdlLsb;
  250.    Port[ComPort+1] := TdlMsb;
  251.    Port[LCR] := 3;
  252.    CommIntOn;
  253. END;
  254.  
  255.  
  256. PROCEDURE Clear_Buffer;                        (* empties the buffer queue *)
  257. BEGIN
  258.   CommIntOff;                                                        { CLI }
  259.   Head := 0;
  260.   Tail := 0;
  261.   CommIntOn;                                                          { STI }
  262. END;
  263.  
  264.  
  265.  
  266.  
  267. PROCEDURE WriteCom(Ch : Char; screen : Boolean);      (* write Ch to modem *)
  268. VAR X : Integer;                           (* screen determines if written *)
  269.   BEGIN                                                 (* to screen as well *)
  270.     REPEAT UNTIL Odd(Port[LSR] SHR 5);
  271.     Port[ComPort] := Ord(Ch);
  272.     IF screen THEN Write(Ch);
  273.   END;
  274.  
  275.  
  276. FUNCTION ModemInput : Boolean; (* returns true is a character is available *)
  277. BEGIN
  278.     ModemInput := (Head <> Tail);
  279.   END;
  280.  
  281.  
  282. FUNCTION ReadCom : Char; (* reads [if one is avaiable] a char from the modem *)
  283. BEGIN
  284.     CommIntOff;
  285.     IF (Head <> Tail) THEN
  286.       BEGIN
  287.         Tail := (Tail+1) MOD BuffSize;
  288.         ReadCom := IntBuffer[Tail].C;
  289.       END;
  290.     CommIntOn;
  291.   END;
  292.  
  293. FUNCTION Online : Boolean;       (* returns true if caller or sysop online *)
  294. BEGIN
  295.   Online := (Port[MSR] AND CdMask = CDMask) OR Local;
  296. END;
  297.  
  298.  
  299. FUNCTION Ringing : Boolean;            (* returns true if phone is ringing *)
  300. BEGIN
  301.   Ringing := Port[MSR] AND 64 = 64;
  302. END;
  303.  
  304.  
  305. PROCEDURE Drop;
  306. BEGIN
  307.   Port[MCR] := (Port[MCR] AND 254);
  308.   Delay(1000);
  309. END;
  310.  
  311.  
  312. PROCEDURE On_Hook;
  313. BEGIN                                       { Simple procedure to place the }
  314.   IF On THEN
  315.   Send('ATM0H1') ELSE
  316.     Send('ATH0');
  317.   Delay(600);                                           { Modem On/Off Hook }
  318. END;
  319.  
  320.  
  321. PROCEDURE Raise;
  322. BEGIN
  323.   Port[MCR] := (Port[MCR] OR 1);
  324. END;
  325.  
  326. PROCEDURE Drop_DTR;
  327. BEGIN
  328.   Drop;
  329.   Raise;
  330.   Local := False;
  331. END;
  332.  
  333. PROCEDURE Determine_Bits;                    (* determines the parity bits *)
  334. BEGIN
  335.   EightBits := 0;
  336.   C := Chr(Ord(ReadCom));
  337.   IF (C = #13) THEN EightBits := 1;
  338.   IF (C = #141) THEN EightBits := 2;
  339.   C := Chr(Ord(C) AND $7F);
  340. END;
  341.  
  342.  
  343. PROCEDURE SendString(Txt : String; Crs : Integer); (* sends a string with CRS *)
  344. VAR I : Integer;                                   (* carriage returns after *)
  345. BEGIN
  346.   FOR I := 1 TO Crs DO Txt := Txt+#13+#10;
  347.    IF Local AND prt THEN Write(Txt);
  348.     IF NOT Local THEN
  349.       IF Online THEN FOR I := 1 TO Length(Txt) DO WriteCom(Txt[I], prt);
  350. END;
  351.  
  352.  
  353. PROCEDURE Send(Txt : String);     (* sends a string with NO screen echo *)
  354. VAR I : Integer;
  355. BEGIN
  356.   Txt := Txt+Cr+Lf;
  357.   FOR I := 1 TO Length(Txt) DO WriteCom(Txt[I], False);
  358. END;
  359.  
  360.  
  361. PROCEDURE Check_Ring;                    (* if modem is ringing, sends ATA *)
  362. VAR T : Integer;
  363.   BEGIN
  364.     IF Ringing THEN
  365.       BEGIN
  366.         Delay(800);
  367.         Send('ATA');
  368.         WriteLn('■ Ring Detected - Answering Phone');
  369.         T := 0;
  370.         WHILE NOT Online AND (T < ModemWait) DO
  371.           BEGIN
  372.             Delay(1000);
  373.             T := T+1;
  374.           END;
  375.       END;
  376.   END;
  377.  
  378. End.
  379.