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

📄 serialcommlayer.cpp

📁 串口通讯在客户端/服务器类型的应用程序设计中经常要使用到
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	if ((*lpfdwEvtMask & EV_ERR) != 0)
	{
#ifdef __RCC_DEBUG__
		DisplayMessage("链接检测到错误");
#endif
		// Which error was it?
		if(!ClearCommError( hCommFile, &dwErrors, NULL))
		{
			dwLastError = GetLastError();
			
			// Its possible for this error to occur if the
			// service provider has closed the port.  Time to end.
			if(dwLastError == ERROR_INVALID_HANDLE)
				return FALSE;
			
			PostHangupCall();
			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(!ReceiveError( dwErrors ))
			return FALSE;
	}
	dwModemEvent = 0;
	
	if ((*lpfdwEvtMask & EV_RLSD) != 0)
	{
		dwModemEvent = MDM_CONN;
#ifdef __RCC_DEBUG__
		DisplayMessage("链接检测到");
#endif
	}
	if ((*lpfdwEvtMask & EV_RING) != 0) 
	{
		dwModemEvent = dwModemEvent | MDM_RING;
#ifdef __RCC_DEBUG__
		DisplayMessage("检测到RING");
#endif
	}
	
	if( dwModemEvent != 0 )
	{
		if(!ModemStateChange( dwModemEvent ))
		{
			return FALSE;
		}
	}
	
	if(((*lpfdwEvtMask & EV_ERR)==0) && (dwModemEvent==0))
	{
		// Should not have gotten here.
		PostHangupCall();
	}
	return TRUE;
}

//
//  FUNCTION: HandleReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD)
//
//  PURPOSE: Retrieves and handles data when there is data ready.
//
//  PARAMETERS:
//    lpOverlappedRead      - address of overlapped structure to use.
//    lpszInputBuffer       - Buffer to place incoming bytes.
//    dwSizeofBuffer        - size of lpszInputBuffer.
//    lpnNumberOfBytesRead  - address of DWORD to place the number of read bytes.
//
//  RETURN VALUE:
//    TRUE if able to successfully retrieve and handle the available data.
//    FALSE if unable to retrieve or handle the data.
//
//  COMMENTS:
//
//    This function is another helper function for the Read Thread.  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 CCommReadThread::HandleReadEvent(LPOVERLAPPED lpOverlappedRead,LPSTR lpszInputBuffer,
									  DWORD dwSizeOfBuffer,LPDWORD lpnNumberOfBytesRead)
{
	DWORD dwLastError;
	
    if (GetOverlappedResult( hCommFile,
		lpOverlappedRead, lpnNumberOfBytesRead, TRUE ))
	{
		return HandleReadData( lpszInputBuffer, *lpnNumberOfBytesRead );
		  }
	
	// Error in GetOverlappedResult; handle it.
	
	dwLastError = GetLastError();
//	if(dwLastError == ERROR_IO_INCOMPLETE)
//	{
//		return TRUE;
//	}
	
	// Its possible for this error to occur if the
	// service provider has closed the port.  Time to end.
	if(dwLastError == ERROR_INVALID_HANDLE)
	{
		return FALSE;
	}
	
	// Unexpected error come here. No idea what could cause this to happen.
	PostHangupCall();
	return TRUE;
}

//
//  FUNCTION: HandleReadData(LPCSTR, DWORD)
//
//  PURPOSE: Deals with data after its been read from the comm file.
//
//  PARAMETERS:
//    lpszInputBuffer  - Buffer to place incoming bytes.
//    dwSizeofBuffer   - size of lpszInputBuffer.
//
//  RETURN VALUE:
//    TRUE if able to successfully handle the data.
//    FALSE if unable to allocate memory or handle the data.
//
//  COMMENTS:
//
//    This function is yet another helper function for the Read Thread.
//    It LocalAlloc()s a buffer, copies the new data to this buffer and
//    calls PostWriteToDisplayCtl to let the EditCtls module deal with
//    the data.  Its assumed that PostWriteToDisplayCtl posts the message
//    rather than dealing with it right away so that the Read Thread
//    is free to get right back to waiting for data.  Its also assumed
//    that the EditCtls module is responsible for LocalFree()ing the
//    pointer that is passed on.
//
//
BOOL CCommReadThread::HandleReadData(LPCSTR lpszInputBuffer,DWORD dwSizeOfBuffer)
{
	LPSTR lpszPostedBytes;
	
	// If we got data and didn't just time out empty...
	if( dwSizeOfBuffer != 0)
	{
		// Do something with the bytes read.
		
		lpszPostedBytes = new char[dwSizeOfBuffer+1];
		
		if (lpszPostedBytes == NULL)
		{
			// Out of memory
			
			PostHangupCall();
		}
		
		memcpy((void *)lpszPostedBytes,lpszInputBuffer,dwSizeOfBuffer );
		lpszPostedBytes[dwSizeOfBuffer] = 0;
		
		return ReceiveData( lpszPostedBytes, dwSizeOfBuffer );
	}
	return FALSE;
}

BOOL CCommReadThread::ReceiveData(LPSTR lpNewString,DWORD dwSizeOfNewString)
{
	if(!PostMessage( hComm32Window, PWM_GOTCOMMDATA,
		WPARAM(dwSizeOfNewString), LPARAM(lpNewString) ))
	{
        PostHangupCall();
		return FALSE;
	}
	return TRUE;
}

BOOL CCommReadThread::ReceiveError(DWORD EvtMask)
{
	if(!PostMessage( hComm32Window, PWM_RECEIVEERROR, 0, LPARAM(EvtMask)))
	{
        PostHangupCall();
		return FALSE;
	}
	return TRUE;
}

BOOL CCommReadThread::ModemStateChange(DWORD ModemEvent)
{
	if(!PostMessage( hComm32Window, WM_RCCNOTIFY, MAKEWPARAM(RCC_BIN_STATE,0), LPARAM(ModemEvent)))
	{
        PostHangupCall();
		return FALSE;
	}
	return TRUE;
}

void CCommReadThread::PostHangupCall(void)
{
     PostMessage( hComm32Window, PWM_REQUESTHANGUP, 0, 0 );
}

//(******************************************************************************)
//  WRITE THREAD
//(******************************************************************************)

//
//  PROCEDURE: TWriteThread.Execute
//
//  PURPOSE: The starting point for the Write thread.
//
//  PARAMETERS:
//    lpvParam - unused.
//
//  RETURN VALUE:
//    DWORD - unused.
//
//  COMMENTS:
//
//    The Write thread uses a PeekMessage loop to wait for a string to write,
//    and when it gets one, it writes it to the Comm port.  If the CloseEvent
//    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.
//
//
int CCommWriteThread::Run() 
{
	// TODO: Add your specialized code here and/or call the base class
	MSG msg;
	DWORD dwHandleSignaled;
	OVERLAPPED overlappedWrite;
	BOOL CompleteOneWriteRequire;
	
	// Needed for overlapped I/O.
	memset( &overlappedWrite, sizeof(overlappedWrite), 0 );//  {0, 0, 0, 0, NULL}
	
	overlappedWrite.hEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
	if(overlappedWrite.hEvent == 0)
	{
		PostHangupCall();
		goto EndWriteThread;
	}
	
	CompleteOneWriteRequire = TRUE;
	
	// This is the main loop.  Loop until we break out.
	while(TRUE)
	{
		if(!PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
		{
			// If there are no messages pending, wait for a message or
			// the CloseEvent.
			
			SendDataEmpty = TRUE;
			
			if(CompleteOneWriteRequire)
			{
				if(!PostMessage( hComm32Window, PWM_SENDDATAEMPTY, 0, 0 ))
				{
					PostHangupCall();
					goto EndWriteThread;
				}
			}
			
			CompleteOneWriteRequire = FALSE;
			
			dwHandleSignaled = MsgWaitForMultipleObjects(1, &hCloseEvent, FALSE,
				INFINITE, QS_ALLINPUT);
			
			switch(dwHandleSignaled)
			{
			case WAIT_OBJECT_0:     // CloseEvent signaled!
				// Time to exit.
				goto 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.
				PostHangupCall();
				goto EndWriteThread;
			default:// This case should never occur.
				PostHangupCall();
				goto EndWriteThread;
			}
		}
		
		// Make sure the CloseEvent isn't signaled while retrieving messages.
		if(WaitForSingleObject(hCloseEvent,0) !=  WAIT_TIMEOUT)
			goto 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 != 0)
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			continue;
		}
		
		// Handle the message.
		switch(msg.message)
		{
		case PWM_COMMWRITE:  // New string to write to Comm port.
			// 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(!HandleWriteData( &overlappedWrite,
				(LPSTR)msg.lParam, (DWORD)msg.wParam ))
			{
				// If it failed, either we got a signal to end or there
				// really was a failure.
				
				LocalFree( HLOCAL(msg.lParam) );
				goto EndWriteThread;
			}
			
			CompleteOneWriteRequire = TRUE;
			// Data was sent in a LocalAlloc()d buffer.  Must free it.
			LocalFree( HLOCAL(msg.lParam) );
			break;
		}
	}//{main loop}
		
		// Thats the end.  Now clean up.
EndWriteThread:
		
	PostHangupCall();
	PurgeComm(hCommFile, PURGE_TXABORT | PURGE_TXCLEAR);
	SendDataEmpty = TRUE;
	CloseHandle(overlappedWrite.hEvent);
	
	return 0; //CWinThread::Run();
}

//
//  FUNCTION: HandleWriteData(LPOVERLAPPED, LPCSTR, DWORD)
//
//  PURPOSE: Writes a given string to the comm file handle.
//
//  PARAMETERS:
//    lpOverlappedWrite  - Overlapped structure to use in WriteFile
//    pDataToWrite       - String to write.
//    dwNumberOfBytesToWrite - Length of String to write.
//
//  RETURN VALUE:
//    TRUE if all bytes were written.  False if there was a failure to
//    write the whole string.
//
//  COMMENTS:
//
//    This function is a helper function for the Write Thread.  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 CCommWriteThread::HandleWriteData(LPOVERLAPPED lpOverlappedWrite,LPSTR pDataToWrite,
		DWORD dwNumberOfBytesToWrite)
{
	DWORD dwLastError,dwNumberOfBytesWritten,
		dwWhereToStartWriting,dwHandleSignaled;
	HANDLE HandlesToWaitFor[2];
	
	dwNumberOfBytesWritten = 0;
	dwWhereToStartWriting = 0; // Start at the beginning.
	
	HandlesToWaitFor[0] = hCloseEvent;
	HandlesToWaitFor[1] = lpOverlappedWrite->hEvent;
	
	// Keep looping until all characters have been written.
	do
	{
		// Start the overlapped I/O.
		if(!WriteFile( hCommFile,
			&(pDataToWrite[ dwWhereToStartWriting ]),
			dwNumberOfBytesToWrite, &dwNumberOfBytesWritten,
			lpOverlappedWrite ))
		{
			// WriteFile failed.  Expected; lets handle it.
			dwLastError = GetLastError();
			
			// Its possible for this error to occur if the
			// service provider has closed the port.  Time to end.
			if(dwLastError == ERROR_INVALID_HANDLE)
				return FALSE;
			
			// Unexpected error.  No idea what.
			if (dwLastError != ERROR_IO_PENDING)
			{
				PostHangupCall();
				return FALSE;
			}
			
			// 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, 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
				if(!GetOverlappedResult(hCommFile,
					lpOverlappedWrite,
					&dwNumberOfBytesWritten, TRUE))
				{
					dwLastError = GetLastError();
					
					// Its possible for this error to occur if the
					// service provider has closed the port.
					if(dwLastError == ERROR_INVALID_HANDLE)
						return FALSE;
					
					// No idea what could cause another error.
					PostHangupCall();
					return FALSE;
				}
				break;
				
			case WAIT_FAILED: // Wait failed.  Shouldn't happen.
				PostHangupCall();
				return FALSE;
			default:// This case should never occur.
				PostHangupCall();
				return FALSE;
			}//end of case
		}// end of WriteFile failure
		
		// Some data was written.  Make sure it all got written.
		
		dwNumberOfBytesToWrite-= dwNumberOfBytesWritten;
		dwWhereToStartWriting+= dwNumberOfBytesWritten;
	}while(dwNumberOfBytesToWrite > 0);  // Write the whole thing!
//	}while(dwNumberOfBytesToWrite <= 0);  // Write the whole thing!
	
	// Wrote the whole string.
	return TRUE;
}

void CCommWriteThread::PostHangupCall(void)
{
     PostMessage( hComm32Window, PWM_REQUESTHANGUP, 0, 0 );
}

/////////////////////////////////////////////////////////////////////////////
// CRCCComm

CRCCComm::CRCCComm()
{
	hCloseEvent = INVALID_HANDLE;
	hCommFile = INVALID_HANDLE;
	ReadThread = NULL;
	WriteThread = NULL;
	CommNo = 1;
	RCCMode = MODE_MODEM;
	Init();
}

CRCCComm::CRCCComm(int PortNo)
{
	hCloseEvent = INVALID_HANDLE;
	hCommFile = INVALID_HANDLE;
	ReadThread = NULL;
	WriteThread = NULL;
	CommNo = PortNo;
	RCCMode = MODE_MODEM;
	Init();
}

void CRCCComm::SetPortNo(int PortNo)
{
	if(RCCStatus == RCC_STAT_INIT)
	{
		CommNo = PortNo;
	}
}

void CRCCComm::Init()
{
	RCCStatus = RCC_STAT_INIT;
	LastError = RCC_ERROR_SUCCESS;

⌨️ 快捷键说明

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