/*--------------------------------------------------------------------*/ /* u l i b o s 2 . c */ /* */ /* OS/2 serial port support for UUCICO */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* Changes Copyright (c) 1989 by Andrew H. Derbyshire. */ /* */ /* Changes Copyright (c) 1990-1993 by Kendra Electronic */ /* Wonderworks. */ /* */ /* All rights reserved except those explicitly granted by the */ /* UUPC/extended license agreement. */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* RCS Information */ /*--------------------------------------------------------------------*/ /* * $Id: ULIBOS2.C 1.11 1993/04/11 00:34:11 ahd Exp $ * $Log: ULIBOS2.C $ * Revision 1.11 1993/04/11 00:34:11 ahd * Global edits for year, TEXT, etc. * * Revision 1.10 1993/04/10 21:25:16 dmwatt * Add Windows/NT support * * Revision 1.9 1993/04/05 04:32:19 ahd * Additional traps for modem dropping out * * Revision 1.8 1993/04/04 04:57:01 ahd * Add configurable OS/2 priority values * * Revision 1.7 1992/12/30 13:02:55 dmwatt * Dual path for Windows/NT and OS/2 * * Revision 1.6 1992/12/11 12:45:11 ahd * Correct RTS handshake * * Revision 1.5 1992/12/04 01:00:27 ahd * Add copyright message, reblock other comments * * Revision 1.4 1992/11/29 22:09:10 ahd * Add new define for BC++ OS/2 build * * Revision 1.3 1992/11/19 03:00:39 ahd * drop rcsid * * Revision 1.2 1992/11/15 20:11:48 ahd * Add English display of modem status and error bits * */ /*--------------------------------------------------------------------*/ /* System include files */ /*--------------------------------------------------------------------*/ #include #include #include #include #include #include /*--------------------------------------------------------------------*/ /* Windows/NT include files */ /*--------------------------------------------------------------------*/ #ifdef WIN32 #include #include #else /*--------------------------------------------------------------------*/ /* OS/2 include files */ /*--------------------------------------------------------------------*/ #define INCL_DOSDEVIOCTL #define INCL_BASE #include #include #endif /*--------------------------------------------------------------------*/ /* UUPC/extended include files */ /*--------------------------------------------------------------------*/ #include "lib.h" #include "ulib.h" #include "ssleep.h" #include "catcher.h" /*--------------------------------------------------------------------*/ /* Global variables */ /*--------------------------------------------------------------------*/ currentfile(); boolean port_active = FALSE; /* TRUE = port handler handler active */ static boolean carrierdetect = FALSE; /* Modem is not connected */ #define LINELOG "LineData.Log" /* log serial line data here */ static int log_handle; static int logmode = 0; /* Not yet logging */ #define WRITING 1 #define READING 2 static FILE *log_stream; static boolean hangup_needed = FALSE; static boolean console = FALSE; static current_baud = 0; #define FAR_NULL ((PVOID) 0L) /*--------------------------------------------------------------------*/ /* Definitions of control structures for DOS API */ /*--------------------------------------------------------------------*/ #ifdef WIN32 static HANDLE hCom; static COMMTIMEOUTS CommTimeout; static DCB dcb; #else /* OS/2 */ static HFILE com_handle; static struct _LINECONTROL com_attrib; static struct _RXQUEUE com_queue; static struct _MODEMSTATUS com_signals; static struct _DCBINFO com_dcbinfo; #endif static BYTE com_status; static USHORT com_error; static USHORT usPrevPriority; static void ShowError( const USHORT status ); #ifdef WIN32 static void ShowModem( const DWORD status ); #else /* OS/2 */ static void ShowModem( const BYTE status ); #endif /*--------------------------------------------------------------------*/ /* o p e n l i n e */ /* */ /* Open the serial port for I/O */ /*--------------------------------------------------------------------*/ int openline(char *name, BPS baud, const boolean direct ) { #ifdef WIN32 DWORD dwError; DWORD Error; BOOL rc; HANDLE hProcess; #else USHORT rc; USHORT action; USHORT priority = (E_priority == -99) ? PRTYC_FOREGROUNDSERVER : (USHORT) E_priority; USHORT prioritydelta = (E_prioritydelta == -99) ? 0 : (USHORT) (E_prioritydelta + PRTYD_MINIMUM); #endif if (port_active) /* Was the port already active? ahd */ closeline(); /* Yes --> Shutdown it before open ahd */ #ifdef UDEBUG printmsg(15, "openline: %s, %d", name, baud); #endif /*--------------------------------------------------------------------*/ /* Validate the port format */ /*--------------------------------------------------------------------*/ if (!equal(name,"CON") && !equaln(name, "COM", 3 )) { printmsg(0,"openline: Communications port begin with COM, was %s", name); panic(); } /*--------------------------------------------------------------------*/ /* Perform the open */ /*--------------------------------------------------------------------*/ #ifdef WIN32 hCom = CreateFile( name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); #else /* OS/2 */ rc = DosOpen( name, &com_handle, &action, 0L, 0 , FILE_OPEN , OPEN_FLAGS_FAIL_ON_ERROR | OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, 0L ); #endif /*--------------------------------------------------------------------*/ /* Check the open worked. We translation the common obvious */ /* error of file in use to english, for all other errors are we */ /* report the raw error code. */ /*--------------------------------------------------------------------*/ #ifdef WIN32 if (hCom == INVALID_HANDLE_VALUE) { dwError = GetLastError(); printmsg(0, "openline: OpenFile Error %d on port %s", dwError, name); return TRUE; } #else if ( rc == ERROR_SHARING_VIOLATION) { printmsg(0,"Port %s already in use", name); return TRUE; } else if ( rc != 0 ) { printmsg(0,"openline: DosOpen error %d on port %s", (int) rc, name ); return TRUE; } #endif /*--------------------------------------------------------------------*/ /* Check for special test mode */ /*--------------------------------------------------------------------*/ if ( equal(name,"CON")) { port_active = TRUE; /* record status for error handler */ carrierdetect = FALSE; /* Modem is not connected */ console = TRUE; return 0; } console = FALSE; /*--------------------------------------------------------------------*/ /* Reset any errors on the communications port */ /*--------------------------------------------------------------------*/ #ifdef WIN32 rc = ClearCommError (hCom, &Error, NULL); if (!rc) { printmsg(0, "openline: Error in ClearCommError() call\n"); printmsg(0, "Error returned was %d\n", Error); } #else /* OS/2 */ rc = DosDevIOCtl( &com_error, FAR_NULL, ASYNC_GETCOMMERROR , IOCTL_ASYNC, com_handle); if (rc) { printmsg(0, "openline: Unable to read errors for %s, error bits %x", name, (int) com_error ); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); } /*if */ else if ( com_error ) ShowError( com_error ); #endif /*--------------------------------------------------------------------*/ /* Set baud rate */ /*--------------------------------------------------------------------*/ SIOSpeed(baud); /*--------------------------------------------------------------------*/ /* Set line attributes */ /*--------------------------------------------------------------------*/ #ifdef UDEBUG printmsg(15,"openline: Getting attributes"); #endif #ifdef WIN32 rc = GetCommState(hCom, &dcb); if (!rc) { printmsg(0,"openline: Unable to get line attributes for %s",name); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } dcb.StopBits = ONESTOPBIT; dcb.Parity = NOPARITY; dcb.ByteSize = 8; #else /* OS/2 */ rc = DosDevIOCtl( &com_attrib, FAR_NULL, ASYNC_GETLINECTRL, IOCTL_ASYNC, com_handle); /* Get old attributes from device */ if (rc) { printmsg(0,"openline: Unable to get line attributes for %s",name); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ com_attrib.bDataBits = 0x08; /* Use eight bit path for data */ com_attrib.bParity = 0x00; /* No parity */ com_attrib.bStopBits = 0x00; /* 1 Stop Bit */ #endif #ifdef UDEBUG printmsg(15,"openline: Setting attributes"); #endif #ifdef WIN32 rc = SetCommState(hCom, &dcb); if (!rc) { printmsg(0,"openline: Unable to set line attributes for %s",name); panic(); } #else /* OS/2 */ rc = DosDevIOCtl( FAR_NULL, &com_attrib, ASYNC_SETLINECTRL, IOCTL_ASYNC, com_handle); if (rc) { printmsg(0,"openline: Unable to set line attributes for %s",name); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ #endif /*--------------------------------------------------------------------*/ /* Disable XON/XOFF flow control */ /* Enable CTS handling for flow control */ /*--------------------------------------------------------------------*/ #ifdef UDEBUG printmsg(15,"openline: Getting flow control information"); #endif #ifdef WIN32 GetCommState(hCom, &dcb); dcb.fOutX = 0; dcb.fInX = 0; dcb.fOutxCtsFlow = 1; rc = SetCommState(hCom, &dcb); if (!rc) { printmsg(0,"openline: Unable to set comm attributes for %s",name); panic(); } /* Get communications timeout information */ rc = GetCommTimeouts(hCom, &CommTimeout); if (!rc) { Error = GetLastError(); printmsg(0, "openline: error on GetCommTimeouts() on %s: error %d", name, Error); panic(); } #else /* OS/2 */ rc = DosDevIOCtl( &com_dcbinfo, FAR_NULL, ASYNC_GETDCBINFO, IOCTL_ASYNC, com_handle); /* Get old attributes from device */ if (rc) { printmsg(0,"openline: Unable to get line attributes for %s",name); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ com_dcbinfo.usWriteTimeout = 2999; /* Write timeout 30 seconds */ com_dcbinfo.usReadTimeout = 24; /* Read timeout .25 seconds */ com_dcbinfo.fbCtlHndShake = (BYTE) (direct ? 0 : MODE_CTS_HANDSHAKE); com_dcbinfo.fbFlowReplace = 0; /* Unless rquested */ com_dcbinfo.fbTimeout = MODE_READ_TIMEOUT | MODE_NO_WRITE_TIMEOUT; #ifdef UDEBUG printmsg(15,"openline: Setting dcb information"); #endif rc = DosDevIOCtl( FAR_NULL, &com_dcbinfo, ASYNC_SETDCBINFO, IOCTL_ASYNC, com_handle); if ( rc ) { printmsg(0,"openline: Unable to set flow control for %s",name); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ #endif /*--------------------------------------------------------------------*/ /* Raise Data Terminal Ready */ /*--------------------------------------------------------------------*/ #ifdef WIN32 GetCommState(hCom, &dcb); dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE; rc = SetCommState(hCom, &dcb); if (!rc) { printmsg(0, "openline: Unable to raise DTR/RTS for %s", name); panic(); } #else /* OS/2 */ com_signals.fbModemOn = DTR_ON | RTS_ON ; com_signals.fbModemOff = 0xff; #ifdef UDEBUG printmsg(15,"openline: Raising RTS/DTR"); #endif rc = DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL, IOCTL_ASYNC, com_handle); if (rc) { printmsg(0, "openline: Unable to raise DTR/RTS for %s, error bits %#x", name, (int) com_error ); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ #endif /*--------------------------------------------------------------------*/ /* Log serial line data only if log file already exists */ /*--------------------------------------------------------------------*/ log_handle = open(LINELOG, O_WRONLY | O_TRUNC | O_BINARY); if (log_handle != -1) { #ifdef UDEBUG printmsg(15, "openline: logging serial line data to %s", LINELOG); #endif log_stream = fdopen(log_handle, "wb"); } port_active = TRUE; /* record status for error handler */ carrierdetect = FALSE; /* Modem is not connected */ /*--------------------------------------------------------------------*/ /* Up our processing priority */ /*--------------------------------------------------------------------*/ #ifdef WIN32 hProcess = GetCurrentProcess(); rc = SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS); if (!rc) { printmsg(0, "openline: unable to set priority for process"); panic(); } #else /* OS/2 */ rc = DosGetPrty(PRTYS_PROCESS, &usPrevPriority, 0); if (rc) { printmsg(0,"openline: Unable to get priority for task"); printmsg(0,"Return code from DosGetPrty was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ rc = DosSetPrty(PRTYS_PROCESS, priority, prioritydelta, 0); if (rc) { printmsg(0,"openline: Unable to set priority %u,%u for task", priority, prioritydelta); printmsg(0,"Return code from DosSetPrty was %#04x (%d)", (int) rc , (int) rc); } /*if */ #endif /*--------------------------------------------------------------------*/ /* Wait for port to stablize */ /*--------------------------------------------------------------------*/ ddelay(500); /* Allow port to stablize */ return 0; } /*openline*/ /*--------------------------------------------------------------------*/ /* s r e a d */ /* */ /* Read from the serial port */ /* */ /* Non-blocking read essential to "g" protocol. See "dcpgpkt.c" */ /* for description. */ /* */ /* 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. */ /* */ /* OS/2 we could multitask, but we just let the system provide */ /* a timeout for us with very little CPU usage. */ /*--------------------------------------------------------------------*/ unsigned int sread(char *output, unsigned int wanted, unsigned int timeout) { #ifdef WIN32 static LPVOID psave; DWORD Error; BOOL rc; #else /* OS/2 */ USHORT rc; #endif static char save[BUFSIZ]; static USHORT bufsize = 0; time_t stop_time ; time_t now ; /*--------------------------------------------------------------------*/ /* Determine if our internal buffer has the data */ /*--------------------------------------------------------------------*/ if (bufsize >= wanted) { memmove( output, save, wanted ); bufsize -= wanted; if ( bufsize ) /* Any data left over? */ memmove( save, &save[wanted], bufsize ); /* Yes --> Save it*/ return wanted + bufsize; } /* if */ /*--------------------------------------------------------------------*/ /* Reset any errors on the communications port */ /*--------------------------------------------------------------------*/ #ifdef WIN32 rc = ClearCommError (hCom, &Error, NULL); if (!rc) { printmsg(0, "sread: Unable to read port errors\n"); printmsg(0, "Error mask was set to %d\n", Error); } #else /* OS/2 */ rc = DosDevIOCtl( &com_error, FAR_NULL, ASYNC_GETCOMMERROR , IOCTL_ASYNC, com_handle); if (rc && ! console ) { printmsg(0,"sread: Unable to read port errors"); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); } /*if */ else if ( com_error ) ShowError( com_error ); #endif /*--------------------------------------------------------------------*/ /* Determine when to stop processing */ /*--------------------------------------------------------------------*/ if ( timeout == 0 ) { stop_time = 0; now = 1; /* Any number greater than stop time */ } else { time( & now ); stop_time = now + timeout; } /*--------------------------------------------------------------------*/ /* Try to read any needed data into the buffer */ /*--------------------------------------------------------------------*/ do { #ifdef WIN32 DWORD received; DWORD needed = wanted - bufsize; DWORD port_timeout; #else /* OS/2 */ USHORT needed = (USHORT) wanted - bufsize; USHORT port_timeout; USHORT received = 0; #endif /*--------------------------------------------------------------------*/ /* Handle an aborted program */ /*--------------------------------------------------------------------*/ if ( terminate_processing ) { static boolean recurse = FALSE; if ( ! recurse ) { printmsg(2,"sread: User aborted processing"); recurse = TRUE; } return 0; } /*--------------------------------------------------------------------*/ /* Compute a new timeout for the read, if needed */ /*--------------------------------------------------------------------*/ if (stop_time > now ) { port_timeout = (USHORT) (stop_time - now) / needed * 100; if (port_timeout < 100) port_timeout = 100; } else port_timeout = 0; #ifdef WIN32 if (!console) { port_timeout *= 10; /* OS/2 is in hundredths; NT in msec */ CommTimeout.ReadTotalTimeoutConstant = 0; CommTimeout.WriteTotalTimeoutConstant = 0; CommTimeout.ReadIntervalTimeout = port_timeout; CommTimeout.ReadTotalTimeoutMultiplier = 1; CommTimeout.WriteTotalTimeoutMultiplier = 0; rc = SetCommTimeouts(hCom, &CommTimeout); if ( !rc ) { LPVOID lpMessageBuffer; Error = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, Error, LANG_USER_DEFAULT, &lpMessageBuffer, 0, NULL); printmsg(0, "sread: unable to set timeout for comm port"); printmsg(0, "sread: %s", lpMessageBuffer); LocalFree((HLOCAL)lpMessageBuffer); panic(); } } #else /* OS/2 */ if (( port_timeout != com_dcbinfo.usReadTimeout ) && ! console ) { com_dcbinfo.usReadTimeout = port_timeout; rc = DosDevIOCtl(FAR_NULL, &com_dcbinfo, ASYNC_SETDCBINFO, IOCTL_ASYNC, com_handle); if ( rc ) { printmsg(0,"sread: Unable to set timeout for comm port"); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /* if */ } /* if */ #endif #ifdef UDEBUG printmsg(15,"sread: Port time out is %ud seconds/100", port_timeout); #endif /*--------------------------------------------------------------------*/ /* Read the data from the serial port */ /*--------------------------------------------------------------------*/ #ifdef WIN32 rc = ReadFile (hCom, &save[bufsize], needed, &received, NULL); if (!rc) { printmsg(0, "sread: Read from comm port for %d bytes failed, received = %d.", needed, received); bufsize = 0; return 0; } #else /* OS/2 */ rc = DosRead( com_handle, &save[bufsize], needed, &received ); if ( rc == ERROR_INTERRUPT) { printmsg(2,"Read Interrupted"); return 0; } else if ( rc != 0 ) { printmsg(0,"sread: Read from comm port for %d bytes failed.", needed); printmsg(0,"Return code from DosRead was %#04x (%d)", (int) rc , (int) rc); bufsize = 0; return 0; } #endif #ifdef UDEBUG printmsg(15,"sread: Want %d characters, received %d, total %d in buffer", (int) wanted, (int) received, (int) bufsize + received); #endif /*--------------------------------------------------------------------*/ /* Log the newly received data */ /*--------------------------------------------------------------------*/ if (log_handle != -1) { #ifdef VERBOSE size_t column; #endif if (logmode != READING) { fputs("\nRead: ", log_stream); logmode = READING; } /* if */ #ifdef VERBOSE for (column = 0; column < received; column++) { char s[18]; itoa(0x100 | (unsigned) save[bufsize + column], s, 16); /* Make it printable hex */ fwrite(s, 1, 2, log_stream); /* Write hex to the log */ } /* for */ #else fwrite(&save[bufsize], 1, received, log_stream); #endif } /* if */ /*--------------------------------------------------------------------*/ /* If we got the data, return it to the caller */ /*--------------------------------------------------------------------*/ bufsize += received; if ( bufsize == wanted ) { memmove( output, save, bufsize); bufsize = 0; if (debuglevel > 14) fwrite(output,1,bufsize,stdout); return wanted; } /* if */ /*--------------------------------------------------------------------*/ /* Update the clock for the next pass */ /*--------------------------------------------------------------------*/ if (stop_time > 0) time( &now ); } while (stop_time > now); /*--------------------------------------------------------------------*/ /* We don't have enough data; report what we do have */ /*--------------------------------------------------------------------*/ return bufsize; } /*sread*/ /*--------------------------------------------------------------------*/ /* s w r i t e */ /* */ /* Write to the serial port */ /*--------------------------------------------------------------------*/ int swrite(char *data, unsigned int len) { #ifdef WIN32 DWORD bytes; BOOL rc; #else size_t bytes; USHORT rc; #endif hangup_needed = TRUE; /* Flag that the port is now dirty */ /*--------------------------------------------------------------------*/ /* Write the data out as the queue becomes available */ /*--------------------------------------------------------------------*/ #ifdef WIN32 rc = WriteFile (hCom, data, len, &bytes, NULL); if (!rc) { printmsg(0,"swrite: Write to communications port failed."); return bytes; } #else /* OS/2 */ rc = DosWrite( com_handle, data , len, &bytes); if (rc) { printmsg(0,"swrite: Write to communications port failed."); printmsg(0,"Return code from DosWrite was %#04x (%d)", (int) rc , (int) rc); return bytes; } /*if */ #endif /*--------------------------------------------------------------------*/ /* Log the data written */ /*--------------------------------------------------------------------*/ if (log_handle != -1) { #ifdef VERBOSE char s[18]; #endif if (logmode != WRITING) { fputs("\nWrite: ", log_stream); logmode = WRITING; } #ifdef VERBOSE for (bytes = 0; bytes < len; bytes++) { itoa(0x100 | (unsigned) *data++, s, 16); /* Make it printable hex ahd */ fputc(s[1], log_stream); /* Put it in the log */ fputc(s[2], log_stream); /* Put it in the log */ } #else fwrite(data, 1, len, log_stream); #endif } /*--------------------------------------------------------------------*/ /* Return bytes written to the port to the caller */ /*--------------------------------------------------------------------*/ return len; } /*swrite*/ /*--------------------------------------------------------------------*/ /* s s e n d b r k */ /* */ /* send a break signal out the serial port */ /*--------------------------------------------------------------------*/ void ssendbrk(unsigned int duration) { #ifdef UDEBUG printmsg(12, "ssendbrk: %d", duration); #endif #ifdef WIN32 SetCommBreak(hCom); #else /* OS/2 */ DosDevIOCtl( &com_error, FAR_NULL, ASYNC_SETBREAKON, IOCTL_ASYNC, com_handle); if ( com_error ) ShowError( com_error ); #endif ddelay( duration == 0 ? 200 : duration); #ifdef WIN32 ClearCommBreak(hCom); #else /* OS/2 */ DosDevIOCtl( &com_error, FAR_NULL, ASYNC_SETBREAKOFF, IOCTL_ASYNC, com_handle); if ( com_error ) ShowError( com_error ); #endif } /*ssendbrk*/ /*--------------------------------------------------------------------*/ /* c l o s e l i n e */ /* */ /* Close the serial port down */ /*--------------------------------------------------------------------*/ void closeline(void) { USHORT rc; #ifdef WIN32 HANDLE hProcess; #endif if ( ! port_active ) panic(); port_active = FALSE; /* flag port closed for error handler */ hangup_needed = FALSE; /* Don't fiddle with port any more */ /*--------------------------------------------------------------------*/ /* Lower priority */ /*--------------------------------------------------------------------*/ #ifdef WIN32 hProcess = GetCurrentProcess(); rc = SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS); if (!rc) { printmsg(0, "closeline: Unable to lower priority for task"); panic(); } #else /* OS/2 */ rc = DosSetPrty(PRTYS_PROCESS, usPrevPriority >> 8 , usPrevPriority & 0xff, 0); if (rc) { printmsg(0,"closeline: Unable to set priority for task"); printmsg(0,"Return code from DosSetPrty was %#04x (%d)", (int) rc , (int) rc); } /*if */ #endif /*--------------------------------------------------------------------*/ /* Lower DTR */ /*--------------------------------------------------------------------*/ #ifdef WIN32 if (!EscapeCommFunction(hCom, CLRDTR | CLRRTS)) { printmsg(0,"closeline: Unable to lower DTR/RTS"); } #else /* OS/2 */ com_signals.fbModemOn = 0x00; com_signals.fbModemOff = DTR_OFF | RTS_OFF; if (DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL, IOCTL_ASYNC, com_handle)) { printmsg(0,"closeine: Unable to lower DTR/RTS for port"); } /*if */ else if ( com_error ) ShowError( com_error ); #endif /*--------------------------------------------------------------------*/ /* Actually close the port */ /*--------------------------------------------------------------------*/ #ifdef WIN32 if(!CloseHandle(hCom)) { printmsg(0, "closeline: close of serial port failed, reason %d", GetLastError()); } #else /* OS/2 */ rc = DosClose( com_handle ); if ( rc != 0 ) printmsg( 0,"Close of serial port failed, reason %d", (int) rc); #endif /*--------------------------------------------------------------------*/ /* Stop logging the data to disk */ /*--------------------------------------------------------------------*/ if (log_handle != -1) { /* close serial line log file */ fclose(log_stream); close(log_handle); }; printmsg(3,"Serial port closed"); } /* closeline */ /*--------------------------------------------------------------------*/ /* H a n g u p */ /* */ /* Hangup the telephone by dropping DTR. Works with HAYES and */ /* many compatibles. */ /* 14 May 89 Drew Derbyshire */ /*--------------------------------------------------------------------*/ void hangup( void ) { if (!hangup_needed) return; hangup_needed = FALSE; if ( console ) return; /*--------------------------------------------------------------------*/ /* Drop DTR */ /*--------------------------------------------------------------------*/ #ifdef WIN32 if (!EscapeCommFunction(hCom, CLRDTR)) { printmsg(0, "hangup: Unable to lower DTR for comm port"); panic(); } #else /* OS/2 */ com_signals.fbModemOn = 0x00; com_signals.fbModemOff = DTR_OFF; if (DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL, IOCTL_ASYNC, com_handle)) { printmsg(0,"hangup: Unable to lower DTR for comm port"); panic(); } /*if */ else if ( com_error ) ShowError( com_error ); #endif /*--------------------------------------------------------------------*/ /* Wait for the telephone to hangup */ /*--------------------------------------------------------------------*/ printmsg(3,"hangup: Dropped DTR"); carrierdetect = FALSE; /* Modem is not connected */ ddelay(500); /* Really only need 250 milliseconds */ /*--------------------------------------------------------------------*/ /* Bring DTR back up */ /*--------------------------------------------------------------------*/ #ifdef WIN32 if (!EscapeCommFunction(hCom, SETDTR)) { printmsg(0, "hangup: Unable to raise DTR for comm port"); panic(); } #else /* OS/2 */ com_signals.fbModemOn = DTR_ON; com_signals.fbModemOff = 0xff; if (DosDevIOCtl( &com_error, &com_signals, ASYNC_SETMODEMCTRL, IOCTL_ASYNC, com_handle)) { printmsg(0,"hangup: Unable to raise DTR for comm port"); panic(); } /*if */ else if ( com_error ) ShowError( com_error ); #endif ddelay(2000); /* Now wait for the poor thing to recover */ } /* hangup */ /*--------------------------------------------------------------------*/ /* S I O S p e e d */ /* */ /* Re-specify the speed of an opened serial port */ /* */ /* Dropped the DTR off/on calls because this makes a Hayes drop */ /* the line if configured properly, and we don't want the modem */ /* to drop the phone on the floor if we are performing */ /* autobaud. */ /* */ /* (Configured properly = standard method of making a Hayes */ /* hang up the telephone, especially when you can't get it into */ /* command state because it is at the wrong speed or whatever.) */ /*--------------------------------------------------------------------*/ void SIOSpeed(BPS baud) { USHORT rc; #ifdef UDEBUG printmsg(15,"SIOSpeed: Setting baud rate to %u", (unsigned int) baud); #endif #ifdef WIN32 GetCommState (hCom, &dcb); dcb.BaudRate = baud; rc = SetCommState (hCom, &dcb); if (!rc && !console) { printmsg(0,"SIOSpeed: Unable to set baud rate for port to %d",baud); panic(); } #else /* OS/2 */ rc = DosDevIOCtl( FAR_NULL, &baud, ASYNC_SETBAUDRATE, IOCTL_ASYNC, com_handle); if (rc && ! console ) { printmsg(0,"SIOSPeed: Unable to set baud rate for port to %d", baud); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ #endif current_baud = baud; } /* SIOSpeed */ /*--------------------------------------------------------------------*/ /* f l o w c o n t r o l */ /* */ /* Enable/Disable in band (XON/XOFF) flow control */ /*--------------------------------------------------------------------*/ void flowcontrol( boolean flow ) { USHORT rc; #ifdef WIN32 DCB dcb; #endif if ( console ) return; #ifdef WIN32 GetCommState(hCom, &dcb); if (flow) { dcb.fOutX = TRUE; dcb.fInX = TRUE; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fOutxCtsFlow = FALSE; } else { dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fOutxCtsFlow = TRUE; } rc = SetCommState(hCom, &dcb); if ( !rc ) { printmsg(0,"flowcontrol: Unable to set flow control"); printmsg(0,"Return code from SetCommState() was %d", GetLastError()); panic(); } /*if */ #else /* OS/2 */ if ( flow ) com_dcbinfo.fbFlowReplace = (char) (com_dcbinfo.fbFlowReplace | (MODE_AUTO_TRANSMIT | MODE_AUTO_RECEIVE)); else com_dcbinfo.fbFlowReplace = (char) (com_dcbinfo.fbFlowReplace & (0xff - MODE_AUTO_TRANSMIT - MODE_AUTO_RECEIVE)); rc = DosDevIOCtl( FAR_NULL, &com_dcbinfo, ASYNC_SETDCBINFO, IOCTL_ASYNC, com_handle); if ( rc ) { printmsg(0,"flowcontrol: Unable to set flow control"); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ #endif } /*flowcontrol*/ /*--------------------------------------------------------------------*/ /* G e t S p e e d */ /* */ /* Report current speed of communications connection */ /*--------------------------------------------------------------------*/ BPS GetSpeed( void ) { return current_baud; } /* GetSpeed */ /*--------------------------------------------------------------------*/ /* C D */ /* */ /* Return status of carrier detect */ /*--------------------------------------------------------------------*/ boolean CD( void ) { boolean previous_carrierdetect = carrierdetect; USHORT rc; #ifdef WIN32 DWORD status; static DWORD oldstatus = (DWORD) 0xDEADBEEF; #else /* OS/2 */ BYTE status; static BYTE oldstatus = (BYTE) 0xDEAD; #endif if ( console ) return feof( stdin ) == 0; #ifdef WIN32 rc = GetCommModemStatus(hCom, &status); if ( !rc ) { printmsg(0,"CD: Unable to get modem status"); printmsg(0,"Return code from GetCommModemStatus() was %d", GetLastError()); panic(); } /*if */ #else /* OS/2 */ rc = DosDevIOCtl( &status, 0L, ASYNC_GETMODEMINPUT, IOCTL_ASYNC, com_handle ); if ( rc ) { printmsg(0,"CD: Unable to get modem status"); printmsg(0,"Return code from DosDevIOCtl was %#04x (%d)", (int) rc , (int) rc); panic(); } /*if */ #endif if ( status != oldstatus ) { ShowModem( status ); oldstatus = status; } /*--------------------------------------------------------------------*/ /* 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. */ /*--------------------------------------------------------------------*/ #ifdef WIN32 carrierdetect = status && MS_RLSD_ON; if (previous_carrierdetect) return (status && (MS_RLSD_ON || MS_DSR_ON)) == (MS_RLSD_ON || MS_DSR_ON); else return (status && MS_DSR_ON); #else /* OS/2 */ carrierdetect = status && DCD_ON; if (previous_carrierdetect) return carrierdetect; else return (status && DSR_ON); #endif } /* CD */ /*--------------------------------------------------------------------*/ /* S h o w M o d e m */ /* */ /* Report current modem status */ /*--------------------------------------------------------------------*/ #define mannounce(flag, bits, text ) ((flag & bits) ? text : "" ) #ifdef WIN32 static void ShowModem( const DWORD status ) { if ( debuglevel < 4 ) return; printmsg(0, "ShowModem: %#02x%s%s%s%s", status, mannounce(MS_RLSD_ON, status, " Carrier Detect"), mannounce(MS_RING_ON, status, " Ring Indicator"), mannounce(MS_DSR_ON, status, " Data Set Ready"), mannounce(MS_CTS_ON, status, " Clear to Send")); } /* ShowModem */ #else /* OS/2 */ static void ShowModem( const BYTE status ) { if ( debuglevel < 4 ) return; printmsg(0, "ShowModem: %#02x%s%s%s%s", (int) status, mannounce(DCD_ON, status, " Carrier Detect"), mannounce(RI_ON, status, " Ring Indicator"), mannounce(DSR_ON, status, " Data Set Ready"), mannounce(CTS_ON, status, " Clear to Send")); } /* ShowModem */ #endif #ifdef WIN32 #else /*--------------------------------------------------------------------*/ /* S h o w E r r o r */ /* */ /* Report modem error bits in English (more or less) */ /*--------------------------------------------------------------------*/ static void ShowError( const USHORT status ) { printmsg(2, "Port Error: %#04x%s%s%s%s", (int) status, mannounce(RX_QUE_OVERRUN, status, " Queue Overrrun"), mannounce(RX_HARDWARE_OVERRUN, status, " Hardware Overrun"), mannounce(PARITY_ERROR, status, " Parity Error"), mannounce(FRAMING_ERROR, status, " Framing Error")); } /* ShowError */ #endif