/* Copyright 2017 Benjamin Vedder benjamin@vedder.se This file is part of VESC Tool. VESC 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. VESC 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 . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import Ennoid.bmsinterface 1.0 import Ennoid.commands 1.0 import Ennoid.configparams 1.0 import Ennoid.fwhelper 1.0 import Ennoid.utility 1.0 Item { property Commands mCommands: VescIf.commands() property ConfigParams mInfoConf: VescIf.infoConfig() FwHelper { id: fwHelper } ColumnLayout { anchors.fill: parent spacing: 0 RowLayout { Layout.fillHeight: true Layout.fillWidth: true spacing: 0 Rectangle { color: "#4f4f4f" width: 16 Layout.fillHeight: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter PageIndicator { id: indicator count: swipeView.count currentIndex: swipeView.currentIndex Layout.preferredWidth: 15 Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter rotation: 90 } } SwipeView { id: swipeView enabled: true clip: true Layout.fillWidth: true Layout.fillHeight: true Layout.rightMargin: 15 orientation: Qt.Vertical Page { ColumnLayout { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 Rectangle { Layout.fillWidth: true height: 30; border.width: 0 gradient: Gradient { GradientStop { position: 0.00; color: "#002dcbff"; } GradientStop { position: 0.3; color: "#80014cb2"; } GradientStop { position: 0.7; color: "#80014cb2"; } GradientStop { position: 1.00; color: "#000dc3ff"; } } border.color: "#00000000" Text { anchors.centerIn: parent color: "white" text: "Included Files" font.bold: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } Item { // Spacer Layout.fillWidth: true Layout.fillHeight: true } Text { color: "white" Layout.fillWidth: true height: 30; text: "Hardware" horizontalAlignment: Text.AlignHCenter } ComboBox { id: hwBox Layout.preferredHeight: 48 Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter textRole: "key" model: ListModel { id: hwItems } Component.onCompleted: { updateHw("") } onCurrentIndexChanged: { if (hwItems.rowCount() === 0) { return } var fws = fwHelper.getFirmwares(hwItems.get(hwBox.currentIndex).value) fwItems.clear() for (var name in fws) { if (name.toLowerCase().indexOf("ENNOID-BMS.bin") !== -1) { fwItems.insert(0, { key: name, value: fws[name] }) } else { fwItems.append({ key: name, value: fws[name] }) } } fwBox.currentIndex = 0 } } Text { color: "white" Layout.fillWidth: true height: 30; text: "Firmware" horizontalAlignment: Text.AlignHCenter } ComboBox { id: fwBox Layout.preferredHeight: 48 Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter textRole: "key" model: ListModel { id: fwItems } } Button { text: "Show Changelog" Layout.fillWidth: true onClicked: { VescIf.emitMessageDialog( "Firmware Changelog", Utility.fwChangeLog(), true) } } Item { // Spacer Layout.fillWidth: true Layout.fillHeight: true } } } Page { ColumnLayout { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 Rectangle { Layout.fillWidth: true height: 30; border.width: 0 gradient: Gradient { GradientStop { position: 0.00; color: "#002dcbff"; } GradientStop { position: 0.3; color: "#80014cb2"; } GradientStop { position: 0.7; color: "#80014cb2"; } GradientStop { position: 1; color: "#000dc3ff"; } } border.color: "#00000000" Text { anchors.centerIn: parent color: "white" text: "Custom File" font.bold: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } Item { // Spacer Layout.fillWidth: true Layout.fillHeight: true } TextInput { color: "white" id: customFwText Layout.fillWidth: true } Button { text: "Choose File..." Layout.fillWidth: true onClicked: { if (Utility.requestFilePermission()) { filePicker.enabled = true filePicker.visible = true } else { VescIf.emitMessageDialog( "File Permissions", "Unable to request file system permission.", false, false) } } } Item { // Spacer Layout.fillWidth: true Layout.fillHeight: true } } FilePicker { id: filePicker anchors.fill: parent showDotAndDotDot: true nameFilters: "*.bin" visible: false enabled: false onFileSelected: { customFwText.text = currentFolder() + "/" + fileName visible = false enabled = false } } } Page { ColumnLayout { anchors.fill: parent anchors.leftMargin: 10 anchors.rightMargin: 10 Rectangle { Layout.fillWidth: true height: 30; border.width: 0 gradient: Gradient { GradientStop { position: 0.00; color: "#002dcbff"; } GradientStop { position: 0.3; color: "#80014cb2"; } GradientStop { position: 0.7; color: "#80014cb2"; } GradientStop { position: 1.00; color: "#000dc3ff" } } border.color: "#00000000" Text { anchors.centerIn: parent color: "white" text: "Bootloader" font.bold: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } Item { // Spacer Layout.fillWidth: true Layout.fillHeight: true } Text { color: "white" Layout.fillWidth: true height: 30; text: "Hardware" horizontalAlignment: Text.AlignHCenter } ComboBox { id: blBox Layout.preferredHeight: 48 Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter textRole: "key" model: ListModel { id: blItems } Component.onCompleted: { updateBl("") } } Item { // Spacer Layout.fillWidth: true Layout.fillHeight: true } } } } } Rectangle { Layout.fillWidth: true height: asd.implicitHeight + 20 color: "#414141" ColumnLayout { id: asd anchors.fill: parent anchors.margins: 10 Text { Layout.fillWidth: true color: "white" id: uploadText text: qsTr("Not Uploading") horizontalAlignment: Text.AlignHCenter } ProgressBar { id: uploadProgress Layout.fillWidth: true } RowLayout { Layout.fillWidth: true Button { id: uploadButton text: qsTr("Upload") Layout.fillWidth: true onClicked: { if (!VescIf.isPortConnected()) { VescIf.emitMessageDialog( "Connection Error", "The BMS is not connected. Please open a connection.", false) return } if (swipeView.currentIndex == 0) { if (fwItems.rowCount() === 0) { VescIf.emitMessageDialog( "Upload Error", "This version of ENNOID-BMS Tool 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.", false) return; } if (hwItems.rowCount() === 1) { uploadDialog.title = "Warning" uploadDialogLabel.text = "Uploading new firmware will clear all settings on your ENNOID-BMS " + "and you have to do the configuration again. Do you want to " + "continue?" uploadDialog.open() } else { uploadDialog.title = "Warning" uploadDialogLabel.text = "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?" uploadDialog.open() } } else if (swipeView.currentIndex == 1) { if (customFwText.text.length > 0) { uploadDialog.title = "Warning" uploadDialogLabel.text = "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?" uploadDialog.open() } else { VescIf.emitMessageDialog( "Error", "Please select a file", false, false) } } else if (swipeView.currentIndex == 2) { if (blItems.rowCount() === 0) { VescIf.emitMessageDialog( "Upload Error", "This version of ENNOID-BMS Tool does not include any bootloader " + "for your hardware version.", false) return; } uploadDialog.title = "Warning" uploadDialogLabel.text = "This will attempt to upload a bootloader to the connected VESC. " + "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?" uploadDialog.open() } } } Button { id: cancelButton text: qsTr("Cancel") Layout.fillWidth: true enabled: false onClicked: { mCommands.cancelFirmwareUpload() } } } Text { Layout.fillWidth: true id: versionText color: "#e0e0e0" text: "FW : \n" + "HW : \n" + "UUID : " font.family: "DejaVu Sans Mono" verticalAlignment: Text.AlignVCenter } } } } Dialog { id: uploadDialog standardButtons: Dialog.Ok | Dialog.Cancel modal: true focus: true width: parent.width - 20 closePolicy: Popup.CloseOnEscape x: (parent.width - width) / 2 y: (parent.height - height) / 2 Text { color: "#ffffff" id: uploadDialogLabel verticalAlignment: Text.AlignVCenter anchors.fill: parent wrapMode: Text.WordWrap } onAccepted: { if (swipeView.currentIndex == 0) { fwHelper.uploadFirmware(fwItems.get(fwBox.currentIndex).value, VescIf, false, false) } else if (swipeView.currentIndex == 1) { fwHelper.uploadFirmware(customFwText.text, VescIf, false, true) } else if (swipeView.currentIndex == 2) { fwHelper.uploadFirmware(blItems.get(blBox.currentIndex).value, VescIf, true, false) } } } function updateHw(hw) { var hws = fwHelper.getHardwares(hw) hwItems.clear() for (var name in hws) { if (name.indexOf("412") !== -1) { hwItems.insert(0, { key: name, value: hws[name] }) } else { hwItems.append({ key: name, value: hws[name] }) } } hwBox.currentIndex = 0 } function updateBl(hw) { var bls = fwHelper.getBootloaders(hw) blItems.clear() for (var name in bls) { if (name.indexOf("412") !== -1) { blItems.insert(0, { key: name, value: bls[name] }) } else { blItems.append({ key: name, value: bls[name] }) } } blBox.currentIndex = 0 } Connections { target: VescIf onFwUploadStatus: { if (isOngoing) { uploadText.text = status + " (" + parseFloat(progress * 100.0).toFixed(2) + " %)" } else { uploadText.text = status } uploadProgress.value = progress uploadButton.enabled = !isOngoing cancelButton.enabled = isOngoing } } Connections { target: mCommands onFwVersionReceived: { updateHw(hw) updateBl(hw) versionText.text = "FW : " + major + "." + minor + "\n" + "HW : " + hw + "\n" + "UUID : " + Utility.uuid2Str(uuid, false) } } }