2025-11-27 16:46:48 +09:00

459 lines
11 KiB
C++

// ==========================================================================
// Class Implementation : COXSerialCommFile
// ==========================================================================
// Source file : oxscfile.cpp
// This software along with its related components, documentation and files ("The Libraries")
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "OXSCFILE.H"
#include "OXSCCNST.H"
//private headers
#include "OXRSERCM.H"
COXSerialCommFile::COXSerialCommFile() :
m_hCommDevice(NULL)
{
m_bCloseOnDelete = TRUE;
}
COXSerialCommFile::~COXSerialCommFile()
{
if (m_hCommDevice)
Close();
}
BOOL COXSerialCommFile::Open(const COXSerialCommConfig& config,
COXSerialCommException* pException /* = NULL */)
{
if (pException)
{
pException->m_ext_cause = COXSerialCommException::none;
pException->m_strFileName = config.GetCommName();
}
if (m_hCommDevice)
Close();
if (!config.IsPortAvailable())
{
if (pException)
pException->m_ext_cause = COXSerialCommException::notAvailable;
return FALSE;
}
VERIFY ( (m_hCommDevice =::CreateFile(config.GetCommName(),
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) !=
INVALID_HANDLE_VALUE);
if (m_hCommDevice == INVALID_HANDLE_VALUE)
{
if (pException)
pException->m_ext_cause = COXSerialCommException::notAvailable;
return FALSE;
}
::SetupComm(m_hCommDevice, config.m_nSizeReceivingQueue,
config.m_nSizeTransmissionQueue);
DCB dcb;
::GetCommState(m_hCommDevice, &dcb);
dcb.BaudRate = config.m_nBaudRate;
dcb.ByteSize = config.m_nByteSize;
dcb.Parity = config.m_nParity;
dcb.StopBits = config.m_nStopBits;
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
dcb.fNull = FALSE;
if (config.m_eFlowControl == COXSerialCommConfig::HARDWARE)
{
dcb.fOutxCtsFlow = TRUE;
dcb.fOutxDsrFlow = TRUE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fDsrSensitivity = TRUE;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
}
else
{
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
}
dcb.XonLim = 1;
dcb.XoffLim = (WORD)(config.m_nSizeReceivingQueue / 2);
if (config.m_eFlowControl == COXSerialCommConfig::XON_XOFF)
{
dcb.fOutX = TRUE;
dcb.fInX = TRUE;
}
else
{
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
}
dcb.fAbortOnError = TRUE;
VERIFY ( ::SetCommState(m_hCommDevice, &dcb) != FALSE );
COMSTAT tmp;
GetCommException(tmp);
SetTimeouts(config.m_nDsrTimeout, config.m_nCtsTimeout);
PurgeRx();
PurgeTx();
m_strFileName = config.GetCommName();
return TRUE;
}
BOOL COXSerialCommFile::SetTimeouts(DWORD dwRxTimeout/*=5000*/, DWORD dwTxTimeout/*=5000*/)
{
if (m_hCommDevice == NULL)
{
TRACE(_T("'COXSerialCommFile::SetTimeouts': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
COMMTIMEOUTS commTimeOuts ;
commTimeOuts.ReadIntervalTimeout = dwRxTimeout;
commTimeOuts.ReadTotalTimeoutMultiplier = 1;
commTimeOuts.ReadTotalTimeoutConstant = dwRxTimeout;
commTimeOuts.WriteTotalTimeoutMultiplier = 1;
commTimeOuts.WriteTotalTimeoutConstant = dwTxTimeout;
SetCommTimeouts( m_hCommDevice, &commTimeOuts ) ;
return TRUE;
}
void COXSerialCommFile::Close()
{
if (m_hCommDevice)
{
PurgeRx();
PurgeTx();
CloseHandle(m_hCommDevice);
m_hCommDevice = NULL;
}
}
UINT COXSerialCommFile::Read( void* lpBuf, UINT nCount )
{
DWORD dwByteRead = 0;
if (m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::Read': NULL handle !"));
ASSERT(FALSE);
return 0;
}
if (!ReadFile(m_hCommDevice, lpBuf, nCount, &dwByteRead, NULL))
{
if (GetLastError() == ERROR_HANDLE_EOF)
AfxThrowSerialCommException(COXSerialCommException::rxTimeout, m_strFileName);
else
{
COMSTAT comstat;
AfxThrowSerialCommException(GetCommException(comstat), m_strFileName);
}
}
/* else
{
if (dwByteRead != (DWORD)nCount)
{
AfxThrowSerialCommException(COXSerialCommException::rxTimeout, m_strFileName);
}
}
*/
return dwByteRead;
}
void COXSerialCommFile::Write( const void* lpBuf, UINT nCount )
{
DWORD dwByteWritten;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::Write': NULL handle !"));
ASSERT(FALSE);
return;
}
WriteFile(m_hCommDevice, lpBuf, nCount, &dwByteWritten, NULL);
if (dwByteWritten != nCount)
{
COMSTAT tmp;
AfxThrowSerialCommException(GetCommException(tmp), m_strFileName);
}
}
void COXSerialCommFile::PurgeRx()
{
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::PurgeRx': NULL handle !"));
ASSERT(FALSE);
return;
}
PurgeComm(m_hCommDevice, PURGE_RXABORT | PURGE_RXCLEAR);
}
void COXSerialCommFile::PurgeTx()
{
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::PurgeTx': NULL handle !"));
ASSERT(FALSE);
return;
}
PurgeComm(m_hCommDevice, PURGE_TXABORT | PURGE_TXCLEAR);
}
BOOL COXSerialCommFile::IsTxQueueEmpty() const
{
COMSTAT comstat;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::IsTxQueueEmpty': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
GetCommException(comstat);
return (comstat.cbOutQue == 0) ? TRUE : FALSE;
}
BOOL COXSerialCommFile::IsRxQueueEmpty() const
{
COMSTAT comstat;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::IsRxQueueEmpty': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
GetCommException(comstat);
return (comstat.cbInQue == 0) ? TRUE : FALSE;
}
void COXSerialCommFile::SetDTR(BOOL bValue)
{
int nFunction;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::SetDTR': NULL handle !"));
ASSERT(FALSE);
return;
}
nFunction = (bValue == TRUE) ? SETDTR : CLRDTR;
::EscapeCommFunction(m_hCommDevice, nFunction);
}
void COXSerialCommFile::SetRTS(BOOL bValue)
{
int nFunction;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::SetRTS': NULL handle !"));
ASSERT(FALSE);
return;
}
nFunction = (bValue == TRUE) ? SETRTS : CLRRTS;
::EscapeCommFunction(m_hCommDevice, nFunction);
}
BOOL COXSerialCommFile::GetCTS() const
{
DWORD dwPortStatus;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::GetCTS': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
GetCommModemStatus(m_hCommDevice, &dwPortStatus);
return ( (dwPortStatus & MS_CTS_ON) ? TRUE : FALSE);
}
BOOL COXSerialCommFile::GetDSR() const
{
DWORD dwPortStatus;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::GetDSR': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
GetCommModemStatus(m_hCommDevice, &dwPortStatus);
return ( (dwPortStatus & MS_DSR_ON) ? TRUE : FALSE);
}
BOOL COXSerialCommFile::GetCD() const
{
DWORD dwPortStatus;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::GetCD': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
GetCommModemStatus(m_hCommDevice, &dwPortStatus);
return ( (dwPortStatus & MS_RLSD_ON) ? TRUE : FALSE);
}
BOOL COXSerialCommFile::GetRI() const
{
DWORD dwPortStatus;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::GetRI': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
GetCommModemStatus(m_hCommDevice, &dwPortStatus);
return ( (dwPortStatus & MS_RING_ON) ? TRUE : FALSE);
}
COXSerialCommException::VALUE COXSerialCommFile::GetCommException(COMSTAT& comstat) const
{
COXSerialCommException::VALUE exception = COXSerialCommException::none;
DWORD dwError = 0;
if ( m_hCommDevice == NULL )
{
TRACE(_T("'COXSerialCommFile::GetCommException': NULL handle !"));
ASSERT(FALSE);
return COXSerialCommException::ioError;
}
VERIFY (::ClearCommError(m_hCommDevice, &dwError, &comstat));
if (dwError != 0)
{
if (dwError & CE_RXPARITY)
exception = COXSerialCommException::parityError;
else if (dwError & CE_OVERRUN)
exception = COXSerialCommException::overrunError;
else if (dwError & CE_FRAME)
exception = COXSerialCommException::frameError;
else if (dwError & CE_BREAK)
exception = COXSerialCommException::breakDetect;
else if (dwError & CE_IOE)
exception = COXSerialCommException::ioError;
else if (dwError & CE_MODE)
exception = COXSerialCommException::modeError;
else if (dwError & CE_RXOVER)
exception = COXSerialCommException::rxQueueOverflow;
else if (dwError & CE_TXFULL)
exception = COXSerialCommException::txQueueFull;
else
exception = COXSerialCommException::none;
}
return exception;
}
BOOL COXSerialCommFile::SetCommMask(const DWORD dwEventMask)
{
if (m_hCommDevice == NULL)
{
TRACE(_T("'COXSerialCommFile::SetCommMask': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
return ::SetCommMask(m_hCommDevice, dwEventMask);
}
BOOL COXSerialCommFile::GetCommMask(DWORD& dwEventMask) const
{
if (m_hCommDevice == NULL)
{
TRACE(_T("'COXSerialCommFile::GetCommMask': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
return ::GetCommMask(m_hCommDevice, &dwEventMask);
}
BOOL COXSerialCommFile::GetCommProperties(LPCOMMPROP lpCommProp) const
{
if (m_hCommDevice == NULL)
{
TRACE(_T("'COXSerialCommFile::GetCommProperties': NULL handle !"));
ASSERT(FALSE);
return FALSE;
}
return ::GetCommProperties(m_hCommDevice, lpCommProp);
}
UINT COXSerialCommFile::GetBytesToRead() const
{
if (m_hCommDevice == NULL)
{
TRACE(_T("'COXSerialCommFile::GetBytesToRead': NULL handle !"));
ASSERT(FALSE);
return 0;
}
COXSerialCommException::VALUE exception = COXSerialCommException::none;
COMSTAT cs;
::ZeroMemory((void*)&cs,sizeof(cs));
if ((exception = GetCommException(cs)) != COXSerialCommException::none)
{
AfxThrowSerialCommException(exception, m_strFileName);
return 0;
}
return cs.cbInQue;
}
UINT COXSerialCommFile::GetBytesToWrite() const
{
if (m_hCommDevice == NULL)
{
TRACE(_T("'COXSerialCommFile::GetBytesToWrite': NULL handle !"));
ASSERT(FALSE);
return 0;
}
COXSerialCommException::VALUE exception = COXSerialCommException::none;
COMSTAT cs;
::ZeroMemory((void*)&cs,sizeof(cs));
if ((exception = GetCommException(cs)) != COXSerialCommException::none)
{
AfxThrowSerialCommException(exception, m_strFileName);
return 0;
}
return cs.cbOutQue;
}