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

📄 serialcommhelper.cpp

📁 一个串口编程的例子
💻 CPP
字号:
// RCSerial.cpp: implementation of the CSerialCommHelper class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "SerialCommHelper.h"
#include <Process.h>
#include <string>


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

CDebugDump	m_DebugFile;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

#define ATLTRACE6 m_DebugFile.Dump

void CSerialCommHelper::InvalidateHandle(HANDLE& hHandle )
{
	hHandle = INVALID_HANDLE_VALUE;
}


void CSerialCommHelper::CloseAndCleanHandle(HANDLE& hHandle)
{

	BOOL abRet  = CloseHandle( hHandle ) ;
	if ( !abRet )
	{
		ASSERT(0);
		ATLTRACE6 ( "CSerialCommHelper : Failed to open Close Handle %d :Last Error: %d",hHandle,GetLastError());
	}
	InvalidateHandle ( hHandle );

}
CSerialCommHelper::CSerialCommHelper()
{

	InvalidateHandle( m_hThreadTerm );
	InvalidateHandle( m_hThread	);
	InvalidateHandle( m_hThreadStarted );
	InvalidateHandle( m_hCommPort );
	InvalidateHandle( m_hDataRx );
 	
	InitLock();
	m_eState = SS_UnInit;

	m_DebugFile.Init(_T("c:\\Temp\\") ,_T("SerialIO"),_T("RCSERIAL:"));
}

CSerialCommHelper::~CSerialCommHelper()
{

	m_eState = SS_Unknown;
	DelLock();
}


HRESULT CSerialCommHelper:: Init(std::string szPortName, DWORD dwBaudRate,BYTE byParity,BYTE byStopBits,BYTE byByteSize)
{
	HRESULT hr = S_OK;
	try
	{
		m_hDataRx  = CreateEvent(0,0,0,0);		
		//打开COM串口
		m_hCommPort = ::CreateFile(szPortName.c_str (),
									GENERIC_READ|GENERIC_WRITE,
									0,				//不共享COM口	
									0,				//无安全策略	
									OPEN_EXISTING,	//打开已有的文件
									FILE_FLAG_OVERLAPPED,//I/O重叠
									0				// 不为COM口生成临时文件
									);
		//串口打开失败
		if ( m_hCommPort == INVALID_HANDLE_VALUE )
		{
			ATLTRACE6 ( "CSerialCommHelper : Failed to open COM Port Reason: %d",GetLastError());
			AfxMessageBox("这个串口没有装备好或者已经被其他设备占用了");
			return E_FAIL;
		}

		
		ATLTRACE6 ( "CSerialCommHelper : COM port opened successfully" );
		
		//COM口掩码参数设置
		if (!::SetCommMask(m_hCommPort,EV_RXCHAR|EV_TXEMPTY) )
		{
			AfxMessageBox("串口掩码设置错误");
			ATLTRACE6 ( "CSerialCommHelper : Failed to Set Comm Mask Reason: %d",GetLastError());
			return E_FAIL;
		}
		ATLTRACE6 ( "CSerialCommHelper : SetCommMask() success");
		
		//COM口的通信参数设置
		DCB dcb = {0};		
		dcb.DCBlength = sizeof(DCB);
		
		if (!::GetCommState (m_hCommPort,&dcb))
		{
			ATLTRACE6 ( "CSerialCommHelper : Failed to Get Comm State Reason: %d",GetLastError());
			return E_FAIL;
		}
		
		dcb.BaudRate	= dwBaudRate;//波特率
		dcb.ByteSize	= byByteSize;//数据尺寸
		dcb.Parity		= byParity;	 //校验选择	
		if ( byStopBits == 1 )		 //终止位	
			dcb.StopBits	= ONESTOPBIT;
		else if (byStopBits == 2 ) 
			dcb.StopBits	= TWOSTOPBITS;
		else 
			dcb.StopBits	= ONE5STOPBITS;

		dcb.fDsrSensitivity = 0;
		dcb.fDtrControl = DTR_CONTROL_ENABLE;
		dcb.fOutxDsrFlow = 0;

		
		if (!::SetCommState (m_hCommPort,&dcb))
		{
			AfxMessageBox("串口通信参数设置错误");
			ATLTRACE6 ( "CSerialCommHelper : Failed to Set Comm State Reason: %d",GetLastError());
			return E_FAIL;
		}
		ATLTRACE6 ( "CSerialCommHelper : Current Settings, (Baud Rate %d; Parity %d; Byte Size %d; Stop Bits %d", dcb.BaudRate, 
								dcb.Parity,dcb.ByteSize,dcb.StopBits);
		

		
		//COM口超时参数设置( we control the timeout overselves using WaitForXXX()
		COMMTIMEOUTS timeouts;
		
		timeouts.ReadIntervalTimeout			= MAXDWORD; 
		timeouts.ReadTotalTimeoutMultiplier		= 0;
		timeouts.ReadTotalTimeoutConstant		= 0;
		timeouts.WriteTotalTimeoutMultiplier	= 0;
		timeouts.WriteTotalTimeoutConstant		= 0;
		
		if (!SetCommTimeouts(m_hCommPort, &timeouts))
		{
			AfxMessageBox("串口超时状态设置错误");
			ATLTRACE6 ( "CSerialCommHelper :  Error setting time-outs. %d",GetLastError());
			return E_FAIL;
		}
		//创建线程终结和开始事件
		m_hThreadTerm = CreateEvent(0,0,0,0);
		m_hThreadStarted = CreateEvent(0,0,0,0);
		
		m_hThread= 	(HANDLE)_beginthreadex(0,0,CSerialCommHelper::ThreadFn,(void*)this,0,0 );

		DWORD dwWait = WaitForSingleObject ( m_hThreadStarted , INFINITE );
		
		ASSERT ( dwWait ==WAIT_OBJECT_0 );
		
		CloseHandle(m_hThreadStarted);
		
		InvalidateHandle(m_hThreadStarted );
		m_abIsConnected = true;
		
	}
	catch(...)
	{
		AfxMessageBox("串口设置异常");
		hr = E_FAIL;
	}
	if ( SUCCEEDED(hr) ) 
	{
		AfxMessageBox("串口设置成功");
		m_eState = SS_Init;
	}
	return hr;
 	
}	
	
 
HRESULT CSerialCommHelper:: Start()
{
		m_eState = SS_Started;
		return S_OK;
}
HRESULT CSerialCommHelper:: Stop()
{

	m_eState = SS_Stopped;
	return S_OK;
}
//终止线程运行
HRESULT CSerialCommHelper:: UnInit()
{
	HRESULT hr = S_OK;
	try
	{
		m_abIsConnected = false;
		SignalObjectAndWait(m_hThreadTerm,m_hThread,INFINITE,FALSE);
		CloseAndCleanHandle( m_hThreadTerm);
		CloseAndCleanHandle( m_hThread);
		CloseAndCleanHandle( m_hDataRx );
		CloseAndCleanHandle( m_hCommPort );
	}
	catch(...)
	{
		ASSERT(0);
		hr = E_FAIL;
	}
	if ( SUCCEEDED(hr)) 
		m_eState = SS_UnInit;
	return hr;
}

unsigned __stdcall CSerialCommHelper::ThreadFn(void*pvParam)
{
	CSerialCommHelper* apThis = (CSerialCommHelper*) pvParam ;
	bool abContinue = true;
	DWORD dwEventMask=0;
	
	OVERLAPPED ov;
	memset(&ov,0,sizeof(ov));
	ov.hEvent = CreateEvent( 0,true,0,0);
	HANDLE arHandles[2];
	arHandles[0] = apThis->m_hThreadTerm;

	DWORD dwWait;
	SetEvent(apThis->m_hThreadStarted);
	while (  abContinue )
	{
		
		BOOL abRet = ::WaitCommEvent(apThis->m_hCommPort,&dwEventMask, &ov) ;
		if ( !abRet )
		{
			ASSERT( GetLastError () == ERROR_IO_PENDING);
		}

		
		arHandles[1] = ov.hEvent ;
		
		dwWait = WaitForMultipleObjects (2,arHandles,FALSE,INFINITE);
		switch ( dwWait )
		{
		case WAIT_OBJECT_0:
			{
				_endthreadex(1);
			}
			break;
		case WAIT_OBJECT_0 + 1:
			{
				DWORD dwMask;
				if (GetCommMask(apThis->m_hCommPort,&dwMask) )
				{
					if ( dwMask == EV_TXEMPTY )
					{
						AfxMessageBox("Data sent");
						ResetEvent ( ov.hEvent );
						continue;
					}
					
				}

				//读数据
				int iAccum = 0;
				
				apThis->m_theSerialBuffer.LockBuffer();
				
				try 
				{
					std::string szDebug;
					BOOL abRet = false;
					
					DWORD dwBytesRead = 0;
					OVERLAPPED ovRead;
					memset(&ovRead,0,sizeof(ovRead));
					ovRead.hEvent = CreateEvent( 0,true,0,0);

					do
					{
						ResetEvent( ovRead.hEvent  );
						char szTmp[1];
						int iSize  = sizeof ( szTmp );
						memset(szTmp,0,sizeof szTmp);
						abRet = ::ReadFile(apThis->m_hCommPort,szTmp,sizeof(szTmp),&dwBytesRead,&ovRead);
						if (!abRet ) 
						{
							abContinue = FALSE;
							break;
						}
						if ( dwBytesRead > 0 )
						{
							apThis->m_theSerialBuffer.AddData ( szTmp,dwBytesRead );
							iAccum += dwBytesRead;
						}
					}while (0);// dwBytesRead > 0 );
					CloseHandle(ovRead.hEvent );
				}
				catch(...)
				{
					ASSERT(0);
				}
				
				//if we are not in started state then we should flush the queue...( we would still read the data)
				if (apThis->GetCurrentState() != SS_Started ) 
				{
					iAccum  = 0;
					apThis->m_theSerialBuffer.Flush ();
				}
				
				apThis->m_theSerialBuffer.UnLockBuffer();
				
				ATLTRACE6(_T("RCSerial: Q Unlocked:"));
				if ( iAccum > 0 )
				{
					ATLTRACE6(_T("CSerialCommHelper(worker thread):  SetDataReadEvent() len:{%d} data:{%s}"),iAccum,(apThis->m_theSerialBuffer.GetData()).c_str ()  );
					apThis->SetDataReadEvent(); 
				}
				ResetEvent ( ov.hEvent );
			}
			break;
		}
	}
	return 0;
}


HRESULT  CSerialCommHelper::CanProcess ()
{
	
	switch ( m_eState  ) 
	{
		case SS_Unknown	:ASSERT(0);return E_FAIL;
		case SS_UnInit	:return E_FAIL;
		case SS_Started :return S_OK;
		case SS_Init		:
		case SS_Stopped :
				return E_FAIL;
		default:ASSERT(0);	

	}	
	return E_FAIL;
}

HRESULT CSerialCommHelper::Write (const char* data,DWORD dwSize)
{
	HRESULT hr = CanProcess();
	if ( FAILED(hr)) return hr;
	int iRet = 0 ;
	OVERLAPPED ov;
	memset(&ov,0,sizeof(ov));
	ov.hEvent = CreateEvent( 0,true,0,0);
	DWORD dwBytesWritten = 0;
	do
	{
		iRet = WriteFile (m_hCommPort,data,dwSize,&dwBytesWritten  ,&ov);
		if ( iRet == 0 )
		{
			WaitForSingleObject(ov.hEvent ,INFINITE);
		}
 
	}	while ( ov.InternalHigh != dwSize ) ;
	CloseHandle(ov.hEvent);
	std::string szData(data);
	ATLTRACE6(_T("RCSerial:Writing:{%s} len:{%d}"),(szData).c_str(),szData.size());
	
	return S_OK;
}





HRESULT CSerialCommHelper::Read_Upto	(std::string& data,char chTerminator ,long* alCount,long alTimeOut)
{
	HRESULT hr = CanProcess();
	if ( FAILED(hr)) return hr;

	ATLTRACE6("CSerialCommHelper : CSerialCommHelper: Read_Upto called  ");
	try
	{
	 	
		std::string szTmp;
		szTmp.erase ();
		long alBytesRead;
		
		bool abFound =  m_theSerialBuffer.Read_Upto(szTmp ,chTerminator,alBytesRead,m_hDataRx );

		if ( abFound ) 
		{
			data = szTmp ;
		}
		else
		{//there are either none or less bytes...
			long iRead = 0;
			bool abContinue =  true;
			while (  abContinue )
			{
				ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_Upto () making blocking read call  ");
				DWORD dwWait  = ::WaitForSingleObject ( m_hDataRx , alTimeOut ) ;
				
				if  ( dwWait == WAIT_TIMEOUT) 
				{
					ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_Upto () timed out in blocking read");
					data.erase ();
					hr = E_FAIL;
					return hr;

				}
   				
				bool abFound =  m_theSerialBuffer.Read_Upto(szTmp ,chTerminator,alBytesRead,m_hDataRx );
				

				if ( abFound ) 
				{
					data = szTmp;
					ATLTRACE6("CSerialCommHelper : CSerialCommHelper: Read_Upto WaitForSingleObject  data:{%s}len:{%d}",((szTmp)).c_str(),szTmp.size ());
					return S_OK;
				}
				ATLTRACE6("CSerialCommHelper : CSerialCommHelper: Read_Upto WaitForSingleObject  not FOUND ");

			}
		}
	}
	catch(...)
	{
		ATLTRACE6(_T("CSerialCommHelperUnhandled exception"));
		ASSERT ( 0  ) ;
	}
	return hr;
	
}
HRESULT CSerialCommHelper::Read_N(std::string& data,long alCount,long  alTimeOut )
{
	HRESULT hr = CanProcess();
	
	if ( FAILED(hr)) 
	{
		ASSERT(0);
		return hr;
	}
	
	ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N called for %d bytes",alCount);
	try
	{
	 	
		std::string szTmp ;
		szTmp.erase();

		ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) locking the queue  ",alCount);
		
		int iLocal =  m_theSerialBuffer.Read_N(szTmp ,alCount ,m_hDataRx );
		
		if ( iLocal == alCount ) 
		{
			data = szTmp;
		}
		else
		{//there are either none or less bytes...
			long iRead = 0;
			int iRemaining = alCount - iLocal;
			while (  1 )
			{
				
				ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) making blocking read() ",alCount);
				
				DWORD dwWait  = WaitForSingleObject ( m_hDataRx , alTimeOut ) ;

				if  ( dwWait == WAIT_TIMEOUT ) 
				{
					ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) timed out in blocking read",alCount);
					data.erase ();
					hr = E_FAIL;
					return hr;

				}
				
				ASSERT ( dwWait == WAIT_OBJECT_0 );
				ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) Woke Up from WaitXXX() locking Q",alCount);
 				
				
				iRead =  m_theSerialBuffer.Read_N(szTmp , iRemaining  ,m_hDataRx);
				iRemaining -= iRead ;
				
				ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) Woke Up from WaitXXX() Unlocking Q",alCount);


				if (  iRemaining  == 0) 
				{
					ATLTRACE6("CSerialCommHelper : CSerialCommHelper : Read_N (%d) Woke Up from WaitXXX() Done reading ",alCount);
					data = szTmp;
					return S_OK;
				}
			}
		}
	}
	catch(...)
	{
		ATLTRACE6(_T("CSerialCommHelper Unhandled exception"));
		ASSERT ( 0  ) ;
	}
	return hr;
	
}

//读取所有本地缓冲区中的数据,如果缓冲区是空的也不会做阻塞调用
HRESULT CSerialCommHelper::ReadAvailable(std::string& data)
{
	
	HRESULT hr = CanProcess();
	if ( FAILED(hr)) return hr;
	try
	{
		std::string szTemp;
		bool abRet = m_theSerialBuffer.Read_Available (szTemp,m_hDataRx);
		data = szTemp;
	}
	catch(...)
	{
		ATLTRACE6(_T("CSerialCommHelper Unhandled exception in ReadAvailable()"));
		ASSERT ( 0  ) ;
		hr = E_FAIL;
	}
	return hr;
}





⌨️ 快捷键说明

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