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

📄 comcontrol.cpp

📁 MODBUS主、子站规约模拟程序。可以做为MODBUS规约测试的工具
💻 CPP
字号:
// ComControl.cpp

#include "StdAfx.h"
#include "ComControl.h"
#include "DlgComSet.h"

UINT ComThreadProc(LPVOID para)
{
	CComControl* pCom = (CComControl*)para;
	DWORD dwEventMask;
	OVERLAPPED eov;
	memset( &eov, 0, sizeof( OVERLAPPED ) ) ;
	eov.hEvent = CreateEvent( NULL,		// no security attributes
							  FALSE,	// auto reset event
							  FALSE,	// not signaled
							  NULL		// no name
							);
	HANDLE hWaits[2];
	DWORD dwWait;
	hWaits[0] = eov.hEvent;
	hWaits[1] = pCom->m_hExit;
	while(true)
	{
		dwEventMask = 0;
		WaitCommEvent(pCom->m_hCom, &dwEventMask, &eov);
		dwWait = WaitForMultipleObjects(2, hWaits, false, INFINITE);
		if(dwWait == WAIT_OBJECT_0+1)
			break;
		
		//EnterCriticalSection(&pCom->m_csWmThreshold);
		pCom->ResetBytes();

		if(dwEventMask & EV_ERR)		// 线路错误CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
		{
			SendMessage( pCom->m_hOwner, WM_COM, COM_ERR ,0 );
		}

		if(dwEventMask & EV_TXEMPTY)	// 输出缓冲区空
		{
			SendMessage( pCom->m_hOwner, WM_COM, COM_EMPTY ,0 );
		}

		if( dwEventMask & EV_RXCHAR && 
//			pCom->m_bCanInterrupt	&&				//确认上一条消息已处理完
//			pCom->m_nThresHold		&&
			pCom->m_cbInQue >= pCom->m_nThresHold	// 输入缓冲区接收到一字符
		  ) 	
		{
			pCom->m_bCanInterrupt = false;
			SendMessage( pCom->m_hOwner, WM_COM,COM_THRESHOLD,0);
		}
		//LeaveCriticalSection(&pCom->m_csWmThreshold);
	}
	CloseHandle(eov.hEvent);

	return true;
}

CComControl::CComControl(HWND hOwner)
{
	m_hOwner	= hOwner;
	InitCom();
}

void CComControl::InitCom()
{
	InitializeCriticalSection(&m_csWmThreshold);
	memset( &m_ovRead,	0, sizeof( OVERLAPPED ) ) ;
    memset( &m_ovWrite, 0, sizeof( OVERLAPPED ) ) ;
    m_ovRead.hEvent = CreateEvent( NULL,	// no security
                                   TRUE,	// explicit reset req;TRUE=人工重置;FASE=自动重置
                                   FALSE,	// initial event reset;TRUE=已通知状态;FALSE=未通知状态
                                   NULL		// no name
								  );       
    m_ovWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );  // See above
	m_nThresHold	= 0;
	m_bCanInterrupt = false;
	m_hExit			= CreateEvent(NULL, false, false, NULL);
	m_szPortName	= "COM1";
	m_lBaudRate		= 9600;
	m_nParity		= NOPARITY;
	m_hCom			= INVALID_HANDLE_VALUE;
	m_cbInQue		= 0;
	m_cbOutQue		= 0;
	m_pThread = AfxBeginThread(ComThreadProc, (LPVOID)this,THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); 
}

CComControl::~CComControl()
{
	m_pThread->ResumeThread();
	SetEvent(m_hExit);
	WaitForSingleObject(m_pThread->m_hThread, INFINITE);
	m_pThread = NULL;	  //this ensure pCom->ClosePort work correct	
	ClosePort();
	CloseHandle(m_ovRead.hEvent);
	CloseHandle(m_ovWrite.hEvent);
	CloseHandle(m_hExit);
	DeleteCriticalSection(&m_csWmThreshold);
}

bool __fastcall CComControl::IsWindowsNT()
{
	OSVERSIONINFO osv;
	osv.dwOSVersionInfoSize = sizeof(osv);
	GetVersionEx(&osv);
	return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT);
}

void CComControl::ResetBytes()
{
	DWORD dwErrWord;
	COMSTAT comstat;
	ClearCommError(m_hCom, &dwErrWord, &comstat);
	m_cbInQue  = comstat.cbInQue;
	m_cbOutQue = comstat.cbOutQue;
}

bool CComControl::OpenPort()
{
	if(m_hCom != INVALID_HANDLE_VALUE) {
		ClosePort();
	}

	m_hCom = CreateFile( "\\\\.\\" + m_szPortName,		// pointer to name of the file
						 GENERIC_READ | GENERIC_WRITE,	// access (read-write) mode
						 0,								// share mode
						 NULL,							// lpsa;pointer to security attributes
						 OPEN_EXISTING,					// how to create
						 FILE_FLAG_OVERLAPPED,			// file attributes //fdwAttrsAndFlags
						 NULL							// handle to file with attributes to copy
						);

	if(m_hCom == INVALID_HANDLE_VALUE) {
		return false;
	}

	DCB dcb;
	memset(&dcb, 0, sizeof(dcb));	
	dcb.DCBlength	= sizeof(dcb);	// 以字节数指定当前的波特率
	dcb.fBinary		= true;			// 必须是true
	dcb.BaudRate	= m_lBaudRate;	// 当前的波特率
	dcb.Parity		= m_nParity;	// 奇偶校验方法,NOPARITY / ODDPARITY / EVENPARITY / MARKPARITY
	if(m_nParity != NOPARITY)
	{	
		dcb.fParity = true;			// 指定奇偶校验是否是允许的
	}
	dcb.ByteSize	= 8;			// 指定端口当前使用的数据位数
	dcb.StopBits	= ONESTOPBIT;			// 指定端口当前使用的停止位数 ONESTOPBIT / ONE5STOPBITS / TWOSTOPBITS
	dcb.fDtrControl = DTR_CONTROL_DISABLE;	// DTR_CONTROL_DISABLE置DTR为OFF,DTR_CONTROL_ENABLE置DTR为ON,DTR_CONTROL_HANDSHAKE允许DTR"握手"
	dcb.fRtsControl = RTS_CONTROL_DISABLE;	// RTS置OFF
	dcb.fAbortOnError = true;		// 有错误发生时中止读、写操作
	dcb.fDsrSensitivity = false;	// 若为TRUE,则DSR为OFF时接收的字节被忽略
	dcb.wReserved1	= 0;			// 没有使用,必须为零

	COMMTIMEOUTS timeouts;			// 定义超时时间
	timeouts.ReadIntervalTimeout		= 10*9600 / m_lBaudRate + 100;
	timeouts.ReadTotalTimeoutConstant	= 0;
	timeouts.ReadTotalTimeoutMultiplier = 10*9600 / m_lBaudRate;
	timeouts.WriteTotalTimeoutConstant	= 0;
	timeouts.WriteTotalTimeoutMultiplier= 2*9600 / m_lBaudRate;
	//////////////////// 张尚文CommTest的超时时间处理结果。///////////////////
	//	CommTimeOuts.ReadIntervalTimeout = 10*CBR_9600/FBaudRate + 100 ;	//  
	//	CommTimeOuts.ReadTotalTimeoutMultiplier = 10*CBR_9600/FBaudRate;	//
	//	CommTimeOuts.ReadTotalTimeoutConstant = 0 ;							//	
	//	// CBR_9600 is approximately 1byte/ms. For our purposes, allow		//
	//	// double the expected time per character for a fudge factor.		//
	//	CommTimeOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600/FBaudRate;	//
	//	CommTimeOuts.WriteTotalTimeoutConstant = 0 ;						//
	//////////////////////////////////////////////////////////////////////////	
	
	if(	!SetCommState(m_hCom, &dcb)						  ||
		!SetupComm(m_hCom, 2048, 2048)					  ||
		!SetCommTimeouts(m_hCom, &timeouts)				  ||
		!SetCommMask(m_hCom, EV_RXCHAR|EV_TXEMPTY|EV_ERR) ||
		!PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT |
                   PURGE_TXCLEAR | PURGE_RXCLEAR )
	  )
	{
		ClosePort();
		return false;
	}

	m_pThread->ResumeThread();
	return true;
}

void CComControl::ClosePort()
{
	if(m_hCom != INVALID_HANDLE_VALUE)
	{
		if(m_pThread)
			m_pThread->SuspendThread();
		PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT |
                      PURGE_TXCLEAR | PURGE_RXCLEAR );
		CloseHandle(m_hCom);
		m_hCom = INVALID_HANDLE_VALUE;
	}
}

void CComControl::SetParam()
{
	CDlgComSet	DlgComSet;
	DlgComSet.m_szPort = m_szPortName;

	CString br;
	br.Format("%d", m_lBaudRate);
	DlgComSet.m_szBaud = br;
	
	CString jy;
	switch(m_nParity)
	{
		case ODDPARITY:
			jy = "奇校验";
			break;
		case EVENPARITY:
			jy = "偶校验";
			break;
		default:
			jy = "无校验";
			break;
	}
	DlgComSet.m_szParity = jy;

	if(DlgComSet.DoModal() == IDOK)
	{
		m_szPortName	= DlgComSet.m_szPort;
		m_lBaudRate		= atol(DlgComSet.m_szBaud);
		jy = DlgComSet.m_szParity;
		if(jy == "奇校验")
			m_nParity = ODDPARITY;
		else if(jy == "偶校验")
			m_nParity = EVENPARITY;
		else 
			m_nParity = NOPARITY;

/*		if(m_hCom != INVALID_HANDLE_VALUE)//设置串口后直接打开串口
		{
			ClosePort();
			Sleep(10);		// I don't know reason,if don't do this,OpenPort may fail
			OpenPort();
		}
*/	}
}

void CComControl::SetParam(const char* szPortName, long lBaudRate, int nParity)
{
	m_szPortName	= szPortName;
	m_lBaudRate		= lBaudRate;
	m_nParity		= nParity;
	
	if(m_hCom != INVALID_HANDLE_VALUE)
	{
		ClosePort();
		Sleep(10);
		OpenPort();
	}
}

void CComControl::SetThreshold(DWORD nThreshold)
{
	//EnterCriticalSection(&m_csWmThreshold);
	m_nThresHold	= nThreshold;
	if(!PortOpened())
		return;
	m_bCanInterrupt = true;
	ResetBytes();
	if(m_nThresHold && m_cbInQue >= m_nThresHold && m_bCanInterrupt)
	{
		m_bCanInterrupt = false;
		PostMessage( m_hOwner, WM_COM, COM_THRESHOLD ,0 );
	}
	//LeaveCriticalSection(&m_csWmThreshold);
}

bool CComControl::Send(BYTE* pBuff, DWORD dwBytesSend)
{
	if(!PortOpened())	return false;
	BOOL wRes;
	DWORD dwBytesW;
	wRes = WriteFile( m_hCom,
					  pBuff,
					  dwBytesSend,
					  &dwBytesW,
					  &m_ovWrite
					);
	if(!wRes)	//there are some data not send
	{	
		if(GetLastError() == ERROR_IO_PENDING)
		{
			WaitForSingleObject(m_ovWrite.hEvent, 20*1000);	//this block the calling thread
			wRes = GetOverlappedResult( m_hCom,		// handle to comm device
										&m_ovWrite,	// pointer to overlapped structure
										&dwBytesW,	// pointer to actual bytes count
										false		// wait flag
									  );
			if(!wRes || dwBytesW != dwBytesSend)
			{
				ClearInOut();
				return false;
			}
		} 
		else	// an error occured
		{	
			ClearInOut();
			return false;
		}
	}
	return true;
}

bool CComControl::Receive(BYTE* pBuff, DWORD dwBytesRead)
{
	DWORD dwBytesReaded = 0;
	return Receive(pBuff, dwBytesRead, dwBytesReaded);
}

bool CComControl::Receive(BYTE* pBuff, DWORD dwBytesRead, DWORD& dwBytesReaded)
{
	dwBytesReaded = 0;
	if(!PortOpened())	return false;
	BOOL rRes=true;
	if(m_hCom == INVALID_HANDLE_VALUE)	return false;

	//EnterCriticalSection(&m_csWmThreshold);
	if( !ReadFile( m_hCom,			//	handle of file to read
				   pBuff,			//	address of buffer that receives data       
				   dwBytesRead,		//	number of bytes to read
				   &dwBytesReaded,	//	address of number of bytes read
				   &m_ovRead		//	address of structure for data
				 )
	  )
	{
		if (GetLastError() == ERROR_IO_PENDING)
		{
			WaitForSingleObject(m_ovRead.hEvent, INFINITE);	//this block the calling thread,if err or timeout it return
			rRes = GetOverlappedResult(m_hCom, &m_ovRead, &dwBytesReaded, false);
			if(!rRes || dwBytesReaded != dwBytesRead)
			{	// an error occurred, i think it most was timeout also it return when line error
				rRes = false;
			}
			else
			{   // some other error occurred
				rRes = true;
			}
		}
	}
	
	ResetBytes();
	//LeaveCriticalSection(&m_csWmThreshold);
	if(rRes) 
		return true;
	else 
		return false;

}

void CComControl::ClearInOut()
{
	if(m_hCom == INVALID_HANDLE_VALUE) 
		return;
	PurgeComm(m_hCom, PURGE_TXABORT | PURGE_TXCLEAR);
	ResetBytes();
}

⌨️ 快捷键说明

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