home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / t_power / comport.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-02-07  |  6.9 KB  |  282 lines

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