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

📄 serialport.cpp

📁 云台控制的工具
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//=======================================================================================
//	Module : SERIALPORT.CPP
//	Purpose: Implementation for an MFC wrapper class for serial ports
//	Created: PJN / 31-05-1999
//=======================================================================================

//=======================================================================================
//	Includes
#include "stdafx.h"
#include "serialport.h"
#ifndef _WINERROR_
#include "winerror.h"
#endif


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



//=======================================================================================
//	Implementation

//---------------------------------------------------------------------------------------
//	Class which handles CancelIo function which must be constructed at run time since it
//	is not imeplemented on NT 3.51 or Windows 95. To avoid the loader bringing up a 
//	message such as "Failed to load due to missing export...", the function is constructed
//	using GetProcAddress. The CSerialPort::CancelIo function then checks to see if the
//	function pointer is NULL and if it is it throws an exception using the error code
//	ERROR_CALL_NOT_IMPLEMENTED which is what 95 would have done if it had implemented
//	a stub for it in the first place.
//---------------------------------------------------------------------------------------

class _SERIAL_PORT_DATA
{
public:
	//Constructors /Destructors
	_SERIAL_PORT_DATA();
	~_SERIAL_PORT_DATA();

	HINSTANCE m_hKernel32;
	typedef BOOL (WINAPI CANCELIO) (HANDLE);
	typedef CANCELIO* LPCANCELIO;
	LPCANCELIO m_lpfnCancelIo;
};

_SERIAL_PORT_DATA::_SERIAL_PORT_DATA()
{
#ifdef UNDER_CE
	//	CE 下根本就不支持
	m_hKernel32 = NULL;
	m_lpfnCancelIo = NULL;
#else
	m_hKernel32 = LoadLibrary( _T("KERNEL32.DLL") );
	VERIFY( m_hKernel32 != NULL );
	m_lpfnCancelIo = (LPCANCELIO) GetProcAddress( m_hKernel32, "CancelIo" );
#endif
}

_SERIAL_PORT_DATA::~_SERIAL_PORT_DATA()
{
#ifndef UNDER_CE
	FreeLibrary(m_hKernel32);
	m_hKernel32 = NULL;
#endif
}

// The local variable which handle the function pointers
static _SERIAL_PORT_DATA _SerialPortData;



//***************************************************************************************
//	Exception handling code
//***************************************************************************************

void AfxThrowSerialException(DWORD dwError /* = 0 */)
{
	if (dwError == 0)
		//	为 0 时表示出现系统错误,而不是我们所定义的
		dwError = ::GetLastError();

	CSerialException* pException = new CSerialException(dwError);
	TRACE(_T("Warning: throwing CSerialException for error %d\n"), dwError);
	THROW(pException);
}

//---------------------------------------------------------------------------------------
//	GetErrorMessage 将错误消息拷贝到 pstrError 中,最大 nMaxError 个字符
//---------------------------------------------------------------------------------------

BOOL CSerialException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError, PUINT pnHelpContext)
{
	ASSERT(pstrError != NULL && AfxIsValidString(pstrError, nMaxError));
	if (pnHelpContext != NULL)
		*pnHelpContext = 0;

	LPTSTR lpBuffer;
	BOOL bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
							  NULL,  m_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
							  (LPTSTR) &lpBuffer, 0, NULL);

	if (bRet == FALSE)
	{
		*pstrError = _T('\0');
	}
	else
	{
		_tcsncpy(pstrError, lpBuffer, nMaxError);
		bRet = TRUE;
		LocalFree(lpBuffer);
	}

	return bRet;
}

CString CSerialException::GetErrorMessage()
{
	CString strVal;
	LPTSTR pstrError = strVal.GetBuffer( 2048*sizeof(TCHAR) );
	GetErrorMessage( pstrError, 2048, NULL );
	strVal.ReleaseBuffer();

	return strVal;
}

IMPLEMENT_DYNAMIC(CSerialException, CException)

#ifdef _DEBUG
void CSerialException::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc);
	dc << "m_dwError = " << m_dwError;
}
#endif



//***************************************************************************************
//	The actual serial port code
//***************************************************************************************

CSerialPort::CSerialPort()
{
	m_hComm = INVALID_HANDLE_VALUE;
	m_bOverlapped = FALSE;
	m_hEvent = NULL;
}

CSerialPort::~CSerialPort()
{
	Close();
}

IMPLEMENT_DYNAMIC(CSerialPort, CObject)

#ifdef _DEBUG
void CSerialPort::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc);

	dc << _T("m_hComm = ") << m_hComm << _T("\n");
	dc << _T("m_bOverlapped = ") << m_bOverlapped;
}
#endif



//---------------------------------------------------------------------------------------
//	串口打开操作
//---------------------------------------------------------------------------------------

void CSerialPort::Open(int nPort, DWORD dwBaud, Parity parity, BYTE DataBits,
					   StopBits stopbits, FlowControl fc, BOOL bOverlapped)
{
	// Validate our parameters
	ASSERT(nPort>0 && nPort<=255);

	Close(); // In case we are already open

	// Call CreateFile to open up the comms port
	CString strPort;
#ifdef UNDER_CE
	//	注意 ':' 号
	strPort.Format(_T("COM%d:"), nPort);
#else
	strPort.Format(_T("\\\\.\\COM%d"), nPort);
#endif

	//	CE 下根本就不支持重叠操作,因此始终为 FALSE
#ifdef UNDER_CE
	bOverlapped = FALSE;
#endif
	DWORD dwCreateProperty;
	if(bOverlapped) 
	{
		dwCreateProperty = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
	}
	else
	{
		dwCreateProperty = FILE_ATTRIBUTE_NORMAL;
	}

	// bOverlapped ? FILE_FLAG_OVERLAPPED : 0
	// Open the serial port.
	m_hComm = CreateFile(strPort,			// Pointer to the name of the port
						 GENERIC_READ | GENERIC_WRITE,
											// Access (read-write) mode
						 0,					// Share mode
						 NULL,				// Pointer to the security attribute
						 OPEN_EXISTING,		// How to open the serial port
						 dwCreateProperty,	// Port attributes
						 NULL);				// Handle to port with attribute to copy
	if (m_hComm == INVALID_HANDLE_VALUE)
	{
		TRACE(_T("Failed to open up the comms port!\n"));
		AfxThrowSerialException();
	}
	m_CurPortNum = nPort;

/*
	// Create the event we need for later synchronisation use
	if(bOverlapped)
	{
		m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		if (m_hEvent == NULL)
		{
			Close();
			TRACE(_T("Failed in call to CreateEvent in Open\n"));
			AfxThrowSerialException();
		}
	}
*/

	m_bOverlapped = bOverlapped;

	// Get the current state prior to changing it
	DCB dcb;
	dcb.DCBlength = sizeof(DCB);
	GetState(dcb);

	//-------------------------------------------------------------------------
	// 设置串口属性
	//-------------------------------------------------------------------------

	// Setup the baud rate
	dcb.BaudRate = dwBaud; 
	// Setup the Parity
	switch (parity)
	{
	case EvenParity:  dcb.Parity = EVENPARITY;  break;
	case MarkParity:  dcb.Parity = MARKPARITY;  break;
	case NoParity:    dcb.Parity = NOPARITY;    break;
	case OddParity:   dcb.Parity = ODDPARITY;   break;
	case SpaceParity: dcb.Parity = SPACEPARITY; break;
	default:
		ASSERT(FALSE);
		break;
	}
	// Setup the data bits
	dcb.ByteSize = DataBits;
	// Setup the stop bits
	switch (stopbits)
	{
	case OneStopBit:           dcb.StopBits = ONESTOPBIT;   break;
	case OnePointFiveStopBits: dcb.StopBits = ONE5STOPBITS; break;
	case TwoStopBits:          dcb.StopBits = TWOSTOPBITS;  break;
	default:
		ASSERT(FALSE);
		break;
	}
	// Setup the flow control 
	dcb.fDsrSensitivity = FALSE;
	switch (fc)
	{
	case NoFlowControl:
		{
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
		}
	case CtsRtsFlowControl:
		{
		dcb.fOutxCtsFlow = TRUE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
		}
	case CtsDtrFlowControl:
		{
		dcb.fOutxCtsFlow = TRUE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
		}
	case DsrRtsFlowControl:
		{
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = TRUE;
		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
		}
	case DsrDtrFlowControl:
		{
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = TRUE;
		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
		dcb.fOutX = FALSE;
		dcb.fInX = FALSE;
		break;
		}
	case XonXoffFlowControl:
		{
		dcb.fOutxCtsFlow = FALSE;
		dcb.fOutxDsrFlow = FALSE;
		dcb.fOutX = TRUE;
		dcb.fInX = TRUE;
		dcb.XonChar = 0x11;
		dcb.XoffChar = 0x13;
		dcb.XoffLim = 100;
		dcb.XonLim = 100;
		break;
		}
	default:
		ASSERT(FALSE);
		break;
	}
	dcb.fAbortOnError = FALSE;	//	Terminate Reads & Writes if there's an error
	dcb.fErrorChar	  = TRUE;	//	Replace any garbled bytes with ErrorChar
	dcb.ErrorChar	  = ' ';	//	Garbage bytes are spaces
	dcb.fBinary		  = TRUE;	//	Ignore EOF

	// Now that we have all the settings in place, make the changes
	SetState(dcb);
}

void CSerialPort::Close()
{
	if (!IsOpen())
		return;

	//	Close down the comms port
	BOOL bSuccess = CloseHandle(m_hComm);
	m_hComm = INVALID_HANDLE_VALUE;
	if (!bSuccess)
	{
		TRACE(_T("Failed to close up the comms port, GetLastError:%d.\n"), GetLastError());
	}
	m_bOverlapped = FALSE;

	//	Free up the event object we are using
	if(m_hEvent)
	{
		CloseHandle(m_hEvent);
		m_hEvent = NULL;
	}
}

void CSerialPort::Attach(HANDLE hComm, BOOL bOverlapped)
{
	Close();
	m_hComm = hComm;  
	m_bOverlapped = bOverlapped;

	if( m_bOverlapped )
	{
		//	Create the event we need for later synchronisation use
		m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		if (m_hEvent == NULL)
		{
			Close();
			TRACE(_T("Failed in call to \"CreateEvent()\" in \"Attach()\".\n"));
			AfxThrowSerialException();
		}
	}
}

HANDLE CSerialPort::Detach()
{
	HANDLE hrVal = m_hComm;
	m_hComm = INVALID_HANDLE_VALUE;
	if( m_bOverlapped )
	{
		CloseHandle(m_hEvent);
		m_hEvent = NULL;
	}

	return hrVal;
}

//---------------------------------------------------------------------------------------
//	读取 dwCount 个字节到 lpBuf 中,同步操作
//		没有读到任何数据或者读取数据过程中出错,返回 0
//	如果 dwCount 比 comstat.cbInQue,那么表示 lpBuf 足够大,可以放下待接收的数据
//	使用 comstat.cbInQue 为读取缓冲区大小
//---------------------------------------------------------------------------------------

DWORD CSerialPort::Read(void* lpBuf, DWORD dwCount)
{
	ASSERT(IsOpen());
	ASSERT(!m_bOverlapped);

	DWORD errors;
	COMSTAT comstat;
	BOOL ok;
	ok = ::ClearCommError(this->m_hComm, &errors, &comstat);
	if( !ok )
	{
		return 0;
	}
	if( comstat.cbInQue == 0 )
	{
		return 0;
	}

	DWORD dwBytesRead = 0;
	if( dwCount > comstat.cbInQue )
		dwCount = comstat.cbInQue;
	if (!ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, NULL))
	{
		TRACE(_T("Failed in call to \"ReadFile()\" in \"Read()\".\n"));
		AfxThrowSerialException();
	}

	return dwBytesRead;
}

//---------------------------------------------------------------------------------------
//	读取 dwCount 个字节到 lpBuf 中,异步操作
//		读取完成或超时后,读取字节个数在 pBytesRead 中返回
//---------------------------------------------------------------------------------------

BOOL CSerialPort::Read(void* lpBuf, DWORD dwCount, OVERLAPPED& overlapped,
					   DWORD* pBytesRead)
{
	ASSERT(IsOpen());
	ASSERT(m_bOverlapped);

	DWORD dwBytesRead = 0;
	BOOL bSuccess = ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, &overlapped);
	if (!bSuccess)
	{
		if (GetLastError() != ERROR_IO_PENDING)
		{
			TRACE(_T("Failed in call to \"ReadFile()\" in \"Read()\".\n"));
			AfxThrowSerialException();
		}
	}
	else
	{
		if (pBytesRead)
			*pBytesRead = dwBytesRead;
	}

	return bSuccess;
}

//---------------------------------------------------------------------------------------
//	将 lpBuf 中的 dwCount 个字节写入串口中,同步操作
//		返回实际写入的字节数
//---------------------------------------------------------------------------------------

DWORD CSerialPort::Write(const void* lpBuf, DWORD dwCount)
{
	ASSERT(IsOpen());
	ASSERT(!m_bOverlapped);

	DWORD dwBytesWritten = 0;
	if (!WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, NULL))
	{
		TRACE(_T("Failed in call to \"WriteFile()\" in \"Write()\".\n"));
		AfxThrowSerialException();
	}

	return dwBytesWritten;
}

//---------------------------------------------------------------------------------------
//	将 lpBuf 中的 dwCount 个字节写入串口中,异步操作
//		实际写入的字节数在 pBytesWritten 中返回
//---------------------------------------------------------------------------------------

BOOL CSerialPort::Write(const void* lpBuf, DWORD dwCount, OVERLAPPED& overlapped,
						DWORD* pBytesWritten)
{
	ASSERT(IsOpen());
	ASSERT(m_bOverlapped);

	DWORD dwBytesWritten = 0;
	BOOL bSuccess = WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, &overlapped);
	if (!bSuccess)
	{
		if (GetLastError() != ERROR_IO_PENDING)
		{
			TRACE(_T("Failed in call to \"WriteFile()\" in \"Write()\".\n"));
			AfxThrowSerialException();
		}
	}
	else
	{
		if (pBytesWritten)
			*pBytesWritten = dwBytesWritten;
	}

	return bSuccess;
}

BOOL CSerialPort::GetOverlappedResult(OVERLAPPED& overlapped, DWORD& dwBytesTransferred, BOOL bWait)
{
#ifdef UNDER_CE
	dwBytesTransferred = 0;
//	TRACE(_T("Call unsupported function \"GetOverlappedResult()\"!\n"));
//	AfxThrowSerialException(ERROR_CALL_NOT_IMPLEMENTED);
	return FALSE;
#else
	ASSERT(IsOpen());
	ASSERT(m_bOverlapped);

	BOOL bSuccess = ::GetOverlappedResult(m_hComm, &overlapped, &dwBytesTransferred, bWait);
	if (!bSuccess)
	{
		if (GetLastError() != ERROR_IO_PENDING)
		{
			TRACE(_T("Failed in call to \"GetOverlappedResult()\".\n"));
			AfxThrowSerialException();
		}
	}

⌨️ 快捷键说明

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