*/
Written some cool source code? Upload it to Programmer's Heaven.
*/

View \ASYNC2.PAS

DDPLUS 7.1 Turbo Pascal 7.0 Door Kit

Submitted By: WEBMASTER
Rating: starstarstarstar (Rate It)


{*--------------------------------------------------------------------------*}
{*                                                                          *}
{*  Status byte definition (C_Status):                                      *}
{*                                                                          *}
{*  7   6   5   4   3   2   1   0                                           *}
{*  |   |   |   |   |   |   |   |____ Input buffer empty                    *}
{*  |   |   |   |   |   |   |________ Input buffer full                     *}
{*  |   |   |   |   |   |____________ Output buffer empty                   *}
{*  |   |   |   |   |________________ Output buffer full                    *}
{*  |   |   |   |____________________ Input buffer overflow                 *}
{*  |   |   |________________________ Output buffer overflow                *}
{*  |   |____________________________ Hard handshake active (xmit stopped)  *}
{*  |________________________________ Soft handshake active (xmit stopped)  *}
{*                                                                          *}
{*  Control byte definition (C_Ctrl):                                       *}
{*                                                                          *}
{*  7   6   5   4   3   2   1   0                                           *}
{*  |   |   |   |   |   |   |   |____ Enable RTS handshake                  *}
{*  |   |   |   |   |   |   |________ Enable CTS handshake                  *}
{*  |   |   |   |   |   |____________ Enable software handshake             *}
{*  |   |   |   |   |________________                                       *}
{*  |   |   |   |____________________                                       *}
{*  |   |   |________________________                                       *}
{*  |   |____________________________                                       *}
{*  |________________________________                                       *}
{*                                                                          *}
{****************************************************************************}

{$R-,V-,B-,S-}

Unit ASYNC2;

INTERFACE

{----------------------------------------------------------------------------}

Const
  C_MinBaud = 300;
  C_MaxBaud = 115200;
  C_MaxPort = 4;
  C_MaxCom : byte = C_MaxPort;
  D_PortAddr : Array[1..C_MaxPort] Of Word = ($03F8,$02F8,$03E8,$02E8);
  D_PortInt  : Array[1..C_MaxPort] Of Byte = (4,3,4,3);

{----------------------------------------------------------------------------}

Type
  C_VectorArray  = Array[0..15] Of Pointer;
  C_PointerArray = Array[1..C_MaxPort]  Of Pointer;
  C_WordArray    = Array[1..C_MaxPort] Of Word;
  C_ByteArray    = Array[1..C_MaxPort] Of Byte;
  C_CharArray    = Array[1..C_MaxPort] Of Char;
  C_BooleanArray = Array[1..C_MaxPort] Of Boolean;

{----------------------------------------------------------------------------}

Var
  { Base port addresses & interrupt usage }
  C_PortAddr : Array[1..C_MaxPort] Of Word;
  C_PortInt  : Array[1..C_MaxPort] Of Byte;
  ComPort  : Byte;
  C_InBufPtr,C_OutBufPtr : C_PointerArray;    { Input/output buffer pointers }
  C_InHead,C_OutHead     : C_WordArray;       { Input/output head pointers }
  C_InTail,C_OutTail     : C_WordArray;       { Input/output tail pointers }
  C_InSize,C_OutSize     : C_WordArray;       { Input/output buffer sizes }
  C_RTSOn,C_RTSOff       : C_WordArray;       { RTS assert/drop buffer points }
  C_StartChar,C_StopChar : C_CharArray;       { Soft hndshake start/stop char }
  C_Status,C_Ctrl        : C_ByteArray;       { STATUS and CONTROL registers }
  C_XL3Ptr               : C_ByteArray;
  C_PortOpen             : C_BooleanArray;    { Port open/close flags }
  C_Temp                 : Word;              { Used for debugging }
  C_msrport              : word;
{ RTSOn,RTSOff           : Word;}             { RTS assert/drop buffer points }
  oldier,oldmcr          : byte;
  c_buffull              : c_wordarray;
  C_Cascade              : Byte;              { Flag set 0 normally }
  C_CascadeOK            : boolean;           { Flag if IRQ > 7 }

{----------------------------------------------------------------------------}

Function  ComReadCh(ComPort:Byte) : Char;
Function  ComReadChW(ComPort:Byte) : Char;
{ Procedure ComWriteCh(ComPort:Byte; Ch:Char); }
Procedure ComWriteChW(ComPort:Byte; Ch:Char);
Procedure SetDTR(ComPort:Byte; Assert:Boolean);
Procedure SetRTS(ComPort:Byte; Assert:Boolean);
{
Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
 }

Function  CTSStat(ComPort:Byte) : Boolean;
Function  RTSStat(ComPort:Byte) : Boolean;
Function  DSRStat(ComPort:Byte) : Boolean;
Function  RIStat(ComPort:Byte) : Boolean;
Function  DCDStat(ComPort:Byte) : Boolean;
Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);
Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);
Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);
Procedure ClearCom(ComPort:Byte; IO:Char);
Function  ComBufferLeft(ComPort:Byte; IO:Char) : Word;
Procedure ComWaitForClear(ComPort:Byte);
Procedure ComWrite(ComPort:Byte; St:String);
Procedure ComWriteln(ComPort:Byte; St:String);
Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);
Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean);
Function  ComExist(ComPort:Byte) : Boolean;
Function  ComTrueBaud(Baud:Longint) : Real;
Procedure ComParams(ComPort:Byte; Baud:LongInt; WordSize:Byte; Parity:Char; StopBits:Byte);
Function  OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word) : Boolean;
Procedure CloseCom(ComPort:Byte);
Procedure CloseAllComs;

{----------------------------------------------------------------------------}

IMPLEMENTATION

Uses DOS,CRT;

{$L SLASYNC.OBJ}

Const
  C_IER = 1;                           { 8250 register offsets }
  C_IIR = 2;
  C_LCR = 3;
  C_MCR = 4;
  C_LSR = 5;
  C_MSR = 6;
  C_SCR = 7;

Var
  C_OldINTVec : C_VectorArray;        { Storage for old hardware INT vectors }
  X : Byte;                            { Used by initialization code }

{****************************************************************************}
{*                                                                          *}
{*  Procedure INT_Handler; External;                                        *}
{*                                                                          *}
{*  Hardware interrupts 0-15 (vectors $08 - $0F,$70 - $77) are pointed to   *}
{*  this routine.  It is for internal use only and should NOT be called     *}
{*  directly.  Written in assembly language (see SLASYNC.ASM).              *}
{*                                                                          *}
{****************************************************************************}

Procedure INT_Handler; External;

{****************************************************************************}
{*                                                                          *}
{*  Procedure ComReadCh(ComPort:Byte) : Char; External;                     *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*                                                                          *}
{*  Returns character from input buffer of specified port.  If the buffer   *}
{*  is empty, the port # invalid or not opened, a Chr(0) is returned.       *}
{*  Written in assembly language for best possible speed (see ASYNC11.ASM)  *}
{*                                                                          *}
{****************************************************************************}

Function ComReadCh(ComPort:Byte) : Char; External;

{****************************************************************************}
{*                                                                          *}
{*  Function ComReadChW(ComPort:Byte) : Char; External;                     *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*                                                                          *}
{*  Works like ComReadCh, but will wait until at least 1 character is       *}
{*  present in the specified input buffer before exiting.  Thus, ComReadChW *}
{*  works much like the ReadKey predefined function.  Written in assembly   *}
{*  language to maximize performance (see ASYNC11.ASM)                      *}
{*                                                                          *}
{****************************************************************************}

Function ComReadChW(ComPort:Byte) : Char; External;

{****************************************************************************}
{*                                                                          *}
{*  Procedure ComWriteCh(ComPort:Byte; Ch:Char); External                   *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*  Ch:Char       ->  Character to send                                     *}
{*                                                                          *}
{*  Places the character [Ch] in the transmit buffer of the specified port. *}
{*  If the port specified is not open or nonexistent, or if the buffer is   *}
{*  filled, the character is discarded.  Written in assembly language to    *}
{*  maximize performance (see ASYNC11.ASM)                                  *}
{*                                                                          *}
{****************************************************************************}

Procedure ComWriteCh(ComPort:Byte; Ch:Char); External;

{****************************************************************************}
{*                                                                          *}
{*  Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;                 *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*  Ch:Char       ->  Character to send                                     *}
{*                                                                          *}
{*  Works as ComWriteCh, but will wait until at least 1 free position is    *}
{*  available in the output buffer before attempting to place the character *}
{*  [Ch] in it.  Allows the programmer to send characters without regard to *}
{*  available buffer space.  Written in assembly language to maximize       *}
{*  performance (see ASYNC11.ASM)                                           *}
{*                                                                          *}
{****************************************************************************}

Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;

{****************************************************************************}
{*                                                                          *}
{*  Procedure SetDTR(ComPort:Byte; Assert:Boolean);                         *}
{*                                                                          *}
{*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
{*                      Call ignored if out-of-range                        *}
{*  Assert:Boolean  ->  DTR assertion flag (TRUE to assert DTR)             *}
{*                                                                          *}
{*  Provides a means to control the port's DTR (Data Terminal Ready) signal *}
{*  line.  When [Assert] is TRUE, the DTR line is placed in the "active"    *}
{*  state, signalling to a remote system that the host is "on-line"         *}
{*  (although not nessesarily ready to receive data - see SetRTS).          *}
{*                                                                          *}
{****************************************************************************}

Procedure SetDTR(ComPort:Byte; Assert:Boolean);

Var
  P,X : Integer;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  P := C_PortAddr[ComPort];

  X := Port[P+C_MCR];
  If Assert Then
    X := X Or $01
  Else
    X := X And $FE;
  Port[P+C_MCR] := X;
End;

{****************************************************************************}
{*                                                                          *}
{*  Procedure SetRTS(ComPort:Byte; Assert:Boolean)                          *}
{*                                                                          *}
{*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
{*                      Call ignored if out-of-range                        *}
{*  Assert:Boolean  ->  RTS assertion flag (Set TRUE to assert RTS)         *}
{*                                                                          *}
{*  SetRTS allows a program to manually control the Request-To-Send (RTS)   *}
{*  signal line.  If RTS handshaking is disabled (see C_Ctrl definition     *}
{*  and the the SetRTSMode procedure), this procedure may be used.  SetRTS  *}
{*  should NOT be used if RTS handshaking is enabled.                       *}
{*                                                                          *}
{****************************************************************************}

Procedure SetRTS(ComPort:Byte; Assert:Boolean);

Var
  P,X : Integer;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  P := C_PortAddr[ComPort];

  X := Port[P+C_MCR];
  If Assert Then
    X := X Or $02
  Else
    X := X And $FD;
  Port[P+C_MCR] := X;
End;

{****************************************************************************}
{*                                                                          *}
{*  Procedure SetOUT1(ComPort:Byte; Assert:Boolean)                         *}
{*                                                                          *}
{*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
{*                      Call ignored if out-of-range                        *}
{*  Assert:Boolean  ->  OUT1 assertion flag (set TRUE to assert OUT1 line)  *}
{*                                                                          *}
{*  SetOUT1 is provided for reasons of completeness only, since the         *}
{*  standard PC/XT/AT configurations do not utilize this control signal.    *}
{*  If [Assert] is TRUE, the OUT1 signal line on the 8250 will be set to a  *}
{*  LOW logic level (inverted logic).  The OUT1 signal is present on pin 34 *}
{*  of the 8250 (but not on the port itself).                               *}
{*                                                                          *}
{****************************************************************************}
{
Procedure SetOUT1(ComPort:Byte; Assert:Boolean);

Var
  P,X : Integer;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  P := C_PortAddr[ComPort];

  X := Port[P+C_MCR];
  If Assert Then
    X := X Or $04
  Else
    X := X And $FB;
  Port[P+C_MCR] := X;
End;
 }

{****************************************************************************}
{*                                                                          *}
{*  Procedure SetOUT2(ComPort:Byte; Assert:Boolean)                         *}
{*                                                                          *}
{*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
{*                      Call ignored if out-of-range                        *}
{*  Assert:Boolean  ->  OUT2 assertion flag (set TRUE to assert OUT2 line)  *}
{*                                                                          *}
{*  The OUT2 signal line, although not available on the port itself, is     *}
{*  used to gate the 8250 <INTRPT> (interrupt) line and thus acts as a      *}
{*  redundant means of controlling 8250 interrupts.  When [Assert] is TRUE, *}
{*  the /OUT2 line on the 8250 is lowered, which allows the passage of the  *}
{*  <INTRPT> signal through a gating arrangement, allowing the 8250 to      *}
{*  generate interrupts.  Int's can be disabled bu unASSERTing this line.   *}
{*                                                                          *}
{****************************************************************************}
{
Procedure SetOUT2(ComPort:Byte; Assert:Boolean);

Var
  P,X : Integer;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  P := C_PortAddr[ComPort];

  X := Port[P+C_MCR];
  If Assert Then
    X := X Or $08
  Else
    X := X And $F7;
  Port[P+C_MCR] := X;
End;
 }

{****************************************************************************}
{*                                                                          *}
{*  Function CTSStat(ComPort:Byte) : Boolean                                *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*                    Call ignored if out-of-range                          *}
{*  Returns status of Clear-To-Send line (TRUE if CTS asserted)             *}
{*                                                                          *}
{*  CTSStat provides a means to interrogate the Clear-To-Send hardware      *}
{*  handshaking line.  In a typical arrangement, when CTS is asserted, this *}
{*  signals the host (this computer) that the receiver is ready to accept   *}
{*  data (in contrast to the DSR line, which signals the receiver as        *}
{*  on-line but not nessesarily ready to accept data).  An automated mech-  *}
{*  ansim (see CTSMode) is provided to do this, but in cases where this is  *}
{*  undesirable or inappropriate, the CTSStat function can be used to int-  *}
{*  terrogate this line manually.                                           *}
{*                                                                          *}
{****************************************************************************}

Function CTSStat(ComPort:Byte) : Boolean;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then
    CTSStat := False
  Else
    CTSStat := (Port[C_PortAddr[ComPort]+C_MSR] And $10 <> $10);
End;

{****************************************************************************}
{*                                                                          *}
{*  Function RTSStat(ComPort:Byte) : Boolean                                *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*                    Call ignored if out-of-range                          *}
{*  Returns status of Ready-To-Send line (TRUE if RTS asserted)             *}
{*                                                                          *}
{****************************************************************************}


Function RTSStat(ComPort:Byte) : Boolean;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then
    RTSStat := False
  Else
    RTSStat := (Port[C_PortAddr[ComPort]+C_LSR] And $20 <> $20);
End;

{****************************************************************************}
{*                                                                          *}
{*  Function DSRStat(ComPort:Byte) : Boolean                                *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*                    Call ignored if out-of-range                          *}
{*  Returns status of Data Set Ready (DSR) signal line.                     *}
{*                                                                          *}
{*  The Data Set Ready (DSR) line is typically used by a remote station     *}
{*  to signal the host system that it is on-line (although not nessesarily  *}
{*  ready to receive data yet - see CTSStat).  A remote station has the DSR *}
{*  line asserted if DSRStat returns TRUE.                                  *}
{*                                                                          *}
{****************************************************************************}

Function DSRStat(ComPort:Byte) : Boolean;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then
    DSRStat := False
  Else
    DSRStat := (Port[C_PortAddr[ComPort]+C_MSR] And $20) > 0;
End;

{****************************************************************************}
{*                                                                          *}
{*  Function RIStat(ComPort:Byte) : Boolean                                 *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*                    Call ignored if out-of-range                          *}
{*                                                                          *}
{*  Returns the status of the Ring Indicator (RI) line.  This line is       *}
{*  typically used only by modems, and indicates that the modem has detect- *}
{*  ed an incoming call if RIStat returns TRUE.                             *}
{*                                                                          *}
{****************************************************************************}

Function RIStat(ComPort:Byte) : Boolean;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then
    RIStat := False
  Else
    RIStat := (Port[C_PortAddr[ComPort]+C_MSR] And $40) > 0;
End;

{****************************************************************************}
{*                                                                          *}
{*  Function DCDStat(ComPort:Byte) : Boolean                                *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
{*                    Call ignored if out-of-range                          *}
{*                                                                          *}
{*  Returns the status of the Data Carrier Detect (DCD) line from the rem-  *}
{*  ote device, typically a modem.  When asserted (DCDStat returns TRUE),   *}
{*  the modem indicates that it has successfuly linked with another modem   *}
{*  device at another site.                                                 *}
{*                                                                          *}
{****************************************************************************}

Function DCDStat(ComPort:Byte) : Boolean;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Then
    DCDStat := False
  Else
    DCDStat := (Port[C_PortAddr[ComPort]+C_MSR] And $80) > 0;
End;

{****************************************************************************}
{*                                                                          *}
{*  Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word)     *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
{*                    Request ignored if out of range or unopened.          *}
{*  Mode:Boolean  ->  TRUE to enable automatic RTS handshake                *}
{*  RTSOn:Word    ->  Buffer-usage point at which the RTS line is asserted  *}
{*  RTSOff:Word   ->  Buffer-usage point at which the RTS line is dropped   *}
{*                                                                          *}
{*  SetRTSMode enables or disables automated RTS handshaking.  If [MODE] is *}
{*  TRUE, automated RTS handshaking is enabled.  If enabled, the RTS line   *}
{*  will be DROPPED when the # of buffer bytes used reaches or exceeds that *}
{*  of [RTSOff].  The RTS line will then be re-asserted when the buffer is  *}
{*  emptied down to the [RTSOn] usage point.  If either [RTSOn] or [RTSOff] *}
{*  exceeds the input buffer size, they will be forced to (buffersize-1).   *}
{*  If [RTSOn] > [RTSOff] then [RTSOn] will be the same as [RTSOff].        *}
{*  The actual handshaking control is located in the interrupt driver for   *}
{*  the port (see ASYNC11.ASM).                                             *}
{*                                                                          *}
{****************************************************************************}

Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);

Var
  X : Byte;

Begin
  If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;

  X := C_Ctrl[ComPort];
  If Mode Then X := X Or $01 Else X := X And $FE;
  C_Ctrl[ComPort] := X;

  If Mode Then
    Begin
      If (RTSOff >= C_InSize[ComPort]) Then RTSOff := C_InSize[ComPort] - 1;
      If (RTSOn > RTSOff) Then RTSOff := RTSOn;
      C_RTSOn[ComPort] := RTSOn;
      C_RTSOff[ComPort] := RTSOff;
    End;
End;

{****************************************************************************}
{*                                                                          *}
{*  Procedure SetCTSMode(ComPort:Byte; Mode:Boolean)                        *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
{*                    Request ignored if out of range or unopened.          *}
{*  Mode:Boolean  ->  Set to TRUE to enable automatic CTS handshake.        *}
{*                                                                          *}
{*  SetCTSMode allows the enabling or disabling of automated CTS handshak-  *}
{*  ing.  If [Mode] is TRUE, CTS handshaking is enabled, which means that   *}
{*  if the remote drops the CTS line, the transmitter will be disabled      *}
{*  until the CTS line is asserted again.  Automatic handshake is disabled  *}
{*  if [Mode] is FALSE.  CTS handshaking and "software" handshaking (pro-   *}
{*  vided by the SoftHandshake procedure) ARE compatable and may be used    *}
{*  in any combination.  The actual logic for CTS handshaking is located    *}
{*  in the communications interrupt driver (see ASYNC11.ASM).               *}
{*                                                                          *}
{****************************************************************************}

Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);

Var
  X : Byte;

Begin
  If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;

  X := C_Ctrl[ComPort];
  If Mode Then X := X Or $02 Else X := X And $FD;
  C_Ctrl[ComPort] := X;
End;

{****************************************************************************}
{*                                                                          *}
{*  Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char)    *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
{*                    Request ignored if out of range or unopened.          *}
{*  Mode:Boolean  ->  Set to TRUE to enable transmit software handshake     *}
{*  Start:Char    ->  START control character (usually ^Q)                  *}
{*                    Defaults to ^Q if character passed is >= <Space>      *}
{*  Stop:Char     ->  STOP control character (usually ^S)                   *}
{*                    Defaults to ^S if character passed is >= <Space>      *}
{*                                                                          *}
{*  SoftHandshake controls the usage of "Software" (control-character)      *}
{*  handshaking on transmission.  If "software handshake" is enabled        *}
{*  ([Mode] is TRUE), transmission will be halted if the character in       *}
{*  [Stop] is received.  Transmission is re-enabled if the [Start] char-    *}
{*  acter is received.  Both the [Start] and [Stop] characters MUST be      *}
{*  CONTROL characters (i.e. Ord(Start) and Ord(Stop) must both be < 32).   *}
{*  Also, <Start> and <Stop> CANNOT be the same character.  If either one   *}
{*  of these restrictions are violated, the defaults (^Q for <Start> and ^S *}
{*  for <Stop>) will be used.  Software handshaking control is implimented  *}
{*  within the communications interrupt driver (see ASYNC11.ASM).           *}
{*                                                                          *}
{****************************************************************************}

Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);

Var
  X : Byte;

Begin
  If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;

  X := C_Ctrl[ComPort];
  If Mode Then
    Begin
      X := X Or $04;
      If Start=Stop Then Begin Start := ^Q; Stop := ^S; End;
      If Start>#32 Then Start := ^Q;
      If Stop>#32 Then Stop := ^S;
      C_StartChar[ComPort] := Start;
      C_StopChar[ComPort] := Stop;
    End
  Else
    X := X And $FB;
  C_Ctrl[ComPort] := X;
End;

{****************************************************************************}
{*                                                                          *}
{*  Procedure ClearCom(ComPort:Byte); IO:Char)                              *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
{*                    Request ignored if out of range or unopened.          *}
{*  IO:Char       ->  Action code; I=Input, O=Output, B=Both                *}
{*                    No action taken if action code unrecognized.          *}
{*                                                                          *}
{*  ClearCom allows the user to completely clear the contents of either     *}
{*  the input (receive) and/or output (transmit) buffers.  The "action      *}
{*  code" passed in <IO> determines if the input (I) or output (O) buffer   *}
{*  is cleared.  Action code (B) will clear both buffers.  This is useful   *}
{*  if you wish to cancel a transmitted message or ignore part of a         *}
{*  received message.                                                       *}
{*                                                                          *}
{****************************************************************************}

Procedure ClearCom(ComPort:Byte; IO:Char);

Var
  P,X : Word;

Begin
  If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;

  IO := Upcase(IO);
  P := C_PortAddr[ComPort];

  Inline($FA);
  If (IO='I') Or (IO='B') Then
    Begin
      C_InHead[ComPort] := 0;
      C_InTail[ComPort] := 0;
      C_Status[ComPort] := (C_Status[ComPort] And $EC) Or $01;
      X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
    End;
  If (IO='O') Or (IO='B') Then
    Begin
      C_OutHead[ComPort] := 0;
      C_OutTail[ComPort] := 0;
      C_Status[ComPort] := (C_Status[ComPort] And $D3) Or $04;
      X := Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
    End;
  Inline($FB);
End;

{****************************************************************************}
{*                                                                          *}
{*  Procedure ComBufferLeft(ComPort:Byte; IO:Char) : Word                   *}
{*                                                                          *}
{*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
{*                    Returns 0 if Port # invalid or unopened.              *}
{*  IO:Char       ->  Action code; I=Input, O=Output                        *}
{*                    Returns 0 if action code unrecognized.                *}
{*                                                                          *}
{*  ComBufferLeft will return a number (bytes) indicating how much space    *}
{*  remains in the selected buffer.  The INPUT buffer is checked if <IO> is *}
{*  (I), and the output buffer is interrogated when <IO> is (O).  Any other *}
{*  "action code" will return a result of 0.  Use this function when it is  *}
{*  important to avoid program delays due to calls to output procedures or  *}
{*  to prioritize the reception of data (to prevent overflows).             *}