{*--------------------------------------------------------------------------*}
{* *}
{* 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). *}