#include "stdafx.h"
#include "SerialPort.h"
#include "assert.h"
CSerialPort::CSerialPort()
{
memset(&m_OverlappedRead, 0, sizeof(m_OverlappedRead));
memset(&m_OverlappedWrite, 0, sizeof(m_OverlappedWrite));
m_bOpened = false;
m_ReadComThread = NULL;
m_hIDCom = NULL;
m_dwReadLen = 0;
}
CSerialPort::~CSerialPort()
{
}
BOOL CSerialPort::OpenPort(UINT nPort, UINT nBaud)
{
ASSERT(nPort > 0 && nPort < 5);
if(m_bOpened)
return true;
TCHAR szPort[15];
TCHAR szComParams[50];
DCB dcb;
wsprintf(szPort, _T("COM%d"), nPort);
m_hIDCom = ::CreateFile(szPort,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if(m_hIDCom == NULL)
return false;
memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;
::SetCommTimeouts(m_hIDCom, &CommTimeOuts);
wsprintf(szComParams, _T("COM%d:%d,N,8,1"), nPort, nBaud);
m_OverlappedRead.Offset = 0;
m_OverlappedRead.OffsetHigh = 0;
m_OverlappedRead.hEvent = ::CreateEvent(NULL, true, false, NULL);
m_OverlappedWrite.Offset = 0;
m_OverlappedWrite.OffsetHigh = 0;
m_OverlappedWrite.hEvent = ::CreateEvent(NULL, true, false, NULL);
dcb.DCBlength = sizeof(DCB);
::GetCommState(m_hIDCom, &dcb);
dcb.BaudRate = nBaud;
dcb.ByteSize = 8;
dcb.Parity = 0;
if(!SetCommState(m_hIDCom, &dcb) || !SetupComm(m_hIDCom, 4096, 4096) ||
m_OverlappedRead.hEvent == NULL || m_OverlappedWrite.hEvent == NULL)
{
DWORD dwError = ::GetLastError();
if(m_OverlappedRead.hEvent != NULL)
::CloseHandle(m_OverlappedRead.hEvent);
if(m_OverlappedWrite.hEvent != NULL)
::CloseHandle(m_OverlappedWrite.hEvent);
::CloseHandle(m_hIDCom);
return false;
}
::SetCommMask(m_hIDCom, EV_RXCHAR);
::PurgeComm(m_hIDCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
::EscapeCommFunction(m_hIDCom, SETDTR);
m_bOpened =true;
m_bExitThread =false;
StartMonitoring();
return m_bOpened;
}
BOOL CSerialPort::Close()
{
if(!m_bOpened || m_hIDCom == NULL)
return true;
m_bExitThread = true;
::SetCommMask(m_hIDCom, 0);
StopMonitoring();
if(m_OverlappedRead.hEvent != NULL)
::CloseHandle(m_OverlappedRead.hEvent);
if(m_OverlappedWrite.hEvent != NULL)
::CloseHandle(m_OverlappedWrite.hEvent);
::CloseHandle(m_hIDCom);
m_bOpened = false;
m_hIDCom = NULL;
return true;
}
//向串口写数据
void CSerialPort::WriteToPort(BYTE *Byte, int Len)
{
if(!m_bOpened || m_hIDCom == NULL)
return;
BOOL bWriteStat;
DWORD dwBytesWritten;
ClearReadBuf();
bWriteStat = ::WriteFile(m_hIDCom, Byte, Len, &dwBytesWritten, &m_OverlappedWrite);
if(!bWriteStat && (::GetLastError() == ERROR_IO_PENDING))
{
//WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就
//返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,
//否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。
DWORD dw = ::WaitForSingleObject(m_OverlappedWrite.hEvent, INFINITE );
if(dw == WAIT_TIMEOUT)
{
dwBytesWritten = 0;
DCB dcb;
::GetCommState(m_hIDCom, &dcb);
::PurgeComm(m_hIDCom, PURGE_TXCLEAR);
return;
}
else
{
::GetOverlappedResult(m_hIDCom, &m_OverlappedWrite, &dwBytesWritten, false);//等待服务器完成IO操作
m_OverlappedWrite.Offset += dwBytesWritten;
}
}
return ;
}
//从串口读取数据
int CSerialPort::ReadFromPort(BYTE *lpszBlock, int nRLen)
{
if(!m_bOpened || m_hIDCom == NULL)
return 0;
BOOL bReadStat;
DWORD dwBytesRead, dwErrorFlags;
COMSTAT ComStat;
::ClearCommError(m_hIDCom, &dwErrorFlags, &ComStat);
if(!ComStat.cbInQue)
return 0;
dwBytesRead = (DWORD) ComStat.cbInQue;
if(nRLen < (int)dwBytesRead)
dwBytesRead = (DWORD) nRLen;
bReadStat = ::ReadFile(m_hIDCom, lpszBlock, dwBytesRead, &dwBytesRead, &m_OverlappedRead);
if(!bReadStat)
{
if(::GetLastError() == ERROR_IO_PENDING)
{
::WaitForSingleObject(m_OverlappedRead.hEvent, INFINITE);
return (int)dwBytesRead;
}
return 0;
}
return (int)dwBytesRead;
}
UINT CSerialPort::CommThread(LPVOID pParam)
{
CSerialPort* pSerialPort = (CSerialPort*)pParam;
BYTE Buffer[4096];
DWORD dwEvent, dwError;
COMSTAT ComStat;
int ReadLen = 0;
memset(pSerialPort->m_ReadBuf, '\0', sizeof(pSerialPort->m_ReadBuf));
::SetCommMask(pSerialPort->m_hIDCom, EV_RXCHAR);
while(!pSerialPort->m_bExitThread)
{
memset(Buffer, '\0', 4096);
::WaitCommEvent(pSerialPort->m_hIDCom, &dwEvent, NULL);
::ClearCommError(pSerialPort->m_hIDCom, &dwError, &ComStat);
if((dwEvent & EV_RXCHAR) && ComStat.cbInQue)
{
pSerialPort->m_dwReadLen = pSerialPort->ReadFromPort(Buffer,4096);
pSerialPort->m_dwReadLen = ReadLen >4096 ? 4096 : ReadLen;
if(pSerialPort->m_dwReadLen > 0)
{
memcpy(pSerialPort->m_ReadBuf, Buffer,pSerialPort->m_dwReadLen);
}
}
::PurgeComm(pSerialPort->m_hIDCom, PURGE_RXCLEAR);
}
return 0;
}
BOOL CSerialPort::StartMonitoring()
{
if(m_ReadComThread == NULL)
{
if(!(m_ReadComThread = ::AfxBeginThread(CommThread, this)))
return false;
}
return true;
}
BOOL CSerialPort::StopMonitoring()
{
if(m_ReadComThread != NULL)
{
::TerminateThread(m_ReadComThread->m_hThread, 0); //终结线程
m_ReadComThread = NULL;
}
return true;
}
void CSerialPort::ClearReadBuf()
{
memset(m_ReadBuf, '\0', sizeof(m_ReadBuf));
m_dwReadLen = 0;
}