修改文件换行符,修正轮班图元长度计算问题
This commit is contained in:
+353
-353
@@ -1,353 +1,353 @@
|
||||
#include "UpdateFPGA.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QLayout>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
UpdateFPGA::UpdateFPGA(const QString& pythonScriptPath, QWidget* parent)
|
||||
: QDialog(parent), m_PythonScriptPath(pythonScriptPath)
|
||||
{
|
||||
this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);
|
||||
this->setObjectName("UpdateFPGA");
|
||||
this->setStyleSheet("QDialog#UpdateFPGA{background-color:#FFFFFF;border:0px solid #D6D6D6;}");
|
||||
this->setWindowIcon(QPixmap(":/UpdateFPGA/logo.png"));
|
||||
// init();
|
||||
}
|
||||
|
||||
UpdateFPGA::~UpdateFPGA()
|
||||
{
|
||||
if (conversionProcess->state() == QProcess::Running)
|
||||
{
|
||||
conversionProcess->terminate();
|
||||
conversionProcess->waitForFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFPGA::init()
|
||||
{
|
||||
setWindowTitle(tr("升级工具"));
|
||||
setMinimumSize(600, 400);
|
||||
|
||||
QLabel* Logo = new QLabel(this);
|
||||
Logo->setFixedSize(67, 25);
|
||||
Logo->setPixmap(QPixmap(":/UpdateFPGA/logo.png"));
|
||||
Logo->setScaledContents(true);
|
||||
|
||||
m_Title = new QLabel(this);
|
||||
m_Title->setStyleSheet("font-family:\"Microsoft YaHei\";color:#333333;font-size:16px;");
|
||||
m_Title->setFixedHeight(25);
|
||||
m_Title->setText(tr("升级工具"));
|
||||
|
||||
m_CloseBtn = new QPushButton(this);
|
||||
m_CloseBtn->setFixedSize(25, 25);
|
||||
m_CloseBtn->setIconSize(QSize(20, 20));
|
||||
m_CloseBtn->setIcon(QPixmap(":/UpdateFPGA/close.svg"));
|
||||
m_CloseBtn->setCursor(Qt::PointingHandCursor);
|
||||
m_CloseBtn->setStyleSheet("QPushButton{background-color:#ffffff;border-radius:3px;border:none;}\
|
||||
QPushButton::hover{background-color:#EEEEEE;}");
|
||||
connect(m_CloseBtn, &QPushButton::released, this, [this]() {
|
||||
this->close();
|
||||
});
|
||||
|
||||
QHBoxLayout* hlayout = new QHBoxLayout;
|
||||
hlayout->addSpacing(5);
|
||||
hlayout->addWidget(Logo);
|
||||
hlayout->addWidget(m_Title);
|
||||
hlayout->addStretch();
|
||||
hlayout->addWidget(m_CloseBtn);
|
||||
hlayout->addSpacing(10);
|
||||
|
||||
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
m_UpdateButton = new QPushButton(tr("开始升级"), this);
|
||||
m_UpdateButton->setFixedHeight(30);
|
||||
|
||||
logLabel = new QLabel(tr("升级日志:"), this);
|
||||
logTextEdit = new QTextEdit(this);
|
||||
logTextEdit->setReadOnly(true);
|
||||
|
||||
mainLayout->addLayout(hlayout);
|
||||
mainLayout->addWidget(m_UpdateButton);
|
||||
mainLayout->addWidget(logLabel);
|
||||
mainLayout->addWidget(logTextEdit, 1);
|
||||
|
||||
conversionProcess = new QProcess(this);
|
||||
|
||||
connect(m_UpdateButton, &QPushButton::clicked, this, &UpdateFPGA::startUpdate);
|
||||
connect(conversionProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &UpdateFPGA::processFinished);
|
||||
connect(conversionProcess, &QProcess::errorOccurred, this, &UpdateFPGA::processError);
|
||||
connect(conversionProcess, &QProcess::readyReadStandardOutput, [this]() {
|
||||
logTextEdit->append(conversionProcess->readAllStandardOutput());
|
||||
}
|
||||
);
|
||||
connect(conversionProcess, &QProcess::readyReadStandardError, [this]() {
|
||||
logTextEdit->append(conversionProcess->readAllStandardError());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void UpdateFPGA::startUpdate()
|
||||
{
|
||||
m_CloseBtn->setEnabled(false);
|
||||
if (m_PythonScriptPath.isEmpty())
|
||||
{
|
||||
logTextEdit->append(tr("错误: 脚本为空"));
|
||||
return;
|
||||
}
|
||||
QFile inputFile(m_PythonScriptPath);
|
||||
if (!inputFile.exists())
|
||||
{
|
||||
logTextEdit->append(tr("错误: 脚本不存在 - %1").arg(m_PythonScriptPath));
|
||||
return;
|
||||
}
|
||||
|
||||
logTextEdit->append(tr("开始升级..."));
|
||||
logTextEdit->append(tr("文件:%1").arg(m_PythonScriptPath));
|
||||
|
||||
// 自动查找Ubuntu 22.04中可用的Python解释器
|
||||
QString pythonPath = findValidPythonInterpreter();
|
||||
if (pythonPath.isEmpty())
|
||||
{
|
||||
logTextEdit->append(tr("错误: 未找到可用的Python解释器或缺少serial模块"));
|
||||
m_CloseBtn->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
logTextEdit->append(tr("使用Python解释器: %1").arg(pythonPath));
|
||||
|
||||
QStringList pythonArgs;
|
||||
pythonArgs << m_PythonScriptPath;
|
||||
|
||||
conversionProcess->start(pythonPath, pythonArgs);
|
||||
m_UpdateButton->setEnabled(false); // 运行中禁用按钮
|
||||
}
|
||||
|
||||
// 查找并验证Ubuntu系统中有效的Python解释器
|
||||
QString UpdateFPGA::findValidPythonInterpreter()
|
||||
{
|
||||
QStringList pythonNames = { "python3", "python3.10", "python3.11", "python3.9" };
|
||||
QStringList searchPaths;
|
||||
|
||||
QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
searchPaths << home + "/.local/bin"
|
||||
<< home + "/.pyenv/shims"
|
||||
<< home + "/.virtualenvs/*/bin"
|
||||
<< home + "/venv/bin"
|
||||
<< home + "/env/bin";
|
||||
|
||||
|
||||
searchPaths << "/usr/bin"
|
||||
<< "/usr/local/bin"
|
||||
<< "/bin"
|
||||
<< "/opt/bin"
|
||||
<< "/snap/bin";
|
||||
|
||||
|
||||
QByteArray pathEnvBytes = qgetenv("PATH");
|
||||
QString pathEnvStr = QString::fromLocal8Bit(pathEnvBytes);
|
||||
QStringList pathEnv = pathEnvStr.split(QDir::listSeparator());
|
||||
foreach(const QString & path, pathEnv)
|
||||
{
|
||||
if (!searchPaths.contains(path))
|
||||
{
|
||||
searchPaths << path;
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历所有可能的组合查找有效解释器
|
||||
foreach(const QString & path, searchPaths)
|
||||
{
|
||||
foreach(const QString & name, pythonNames)
|
||||
{
|
||||
if (path.contains("*"))
|
||||
{
|
||||
QDir dir(path.left(path.indexOf("*")));
|
||||
if (dir.exists())
|
||||
{
|
||||
QStringList subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
foreach(const QString & subDir, subDirs)
|
||||
{
|
||||
QString fullPath = dir.filePath(subDir + "/bin/" + name);
|
||||
if (QFile::exists(fullPath) && isValidPythonWithSerial(fullPath))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString fullPath = QDir(path).filePath(name);
|
||||
if (QFile::exists(fullPath) && isValidPythonWithSerial(fullPath))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// 验证Python解释器是否包含serial模块
|
||||
bool UpdateFPGA::isValidPythonWithSerial(const QString& pythonPath)
|
||||
{
|
||||
// 检查Python是否可运行
|
||||
QProcess testProcess;
|
||||
testProcess.setProcessChannelMode(QProcess::MergedChannels); // 合并输出通道
|
||||
testProcess.start(pythonPath, { "-c", "import sys; sys.exit(0)" });
|
||||
|
||||
if (!testProcess.waitForFinished(3000) || testProcess.exitCode() != 0)
|
||||
{
|
||||
logTextEdit->append(tr("调试: 无效的Python解释器 - %1").arg(pythonPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否安装了serial模块
|
||||
testProcess.start(pythonPath, { "-c", "import serial; print('serial found: ' + serial.__version__)" });
|
||||
if (testProcess.waitForFinished(3000))
|
||||
{
|
||||
if (testProcess.exitCode() == 0)
|
||||
{
|
||||
QString output = testProcess.readAll().trimmed();
|
||||
logTextEdit->append(tr("调试: %1").arg(output));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logTextEdit->append(tr("调试: %1 缺少serial模块").arg(pythonPath));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logTextEdit->append(tr("调试: %1 响应超时").arg(pythonPath));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 根据错误码解析具体错误信息
|
||||
QString UpdateFPGA::getErrorDescription(int errorCode)
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 1: return tr("文件不存在(请检查FPGA固件文件路径)");
|
||||
case 2: return tr("无可用串口(请检查设备连接)");
|
||||
case 3: return tr("串口通信错误(可能是波特率不匹配或设备断开)");
|
||||
case 4: return tr("数据发送失败(尝试重新发送)");
|
||||
case 5: return tr("数据校验失败(数据传输过程中损坏)");
|
||||
case 6: return tr("接收数据不完整(可能是传输中断)");
|
||||
case 7: return tr("文件大小发送失败(协议握手错误)");
|
||||
case 8: return tr("文件内容发送失败(大文件传输超时)");
|
||||
case 9: return tr("未知错误(请查看详细日志)");
|
||||
default: return tr("未定义错误");
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFPGA::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (exitStatus == QProcess::NormalExit)
|
||||
{
|
||||
if (exitCode == 0) // 成功(错误码0)
|
||||
{
|
||||
logTextEdit->append(tr("升级成功!"));
|
||||
QMessageBox::information(this, tr("成功"), tr("FPGA升级完成,请重启QtUI"), QMessageBox::Ok);
|
||||
close(); // 成功后关闭界面
|
||||
emit upgradeFPGAFinished();
|
||||
}
|
||||
else // 有错误码的失败
|
||||
{
|
||||
QString errorDesc = getErrorDescription(exitCode);
|
||||
logTextEdit->append(tr("升级失败,错误码: %1,原因: %2").arg(exitCode).arg(errorDesc));
|
||||
|
||||
// 询问用户是否重试(针对可恢复错误)
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this,
|
||||
tr("升级失败"),
|
||||
tr("错误码%1: %2\n是否重新尝试升级?").arg(exitCode).arg(errorDesc),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
startUpdate(); // 重新运行
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
emit upgradeFPGAFinished();
|
||||
m_UpdateButton->setEnabled(true); // 允许手动再次尝试
|
||||
m_CloseBtn->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // 进程异常退出(无错误码)
|
||||
{
|
||||
logTextEdit->append(tr("升级进程异常退出,退出码: %1").arg(exitCode));
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this,
|
||||
tr("进程异常"),
|
||||
tr("升级过程中程序崩溃,是否重新尝试?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
startUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
emit upgradeFPGAFinished();
|
||||
m_UpdateButton->setEnabled(true);
|
||||
m_CloseBtn->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFPGA::processError(QProcess::ProcessError error)
|
||||
{
|
||||
QString errorMsg;
|
||||
switch (error)
|
||||
{
|
||||
case QProcess::FailedToStart:
|
||||
errorMsg = tr("错误: 无法启动脚本(可能是Python环境未配置)");
|
||||
break;
|
||||
case QProcess::Crashed:
|
||||
errorMsg = tr("错误: 脚本进程崩溃");
|
||||
break;
|
||||
case QProcess::Timedout:
|
||||
errorMsg = tr("错误: 启动超时(设备无响应)");
|
||||
break;
|
||||
case QProcess::WriteError:
|
||||
errorMsg = tr("错误: 写入进程失败(权限不足)");
|
||||
break;
|
||||
case QProcess::ReadError:
|
||||
errorMsg = tr("错误: 读取进程输出失败");
|
||||
break;
|
||||
case QProcess::UnknownError:
|
||||
default:
|
||||
errorMsg = tr("错误: 未知错误");
|
||||
break;
|
||||
}
|
||||
|
||||
logTextEdit->append(errorMsg);
|
||||
logTextEdit->append(tr("错误详情: ") + QString::fromLocal8Bit(conversionProcess->readAllStandardError()));
|
||||
|
||||
// 进程错误时也提示重试
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, tr("操作错误"), errorMsg + tr("\n是否重新尝试?"), QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
startUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
emit upgradeFPGAFinished();
|
||||
m_UpdateButton->setEnabled(true);
|
||||
m_CloseBtn->setEnabled(true);
|
||||
}
|
||||
}
|
||||
#include "UpdateFPGA.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QLayout>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
UpdateFPGA::UpdateFPGA(const QString& pythonScriptPath, QWidget* parent)
|
||||
: QDialog(parent), m_PythonScriptPath(pythonScriptPath)
|
||||
{
|
||||
this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);
|
||||
this->setObjectName("UpdateFPGA");
|
||||
this->setStyleSheet("QDialog#UpdateFPGA{background-color:#FFFFFF;border:0px solid #D6D6D6;}");
|
||||
this->setWindowIcon(QPixmap(":/UpdateFPGA/logo.png"));
|
||||
// init();
|
||||
}
|
||||
|
||||
UpdateFPGA::~UpdateFPGA()
|
||||
{
|
||||
if (conversionProcess->state() == QProcess::Running)
|
||||
{
|
||||
conversionProcess->terminate();
|
||||
conversionProcess->waitForFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFPGA::init()
|
||||
{
|
||||
setWindowTitle(tr("升级工具"));
|
||||
setMinimumSize(600, 400);
|
||||
|
||||
QLabel* Logo = new QLabel(this);
|
||||
Logo->setFixedSize(67, 25);
|
||||
Logo->setPixmap(QPixmap(":/UpdateFPGA/logo.png"));
|
||||
Logo->setScaledContents(true);
|
||||
|
||||
m_Title = new QLabel(this);
|
||||
m_Title->setStyleSheet("font-family:\"Microsoft YaHei\";color:#333333;font-size:16px;");
|
||||
m_Title->setFixedHeight(25);
|
||||
m_Title->setText(tr("升级工具"));
|
||||
|
||||
m_CloseBtn = new QPushButton(this);
|
||||
m_CloseBtn->setFixedSize(25, 25);
|
||||
m_CloseBtn->setIconSize(QSize(20, 20));
|
||||
m_CloseBtn->setIcon(QPixmap(":/UpdateFPGA/close.svg"));
|
||||
m_CloseBtn->setCursor(Qt::PointingHandCursor);
|
||||
m_CloseBtn->setStyleSheet("QPushButton{background-color:#ffffff;border-radius:3px;border:none;}\
|
||||
QPushButton::hover{background-color:#EEEEEE;}");
|
||||
connect(m_CloseBtn, &QPushButton::released, this, [this]() {
|
||||
this->close();
|
||||
});
|
||||
|
||||
QHBoxLayout* hlayout = new QHBoxLayout;
|
||||
hlayout->addSpacing(5);
|
||||
hlayout->addWidget(Logo);
|
||||
hlayout->addWidget(m_Title);
|
||||
hlayout->addStretch();
|
||||
hlayout->addWidget(m_CloseBtn);
|
||||
hlayout->addSpacing(10);
|
||||
|
||||
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
m_UpdateButton = new QPushButton(tr("开始升级"), this);
|
||||
m_UpdateButton->setFixedHeight(30);
|
||||
|
||||
logLabel = new QLabel(tr("升级日志:"), this);
|
||||
logTextEdit = new QTextEdit(this);
|
||||
logTextEdit->setReadOnly(true);
|
||||
|
||||
mainLayout->addLayout(hlayout);
|
||||
mainLayout->addWidget(m_UpdateButton);
|
||||
mainLayout->addWidget(logLabel);
|
||||
mainLayout->addWidget(logTextEdit, 1);
|
||||
|
||||
conversionProcess = new QProcess(this);
|
||||
|
||||
connect(m_UpdateButton, &QPushButton::clicked, this, &UpdateFPGA::startUpdate);
|
||||
connect(conversionProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &UpdateFPGA::processFinished);
|
||||
connect(conversionProcess, &QProcess::errorOccurred, this, &UpdateFPGA::processError);
|
||||
connect(conversionProcess, &QProcess::readyReadStandardOutput, [this]() {
|
||||
logTextEdit->append(conversionProcess->readAllStandardOutput());
|
||||
}
|
||||
);
|
||||
connect(conversionProcess, &QProcess::readyReadStandardError, [this]() {
|
||||
logTextEdit->append(conversionProcess->readAllStandardError());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void UpdateFPGA::startUpdate()
|
||||
{
|
||||
m_CloseBtn->setEnabled(false);
|
||||
if (m_PythonScriptPath.isEmpty())
|
||||
{
|
||||
logTextEdit->append(tr("错误: 脚本为空"));
|
||||
return;
|
||||
}
|
||||
QFile inputFile(m_PythonScriptPath);
|
||||
if (!inputFile.exists())
|
||||
{
|
||||
logTextEdit->append(tr("错误: 脚本不存在 - %1").arg(m_PythonScriptPath));
|
||||
return;
|
||||
}
|
||||
|
||||
logTextEdit->append(tr("开始升级..."));
|
||||
logTextEdit->append(tr("文件:%1").arg(m_PythonScriptPath));
|
||||
|
||||
// 自动查找Ubuntu 22.04中可用的Python解释器
|
||||
QString pythonPath = findValidPythonInterpreter();
|
||||
if (pythonPath.isEmpty())
|
||||
{
|
||||
logTextEdit->append(tr("错误: 未找到可用的Python解释器或缺少serial模块"));
|
||||
m_CloseBtn->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
logTextEdit->append(tr("使用Python解释器: %1").arg(pythonPath));
|
||||
|
||||
QStringList pythonArgs;
|
||||
pythonArgs << m_PythonScriptPath;
|
||||
|
||||
conversionProcess->start(pythonPath, pythonArgs);
|
||||
m_UpdateButton->setEnabled(false); // 运行中禁用按钮
|
||||
}
|
||||
|
||||
// 查找并验证Ubuntu系统中有效的Python解释器
|
||||
QString UpdateFPGA::findValidPythonInterpreter()
|
||||
{
|
||||
QStringList pythonNames = { "python3", "python3.10", "python3.11", "python3.9" };
|
||||
QStringList searchPaths;
|
||||
|
||||
QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
searchPaths << home + "/.local/bin"
|
||||
<< home + "/.pyenv/shims"
|
||||
<< home + "/.virtualenvs/*/bin"
|
||||
<< home + "/venv/bin"
|
||||
<< home + "/env/bin";
|
||||
|
||||
|
||||
searchPaths << "/usr/bin"
|
||||
<< "/usr/local/bin"
|
||||
<< "/bin"
|
||||
<< "/opt/bin"
|
||||
<< "/snap/bin";
|
||||
|
||||
|
||||
QByteArray pathEnvBytes = qgetenv("PATH");
|
||||
QString pathEnvStr = QString::fromLocal8Bit(pathEnvBytes);
|
||||
QStringList pathEnv = pathEnvStr.split(QDir::listSeparator());
|
||||
foreach(const QString & path, pathEnv)
|
||||
{
|
||||
if (!searchPaths.contains(path))
|
||||
{
|
||||
searchPaths << path;
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历所有可能的组合查找有效解释器
|
||||
foreach(const QString & path, searchPaths)
|
||||
{
|
||||
foreach(const QString & name, pythonNames)
|
||||
{
|
||||
if (path.contains("*"))
|
||||
{
|
||||
QDir dir(path.left(path.indexOf("*")));
|
||||
if (dir.exists())
|
||||
{
|
||||
QStringList subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
foreach(const QString & subDir, subDirs)
|
||||
{
|
||||
QString fullPath = dir.filePath(subDir + "/bin/" + name);
|
||||
if (QFile::exists(fullPath) && isValidPythonWithSerial(fullPath))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString fullPath = QDir(path).filePath(name);
|
||||
if (QFile::exists(fullPath) && isValidPythonWithSerial(fullPath))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// 验证Python解释器是否包含serial模块
|
||||
bool UpdateFPGA::isValidPythonWithSerial(const QString& pythonPath)
|
||||
{
|
||||
// 检查Python是否可运行
|
||||
QProcess testProcess;
|
||||
testProcess.setProcessChannelMode(QProcess::MergedChannels); // 合并输出通道
|
||||
testProcess.start(pythonPath, { "-c", "import sys; sys.exit(0)" });
|
||||
|
||||
if (!testProcess.waitForFinished(3000) || testProcess.exitCode() != 0)
|
||||
{
|
||||
logTextEdit->append(tr("调试: 无效的Python解释器 - %1").arg(pythonPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否安装了serial模块
|
||||
testProcess.start(pythonPath, { "-c", "import serial; print('serial found: ' + serial.__version__)" });
|
||||
if (testProcess.waitForFinished(3000))
|
||||
{
|
||||
if (testProcess.exitCode() == 0)
|
||||
{
|
||||
QString output = testProcess.readAll().trimmed();
|
||||
logTextEdit->append(tr("调试: %1").arg(output));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logTextEdit->append(tr("调试: %1 缺少serial模块").arg(pythonPath));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logTextEdit->append(tr("调试: %1 响应超时").arg(pythonPath));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 根据错误码解析具体错误信息
|
||||
QString UpdateFPGA::getErrorDescription(int errorCode)
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 1: return tr("文件不存在(请检查FPGA固件文件路径)");
|
||||
case 2: return tr("无可用串口(请检查设备连接)");
|
||||
case 3: return tr("串口通信错误(可能是波特率不匹配或设备断开)");
|
||||
case 4: return tr("数据发送失败(尝试重新发送)");
|
||||
case 5: return tr("数据校验失败(数据传输过程中损坏)");
|
||||
case 6: return tr("接收数据不完整(可能是传输中断)");
|
||||
case 7: return tr("文件大小发送失败(协议握手错误)");
|
||||
case 8: return tr("文件内容发送失败(大文件传输超时)");
|
||||
case 9: return tr("未知错误(请查看详细日志)");
|
||||
default: return tr("未定义错误");
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFPGA::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (exitStatus == QProcess::NormalExit)
|
||||
{
|
||||
if (exitCode == 0) // 成功(错误码0)
|
||||
{
|
||||
logTextEdit->append(tr("升级成功!"));
|
||||
QMessageBox::information(this, tr("成功"), tr("FPGA升级完成,请重启QtUI"), QMessageBox::Ok);
|
||||
close(); // 成功后关闭界面
|
||||
emit upgradeFPGAFinished();
|
||||
}
|
||||
else // 有错误码的失败
|
||||
{
|
||||
QString errorDesc = getErrorDescription(exitCode);
|
||||
logTextEdit->append(tr("升级失败,错误码: %1,原因: %2").arg(exitCode).arg(errorDesc));
|
||||
|
||||
// 询问用户是否重试(针对可恢复错误)
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this,
|
||||
tr("升级失败"),
|
||||
tr("错误码%1: %2\n是否重新尝试升级?").arg(exitCode).arg(errorDesc),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
startUpdate(); // 重新运行
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
emit upgradeFPGAFinished();
|
||||
m_UpdateButton->setEnabled(true); // 允许手动再次尝试
|
||||
m_CloseBtn->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // 进程异常退出(无错误码)
|
||||
{
|
||||
logTextEdit->append(tr("升级进程异常退出,退出码: %1").arg(exitCode));
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this,
|
||||
tr("进程异常"),
|
||||
tr("升级过程中程序崩溃,是否重新尝试?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
startUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
emit upgradeFPGAFinished();
|
||||
m_UpdateButton->setEnabled(true);
|
||||
m_CloseBtn->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFPGA::processError(QProcess::ProcessError error)
|
||||
{
|
||||
QString errorMsg;
|
||||
switch (error)
|
||||
{
|
||||
case QProcess::FailedToStart:
|
||||
errorMsg = tr("错误: 无法启动脚本(可能是Python环境未配置)");
|
||||
break;
|
||||
case QProcess::Crashed:
|
||||
errorMsg = tr("错误: 脚本进程崩溃");
|
||||
break;
|
||||
case QProcess::Timedout:
|
||||
errorMsg = tr("错误: 启动超时(设备无响应)");
|
||||
break;
|
||||
case QProcess::WriteError:
|
||||
errorMsg = tr("错误: 写入进程失败(权限不足)");
|
||||
break;
|
||||
case QProcess::ReadError:
|
||||
errorMsg = tr("错误: 读取进程输出失败");
|
||||
break;
|
||||
case QProcess::UnknownError:
|
||||
default:
|
||||
errorMsg = tr("错误: 未知错误");
|
||||
break;
|
||||
}
|
||||
|
||||
logTextEdit->append(errorMsg);
|
||||
logTextEdit->append(tr("错误详情: ") + QString::fromLocal8Bit(conversionProcess->readAllStandardError()));
|
||||
|
||||
// 进程错误时也提示重试
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, tr("操作错误"), errorMsg + tr("\n是否重新尝试?"), QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
startUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
emit upgradeFPGAFinished();
|
||||
m_UpdateButton->setEnabled(true);
|
||||
m_CloseBtn->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user