home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.wwiv.com
/
ftp.wwiv.com.zip
/
ftp.wwiv.com
/
pub
/
INTERNET
/
UPC2S1.ZIP
/
ULIBWIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-03
|
28KB
|
771 lines
/*--------------------------------------------------------------------*/
/* u l i b w i n . C */
/* */
/* UUPC/extended serial port communications for Windows 3.1 */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* Changes copyright (c) 1993, by Robert Denny */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* Changes Copyright (c) 1989-1993 by Kendra Electronic */
/* Wonderworks. */
/* */
/* All rights reserved except those explicitly granted by */
/* the UUPC/extended license agreement. */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* RCS Information */
/*--------------------------------------------------------------------*/
/*
* $Id: ulibwin.c 1.7 1993/10/03 22:09:09 ahd Exp $
*
* Revision history:
* $Log: ulibwin.c $
* Revision 1.7 1993/10/03 22:09:09 ahd
* Use unsigned long to display speed
*
* Revision 1.6 1993/10/01 02:36:45 dmwatt
* Suppress odd debugging messages in normal compile
* Reformat source
*
* Revision 1.5 1993/09/29 13:18:06 ahd
* Use new dummy setprty function
*
* Revision 1.4 1993/09/27 00:48:43 ahd
* Add dummy set and reset priority functions
*
* Revision 1.3 1993/08/02 03:24:59 ahd
* Further changes in support of Robert Denny's Windows 3.x support
*
* Revision 1.2 1993/07/31 16:27:49 ahd
* Changes in support of Robert Denny's Windows support
*
* Revision 1.1 1993/07/22 23:24:23 ahd
* Initial revision
*
*/
/*--------------------------------------------------------------------*/
/* Services provided by ulib.c: */
/* */
/* - serial I/O */
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/* System include files */
/*--------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <time.h>
/*--------------------------------------------------------------------*/
/* MS Windows 3.1 include files */
/*--------------------------------------------------------------------*/
#include <windows.h>
/*--------------------------------------------------------------------*/
/* UUPC/extended include files */
/*--------------------------------------------------------------------*/
#include "lib.h"
#include "ulib.h"
#include "ssleep.h"
#include "commlib.h"
//
// Finally, Microsoft has documented a way to see the Modem Status
// Register bits for modem control lines. This was a real bizarre
// mess with SetCommEventMask() and GetCommEventMask(). The document
// is in the Developer's Knowledge Base:
//
// Title: INF: Accessing the Modem Status Register (MSR) in Windows
// Document Number: Q101417 Publ Date: 15-JUL-1993
// Product Name: Microsoft Windows Software Development Kit
// Product Version: 3.10
// Operating System: WINDOWS
//
#define COMM_MSRSHADOW 35 // Offset in DEB of MSR shadow
#define MSR_CTS 0x10 // absolute CTS state in MSR
#define MSR_DSR 0x20 // absolute DSR state in MSR
#define MSR_RI 0x40 // absolute RI state in MSR
#define MSR_RLSD 0x80 // absolute RLSD state in MSR
currentfile();
static boolean carrierdetect = FALSE; /* Modem is not connected */
static boolean hangupNeeded = FALSE;
static UINT currentSpeed = 0;
static LPBYTE lpbModemBits; // --> Modem Status Register bits
#define FAR_NULL ((PVOID) 0L)
#define IN_QUEUE_SIZE 2048
#define OUT_QUEUE_SIZE 2048
#define IN_XOFF_LIM 256
#define IN_XON_LIM 256
/*--------------------------------------------------------------------*/
/* Definitions of control structures for Win 3.1 API */
/*--------------------------------------------------------------------*/
static int nCid;
static DCB dcb;
/*--------------------------------------------------------------------*/
/* Internal prototypes */
/*--------------------------------------------------------------------*/
static void ShowModem( void );
static void ShowError( int status );
/*--------------------------------------------------------------------*/
/* n o p e n l i n e */
/* */
/* Open the serial port for I/O */
/*--------------------------------------------------------------------*/
#ifdef __TURBOC__
#pragma argsused
#endif
int nopenline(char *name, BPS baud, const boolean direct )
{
int rc;
if (portActive) /* Was the port already active? ahd */
closeline(); /* Yes --> Shutdown it before open ahd */
#ifdef UDEBUG
printmsg(15, "openline: %s, %ul", name, (unsigned long) baud);
#endif
if (!equaln(name, "COM", 3 ))
{
printmsg(0,
"openline: Communications port must be format COMx, was %s",
name);
return TRUE;
}
if((nCid = OpenComm(name, IN_QUEUE_SIZE, OUT_QUEUE_SIZE)) < 0)
{
printmsg(0, "openline: Failed to open port %s.", name);
printmsg(0, "nopenline: %s: OpenComm returned %#04X (%d)",
name,
nCid,
nCid);
return TRUE;
}
/*--------------------------------------------------------------------*/
/* Get the pointer to the MSR shadow in COMM.DRV's DEB */
/*--------------------------------------------------------------------*/
lpbModemBits = (LPBYTE)SetCommEventMask(nCid, 0) + COMM_MSRSHADOW;
/*--------------------------------------------------------------------*/
/* Reset any errors on the communications port */
/*--------------------------------------------------------------------*/
if ((rc = GetCommError (nCid, NULL)) != 0)
{
printmsg(0, "openline: Error condition reset on port %s.", name);
ShowError(rc);
}
/*--------------------------------------------------------------------*/
/* Set baud rate */
/*--------------------------------------------------------------------*/
nSIOSpeed(baud);
/*--------------------------------------------------------------------*/
/* Set line attributes */
/*--------------------------------------------------------------------*/
printmsg(15,"openline: Getting attributes");
if ((rc = GetCommState(nCid, &dcb)) != 0)
{
printmsg(0,"nopenline: %s: GetCommState was %#04x (%d)",
name,
rc,
rc);
panic();
}
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
dcb.ByteSize = 8;
/*--------------------------------------------------------------------*/
/* Set up for Flow Control */
/*--------------------------------------------------------------------*/
printmsg(15,"openline: Disabling XON/XOFF flow control");
dcb.fOutX = 0;
dcb.fInX = 0;
if(!direct) // nodirect means RTS/CTS flow OK
{
#ifdef UDEBUG
printmsg(15, "openline: Enabling RTS/CTS flow control");
#endif
dcb.fOutxCtsFlow = 1;
dcb.fRtsflow = 1;
dcb.XoffLim = IN_XOFF_LIM;
dcb.XonLim = IN_XON_LIM;
}
else {
#ifdef UDEBUG
printmsg(4, "openline: Disabling RTS/CTS flow control");
#endif
dcb.fOutxCtsFlow = 0;
dcb.fRtsflow = 0;
}
/*--------------------------------------------------------------------*/
/* Set up for Modem Control as needed */
/*--------------------------------------------------------------------*/
dcb.fDtrDisable = 0;
dcb.fRtsDisable = 0;
/*--------------------------------------------------------------------*/
/* Modify the DCB with the new attributes */
/*--------------------------------------------------------------------*/
#ifdef UDEBUG
printmsg(15,"openline: Setting attributes");
#endif
if ((rc = SetCommState(&dcb)) != 0)
{
printmsg(0,"nopenline: %s: return code from SetCommState was %#04X (%d)",
name,
rc,
rc);
panic();
}
/*--------------------------------------------------------------------*/
/* Assure RTS and DTR are asserted */
/*--------------------------------------------------------------------*/
#ifdef UDEBUG
printmsg(15,"openline: Raising RTS/DTR");
#endif
if (EscapeCommFunction(nCid, SETRTS) != 0)
{
printmsg(0, "openline: Failed to raise RTS for %s", name);
panic();
}
if (EscapeCommFunction(nCid, SETDTR) != 0)
{
printmsg(0, "openline: Unable to raise DTR for %s", name);
panic();
}
ShowModem();
/*--------------------------------------------------------------------*/
/* Log serial line data only if log file already exists */
/*--------------------------------------------------------------------*/
traceStart( name );
portActive = TRUE; /* record status for error handler */
/*--------------------------------------------------------------------*/
/* Wait for port to stablize */
/*--------------------------------------------------------------------*/
ssleep(2); /* Allow port to stabilize per V.24 */
return 0;
} /* nopenline */
/*--------------------------------------------------------------------*/
/* s r e a d */
/* */
/* Read from the serial port */
/* */
/* Non-blocking read essential to "g" protocol. The rather cryptic */
/* "description" in dcpgpkt.c is: */
/* */
/* sread(buf, n, timeout) */
/* while(TRUE) */
/* if # of chars available >= n (w/o dec internal counter) */
/* read n chars into buf (dec internal counter) */
/* break */
/* else */
/* if time > timeout */
/* break */
/* */
/* NOTE: Timeout of 0 returns right away, indicating the number of */
/* bytes in our local receive buffer. There's GOTTA be a */
/* better way... */
/* */
/* This all changes in a multi-tasking system. Requests for I/O */
/* should get queued and an event flag given. Then the */
/* requesting process (e.g. gmachine()) waits for the event flag */
/* to fire processing either a read or a write. Could be */
/* implemented on VAX/VMS or DG but not MS-DOS. */
/* */
/*--------------------------------------------------------------------*/
unsigned int nsread(char *output, unsigned int wanted, unsigned int timeout)
{
int rc, received;
time_t stop_time;
time_t now;
COMSTAT stat;
//
// This catches a fencepost condition later...
//
if (wanted == 0)
{
ddelay(0);
return(0);
}
/*--------------------------------------------------------------------*/
/* Report our modem status */
/*--------------------------------------------------------------------*/
ShowModem();
/*--------------------------------------------------------------------*/
/* Determine when to stop processing */
/*--------------------------------------------------------------------*/
if ( timeout == 0 ) /* 0 = don't wait around. */
{
stop_time = 0;
now = 1; /* Any number greater than stop time */
}
else {
time( & now );
stop_time = now + timeout;
}
/*--------------------------------------------------------------------*/
/* Watch RX Queue till wanted bytes available or timeout */
/*--------------------------------------------------------------------*/
while(TRUE)
{
//
// Check & clear the comm port. This gets the #chars in the
// receive queue as well, in the COMSTAT structure.
//
if ((rc = GetCommError(nCid, &stat)) != 0)
{
printmsg(0,"sread: Read of %d bytes failed.", wanted);
printmsg(0," return code from GetCommError was %#04x (%d)",
rc , rc);
ShowError(rc);
return 0;
}
//
// If wanted # bytes are available, break out and read 'em.
//
if (stat.cbInQue >= wanted)
break; // We have enough, break out!
//
// Be friendly to Windows' cooperative multitasking...
//
ddelay(0);
//
// If timeout is zero, return immediately.
//
if (stop_time == 0)
return(stat.cbInQue);
//
// Check for timeout. If timed out, return.
//
time( &now );
if(stop_time <= now)
{
printmsg(15, "sread: timeout(%d) - %d chars avail",
timeout, stat.cbInQue);
return(stat.cbInQue);
}
} // end of while(TRUE)
//
// We have enough in the RX queue. Grab 'em right into the
// caller's buffer.
//
received = ReadComm(nCid, output, wanted);
printmsg(15, "sread: Got %d characters, %d still in RX queue.",
(int)received, (int)(stat.cbInQue - received));
/*--------------------------------------------------------------------*/
/* Log the newly received data */
/*--------------------------------------------------------------------*/
traceData( output, wanted, FALSE );
return(received);
} /* nsread */
/*--------------------------------------------------------------------*/
/* n s w r i t e */
/* */
/* Write to the serial port */
/*--------------------------------------------------------------------*/
int nswrite(const char *data, unsigned int len)
{
int bytes;
int rc;
hangupNeeded = TRUE; /* Flag that the port is now dirty */
/*--------------------------------------------------------------------*/
/* Report our modem status */
/*--------------------------------------------------------------------*/
ShowModem();
/*--------------------------------------------------------------------*/
/* Write the data out as the queue becomes available */
/*--------------------------------------------------------------------*/
bytes = WriteComm(nCid, data, len);
rc = GetCommError(nCid, NULL);
if (rc)
{
printmsg(0,"nswrite: WriteComm failed, "
"return code from GetCommError was %#04x (%d)",
rc , rc);
ShowError(rc);
return bytes;
}
/*--------------------------------------------------------------------*/
/* Log the data written */
/*--------------------------------------------------------------------*/
traceData( data, len, TRUE );
/*--------------------------------------------------------------------*/
/* Return bytes written to the port to the caller */
/*--------------------------------------------------------------------*/
return len;
} /* nswrite */
/*--------------------------------------------------------------------*/
/* n s s e n d b r k */
/* */
/* send a break signal out the serial port */
/*--------------------------------------------------------------------*/
void nssendbrk(unsigned int duration)
{
#ifdef UDEBUG
printmsg(12, "ssendbrk: %d", duration);
#endif
SetCommBreak(nCid);
ddelay(duration == 0 ? 200 : duration);
ClearCommBreak(nCid);
} /*ssendbrk*/
/*--------------------------------------------------------------------*/
/* n c l o s e l i n e */
/* */
/* Close the serial port down */
/*--------------------------------------------------------------------*/
void ncloseline(void)
{
if ( ! portActive )
panic();
portActive = FALSE; /* flag port closed for error handler */
hangupNeeded = FALSE; /* Don't fiddle with port any more */
/*--------------------------------------------------------------------*/
/* Lower DTR */
/*--------------------------------------------------------------------*/
if (EscapeCommFunction(nCid, CLRDTR | CLRRTS) != 0)
printmsg(0,"closeline: Unable to lower DTR/RTS");
/*--------------------------------------------------------------------*/
/* Actually close the port */
/*--------------------------------------------------------------------*/
if(CloseComm(nCid) != 0)
printmsg(0, "closeline: close of serial port failed");
/*--------------------------------------------------------------------*/
/* Stop logging the data to disk */
/*--------------------------------------------------------------------*/
traceStop();
printmsg(3,"Serial port closed");
} /* ncloseline */
/*--------------------------------------------------------------------*/
/* n h a n g u p */
/* */
/* Hangup the telephone by dropping DTR. Works with HAYES and */
/* many compatibles. */
/* 14 May 89 Drew Derbyshire */
/*--------------------------------------------------------------------*/
void nhangup( void )
{
hangupNeeded = FALSE;
/*--------------------------------------------------------------------*/
/* Drop DTR */
/*--------------------------------------------------------------------*/
if (EscapeCommFunction(nCid, CLRDTR) != 0)
{
printmsg(0, "hangup: Unable to lower DTR for comm port");
panic();
}
/*--------------------------------------------------------------------*/
/* Wait for the telephone to hangup */
/*--------------------------------------------------------------------*/
printmsg(3,"hangup: Dropped DTR");
ddelay(1000); /* Really only need 250 milliseconds (HA) */
/*--------------------------------------------------------------------*/
/* Bring DTR backup */
/*--------------------------------------------------------------------*/
if (EscapeCommFunction(nCid, SETDTR) != 0)
{
printmsg(0, "hangup: Unable to raise DTR for comm port");
panic();
}
ddelay(500); /* Now wait for the poor thing to recover */
} /* nhangup */
/*--------------------------------------------------------------------*/
/* S I O S p e e d */
/* */
/* Re-specify the speed of an opened serial port */
/*--------------------------------------------------------------------*/
void nSIOSpeed(BPS baud)
{
WORD rc;
currentSpeed = (UINT) baud;
printmsg(15,"SIOSpeed: Setting baud rate to %lu",
(unsigned long) currentSpeed);
ShowModem();
GetCommState (nCid, &dcb);
dcb.BaudRate = currentSpeed;
rc = SetCommState (&dcb);
if (rc)
{
printmsg(0,"SIOSPeed: Unable to set baud rate for port to %lu",
(unsigned long) currentSpeed);
panic();
}
} /* nSIOSpeed */
/*--------------------------------------------------------------------*/
/* n f l o w c o n t r o l */
/* */
/* Enable/Disable in band (XON/XOFF) flow control */
/*--------------------------------------------------------------------*/
void nflowcontrol( boolean flow )
{
int rc;
DCB dcb;
GetCommState(nCid, &dcb);
if (flow)
{
dcb.fOutX = TRUE;
dcb.fInX = TRUE;
dcb.fRtsflow = FALSE;
dcb.fOutxCtsFlow = FALSE;
}
else {
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fRtsflow = TRUE;
dcb.fOutxCtsFlow = TRUE;
}
if ((rc = SetCommState(&dcb)) != 0)
{
printmsg(0,"flowcontrol: Unable to set flow control");
printmsg(0,"Return code fromSetCommState was %#04x (%d)",
(int) rc,
(int) rc);
panic();
} /*if */
} /* nflowcontrol */
/*--------------------------------------------------------------------*/
/* n G e t S p e e d */
/* */
/* Report current speed of communications connection */
/*--------------------------------------------------------------------*/
BPS nGetSpeed( void )
{
return currentSpeed;
} /* GetSpeed */
/*--------------------------------------------------------------------*/
/* n C D */
/* */
/* Return status of carrier detect */
/*--------------------------------------------------------------------*/
boolean nCD( void )
{
boolean online = carrierdetect;
boolean modem_present;
carrierdetect = ((*lpbModemBits & MSR_RLSD) != 0);
modem_present = ((*lpbModemBits & MSR_DSR) != 0);
/*--------------------------------------------------------------------*/
/* If we previously had carrier detect but have lost it, we */
/* report it was lost. If we do not yet have carrier detect, */
/* we return success because we may not have connected yet. */
/* If DSR is not present, we always report no carrier, as there */
/* is either no modem at all(!) or it's not turned on. */
/*--------------------------------------------------------------------*/
if (online)
return (modem_present && carrierdetect);
else
return (modem_present);
} /* nCD */
/*--------------------------------------------------------------------*/
/* S h o w M o d e m */
/* */
/* Report current modem status when changed from last call */
/*--------------------------------------------------------------------*/
#define mannounce(flag, bits, text ) (((flag & bits) != 0) ? text : "" )
static void ShowModem( void )
{
BYTE modem_bits = *lpbModemBits;
static BYTE old_bits = 0xFF;
if ( debuglevel < 4 )
return;
if ( (debuglevel < 4) || // Silent at lower debuglevels
(modem_bits == old_bits)) // Show only changes in modem signals
return;
printmsg(0, "ShowModem: %#02x %s %s %s",
modem_bits,
mannounce(MSR_RLSD, modem_bits, "DCD"),
mannounce(MSR_DSR, modem_bits, "DSR"),
mannounce(MSR_CTS, modem_bits, "CTS"));
old_bits = modem_bits;
} /* ShowModem */
/*--------------------------------------------------------------------*/
/* S h o w E r r o r */
/* */
/* Report modem error bits in English (more or less) */
/*--------------------------------------------------------------------*/
static void ShowError( int status )
{
printmsg(2, "Port Error: %#04x%s%s%s%s%s",
status,
mannounce(CE_RXOVER, status, " Recv Queue Ovfl"),
mannounce(CE_OVERRUN, status, " Hardware Overrun"),
mannounce(CE_RXPARITY, status, " Parity Error"),
mannounce(CE_FRAME, status, " Framing Error"),
mannounce(CE_TXFULL, status, " Xmit Queue Full"));
} /* ShowError */
/*--------------------------------------------------------------------*/
/* s e t P r t y */
/* */
/* No operation under Windows */
/*--------------------------------------------------------------------*/
#ifdef __TURBOC__
#pragma argsused
#endif
void setPrty( const KEWSHORT priorityIn, const KEWSHORT prioritydeltaIn )
{
} /* setPrty */
/*--------------------------------------------------------------------*/
/* r e s e t P r t y */
/* */
/* No operation under Windows */
/*--------------------------------------------------------------------*/
void resetPrty( void )
{
} /* resetPrty */