home *** CD-ROM | disk | FTP | other *** search
/ POINT Software Programming / PPROG1.ISO / pascal / swag / comm.swg / 0069_Modem Communication.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-03-26  |  6.9 KB  |  283 lines

  1.  
  2. {$R-,S-}
  3. unit ComPort;
  4.  
  5. interface
  6.  
  7. uses TPDos,
  8.      TpString,
  9.      TpInt;
  10.  
  11.  
  12. function OpenCom(PortNum,Params: Word): boolean;
  13.  
  14. { Issues interrupt $14 to initialize the UART, sets up buffers            }
  15. { This procedure should be called using the const declarations following. }
  16. { Sample calling sequence:                                                }
  17. {      Port := Com1Port;                                                  }
  18. {      Params := Baud9600 + NoParity + WordSize8 + StopBits1;             }
  19. {      if InitCom( Port, Params ) then;                                   }
  20.  
  21. function ComReady: boolean;
  22. {returns true if character ready;  false if no character waiting }
  23.  
  24. function ReadCom: char;
  25. {returns character from com port}
  26.  
  27. procedure WriteCom( C: char );
  28. {Send a character}
  29.  
  30. procedure WriteComStr( S: string );
  31. {Writes a string, S, by repeatedly calling WriteCom}
  32.  
  33. const
  34.   AsyncBufMax = 4095;     {Upper limit of Async Buffer}
  35.  
  36. var
  37.   Async: record
  38.     Overflow: boolean;
  39.     PortNum,
  40.     Base,
  41.     Max,
  42.     Head,
  43.     Tail:    word;
  44.     Buffer: array[0..AsyncBufMax] of char;
  45.     end;
  46.  
  47. const
  48.   Baud110 =       $00;
  49.   Baud150 =       $20;
  50.   Baud300 =       $40;
  51.   Baud600 =       $60;
  52.   Baud1200 =      $80;
  53.   Baud2400 =      $A0;
  54.   Baud4800 =      $C0;
  55.   Baud9600 =      $E0;
  56.   EvenParity =    $18;
  57.   OddParity =     $08;
  58.   NoParity =      $00;
  59.   WordSize7 =     $02;
  60.   WordSize8 =     $03;
  61.   StopBits1 =     $04;
  62.   StopBits2 =     $00;
  63.   Com1Port =      $00;
  64.   Com2Port =      $01;
  65.  
  66. {===========================================================================}
  67. {.pa}
  68. implementation
  69.  
  70. const
  71.   UART_THR  = $00;     {Transmit Hold Register}
  72.   UART_RBR  = $00;     {Receive Buffer Register}
  73.   UART_IER  = $01;     {Data ready interrupt}
  74.   UART_IIR  = $02;     {}
  75.   UART_LCR  = $03;     {}
  76.   UART_MCR  = $04;     {OUT2}
  77.   UART_LSR  = $05;     {Line Status Register}
  78.   UART_MSR  = $06;     {}
  79.   I8088_IMR = $21;     {Interrupt Mask Register on 8250\9}
  80.  
  81. var
  82.   AsyncBIOSPortTable: array[1..2] of word absolute $40:0;
  83.   SaveExitProc:  pointer;
  84.  
  85. procedure BiosInitCom(PortNum,Params: Word);
  86. inline(
  87.   $58/          { POP   AX      ;Pop parameters         }
  88.   $5A/          { POP   DX      ;Pop port number        }
  89.   $B4/$00/      { MOV   AH,0    ;Code for initialize    }
  90.   $CD/$14);     { INT   14H     ;Call BIOS              }
  91.  
  92. function InChar(PortNum: Word): Char;
  93. inline(
  94.   $5A/          { POP   DX      ;Pop port number        }
  95.   $B4/$02/      { MOV   AH,2    ;Code for input         }
  96.   $CD/$14);     { INT   14H     ;Call BIOS              }
  97.  
  98. function InReady(PortNum: Word): Boolean;
  99. inline(
  100.   $5A/          { POP   DX      ;Pop port number        }
  101.   $B4/$03/      { MOV   AH,3    ;Code for status        }
  102.   $CD/$14/      { INT   14H     ;Call BIOS              }
  103.   $88/$E0/      { MOV   AL,AH   ;Get line status in AH  }
  104.   $24/$01);     { AND   AL,1    ;Isolate Data Ready bit }
  105.  
  106. {$F+} procedure ComIntHandler( BP: word ); interrupt; {$F-}
  107.  
  108. var
  109.   Regs:      IntRegisters absolute BP;
  110.   NewHead:   word;
  111.  
  112. begin   {ComIntHandler}
  113.  
  114.   with Async do begin
  115.     Buffer[Head] := Chr( Port[UART_RBR + Base] );
  116.     NewHead := succ( Head );
  117.     if NewHead > Max then NewHead := 0;
  118.     if NewHead = Tail then Overflow := true
  119.     else Head := NewHead;
  120.     InterruptsOff;
  121.     Port[$20] := $20;   {use non-specific EOI}
  122.     end;  {with Async}
  123.  
  124.   end;   {ComIntHandler}
  125.  
  126. function OpenCom(PortNum,Params: Word): boolean;
  127.  
  128. const
  129.   Handle =  15;    {Select an arbitrary handle for TPInt}
  130.  
  131. var
  132.   IntNumber: byte;
  133.   Junk,
  134.   Mask:      word;
  135.   IRQ,
  136.   Vector:    byte;
  137.   I:         integer;
  138.  
  139. begin
  140.  
  141.   if Async.PortNum <> $FFFF then begin
  142.     OpenCom := false;
  143.     exit;
  144.     end;
  145.   Async.Base := AsyncBIOSPortTable[PortNum + 1];
  146.   IRQ := Hi(Async.Base) + 1;
  147.   IntNumber := IRQ + $8;
  148.   if (Port[UART_IIR + Async.Base] and $F8) <> 0 then begin
  149.     OpenCom := false;
  150.     exit;
  151.     end;
  152.   if not InitVector( IntNumber, Handle, @ComIntHandler ) then begin
  153.     OpenCom := false;
  154.     exit;
  155.     end;
  156.   Async.PortNum := PortNum;
  157.   {Other parameters already initialized}
  158.   BiosInitCom(PortNum,Params);
  159.   InterruptsOff;
  160.   Port[UART_LCR + Async.Base] := Port[UART_LCR + Async.Base] and $7F;
  161.   Junk := Port[UART_LSR + Async.Base];  {Reset any Line Status Register errors}
  162.   Junk := Port[UART_RBR + Async.Base];  {Empty Receive Buffer Register}
  163.  
  164.   {Enable IRQ on the 8259 controller}
  165.   Port[I8088_IMR] := Port[I8088_IMR] and ((1 shl IRQ) xor $FF);
  166.  
  167.   Port[UART_IER + Async.Base] := $01; {Enable data ready interrupt on the 8250}
  168.  
  169.   {Enable OUT2 on 8250}
  170.   Port[UART_MCR + Async.Base] := Port[UART_MCR + Async.Base] or $08;
  171.   Port[$20] := $20;   {clear out non-specific EOI}
  172.  
  173.   InterruptsOn;
  174.   OpenCom := true;
  175.  
  176.   end;
  177.  
  178. function ReadCom: char;
  179. {returns character from com port}
  180.  
  181. begin
  182.  
  183.   with Async do begin
  184.     repeat until Head <> Tail;   {Wait here for a character}
  185.     ReadCom := Buffer[Tail];
  186.     InterruptsOff;
  187.     Inc( Tail );
  188.     if Tail > Max then Tail := 0;
  189.     InterruptsOn;
  190.     end;
  191.  
  192.   end;    {ReadCom}
  193.  
  194. function ComReady: boolean;
  195. {returns true if character ready;  false if no character waiting }
  196.  
  197. begin
  198.  
  199.   with Async do begin
  200.     if Head = Tail then ComReady := false
  201.     else ComReady := true;
  202.     end;
  203.  
  204.   end;    {ComReady}
  205.  
  206. procedure WriteCom( C: char );
  207. {Send a character}
  208.  
  209. var
  210.   WaitCount: word;
  211.  
  212. begin
  213.  
  214.   with Async do begin
  215.     Port[UART_MCR + Base] := $0B;  {Turn on OUT2, DTR, and RTS}
  216.     WaitCount := $FFFF;
  217.     while (WaitCount <> 0) and ((Port[UART_MSR + Base] and $10) = 0) do
  218.       dec(WaitCount);   {Wait for CTS (clear to send)}
  219.     if WaitCount <> 0 then WaitCount := $FFFF;
  220.     while (WaitCount <> 0) and ((Port[UART_LSR + Base] and $20) = 0) do
  221.       dec(WaitCount);   {Wait for THRE  (transmit hold register empty)}
  222.     if WaitCount <> 0 then begin
  223.       InterruptsOff;
  224.       Port[UART_THR + Base] := ord(C);   {send the character}
  225.       InterruptsOn;
  226.       end;
  227.     end;
  228.  
  229.   end;   {WriteCom}
  230.  
  231. procedure WriteComStr( S: string );
  232. {Writes a string, S, by repeatedly calling WriteCom}
  233.  
  234. begin
  235.  
  236.   while length(S) > 0 do begin
  237.     WriteCom( S[1] );
  238.     S := copy( S, 2, 255 );     {throw away first character}
  239.     end;
  240.  
  241.   end;
  242.  
  243. procedure CloseCom;
  244.  
  245. var
  246.   IRQ:  byte;
  247.  
  248. begin
  249.  
  250.  
  251.   if Async.PortNum <> $FFFF then begin
  252.     IRQ := Hi(Async.Base) + 1;
  253.     InterruptsOff;
  254.     Port[I8088_IMR] := Port[I8088_IMR] or (1 shl IRQ); {Turn off int reqs}
  255.     Port[UART_IER + Async.Base] := 0;  {Disable 8250 Data ready interrupt}
  256.     Port[UART_MCR + Async.Base] := 0;   {Disable OUT2 on 8250}
  257.     InterruptsOn;
  258.     end;
  259.  
  260.   end;   {CloseCom}
  261.  
  262. {$F+} procedure ExitCom; {$F-}
  263.  
  264. begin
  265.  
  266.   ExitProc := SaveExitProc;
  267.   CloseCom;
  268.  
  269.   end;
  270. begin
  271.  
  272.   with Async do begin
  273.     Overflow := false;
  274.     PortNum := $FFFF;
  275.     Max := AsyncBufMax;
  276.     Head := 0;
  277.     Tail := 0;
  278.     end;
  279.   SaveExitProc := ExitProc;
  280.   ExitProc := @ExitCom;
  281.  
  282. end.
  283.