#include "stdafx.h" #include "Serial.h" DCB *CBaseSerial::GetState() { return IsOpen() && ::GetCommState(_hCommHandle, &_DCB) == TRUE ? &_DCB : NULL; } bool CBaseSerial::SetState(DCB *pdcb /*= NULL*/) { return IsOpen() ? ::SetCommState(_hCommHandle, pdcb == NULL ? &_DCB : pdcb) == TRUE : false; } bool CBaseSerial::SetState(TCHAR *lpszSetStr /* = _T("baud=115200 parity=N data=8 stop=1") */) { if (lpszSetStr && lpszSetStr[0] != '\0' && IsOpen()) { if (::GetCommState(_hCommHandle, &_DCB) != TRUE) return false; // COMx[:][baud=b][parity=p][data=d][stop=s][to={on|off}][xon={on|off}][odsr={on|off}][octs={on|off}][dtr={on|off|hs}][rts={on|off|hs|tg}][idsr={on|off}] if (::BuildCommDCB(lpszSetStr, &_DCB) != TRUE) return false; return ::SetCommState(_hCommHandle, &_DCB) == TRUE; } return false; } bool CBaseSerial::SetState(DWORD dwBaudRate, DWORD dwByteSize /* = 8 */, DWORD dwParity /* = NOPARITY */, DWORD dwStopBits /* = ONESTOPBIT */) { if (!IsOpen()) return false; if (::GetCommState(_hCommHandle, &_DCB) != TRUE) return false; _DCB.BaudRate = dwBaudRate; _DCB.ByteSize = (BYTE)dwByteSize; _DCB.Parity = (BYTE)dwParity; _DCB.StopBits = (BYTE)dwStopBits; return ::SetCommState(_hCommHandle, &_DCB) == TRUE; } LPCOMMTIMEOUTS CBaseSerial::GetTimeouts() { return IsOpen() && ::GetCommTimeouts(_hCommHandle, &_CO) == TRUE ? &_CO : NULL; } bool CBaseSerial::SetTimeouts(COMMTIMEOUTS CO) { return IsOpen() ? ::SetCommTimeouts(_hCommHandle, &CO) == TRUE : false; } bool CBaseSerial::SetTimeouts(LPCOMMTIMEOUTS lpCO) { return IsOpen() ? ::SetCommTimeouts(_hCommHandle, lpCO) == TRUE : false; } bool CBaseSerial::SetBufferSize(DWORD dwInputSize, DWORD dwOutputSize) { // SetupComm设置输入输出缓冲区大小; return IsOpen() ? ::SetupComm(_hCommHandle, dwInputSize, dwOutputSize) == TRUE : false; } void CBaseSerial::SetMaskEvent(DWORD dwEvent /* = DEFAULT_COM_MASK_EVENT */) { _dwMaskEvent = dwEvent; } int CBaseSerial::GetInputSize() { COMSTAT Stat; DWORD dwError; return ::ClearCommError(_hCommHandle, &dwError, &Stat) == TRUE ? Stat.cbInQue : (DWORD)-1L; } bool CBaseSerial::Open(DWORD dwPort) { return Open(dwPort, 19200); } bool CBaseSerial::Open(DWORD dwPort, DWORD dwBaudRate) { if (dwPort < 1 || dwPort > 1024) return false; BindCommPort(dwPort); if (!OpenCommPort()) return false; if (!SetupPort()) return false; return SetState(dwBaudRate); } bool CBaseSerial::Open(DWORD dwPort, TCHAR *lpszSetStr /* = _T("baud/* =115200 parity/* =N data/* =8 stop/* =1") */ ) { if (dwPort < 1 || dwPort > 1024) return false; BindCommPort(dwPort); if (!OpenCommPort()) return false; if (!SetupPort()) return false; return SetState(lpszSetStr); } DWORD CBaseSerial::Read(LPVOID Buffer, DWORD dwBufferLength, DWORD dwWaitTime /* = 10 */) { if (!IsOpen()) return 0; COMSTAT Stat; DWORD dwError; if (::ClearCommError(_hCommHandle, &dwError, &Stat) && dwError > 0) { ::PurgeComm(_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR); // 清空输入缓冲区(PURGE_RXCLEAR) return 0; } #if 0 // 暂时保留:要视机器情况而定,有些响应慢缓冲区会暂时性无数据; if (!Stat.cbInQue) return 0; // 缓冲区无数据 #endif unsigned long uReadLength = 0; // dwBufferLength = dwBufferLength > Stat.cbInQue ? Stat.cbInQue : dwBufferLength;//会越界; if (!::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength, &_ReadOverlapped)) // 可能Buffer不够大,装不完; { if (::GetLastError() == ERROR_IO_PENDING) { WaitForSingleObject(_ReadOverlapped.hEvent, dwWaitTime); // 结束异步I/O while (!::GetOverlappedResult(_hCommHandle, &_ReadOverlapped, &uReadLength, false)) { Sleep(50); } if (::GetLastError() != ERROR_IO_INCOMPLETE) uReadLength = 0; } else uReadLength = 0; } return uReadLength; } char* CBaseSerial::ReadString(char *szBuffer, DWORD dwBufferLength, DWORD dwWaitTime /* = 20 */) { unsigned long uReadLength = Read(szBuffer, dwBufferLength - 1, dwWaitTime); szBuffer[uReadLength] = '\0'; return szBuffer; } DWORD CBaseSerial::Write(LPVOID Buffer, DWORD dwBufferLength) { if (!IsOpen()) return 0; DWORD dwError; if (::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0) ::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR); // 清空输出缓冲区(PURGE_TXCLEAR) unsigned long uWriteLength = 0; if (!::WriteFile(_hCommHandle, Buffer, dwBufferLength, &uWriteLength, &_WriteOverlapped)) { if (::GetLastError() != ERROR_IO_PENDING) { uWriteLength = 0; } } return uWriteLength; } DWORD CBaseSerial::Write(const TCHAR *szBuffer) { assert(szBuffer); return Write((void *)szBuffer, _tclen(szBuffer)); } DWORD CBaseSerial::ReadSync(LPVOID Buffer, DWORD dwBufferLength) { if (!IsOpen()) return 0; DWORD dwError; if (::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0) { ::PurgeComm(_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR); // 清空输入缓冲区(PURGE_RXCLEAR) return 0; } DWORD uReadLength = 0; ::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength, NULL); return uReadLength; } DWORD CBaseSerial::WriteSync(LPVOID Buffer, DWORD dwBufferLength) { if (!IsOpen()) return 0; DWORD dwError; if (::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0) ::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR); // 清空输出缓冲区(PURGE_TXCLEAR) unsigned long uWriteLength = 0; ::WriteFile(_hCommHandle, Buffer, dwBufferLength, &uWriteLength, NULL); return uWriteLength; } DWORD CBaseSerial::Write(TCHAR *szBuffer, DWORD dwBufferLength, TCHAR *szFormat, ...) { if (!IsOpen()) return 0; va_list va; va_start(va, szFormat); #if _MSC_VER < 1500 _vsnprintf(szBuffer, dwBufferLength, szFormat, va); #endif #if _MSC_VER >=1500 // VC9.0以上版本; //_vsntprintf(szBuffer, dwBufferLength, szFormat, va); _vsntprintf_s(szBuffer, dwBufferLength, _TRUNCATE, szFormat, va); #endif va_end(va); return Write(szBuffer); } DWORD CBaseSerial::Write(TCHAR *szBuffer, TCHAR *szFormat, ...) { if (!IsOpen()) return 0; va_list va; va_start(va, szFormat); #if _MSC_VER < 1500 vsprintf(szBuffer, szFormat, va); #endif #if _MSC_VER >=1500 // VC9.0以上版本; _vstprintf(szBuffer, szFormat, va); #endif va_end(va); return Write(szBuffer); } void CBaseSerial::Close() { if (!IsOpen()) return; PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR); // 清空输出缓冲区(PURGE_TXCLEAR) ::CloseHandle(_hCommHandle); _hCommHandle = INVALID_HANDLE_VALUE; } bool CBaseSerial::SetDTR(bool OnOrOff) { return IsOpen() ? EscapeCommFunction(_hCommHandle, OnOrOff ? SETDTR : CLRDTR) : false; } bool CBaseSerial::SetRTS(bool OnOrOff) { return IsOpen() ? EscapeCommFunction(_hCommHandle, OnOrOff ? SETRTS : CLRRTS) : false; } bool CBaseSerial::SetBreak(bool OnOrOff) { return IsOpen() ? EscapeCommFunction(_hCommHandle, OnOrOff ? SETBREAK : CLRBREAK) : false; } void CBaseSerial::Init() { memset(_szCommStr, 0, 20*sizeof(TCHAR)); memset(&_DCB, 0, sizeof(_DCB)); _DCB.DCBlength = sizeof(_DCB); _hCommHandle = INVALID_HANDLE_VALUE; memset(&_ReadOverlapped, 0, sizeof(_ReadOverlapped)); memset(&_WriteOverlapped, 0, sizeof(_WriteOverlapped)); _ReadOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL); assert(_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE); _WriteOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL); assert(_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE); _hNotifyWnd = NULL; _dwNotifyNum = 0; _dwMaskEvent = DEFAULT_COM_MASK_EVENT; memset(&_WaitOverlapped, 0, sizeof(_WaitOverlapped)); _WaitOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL); assert(_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE); } void CBaseSerial::UnInit() { if (_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE) CloseHandle(_ReadOverlapped.hEvent); if (_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE) CloseHandle(_WriteOverlapped.hEvent); if (_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE) CloseHandle(_WaitOverlapped.hEvent); } void CBaseSerial::BindCommPort(DWORD dwPort) { assert(dwPort >= 1 && dwPort <= 1024); TCHAR p[5] = {0}; _dwPort = dwPort; _tcscpy_s(_szCommStr, _T("\\\\.\\COM")); _ltot_s(_dwPort, p, 10); _tcscat_s(_szCommStr, p); } bool CBaseSerial::OpenCommPort() { if (IsOpen()) Close(); _hCommHandle = ::CreateFile(_szCommStr, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | _dwIOMode, NULL); return IsOpen(); } bool CBaseSerial::SetupPort() { if (!IsOpen()) return false; // SetupComm设置输入输出缓冲区大小; if (!::SetupComm(_hCommHandle, 8192, 8192)) return false; if (!::GetCommTimeouts(_hCommHandle, &_CO)) return false; _CO.ReadIntervalTimeout = 0; _CO.ReadTotalTimeoutMultiplier = 10; _CO.ReadTotalTimeoutConstant = 1500; _CO.WriteTotalTimeoutMultiplier = 10; _CO.WriteTotalTimeoutConstant = 1500; if (!::SetCommTimeouts(_hCommHandle, &_CO)) return false; // 清空输入输出缓冲区; if (!::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) return false; return true; }