serialcommunication.h
#ifndef SERIALCOMMUNICATOR_H
#define SERIALCOMMUNICATOR_H
#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QTimer>
#include <QMutex>
class SerialCommunicator : public QObject
{
Q_OBJECT
public:
explicit SerialCommunicator(QObject *parent = nullptr);
~SerialCommunicator();
// 配置串口名称
bool setPortName(const QString &portName);
QString portName() const;
// 同步读写接口
bool writeData(const QByteArray &data, int timeout = 3000);
QByteArray readData(int timeout = 3000);
// 打开/关闭串口
bool open();
void close();
bool isOpen() const;
signals:
// 故障通知信号
void errorOccurred(const QString &errorMsg);
void portReconnected();
private slots:
void handleError(QSerialPort::SerialPortError error);
void attemptReconnect();
private:
QSerialPort *m_serialPort;
QString m_portName;
bool m_isReconnecting;
QTimer *m_reconnectTimer;
QMutex m_mutex;
};
#endif // SERIALCOMMUNICATOR_H
serialcommunication.cpp
#include "serialcommunicator.h"
#include <QDebug>
SerialCommunicator::SerialCommunicator(QObject *parent) : QObject(parent),
m_serialPort(new QSerialPort(this)),
m_isReconnecting(false),
m_reconnectTimer(new QTimer(this))
{
// 连接错误信号
connect(m_serialPort, &QSerialPort::errorOccurred, this, &SerialCommunicator::handleError);
// 配置重连定时器
m_reconnectTimer->setInterval(2000); // 2秒重试间隔
connect(m_reconnectTimer, &QTimer::timeout, this, &SerialCommunicator::attemptReconnect);
}
SerialCommunicator::~SerialCommunicator()
{
close();
}
bool SerialCommunicator::setPortName(const QString &portName)
{
QMutexLocker locker(&m_mutex);
if (m_serialPort->isOpen()) {
qDebug() << "请先关闭串口再修改端口名称";
return false;
}
m_portName = portName;
return true;
}
QString SerialCommunicator::portName() const
{
return m_portName;
}
bool SerialCommunicator::writeData(const QByteArray &data, int timeout)
{
QMutexLocker locker(&m_mutex);
if (!m_serialPort->isOpen()) {
emit errorOccurred("串口未打开,无法写入数据");
return false;
}
qint64 bytesWritten = m_serialPort->write(data);
if (bytesWritten == -1) {
emit errorOccurred("写入数据失败: " + m_serialPort->errorString());
return false;
} else if (bytesWritten != data.size()) {
emit errorOccurred("未能写入全部数据");
return false;
}
if (m_serialPort->waitForBytesWritten(timeout)) {
return true;
} else {
emit errorOccurred("写入超时: " + m_serialPort->errorString());
return false;
}
}
QByteArray SerialCommunicator::readData(int timeout)
{
QMutexLocker locker(&m_mutex);
if (!m_serialPort->isOpen()) {
emit errorOccurred("串口未打开,无法读取数据");
return QByteArray();
}
if (m_serialPort->waitForReadyRead(timeout)) {
QByteArray data = m_serialPort->readAll();
// 处理可能的连续数据
while (m_serialPort->waitForReadyRead(10))
data.append(m_serialPort->readAll());
return data;
} else {
emit errorOccurred("读取超时: " + m_serialPort->errorString());
return QByteArray();
}
}
bool SerialCommunicator::open()
{
QMutexLocker locker(&m_mutex);
if (m_serialPort->isOpen())
return true;
m_serialPort->setPortName(m_portName);
// 使用默认配置,但设置为阻塞模式用于同步操作
if (m_serialPort->open(QIODevice::ReadWrite)) {
m_serialPort->setBaudRate(QSerialPort::Baud115200);
m_serialPort->setDataBits(QSerialPort::Data8);
m_serialPort->setParity(QSerialPort::NoParity);
m_serialPort->setStopBits(QSerialPort::OneStop);
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
qDebug() << "串口已成功打开: " << m_portName;
return true;
} else {
emit errorOccurred("无法打开串口: " + m_serialPort->errorString());
return false;
}
}
void SerialCommunicator::close()
{
QMutexLocker locker(&m_mutex);
if (m_serialPort->isOpen()) {
m_serialPort->close();
qDebug() << "串口已关闭: " << m_portName;
}
}
bool SerialCommunicator::isOpen() const
{
return m_serialPort->isOpen();
}
void SerialCommunicator::handleError(QSerialPort::SerialPortError error)
{
if (error == QSerialPort::NoError)
return;
// 忽略一些不重要的错误
if (error == QSerialPort::ParityError ||
error == QSerialPort::FramingError ||
error == QSerialPort::OverrunError) {
emit errorOccurred("通信错误: " + m_serialPort->errorString());
return;
}
// 处理严重错误,尝试重新连接
if (!m_isReconnecting && m_serialPort->isOpen()) {
QString errorMsg = "串口故障: " + m_serialPort->errorString();
emit errorOccurred(errorMsg);
qDebug() << errorMsg << "- 尝试重新连接";
m_isReconnecting = true;
close();
m_reconnectTimer->start();
}
}
void SerialCommunicator::attemptReconnect()
{
qDebug() << "尝试重新连接串口: " << m_portName;
if (open()) {
m_reconnectTimer->stop();
m_isReconnecting = false;
emit portReconnected();
qDebug() << "串口重新连接成功";
} else {
qDebug() << "串口重新连接失败,将再次尝试";
}
}
Q.E.D.
Comments | 0 条评论