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
}