|
@@ -1,6 +1,21 @@
|
|
|
#include "stdafx.h"
|
|
|
#include "Serial.h"
|
|
|
|
|
|
+VOID _dprintf(CHAR* pszStr, ...)
|
|
|
+{
|
|
|
+ const int LOGLEN = 3072;
|
|
|
+ char szData[LOGLEN] = { 0 };
|
|
|
+ _stprintf_s(szData, _T("[%s %s]\n\t"), _T("Db"), CTime::GetCurrentTime().Format(_T("%H:%M:%S")).GetString());
|
|
|
+ int len = strlen(szData);
|
|
|
+ va_list args;
|
|
|
+ va_start(args, pszStr);
|
|
|
+ _vsnprintf_s(szData + len, LOGLEN - len, LOGLEN - len, pszStr, args);
|
|
|
+ va_end(args);
|
|
|
+ if (szData[strlen(szData) - 1] != '\n')
|
|
|
+ strcat_s(szData, "\n");
|
|
|
+ OutputDebugStringA(szData);
|
|
|
+}
|
|
|
+
|
|
|
DCB *CBaseSerial::GetState()
|
|
|
{
|
|
|
return IsOpen() && ::GetCommState(_hCommHandle, &_DCB) == TRUE ? &_DCB : NULL;
|
|
@@ -45,8 +60,9 @@ LPCOMMTIMEOUTS CBaseSerial::GetTimeouts()
|
|
|
return IsOpen() && ::GetCommTimeouts(_hCommHandle, &_CO) == TRUE ? &_CO : NULL;
|
|
|
}
|
|
|
|
|
|
-bool CBaseSerial::SetTimeouts(COMMTIMEOUTS CO)
|
|
|
+bool CBaseSerial::SetTimeouts(DWORD ReadIntervalTimeout /* = 0 */, DWORD ReadTotalTimeoutMultiplier /* = 10 */, DWORD ReadTotalTimeoutConstant /* = 1500 */, DWORD WriteTotalTimeoutMultiplier /* = 10 */, DWORD WriteTotalTimeoutConstant /* = 1500 */)
|
|
|
{
|
|
|
+ COMMTIMEOUTS CO = {ReadIntervalTimeout, ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant, WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant};
|
|
|
return IsOpen() ? ::SetCommTimeouts(_hCommHandle, &CO) == TRUE : false;
|
|
|
}
|
|
|
|
|
@@ -113,8 +129,7 @@ DWORD CBaseSerial::Read(LPVOID Buffer, DWORD dwBufferLength, DWORD dwWaitTime /*
|
|
|
|
|
|
COMSTAT Stat;
|
|
|
DWORD dwError;
|
|
|
- if (::ClearCommError(_hCommHandle, &dwError, &Stat) && dwError > 0)
|
|
|
- {
|
|
|
+ if (::ClearCommError(_hCommHandle, &dwError, &Stat) && dwError > 0) {
|
|
|
::PurgeComm(_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR); // 清空输入缓冲区(PURGE_RXCLEAR)
|
|
|
return 0;
|
|
|
}
|
|
@@ -124,25 +139,33 @@ DWORD CBaseSerial::Read(LPVOID Buffer, DWORD dwBufferLength, DWORD dwWaitTime /*
|
|
|
if (!Stat.cbInQue)
|
|
|
return 0; // 缓冲区无数据
|
|
|
#endif
|
|
|
+ _dprintf("缓冲区数据量:%ld", Stat.cbInQue);
|
|
|
|
|
|
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 (!::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength, &_ReadOverlapped)) { // 可能Buffer不够大,装不完;
|
|
|
+ // WaitForSingleObject(_ReadOverlapped.hEvent, dwWaitTime); // 没必要这里等;
|
|
|
+ if (::GetLastError() == ERROR_IO_PENDING) {
|
|
|
+ while (!::GetOverlappedResult(_hCommHandle, &_ReadOverlapped, &uReadLength, false)) {
|
|
|
+ dwError = ::GetLastError();
|
|
|
+ if ( dwError == ERROR_IO_PENDING ) {
|
|
|
+ Sleep(50);
|
|
|
+ _dprintf("读等待:%ld", dwError);
|
|
|
+ } else if ( dwError == ERROR_SUCCESS || dwError == ERROR_IO_INCOMPLETE ) {
|
|
|
+ _dprintf("读完成:%ld,%ld,%ld", dwError, uReadLength,_ReadOverlapped.InternalHigh);
|
|
|
+ // 奇葩:_ReadOverlapped并不能马上出长度,在超时后才会刷新出来(不知是否与Win平台有关);
|
|
|
+ if ( _ReadOverlapped.InternalHigh )
|
|
|
+ uReadLength = _ReadOverlapped.InternalHigh;
|
|
|
+ else
|
|
|
+ uReadLength = Stat.cbInQue;
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ _dprintf("读错误:%ld", dwError);
|
|
|
+ uReadLength = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- if (::GetLastError() != ERROR_IO_INCOMPLETE)
|
|
|
- uReadLength = 0;
|
|
|
}
|
|
|
- else
|
|
|
- uReadLength = 0;
|
|
|
}
|
|
|
|
|
|
return uReadLength;
|
|
@@ -166,8 +189,24 @@ DWORD CBaseSerial::Write(LPVOID Buffer, DWORD dwBufferLength)
|
|
|
|
|
|
unsigned long uWriteLength = 0;
|
|
|
if (!::WriteFile(_hCommHandle, Buffer, dwBufferLength, &uWriteLength, &_WriteOverlapped)) {
|
|
|
- if (::GetLastError() != ERROR_IO_PENDING) {
|
|
|
- uWriteLength = 0;
|
|
|
+ if (ERROR_IO_PENDING == GetLastError()) {
|
|
|
+ while (!GetOverlappedResult(_hCommHandle, &_WriteOverlapped, &uWriteLength, FALSE)) {
|
|
|
+ _dprintf("GetOverlappedResult");
|
|
|
+ dwError = GetLastError();
|
|
|
+ if (ERROR_IO_PENDING == dwError) {
|
|
|
+ _dprintf("写等待");
|
|
|
+ continue;
|
|
|
+ } else if (dwError == ERROR_SUCCESS || dwError == ERROR_IO_INCOMPLETE){
|
|
|
+ uWriteLength = _WriteOverlapped.InternalHigh;
|
|
|
+ _dprintf("写完成:%ld", dwError);
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ _dprintf("写出错:%ld",dwError);
|
|
|
+ uWriteLength = 0;
|
|
|
+ ClearCommError(_hCommHandle, &dwError, NULL);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -185,15 +224,46 @@ DWORD CBaseSerial::ReadSync(LPVOID Buffer, DWORD dwBufferLength)
|
|
|
if (!IsOpen())
|
|
|
return 0;
|
|
|
|
|
|
+ COMSTAT Stat;
|
|
|
DWORD dwError;
|
|
|
- if (::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0)
|
|
|
- {
|
|
|
- ::PurgeComm(_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR); // 清空输入缓冲区(PURGE_RXCLEAR)
|
|
|
+
|
|
|
+ DWORD dwLastLen = 0;
|
|
|
+ ULONGLONG ulTick = GetTickCount();
|
|
|
+ // 直到有数据为止,超时3秒;
|
|
|
+ while (true) {// cbInQue表示输入缓冲区的字节数;
|
|
|
+ if (GetTickCount() - ulTick > 3000) {
|
|
|
+ _dprintf("读出错: 超过3秒仍未读完");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( ::ClearCommError(_hCommHandle, &dwError, &Stat) && dwError > 0 ) {
|
|
|
+ ::PurgeComm(_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR); // 清空输入缓冲区(PURGE_RXCLEAR)
|
|
|
+ _dprintf("读出错: ClearCommError出错");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 防止读一次没读完,再读一次;二次长度一样表示读完;
|
|
|
+ if (Stat.cbInQue != 0 && dwLastLen == Stat.cbInQue)
|
|
|
+ break;
|
|
|
+ dwLastLen = Stat.cbInQue;
|
|
|
+ Sleep(100);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Stat.cbInQue == 0) {
|
|
|
+ // 串口超时,无数据返回;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ if (dwBufferLength < Stat.cbInQue) {
|
|
|
+ _dprintf("读出错: 缓冲数据过大 %ld > %ld", dwBufferLength, Stat.cbInQue);
|
|
|
+ }
|
|
|
+
|
|
|
DWORD uReadLength = 0;
|
|
|
- ::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength, NULL);
|
|
|
+ if ( !::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength, NULL) )
|
|
|
+ {
|
|
|
+ DWORD dwError = GetLastError();
|
|
|
+ _dprintf("读出错:%ld", dwError);
|
|
|
+ }
|
|
|
|
|
|
return uReadLength;
|
|
|
}
|
|
@@ -208,7 +278,11 @@ DWORD CBaseSerial::WriteSync(LPVOID Buffer, DWORD dwBufferLength)
|
|
|
::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR); // 清空输出缓冲区(PURGE_TXCLEAR)
|
|
|
|
|
|
unsigned long uWriteLength = 0;
|
|
|
- ::WriteFile(_hCommHandle, Buffer, dwBufferLength, &uWriteLength, NULL);
|
|
|
+ if ( !::WriteFile(_hCommHandle, Buffer, dwBufferLength, &uWriteLength, NULL) )
|
|
|
+ {
|
|
|
+ DWORD dwError = GetLastError();
|
|
|
+ _dprintf("写出错:%ld", dwError);
|
|
|
+ }
|
|
|
|
|
|
return uWriteLength;
|
|
|
}
|