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

📄 serial.cpp

📁 GSM Mobile收发短信
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//	Serial.cpp - Implementation of the CSerial class
//////////////////////////////////////////////////////////////////////
// Include the precompiled header

#include "StdAfx.h"
#include "Resource.h"

#include <crtdbg.h>
#include <tchar.h>
#include <windows.h>

//////////////////////////////////////////////////////////////////////
// Include module headerfile
#include "Serial.h"

//////////////////////////////////////////////////////////////////////
// Disable warning C4127: conditional expression is constant, which
// is generated when using the _RPTF and _ASSERTE macros.
#pragma warning(disable: 4127)

//////////////////////////////////////////////////////////////////////
// Enable debug memory manager
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//////////////////////////////////////////////////////////////////////
// Code

CSerial::CSerial ()
{
	// Reset data
	m_lLastError     = ERROR_SUCCESS;
	m_hFile          = NULL;
	m_eEvent         = EEventNone;
	m_hevtOverlapped = NULL;

}

CSerial::~CSerial ()
{
	// If the device is already closed,
	// then we don't need to do anything.
	if (m_hFile != NULL)
	{
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n");
		// Close implicitly
		Close();
	}
}

CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice)
{
	// Try to open the device
	HANDLE hFile = ::CreateFile(lpszDevice, 
								GENERIC_READ|GENERIC_WRITE, 
								0, 
								0, 
								OPEN_EXISTING, 
								FILE_FLAG_OVERLAPPED, 
								0
								);

	// Check if we could open the device
	if (hFile == INVALID_HANDLE_VALUE)
	{
		// Display error
		switch (::GetLastError())
		{
			case ERROR_FILE_NOT_FOUND:
				// The specified COM-port does not exist
				return EPortNotAvailable;
			case ERROR_ACCESS_DENIED:
				// The specified COM-port is in use
				return EPortInUse;
			default:
				// Something else is wrong
				return EPortUnknownError;
		}
	}
	// Close handle
	::CloseHandle(hFile);
	// Port is available
	return EPortAvailable;
}

LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the port isn't already opened
	if (m_hFile != NULL)
	{
		//m_lLastError = ERROR_ALREADY_INITIALIZED;
		//_RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n");
		//return m_lLastError;
		Close();
	}
	// Open the device
	m_hFile = ::CreateFile( lpszDevice,
							GENERIC_READ|GENERIC_WRITE,
							0,
							0,
							OPEN_EXISTING,
							FILE_FLAG_OVERLAPPED,
							0
							);
	if (m_hFile == INVALID_HANDLE_VALUE)
	{
		// Reset file handle
		m_hFile = NULL;
		// Display error
		m_lLastError = ::GetLastError();
		_RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
		return m_lLastError;
	}
	// We cannot have an event handle yet
	_ASSERTE(m_hevtOverlapped == 0);
	// Create the event handle for internal overlapped operations (manual reset)
	m_hevtOverlapped = ::CreateEvent(0,true,false,0);
	if (m_hevtOverlapped == 0)
	{
		// Obtain the error information
		m_lLastError = ::GetLastError();
		_RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n");
		// Close the port
		::CloseHandle(m_hFile);
		m_hFile = NULL;
		// Return the error
		return m_lLastError;
	}
	// Setup the COM-port
	if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
	{
		// Display a warning
		long lLastError = ::GetLastError();
		_RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n");
		// Close the port
		Close();
		// Save last error from SetupComm
		m_lLastError = lLastError;
		return m_lLastError;
	}
	// Setup the default communication mask
	SetMask();
	// Setup the device for default settings
	Setup();
	// Non-blocking reads is default
	SetupReadTimeouts(EReadTimeoutNonblocking);
	// Default is no handshaking
	SetupHandshaking(EHandshakeHardware);
	// Return successful
	return m_lLastError;
}

LONG CSerial::Close (void)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// If the device is already closed,
	// then we don't need to do anything.
	if (m_hFile == NULL)
	{
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n");
		return m_lLastError;
	}
	// Free event handle
	::CloseHandle(m_hevtOverlapped);
	m_hevtOverlapped = 0;
	// Close COM port
	::CloseHandle(m_hFile);
	m_hFile = NULL;
	// Return successful
	return m_lLastError;
}

LONG CSerial::Setup(EBaudrate eBaudrate,EDataBits eDataBits,EParity eParity,EStopBits eStopBits)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the device is open
	if (m_hFile == NULL)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;
		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n");
		return m_lLastError;
	}
	// Obtain the DCB structure for the device
	CDCB dcb;
	if (!::GetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
		return m_lLastError;
	}
	// Set the new data
	dcb.BaudRate = DWORD(eBaudrate);
	dcb.ByteSize = BYTE(eDataBits);
	dcb.Parity   = BYTE(eParity);
	dcb.StopBits = BYTE(eStopBits);
	// Determine if parity is used
	dcb.fParity  = (eParity != EParNone);
	// Set the new DCB structure
	if (!::SetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n");
		return m_lLastError;
	}
	// Return successful
	return m_lLastError;
}
//=====================================================================================
LONG CSerial::SetEventChar(BYTE bEventChar, bool fAdjustMask)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the device is open
	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;
		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Device is not opened\n");
		return m_lLastError;
	}
	// Obtain the DCB structure for the device
	CDCB dcb;
	if (!::GetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to obtain DCB information\n");
		return m_lLastError;
	}
	// Set the new event character
	dcb.EvtChar = char(bEventChar);
	// Adjust the event mask, to make sure the event will be received
	if (fAdjustMask)
	{
		// Enable 'receive event character' event.  Note that this
		// will generate an EEventNone if there is an asynchronous
		// WaitCommEvent pending.
		SetMask(GetEventMask() | EEventRcvEv);
	}
	// Set the new DCB structure
	if (!::SetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to set DCB information\n");
		return m_lLastError;
	}
	// Return successful
	return m_lLastError;

}
//======================================================================================
LONG CSerial::SetMask (DWORD dwMask)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the device is open
	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;
		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::SetMask - Device is not opened\n");
		return m_lLastError;
	}
	// Set the new mask. Note that this will generate an EEventNone
	// if there is an asynchronous WaitCommEvent pending.
	if (!::SetCommMask(m_hFile,dwMask))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n");
		return m_lLastError;
	}
	// Return successful
	return m_lLastError;
}
//====================================================================================
LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the device is open
	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;
		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n");
		return m_lLastError;
	}
	// Wait for the event to happen
	OVERLAPPED ovInternal;
	if (lpOverlapped == 0)
	{
		// Setup our own overlapped structure
		memset(&ovInternal,0,sizeof(ovInternal));
		ovInternal.hEvent = m_hevtOverlapped;
		// Use our internal overlapped structure
		lpOverlapped = &ovInternal;
	}
	// Make sure the overlapped structure isn't busy
	_ASSERTE(HasOverlappedIoCompleted(lpOverlapped));
	// Wait for the COM event
	if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped))
	{
		// Set the internal error code
		long lLastError = ::GetLastError();
		// Overlapped operation in progress is not an actual error
		if (lLastError != ERROR_IO_PENDING)
		{
			// Save the error
			m_lLastError = lLastError;
			// Issue an error and quit
			_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
			return m_lLastError;
		}
		// We need to block if the client didn't specify an overlapped structure
		if (lpOverlapped == &ovInternal)
		{
			// Wait for the overlapped operation to complete
			switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
			{
				case WAIT_OBJECT_0:
					// The overlapped operation has completed
					break;
				case WAIT_TIMEOUT:
					// Cancel the I/O operation
					::CancelIo(m_hFile);
					// The operation timed out. Set the internal error code and quit
					m_lLastError = ERROR_TIMEOUT;
					return m_lLastError;
				default:
					// Set the internal error code
					m_lLastError = ::GetLastError();
					// Issue an error and quit
					_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait until COM event has arrived\n");
					return m_lLastError;
			}
		}
	}
	else
	{
		// The operation completed immediatly. Just to be sure
		// we'll set the overlapped structure's event handle.
		::SetEvent(lpOverlapped->hEvent);
	}
	// Return successfully
	return m_lLastError;
}
//=========================================================================================
LONG CSerial::SetupHandshaking (EHandshake eHandshake)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the device is open
	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;
		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Device is not opened\n");
		return m_lLastError;
	}
	// Obtain the DCB structure for the device
	CDCB dcb;
	if (!::GetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to obtain DCB information\n");
		return m_lLastError;
	}
	// Set the handshaking flags
	switch (eHandshake)
	{
		case EHandshakeOff:
			dcb.fOutxCtsFlow = false;					// Disable CTS monitoring
			dcb.fOutxDsrFlow = false;					// Disable DSR monitoring
			dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR monitoring
			dcb.fOutX = false;							// Disable XON/XOFF for transmission
			dcb.fInX = false;							// Disable XON/XOFF for receiving
			dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
			break;
		case EHandshakeHardware:
			dcb.fOutxCtsFlow = true;					// Enable CTS monitoring
			dcb.fOutxDsrFlow = true;					// Enable DSR monitoring
			dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;	// Enable DTR handshaking
			dcb.fOutX = false;							// Disable XON/XOFF for transmission
			dcb.fInX = false;							// Disable XON/XOFF for receiving
			dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;	// Enable RTS handshaking
			break;
		case EHandshakeSoftware:
			dcb.fOutxCtsFlow = false;					// Disable CTS (Clear To Send)
			dcb.fOutxDsrFlow = false;					// Disable DSR (Data Set Ready)
			dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR (Data Terminal Ready)
			dcb.fOutX = true;							// Enable XON/XOFF for transmission
			dcb.fInX = true;							// Enable XON/XOFF for receiving
			dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
			break;
		default:
			// This shouldn't be possible
			_ASSERTE(false);
			m_lLastError = E_INVALIDARG;
			return m_lLastError;
	}
	// Set the new DCB structure
	if (!::SetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to set DCB information\n");
		return m_lLastError;
	}
	// Return successful
	return m_lLastError;

}
//======================================================================================
LONG CSerial::SetupReadTimeouts (EReadTimeout eReadTimeout)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the device is open
	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;
		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Device is not opened\n");
		return m_lLastError;
	}
	// Determine the time-outs
	COMMTIMEOUTS cto;
	if (!::GetCommTimeouts(m_hFile,&cto))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to obtain timeout information\n");
		return m_lLastError;
	}
	// Set the new timeouts
	switch (eReadTimeout)
	{
		case EReadTimeoutBlocking:
			cto.ReadIntervalTimeout = 0;
			cto.ReadTotalTimeoutConstant = 0;
			cto.ReadTotalTimeoutMultiplier = 0;
			break;
		case EReadTimeoutNonblocking:
			cto.ReadIntervalTimeout = MAXDWORD;
			cto.ReadTotalTimeoutConstant = 0;
			cto.ReadTotalTimeoutMultiplier = 0;
			break;
		default:
			// This shouldn't be possible
			_ASSERTE(false);
			m_lLastError = E_INVALIDARG;
			return m_lLastError;
	}
	// Set the new DCB structure
	if (!::SetCommTimeouts(m_hFile,&cto))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to set timeout information\n");
		return m_lLastError;

	}
	// Return successful
	return m_lLastError;

}
//==========================================================================================
CSerial::EBaudrate CSerial::GetBaudrate (void)
{
	// Reset error state
	m_lLastError = ERROR_SUCCESS;
	// Check if the device is open
	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;
		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Device is not opened\n");
		return EBaudUnknown;
	}
	// Obtain the DCB structure for the device
	CDCB dcb;
	if (!::GetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Unable to obtain DCB information\n");
		return EBaudUnknown;
	}
	// Return the appropriate baudrate
	return EBaudrate(dcb.BaudRate);

}

⌨️ 快捷键说明

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