#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; }