一个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);
}
}
C++串口通信类
最新推荐文章于 2024-08-11 01:30:13 发布