/*---------------------------------------------------------------------------*
*
* BinkleyTerm
*
* (C) Copyright 1987-96, Bit Bucket Software Co.
* For license and contact information see /doc/orig_260/license.260.
*
* This version was modified by the BinkleyTerm XE Team.
* For contact information see /doc/team.lst and /doc/join.us.
* For a complete list of changes see /doc/xe_user.doc and /doc/xe_hist.doc.
*
* Filename : $Source: /cvsroot/btxe/btnt/sources/asyn_os2.cpp,v $
* Revision : $Revision: 1.1 $
* Tagname : $Name: $
* Last updated: $Date: 2005/01/01 15:18:10 $
* State : $State: Exp $
* Orig. Author: Peter Fitzsimmons
*
* Description : BinkleyTerm OS/2 Async Comm I/O Routines
*
*---------------------------------------------------------------------------*/
/* Include this file before any other includes or defines! */
#include "includes.h"
/*
* code snippet from Harald Pollack, 2:310/14.59
* intializes com port to use fifo, CTS/RTS, 8n1
*
* APIRET APIENTRY comport_init(BOOL fifo)
* {
* APIRET rc;
* LINECONTROL LineCntrl;
*
* if (fifo)
* {
* if (dcbCom.fbTimeout & 0x18) // DISABLE, ENABLE or AUTO
* {
* status_line (">PortInit Enable Fifo Rx=8 Tx=16");
* dcbCom.fbTimeout &= ~0x18; // DISABLE
* dcbCom.fbTimeout |= 0x10; // ENABLE
* dcbCom.fbTimeout &= ~0x60; // Rx=1
* dcbCom.fbTimeout |= 0x40; // Rx=8
* dcbCom.fbTimeout |= 0x80; // Tx=16
* }
* else
* status_line (">No Fifo detected!");
* }
*
* status_line (">PortInit CTS/RTS-Handshake DTR-Control XON/XOFF disabled");
* dcbCom.fbCtlHndShake = MODE_CTS_HANDSHAKE | MODE_DTR_CONTROL;
* dcbCom.fbFlowReplace = MODE_RTS_HANDSHAKE;
* rc = DevIOCtl(NULL,0,&dcbCom,sizeof(dcbCom),ASYNC_SETDCBINFO,IOCTL_ASYNC,hTTY);
* if (rc) return rc;
*
* status_line (">PortInit DataBits 8n1");
* LineCntrl.bDataBits = 8; // 8 Databits
* LineCntrl.bParity = 0; // no Parity
* LineCntrl.bStopBits = 0; // 1 Stopbit
* rc = DevIOCtl(NULL,0,&LineCntrl,sizeof(LineCntrl),ASYNC_SETLINECTRL,IOCTL_ASYNC,hTTY);
*
* rc = raise_dtr();
* if (rc) return rc;
*
* return(0);
* }
*/
#ifndef NEED_OS2COMMS
/* These must be in "includes.h" for C7 precompiled headers to work (as if
we'll ever get any MS support for OS/2-targetted C7!!!)
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_DOSDEVIOCTL
#include "includes.h" (And this I put up top to avoid confusion) */
/* This module by Peter Fitzsimmons */
/* Modified 6/13/92 for exit (3) WRA */
char ascii_comport[] = "COM";
HCOMM hcModem = 0; /* comm.dll handle */
#define RBSIZE 8200 /* MB */
#define TBSIZE 8200 /* MB */
USHORT rBufsize = RBSIZE;
USHORT tBufsize = TBSIZE;
/* CFS 961120 - an attempt to make BT-XE work without CFOS's -kx */
/* (SIO compatibility). */
void
com_DTR_on (void)
{
MODEMSTATUS ModemStatus;
USHORT usComError;
DCBINFO sDCB;
USHORT rc;
if (NoModem)
return;
if (SIOMode)
{
ModemStatus.fbModemOn = DTR_ON;
ModemStatus.fbModemOff = 0;
DosDevIOCtl (ComGetFH (hcModem), IOCTL_ASYNC, ASYNC_SETMODEMCTRL,
(PVOID) & ModemStatus, sizeof (MODEMSTATUS), NULL,
(PVOID) & usComError, sizeof (USHORT), NULL);
}
else
{
if (!(rc = ComGetDCB (hcModem, &sDCB)))
{
sDCB.fbCtlHndShake |= MODE_DTR_CONTROL; /* raise DTR */
ComSetDCB (hcModem, &sDCB);
}
else
{
status_line ("!SYS%04hu: ComGetDCB()", rc);
exit (3);
}
}
}
void
com_DTR_off (void)
{
MODEMSTATUS ModemStatus;
USHORT usComError;
DCBINFO sDCB;
USHORT rc;
if (NoModem)
return;
if (SIOMode)
{
ModemStatus.fbModemOn = 0;
ModemStatus.fbModemOff = DTR_OFF;
DosDevIOCtl (ComGetFH (hcModem), IOCTL_ASYNC, ASYNC_SETMODEMCTRL,
(PVOID) & ModemStatus, sizeof (MODEMSTATUS), NULL,
(PVOID) & usComError, sizeof (USHORT), NULL);
}
else
{
if (!(rc = ComGetDCB (hcModem, &sDCB)))
{
sDCB.fbCtlHndShake &= ~MODE_DTR_CONTROL; /* lower DTR */
ComSetDCB (hcModem, &sDCB);
com_kick ();
}
else
{
status_line ("!SYS%04hu: ComGetDCB()", rc);
exit (3);
}
}
}
void
com_XON_disable (void)
{
DCBINFO sDCB;
USHORT rc;
if (NoModem)
return;
if (!(rc = ComGetDCB (hcModem, &sDCB)))
{
/* disable auto Xmit and recv flow control */
sDCB.fbFlowReplace &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE);
ComSetDCB (hcModem, &sDCB);
com_kick ();
}
else
{
status_line ("!SYS%04hu: ComGetDCB()", rc);
exit (3);
}
}
void
com_XON_enable (void)
{
DCBINFO sDCB;
USHORT rc;
if (NoModem)
return;
if (!(rc = ComGetDCB (hcModem, &sDCB)))
{
/* enable auto Xmit and recv flow control */
sDCB.fbFlowReplace |= MODE_AUTO_TRANSMIT; /*PLF Wed 04-04-1990 02:35:41 */
ComSetDCB (hcModem, &sDCB);
}
else
{
status_line ("!SYS%04hu: ComGetDCB()", rc);
exit (3);
}
}
int
com_getc (int t)
{
if (NoModem)
return (0);
if (t)
ComRxWait (hcModem, t * 1000L);
return ComGetc (hcModem);
}
/* com_break() : start break if on==TRUE, stop break if on==FALSE */
void
com_break (int on)
{
ULONG cmd;
HFILE hf;
PVOID ParmList;
ULONG ParmLengthMax;
ULONG ParmLengthInOut;
UCHAR DataArea[2];
ULONG DataLengthMax;
ULONG DataLengthInOut;
APIRET rc;
if (NoModem)
return;
ParmList = 0;
ParmLengthInOut = 0;
ParmLengthMax = 0;
DataLengthInOut = 0;
DataLengthMax = 2;
cmd = (on) ? ASYNC_SETBREAKON : ASYNC_SETBREAKOFF;
hf = ComGetFH (hcModem);
if (hf)
{
/* rc = DosDevIOCtl(&comerr, 0L, cmd, IOCTL_ASYNC, hf); */
rc = DosDevIOCtl (hf, IOCTL_ASYNC, cmd, ParmList, ParmLengthMax,
&ParmLengthInOut, DataArea, DataLengthMax,
&DataLengthInOut);
if (rc)
status_line ("!SYS%04ld: ASYNC_SETBREAK", rc);
}
}
void
MDM_ENABLE (unsigned long rate)
{
char _parity;
short databits;
short stopbits;
if (NoModem)
return;
if (!hcModem)
return;
if (lock_baud && rate != max_baud.rate_value)
{
status_line (">Pretending baud is %lu (locked at %lu)", rate, max_baud.rate_value);
rate = max_baud.rate_value;
}
databits = 7 + (comm_bits == BITS_8);
stopbits = 1 + (stop_bits == STOP_2);
switch (parity)
{
case NO_PARITY:
_parity = 'N';
break;
case ODD_PARITY:
_parity = 'O';
break;
case EVEN_PARITY:
_parity = 'E';
break;
default:
_parity = 'N';
status_line ("!Invalid parity");
}
ComSetBaudRate (hcModem, (long) rate, _parity, (USHORT) databits, (USHORT) stopbits);
}
void
MDM_DISABLE (void)
{
if (NoModem)
return;
if (hcModem)
{
ComClose (hcModem);
hcModem = 0;
}
}
void
ShowMdmSettings (void)
{
DCBINFO dcb;
USHORT rc;
char *On = "On";
char *Off = "Off";
char *dtr;
char *rts;
char *buffer;
short Rx = 0, Tx;
if (NoModem)
return;
if (!(rc = ComGetDCB (hcModem, &dcb)))
{
status_line (">Modem: TO=%s,XON(Rx)=%s,XON(Tx)=%s",
(dcb.fbTimeout & MODE_NO_WRITE_TIMEOUT) ? On : Off,
(dcb.fbFlowReplace & MODE_AUTO_RECEIVE) ? On : Off,
(dcb.fbFlowReplace & MODE_AUTO_TRANSMIT) ? On : Off);
status_line (">Modem: IDSR=%s,ODSR=%s,OCTS=%s",
(dcb.fbCtlHndShake & MODE_DSR_SENSITIVITY) ? On : Off,
(dcb.fbCtlHndShake & MODE_DSR_HANDSHAKE) ? On : Off,
(dcb.fbCtlHndShake & MODE_CTS_HANDSHAKE) ? On : Off);
switch (dcb.fbCtlHndShake & (MODE_DTR_CONTROL | MODE_DTR_HANDSHAKE))
{
case 0:
dtr = Off;
break;
case MODE_DTR_CONTROL:
dtr = On;
break;
case MODE_DTR_HANDSHAKE:
dtr = "IHS";
break; /* input handshaking */
default:
dtr = "??";
break;
}
switch (dcb.fbFlowReplace & (MODE_RTS_CONTROL | MODE_RTS_HANDSHAKE | MODE_TRANSMIT_TOGGLE))
{
case 0:
rts = Off;
break;
case MODE_RTS_CONTROL:
rts = On;
break;
case MODE_RTS_HANDSHAKE:
rts = "IHS";
break;
case MODE_TRANSMIT_TOGGLE:
rts = "TOG";
break;
default:
rts = "??";
break;
}
switch (dcb.fbTimeout & 0x18)
{
case 0x08:
buffer = Off;
break;
case 0x10:
buffer = On;
break;
case 0x18:
buffer = "Auto";
break;
default:
buffer = "??";
break;
}
switch (dcb.fbTimeout & 0x60)
{
case 0:
Rx = 1;
break;
case 0x20:
Rx = 4;
break;
case 0x40:
Rx = 8;
break;
case 0x60:
Rx = 14;
break;
}
Tx = (dcb.fbTimeout & 0x80) ? 16 : 1;
status_line (">Modem: DTR=%s,RTS=%s,BUFFER=%s (Rx=%hd, Tx=%hd)",
dtr,
rts,
buffer,
Rx, Tx);
status_line (">Modem: Buffers R: %hu T: %hu", rBufsize, tBufsize); /* MB 94-01-02 */
}
else
{
status_line ("!SYS%04hu: ComGetDCB()", rc);
exit (3);
}
}
unsigned
Com_init (int port)
{
USHORT rc;
char *s;
char dev[256];
if (NoModem)
return (0);
if (port_device == NULL)
port_device = ascii_comport;
sprintf (dev, "%s%d", port_device, port + 1);
printf ("Async device %s\r\n", dev);
s = getenv ("RBUF"); /* MB 94-01-02 */
if (s)
rBufsize = (USHORT) min (32000, atoi (s));
else
rBufsize = RBSIZE;
s = getenv ("TBUF");
if (s)
tBufsize = (USHORT) min (32000, atoi (s));
else
tBufsize = TBSIZE;
rc = ComOpen ((PSZ) dev, &hcModem, rBufsize, tBufsize);
if (rc)
{
status_line ("!SYS%04hu: ComOpen(%s)", rc, dev);
return (rc);
}
else
ShowMdmSettings ();
return (rc);
}
unsigned
Cominit (int port, int failsafe)
{
int ret = 0x1954;
failsafe = failsafe;
if (NoModem)
return (ret);
if (!hcModem)
{
if (Com_init (port))
ret = 0;
}
else
ComResume (hcModem);
return ret;
}
/* force transmitter to go */
void
com_kick (void)
{
HFILE hf;
PVOID ParmList;
ULONG ParmLengthMax;
ULONG ParmLengthInOut;
PVOID DataArea;
ULONG DataLengthMax;
ULONG DataLengthInOut;
APIRET rc;
if (NoModem)
return;
ParmList = 0;
ParmLengthInOut = 0;
ParmLengthMax = 0;
DataArea = 0;
DataLengthInOut = 0;
DataLengthMax = 0;
if (hcModem)
{
hf = ComGetFH (hcModem);
if (hf)
{
rc = DosDevIOCtl (hf, IOCTL_ASYNC, ASYNC_STARTTRANSMIT, ParmList, ParmLengthMax,
&ParmLengthInOut, DataArea, DataLengthMax,
&DataLengthInOut);
if (rc && rc != 31)
{
status_line ("!SYS%04ld: ASYNC_STARTTRANSMIT", rc);
/* exit (3); */
}
}
}
}
/* Currently only used by HYDRA */
/*
* This is a lot like ComWrite, but will return the sent-character
* count if either a timeout occurs or carrier is lost. The timer
* is specified by passing in a time_t for end-of-time. If zero is
* passed for the timer, we'll just check for carrier loss.
*
*/
USHORT
ComTXBlockTimeout (BYTE * lpBuf, USHORT cbBuf, ULONG ulTimer)
{
USHORT cbRemaining = cbBuf;
USHORT cbToSend;
int fTimedOut;
if (NoModem)
return (0);
fTimedOut = (ulTimer != 0) ? (ulTimer < (ULONG) unix_time (NULL)) : FALSE;
while (!fTimedOut && CARRIER && cbRemaining)
{
cbToSend = ComOutSpace (hcModem);
if ((--cbToSend) > 0)
{
if (cbToSend > cbRemaining)
cbToSend = cbRemaining;
ComWrite (hcModem, lpBuf, cbToSend);
lpBuf += cbToSend;
cbRemaining -= cbToSend;
}
else
time_release ();
fTimedOut = (ulTimer != 0) ? (ulTimer < (ULONG) unix_time (NULL)) : FALSE;
}
return (cbBuf - cbRemaining);
}
USHORT
ComTXRemain (void) /* MB 93-12-03 */
{
if (NoModem)
return (0);
return (tBufsize - ComOutSpace (hcModem));
}
#else // NEED_OS2COMMS
#define __BTPE_DEBUG
#define __IOCTL_DEBUG
#define __LOG_TO_FILE
#include "async.h"
/* Private data */
HFILE hfComHandle = NULLHANDLE; /* handle from DosOpen() */
char ascii_comport[] = "COM";
/* transmitter stuff */
#define TSIZE 8192
static unsigned char *tBuf = NULL;
static unsigned char *zTxBuf = NULL;
static int zpos = 0;
static int tBufsize = 0;
static ULONG tpos = 0;
static ULONG tlen = 0;
static BOOL32 thread = FALSE;
HEV buffer_empty, buffer_full;
/* receiver stuff */
#define RSIZE 32768
static unsigned char *rbuf = NULL;
static ULONG rpos = 0;
static int rbufsize = 0;
static ULONG Rbytes = 0;
/* prototypes of local functions */
static APIRET IOCTL (HFILE, ULONG, ULONG, PVOID, ULONG, PULONG, PVOID,
ULONG, PULONG, PCHAR);
static int com_getDCB (DCBINFO * dcb);
static int com_setDCB (DCBINFO * dcb);
static void ShowMdmSettings (void);
static void setup_port (void);
static void HydraWrite (PVOID);
#ifdef BTPE_DEBUG
#define debug_msg(m,c) status_line(">" m, c)
#else
#define debug_msg(m,c)
#endif
#ifdef LOG_TO_FILE
static FILE *every = NULL;
static char *dbgfnm;
static void logAll (int ch, int type);
static int peeking = 0;
#endif
/* com_init() : Intialize communications port. Baud rate is preserved.
* int port : Hardware port (0 based) to init
* -OR- char *unc : Full UNC \\networkId\modemId to init.
*
* if unc==NULL, port is used. if unc != NULL, unc is used
*/
int
com_init (int port, char *unc)
{
static char did_it = 0;
char str[30];
ULONG ActionTaken, share_mode;
APIRET ulrc;
if (!did_it)
{
printf ("\033[1;33mOS/2 FOSSIL emulator for BinkleyTerm, Peter Fitzsimmons (1:250/628)\033[0m\r\n");
printf ("\033[1;33mSupport for Hydra added and bugfixes, Steffen Motzer (2:2471/1071.3)\033[0m\r\n");
did_it = 1;
}
if (port_device == NULL)
port_device = ascii_comport;
sprintf (str, "%s%d", port_device, port + 1);
if (!unc)
unc = str;
share_mode = share_port ? OPEN_SHARE_DENYNONE : OPEN_SHARE_DENYREADWRITE;
#ifdef BTPE_DEBUG
ulrc = DosOpen ((PSZ) unc, &hfComHandle, &ActionTaken, 0L,
FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
OPEN_FLAGS_WRITE_THROUGH | share_mode |
OPEN_ACCESS_READWRITE, 0L);
#else
ulrc = DosOpen ((PSZ) unc, &hfComHandle, &ActionTaken, 0L,
FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
OPEN_FLAGS_WRITE_THROUGH | share_mode |
OPEN_ACCESS_READWRITE | OPEN_FLAGS_FAIL_ON_ERROR, 0L);
#endif
if (ulrc != NO_ERROR)
{
hfComHandle = NULLHANDLE;
status_line ("!com_init() : DosOpen() error 0x%x on '%s'\n", ulrc, unc);
return ulrc;
}
if (rbuf == NULL)
{
char *s = getenv ("RBUF");
if (s)
rbufsize = max (H_MAXBLKLEN * 3, atoi (s));
else
rbufsize = RSIZE;
rbuf = malloc (rbufsize + 1);
}
if (zTxBuf == NULL)
{
char *s = getenv ("TBUF");
if (s)
tBufsize = min (TSIZE, atoi (s));
else
tBufsize = TSIZE;
zTxBuf = malloc (tBufsize + 1);
}
setup_port ();
ShowMdmSettings ();
return (NO_ERROR);
}
void
com_DTR_on (void)
{
DCBINFO sDCB;
MODEMSTATUS ModemStatus;
ULONG Data;
if (SIOMode)
{
ModemStatus.fbModemOn = DTR_ON;
ModemStatus.fbModemOff = 0;
IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL,
(PVOID) & ModemStatus, sizeof (MODEMSTATUS), NULL,
(PVOID) & Data, sizeof (ULONG), NULL, "com_DTR_on()");
}
else
{
com_getDCB (&sDCB);
sDCB.fbCtlHndShake |= MODE_DTR_CONTROL; /* raise DTR */
com_setDCB (&sDCB);
}
debug_msg ("DTR %s", "on");
}
void
com_DTR_off (void)
{
DCBINFO sDCB;
MODEMSTATUS ModemStatus;
ULONG Data;
if (SIOMode)
{
ModemStatus.fbModemOn = 0;
ModemStatus.fbModemOff = DTR_OFF;
IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL,
(PVOID) & ModemStatus, sizeof (MODEMSTATUS), NULL,
(PVOID) & Data, sizeof (ULONG), NULL, "com_DTR_off()");
}
else
{
com_getDCB (&sDCB);
sDCB.fbCtlHndShake &= ~MODE_DTR_CONTROL; /* lower DTR */
com_setDCB (&sDCB);
}
debug_msg ("DTR %s", "off");
#ifdef LOG_TO_FILE
if (every != NULL)
{
fflush (every);
}
#endif
zpos = 0; /* "remove" the characters from the buffer */
}
/* close communications channel. Baud rate is preserved. */
int
com_fini (void)
{
int stat;
if (hfComHandle != NULLHANDLE)
{
if (thread)
{
thread = FALSE;
DosPostEventSem (buffer_full);
DosSleep (500);
}
com_wait ();
com_clear_in ();
com_clear_out ();
stat = DosClose (hfComHandle);
hfComHandle = NULLHANDLE;
#ifdef LOG_TO_FILE
logAll (0, '-');
#endif
if (stat)
{
debug_msg ("Async: DosClose() error 0x%x", stat);
return (FALSE);
}
}
return (TRUE);
}
long
com_cur_baud (void)
{
EXTBAUDRATE extrate;
if (hfComHandle == NULLHANDLE)
return (0);
IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_EXTGETBAUDRATE,
NULL, 0, NULL, &extrate, sizeof extrate, NULL, "com_cur_baud()");
return ((long) extrate.cur_bps);
}
/* com_set_baud() :
* rate = 110..19200
* parity = N, E, O, M, S (none,even, odd, mark, space)
* databits = 5..8
* stopbits = 1..2
*
*/
int
com_set_baud (unsigned long ratei, char parity, int databits, int stopbits)
{
APIRET stat;
ULONG ratel = ratei;
struct _LINECONTROL
{
BYTE bDataBits;
BYTE bParity;
BYTE bStopBits;
BYTE fbTransBreak;
}
lc;
#ifdef BTPE_DEBUG
static long cnt = 0;
cnt++;
#endif
if (hfComHandle == NULLHANDLE)
return (0);
stat = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE,
&ratel, sizeof ratel, NULL, NULL, 0, NULL, "com_set_baud()");
if (stat)
{
#ifdef BTPE_DEBUG
if (cnt <= 2)
printf (">status from setbaudrate was %d\n", stat);
else
status_line (" status from setbaudrate was %d", stat);
#endif
return (FALSE);
}
lc.bDataBits = (BYTE) databits;
switch (stopbits)
{
case 1:
lc.bStopBits = 0;
break;
case 2:
lc.bStopBits = 2;
break;
default:
if (databits == 5)
lc.bStopBits = 1;
}
lc.fbTransBreak = 0;
switch (toupper (parity))
{
case 'N':
lc.bParity = 0;
break;
case 'O':
lc.bParity = 1;
break;
case 'E':
lc.bParity = 2;
break;
case 'M':
lc.bParity = 3;
break;
case 'S':
lc.bParity = 4;
break;
default:
debug_msg ("Bad parity '%c'", parity);
return (FALSE);
}
stat = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_SETLINECTRL,
&lc, sizeof lc, NULL, NULL, 0, NULL, "com_set_baud()");
return (!stat);
}
static int
com_getDCB (DCBINFO * dcb)
{
APIRET stat;
if (hfComHandle == NULLHANDLE)
return (0);
stat = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETDCBINFO,
NULL, 0, NULL, dcb, sizeof *dcb, NULL, "com_getDCB()");
return (!stat);
}
static int
com_setDCB (DCBINFO * dcb)
{
APIRET stat;
if (hfComHandle == NULLHANDLE)
return (0);
stat = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_SETDCBINFO,
dcb, sizeof *dcb, NULL, NULL, 0, NULL, "com_setDCB()");
return (!stat);
}
void
com_XON_disable (void)
{
DCBINFO sDCB;
if (com_getDCB (&sDCB))
{
/* disable auto Xmit and recv flow control */
sDCB.fbFlowReplace &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE);
com_setDCB (&sDCB);
}
com_kick ();
}
void
com_XON_enable (void)
{
DCBINFO sDCB;
if (com_getDCB (&sDCB))
{
/* enable auto Xmit and recv flow control */
sDCB.fbFlowReplace |= (MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE);
com_setDCB (&sDCB);
}
}
/* nuke receive buffer */
void
com_clear_in (void)
{
char FlushParm = 0; /* param to flush IOCTL function */
if (hfComHandle == NULLHANDLE)
return;
Rbytes = rpos = 0;
IOCTL (hfComHandle, IOCTL_GENERAL, DEV_FLUSHINPUT,
(PVOID) & FlushParm, sizeof FlushParm, NULL,
NULL, 0, NULL, "com_clear_in()");
}
/* com_getbuf() : return negative value if error */
int
com_getbuf (void)
{
APIRET stat = 0;
ULONG bytes;
RXQUEUE q;
if (hfComHandle == NULLHANDLE)
return (-1);
if (rpos > 1024)
{
memmove (rbuf, rbuf + rpos, Rbytes - rpos); /* SM 961127 */
Rbytes -= rpos;
rpos = 0;
}
if (!IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETINQUECOUNT,
NULL, 0, NULL, &q, sizeof q, NULL, "com_getbuf()"))
{
if (q.cch > 0)
{
stat = DosRead (hfComHandle, rbuf + Rbytes, (USHORT) min (rbufsize -
Rbytes,
q.cch), &bytes);
}
else
return (-1);
}
else
return (-1);
if (stat && !bytes && (!(stat == ERROR_MORE_DATA)))
{
debug_msg ("DosRead() error 0x%x", stat);
return (-1);
}
Rbytes += bytes;
return (TRUE);
}
/* com_getchar() : return negative value if error */
int
com_getchar (void)
{
int ret;
if (rpos == Rbytes)
com_getbuf ();
if (rpos < Rbytes)
ret = rbuf[rpos++];
else
ret = -1;
#ifdef LOG_TO_FILE
if ((ret != -1) && !peeking)
{
logAll (ret, 'R');
}
peeking = 0;
#endif
return (ret);
}
/*non destructive read ahead; no wait */
int
com_peek (void)
{
#ifdef LOG_TO_FILE
peeking = 1;
#endif
if (rpos == Rbytes)
com_getbuf ();
return (rpos == Rbytes) ? -1 : rbuf[rpos];
}
/* if there are enough characters in RXQueue , return TRUE */
bool
com_in_check (void)
{
RXQUEUE q;
APIRET stat;
if (hfComHandle == NULLHANDLE)
return (FALSE);
stat = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETINQUECOUNT,
NULL, 0, NULL, &q, sizeof q, NULL, "com_in_check()");
if (stat)
return (FALSE);
return (q.cch > (q.cb / 2)) ? TRUE : FALSE;
}
/* return number of chars in input buffer */
int
com_char_avail (void)
{
RXQUEUE q;
if (rpos < Rbytes)
return (Rbytes - rpos);
if (hfComHandle == NULLHANDLE)
return (0);
if (IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETINQUECOUNT,
NULL, 0, NULL, &q, sizeof q, NULL, "com_char_avail()"))
return (0);
return (q.cch);
}
/* return non 0 value if carrier detected */
bool
com_online (void)
{
BYTE msr;
APIRET rc;
if (hfComHandle == NULLHANDLE)
return (FALSE);
rc = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETMODEMINPUT,
NULL, 0, NULL, &msr, sizeof msr, NULL, "com_online()");
if (rc)
return (FALSE);
return ((msr & DCD_ON) == DCD_ON);
}
/* com_break() : start break if on==TRUE, stop break if on==FALSE */
void
com_break (int on)
{
int cmd;
USHORT comerr;
cmd = (on) ? ASYNC_SETBREAKON : ASYNC_SETBREAKOFF;
IOCTL (hfComHandle, IOCTL_ASYNC, cmd,
NULL, 0, NULL, &comerr, sizeof comerr, NULL, "com_break()");
}
/* com_out_empty() : return TRUE if output buffer is empty */
bool
com_out_empty (void)
{
RXQUEUE q;
if (hfComHandle == NULLHANDLE)
return (TRUE);
/* Service Inbound side if necessary */
if (com_in_check ())
com_getbuf ();
if (zpos != 0)
UNBUFFER_BYTES ();
if (IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETOUTQUECOUNT,
NULL, 0, NULL, &q, sizeof q, NULL, "com_out_empty()"))
return (TRUE);
return ((bool) (q.cch == 0));
}
/* nuke transmit buffer */
void
com_clear_out (void)
{
char FlushParm = 0; /* param to flush IOCTL function */
zpos = 0;
if (hfComHandle == NULLHANDLE)
return;
IOCTL (hfComHandle, IOCTL_GENERAL, DEV_FLUSHOUTPUT,
(PVOID) & FlushParm, sizeof FlushParm, NULL,
NULL, 0, NULL, "com_clear_out()");
com_kick ();
}
/* com_putc() : output to com port */
/* This function is very slow..where possile, write to com port in blocks
* using com_write() instead...especially above 2400 bps
*/
void
com_putc (byte c)
{
ULONG bytes;
APIRET stat;
RXQUEUE q;
if (hfComHandle == NULLHANDLE)
return;
#ifdef LOG_TO_FILE
logAll (c, 'S');
#endif
if (com_in_check ())
com_getbuf ();
do
{
if (com_in_check ())
com_getbuf ();
stat = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETOUTQUECOUNT,
NULL, 0, NULL, &q, sizeof q, NULL, "com_putc()");
if (stat != NO_ERROR)
return;
if (q.cch >= q.cb)
{
com_kick ();
DosSleep (1L);
}
}
while ((q.cch >= q.cb) && com_online ());
stat = DosWrite (hfComHandle, &c, 1L, &bytes);
if (stat)
{
stat = stat; /* to prevent a compiler warning in case of no DEBUG */
debug_msg ("DosWrite() err 0x%x", stat);
}
}
/* com_write() : buffered block write */
void
com_write (char *buf, unsigned int num, int carcheck)
{
ULONG bytes;
APIRET rc;
#ifdef LOG_TO_FILE
int x;
#endif
if (hfComHandle == NULLHANDLE)
return;
#ifdef LOG_TO_FILE
logAll ((unsigned char) buf[0], 'S');
if (every != NULL)
{
for (x = 1; x < num; x++)
{
logAll ((unsigned char) buf[x], 'S');
}
}
#endif
if ((carcheck) && !com_online ())
return;
if (com_in_check ())
com_getbuf ();
rc = DosWrite (hfComHandle, buf, (ULONG) num, &bytes);
if (rc)
{
rc = rc; /* to prevent a compiler warning in case of no DEBUG */
debug_msg ("DosWrite() err 0x%x", rc);
}
rc = rc;
}
/* wait for output buffer to empty */
void
com_wait (void)
{
while ((!com_out_empty ()) && com_online ())
DosSleep (1L);
}
/* force transmitter to go */
void
com_kick (void)
{
if (hfComHandle == NULLHANDLE)
return;
IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_STARTTRANSMIT,
NULL, 0, NULL, NULL, 0, NULL, "com_kick()");
}
extern unsigned int comm_bits;
extern unsigned int parity;
extern unsigned int stop_bits;
extern struct baud_str btypes[];
void
MDM_ENABLE (unsigned long rate)
{
char _parity;
int databits;
int stopbits;
if (lock_baud && rate != max_baud.rate_value)
{
status_line (">Pretending baud is %lu (locked at %lu)", rate, max_baud.rate_value);
rate = max_baud.rate_value;
}
databits = 7 + (comm_bits == BITS_8);
stopbits = 1 + (stop_bits == STOP_2);
switch (parity)
{
case NO_PARITY:
_parity = 'N';
break;
case ODD_PARITY:
_parity = 'O';
break;
case EVEN_PARITY:
_parity = 'E';
break;
default:
_parity = 'N';
status_line ("!Invalid parity");
}
com_set_baud (rate, _parity, databits, stopbits);
}
void
MDM_DISABLE (void)
{
if (hfComHandle == NULLHANDLE)
return;
com_clear_out ();
com_clear_in ();
com_fini ();
}
/* zsend.c uses BUFFER_BYTE and UNBUFFER_BYTES...good idea. */
void
BUFFER_BYTE (unsigned char ch)
{
if (zpos == tBufsize)
UNBUFFER_BYTES ();
zTxBuf[zpos++] = ch;
}
void
UNBUFFER_BYTES (void)
{
if (com_online () && zpos)
(zpos == 1) ? (com_putc (zTxBuf[0])) :
(com_write ((char *) zTxBuf, zpos, 1));
zpos = 0;
}
unsigned
Cominit (int port, int failsafe)
{
failsafe = failsafe;
if (NoModem)
return (0x1954);
if (hfComHandle == NULLHANDLE)
{
if (com_init (port, NULL))
return 0;
}
else
setup_port ();
return (0x1954);
}
int
com_getc (int t)
{
long t1;
if (NoModem)
return (0);
if (!CHAR_AVAIL ())
{
t1 = timerset ((unsigned int) (t * PER_SECOND));
while (!CHAR_AVAIL ())
{
if (timeup (t1))
{
return (EOF);
}
/* This should work because we only do TIMED_READ when we have
* carrier */
if (!CARRIER)
{
return (EOF);
}
time_release ();
}
}
return ((unsigned int) (MODEM_IN ()) & 0x00ff);
}
#ifdef LOG_TO_FILE
static void
logAll (int ch, int type)
{
static int lastType = 0;
static int lastchar = 0;
static time_t lastTime = 0;
time_t tt;
struct tm *tms;
if (debugging_log && (every == NULL))
{
dbgfnm = getenv ("BINKDBG");
if (dbgfnm != NULL)
{
every = fopen (dbgfnm, append_ascii);
if (every != NULL)
{
setvbuf (every, NULL, _IOFBF, 1000000);
logAll (0, 'X'); /* REKURSIVE! */
}
}
}
if (every == NULL)
return;
if ((ch != 0x0d) && (ch != 0x0a))
{
if ((lastchar == 0x0d) || (lastchar == 0x0a))
{
lastType = 0;
}
}
time (&tt);
if (tt != lastTime)
{
tms = localtime (&tt);
fprintf (every, "\n\nTime: %.2d:%.2d:%.2d\n",
tms->tm_hour, tms->tm_min, tms->tm_sec);
lastTime = tt;
}
if (type != lastType)
{
if (type == 'S')
{
fprintf (every, "\nSEND: ");
}
else if (type == 'R')
{
fprintf (every, "\nRECV: ");
}
else if (type == 'X')
{
fprintf (every, "\nSTART\n");
}
else if (type == '-')
{
fprintf (every, "\nFINISHED\n");
}
lastType = type;
}
if (type != 'X')
{
if ((ch > 0x1f) && (ch < 0x255))
{
fprintf (every, "%c", (char) ch);
}
else
{
if ((ch == 0x0d) || (ch == 0x0a))
{
fprintf (every, " (CR)");
}
else
{
fprintf (every, " 0x%02x,", ch);
}
}
lastchar = ch;
}
if (type == '-')
{
fclose (every);
every = NULL;
}
return;
}
#endif
/* Currently only used by HYDRA */
/*
* This is a lot like ComWrite, but will return the sent-character
* count if either a timeout occurs or carrier is lost. The timer
* is specified by passing in a time_t for end-of-time. If zero is
* passed for the timer, we'll just check for carrier loss.
*
*/
USHORT
ComTXBlockTimeout (BYTE * lpBuf, USHORT cbBuf, ULONG ulTimer)
{
ULONG ulPostCt = 0;
APIRET ulrc;
ULONG bytes, tpos2;
if (hfComHandle == NULLHANDLE)
return (0);
if (cbBuf == 0 || ulTimer == 0)
return 0; /* nothing to do */
#ifdef LOG_TO_FILE
logAll ((unsigned char) lpBuf[0], 'S');
if (every != NULL)
{
int x;
for (x = 1; x < cbBuf; x++)
{
logAll ((unsigned char) lpBuf[x], 'S');
}
}
#endif
tpos2 = 0;
if (!thread)
{
DosCreateEventSem (NULL, &buffer_empty, 0, FALSE);
DosCreateEventSem (NULL, &buffer_full, 0, FALSE);
thread = TRUE;
ulrc = _beginthread (HydraWrite, NULL, 32768L, NULL);
if (ulrc == -1)
{
status_line ("!could not create thread HydraWrite()");
thread = FALSE;
return 0;
}
}
if (cbBuf < 1024 && tpos == 0) /* small chunks of data should be send */
{
/* as fast as possible */
do
{
if (com_in_check ())
com_getbuf ();
ulrc = DosWrite (hfComHandle, lpBuf + tpos2, cbBuf - tpos2, &bytes);
if (ulrc != NO_ERROR || bytes == 0)
DosSleep (1);
if (ulrc == NO_ERROR)
tpos2 += bytes;
}
while ((ulTimer > unix_time (NULL)) && (tpos2 != cbBuf) && com_online ());
}
else
{
BOOL32 abort = FALSE;
BOOL32 timeout = FALSE;
DosWaitEventSem (buffer_empty, SEM_INDEFINITE_WAIT);
DosResetEventSem (buffer_empty, &ulPostCt);
tBuf = lpBuf;
tlen = cbBuf;
DosPostEventSem (buffer_full);
do
{
DosQueryEventSem (buffer_empty, &ulPostCt);
if (com_in_check ())
com_getbuf ();
abort = keyabort ();
timeout = ulTimer <= unix_time (NULL);
time_release ();
}
while (ulPostCt < 1 && com_online () && !abort && !timeout);
if (!com_online () || abort || timeout)
{
thread = FALSE;
DosPostEventSem (buffer_full);
DosSleep (500);
if (abort)
_ungetch (27);
}
}
return cbBuf;
}
void
HydraWrite (PVOID ignore_me)
{
ULONG bytes, ulPostCt;
APIRET ulrc;
ignore_me = ignore_me; /* make the compiler happy */
DosPostEventSem (buffer_empty);
while (thread) /* if we can write to the port */
{
DosWaitEventSem (buffer_full, SEM_INDEFINITE_WAIT);
DosResetEventSem (buffer_full, &ulPostCt);
if (tBuf != NULL)
{
while (tpos < tlen && thread) /* buffer not empty */
{
ulrc = DosWrite (hfComHandle, tBuf + tpos, tlen - tpos, &bytes);
if (ulrc != NO_ERROR || bytes == 0)
DosSleep (1);
if (ulrc == NO_ERROR)
tpos += bytes;
}
}
tpos = 0;
tlen = 0;
DosPostEventSem (buffer_empty);
}
DosCloseEventSem (buffer_empty);
DosCloseEventSem (buffer_full);
thread = FALSE; /* comTXBlockTimeout can start an other */
/* incarnation of this thread later */
_endthread ();
}
USHORT
ComTXRemain (void) /* SM 961109 */
{
return (Rbytes - rpos) < (H_MAXBLKLEN * 2) ? 0 : H_MAXBLKLEN + 1;
}
USHORT
ComOutSpace (HFILE hfComHandle) /* SM 961109 */
{
RXQUEUE q;
APIRET rc;
if (hfComHandle == NULLHANDLE)
return (0);
rc = IOCTL (hfComHandle, IOCTL_ASYNC, ASYNC_GETOUTQUECOUNT,
NULL, 0, NULL, &q, sizeof q, NULL, "ComOutSpace()");
if (rc)
return (0);
return (q.cb - q.cch);
}
APIRET
IOCTL (HFILE hDevice, ULONG category, ULONG function,
PVOID pParams, ULONG cbParmLenMax, PULONG pcbParmLen,
PVOID pData, ULONG cbDataLenMax, PULONG pcbDataLen,
PCHAR errtext)
{
APIRET ulrc;
ULONG parmlen = cbParmLenMax;
ULONG datalen = cbDataLenMax;
if (pParams != NULL && pcbParmLen == NULL)
pcbParmLen = &parmlen;
if (pData != NULL && pcbDataLen == NULL)
pcbDataLen = &datalen;
ulrc = DosDevIOCtl (hDevice, category, function,
pParams, cbParmLenMax, pcbParmLen,
pData, cbDataLenMax, pcbDataLen);
#ifdef IOCTL_DEBUG
if (ulrc != NO_ERROR)
{
status_line ("!%s", errtext);
status_line ("!=================================");
status_line ("!DosDevIOCtl() error : %u", ulrc);
status_line ("!DosDevIOCtl() category : %u", category);
status_line ("!DosDevIOCtl() function : %u", function);
status_line ("!=================================");
}
#else
errtext = errtext;
#endif
return ulrc;
}
void
ShowMdmSettings (void)
{
DCBINFO sDCB;
char *On = "On";
char *Off = "Off";
char *dtr;
char *rts;
char *buffer;
short Rx = 0, Tx;
if (NoModem)
return;
if (com_getDCB (&sDCB))
{
status_line (">Modem: TO=%s,XON(Rx)=%s,XON(Tx)=%s",
(sDCB.fbTimeout & MODE_NO_WRITE_TIMEOUT) ? On : Off,
(sDCB.fbFlowReplace & MODE_AUTO_RECEIVE) ? On : Off,
(sDCB.fbFlowReplace & MODE_AUTO_TRANSMIT) ? On : Off);
status_line (">Modem: IDSR=%s,ODSR=%s,OCTS=%s",
(sDCB.fbCtlHndShake & MODE_DSR_SENSITIVITY) ? On : Off,
(sDCB.fbCtlHndShake & MODE_DSR_HANDSHAKE) ? On : Off,
(sDCB.fbCtlHndShake & MODE_CTS_HANDSHAKE) ? On : Off);
switch (sDCB.fbCtlHndShake & (MODE_DTR_CONTROL | MODE_DTR_HANDSHAKE))
{
case 0:
dtr = Off;
break;
case MODE_DTR_CONTROL:
dtr = On;
break;
case MODE_DTR_HANDSHAKE:
dtr = "IHS";
break; /* input handshaking */
default:
dtr = "??";
break;
}
switch (sDCB.fbFlowReplace & (MODE_RTS_CONTROL | MODE_RTS_HANDSHAKE | MODE_TRANSMIT_TOGGLE))
{
case 0:
rts = Off;
break;
case MODE_RTS_CONTROL:
rts = On;
break;
case MODE_RTS_HANDSHAKE:
rts = "IHS";
break;
case MODE_TRANSMIT_TOGGLE:
rts = "TOG";
break;
default:
rts = "??";
break;
}
switch (sDCB.fbTimeout & 0x18)
{
case 0x08:
buffer = Off;
break;
case 0x10:
buffer = On;
break;
case 0x18:
buffer = "Auto";
break;
default:
buffer = "??";
break;
}
switch (sDCB.fbTimeout & 0x60)
{
case 0:
Rx = 1;
break;
case 0x20:
Rx = 4;
break;
case 0x40:
Rx = 8;
break;
case 0x60:
Rx = 14;
break;
}
Tx = (sDCB.fbTimeout & 0x80) ? 16 : 1;
status_line (">Modem: DTR=%s,RTS=%s,BUFFER=%s (Rx=%hd, Tx=%hd)",
dtr,
rts,
buffer,
Rx, Tx);
status_line (">Modem: Buffers R: %hu T: %hu", rbufsize, tBufsize);
}
}
void
setup_port ()
{
DCBINFO sDCB;
if (NoModem)
return;
com_getDCB (&sDCB);
sDCB.usWriteTimeout = 1000;
sDCB.usReadTimeout = 1000;
sDCB.fbCtlHndShake |= (MODE_DTR_CONTROL | MODE_CTS_HANDSHAKE);
sDCB.fbCtlHndShake &= ~(MODE_DSR_SENSITIVITY | MODE_DSR_HANDSHAKE | MODE_DTR_HANDSHAKE);
sDCB.fbFlowReplace |= (MODE_RTS_HANDSHAKE);
sDCB.fbFlowReplace &= ~(MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE | MODE_RTS_CONTROL);
sDCB.fbTimeout = (MODE_NO_WRITE_TIMEOUT | MODE_READ_TIMEOUT | 0x10 | 0x40
| 0x80);
com_setDCB (&sDCB);
}
# endif /* NEED_OS2COMMS */
/* $Id: asyn_os2.cpp,v 1.1 2005/01/01 15:18:10 vildanov Exp $ */