修改文件换行符,修正轮班图元长度计算问题

This commit is contained in:
2026-08-19 11:55:10 +08:00
parent 176b53b654
commit a274b75705
116 changed files with 68711 additions and 68660 deletions
+353 -353
View File
@@ -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);
}
}