home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / ASYINL00.ZIP / ASYINL00.PAS
Encoding:
Pascal/Delphi Source File  |  1986-05-28  |  25.3 KB  |  659 lines

  1. {$K-}
  2. {$R-}
  3. Program NewAsyInterrupt ;
  4.  
  5. (*****************************************************************************
  6.  
  7.    First Release : March 10, 1986 by Gene Harris
  8.  
  9.    This program is designed to allow your PC, XT, AT or jr to have access to
  10.    a full support RS-232 set of routines written in Turbo Pascal.  The down
  11.    load archive files should contain two versions of this program.  The first
  12.    program is NewAsyInterrupt (this routine).  This program is written com-
  13.    pletely in Turbo Pascal.  I suspect it will only handle baud rates of about
  14.    2400.  It has only been tested to 1200 baud.
  15.  
  16.    The second routine is AsyInlInterrupt.  The second program has parts of
  17.    the interrupt service routine coded in inline assembler code.  The source
  18.    code for the interrupt service routines is included as comments.  The second
  19.    version has been tested to 4800 baud and will probably handle 9600 baud.
  20.  
  21.    Both routines have been tested on an IBM PCjr equipped with an NEC V20,
  22.    an XT clone running at six and eight MHz and an 8 MHz PC AT clone
  23.    successfully.  The OPENCOM routine must be changed to run with a jr.
  24.    Appropriate changes and intructions for implementing these changes is
  25.    included as comments.
  26.  
  27.    This code is copyrighted by M. Eugene Harris, Jr.  It is released to the
  28.    public domain, and may not be used for commercial gain.  The program is
  29.    user supported, and updates may be obtained from Remark BBS, in Oklahoma
  30.    City 405 728-2463.
  31.  
  32.    A 3rd version of the program will be released in April which will
  33.    automatically support XON/XOFF from the interrupt routine, as well as
  34.    incorporate several enhanced string instructions.  The program will also
  35.    support the Intel 80188 and NEC-V20.
  36.  
  37.  *****************************************************************************
  38.  
  39.    Routines included in this code:
  40.  
  41.    OpenCom (icomport,ibaudrate,idatabits,istopbits:integer;
  42.                 iparity:char) ;
  43.  
  44.    icomport : 1 or 2 only, no other ports supported.
  45.  
  46.    ibaudrate : 110, 150, 300, 600, 1200, 2400, 4800, 9600 baud supported.
  47.  
  48.    idatabits : 5, 6, 7, 8 data bits supported.
  49.  
  50.    istopbits : 1 or 2 stopbits supported.
  51.  
  52.    iparity : 'E'ven, 'O'dd, 'N'one, 'M'ark, 'S'pace are supported.
  53.  
  54.    Purpose of the routine: User supplied communication port values are
  55.                            converted to the proper set values used by
  56.                            the asynch routines.  Sets are used internally
  57.                            to avoid var conflicts and improve speed.
  58.                            The routine returns an OpenError = TRUE if
  59.                            the specified COM port does not exist.  Therefore,
  60.                            the user code needs to check OpenError before
  61.                            preceding to the next logical phase.
  62.  
  63.  *****************************************************************************
  64.  
  65.    Break - No Parameters.
  66.  
  67.    Purpose : drop DTR to effectively hang up the modem.
  68.  
  69.  *****************************************************************************
  70.  
  71.    Purge - No Parameters.
  72.  
  73.    Purpose : Purge the circular queues.
  74.              Reset the 8250 interrupt control register.
  75.  
  76.  *****************************************************************************
  77.  
  78.    RS232ChrAvailable : Boolean ;
  79.  
  80.    Purpose : Returns true if there are characters in the RS232 input queue
  81.              otherwise returns false.
  82.  
  83.  ****************************************************************************
  84.  
  85.    Function ReadChar : char ;
  86.  
  87.    Purpose : Returns the next character in the RS232 input buffer.  If no
  88.              characters are present, the routine returns a null byte.  The
  89.              RS232ChrAvailable routine should ALWAYS be checked before
  90.              trying to read a character, otherwise you will not be able
  91.              to tell if the null returned is correct.  The routine is
  92.              designed to be used in the following format:
  93.  
  94.              begin
  95.                 auxoutptr := ofs(readchar) ; { Install device driver }
  96.              ....
  97.              program body
  98.              ....
  99.                 if RS232ChrAvailable then read( aux, byte or char) ;
  100.              ....
  101.              rest of program
  102.  
  103.  ***************************************************************************
  104.  
  105.    Procedure WriteChar ;
  106.  
  107.    Purpose : Writes the next character into the RS232 character buffer.
  108.              The Asynch_Interrupt routine will output the characters in
  109.              the queue as THRE interrupts are generated by the 8250.
  110.              This routine is intended to be a device driver for the logical
  111.              devices USR or AUX.
  112.  
  113.              EXAMPLE :
  114.                     begin
  115.                        auxinptr := ofs(WriteChar) ; { Install Device Driver. }
  116.                        . . . .
  117.                        . . . .
  118.                        Write (aux, variable) ; { Put in RS232 output queue }
  119.  
  120.  ***************************************************************************
  121.  
  122.    Caveats : The Asynch_interrupt routine is written in pascal.  It is fast
  123.              enough to handle 1200 baud, and may handle 2400 baud.  You will
  124.              not get 4800 or 9600 baud support with this routine.  If you
  125.              need high speed support, use the companion routine ASYINL00.PAS
  126.              which handles 8250 interrupt processing with inline assembler
  127.              routines.
  128.  
  129.              The buffer input routine always checks that the variable
  130.              LSRstat is zero.  The LSRstat (Line Status Register) is utilized
  131.              to show buffer overflow on input.  Therefore, your program
  132.              must monitor LSRstat to determine if a buffer overflow has
  133.              occurred.  Bit 1 will be set if buffer overflow has occured.
  134.  
  135.              EXAMPLE :          if LSRstat <> 0 then begin
  136.                                    writeln('Line Status Error: ',LSRstat) ;
  137.  
  138.                                    . . . .
  139.                                    Handle LSR error condition. . .
  140.                                    . . . .
  141.  
  142.                                    { Reset LSRstat so that transmission can
  143.                                      begin again. Turn of bit 1. }
  144.  
  145.                                    LSRstat := LSRstat and $FD ;
  146.                                 end ;
  147.  
  148. *)
  149.  
  150. Type
  151.      tComPort =  (Com1, Com2);
  152.      tBaud = (b110, b150, b300, b600, b1200, b2400, b4800, b9600);
  153.      tParity = (pSpace, pOdd, pMark, pEven, pNone);
  154.      tDatabits = (d5, d6, d7, d8);
  155.      tStopbits = (s1, s2);
  156.  
  157.      tSaveVector = record     {  Saved Com interrupt vector          }
  158.        IP: integer;
  159.        CS: integer;
  160.      end;
  161.  
  162.      regpak = record case integer of
  163.                 1: (AX, BX, CX, DX, BP, SI, DI, DS, ES, FLAGS : integer) ;
  164.                 2: (al,ah, bl,bh, cl,ch, dl,dh : byte) ;
  165.               end;
  166.  
  167. Const
  168.      ourDS: integer = -1;    {  Will be init to contents of our DS
  169.                                   for later use in Interrupt routine  }
  170.  
  171.                               {  ASynch Interrupt Masks              }
  172.      imlist: array[Com1..Com2] of integer = ($EF, $F7);
  173.  
  174.                               {  ASynch hardware interrupt addresses }
  175.      ivlist: array[Com1..Com2] of integer = ($000C, $000B);
  176.  
  177.      PICCMD = $20;           {  8259 Priority Interrupt Controller  }
  178.      PICMSK = $21;           {  8259 Priority Interrupt Controller  }
  179.      EOI    = $20 ;          { End of Interrupt command for 8259.   }
  180.                              {  Asynch base port addresses are
  181.                                 in the ROM BIOS data area           }
  182.  
  183. var
  184.      ComBaseAddr: array[Com1..Com2] of integer Absolute $0040:$0000;
  185.  
  186. {
  187.     Define a ring buffer for Asynch_Interrupt to write into
  188.     and ReadCom to read from.
  189. }
  190.      Input_Ring_Buffer : array[0..2048] of char;
  191.      Input_Read_Ptr,             {  Index which ReadCom will next read from.   }
  192.      Input_Write_Ptr : integer ; {  Index which Asynch_Interrupt will next     }
  193.                                 {  write into. If readptr=writptr then        }
  194.                                 {  the buffer is empty.                       }
  195.  
  196.      OutPut_Ring_Buffer : array[0..2048] of char ;
  197.      OutPut_Read_Ptr,            {  Index which WriteCom will next input to.   }
  198.      OutPut_Write_Ptr : integer ;{  Index which Asynch_Interrupt will next     }
  199.                                 {  read from.  If readptr=writptr then the    }
  200.                                 {  buffer is full.                            }
  201.  
  202.      LSRstat,                           {  Line Status Reg at interrupt        }
  203.      MSRstat       : byte ;             {  Modem Status Reg at interrupt.      }
  204.      ComSaveVec    : tSaveVector ;      {  saved Async Interrupt vector        }
  205.      ComBase       : integer ;          {  Opened Com port base address        }
  206.      ActiveComPort : tComPort ;         {  Opened Com                          }
  207.      imvalue       : integer ;          {  Interrupt Mask value in use         }
  208.      IERMask       : byte ;
  209.  
  210.     { Define Equivalent Port Address Registers. }
  211.  
  212.      RBR_Port,
  213.      THR_Port,
  214.      IER_Port,
  215.      IIR_Port,
  216.      LCR_Port,
  217.      MCR_Port,
  218.      LSR_Port,
  219.      MSR_Port,
  220.      DLL_Port,
  221.      DLM_Port      : integer ;
  222.  
  223.     { Define Variables needed by Asynch_Interrupts procedure. }
  224.  
  225.      IIRreg,
  226.      Int_Type          : byte ;
  227.      Temp              : integer ;
  228.      OpenError         : boolean ;
  229.      Max_output_buffer,
  230.      Max_input_buffer  : integer ;
  231.  
  232. Procedure InstallInterrupt(IntVect: integer;
  233.                         Var SaveVector: tSaveVector);
  234. Var
  235.     dosregs: regpak ;
  236.  
  237. Begin
  238.   inline($FA);                        {  cli        disable interrupts       }
  239.  
  240.   With dosregs Do Begin
  241.     ds := SaveVector.CS;
  242.     dx := SaveVector.IP;
  243.     ah := $25 ;
  244.     al := IntVect ;
  245.     MsDos(dosregs);                   {  DOS function 25 - set vector        }
  246.   End;
  247.   inline($FB);                        {  sti        re-enable ints           }
  248. End;
  249.  
  250. {********************************************************************}
  251. {                                                                    }
  252. {       This routine gets control upon an Asynch Interrupt           }
  253. {       We service all four interrupt types generated by the         }
  254. {       INS8250 chip:                                                }
  255. {                    1. Received character error or break.           }
  256. {                    2. Received data ready.                         }
  257. {                    3. Transmit Hold Register Empty.                }
  258. {                    4. Modem Status Change                          }
  259. {                                                                    }
  260. {       In addition, circular queues are used for transmitting       }
  261. {       and receiveing data from the COM1 port.  These queues        }
  262. {       can optionally be turned off if buffer overflow is           }
  263. {       detected.                                                    }
  264. {                                                                    }
  265. {********************************************************************}
  266.  
  267. Procedure asynch_interrupt ;
  268.  
  269. begin
  270.  
  271. Inline(
  272.   $50                         {push ax}
  273.   /$53                        {push bx}
  274.   /$51                        {push cx}
  275.   /$52                        {push dx}
  276.   /$57                        {push di}
  277.   /$56                        {push si}
  278.   /$06                        {push es}
  279.   /$1E                        {push ds}
  280.                               {;}
  281.                               {; get the correct data segment}
  282.                               {;}
  283.   /$2E/$A1/>OURDS             {cs: mov ax, [>ourDS]}
  284.   /$8E/$D8                    {mov ds, ax}
  285.                               {;}
  286.                               {begin:}
  287.                               {;}
  288.   /$8B/$16/>IIR_PORT          {mov dx [>IIR_Port]}
  289.   /$EC                        {in al, dx}
  290.   /$A2/>IIRREG                {mov [>IIRreg], al}
  291.                               {;}
  292.   /$A0/>IIRREG                {mov al, [>IIRreg]}
  293.   /$A8/$01                    {test al, $01}
  294.   /$74/$03                    {jz cont}
  295.   /$E9/$9D/$00                {jmp noint}
  296.                               {;}
  297.                               {cont:}
  298.                               {;}
  299.   /$24/$06                    {and al, $06}
  300.   /$A2/>INT_TYPE              {mov [>int_type], al}
  301.                               {;}
  302.   /$3C/$04                    {cmp al, $04}
  303.   /$75/$39                    {jnz int0}
  304.                               {;}
  305.   /$A1/>INPUT_WRITE_PTR       {mov ax, [>input_write_ptr]}
  306.   /$40                        {inc ax}
  307.   /$31/$D2                    {xor dx, dx}
  308.   /$F7/$36/>MAX_INPUT_BUFFER  {div word ptr [>Max_input_buffer]}
  309.   /$89/$16/>TEMP              {mov [>temp], dx}
  310.                               {;}
  311.   /$80/$3E/>LSRSTAT/$00       {cmp byte ptr [>lsrstat], $00}
  312.   /$75/$D0                    {jnz begin}
  313.                               {;}
  314.   /$39/$16/>INPUT_READ_PTR    {cmp word ptr [>input_read_ptr], dx}
  315.   /$74/$16                    {jz ovrflow}
  316.                               {;}
  317.   /$8B/$16/>RBR_PORT          {mov dx, [>rbr_port]}
  318.   /$EC                        {in al, dx}
  319.   /$8B/$1E/>INPUT_WRITE_PTR   {mov bx, [>input_write_ptr]}
  320.   /$88/$87/>INPUT_RING_BUFFER {mov [>input_ring_buffer][bx], al}
  321.                               {;}
  322.   /$A1/>TEMP                  {mov ax, [>temp]}
  323.   /$A3/>INPUT_WRITE_PTR       {mov [>input_write_ptr], ax}
  324.   /$E9/$B4/$FF                {jmp near begin}
  325.                               {;}
  326.                               {ovrflow:}
  327.                               {;}
  328.   /$80/$0E/>LSRSTAT/$02       {or byte ptr [>lsrstat], $02}
  329.   /$E9/$AC/$FF                {jmp near begin}
  330.                               {;}
  331.                               {int0:}
  332.                               {;}
  333.   /$80/$3E/>INT_TYPE/$00      {cmp byte ptr [>int_type], $00}
  334.   /$75/$08                    {jnz int2}
  335.   /$8B/$16/>MSR_PORT          {mov dx, [>msr_port]}
  336.   /$EC                        {in al, dx}
  337.   /$A2/>MSRSTAT               {mov [>msrstat], al}
  338.                               {;}
  339.                               {int2:}
  340.                               {;}
  341.   /$80/$3E/>INT_TYPE/$02      {cmp byte ptr [>int_type], $02}
  342.   /$75/$31                    {jnz int6}
  343.                               {;}
  344.   /$A1/>OUTPUT_WRITE_PTR      {mov ax, [>output_write_ptr]}
  345.   /$3B/$06/>OUTPUT_READ_PTR   {cmp ax, [>output_read_ptr]}
  346.   /$75/$0B                    {jnz wrtchr}
  347.                               {;}
  348.   /$8B/$16/>IER_PORT          {mov dx, [>ier_port]}
  349.   /$EC                        {in al, dx}
  350.   /$24/$FD                    {and al, $fd}
  351.   /$EE                        {out dx, al}
  352.   /$E9/$82/$FF                {jmp near begin}
  353.                               {;}
  354.                               {wrtchr:}
  355.   /$8B/$1E/>OUTPUT_WRITE_PTR  {mov bx, [>output_write_ptr]}
  356.   /$8A/$87/>OUTPUT_RING_BUFFER{mov al, [>output_ring_buffer][bx]}
  357.   /$8B/$16/>THR_PORT          {mov dx, [>thr_port]}
  358.   /$EE                        {out dx, al}
  359.                               {;}
  360.   /$43                        {inc bx}
  361.   /$89/$D8                    {mov ax, bx}
  362.   /$31/$D2                    {xor dx, dx}
  363.   /$F7/$36/>MAX_OUTPUT_BUFFER {div word ptr [>max_output_buffer]}
  364.   /$89/$16/>OUTPUT_WRITE_PTR  {mov [>output_write_ptr], dx}
  365.   /$E9/$65/$FF                {jmp near begin}
  366.                               {;}
  367.                               {int6:}
  368.                               {;}
  369.   /$80/$3E/>INT_TYPE/$06      {cmp byte ptr [>int_type], $06}
  370.   /$75/$0A                    {jnz alldone}
  371.                               {;}
  372.   /$8B/$16/>LSR_PORT          {mov dx, [>lsr_port]}
  373.   /$EC                        {in al, dx}
  374.   /$24/$1E                    {and al, $1e}
  375.   /$A2/>LSRSTAT               {mov [>lsrstat], al}
  376.                               {;}
  377.                               {alldone:}
  378.                               {;}
  379.   /$E9/$51/$FF                {jmp near begin}
  380.                               {;}
  381.                               {noint:}
  382.                               {;}
  383.   /$B0/$20                    {mov al, $20}
  384.   /$E6/$20                    {out $20, al}
  385.   /$1F                        {pop ds}
  386.   /$07                        {pop es}
  387.   /$5E                        {pop si}
  388.   /$5F                        {pop di}
  389.   /$5A                        {pop dx}
  390.   /$59                        {pop cx}
  391.   /$5B                        {pop bx}
  392.   /$58                        {pop ax}
  393.   /$89/$EC                    {mov sp, bp}
  394.   /$5D                        {pop bp}
  395.   /$FB                        {sti}
  396.   /$CF                        {iret}
  397. );
  398.  
  399. End;
  400.  
  401. {                     Open COM1 or COM2, a la Basic                  }
  402.  
  403. Procedure OpenCom(ComPort, Baud, Databits, Stopbits : integer ;
  404.                   Parity : char ) ;
  405.  
  406. Const
  407.  
  408. {  Define addresses for the various Async card registers.           }
  409.  
  410.      RBR = $00;         { xF8   Receive Buffer Register             }
  411.      THR = $00;         { xF8   Transmitter Holding Register        }
  412.      IER = $01;         { xF9   Interrupt Enable Register           }
  413.      IIR = $02;         { xFA   Interrupt Identification Register   }
  414.      LCR = $03;         { xFB   Line Control Register               }
  415.      MCR = $04;         { xFC   Modem Control Register              }
  416.      LSR = $05;         { xFD   Line Status Register                }
  417.      MSR = $06;         { xFE   Modem Status Register               }
  418.      DLL = $00;         { xF8   Divisor Latch Least Significant     }
  419.      DLM = $01;         { xF9   Divisor Latch Most  Significant     }
  420.  
  421.       baudcode: array[b110..b9600] of integer =
  422.                            ($417, $300, $180, $C0, $60, $30, $18, $0C);
  423.       paritycode: array[pSpace..pNone] of byte =
  424.                                              ($38, $08, $28, $18, $00);
  425.       databitscode: array[d5..d8] of byte = ($00, $01, $02, $03);
  426.       stopbitscode: array[s1..s2] of byte = ($00, $04);
  427.  
  428. Var
  429.       LCRreg,
  430.       errclear    : byte ;
  431.       baudindex   : tbaud ;
  432. Begin
  433.  
  434.   OpenError := FALSE ;            {  Default no error on open.           }
  435.                                   {  Init the Const "ourDS" for use by
  436.                                      the Async_Interrupt routine         }
  437.   ourDS := DSEG ;
  438.                                   {  Swap Com interrupt vector           }
  439.   With ComSaveVec Do Begin
  440.     CS := CSEG;
  441.     IP := OFS(Asynch_Interrupt);
  442.   End;
  443.  
  444.   if Comport = 2 then ActiveComPort := Com2 else ActiveComPort := Com1 ;
  445.  
  446.   InstallInterrupt(ivlist[ActiveComPort], ComSaveVec);
  447.  
  448.   imvalue := imlist[ActiveComPort] ;      {  Select Interrupt Mask val }
  449.  
  450.   ComBase := ComBaseAddr[ActiveComPort];  {  Select Input Port         }
  451.   if ComBase = 0 then OpenError := TRUE ;
  452.  
  453.   Input_Read_Ptr   := 0 ;                 {  Init buffer pointers      }
  454.   Input_Write_Ptr  := 0 ;
  455.   OutPut_Read_Ptr  := 0 ;
  456.   OutPut_Write_Ptr := 0 ;
  457.  
  458.   RBR_Port := RBR + ComBase ;
  459.   THR_Port := THR + ComBase ;
  460.   IER_POrt := IER + ComBase ;
  461.   IIR_Port := IIR + ComBase ;
  462.   LCR_Port := LCR + ComBase ;
  463.   MCR_Port := MCR + ComBase ;
  464.   LSR_Port := LSR + ComBase ;
  465.   MSR_Port := MSR + ComBase ;
  466.   DLL_Port := DLL + ComBase ;
  467.   DLM_Port := DLM + ComBase ;
  468.  
  469.   inline ($FA) ;
  470.   {
  471.      Reset any pending error conditions and turn off DLAB.
  472.   }
  473.   PORT[PICMSK] := PORT[PICMSK] or ($FF - imvalue);
  474.   PORT[IER_Port] := 0 ;   {  Disable Data Avail interrupt        }
  475.   Port[MCR_Port] := 0 ;
  476.   Port[LCR_Port] := Port[LCR_Port] and $7F ;
  477.   errclear := PORT[LSR_Port] ;
  478.   errclear := PORT[RBR_Port] ;
  479.   errclear := PORT[MSR_Port] ;
  480.  
  481.   {
  482.           Set Baud Rate Divisor Registers and the Line Control Register
  483.   }
  484.   LCRreg := $80;               {  Set Divisor Latch Access Bit in LCR }
  485.  
  486.   case Parity of
  487.    'S' : LCRreg := LCRreg or paritycode[pSpace] ;
  488.    'O' : LCRreg := LCRreg or paritycode[pOdd]   ;
  489.    'M' : LCRreg := LCRreg or paritycode[pMark]  ;
  490.    'E' : LCRreg := LCRreg or paritycode[pEven]  ;
  491.    'N' : LCRreg := LCRreg or paritycode[pNone]  ;
  492.    else LCRreg  := LCRreg or paritycode[pNone]   ;
  493.   end ; { case }
  494.  
  495.   case databits of
  496.     5 : LCRreg := LCRreg or databitscode[d5] ;
  497.     6 : LCRreg := LCRreg or databitscode[d6] ;
  498.     7 : LCRreg := LCRreg or databitscode[d7] ;
  499.     8 : LCRreg := LCRreg or databitscode[d8] ;
  500.     else LCRreg := LCRreg or databitscode[d8] ;
  501.   end ; { case }
  502.  
  503.   case stopbits of
  504.     1 : LCRreg := LCRreg or stopbitscode[s1] ;
  505.     2 : LCRreg := LCRreg or stopbitscode[s2] ;
  506.     else LCRreg := LCRreg or stopbitscode[s1] ;
  507.   end ; { case }
  508.  
  509.   PORT[LCR_Port] := LCRreg;     {  Set Parity, Data and Stop Bits
  510.                                    and set DLAB                          }
  511.   baudindex := b1200 ;
  512.   if baud = 110 then baudindex := b110 ;
  513.   if baud = 150 then baudindex := b150 ;
  514.   if baud = 300 then baudindex := b300 ;
  515.   if baud = 600 then baudindex := b600 ;
  516.   if baud = 1200 then baudindex := b1200 ;
  517.   if baud = 2400 then baudindex := b2400 ;
  518.   if baud = 4800 then baudindex := b4800 ;
  519.   if baud = 9600 then baudindex := b9600 ;
  520.  
  521.   PORT[DLM_Port] := Hi(baudcode[Baudindex]);   {  Set Baud rate               }
  522.   PORT[DLL_Port] := Lo(baudcode[Baudindex]);   {  Set Baud rate               }
  523.   PORT[LCR_Port] := LCRreg and $7F ;      {  Reset DLAB                  }
  524.  
  525.   PORT[PICMSK] := PORT[PICMSK] and imvalue;  {  Enable ASynch Int         }
  526.   PORT[IER_Port] := $0F ;               {  Enable some interrupts     }
  527.                                { Note: OUT2, despite documentation,
  528.                                  MUST be ON, to enable interrupts     }
  529.   PORT[MCR_Port] := $0F;                 {  Set RTS, DTR, OUT1, OUT2 }
  530.   inline ($FB) ;
  531.   PORT[PICCMD] := EOI ;
  532.   LSRstat := 0 ;                        {  Reset LSR status          }
  533.   MSRstat := 0 ;
  534. End;
  535.  
  536.  
  537. {                 Close any initialized COM                          }
  538.  
  539. Procedure CloseCom;
  540. Begin
  541.                               {  Disable Async interrupt             }
  542.   PORT[PICMSK] := PORT[PICMSK] or ($FF - imvalue);
  543.   PORT[IER_Port] := 0 ;   {  Disable Data Avail interrupt        }
  544.   Port[MCR_Port] := 0 ;
  545. End;
  546.  
  547. Procedure Break ;
  548.  
  549. var
  550.     LCRreg,
  551.     DropDTR   : byte ;
  552.  
  553. begin
  554.    LCRreg := Port[LCR_Port] ;
  555.    DropDTR := (LCRreg and $7F) or $40 ;
  556.    Port[LCR_Port] := DropDTR ;
  557.    Delay (600) ;
  558.    Port[LCR_Port] := LCRreg ;
  559. end ;
  560.  
  561. Procedure Purge ;
  562.  
  563. { Purpose : Purge all circular queues. }
  564.  
  565. begin
  566.   Input_Read_Ptr   := 0;                  {  Init buffer pointers      }
  567.   Input_Write_Ptr  := 0;
  568.   OutPut_Read_Ptr  := 0 ;
  569.   OutPut_Write_Ptr := 0 ;
  570.  
  571. { Reset 8250 Interrupt Enable Registers. }
  572.  
  573.   Port [IER_Port] := Port [IER_Port] and $0F ;
  574. end ;
  575.  
  576. Function  ReadChar : char ;
  577.  
  578. {
  579.   This routine is intended to function as an AUX or USR logical character
  580.   input device driver.  Usage is AuxInPtr := ofs(Readchar) followed by
  581.   the actual read operation read(AUX, var).
  582. }
  583.  
  584. Begin
  585.     if Input_Read_Ptr = Input_Write_Ptr then ReadChar := chr(0)
  586.     else begin
  587.       ReadChar := Input_Ring_Buffer[Input_Read_Ptr];
  588.       inline ($FA) ;
  589.       Input_Read_Ptr := (Input_Read_Ptr + 1) mod Max_Input_Buffer ;
  590.       inline ($FB) ;
  591.     end
  592. End;
  593.  
  594. Function RS232ChrAvailable : boolean ;
  595.  
  596. {
  597.   This routine should be checked before reading a character from the RS232
  598.   port, otherwise garbage will be returned and the buffer count messed up.
  599. }
  600.  
  601. begin
  602.   If Input_Read_Ptr = Input_Write_Ptr then RS232ChrAvailable := FALSE
  603.     else RS232ChrAvailable := TRUE ;
  604. end ;
  605.  
  606. Procedure WriteChar (ch:char) ;
  607.  
  608. {
  609.   This is the corresponding AuxOutPtr routine for use with write (aux, var).
  610. }
  611.  
  612. begin
  613.   OutPut_Ring_Buffer[OutPut_Read_Ptr] := ch ;
  614.   inline ($FA) ;
  615.   OutPut_Read_Ptr := (Output_Read_Ptr + 1) mod Max_Output_Buffer ;
  616.   inline ($FB) ;
  617.   if (IERMask and $02) = 0 then Port [IER_Port] := (Port [IER_Port] or $02) ;
  618. end ;
  619.  
  620. {=============================================================================
  621.   The following program is a VERY dumb glass CRT example program on how to use
  622.   the asynchronos routines.  I hope this routine is of some help.
  623.  =============================================================================}
  624.  
  625. label quit ;
  626.  
  627. var
  628.   ser_char,
  629.   key_char       :char ;
  630.  
  631. begin
  632.   Max_Output_Buffer := 1024 ;
  633.   Max_Input_Buffer := 1024 ;
  634.   AUXINPTR := ofs(Readchar) ;           { Assign aux input device driver      }
  635.   AUXOUTPTR := ofs(Writechar) ;         { Assign aux output device driver     }
  636.   OPENCOM (1,1200,8,1,'N') ;            { Open the communications port.       }
  637.   if OpenError then goto quit ;
  638.   writeln ('Port Opened') ;
  639.   key_char := #32 ;
  640.   repeat
  641.     if keypressed then begin            { Correct procedure for reading the   }
  642.       read (kbd, key_char) ;            { keyboard and sending a character    }
  643.       if key_char <> #27 then write( aux, key_char) ;
  644.       end ;
  645.     if RS232ChrAvailable then begin     { Correct procedure to read the RS232 }
  646.          read(aux, ser_char) ;          { communications port.                }
  647.          write (ser_char)
  648.        end ;
  649.     if LSRstat <> 0 then begin          { Check LSRstat byte for overflow.    }
  650.        writeln('Line Status Error: ',LSRstat) ;
  651.        LSRstat := 0 ;
  652.     end ;
  653.   until key_char = #27 ;
  654. quit :
  655.   Break ;
  656.   CloseCom ;
  657.  end. LCRreg or databitscode[d7] ;
  658.     8 : LCRreg := LCRreg or databitscode[d8] ;
  659.     else LCRreg :=