www.pudn.com > ChatUseIOCP.rar > DtSerialSocket.cpp


#include "StdAfx.h" 
#include "dtserialsocket.h" 
 
Datatal::DtSerialSocket::DtSerialSocket(void) 
{ 
	m_hComm = NULL; 
	m_bParity = NOPARITY; 
	m_dwStopBits = ONESTOPBIT; 
	m_bByteSize = 8; 
	m_dwBaudRate = CBR_9600; 
 
	m_hComm = NULL; 
 
} 
 
Datatal::DtSerialSocket::~DtSerialSocket(void) 
{ 
} 
 
void Datatal::DtSerialSocket::SetCommPort(DWORD dwPort) 
{ 
	m_dwComPort = dwPort; 
} 
 
void Datatal::DtSerialSocket::SetParity(bool bSet) 
{ 
	m_bParity = bSet ? EVENPARITY : NOPARITY; 
} 
 
void Datatal::DtSerialSocket::SetBaudRate(DWORD dwBaudrate) 
{ 
	m_dwBaudRate = dwBaudrate; 
} 
 
void Datatal::DtSerialSocket::SetStopBits(DWORD dwStopBits) 
{ 
	m_dwStopBits = dwStopBits; 
} 
 
void Datatal::DtSerialSocket::SetByteSize(BYTE bByteSize) 
{ 
	m_bByteSize = bByteSize; 
} 
 
void Datatal::DtSerialSocket::Connect(int ComPort, DWORD BaudRate, BYTE ByteSize, bool bParity, DWORD StopBits) 
{ 
	SetCommPort(ComPort); 
	SetParity(bParity); 
	SetBaudRate(BaudRate); 
	SetStopBits(StopBits); 
	Connect(); 
} 
 
void Datatal::DtSerialSocket::Connect() 
{ 
 
	if (GetState() == DTSS_CONNECTING) 
		return; 
 
	//Disconnect if we are connected. 
	if (m_hComm) 
		Disconnect(); 
		 
	SetState(DTSS_CONNECTING); 
 
	//Lets connect to the port 
	char szPortName[10]; 
	sprintf(szPortName, "\\\\.\\COM%d", m_dwComPort); 
	m_hComm = CreateFile( 
		szPortName,					 // Name of port 
		GENERIC_READ|GENERIC_WRITE,  // access ( read and write) 
		0,                           // (share) 0: cannot share the COM port 
		0,                           // security  (None) 
		OPEN_EXISTING,               // creation : open_existing 
		FILE_FLAG_OVERLAPPED,        // we want overlapped operation FILE_FLAG_OVERLAPPED 
		0                            // no templates file for COM port... 
	); 
 
 
	// Check if we could open the port 
	if (m_hComm == INVALID_HANDLE_VALUE) 
	{ 
		SetState(DTSS_DISCONNECTED); 
		throw DtSocketException(GetLastError(), "Connect failed", "Failed to open port."); 
	} 
 
	//Com settings structure 
	DCB dcb = {0}; 
	dcb.DCBlength = sizeof(DCB); 
 
	if (!GetCommState (m_hComm, &dcb)) 
	{ 
		SetState(DTSS_DISCONNECTED); 
		CloseHandle(m_hComm); 
		throw DtSocketException(GetLastError(), "Connect failed", "GetCommState failed."); 
	} 
 
	dcb.fBinary=TRUE; 
 
	// custom 
	dcb.BaudRate		= m_dwBaudRate; 
	dcb.ByteSize		= m_bByteSize; 
	dcb.Parity			= m_bParity; 
	if ( m_dwStopBits == 1 ) 
		dcb.StopBits  = ONESTOPBIT; 
	else if (m_dwStopBits == 2 ) 
		dcb.StopBits  = TWOSTOPBITS; 
	else  
		dcb.StopBits  = ONE5STOPBITS; 
 
 
	//Tell the comport how it should work. 
	if (!SetCommState (m_hComm,&dcb)) 
	{ 
		SetState(DTSS_DISCONNECTED); 
		CloseHandle(m_hComm); 
		throw DtSocketException(GetLastError(), "Connect failed", "SetCommState failed."); 
	} 
 
	//Set DTS  
	/* 
	if ( !EscapeCommFunction(m_hComm, SETDTR))  
	{ 
		SetState(DTSS_DISCONNECTED); 
		CloseHandle(m_hComm); 
		throw DtSocketException(GetLastError(), "Connect failed", "EscapeCommFunction failed."); 
	} 
	*/ 
 
	// Done with connecting, launch the thread 
	ResetEvent(DtSocketBase::m_hNewDataEvent); 
 
	if (!IsThreadRunning()) 
	{ 
		if (StartThread() == 0) 
		{ 
			SetState(DTSS_CONNECTED); 
			HandleConnect(); 
		} 
		else 
		{ 
			SetState(DTSS_DISCONNECTED); 
			throw DtSocketException(-1, "Connect failed", "Failed to start worker thread."); 
		} 
	} 
 
} 
 
bool Datatal::DtSerialSocket::Disconnect(bool bStopThread) 
{ 
	Datatal::DtSocketBase::Disconnect(bStopThread); 
 
	//Close the port. 
	CloseHandle(m_hComm); 
 
	return true; 
} 
 
void Datatal::DtSerialSocket::ThreadFunc(HANDLE hStopEvent) 
{ 
	OVERLAPPED				ovRead, ovWrite; 
	HANDLE					hEvents[4]; 
	DWORD					dwWait; 
	bool					bCanRun = true; 
	bool					bSending = false; 
	bool					bReading = false; 
	bool					bNewData = false; 
	bool					bReadComplete = false; 
	char					szInBuffer[_SOCKETLIB_WORK_SIZE_];  //In workbuffer, 
	char					szOutBuffer[_SOCKETLIB_WORK_SIZE_];  //Out workbuffer, 
	DWORD					dwBytesRead = 0; 
	DWORD					dwFlags = 0; 
 
	// Overlapped structures. 
	memset(&ovRead, 0, sizeof(ovRead)); 
	memset(&ovWrite, 0, sizeof(ovWrite)); 
 
	//Create events 
	ovRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
	if (!ovRead.hEvent) 
	{ 
		WriteLog(1, "misc", "Failed to create ovRead event: %d", GetLastError()); 
		return; 
	} 
	ovWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
	if (!ovWrite.hEvent) 
	{ 
		WriteLog(1, "misc", "Failed to create ovWrite event: %d", GetLastError()); 
		return; 
	} 
 
	//Event array 
	hEvents[0] = hStopEvent; 
	hEvents[1] = ovRead.hEvent; 
	hEvents[2] = ovWrite.hEvent; 
	hEvents[3] = m_hNewDataEvent; 
 
	while ( bCanRun ) 
	{ 
 
		if (GetState() == DTSS_ERROR || GetState() == DTSS_CONNECTING) 
		{ 
			bSending = false; 
			bReading = false; 
			bNewData = false; 
			bReadComplete = false; 
 
			DWORD dwRes = WaitForSingleObject(m_hStopEvent, 500); 
			if (dwRes == WAIT_OBJECT_0) 
			{ 
				bCanRun = false; 
				continue; 
			} 
			continue; 
		} 
 
		if (GetState() == DTSS_DISCONNECTED) 
		{ 
			if (m_bReconnect)  
				Connect(); 
 
			if (GetState() != DTSS_CONNECTED) 
			{ 
				DWORD dwRes = WaitForSingleObject(m_hStopEvent, 5000); 
				if (dwRes == WAIT_OBJECT_0) 
				{ 
					bCanRun = false; 
					continue; 
				} 
			} 
		} 
 
 
		// Tell us that we want to Receive data 
		 
		if (bReading) 
			dwWait = WaitForMultipleObjects (4, hEvents, FALSE, INFINITE); 
		else 
			dwWait = 1000; //will not be found in the switch. 
 
		switch ( dwWait ) 
		{ 
 
			// Stop event 
		case WAIT_OBJECT_0: 
			bCanRun = false; 
			WriteLog(1, "misc", "DIE EVENT triggered."); 
			continue; 
			break; 
 
			// Overlapped Read is completed. 
		case WAIT_OBJECT_0 + 1: 
			ResetEvent(ovRead.hEvent); 
			bReadComplete = true; 
			break; 
 
			// Overlapped write is completed. 
		case WAIT_OBJECT_0 + 2: 
			HandleSendComplete(); 
			ResetEvent(ovWrite.hEvent); 
			bSending = false; 
 
			if (Datatal::DtSocketBase::m_lOutBuffers.pFirst) 
				bNewData = true; 
			else 
				bNewData = false; 
 
			break; 
 
 
			// A Send() have been done. 
		case WAIT_OBJECT_0 + 3: 
			ResetEvent(m_hNewDataEvent); 
			bNewData = true; 
			break; 
 
		case 1000: 
			break; 
 
		default: 
			WriteLog(1, "misc", "ThreadFunc, Incorrect dwRes: %d, error: %d", dwWait, GetLastError()); 
			break; 
 
 
		} //switch 
 
 
		//dwBytesRead = 0; 
		if (!bReading) 
		{ 
			bReading = true; 
			bReadComplete = false; 
			memset(szInBuffer, 0, _SOCKETLIB_WORK_SIZE_); 
			if (!ReadFile(m_hComm, szInBuffer, 1, &dwBytesRead, &ovRead)) 
			{ 
				int nErr = GetLastError(); 
				if (nErr != ERROR_IO_PENDING) 
				{ 
					SetState(DTSS_ERROR); 
					OnError(GetLastError(), "ReadFile failed!"); 
					continue; 
				} 
 
				WriteLog(3, "Read", "Pending read inited"); 
			} 
			else 
			{ 
				WriteLog(3, "Read", "Completed directly, %d bytes", dwBytesRead); 
				if (dwBytesRead == 0) 
				{ 
					SetState(DTSS_ERROR); 
					OnError(-1, "ReadFile failed, 0 bytes read."); 
					continue; 
				} 
				else 
				{ 
					bReadComplete = true; 
					bReading = false; 
				} 
			} 
		} 
 
		if (bReadComplete) 
		{ 
 
			//If a read was not completed directly, dwReadBytes = 0, fetch overlapped result. 
			if (dwBytesRead == 0) 
			{ 
				dwFlags = 0; 
				if(!GetOverlappedResult(m_hComm, &ovRead, &dwBytesRead, false)) 
				{ 
					SetState(DTSS_ERROR); 
					OnError(GetLastError(), "Read, GetOverlappedResult() failed on Read!"); 
					continue; 
				} 
			} 
 
			//Closed? 
			if ( dwBytesRead == 0) 
			{ 
				SetState(DTSS_ERROR); 
				OnError(-1, "ReadFile failed, 0 bytes read."); 
				continue; 
			} 
 
			m_CritRead.Lock(); 
			HandleReceive(szInBuffer, dwBytesRead); 
			m_CritRead.Unlock(); 
 
			bReadComplete = false; 
			bReading = false; 
		} 
 
		//We gotto write some stuff, and we only do it if no operations are ongoing 
		if (bNewData && !bSending) 
		{ 
			//Lock buffer and fetch data 
			m_CritWrite.Lock(); 
			bSending = true; 
			size_t nBufferLen = 0; 
 
			Outbuffer* pBuffer = m_lOutBuffers.pFirst; 
			if (pBuffer->nSize - m_nBufferPos <= _SOCKETLIB_WORK_SIZE_) 
			{ 
				memcpy(szOutBuffer, pBuffer->pBuffer + m_nBufferPos, pBuffer->nSize - m_nBufferPos); 
				nBufferLen = pBuffer->nSize - m_nBufferPos; 
				m_lOutBuffers.RemoveFirst(); 
				m_nBufferPos = 0; 
			} 
			else 
			{ 
				memcpy(szOutBuffer, pBuffer->pBuffer + m_nBufferPos, _SOCKETLIB_WORK_SIZE_); 
				m_nBufferPos += _SOCKETLIB_WORK_SIZE_; 
				nBufferLen = _SOCKETLIB_WORK_SIZE_; 
			} 
			m_CritWrite.Unlock(); 
 
			DWORD dwBytesWritten; 
			if (!WriteFile(m_hComm, szOutBuffer, (DWORD)nBufferLen, &dwBytesWritten, &ovWrite)) 
			{ 
				//Overlapped? 
				if (GetLastError() != ERROR_IO_PENDING)  
				{ 
					SetState(DTSS_ERROR); 
					OnError(GetLastError(), "WriteFile() failed"); 
					break; 
				} 
				bSending = true; //only set pending write if we do not complete directly. 
			} 
			else 
				bSending = false; 
 
 
 
		} //if (!bSending && !bReading) 
 
 
	} //while 
 
}