Files
CuboBmsTool/pages/pagefirmware.cpp
2022-08-01 21:53:36 +03:00

369 lines
13 KiB
C++

/*
Original copyright 2018 Benjamin Vedder benjamin@vedder.se and the VESC Tool project ( https://github.com/vedderb/vesc_tool )
Forked to:
Copyright 2018 Danny Bokma github@diebie.nl (https://github.com/DieBieEngineering/DieBieMS-Tool)
Now forked to:
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me (https://github.com/EnnoidMe/ENNOID-BMS-Tool)
This file is part of ENNOID-BMS Tool.
ENNOID-BMS Tool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ENNOID-BMS Tool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pagefirmware.h"
#include "ui_pagefirmware.h"
#include "widgets/helpdialog.h"
#include "utility.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QDirIterator>
PageFirmware::PageFirmware(QWidget *parent) :
QWidget(parent),
ui(new Ui::PageFirmware)
{
ui->setupUi(this);
layout()->setContentsMargins(0, 0, 0, 0);
ui->cancelButton->setEnabled(false);
mDieBieMS = 0;
updateHwList();
updateBlList();
connect(ui->hwList, SIGNAL(currentRowChanged(int)),
this, SLOT(updateFwList()));
connect(ui->showNonDefaultBox, SIGNAL(toggled(bool)),
this, SLOT(updateFwList()));
}
PageFirmware::~PageFirmware()
{
delete ui;
}
BMSInterface *PageFirmware::bms() const
{
return mDieBieMS;
}
void PageFirmware::setDieBieMS(BMSInterface *dieBieMS)
{
mDieBieMS = dieBieMS;
if (mDieBieMS) {
ui->display->setText(mDieBieMS->commands()->getFirmwareUploadStatus());
QStringList fws = mDieBieMS->getSupportedFirmwares();
QString str;
for (int i = 0;i < fws.size();i++) {
str.append(fws.at(i));
if (i < (fws.size() - 1)) {
str.append(", ");
}
}
ui->supportedLabel->setText(str);
connect(mDieBieMS, SIGNAL(fwUploadStatus(QString,double,bool)),
this, SLOT(fwUploadStatus(QString,double,bool)));
connect(mDieBieMS->commands(), SIGNAL(fwVersionReceived(int,int,QString,QByteArray)),
this, SLOT(fwVersionReceived(int,int,QString,QByteArray)));
}
}
void PageFirmware::fwUploadStatus(const QString &status, double progress, bool isOngoing)
{
if (isOngoing) {
ui->display->setText(tr("%1 (%2 %)").
arg(status).
arg(progress * 100, 0, 'f', 1));
} else {
ui->display->setText(status);
}
ui->display->setValue(progress * 100.0);
ui->uploadButton->setEnabled(!isOngoing);
ui->cancelButton->setEnabled(isOngoing);
}
void PageFirmware::fwVersionReceived(int major, int minor, QString hw, QByteArray uuid)
{
QString fwStr;
QString strUuid = Utility::uuid2Str(uuid, true);
if (!strUuid.isEmpty()) {
fwStr += ", UUID: " + strUuid;
}
if (major >= 0) {
fwStr.sprintf("Fw: %d.%d", major, minor);
if (!hw.isEmpty()) {
fwStr += ", Hw: " + hw;
}
if (!strUuid.isEmpty()) {
fwStr += "\n" + strUuid;
}
}
ui->currentLabel->setText(fwStr);
updateHwList(hw);
updateBlList(hw);
update();
}
void PageFirmware::updateHwList(QString hw)
{
ui->hwList->clear();
QDirIterator it("://res/firmwares");
while (it.hasNext()) {
QFileInfo fi(it.next());
QStringList names = fi.fileName().split("_o_");
if (fi.isDir() && (hw.isEmpty() || names.contains(hw, Qt::CaseInsensitive))) {
QListWidgetItem *item = new QListWidgetItem;
QString name = names.at(0);
for(int i = 1;i < names.size();i++) {
name += " & " + names.at(i);
}
item->setText(name);
item->setData(Qt::UserRole, fi.absoluteFilePath());
ui->hwList->insertItem(ui->hwList->count(), item);
}
}
if (ui->hwList->count() > 0) {
ui->hwList->setCurrentRow(0);
}
updateFwList();
}
void PageFirmware::updateFwList()
{
ui->fwList->clear();
QListWidgetItem *item = ui->hwList->currentItem();
if (item != 0) {
QString hw = item->data(Qt::UserRole).toString();
QDirIterator it(hw);
while (it.hasNext()) {
QFileInfo fi(it.next());
if (ui->showNonDefaultBox->isChecked() ||
fi.fileName().toLower() == "ennoid-bms.bin") {
QListWidgetItem *item = new QListWidgetItem;
item->setText(fi.fileName());
item->setData(Qt::UserRole, fi.absoluteFilePath());
ui->fwList->insertItem(ui->fwList->count(), item);
}
}
}
if (ui->fwList->count() > 0) {
ui->fwList->setCurrentRow(0);
}
}
void PageFirmware::updateBlList(QString hw)
{
ui->blList->clear();
QDirIterator it("://res/bootloaders");
while (it.hasNext()) {
QFileInfo fi(it.next());
QStringList names = fi.fileName().replace(".bin", "").split("_o_");
if (!fi.isDir() && (hw.isEmpty() || names.contains(hw, Qt::CaseInsensitive))) {
QListWidgetItem *item = new QListWidgetItem;
QString name = names.at(0);
for(int i = 1;i < names.size();i++) {
name += " & " + names.at(i);
}
item->setText(name);
item->setData(Qt::UserRole, fi.absoluteFilePath());
ui->blList->insertItem(ui->blList->count(), item);
}
}
if (ui->blList->count() == 0) {
QFileInfo generic("://res/bootloaders/generic.bin");
if (generic.exists()) {
QListWidgetItem *item = new QListWidgetItem;
item->setText("generic");
item->setData(Qt::UserRole, generic.absoluteFilePath());
ui->blList->insertItem(ui->blList->count(), item);
}
}
if (ui->blList->count() > 0) {
ui->blList->setCurrentRow(0);
}
}
void PageFirmware::on_chooseButton_clicked()
{
QString filename = QFileDialog::getOpenFileName(this,
tr("Choose Firmware File"), ".",
tr("Binary files (*.bin)"));
if (filename.isNull()) {
return;
}
ui->fwEdit->setText(filename);
}
void PageFirmware::on_uploadButton_clicked()
{
if (mDieBieMS) {
if (!mDieBieMS->isPortConnected()) {
QMessageBox::critical(this,
tr("Connection Error"),
tr("The ENNOID-BMS is not connected. Please connect it."));
return;
}
QFile file;
if (ui->fwTabWidget->currentIndex() == 0) {
QListWidgetItem *item = ui->fwList->currentItem();
if (item) {
file.setFileName(item->data(Qt::UserRole).toString());
} else {
if (ui->hwList->count() == 0) {
QMessageBox::warning(this,
tr("Upload Error"),
tr("This version of DieBie does not include any firmware "
"for your hardware version. You can either "
"upload a custom file or look for a later version of ENNOID-BMS "
"Tool that might support your hardware."));
} else {
QMessageBox::warning(this,
tr("Upload Error"),
tr("No firmware is selected."));
}
return;
}
} else if (ui->fwTabWidget->currentIndex() == 1) {
file.setFileName(ui->fwEdit->text());
QFileInfo fileInfo(file.fileName());
if (!(fileInfo.fileName().startsWith("ENNOID")) || !fileInfo.fileName().endsWith(".bin")) {
QMessageBox::critical(this,tr("Upload Error"),tr("The selected file name seems to be invalid."));
return;
}
} else {
QListWidgetItem *item = ui->blList->currentItem();
if (item) {
file.setFileName(item->data(Qt::UserRole).toString());
} else {
if (ui->blList->count() == 0) {
QMessageBox::warning(this,
tr("Upload Error"),
tr("This version of ENNOID-BMS does not include any bootloader "
"for your hardware version."));
} else {
QMessageBox::warning(this,
tr("Upload Error"),
tr("No bootloader is selected."));
}
return;
}
}
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this,
tr("Upload Error"),
tr("Could not open file. Make sure that the path is valid."));
return;
}
if (file.size() > 400000) {
QMessageBox::critical(this,
tr("Upload Error"),
tr("The selected file is too large to be a firmware."));
return;
}
QMessageBox::StandardButton reply;
bool isBootloader = false;
if (ui->fwTabWidget->currentIndex() == 0 && ui->hwList->count() == 1) {
reply = QMessageBox::warning(this,
tr("Warning"),
tr("Uploading new firmware will clear all settings on your ENNOID-BMS "
"and you have to do the configuration again. Do you want to "
"continue?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
} else if ((ui->fwTabWidget->currentIndex() == 0 && ui->hwList->count() > 1) || ui->fwTabWidget->currentIndex() == 1) {
reply = QMessageBox::warning(this,
tr("Warning"),
tr("Uploading firmware for the wrong hardware version "
"WILL damage the ENNOID-BMS for sure. Are you sure that you have "
"chosen the correct hardware version?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
} else if (ui->fwTabWidget->currentIndex() == 2) {
reply = QMessageBox::warning(this,
tr("Warning"),
tr("This will attempt to upload a bootloader to the connected ENNOID-BMS. "
"If the connected ENNOID-BMS already has a bootloader this will destroy "
"the bootloader and firmware updates cannot be done anymore. Do "
"you want to continue?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
isBootloader = true;
} else {
reply = QMessageBox::No;
}
if (reply == QMessageBox::Yes) {
QByteArray data = file.readAll();
mDieBieMS->commands()->startFirmwareUpload(data, isBootloader);
QMessageBox::warning(this,
tr("Warning"),
tr("The firmware upload is now ongoing. After the upload has finished you must wait at least "
"10 seconds before unplugging power. Otherwise the firmware will get corrupted and your "
"ENNOID-BMS will become bricked. If that happens you need a SWD programmer to recover it."));
}
}
}
void PageFirmware::on_readVersionButton_clicked()
{
if (mDieBieMS) {
mDieBieMS->commands()->getFwVersion();
}
}
void PageFirmware::on_cancelButton_clicked()
{
if (mDieBieMS) {
mDieBieMS->commands()->cancelFirmwareUpload();
}
}
void PageFirmware::on_changelogButton_clicked()
{
HelpDialog::showHelp(this, "Firmware Changelog", Utility::fwChangeLog());
}