home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / delite / miniterm / v24.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1992-04-01  |  15.6 KB  |  397 lines

  1. Unit V24;
  2.  
  3. { **************************************************************************
  4.   Name:              V24.PAS
  5.   Version:           1.0
  6.   Edit Date:         30.1.1992
  7.   Author:            Frank R. Seidinger
  8.   Comment:           V24 (RS232) communication with Turbo Pascal 6.0
  9.   **************************************************************************
  10.  
  11.   This unit implements an interrupt driven V24 handler for Turbo Pascal 6.0. 
  12.   It is based on ideas from Mike Halliday and Christian  Phillips.   V24.PAS 
  13.   can be used freely.  If  you  want to modify it,  please don't  forget  to
  14.   mention the authors.
  15.  
  16.   To start communications use the function OpenCom. If opening the requested 
  17.   com-port was successful, the function returns TRUE, otherwise FALSE. There 
  18.   are several parameters  to pass to OpenCom  to meet nearly all desires one 
  19.   can have when tinking  off interrupt  driven  communication.   Beside  the 
  20.   normal parameters  that a normal V24 packet has (baud rate, parity, number 
  21.   of data  bits and stop  bits)  OpenCom  is able to dynaically  adjust  the 
  22.   ringbuffer  size  for incoming  characters  via the MyBuffSize  parameter. 
  23.   Possible  values  can be KB1, KB2,  KB4,  KB8 and KB16.   The ringbuffer's 
  24.   memory  is allocated  on the  system  heap  by calling  the  Turbo  Pascal 
  25.   procedure  GetMem.   Also OpenCom  tries  to use the FIFO features  of the 
  26.   xx16550xx chipset if requested by the ComMode parameter. 
  27.  
  28.   To end communication use the procedure CloseCom. This procedure resets the 
  29.   aktual com port in use and deaktivates  the interrupt  vectors uses by the 
  30.   V24 unit.  Calling  OpenCom  automatically  calls CloseCom  thus gives the 
  31.   possibility  to switch few or any com port parameters  by calling  OpenCom 
  32.   again.   Therefore  it is no problem  to switch  to another  com port  for 
  33.   example. 
  34.  
  35.   To meet the greatest  flexibility  in assigning  different  com ports, the 
  36.   OpenCom  parameter  ComPort  takes default values for standard  ports Com1 
  37.   through Com4.  Additionally it it possible to set a none standard com port 
  38.   by selecting  UserCom  for the ComPort parameter  and setting  the desired 
  39.   com port parameters through the function SetUserCom.   SetUserCom needs to 
  40.   know on witch address the com port is located and what IRQ line (Interrupt 
  41.   request)  it uses.   Possible  values  for IrqNr  are are 2,3,4,5  and  7. 
  42.   SetUserCom should be called before using OpenCom. 
  43.  
  44.   After  successfully  opening  a com port you are able  to send and receive 
  45.   characters  throug  the V24 hardware.   Sending  a character  is done with 
  46.   PutComData  and receiving  with  GetComData.   If there  are no characters 
  47.   waiting in the ringbuffer,  GetComData  returns zero (ASCII NUL).  You are 
  48.   able to check wether  there  are waiting  characters  by using the boolean 
  49.   function IsComDataAvail. 
  50.   
  51.   If you want  to use the  xx16550xx  chipset  features,  there  are several 
  52.   possibilities for the ComMode parameter when calling OpenCom: 
  53.   
  54.      Normal   - No xx16650xx features are used. This is the recommended mode 
  55.         when using the 8250xx chipset. 
  56.  
  57.      FIFOComp - The xx16550xx is used in compatible  mode.  In this mode the 
  58.         FIFO  is disabled  and the  chipset  behaves  like  a normal 
  59.         8250xx chipset. 
  60.  
  61.      FIFO1    - The xx16550xx  FIFO is enabled and the chipset will generate 
  62.         an interrupt each time a character  is placed into the FIFO. 
  63.         This  mode also results  the same behaviour  as the FIFOComp 
  64.         mode does. 
  65.  
  66.      FIFO4    -    The xx16550xx  FIFO is enabled and the chipset will generate 
  67.         an interrupt if the forth character is placed into the FIFO. 
  68.         The interrupt handler reads all four characters  at the same 
  69.         time.  Thus the interrupt  overhead  is reduced  by four and 
  70.         results in better overall performance. 
  71.      
  72.      FIFO8    - Like  FIFO4  but  generates  an  interrupt   if  the  eighth 
  73.         character is placed into the FIFO. 
  74.  
  75.      FIFO14   - Like  FIFO4  but  generates  an interrupt  if the fourteenth 
  76.         character is placed into the FIFO. 
  77.  
  78.   
  79.   If you have questions, please contact:
  80.  
  81.   address:
  82.   **************************************
  83.   BrainLab
  84.   Frank R. Seidinger & Andreas Schumm
  85.   Koloniestraße 71
  86.   W-1000 Berlin 65
  87.   
  88.   Federal Republik of Germany
  89.   **************************************
  90.   
  91.   or via e-mail:
  92.   **************************************
  93.   1st: docbrain@netmbx.in-berlin.de
  94.   2nd: seid4000@w250zrz.zrz.tu-berlin.de
  95.   **************************************
  96.  
  97.   ************************************************************************** }
  98.  
  99. Interface
  100.  
  101.   Const XON         = $0001;
  102.         CTS         = $0002;
  103.         DSR         = $0004;
  104.         StopFlag    = $8000;
  105.  
  106.   Type  ComPortType = (Com1,Com2,Com3,Com4,UserCom,NoCom);
  107.         ComBaudType = (b110,b150,b300,b600,b1200,b2400,b4800,b9600,b19200,
  108.                        b38400,b57600,b115200);
  109.         ComDataType = (Space,Odd,Mark,Even,NoParity);
  110.         ComBitsType = (d5,d6,d7,d8);
  111.         ComStopType = (s1,s2);
  112.         ComBuffType = (Kb1,Kb2,Kb4,Kb8,Kb16);
  113.  
  114.         ComModeType = (Normal,FIFOComp,FIFO1,FIFO4,FIFO8,FIFO14);
  115.  
  116.   Function  OpenCom(ComPort    : ComPortType; Baudrate   : ComBaudType;
  117.                     Data       : ComBitsType; Parity     : ComDataType;
  118.                     StopBits   : ComStopType; ComMode    : ComModeType;
  119.                     MyBuffSize : ComBuffType) : Boolean;
  120.  
  121.   Procedure CloseCom;
  122.  
  123.   Function  IsComDataAvail : Boolean;
  124.  
  125.   Function  GetComData : Byte;
  126.  
  127.   Procedure PutComData(Data : Byte);
  128.  
  129.   Function  SetUserComPort(ComBaseAddr : Word; IrqNr : Byte) : Boolean;
  130.  
  131.   Procedure SetHandShake(MyHandShake : Word);
  132.  
  133. Implementation
  134.  
  135.   Uses  DOS;
  136.  
  137.   Type  BufType     = Array[0..$3FFF] of Byte; { type of ringbuffer}
  138.         BufPtrType  = ^BufType;
  139.  
  140.   Const ComAddrArr  : Array[ComPortType] of Word =
  141.                       ($03F8,$02F8,$02E8,$03E8,$FFFF,$FFFF);
  142.         ComIntMasks : Array[ComPortType] of Byte = ($EF,$F7,$EF,$F7,$FF,$FF);
  143.         ComIntVecs  : Array[ComPortType] of Byte = ($0C,$0B,$0C,$0C,$FF,$FF);
  144.  
  145.         BuffSizeArr : Array[ComBuffType] of Word =
  146.                       ($0400,$0800,$1000,$2000,$4000);
  147.  
  148.         Buffer      : BufPtrType = NIL; { pointer to com port ringbuffer }
  149.         BufferSize  : Word = 1024;      { aktual size of ringbuffer }
  150.  
  151.         Top         : Word = 0;
  152.     Bottom      : Word = 0;     { Top and Bottom of ringbuffer }
  153.  
  154.         ComPortAddr : Word = $FFFF; { address of com port in use }
  155.  
  156.         RBR         = $00;         { xF8 Receive Buffer Register            }
  157.         THR         = $00;         { xF8 Transmitter Holding Register       }
  158.         IER         = $01;         { xF9 Interrupt Enable Register          }
  159.         IIR         = $02;         { xFA Interrupt Identification Register  }
  160.         LCR         = $03;         { xFB Line Control Register              }
  161.         MCR         = $04;         { xFC Modem Control Register             }
  162.         LSR         = $05;         { xFD Line Status Register               }
  163.         MSR         = $06;         { xFE Modem Status Register              }
  164.  
  165.         DLL         = $00;         { xF8 Divisor Latch Low Byte             }
  166.         DLH         = $01;         { xF9 Divisor Latch Hi  Byte             }
  167.  
  168.         CMD8259     = $20;         { Interrupt Controller Command Register  }
  169.         IMR8259     = $21;         { Interrupt Controller Mask Register     }
  170.  
  171.         AktivePort  : ComPortType = NoCom;  { aktive port ID }
  172.         FIFOMode    : ComModeType = Normal; { 16550 FIFO ID }
  173.  
  174.         HandShake   : Word = 0;
  175.  
  176.   Var   OldComIntVec : Pointer;
  177.  
  178.   Procedure ClearPendingInterrupts;
  179.   { Clears all interrupts, that are pending in the UART hardware }
  180.   Var Dummy : Byte;
  181.   Begin
  182.     If (AktivePort <> NoCom) Then
  183.       Begin
  184.         While ((Port[ComPortAddr+IIR] And 1) = 0) do
  185.       Begin { while interrupts are pending }
  186.             Dummy := Port[ComPortAddr+LSR]; { reset priority level 1 }
  187.             Dummy := Port[ComPortAddr+RBR]; { reset priority level 2 }
  188.             Dummy := Port[ComPortAddr+MSR]; { reset priority level 4 }
  189.             { priority level 3 is cleared by the while statement }
  190.             Port[CMD8259] := $20;           { reset interrupt controller }
  191.           End;
  192.       End;
  193.   End;
  194.  
  195.   Function IsComDataAvail : Boolean;
  196.   Begin
  197.     IsComDataAvail := (Top <> Bottom);
  198.   End;
  199.  
  200.   Function GetComData : Byte;
  201.   Var Free : Integer;
  202.   Begin
  203.     If (AktivePort <> NoCom) Then
  204.       Begin
  205.         If (Top <> Bottom) Then
  206.           Begin
  207.             GetComData := Buffer^[Bottom];
  208.             Bottom     := Succ(Bottom) mod BufferSize;
  209.             If (HandShake <> 0) and ((HandShake and StopFlag) <> 0) Then
  210.               Begin
  211.                 If Top > Bottom Then
  212.                   Free := Bottom - Top + BufferSize
  213.                 Else
  214.                   Free := Bottom - (Top + BufferSize) + BufferSize;
  215.                 If (Free > (BufferSize-256)) Then
  216.                   Begin
  217.                     If ((HandShake and XON) <> 0) Then
  218.                       PutComData(17);
  219.                     If ((HandShake and CTS) <> 0) Then
  220.                       Port[ComPortAddr+MCR] := Port[ComPortAddr+MCR] or $2;
  221.                     If ((HandShake and DSR) <> 0) Then
  222.                       Port[ComPortAddr+MCR] := Port[ComPortAddr+MCR] or $1;
  223.                     HandShake := HandShake and Not StopFlag;
  224.                   End;
  225.               End;
  226.           End
  227.         Else GetComData := 0;
  228.       End
  229.     Else GetComData := 0;
  230.   End;
  231.  
  232.   Procedure PutComData(Data : Byte);
  233.   Begin
  234.     If (AktivePort <> NoCom) Then
  235.       Begin
  236.         Repeat
  237.           { wait for THRE = 1 }
  238.         Until ((Port[ComPortAddr+LSR] and $20) = $20);
  239.         Port[ComPortAddr] := Data;
  240.       End;
  241.   End;
  242.  
  243.   Procedure NewComIntSupport; FAR;
  244.   Var NextPos : Word;
  245.       MyByte  : Byte;
  246.       Free    : Integer;
  247.   Begin
  248.     While ((Port[ComPortAddr+LSR] and $1) <> 0) do
  249.       Begin
  250.         MyByte  := Port[ComPortAddr];
  251.         NextPos := Succ(Top) mod BufferSize;
  252.         If (NextPos <> Bottom) Then
  253.           Begin
  254.             Buffer^[Top] := MyByte;
  255.             Top          := NextPos;
  256.           End;
  257.       End;
  258.     Port[CMD8259] := $20;
  259.     If (HandShake <> 0) and ((HandShake and StopFlag) = 0) Then
  260.       Begin
  261.         If (NextPos < Bottom) Then
  262.           NextPos := NextPos + BufferSize;
  263.         Free := Bottom - NextPos + BufferSize;
  264.         If Free < 256 Then
  265.           Begin
  266.             If ((HandShake and XON) <> 0) Then
  267.               PutComData(19);
  268.             If ((HandShake and CTS) <> 0) Then
  269.               Port[ComPortAddr+MCR] := Port[ComPortAddr+MCR] and $FD;
  270.             If ((HandShake and DSR) <> 0) Then
  271.               Port[ComPortAddr+MCR] := Port[ComPortAddr+MCR] and $FE;
  272.             HandShake := HandShake or StopFlag;
  273.           End;
  274.       End;
  275.   End;
  276.  
  277.   Procedure NewComInt; FAR; ASSEMBLER;
  278.   ASM
  279.    push  ax
  280.    push  bx
  281.    push  cx
  282.    push  dx
  283.    push  si
  284.    push  di
  285.    push  ds
  286.    push  es
  287.  
  288.    mov   ax,SEG @Data             { load turbo pascal ds }
  289.    mov   ds,ax                    { and set ds }
  290.  
  291.    call  NewComIntSupport;
  292.  
  293.    pop   es
  294.    pop   ds
  295.    pop   di
  296.    pop   si
  297.    pop   dx
  298.    pop   cx
  299.    pop   bx
  300.    pop   ax
  301.  
  302.    iret                           { Bye, bye }
  303.   End;
  304.  
  305.   Procedure CloseCom;
  306.   Begin
  307.     If (AktivePort  <> NoCom) and
  308.        (ComPortAddr <> $FFFF) and
  309.        (ComIntMasks[AktivePort] <> $FF) Then
  310.       Begin
  311.         Inline($FA);
  312.         Port[ComPortAddr+MCR] := 0;
  313.         Port[IMR8259] := Port[IMR8259] or (Not ComIntMasks[AktivePort]);
  314.         Port[ComPortAddr+IER] := 0;
  315.         ClearPendingInterrupts;
  316.         SetIntVec(ComIntVecs[AktivePort],OldComIntVec);
  317.         ComPortAddr := $FFFF;
  318.         AktivePort  := NoCom;
  319.         Inline($FB);
  320.       End;
  321.   End;
  322.  
  323.   Function OpenCom(ComPort    : ComPortType; Baudrate   : ComBaudType;
  324.                    Data       : ComBitsType; Parity     : ComDataType;
  325.                    StopBits   : ComStopType; ComMode    : ComModeType;
  326.                    MyBuffSize : ComBuffType) : Boolean;
  327.   Const BaudConst   : Array[ComBaudType] of Word =
  328.                       ($417,$300,$180,$C0,$60,$30,$18,$0C,$06,$03,$02,$01);
  329.         ParityConst : Array[ComDataType] of Byte =
  330.                       ($38,$08,$28,$18,$00);
  331.         BitsConst   : Array[ComBitsType] of Byte =
  332.                       ($00,$01,$02,$03);
  333.         StopConst   : Array[ComStopType] of Byte =
  334.                       ($00,$04);
  335.         ModeConst   : Array[ComModeType] of Byte =
  336.                       ($06,$06,$07,$47,$87,$C7);
  337.   Var   NewBuffSize : Word;
  338.   Begin
  339.     OpenCom := False;
  340.     If (ComPort              <> NoCom) and
  341.        (ComAddrArr[ComPort]  <> $FFFF) and
  342.        (ComIntMasks[ComPort] <> $FF) Then           { all values are correct }
  343.       Begin
  344.         Port[ComAddrArr[ComPort]+IER] := $F0;       { disable interrupts }
  345.         If Port[ComAddrArr[ComPort]+IER] = 0 Then
  346.           Begin                                      { new port is valid }
  347.             CloseCom;                                    { close old port }
  348.             If (Buffer <> NIL) Then
  349.               FreeMem(Buffer,BufferSize);                { free mem of old buffer }
  350.             NewBuffSize := BuffSizeArr[MyBuffSize];      { calculate new buffer size }
  351.             GetMem(Buffer,NewBuffSize);                  { allocate new buffer memory }
  352.             BufferSize := NewBuffSize;                   { set new buffer size }
  353.             Top    := 0;
  354.             Bottom := 0;                                 { initialize ringbuffer }
  355.             ComPortAddr := ComAddrArr[ComPort];          { set com port address }
  356.             AktivePort  := ComPort;                      { keep aktive port in mind }
  357.             Inline($FA);                                 { STI }
  358.             Port[ComPortAddr+IER] := 0;                  { disable all interrupts }
  359.             ClearPendingInterrupts;                      { clear all interrupts }
  360.             GetIntVec(ComIntVecs[ComPort],OldComIntVec); { get old interrupt vector }
  361.             SetIntVec(ComIntVecs[ComPort],@NewComInt);   { install new handler }
  362.             Port[ComPortAddr+IIR] := ModeConst[ComMode]; { set FIFO Mode }
  363.             Port[ComPortAddr+LCR] := $80;                { divisor latch access enable }
  364.             Port[ComPortAddr+DLH] := Hi(BaudConst[Baudrate]);
  365.             Port[ComPortAddr+DLL] := Lo(BaudConst[Baudrate]); { set baud rate }
  366.             Port[ComPortAddr+LCR] := ($00 or ParityConst[Parity]
  367.                                           or BitsConst[Data]
  368.                                           or StopConst[StopBits]);
  369.             Port[ComPortAddr+MCR] := $0B;                { set RTS,DTR,OUT2 }
  370.             Port[ComPortAddr+IER] := $01;                { enable interrupt }
  371.             Port[IMR8259] := Port[IMR8259] and ComIntMasks[ComPort];
  372.             Inline($FB);                                 { STI }
  373.             OpenCom := True;
  374.           End;
  375.       End;
  376.   End;
  377.  
  378.   Function SetUserComPort(ComBaseAddr : Word; IrqNr : Byte) : Boolean;
  379.   Const IrqMasks : Array[0..7] of Byte = ($01,$02,$04,$08,$10,$20,$40,$80);
  380.   Begin
  381.     If IrqNr IN [2,3,4,5,7] Then
  382.       Begin
  383.         ComIntVecs[UserCom]  := IrqNr + 8;
  384.         ComIntMasks[UserCom] := Not IrqMasks[IrqNr];
  385.         ComAddrArr[UserCom]  := ComBaseAddr;
  386.         SetUserComPort := True;
  387.       End
  388.     Else SetUserComPort := False;
  389.   End;
  390.  
  391.   Procedure SetHandShake(MyHandShake : Word);
  392.   Begin
  393.     HandShake := HandShake and $8000;
  394.     HandShake := HandShake or  (MyHandShake and (XON or CTS or DSR));
  395.   End;
  396.  
  397. End.