📄 commport.cpp
字号:
} // switch (dwWaitStatus)
// Break out of the while loop.
break;
} // while (1)
// Thats the end. Now clean up.
//EndThread:
OutputDebugString("CommPort write thread shutting down\n");
CloseHandle(p->m_hWriteThread);
return 0;
}
BOOL CCommPort::SetState()
{
COMMPROP commprop;
COMMTIMEOUTS commtimeouts;
DCB dcb;
if (!PurgeComm(m_hCommFile, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR))
{
OutputDebugString("Purge Comm fail\n");
return FALSE;
}
if (!GetCommProperties(m_hCommFile, &commprop))
{
OutputDebugString("Get Comm Properties fail\n");
return FALSE;
}
if (!SetupComm(m_hCommFile, COMMPORT_DATA_SIZE, COMMPORT_DATA_SIZE))
{
OutputDebugString("Setup Comm fail\n");
return FALSE;
}
commtimeouts.ReadIntervalTimeout = 0;
commtimeouts.ReadTotalTimeoutMultiplier = 0;
commtimeouts.ReadTotalTimeoutConstant = 1;
commtimeouts.WriteTotalTimeoutMultiplier = 0;
commtimeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(m_hCommFile, &commtimeouts))
{
OutputDebugString("Set Comm Timeout fail\n");
return FALSE;
}
if (!GetCommState(m_hCommFile, &dcb))
{
OutputDebugString("Get Comm State fail\n");
return FALSE;
}
dcb.fAbortOnError = FALSE;
dcb.BaudRate = m_iBaudRate;
dcb.fBinary = TRUE;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
dcb.fParity = FALSE;
dcb.fNull = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fTXContinueOnXoff = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
if (!SetCommState(m_hCommFile, &dcb))
{
OutputDebugString("Set Comm State fail\n");
return FALSE;
}
if (!SetCommMask(m_hCommFile, EV_ERR)) // Set the comm mask so we receive error signals.
{
OutputDebugString("Unable to SetCommMask: EV_ERR\n");
return FALSE;
}
return TRUE;
}
BOOL CCommPort::SetupReadEvent()
{
DWORD dwLastError, dwRead;
char * pData;
while (TRUE)
{
// Make sure the CloseEvent hasn't been signaled yet. Check is needed because this function is potentially recursive.
if (WAIT_TIMEOUT != WaitForSingleObject(m_hQuitEvent, 0))
{
return FALSE;
}
// Start the overlapped ReadFile.
pData = (char *)malloc(COMMPORT_DATA_SIZE);
if (pData == NULL) return FALSE;
if (ReadFile(m_hCommFile, pData, COMMPORT_DATA_SIZE, &dwRead, &m_overlappedRead))
{ // This would only happen if there was data waiting to be read.
OutputDebugString("Data waiting for ReadFile.\n");
// Handle the data.
if (dwRead > 0)
{
CString temp;
temp.Format("Read %d bytes\n", dwRead);
OutputDebugString(temp);
PostMessage(m_hWnd, m_uMsg, (WPARAM)dwRead, (LPARAM)pData);
}
else
{
free(pData);
}
}
else
break;
}
// ReadFile failed. Expected because of overlapped I/O.
dwLastError = GetLastError();
if (dwLastError == ERROR_IO_PENDING) // LastError was ERROR_IO_PENDING, as expected.
{
if (m_pOverlappedRead != NULL)
free(m_pOverlappedRead);
m_pOverlappedRead = pData;
return TRUE;
}
else if (dwLastError == ERROR_INVALID_HANDLE)
{ // Its possible for this error to occur if the service provider has closed the port. Time to end.
OutputDebugString("ERROR_INVALID_HANDLE: Likely that the Service Provider has closed the port.\n");
}
// Unexpected error. No idea what could cause this to happen.
OutputDebugString("Unexpected ReadFile error in CommPort read thread.\n");
free(pData);
return FALSE;
}
BOOL CCommPort::HandleReadEvent()
{
DWORD dwLastError, dwRead;
if (GetOverlappedResult(m_hCommFile, &m_overlappedRead, &dwRead, FALSE))
{
if (dwRead > 0)
{
PostMessage(m_hWnd, m_uMsg, (WPARAM)dwRead, (LPARAM)m_pOverlappedRead);
}
else
{
free(m_pOverlappedRead);
}
m_pOverlappedRead = NULL;
return TRUE;
}
free(m_pOverlappedRead);
m_pOverlappedRead = NULL;
// Error in GetOverlappedResult; handle it.
dwLastError = GetLastError();
if (dwLastError == ERROR_INVALID_HANDLE)
{ // Its possible for this error to occur if the service provider has closed the port. Time to end.
OutputDebugString("ERROR_INVALID_HANDLE: Likely that the Service Provider has closed the port.\n");
}
OutputDebugString("Unexpected GetOverlappedResult Read Error in CommPort read thread.\n");
return FALSE;
}
BOOL CCommPort::SetupCommEvent()
{
DWORD dwLastError;
while (TRUE)
{
// Make sure the CloseEvent hasn't been signaled yet. Check is needed because this function is potentially recursive.
if (WAIT_TIMEOUT != WaitForSingleObject(m_hQuitEvent, 0))
{
return FALSE;
}
// Start waiting for Comm Errors.
if (WaitCommEvent(m_hCommFile, &m_dwEventMask, &m_overlappedCommEvent))
{
// This could happen if there was an error waiting on the comm port. Lets try and handle it.
OutputDebugString("Event (Error) waiting before WaitCommEvent.\n");
if (!HandleCommEvent(FALSE))
{
return FALSE;
}
// What could cause infinite recursion at this point?
continue;
}
break;
}
// We expect ERROR_IO_PENDING returned from WaitCommEvent because we are waiting with an overlapped structure.
dwLastError = GetLastError();
if (dwLastError == ERROR_IO_PENDING)
{ // LastError was ERROR_IO_PENDING, as expected.
OutputDebugString("Waiting for a CommEvent (Error) to occur.\n");
return TRUE;
}
else if (dwLastError == ERROR_INVALID_HANDLE)
{ // Its possible for this error to occur if the service provider has closed the port. Time to end.
OutputDebugString("ERROR_INVALID_HANDLE: Likely that the Service Provider has closed the port.\n");
return FALSE;
}
// Unexpected error. No idea what could cause this to happen.
OutputDebugString("Unexpected WaitCommEvent error in CommPort read thread.\n");
return FALSE;
}
BOOL CCommPort::HandleCommEvent(BOOL bRetrieveEvent)
{
DWORD dwDummy, dwErrors, dwLastError;
CString strError = "Comm Event: ";
// If this fails, it could be because the file was closed (and I/O is finished) or because the overlapped I/O
// is still in progress. In either case (or any others) its a bug and return FALSE.
if (bRetrieveEvent)
{
if (!GetOverlappedResult(m_hCommFile, &m_overlappedCommEvent, &dwDummy, FALSE))
{
dwLastError = GetLastError();
if (dwLastError == ERROR_INVALID_HANDLE)
{ // Its possible for this error to occur if the service provider has closed the port. Time to end.
OutputDebugString("ERROR_INVALID_HANDLE: Likely that the Service Provider has closed the port.\n");
return FALSE;
}
OutputDebugString("Unexpected GetOverlappedResult for WaitCommEvent in CommPort IO threaed.\n");
return FALSE;
}
}
// Was the event an error?
if (m_dwEventMask & EV_ERR)
{
// Which error was it?
if (!ClearCommError(m_hCommFile, &dwErrors, NULL))
{
dwLastError = GetLastError();
if (dwLastError == ERROR_INVALID_HANDLE)
{ // Its possible for this error to occur if the service provider has closed the port. Time to end.
OutputDebugString("ERROR_INVALID_HANDLE: Likely that the Service Provider has closed the port.\n");
return FALSE;
}
OutputDebugString("ClearCommError in CommPort read thread.\n");
return FALSE;
}
// Its possible that multiple errors occured and were handled in the last ClearCommError. Because all errors
// were signaled individually, but cleared all at once, pending comm events can yield EV_ERR while dwErrors equals 0. Ignore this event.
if (dwErrors == 0)
{
strError += "NULL Error, ";
}
if (dwErrors & CE_FRAME)
{
strError += "CE_FRAME, ";
}
if (dwErrors & CE_OVERRUN)
{
strError += "CE_OVERRUN, ";
}
if (dwErrors & CE_RXPARITY)
{
strError += "CE_RXPARITY, ";
}
if (dwErrors & ~ (CE_FRAME | CE_OVERRUN | CE_RXPARITY))
{
strError += "EV_ERR Unknown EvtMask";
}
strError += "\n";
OutputDebugString(strError);
return TRUE;
}
// Should not have gotten here. Only interested in ERR conditions.
OutputDebugString("Unexpected comm event in CommPort read thread.\n");
return FALSE;
}
BOOL CCommPort::HandleWriteEvent()
{
DWORD dwHandleSignaled, dwLastError, dwNumberWritten = 0, dwStartWriting = 0;
int iLength; // Start at the beginning.
char * pData;
HANDLE eventArray[2]; // The array of events which the write operation is currently waiting on.
CSingleLock sLock(&m_critical);
Data * p = NULL;
sLock.Lock();
if (!m_sendQueue.IsEmpty())
{
p = m_sendQueue.RemoveHead();
}
sLock.Unlock();
if (p == NULL)
return TRUE;
iLength = p->iLength;
pData = p->pData;
eventArray[0] = m_hQuitEvent;
eventArray[1] = m_overlappedWrite.hEvent;
// Keep looping until all bytes have been written.
do
{
// Start the overlapped I/O.
if (!WriteFile(m_hCommFile, &pData[dwStartWriting], iLength, &dwNumberWritten, &m_overlappedWrite))
{
// WriteFile failed. Expected; lets handle it.
dwLastError = GetLastError();
if (dwLastError == ERROR_INVALID_HANDLE)
{ // Its possible for this error to occur if the service provider has closed the port. Time to end.
OutputDebugString("ERROR_INVALID_HANDLE: Likely that the Service Provider has closed the port.\n");
goto Error;
}
if (dwLastError != ERROR_IO_PENDING)
{ // Unexpected error. No idea what.
OutputDebugString("Error to writing to CommFile in CommPort write thread.\n");
goto Error;
}
// This is the expected ERROR_IO_PENDING case.
// Wait for either overlapped I/O completion, or for the CloseEvent to get signaled.
dwHandleSignaled = WaitForMultipleObjects(2, eventArray, FALSE, INFINITE);
switch (dwHandleSignaled)
{
case WAIT_OBJECT_0: // CloseEvent signaled! Time to exit.
goto Error;
case WAIT_OBJECT_0 + 1: // Wait finished. Time to get the results of the WriteFile
break;
case WAIT_FAILED: // Wait failed. Shouldn't happen.
OutputDebugString("Write WAIT_FAILED in CommPort write thread.\n");
goto Error;
default: // This case should never occur.
OutputDebugString("Unexpected Wait return value in CommPort write thread.\n");
goto Error;
}
if (!GetOverlappedResult(m_hCommFile, &m_overlappedWrite, &dwNumberWritten, TRUE))
{
dwLastError = GetLastError();
if (dwLastError == ERROR_INVALID_HANDLE)
{ // Its possible for this error to occur if the service provider has closed the port.
OutputDebugString("ERROR_INVALID_HANDLE: Likely that the Service Provider has closed the port.\n");
goto Error;
}
// No idea what could cause another error.
OutputDebugString("Error writing to CommFile while waiting in CommPort write thread.\n");
goto Error;
}
}
// Some data was written. Make sure it all got written.
iLength -= dwNumberWritten;
dwStartWriting += dwNumberWritten;
} while(iLength > 0); // Write the whole thing!
free(pData);
free(p);
sLock.Lock();
if (!m_sendQueue.IsEmpty())
{
SetEvent(m_hOutputEvent);
}
sLock.Unlock();
return TRUE;
Error:
free(pData);
free(p);
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -