From fdaca40a06c2ec6ba1a75d35d3c4cea7df14b1b6 Mon Sep 17 00:00:00 2001 From: Yury Shuvakin Date: Fri, 26 Aug 2022 13:24:00 +0300 Subject: [PATCH] Implemented writing configuration settings to the board. Added various fixes for configuration fields --- commands.h | 2 +- configparams.h | 11 +- qml/MainWindow.qml | 35 ++++-- qml/Screens/AkbMonitorScreen.qml | 3 +- qml/Screens/BmsSettingsScreen.qml | 192 +++++++++++++++++++++--------- 5 files changed, 169 insertions(+), 74 deletions(-) diff --git a/commands.h b/commands.h index e010ea0..cdd0cca 100644 --- a/commands.h +++ b/commands.h @@ -51,7 +51,7 @@ public: Q_INVOKABLE QString getFirmwareUploadStatus(); Q_INVOKABLE void cancelFirmwareUpload(); void checkbmsConfig(); - void storeBMSConfig(); + Q_INVOKABLE void storeBMSConfig(); Q_INVOKABLE void emitEmptyValues(); Q_INVOKABLE void emitEmptySetupValues(); diff --git a/configparams.h b/configparams.h index ddebf8d..84e355b 100644 --- a/configparams.h +++ b/configparams.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include "configparam.h" @@ -50,7 +51,7 @@ public: Q_INVOKABLE bool hasParam(const QString &name); ConfigParam *getParam(const QString &name); ConfigParam getParamCopy(const QString &name) const; - void setParamValue(const QString &name, QVariant val); + Q_INVOKABLE void setParamValue(const QString &name, QVariant val); Q_INVOKABLE bool isParamDouble(const QString &name); Q_INVOKABLE bool isParamInt(const QString &name); @@ -97,12 +98,12 @@ public: void getXML(QXmlStreamWriter &stream, QString configName); bool setXML(QXmlStreamReader &stream, QString configName); - bool saveXml(QString fileName, QString configName); - bool loadXml(QString fileName, QString configName); + Q_INVOKABLE bool saveXml(QString fileName, QString configName); + Q_INVOKABLE bool loadXml(QString fileName, QString configName); QString xmlStatus(); - Q_INVOKABLE void getParamsXML(QXmlStreamWriter &stream); - Q_INVOKABLE bool setParamsXML(QXmlStreamReader &stream); + void getParamsXML(QXmlStreamWriter &stream); + bool setParamsXML(QXmlStreamReader &stream); Q_INVOKABLE bool saveParamsXml(QString fileName); Q_INVOKABLE bool loadParamsXml(QString fileName); diff --git a/qml/MainWindow.qml b/qml/MainWindow.qml index 2daeacb..3c458ce 100644 --- a/qml/MainWindow.qml +++ b/qml/MainWindow.qml @@ -36,13 +36,13 @@ ApplicationWindow { Image { source: "qrc:/Icons/cubo-logo.svg" - sourceSize.width: pane.minimized ? 80 : 115 - sourceSize.height: pane.minimized ? 80 : 115 + sourceSize.width: pane.minimized ? 70 : 115 + sourceSize.height: pane.minimized ? 70 : 115 Layout.alignment: Qt.AlignCenter } Item { - Layout.preferredHeight: pane.minimized ? 75 : 40 + Layout.preferredHeight: pane.minimized ? 85 : 40 } ItemDelegate { @@ -255,7 +255,8 @@ ApplicationWindow { } Controls.ContentLabel { - text: qsTr("V1.3") + id: firmwareLabel + text: "-" Layout.alignment: Qt.AlignRight } @@ -269,7 +270,8 @@ ApplicationWindow { } Controls.SubtitleLabel { - text: qsTr("9999997") + id: serialLabel + text: "-" Layout.alignment: Qt.AlignRight } @@ -319,6 +321,12 @@ ApplicationWindow { onPortConnectedChanged: { connectionStatusLabel.text = BmsInterface.isPortConnected() ? qsTr("Connected") : qsTr("Disconnected") connectionStatusIndicator.enabled = BmsInterface.isPortConnected() + if (BmsInterface.isPortConnected()) { + BmsInterface.commands().getBMSconf() + } else { + serialLabel.text = "-" + firmwareLabel.text = "-" + } } onMessageDialog: { @@ -352,6 +360,20 @@ ApplicationWindow { } } + Connections { + target: BmsInterface.bmsConfig() + onUpdated: { + serialLabel.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed() + } + } + + Connections { + target: BmsInterface.commands() + onFwVersionReceived: { + firmwareLabel.text = major + "." + minor + } + } + Screens.ConnectionDialog { id: connectionDialog } @@ -373,7 +395,7 @@ ApplicationWindow { Screens.StatusPopup { id: statusPopup - property var filteredStatuses: [qsTr("BMS configuration updated")] + property var filteredStatuses: []//[qsTr("BMS configuration updated")] property var queue: [] onClosed: { @@ -400,7 +422,6 @@ ApplicationWindow { Component.onCompleted: { // BmsInterface.bmsConfig().loadParamsXml("://res/config.xml") // BmsInterface.infoConfig().loadParamsXml("://res/info.xml") - connectionDialog.open() } } diff --git a/qml/Screens/AkbMonitorScreen.qml b/qml/Screens/AkbMonitorScreen.qml index bd17835..7e9b27d 100644 --- a/qml/Screens/AkbMonitorScreen.qml +++ b/qml/Screens/AkbMonitorScreen.qml @@ -315,7 +315,7 @@ Item { Connections { target: BmsInterface.bmsConfig() onUpdated: { - serialNumberField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")) // TODO + serialNumberField.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed() numberOfModulesLabel.text = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount") numberOfCellsLabel.text = BmsInterface.bmsConfig().getParamInt("noOfCellsSeries") @@ -335,7 +335,6 @@ Item { function getValues() { if (BmsInterface.isPortConnected() && visible) { BmsInterface.commands().getValues() - BmsInterface.commands().getBMSconf() } } } diff --git a/qml/Screens/BmsSettingsScreen.qml b/qml/Screens/BmsSettingsScreen.qml index 5a56a3d..3ff4dc4 100644 --- a/qml/Screens/BmsSettingsScreen.qml +++ b/qml/Screens/BmsSettingsScreen.qml @@ -1,9 +1,11 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 +import QtQuick.Dialogs 1.2 import Controls 1.0 as Controls import Cubo 1.0 +import Utils 1.0 RowLayout { property real contentPadding: 35 @@ -40,6 +42,7 @@ RowLayout { Controls.TextField { id: serialNumberField + validator: RegExpValidator { regExp: /[1-9][0-9]*/ } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.spacing) / 2 } @@ -133,7 +136,7 @@ RowLayout { Controls.TextField { id: batteryCapacityField - validator: DoubleValidator {} + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } @@ -172,14 +175,14 @@ RowLayout { Controls.TextField { id: maximumChargeCurrentField - validator: DoubleValidator {} + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: maximumLoadCurrentField - validator: DoubleValidator {} + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } @@ -193,7 +196,7 @@ RowLayout { Controls.TextField { id: maximumTemperatureField - validator: DoubleValidator {} + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 Layout.columnSpan: 2 @@ -220,55 +223,58 @@ RowLayout { } Controls.SubtitleLabel { - text: qsTr("Lower shutdown threshold, V") + text: qsTr("Lower disable threshold, V") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { - text: qsTr("Upper shutdown threshold, V") + text: qsTr("Upper disable threshold, V") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { - id: lowerShutdownThresholdField - validator: DoubleValidator {} + id: lowerDisableThresholdField + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { - id: upperShutdownThresholdField - validator: DoubleValidator {} + id: upperDisableThresholdField + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } - // TODO -// Controls.SubtitleLabel { -// text: qsTr("Lower shutdown threshold, V") -// Layout.fillWidth: true -// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 -// } + Controls.SubtitleLabel { + text: qsTr("Lower enable threshold (should be higher than disable), V") + maximumLineCount: 2 + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } -// Controls.SubtitleLabel { -// text: qsTr("Upper shutdown threshold, V") -// Layout.fillWidth: true -// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 -// } + Controls.SubtitleLabel { + text: qsTr("Upper enable threshold (should be higher than disable), V") + maximumLineCount: 2 + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } -// Controls.TextField { -// id: lowerShutdownThresholdField -// Layout.fillWidth: true -// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 -// } + Controls.TextField { + id: lowerEnableThresholdField + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } -// Controls.TextField { -// id: upperShutdownThresholdField -// Layout.fillWidth: true -// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 -// } + Controls.TextField { + id: upperEnableThresholdField + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + } } } @@ -308,17 +314,32 @@ RowLayout { Controls.TextField { id: balancingStartVoltageField - validator: DoubleValidator {} + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: balancingStartDeltaVoltageField - validator: DoubleValidator {} + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } + + Controls.SubtitleLabel { + text: qsTr("Cell balancing interval, ms") + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + Layout.columnSpan: 2 + } + + Controls.TextField { + id: balancingCellIntervalField + validator: IntValidator {} + Layout.fillWidth: true + Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 + Layout.columnSpan: 2 + } } } @@ -520,7 +541,7 @@ RowLayout { Controls.TextField { id: zeroSensorValueField - validator: DoubleValidator {} + validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 Layout.columnSpan: 2 @@ -532,6 +553,38 @@ RowLayout { Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 Layout.columnSpan: 2 + onClicked: BmsInterface.commands().sendTerminalCmd("setZeroCurrent") + } + } + } + + Controls.OutlineButton { + text: qsTr("Load settings from file") + onClicked: loadFileDialog.open() + + FileDialog { + id: loadFileDialog + title: qsTr("Select configuration file") + folder: shortcuts.documents + nameFilters: [ qsTr("Configuration files (*.xml)"), qsTr("All files (*)") ] + onAccepted: { + BmsInterface.bmsConfig().loadXml(loadFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration") + } + } + } + + Controls.OutlineButton { + text: qsTr("Save settings to file") + onClicked: saveFileDialog.open() + + FileDialog { + id: saveFileDialog + title: qsTr("Select configuration file") + selectExisting: false + folder: shortcuts.documents + nameFilters: [ qsTr("Configuration files (*.xml)"), qsTr("All files (*)") ] + onAccepted: { + BmsInterface.bmsConfig().saveXml(saveFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration") } } } @@ -610,11 +663,19 @@ RowLayout { Controls.OutlineButton { text: qsTr("Write to non-volatile memory of BMS") Layout.fillWidth: true + onClicked: { + writeValuesToConfig() + BmsInterface.commands().storeBMSConfig() + } } Controls.Button { text: qsTr("Write current values to BMS") Layout.fillWidth: true + onClicked: { + writeValuesToConfig() + BmsInterface.commands().setBMSconf() + } } Layout.fillWidth: true @@ -624,43 +685,56 @@ RowLayout { Layout.fillHeight: true } + function writeValuesToConfig() { + BmsInterface.bmsConfig().setParamValue("notUsedCurrentThreshold", parseFloat(serialNumberField.text)) + + BmsInterface.bmsConfig().setParamValue("cellMonitorICCount", parseInt(numberOfBoardsField.text)) + BmsInterface.bmsConfig().setParamValue("noOfCellsSeries", parseInt(numberOfCellsField.text)) + + BmsInterface.bmsConfig().setParamValue("noOfCellsParallel", parseInt(numberOfParallelCellsField.text)) + BmsInterface.bmsConfig().setParamValue("batteryCapacity", parseFloat(batteryCapacityField.text)) + + BmsInterface.bmsConfig().setParamValue("maxAllowedCurrent", parseFloat(maximumChargeCurrentField.text)) + BmsInterface.bmsConfig().setParamValue("maxMismatchThreshold", parseFloat(maximumLoadCurrentField.text)) + BmsInterface.bmsConfig().setParamValue("allowedTempBattChargingMax", parseFloat(maximumTemperatureField.text)) + + BmsInterface.bmsConfig().setParamValue("cellHardUnderVoltage", parseFloat(lowerDisableThresholdField.text)) + BmsInterface.bmsConfig().setParamValue("cellHardOverVoltage", parseFloat(upperDisableThresholdField.text)) + BmsInterface.bmsConfig().setParamValue("cellLCSoftUnderVoltage", parseFloat(lowerEnableThresholdField.text)) + BmsInterface.bmsConfig().setParamValue("cellSoftOverVoltage", parseFloat(upperEnableThresholdField.text)) + + BmsInterface.bmsConfig().setParamValue("cellBalanceStart", parseFloat(balancingStartVoltageField.text)) + BmsInterface.bmsConfig().setParamValue("cellBalanceDifferenceThreshold", parseFloat(balancingStartDeltaVoltageField.text)) + BmsInterface.bmsConfig().setParamValue("cellBalanceUpdateInterval", parseInt(balancingCellIntervalField.text)) + + BmsInterface.bmsConfig().setParamValue("shuntLCFactor", parseFloat(zeroSensorValueField.text)) + } + Connections { target: BmsInterface.bmsConfig() onUpdated: { - serialNumberField.text = BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold") + serialNumberField.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed() numberOfBoardsField.text = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount") numberOfCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsSeries") numberOfParallelCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsParallel") - batteryCapacityField.text = BmsInterface.bmsConfig().getParamDouble("batteryCapacity") + batteryCapacityField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("batteryCapacity")) - maximumChargeCurrentField.text = BmsInterface.bmsConfig().getParamDouble("maxAllowedCurrent") - maximumLoadCurrentField.text = BmsInterface.bmsConfig().getParamDouble("maxMismatchThreshold") - maximumTemperatureField.text = BmsInterface.bmsConfig().getParamDouble("allowedTempBattChargingMax") + maximumChargeCurrentField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("maxAllowedCurrent")) + maximumLoadCurrentField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("maxMismatchThreshold")) + maximumTemperatureField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("allowedTempBattChargingMax")) - // TODO - lowerShutdownThresholdField.text = BmsInterface.bmsConfig().getParamDouble("cellHardUnderVoltage") - upperShutdownThresholdField.text = BmsInterface.bmsConfig().getParamDouble("cellHardOverVoltage") + lowerDisableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellHardUnderVoltage")) + upperDisableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellHardOverVoltage")) + lowerEnableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellLCSoftUnderVoltage")) + upperEnableThresholdField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellSoftOverVoltage")) - // TODO - balancingStartVoltageField.text = BmsInterface.bmsConfig().getParamDouble("cellBalanceStart") - balancingStartDeltaVoltageField.text = BmsInterface.bmsConfig().getParamDouble("cellBalanceDifferenceThreshold") + balancingStartVoltageField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellBalanceStart")) + balancingStartDeltaVoltageField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellBalanceDifferenceThreshold")) + balancingCellIntervalField.text = BmsInterface.bmsConfig().getParamInt("cellBalanceUpdateInterval") - zeroSensorValueField.text = BmsInterface.bmsConfig().getParamDouble("shuntLCFactor") - } - } - - Connections { - target: BmsInterface - onPortConnectedChanged: getValues() - } - - onVisibleChanged: getValues() - - function getValues() { - if (BmsInterface.isPortConnected() && visible) { - BmsInterface.commands().getBMSconf() + zeroSensorValueField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("shuntLCFactor")) } } }