⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comm.cpp

📁 串口调试助手的源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// object is signaled, then it exits.  The use of messages to tell the
// Write thread what to write provides a natural desynchronization between
// the UI and the Write thread.
DWORD	CCommInfo::WriteThreadProc(LPVOID  lpvParam)
{
	CCommInfo*	pComm = (CCommInfo*)lpvParam;
	if (pComm == NULL ||
		!pComm->IsKindOf(RUNTIME_CLASS(CCommInfo)))
		return  -1;	// illegal parameter

	// Needed for overlapped I/O.
	OVERLAPPED	overlappedWrite = {0, 0, 0, 0, NULL};
	overlappedWrite.hEvent = ::CreateEvent(NULL, TRUE, TRUE, NULL);
	if (overlappedWrite.hEvent == NULL)
	{
		TRACE0("Unable to CreateEvent: overlappedWrite\n");
		pComm->PostCommError();
		goto  LABEL_ENDWRITETHREAD;
	}

	// This is the main loop.  Loop until we break out.
	while (TRUE)
	{
		MSG	msg;
		if (!::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			// If there are no messages pending, wait for a message or the CloseEvent.
			DWORD	dwHandleSignaled = 
				::MsgWaitForMultipleObjects(1, &pComm->m_hCloseEvent, FALSE,
					INFINITE, QS_ALLINPUT);

			switch (dwHandleSignaled)
			{
			case WAIT_OBJECT_0:	// CloseEvent signaled!
				// Time to exit.
				goto  LABEL_ENDWRITETHREAD;

                case WAIT_OBJECT_0 + 1: // New message was received.
                    // Get the message that woke us up by looping again.
                    continue;

                case WAIT_FAILED:	// Wait failed.  Shouldn't happen.
                    TRACE0("Write WAIT_FAILED \n");
                    pComm->PostCommError();
                    goto  LABEL_ENDWRITETHREAD;

                default:	// This case should never occur.
                    TRACE1("Unexpected Wait return value '%lx'", dwHandleSignaled);
                    pComm->PostCommError();
                    goto LABEL_ENDWRITETHREAD;
			}
		}

		// Make sure the CloseEvent isn't signaled while retrieving messages.
		if (::WaitForSingleObject(pComm->m_hCloseEvent, 0) != WAIT_TIMEOUT)
			goto  LABEL_ENDWRITETHREAD;

		// Process the message.
		// This could happen if a dialog is created on this thread.
		// This doesn't occur in this sample, but might if modified.
		if (msg.hwnd != NULL)
		{
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
			continue;
		}

		// Handle the message.
		CString	 strWriteValue;
		switch (msg.message)
		{
		case PWM_COMMWRITE:  // New string to write to Comm port.
			TRACE0("Writing to comm port\n");
		//	TRACE0((LPSTR)msg.lParam);
			TRACE0("....\n");
			// Write the string to the comm port.  HandleWriteData
			// does not return until the whole string has been written,
			// an error occurs or until the CloseEvent is signaled.
			if (!pComm->HandleWriteData(&overlappedWrite,
				(LPSTR)msg.lParam, (DWORD)msg.wParam))
			{
				// If it failed, either we got a signal to end or there
				// really was a failure.
				goto  LABEL_ENDWRITETHREAD;
			}
			break;

		// What other messages could the thread get?
		default:
			TRACE1("Unexpected message posted to Write thread: %ui\n",
				msg.message);
			break;
		}	// End of switch(message)
	}	// End of main loop.

	// Thats the end.  Now clean up.
LABEL_ENDWRITETHREAD:

	TRACE0("Write thread shutting down\n");
	::PurgeComm(pComm->m_hCommFile, PURGE_TXABORT | PURGE_TXCLEAR);
	::CloseHandle(overlappedWrite.hEvent);
	
//	pComm->m_pWriteThread = NULL;
	::AfxEndThread(0);

//	pComm->m_dwWriteThreadID = 0;
//	::CloseHandle(pComm->m_hWriteThread);
//	pComm->m_hWriteThread = 0;
	return  0;
}

// Writes a given string to the comm file handle.
// It is this call that actually writes a string to the comm file.
// Note that this call blocks and waits for the Write to complete
// or for the CloseEvent object to signal that the thread should end.
// Another possible reason for returning FALSE is if the comm port
// is closed by the service provider.
BOOL	CCommInfo::HandleWriteData(LPOVERLAPPED  lpOverlappedWrite,
	LPCSTR  lpszStringToWrite, DWORD  dwNumberOfBytesToWrite)
{
	if (m_bRTS)
	{
		// special for connection with DIANTAI ? 
		// assert RTS
		::EscapeCommFunction(m_hCommFile, SETRTS);
		::Sleep(500);
	}

	HANDLE	HandlesToWaitFor[2];
	HandlesToWaitFor[0] = m_hCloseEvent;
	HandlesToWaitFor[1] = lpOverlappedWrite->hEvent;

	// Keep looping until all characters have been written.
	DWORD	dwNumberOfBytesWritten = 0;
	DWORD	dwWhereToStartWriting = 0; // Start at the beginning.

	do
	{
		// Start the overlapped I/O.
		if (!::WriteFile(m_hCommFile,
			&lpszStringToWrite[dwWhereToStartWriting], 
			dwNumberOfBytesToWrite, &dwNumberOfBytesWritten,
			lpOverlappedWrite))
		{
			// WriteFile failed.  Expected; lets handle it.
			switch (::GetLastError())
			{
			// Its possible for this error to occur if the 
			// service provider has closed the port.  Time to end.
			case ERROR_INVALID_HANDLE:
				TRACE0("ERROR_INVALID_HANDLE, Likely that the Service Provider has closed the port.\n");
				return  FALSE;


			// This is the expected ERROR_IO_PENDING case.
			case ERROR_IO_PENDING:
			{
				// Wait for either overlapped I/O completion,
				// or for the CloseEvent to get signaled.
				DWORD	dwHandleSignaled = ::WaitForMultipleObjects(2, HandlesToWaitFor,
					FALSE, INFINITE);

				switch (dwHandleSignaled)
				{
				case WAIT_OBJECT_0:	// CloseEvent signaled!
					// Time to exit.
					return  FALSE;

				case  WAIT_OBJECT_0 + 1:	// Wait finished.
					// Time to get the results of the WriteFile
					break;

				case  WAIT_FAILED: // Wait failed.  Shouldn't happen.
					TRACE0("Write WAIT_FAILED !\n");
					PostCommError();
					return  FALSE;

				default:	// This case should never occur.
					TRACE1("Unexpected Wait return value '%lx'",
						dwHandleSignaled);
					PostCommError();
					return  FALSE;
				}

				if (!::GetOverlappedResult(m_hCommFile,
					lpOverlappedWrite,
					&dwNumberOfBytesWritten, TRUE))
				{
					switch (::GetLastError())
					{
					// Its possible for this error to occur if the 
					// service provider has closed the port.
					case ERROR_INVALID_HANDLE:
						TRACE0("ERROR_INVALID_HANDLE, Likely that the Service Provider has closed the port.\n");
						return  FALSE;

					default:
						// No idea what could cause another error.
						TRACE0("Error writing to CommFile while waiting\n");
						TRACE0("Closing TAPI\n");
						PostCommError();
						return  FALSE;
					}
				}
				break;
			}

			// Unexpected error.  No idea what.
			default:
				TRACE0("Error to writing to CommFile, Closing TAPI\n");
				PostCommError();
				return  FALSE;
			}
		}

		// Some data was written.  Make sure it all got written.
		dwNumberOfBytesToWrite -= dwNumberOfBytesWritten;
		dwWhereToStartWriting += dwNumberOfBytesWritten;
	}
	while (dwNumberOfBytesToWrite > 0);	// Write the whole thing!

	// 1997.03.27
	if (m_bRTS)
	{
		// special for connection with DIANTAI ? 
		::Sleep(500);
		// drop RTS
		::EscapeCommFunction(m_hCommFile, CLRRTS);
		::Sleep(200);
	}

	// Wrote the whole string.
	return  TRUE;
}

// Sets up an overlapped ReadFile
// This function sets up the overlapped ReadFile so that it can later
// be waited on (or more appropriatly, so the event in the overlapped
// structure can be waited upon).  If there is data waiting, it is
// handled and the next ReadFile is initiated.
// Another possible reason for returning FALSE is if the comm port
// is closed by the service provider.
BOOL	CCommInfo::SetupReadEvent(LPOVERLAPPED  lpOverlappedRead,
	LPDWORD  lpnNumberOfBytesRead)
{
//	while (*((WORD*)m_pReadBuf) != 0)
//		;

	while (TRUE)
	{
		// Make sure the CloseEvent hasn't been signaled yet.
		// Check is needed because this function is potentially recursive.
		if (::WaitForSingleObject(m_hCloseEvent, 0) != WAIT_TIMEOUT)
			return  FALSE;
    
		::WaitForSingleObject(m_hPostEvent, INFINITE);

		// Start the overlapped ReadFile.
		if (::ReadFile(m_hCommFile,
			m_pReadBuf + sizeof(WORD), m_nReadBufLen,
			lpnNumberOfBytesRead, lpOverlappedRead))
		{
			// This would only happen if there was data waiting to be read.
			TRACE0("Data waiting for ReadFile.\n");

			// Handle the data.
			if (!HandleReadData(*lpnNumberOfBytesRead))
			{
				return  FALSE;
			}
		}
		else
			break;
	}

	// ReadFile failed.  Expected because of overlapped I/O.
	switch (::GetLastError())
	{
	// LastError was ERROR_IO_PENDING, as expected.
	case ERROR_IO_PENDING:
//		TRACE0("Waiting for data from comm connection.\n");
		return  TRUE;

	// Its possible for this error to occur if the 
	// service provider has closed the port.  Time to end.
	case ERROR_INVALID_HANDLE:
		TRACE0("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.
	default:
		TRACE0("Unexpected ReadFile error");
		PostCommError();
		return  FALSE;
	}
}
 
// Retrieves and handles data when there is data ready.
// This is the function that is called when there is 
// data available after an overlapped ReadFile has been 
// setup. It retrieves the data and handles it.
BOOL	CCommInfo::HandleReadEvent(LPOVERLAPPED  lpOverlappedRead,
	LPDWORD  lpnNumberOfBytesRead)
{
	if (::GetOverlappedResult(m_hCommFile,
		lpOverlappedRead, lpnNumberOfBytesRead, FALSE))
	{
//		*((WORD*)m_pReadBuf) = (WORD)*lpnNumberOfBytesRead;
		return  HandleReadData(*lpnNumberOfBytesRead);
	}

	// Error in GetOverlappedResult; handle it.
	switch (::GetLastError())
	{
	// Its possible for this error to occur if the 
	// service provider has closed the port. Time to end.
	case ERROR_INVALID_HANDLE:
		TRACE0("ERROR_INVALID_HANDLE, Likely that the Service Provider has closed the port.\n");
		return  FALSE;

	default:
		TRACE0("Unexpected GetOverlappedResult Read Error !\n");
		PostCommError();
		return  FALSE;
	}
}

// Deals with data after its been read from the comm file.
// This function is yet another helper function for the Read Thread.
BOOL	CCommInfo::HandleReadData(DWORD  dwSizeofBuffer)
{
	// If we got data and didn't just time out empty...
	if (dwSizeofBuffer)
	{
		// Do something with the bytes read.
		TRACE0("Got something from Comm port!!!\n");

		::ResetEvent(m_hPostEvent);
		*((WORD*)m_pReadBuf) = (WORD)dwSizeofBuffer;
			
		if (m_pNotifyWnd != NULL)
		{
			if (m_pNotifyWnd->PostMessage(WM_COMMAND,
				m_dwCommBaseCommandID + ID_COMM_READ,
				(LPARAM)m_pNotifyWnd->GetSafeHwnd()) == FALSE)
			{
				::SetEvent(m_hPostEvent);
				return  FALSE;
			}
			else
				return  TRUE;
		}
		else
		{
			// avoid MainWnd is NULL
			if (::AfxGetApp()->m_pMainWnd != NULL)
			{
				if (::AfxGetApp()->m_pMainWnd->PostMessage(WM_COMMAND,
					m_dwCommBaseCommandID + ID_COMM_READ,
					0) == FALSE)
				{
					::SetEvent(m_hPostEvent);
					return  FALSE;
				}
				else
					return  TRUE;
			}
			else
			{
				::SetEvent(m_hPostEvent);
				return  TRUE;	// only 
			}
		}
	}
	return  TRUE;
}

BOOL	CCommInfo::PostCommError(void)
{
	if (m_pNotifyWnd != NULL)
	{
		return  m_pNotifyWnd->PostMessage(WM_COMMAND,
			m_dwCommBaseCommandID + ID_COMM_ERROR,
			(LPARAM)m_pNotifyWnd->GetSafeHwnd());
	}
	else
	{
		// avoid MainWnd is NULL
		if (::AfxGetApp()->m_pMainWnd != NULL)
		{
			return  ::AfxGetApp()->m_pMainWnd->PostMessage(WM_COMMAND,
				m_dwCommBaseCommandID + ID_COMM_ERROR,
				0);
		}
		else
			return  FALSE;
	}
}
		
void	CCommInfo::SuspendReadThread(void)
{
//	::SuspendThread(m_hReadThread);
	m_pReadThread->SuspendThread();
}

void	CCommInfo::ResumeReadThread(void)
{
//	::ResumeThread(m_hReadThread);
	m_pReadThread->ResumeThread();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -