import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Dialogs 1.2 import Qt.labs.settings 1.1 import Controls 1.0 as Controls import Cubo 1.0 import Utils 1.0 RowLayout { property real contentPadding: 35 property real contentRowSpacing: 20 property real contentColumnSpacing: 35 signal needWait(bool active, string text) spacing: contentColumnSpacing - 10 Flickable { id: settingsFlickable clip: true contentWidth: width - rightMargin - leftMargin contentHeight: configLayout.height boundsBehavior: Flickable.StopAtBounds rightMargin: 10 ColumnLayout { id: configLayout width: parent.width spacing: 15 Controls.Frame { id: serialNumberSettingsFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true RowLayout { spacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("Serial number") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.spacing) / 2 } Controls.TextField { id: serialNumberField validator: RegExpValidator { regExp: /[1-9][0-9]*/ } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.spacing) / 2 } } } Controls.Frame { id: configurationSettingsFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true GridLayout { id: configurationLayout columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("Configuration") Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Number of boards") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Number of cells") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: numberOfBoardsField validator: IntValidator { bottom: 0 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 onTextChanged: configurationLayout.recalculateSensorsMasks() } Controls.TextField { id: numberOfCellsField validator: IntValidator { bottom: 0 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Repeater { id: bmsSensorsMaskRepeater property var bmsSensorsMaskModel: [] ColumnLayout { id: bmsSensorsMaskLayout Layout.fillWidth: true property var boardIndex: index Controls.SubtitleLabel { text: index === 0 ? qsTr("BMS sensors mask for master board") : qsTr("BMS sensors mask for slave board #") + index maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true } Controls.Frame { padding: 10 Layout.fillWidth: true Layout.fillHeight: true ColumnLayout { spacing: 10 anchors.fill: parent Repeater { model: 4 Controls.CheckBox { text: qsTr("#") + (index + 1) opacity: (bmsSensorsMaskLayout.boardIndex === 0 && (index === 2 || index === 3)) ? 0 : 1 enabled: opacity checked: bmsSensorsMaskRepeater.bmsSensorsMaskModel[bmsSensorsMaskLayout.boardIndex * 4 + index] onCheckedChanged: bmsSensorsMaskRepeater.bmsSensorsMaskModel[bmsSensorsMaskLayout.boardIndex * 4 + index] = checked } } Item { visible: index === 0 Layout.fillHeight: true } } } } } Repeater { id: batterySensorsMaskRepeater property var batterySensorsMaskModel: [] ColumnLayout { id: batterySensorsMaskLayout Layout.fillWidth: true property var boardIndex: index Controls.SubtitleLabel { text: index === 0 ? qsTr("Battery sensors mask for master board") : qsTr("Battery sensors mask for slave board #") + index maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true } Controls.Frame { padding: 10 Layout.fillWidth: true Layout.fillHeight: true ColumnLayout { spacing: 10 anchors.fill: parent Repeater { model: 4 Controls.CheckBox { text: qsTr("#") + (index + 1) enabled: opacity opacity: (batterySensorsMaskLayout.boardIndex === 0 && (index === 2 || index === 3)) ? 0 : 1 checked: batterySensorsMaskRepeater.batterySensorsMaskModel[batterySensorsMaskLayout.boardIndex * 4 + index] onCheckedChanged: batterySensorsMaskRepeater.batterySensorsMaskModel[batterySensorsMaskLayout.boardIndex * 4 + index] = checked } } Item { visible: index === 0 Layout.fillHeight: true } } } } } function recalculateSensorsMasks() { const bmsSensorsModel = bmsSensorsMaskRepeater.bmsSensorsMaskModel const batterySensorsModel = batterySensorsMaskRepeater.batterySensorsMaskModel const newSize = parseInt(numberOfBoardsField.text) * 4 if (newSize) { arrayResize(bmsSensorsModel, newSize, false) arrayResize(batterySensorsModel, newSize, true) bmsSensorsMaskRepeater.model = 0 bmsSensorsMaskRepeater.bmsSensorsMaskModel = bmsSensorsModel bmsSensorsMaskRepeater.model = parseInt(numberOfBoardsField.text) batterySensorsMaskRepeater.model = 0 batterySensorsMaskRepeater.batterySensorsMaskModel = batterySensorsModel batterySensorsMaskRepeater.model = parseInt(numberOfBoardsField.text) } } function arrayResize(array, size, value) { while (array.length > size) { array.pop(); } while (array.length < size) { array.push(value); } } } } Controls.Frame { id: socSettingsFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true GridLayout { columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("SOC") Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Number of cells connected in parallel") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Battery capacity") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: numberOfParallelCellsField validator: IntValidator {} Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: batteryCapacityField validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } } } Controls.Frame { id: limitSettingsFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true GridLayout { columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("Limits") Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Maximum charge current, A") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Maximum load current, A") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: maximumChargeCurrentField 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 { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Maximum temperature, °C") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 Layout.columnSpan: 2 } Controls.TextField { id: maximumTemperatureField validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 Layout.columnSpan: 2 } } } Controls.Frame { id: cellSettingsFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true GridLayout { columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("Cell configuration") Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Lower disable threshold, V") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Upper disable threshold, V") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { 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: upperDisableThresholdField validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Lower enable threshold (should be higher than disable), V") maximumLineCount: 3 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Upper enable threshold (should be higher than disable), V") maximumLineCount: 3 wrapMode: Text.WordWrap 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: upperEnableThresholdField validator: DoubleValidator { decimals: 2; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } } } Controls.Frame { id: balancingSettingsFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true GridLayout { columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("Balancing configuration") Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Balancing start voltage, V") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Cell voltage delta to start balancing, V") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: balancingStartVoltageField 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 { 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") maximumLineCount: 2 wrapMode: Text.WordWrap 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 } } } Controls.Frame { id: currentConfigurationFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true GridLayout { columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("Current configuration") Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Current factor K1") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Current factor K2") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: currentFactorK1Field validator: DoubleValidator { decimals: 3; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: currentFactorK2Field validator: DoubleValidator { decimals: 3; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Current sensor value \"0\"") Layout.fillWidth: true Layout.columnSpan: 2 } Controls.TextField { id: zeroSensorValueField validator: DoubleValidator { decimals: 3; locale: "en-US"; notation: DoubleValidator.StandardNotation } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 Layout.columnSpan: 2 } Controls.Button { id: zeroSensorValueCalibrationButton text: qsTr("Calibrate \"0\"") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 Layout.columnSpan: 2 onClicked: { BmsInterface.commands().sendTerminalCmd("setZeroCurrent") Qt.callLater(storeBmsConfigurationButton.clicked) } } } } Controls.Frame { id: outputSettingsFrame padding: contentPadding implicitWidth: parent.width Layout.fillWidth: true property real outputNumberSize: 60 GridLayout { columns: 2 rowSpacing: contentRowSpacing columnSpacing: contentColumnSpacing anchors.fill: parent Controls.TitleLabel { text: qsTr("Output settings") Layout.fillWidth: true Layout.columnSpan: 2 } RowLayout { spacing: 20 Controls.LabelWithBackground { text: qsTr("# 1") Layout.preferredWidth: outputSettingsFrame.outputNumberSize Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Controls.CheckBox { id: chargeBatteryOutputCheckBox text: qsTr("Use to control charger") Layout.fillWidth: true Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Layout.fillWidth: true Layout.columnSpan: 2 } Controls.LineSeparator { Layout.fillWidth: true Layout.columnSpan: 2 } RowLayout { spacing: 20 Controls.LabelWithBackground { text: qsTr("# 2") Layout.preferredWidth: outputSettingsFrame.outputNumberSize Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Controls.CheckBox { id: brushOrShuntOutputCheckBox text: qsTr("Active") Layout.fillWidth: true Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Layout.fillWidth: true Layout.columnSpan: 2 } Controls.RadioButton { id: brushControlRadioButton text: qsTr("Brush control") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.RadioButton { id: shuntChargingContactorRadioButton text: qsTr("Shunt charging contactor") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("SOC threshold, %") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Delay, s") maximumLineCount: 2 wrapMode: Text.WordWrap Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: brushUsageSocThresholdField validator: IntValidator { bottom: 0; top: 100 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: shuntChargingContactorDelayField validator: IntValidator { bottom: 0; top: 65535 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.LineSeparator { Layout.fillWidth: true Layout.columnSpan: 2 } RowLayout { spacing: 20 Controls.LabelWithBackground { text: qsTr("# 3") Layout.preferredWidth: outputSettingsFrame.outputNumberSize Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Controls.CheckBox { id: coolingOutputCheckBox text: qsTr("Cooling activation") Layout.fillWidth: true Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Closes at t<, °C") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Opens at t>, °C") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: coolingStartThresholdField validator: IntValidator { bottom: -32768; top: 32768 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: coolingStopThresholdField validator: IntValidator { bottom: -32768; top: 32768 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.LineSeparator { Layout.fillWidth: true Layout.columnSpan: 2 } RowLayout { spacing: 20 Controls.LabelWithBackground { text: qsTr("# 4") Layout.preferredWidth: outputSettingsFrame.outputNumberSize Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Controls.CheckBox { id: heatingOutputCheckBox text: qsTr("Heating activation") Layout.fillWidth: true Layout.preferredHeight: outputSettingsFrame.outputNumberSize } Layout.fillWidth: true Layout.columnSpan: 2 } Controls.SubtitleLabel { text: qsTr("Closes at t<, °C") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.SubtitleLabel { text: qsTr("Opens at t>, °C") Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: heatingStartThresholdField validator: IntValidator { bottom: -32768; top: 32768 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.TextField { id: heatingStopThresholdField validator: IntValidator { bottom: -32768; top: 32768 } Layout.fillWidth: true Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2 } Controls.LineSeparator { Layout.fillWidth: true Layout.columnSpan: 2 } } } Controls.OutlineButton { text: qsTr("Load settings from file") onClicked: loadFileDialog.open() Layout.preferredWidth: 270 FileDialog { id: loadFileDialog title: qsTr("Select configuration file") folder: shortcuts.documents nameFilters: [ qsTr("Configuration files (*.xml)"), qsTr("All files (*)") ] onAccepted: { let result = BmsInterface.bmsConfig().loadXml(loadFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration") if (!result) { BmsInterface.emitStatusMessage(BmsInterface.bmsConfig().xmlStatus(), false) } } } Settings { category: "loadConfiguration" property alias folder: loadFileDialog.folder } } Controls.OutlineButton { text: qsTr("Save settings to file") onClicked: saveFileDialog.open() Layout.preferredWidth: 270 FileDialog { id: saveFileDialog title: qsTr("Select configuration file") selectExisting: false folder: shortcuts.documents nameFilters: [ qsTr("Configuration files (*.xml)"), qsTr("All files (*)") ] onAccepted: { let result = BmsInterface.bmsConfig().saveXml(saveFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), "bmsConfiguration") if (!result) { BmsInterface.emitStatusMessage(BmsInterface.bmsConfig().xmlStatus(), false) } else { BmsInterface.emitStatusMessage(qsTr("BMS configuration saved to file"), true) } } } Settings { category: "saveConfiguration" property alias folder: saveFileDialog.folder } } } ScrollBar.vertical: Controls.ScrollBar {} Layout.fillWidth: true Layout.fillHeight: true } ColumnLayout { spacing: contentRowSpacing Controls.LinkLabel { text: qsTr("Serial number") onClicked: settingsFlickable.contentY = serialNumberSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { text: qsTr("Configuration") onClicked: settingsFlickable.contentY = configurationSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { text: qsTr("SOC") onClicked: settingsFlickable.contentY = socSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { text: qsTr("Limits") onClicked: settingsFlickable.contentY = limitSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { text: qsTr("Cell configuration") onClicked: settingsFlickable.contentY = cellSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { text: qsTr("Balancing configuration") onClicked: settingsFlickable.contentY = balancingSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { text: qsTr("Current configuration") onClicked: settingsFlickable.contentY = currentConfigurationFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y } Controls.LinkLabel { text: qsTr("Output settings") onClicked: { settingsFlickable.contentY = outputSettingsFrame.mapToItem(settingsFlickable.contentItem, 0, 0).y settingsFlickable.returnToBounds() } } Item { Layout.fillHeight: true } ColumnLayout { spacing: 15 Controls.OutlineButton { text: qsTr("Read default settings") Layout.fillWidth: true onClicked: if (BmsInterface.isPortConnected()) { BmsInterface.commands().getBMSconfDefault() } } Controls.OutlineButton { text: qsTr("Read current settings from BMS") Layout.fillWidth: true onClicked: if (BmsInterface.isPortConnected()) { BmsInterface.commands().getBMSconf() } } Controls.OutlineButton { id: writeBmsConfigurationButton text: qsTr("Write current values to BMS") Layout.fillWidth: true onClicked: if (BmsInterface.isPortConnected()) { writeValuesToConfig() BmsInterface.commands().setBMSconf() } } Controls.Button { id: storeBmsConfigurationButton text: qsTr("Write to non-volatile memory of BMS") Layout.fillWidth: true onClicked: if (BmsInterface.isPortConnected()) { needWait(true, qsTr("The settings are written to non-volatile memory.\nWait, please.")) writeValuesToConfig() BmsInterface.commands().storeBMSConfig() } } Layout.fillWidth: true } Layout.maximumWidth: 280 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)) const numberOfBoards = parseInt(numberOfBoardsField.text) const bmsSensorsModel = bmsSensorsMaskRepeater.bmsSensorsMaskModel const batterySensorsModel = batterySensorsMaskRepeater.batterySensorsMaskModel let bmsSensorsMask = 0 let batterySensorsMask = 0 for (let i = 0; i < numberOfBoards * 4; ++i) { bmsSensorsMask |= Number(bmsSensorsModel[i]) << i batterySensorsMask |= Number(batterySensorsModel[i]) << i } // disable 3 and 4 sensor for master bmsSensorsMask = bmsSensorsMask & ~(1 << 2) bmsSensorsMask = bmsSensorsMask & ~(1 << 3) batterySensorsMask = batterySensorsMask & ~(1 << 2) batterySensorsMask = batterySensorsMask & ~(1 << 3) print(bmsSensorsMask, batterySensorsMask) BmsInterface.bmsConfig().setParamValue("tempEnableMaskBMS", bmsSensorsMask) BmsInterface.bmsConfig().setParamValue("tempEnableMaskBattery", batterySensorsMask) 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("floatCurrentK1", parseFloat(currentFactorK1Field.text)) BmsInterface.bmsConfig().setParamValue("floatCurrentK2", parseFloat(currentFactorK2Field.text)) BmsInterface.bmsConfig().setParamValue("shuntLCFactor", parseFloat(zeroSensorValueField.text)) BmsInterface.bmsConfig().setParamValue("chargeBatteryOutputChecked", chargeBatteryOutputCheckBox.checked) BmsInterface.bmsConfig().setParamValue("brushOrShuntOutputChecked", brushOrShuntOutputCheckBox.checked) BmsInterface.bmsConfig().setParamValue("brushOrShuntMode", shuntChargingContactorRadioButton.checked) BmsInterface.bmsConfig().setParamValue("brushUsageSocThreshold", parseInt(brushUsageSocThresholdField.text)) BmsInterface.bmsConfig().setParamValue("shuntChargingContactorDelay", parseInt(shuntChargingContactorDelayField.text)) BmsInterface.bmsConfig().setParamValue("coolingOutputChecked", coolingOutputCheckBox.checked) BmsInterface.bmsConfig().setParamValue("coolingStartThreshold", parseInt(coolingStartThresholdField.text)) BmsInterface.bmsConfig().setParamValue("coolingStopThreshold", parseInt(coolingStopThresholdField.text)) BmsInterface.bmsConfig().setParamValue("heatingOutputChecked", heatingOutputCheckBox.checked) BmsInterface.bmsConfig().setParamValue("heatingStartThreshold", parseInt(heatingStartThresholdField.text)) BmsInterface.bmsConfig().setParamValue("heatingStopThreshold", parseInt(heatingStopThresholdField.text)) } Connections { target: BmsInterface.bmsConfig() onUpdated: { serialNumberField.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed() numberOfBoardsField.text = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount") numberOfCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsSeries") const numberOfBoards = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount") const numberOfSensorsPerBoard = BmsInterface.bmsConfig().getParamInt("noOfTempSensorPerModule") const bmsSensorsMask = BmsInterface.bmsConfig().getParamInt("tempEnableMaskBMS") const batterySensorsMask = BmsInterface.bmsConfig().getParamInt("tempEnableMaskBattery") const bmsSensorsModel = [] const batterySensorsModel = [] for (let i = 0; i < numberOfBoards * numberOfSensorsPerBoard; ++i) { bmsSensorsModel.push((bmsSensorsMask & (1 << i)) != 0) batterySensorsModel.push((batterySensorsMask & (1 << i)) != 0) } bmsSensorsMaskRepeater.bmsSensorsMaskModel = bmsSensorsModel batterySensorsMaskRepeater.batterySensorsMaskModel = batterySensorsModel numberOfParallelCellsField.text = BmsInterface.bmsConfig().getParamInt("noOfCellsParallel") batteryCapacityField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("batteryCapacity")) maximumChargeCurrentField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("maxAllowedCurrent")) maximumLoadCurrentField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("maxMismatchThreshold")) maximumTemperatureField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("allowedTempBattChargingMax")) 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")) balancingStartVoltageField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellBalanceStart")) balancingStartDeltaVoltageField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("cellBalanceDifferenceThreshold")) balancingCellIntervalField.text = BmsInterface.bmsConfig().getParamInt("cellBalanceUpdateInterval") currentFactorK1Field.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("floatCurrentK1"), 3) currentFactorK2Field.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("floatCurrentK2"), 3) zeroSensorValueField.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("shuntLCFactor"), 3) chargeBatteryOutputCheckBox.checked = BmsInterface.bmsConfig().getParamBool("chargeBatteryOutputChecked") brushOrShuntOutputCheckBox.checked = BmsInterface.bmsConfig().getParamBool("brushOrShuntOutputChecked") brushControlRadioButton.checked = !BmsInterface.bmsConfig().getParamBool("brushOrShuntMode") shuntChargingContactorRadioButton.checked = BmsInterface.bmsConfig().getParamBool("brushOrShuntMode") brushUsageSocThresholdField.text = BmsInterface.bmsConfig().getParamInt("brushUsageSocThreshold") shuntChargingContactorDelayField.text = BmsInterface.bmsConfig().getParamInt("shuntChargingContactorDelay") coolingOutputCheckBox.checked = BmsInterface.bmsConfig().getParamBool("coolingOutputChecked") coolingStartThresholdField.text = BmsInterface.bmsConfig().getParamInt("coolingStartThreshold") coolingStopThresholdField.text = BmsInterface.bmsConfig().getParamInt("coolingStopThreshold") heatingOutputCheckBox.checked = BmsInterface.bmsConfig().getParamBool("heatingOutputChecked") heatingStartThresholdField.text = BmsInterface.bmsConfig().getParamInt("heatingStartThreshold") heatingStopThresholdField.text = BmsInterface.bmsConfig().getParamInt("heatingStopThreshold") } } }