⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 commport.cpp

📁 fax engine 传真引擎 relay fax 的开源项目 商业软件使用 高质量 高可靠
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************
* RelayFax Open Source Project
* Copyright 1996-2004 Alt-N Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the RelayFax Open 
* Source License.  A copy of this license is available in file LICENSE 
* in the top-level directory of the distribution.
*
* RelayFax is a registered trademark of Alt-N Technologies, Ltd.
*
* Individual files and/or contributed packages may be copyright by
* other parties and subject to additional restrictions.
*****************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// The purpose of CCommPort is to encapsulate all the Win32 communication API
//
////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CommPort.h"


CLS1SPEEDS cls1Speeds[MAX_CLS1SPEEDS] = 
{ 
	0x00,	24,		24,		2400,	0,	// 2400, v.27 ter
	0x04,	48,		48,		4800,	1,	// 4800, v.27
	0x0c,	72,		72,		7200,	2,	// 7200, v.29
	0x08,	96,		96,		9600,	3,	// 9600, v.29
	0x06,	121,	121,	12000,	4,	// 12000, V.33
	0x02,	145,	145,	14400,	5,	// 14400, V.33
	0x0d,	73,		74,		7200,	2,	// 7200, v.17
	0x09,	97,		98,		9600,	3,	// 9600, v.17
	0x05,	121,	122,	12000,	4,	// 12000, v.17
	0x01,	145,	146,	14400,	5,	// 14400, v.17									 										
};

WORD Cls1ScanTimes_normal[8] = {20,40,10,5,10,20,40,0};
WORD Cls1ScanTimes_fine[8] =   {20,40,10,5,5,10,20,0};

WORD Cls2ScanTimes_normal[8] = { 0, 5, 10, 10, 20, 20, 40, 40 };
WORD Cls2ScanTimes_fine[8] = { 0, 5, 5, 10, 10, 20, 20, 40 };

WORD  Cls2FaxParamBitRates[6] = { 2400, 4800, 7200, 9600, 12000, 14400 };

char CCommPort::s_HexDigits[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CCommPort::CCommPort()
{
	m_hPort = NULL;
	m_bDSRFlowControl = true;
	m_bCTSFlowControl = true;
	m_bSoftFlowControl = true;

	m_BaudRate = CBR_19200;
	m_ByteSize = 8;
	m_Parity = NOPARITY;
	m_StopBits = ONESTOPBIT;

	ZeroMemory( &m_ReadOverlapped, sizeof(m_ReadOverlapped) );
	ZeroMemory( &m_WriteOverlapped, sizeof(m_WriteOverlapped) );
	ZeroMemory( &m_CommEventOverlapped, sizeof(m_CommEventOverlapped) );

	m_ReadOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	m_WriteOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	m_CommEventOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	InitLineParser();

	m_bWriteInProgress = false;

	memset( &m_dcb, 0, sizeof(m_dcb) );
	m_dcb.DCBlength = sizeof(m_dcb); 

	m_bDebugLog = false;
	m_pLogFile = NULL;

}

CCommPort::~CCommPort()
{

	CloseHandle( m_ReadOverlapped.hEvent );
	CloseHandle( m_WriteOverlapped.hEvent );
	CloseHandle( m_CommEventOverlapped.hEvent );

}


//////////////////////////////////////////////////////////////////////
// ConnectPort
//////////////////////////////////////////////////////////////////////
bool CCommPort::ConnectPort( string& sErr )
{
	char szComDevice[16];
	
	wsprintf( szComDevice, "\\\\.\\%s",  m_sPort.c_str() );
	m_hPort = CreateFile( szComDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL, 
						  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
	
	// see if this works before committing
	if( m_hPort == NULL || m_hPort == INVALID_HANDLE_VALUE )
	{
		if( GetLastError() == ERROR_ACCESS_DENIED )
		{
			// wait a second and try again
			Sleep( 1000 );
			m_hPort = CreateFile( szComDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL, 
								  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
		}
	}

	if( m_hPort != NULL && m_hPort != INVALID_HANDLE_VALUE )
	{
		PurgeComm( m_hPort, PURGE_RXCLEAR | PURGE_TXCLEAR );

		if( !GetCommState( m_hPort, &m_dcb ) )
		{
			sErr.assign( "Error in GetCommState" );
			CloseHandle( m_hPort );
			return false;
		}

		if( !SetupComm( m_hPort, 20000, 20000 ) )
		{
			sErr.assign( "Error in SetupComm" );
			CloseHandle( m_hPort );
			return false;
		}

		m_dcb.BaudRate = m_BaudRate;
		m_dcb.ByteSize=  m_ByteSize;
		m_dcb.fBinary = TRUE;
		m_dcb.Parity = m_Parity;
		m_dcb.StopBits = m_StopBits;

		m_dcb.fOutxCtsFlow = (m_bCTSFlowControl) ? TRUE : FALSE;
		m_dcb.fOutxDsrFlow = (m_bDSRFlowControl) ? TRUE : FALSE;

		m_dcb.fOutX = (m_bSoftFlowControl) ? 1 : 0;
		m_dcb.fInX = 0; // we shouldn't need flow control for receiving data
		                // since we are using 20k buffers

		m_dcb.XonChar = XON;
		m_dcb.XoffChar = XOFF;

// One of these two was causing a problem with Multitech ISI5634/8 multi-port modem card
//		m_dcb.fTXContinueOnXoff = TRUE;

		m_dcb.fRtsControl = RTS_CONTROL_ENABLE;
		m_dcb.fDtrControl = DTR_CONTROL_ENABLE;
		m_dcb.fAbortOnError = FALSE; // Make sure this is reset otherwise any 
		                             //line errors will cause io to terminate

		m_dcb.fErrorChar = FALSE;
		m_dcb.fParity = FALSE;
//		m_dcb.fDsrSensitivity = TRUE;

		m_dcb.fNull = FALSE;

		if ( !SetCommState( m_hPort, &m_dcb) ) 
		{
			sErr.assign( "Error in SetCommState" );
			CloseHandle( m_hPort );
			return false;
		}

		COMMTIMEOUTS cto;
		//cto.ReadIntervalTimeout = 10;	
		//cto.ReadIntervalTimeout = (m_BaudRate / 10)
		cto.ReadIntervalTimeout = 2;
		cto.ReadTotalTimeoutMultiplier = 0;
		cto.ReadTotalTimeoutConstant = 0;
		cto.WriteTotalTimeoutMultiplier = 5;
		cto.WriteTotalTimeoutConstant = 5000;

		if( !SetCommTimeouts( m_hPort, &cto ) )
		{
			sErr.assign( "Error in SetCommTimeouts" );
			CloseHandle( m_hPort );
			return false;
		}

		COMSTAT cs = {0};
		DWORD dwErrs = 0;

		if( !ClearCommError( m_hPort, &dwErrs, &cs ) )
		{
			sErr.assign( "Error in ClearCommError" );
			CloseHandle( m_hPort );
			return false;
		}

		//DWORD dwMask = EV_CTS | EV_ERR | EV_DSR | EV_RLSD | EV_BREAK | EV_RING;
		DWORD dwMask = EV_ERR;

		if (!SetCommMask(m_hPort, dwMask))
		{
			sErr.assign( "Error in SetCommMask!" );
			CloseHandle( m_hPort );
			return false;
		}

		OpenDebugLog();
		
		DoWaitCommEventLoop();

		DoReadLoop();

		OnConnect(); //-- moved to OnWaitTimeout to let the read buffer flush

		return true;
	}
	else
	{
		// could not open port
		char szError[256];
		szError[0] = '\0';
		GetLastErrorText( szError, 255 );
		sErr.assign( szError );
	}

	return false;
}


//////////////////////////////////////////////////////////////////////
// DisconnectPort
//////////////////////////////////////////////////////////////////////
void CCommPort::DisconnectPort( void )
{

	PurgeComm( m_hPort, PURGE_RXABORT | PURGE_RXCLEAR | 
		                PURGE_TXABORT | PURGE_TXCLEAR );

	CloseHandle( m_hPort );

	m_hPort = NULL;

	CloseDebugLog();
}

//////////////////////////////////////////////////////////////////////
// DoRead
//////////////////////////////////////////////////////////////////////
bool CCommPort::DoRead( void )
{
	BOOL bRet;

	m_BytesRead = 0;

	bRet = ReadFile( m_hPort, m_szReadBuff, READBUF_SIZE, &m_BytesRead, &m_ReadOverlapped );

	if( bRet )
	{
		return true;
	}
	else
	{
		DWORD  dwLastError = GetLastError();

		// LastError was ERROR_IO_PENDING, as expected.
		if (dwLastError != ERROR_IO_PENDING)
		{
			OutputDebugString("Unexpected error.\n");
		}

		// Its possible for this error to occur if the 
		// service provider has closed the port.  Time to end.
		if (dwLastError == ERROR_INVALID_HANDLE)
		{
			OutputDebugString( "Likely that the Service Provider has closed the port.\n");
		}

		return false;
	}
}


void CCommPort::FillWriteQueue( char* szChars, unsigned long nBytes, bool bCrLf )
{
	bool bAddedCrLf = false;

	while( nBytes > 0 )
	{
		int nbuflen = MAX_WRITE;

		if( nbuflen > nBytes ) 
		{
			nbuflen = nBytes;
		}

		CWriteBuffer *buf = new CWriteBuffer;

		memcpy( buf->Buffer, szChars, nbuflen );
		buf->Bytes = nbuflen;

		if( bCrLf && (nbuflen < MAX_WRITE) )
		{
			// must be last one
			buf->Buffer[buf->Bytes++] = '\r';
			bAddedCrLf = true;
		}

		m_WriteQueue.push_back( buf );

		szChars += nbuflen;
		nBytes -= nbuflen;
	}

	if( bCrLf && !bAddedCrLf)
	{
		CWriteBuffer *buf = new CWriteBuffer;
		buf->Buffer[0] = '\r';
		buf->Bytes = 1;
		m_WriteQueue.push_back( buf );
	}
}


bool CCommPort::WritePacket( char* szChars, unsigned long nBytes )
{
	m_WriteOverlapped.Offset = 0;
	m_WriteOverlapped.OffsetHigh = 0;

		
	if( WriteFile( m_hPort, szChars, nBytes, 
		&m_BytesWritten, &m_WriteOverlapped ) )
	{
		//char szMsg[80];
		//wsprintf( szMsg, "Wrote %d bytes 2\n", m_BytesWritten );
		//OutputDebugString( szMsg );
		
		ResetEvent( m_WriteOverlapped.hEvent );

		OnWrite();

		if( m_bDebugLog )
		{
			WriteDebugLog( false );
		}
	}
	else
	{
		//char szMsg[80];
		//wsprintf( szMsg, "Queued up %d bytes\n", nBytes );
		//OutputDebugString( szMsg );

		m_bWriteInProgress = true;
		
		DWORD  dwLastError = GetLastError();
		
		// LastError was ERROR_IO_PENDING, as expected.
		if (dwLastError != ERROR_IO_PENDING)
		{
			OutputDebugString("Unexpected error.\n");
		}
		
		// Its possible for this error to occur if the 
		// service provider has closed the port.  Time to end.
		if (dwLastError == ERROR_INVALID_HANDLE)
		{
			OutputDebugString( "Likely that the Service Provider has closed the port.\n");
		}
		
		return false;
	}

	return true;
}

//////////////////////////////////////////////////////////////////////
// DoWrite
//////////////////////////////////////////////////////////////////////
bool CCommPort::DoWrite( char* szChars, unsigned long nBytes, bool bCrLf )
{
	if( m_bWriteInProgress )
	{
		FillWriteQueue( szChars, nBytes, bCrLf );
	}
	else
	{
		if( nBytes > MAX_WRITE )
		{
			FillWriteQueue( szChars, nBytes, bCrLf );
			DoWriteLoop();
		}
		else
		{
			memcpy( m_szWriteBuff, szChars, nBytes );

			if( bCrLf )
			{
				m_szWriteBuff[nBytes++] = '\r';
				//m_szWriteBuff[nBytes++] = '\n';
			}

			if( WritePacket( m_szWriteBuff, nBytes ) )
			{
				//char szMsg[80];
				//wsprintf( szMsg, "Sent %d bytes 3\n", nBytes  );
				//OutputDebugString( szMsg );
			}
		}
	}

	return true;
}


//////////////////////////////////////////////////////////////////////
// DoRead
//////////////////////////////////////////////////////////////////////
bool CCommPort::DoWaitCommEvent( void )
{
	BOOL bRet;

	m_BytesRead = 0;

	bRet = WaitCommEvent( m_hPort, &m_CommEvent, &m_CommEventOverlapped );

	if( bRet )
	{
		return true;
	}
	else
	{
		DWORD  dwLastError = GetLastError();

		// LastError was ERROR_IO_PENDING, as expected.
		if (dwLastError != ERROR_IO_PENDING)
		{
			OutputDebugString("Unexpected error.\n");
		}

		// Its possible for this error to occur if the 
		// service provider has closed the port.  Time to end.
		if (dwLastError == ERROR_INVALID_HANDLE)
		{
			OutputDebugString( "Likely that the Service Provider has closed the port.\n");
		}

		return false;
	}
}


//////////////////////////////////////////////////////////////////////
// DoReadLoop
//////////////////////////////////////////////////////////////////////
void CCommPort::DoReadLoop( void )
{
	int i;

	for( i = 0; i < 100; i++ )
	{
		if( m_hPort == NULL )
			break;

		if( DoRead() ) 
		{
			m_szReadBuff[m_BytesRead] = '\0';
			
			if( m_bDebugLog )
			{
				WriteDebugLog( true );
			}

			OnRead();
		}
		else
		{
			break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -