精简版CE串口类库

#ifndef SERIAL_PORT_H
#define SERIAL_PORT_H

#include <afxwin.h> // MFC 核心组件和标准组件

/// <summary>
/// 描述:EVC串口类库
/// 日期:2012/3/30
/// </summary>
class CSerialPort : public CObject
{
public:
	CSerialPort()
	{
		m_hSerialPort = INVALID_HANDLE_VALUE;
		m_bWatchThreadLived = FALSE;
	}

	virtual ~CSerialPort()
	{
		Close(5000);
	}

	/// <summary>最大输入缓冲大小</summary>
	static CONST UINT32 s_MaxInQueue = 4096;

	/// <summary>最大输出缓冲大小</summary>
	static CONST UINT32 s_MaxOutQueue = 4096;

	/// <summary>获取系统错误消息</summary>
	/// <param name="psErrorMessage">输出的错误消息</param>
	static void GetLastError(CString& psErrorMessage)
	{
		if (DWORD dwLastError = ::GetLastError())
		{
			LPVOID lpMsgBuf;
			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL, dwLastError, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPTSTR) &lpMsgBuf, 0, NULL);
			psErrorMessage.Format(_T("(%d): %s"), dwLastError, (LPCTSTR)lpMsgBuf);
			LocalFree( lpMsgBuf );
		}
	}

	/// <summary>获取串口设备控制块</summary>
	/// <param name="lpDCB">输出的串口设备控制块</param>
	BOOL GetCommState(LPDCB lpDCB)
	{
		return ::GetCommState(m_hSerialPort, lpDCB);
	}

	/// <summary>设置串口设备控制块</summary>
	/// <param name="lpDCB">输入的串口设备控制块</param>
	BOOL SetCommState(LPDCB lpDCB)
	{
		return ::SetCommState(m_hSerialPort, lpDCB);
	}

	/// <summary>打开串口设备</summary>
	/// <param name="dwPort">端口号</param>
	/// <param name="dwBaudRate">波特率</param>
	/// <param name="byParity">奇偶校验</param>
	/// <param name="byByteSize">数据位</param>
	/// <param name="byStopBits">停止位</param>
	/// <example>CSerialPort::Open(1, 9600, 0, 8, 0)</example>
	/// <returns>是否打开成功</returns>
	virtual BOOL Open(DWORD dwPort, DWORD dwBaudRate = CBR_9600, BYTE byParity = NOPARITY,
		BYTE byByteSize = 8, BYTE byStopBits = ONESTOPBIT)
	{
		CString strPort;
		strPort.Format(_T("\\$device\\COM%d"), dwPort);
		return Open(strPort, dwBaudRate, byParity, byByteSize, byStopBits);
	}

	/// <summary>打开串口设备</summary>
	/// <param name="pszPort">端口名称</param>
	/// <param name="dwBaudRate">波特率</param>
	/// <param name="byParity">奇偶校验</param>
	/// <param name="byByteSize">数据位</param>
	/// <param name="byStopBits">停止位</param>
	/// <example>CSerialPort::Open(1, 9600, 0, 8, 0)</example>
	/// <returns>是否打开成功</returns>
	virtual BOOL Open(LPCTSTR pszPort, DWORD dwBaudRate = CBR_9600, BYTE byParity = NOPARITY,
		BYTE byByteSize = 8, BYTE byStopBits = ONESTOPBIT)
	{
		if (IsOpen()) return TRUE; // 防止重复创建串口句柄

		m_hSerialPort = CreateFile(pszPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

		GetCommState(&m_tDeviceControlBlock);
		m_tDeviceControlBlock.BaudRate = dwBaudRate;
		m_tDeviceControlBlock.Parity = byParity;
		m_tDeviceControlBlock.ByteSize = byByteSize;
		m_tDeviceControlBlock.StopBits = byStopBits;
		m_tDeviceControlBlock.fParity = (byParity != NOPARITY);
		SetCommState(&m_tDeviceControlBlock); // 设置串口设备控制块
	
		SetupComm(m_hSerialPort, s_MaxInQueue, s_MaxOutQueue); // 初始化串口参数(不能在此处设置断言),即设置输入输出缓冲区大小
		
		GetCommTimeouts(m_hSerialPort, &m_tCommTimeOuts);		
		m_tCommTimeOuts.ReadIntervalTimeout = 100;// 字符读取间隔
		m_tCommTimeOuts.ReadTotalTimeoutMultiplier = 0;
		m_tCommTimeOuts.ReadTotalTimeoutConstant = 250;// 读取超时间隔
		m_tCommTimeOuts.WriteTotalTimeoutMultiplier = 0;
		m_tCommTimeOuts.WriteTotalTimeoutConstant = 250;// 写入超时间隔
		SetCommTimeouts(m_hSerialPort, &m_tCommTimeOuts); // 设置串口超时参数
	
		PurgeComm(m_hSerialPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); // 清空串口缓冲区数据

		m_bWatchThreadLived = TRUE;
		m_hWatchThread = CreateThread(NULL, 0, WatchThreadProc, this, 0, NULL); // 创建串口监视线程
	
		return TRUE;
	}
	
	/// <summary>关闭串口设备</summary>
	/// <returns>是否关闭成功</returns>
	virtual void Close(DWORD dwTimeout = 5000)
	{
		if (IsOpen())
		{
			m_bWatchThreadLived = FALSE;
			SetCommMask(m_hSerialPort, 0); // 停止监视串口接收事件

			PurgeComm(m_hSerialPort, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_RXABORT);  // 清空串口缓冲区数据

			if (WaitForSingleObject(m_hWatchThread, dwTimeout) != WAIT_OBJECT_0) 
			{
				TerminateThread(m_hWatchThread, WAIT_ABANDONED);
			}
			CloseHandle(m_hWatchThread);
			m_hWatchThread = NULL;

			CloseHandle(m_hSerialPort);
			m_hSerialPort = INVALID_HANDLE_VALUE;
		}		
	}
	
	/// <summary>获取串口设备状态</summary>
	/// <returns>是否已打开</returns>
	BOOL IsOpen()
	{
		return (m_hSerialPort != INVALID_HANDLE_VALUE);
	}
	
	/// <summary>将指定数量的数据写入串口</summary>
	/// <param name="pbyBuffer">输入缓冲区指针</param>
	/// <param name="dwOffset">输入缓冲区位置</param>
	/// <param name="dwCount">输入缓冲区大小</param>
	/// <returns>是否写入成功</returns>
	BOOL Write(const BYTE* pbyBuffer, DWORD dwOffset = 0, DWORD dwCount = 1)
	{
		ASSERT(IsOpen());

		DWORD dwCommError;
		if (ClearCommError(m_hSerialPort, &dwCommError, NULL) && dwCommError > 0)
			PurgeComm(m_hSerialPort, PURGE_TXABORT);

		DWORD dwBytesWritten;
		return WriteFile(m_hSerialPort, pbyBuffer + dwOffset, dwCount, &dwBytesWritten, NULL);
	}

	/// <summary>将指定数量的字符写入串口</summary>
	/// <param name="pszBuffer">输入缓冲区指针</param>
	/// <param name="dwOffset">输入缓冲区位置</param>
	/// <param name="dwCount">输入缓冲区大小</param>
	/// <returns>是否写入成功</returns>
	BOOL Write(LPCTSTR pszBuffer, DWORD dwOffset = 0, DWORD dwCount = 1)
	{
		return Write(pszBuffer, dwOffset * sizeof(TCHAR), dwCount * sizeof(TCHAR));
	}

	/// <summary>从串口读取指定数量的数据</summary>
	/// <param name="pbyBuffer">输出缓冲区指针</param>
	/// <param name="dwOffset">输出缓冲区位置</param>
	/// <param name="dwCount">输出缓冲区大小</param>
	/// <returns>是否读取成功</returns>
	BOOL Read(LPBYTE pbyBuffer, DWORD dwOffset = 0, DWORD dwCount = 1)
	{
		ASSERT(IsOpen());

		DWORD dwCommError;
		if (ClearCommError(m_hSerialPort, &dwCommError, NULL) && dwCommError > 0)
			PurgeComm(m_hSerialPort, PURGE_RXABORT);

		DWORD dwBytesRead;
		return ReadFile(m_hSerialPort, pbyBuffer + dwOffset, dwCount, &dwBytesRead, NULL);
	}

	/// <summary>从串口读取指定数量的字符</summary>
	/// <param name="pszBuffer">输出缓冲区指针</param>
	/// <param name="dwOffset">输出缓冲区位置</param>
	/// <param name="dwCount">输出缓冲区大小</param>
	/// <returns>是否读取成功</returns>
	BOOL Read(LPTSTR pszBuffer, DWORD dwOffset = 0, DWORD dwCount = 1)
	{
		return Read(pszBuffer, dwOffset * sizeof(TCHAR), dwCount * sizeof(TCHAR));
	}

	/// <summary>监视串口数据收发线程处理函数</summary>
	/// <returns>线程退出代码</returns>
	static DWORD WINAPI WatchThreadProc(LPVOID lpParam)
	{
		CSerialPort* pSender = (CSerialPort*) lpParam;
		
		return pSender->WatchThreadProc();
	}

	/// <summary>监视串口数据收发线程处理函数</summary>
	/// <returns>线程退出代码</returns>
	virtual DWORD WatchThreadProc()
	{
		ASSERT(IsOpen());

		SetCommMask(m_hSerialPort, EV_RXCHAR); // 设置监视串口数据接收事件

		DWORD dwCommEvent; // 串口事件掩码
		DWORD dwCommError;
		COMSTAT tComStat; // 串口设备数据
		while (m_bWatchThreadLived)
		{
			if (WaitCommEvent(m_hSerialPort, &dwCommEvent, NULL))
			{
				if (dwCommEvent & EV_RXCHAR)
				{
					if (ClearCommError(m_hSerialPort, &dwCommError, &tComStat)) // 获取串口错误信息
					{
						if (tComStat.cbInQue)
						{
							DataReceived(tComStat.cbInQue);
						}
					}
				}
			}
		}
		return 0; // 线程正常退出
	}

	/// <summary>串口接收事件处理函数</summary>
	/// <param name="dwBytesSize">接收到的数据大小</param>
	virtual void DataReceived(int nBytesSize) { ; }

private:
	/// <summary>串口设备句柄</summary>
	HANDLE m_hSerialPort;

	/// <summary>串口超时参数</summary>
	COMMTIMEOUTS m_tCommTimeOuts;

	/// <summary>串口设备控制块</summary>
	DCB m_tDeviceControlBlock;

	/// <summary>收发线程句柄</summary>
	HANDLE m_hWatchThread;

	/// <summary>收发线程是否活动</summary>
	BOOL m_bWatchThreadLived;
};

#endif // SERIAL_PORT_H

你可能感兴趣的:(精简版CE串口类库)