179 lines
5.7 KiB
C++
179 lines
5.7 KiB
C++
#include "ParameterHandler.h"
|
||
#include <QCoreApplication>
|
||
#include <QDebug>
|
||
#include <QThread>
|
||
|
||
ParameterHandler::ParameterHandler(QObject *parent)
|
||
: QObject(parent)
|
||
, m_serialPort(new QSerialPort(this))
|
||
{
|
||
// 将 QSerialPort 的 readyRead 信号连接到槽函数,用于数据接收
|
||
connect(m_serialPort, &QSerialPort::readyRead, this, &ParameterHandler::handleReadyRead);
|
||
|
||
// 将 QSerialPort 的 errorOccurred 信号连接到槽函数,用于错误处理
|
||
// 使用 QOverload 确保连接到正确的重载函数
|
||
connect(m_serialPort,
|
||
QOverload<QSerialPort::SerialPortError>::of(&QSerialPort::errorOccurred),
|
||
this,
|
||
&ParameterHandler::handleError);
|
||
}
|
||
|
||
ParameterHandler::~ParameterHandler()
|
||
{
|
||
// 析构时确保串口关闭
|
||
closePort();
|
||
// m_serialPort 的父对象是 ParameterHandler (this),所以它会被 QObject 机制自动删除。
|
||
}
|
||
|
||
/**
|
||
* @brief 静态函数实现:获取系统上所有可用串口的名称列表
|
||
* @return 包含所有可用串口名称的 QStringList
|
||
*/
|
||
QStringList ParameterHandler::getAvailablePortNames()
|
||
{
|
||
QStringList portNames;
|
||
// 使用 QSerialPortInfo::availablePorts() 获取可用串口列表
|
||
const auto serialPortInfos = QSerialPortInfo::availablePorts();
|
||
for (const QSerialPortInfo &portInfo : serialPortInfos) {
|
||
portNames << portInfo.portName();
|
||
}
|
||
|
||
return portNames;
|
||
}
|
||
|
||
bool ParameterHandler::openPort(const QString &portName)
|
||
{
|
||
// 如果串口已打开,先关闭
|
||
if (m_serialPort->isOpen()) {
|
||
m_serialPort->close();
|
||
}
|
||
|
||
m_serialPort->setPortName(portName);
|
||
|
||
// 1. 尝试打开串口,以读写模式
|
||
if (!m_serialPort->open(QIODevice::ReadWrite)) {
|
||
QString errorMsg
|
||
= QString("无法打开串口 %1: %2").arg(portName).arg(m_serialPort->errorString());
|
||
qWarning() << errorMsg;
|
||
emit errorOccurred(errorMsg);
|
||
return false;
|
||
}
|
||
|
||
// --- 2. 串口配置(根据您的要求) ---
|
||
// 波特率: 115200
|
||
if (!m_serialPort->setBaudRate(QSerialPort::Baud115200)) {
|
||
qWarning() << "设置波特率失败:" << m_serialPort->errorString();
|
||
goto config_error;
|
||
}
|
||
|
||
// 数据位: 8 bit
|
||
if (!m_serialPort->setDataBits(QSerialPort::Data8)) {
|
||
qWarning() << "设置数据位失败:" << m_serialPort->errorString();
|
||
goto config_error;
|
||
}
|
||
|
||
// 校验位: 无校验 (No Parity)。 忽略“1bit校验位”而采用“无校验”
|
||
if (!m_serialPort->setParity(QSerialPort::NoParity)) {
|
||
qWarning() << "设置校验位失败:" << m_serialPort->errorString();
|
||
goto config_error;
|
||
}
|
||
|
||
// 停止位: 1 bit
|
||
if (!m_serialPort->setStopBits(QSerialPort::OneStop)) {
|
||
qWarning() << "设置停止位失败:" << m_serialPort->errorString();
|
||
goto config_error;
|
||
}
|
||
|
||
// 流量控制: 无流量控制 (No Flow Control)
|
||
if (!m_serialPort->setFlowControl(QSerialPort::NoFlowControl)) {
|
||
qWarning() << "设置流控制失败:" << m_serialPort->errorString();
|
||
goto config_error;
|
||
}
|
||
|
||
qDebug() << "串口" << portName << "成功打开并配置为 115200/8/N/1";
|
||
return true;
|
||
|
||
config_error:
|
||
// 配置失败时的错误处理
|
||
QString errMsg = QString("串口配置失败: %1").arg(m_serialPort->errorString());
|
||
qCritical() << errMsg;
|
||
m_serialPort->close(); // 配置失败则关闭串口
|
||
emit errorOccurred(errMsg);
|
||
return false;
|
||
}
|
||
|
||
void ParameterHandler::closePort()
|
||
{
|
||
if (m_serialPort->isOpen()) {
|
||
m_serialPort->close();
|
||
qDebug() << "串口" << m_serialPort->portName() << "已关闭";
|
||
}
|
||
}
|
||
|
||
bool ParameterHandler::isPortOpen() const
|
||
{
|
||
return m_serialPort->isOpen();
|
||
}
|
||
|
||
qint64 ParameterHandler::writeData(const QByteArray &data)
|
||
{
|
||
if (!m_serialPort->isOpen()) {
|
||
qWarning() << "写入失败: 串口未打开";
|
||
emit errorOccurred("写入失败: 串口未打开。");
|
||
return -1;
|
||
}
|
||
|
||
qint64 bytesWritten = m_serialPort->write(data);
|
||
|
||
if (bytesWritten == -1) {
|
||
// 写入操作本身出错
|
||
QString errorMsg = QString("写入数据时出错: %1").arg(m_serialPort->errorString());
|
||
qWarning() << errorMsg;
|
||
emit errorOccurred(errorMsg);
|
||
} else if (bytesWritten != data.size()) {
|
||
// 写入的数据量不完整
|
||
qWarning() << "警告: 仅写入了部分数据。期望:" << data.size() << "实际:" << bytesWritten;
|
||
} else {
|
||
qDebug() << "成功写入" << bytesWritten << "字节数据:" << data.toHex().toUpper();
|
||
}
|
||
|
||
// 等待数据发送完成,防止在主线程中阻塞太久,设置一个较短的超时
|
||
m_serialPort->waitForBytesWritten(10);
|
||
|
||
return bytesWritten;
|
||
}
|
||
|
||
QString ParameterHandler::portName() const
|
||
{
|
||
return m_serialPort->portName();
|
||
}
|
||
|
||
void ParameterHandler::handleReadyRead()
|
||
{
|
||
// 读取所有等待中的数据
|
||
QByteArray data = m_serialPort->readAll();
|
||
|
||
qDebug() << "接收到数据,字节数:" << data.size() << "数据(Hex):" << data.toHex().toUpper();
|
||
|
||
// 发出信号通知外部有新数据
|
||
emit dataReceived(data);
|
||
}
|
||
|
||
void ParameterHandler::handleError(QSerialPort::SerialPortError error)
|
||
{
|
||
// 忽略 NoError,只处理实际错误
|
||
if (error != QSerialPort::NoError && m_serialPort->isOpen()) {
|
||
QString errorString = m_serialPort->errorString();
|
||
qCritical() << "串口发生错误:" << errorString << "(错误码:" << error << ")";
|
||
|
||
// 发出信号通知外部错误
|
||
emit errorOccurred(errorString);
|
||
|
||
// 如果是资源错误(例如设备被拔出),则自动关闭串口
|
||
if (error == QSerialPort::ResourceError) {
|
||
qCritical() << "资源错误,自动关闭串口。";
|
||
m_serialPort->close();
|
||
}
|
||
}
|
||
}
|