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

📄 asyncserialport.cpp

📁 串口通信mfc源码
💻 CPP
字号:
#include "StdAfx.h"
#include "AsyncSerialPort.h"
#include "RuntimeException.h"

CAsyncSerialPort::CAsyncSerialPort(void)
{
	m_breakEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	m_readEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	m_portClosingEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	m_writeEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

	::ZeroMemory(&m_readOverlapped,sizeof(m_readOverlapped));
	::ZeroMemory(&m_breakOverlapped,sizeof(m_breakOverlapped));
	::ZeroMemory(&m_writeOverlapped,sizeof(m_writeOverlapped));

	m_readOverlapped.hEvent = m_readEvent;
	m_breakOverlapped.hEvent = m_breakEvent;
	m_writeOverlapped.hEvent = m_writeEvent;

	ASSERT(m_breakEvent!=NULL);
	ASSERT(m_readEvent!=NULL);
	ASSERT(m_portClosingEvent!=NULL);
	ASSERT(m_writeEvent!=NULL);
}

CAsyncSerialPort::~CAsyncSerialPort(void)
{
	Close();

	::CloseHandle(m_breakEvent);
	::CloseHandle(m_readEvent);
	::CloseHandle(m_portClosingEvent);
	::CloseHandle(m_writeEvent);

}

void CAsyncSerialPort::Open(int nPort, DWORD dwBaud, Parity parity, BYTE DataBits,
							   StopBits stopbits, FlowControl fc, BOOL bOverlapped)
{
	CSerialPort::Open(nPort,dwBaud,parity,DataBits,stopbits,fc,TRUE);

	m_isWriting = FALSE;

	//This config is very useful
	COMMTIMEOUTS timeouts;
	GetTimeouts(timeouts);
	timeouts.ReadIntervalTimeout = 100;
	SetTimeouts(timeouts);
	
	//Discards all characters from the output or input buffer 
	Purge(PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
	//Set buffer length
	Setup( ReadBufferLength, WriteBufferLength);
		
	CThread::Start();
	CThread::SetPriority(THREAD_PRIORITY_HIGHEST);

	for(PortObserverList::iterator iter = m_portObservers.begin(); iter != m_portObservers.end(); ++ iter )
	{
		(*iter)->OnPortOpen(this);
	}
}

void CAsyncSerialPort::Close()
{
	if(IsOpen())
	{
		::SetEvent(m_portClosingEvent);
		CThread::Wait(5000);
		CThread::Terminate();
		::ResetEvent(m_portClosingEvent);

		for(PortObserverList::iterator iter = m_portObservers.begin(); iter != m_portObservers.end(); ++ iter )
		{
			(*iter)->OnPortClose(this);
		}

	}
	
	CSerialPort::Close();
}

void CAsyncSerialPort::OnRead(const byte *pData, size_t dataLength)
{
	try
	{
		for(PortObserverList::iterator iter = m_portObservers.begin(); iter != m_portObservers.end(); ++ iter )
		{
			(*iter)->OnRead(this, pData, dataLength);
		}
	}
	catch (CRuntimeException* e)
	{
		OnError( e->GetErrorMessage());
		e->Delete();
	}
	
}

void CAsyncSerialPort::OnWrite(const byte *pData,size_t dataLength)
{
	for(PortObserverList::iterator iter = m_portObservers.begin(); iter != m_portObservers.end(); ++ iter )
	{
		(*iter)->OnWrite(this,pData, dataLength );
	}
}

void CAsyncSerialPort::HandleBreakEvent(DWORD &dwMask)
{
	DWORD dwReadBytes;
	CSerialPort::GetOverlappedResult(m_breakOverlapped,dwReadBytes, FALSE);
	OnBreak(dwMask);
}

void CAsyncSerialPort::OnError(LPCTSTR lpszErrorMessage)
{
	for(PortObserverList::iterator iter = m_portObservers.begin(); iter != m_portObservers.end(); ++ iter )
	{
		(*iter)->OnError(this,lpszErrorMessage);
	}
}

void CAsyncSerialPort::SetBreakEvent(DWORD &dwMask)
{
	while(true)
	{
		if(WaitEvent(dwMask,m_breakOverlapped))
		{
			HandleBreakEvent(dwMask);
		}
		else
		{
			DWORD dwError = ::GetLastError();
			if( ERROR_IO_PENDING == dwError)
			{
				break;
			}
			else
			{
				THROW_EX_CODE(dwError);
			}
		}
	}

}

void CAsyncSerialPort::SetReadEvent(OVERLAPPED& overlapped)
{
	DWORD readCount=0;
	while(true)
	{
		if(Read(m_readBuffer, ReadBufferLength, overlapped, &readCount))
		{
			OnRead(m_readBuffer,readCount);
			ResetEvent(m_readEvent);
		}
		else
		{
			DWORD dwError = ::GetLastError();
			if( ERROR_IO_PENDING == dwError)
			{
				return;
			}
			else
			{
				THROW_EX_CODE(dwError);
			}
		}
	}
}

void CAsyncSerialPort::HandleReadEvent(OVERLAPPED& overlapped)
{
	DWORD dwReadCount;
	GetOverlappedResult(m_readOverlapped, dwReadCount, FALSE);
	OnRead(m_readBuffer, dwReadCount);
}

void CAsyncSerialPort::HandleWriteEvent(OVERLAPPED& overlapped)
{
	ASSERT(m_isWriting == TRUE);

	DWORD dwWriteCount;

	GetOverlappedResult(m_writeOverlapped, dwWriteCount, FALSE);
	OnWrite(m_writeBuffer, dwWriteCount);

	m_isWriting = FALSE;
	::ResetEvent(m_writeEvent);
}

void CAsyncSerialPort::OnBreak(DWORD dwMask)
{
}

//Thread worker
int CAsyncSerialPort::Run()
{
	try
	{
		TRACE(_T("Run read thread.\n"));


		//events array
		HANDLE waitHandles[4]= { 
			m_portClosingEvent,
			m_readEvent, 
			m_breakEvent,
			m_writeEvent}; 
			
		WORD dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | \
			EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY;

		SetMask(dwStoredFlags);
		DWORD dwMask;
		SetBreakEvent(dwMask);
		SetReadEvent(m_readOverlapped);
		
		DWORD dwEventIndex;
		while(TRUE)
		{
			dwEventIndex = ::WaitForMultipleObjects(4,waitHandles,false,INFINITE);
			switch(dwEventIndex)
			{
			case WAIT_OBJECT_0:
				TRACE(_T("Receive serial port close event, exit read thread.\n"));
				return 0L;
			case WAIT_OBJECT_0+1: //read event
				{
					HandleReadEvent(m_readOverlapped);
					SetReadEvent(m_readOverlapped);
				}
				break;
			case WAIT_OBJECT_0 +2: //break event
				{
					HandleBreakEvent(dwMask);
					SetBreakEvent(dwMask);
				}
				break;
			case WAIT_OBJECT_0 +3:
				{
					HandleWriteEvent(m_writeOverlapped);
				}
				break;
			case WAIT_FAILED:
				THROW_EX_CODE( ::GetLastError() );
			default:
				ASSERT(FALSE);
				return 0L;
			}
		}
	}
	catch (CRuntimeException* e)
	{
		OnError(e->GetErrorMessage());

		e->Delete();
	}

	return 0L;
}

void CAsyncSerialPort::WriteEx(const void* lpBuf, DWORD dwCount)
{
	if( dwCount > WriteBufferLength)
	{
		THROW_EX_CODE(_T("Too much data to write"));
	}

	if( !IsOpen())
	{
		THROW_EX_CODE(_T("SerialPort is closed, write data fail"));
	}

	ASSERT( lpBuf != NULL );

	if( m_isWriting )
	{
		THROW_EX_CODE(_T("Send not completed, write data fail"));
	}

	::CopyMemory(m_writeBuffer, lpBuf, dwCount);

	m_isWriting = TRUE;

	DWORD dwWriteBytes = 0;

	if( CSerialPort::Write(m_writeBuffer, dwCount, m_writeOverlapped, &dwWriteBytes) )
	{
		OnWrite(m_writeBuffer,dwWriteBytes);
		ResetEvent(m_writeEvent);
	}
}

void  CAsyncSerialPort::AtachObserver(ISerialPortObserver  *pObserver)
{
	ASSERT(pObserver!=NULL);
	m_portObservers.push_back(pObserver);
}

void  CAsyncSerialPort::DetchObserver(ISerialPortObserver *pObserver)
{
	ASSERT(pObserver!=NULL);
	m_portObservers.remove(pObserver);
}

⌨️ 快捷键说明

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