///////////////////////////////// Includes ////////////////////////////////////
#include "pch.h"
#include "serialport.h"
#ifndef _WINERROR
#pragma message("To avoid this message, please put WinError.h in your pre compiled header")
#include <WinError.h>
#endif

///////////////////////////////// Defines /////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//////////////////////////////// Implementation ///////////////////////////////
CSerialException::CSerialException(DWORD dwError) : m_dwError(dwError)
{
}

BOOL CSerialException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError, PUINT pnHelpContext /* = 0 */)
{
	// Validate our parameters
	ASSERT(lpszError != NULL && AfxIsValidString(lpszError, nMaxError));
	
	if(pnHelpContext != NULL)
		*pnHelpContext = 0;

	// What will be the return value from this function(assume the worst)
	BOOL bSuccess = FALSE;
	
	LPTSTR lpBuffer;
	DWORD dwReturn = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
									NULL, 
									m_dwError, 
									MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
									reinterpret_cast<LPTSTR>(&lpBuffer), 
									0, 
									NULL
									);
	if(dwReturn == 0)
	{
		*lpszError = _T('\0');
	}
	else
	{
		bSuccess = TRUE;
		Checked::tcsncpy_s(lpszError, nMaxError, lpBuffer, _TRUNCATE);
		LocalFree(lpBuffer);
	}
	
	return bSuccess;
}

CString CSerialException::GetErrorMessage()
{
	CString strVal;
	LPTSTR pstrError = strVal.GetBuffer(ERR_BUFFER);

	GetErrorMessage(pstrError, ERR_BUFFER, NULL);
	strVal.ReleaseBuffer();

	return strVal;
}

IMPLEMENT_DYNAMIC(CSerialException, CException)

#ifdef _DEBUG
void CSerialException::Dump(CDumpContext &dc) const
{
	CObject::Dump(dc);
	dc << _T("m_dwError = ") << m_dwError << _T("\n");
}
#endif

CSerialPort::CSerialPort() : m_hComm(INVALID_HANDLE_VALUE), m_hEvent(NULL)
{
	m_hKernel32 = GetModuleHandle(_T("KERNEL32.DLL"));
	if(m_hKernel32)
		m_lpfnCancelIO = reinterpret_cast<LPCANCELIO>(GetProcAddress(m_hKernel32, "CancelIo"));
	else
		m_lpfnCancelIO = NULL;
}

CSerialPort::~CSerialPort()
{
	Close();
}

void CSerialPort::ThrowSerialException(DWORD dwError	/* = 0 */)
{
	if(dwError == 0)
		dwError = GetLastError();

	CSerialException* pException = new CSerialException(dwError);

	TRACE(_T("Warning: throwing CSerialException for error %d\n"), dwError);
	THROW(pException);
}

#ifdef _DEBUG
void CSerialPort::Dump(CDumpContext &dc) const
{
	dc << _T("m_hComm = ") << m_hComm << _T("\n");
}
#endif

void CSerialPort::Open(LPCTSTR pszPort,					/* COM1   */
					   DWORD dwBaud						/* = 9600 */, 
					   CSerialPort::Parity parity		/* = NoParity */, 
					   BYTE dataBits					/* = 8 */, 
					   CSerialPort::StopBits stopBits	/* = OneStopBit */, 
					   CSerialPort::FlowControl flowCtl	/* = NoFlowControl */, 
					   BOOL bOverlapped					/* = 0 */)
{
	Close();	// In case we are already open

	// Call CreateFile to open the comms port
	TCHAR szPort[10] = {0};
	_stprintf_s(szPort, _T("\\\\.\\%s"), pszPort);
	m_hComm = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, bOverlapped ? FILE_FLAG_OVERLAPPED : 0, NULL);
	if(m_hComm == INVALID_HANDLE_VALUE)
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Open, Failed to open the comms port, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"%s打开失败，GetLastError=%ld", szPort, dwLastError));
		//ThrowSerialException(dwLastError);
	}

	// Create the event we need for later synchronisation use
	m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if(m_hEvent == NULL)
	{
		DWORD dwLastError = GetLastError();
		Close();
		//TRACE(_T("CSerialPort::Open, Failed in call to CreateEvent in Open, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"CreateEvent失败，GetLastError=%ld", szPort, dwLastError));
		//ThrowSerialException(dwLastError);
	}

	if ( !SetupComm(m_hComm,10240,2048) )
	{
		CloseHandle(m_hComm);
		CloseHandle(m_hEvent);
		return ;
	}
	// Get the current state prior to changing it
	DCB dcb;
	dcb.DCBlength = sizeof(DCB);
	GetState(dcb);

	// Setup the baud rate
	dcb.BaudRate = dwBaud;

	// Setup the Parity
	switch(parity)
	{
	case NoParity:
		dcb.Parity = NOPARITY;
		break;
	case OddParity:
		dcb.Parity = ODDPARITY;
		break;
	case EvenParity:
		dcb.Parity = EVENPARITY;
		break;
	case MarkParity:
		dcb.Parity = MARKPARITY;
		break;
	case SpaceParity:
		dcb.Parity = SPACEPARITY;
		break;
	default:
		ASSERT(FALSE);
		break;
	}

	// Setup the data bits
	dcb.ByteSize = dataBits;

	// Setup the stop bits
	switch(stopBits)
	{
	case OneStopBit:
		dcb.StopBits = ONESTOPBIT;
		break;
	case OnePointFiveStopBits:
		dcb.StopBits = ONE5STOPBITS;
		break;
	case TwoStopBits:
		dcb.StopBits = TWOSTOPBITS;
		break;
	default:
		ASSERT(FALSE);
		break;
	}

	// Setup the flow control
	dcb.fDsrSensitivity = FALSE;
	switch(flowCtl)
	{
	case NoFlowControl:
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
	case CtsRtsFlowControl:
		dcb.fOutxCtsFlow = TRUE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
	case CtsDtrFlowControl:
		dcb.fOutxCtsFlow = TRUE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
	case DsrRtsFlowControl:
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = TRUE;
		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
	case DsrDtrFlowControl:
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = TRUE;
		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
	case XonXoffFlowControl:
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fOutX = TRUE;
		dcb.fInX = TRUE;
		dcb.XonChar = 0x11;
		dcb.XoffChar = 0x13;
		dcb.XoffLim = 100;
		dcb.XonLim = 100;
		break;
	default:
		ASSERT(FALSE);
		break;
	}

	//Now that we have all the settings in place, make the changes
	SetState(dcb);
}

void CSerialPort::Open(int nPort, 
					   DWORD dwBaud						/* = 9600 */, 
					   CSerialPort::Parity parity		/* = NoParity */, 
					   BYTE dataBits					/* = 8 */, 
					   CSerialPort::StopBits stopBits	/* = OneStopBit */, 
					   CSerialPort::FlowControl flowCtl	/* = NoFlowControl */, 
					   BOOL bOverlapped					/* = 0 */)
{
	//Form the string version of the port number
	CString strPort;
	strPort.Format(_T("\\\\.\\COM%d"), nPort);

	//Then delegate the work to the other version of Open
	Open(strPort, dwBaud, parity, dataBits, stopBits, flowCtl, bOverlapped);
}

void CSerialPort::Close()
{
	if(IsOpen())
	{
		// Close down the comms port
		BOOL bSuccess = CloseHandle(m_hComm);
		m_hComm = INVALID_HANDLE_VALUE;
		if(!bSuccess)
			//TRACE(_T("CSerialPort::Close, Failed to close up the comms port, Error:%d\n"), GetLastError());
			LOG4C((LOG_WARN,"关闭串口失败，GetLastError=%ld", GetLastError()));

		// Free the event object we are using
		if(m_hEvent)
		{
			CloseHandle(m_hEvent);
			m_hEvent = NULL;
		}
	}
}

void CSerialPort::Attach(HANDLE hComm)
{
	Close();

	//Validate our parameters, now that the port has been closed
	ASSERT(m_hComm == INVALID_HANDLE_VALUE);
	ASSERT(m_hEvent == NULL);

	m_hComm = hComm;

	//Create the event we need for later synchronisation use
	m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (m_hEvent == NULL)
	{
		DWORD dwLastError = GetLastError();
		Close();
		//TRACE(_T("CSerialPort::Attach, Failed in call to CreateEvent in Attach, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"CreateEvent失败，GetLastError=%ld", GetLastError()));
		//ThrowSerialException(dwLastError);
	}
}

HANDLE CSerialPort::Detach()
{
	// What will be the return value from this function
	HANDLE hVal = m_hComm;

	m_hComm = INVALID_HANDLE_VALUE;

	if(m_hEvent)
	{
		CloseHandle(m_hEvent);
		m_hEvent = NULL;
	}
	
	return hVal;
}

DWORD CSerialPort::Read(void *lpBuf, DWORD dwCount)
{
	// Validate our parameters
	ASSERT(IsOpen());

	if (lpBuf == NULL || !::AfxIsValidAddress(lpBuf, dwCount, FALSE))
	{
		LOG4C((LOG_WARN, "Read的缓存地址无效！"))
		return 0;
	}

	DWORD dwErrorFlags = 0;
	COMSTAT ComStat;
	ClearCommError(m_hComm, &dwErrorFlags, &ComStat);

#if 1
	// 使用ClearCommError来读取缓存区接受到的字节时, 
	// 可能受系统线程调试或硬件延时, cbInQue为空, 
	// 这里要用while延时获取;
	DWORD dwTick = GetTickCount();
	DWORD dwLastLen = 0;
	//while (ComStat.cbInQue == 0)
	while(1)
	{// cbInQue表示输入缓冲区的字节数; 
		Sleep(150);
		if (GetTickCount() - dwTick > 5000)
			break;
		ClearCommError(m_hComm, &dwErrorFlags, &ComStat);
		if ( ComStat.cbInQue != 0 && dwLastLen == ComStat.cbInQue )
			break;
		dwLastLen = ComStat.cbInQue;
	}

	if (ComStat.cbInQue == 0)
	{
		// 串口无数据返回;
		LOG4C((LOG_ERROR, "1.5秒超时已过，读串口失败，缓存区无数据"));
		return 0;
	}
#endif

	DWORD dwBytesRead = 0;
	if(!ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, NULL))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Read, Failed in call to ReadFile, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"ReadFile失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}

	return dwBytesRead;
}

void CSerialPort::Read(void *lpBuf, DWORD dwCount, OVERLAPPED &overlapped, DWORD *pBytesRead /* = 0 */)
{
	// Validate our parameters
	ASSERT(IsOpen());

	DWORD dwBytesRead = 0;
	BOOL bSuccess = ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, &overlapped);
	if(!bSuccess)
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Read, Failed in call to ReadFile, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"ReadFile失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
	else
	{
		if(pBytesRead)
			*pBytesRead = dwBytesRead;
	}
}

DWORD CSerialPort::Write(const void *lpBuf, DWORD dwCount)
{
	// Validate our parameters
	ASSERT(IsOpen());

	DWORD dwBytesWritten = 0;
	// 写前，清空缓存区;
	PurgeComm(m_hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
	if(!WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, NULL))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Write, Failed in call to WriteFile, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"WriteFile失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}

	return dwBytesWritten;
}

void CSerialPort::Write(const void *lpBuf, DWORD dwCount, OVERLAPPED &overlapped, DWORD *pBytesWritten /* = 0 */)
{
	// Validate our parameters
	ASSERT(IsOpen());

	DWORD dwBytesWritten = 0;
	// 写前，清空缓存区;
	PurgeComm(m_hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
	BOOL bSuccess = WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, &overlapped);
	if(!bSuccess)
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Write, Failed in call to WriteFile, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"WriteFile失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
	else
	{
		if(pBytesWritten)
			*pBytesWritten = dwBytesWritten;
	}
}

void CSerialPort::GetOverlappedResult(OVERLAPPED &overlapped, DWORD &dwBytesTransferred, BOOL bWait)
{
	// Validate our parameters
	ASSERT(IsOpen());

	if(!::GetOverlappedResult(m_hComm, &overlapped, &dwBytesTransferred, bWait))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetOverlappedResult, Failed in call to GetOverlappedResult, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetOverlappedResult失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::_OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped)
{
	// Validate our parameters
	AFXASSUME(lpOverlapped);

	// Convert back to the C++ world
	CSerialPort* pSerialPort = static_cast<CSerialPort*>(lpOverlapped->hEvent);
	AFXASSUME(pSerialPort);

	// Call the C++ function
	pSerialPort->OnCompletion(dwErrorCode, dwCount, lpOverlapped);
}

void CSerialPort::OnCompletion(DWORD /* dwErrorCode */, DWORD /* dwCount */, LPOVERLAPPED lpOverlapped)
{
	// Just free the memory which was previously allocated for the OVERLAPPED structure
	delete lpOverlapped;

	// Your derived classes can do something useful in OnCompletion, but don't forget to 
	// call CSerialPort::OnCompletion to ensure the memory is freed
}

void CSerialPort::CancelIO()
{
	// Validate our parameters
	ASSERT(IsOpen());

	if(m_lpfnCancelIO == NULL)
	{
		//TRACE(_T("CSerialPort::CancelIO, CancelIO function is not supported on this OS, You need to be running at least NT 4 or Win 98 to use this function\n"));
		LOG4C((LOG_WARN,"CancelIO失败，m_lpfnCancelIO函数指针空"));
		//ThrowSerialException(ERROR_CALL_NOT_IMPLEMENTED);
	}

	if(!m_lpfnCancelIO(m_hComm))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("Failed in call to CancelIO, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"CancelIO失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

DWORD CSerialPort::BytesWaiting()
{
	// Validate our parameters
	ASSERT(IsOpen());

	// Check to see how many characters are unread
	COMSTAT stat;
	GetStatus(stat);
	return stat.cbInQue;
}

BOOL CSerialPort::DataWaiting(DWORD dwTimeout)
{
	// Validate our parameters
	ASSERT(IsOpen());

	// Setup to wait fo incoming data
	DWORD dwOldMask;
	GetMask(dwOldMask);
	SetMask(EV_RXCHAR);

	// Setup the overlapped structure
	OVERLAPPED overlapped;
	overlapped.hEvent = m_hEvent;

	// Assume the worst
	BOOL bSuccess = FALSE;

	DWORD dwEvent;
	bSuccess = WaitEvent(dwEvent, overlapped);
	if(!bSuccess)
	{
		if(WaitForSingleObject(overlapped.hEvent, dwTimeout) == WAIT_OBJECT_0)
		{
			DWORD dwBytesTransferred;
			GetOverlappedResult(overlapped, dwBytesTransferred, FALSE);
			bSuccess = TRUE;
		}
	}

	// Reset the event mask
	SetMask(dwOldMask);

	return bSuccess;
}

void CSerialPort::WriteEx(const void *lpBuf, DWORD dwCount)
{
	// Validate our parameters
	ASSERT(IsOpen());

	OVERLAPPED* pOverlapped = new OVERLAPPED;
	memset(pOverlapped, 0, sizeof(OVERLAPPED));
	pOverlapped->hEvent = static_cast<HANDLE>(this);
	if(!WriteFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion))
	{
		DWORD dwLastError = GetLastError();
		delete pOverlapped;
		//TRACE(_T("CSerialPort::WriteEx, Failed in call to WriteFileEx, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"WriteEx失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::ReadEx(void *lpBuf, DWORD dwCount)
{
	// Validate our parameters
	ASSERT(IsOpen());

	OVERLAPPED* pOverlapped = new OVERLAPPED;
	memset(pOverlapped, 0, sizeof(OVERLAPPED));
	pOverlapped->hEvent = static_cast<HANDLE>(this);
	if(!ReadFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion))
	{
		DWORD dwLastError = GetLastError();
		delete pOverlapped;
		//TRACE(_T("CSerialPort::ReadEx, Failed in call to ReadFileEx, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"ReadEx失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::TransmitChar(char cChar)
{
	// Validate our parameters
	ASSERT(IsOpen());

	if(!TransmitCommChar(m_hComm, cChar))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::TransmitChar, Failed in call to TransmitCommChar, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"TransmitCommChar失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::GetConfig(COMMCONFIG &config)
{
	// Validate our parameters
	ASSERT(IsOpen());

	DWORD dwSize = sizeof(COMMCONFIG);
	if(!GetCommConfig(m_hComm, &config, &dwSize))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetConfig, Failed in call to GetCommConfig, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetCommConfig失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::SetConfig(COMMCONFIG &config)
{
	// Validate our parameters
	ASSERT(IsOpen());

	DWORD dwSize = sizeof(COMMCONFIG);
	if(!SetCommConfig(m_hComm, &config, dwSize))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::SetConfig, Failed in call to SetCommConfig, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"SetCommConfig失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::SetBreak()
{
	// Validate our parameters
	ASSERT(IsOpen());

	if(!SetCommBreak(m_hComm))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::SetBreak, Failed in call to SetCommBreak, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"SetCommBreak失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::ClearBreak()
{
	// Validate our parameters
	ASSERT(IsOpen());

	if(!ClearCommBreak(m_hComm))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::ClearBreak, Failed in call to ClearCommBreak, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"ClearCommBreak失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::ClearError(DWORD &dwErrors)
{
	// Validate our parameters
	ASSERT(IsOpen());

	if(!ClearCommError(m_hComm, &dwErrors, NULL))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::ClearError, Failed in call to ClearCommError, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"ClearCommError失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::GetDefaultConfig(int nPort, COMMCONFIG &config)
{
	// Create the device name as a string
	CString strPort;
	strPort.Format(_T("COM%d"), nPort);

	DWORD dwSize = sizeof(COMMCONFIG);
	if(!GetDefaultCommConfig(strPort, &config, &dwSize))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetDefaultConfig, Failed in call to GetDefaultCommConfig, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetDefaultCommConfig失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::SetDefaultConfig(int nPort, COMMCONFIG &config)
{
	// Create the device name as a string
	CString strPort;
	strPort.Format(_T("COM%d"), nPort);

	DWORD dwSize = sizeof(COMMCONFIG);
	if(!SetDefaultCommConfig(strPort, &config, dwSize))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::SetDefaultConfig, Failed in call to SetDefaultCommConfig, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"SetDefaultConfig失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::GetStatus(COMSTAT &stat)
{
	// Validate our parameters
	ASSERT(IsOpen());

	DWORD dwErrors;
	if (!ClearCommError(m_hComm, &dwErrors, &stat))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetStatus, Failed in call to ClearCommError, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"ClearCommError失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::GetState(DCB &dcb)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!GetCommState(m_hComm, &dcb))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetState, Failed in call to GetCommState, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetCommState失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::SetState(DCB &dcb)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!SetCommState(m_hComm, &dcb))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::SetState, Failed in call to SetCommState, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"SetState失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::Escape(DWORD dwFunc)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!EscapeCommFunction(m_hComm, dwFunc))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Escape, Failed in call to EscapeCommFunction, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"Escape失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::ClearDTR()
{
  Escape(CLRDTR);
}

void CSerialPort::ClearRTS()
{
	Escape(CLRRTS);
}

void CSerialPort::SetDTR()
{
	Escape(SETDTR);
}

void CSerialPort::SetRTS()
{
	Escape(SETRTS);
}

void CSerialPort::SetXOFF()
{
	Escape(SETXOFF);
}

void CSerialPort::SetXON()
{
	Escape(SETXON);
}

void CSerialPort::GetProperties(COMMPROP& properties)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!GetCommProperties(m_hComm, &properties))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetProperties, Failed in call to GetCommProperties, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetProperties失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::GetModemStatus(DWORD& dwModemStatus)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!GetCommModemStatus(m_hComm, &dwModemStatus))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetModemStatus, Failed in call to GetCommModemStatus, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetModemStatus失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::SetMask(DWORD dwMask)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!SetCommMask(m_hComm, dwMask))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::SetMask, Failed in call to SetCommMask, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"SetMask失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::GetMask(DWORD& dwMask)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!GetCommMask(m_hComm, &dwMask))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetMask, Failed in call to GetCommMask, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetMask失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::Flush()
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!FlushFileBuffers(m_hComm))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Flush, Failed in call to FlushFileBuffers, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"Flush失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::Purge(DWORD dwFlags)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!PurgeComm(m_hComm, dwFlags))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Purge, Failed in call to PurgeComm, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"Purge失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::TerminateOutstandingWrites()
{
	Purge(PURGE_TXABORT);
}

void CSerialPort::TerminateOutstandingReads()
{
	Purge(PURGE_RXABORT);
}

void CSerialPort::ClearWriteBuffer()
{
	Purge(PURGE_TXCLEAR);
}

void CSerialPort::ClearReadBuffer()
{
	Purge(PURGE_RXCLEAR);
}

void CSerialPort::Setup(DWORD dwInQueue, DWORD dwOutQueue)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!SetupComm(m_hComm, dwInQueue, dwOutQueue))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::Setup, Failed in call to SetupComm, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"Setup失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::SetTimeouts(COMMTIMEOUTS& timeouts)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!SetCommTimeouts(m_hComm, &timeouts))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::SetTimeouts, Failed in call to SetCommTimeouts, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"SetTimeouts失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::GetTimeouts(COMMTIMEOUTS& timeouts)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!GetCommTimeouts(m_hComm, &timeouts))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::GetTimeouts, Failed in call to GetCommTimeouts, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"GetTimeouts失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

void CSerialPort::Set0Timeout()
{
	COMMTIMEOUTS Timeouts;
	memset(&Timeouts, 0, sizeof(Timeouts));
	Timeouts.ReadIntervalTimeout = MAXDWORD;
	SetTimeouts(Timeouts);
}

void CSerialPort::Set0WriteTimeout()
{
	COMMTIMEOUTS Timeouts;
	GetTimeouts(Timeouts);
	Timeouts.WriteTotalTimeoutMultiplier = 0;
	Timeouts.WriteTotalTimeoutConstant = 0;
	SetTimeouts(Timeouts);
}

void CSerialPort::Set0ReadTimeout()
{
	COMMTIMEOUTS Timeouts;
	GetTimeouts(Timeouts);
	Timeouts.ReadIntervalTimeout = MAXDWORD;
	Timeouts.ReadTotalTimeoutMultiplier = 0;
	Timeouts.ReadTotalTimeoutConstant = 0;
	SetTimeouts(Timeouts);
}

void CSerialPort::WaitEvent(DWORD& dwMask)
{
	//Validate our parameters
	ASSERT(IsOpen());

	if (!WaitCommEvent(m_hComm, &dwMask, NULL))
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::WaitEvent, Failed in call to WaitCommEvent, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"WaitEvent失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}
}

BOOL CSerialPort::WaitEvent(DWORD& dwMask, OVERLAPPED& overlapped)
{
	//Validate our parameters
	ASSERT(IsOpen());
	ASSERT(overlapped.hEvent);

	BOOL bSuccess = WaitCommEvent(m_hComm, &dwMask, &overlapped);
	if (!bSuccess)
	{
		DWORD dwLastError = GetLastError();
		//TRACE(_T("CSerialPort::WaitEvent, Failed in call to WaitCommEvent, Error:%d\n"), dwLastError);
		LOG4C((LOG_WARN,"WaitEvent失败，GetLastError=%ld", dwLastError));
		//ThrowSerialException(dwLastError);
	}

	return bSuccess;
}
