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

📄 serialport.cpp

📁 使用Socket和多线程技术实现远程通信
💻 CPP
字号:
// SerialPort.cpp: implementation of the CSerialPort class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SerialPort.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSerialPort::CSerialPort()
{
	m_hComm = NULL;

	// initialize overlapped structure members to zero
	m_ov.Offset = 0;
	m_ov.OffsetHigh = 0;

	// create events
	m_ov.hEvent = NULL;
	m_hWriteEvent = NULL;
	m_hShutdownEvent = NULL;

	m_szWriteBuffer = NULL;
	m_szReadBuffer = NULL;
	m_nWriteSize = 1;
//	m_nReadSize = 1;

	m_bThreadAlive = FALSE;

}

CSerialPort::~CSerialPort()
{
	do
	{
		SetEvent(m_hShutdownEvent);
	} while (m_bThreadAlive);

	TRACE("Thread ended\n");
	delete [] m_szWriteBuffer;
	delete [] m_szReadBuffer;

}


UINT CSerialPort::CommThread(LPVOID pParam)
{
	//---定义一个CSerialPort类指针,使得传给线程一个空的指针
	//返回一个CSerialPort类指针
	CSerialPort* port = (CSerialPort*) pParam;
	
	port->m_bThreadAlive = TRUE;     //表明线程在运行
	
	DWORD	BytesTansfered = 0;
	DWORD	Event = 0;
	DWORD	CommEvent = 0;
	DWORD	dwError = 0;
	COMSTAT comstat;
	BOOL	bResult = TRUE;
	
	//清除Comm的缓冲区
	if(port->m_hComm)
		PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR 
		| PURGE_RXABORT | PURGE_TXABORT);
	
	//---无线等待,除非线程终止
	
	for(;;)
	{
		//---调用WaitCommEvent函数查询Com的事件
		bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);
		
		if(!bResult)
		{
			//--如果返回为假,查询最后一个错误的原因
			switch(dwError = GetLastError())
			{
			case ERROR_IO_PENDING: //如果串口没有待读字节,这是一个正常返回结果,继续
				break;
			case 87:                //有效的返回
				break;
			default:
				{
					//其他的返回说明存在严重的错误,处理错误
					port->ProcessErrorMessage("WaitCommEvent()");
					break;
				}
			}
		}
		
		else
		{
			bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
			if(0 == comstat.cbInQue)
				continue;
		}
			
		Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
		
		switch(Event)
		{
		case 0:
			{
				//关闭串口
				CloseHandle(port->m_hComm);
				port->m_hComm = NULL;
				port->m_bThreadAlive = FALSE;
				
				AfxEndThread(100);
				break;
			}
		case 1:
			{
				GetCommMask(port->m_hComm, &CommEvent);
				//如果接受到数据
				if(CommEvent & EV_RXCHAR)
					ReadComm(port, comstat);
				
				if (CommEvent & EV_CTS)
					::SendMessage(port->m_hWnd->m_hWnd, WM_COMM_CTS_DETECTED, 
					(WPARAM) 0, (LPARAM) port->m_nPortID);
				if (CommEvent & EV_BREAK)
					::SendMessage(port->m_hWnd->m_hWnd, WM_COMM_BREAK_DETECTED,
					(WPARAM) 0, (LPARAM) port->m_nPortID);
				if (CommEvent & EV_ERR)
					::SendMessage(port->m_hWnd->m_hWnd, WM_COMM_ERR_DETECTED, 
					(WPARAM) 0, (LPARAM) port->m_nPortID);
				if (CommEvent & EV_RING)
					::SendMessage(port->m_hWnd->m_hWnd, WM_COMM_RING_DETECTED,
					(WPARAM) 0, (LPARAM) port->m_nPortID);				
				if (CommEvent & EV_RXFLAG)
					::SendMessage(port->m_hWnd->m_hWnd, WM_COMM_RXFLAG_DETECTED, 
					(WPARAM) 0, (LPARAM) port->m_nPortID);
				break;
			}
		case 2:
			{
				WriteComm(port);
				break;
			}
		default:
			break;
		}
	}
	return 0;
}
int CSerialPort::InitialPort(CWnd* pPortwnd,
									  UINT nMinPort, UINT nMaxPort,
									  UINT baud, 
									  char parity, 
									  UINT databits, 
									  UINT stopbits, 
									  DWORD dwCommEvents, 
									  UINT writebuffersize,
									  UINT readbuffersize)
{
	BOOL bFinded = FALSE;
	while(!InitialPort(pPortwnd, nMinPort, baud, parity, databits,stopbits,
		dwCommEvents, writebuffersize, 
		readbuffersize) && (nMinPort < nMaxPort))
	{
		nMinPort ++;
	}
	if(nMinPort == nMaxPort)
		return -1;
	
	return m_nPortID;
	
}

BOOL CSerialPort::InitialPort(CWnd* pPortwnd,
							  UINT portnr,
							  UINT baud,
							  char parity,
							  UINT databits,
							  UINT stopbits,
							  DWORD dwCommEvents,
							  UINT writebuffersize,
							  UINT readbuffersize)
{
	ASSERT(portnr>0 && portnr<9);
	ASSERT(pPortwnd);
	if(m_bThreadAlive)
	{
		do
		{
			SetEvent(m_hShutdownEvent);
		} while (m_bThreadAlive);
		TRACE("Thread ended\n");
	}

	//---创建事件
	if(m_ov.hEvent != NULL)
		ResetEvent(m_ov.hEvent);
	m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	if (m_hWriteEvent != NULL)
		ResetEvent(m_hWriteEvent);
	m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	
	if (m_hShutdownEvent != NULL)
		ResetEvent(m_hShutdownEvent);
	m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	//---初始化事件对象
	m_hEventArray[0] = m_hShutdownEvent;	
	m_hEventArray[1] = m_ov.hEvent;
	m_hEventArray[2] = m_hWriteEvent;

	//---
	InitializeCriticalSection(&m_csCommunicationSync);

	m_hWnd = pPortwnd;

	if (m_szWriteBuffer != NULL)
		delete [] m_szWriteBuffer;
	if (m_szReadBuffer != NULL)
		delete [] m_szReadBuffer;

	m_szWriteBuffer = new char[writebuffersize];
	m_szReadBuffer = new char[readbuffersize];

	m_nPortID = portnr;

	m_dwWriteBufferSize = writebuffersize;
	m_dwReadBufferSize = readbuffersize;
	m_dwCommEvents = dwCommEvents;

	BOOL bResult = FALSE;
	char *szPort = new char[50];
	char *szBaud = new char[50];

	EnterCriticalSection(&m_csCommunicationSync);

	// 如果串口已经打开,关闭串口
	if (m_hComm != NULL)
	{
		CloseHandle(m_hComm);
	//	AfxMessageBox("Nothing");
		m_hComm = NULL;
	}

	
	sprintf(szPort, "COM%d", portnr);
	sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);

	//打开串口
	m_hComm = CreateFile(szPort,						
					     GENERIC_READ | GENERIC_WRITE,	
					     0,								
					     NULL,							
					     OPEN_EXISTING,					
					     FILE_FLAG_OVERLAPPED,			
					     0);	
	
	if (m_hComm == INVALID_HANDLE_VALUE)
	{
		// 串口没找到
		delete [] szPort;
		delete [] szBaud;
//		MessageBox(NULL, "没找到串口", "警告", MB_ICONINFORMATION);

		return FALSE;
	}

	// 设置时间
	m_CommTimeouts.ReadIntervalTimeout = 1000;
	m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
	m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
	m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
	m_CommTimeouts.WriteTotalTimeoutConstant = 1000;

	//---配置串口
	if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
	{						   
		if (SetCommMask(m_hComm, dwCommEvents))
		{
			if (GetCommState(m_hComm, &m_hDcb))
			{
				m_hDcb.EvtChar = 'q';
				m_hDcb.fRtsControl = RTS_CONTROL_ENABLE;		
				if (BuildCommDCB(szBaud, &m_hDcb))
				{
					if (SetCommState(m_hComm, &m_hDcb)); 
					else	ProcessErrorMessage("SetCommState()");
				}
				else	ProcessErrorMessage("BuildCommDCB()");
			}
			else	ProcessErrorMessage("GetCommState()");
		}
		else	ProcessErrorMessage("SetCommMask()");
	}
	else	ProcessErrorMessage("SetCommTimeouts()");

	delete [] szPort;
	delete [] szBaud;

	
	PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

	LeaveCriticalSection(&m_csCommunicationSync);

	TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr);

	return TRUE;

}



void CSerialPort::ReadComm(CSerialPort* port, COMSTAT ComStat)
{
	BOOL  bRead = TRUE; 
	BOOL  bResult = TRUE;
	DWORD dwError = 0;
	DWORD BytesRead = 0;
	unsigned char RXBuff;

	for (;;) 
	{ 
		//确定串口资源没有被其他程序所用		
		EnterCriticalSection(&port->m_csCommunicationSync);

		// 清除错误		
		bResult = ClearCommError(port->m_hComm, &dwError, &ComStat);

		LeaveCriticalSection(&port->m_csCommunicationSync);
				
		if (ComStat.cbInQue == 0)
		{
			// 读完退出
			break;
		}
						
		EnterCriticalSection(&port->m_csCommunicationSync);

		if (bRead)
		{
			bResult = ReadFile(port->m_hComm,		
							   &RXBuff,				
							   1,					
							   &BytesRead,			
							   &port->m_ov);		
			// 
			if (!bResult)  
			{ 
				switch (dwError = GetLastError()) 
				{ 
					case ERROR_IO_PENDING: 	
						{ 
							bRead = FALSE;
							break;
						}
					default:
						{
							port->ProcessErrorMessage("ReadFile()");
							break;
						} 
				}
			}
			else
			{
				bRead = TRUE;
			}
		}  

		if (!bRead)
		{
			bRead = TRUE;
			bResult = GetOverlappedResult(port->m_hComm,	
										  &port->m_ov,		
										  &BytesRead,		
										  TRUE); 		

			if (!bResult)  
			{
				port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");
			}	
		}  
				
		LeaveCriticalSection(&port->m_csCommunicationSync);

		// 通知窗体
		::SendMessage((port->m_hWnd)->m_hWnd, WM_COMM_RXCHAR, (WPARAM) RXBuff, (LPARAM) port->m_nPortID);
	} 

}


void CSerialPort::WriteComm(CSerialPort* port)
{
	BOOL bWrite = TRUE;
	BOOL bResult = TRUE;

	DWORD BytesSent = 0;
	ResetEvent(port->m_hWriteEvent);
	
	EnterCriticalSection(&port->m_csCommunicationSync);

	if (bWrite)
	{
		// 初始化变量
		port->m_ov.Offset = 0;
		port->m_ov.OffsetHigh = 0;

		// 清除缓冲区
		PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

		bResult = WriteFile(port->m_hComm,							
							port->m_szWriteBuffer,					
							port->m_nWriteSize,	 //要发送的字符串的长度
							&BytesSent,			//应尽发送的长度						
							&port->m_ov);
		
		if (!bResult)  
		{
			DWORD dwError = GetLastError();
			switch (dwError)
			{
				case ERROR_IO_PENDING:
					{
						BytesSent = 0;
						bWrite = FALSE;
						break;
					}
				default:
					{
						port->ProcessErrorMessage("WriteFile()");
					}
			}
		} 
		else
		{
			LeaveCriticalSection(&port->m_csCommunicationSync);
		}
	} 

	if (!bWrite)
	{
		bWrite = TRUE;
	
		bResult = GetOverlappedResult(port->m_hComm,	
									  &port->m_ov,		
									  &BytesSent,		
									  TRUE); 			

		LeaveCriticalSection(&port->m_csCommunicationSync);
	}
	
	::SendMessage((port->m_hWnd)->m_hWnd, WM_COMM_TXEMPTY_DETECTED,0,(LPARAM) port->m_nPortID);


}


//--发送字符串
void CSerialPort::SendString(CString str)
{

	CString strtemp;
	String2Hex(str, strtemp);
	WriteToPort((LPCTSTR)strtemp);

}

void CSerialPort::WriteToPort(LPCTSTR string)
{		
	ASSERT(m_hComm != 0);

	memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
	strcpy(m_szWriteBuffer, string);
	m_nWriteSize=strlen(string);

	// set event for write
	SetEvent(m_hWriteEvent);
}

//---错误的处理
void CSerialPort::ProcessErrorMessage(char *ErrorText)
{
	char *Temp = new char[200];
	
	LPVOID lpMsgBuf;

	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
		(LPTSTR) &lpMsgBuf,
		0,
		NULL 
	);

	sprintf(Temp, "WARNING:  %E Failed with the following error: \n%s\nPort: %d\n",
		(char*)ErrorText, lpMsgBuf, m_nPortID); 

	MessageBox(NULL, Temp, "Application Error", MB_ICONINFORMATION);
	LocalFree(lpMsgBuf);
	delete [] Temp;

}
	

//---获取当前事件
DWORD CSerialPort::GetCommEvents()
{
	return m_dwCommEvents;
}

//----------------
DWORD CSerialPort::GetWriteBufferSize()
{
	return m_dwWriteBufferSize;
}
//-----------------
void CSerialPort::ClosePort()
{	
	SetEvent(m_hShutdownEvent);

	SetCommMask(m_hComm, 0);
	 EscapeCommFunction( m_hComm, CLRDTR );
	 PurgeComm( m_hComm, PURGE_TXABORT | PURGE_RXABORT |
		 PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
	 CloseHandle( m_hComm ) ;
	 m_hComm = NULL;
	 // change the selectable items in the menu
	 CloseHandle(m_ov.hEvent);
}


DCB CSerialPort::GetDCB()
{
	return m_hDcb;
}

//---启动线程
BOOL CSerialPort::StartThread()
{
	if (!(m_pThread = AfxBeginThread(CommThread, this)))
		return FALSE;
	TRACE("Thread started\n");
	return TRUE;
}


//---重新启动线程
BOOL CSerialPort::RestartThread()
{
	TRACE("Thread resumed\n");
	m_pThread->ResumeThread();
	return TRUE;
}


//---停止线程
BOOL CSerialPort::PauseThread()
{
	TRACE("Thread suspended\n");
	m_pThread->SuspendThread(); 
	return TRUE;
}

char CSerialPort::ConvertHexChar(char ch)
{
	if((ch>='0')&&(ch<='9'))
		return ch-0x30;
	else if((ch>='A')&&(ch<='F'))
		return ch-'A'+10;
	else if((ch>='a')&&(ch<='f'))
		return ch-'a'+10;
	else return (-1);
}


void CSerialPort::String2Hex(CString str, CString &senddata)
{
	int hexdata,lowhexdata;
	int hexdatalen=0;
	int len=str.GetLength();	
	
	for(int i=0;i<len;)
	{
		char lstr,hstr=str[i];
		if(hstr==' ')
		{
			i++;
			continue;
		}
		i++;
		if(i>=len)
			break;
		lstr = str[i];
		hexdata=ConvertHexChar(hstr);
		lowhexdata=ConvertHexChar(lstr);
		if((hexdata==16)||(lowhexdata==16))
			break;
		else 
			hexdata=hexdata*16+lowhexdata;
		i++;
		senddata+=(char)hexdata;
		hexdatalen++;
	}


}

⌨️ 快捷键说明

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