home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
comos2.zip
/
COMMOS2.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-02-21
|
22KB
|
888 lines
/**************************************************************************
*
* COMMOS2.CPP
*
* This file contains the 32-bit routines which provide the CommPort
* class methods
*
* This file was compiled with the IBM C/C++ beta compiler using the
* following flags:
*
* /Fd /Tdp /G3m+s-d-e+ /O /Re /C /W3gen+ppc+enu+par+
*_________________________________________________________________________
*
* Copyright (c) 1992 by ASH Software, Inc.
*
* Update History
*
* 11/28/1992 - Module created
*
**************************************************************************/
#include "COMM.HPP"
/*------------------------------------------------------------------------*
* CommPort
*
* This is the class constructor which initializes each instance of the
* class.
*------------------------------------------------------------------------*/
CommPort::CommPort(VOID)
{
//
// Initialize the Comm data
//
ulCommError = COMM_ERROR_NOERROR;
ulDosError = NO_ERROR;
hCommPort = 0;
ulCommMode = COMM_MODE_NOTSTARTED;
fPortOpen = FALSE;
fPortOpened = FALSE;
return;
}
/*------------------------------------------------------------------------*
* ~CommPort
*
* This is the class destructor.
*------------------------------------------------------------------------*/
CommPort::~CommPort(VOID)
{
if (fPortOpen)
Close();
return;
}
/*------------------------------------------------------------------------*
* GetLastError
*
* This method returns information concerning the last error for the
* port.
*------------------------------------------------------------------------*/
ULONG CommPort::GetLastError(PULONG pulCommError,PULONG pulDosError,
PULONG pulCommMode)
{
if (!fPortOpen)
return COMM_ERROR_PORTNOTFOUND; // Unable to locate comm port
(*pulCommError) = ulCommError;
(*pulDosError) = ulDosError;
(*pulCommMode) = ulCommMode;
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* Open
*
* This method invokes DosOpen to open the specified serial comm port.
*------------------------------------------------------------------------*/
ULONG CommPort::Open(INT iCommPort)
{
INT
iLoop,
fKeepLooping;
ULONG
ulParmLength,
ulAction,
ulRC;
CHAR
cPortName[21];
LINECONTROL
COMParams;
fPortOpened=TRUE;
sprintf(cPortName,"COM%d",iCommPort);
ulRC=DosOpen(cPortName,&hCommPort,&ulAction,0L,
FILE_NORMAL,FILE_OPEN,
OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE,
NULL);
if (ulRC)
{
fPortOpen = FALSE;
ulCommError = COMM_ERROR_OPENFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_OPEN;
return COMM_ERROR_OPENFAILED;
}
else
{
ulCommError = COMM_ERROR_NOERROR;
ulDosError = NO_ERROR;
ulCommMode = COMM_MODE_OPEN;
fPortOpen = TRUE;
}
//
// Create/Initialize the read & write semaphores
//
ulRC=DosCreateMutexSem(NULL,&hCommWriteSem,0L,FALSE);
if (ulRC)
return COMM_ERROR_SEMAPHOREFAILED;
ulRC=DosCreateMutexSem(NULL,&hCommReadSem,0L,FALSE);
if (ulRC)
return COMM_ERROR_SEMAPHOREFAILED;
//
// Initialize the DCB structure
//
ulRC=GetDCBInfo();
if (ulRC)
return COMM_ERROR_DCBINFOFAILED;
DCBOriginal=DCBInfo;
//
// Initialize other parameters
//
ulParmLength=sizeof(LINECONTROL);
ulRC=DosDevIOCtl(hCommPort,IOCTL_ASYNC,ASYNC_GETLINECTRL,
NULL,0L,NULL,&COMParams,ulParmLength,&ulParmLength);
usDataBits = COMParams.bDataBits;
usParity = COMParams.bParity;
usStopBits = COMParams.bStopBits;
usTxBreak = COMParams.fTransBreak;
if (ulRC)
return COMM_ERROR_BAUDFAILED;
ulParmLength=sizeof(short);
ulRC=DosDevIOCtl(hCommPort,IOCTL_ASYNC,ASYNC_GETBAUDRATE,
NULL,0L,NULL,&usBaudRate,ulParmLength,&ulParmLength);
if (ulRC)
return COMM_ERROR_BAUDFAILED;
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* Initialize
*
* This method initializes a serial comm port by calling the
* DosDevIOCtl routine with the proper parameters.
*------------------------------------------------------------------------*/
ULONG CommPort::Initialize(USHORT usBaudRate,USHORT usParity,
USHORT usDataBits,USHORT usStopBits,
USHORT usTxBreak)
{
USHORT
usErrorCode;
ULONG
ulParmLength,
ulDataLength,
ulRC;
LINECONTROL
COMParams;
//
// Set the baud rate
//
ulParmLength=sizeof(USHORT);
ulRC=DosDevIOCtl(hCommPort,IOCTL_ASYNC,ASYNC_SETBAUDRATE,
&usBaudRate,ulParmLength,&ulParmLength,
NULL,0L,NULL);
if (ulRC)
{
ulCommError = COMM_ERROR_BAUDFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_SETBAUD;
return COMM_ERROR_BAUDFAILED;
}
//
// Set the number of bits, parity, stop bits, and Transmit break
//
COMParams.bDataBits =(unsigned char)usDataBits; // Set data bits
COMParams.bParity =(unsigned char)usParity; // Set parity
COMParams.bStopBits =(unsigned char)usStopBits; // Set stop bits
COMParams.fTransBreak=(unsigned char)usTxBreak; // Set Transmit break
ulParmLength=sizeof(LINECONTROL);
ulRC=DosDevIOCtl(hCommPort,IOCTL_ASYNC,ASYNC_SETLINECTRL,
&COMParams,ulParmLength,&ulParmLength,
NULL,0L,NULL);
if (ulRC)
{
ulCommError = COMM_ERROR_LINECNTRLFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_SETLINECNTRL;
return COMM_ERROR_LINECNTRLFAILED;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* ClearBuffers
*
* This method clears both the transmit and receive buffers for the
* com port.
*------------------------------------------------------------------------*/
ULONG CommPort::ClearBuffers(VOID)
{
ULONG
ulRC;
ulRC=ClearTxBuffer();
if (!ulRC)
ulRC=ClearRxBuffer();
return ulRC;
}
/*------------------------------------------------------------------------*
* ClearTxBuffer
*
* This method clears the transmit buffer for the com port.
*------------------------------------------------------------------------*/
ULONG CommPort::ClearTxBuffer(VOID)
{
UCHAR
ucZero;
ULONG
ulRC,
ulParmLength;
ucZero=0;
ulParmLength=sizeof(UCHAR);
ulRC=DosDevIOCtl(hCommPort,IOCTL_GENERAL,DEV_FLUSHOUTPUT,
&ucZero,ulParmLength,&ulParmLength,
NULL,0L,NULL);
if (ulRC)
{
ulCommError = COMM_ERROR_CLEARBUFFERFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_CLEARTXBUFFER;
return COMM_ERROR_CLEARBUFFERFAILED;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* ClearRxBuffer
*
* This methoc clears receive buffer for the com port
*------------------------------------------------------------------------*/
ULONG CommPort::ClearRxBuffer(VOID)
{
UCHAR
ucZero;
ULONG
ulRC,
ulParmLength;
ucZero=0;
ulParmLength=sizeof(UCHAR);
ulRC=DosDevIOCtl(hCommPort,IOCTL_GENERAL,DEV_FLUSHINPUT,
&ucZero,ulParmLength,&ulParmLength,
NULL,0L,NULL);
if (ulRC)
{
ulCommError = COMM_ERROR_CLEARBUFFERFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_CLEARRXBUFFER;
return COMM_ERROR_CLEARBUFFERFAILED;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* Close
*
* This method invokes DosClose to close a serial comm port.
*------------------------------------------------------------------------*/
ULONG CommPort::Close(VOID)
{
ULONG
ulDCBSize;
if (!fPortOpened)
return COMM_ERROR_PORTNOTFOUND; // Unable to locate comm port
if (fPortOpen)
{
ulDCBSize=sizeof(DCBINFO);
DosDevIOCtl(hCommPort,IOCTL_ASYNC,ASYNC_SETDCBINFO,
&DCBOriginal,ulDCBSize,&ulDCBSize,NULL,0L,NULL);
Initialize(usBaudRate,usParity,usDataBits,usStopBits,usTxBreak);
DosClose(hCommPort);
}
DosCloseMutexSem(hCommReadSem);
DosCloseMutexSem(hCommWriteSem);
ulCommError = COMM_ERROR_NOERROR;
ulDosError = NO_ERROR;
ulCommMode = COMM_MODE_NOTSTARTED;
fPortOpen = FALSE;
fPortOpened = FALSE;
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* Write
*
* This method invokes DosWrite to write the data to the serial comm
* port.
*------------------------------------------------------------------------*/
ULONG CommPort::Write(PUCHAR pucDataArea,ULONG ulDataAreaSize,
PULONG pulWritten)
{
ULONG
ulRC;
ulRC=DosRequestMutexSem(hCommWriteSem,COMMOS2_RESOURCE_SEM_WAIT);
if (ulRC)
{
ulCommError = COMM_ERROR_SEMAPHOREFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_WRITE;
return COMM_ERROR_SEMAPHOREFAILED;
}
ulRC=DosWrite(hCommPort,pucDataArea,ulDataAreaSize,pulWritten);
DosReleaseMutexSem(hCommWriteSem);
if (ulRC)
{
ulCommError = COMM_ERROR_WRITEFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_WRITE;
return COMM_ERROR_WRITEFAILED;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* Read
*
* This method invokes DosRead to read the data from the serial comm
* port. This routine reads whatever data is currently available from
* the port buffer. It does not wait for information to arrive.
*------------------------------------------------------------------------*/
ULONG CommPort::Read(PUCHAR pucDataArea,ULONG ulDataAreaSize,
PULONG pulRead)
{
ULONG
ulRC;
ulRC=DosRequestMutexSem(hCommReadSem,COMMOS2_RESOURCE_SEM_WAIT);
if (ulRC)
{
ulCommError = COMM_ERROR_SEMAPHOREFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_READ;
return COMM_ERROR_SEMAPHOREFAILED;
}
ulRC=DosRead(hCommPort,pucDataArea,ulDataAreaSize,pulRead);
DosReleaseMutexSem(hCommReadSem);
if (ulRC)
{
ulCommError = COMM_ERROR_READFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_READ;
return COMM_ERROR_WRITEFAILED;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* ReadTimeOut
*
* This method invokes DosRead and DosDevIOCtl to either read the
* specified number of characters or to return once the timeout specified
* has elapsed.
*------------------------------------------------------------------------*/
ULONG CommPort::ReadTimeOut(PUCHAR pucDataArea,ULONG ulDataAreaSize,
PULONG pulRead,LONG lTimeOutmSec)
{
INT
fCheck,
fKeepWaiting;
ULONG
ulStartTime,
ulTimeOut,
ulCharCount,
ulSleepTime,
ulReadRC,
ulRC;
ulRC=DosRequestMutexSem(hCommReadSem,COMMOS2_RESOURCE_SEM_WAIT);
if (ulRC)
{
ulCommError = COMM_ERROR_SEMAPHOREFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_READTIMEOUT;
return COMM_ERROR_SEMAPHOREFAILED;
}
ulStartTime=TimerValue();
ulTimeOut=lTimeOutmSec/10L;
ulSleepTime=1L;
fKeepWaiting=TRUE;
if (lTimeOutmSec == TIMEOUT_INDEFINITE)
fCheck=FALSE;
else
fCheck=TRUE;
ulReadRC=COMM_ERROR_NOERROR;
do
{
ulRC=QueryQueue(COMM_QUERY_RXCOUNT,&ulCharCount);
if (ulRC)
{
ulCommError = COMM_ERROR_IOCTLFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_READTIMEOUT;
DosReleaseMutexSem(hCommReadSem);
return COMM_ERROR_IOCTLFAILED;
}
if (ulCharCount >= ulDataAreaSize)
{
//
// The number of characters requested are available. Read the data
// and return to the calling program.
//
fKeepWaiting=FALSE;
ulReadRC=Read(pucDataArea,ulDataAreaSize,pulRead);
}
else
{
//
// The requested number of characters are not available at this
// time. Test to see if the specified time has elapsed and return
// to the calling program if it has.
//
if (fCheck && (TimerDifference(ulStartTime) > ulTimeOut))
{
fKeepWaiting=FALSE;
(*pulRead)=0;
ulCommError = COMM_ERROR_TIMEOUTEXCEEDED;
ulDosError = NO_ERROR;
ulCommMode = COMM_MODE_READTIMEOUT;
ulReadRC=COMM_ERROR_TIMEOUTEXCEEDED;
}
}
if (fKeepWaiting)
{
DosSleep(ulSleepTime);
//
// If port is not responding, slowly increase sleep interval. Do
// not exceed 256 (approximately 1/4 second).
//
if (ulSleepTime < 256L)
ulSleepTime *= 2L;
}
} while (fKeepWaiting);
DosReleaseMutexSem(hCommReadSem);
return ulReadRC;
}
/*------------------------------------------------------------------------*
* ReadUntilByte
*
* This method invokes DosRead and DosDevIOCtl to either read either the
* specified number of characters or to return once the character
* specified has been read. The routine will also return if the timeout
* specified has elapsed.
*------------------------------------------------------------------------*/
ULONG CommPort::ReadUntilByte(PUCHAR pucDataArea,ULONG ulDataAreaSize,
PULONG pulRead,UCHAR ucWaitByte,
LONG lTimeOutmSec)
{
ULONG
ulStartTime,
ulTimeOut,
ulSleepTime,
ulCharCount,
ulReadRC,
ulRC,
ulDataPosition;
UCHAR
ucNextChar;
INT
fCheck,
fKeepWaiting;
ulRC=DosRequestMutexSem(hCommReadSem,COMMOS2_RESOURCE_SEM_WAIT);
if (ulRC)
{
ulCommError = COMM_ERROR_SEMAPHOREFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_READUNTILBYTE;
return COMM_ERROR_SEMAPHOREFAILED;
}
ulStartTime=TimerValue();
ulTimeOut=lTimeOutmSec/10L;
ulSleepTime=1L;
fKeepWaiting=TRUE;
if (lTimeOutmSec == TIMEOUT_INDEFINITE)
fCheck=FALSE;
else
fCheck=TRUE;
ulReadRC=COMM_ERROR_NOERROR;
ulDataPosition=0;
(*pulRead)=0;
do
{
ulRC=QueryQueue(COMM_QUERY_RXCOUNT,&ulCharCount);
if (ulRC)
{
ulCommError = COMM_ERROR_IOCTLFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_READUNTILBYTE;
DosReleaseMutexSem(hCommReadSem);
return COMM_ERROR_IOCTLFAILED;
}
if (ulCharCount > 0)
{
//
// Some characters are available. Read them one by one checking
// to see if the termination character is present or the maximum
// number of characters have been read.
//
do
{
ulReadRC=Read(&ucNextChar,1,pulRead);
if (ulReadRC)
fKeepWaiting=FALSE;
if (fKeepWaiting)
{
pucDataArea[ulDataPosition]=ucNextChar;
ulDataPosition++;
ulCharCount--;
if (ucNextChar == ucWaitByte)
fKeepWaiting=FALSE;
if (ulDataPosition >= ulDataAreaSize)
fKeepWaiting=FALSE;
}
} while (fKeepWaiting && (ulCharCount > 0));
(*pulRead)=ulDataPosition;
}
else
{
//
// The requested number of characters are not available at this
// time. Test to see if the specified time has elapsed and return
// to the calling program if it has.
//
if (fCheck && (TimerDifference(ulStartTime) > ulTimeOut))
{
fKeepWaiting=FALSE;
ulCommError = COMM_ERROR_TIMEOUTEXCEEDED;
ulDosError = NO_ERROR;
ulCommMode = COMM_MODE_READUNTILBYTE;
ulReadRC=COMM_ERROR_TIMEOUTEXCEEDED;
}
}
if (fKeepWaiting)
{
DosSleep(ulSleepTime);
//
// If port is not responding, slowly increase sleep interval. Do
// not exceed 256 (approximately 1/4 second).
//
if (ulSleepTime < 256L)
ulSleepTime *= 2L;
}
} while (fKeepWaiting);
DosReleaseMutexSem(hCommReadSem);
return ulReadRC;
}
/*------------------------------------------------------------------------*
* QueryQueue
*
* This method queries the values of count and size for both the
* receive and transmit buffers.
*------------------------------------------------------------------------*/
ULONG CommPort::QueryQueue(USHORT usMode,PULONG pulValue)
{
RXQUEUE
RxQueue;
ULONG
ulRC,
ulRxQueue,
ulFunction;
switch (usMode)
{
case COMM_QUERY_RXCOUNT: // Query Rx character count
case COMM_QUERY_RXBUFFER: // Query Rx buffer size
ulFunction=ASYNC_GETINQUECOUNT;
break;
case COMM_QUERY_TXCOUNT: // Query Tx character count
case COMM_QUERY_TXBUFFER: // Query Tx buffer size
ulFunction=ASYNC_GETOUTQUECOUNT;
break;
}
ulRxQueue=sizeof(RXQUEUE);
(*pulValue)=0;
ulRC=(unsigned long)DosDevIOCtl(hCommPort,IOCTL_ASYNC,
ulFunction,NULL,0L,NULL,
&RxQueue,ulRxQueue,&ulRxQueue);
if (ulRC)
{
ulCommError = COMM_ERROR_IOCTLFAILED;
ulDosError = ulRC;
return COMM_ERROR_IOCTLFAILED;
}
switch (usMode)
{
case COMM_QUERY_RXCOUNT: // Return Rx buffer count
case COMM_QUERY_TXCOUNT: // Return Tx buffer count
(*pulValue)=RxQueue.cch;
break;
case COMM_QUERY_RXBUFFER: // Return Rx buffer size
case COMM_QUERY_TXBUFFER: // Return Tx buffer size
(*pulValue)=RxQueue.cb;
break;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* QueryRxCount
*
* This method returns the number of characters in the receiver buffer.
*------------------------------------------------------------------------*/
ULONG CommPort::QueryRxCount(PULONG pulCount)
{
ULONG
ulRC;
ulRC=QueryQueue(COMM_QUERY_RXCOUNT,pulCount);
if (ulRC)
{
ulCommMode = COMM_MODE_QUERYRXCOUNT;
}
return ulRC;
}
/*------------------------------------------------------------------------*
* QueryRxBufSize
*
* This method returns the size of the receiver buffer.
*------------------------------------------------------------------------*/
ULONG CommPort::QueryRxBufferSize(PULONG pulSize)
{
ULONG
ulRC;
ulRC=QueryQueue(COMM_QUERY_RXBUFFER,pulSize);
if (ulRC)
{
ulCommMode = COMM_MODE_QUERYRXBUFSIZE;
}
return ulRC;
}
/*------------------------------------------------------------------------*
* QueryTxCount
*
* This method returns the number of characters in the transmit buffer.
*------------------------------------------------------------------------*/
ULONG CommPort::QueryTxCount(PULONG pulCount)
{
ULONG
ulRC;
ulRC=QueryQueue(COMM_QUERY_TXCOUNT,pulCount);
if (ulRC)
{
ulCommMode = COMM_MODE_QUERYTXCOUNT;
}
return ulRC;
}
/*------------------------------------------------------------------------*
* QueryTxBufSize
*
* This method returns the size of the transmit buffer.
*------------------------------------------------------------------------*/
ULONG CommPort::QueryTxBufferSize(PULONG pulSize)
{
ULONG
ulRC;
ulRC=QueryQueue(COMM_QUERY_TXBUFFER,pulSize);
if (ulRC)
{
ulCommMode = COMM_MODE_QUERYTXBUFSIZE;
}
return ulRC;
}
/*------------------------------------------------------------------------*
* GetDCBInfo
*
* This method gets the DCB information for the comm port.
*------------------------------------------------------------------------*/
ULONG CommPort::GetDCBInfo(VOID)
{
ULONG
ulRC,
ulDCBSize;
ulDCBSize=sizeof(DCBINFO);
ulRC=(unsigned long)DosDevIOCtl(hCommPort,IOCTL_ASYNC,ASYNC_GETDCBINFO,
NULL,0L,NULL,&DCBInfo,ulDCBSize,&ulDCBSize);
if (ulRC)
{
ulCommError = COMM_ERROR_DCBINFOFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_GETDCBINFO;
return COMM_ERROR_DCBINFOFAILED;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* SetDCBInfo
*
* This method sets the DCB information for the comm port.
*------------------------------------------------------------------------*/
ULONG CommPort::SetDCBInfo(VOID)
{
ULONG
ulRC,
ulDCBSize;
ulDCBSize=sizeof(DCBINFO);
ulRC=(unsigned long)DosDevIOCtl(hCommPort,IOCTL_ASYNC,ASYNC_SETDCBINFO,
&DCBInfo,ulDCBSize,&ulDCBSize,NULL,0L,NULL);
if (ulRC)
{
ulCommError = COMM_ERROR_DCBINFOFAILED;
ulDosError = ulRC;
ulCommMode = COMM_MODE_SETDCBINFO;
return COMM_ERROR_DCBINFOFAILED;
}
return COMM_ERROR_NOERROR;
}
/*------------------------------------------------------------------------*
* TimerValue
*
* This routine returns a timer value in hundredths of seconds. This
* routine does not return a value which can be used for the current time,
* but it does return a value useful for use as a timer. If the value
* returned is less than a previous value, you should add 8,640,000 which
* is equivalent to one day in hundredths of seconds.
*------------------------------------------------------------------------*/
static ULONG TimerValue()
{
DATETIME
CurrentTime;
DosGetDateTime(&CurrentTime);
return 360000L*(unsigned long)CurrentTime.hours+
6000L*(unsigned long)CurrentTime.minutes+
100L*(unsigned long)CurrentTime.seconds+
(unsigned long)CurrentTime.hundredths;
}
/*------------------------------------------------------------------------*
* TimerDifference
*
* This routine uses a base value obtained from TimerValue and calls
* TimerValue itself to return the difference in hundreths of seconds.
*------------------------------------------------------------------------*/
static ULONG TimerDifference(ULONG ulBaseTimerValue)
{
ULONG
ulCurrentTime;
ulCurrentTime=TimerValue();
if (ulCurrentTime < ulBaseTimerValue)
ulCurrentTime += 8640000L;
return ulCurrentTime-ulBaseTimerValue;
}