/* 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 . */ #include "pagefirmware.h" #include "ui_pagefirmware.h" #include "widgets/helpdialog.h" #include "utility.h" #include #include #include 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()); }