C++串口通信类

一个C++编写的串口通信类,实现了异步通信功能。
.h 头文件:
class BASE_API CBSerialPort final : private noncopyable
{
public:
	CBSerialPort(void);	
	CBSerialPort(const tstring& strPortName);
	virtual ~CBSerialPort(void);
public:
	void SetBaudRate(const DWORD baudRate);
	void SetByteSize(const BYTE byteSize);
	void SetStopBits(const BYTE stopBits);
	void SetParity(const BYTE parity);
	DWORD WriteData(const char* data, const DWORD dataSize);
	DWORD ReadData(char* buffer, const DWORD bufferSize);

private:
	void UpdateSettings(void) const;

private:
	tstring m_strPortName;
	HANDLE m_portHandle;
	DWORD m_baudRate;
	BYTE m_byteSize;
	BYTE m_stopBits;
	BYTE m_parity;
	OVERLAPPED m_readOverlapped;
	OVERLAPPED m_writeOverlapped;
};

.cpp 实现文件:
#define DEFAULT_COM_PORT _T("COM1")

// 根据波特率计算超时时间
static DWORD CalculateTimeout(const DWORD baudRate, const int nByteSize) noexcept {
	// 计算超时时间
	const double timeout = (double)nByteSize * 1000u / (double)baudRate;
	return (DWORD)(timeout+1);
}

CBSerialPort::CBSerialPort(void)
	: m_strPortName(DEFAULT_COM_PORT)
	, m_portHandle(INVALID_HANDLE_VALUE)
	, m_baudRate(CBR_14400)
	, m_byteSize(8)
	, m_stopBits(ONESTOPBIT)
	, m_parity(NOPARITY)
	, m_readOverlapped({0})
	, m_writeOverlapped({0})
{
	Log::DebugInfo(_T("CBSerialPort::CBSerialPort0 this=0x%08x"), this);
}

CBSerialPort::CBSerialPort(const tstring& strPortName)
	: m_strPortName(strPortName)
	, m_portHandle(INVALID_HANDLE_VALUE)
	, m_baudRate(CBR_14400)
	, m_byteSize(8)
	, m_stopBits(ONESTOPBIT)
	, m_parity(NOPARITY)
	, m_readOverlapped({0})
	, m_writeOverlapped({0})
{
	Log::DebugInfo(_T("CBSerialPort::CBSerialPort1 this=0x%08x"), this);
	if (strPortName.empty())
		m_strPortName = DEFAULT_COM_PORT;

	m_portHandle = CreateFile(m_strPortName.c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
	if (INVALID_HANDLE_VALUE == m_portHandle) {
		Log::DebugError(_T("Unable to open serial port!err=0x%08x"), GetLastError());
	}
	else
	{
		// 建立缓冲区,设置读写缓冲区大小
		//SetupComm(m_portHandle, 1600, 1600);
		// 设置掩码
		//SetCommMask(m_portHandle, EV_RXCHAR|EV_TXEMPTY)

		COMMTIMEOUTS timeout = { 0 };
		timeout.ReadIntervalTimeout = MAXDWORD;
		timeout.ReadTotalTimeoutMultiplier = 10;
		timeout.ReadTotalTimeoutConstant = 2000;

		timeout.WriteTotalTimeoutMultiplier = 10;
		timeout.WriteTotalTimeoutConstant = 2000;
		if (!SetCommTimeouts(m_portHandle, &timeout))
			Log::DebugError(_T("SetCommTimeouts failed!err=0x%08x"), GetLastError());

		m_readOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	}
}

CBSerialPort::~CBSerialPort(void) {
	Log::DebugInfo(_T("CBSerialPort::~CBSerialPort0 this=0x%08x"), this);
	SafeCloseHandle(m_readOverlapped.hEvent);
	CloseFileHandle(m_portHandle);
}

void CBSerialPort::SetBaudRate(const DWORD baudRate) {
	Log::DebugInfo(_T("SetBaudRate:%d"), baudRate);
	m_baudRate = baudRate;
	UpdateSettings();
}
void CBSerialPort::SetByteSize(const BYTE byteSize) {
	Log::DebugInfo(_T("SetByteSize:%d"), (DWORD)byteSize);
	m_byteSize = byteSize;
	UpdateSettings();
}
void CBSerialPort::SetStopBits(const BYTE stopBits) {
	Log::DebugInfo(_T("SetStopBits:%d"), (DWORD)stopBits);
	m_stopBits = stopBits;
	UpdateSettings();
}
void CBSerialPort::SetParity(const BYTE parity) {
	Log::DebugInfo(_T("SetParity:%d"), (DWORD)parity);
	m_parity = parity;
	UpdateSettings();
}
DWORD CBSerialPort::WriteData(const char* data, const DWORD dataSize) {
	DWORD dwBytesWritten = 0u;
	if (WriteFile(m_portHandle, data, dataSize, &dwBytesWritten, &m_writeOverlapped)) {
		// Write operation completed immediately
		return dwBytesWritten;
	}	
	if (ERROR_IO_PENDING == GetLastError()) { // Write operation is pending
		DWORD bytesTransferred;
		if (!GetOverlappedResult(m_portHandle, &m_writeOverlapped, &bytesTransferred, TRUE))
		{
			Log::DebugError(_T("Unable to write data(IO_PENDING)!err=0x%08x"), GetLastError());
		}
		return bytesTransferred;
	}
	else {
		Log::DebugError(_T("Unable to write data!err=0x%08x"), GetLastError());
		return dwBytesWritten;
	}
	return dwBytesWritten;
}

DWORD CBSerialPort::ReadData(char* buffer, const DWORD bufferSize)
{
	DWORD dwBytesRead = 0u;
	if (ReadFile(m_portHandle, buffer, bufferSize, &dwBytesRead, &m_readOverlapped)) {
		// Read operation completed immediately
		return dwBytesRead;
	}
	if (ERROR_IO_PENDING == GetLastError()) { // Read operation is pending
		DWORD bytesTransferred;
		if (!GetOverlappedResult(m_portHandle, &m_readOverlapped, &bytesTransferred, TRUE))
		{
			Log::DebugError(_T("Unable to read data(IO_PENDING)!err=0x%08x"), GetLastError());
		}
		return bytesTransferred;
	}
	else {
		Log::DebugError(_T("Unable to read data!err=0x%08x"), GetLastError());
		return dwBytesRead;
	}	
	return dwBytesRead;
}

void CBSerialPort::UpdateSettings(void) const
{
	DCB dcb = { 0 };
	dcb.DCBlength = sizeof(DCB);
	if (!GetCommState(m_portHandle, &dcb)) {
		Log::DebugError(_T("GetCommState failed!err=0x%08x"), GetLastError());
		return;
	}
	dcb.BaudRate = m_baudRate;
	dcb.ByteSize = m_byteSize;
	dcb.StopBits = m_stopBits;
	dcb.Parity = m_parity;
	if (!SetCommState(m_portHandle, &dcb)) {
		Log::DebugError(_T("SetCommState failed!err=0x%08x"), GetLastError());
		return;
	}

	COMMTIMEOUTS timeout = { 0 };
	timeout.ReadIntervalTimeout = MAXDWORD;
	timeout.ReadTotalTimeoutMultiplier = 1;
	timeout.ReadTotalTimeoutConstant = CalculateTimeout(m_baudRate, m_byteSize);

	timeout.WriteTotalTimeoutMultiplier = 1;
	timeout.WriteTotalTimeoutConstant = timeout.ReadTotalTimeoutConstant;
	if (!SetCommTimeouts(m_portHandle, &timeout))
		Log::DebugError(_T("SetCommTimeouts failed!err=0x%08x"), GetLastError());
}
单元测试代码:

TEST_F(CBSerialPortTest, Test_NULL)
{
	DECARE_DETECT_MEMORY_LEAKS0

	CBSerialPort serialPort(_T("COM4"));	
	serialPort.SetBaudRate(CBR_256000);
	serialPort.SetByteSize(8);
	serialPort.SetStopBits(ONESTOPBIT);
	serialPort.SetParity(NOPARITY);	

	std::string str = "Hello, Serial Port!00-recom-The Elements of Computing SystemsBuilding a Modern Computer from First Principles.Computer science books Recommended by AzatAI. (Education ONLY)";
	for (UINT i = 0; i<str.length(); ++i) {
		std::string strSub = str.substr(0, i + 1);
		const DWORD dwBytesWrite = serialPort.WriteData(strSub.c_str(), strSub.length());
		EXPECT_TRUE(strSub.length() == dwBytesWrite);
		std::cout << "(" << i << ")>>>S:" << strSub << std::endl;

		// Allow receiving buffer to receive complete data with sufficient time
		// To avoid the situations that data is not fully received
		// e.g.
		// (32)>>>S:Hello, Serial Port!00-recom-The E
		// (32)<<<R:Hello, Serial Port!00-recom-The
		Sleep(5);

		char buffer[256] = { 0 };
		const DWORD dwBytesRead = serialPort.ReadData(buffer, sizeof(buffer));
		std::cout << "(" << i << ")<<<R:" << buffer << std::endl;
		EXPECT_TRUE(strSub.length() == dwBytesRead);
		EXPECT_TRUE(strSub == buffer);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值