Initial commit (project based on widgets)
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
*.user
|
||||||
|
*.o
|
||||||
|
moc_*.cpp
|
||||||
|
moc_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
qrc_*.h
|
||||||
|
ui_*.h
|
||||||
|
Makefile
|
||||||
|
ENNOID-BMS-ToolV*
|
||||||
176
ENNOID-BMS-Tool.pro
Normal file
176
ENNOID-BMS-Tool.pro
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#-------------------------------------------------
|
||||||
|
#
|
||||||
|
# Project created by QtCreator 2016-08-12T21:55:19
|
||||||
|
#
|
||||||
|
#-------------------------------------------------
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
# Version
|
||||||
|
DT_VERSION = 1.3
|
||||||
|
DEFINES += DT_VERSION=$$DT_VERSION
|
||||||
|
|
||||||
|
!android: {
|
||||||
|
# Serial port available
|
||||||
|
DEFINES += HAS_SERIALPORT
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||||
|
|
||||||
|
# Options
|
||||||
|
#Build mobile GUI
|
||||||
|
#CONFIG += build_mobile
|
||||||
|
|
||||||
|
|
||||||
|
# Bluetooth available
|
||||||
|
DEFINES += HAS_BLUETOOTH
|
||||||
|
|
||||||
|
QT += core gui
|
||||||
|
QT += widgets
|
||||||
|
QT += printsupport
|
||||||
|
QT += network
|
||||||
|
QT += bluetooth
|
||||||
|
QT += quick
|
||||||
|
QT += quickcontrols2
|
||||||
|
QT += charts
|
||||||
|
|
||||||
|
contains(DEFINES, HAS_SERIALPORT) {
|
||||||
|
QT += serialport
|
||||||
|
}
|
||||||
|
|
||||||
|
android: QT += androidextras
|
||||||
|
|
||||||
|
android: TARGET = ENNOID-BMS-Tool
|
||||||
|
!android: TARGET = ENNOID-BMS-ToolV$$DT_VERSION
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
release_win {
|
||||||
|
DESTDIR = build/win
|
||||||
|
OBJECTS_DIR = build/win/obj
|
||||||
|
MOC_DIR = build/win/obj
|
||||||
|
RCC_DIR = build/win/obj
|
||||||
|
UI_DIR = build/win/obj
|
||||||
|
}
|
||||||
|
|
||||||
|
release_lin {
|
||||||
|
# http://micro.nicholaswilson.me.uk/post/31855915892/rules-of-static-linking-libstdc-libc-libgcc
|
||||||
|
# http://insanecoding.blogspot.se/2012/07/creating-portable-linux-binaries.html
|
||||||
|
QMAKE_LFLAGS += -static-libstdc++ -static-libgcc
|
||||||
|
DESTDIR = build/lin
|
||||||
|
OBJECTS_DIR = build/lin/obj
|
||||||
|
MOC_DIR = build/lin/obj
|
||||||
|
RCC_DIR = build/lin/obj
|
||||||
|
UI_DIR = build/lin/obj
|
||||||
|
}
|
||||||
|
|
||||||
|
release_android {
|
||||||
|
DESTDIR = build/android
|
||||||
|
OBJECTS_DIR = build/android/obj
|
||||||
|
MOC_DIR = build/android/obj
|
||||||
|
RCC_DIR = build/android/obj
|
||||||
|
UI_DIR = build/android/obj
|
||||||
|
}
|
||||||
|
|
||||||
|
build_mobile {
|
||||||
|
DEFINES += USE_MOBILE
|
||||||
|
}
|
||||||
|
|
||||||
|
SOURCES += main.cpp\
|
||||||
|
akbmonitorpage.cpp \
|
||||||
|
bmsservicepage.cpp \
|
||||||
|
bmssettings.cpp \
|
||||||
|
bmssettingswidget.cpp \
|
||||||
|
cellsmonitorcheckboxdelegate.cpp \
|
||||||
|
cellsmonitorlabelvoltagedelegate.cpp \
|
||||||
|
cellsmonitorpage.cpp \
|
||||||
|
configparamsgetter.cpp \
|
||||||
|
configurationpage.cpp \
|
||||||
|
connectandenterpage.cpp \
|
||||||
|
customlefttabbarbutton.cpp \
|
||||||
|
debugprintpage.cpp \
|
||||||
|
historylineeditbox.cpp \
|
||||||
|
hoverablecombobox.cpp \
|
||||||
|
languageselectorbutton.cpp \
|
||||||
|
mainwindow.cpp \
|
||||||
|
mainwindownew.cpp \
|
||||||
|
packet.cpp \
|
||||||
|
settingsextrapage.cpp \
|
||||||
|
vbytearray.cpp \
|
||||||
|
commands.cpp \
|
||||||
|
configparams.cpp \
|
||||||
|
configparam.cpp \
|
||||||
|
parametereditor.cpp \
|
||||||
|
digitalfiltering.cpp \
|
||||||
|
bleuart.cpp \
|
||||||
|
utility.cpp \
|
||||||
|
bmsinterface.cpp \
|
||||||
|
visualizationchart.cpp \
|
||||||
|
visualizationpage.cpp
|
||||||
|
|
||||||
|
HEADERS += mainwindow.h \
|
||||||
|
akbmonitorpage.h \
|
||||||
|
bmsservicepage.h \
|
||||||
|
bmssettings.h \
|
||||||
|
bmssettingswidget.h \
|
||||||
|
cellsmonitorcheckboxdelegate.h \
|
||||||
|
cellsmonitorlabelvoltagedelegate.h \
|
||||||
|
cellsmonitorpage.h \
|
||||||
|
configparamsgetter.h \
|
||||||
|
configurationpage.h \
|
||||||
|
connectandenterpage.h \
|
||||||
|
customlefttabbarbutton.h \
|
||||||
|
debugprintpage.h \
|
||||||
|
historylineedit.h \
|
||||||
|
historylineeditbox.h \
|
||||||
|
hoverablecombobox.h \
|
||||||
|
languageselectorbutton.h \
|
||||||
|
mainwindownew.h \
|
||||||
|
packet.h \
|
||||||
|
settingsextrapage.h \
|
||||||
|
vbytearray.h \
|
||||||
|
commands.h \
|
||||||
|
datatypes.h \
|
||||||
|
configparams.h \
|
||||||
|
configparam.h \
|
||||||
|
parametereditor.h \
|
||||||
|
digitalfiltering.h \
|
||||||
|
bleuart.h \
|
||||||
|
utility.h \
|
||||||
|
bmsinterface.h \
|
||||||
|
visualizationchart.h \
|
||||||
|
visualizationpage.h
|
||||||
|
|
||||||
|
FORMS += mainwindow.ui \
|
||||||
|
akbmonitorpage.ui \
|
||||||
|
bmsservicepage.ui \
|
||||||
|
bmssettings.ui \
|
||||||
|
bmssettingswidget.ui \
|
||||||
|
cellsmonitorpage.ui \
|
||||||
|
configurationpage.ui \
|
||||||
|
connectandenterpage.ui \
|
||||||
|
debugprintpage.ui \
|
||||||
|
mainwindownew.ui \
|
||||||
|
parametereditor.ui \
|
||||||
|
settingsextrapage.ui \
|
||||||
|
visualizationpage.ui
|
||||||
|
|
||||||
|
include(pages/pages.pri)
|
||||||
|
include(widgets/widgets.pri)
|
||||||
|
include(mobile/mobile.pri)
|
||||||
|
|
||||||
|
RESOURCES += res.qrc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
android/AndroidManifest.xml \
|
||||||
|
android/gradle/wrapper/gradle-wrapper.jar \
|
||||||
|
android/gradlew \
|
||||||
|
android/res/values/libs.xml \
|
||||||
|
android/build.gradle \
|
||||||
|
android/gradle/wrapper/gradle-wrapper.properties
|
||||||
|
|
||||||
|
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
|
||||||
|
|
||||||
|
ANDROID_ABIS = x86
|
||||||
|
|
||||||
20
README.md
Normal file
20
README.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ENNOID-BMS Tool (based on DieBieMS-Tool)
|
||||||
|
|
||||||
|
The ENNOID-BMS tool can be used to configure the ENNOID-BMS, update the firmware.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Latest compiled version can be found in the release tab:
|
||||||
|
[ENNOID-BMS Tool](https://github.com/EnnoidMe/ENNOID-BMS-Tool/releases/tag/V1.1)
|
||||||
|
|
||||||
|
# Other parts of this project:
|
||||||
|
|
||||||
|
[ENNOID-BMS Hardware](https://github.com/EnnoidMe/ENNOID-BMS)
|
||||||
|
|
||||||
|
[ENNOID-BMS Bootloader](https://github.com/EnnoidMe/DieBieMS-Bootloader) Same as DieBieMS bootloader Can be flashed with the ENNOID-BMS Tool in the firmware tab or with an STlink-V2.
|
||||||
|
|
||||||
|
[ENNOID-BMS Firmware](https://github.com/EnnoidMe/ENNOID-BMS-Firmware/tree/ENNOID) Can be flashed with the ENNOID-BMS Tool in the firmware tab.
|
||||||
|
|
||||||
|
The compiled build .bin and hex files can be found in the MDK-ARM folder [Firmware files](https://github.com/EnnoidMe/ENNOID-BMS-Firmware/blob/master/MDK-ARM/DieBieMS/ENNOID-BMS.bin)
|
||||||
496
akbmonitorpage.cpp
Normal file
496
akbmonitorpage.cpp
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
#include "akbmonitorpage.h"
|
||||||
|
#include "ui_akbmonitorpage.h"
|
||||||
|
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QDoubleValidator>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "configparamsgetter.h"
|
||||||
|
|
||||||
|
AkbMonitorPage::AkbMonitorPage(QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
ui(new Ui::AkbMonitorPage)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->pbLoadDataFromBmsMemory->hide();
|
||||||
|
|
||||||
|
// L
|
||||||
|
ui->lbCellNumberLeft->hide();
|
||||||
|
ui->lbCellNumberLeftDots->hide();
|
||||||
|
ui->editCellNumberLeft->hide();
|
||||||
|
// R
|
||||||
|
ui->lbCellNumberRight->hide();
|
||||||
|
ui->lbCellNumberRightDots->hide();
|
||||||
|
ui->editCellNumberRight->hide();
|
||||||
|
|
||||||
|
// 1 // L
|
||||||
|
ui->editBatteryChargeLevel ->setValidator( new QIntValidator(-1000, 1000, this) ); // mValues.soC
|
||||||
|
ui->editBatteryVoltage ->setValidator( new QIntValidator(-1000, 1000, this) ); // mValues.packVoltage
|
||||||
|
ui->editNominalCapacity ->setValidator( new QIntValidator(-1000, 1000, this) ); //, mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
ui->editBatteryTemperature ->setValidator( new QDoubleValidator(-100, 100, 2, this) ); // mValues.tempBattHigh
|
||||||
|
// 1 // R
|
||||||
|
ui->editModulesNumber ->setValidator( new QIntValidator(-1000, 1000, this) ); //, mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
ui->editCellsNumber ->setValidator( new QIntValidator(-1000, 1000, this) ); //, mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
ui->editActualCapacity ->setValidator( new QIntValidator(-1000, 1000, this) ); // NOT IN SETTINGS
|
||||||
|
ui->editBmsTemperature ->setValidator( new QDoubleValidator(-100, 100, 2, this) ); // mValues.tempBMSHigh
|
||||||
|
//
|
||||||
|
// 2 // L ->clear();
|
||||||
|
ui->editMaxVoltageOnCell ->setValidator( new QDoubleValidator(-100, 100, 2, this) ); // mValues.cVHigh
|
||||||
|
ui->editCellNumberLeft ->setValidator( new QIntValidator(-1000, 1000, this) ); // NOT IN SETTINGS
|
||||||
|
ui->editCircuit ->setValidator( new QIntValidator(-1000, 1000, this) ); // mValues.packCurrent
|
||||||
|
// 2 // R ->clear();
|
||||||
|
ui->editMinVoltageOnCell ->setValidator( new QDoubleValidator(-100, 100, 2, this) ); // mValues.cVLow
|
||||||
|
ui->editCellNumberRight ->setValidator( new QIntValidator(-100, 1000, this) ); // NOT IN SETTINGS
|
||||||
|
|
||||||
|
|
||||||
|
mTimer = new QTimer(this);
|
||||||
|
mTimer->start(1000);
|
||||||
|
|
||||||
|
connect(mTimer, &QTimer::timeout,this, &AkbMonitorPage::timerSlot);
|
||||||
|
|
||||||
|
clearControlls();
|
||||||
|
}
|
||||||
|
|
||||||
|
AkbMonitorPage::~AkbMonitorPage()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BMSInterface *AkbMonitorPage::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkbMonitorPage::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
|
||||||
|
if (mDieBieMS) {
|
||||||
|
connect(mDieBieMS->commands(), &Commands::valuesReceived,this, &AkbMonitorPage::valuesReceived);
|
||||||
|
//connect(mDieBieMS->commands(), &Commands::cellsReceived,this, &VisualizationPage::cellsReceived);
|
||||||
|
connect(mDieBieMS->bmsConfig(), &ConfigParams::updated, this, &AkbMonitorPage::onLoadParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AkbMonitorPage::timerSlot()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// We will start revieve Data WHEN
|
||||||
|
// SEE - void MainWindowNew::onTimerSlot()
|
||||||
|
// one of those left-tab-bar buttons are selected (ui->pbMainMenuBarVisualization->isChecked() || ui->pbMainMenuBarVisualization->isChecked())
|
||||||
|
//
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// 1 // L
|
||||||
|
if(!mSoc.empty())
|
||||||
|
ui->editBatteryChargeLevel->setText(QString::number(mSoc.last())); // mValues.soC
|
||||||
|
|
||||||
|
if(!mPackVoltage.empty()) {
|
||||||
|
//ui->editBatteryVoltage->setText(QString::number(mPackVoltage.last())); // mValues.packVoltage
|
||||||
|
ui->editBatteryVoltage->setText(QString::number(mPackVoltage.last(), 'f', 2)); // mValues.packVoltage
|
||||||
|
}
|
||||||
|
|
||||||
|
//addParamRow(ui->editNominalCapacity, mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
if(!mTempBattHigh.empty())
|
||||||
|
ui->editBatteryTemperature->setText(QString::number((int)mTempBattHigh.last())); // mValues.tempBattHigh
|
||||||
|
//ui->editBatteryTemperature->setText(QString::number(mTempBattHigh.last(), 'f', 2)); // mValues.tempBattHigh
|
||||||
|
|
||||||
|
// 1 // R
|
||||||
|
//addParamRow(ui->editModulesNumber, mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
//addParamRow(ui->editCellsNumber, mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
//// ui->editActualCapacity // NOT IN SETTINGS // AND NOT IN BMS_VALUES - valuesReceived(BMS_VALUES values)
|
||||||
|
if(!mTempBMSHigh.empty())
|
||||||
|
ui->editBmsTemperature->setText(QString::number((int)mTempBMSHigh.last())); // mValues.tempBMSHigh
|
||||||
|
//ui->editBmsTemperature->setText(QString::number(mTempBMSHigh.last(), 'f', 2)); // mValues.tempBMSHigh
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// 2 // L
|
||||||
|
if(!mCellVHigh.empty())
|
||||||
|
ui->editMaxVoltageOnCell->setText(QString::number(mCellVHigh.last(), 'f', 2)); // mValues.cVHigh
|
||||||
|
|
||||||
|
//// ui->editCellNumberLeft // NOT IN SETTINGS // AND NOT IN BMS_VALUES - valuesReceived(BMS_VALUES values)
|
||||||
|
|
||||||
|
if(!mPackCurrent.empty())
|
||||||
|
ui->editCircuit->setText(QString::number(mPackCurrent.last())); // mValues.packCurrent
|
||||||
|
// 2 // R
|
||||||
|
|
||||||
|
if(!mCellVLow.empty())
|
||||||
|
ui->editMinVoltageOnCell->setText(QString::number(mCellVLow.last(), 'f', 2)); // mValues.cVLow
|
||||||
|
|
||||||
|
//// ui->editCellNumberRight // NOT IN SETTINGS // AND NOT IN BMS_VALUES - valuesReceived(BMS_VALUES values)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//if (mUpdateValPlot)
|
||||||
|
//{
|
||||||
|
/*
|
||||||
|
int dataSize = mPackVoltage.size();
|
||||||
|
|
||||||
|
QVector<double> xAxis(dataSize);
|
||||||
|
for (int i = 0;i < mSeconds.size();i++) {
|
||||||
|
xAxis[i] = mSeconds[i];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Current and duty-plot
|
||||||
|
///int graphIndex = 0;
|
||||||
|
///ui->ivLCGraph->graph(graphIndex++)->setData(xAxis, mPackVoltage);
|
||||||
|
///ui->ivLCGraph->graph(graphIndex++)->setData(xAxis, mLCLoadVoltage);
|
||||||
|
///ui->ivLCGraph->graph(graphIndex++)->setData(xAxis, mLCLoadCurrent);
|
||||||
|
|
||||||
|
///graphIndex = 0;
|
||||||
|
///ui->ivHCGraph->graph(graphIndex++)->setData(xAxis, mHCLoadVoltage);
|
||||||
|
///ui->ivHCGraph->graph(graphIndex++)->setData(xAxis, mHCLoadCurrent);
|
||||||
|
|
||||||
|
///graphIndex = 0;
|
||||||
|
///ui->cellGraph->graph(graphIndex++)->setData(xAxis, mCellVHigh);
|
||||||
|
///ui->cellGraph->graph(graphIndex++)->setData(xAxis, mCellVAverage);
|
||||||
|
///ui->cellGraph->graph(graphIndex++)->setData(xAxis, mCellVLow);
|
||||||
|
|
||||||
|
///graphIndex = 0;
|
||||||
|
///mTempBMSLow.fill(0,1);
|
||||||
|
///ui->tempGraph->graph(graphIndex++)->setData(xAxis, mTempBMSHigh);
|
||||||
|
///ui->tempGraph->graph(graphIndex++)->setData(xAxis, mTempBMSAverage);
|
||||||
|
///ui->tempGraph->graph(graphIndex++)->setData(xAxis, mTempBMSLow);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// V
|
||||||
|
/*
|
||||||
|
double valVMax = mHCLoadVoltage.last();
|
||||||
|
double valVMid = mPackVoltage.last();
|
||||||
|
double valVMin = mLCLoadVoltage.last();
|
||||||
|
*/
|
||||||
|
/*// increas X
|
||||||
|
chartV->appendNextX();
|
||||||
|
// then set all new Ys
|
||||||
|
chartV->appendYToSeries(VoltageMax, valVMax);
|
||||||
|
chartV->appendYToSeries(VoltageMid, valVMid);
|
||||||
|
chartV->appendYToSeries(VoltageMin, valVMin);
|
||||||
|
|
||||||
|
ui->lbVMaxLegendVal->setText(QString("%1").arg(valVMax));
|
||||||
|
ui->lbVMidLegendVal->setText(QString("%1").arg(valVMid));
|
||||||
|
ui->lbVMinLegendVal->setText(QString("%1").arg(valVMin));
|
||||||
|
|
||||||
|
chartV->update();
|
||||||
|
ui->chartViewVoltage->repaint();
|
||||||
|
*/
|
||||||
|
|
||||||
|
// A
|
||||||
|
/*
|
||||||
|
double valAMax = mHCLoadCurrent.last();
|
||||||
|
double valAMid = mMCLoadCurrent_.last();
|
||||||
|
double valAMin = mLCLoadCurrent.last();
|
||||||
|
*/
|
||||||
|
/*// increas X
|
||||||
|
chartA->appendNextX();
|
||||||
|
// then set all new Ys
|
||||||
|
chartA->appendYToSeries(AmperageMax, valAMax);
|
||||||
|
chartA->appendYToSeries(AmperageMid, valAMid);
|
||||||
|
chartA->appendYToSeries(AmperageMin, valAMin);
|
||||||
|
|
||||||
|
ui->lbAMaxLegendVal->setText(QString("%1").arg(valAMax));
|
||||||
|
ui->lbAMidLegendVal->setText(QString("%1").arg(valAMid));
|
||||||
|
ui->lbAMinLegendVal->setText(QString("%1").arg(valAMin));
|
||||||
|
|
||||||
|
chartA->update();
|
||||||
|
ui->chartViewAmperage->repaint();
|
||||||
|
*/
|
||||||
|
|
||||||
|
// T
|
||||||
|
/*
|
||||||
|
double valTMax = mTempBattHigh.last();
|
||||||
|
double valTMid = mTempBattAverage.last();
|
||||||
|
double valTMin = mTempBattLow_.last();
|
||||||
|
*/
|
||||||
|
/*mTempBattLow_.fill(0,1);
|
||||||
|
// increas X
|
||||||
|
chartT->appendNextX();
|
||||||
|
// then set all new Ys
|
||||||
|
chartT->appendYToSeries(TemperatureMax, valTMax);
|
||||||
|
chartT->appendYToSeries(TemperatureMid, valTMid);
|
||||||
|
chartT->appendYToSeries(TemperatureMin, valTMin);
|
||||||
|
|
||||||
|
ui->lbTMaxLegendVal->setText(QString("%1").arg(valTMax));
|
||||||
|
ui->lbTMidLegendVal->setText(QString("%1").arg(valTMid));
|
||||||
|
ui->lbTMinLegendVal->setText(QString("%1").arg(valTMin));
|
||||||
|
|
||||||
|
chartT->update();
|
||||||
|
ui->chartViewTemperature->repaint();
|
||||||
|
*/
|
||||||
|
|
||||||
|
// C
|
||||||
|
/*
|
||||||
|
double valCMax = mCellVHigh.last();
|
||||||
|
double valCMid = mCellVAverage.last();
|
||||||
|
double valCMin = mCellVLow.last();
|
||||||
|
*/
|
||||||
|
/*// increas X
|
||||||
|
chartC->appendNextX();
|
||||||
|
// then set all new Ys
|
||||||
|
chartC->appendYToSeries(CellsMax, valCMax);
|
||||||
|
chartC->appendYToSeries(CellsMid, valCMid);
|
||||||
|
chartC->appendYToSeries(CellsMin, valCMin);
|
||||||
|
|
||||||
|
ui->lbCMaxLegendVal->setText(QString("%1").arg(valCMax));
|
||||||
|
ui->lbCMidLegendVal->setText(QString("%1").arg(valCMid));
|
||||||
|
ui->lbCMinLegendVal->setText(QString("%1").arg(valCMin));
|
||||||
|
|
||||||
|
chartC->update();
|
||||||
|
ui->chartViewCells->repaint();
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
ui->tempGraph->graph(graphIndex++)->setData(xAxis, mTempBattHigh);
|
||||||
|
ui->tempGraph->graph(graphIndex++)->setData(xAxis, mTempBattAverage);
|
||||||
|
ui->tempGraph->graph(graphIndex++)->setData(xAxis, mTempBattLow);
|
||||||
|
|
||||||
|
///if (ui->autoscaleButton->isChecked())
|
||||||
|
{
|
||||||
|
///ui->ivLCGraph->rescaleAxes();
|
||||||
|
///ui->ivHCGraph->rescaleAxes();
|
||||||
|
///ui->cellGraph->rescaleAxes();
|
||||||
|
ui->tempGraph->rescaleAxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
///ui->ivLCGraph->replot();
|
||||||
|
///ui->ivHCGraph->replot();
|
||||||
|
///ui->cellGraph->replot();
|
||||||
|
ui->tempGraph->replot();
|
||||||
|
///ui->cellBarGraph->replot();
|
||||||
|
|
||||||
|
mUpdateValPlot = false;
|
||||||
|
*/
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AkbMonitorPage::valuesReceived(BMS_VALUES values)
|
||||||
|
{
|
||||||
|
//ui->rtText->setValues(values);
|
||||||
|
|
||||||
|
const int maxS = 500;
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mSoc, values.soC, maxS);
|
||||||
|
appendDoubleAndTrunc(&mPackCurrent, values.packCurrent, maxS);
|
||||||
|
appendDoubleAndTrunc(&mPackVoltage, values.packVoltage, maxS);
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mLCLoadVoltage, values.loadLCVoltage, maxS);
|
||||||
|
appendDoubleAndTrunc(&mLCLoadCurrent, values.loadLCCurrent, maxS);
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mHCLoadVoltage, values.loadHCVoltage, maxS);
|
||||||
|
appendDoubleAndTrunc(&mHCLoadCurrent, values.loadHCCurrent, maxS);
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mAuxVoltage, values.auxVoltage, maxS);
|
||||||
|
appendDoubleAndTrunc(&mAuxCurrent, values.auxCurrent, maxS);
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mCellVHigh, values.cVHigh, maxS);
|
||||||
|
appendDoubleAndTrunc(&mCellVAverage, values.cVAverage, maxS);
|
||||||
|
appendDoubleAndTrunc(&mCellVLow, values.cVLow, maxS);
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mTempBMSHigh, values.tempBMSHigh, maxS);
|
||||||
|
appendDoubleAndTrunc(&mTempBMSAverage, values.tempBMSAverage, maxS);
|
||||||
|
//appendDoubleAndTrunc(&mTempBMSLow_, values.tempBMSLow_, maxS);
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mTempBattHigh, values.tempBattHigh, maxS);
|
||||||
|
appendDoubleAndTrunc(&mTempBattAverage, values.tempBattAverage, maxS);
|
||||||
|
//appendDoubleAndTrunc(&mTempBattLow_, values.tempBattLow_, maxS);
|
||||||
|
|
||||||
|
|
||||||
|
qint64 tNow = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
|
||||||
|
double elapsed = (double)(tNow - mLastUpdateTime) / 1000.0;
|
||||||
|
if (elapsed > 1.0) {
|
||||||
|
elapsed = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSecondCounter += elapsed;
|
||||||
|
|
||||||
|
appendDoubleAndTrunc(&mSeconds, mSecondCounter, maxS);
|
||||||
|
|
||||||
|
mLastUpdateTime = tNow;
|
||||||
|
|
||||||
|
mUpdateValPlot = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void AkbMonitorPage::cellsReceived(int cellCount, QVector<double> cellVoltageArray)
|
||||||
|
{
|
||||||
|
QVector<double> dataxNew;
|
||||||
|
dataxNew.clear();
|
||||||
|
QVector<double> datayNormal;
|
||||||
|
datayNormal.clear();
|
||||||
|
QVector<double> datayBalance;
|
||||||
|
datayBalance.clear();
|
||||||
|
QVector<QString> labels;
|
||||||
|
int indexPointer;
|
||||||
|
|
||||||
|
double cellHardUnder = mDieBieMS->bmsConfig()->getParamDouble("cellHardUnderVoltage");
|
||||||
|
double cellHardOver = mDieBieMS->bmsConfig()->getParamDouble("cellHardOverVoltage");
|
||||||
|
|
||||||
|
for(indexPointer = 0; indexPointer < cellCount; indexPointer++){
|
||||||
|
dataxNew.append(indexPointer + 1);
|
||||||
|
|
||||||
|
if(cellVoltageArray[indexPointer] < 0.0){
|
||||||
|
datayNormal.append(0.0);
|
||||||
|
datayBalance.append(fabs(cellVoltageArray[indexPointer]));
|
||||||
|
}else{
|
||||||
|
datayNormal.append(fabs(cellVoltageArray[indexPointer]));
|
||||||
|
datayBalance.append(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString voltageString = QStringLiteral("%1V (C").arg(fabs(cellVoltageArray[indexPointer]), 0, 'f',3);
|
||||||
|
labels.append(voltageString + QString::number(indexPointer) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
//QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
|
||||||
|
//textTicker->addTicks(dataxNew, labels);
|
||||||
|
|
||||||
|
//ui->cellBarGraph->xAxis->setTicker(textTicker);
|
||||||
|
//ui->cellBarGraph->xAxis->setRange(0.5, indexPointer + 0.5);
|
||||||
|
//ui->cellBarGraph->yAxis->setRange(cellHardUnder, cellHardOver);
|
||||||
|
//barsNormal->setData(dataxNew, datayNormal);
|
||||||
|
//barsBalance->setData(dataxNew, datayBalance);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void AkbMonitorPage::appendDoubleAndTrunc(QVector<double> *vec, double num, int maxSize)
|
||||||
|
{
|
||||||
|
vec->append(num);
|
||||||
|
|
||||||
|
if(vec->size() > maxSize) {
|
||||||
|
vec->remove(0, vec->size() - maxSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AkbMonitorPage::clearControlls()
|
||||||
|
{
|
||||||
|
// 1 // L
|
||||||
|
ui->editBatteryChargeLevel ->clear(); // mValues.soC
|
||||||
|
ui->editBatteryVoltage ->clear(); // mValues.packVoltage
|
||||||
|
ui->editNominalCapacity ->clear(); //, mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
ui->editBatteryTemperature ->clear(); // mValues.tempBattHigh
|
||||||
|
// 1 // R ->clear();
|
||||||
|
ui->editModulesNumber ->clear(); //, mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
ui->editCellsNumber ->clear(); //, mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
ui->editActualCapacity ->clear(); // NOT IN SETTINGS
|
||||||
|
ui->editBmsTemperature ->clear(); // mValues.tempBMSHigh
|
||||||
|
// ->clear();
|
||||||
|
// 2 // L ->clear();
|
||||||
|
ui->editMaxVoltageOnCell ->clear(); // mValues.cVHigh
|
||||||
|
ui->editCellNumberLeft ->clear(); // NOT IN SETTINGS
|
||||||
|
ui->editCircuit ->clear(); // mValues.packCurrent
|
||||||
|
// 2 // R ->clear();
|
||||||
|
ui->editMinVoltageOnCell ->clear(); // mValues.cVLow
|
||||||
|
ui->editCellNumberRight ->clear(); // NOT IN SETTINGS
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkbMonitorPage::onLoadParams()
|
||||||
|
{
|
||||||
|
///QHash<QString, ConfigParam> mParams;
|
||||||
|
|
||||||
|
//addParamRow(ui->editPointZeroDetectorValue, mDieBieMS->bmsConfig(), "shuntLCFactor");
|
||||||
|
//ui->specificationsTab->addRowSeparator(tr("Pack configuration"));
|
||||||
|
|
||||||
|
// Серийный номер * //ui->editSerialNumber
|
||||||
|
getSerialNumber(ui->editSerialNumber, mDieBieMS->bmsConfig(), "notUsedCurrentThreshold");
|
||||||
|
// 1 // L
|
||||||
|
// ui->editBatteryChargeLevel // mValues.soC
|
||||||
|
// ui->editBatteryVoltage // mValues.packVoltage
|
||||||
|
addParamRow(ui->editNominalCapacity, mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
// ui->editBatteryTemperature // mValues.tempBattHigh
|
||||||
|
// 1 // R
|
||||||
|
addParamRow(ui->editModulesNumber, mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
addParamRow(ui->editCellsNumber, mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
//// ui->editActualCapacity // NOT IN BMS_CONFIG
|
||||||
|
// ui->editBmsTemperature // mValues.tempBMSHigh
|
||||||
|
|
||||||
|
// 2 // L
|
||||||
|
// ui->editMaxVoltageOnCell // mValues.cVHigh
|
||||||
|
//// ui->editCellNumberLeft // NOT IN BMS_CONFIG
|
||||||
|
// ui->editCircuit // mValues.packCurrent
|
||||||
|
// 2 // R
|
||||||
|
// ui->editMinVoltageOnCell // mValues.cVLow
|
||||||
|
//// ui->editCellNumberRight // NOT IN BMS_CONFIG
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool AkbMonitorPage::addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
QWidget *editor = params->getEditor(paramName);
|
||||||
|
QString name = params->getLongName(paramName);
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
//int row = rowCount();
|
||||||
|
//setRowCount(row + 1);
|
||||||
|
//QTableWidgetItem *item = new QTableWidgetItem(name);
|
||||||
|
//item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||||
|
//setItem(row, 0, item);
|
||||||
|
//setCellWidget(row, 1, editor);
|
||||||
|
//edit->setText(editor->);
|
||||||
|
|
||||||
|
auto vtype = editor->property("type");
|
||||||
|
auto type = vtype.toInt();
|
||||||
|
//CFG_T_UNDEFINED = 0,
|
||||||
|
if(type == 1) // CFG_T_DOUBLE,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toDouble();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 2) // CFG_T_INT,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toInt();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 3) // CFG_T_QSTRING,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toString();
|
||||||
|
edit->setText(val);
|
||||||
|
}
|
||||||
|
else if(type == 4) // CFG_T_ENUM,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toInt();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 5) // CFG_T_BOOL
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toBool();
|
||||||
|
edit->setText(val ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vsuffix = editor->property("suffix");
|
||||||
|
auto suffix = vsuffix.toString();
|
||||||
|
auto veditorDecimalsDouble = editor->property("editorDecimalsDouble");
|
||||||
|
auto editorDecimalsDouble = veditorDecimalsDouble.toDouble();
|
||||||
|
auto veditAsPercentage = editor->property("editAsPercentage");
|
||||||
|
auto editAsPercentage = veditAsPercentage.toBool();
|
||||||
|
|
||||||
|
res = true;
|
||||||
|
//resizeColumnToContents(0);
|
||||||
|
//resizeRowsToContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
|
||||||
90
akbmonitorpage.h
Normal file
90
akbmonitorpage.h
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#ifndef AKBMONITORPAGE_H
|
||||||
|
#define AKBMONITORPAGE_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class AkbMonitorPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AkbMonitorPage : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AkbMonitorPage(QWidget *parent = nullptr);
|
||||||
|
~AkbMonitorPage();
|
||||||
|
|
||||||
|
void clearControlls();
|
||||||
|
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onLoadParams();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void timerSlot();
|
||||||
|
void valuesReceived(BMS_VALUES values);
|
||||||
|
// void cellsReceived(int cellCount, QVector<double> cellVoltageArray);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::AkbMonitorPage *ui;
|
||||||
|
|
||||||
|
BMSInterface *mDieBieMS;
|
||||||
|
|
||||||
|
|
||||||
|
// bool addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName);
|
||||||
|
|
||||||
|
//
|
||||||
|
QVector<double> mSoc;
|
||||||
|
|
||||||
|
QVector<double> mPackVoltage;
|
||||||
|
QVector<double> mPackCurrent;
|
||||||
|
|
||||||
|
QVector<double> mLCLoadVoltage;
|
||||||
|
QVector<double> mLCLoadCurrent;
|
||||||
|
|
||||||
|
QVector<double> mHCLoadVoltage;
|
||||||
|
QVector<double> mHCLoadCurrent;
|
||||||
|
|
||||||
|
QVector<double> mChargerVoltage;
|
||||||
|
|
||||||
|
QVector<double> mAuxVoltage;
|
||||||
|
QVector<double> mAuxCurrent;
|
||||||
|
|
||||||
|
QVector<double> mCellVHigh;
|
||||||
|
QVector<double> mCellVAverage;
|
||||||
|
QVector<double> mCellVLow;
|
||||||
|
|
||||||
|
QVector<double> mTempBMSHigh;
|
||||||
|
QVector<double> mTempBMSAverage;
|
||||||
|
QVector<double> mTempBMSLow;
|
||||||
|
|
||||||
|
QVector<double> mTempBattHigh;
|
||||||
|
QVector<double> mTempBattAverage;
|
||||||
|
QVector<double> mTempBattLow;
|
||||||
|
|
||||||
|
QVector<double> mHumidity;
|
||||||
|
|
||||||
|
QVector<double> mSeconds;
|
||||||
|
|
||||||
|
double mSecondCounter;
|
||||||
|
qint64 mLastUpdateTime;
|
||||||
|
bool mUpdateValPlot;
|
||||||
|
|
||||||
|
QTimer* mTimer;
|
||||||
|
|
||||||
|
void initForPlot();
|
||||||
|
|
||||||
|
void initForCharts();
|
||||||
|
|
||||||
|
void appendDoubleAndTrunc(QVector<double> *vec, double num, int maxSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AKBMONITORPAGE_H
|
||||||
1520
akbmonitorpage.ui
Normal file
1520
akbmonitorpage.ui
Normal file
File diff suppressed because it is too large
Load Diff
74
android/AndroidManifest.xml
Normal file
74
android/AndroidManifest.xml
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<manifest package="ennoid.bms" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1" android:versionCode="1" android:installLocation="auto">
|
||||||
|
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="ENNOID" android:icon="@drawable/icon">
|
||||||
|
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="ENNOID BMS Tool" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
<!-- Application arguments -->
|
||||||
|
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
|
||||||
|
<!-- Application arguments -->
|
||||||
|
<meta-data android:name="android.app.lib_name" android:value="ENNOID-BMS-Tool"/>
|
||||||
|
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||||
|
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||||
|
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||||
|
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||||
|
<!-- Deploy Qt libs as part of package -->
|
||||||
|
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
|
||||||
|
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
|
||||||
|
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
|
||||||
|
<!-- Run with local libs -->
|
||||||
|
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
||||||
|
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||||
|
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
|
||||||
|
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
||||||
|
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
||||||
|
<!-- Messages maps -->
|
||||||
|
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||||
|
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||||
|
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||||
|
<!-- Messages maps -->
|
||||||
|
<!-- Splash screen -->
|
||||||
|
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
|
||||||
|
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
|
||||||
|
<!-- Splash screen -->
|
||||||
|
<!-- Background running -->
|
||||||
|
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||||
|
application still try to draw after
|
||||||
|
"applicationStateChanged(Qt::ApplicationSuspended)"
|
||||||
|
signal is sent! -->
|
||||||
|
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||||
|
<!-- Background running -->
|
||||||
|
<!-- auto screen scale factor -->
|
||||||
|
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||||
|
<!-- auto screen scale factor -->
|
||||||
|
<!-- extract android style -->
|
||||||
|
<!-- available android:values :
|
||||||
|
* full - useful QWidget & Quick Controls 1 apps
|
||||||
|
* minimal - useful for Quick Controls 2 apps, it is much faster than "full"
|
||||||
|
* none - useful for apps that don't use any of the above Qt modules
|
||||||
|
-->
|
||||||
|
<meta-data android:name="android.app.extract_android_style" android:value="full"/>
|
||||||
|
<!-- extract android style -->
|
||||||
|
</activity>
|
||||||
|
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="29"/>
|
||||||
|
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||||
|
|
||||||
|
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||||
|
Remove the comment if you do not require these default permissions. -->
|
||||||
|
<!-- %%INSERT_PERMISSIONS -->
|
||||||
|
|
||||||
|
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||||
|
Remove the comment if you do not require these default features. -->
|
||||||
|
<!-- %%INSERT_FEATURES -->
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||||
|
<uses-permission android:name="android.permission.SET_ORIENTATION"/>
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
</manifest>
|
||||||
55
android/build.gradle
Normal file
55
android/build.gradle
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
/*******************************************************
|
||||||
|
* The following variables:
|
||||||
|
* - androidBuildToolsVersion,
|
||||||
|
* - androidCompileSdkVersion
|
||||||
|
* - qt5AndroidDir - holds the path to qt android files
|
||||||
|
* needed to build any Qt application
|
||||||
|
* on Android.
|
||||||
|
*
|
||||||
|
* are defined in gradle.properties file. This file is
|
||||||
|
* updated by QtCreator and androiddeployqt tools.
|
||||||
|
* Changing them manually might break the compilation!
|
||||||
|
*******************************************************/
|
||||||
|
|
||||||
|
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||||
|
buildToolsVersion androidBuildToolsVersion
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
manifest.srcFile 'AndroidManifest.xml'
|
||||||
|
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
|
||||||
|
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
|
||||||
|
res.srcDirs = [qt5AndroidDir + '/res', 'res']
|
||||||
|
resources.srcDirs = ['src']
|
||||||
|
renderscript.srcDirs = ['src']
|
||||||
|
assets.srcDirs = ['assets']
|
||||||
|
jniLibs.srcDirs = ['libs']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#Mon Feb 20 10:43:22 EST 2017
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4-bin.zip
|
||||||
172
android/gradlew
vendored
Normal file
172
android/gradlew
vendored
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS="-Xmx1024m -Dfile.encoding=UTF-8"
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save ( ) {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
BIN
android/res/drawable-hdpi/icon.png
Normal file
BIN
android/res/drawable-hdpi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 546 B |
BIN
android/res/drawable-ldpi/icon.png
Normal file
BIN
android/res/drawable-ldpi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 363 B |
BIN
android/res/drawable-mdpi/icon.png
Normal file
BIN
android/res/drawable-mdpi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 421 B |
25
android/res/values/libs.xml
Normal file
25
android/res/values/libs.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<array name="qt_sources">
|
||||||
|
<item>https://download.qt.io/ministro/android/qt5/qt-5.9</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<!-- The following is handled automatically by the deployment tool. It should
|
||||||
|
not be edited manually. -->
|
||||||
|
|
||||||
|
<array name="bundled_libs">
|
||||||
|
<!-- %%INSERT_EXTRA_LIBS%% -->
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="qt_libs">
|
||||||
|
<!-- %%INSERT_QT_LIBS%% -->
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="bundled_in_lib">
|
||||||
|
<!-- %%INSERT_BUNDLED_IN_LIB%% -->
|
||||||
|
</array>
|
||||||
|
<array name="bundled_in_assets">
|
||||||
|
<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->
|
||||||
|
</array>
|
||||||
|
|
||||||
|
</resources>
|
||||||
301
bleuart.cpp
Normal file
301
bleuart.cpp
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
/*
|
||||||
|
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 "bleuart.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QLowEnergyConnectionParameters>
|
||||||
|
|
||||||
|
BleUart::BleUart(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
mControl = 0;
|
||||||
|
mService = 0;
|
||||||
|
mUartServiceFound = false;
|
||||||
|
mConnectDone = false;
|
||||||
|
|
||||||
|
mServiceUuid = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
|
||||||
|
mRxUuid = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
|
||||||
|
mTxUuid = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
|
||||||
|
|
||||||
|
mDeviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
|
||||||
|
|
||||||
|
connect(mDeviceDiscoveryAgent, SIGNAL(deviceDiscovered(const QBluetoothDeviceInfo&)),
|
||||||
|
this, SLOT(addDevice(const QBluetoothDeviceInfo&)));
|
||||||
|
connect(mDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)),
|
||||||
|
this, SLOT(deviceScanError(QBluetoothDeviceDiscoveryAgent::Error)));
|
||||||
|
connect(mDeviceDiscoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::startScan()
|
||||||
|
{
|
||||||
|
mDevs.clear();
|
||||||
|
mDeviceDiscoveryAgent->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::startConnect(QString addr)
|
||||||
|
{
|
||||||
|
disconnectBle();
|
||||||
|
|
||||||
|
mUartServiceFound = false;
|
||||||
|
mConnectDone = false;
|
||||||
|
|
||||||
|
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||||
|
// Create BT Controller from unique device UUID stored as addr. Creating
|
||||||
|
// a controller using a devices address is not supported on macOS or iOS.
|
||||||
|
QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo();
|
||||||
|
deviceInfo.setDeviceUuid(QBluetoothUuid(addr));
|
||||||
|
mControl = new QLowEnergyController(deviceInfo);
|
||||||
|
|
||||||
|
#else
|
||||||
|
mControl = new QLowEnergyController(QBluetoothAddress(addr));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mControl->setRemoteAddressType(QLowEnergyController::RandomAddress);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
connect(mControl, SIGNAL(serviceDiscovered(QBluetoothUuid)),
|
||||||
|
this, SLOT(serviceDiscovered(QBluetoothUuid)));
|
||||||
|
connect(mControl, SIGNAL(discoveryFinished()),
|
||||||
|
this, SLOT(serviceScanDone()));
|
||||||
|
connect(mControl, SIGNAL(error(QLowEnergyController::Error)),
|
||||||
|
this, SLOT(controllerError(QLowEnergyController::Error)));
|
||||||
|
connect(mControl, SIGNAL(connected()),
|
||||||
|
this, SLOT(deviceConnected()));
|
||||||
|
connect(mControl, SIGNAL(disconnected()),
|
||||||
|
this, SLOT(deviceDisconnected()));
|
||||||
|
connect(mControl, SIGNAL(stateChanged(QLowEnergyController::ControllerState)),
|
||||||
|
this, SLOT(controlStateChanged(QLowEnergyController::ControllerState)));
|
||||||
|
connect(mControl, SIGNAL(connectionUpdated(QLowEnergyConnectionParameters)),
|
||||||
|
this, SLOT(connectionUpdated(QLowEnergyConnectionParameters)));
|
||||||
|
|
||||||
|
mControl->connectToDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::disconnectBle()
|
||||||
|
{
|
||||||
|
if (mService) {
|
||||||
|
delete mService;
|
||||||
|
mService = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mControl) {
|
||||||
|
mControl->disconnectFromDevice();
|
||||||
|
delete mControl;
|
||||||
|
mControl = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BleUart::isConnected()
|
||||||
|
{
|
||||||
|
return mControl != 0 && mConnectDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BleUart::isConnecting()
|
||||||
|
{
|
||||||
|
return mControl && !mConnectDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::writeData(QByteArray data)
|
||||||
|
{
|
||||||
|
if (isConnected()) {
|
||||||
|
const QLowEnergyCharacteristic rxChar = mService->characteristic(QBluetoothUuid(QUuid(mRxUuid)));
|
||||||
|
if (rxChar.isValid()) {
|
||||||
|
while(data.size() > 20) {
|
||||||
|
mService->writeCharacteristic(rxChar, data.mid(0, 20),
|
||||||
|
QLowEnergyService::WriteWithoutResponse);
|
||||||
|
data.remove(0, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
mService->writeCharacteristic(rxChar, data, QLowEnergyService::WriteWithoutResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::addDevice(const QBluetoothDeviceInfo &dev)
|
||||||
|
{
|
||||||
|
if (dev.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
|
||||||
|
qDebug() << "BLE scan found device:" << dev.name();
|
||||||
|
|
||||||
|
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
|
||||||
|
// macOS and iOS do not expose the hardware address of BLTE devices, must use
|
||||||
|
// the OS generated UUID.
|
||||||
|
mDevs.insert(dev.deviceUuid().toString(), dev.name());
|
||||||
|
#else
|
||||||
|
mDevs.insert(dev.address().toString(), dev.name());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
emit scanDone(mDevs, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::scanFinished()
|
||||||
|
{
|
||||||
|
qDebug() << "BLE scan finished";
|
||||||
|
emit scanDone(mDevs, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::deviceScanError(QBluetoothDeviceDiscoveryAgent::Error e)
|
||||||
|
{
|
||||||
|
qWarning() << "BLE Scan error:" << e;
|
||||||
|
|
||||||
|
mDevs.clear();
|
||||||
|
emit scanDone(mDevs, true);
|
||||||
|
//emit bleError(tr("BLE Scan error: ") + Utility::QEnumToQString(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::serviceDiscovered(const QBluetoothUuid &gatt)
|
||||||
|
{
|
||||||
|
if (gatt==QBluetoothUuid(QUuid(mServiceUuid))){
|
||||||
|
qDebug() << "BLE UART service found!";
|
||||||
|
mUartServiceFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::serviceScanDone()
|
||||||
|
{
|
||||||
|
if (mService) {
|
||||||
|
delete mService;
|
||||||
|
mService = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUartServiceFound) {
|
||||||
|
qDebug() << "Connecting to BLE UART service";
|
||||||
|
mService = mControl->createServiceObject(QBluetoothUuid(QUuid(mServiceUuid)), this);
|
||||||
|
|
||||||
|
connect(mService, SIGNAL(stateChanged(QLowEnergyService::ServiceState)),
|
||||||
|
this, SLOT(serviceStateChanged(QLowEnergyService::ServiceState)));
|
||||||
|
connect(mService, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),
|
||||||
|
this, SLOT(updateData(QLowEnergyCharacteristic,QByteArray)));
|
||||||
|
connect(mService, SIGNAL(descriptorWritten(QLowEnergyDescriptor,QByteArray)),
|
||||||
|
this, SLOT(confirmedDescriptorWrite(QLowEnergyDescriptor,QByteArray)));
|
||||||
|
|
||||||
|
mService->discoverDetails();
|
||||||
|
} else {
|
||||||
|
qWarning() << "BLE UART service not found";
|
||||||
|
disconnectBle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::controllerError(QLowEnergyController::Error e)
|
||||||
|
{
|
||||||
|
qWarning() << "BLE error:" << e;
|
||||||
|
//disconnectBle();
|
||||||
|
//emit bleError(tr("BLE error: ") + Utility::QEnumToQString(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::deviceConnected()
|
||||||
|
{
|
||||||
|
qDebug() << "BLE device connected";
|
||||||
|
mControl->discoverServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::deviceDisconnected()
|
||||||
|
{
|
||||||
|
qDebug() << "BLE service disconnected";
|
||||||
|
disconnectBle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::serviceStateChanged(QLowEnergyService::ServiceState s)
|
||||||
|
{
|
||||||
|
// A descriptor can only be written if the service is in the ServiceDiscovered state
|
||||||
|
switch (s) {
|
||||||
|
case QLowEnergyService::ServiceDiscovered: {
|
||||||
|
//looking for the TX characteristic
|
||||||
|
const QLowEnergyCharacteristic txChar = mService->characteristic(
|
||||||
|
QBluetoothUuid(QUuid(mTxUuid)));
|
||||||
|
|
||||||
|
if (!txChar.isValid()){
|
||||||
|
qDebug() << "BLE Tx characteristic not found";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//looking for the RX characteristic
|
||||||
|
const QLowEnergyCharacteristic rxChar = mService->characteristic(QBluetoothUuid(QUuid(mRxUuid)));
|
||||||
|
|
||||||
|
if (!rxChar.isValid()) {
|
||||||
|
qDebug() << "BLE Rx characteristic not found";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bluetooth LE spec Where a characteristic can be notified, a Client Characteristic Configuration descriptor
|
||||||
|
// shall be included in that characteristic as required by the Bluetooth Core Specification
|
||||||
|
// Tx notify is enabled
|
||||||
|
mNotificationDescTx = txChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
|
||||||
|
|
||||||
|
if (mNotificationDescTx.isValid()) {
|
||||||
|
// enable notification
|
||||||
|
mService->writeDescriptor(mNotificationDescTx, QByteArray::fromHex("0100"));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::updateData(const QLowEnergyCharacteristic &c, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (c.uuid() == QBluetoothUuid(QUuid(mTxUuid))) {
|
||||||
|
emit dataRx(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::confirmedDescriptorWrite(const QLowEnergyDescriptor &d, const QByteArray &value)
|
||||||
|
{
|
||||||
|
if (d.isValid() && d == mNotificationDescTx && value == QByteArray("0000")) {
|
||||||
|
//disabled notifications -> assume disconnect intent
|
||||||
|
disconnectBle();
|
||||||
|
} else {
|
||||||
|
mConnectDone = true;
|
||||||
|
// emit connected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::controlStateChanged(QLowEnergyController::ControllerState state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
// qDebug() << state;
|
||||||
|
|
||||||
|
// if (state == QLowEnergyController::ConnectedState) {
|
||||||
|
// QLowEnergyConnectionParameters param;
|
||||||
|
// param.setIntervalRange(7.5, 7.5);
|
||||||
|
// param.setSupervisionTimeout(10000);
|
||||||
|
// param.setLatency(0);
|
||||||
|
// mControl->requestConnectionUpdate(param);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void BleUart::connectionUpdated(const QLowEnergyConnectionParameters &newParameters)
|
||||||
|
{
|
||||||
|
(void)newParameters;
|
||||||
|
qDebug() << "BLE connection parameters updated";
|
||||||
|
}
|
||||||
89
bleuart.h
Normal file
89
bleuart.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BLEUART_H
|
||||||
|
#define BLEUART_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QBluetoothDeviceDiscoveryAgent>
|
||||||
|
#include <QBluetoothDeviceInfo>
|
||||||
|
#include <QLowEnergyController>
|
||||||
|
#include <QLowEnergyService>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
class BleUart : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BleUart(QObject *parent = 0);
|
||||||
|
|
||||||
|
Q_INVOKABLE void startScan();
|
||||||
|
Q_INVOKABLE void startConnect(QString addr);
|
||||||
|
Q_INVOKABLE void disconnectBle();
|
||||||
|
Q_INVOKABLE bool isConnected();
|
||||||
|
Q_INVOKABLE bool isConnecting();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void dataRx(QByteArray data);
|
||||||
|
void scanDone(QVariantMap devs, bool done);
|
||||||
|
void bleError(QString info);
|
||||||
|
void connected();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void writeData(QByteArray data);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void addDevice(const QBluetoothDeviceInfo&dev);
|
||||||
|
void scanFinished();
|
||||||
|
void deviceScanError(QBluetoothDeviceDiscoveryAgent::Error e);
|
||||||
|
|
||||||
|
void serviceDiscovered(const QBluetoothUuid &);
|
||||||
|
void serviceScanDone();
|
||||||
|
void controllerError(QLowEnergyController::Error);
|
||||||
|
void deviceConnected();
|
||||||
|
void deviceDisconnected();
|
||||||
|
|
||||||
|
void serviceStateChanged(QLowEnergyService::ServiceState s);
|
||||||
|
void updateData(const QLowEnergyCharacteristic &c, const QByteArray &value);
|
||||||
|
void confirmedDescriptorWrite(const QLowEnergyDescriptor &d, const QByteArray &value);
|
||||||
|
|
||||||
|
void controlStateChanged(QLowEnergyController::ControllerState state);
|
||||||
|
void connectionUpdated(const QLowEnergyConnectionParameters &newParameters);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QBluetoothDeviceDiscoveryAgent *mDeviceDiscoveryAgent;
|
||||||
|
QLowEnergyController *mControl;
|
||||||
|
QLowEnergyService *mService;
|
||||||
|
QLowEnergyDescriptor mNotificationDescTx;
|
||||||
|
QVariantMap mDevs;
|
||||||
|
bool mUartServiceFound;
|
||||||
|
bool mConnectDone;
|
||||||
|
QString mServiceUuid;
|
||||||
|
QString mRxUuid;
|
||||||
|
QString mTxUuid;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BLEUART_H
|
||||||
894
bmsinterface.cpp
Normal file
894
bmsinterface.cpp
Normal file
@@ -0,0 +1,894 @@
|
|||||||
|
/**
|
||||||
|
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 "bmsinterface.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QHostInfo>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <utility.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
#include <QSerialPortInfo>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BMSInterface::BMSInterface(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
mbmsConfig = new ConfigParams(this);
|
||||||
|
mInfoConfig = new ConfigParams(this);
|
||||||
|
mPacket = new Packet(this);
|
||||||
|
mCommands = new Commands(this);
|
||||||
|
|
||||||
|
// Compatible firmwares
|
||||||
|
mFwVersionReceived = false;
|
||||||
|
mFwRetries = 0;
|
||||||
|
mFwPollCnt = 0;
|
||||||
|
mFwTxt = "x.x";
|
||||||
|
mIsUploadingFw = false;
|
||||||
|
|
||||||
|
mTimer = new QTimer(this);
|
||||||
|
mTimer->setInterval(20);
|
||||||
|
mTimer->start();
|
||||||
|
|
||||||
|
mLastConnType = static_cast<conn_t>(QSettings().value("connection_type", CONN_NONE).toInt());
|
||||||
|
mLastTcpServer = mSettings.value("tcp_server", "127.0.0.1").toString();
|
||||||
|
mLastTcpPort = mSettings.value("tcp_port", 65102).toInt();
|
||||||
|
|
||||||
|
mSendCanBefore = false;
|
||||||
|
mCanIdBefore = 0;
|
||||||
|
mWasConnected = false;
|
||||||
|
mAutoconnectOngoing = false;
|
||||||
|
mAutoconnectProgress = 0.0;
|
||||||
|
|
||||||
|
// Serial
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
mSerialPort = new QSerialPort(this);
|
||||||
|
mLastSerialPort = "";
|
||||||
|
mLastSerialBaud = 0;
|
||||||
|
|
||||||
|
connect(mSerialPort, SIGNAL(readyRead()),this, SLOT(serialDataAvailable()));
|
||||||
|
connect(mSerialPort, SIGNAL(error(QSerialPort::SerialPortError)),this, SLOT(serialPortError(QSerialPort::SerialPortError)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TCP
|
||||||
|
mTcpSocket = new QTcpSocket(this);
|
||||||
|
mTcpConnected = false;
|
||||||
|
mLastTcpServer = QSettings().value("tcp_server").toString();
|
||||||
|
mLastTcpPort = QSettings().value("tcp_port").toInt();
|
||||||
|
|
||||||
|
connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(tcpInputDataAvailable()));
|
||||||
|
connect(mTcpSocket, SIGNAL(connected()), this, SLOT(tcpInputConnected()));
|
||||||
|
connect(mTcpSocket, SIGNAL(disconnected()),this, SLOT(tcpInputDisconnected()));
|
||||||
|
connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(tcpInputError(QAbstractSocket::SocketError)));
|
||||||
|
|
||||||
|
// BLE
|
||||||
|
|
||||||
|
mBleUart = new BleUart(this);
|
||||||
|
mLastBleAddr = QSettings().value("ble_addr").toString();
|
||||||
|
|
||||||
|
int size = mSettings.beginReadArray("bleNames");
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
mSettings.setArrayIndex(i);
|
||||||
|
QString address = mSettings.value("address").toString();
|
||||||
|
QString name = mSettings.value("name").toString();
|
||||||
|
mBleNames.insert(address, name);
|
||||||
|
}
|
||||||
|
mSettings.endArray();
|
||||||
|
|
||||||
|
connect(mBleUart, SIGNAL(dataRx(QByteArray)), this, SLOT(bleDataRx(QByteArray)));
|
||||||
|
|
||||||
|
mCommands->setbmsConfig(mbmsConfig);
|
||||||
|
|
||||||
|
// Other signals/slots
|
||||||
|
connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot()));
|
||||||
|
connect(mPacket, SIGNAL(dataToSend(QByteArray&)),this, SLOT(packetDataToSend(QByteArray&)));
|
||||||
|
connect(mPacket, SIGNAL(packetReceived(QByteArray&)),this, SLOT(packetReceived(QByteArray&)));
|
||||||
|
connect(mCommands, SIGNAL(dataToSend(QByteArray&)),this, SLOT(cmdDataToSend(QByteArray&)));
|
||||||
|
connect(mCommands, SIGNAL(fwVersionReceived(int,int,QString,QByteArray)),this, SLOT(fwVersionReceived(int,int,QString,QByteArray)));
|
||||||
|
connect(mCommands, SIGNAL(ackReceived(QString)), this, SLOT(ackReceived(QString)));
|
||||||
|
connect(mbmsConfig, SIGNAL(updated()), this, SLOT(bmsconfUpdated()));
|
||||||
|
connect(mbmsConfig, SIGNAL(stored()), this, SLOT(bmsconfStored()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BMSInterface::~BMSInterface()
|
||||||
|
{
|
||||||
|
mSettings.beginWriteArray("bleNames");
|
||||||
|
|
||||||
|
QHashIterator<QString, QString> i(mBleNames);
|
||||||
|
int ind = 0;
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
mSettings.setArrayIndex(ind);
|
||||||
|
mSettings.setValue("address", i.key());
|
||||||
|
mSettings.setValue("name", i.value());
|
||||||
|
ind++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSettings.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
Commands *BMSInterface::commands() const
|
||||||
|
{
|
||||||
|
return mCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigParams *BMSInterface::bmsConfig()
|
||||||
|
{
|
||||||
|
return mbmsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigParams *BMSInterface::infoConfig()
|
||||||
|
{
|
||||||
|
return mInfoConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList BMSInterface::getSupportedFirmwares()
|
||||||
|
{
|
||||||
|
QList<QPair<int, int> > fwPairs = getSupportedFirmwarePairs();
|
||||||
|
QStringList fws;
|
||||||
|
|
||||||
|
for (int i = 0;i < fwPairs.size();i++) {
|
||||||
|
QString tmp;
|
||||||
|
tmp.sprintf("%d.%d", fwPairs.at(i).first, fwPairs.at(i).second);
|
||||||
|
fws.append(tmp);
|
||||||
|
}
|
||||||
|
return fws;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QPair<int, int> > BMSInterface::getSupportedFirmwarePairs()
|
||||||
|
{
|
||||||
|
QList<QPair<int, int> > fws;
|
||||||
|
|
||||||
|
ConfigParam *p = mInfoConfig->getParam("fw_version");
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
QStringList strs = p->enumNames;
|
||||||
|
|
||||||
|
for (int i = 0;i < strs.size();i++) {
|
||||||
|
QStringList mami = strs.at(i).split(".");
|
||||||
|
QPair<int, int> fw = qMakePair(mami.at(0).toInt(), mami.at(1).toInt());
|
||||||
|
fws.append(fw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fws;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BMSInterface::getFirmwareNow()
|
||||||
|
{
|
||||||
|
return mFwTxt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::emitStatusMessage(const QString &msg, bool isGood)
|
||||||
|
{
|
||||||
|
emit statusMessage(msg, isGood);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::emitMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText)
|
||||||
|
{
|
||||||
|
emit messageDialog(title, msg, isGood, richText);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMSInterface::fwRx()
|
||||||
|
{
|
||||||
|
return mFwVersionReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BMSInterface::storeSettings()
|
||||||
|
{
|
||||||
|
mSettings.beginWriteArray("bleNames");
|
||||||
|
QHashIterator<QString, QString> i(mBleNames);
|
||||||
|
int ind = 0;
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
mSettings.setArrayIndex(ind);
|
||||||
|
mSettings.setValue("address", i.key());
|
||||||
|
mSettings.setValue("name", i.value());
|
||||||
|
ind++;
|
||||||
|
}
|
||||||
|
mSettings.endArray();
|
||||||
|
|
||||||
|
mSettings.beginWriteArray("profiles");
|
||||||
|
for (int i = 0; i < mProfiles.size(); ++i) {
|
||||||
|
MCCONF_TEMP cfg = mProfiles.value(i).value<MCCONF_TEMP>();
|
||||||
|
mSettings.setArrayIndex(i);
|
||||||
|
mSettings.setValue("current_min_scale", cfg.current_min_scale);
|
||||||
|
mSettings.setValue("current_max_scale", cfg.current_max_scale);
|
||||||
|
mSettings.setValue("erpm_or_speed_min", cfg.erpm_or_speed_min);
|
||||||
|
mSettings.setValue("erpm_or_speed_max", cfg.erpm_or_speed_max);
|
||||||
|
mSettings.setValue("duty_min", cfg.duty_min);
|
||||||
|
mSettings.setValue("duty_max", cfg.duty_max);
|
||||||
|
mSettings.setValue("watt_min", cfg.watt_min);
|
||||||
|
mSettings.setValue("watt_max", cfg.watt_max);
|
||||||
|
mSettings.setValue("name", cfg.name);
|
||||||
|
}
|
||||||
|
mSettings.endArray();
|
||||||
|
|
||||||
|
mSettings.beginWriteArray("pairedUuids");
|
||||||
|
for (int i = 0;i < mPairedUuids.size();i++) {
|
||||||
|
mSettings.setArrayIndex(i);
|
||||||
|
mSettings.setValue("uuid", mPairedUuids.at(i));
|
||||||
|
}
|
||||||
|
mSettings.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAS_BLUETOOTH
|
||||||
|
BleUart *BMSInterface::bleDevice()
|
||||||
|
{
|
||||||
|
return mBleUart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::storeBleName(QString address, QString name)
|
||||||
|
{
|
||||||
|
mBleNames.insert(address, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BMSInterface::getBleName(QString address)
|
||||||
|
{
|
||||||
|
QString res;
|
||||||
|
if(mBleNames.contains(address)) {
|
||||||
|
res = mBleNames[address];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BMSInterface::getLastBleAddr() const
|
||||||
|
{
|
||||||
|
return mLastBleAddr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool BMSInterface::isPortConnected()
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
if (mSerialPort->isOpen()) {
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mTcpConnected) {
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBleUart->isConnected()) {
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::disconnectPort()
|
||||||
|
{
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
if(mSerialPort->isOpen()) {
|
||||||
|
mSerialPort->close();
|
||||||
|
updateFwRx(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mTcpConnected) {
|
||||||
|
mTcpSocket->close();
|
||||||
|
updateFwRx(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBleUart->isConnected()) {
|
||||||
|
mBleUart->disconnectBle();
|
||||||
|
updateFwRx(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
mFwRetries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMSInterface::reconnectLastPort()
|
||||||
|
{
|
||||||
|
if (mLastConnType == CONN_SERIAL) {
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
return connectSerial(mLastSerialPort, mLastSerialBaud);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
} else if (mLastConnType == CONN_TCP) {
|
||||||
|
connectTcp(mLastTcpServer, mLastTcpPort);
|
||||||
|
return true;
|
||||||
|
} else if (mLastConnType == CONN_BLE) {
|
||||||
|
mBleUart->startConnect(mLastBleAddr);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
QList<VSerialInfo_t> ports = listSerialPorts();
|
||||||
|
if (!ports.isEmpty()) {
|
||||||
|
return connectSerial(ports.first().systemPath);
|
||||||
|
} else {
|
||||||
|
emit messageDialog(tr("Reconnect"), tr("No ports found"), false, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
emit messageDialog(tr("Reconnect"),
|
||||||
|
tr("Please specify the connection manually "
|
||||||
|
"the first time you are connecting."),
|
||||||
|
false, false);
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMSInterface::autoconnect()
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
QList<VSerialInfo_t> ports = listSerialPorts();
|
||||||
|
mAutoconnectOngoing = true;
|
||||||
|
mAutoconnectProgress = 0.0;
|
||||||
|
|
||||||
|
disconnectPort();
|
||||||
|
disconnect(mCommands, SIGNAL(fwVersionReceived(int,int,QString,QByteArray)),
|
||||||
|
this, SLOT(fwVersionReceived(int,int,QString,QByteArray)));
|
||||||
|
|
||||||
|
for (int i = 0;i < ports.size();i++) {
|
||||||
|
VSerialInfo_t serial = ports[i];
|
||||||
|
|
||||||
|
if (!connectSerial(serial.systemPath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QEventLoop loop;
|
||||||
|
QTimer timeoutTimer;
|
||||||
|
timeoutTimer.setSingleShot(true);
|
||||||
|
timeoutTimer.start(500);
|
||||||
|
connect(mCommands, SIGNAL(fwVersionReceived(int,int,QString,QByteArray)), &loop, SLOT(quit()));
|
||||||
|
connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||||
|
loop.exec();
|
||||||
|
|
||||||
|
if (timeoutTimer.isActive()) {
|
||||||
|
// If the timer is still running a firmware version was received.
|
||||||
|
res = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
mAutoconnectProgress = (double)i / (double)ports.size();
|
||||||
|
emit autoConnectProgressUpdated(mAutoconnectProgress, false);
|
||||||
|
disconnectPort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(mCommands, SIGNAL(fwVersionReceived(int,int,QString,QByteArray)),
|
||||||
|
this, SLOT(fwVersionReceived(int,int,QString,QByteArray)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
emit autoConnectProgressUpdated(1.0, true);
|
||||||
|
emit autoConnectFinished();
|
||||||
|
mAutoconnectOngoing = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BMSInterface::getConnectedPortName()
|
||||||
|
{
|
||||||
|
QString res = tr("Not connected");
|
||||||
|
bool connected = false;
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
if (mSerialPort->isOpen()) {
|
||||||
|
res = tr("Connected (serial) to %1").arg(mSerialPort->portName());
|
||||||
|
connected = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mTcpConnected) {
|
||||||
|
res = tr("Connected (TCP) to %1:%2").arg(mLastTcpServer).arg(mLastTcpPort);
|
||||||
|
connected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBleUart->isConnected()) {
|
||||||
|
res = tr("Connected (BLE) to %1").arg(mLastBleAddr);
|
||||||
|
connected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected && mCommands->isLimitedMode()) {
|
||||||
|
res += tr(", limited mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMSInterface::connectSerial(QString port, int baudrate)
|
||||||
|
{
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
mLastSerialPort = port;
|
||||||
|
mLastSerialBaud = baudrate;
|
||||||
|
setLastConnectionType(CONN_SERIAL);
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (VSerialInfo_t ser: listSerialPorts()) {
|
||||||
|
if (ser.systemPath == port) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
emit statusMessage(tr("Invalid serial port: %1").arg(port), false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mSerialPort->isOpen()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe this test works on other OSes as well
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
QFileInfo fi(port);
|
||||||
|
if (fi.exists()) {
|
||||||
|
if (!fi.isWritable()) {
|
||||||
|
emit statusMessage(tr("Serial port is not writable"), false);
|
||||||
|
emit serialPortNotWritable(port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mSerialPort->setPortName(port);
|
||||||
|
mSerialPort->open(QIODevice::ReadWrite);
|
||||||
|
|
||||||
|
if(!mSerialPort->isOpen()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSerialPort->setBaudRate(baudrate);
|
||||||
|
mSerialPort->setDataBits(QSerialPort::Data8);
|
||||||
|
mSerialPort->setParity(QSerialPort::NoParity);
|
||||||
|
mSerialPort->setStopBits(QSerialPort::OneStop);
|
||||||
|
mSerialPort->setFlowControl(QSerialPort::NoFlowControl);
|
||||||
|
|
||||||
|
// For nrf
|
||||||
|
mSerialPort->setRequestToSend(true);
|
||||||
|
mSerialPort->setDataTerminalReady(true);
|
||||||
|
QThread::msleep(5);
|
||||||
|
mSerialPort->setDataTerminalReady(false);
|
||||||
|
QThread::msleep(100);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
(void)port;
|
||||||
|
(void)baudrate;
|
||||||
|
emit messageDialog(tr("Connect serial"),
|
||||||
|
tr("Serial port support is not enabled in this build "
|
||||||
|
"of ENNOID-BMS Tool."),
|
||||||
|
false, false);
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<VSerialInfo_t> BMSInterface::listSerialPorts()
|
||||||
|
{
|
||||||
|
QList<VSerialInfo_t> res;
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
|
||||||
|
|
||||||
|
foreach(const QSerialPortInfo &port, ports) {
|
||||||
|
VSerialInfo_t info;
|
||||||
|
info.name = port.portName();
|
||||||
|
info.systemPath = port.systemLocation();
|
||||||
|
int index = res.size();
|
||||||
|
|
||||||
|
if(port.manufacturer().startsWith("Silicon")) {
|
||||||
|
//info.name.insert(0, "ENNOID-BMS - ");
|
||||||
|
info.name.append(" - ENNOID-BMS");
|
||||||
|
info.isVesc = true;
|
||||||
|
index = 0;
|
||||||
|
} else {
|
||||||
|
info.isVesc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.insert(index, info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::connectTcp(QString server, int port)
|
||||||
|
{
|
||||||
|
mLastTcpServer = server;
|
||||||
|
mLastTcpPort = port;
|
||||||
|
setLastConnectionType(CONN_TCP);
|
||||||
|
|
||||||
|
QHostAddress host;
|
||||||
|
host.setAddress(server);
|
||||||
|
|
||||||
|
// Try DNS lookup
|
||||||
|
if (host.isNull()) {
|
||||||
|
QList<QHostAddress> addresses = QHostInfo::fromName(server).addresses();
|
||||||
|
|
||||||
|
if (!addresses.isEmpty()) {
|
||||||
|
host.setAddress(addresses.first().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mTcpSocket->abort();
|
||||||
|
mTcpSocket->connectToHost(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::connectBle(QString address)
|
||||||
|
{
|
||||||
|
mBleUart->startConnect(address);
|
||||||
|
mLastConnType = CONN_BLE;
|
||||||
|
mLastBleAddr = address;
|
||||||
|
setLastConnectionType(CONN_BLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMSInterface::isAutoconnectOngoing() const
|
||||||
|
{
|
||||||
|
return mAutoconnectOngoing;
|
||||||
|
}
|
||||||
|
|
||||||
|
double BMSInterface::getAutoconnectProgress() const
|
||||||
|
{
|
||||||
|
return mAutoconnectProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<int> BMSInterface::scanCan()
|
||||||
|
{
|
||||||
|
QVector<int> canDevs;
|
||||||
|
|
||||||
|
if (!isPortConnected()) {
|
||||||
|
return canDevs;
|
||||||
|
}
|
||||||
|
|
||||||
|
QEventLoop loop;
|
||||||
|
|
||||||
|
bool timeout;
|
||||||
|
auto conn = connect(commands(), &Commands::pingCanRx,
|
||||||
|
[&canDevs, &timeout, &loop](QVector<int> devs, bool isTimeout) {
|
||||||
|
for (int dev: devs) {
|
||||||
|
canDevs.append(dev);
|
||||||
|
}
|
||||||
|
timeout = isTimeout;
|
||||||
|
loop.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
commands()->pingCan();
|
||||||
|
loop.exec();
|
||||||
|
|
||||||
|
disconnect(conn);
|
||||||
|
|
||||||
|
if (!timeout) {
|
||||||
|
mCanDevsLast = canDevs;
|
||||||
|
} else {
|
||||||
|
canDevs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return canDevs;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<int> BMSInterface::getCanDevsLast() const
|
||||||
|
{
|
||||||
|
return mCanDevsLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::ignoreCanChange(bool ignore)
|
||||||
|
{
|
||||||
|
mIgnoreCanChange = ignore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
void BMSInterface::serialDataAvailable()
|
||||||
|
{
|
||||||
|
bool b = true;
|
||||||
|
while (mSerialPort->bytesAvailable() > 0) {
|
||||||
|
mPacket->processData(mSerialPort->readAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::serialPortError(QSerialPort::SerialPortError error)
|
||||||
|
{
|
||||||
|
QString message;
|
||||||
|
switch (error) {
|
||||||
|
case QSerialPort::NoError:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
message = "Serial port error: " + mSerialPort->errorString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!message.isEmpty()) {
|
||||||
|
emit statusMessage(message, false);
|
||||||
|
|
||||||
|
if (mSerialPort->isOpen()) {
|
||||||
|
mSerialPort->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFwRx(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void BMSInterface::tcpInputConnected()
|
||||||
|
{
|
||||||
|
bool b = true;
|
||||||
|
mTcpConnected = true;
|
||||||
|
updateFwRx(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::tcpInputDisconnected()
|
||||||
|
{
|
||||||
|
mTcpConnected = false;
|
||||||
|
updateFwRx(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::tcpInputDataAvailable()
|
||||||
|
{
|
||||||
|
bool b = true;
|
||||||
|
while (mTcpSocket->bytesAvailable() > 0) {
|
||||||
|
mPacket->processData(mTcpSocket->readAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::tcpInputError(QAbstractSocket::SocketError socketError)
|
||||||
|
{
|
||||||
|
(void)socketError;
|
||||||
|
|
||||||
|
QString errorStr = mTcpSocket->errorString();
|
||||||
|
emit statusMessage(tr("TCP Error") + errorStr, false);
|
||||||
|
mTcpSocket->close();
|
||||||
|
updateFwRx(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_BLUETOOTH
|
||||||
|
void BMSInterface::bleDataRx(QByteArray data)
|
||||||
|
{
|
||||||
|
mPacket->processData(data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void BMSInterface::timerSlot()
|
||||||
|
{
|
||||||
|
// Poll the serial port as well since readyRead is not emitted recursively. This
|
||||||
|
// can be a problem when waiting for input with an additional event loop, such as
|
||||||
|
// when using QMessageBox.
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
serialDataAvailable();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (isPortConnected()) {
|
||||||
|
if (mSendCanBefore != mCommands->getSendCan() ||
|
||||||
|
mCanIdBefore != mCommands->getCanSendId()) {
|
||||||
|
updateFwRx(false);
|
||||||
|
mFwRetries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mFwPollCnt++;
|
||||||
|
if (mFwPollCnt >= 4) {
|
||||||
|
mFwPollCnt = 0;
|
||||||
|
if (!mFwVersionReceived) {
|
||||||
|
mCommands->getFwVersion();
|
||||||
|
mFwRetries++;
|
||||||
|
|
||||||
|
// Timeout if the firmware cannot be read
|
||||||
|
if (mFwRetries >= 25) {
|
||||||
|
emit statusMessage(tr("No firmware read response"), false);
|
||||||
|
emit messageDialog(tr("Read Firmware Version"),
|
||||||
|
tr("Could not read firmware version. Make sure "
|
||||||
|
"that selected port really belongs to the ENNOID-BMS. "),
|
||||||
|
false, false);
|
||||||
|
disconnectPort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updateFwRx(false);
|
||||||
|
mFwRetries = 0;
|
||||||
|
}
|
||||||
|
mSendCanBefore = mCommands->getSendCan();
|
||||||
|
mCanIdBefore = mCommands->getCanSendId();
|
||||||
|
|
||||||
|
// Update fw upload bar and label
|
||||||
|
double fwProg = mCommands->getFirmwareUploadProgress();
|
||||||
|
QString fwStatus = mCommands->getFirmwareUploadStatus();
|
||||||
|
if (fwProg > -0.1) {
|
||||||
|
mIsUploadingFw = true;
|
||||||
|
emit fwUploadStatus(fwStatus, fwProg, true);
|
||||||
|
} else {
|
||||||
|
// If the firmware upload just finished or failed
|
||||||
|
if (mIsUploadingFw) {
|
||||||
|
updateFwRx(false);
|
||||||
|
mFwRetries = 0;
|
||||||
|
if (fwStatus.compare("FW Upload Done") == 0) {
|
||||||
|
emit fwUploadStatus(fwStatus, 1.0, false);
|
||||||
|
} else {
|
||||||
|
emit fwUploadStatus(fwStatus, 0.0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIsUploadingFw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mWasConnected != isPortConnected()) {
|
||||||
|
mWasConnected = isPortConnected();
|
||||||
|
emit portConnectedChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::packetDataToSend(QByteArray &data)
|
||||||
|
{
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
if (mSerialPort->isOpen()) {
|
||||||
|
mSerialPort->write(data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mTcpConnected && mTcpSocket->isOpen()) {
|
||||||
|
mTcpSocket->write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBleUart->isConnected()) {
|
||||||
|
mBleUart->writeData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::packetReceived(QByteArray &data)
|
||||||
|
{
|
||||||
|
mCommands->processPacket(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::cmdDataToSend(QByteArray &data)
|
||||||
|
{
|
||||||
|
mPacket->sendPacket(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::fwVersionReceived(int major, int minor, QString hw, QByteArray uuid)
|
||||||
|
{
|
||||||
|
QList<QPair<int, int> > fwPairs = getSupportedFirmwarePairs();
|
||||||
|
|
||||||
|
QString strUuid = Utility::uuid2Str(uuid, true);
|
||||||
|
|
||||||
|
if (fwPairs.isEmpty()) {
|
||||||
|
emit messageDialog(tr("Not Supported Firmwares"),
|
||||||
|
tr("This version of ENNOID-BMS Tool does not seem to have any supported "
|
||||||
|
"firmwares. Something is probably wrong with the BMS configuration "
|
||||||
|
"file."),
|
||||||
|
false, false);
|
||||||
|
updateFwRx(false);
|
||||||
|
mFwRetries = 0;
|
||||||
|
disconnectPort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<int, int> highest_supported = *std::max_element(fwPairs.begin(), fwPairs.end());
|
||||||
|
QPair<int, int> fw_connected = qMakePair(major, minor);
|
||||||
|
|
||||||
|
bool wasReceived = mFwVersionReceived;
|
||||||
|
mCommands->setLimitedMode(false);
|
||||||
|
#if 0
|
||||||
|
if (major < 0) {
|
||||||
|
updateFwRx(false);
|
||||||
|
mFwRetries = 0;
|
||||||
|
disconnectPort();
|
||||||
|
emit messageDialog(tr("Error"), tr("The firmware on the connected ENNOID-BMS is too old. Please update it using a programmer."), false, false);
|
||||||
|
} else if (fw_connected > highest_supported) {
|
||||||
|
mCommands->setLimitedMode(true);
|
||||||
|
updateFwRx(true);
|
||||||
|
if (!wasReceived) {
|
||||||
|
emit messageDialog(tr("Warning"), tr("The connected ENNOID-BMS has newer firmware than this version of the"
|
||||||
|
" ENNOID-BMS Tool supports. It is recommended that you update the ENNOID-BMS"
|
||||||
|
" Tool to the latest version. Alternatively, the firmware on"
|
||||||
|
" the connected ENNOID-BMS can be downgraded in the firmware page."
|
||||||
|
" Until then, limited communication mode will be used where"
|
||||||
|
" only the firmware can be changed."), false, false);
|
||||||
|
}
|
||||||
|
} else if (!fwPairs.contains(fw_connected)) {
|
||||||
|
if (fw_connected >= qMakePair(0, 10)) {
|
||||||
|
mCommands->setLimitedMode(true);
|
||||||
|
updateFwRx(true);
|
||||||
|
if (!wasReceived) {
|
||||||
|
emit messageDialog(tr("Warning"), tr("The connected ENNOID-BMS has too old firmware. Since the"
|
||||||
|
" connected ENNOID-BMS has firmware with bootloader support, it can be"
|
||||||
|
" updated from the Firmware page."
|
||||||
|
" Until then, limited communication mode will be used where only the"
|
||||||
|
" firmware can be changed."), false, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updateFwRx(false);
|
||||||
|
mFwRetries = 0;
|
||||||
|
disconnectPort();
|
||||||
|
if (!wasReceived) {
|
||||||
|
emit messageDialog(tr("Error"), tr("The firmware on the connected ENNOID-BMS is too old. Please"
|
||||||
|
" update it using a programmer."), false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
updateFwRx(true);
|
||||||
|
if ((fw_connected < highest_supported)) {
|
||||||
|
if (!wasReceived) {
|
||||||
|
//emit messageDialog(tr("Warning"), tr("The connected ENNOID-BMS is compatible, but old firmware. It is recommended that you update it."), false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString fwStr;
|
||||||
|
fwStr.sprintf("ENNOID-BMS Firmware Version %d.%d", major, minor);
|
||||||
|
if (!hw.isEmpty()) {
|
||||||
|
fwStr += ", Hardware: " + hw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strUuid.isEmpty()) {
|
||||||
|
fwStr += ", UUID: " + strUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit statusMessage(fwStr, true);
|
||||||
|
#if 0
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (major >= 0) {
|
||||||
|
mFwTxt.sprintf("Fw: %d.%d", major, minor);
|
||||||
|
mHwTxt = hw;
|
||||||
|
if (!hw.isEmpty()) {
|
||||||
|
mFwTxt += ", Hw: " + hw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strUuid.isEmpty()) {
|
||||||
|
mFwTxt += "\n" + strUuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::bmsconfUpdated()
|
||||||
|
{
|
||||||
|
emit statusMessage(tr("BMS configuration updated"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::bmsconfStored() {
|
||||||
|
emit statusMessage(tr("BMS configuration stored to Flash"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::ackReceived(QString ackType)
|
||||||
|
{
|
||||||
|
emit statusMessage(ackType, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::updateFwRx(bool fwRx)
|
||||||
|
{
|
||||||
|
bool change = mFwVersionReceived != fwRx;
|
||||||
|
mFwVersionReceived = fwRx;
|
||||||
|
if (change) {
|
||||||
|
emit fwRxChanged(mFwVersionReceived, mCommands->isLimitedMode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BMSInterface::setLastConnectionType(conn_t type)
|
||||||
|
{
|
||||||
|
mLastConnType = type;
|
||||||
|
QSettings().setValue("connection_type", type);
|
||||||
|
}
|
||||||
214
bmsinterface.h
Normal file
214
bmsinterface.h
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BMSInterface_H
|
||||||
|
#define BMSInterface_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QList>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
#include <QSerialPort>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "configparams.h"
|
||||||
|
#include "commands.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
#ifdef HAS_BLUETOOTH
|
||||||
|
#include "bleuart.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class BMSInterface : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BMSInterface(QObject *parent = 0);
|
||||||
|
~BMSInterface();
|
||||||
|
Q_INVOKABLE Commands *commands() const;
|
||||||
|
Q_INVOKABLE ConfigParams *bmsConfig();
|
||||||
|
Q_INVOKABLE ConfigParams *infoConfig();
|
||||||
|
Q_INVOKABLE QStringList getSupportedFirmwares();
|
||||||
|
QList<QPair<int, int> > getSupportedFirmwarePairs();
|
||||||
|
Q_INVOKABLE QString getFirmwareNow();
|
||||||
|
Q_INVOKABLE void emitStatusMessage(const QString &msg, bool isGood);
|
||||||
|
Q_INVOKABLE void emitMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText = false);
|
||||||
|
Q_INVOKABLE bool fwRx();
|
||||||
|
Q_INVOKABLE void storeSettings();
|
||||||
|
//Q_INVOKABLE QVariantList getProfiles();
|
||||||
|
//Q_INVOKABLE void addProfile(QVariant profile);
|
||||||
|
//Q_INVOKABLE void clearProfiles();
|
||||||
|
//Q_INVOKABLE void deleteProfile(int index);
|
||||||
|
//Q_INVOKABLE void moveProfileUp(int index);
|
||||||
|
//Q_INVOKABLE void moveProfileDown(int index);
|
||||||
|
//Q_INVOKABLE MCCONF_TEMP getProfile(int index);
|
||||||
|
//Q_INVOKABLE void updateProfile(int index, QVariant profile);
|
||||||
|
//Q_INVOKABLE bool isProfileInUse(int index);
|
||||||
|
//Q_INVOKABLE MCCONF_TEMP createMcconfTemp();
|
||||||
|
//Q_INVOKABLE void updateMcconfFromProfile(MCCONF_TEMP profile);
|
||||||
|
// Q_INVOKABLE QStringList getPairedUuids();
|
||||||
|
// Q_INVOKABLE bool addPairedUuid(QString uuid);
|
||||||
|
// Q_INVOKABLE bool deletePairedUuid(QString uuid);
|
||||||
|
// Q_INVOKABLE void clearPairedUuids();
|
||||||
|
// Q_INVOKABLE bool hasPairedUuid(QString uuid);
|
||||||
|
// Q_INVOKABLE QString getConnectedUuid();
|
||||||
|
// Q_INVOKABLE bool isIntroDone();
|
||||||
|
// Q_INVOKABLE void setIntroDone(bool done);
|
||||||
|
// Q_INVOKABLE QString getLastTcpServer() const;
|
||||||
|
// Q_INVOKABLE int getLastTcpPort() const;
|
||||||
|
//#ifdef HAS_SERIALPORT
|
||||||
|
// Q_INVOKABLE QString getLastSerialPort() const;
|
||||||
|
// Q_INVOKABLE int getLastSerialBaud() const;
|
||||||
|
//#endif
|
||||||
|
bool swdEraseFlash();
|
||||||
|
bool swdUploadFw(QByteArray newFirmware, uint32_t startAddr = 0);
|
||||||
|
void swdCancel();
|
||||||
|
bool swdReboot();
|
||||||
|
|
||||||
|
#ifdef HAS_BLUETOOTH
|
||||||
|
Q_INVOKABLE BleUart* bleDevice();
|
||||||
|
Q_INVOKABLE void storeBleName(QString address, QString name);
|
||||||
|
Q_INVOKABLE QString getBleName(QString address);
|
||||||
|
Q_INVOKABLE QString getLastBleAddr() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Connection
|
||||||
|
Q_INVOKABLE bool isPortConnected();
|
||||||
|
Q_INVOKABLE void disconnectPort();
|
||||||
|
Q_INVOKABLE bool reconnectLastPort();
|
||||||
|
Q_INVOKABLE bool autoconnect();
|
||||||
|
Q_INVOKABLE QString getConnectedPortName();
|
||||||
|
bool connectSerial(QString port, int baudrate = 115200);
|
||||||
|
QList<VSerialInfo_t> listSerialPorts();
|
||||||
|
Q_INVOKABLE void connectTcp(QString server, int port);
|
||||||
|
Q_INVOKABLE void connectBle(QString address);
|
||||||
|
Q_INVOKABLE bool isAutoconnectOngoing() const;
|
||||||
|
Q_INVOKABLE double getAutoconnectProgress() const;
|
||||||
|
Q_INVOKABLE QVector<int> scanCan();
|
||||||
|
Q_INVOKABLE QVector<int> getCanDevsLast() const;
|
||||||
|
Q_INVOKABLE void ignoreCanChange(bool ignore);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void statusMessage(const QString &msg, bool isGood);
|
||||||
|
void messageDialog(const QString &title, const QString &msg, bool isGood, bool richText);
|
||||||
|
void fwUploadStatus(const QString &status, double progress, bool isOngoing);
|
||||||
|
void serialPortNotWritable(const QString &port);
|
||||||
|
void fwRxChanged(bool rx, bool limited);
|
||||||
|
void portConnectedChanged();
|
||||||
|
void autoConnectProgressUpdated(double progress, bool isOngoing);
|
||||||
|
void autoConnectFinished();
|
||||||
|
void pairingListUpdated();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
void serialDataAvailable();
|
||||||
|
void serialPortError(QSerialPort::SerialPortError error);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void tcpInputConnected();
|
||||||
|
void tcpInputDisconnected();
|
||||||
|
void tcpInputDataAvailable();
|
||||||
|
void tcpInputError(QAbstractSocket::SocketError socketError);
|
||||||
|
|
||||||
|
void bleDataRx(QByteArray data);
|
||||||
|
|
||||||
|
void timerSlot();
|
||||||
|
void packetDataToSend(QByteArray &data);
|
||||||
|
void packetReceived(QByteArray &data);
|
||||||
|
void cmdDataToSend(QByteArray &data);
|
||||||
|
void fwVersionReceived(int major, int minor, QString hw, QByteArray uuid);
|
||||||
|
void bmsconfUpdated();
|
||||||
|
void bmsconfStored();
|
||||||
|
void ackReceived(QString ackType);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef enum {
|
||||||
|
CONN_NONE = 0,
|
||||||
|
CONN_SERIAL,
|
||||||
|
CONN_TCP,
|
||||||
|
CONN_BLE
|
||||||
|
} conn_t;
|
||||||
|
|
||||||
|
QSettings mSettings;
|
||||||
|
QHash<QString, QString> mBleNames;
|
||||||
|
QVariantList mProfiles;
|
||||||
|
QStringList mPairedUuids;
|
||||||
|
|
||||||
|
ConfigParams *mbmsConfig;
|
||||||
|
ConfigParams *mInfoConfig;
|
||||||
|
|
||||||
|
QTimer *mTimer;
|
||||||
|
Packet *mPacket;
|
||||||
|
Commands *mCommands;
|
||||||
|
bool mFwVersionReceived;
|
||||||
|
int mFwRetries;
|
||||||
|
int mFwPollCnt;
|
||||||
|
QString mFwTxt;
|
||||||
|
QString mHwTxt;
|
||||||
|
bool mIsUploadingFw;
|
||||||
|
|
||||||
|
bool mCancelSwdUpload;
|
||||||
|
|
||||||
|
// Connections
|
||||||
|
conn_t mLastConnType;
|
||||||
|
|
||||||
|
#ifdef HAS_SERIALPORT
|
||||||
|
QSerialPort *mSerialPort;
|
||||||
|
QString mLastSerialPort;
|
||||||
|
int mLastSerialBaud;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QTcpSocket *mTcpSocket;
|
||||||
|
bool mTcpConnected;
|
||||||
|
QString mLastTcpServer;
|
||||||
|
int mLastTcpPort;
|
||||||
|
|
||||||
|
#ifdef HAS_BLUETOOTH
|
||||||
|
BleUart *mBleUart;
|
||||||
|
QString mLastBleAddr;
|
||||||
|
#endif
|
||||||
|
bool mSendCanBefore = false;
|
||||||
|
int mCanIdBefore = 0;
|
||||||
|
bool mWasConnected;
|
||||||
|
bool mAutoconnectOngoing;
|
||||||
|
double mAutoconnectProgress;
|
||||||
|
bool mIgnoreCanChange;
|
||||||
|
|
||||||
|
QVector<int> mCanDevsLast;
|
||||||
|
|
||||||
|
void updateFwRx(bool fwRx);
|
||||||
|
void setLastConnectionType(conn_t type);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BMSInterface_H
|
||||||
97
bmsservicepage.cpp
Normal file
97
bmsservicepage.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include "bmsservicepage.h"
|
||||||
|
#include "ui_bmsservicepage.h"
|
||||||
|
#include <QTimer>
|
||||||
|
//#include "widgets/historylineedit.h"
|
||||||
|
|
||||||
|
BmsServicePage::BmsServicePage(QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
ui(new Ui::BmsServicePage)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
connect(ui->helpButton, &QPushButton::clicked, this, &BmsServicePage::on_helpButton_clicked);
|
||||||
|
connect(ui->sendButton, &QPushButton::clicked, this, &BmsServicePage::on_sendButton_clicked);
|
||||||
|
connect(ui->terminalEdit, &HistoryLineEditBox::enterClicked, this, &BmsServicePage::on_sendButton_clicked);
|
||||||
|
//connect(ui->terminalEdit, &HistoryLineEditBox::upClicked, this, &BmsServicePage::onUpButtonClicked);
|
||||||
|
//connect(ui->terminalEdit, &HistoryLineEditBox::downClicked, this, &BmsServicePage::onDownButtonClicked);
|
||||||
|
|
||||||
|
connect(ui->clearButton, &QPushButton::clicked, this, &BmsServicePage::on_clearButton_clicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
BmsServicePage::~BmsServicePage()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void BmsServicePage::onUpButtonClicked()
|
||||||
|
{
|
||||||
|
ui->terminalEdit->
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsServicePage::onDownButtonClicked()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void BmsServicePage::on_clearButton_clicked()
|
||||||
|
{
|
||||||
|
clearTerminal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsServicePage::clearTerminal()
|
||||||
|
{
|
||||||
|
ui->terminalBrowser->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
BMSInterface *BmsServicePage::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsServicePage::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
|
||||||
|
if (mDieBieMS) {
|
||||||
|
connect(mDieBieMS->commands(), SIGNAL(printReceived(QString)), this, SLOT(printReceived(QString)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsServicePage::printReceived(QString str)
|
||||||
|
{
|
||||||
|
ui->terminalBrowser->append(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*
|
||||||
|
bool BmsServicePage::eventFilter(QObject *O, QEvent *E)
|
||||||
|
{
|
||||||
|
if(O == ui->terminalEdit)
|
||||||
|
{
|
||||||
|
if(E->type() == QKeyEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent *pkey = (QKeyEvent *)E;
|
||||||
|
if( pkey->key()==Qt::Key_Enter || pkey->key()==Qt::Key_Return)
|
||||||
|
{
|
||||||
|
int a = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::eventFilter(O,E);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsServicePage::on_sendButton_clicked()
|
||||||
|
{
|
||||||
|
if (mDieBieMS) {
|
||||||
|
mDieBieMS->commands()->sendTerminalCmd(ui->terminalEdit->text());
|
||||||
|
ui->terminalEdit->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsServicePage::on_helpButton_clicked()
|
||||||
|
{
|
||||||
|
if (mDieBieMS) {
|
||||||
|
mDieBieMS->commands()->sendTerminalCmd("help");
|
||||||
|
}
|
||||||
|
}
|
||||||
60
bmsservicepage.h
Normal file
60
bmsservicepage.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#ifndef BMSSERVICEPAGE_H
|
||||||
|
#define BMSSERVICEPAGE_H
|
||||||
|
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QButtonGroup>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class BmsServicePage;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
class KeyboardFilter : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeyboardFilter( QObject *parent = 0 ) : QObject( parent ) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter( QObject *dist, QEvent *event );
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
class BmsServicePage : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BmsServicePage(QWidget *parent = nullptr);
|
||||||
|
~BmsServicePage();
|
||||||
|
|
||||||
|
|
||||||
|
void clearTerminal();
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// void keyPressEvent(QKeyEvent *);
|
||||||
|
bool eventFilter(QObject *, QEvent *);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void printReceived(QString str);
|
||||||
|
|
||||||
|
//void onUpButtonClicked();
|
||||||
|
//void onDownButtonClicked();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_sendButton_clicked();
|
||||||
|
void on_helpButton_clicked();
|
||||||
|
void on_clearButton_clicked();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::BmsServicePage *ui;
|
||||||
|
BMSInterface *mDieBieMS;
|
||||||
|
//KeyboardFilter filter;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BMSSERVICEPAGE_H
|
||||||
281
bmsservicepage.ui
Normal file
281
bmsservicepage.ui
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>BmsServicePage</class>
|
||||||
|
<widget class="QFrame" name="BmsServicePage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1071</width>
|
||||||
|
<height>755</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">
|
||||||
|
QWidget#BmsServicePage
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage
|
||||||
|
{
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
border-top-left-radius: 15px;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
font-size: 18px;
|
||||||
|
border-right-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarAmperage
|
||||||
|
{
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
/* border-top-left-radius: 20px;*/
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
font-size: 18px;
|
||||||
|
border-left-color: white;
|
||||||
|
border-right-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarTemperature
|
||||||
|
{
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
font-size: 18px;
|
||||||
|
border-left-color: white;
|
||||||
|
border-right-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage:hover:checked,
|
||||||
|
#pbVisualizationMenuBarAmperage:hover:checked,
|
||||||
|
#pbVisualizationMenuBarTemperature:hover:checked
|
||||||
|
{
|
||||||
|
/*background-color: #01673a;*/
|
||||||
|
border-bottom-color:#009352;
|
||||||
|
color:#009352;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage:!hover:checked,
|
||||||
|
#pbVisualizationMenuBarAmperage:!hover:checked,
|
||||||
|
#pbVisualizationMenuBarTemperature:!hover:checked
|
||||||
|
{
|
||||||
|
/*background-color: #01673a;*/
|
||||||
|
border-bottom-color: #009352;
|
||||||
|
color:#009352;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage:hover:!checked,
|
||||||
|
#pbVisualizationMenuBarAmperage:hover:!checked,
|
||||||
|
#pbVisualizationMenuBarTemperature:hover:!checked
|
||||||
|
{
|
||||||
|
/*background-color: #009352;*/
|
||||||
|
/*background-color: #028249;*/
|
||||||
|
border-bottom-color: lightgrey;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="lbCenterTabName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>30</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>921</width>
|
||||||
|
<height>41</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>26</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Терминал</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="labTerminalBrowserBackground">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>33</x>
|
||||||
|
<y>90</y>
|
||||||
|
<width>991</width>
|
||||||
|
<height>581</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"> background-color:#FFFFFF;
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
border-top-left-radius: 15px;
|
||||||
|
border-top-right-radius: 15px;
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="layoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>30</x>
|
||||||
|
<y>680</y>
|
||||||
|
<width>991</width>
|
||||||
|
<height>42</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="helpButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Send help command to VESC</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Help-96.png</normaloff>:/res/icons/Help-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="HistoryLineEditBox" name="terminalEdit">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="sendButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Send command</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Send File-96.png</normaloff>:/res/icons/Send File-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="clearButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Clear terminal</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Delete-96.png</normaloff>:/res/icons/Delete-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTextBrowser" name="terminalBrowser">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>33</x>
|
||||||
|
<y>91</y>
|
||||||
|
<width>991</width>
|
||||||
|
<height>581</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>DejaVu Sans Mono</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"> background-color:transparent;
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
border-top-left-radius: 15px;
|
||||||
|
border-top-right-radius: 15px;
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<zorder>labTerminalBrowserBackground</zorder>
|
||||||
|
<zorder>lbCenterTabName</zorder>
|
||||||
|
<zorder>layoutWidget</zorder>
|
||||||
|
<zorder>terminalBrowser</zorder>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>HistoryLineEditBox</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header location="global">historylineeditbox.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
646
bmssettings.cpp
Normal file
646
bmssettings.cpp
Normal file
@@ -0,0 +1,646 @@
|
|||||||
|
#include "bmssettings.h"
|
||||||
|
#include "ui_bmssettings.h"
|
||||||
|
|
||||||
|
#include "widgets/paramtable.h"
|
||||||
|
#include "widgets/parameditdouble.h"
|
||||||
|
#include "configparamsgetter.h"
|
||||||
|
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QDoubleValidator>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
BmsSettings::BmsSettings(QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
ui(new Ui::BmsSettings)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->pbWriteToNonVolatileBmsMemory->hide();
|
||||||
|
ui->pbWriteCurrentValuesToBms->hide();
|
||||||
|
|
||||||
|
// https://localcoder.org/set-qlineedit-to-accept-only-numbers
|
||||||
|
ui->editSerialNumber->setValidator(new QRegExpValidator(QRegExp("[1-9][0-9]*"), this)); // only numbers // leading digit must be 1 to 9 (prevents leading zeroes).
|
||||||
|
|
||||||
|
ui->editGroupsNumber->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editCellsNumber->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
ui->editCellsInParallelGroup->setValidator( new QIntValidator(1, 1000, this) );
|
||||||
|
ui->editBatteryCapacity->setValidator( new QIntValidator(0, 10000, this) );
|
||||||
|
|
||||||
|
ui->editMaxVoltageCharge->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editMaxCircuitLoad->setValidator( new QIntValidator(-1000, 10000, this) );
|
||||||
|
ui->editMaxTemperature->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
ui->editMinVoltageWhenWeTurnLoadOff->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editSuchVoltageWhenWeTurnLoadOn->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editSuchVoltageWhenWeTurnChargeOn->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editMaxVoltageWhenWeTurnChargeOff->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
|
||||||
|
ui->editVoltageBalancingStart->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editVoltageDifferenceThreshold->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editCellBalancingInterval->setValidator( new QIntValidator(-1000, 100000, this) );
|
||||||
|
|
||||||
|
//V
|
||||||
|
//ui->cboxUseToManageStorageDevice
|
||||||
|
//ui->cboxNormallyClosed
|
||||||
|
ui->editSocValueEdit->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
|
||||||
|
//ui->cboxTemperatureSettingsOver
|
||||||
|
ui->editTemperatureIfLessThenCloseOver->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editTemperatureIfMoeeThenOpenOver->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
//ui->cboxTemperatureSettingsUnder
|
||||||
|
ui->editTemperatureIfLessThenCloseUnder->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editTemperatureIfMoeeThenOpenUnder->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
ui->editPointZeroDetectorValue->setValidator( new QDoubleValidator(-1000, 1000, 2, this) );
|
||||||
|
|
||||||
|
// BTNS
|
||||||
|
//ui->pbCalibrateZeroPoint
|
||||||
|
//ui->pbWriteIntoNonVolatileMemoryOfBsm
|
||||||
|
//ui->pbWriteCurrentValuesIntoBsm
|
||||||
|
|
||||||
|
connect(ui->pbSaveBMSConfToXmlFile, &QPushButton::clicked, this, &BmsSettings::onSaveBMSConfToXmlFileClicked);
|
||||||
|
connect(ui->pbLoadBMSConfFromXmlFile, &QPushButton::clicked, this, &BmsSettings::onLoadBMSConfFromXmlFileClicked);
|
||||||
|
|
||||||
|
|
||||||
|
clearControlls();
|
||||||
|
}
|
||||||
|
|
||||||
|
BmsSettings::~BmsSettings()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void BmsSettings::onBmsconfUpdateRequested()
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::onBmsconfUpdateRequestDefault()
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::onBmsconfUpdated()
|
||||||
|
{
|
||||||
|
// ^ - 8 7 | 8 8 read bms conf
|
||||||
|
// After we hav red real BMS Config params from BMS we put all of them into the GUI elements
|
||||||
|
|
||||||
|
// Load default params from Bms to GUI Elements
|
||||||
|
//-> - 7 7 | 7 8 read default 8 is defaul - that was on the start
|
||||||
|
// Загрузить настройки\nпо умолчанию
|
||||||
|
//mDieBieMS->commands()->getBMSconfDefault();
|
||||||
|
|
||||||
|
onLoadParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::onBmsconfStored()
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BmsSettings::clearControlls()
|
||||||
|
{
|
||||||
|
ui->editSerialNumber ->clear();
|
||||||
|
|
||||||
|
ui->editGroupsNumber ->clear();
|
||||||
|
ui->editCellsNumber ->clear();
|
||||||
|
|
||||||
|
ui->editCellsInParallelGroup ->clear();
|
||||||
|
ui->editBatteryCapacity ->clear();
|
||||||
|
|
||||||
|
ui->editMaxVoltageCharge ->clear();
|
||||||
|
ui->editMaxCircuitLoad ->clear();
|
||||||
|
ui->editMaxTemperature ->clear();
|
||||||
|
|
||||||
|
ui->editMinVoltageWhenWeTurnLoadOff ->clear();
|
||||||
|
ui->editSuchVoltageWhenWeTurnLoadOn ->clear();
|
||||||
|
ui->editSuchVoltageWhenWeTurnChargeOn ->clear();
|
||||||
|
ui->editMaxVoltageWhenWeTurnChargeOff ->clear();
|
||||||
|
|
||||||
|
|
||||||
|
ui->editVoltageBalancingStart ->clear();
|
||||||
|
ui->editVoltageDifferenceThreshold ->clear();
|
||||||
|
ui->editCellBalancingInterval ->clear();
|
||||||
|
|
||||||
|
//1
|
||||||
|
ui->cboxUseToManageStorageDevice ->setChecked(false);
|
||||||
|
//2
|
||||||
|
ui->cboxNormallyClosed ->setChecked(false);
|
||||||
|
ui->editSocValueEdit ->clear();
|
||||||
|
//3
|
||||||
|
ui->cboxTemperatureSettingsOver ->setChecked(false);
|
||||||
|
ui->editTemperatureIfLessThenCloseOver ->clear();
|
||||||
|
ui->editTemperatureIfMoeeThenOpenOver ->clear();
|
||||||
|
//4
|
||||||
|
ui->cboxTemperatureSettingsUnder ->setChecked(false);
|
||||||
|
ui->editTemperatureIfLessThenCloseUnder ->clear();
|
||||||
|
ui->editTemperatureIfMoeeThenOpenUnder ->clear();
|
||||||
|
// 0
|
||||||
|
ui->editPointZeroDetectorValue ->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::prepareSettersFromGuiControlsToSettingsFile()
|
||||||
|
{
|
||||||
|
/// Setters
|
||||||
|
#define QS QString
|
||||||
|
|
||||||
|
auto cfg = mDieBieMS->bmsConfig();
|
||||||
|
|
||||||
|
/// Серийный номер * //ui->editSerialNumber
|
||||||
|
connect(ui->editSerialNumber, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{
|
||||||
|
QS s =ui->editSerialNumber->text();
|
||||||
|
QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt());
|
||||||
|
cfg->setParamValue("notUsedCurrentThreshold", val);
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Конфигурация *
|
||||||
|
connect(ui->editGroupsNumber, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editGroupsNumber->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("cellMonitorICCount", val); });
|
||||||
|
connect(ui->editCellsNumber, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{
|
||||||
|
QS s =ui->editCellsNumber->text();
|
||||||
|
QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt());
|
||||||
|
cfg->setParamValue("noOfCellsSeries", val);
|
||||||
|
});
|
||||||
|
// Конфигурация *
|
||||||
|
//addParamRow(ui->editGroupsNumber , mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
//addParamRow(ui->editCellsNumber , mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
|
||||||
|
/// SOC *
|
||||||
|
connect(ui->editCellsInParallelGroup, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editCellsInParallelGroup->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("noOfCellsParallel", val); });
|
||||||
|
connect(ui->editBatteryCapacity, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editBatteryCapacity->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("batteryCapacity", val); });
|
||||||
|
// SOC *
|
||||||
|
//addParamRow(ui->editCellsInParallelGroup , mDieBieMS->bmsConfig(), "noOfCellsParallel");
|
||||||
|
//addParamRow(ui->editBatteryCapacity , mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
|
||||||
|
/// Ограничения *
|
||||||
|
connect(ui->editMaxVoltageCharge, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxVoltageCharge->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("maxAllowedCurrent", val); });
|
||||||
|
connect(ui->editMaxCircuitLoad, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxCircuitLoad->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("maxMismatchThreshold", val); });
|
||||||
|
connect(ui->editMaxTemperature, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxTemperature->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("allowedTempBattChargingMax", val); });
|
||||||
|
// Ограничения *
|
||||||
|
//addParamRow(ui->editMaxVoltageCharge , mDieBieMS->bmsConfig(), "maxAllowedCurrent");
|
||||||
|
//addParamRow(ui->editMaxCircuitLoad , mDieBieMS->bmsConfig(), "maxMismatchThreshold");
|
||||||
|
//addParamRow(ui->editMaxTemperature , mDieBieMS->bmsConfig(), "allowedTempBattChargingMax");
|
||||||
|
|
||||||
|
/// Конфигурация ячеек *
|
||||||
|
connect(ui->editMinVoltageWhenWeTurnLoadOff, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMinVoltageWhenWeTurnLoadOff->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellHardUnderVoltage", val); });
|
||||||
|
connect(ui->editSuchVoltageWhenWeTurnLoadOn, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editSuchVoltageWhenWeTurnLoadOn->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellHardOverVoltage", val); });
|
||||||
|
connect(ui->editSuchVoltageWhenWeTurnChargeOn, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editSuchVoltageWhenWeTurnChargeOn->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellLCSoftUnderVoltage", val); });
|
||||||
|
connect(ui->editMaxVoltageWhenWeTurnChargeOff, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxVoltageWhenWeTurnChargeOff->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellSoftOverVoltage", val); });
|
||||||
|
// Конфигурация ячеек *
|
||||||
|
//addParamRow(ui->editMinVoltageWhenWeTurnLoadOff , mDieBieMS->bmsConfig(), "cellHardUnderVoltage");
|
||||||
|
//addParamRow(ui->editSuchVoltageWhenWeTurnLoadOn , mDieBieMS->bmsConfig(), "cellHardOverVoltage");
|
||||||
|
//addParamRow(ui->editSuchVoltageWhenWeTurnChargeOn , mDieBieMS->bmsConfig(), "cellLCSoftUnderVoltage");
|
||||||
|
//addParamRow(ui->editMaxVoltageWhenWeTurnChargeOff , mDieBieMS->bmsConfig(), "cellSoftOverVoltage");
|
||||||
|
|
||||||
|
/// Конфигурация балансировки * // ui->balancingTab
|
||||||
|
connect(ui->editVoltageBalancingStart, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editVoltageBalancingStart->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellBalanceStart", val); });
|
||||||
|
connect(ui->editVoltageDifferenceThreshold, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editVoltageDifferenceThreshold->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellBalanceDifferenceThreshold", val); });
|
||||||
|
connect(ui->editCellBalancingInterval, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editCellBalancingInterval->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("cellBalanceUpdateInterval", val); });
|
||||||
|
// Конфигурация балансировки * // ui->balancingTab
|
||||||
|
//addParamRow(ui->editVoltageBalancingStart , mDieBieMS->bmsConfig(), "cellBalanceStart");
|
||||||
|
//addParamRow(ui->editVoltageDifferenceThreshold , mDieBieMS->bmsConfig(), "cellBalanceDifferenceThreshold");
|
||||||
|
//addParamRow(ui->editCellBalancingInterval , mDieBieMS->bmsConfig(), "cellBalanceUpdateInterval");
|
||||||
|
|
||||||
|
/// Калибровать Нулевую точку * // ui->signalsTab
|
||||||
|
connect(ui->editPointZeroDetectorValue, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{
|
||||||
|
QS s =ui->editPointZeroDetectorValue->text();
|
||||||
|
QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble());
|
||||||
|
cfg->setParamValue("shuntLCFactor", val);
|
||||||
|
});
|
||||||
|
// Нулевая точка * // ui->signalsTab
|
||||||
|
//addParamRow(ui->editPointZeroDetectorValue , mDieBieMS->bmsConfig(), "shuntLCFactor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::onLoadParams()
|
||||||
|
{
|
||||||
|
////
|
||||||
|
|
||||||
|
// Серийный номер * //ui->editSerialNumber
|
||||||
|
getSerialNumber(ui->editSerialNumber , mDieBieMS->bmsConfig(), "notUsedCurrentThreshold");
|
||||||
|
// Конфигурация *
|
||||||
|
addParamRow(ui->editGroupsNumber , mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
addParamRow(ui->editCellsNumber , mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
// SOC *
|
||||||
|
addParamRow(ui->editCellsInParallelGroup , mDieBieMS->bmsConfig(), "noOfCellsParallel");
|
||||||
|
addParamRow(ui->editBatteryCapacity , mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
// Ограничения *
|
||||||
|
addParamRow(ui->editMaxVoltageCharge , mDieBieMS->bmsConfig(), "maxAllowedCurrent");
|
||||||
|
addParamRow(ui->editMaxCircuitLoad , mDieBieMS->bmsConfig(), "maxMismatchThreshold");
|
||||||
|
addParamRow(ui->editMaxTemperature , mDieBieMS->bmsConfig(), "allowedTempBattChargingMax");
|
||||||
|
// Конфигурация ячеек *
|
||||||
|
addParamRow(ui->editMinVoltageWhenWeTurnLoadOff , mDieBieMS->bmsConfig(), "cellHardUnderVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnLoadOn , mDieBieMS->bmsConfig(), "cellHardOverVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnChargeOn , mDieBieMS->bmsConfig(), "cellLCSoftUnderVoltage");
|
||||||
|
addParamRow(ui->editMaxVoltageWhenWeTurnChargeOff , mDieBieMS->bmsConfig(), "cellSoftOverVoltage");
|
||||||
|
// Конфигурация балансировки *
|
||||||
|
// ui->balancingTab
|
||||||
|
addParamRow(ui->editVoltageBalancingStart , mDieBieMS->bmsConfig(), "cellBalanceStart");
|
||||||
|
addParamRow(ui->editVoltageDifferenceThreshold , mDieBieMS->bmsConfig(), "cellBalanceDifferenceThreshold");
|
||||||
|
addParamRow(ui->editCellBalancingInterval , mDieBieMS->bmsConfig(), "cellBalanceUpdateInterval");
|
||||||
|
// Нулевая точка *
|
||||||
|
// ui->signalsTab
|
||||||
|
addParamRow(ui->editPointZeroDetectorValue , mDieBieMS->bmsConfig(), "shuntLCFactor");
|
||||||
|
////*/
|
||||||
|
|
||||||
|
// Turn ON Setters only AFTER we load all data from file
|
||||||
|
|
||||||
|
prepareSettersFromGuiControlsToSettingsFile();
|
||||||
|
|
||||||
|
// Turn ON Setters only AFTER we load all data from file
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
<cellBalanceStart>
|
||||||
|
<longName>Cell balance start voltage</longName>
|
||||||
|
|
||||||
|
cellMonitorICCount ->
|
||||||
|
noOfCellsSeries ->
|
||||||
|
--
|
||||||
|
noOfCellsParallel ->
|
||||||
|
<batteryCapacity>
|
||||||
|
<longName>Battery capacity total</longName>
|
||||||
|
--
|
||||||
|
<maxMismatchThreshold>
|
||||||
|
<longName>Mismatch threshold</longName>
|
||||||
|
<maxAllowedCurrent>
|
||||||
|
<longName>Max allowed current</longName>
|
||||||
|
<allowedTempBattChargingMax>
|
||||||
|
<longName>Battery temperature charging max</longName>
|
||||||
|
--
|
||||||
|
<cellHardUnderVoltage>
|
||||||
|
<longName>Cell hard undervoltage</longName>
|
||||||
|
<cellHardOverVoltage>
|
||||||
|
<longName>Cell hard overvoltage</longName>
|
||||||
|
<cellLCSoftUnderVoltage>
|
||||||
|
<longName>Cell low current soft undervoltage</longName>
|
||||||
|
<cellSoftOverVoltage>
|
||||||
|
<longName>Cell soft overvoltage</longName>
|
||||||
|
--
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
#if 0
|
||||||
|
ConfigParam *p = mDieBieMS->infoConfig()->getParam("master_setting_description");
|
||||||
|
if (p != 0) {
|
||||||
|
ui->textEdit->setHtml(p->description);
|
||||||
|
} else {
|
||||||
|
ui->textEdit->setText("Master Setting Description not found.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ConfigParams *const conf = mDieBieMS->bmsConfig();
|
||||||
|
///ParamTable *const pt = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
///pt->addRowSeparator(tr("Current"));
|
||||||
|
// Нулевая точка
|
||||||
|
addParamRow(ui->editPointZeroDetectorValue , mDieBieMS->bmsConfig(), "shuntLCFactor");
|
||||||
|
//pt->addParamRow(conf, "shuntLCFactor");
|
||||||
|
////pt->addParamRow(conf, "shuntOffset");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Pack configuration"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "cellMonitorICType");
|
||||||
|
#endif
|
||||||
|
// Конфигурация
|
||||||
|
addParamRow(ui->editGroupsNumber , mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
addParamRow(ui->editCellsNumber , mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
//pt->addParamRow(conf, "cellMonitorICCount");
|
||||||
|
///pt->addParamRow(conf, "noOfParallelModules");
|
||||||
|
//pt->addParamRow(conf, "noOfCellsSeries");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("SOC - Pack capacity"));
|
||||||
|
//pt->addParamRow(conf, "noOfCellsParallel");
|
||||||
|
//pt->addParamRow(conf, "batteryCapacity");
|
||||||
|
// SOC
|
||||||
|
addParamRow(ui->editCellsInParallelGroup , mDieBieMS->bmsConfig(), "noOfCellsParallel");
|
||||||
|
addParamRow(ui->editBatteryCapacity , mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Cell specifications"));
|
||||||
|
//pt->addParamRow(conf, "cellHardUnderVoltage");
|
||||||
|
//pt->addParamRow(conf, "cellHardOverVoltage");
|
||||||
|
//pt->addParamRow(conf, "cellLCSoftUnderVoltage");
|
||||||
|
//pt->addParamRow(conf, "cellSoftOverVoltage");
|
||||||
|
// Конфигурация ячеек
|
||||||
|
addParamRow(ui->editMinVoltageWhenWeTurnLoadOff , mDieBieMS->bmsConfig(), "cellHardUnderVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnLoadOn , mDieBieMS->bmsConfig(), "cellHardOverVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnChargeOn , mDieBieMS->bmsConfig(), "cellLCSoftUnderVoltage");
|
||||||
|
addParamRow(ui->editMaxVoltageWhenWeTurnChargeOff , mDieBieMS->bmsConfig(), "cellSoftOverVoltage");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Balancing configuration"));
|
||||||
|
//pt->addParamRow(conf, "cellBalanceStart");
|
||||||
|
//pt->addParamRow(conf, "cellBalanceDifferenceThreshold");
|
||||||
|
//pt->addParamRow(conf, "cellBalanceUpdateInterval");
|
||||||
|
// Конфигурация балансировки
|
||||||
|
// ui->balancingTab
|
||||||
|
addParamRow(ui->editVoltageBalancingStart , mDieBieMS->bmsConfig(), "cellBalanceStart");
|
||||||
|
addParamRow(ui->editVoltageDifferenceThreshold , mDieBieMS->bmsConfig(), "cellBalanceDifferenceThreshold");
|
||||||
|
addParamRow(ui->editCellBalancingInterval , mDieBieMS->bmsConfig(), "cellBalanceUpdateInterval");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("SoC general"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "stateOfChargeStoreInterval");
|
||||||
|
pt->addParamRow(conf, "timeoutChargeCompleted");
|
||||||
|
pt->addParamRow(conf, "timeoutChargingCompletedMinimalMismatch");
|
||||||
|
#endif
|
||||||
|
///pt->addParamRow(conf, "minimalPrechargePercentage"); // from pagemastersettings.cpp
|
||||||
|
///pt->addParamRow(conf, "timeoutLCPreCharge"); // from pagemastersettings.cpp
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Limits"));
|
||||||
|
//pt->addParamRow(conf, "maxMismatchThreshold");
|
||||||
|
//pt->addParamRow(conf, "maxAllowedCurrent");
|
||||||
|
// Ограничения
|
||||||
|
addParamRow(ui->editMaxVoltageCharge , mDieBieMS->bmsConfig(), "maxAllowedCurrent");
|
||||||
|
addParamRow(ui->editMaxCircuitLoad , mDieBieMS->bmsConfig(), "maxMismatchThreshold");
|
||||||
|
addParamRow(ui->editMaxTemperature , mDieBieMS->bmsConfig(), "allowedTempBattChargingMax");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMax");
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMin");
|
||||||
|
#endif
|
||||||
|
//pt->addParamRow(conf, "allowedTempBattChargingMax");
|
||||||
|
///pt->addParamRow(conf, "allowedTempBattChargingMin");
|
||||||
|
#if 0 // disable
|
||||||
|
///pt->addRowSeparator(tr("NTC specifications battery"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerModule");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "NTCLTC25Deg");
|
||||||
|
///pt->addRowSeparator(tr("NTC specifications expansion Board"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfExpansionBoard");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerExpansionBoard");
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMSInterface *BmsSettings::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{ // void PageMasterSettings::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
|
||||||
|
//pt = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
|
||||||
|
//onLoadParams();
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (mDieBieMS) {
|
||||||
|
#if 0
|
||||||
|
ConfigParam *p = mDieBieMS->infoConfig()->getParam("master_setting_description");
|
||||||
|
if (p != 0) {
|
||||||
|
ui->textEdit->setHtml(p->description);
|
||||||
|
} else {
|
||||||
|
ui->textEdit->setText("Master Setting Description not found.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ConfigParams *const conf = mDieBieMS->bmsConfig();
|
||||||
|
ParamTable *const pt = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
pt->addRowSeparator(tr("Current"));
|
||||||
|
pt->addParamRow(conf, "shuntLCFactor");
|
||||||
|
pt->addParamRow(conf, "shuntOffset");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Pack configuration"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "cellMonitorICType");
|
||||||
|
#endif
|
||||||
|
pt->addParamRow(conf, "cellMonitorICCount");
|
||||||
|
pt->addParamRow(conf, "noOfParallelModules");
|
||||||
|
pt->addParamRow(conf, "noOfCellsSeries");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("SOC - Pack capacity"));
|
||||||
|
pt->addParamRow(conf, "noOfCellsParallel");
|
||||||
|
pt->addParamRow(conf, "batteryCapacity");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Cell specifications"));
|
||||||
|
pt->addParamRow(conf, "cellHardUnderVoltage");
|
||||||
|
pt->addParamRow(conf, "cellHardOverVoltage");
|
||||||
|
pt->addParamRow(conf, "cellLCSoftUnderVoltage");
|
||||||
|
pt->addParamRow(conf, "cellSoftOverVoltage");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Balancing configuration"));
|
||||||
|
pt->addParamRow(conf, "cellBalanceStart");
|
||||||
|
pt->addParamRow(conf, "cellBalanceDifferenceThreshold");
|
||||||
|
pt->addParamRow(conf, "cellBalanceUpdateInterval");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("SoC general"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "stateOfChargeStoreInterval");
|
||||||
|
pt->addParamRow(conf, "timeoutChargeCompleted");
|
||||||
|
pt->addParamRow(conf, "timeoutChargingCompletedMinimalMismatch");
|
||||||
|
#endif
|
||||||
|
pt->addParamRow(conf, "minimalPrechargePercentage"); // from pagemastersettings.cpp
|
||||||
|
pt->addParamRow(conf, "timeoutLCPreCharge"); // from pagemastersettings.cpp
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Limits"));
|
||||||
|
pt->addParamRow(conf, "maxMismatchThreshold");
|
||||||
|
pt->addParamRow(conf, "maxAllowedCurrent");
|
||||||
|
#if 0
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMax");
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMin");
|
||||||
|
#endif
|
||||||
|
pt->addParamRow(conf, "allowedTempBattChargingMax");
|
||||||
|
pt->addParamRow(conf, "allowedTempBattChargingMin");
|
||||||
|
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addRowSeparator(tr("NTC specifications battery"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerModule");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "NTCLTC25Deg");
|
||||||
|
pt->addRowSeparator(tr("NTC specifications expansion Board"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfExpansionBoard");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerExpansionBoard");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool BmsSettings::addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
QWidget *editor = params->getEditor(paramName);
|
||||||
|
QString name = params->getLongName(paramName);
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
//int row = rowCount();
|
||||||
|
//setRowCount(row + 1);
|
||||||
|
//QTableWidgetItem *item = new QTableWidgetItem(name);
|
||||||
|
//item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||||
|
//setItem(row, 0, item);
|
||||||
|
//setCellWidget(row, 1, editor);
|
||||||
|
//edit->setText(editor->);
|
||||||
|
|
||||||
|
auto vtype = editor->property("type");
|
||||||
|
auto type = vtype.toInt();
|
||||||
|
//CFG_T_UNDEFINED = 0,
|
||||||
|
if(type == 1) // CFG_T_DOUBLE,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toDouble();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 2) // CFG_T_INT,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toInt();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 3) // CFG_T_QSTRING,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toString();
|
||||||
|
edit->setText(val);
|
||||||
|
}
|
||||||
|
else if(type == 4) // CFG_T_ENUM,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toInt();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 5) // CFG_T_BOOL
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toBool();
|
||||||
|
edit->setText(val ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vsuffix = editor->property("suffix");
|
||||||
|
auto suffix = vsuffix.toString();
|
||||||
|
auto veditorDecimalsDouble = editor->property("editorDecimalsDouble");
|
||||||
|
auto editorDecimalsDouble = veditorDecimalsDouble.toDouble();
|
||||||
|
auto veditAsPercentage = editor->property("editAsPercentage");
|
||||||
|
auto editAsPercentage = veditAsPercentage.toBool();
|
||||||
|
|
||||||
|
res = true;
|
||||||
|
//resizeColumnToContents(0);
|
||||||
|
//resizeRowsToContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void BmsSettings::on_pbCalibrateZeroPoint_clicked()
|
||||||
|
{
|
||||||
|
// setZeroCurrent to Terminal
|
||||||
|
//emit sendMessage("setZeroCurrent");
|
||||||
|
|
||||||
|
if ( mDieBieMS == nullptr ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !mDieBieMS->isPortConnected() ) {
|
||||||
|
QMessageBox::critical(this,
|
||||||
|
tr("Connection Error"),
|
||||||
|
tr("The ENNOID-BMS is not connected. Please connect it."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDieBieMS->commands()->sendTerminalCmd("setZeroCurrent");
|
||||||
|
QTimer::singleShot(1000, [this](){
|
||||||
|
this->mDieBieMS->commands()->sendTerminalCmd("config_write");
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void BmsSettings::on_pbWriteIntoNonVolatileMemoryOfBsm_clicked()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::on_pbWriteCurrentValuesIntoBsm_clicked()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void BmsSettings::on_pbWriteToNonVolatileBmsMemory_clicked()
|
||||||
|
{
|
||||||
|
// Записать в энергонезависимую\nпамять BMS
|
||||||
|
// actionStoreBMScconf
|
||||||
|
mDieBieMS->commands()->storeBMSConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettings::on_pbWriteCurrentValuesToBms_clicked()
|
||||||
|
{
|
||||||
|
// Записать текущие значения в BMS
|
||||||
|
// actionWriteBMScconf
|
||||||
|
mDieBieMS->commands()->setBMSconf();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BmsSettings::onSaveBMSConfToXmlFileClicked()
|
||||||
|
{
|
||||||
|
QString path;
|
||||||
|
path = QFileDialog::getSaveFileName(this,
|
||||||
|
tr("Choose where to save the motor configuration XML file"),
|
||||||
|
".",
|
||||||
|
tr("Xml files (*.xml)"));
|
||||||
|
|
||||||
|
if (path.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path.toLower().endsWith(".xml")) {
|
||||||
|
path += ".xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = mDieBieMS->bmsConfig()->saveXml(path, "bmsConfiguration");
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
emit showStatusInfo("Saved motor configuration", true);
|
||||||
|
} else {
|
||||||
|
emit showMessageDialog(tr("Save motor configuration"),
|
||||||
|
tr("Could not save motor configuration:<BR>"
|
||||||
|
"%1").arg(mDieBieMS->bmsConfig()->xmlStatus()),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BmsSettings::onLoadBMSConfFromXmlFileClicked()
|
||||||
|
{
|
||||||
|
QString path;
|
||||||
|
path = QFileDialog::getOpenFileName(this,
|
||||||
|
tr("Choose motor configuration file to load"),
|
||||||
|
".",
|
||||||
|
tr("Xml files (*.xml)"));
|
||||||
|
|
||||||
|
if (path.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = mDieBieMS->bmsConfig()->loadXml(path, "bmsConfiguration");
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
emit showStatusInfo("Loaded motor configuration", true);
|
||||||
|
} else {
|
||||||
|
emit showMessageDialog(tr("Load motor configuration"),
|
||||||
|
tr("Could not load motor configuration:<BR>"
|
||||||
|
"%1").arg(mDieBieMS->bmsConfig()->xmlStatus()),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
89
bmssettings.h
Normal file
89
bmssettings.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#ifndef BWINDOWWITHLEFTTABSBAR_H
|
||||||
|
#define BWINDOWWITHLEFTTABSBAR_H
|
||||||
|
// void PageMasterSettings
|
||||||
|
// Test: Cell groups in Series 10 -> 9 // Записать текущ. в БМС
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class BmsSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParamTable;
|
||||||
|
|
||||||
|
class BmsSettings : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BmsSettings(QWidget *parent = nullptr);
|
||||||
|
~BmsSettings();
|
||||||
|
|
||||||
|
void clearControlls();
|
||||||
|
void prepareSettersFromGuiControlsToSettingsFile();
|
||||||
|
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
|
||||||
|
//bool addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sendMessage(QString message);
|
||||||
|
void showStatusInfo(QString info, bool isGood);
|
||||||
|
void showMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onLoadParams();
|
||||||
|
|
||||||
|
void onBmsconfUpdateRequested();
|
||||||
|
void onBmsconfUpdateRequestDefault();
|
||||||
|
void onBmsconfUpdated();
|
||||||
|
void onBmsconfStored();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_pbCalibrateZeroPoint_clicked();
|
||||||
|
//void on_pbWriteIntoNonVolatileMemoryOfBsm_clicked();
|
||||||
|
//void on_pbWriteCurrentValuesIntoBsm_clicked();
|
||||||
|
void on_pbWriteToNonVolatileBmsMemory_clicked();
|
||||||
|
void on_pbWriteCurrentValuesToBms_clicked();
|
||||||
|
|
||||||
|
void onSaveBMSConfToXmlFileClicked();
|
||||||
|
void onLoadBMSConfFromXmlFileClicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::BmsSettings *ui;
|
||||||
|
|
||||||
|
BMSInterface *mDieBieMS = nullptr;
|
||||||
|
|
||||||
|
//ParamTable * pt; // = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BH
|
||||||
|
|
||||||
|
/*
|
||||||
|
<notUsedCurrentThreshold>
|
||||||
|
<longName>Not used current threshold</longName>
|
||||||
|
<type>1</type>
|
||||||
|
<transmittable>1</transmittable>
|
||||||
|
<description><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
</style></head><body style=" font-family:'DejaVu Sans'; ; font-weight:400; font-style:normal;">
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When the battery current goes below this "Not used battery current threshold" value, the "Not used timeout" timer starts.&quot; </p></body></html></description>
|
||||||
|
<cDefine>NOT_USED_CURRENT_THRESHOLD</cDefine>
|
||||||
|
<editorDecimalsDouble>2</editorDecimalsDouble>
|
||||||
|
<editorScale>1</editorScale>
|
||||||
|
<editAsPercentage>0</editAsPercentage>
|
||||||
|
<maxDouble>10</maxDouble>
|
||||||
|
<minDouble>0</minDouble>
|
||||||
|
<showDisplay>0</showDisplay>
|
||||||
|
<stepDouble>0.1</stepDouble>
|
||||||
|
<valDouble>0.5</valDouble>
|
||||||
|
<vTxDoubleScale>100000</vTxDoubleScale>
|
||||||
|
<suffix>A</suffix>
|
||||||
|
<vTx>9</vTx>
|
||||||
|
</notUsedCurrentThreshold>
|
||||||
|
*/
|
||||||
2201
bmssettings.ui
Normal file
2201
bmssettings.ui
Normal file
File diff suppressed because it is too large
Load Diff
572
bmssettingswidget.cpp
Normal file
572
bmssettingswidget.cpp
Normal file
@@ -0,0 +1,572 @@
|
|||||||
|
#include "bmssettingswidget.h"
|
||||||
|
#include "ui_bmssettingswidget.h"
|
||||||
|
|
||||||
|
#include "widgets/paramtable.h"
|
||||||
|
#include "widgets/parameditdouble.h"
|
||||||
|
#include "configparamsgetter.h"
|
||||||
|
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QDoubleValidator>
|
||||||
|
|
||||||
|
BmsSettingsWidget::BmsSettingsWidget(QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
ui(new Ui::BmsSettingsWidget)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->pbWriteToNonVolatileBmsMemory->hide();
|
||||||
|
ui->pbWriteCurrentValuesToBms->hide();
|
||||||
|
|
||||||
|
//ui->editSerialNumber
|
||||||
|
|
||||||
|
ui->editGroupsNumber->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editCellsNumber->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
ui->editCellsInParallelGroup->setValidator( new QIntValidator(1, 1000, this) );
|
||||||
|
ui->editBatteryCapacity->setValidator( new QIntValidator(0, 10000, this) );
|
||||||
|
|
||||||
|
ui->editMaxVoltageCharge->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editMaxCircuitLoad->setValidator( new QIntValidator(-1000, 10000, this) );
|
||||||
|
ui->editMaxTemperature->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
ui->editMinVoltageWhenWeTurnLoadOff->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editSuchVoltageWhenWeTurnLoadOn->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editSuchVoltageWhenWeTurnChargeOn->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editMaxVoltageWhenWeTurnChargeOff->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
|
||||||
|
ui->editVoltageBalancingStart->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editVoltageDifferenceThreshold->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
ui->editCellBalancingInterval->setValidator( new QIntValidator(-1000, 100000, this) );
|
||||||
|
|
||||||
|
//V
|
||||||
|
//ui->cboxUseToManageStorageDevice
|
||||||
|
//ui->cboxNormallyClosed
|
||||||
|
ui->editSocValueEdit->setValidator( new QDoubleValidator(-100, 100, 2, this) );
|
||||||
|
|
||||||
|
//ui->cboxTemperatureSettingsOver
|
||||||
|
ui->editTemperatureIfLessThenCloseOver->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editTemperatureIfMoeeThenOpenOver->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
//ui->cboxTemperatureSettingsUnder
|
||||||
|
ui->editTemperatureIfLessThenCloseUnder->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
ui->editTemperatureIfMoeeThenOpenUnder->setValidator( new QIntValidator(-1000, 1000, this) );
|
||||||
|
|
||||||
|
ui->editPointZeroDetectorValue->setValidator( new QDoubleValidator(-1000, 1000, 2, this) );
|
||||||
|
|
||||||
|
// BTNS
|
||||||
|
//ui->pbCalibrateZeroPoint
|
||||||
|
//ui->pbWriteIntoNonVolatileMemoryOfBsm
|
||||||
|
//ui->pbWriteCurrentValuesIntoBsm
|
||||||
|
|
||||||
|
clearControlls();
|
||||||
|
}
|
||||||
|
|
||||||
|
BmsSettingsWidget::~BmsSettingsWidget()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void BmsSettingsWidget::onBmsconfUpdateRequested()
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::onBmsconfUpdateRequestDefault()
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::onBmsconfUpdated()
|
||||||
|
{
|
||||||
|
// ^ - 8 7 | 8 8 read bms conf
|
||||||
|
// After we hav red real BMS Config params from BMS we put all of them into the GUI elements
|
||||||
|
|
||||||
|
// Load default params from Bms to GUI Elements
|
||||||
|
//-> - 7 7 | 7 8 read default 8 is defaul - that was on the start
|
||||||
|
// Загрузить настройки\nпо умолчанию
|
||||||
|
//mDieBieMS->commands()->getBMSconfDefault();
|
||||||
|
|
||||||
|
onLoadParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::onBmsconfStored()
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BmsSettingsWidget::clearControlls()
|
||||||
|
{
|
||||||
|
ui->editGroupsNumber ->clear();
|
||||||
|
ui->editCellsNumber ->clear();
|
||||||
|
|
||||||
|
ui->editCellsInParallelGroup ->clear();
|
||||||
|
ui->editBatteryCapacity ->clear();
|
||||||
|
|
||||||
|
ui->editMaxVoltageCharge ->clear();
|
||||||
|
ui->editMaxCircuitLoad ->clear();
|
||||||
|
ui->editMaxTemperature ->clear();
|
||||||
|
|
||||||
|
ui->editMinVoltageWhenWeTurnLoadOff ->clear();
|
||||||
|
ui->editSuchVoltageWhenWeTurnLoadOn ->clear();
|
||||||
|
ui->editSuchVoltageWhenWeTurnChargeOn ->clear();
|
||||||
|
ui->editMaxVoltageWhenWeTurnChargeOff ->clear();
|
||||||
|
|
||||||
|
|
||||||
|
ui->editVoltageBalancingStart ->clear();
|
||||||
|
ui->editVoltageDifferenceThreshold ->clear();
|
||||||
|
ui->editCellBalancingInterval ->clear();
|
||||||
|
|
||||||
|
//1
|
||||||
|
ui->cboxUseToManageStorageDevice ->setChecked(false);
|
||||||
|
//2
|
||||||
|
ui->cboxNormallyClosed ->setChecked(false);
|
||||||
|
ui->editSocValueEdit ->clear();
|
||||||
|
//3
|
||||||
|
ui->cboxTemperatureSettingsOver ->setChecked(false);
|
||||||
|
ui->editTemperatureIfLessThenCloseOver ->clear();
|
||||||
|
ui->editTemperatureIfMoeeThenOpenOver ->clear();
|
||||||
|
//4
|
||||||
|
ui->cboxTemperatureSettingsUnder ->setChecked(false);
|
||||||
|
ui->editTemperatureIfLessThenCloseUnder ->clear();
|
||||||
|
ui->editTemperatureIfMoeeThenOpenUnder ->clear();
|
||||||
|
// 0
|
||||||
|
ui->editPointZeroDetectorValue ->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::prepareSettersFromGuiControlsToSettingsFile()
|
||||||
|
{
|
||||||
|
/// Setters
|
||||||
|
#define QS QString
|
||||||
|
|
||||||
|
auto cfg = mDieBieMS->bmsConfig();
|
||||||
|
|
||||||
|
/// Конфигурация *
|
||||||
|
connect(ui->editGroupsNumber, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editGroupsNumber->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("cellMonitorICCount", val); });
|
||||||
|
connect(ui->editCellsNumber, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{
|
||||||
|
QS s =ui->editCellsNumber->text();
|
||||||
|
QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt());
|
||||||
|
cfg->setParamValue("noOfCellsSeries", val);
|
||||||
|
});
|
||||||
|
// Конфигурация *
|
||||||
|
//addParamRow(ui->editGroupsNumber , mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
//addParamRow(ui->editCellsNumber , mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
|
||||||
|
/// SOC *
|
||||||
|
connect(ui->editCellsInParallelGroup, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editCellsInParallelGroup->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("noOfCellsParallel", val); });
|
||||||
|
connect(ui->editBatteryCapacity, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editBatteryCapacity->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("batteryCapacity", val); });
|
||||||
|
// SOC *
|
||||||
|
//addParamRow(ui->editCellsInParallelGroup , mDieBieMS->bmsConfig(), "noOfCellsParallel");
|
||||||
|
//addParamRow(ui->editBatteryCapacity , mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
|
||||||
|
/// Ограничения *
|
||||||
|
connect(ui->editMaxVoltageCharge, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxVoltageCharge->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("maxAllowedCurrent", val); });
|
||||||
|
connect(ui->editMaxCircuitLoad, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxCircuitLoad->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("maxMismatchThreshold", val); });
|
||||||
|
connect(ui->editMaxTemperature, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxTemperature->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("allowedTempBattChargingMax", val); });
|
||||||
|
// Ограничения *
|
||||||
|
//addParamRow(ui->editMaxVoltageCharge , mDieBieMS->bmsConfig(), "maxAllowedCurrent");
|
||||||
|
//addParamRow(ui->editMaxCircuitLoad , mDieBieMS->bmsConfig(), "maxMismatchThreshold");
|
||||||
|
//addParamRow(ui->editMaxTemperature , mDieBieMS->bmsConfig(), "allowedTempBattChargingMax");
|
||||||
|
|
||||||
|
/// Конфигурация ячеек *
|
||||||
|
connect(ui->editMinVoltageWhenWeTurnLoadOff, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMinVoltageWhenWeTurnLoadOff->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellHardUnderVoltage", val); });
|
||||||
|
connect(ui->editSuchVoltageWhenWeTurnLoadOn, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editSuchVoltageWhenWeTurnLoadOn->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellHardOverVoltage", val); });
|
||||||
|
connect(ui->editSuchVoltageWhenWeTurnChargeOn, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editSuchVoltageWhenWeTurnChargeOn->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellLCSoftUnderVoltage", val); });
|
||||||
|
connect(ui->editMaxVoltageWhenWeTurnChargeOff, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editMaxVoltageWhenWeTurnChargeOff->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellSoftOverVoltage", val); });
|
||||||
|
// Конфигурация ячеек *
|
||||||
|
//addParamRow(ui->editMinVoltageWhenWeTurnLoadOff , mDieBieMS->bmsConfig(), "cellHardUnderVoltage");
|
||||||
|
//addParamRow(ui->editSuchVoltageWhenWeTurnLoadOn , mDieBieMS->bmsConfig(), "cellHardOverVoltage");
|
||||||
|
//addParamRow(ui->editSuchVoltageWhenWeTurnChargeOn , mDieBieMS->bmsConfig(), "cellLCSoftUnderVoltage");
|
||||||
|
//addParamRow(ui->editMaxVoltageWhenWeTurnChargeOff , mDieBieMS->bmsConfig(), "cellSoftOverVoltage");
|
||||||
|
|
||||||
|
/// Конфигурация балансировки * // ui->balancingTab
|
||||||
|
connect(ui->editVoltageBalancingStart, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editVoltageBalancingStart->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellBalanceStart", val); });
|
||||||
|
connect(ui->editVoltageDifferenceThreshold, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editVoltageDifferenceThreshold->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble()); cfg->setParamValue("cellBalanceDifferenceThreshold", val); });
|
||||||
|
connect(ui->editCellBalancingInterval, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{ QS s =ui->editCellBalancingInterval->text(); QVariant val((s.isEmpty() || s=="-") ? 0 : s.toInt()); cfg->setParamValue("cellBalanceUpdateInterval", val); });
|
||||||
|
// Конфигурация балансировки * // ui->balancingTab
|
||||||
|
//addParamRow(ui->editVoltageBalancingStart , mDieBieMS->bmsConfig(), "cellBalanceStart");
|
||||||
|
//addParamRow(ui->editVoltageDifferenceThreshold , mDieBieMS->bmsConfig(), "cellBalanceDifferenceThreshold");
|
||||||
|
//addParamRow(ui->editCellBalancingInterval , mDieBieMS->bmsConfig(), "cellBalanceUpdateInterval");
|
||||||
|
|
||||||
|
/// Калибровать Нулевую точку * // ui->signalsTab
|
||||||
|
connect(ui->editPointZeroDetectorValue, &QLineEdit::textChanged, this, [this, cfg]()
|
||||||
|
{
|
||||||
|
QS s =ui->editPointZeroDetectorValue->text();
|
||||||
|
QVariant val((s.isEmpty() || s=="-") ? 0 : s.toDouble());
|
||||||
|
cfg->setParamValue("shuntLCFactor", val);
|
||||||
|
});
|
||||||
|
// Нулевая точка * // ui->signalsTab
|
||||||
|
//addParamRow(ui->editPointZeroDetectorValue , mDieBieMS->bmsConfig(), "shuntLCFactor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::onLoadParams()
|
||||||
|
{
|
||||||
|
////
|
||||||
|
auto cfg = mDieBieMS->bmsConfig();
|
||||||
|
// Конфигурация *
|
||||||
|
addParamRow(ui->editGroupsNumber , cfg, "cellMonitorICCount");
|
||||||
|
addParamRow(ui->editCellsNumber , cfg, "noOfCellsSeries");
|
||||||
|
// SOC *
|
||||||
|
addParamRow(ui->editCellsInParallelGroup , cfg, "noOfCellsParallel");
|
||||||
|
addParamRow(ui->editBatteryCapacity , cfg, "batteryCapacity");
|
||||||
|
// Ограничения *
|
||||||
|
addParamRow(ui->editMaxVoltageCharge , cfg, "maxAllowedCurrent");
|
||||||
|
addParamRow(ui->editMaxCircuitLoad , cfg, "maxMismatchThreshold");
|
||||||
|
addParamRow(ui->editMaxTemperature , cfg, "allowedTempBattChargingMax");
|
||||||
|
// Конфигурация ячеек *
|
||||||
|
addParamRow(ui->editMinVoltageWhenWeTurnLoadOff , cfg, "cellHardUnderVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnLoadOn , cfg, "cellHardOverVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnChargeOn , cfg, "cellLCSoftUnderVoltage");
|
||||||
|
addParamRow(ui->editMaxVoltageWhenWeTurnChargeOff , cfg, "cellSoftOverVoltage");
|
||||||
|
// Конфигурация балансировки *
|
||||||
|
// ui->balancingTab
|
||||||
|
addParamRow(ui->editVoltageBalancingStart , cfg, "cellBalanceStart");
|
||||||
|
addParamRow(ui->editVoltageDifferenceThreshold , cfg, "cellBalanceDifferenceThreshold");
|
||||||
|
addParamRow(ui->editCellBalancingInterval , cfg, "cellBalanceUpdateInterval");
|
||||||
|
// Нулевая точка *
|
||||||
|
// ui->signalsTab
|
||||||
|
addParamRow(ui->editPointZeroDetectorValue , cfg, "shuntLCFactor");
|
||||||
|
////*/
|
||||||
|
|
||||||
|
// Turn ON Setters only ONCE AFTER we load all data from file and when First connection is Ready
|
||||||
|
if(mDoConnectGettersOnStart)
|
||||||
|
{
|
||||||
|
// Выполнили все коннекты при первом старте и более не вызываем
|
||||||
|
qDebug() << "::prepareSettersFromGuiControlsToSettingsFile();";
|
||||||
|
prepareSettersFromGuiControlsToSettingsFile();
|
||||||
|
mDoConnectGettersOnStart = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn ON Setters only ONCE AFTER we load all data from file and when First connection is Ready
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
<cellBalanceStart>
|
||||||
|
<longName>Cell balance start voltage</longName>
|
||||||
|
|
||||||
|
cellMonitorICCount ->
|
||||||
|
noOfCellsSeries ->
|
||||||
|
--
|
||||||
|
noOfCellsParallel ->
|
||||||
|
<batteryCapacity>
|
||||||
|
<longName>Battery capacity total</longName>
|
||||||
|
--
|
||||||
|
<maxMismatchThreshold>
|
||||||
|
<longName>Mismatch threshold</longName>
|
||||||
|
<maxAllowedCurrent>
|
||||||
|
<longName>Max allowed current</longName>
|
||||||
|
<allowedTempBattChargingMax>
|
||||||
|
<longName>Battery temperature charging max</longName>
|
||||||
|
--
|
||||||
|
<cellHardUnderVoltage>
|
||||||
|
<longName>Cell hard undervoltage</longName>
|
||||||
|
<cellHardOverVoltage>
|
||||||
|
<longName>Cell hard overvoltage</longName>
|
||||||
|
<cellLCSoftUnderVoltage>
|
||||||
|
<longName>Cell low current soft undervoltage</longName>
|
||||||
|
<cellSoftOverVoltage>
|
||||||
|
<longName>Cell soft overvoltage</longName>
|
||||||
|
--
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
#if 0
|
||||||
|
ConfigParam *p = mDieBieMS->infoConfig()->getParam("master_setting_description");
|
||||||
|
if (p != 0) {
|
||||||
|
ui->textEdit->setHtml(p->description);
|
||||||
|
} else {
|
||||||
|
ui->textEdit->setText("Master Setting Description not found.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ConfigParams *const conf = mDieBieMS->bmsConfig();
|
||||||
|
///ParamTable *const pt = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
///pt->addRowSeparator(tr("Current"));
|
||||||
|
// Нулевая точка
|
||||||
|
addParamRow(ui->editPointZeroDetectorValue , mDieBieMS->bmsConfig(), "shuntLCFactor");
|
||||||
|
//pt->addParamRow(conf, "shuntLCFactor");
|
||||||
|
////pt->addParamRow(conf, "shuntOffset");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Pack configuration"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "cellMonitorICType");
|
||||||
|
#endif
|
||||||
|
// Конфигурация
|
||||||
|
addParamRow(ui->editGroupsNumber , mDieBieMS->bmsConfig(), "cellMonitorICCount");
|
||||||
|
addParamRow(ui->editCellsNumber , mDieBieMS->bmsConfig(), "noOfCellsSeries");
|
||||||
|
//pt->addParamRow(conf, "cellMonitorICCount");
|
||||||
|
///pt->addParamRow(conf, "noOfParallelModules");
|
||||||
|
//pt->addParamRow(conf, "noOfCellsSeries");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("SOC - Pack capacity"));
|
||||||
|
//pt->addParamRow(conf, "noOfCellsParallel");
|
||||||
|
//pt->addParamRow(conf, "batteryCapacity");
|
||||||
|
// SOC
|
||||||
|
addParamRow(ui->editCellsInParallelGroup , mDieBieMS->bmsConfig(), "noOfCellsParallel");
|
||||||
|
addParamRow(ui->editBatteryCapacity , mDieBieMS->bmsConfig(), "batteryCapacity");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Cell specifications"));
|
||||||
|
//pt->addParamRow(conf, "cellHardUnderVoltage");
|
||||||
|
//pt->addParamRow(conf, "cellHardOverVoltage");
|
||||||
|
//pt->addParamRow(conf, "cellLCSoftUnderVoltage");
|
||||||
|
//pt->addParamRow(conf, "cellSoftOverVoltage");
|
||||||
|
// Конфигурация ячеек
|
||||||
|
addParamRow(ui->editMinVoltageWhenWeTurnLoadOff , mDieBieMS->bmsConfig(), "cellHardUnderVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnLoadOn , mDieBieMS->bmsConfig(), "cellHardOverVoltage");
|
||||||
|
addParamRow(ui->editSuchVoltageWhenWeTurnChargeOn , mDieBieMS->bmsConfig(), "cellLCSoftUnderVoltage");
|
||||||
|
addParamRow(ui->editMaxVoltageWhenWeTurnChargeOff , mDieBieMS->bmsConfig(), "cellSoftOverVoltage");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Balancing configuration"));
|
||||||
|
//pt->addParamRow(conf, "cellBalanceStart");
|
||||||
|
//pt->addParamRow(conf, "cellBalanceDifferenceThreshold");
|
||||||
|
//pt->addParamRow(conf, "cellBalanceUpdateInterval");
|
||||||
|
// Конфигурация балансировки
|
||||||
|
// ui->balancingTab
|
||||||
|
addParamRow(ui->editVoltageBalancingStart , mDieBieMS->bmsConfig(), "cellBalanceStart");
|
||||||
|
addParamRow(ui->editVoltageDifferenceThreshold , mDieBieMS->bmsConfig(), "cellBalanceDifferenceThreshold");
|
||||||
|
addParamRow(ui->editCellBalancingInterval , mDieBieMS->bmsConfig(), "cellBalanceUpdateInterval");
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("SoC general"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "stateOfChargeStoreInterval");
|
||||||
|
pt->addParamRow(conf, "timeoutChargeCompleted");
|
||||||
|
pt->addParamRow(conf, "timeoutChargingCompletedMinimalMismatch");
|
||||||
|
#endif
|
||||||
|
///pt->addParamRow(conf, "minimalPrechargePercentage"); // from pagemastersettings.cpp
|
||||||
|
///pt->addParamRow(conf, "timeoutLCPreCharge"); // from pagemastersettings.cpp
|
||||||
|
|
||||||
|
///pt->addRowSeparator(tr("Limits"));
|
||||||
|
//pt->addParamRow(conf, "maxMismatchThreshold");
|
||||||
|
//pt->addParamRow(conf, "maxAllowedCurrent");
|
||||||
|
// Ограничения
|
||||||
|
addParamRow(ui->editMaxVoltageCharge , mDieBieMS->bmsConfig(), "maxAllowedCurrent");
|
||||||
|
addParamRow(ui->editMaxCircuitLoad , mDieBieMS->bmsConfig(), "maxMismatchThreshold");
|
||||||
|
addParamRow(ui->editMaxTemperature , mDieBieMS->bmsConfig(), "allowedTempBattChargingMax");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMax");
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMin");
|
||||||
|
#endif
|
||||||
|
//pt->addParamRow(conf, "allowedTempBattChargingMax");
|
||||||
|
///pt->addParamRow(conf, "allowedTempBattChargingMin");
|
||||||
|
#if 0 // disable
|
||||||
|
///pt->addRowSeparator(tr("NTC specifications battery"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerModule");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "NTCLTC25Deg");
|
||||||
|
///pt->addRowSeparator(tr("NTC specifications expansion Board"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfExpansionBoard");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerExpansionBoard");
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BmsSettingsWidget::onPortConnectedChanged()
|
||||||
|
{
|
||||||
|
if(mDieBieMS)
|
||||||
|
{
|
||||||
|
mIsBmsConnected = mDieBieMS->isPortConnected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMSInterface *BmsSettingsWidget::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{ // void PageMasterSettings::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
//pt = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
|
||||||
|
connect(mDieBieMS, &BMSInterface::portConnectedChanged, this, &BmsSettingsWidget::onPortConnectedChanged);
|
||||||
|
|
||||||
|
//onLoadParams();
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (mDieBieMS) {
|
||||||
|
#if 0
|
||||||
|
ConfigParam *p = mDieBieMS->infoConfig()->getParam("master_setting_description");
|
||||||
|
if (p != 0) {
|
||||||
|
ui->textEdit->setHtml(p->description);
|
||||||
|
} else {
|
||||||
|
ui->textEdit->setText("Master Setting Description not found.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ConfigParams *const conf = mDieBieMS->bmsConfig();
|
||||||
|
ParamTable *const pt = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
pt->addRowSeparator(tr("Current"));
|
||||||
|
pt->addParamRow(conf, "shuntLCFactor");
|
||||||
|
pt->addParamRow(conf, "shuntOffset");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Pack configuration"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "cellMonitorICType");
|
||||||
|
#endif
|
||||||
|
pt->addParamRow(conf, "cellMonitorICCount");
|
||||||
|
pt->addParamRow(conf, "noOfParallelModules");
|
||||||
|
pt->addParamRow(conf, "noOfCellsSeries");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("SOC - Pack capacity"));
|
||||||
|
pt->addParamRow(conf, "noOfCellsParallel");
|
||||||
|
pt->addParamRow(conf, "batteryCapacity");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Cell specifications"));
|
||||||
|
pt->addParamRow(conf, "cellHardUnderVoltage");
|
||||||
|
pt->addParamRow(conf, "cellHardOverVoltage");
|
||||||
|
pt->addParamRow(conf, "cellLCSoftUnderVoltage");
|
||||||
|
pt->addParamRow(conf, "cellSoftOverVoltage");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Balancing configuration"));
|
||||||
|
pt->addParamRow(conf, "cellBalanceStart");
|
||||||
|
pt->addParamRow(conf, "cellBalanceDifferenceThreshold");
|
||||||
|
pt->addParamRow(conf, "cellBalanceUpdateInterval");
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("SoC general"));
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addParamRow(conf, "stateOfChargeStoreInterval");
|
||||||
|
pt->addParamRow(conf, "timeoutChargeCompleted");
|
||||||
|
pt->addParamRow(conf, "timeoutChargingCompletedMinimalMismatch");
|
||||||
|
#endif
|
||||||
|
pt->addParamRow(conf, "minimalPrechargePercentage"); // from pagemastersettings.cpp
|
||||||
|
pt->addParamRow(conf, "timeoutLCPreCharge"); // from pagemastersettings.cpp
|
||||||
|
|
||||||
|
pt->addRowSeparator(tr("Limits"));
|
||||||
|
pt->addParamRow(conf, "maxMismatchThreshold");
|
||||||
|
pt->addParamRow(conf, "maxAllowedCurrent");
|
||||||
|
#if 0
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMax");
|
||||||
|
pt->addParamRow(conf, "allowedTempBattDischargingMin");
|
||||||
|
#endif
|
||||||
|
pt->addParamRow(conf, "allowedTempBattChargingMax");
|
||||||
|
pt->addParamRow(conf, "allowedTempBattChargingMin");
|
||||||
|
|
||||||
|
#if 0 // disable
|
||||||
|
pt->addRowSeparator(tr("NTC specifications battery"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerModule");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "NTCLTC25Deg");
|
||||||
|
pt->addRowSeparator(tr("NTC specifications expansion Board"));
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfExpansionBoard");
|
||||||
|
pt->addParamRow(mDieBieMS->bmsConfig(), "noOfTempSensorPerExpansionBoard");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool BmsSettingsWidget::addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
QWidget *editor = params->getEditor(paramName);
|
||||||
|
QString name = params->getLongName(paramName);
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
//int row = rowCount();
|
||||||
|
//setRowCount(row + 1);
|
||||||
|
//QTableWidgetItem *item = new QTableWidgetItem(name);
|
||||||
|
//item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||||
|
//setItem(row, 0, item);
|
||||||
|
//setCellWidget(row, 1, editor);
|
||||||
|
//edit->setText(editor->);
|
||||||
|
|
||||||
|
auto vtype = editor->property("type");
|
||||||
|
auto type = vtype.toInt();
|
||||||
|
//CFG_T_UNDEFINED = 0,
|
||||||
|
if(type == 1) // CFG_T_DOUBLE,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toDouble();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 2) // CFG_T_INT,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toInt();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 3) // CFG_T_QSTRING,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toString();
|
||||||
|
edit->setText(val);
|
||||||
|
}
|
||||||
|
else if(type == 4) // CFG_T_ENUM,
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toInt();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
}
|
||||||
|
else if(type == 5) // CFG_T_BOOL
|
||||||
|
{
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
auto val = vval.toBool();
|
||||||
|
edit->setText(val ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vsuffix = editor->property("suffix");
|
||||||
|
auto suffix = vsuffix.toString();
|
||||||
|
auto veditorDecimalsDouble = editor->property("editorDecimalsDouble");
|
||||||
|
auto editorDecimalsDouble = veditorDecimalsDouble.toDouble();
|
||||||
|
auto veditAsPercentage = editor->property("editAsPercentage");
|
||||||
|
auto editAsPercentage = veditAsPercentage.toBool();
|
||||||
|
|
||||||
|
res = true;
|
||||||
|
//resizeColumnToContents(0);
|
||||||
|
//resizeRowsToContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void BmsSettingsWidget::on_pbCalibrateZeroPoint_clicked()
|
||||||
|
{
|
||||||
|
// setZeroCurrent to Terminal
|
||||||
|
emit sendMessage("setZeroCurrent");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void BmsSettingsWidget::on_pbWriteIntoNonVolatileMemoryOfBsm_clicked()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::on_pbWriteCurrentValuesIntoBsm_clicked()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void BmsSettingsWidget::on_pbWriteToNonVolatileBmsMemory_clicked()
|
||||||
|
{
|
||||||
|
// Записать в энергонезависимую\nпамять BMS
|
||||||
|
// actionStoreBMScconf
|
||||||
|
mDieBieMS->commands()->storeBMSConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BmsSettingsWidget::on_pbWriteCurrentValuesToBms_clicked()
|
||||||
|
{
|
||||||
|
// Записать текущие значения в BMS
|
||||||
|
// actionWriteBMScconf
|
||||||
|
mDieBieMS->commands()->setBMSconf();
|
||||||
|
}
|
||||||
|
|
||||||
62
bmssettingswidget.h
Normal file
62
bmssettingswidget.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef BMSSETTINGSWIDGET_H
|
||||||
|
#define BMSSETTINGSWIDGET_H
|
||||||
|
// void PageMasterSettings
|
||||||
|
// Test: Cell groups in Series 10 -> 9 // Записать текущ. в БМС
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class BmsSettingsWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParamTable;
|
||||||
|
|
||||||
|
class BmsSettingsWidget : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BmsSettingsWidget(QWidget *parent = nullptr);
|
||||||
|
~BmsSettingsWidget();
|
||||||
|
|
||||||
|
void clearControlls();
|
||||||
|
void prepareSettersFromGuiControlsToSettingsFile();
|
||||||
|
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
|
||||||
|
//bool addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sendMessage(QString message);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onLoadParams();
|
||||||
|
|
||||||
|
void onBmsconfUpdateRequested();
|
||||||
|
void onBmsconfUpdateRequestDefault();
|
||||||
|
void onBmsconfUpdated();
|
||||||
|
void onBmsconfStored();
|
||||||
|
|
||||||
|
void onPortConnectedChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_pbCalibrateZeroPoint_clicked();
|
||||||
|
//void on_pbWriteIntoNonVolatileMemoryOfBsm_clicked();
|
||||||
|
//void on_pbWriteCurrentValuesIntoBsm_clicked();
|
||||||
|
void on_pbWriteToNonVolatileBmsMemory_clicked();
|
||||||
|
void on_pbWriteCurrentValuesToBms_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::BmsSettingsWidget *ui;
|
||||||
|
|
||||||
|
BMSInterface *mDieBieMS;
|
||||||
|
bool mIsBmsConnected = false;
|
||||||
|
bool mDoConnectGettersOnStart = true;
|
||||||
|
//ParamTable * pt; // = new ParamTable(this); //ui->masterStateTab;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BMSSETTINGSWIDGET_H
|
||||||
2135
bmssettingswidget.ui
Normal file
2135
bmssettingswidget.ui
Normal file
File diff suppressed because it is too large
Load Diff
116
cellsmonitorcheckboxdelegate.cpp
Normal file
116
cellsmonitorcheckboxdelegate.cpp
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include "cellsmonitorcheckboxdelegate.h"
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
|
||||||
|
:QStyledItemDelegate (parent)
|
||||||
|
{
|
||||||
|
m_circleSize = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *CheckBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(option)
|
||||||
|
Q_UNUSED(index)
|
||||||
|
|
||||||
|
//Cоздаем checkbox editor
|
||||||
|
QCheckBox *editor = new QCheckBox(parent);
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
//Установливаем выбрано/не выбрано
|
||||||
|
QCheckBox *cb = qobject_cast<QCheckBox *>(editor);
|
||||||
|
cb->setStyleSheet("QCheckBox::indicator {\n width: 20px;\n height: " + QString::number( m_circleSize ) + "px;\n border: 1px solid grey;\n background: white;\n border-radius:3px;\n} \n\nQCheckBox::indicator:checked {\n border-color: green;\n background: green;\n color:white;\n /*image: url(:/res/checkbox_unchecked_hover.png);*/\n} \n\n\n\nQCheckBox {\n font-weight:bold;\n font-size: 14px;\n}");
|
||||||
|
cb->setChecked(index.data().toBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
//Записываем данные в модель
|
||||||
|
QCheckBox *cb = static_cast<QCheckBox *>(editor);
|
||||||
|
int value = (cb->checkState()==Qt::Checked)? 1 : 0;
|
||||||
|
model->setData(index, value, Qt::EditRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(index);
|
||||||
|
QStyleOptionButton checkboxstyle;
|
||||||
|
QRect checkbox_rect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkboxstyle);
|
||||||
|
|
||||||
|
//Центрирование
|
||||||
|
checkboxstyle.rect = option.rect;
|
||||||
|
checkboxstyle.rect.setLeft(option.rect.x() +
|
||||||
|
option.rect.width()/2 - checkbox_rect.width()/2);
|
||||||
|
|
||||||
|
editor->setGeometry(checkboxstyle.rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
int row = index.row();
|
||||||
|
int col = index.column();
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
//Получаем данные
|
||||||
|
auto data = index.model()->data(index, Qt::DisplayRole);
|
||||||
|
|
||||||
|
//Создаем стиль CheckBox
|
||||||
|
QStyleOptionButton checkboxstyle;
|
||||||
|
//Выбрано или не выбрано
|
||||||
|
|
||||||
|
bool isChecked = data.toBool();
|
||||||
|
if(data.toBool())
|
||||||
|
checkboxstyle.state = QStyle::State_On|QStyle::State_Enabled;
|
||||||
|
else
|
||||||
|
checkboxstyle.state = QStyle::State_Off|QStyle::State_Enabled;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(!index.data().isNull())
|
||||||
|
{
|
||||||
|
QRect checkbox_rect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkboxstyle);
|
||||||
|
|
||||||
|
//Центрирование
|
||||||
|
checkboxstyle.rect = option.rect;
|
||||||
|
checkboxstyle.rect.setLeft(option.rect.x() +
|
||||||
|
option.rect.width()/2 - checkbox_rect.width()/2);
|
||||||
|
RectangleClass r;
|
||||||
|
int centerX = option.rect.width()/2 - m_circleSize/2;
|
||||||
|
int centerY = option.rect.height()/2 - m_circleSize/2;
|
||||||
|
|
||||||
|
|
||||||
|
r.draw
|
||||||
|
(
|
||||||
|
painter,
|
||||||
|
QRectF(
|
||||||
|
option.rect.x() + centerX, //+mx,
|
||||||
|
option.rect.y() + centerY, //+my,
|
||||||
|
m_circleSize,
|
||||||
|
m_circleSize
|
||||||
|
),
|
||||||
|
isChecked ? QColor("#009352") // green
|
||||||
|
: QColor("#dfe0eb"),
|
||||||
|
11
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RectClass r;
|
||||||
|
QRectF rectT( option.rect );
|
||||||
|
r.draw
|
||||||
|
(
|
||||||
|
painter,
|
||||||
|
rectT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
64
cellsmonitorcheckboxdelegate.h
Normal file
64
cellsmonitorcheckboxdelegate.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#ifndef CHECKBOXDELEGATE_H
|
||||||
|
#define CHECKBOXDELEGATE_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
class CheckBoxDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CheckBoxDelegate(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
void setEditorData(QWidget *editor, const QModelIndex &index) const;
|
||||||
|
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
|
||||||
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
|
||||||
|
class RectClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void draw(QPainter *painter, const QRectF &rectL, QColor colorL = QColor("#FFFFFF"), int radiusL = 0) const
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
// Rect
|
||||||
|
QPen penw(colorL);
|
||||||
|
painter->setPen(penw);
|
||||||
|
painter->drawRect(rectL);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class RectangleClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//void draw(QPainter *painter, const QRectF &rect, QColor color = QColor("#FFFFFF"), int radius = 0) const;
|
||||||
|
//void RectangleClass::draw(QPainter *painter, const QRectF &rect, QColor color, int radius) const
|
||||||
|
void draw(QPainter *painter, const QRectF &rect, QColor color = QColor("#FFFFFF"), int radius = 0)
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRoundedRect(rect, radius, radius);
|
||||||
|
QPen pen(color);
|
||||||
|
painter->setPen(pen);
|
||||||
|
painter->fillPath(path, color);
|
||||||
|
painter->drawPath(path);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_circleSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHECKBOXDELEGATE_H
|
||||||
104
cellsmonitorlabelvoltagedelegate.cpp
Normal file
104
cellsmonitorlabelvoltagedelegate.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include "cellsmonitorlabelvoltagedelegate.h"
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
|
||||||
|
LabelVoltageDelegate::LabelVoltageDelegate(QObject *parent)
|
||||||
|
: QStyledItemDelegate(parent) //: QItemDelegate(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *LabelVoltageDelegate::createEditor(QWidget *parent,
|
||||||
|
const QStyleOptionViewItem & option,
|
||||||
|
const QModelIndex & index ) const
|
||||||
|
{
|
||||||
|
QLineEdit *editor = new QLineEdit(parent);
|
||||||
|
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelVoltageDelegate::setEditorData(QWidget *editor,
|
||||||
|
const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QString value = index.model()->data(index, Qt::EditRole).toString();
|
||||||
|
|
||||||
|
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
|
||||||
|
lineEdit->setText(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelVoltageDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||||
|
const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
|
||||||
|
QString value = lineEdit->text();
|
||||||
|
|
||||||
|
model->setData(index, value, Qt::EditRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelVoltageDelegate::updateEditorGeometry(QWidget *editor,
|
||||||
|
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
|
||||||
|
{
|
||||||
|
editor->setGeometry(option.rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelVoltageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
//Получаем данные
|
||||||
|
auto data = index.model()->data(index, Qt::DisplayRole).toString();
|
||||||
|
|
||||||
|
//Создаем стиль CheckBox
|
||||||
|
QStyleOptionButton checkboxstyle;
|
||||||
|
//Выбрано или не выбрано
|
||||||
|
QRect checkbox_rect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &checkboxstyle);
|
||||||
|
|
||||||
|
//Центрирование
|
||||||
|
checkboxstyle.rect = option.rect;
|
||||||
|
checkboxstyle.rect.setLeft(option.rect.x() +
|
||||||
|
option.rect.width()/2 - checkbox_rect.width()/2);
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
if(!data.isEmpty())
|
||||||
|
{
|
||||||
|
|
||||||
|
LineWithText r;
|
||||||
|
|
||||||
|
int centerX = option.rect.width()/2 - m_circleSize/2;
|
||||||
|
int centerY = option.rect.height()/2 - m_circleSize/2;
|
||||||
|
QRectF rectL(
|
||||||
|
option.rect.x(),
|
||||||
|
option.rect.y() + option.rect.height()/2 ,
|
||||||
|
option.rect.width(),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
QRectF rectT( option.rect );
|
||||||
|
//QString res = QString::number(data,'f',1);
|
||||||
|
|
||||||
|
r.draw
|
||||||
|
(
|
||||||
|
painter,
|
||||||
|
rectL,
|
||||||
|
//QColor("#009352"), // green
|
||||||
|
QColor("#bfc5d7"),
|
||||||
|
11,
|
||||||
|
rectT,
|
||||||
|
QString("%1 V").arg(data)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RectClass r;
|
||||||
|
QRectF rectT( option.rect );
|
||||||
|
r.draw
|
||||||
|
(
|
||||||
|
painter,
|
||||||
|
rectT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
75
cellsmonitorlabelvoltagedelegate.h
Normal file
75
cellsmonitorlabelvoltagedelegate.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#ifndef LABELVOLTAGEDELEGATE_H
|
||||||
|
#define LABELVOLTAGEDELEGATE_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
class LabelVoltageDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
LabelVoltageDelegate(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
void setEditorData(QWidget *editor, const QModelIndex &index) const;
|
||||||
|
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
|
||||||
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_circleSize;
|
||||||
|
|
||||||
|
class RectClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void draw(QPainter *painter, const QRectF &rectL, QColor colorL = QColor("#FFFFFF"), int radiusL = 0) const
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
// Rect
|
||||||
|
QPen penw(colorL);
|
||||||
|
painter->setPen(penw);
|
||||||
|
painter->drawRect(rectL);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LineWithText
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void draw(QPainter *painter, const QRectF &rectL, QColor colorL = QColor("#FFFFFF"), int radiusL = 0,
|
||||||
|
const QRectF rectT=QRectF(0,0,0,0), QString text = "", QColor colorT = QColor("#000000"), QFont fontT = QFont("Arial", 13, QFont::Bold) , QColor colorBackground = QColor("#FFFFFF")) const
|
||||||
|
//;
|
||||||
|
//void LineWithText::draw (QPainter *painter, const QRectF &rectL, QColor colorL, int radiusL,
|
||||||
|
// const QRectF rectT, QString text, QColor colorT, QFont fontT ) const
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
// Line
|
||||||
|
QPen pen(colorL);
|
||||||
|
pen.setStyle(Qt::DotLine);
|
||||||
|
painter->setPen(pen);
|
||||||
|
painter->drawLine(rectL.left(), rectL.top(), rectL.right()*1.15, rectL.bottom());
|
||||||
|
// Rect
|
||||||
|
QPen penw(colorBackground);
|
||||||
|
painter->setPen(penw);
|
||||||
|
QFontMetrics fm(fontT);
|
||||||
|
double width = 0.0;
|
||||||
|
//width = fm.horizontalAdvance(text);
|
||||||
|
int width1 = fm.lineWidth();
|
||||||
|
int len = ((rectL.right()/2)-(width/2));
|
||||||
|
painter->drawRect(rectL.left()+27, rectL.top(), width*1.2, rectL.bottom());
|
||||||
|
// Text
|
||||||
|
painter->setFont(fontT);
|
||||||
|
painter->setPen(QPen(colorT));
|
||||||
|
painter->drawText(rectT, Qt::AlignCenter, text);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LABELVOLTAGEDELEGATE_H
|
||||||
458
cellsmonitorpage.cpp
Normal file
458
cellsmonitorpage.cpp
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
#include "cellsmonitorpage.h"
|
||||||
|
#include "ui_cellsmonitorpage.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
#include "cellsmonitorcheckboxdelegate.h"
|
||||||
|
#include "cellsmonitorlabelvoltagedelegate.h"
|
||||||
|
|
||||||
|
CellsMonitorPage::CellsMonitorPage(QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
ui(new Ui::CellsMonitorPage)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
hideTestUi();
|
||||||
|
|
||||||
|
m_tablesNumber = 3;
|
||||||
|
//m_cellsNumber = 26;
|
||||||
|
m_cellsNumber = mCellVoltageArray.size();
|
||||||
|
|
||||||
|
initTableHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
CellsMonitorPage::~CellsMonitorPage()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellsMonitorPage::hideTestUi()
|
||||||
|
{
|
||||||
|
ui->lbCols->hide();
|
||||||
|
ui->lbCells->hide();
|
||||||
|
ui->editCols->hide();
|
||||||
|
ui->editCells->hide();
|
||||||
|
ui->pbTestOne->hide();
|
||||||
|
ui->pbTestTwo->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
BMSInterface *CellsMonitorPage::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellsMonitorPage::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
|
||||||
|
if (mDieBieMS) {
|
||||||
|
//connect(mDieBieMS->commands(), &Commands::valuesReceived,this, &CellsMonitorPage::valuesReceived);
|
||||||
|
connect(mDieBieMS->commands(), &Commands::cellsReceived,this, &CellsMonitorPage::cellsReceived);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CellsMonitorPage::clearTables()
|
||||||
|
{
|
||||||
|
ui->tableViewLeft->reset();
|
||||||
|
ui->tableViewMiddle->reset();
|
||||||
|
ui->tableViewRight->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CellsMonitorPage::initTableHeader()
|
||||||
|
{
|
||||||
|
initTableView(m_tablesNumber, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CellsMonitorPage::initTableView(QTableView* tableView, bool doInitForCellVoltagArray)
|
||||||
|
{
|
||||||
|
//Создаем модель и представление
|
||||||
|
QStandardItemModel *model = new QStandardItemModel(MODEL_ROWS_IN_ONE_TABLE, MODEL_COLUMN_IN_ONE_TABLE);
|
||||||
|
|
||||||
|
int rowWeight = 40;
|
||||||
|
//Заолняем Заголовок
|
||||||
|
QStringList hedarenamesNumVolBalancing = QStringList()
|
||||||
|
<< tr("№")
|
||||||
|
<< tr(" Напряжение ")
|
||||||
|
<< tr(" Балансировка");
|
||||||
|
|
||||||
|
model->setHeaderData(ColNumber, Qt::Horizontal, QObject::tr(hedarenamesNumVolBalancing[ColNumber].toUtf8()));
|
||||||
|
model->setHeaderData(ColVoltage, Qt::Horizontal, QObject::tr(hedarenamesNumVolBalancing[ColVoltage].toUtf8()));
|
||||||
|
model->setHeaderData(ColBalancing, Qt::Horizontal, QObject::tr(hedarenamesNumVolBalancing[ColBalancing].toUtf8()));
|
||||||
|
|
||||||
|
tableView->verticalHeader()->setDefaultSectionSize(rowWeight);
|
||||||
|
|
||||||
|
int tableViewIndexStart = 0;
|
||||||
|
int tableviewIndexEnd = 0;
|
||||||
|
int left = 0;
|
||||||
|
int right = 0;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if(m_tablesNumber == TwoTables)
|
||||||
|
{
|
||||||
|
if(ui->tableViewLeft == tableView)
|
||||||
|
index = FirstSubTable;
|
||||||
|
if(ui->tableViewRight == tableView)
|
||||||
|
index = SecondSubTable;
|
||||||
|
left = (index+0) * MODEL_ROWS_IN_ONE_TABLE;
|
||||||
|
right = (index+1) * MODEL_ROWS_IN_ONE_TABLE;
|
||||||
|
//left = left - ((index+0) * MODEL_ROWS_IN_ONE_TABLE);
|
||||||
|
//right = right - ((index+0) * MODEL_ROWS_IN_ONE_TABLE);
|
||||||
|
|
||||||
|
tableViewIndexStart = (0 * MODEL_ROWS_IN_ONE_TABLE);
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case (FirstSubTable):
|
||||||
|
{
|
||||||
|
tableviewIndexEnd
|
||||||
|
= (m_cellsNumber < MODEL_ROWS_IN_ONE_TABLE)
|
||||||
|
? m_cellsNumber
|
||||||
|
: MODEL_ROWS_IN_ONE_TABLE
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case(SecondSubTable):
|
||||||
|
{
|
||||||
|
tableviewIndexEnd
|
||||||
|
= (m_cellsNumber < MODEL_ROWS_IN_ONE_TABLE)
|
||||||
|
? 0
|
||||||
|
: m_cellsNumber - MODEL_ROWS_IN_ONE_TABLE
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(m_tablesNumber == ThreeTables)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
if(ui->tableViewLeft == tableView)
|
||||||
|
index = FirstSubTable;
|
||||||
|
if(ui->tableViewMiddle == tableView)
|
||||||
|
index = SecondSubTable;
|
||||||
|
if(ui->tableViewRight == tableView)
|
||||||
|
index = ThirdSubTable;
|
||||||
|
left = (index+0) * MODEL_ROWS_IN_ONE_TABLE;
|
||||||
|
right = (index+1) * MODEL_ROWS_IN_ONE_TABLE;
|
||||||
|
|
||||||
|
tableViewIndexStart = (0 * MODEL_ROWS_IN_ONE_TABLE);
|
||||||
|
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case (FirstSubTable):
|
||||||
|
{
|
||||||
|
tableviewIndexEnd
|
||||||
|
= (m_cellsNumber < MODEL_ROWS_IN_ONE_TABLE*1)
|
||||||
|
? m_cellsNumber
|
||||||
|
: MODEL_ROWS_IN_ONE_TABLE
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case (SecondSubTable):
|
||||||
|
{
|
||||||
|
bool isInSecond = (m_cellsNumber>MODEL_ROWS_IN_ONE_TABLE*1) && (m_cellsNumber <= MODEL_ROWS_IN_ONE_TABLE*2);
|
||||||
|
bool isInThird = (m_cellsNumber>MODEL_ROWS_IN_ONE_TABLE*2) && (m_cellsNumber <= MODEL_ROWS_IN_ONE_TABLE*3);
|
||||||
|
|
||||||
|
if(isInSecond)
|
||||||
|
{
|
||||||
|
tableviewIndexEnd = m_cellsNumber - MODEL_ROWS_IN_ONE_TABLE;
|
||||||
|
}
|
||||||
|
if(isInThird)
|
||||||
|
{
|
||||||
|
tableviewIndexEnd = MODEL_ROWS_IN_ONE_TABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case (ThirdSubTable):
|
||||||
|
{
|
||||||
|
bool isInThird = (m_cellsNumber>MODEL_ROWS_IN_ONE_TABLE*2) && (m_cellsNumber <= MODEL_ROWS_IN_ONE_TABLE*3);
|
||||||
|
|
||||||
|
if(isInThird)
|
||||||
|
{
|
||||||
|
tableviewIndexEnd = m_cellsNumber - MODEL_ROWS_IN_ONE_TABLE*2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Заолняем модель данными
|
||||||
|
int cellNumber = 0;
|
||||||
|
for (int row = tableViewIndexStart; row < tableviewIndexEnd; ++row)
|
||||||
|
{
|
||||||
|
cellNumber++;
|
||||||
|
for (int column = 0; column < MODEL_COLUMN_IN_ONE_TABLE; ++column)
|
||||||
|
{
|
||||||
|
//cellNumber++;
|
||||||
|
|
||||||
|
if( cellNumber > m_cellsNumber)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QModelIndex index = model->index(row, column, QModelIndex());
|
||||||
|
switch(column)
|
||||||
|
{
|
||||||
|
case ColNumber:
|
||||||
|
{
|
||||||
|
model->setData(index, QVariant(left + row + 1));
|
||||||
|
model->setData(index, Qt::AlignCenter, Qt::TextAlignmentRole);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ColVoltage:
|
||||||
|
{
|
||||||
|
if(doInitForCellVoltagArray)
|
||||||
|
model->setData(index, mCellVoltageArray[left + row].voltage);
|
||||||
|
else // just test data
|
||||||
|
model->setData(index, QVariant( (left + row + 1) ));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ColBalancing:
|
||||||
|
{
|
||||||
|
if(doInitForCellVoltagArray)
|
||||||
|
model->setData(index, mCellVoltageArray[left + row].balancing);
|
||||||
|
else
|
||||||
|
model->setData(index, QVariant(row%2));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Устанавливаем модель в представление
|
||||||
|
tableView->setModel(model);
|
||||||
|
|
||||||
|
//Устанавливаем делегат в столбец
|
||||||
|
CheckBoxDelegate *delegateCbox = new CheckBoxDelegate();
|
||||||
|
LabelVoltageDelegate *delegateLab = new LabelVoltageDelegate();
|
||||||
|
|
||||||
|
tableView->setItemDelegateForColumn(ColVoltage, delegateLab);
|
||||||
|
tableView->setItemDelegateForColumn(ColBalancing, delegateCbox);
|
||||||
|
//Внешний вид предтавления
|
||||||
|
tableView->verticalHeader()->hide();
|
||||||
|
tableView->horizontalHeader()->setStretchLastSection(false);
|
||||||
|
tableView->setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
|
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
tableView->setShowGrid(false);
|
||||||
|
|
||||||
|
// has to be last
|
||||||
|
tableView->setColumnWidth(ColNumber, 50);
|
||||||
|
tableView->setColumnWidth(ColVoltage, 100);
|
||||||
|
tableView->setColumnWidth(ColBalancing, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CellsMonitorPage::initTableView(int tablesNum, bool doInitForCellVoltagArray)
|
||||||
|
{
|
||||||
|
m_tablesNumber = tablesNum;
|
||||||
|
//m_cellsNumber = cellsNum;
|
||||||
|
m_cellsNumber = mCellVoltageArray.size();
|
||||||
|
|
||||||
|
if(m_cellsNumber > MAX_ROWS_ALL_TABLES)
|
||||||
|
m_cellsNumber = MAX_ROWS_ALL_TABLES;
|
||||||
|
clearTables();
|
||||||
|
auto gBackGr = ui->lbCellsMonitorTableBorderBackground->geometry();
|
||||||
|
auto gL = ui->tableViewLeft->geometry();
|
||||||
|
auto gR = ui->tableViewRight->geometry();
|
||||||
|
|
||||||
|
|
||||||
|
if(tablesNum == TwoTables) { // 13
|
||||||
|
MODEL_ROWS_IN_ONE_TABLE = 13;
|
||||||
|
auto one_half = (double)gBackGr.width()/2.0;
|
||||||
|
|
||||||
|
initTableView(ui->tableViewLeft, doInitForCellVoltagArray); // w=501 // x=340
|
||||||
|
ui->tableViewLeft->setGeometry(gL.x(),
|
||||||
|
gL.y(),
|
||||||
|
one_half + 20,
|
||||||
|
gL.height()
|
||||||
|
);
|
||||||
|
ui->tableViewMiddle->hide();
|
||||||
|
ui->tableViewRight->setGeometry(gL.x() + gBackGr.width()/2,
|
||||||
|
gL.y(),
|
||||||
|
one_half - 3,
|
||||||
|
gL.height()
|
||||||
|
);
|
||||||
|
|
||||||
|
initTableView(ui->tableViewRight, doInitForCellVoltagArray); // w=491 // x=830
|
||||||
|
}
|
||||||
|
else if(tablesNum == ThreeTables) { // 11
|
||||||
|
//340
|
||||||
|
//650
|
||||||
|
//980
|
||||||
|
|
||||||
|
//331
|
||||||
|
//341
|
||||||
|
//341
|
||||||
|
|
||||||
|
MODEL_ROWS_IN_ONE_TABLE = 11;
|
||||||
|
auto one_third = (double)gBackGr.width()/3.0;
|
||||||
|
|
||||||
|
ui->tableViewLeft->setGeometry(gL.x(),
|
||||||
|
gL.y(),
|
||||||
|
(one_third * 1) + 10,
|
||||||
|
gL.height()
|
||||||
|
);
|
||||||
|
|
||||||
|
ui->tableViewMiddle->setGeometry(gL.x() + (one_third * 1), //( (2.0 * (double)gBackGr.width()) / 3.0),
|
||||||
|
gL.y(),
|
||||||
|
(one_third * 1) + 10,
|
||||||
|
gL.height()
|
||||||
|
);
|
||||||
|
ui->tableViewMiddle->show();
|
||||||
|
|
||||||
|
ui->tableViewRight->setGeometry(gL.x() + (one_third * 2),
|
||||||
|
gL.y(),
|
||||||
|
(one_third * 1) - 3,
|
||||||
|
gL.height()
|
||||||
|
);
|
||||||
|
|
||||||
|
initTableView(ui->tableViewLeft, doInitForCellVoltagArray);
|
||||||
|
initTableView(ui->tableViewMiddle, doInitForCellVoltagArray);
|
||||||
|
initTableView(ui->tableViewRight, doInitForCellVoltagArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CellsMonitorPage::cellsReceived(int cellCount, QVector<double> cellVoltageArray)
|
||||||
|
{
|
||||||
|
mCellVoltageArray.clear();
|
||||||
|
mCellVoltageArray.resize(cellCount);
|
||||||
|
|
||||||
|
QVector<double> dataxNew;
|
||||||
|
dataxNew.clear();
|
||||||
|
QVector<double> datayNormal;
|
||||||
|
datayNormal.clear();
|
||||||
|
QVector<double> datayBalance;
|
||||||
|
datayBalance.clear();
|
||||||
|
QVector<QString> labels;
|
||||||
|
int indexPointer = 0;
|
||||||
|
|
||||||
|
double cellHardUnder = mDieBieMS->bmsConfig()->getParamDouble("cellHardUnderVoltage");
|
||||||
|
double cellHardOver = mDieBieMS->bmsConfig()->getParamDouble("cellHardOverVoltage");
|
||||||
|
|
||||||
|
for(indexPointer = 0; indexPointer < cellCount; indexPointer++)
|
||||||
|
{
|
||||||
|
mCellVoltageArray[indexPointer].voltage = cellVoltageArray[indexPointer];
|
||||||
|
|
||||||
|
dataxNew.append(indexPointer + 1);
|
||||||
|
|
||||||
|
if(cellVoltageArray[indexPointer] < 0.0){
|
||||||
|
datayNormal.append(0.0);
|
||||||
|
datayBalance.append(fabs(cellVoltageArray[indexPointer]));
|
||||||
|
}else{
|
||||||
|
datayNormal.append(fabs(cellVoltageArray[indexPointer]));
|
||||||
|
datayBalance.append(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString voltageString = QStringLiteral("%1V (C").arg(fabs(cellVoltageArray[indexPointer]), 0, 'f', 2);
|
||||||
|
labels.append(voltageString + QString::number(indexPointer) + ")");
|
||||||
|
|
||||||
|
bool BALANCE_ON_IS_SAME_AS_EQUAL_ZERO = (datayBalance.last() == 0.0);
|
||||||
|
BALANCE_ON_IS_SAME_AS_EQUAL_ZERO = !BALANCE_ON_IS_SAME_AS_EQUAL_ZERO;
|
||||||
|
mCellVoltageArray[indexPointer].balancing = BALANCE_ON_IS_SAME_AS_EQUAL_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
initTableView(m_tablesNumber, true);
|
||||||
|
|
||||||
|
|
||||||
|
//QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
|
||||||
|
//textTicker->addTicks(dataxNew, labels);
|
||||||
|
|
||||||
|
//ui->cellBarGraph->xAxis->setTicker(textTicker);
|
||||||
|
//ui->cellBarGraph->xAxis->setRange(0.5, indexPointer + 0.5);
|
||||||
|
//ui->cellBarGraph->yAxis->setRange(cellHardUnder, cellHardOver);
|
||||||
|
//barsNormal->setData(dataxNew, datayNormal);
|
||||||
|
//barsBalance->setData(dataxNew, datayBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellsMonitorPage::appendDoubleAndTrunc(QVector<double> *vec, double num, int maxSize)
|
||||||
|
{
|
||||||
|
vec->append(num);
|
||||||
|
|
||||||
|
if(vec->size() > maxSize) {
|
||||||
|
vec->remove(0, vec->size() - maxSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CellsMonitorPage::on_editCols_textChanged(const QString &arg1)
|
||||||
|
{
|
||||||
|
m_tablesNumber = (arg1).toInt();
|
||||||
|
int cells = (ui->editCells->text()).toInt();
|
||||||
|
|
||||||
|
mCellVoltageArray.clear();
|
||||||
|
|
||||||
|
for(int i = 0, ilen = cells; i<ilen ;++i)
|
||||||
|
{
|
||||||
|
CellInfo c;
|
||||||
|
c.voltage = (double)(i*3);
|
||||||
|
c.balancing = (bool)(i%3);
|
||||||
|
|
||||||
|
mCellVoltageArray.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
initTableView(m_tablesNumber, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellsMonitorPage::on_editCells_textChanged(const QString &arg1)
|
||||||
|
{
|
||||||
|
m_tablesNumber = (ui->editCols->text()).toInt();
|
||||||
|
int cells = (arg1).toInt();
|
||||||
|
|
||||||
|
mCellVoltageArray.clear();
|
||||||
|
|
||||||
|
for(int i = 0, ilen = cells; i<ilen ;++i)
|
||||||
|
{
|
||||||
|
CellInfo c;
|
||||||
|
c.voltage = (double)(i*3);
|
||||||
|
c.balancing = (bool)(i%3);
|
||||||
|
|
||||||
|
mCellVoltageArray.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
initTableView(m_tablesNumber, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellsMonitorPage::on_pbTestOne_clicked()
|
||||||
|
{
|
||||||
|
mCellVoltageArray.clear();
|
||||||
|
for(int i = 0, ilen = 21; i<ilen ;++i)
|
||||||
|
{
|
||||||
|
CellInfo c;
|
||||||
|
c.voltage = (double)(i*3);
|
||||||
|
c.balancing = (bool)(i%3);
|
||||||
|
|
||||||
|
mCellVoltageArray.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
initTableView(m_tablesNumber, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellsMonitorPage::on_pbTestTwo_clicked()
|
||||||
|
{
|
||||||
|
mCellVoltageArray.clear();
|
||||||
|
for(int i = 0, ilen = 21; i<ilen ;++i)
|
||||||
|
{
|
||||||
|
CellInfo c;
|
||||||
|
c.voltage = (double)(i*4);
|
||||||
|
c.balancing = (bool)(i%4);
|
||||||
|
|
||||||
|
mCellVoltageArray.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
initTableView(m_tablesNumber, true);
|
||||||
|
}
|
||||||
113
cellsmonitorpage.h
Normal file
113
cellsmonitorpage.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#ifndef CELLSMONITORPAGE_H
|
||||||
|
#define CELLSMONITORPAGE_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class CellsMonitorPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CellInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CellInfo() : voltage(0), balancing(false)
|
||||||
|
{}
|
||||||
|
CellInfo(double v, bool b)
|
||||||
|
:voltage(v), balancing(b)
|
||||||
|
{}
|
||||||
|
|
||||||
|
double voltage;
|
||||||
|
bool balancing;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CellsMonitorPage : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CellsMonitorPage(QWidget *parent = nullptr);
|
||||||
|
~CellsMonitorPage();
|
||||||
|
|
||||||
|
enum TablesNumber
|
||||||
|
{
|
||||||
|
TwoTables = 2,
|
||||||
|
ThreeTables = 3
|
||||||
|
};
|
||||||
|
enum TableIndex
|
||||||
|
{
|
||||||
|
FirstSubTable = 0,
|
||||||
|
SecondSubTable = 1,
|
||||||
|
ThirdSubTable = 2
|
||||||
|
};
|
||||||
|
enum ColumnsInSubTables
|
||||||
|
{
|
||||||
|
ColNumber = 0,
|
||||||
|
ColVoltage, //Столбец с делегатом
|
||||||
|
ColBalancing //Столбец с делегатом
|
||||||
|
};
|
||||||
|
|
||||||
|
int MODEL_ROWS_IN_ONE_TABLE = 13; //Количество строк модели одной из таблиц
|
||||||
|
static constexpr int MODEL_COLUMN_IN_ONE_TABLE = 3; //Количество столбцов модели одной из таблиц (№,Напр,Баланс)
|
||||||
|
static constexpr int MAX_ROWS_ALL_TABLES = 26; //Количество строк для всех трёх таблиц
|
||||||
|
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_editCols_textChanged(const QString &arg1);
|
||||||
|
void on_editCells_textChanged(const QString &arg1);
|
||||||
|
void on_pbTestOne_clicked();
|
||||||
|
void on_pbTestTwo_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::CellsMonitorPage *ui;
|
||||||
|
void hideTestUi();
|
||||||
|
|
||||||
|
BMSInterface *mDieBieMS;
|
||||||
|
|
||||||
|
int m_tablesNumber;
|
||||||
|
int m_cellsNumber;
|
||||||
|
|
||||||
|
QVector<CellInfo> mCellVoltageArray;
|
||||||
|
|
||||||
|
void createUI();
|
||||||
|
|
||||||
|
void clearTables();
|
||||||
|
|
||||||
|
void initTableHeader();
|
||||||
|
// this one is for the real usage
|
||||||
|
void initTableView(QTableView* tableView, bool doInitForCellVoltagArray = true);
|
||||||
|
void initTableView(int tablesNum = TwoTables, bool doInitForCellVoltagArray = true);
|
||||||
|
// this one is just for test
|
||||||
|
//void initTableView(int cellsNum = 0, int tablesNum = TwoTables, bool doInitForCellVoltagArray = true);
|
||||||
|
|
||||||
|
//
|
||||||
|
public slots:
|
||||||
|
///void onLoadParams();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
//void timerSlot();
|
||||||
|
//void valuesReceived(BMS_VALUES values);
|
||||||
|
void cellsReceived(int cellCount, QVector<double> cellVoltageArray);
|
||||||
|
/*
|
||||||
|
QVector<double> mSeconds;
|
||||||
|
|
||||||
|
double mSecondCounter;
|
||||||
|
qint64 mLastUpdateTime;
|
||||||
|
bool mUpdateValPlot;
|
||||||
|
|
||||||
|
QTimer* mTimer;
|
||||||
|
*/
|
||||||
|
///void initForCharts();
|
||||||
|
|
||||||
|
void appendDoubleAndTrunc(QVector<double> *vec, double num, int maxSize);
|
||||||
|
///void clearControlls();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CELLSMONITORPAGE_H
|
||||||
353
cellsmonitorpage.ui
Normal file
353
cellsmonitorpage.ui
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CellsMonitorPage</class>
|
||||||
|
<widget class="QFrame" name="CellsMonitorPage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1071</width>
|
||||||
|
<height>755</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">/*QFrame#CellsMonitorPage
|
||||||
|
{
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
QLabel#lbIconLogo
|
||||||
|
{
|
||||||
|
border-image: url(:/images/cubo-verde-logo-white.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#lbHeaderLanguageIcon
|
||||||
|
{
|
||||||
|
border-image: url(:/images/language-russ.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pushButton,
|
||||||
|
#pushButton_2,
|
||||||
|
#pushButton_3,
|
||||||
|
#pushButton_4,
|
||||||
|
#pushButton_5,
|
||||||
|
#pushButton_6,
|
||||||
|
#pushButton_7,
|
||||||
|
#pushButton_8
|
||||||
|
{
|
||||||
|
color: #FFFFFF;
|
||||||
|
background-color: #009352;
|
||||||
|
border: 0px solid black;
|
||||||
|
background:#009352;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 85px;
|
||||||
|
font-size:17px;
|
||||||
|
}
|
||||||
|
QPushButton#pushButton
|
||||||
|
{
|
||||||
|
font-size:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 186, 162, 255), stop:1 rgba(98, 211, 162, 255))
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pushButton:hover,
|
||||||
|
#pushButton_2:hover,
|
||||||
|
#pushButton_3:hover,
|
||||||
|
#pushButton_4:hover,
|
||||||
|
#pushButton_5:hover,
|
||||||
|
#pushButton_6:hover,
|
||||||
|
#pushButton_7:hover,
|
||||||
|
#pushButton_8:hover
|
||||||
|
{
|
||||||
|
background-color: #01673a;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*------------------*/
|
||||||
|
/*
|
||||||
|
QGroupBox#gbSerialNumber,
|
||||||
|
#gbConfiguration,
|
||||||
|
#gbSoc
|
||||||
|
{
|
||||||
|
border-radius:10px;
|
||||||
|
border-color: grey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*--------------------------------------*/
|
||||||
|
/*--------------TABLE----------------*/
|
||||||
|
/*--------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
QTableView {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
alternate-background-color: #282828;
|
||||||
|
border-radius: 10px;
|
||||||
|
/*color: #000000;*/
|
||||||
|
color: #869098;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTableView QHeaderView {
|
||||||
|
background-color: #f0f1f4;
|
||||||
|
border: none;
|
||||||
|
/*border-bottom: 2px solid #f0f1f4;*/
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
min-height: 70px;
|
||||||
|
/*padding-top: 20px;*/
|
||||||
|
padding-top: 5px;
|
||||||
|
/*padding-right: 15px;*/
|
||||||
|
/*margin-right: 20px;*/
|
||||||
|
/*text-align: center;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QTableView QHeaderView::section {
|
||||||
|
/*
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: #8F8F8F;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
*/
|
||||||
|
background-color: #f0f1f4;
|
||||||
|
/*border: 1px solid #e8e9f1;*/
|
||||||
|
border: none;
|
||||||
|
color: #869098;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
/*padding: 0px 0px 0px 35px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QTableView::item {
|
||||||
|
border: none;
|
||||||
|
/*padding: 0px 35px;*/
|
||||||
|
text-align: center;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar {
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #e8e9f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::vertical {
|
||||||
|
width: 10px;
|
||||||
|
margin: 75px 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------*/
|
||||||
|
QScrollBar::sub-page:horizontal {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-left-radius: 9px;
|
||||||
|
border-bottom-left-radius: 9px;
|
||||||
|
}
|
||||||
|
QScrollBar::add-page:horizontal {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-right-radius: 9px;
|
||||||
|
border-bottom-right-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::sub-page:vertical {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-left-radius: 9px;
|
||||||
|
border-top-right-radius: 9px;
|
||||||
|
}
|
||||||
|
QScrollBar::add-page:vertical {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-bottom-left-radius: 9px;
|
||||||
|
border-bottom-right-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------*/
|
||||||
|
QScrollBar::up-arrow,
|
||||||
|
QScrollBar::sub-line,
|
||||||
|
QScrollBar::add-line {
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::handle {
|
||||||
|
background: #009352;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QTableView" name="tableViewRight">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>670</x>
|
||||||
|
<y>90</y>
|
||||||
|
<width>341</width>
|
||||||
|
<height>621</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTableView" name="tableViewLeft">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>30</x>
|
||||||
|
<y>90</y>
|
||||||
|
<width>331</width>
|
||||||
|
<height>621</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbCellsMonitorTableBorderBackground">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>28</x>
|
||||||
|
<y>88</y>
|
||||||
|
<width>985</width>
|
||||||
|
<height>625</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">/* background-color: #f0fFfF;*/
|
||||||
|
background-color: #e8e9f1;
|
||||||
|
/*grey*/
|
||||||
|
/*#e8e9f1*/
|
||||||
|
/*green*/
|
||||||
|
/*#009352*/
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
/* padding-top: 20px;*/
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTableView" name="tableViewMiddle">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>350</x>
|
||||||
|
<y>90</y>
|
||||||
|
<width>341</width>
|
||||||
|
<height>621</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbCenterTabName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>30</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>351</width>
|
||||||
|
<height>41</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>26</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Монитор ячеек</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLineEdit" name="editCols">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>490</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>61</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLineEdit" name="editCells">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>630</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>61</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbCols">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>410</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>71</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>столбцов</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbCells">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>570</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>51</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ячеек</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbTestOne">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>440</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>75</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Тест 1</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbTestTwo">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>560</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>75</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Тест 2</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<zorder>lbCellsMonitorTableBorderBackground</zorder>
|
||||||
|
<zorder>tableViewMiddle</zorder>
|
||||||
|
<zorder>tableViewLeft</zorder>
|
||||||
|
<zorder>tableViewRight</zorder>
|
||||||
|
<zorder>lbCenterTabName</zorder>
|
||||||
|
<zorder>editCols</zorder>
|
||||||
|
<zorder>editCells</zorder>
|
||||||
|
<zorder>lbCols</zorder>
|
||||||
|
<zorder>lbCells</zorder>
|
||||||
|
<zorder>pbTestOne</zorder>
|
||||||
|
<zorder>pbTestTwo</zorder>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
744
commands.cpp
Normal file
744
commands.cpp
Normal file
@@ -0,0 +1,744 @@
|
|||||||
|
/*
|
||||||
|
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 "commands.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
Commands::Commands(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
mSendCan = QSettings().value("send_can", false).toBool();
|
||||||
|
mCanId = QSettings().value("can_id", 0).toInt();
|
||||||
|
mIsLimitedMode = false;
|
||||||
|
|
||||||
|
// Firmware state
|
||||||
|
mFirmwareIsUploading = false;
|
||||||
|
mFirmwareState = 0;
|
||||||
|
mFimwarePtr = 0;
|
||||||
|
mFirmwareTimer = 0;
|
||||||
|
mFirmwareRetries = 0;
|
||||||
|
mFirmwareUploadStatus = "FW Upload Status";
|
||||||
|
mCheckNextbmsConfig = false;
|
||||||
|
|
||||||
|
mTimer = new QTimer(this);
|
||||||
|
mTimer->setInterval(10);
|
||||||
|
mTimer->start();
|
||||||
|
|
||||||
|
mbmsConfig = 0;
|
||||||
|
|
||||||
|
mTimeoutCount = 50;
|
||||||
|
mTimeoutFwVer = 0;
|
||||||
|
mTimeoutBMSconf = 0;
|
||||||
|
mTimeoutValues = 0;
|
||||||
|
mTimeoutCells = 0;
|
||||||
|
mTimeoutAux = 0;
|
||||||
|
mTimeoutExp = 0;
|
||||||
|
mTimeoutPingCan = 0;
|
||||||
|
|
||||||
|
connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::setLimitedMode(bool is_limited)
|
||||||
|
{
|
||||||
|
mIsLimitedMode = is_limited;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Commands::isLimitedMode()
|
||||||
|
{
|
||||||
|
return mIsLimitedMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::setSendCan(bool sendCan, int id)
|
||||||
|
{
|
||||||
|
mSendCan = sendCan;
|
||||||
|
QSettings().setValue("send_can", sendCan);
|
||||||
|
|
||||||
|
if (id >= 0) {
|
||||||
|
setCanSendId(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Commands::getSendCan()
|
||||||
|
{
|
||||||
|
return mSendCan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::setCanSendId(unsigned int id)
|
||||||
|
{
|
||||||
|
mCanId = id;
|
||||||
|
QSettings().setValue("can_id", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Commands::getCanSendId()
|
||||||
|
{
|
||||||
|
return mCanId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::processPacket(QByteArray data)
|
||||||
|
{
|
||||||
|
VByteArray vb(data);
|
||||||
|
COMM_PACKET_ID id = (COMM_PACKET_ID)vb.vbPopFrontUint8();
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case COMM_FW_VERSION: {
|
||||||
|
mTimeoutFwVer = 0;
|
||||||
|
int fw_major;
|
||||||
|
int fw_minor;
|
||||||
|
QString hw;
|
||||||
|
QByteArray uuid;
|
||||||
|
|
||||||
|
if (vb.size() >= 2) {
|
||||||
|
fw_major = vb.vbPopFrontInt8();
|
||||||
|
fw_minor = vb.vbPopFrontInt8();
|
||||||
|
hw = vb.vbPopFrontString();
|
||||||
|
if (vb.size() >= 12) {
|
||||||
|
uuid.append(vb.left(12));
|
||||||
|
vb.remove(0, 12);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fw_major = -1;
|
||||||
|
fw_minor = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit fwVersionReceived(fw_major, fw_minor, hw, uuid);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case COMM_ERASE_NEW_APP:
|
||||||
|
case COMM_WRITE_NEW_APP_DATA:
|
||||||
|
firmwareUploadUpdate(!vb.at(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMM_GET_VALUES: {
|
||||||
|
mTimeoutValues = 0;
|
||||||
|
BMS_VALUES values;
|
||||||
|
|
||||||
|
values.packVoltage = vb.vbPopFrontDouble32(1e3);
|
||||||
|
values.packCurrent = vb.vbPopFrontDouble32(1e3);
|
||||||
|
|
||||||
|
values.soC = vb.vbPopFrontUint8();
|
||||||
|
|
||||||
|
values.cVHigh = vb.vbPopFrontDouble32(1e3);
|
||||||
|
values.cVAverage = vb.vbPopFrontDouble32(1e3);
|
||||||
|
values.cVLow = vb.vbPopFrontDouble32(1e3);
|
||||||
|
values.cVMisMatch = vb.vbPopFrontDouble32(1e3);
|
||||||
|
|
||||||
|
values.loadLCVoltage = vb.vbPopFrontDouble16(1e1);
|
||||||
|
values.loadLCCurrent = vb.vbPopFrontDouble16(1e1);
|
||||||
|
|
||||||
|
values.chargerVoltage = vb.vbPopFrontDouble16(1e1);
|
||||||
|
|
||||||
|
values.tempBattHigh = vb.vbPopFrontDouble16(1e1);
|
||||||
|
values.tempBattAverage = vb.vbPopFrontDouble16(1e1);
|
||||||
|
values.tempBattLow = vb.vbPopFrontDouble16(1e1);
|
||||||
|
values.tempBMSHigh = vb.vbPopFrontDouble16(1e1);
|
||||||
|
values.tempBMSAverage = vb.vbPopFrontDouble16(1e1);
|
||||||
|
values.tempBMSLow = vb.vbPopFrontDouble16(1e1);
|
||||||
|
values.humidity = vb.vbPopFrontDouble16(1e1);
|
||||||
|
|
||||||
|
values.opState = opStateToStr((OperationalStateTypedef)vb.vbPopFrontUint8());
|
||||||
|
values.balanceActive = vb.vbPopFrontUint8();
|
||||||
|
values.faultState = faultStateToStr((bms_fault_code)vb.vbPopFrontUint8());
|
||||||
|
emit valuesReceived(values);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case COMM_GET_BMS_CELLS:{
|
||||||
|
mTimeoutCells = 0;
|
||||||
|
int mCellAmount;
|
||||||
|
QVector<double> mCellVoltages;
|
||||||
|
mCellVoltages.clear();
|
||||||
|
|
||||||
|
mCellAmount = vb.vbPopFrontUint8();
|
||||||
|
|
||||||
|
for(int cellValuePointer = 0; cellValuePointer < mCellAmount; cellValuePointer++){
|
||||||
|
mCellVoltages.append(vb.vbPopFrontDouble16(1e3));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit cellsReceived(mCellAmount,mCellVoltages);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case COMM_GET_BMS_AUX:{
|
||||||
|
mTimeoutAux = 0;
|
||||||
|
int mAuxAmount;
|
||||||
|
QVector<double> mAuxVoltages;
|
||||||
|
mAuxVoltages.clear();
|
||||||
|
|
||||||
|
mAuxAmount = vb.vbPopFrontUint8();
|
||||||
|
|
||||||
|
for(int auxValuePointer = 0; auxValuePointer < mAuxAmount; auxValuePointer++){
|
||||||
|
mAuxVoltages.append(vb.vbPopFrontDouble16(1e1));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit auxReceived(mAuxAmount,mAuxVoltages);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case COMM_GET_BMS_EXP_TEMP:{
|
||||||
|
mTimeoutExp = 0;
|
||||||
|
int mExpTempAmount;
|
||||||
|
QVector<double> mExpTempVoltages;
|
||||||
|
mExpTempVoltages.clear();
|
||||||
|
|
||||||
|
mExpTempAmount = vb.vbPopFrontUint8();
|
||||||
|
|
||||||
|
for(int expTempValuePointer = 0; expTempValuePointer < mExpTempAmount; expTempValuePointer++){
|
||||||
|
mExpTempVoltages.append(vb.vbPopFrontDouble16(1e1));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit expTempReceived(mExpTempAmount,mExpTempVoltages);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case COMM_PRINT:
|
||||||
|
emit printReceived(QString::fromLatin1(vb));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMM_ROTOR_POSITION:
|
||||||
|
emit rotorPosReceived(vb.vbPopFrontDouble32(1e5));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMM_GET_MCCONF:
|
||||||
|
case COMM_GET_MCCONF_DEFAULT:
|
||||||
|
mTimeoutBMSconf = 0;
|
||||||
|
if (mbmsConfig) {
|
||||||
|
mbmsConfig->deSerialize(vb);
|
||||||
|
mbmsConfig->updateDone();
|
||||||
|
|
||||||
|
if (mCheckNextbmsConfig) {
|
||||||
|
mCheckNextbmsConfig = false;
|
||||||
|
emit bmsConfigCheckResult(mbmsConfig->checkDifference(&mbmsConfigLast));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMM_SET_MCCONF:
|
||||||
|
emit ackReceived("BMS Write OK");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMM_STORE_BMS_CONF:
|
||||||
|
if (mbmsConfig) {
|
||||||
|
mbmsConfig->storingDone();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMM_PING_CAN: {
|
||||||
|
mTimeoutPingCan = 0;
|
||||||
|
QVector<int> devs;
|
||||||
|
while(vb.size() > 0) {
|
||||||
|
devs.append(vb.vbPopFrontUint8());
|
||||||
|
}
|
||||||
|
emit pingCanRx(devs, false);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::getFwVersion()
|
||||||
|
{
|
||||||
|
if (mTimeoutFwVer > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutFwVer = mTimeoutCount;
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_FW_VERSION);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::getValues()
|
||||||
|
{
|
||||||
|
if (mTimeoutValues > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutValues = mTimeoutCount;
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_GET_VALUES);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::getCells()
|
||||||
|
{
|
||||||
|
if (mTimeoutCells > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutCells = mTimeoutCount;
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_GET_BMS_CELLS);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::getAux()
|
||||||
|
{
|
||||||
|
if (mTimeoutAux > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutAux = mTimeoutCount;
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_GET_BMS_AUX);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::getExpansionTemp()
|
||||||
|
{
|
||||||
|
if (mTimeoutExp > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutExp = mTimeoutCount;
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_GET_BMS_EXP_TEMP);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
void Commands::sendTerminalCmd(QString cmd)
|
||||||
|
{
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_TERMINAL_CMD);
|
||||||
|
vb.append(cmd.toLatin1());
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::setDetect(disp_pos_mode mode)
|
||||||
|
{
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_SET_DETECT);
|
||||||
|
vb.vbAppendInt8(mode);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::samplePrint(debug_sampling_mode mode, int sample_len, int dec)
|
||||||
|
{
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_SAMPLE_PRINT);
|
||||||
|
vb.vbAppendInt8(mode);
|
||||||
|
vb.vbAppendUint16(sample_len);
|
||||||
|
vb.vbAppendUint8(dec);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::getBMSconf()
|
||||||
|
{
|
||||||
|
if (mTimeoutBMSconf > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutBMSconf = mTimeoutCount;
|
||||||
|
|
||||||
|
|
||||||
|
mCheckNextbmsConfig = false;
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_GET_MCCONF);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::getBMSconfDefault()
|
||||||
|
{
|
||||||
|
if (mTimeoutBMSconf > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutBMSconf = mTimeoutCount;
|
||||||
|
|
||||||
|
mCheckNextbmsConfig = false;
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_GET_MCCONF_DEFAULT);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::setBMSconf(bool check)
|
||||||
|
{
|
||||||
|
if (mbmsConfig) {
|
||||||
|
mbmsConfigLast = *mbmsConfig;
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_SET_MCCONF);
|
||||||
|
mbmsConfig->serialize(vb);
|
||||||
|
emitData(vb);
|
||||||
|
|
||||||
|
if (check) {
|
||||||
|
checkbmsConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::reboot()
|
||||||
|
{
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_REBOOT);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::sendAlive()
|
||||||
|
{
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_ALIVE);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::pairNrf(int ms)
|
||||||
|
{
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_NRF_START_PAIRING);
|
||||||
|
vb.vbAppendInt32(ms);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::timerSlot()
|
||||||
|
{
|
||||||
|
if (mFirmwareIsUploading) {
|
||||||
|
if (mFirmwareTimer) {
|
||||||
|
mFirmwareTimer--;
|
||||||
|
} else {
|
||||||
|
firmwareUploadUpdate(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTimeoutFwVer > 0) mTimeoutFwVer--;
|
||||||
|
if (mTimeoutBMSconf > 0) mTimeoutBMSconf--;
|
||||||
|
if (mTimeoutValues > 0) mTimeoutValues--;
|
||||||
|
if (mTimeoutCells > 0) mTimeoutCells--;
|
||||||
|
if (mTimeoutAux > 0) mTimeoutAux--;
|
||||||
|
if (mTimeoutExp > 0) mTimeoutExp--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::emitData(QByteArray data)
|
||||||
|
{
|
||||||
|
// Only allow firmware commands in limited mode
|
||||||
|
if (mIsLimitedMode && data.at(0) > COMM_WRITE_NEW_APP_DATA) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSendCan) {
|
||||||
|
data.prepend((char)mCanId);
|
||||||
|
data.prepend((char)COMM_FORWARD_CAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit dataToSend(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::firmwareUploadUpdate(bool isTimeout)
|
||||||
|
{
|
||||||
|
if (!mFirmwareIsUploading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int app_packet_size = 200;
|
||||||
|
const int retries = 5;
|
||||||
|
const int timeout = 350;
|
||||||
|
|
||||||
|
if (mFirmwareState == 0) {
|
||||||
|
mFirmwareUploadStatus = "Buffer Erase";
|
||||||
|
if (isTimeout) {
|
||||||
|
// Erase timed out, abort.
|
||||||
|
mFirmwareIsUploading = false;
|
||||||
|
mFimwarePtr = 0;
|
||||||
|
mFirmwareUploadStatus = "Buffer Erase Timeout";
|
||||||
|
} else {
|
||||||
|
mFirmwareState++;
|
||||||
|
mFirmwareRetries = retries;
|
||||||
|
mFirmwareTimer = timeout;
|
||||||
|
firmwareUploadUpdate(true);
|
||||||
|
}
|
||||||
|
} else if (mFirmwareState == 1) {
|
||||||
|
mFirmwareUploadStatus = "CRC/Size Write";
|
||||||
|
if (isTimeout) {
|
||||||
|
if (mFirmwareRetries > 0) {
|
||||||
|
mFirmwareRetries--;
|
||||||
|
mFirmwareTimer = timeout;
|
||||||
|
} else {
|
||||||
|
mFirmwareIsUploading = false;
|
||||||
|
mFimwarePtr = 0;
|
||||||
|
mFirmwareState = 0;
|
||||||
|
mFirmwareUploadStatus = "CRC/Size Write Timeout";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 crc = Packet::crc16((const unsigned char*)mNewFirmware.constData(), mNewFirmware.size());
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.append((char)COMM_WRITE_NEW_APP_DATA);
|
||||||
|
vb.vbAppendUint32(0);
|
||||||
|
vb.vbAppendUint32(mNewFirmware.size());
|
||||||
|
vb.vbAppendUint16(crc);
|
||||||
|
emitData(vb);
|
||||||
|
} else {
|
||||||
|
mFirmwareState++;
|
||||||
|
mFirmwareRetries = retries;
|
||||||
|
mFirmwareTimer = timeout;
|
||||||
|
firmwareUploadUpdate(true);
|
||||||
|
}
|
||||||
|
} else if (mFirmwareState == 2) {
|
||||||
|
mFirmwareUploadStatus = "FW Data Write";
|
||||||
|
if (isTimeout) {
|
||||||
|
if (mFirmwareRetries > 0) {
|
||||||
|
mFirmwareRetries--;
|
||||||
|
mFirmwareTimer = timeout;
|
||||||
|
} else {
|
||||||
|
mFirmwareIsUploading = false;
|
||||||
|
mFimwarePtr = 0;
|
||||||
|
mFirmwareState = 0;
|
||||||
|
mFirmwareUploadStatus = "FW Data Write Timeout";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fw_size_left = mNewFirmware.size() - mFimwarePtr;
|
||||||
|
int send_size = fw_size_left > app_packet_size ? app_packet_size : fw_size_left;
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.append((char)COMM_WRITE_NEW_APP_DATA);
|
||||||
|
|
||||||
|
if (mFirmwareIsBootloader) {
|
||||||
|
vb.vbAppendUint32(mFimwarePtr + (1024 * 2 * 50));
|
||||||
|
} else {
|
||||||
|
vb.vbAppendUint32(mFimwarePtr + 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
vb.append(mNewFirmware.mid(mFimwarePtr, send_size));
|
||||||
|
emitData(vb);
|
||||||
|
} else {
|
||||||
|
mFirmwareRetries = retries;
|
||||||
|
mFirmwareTimer = timeout;
|
||||||
|
mFimwarePtr += app_packet_size;
|
||||||
|
|
||||||
|
if (mFimwarePtr >= mNewFirmware.size()) {
|
||||||
|
mFirmwareIsUploading = false;
|
||||||
|
mFimwarePtr = 0;
|
||||||
|
mFirmwareState = 0;
|
||||||
|
mFirmwareUploadStatus = "FW Upload Done";
|
||||||
|
|
||||||
|
// Upload done. Enter bootloader!
|
||||||
|
if (!mFirmwareIsBootloader) {
|
||||||
|
QByteArray buffer;
|
||||||
|
buffer.append((char)COMM_JUMP_TO_BOOTLOADER);
|
||||||
|
emitData(buffer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
firmwareUploadUpdate(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Commands::opStateToStr(OperationalStateTypedef fault)
|
||||||
|
{
|
||||||
|
switch (fault) {
|
||||||
|
case OP_STATE_INIT: return "Init";
|
||||||
|
case OP_STATE_CHARGING: return "Charging";
|
||||||
|
case OP_STATE_PRE_CHARGE: return "PreCharging";
|
||||||
|
case OP_STATE_LOAD_ENABLED: return "Load enabled";
|
||||||
|
case OP_STATE_BATTERY_DEAD: return "Battery dead";
|
||||||
|
case OP_STATE_POWER_DOWN: return "Power down";
|
||||||
|
case OP_STATE_EXTERNAL: return "External";
|
||||||
|
case OP_STATE_ERROR: return "Error";
|
||||||
|
case OP_STATE_ERROR_PRECHARGE: return "ErrPreCharge";
|
||||||
|
case OP_STATE_BALANCING: return "Balancing";
|
||||||
|
case OP_STATE_CHARGED: return "Charged";
|
||||||
|
case OP_STATE_FORCEON: return "ForceOn";
|
||||||
|
default: return "Unknown fault";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Commands::faultStateToStr(bms_fault_code fault)
|
||||||
|
{
|
||||||
|
switch (fault) {
|
||||||
|
case FAULT_CODE_NONE: return "System OK";
|
||||||
|
case FAULT_CODE_PACK_OVER_VOLTAGE: return "Pack overvoltage";
|
||||||
|
case FAULT_CODE_PACK_UNDER_VOLTAGE: return "Pack undervoltage";
|
||||||
|
case FAULT_CODE_LOAD_OVER_VOLTAGE: return "Load overvoltage";
|
||||||
|
case FAULT_CODE_LOAD_UNDER_VOLTAGE: return "Load undervoltage";
|
||||||
|
case FAULT_CODE_CHARGER_OVER_VOLTAGE: return "Charger overvoltage";
|
||||||
|
case FAULT_CODE_CHARGER_UNDER_VOLTAGE: return "Charger undervoltgae";
|
||||||
|
case FAULT_CODE_CELL_HARD_OVER_VOLTAGE: return "Cell hard overvoltage";
|
||||||
|
case FAULT_CODE_CELL_HARD_UNDER_VOLTAGE: return "Cell hard undervoltage";
|
||||||
|
case FAULT_CODE_CELL_SOFT_OVER_VOLTAGE: return "Cell soft overvoltage";
|
||||||
|
case FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE: return "Cell soft undervoltage";
|
||||||
|
case FAULT_CODE_MAX_UVP_OVP_ERRORS: return "MAX OVP/UVP errors";
|
||||||
|
case FAULT_CODE_MAX_UVT_OVT_ERRORS: return "MAX OVT/UVT errors";
|
||||||
|
case FAULT_CODE_OVER_CURRENT: return "Over current";
|
||||||
|
case FAULT_CODE_OVER_TEMP_BMS: return "Over temp BMS";
|
||||||
|
case FAULT_CODE_UNDER_TEMP_BMS: return "Under temp BMS";
|
||||||
|
case FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS: return "Discharge over temp cell";
|
||||||
|
case FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS: return "Discharge under temp cell";
|
||||||
|
case FAULT_CODE_CHARGE_OVER_TEMP_CELLS: return "Charge over temp cell";
|
||||||
|
case FAULT_CODE_CHARGE_UNDER_TEMP_CELLS: return "Charge under temp cell";
|
||||||
|
case FAULT_CODE_PRECHARGE_TIMEOUT: return "Precharge timeout";
|
||||||
|
case FAULT_CODE_DISCHARGE_RETRY: return "Discharge retry";
|
||||||
|
case FAULT_CODE_CHARGE_RETRY: return "Charge retry";
|
||||||
|
case FAULT_CODE_CHARGER_DISCONNECT: return "Charge retry";
|
||||||
|
default: return "Unknown fault";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::setbmsConfig(ConfigParams *bmsConfig)
|
||||||
|
{
|
||||||
|
mbmsConfig = bmsConfig;
|
||||||
|
connect(mbmsConfig, SIGNAL(updateRequested()), this, SLOT(getBMSconf()));
|
||||||
|
connect(mbmsConfig, SIGNAL(updateRequestDefault()), this, SLOT(getBMSconfDefault()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::startFirmwareUpload(QByteArray &newFirmware, bool isBootloader)
|
||||||
|
{
|
||||||
|
mFirmwareIsBootloader = isBootloader;
|
||||||
|
mFirmwareIsUploading = true;
|
||||||
|
mFirmwareState = mFirmwareIsBootloader ? 2 : 0;
|
||||||
|
mFimwarePtr = 0;
|
||||||
|
mFirmwareTimer = 500;
|
||||||
|
mFirmwareRetries = 5;
|
||||||
|
mNewFirmware.clear();
|
||||||
|
mNewFirmware.append(newFirmware);
|
||||||
|
mFirmwareUploadStatus = "Buffer Erase";
|
||||||
|
|
||||||
|
if (mFirmwareIsBootloader) {
|
||||||
|
firmwareUploadUpdate(true);
|
||||||
|
} else {
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_ERASE_NEW_APP);
|
||||||
|
vb.vbAppendUint32(mNewFirmware.size());
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double Commands::getFirmwareUploadProgress()
|
||||||
|
{
|
||||||
|
if (mFirmwareIsUploading) {
|
||||||
|
return (double)mFimwarePtr / (double)mNewFirmware.size();
|
||||||
|
} else {
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Commands::getFirmwareUploadStatus()
|
||||||
|
{
|
||||||
|
return mFirmwareUploadStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::cancelFirmwareUpload()
|
||||||
|
{
|
||||||
|
if (mFirmwareIsUploading) {
|
||||||
|
mFirmwareIsUploading = false;
|
||||||
|
mFimwarePtr = 0;
|
||||||
|
mFirmwareState = 0;
|
||||||
|
mFirmwareUploadStatus = "Cancelled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::checkbmsConfig()
|
||||||
|
{
|
||||||
|
mCheckNextbmsConfig = true;
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_GET_MCCONF);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::storeBMSConfig()
|
||||||
|
{
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_STORE_BMS_CONF);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::emitEmptyValues()
|
||||||
|
{
|
||||||
|
BMS_VALUES values;
|
||||||
|
values.packVoltage = 0.0;
|
||||||
|
values.packCurrent = 0.0;
|
||||||
|
values.soC = 0.0;
|
||||||
|
values.cVHigh = 0.0;
|
||||||
|
values.cVAverage = 0.0;
|
||||||
|
values.cVLow = 0.0;
|
||||||
|
values.cVMisMatch = 0.0;
|
||||||
|
values.loadLCVoltage = 0.0;
|
||||||
|
values.loadLCCurrent = 0.0;
|
||||||
|
values.loadHCVoltage = 0.0;
|
||||||
|
values.loadHCCurrent = 0.0;
|
||||||
|
values.chargerVoltage = 0.0;
|
||||||
|
values.auxVoltage = 0.0;
|
||||||
|
values.auxCurrent = 0.0;
|
||||||
|
values.tempBattHigh = 0.0;
|
||||||
|
values.tempBattAverage = 0.0;
|
||||||
|
values.tempBattLow = 0.0;
|
||||||
|
values.tempBMSHigh = 0.0;
|
||||||
|
values.tempBMSAverage = 0.0;
|
||||||
|
values.tempBMSLow = 0.0;
|
||||||
|
values.humidity = 0.0;
|
||||||
|
values.opState = "Unknown";
|
||||||
|
values.balanceActive = 0.0;
|
||||||
|
values.faultState = "Unknown";
|
||||||
|
|
||||||
|
|
||||||
|
emit valuesReceived(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Commands::emitEmptySetupValues()
|
||||||
|
{
|
||||||
|
BMS_VALUES values;
|
||||||
|
values.packVoltage = 0.0;
|
||||||
|
values.packCurrent = 0.0;
|
||||||
|
values.soC = 0.0;
|
||||||
|
values.cVHigh = 0.0;
|
||||||
|
values.cVAverage = 0.0;
|
||||||
|
values.cVLow = 0.0;
|
||||||
|
values.cVMisMatch = 0.0;
|
||||||
|
values.loadLCVoltage = 0.0;
|
||||||
|
values.loadLCCurrent = 0.0;
|
||||||
|
values.loadHCVoltage = 0.0;
|
||||||
|
values.loadHCCurrent = 0.0;
|
||||||
|
values.chargerVoltage = 0.0;
|
||||||
|
values.auxVoltage = 0.0;
|
||||||
|
values.auxCurrent = 0.0;
|
||||||
|
values.tempBattHigh = 0.0;
|
||||||
|
values.tempBattAverage = 0.0;
|
||||||
|
values.tempBattLow = 0.0;
|
||||||
|
values.tempBMSHigh = 0.0;
|
||||||
|
values.tempBMSAverage = 0.0;
|
||||||
|
values.tempBMSLow = 0.0;
|
||||||
|
values.opState = OP_STATE_INIT;
|
||||||
|
values.balanceActive = 1;
|
||||||
|
values.faultState = FAULT_CODE_NONE;
|
||||||
|
|
||||||
|
emit valuesSetupReceived(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Commands::pingCan()
|
||||||
|
{
|
||||||
|
if (mTimeoutPingCan > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimeoutPingCan = 500;
|
||||||
|
|
||||||
|
VByteArray vb;
|
||||||
|
vb.vbAppendInt8(COMM_PING_CAN);
|
||||||
|
emitData(vb);
|
||||||
|
}
|
||||||
131
commands.h
Normal file
131
commands.h
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMMANDS_H
|
||||||
|
#define COMMANDS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
#include "vbytearray.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "packet.h"
|
||||||
|
#include "configparams.h"
|
||||||
|
|
||||||
|
class Commands : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Commands(QObject *parent = 0);
|
||||||
|
|
||||||
|
void setLimitedMode(bool is_limited);
|
||||||
|
Q_INVOKABLE bool isLimitedMode();
|
||||||
|
Q_INVOKABLE void setSendCan(bool sendCan, int id = -1);
|
||||||
|
Q_INVOKABLE bool getSendCan();
|
||||||
|
Q_INVOKABLE void setCanSendId(unsigned int id);
|
||||||
|
Q_INVOKABLE int getCanSendId();
|
||||||
|
void setbmsConfig(ConfigParams *bmsConfig);
|
||||||
|
Q_INVOKABLE void startFirmwareUpload(QByteArray &newFirmware, bool isBootloader = false);
|
||||||
|
Q_INVOKABLE double getFirmwareUploadProgress();
|
||||||
|
Q_INVOKABLE QString getFirmwareUploadStatus();
|
||||||
|
Q_INVOKABLE void cancelFirmwareUpload();
|
||||||
|
void checkbmsConfig();
|
||||||
|
void storeBMSConfig();
|
||||||
|
Q_INVOKABLE void emitEmptyValues();
|
||||||
|
Q_INVOKABLE void emitEmptySetupValues();
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void dataToSend(QByteArray &data);
|
||||||
|
|
||||||
|
void fwVersionReceived(int major, int minor, QString hw, QByteArray uuid);
|
||||||
|
void ackReceived(QString ackType);
|
||||||
|
void valuesReceived(BMS_VALUES values);
|
||||||
|
void cellsReceived(int cellCount, QVector<double> cellVoltageArray);
|
||||||
|
void auxReceived(int auxCount, QVector<double> auxVoltageArray);
|
||||||
|
void expTempReceived(int expTempCount, QVector<double> expTempVoltageArray);
|
||||||
|
void printReceived(QString str);
|
||||||
|
void rotorPosReceived(double pos);
|
||||||
|
void bmsConfigCheckResult(QStringList paramsNotSet);
|
||||||
|
void valuesSetupReceived(BMS_VALUES values);
|
||||||
|
void pingCanRx(QVector<int> devs, bool isTimeout);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void processPacket(QByteArray data);
|
||||||
|
|
||||||
|
void getFwVersion();
|
||||||
|
void getValues();
|
||||||
|
void getCells();
|
||||||
|
void getAux();
|
||||||
|
void getExpansionTemp();
|
||||||
|
void sendTerminalCmd(QString cmd);
|
||||||
|
void setDetect(disp_pos_mode mode);
|
||||||
|
void samplePrint(debug_sampling_mode mode, int sample_len, int dec);
|
||||||
|
void getBMSconf();
|
||||||
|
void getBMSconfDefault();
|
||||||
|
void setBMSconf(bool check = true);
|
||||||
|
void reboot();
|
||||||
|
void sendAlive();
|
||||||
|
void pairNrf(int ms);
|
||||||
|
void pingCan();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void timerSlot();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void emitData(QByteArray data);
|
||||||
|
void firmwareUploadUpdate(bool isTimeout);
|
||||||
|
QString opStateToStr(OperationalStateTypedef fault);
|
||||||
|
QString faultStateToStr(bms_fault_code fault);
|
||||||
|
|
||||||
|
QTimer *mTimer;
|
||||||
|
bool mSendCan;
|
||||||
|
int mCanId;
|
||||||
|
bool mIsLimitedMode;
|
||||||
|
|
||||||
|
// FW upload state
|
||||||
|
QByteArray mNewFirmware;
|
||||||
|
bool mFirmwareIsUploading;
|
||||||
|
int mFirmwareState;
|
||||||
|
int mFimwarePtr;
|
||||||
|
int mFirmwareTimer;
|
||||||
|
int mFirmwareRetries;
|
||||||
|
bool mFirmwareIsBootloader;
|
||||||
|
QString mFirmwareUploadStatus;
|
||||||
|
|
||||||
|
ConfigParams *mbmsConfig;
|
||||||
|
ConfigParams mbmsConfigLast;
|
||||||
|
bool mCheckNextbmsConfig;
|
||||||
|
|
||||||
|
int mTimeoutCount;
|
||||||
|
int mTimeoutFwVer;
|
||||||
|
int mTimeoutBMSconf;
|
||||||
|
int mTimeoutValues;
|
||||||
|
int mTimeoutCells;
|
||||||
|
int mTimeoutAux;
|
||||||
|
int mTimeoutExp;
|
||||||
|
int mTimeoutPingCan;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COMMANDS_H
|
||||||
101
configparam.cpp
Normal file
101
configparam.cpp
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
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 "configparam.h"
|
||||||
|
|
||||||
|
ConfigParam::ConfigParam()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigParam::reset()
|
||||||
|
{
|
||||||
|
type = CFG_T_UNDEFINED;
|
||||||
|
longName = "none";
|
||||||
|
description = "TODO";
|
||||||
|
cDefine.clear();
|
||||||
|
|
||||||
|
valDouble = 0.0;
|
||||||
|
valInt = 0;
|
||||||
|
maxDouble = 99.0;
|
||||||
|
minDouble = 0.0;
|
||||||
|
stepDouble = 1.0;
|
||||||
|
editorDecimalsDouble = 2;
|
||||||
|
editorScale = 1.0;
|
||||||
|
maxInt = 99;
|
||||||
|
minInt = 0;
|
||||||
|
stepInt = 1;
|
||||||
|
vTx = VESC_TX_UNDEFINED;
|
||||||
|
vTxDoubleScale = 1.0;
|
||||||
|
suffix = "";
|
||||||
|
enumNames.clear();
|
||||||
|
editAsPercentage = false;
|
||||||
|
showDisplay = false;
|
||||||
|
transmittable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigParam::setInt(int val, int max, int min, int step)
|
||||||
|
{
|
||||||
|
type = CFG_T_INT;
|
||||||
|
valInt = val;
|
||||||
|
maxInt = max;
|
||||||
|
minInt = min;
|
||||||
|
stepInt = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigParam::setDouble(double val, double max, double min, double step, int decimals)
|
||||||
|
{
|
||||||
|
type = CFG_T_DOUBLE;
|
||||||
|
valDouble = val;
|
||||||
|
maxDouble = max;
|
||||||
|
minDouble = min;
|
||||||
|
stepDouble = step;
|
||||||
|
editorDecimalsDouble = decimals;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigParam::setDoubleTx(VESC_TX_T tx, double scale)
|
||||||
|
{
|
||||||
|
vTx = tx;
|
||||||
|
vTxDoubleScale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigParam::setEnum(int val, QStringList names)
|
||||||
|
{
|
||||||
|
type = CFG_T_ENUM;
|
||||||
|
valInt = val;
|
||||||
|
enumNames = names;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigParam::setString(QString val)
|
||||||
|
{
|
||||||
|
type = CFG_T_QSTRING;
|
||||||
|
valString = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigParam::setBool(bool val)
|
||||||
|
{
|
||||||
|
type = CFG_T_BOOL;
|
||||||
|
valInt = val;
|
||||||
|
}
|
||||||
71
configparam.h
Normal file
71
configparam.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIGPARAM_H
|
||||||
|
#define CONFIGPARAM_H
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
#include "datatypes.h"
|
||||||
|
|
||||||
|
class ConfigParam
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConfigParam();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void setInt(int val, int max = 99, int min = 0, int step = 0);
|
||||||
|
void setDouble(double val, double max = 99.0, double min = 0.0,
|
||||||
|
double step = 1.0, int decimals = 2);
|
||||||
|
void setDoubleTx(VESC_TX_T tx, double scale);
|
||||||
|
void setEnum(int val, QStringList names);
|
||||||
|
void setString(QString val);
|
||||||
|
void setBool(bool val);
|
||||||
|
|
||||||
|
CFG_T type;
|
||||||
|
QString longName;
|
||||||
|
QString description;
|
||||||
|
QString cDefine;
|
||||||
|
double valDouble;
|
||||||
|
int valInt;
|
||||||
|
QString valString;
|
||||||
|
QStringList enumNames;
|
||||||
|
double maxDouble;
|
||||||
|
double minDouble;
|
||||||
|
double stepDouble;
|
||||||
|
int editorDecimalsDouble;
|
||||||
|
int maxInt;
|
||||||
|
int minInt;
|
||||||
|
int stepInt;
|
||||||
|
VESC_TX_T vTx;
|
||||||
|
double vTxDoubleScale;
|
||||||
|
QString suffix;
|
||||||
|
double editorScale;
|
||||||
|
bool editAsPercentage;
|
||||||
|
bool showDisplay;
|
||||||
|
bool transmittable;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONFIGPARAM_H
|
||||||
1559
configparams.cpp
Normal file
1559
configparams.cpp
Normal file
File diff suppressed because it is too large
Load Diff
151
configparams.h
Normal file
151
configparams.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIGPARAMS_H
|
||||||
|
#define CONFIGPARAMS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include "configparam.h"
|
||||||
|
#include "vbytearray.h"
|
||||||
|
|
||||||
|
class ConfigParams : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ConfigParams(QObject *parent = 0);
|
||||||
|
void addParam(const QString &name, ConfigParam param);
|
||||||
|
void deleteParam(const QString &name);
|
||||||
|
Q_INVOKABLE void setUpdateOnly(const QString &name);
|
||||||
|
Q_INVOKABLE QString getUpdateOnly();
|
||||||
|
Q_INVOKABLE bool getUpdatesEnabled() const;
|
||||||
|
Q_INVOKABLE void setUpdatesEnabled(bool updatesEnabled);
|
||||||
|
void clearParams();
|
||||||
|
void clearAll();
|
||||||
|
|
||||||
|
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 bool isParamDouble(const QString &name);
|
||||||
|
Q_INVOKABLE bool isParamInt(const QString &name);
|
||||||
|
Q_INVOKABLE bool isParamEnum(const QString &name);
|
||||||
|
Q_INVOKABLE bool isParamQString(const QString &name);
|
||||||
|
Q_INVOKABLE bool isParamBool(const QString &name);
|
||||||
|
|
||||||
|
Q_INVOKABLE double getParamDouble(const QString &name);
|
||||||
|
Q_INVOKABLE int getParamInt(const QString &name);
|
||||||
|
Q_INVOKABLE int getParamEnum(const QString &name);
|
||||||
|
Q_INVOKABLE QString getParamQString(const QString &name);
|
||||||
|
Q_INVOKABLE bool getParamBool(const QString &name);
|
||||||
|
Q_INVOKABLE QString getLongName(const QString &name);
|
||||||
|
Q_INVOKABLE QString getDescription(const QString &name);
|
||||||
|
|
||||||
|
Q_INVOKABLE double getParamMaxDouble(const QString &name);
|
||||||
|
Q_INVOKABLE double getParamMinDouble(const QString &name);
|
||||||
|
Q_INVOKABLE double getParamStepDouble(const QString &name);
|
||||||
|
Q_INVOKABLE int getParamDecimalsDouble(const QString &name);
|
||||||
|
Q_INVOKABLE int getParamMaxInt(const QString &name);
|
||||||
|
Q_INVOKABLE int getParamMinInt(const QString &name);
|
||||||
|
Q_INVOKABLE int getParamStepInt(const QString &name);
|
||||||
|
Q_INVOKABLE QStringList getParamEnumNames(const QString &name);
|
||||||
|
Q_INVOKABLE double getParamEditorScale(const QString &name);
|
||||||
|
Q_INVOKABLE QString getParamSuffix(const QString &name);
|
||||||
|
Q_INVOKABLE bool getParamEditAsPercentage(const QString &name);
|
||||||
|
Q_INVOKABLE bool getParamShowDisplay(const QString &name);
|
||||||
|
Q_INVOKABLE bool getParamTransmittable(const QString &name);
|
||||||
|
|
||||||
|
QStringList getParamOrder() const;
|
||||||
|
void setParamOrder(const QStringList &order);
|
||||||
|
|
||||||
|
QWidget *getEditor(const QString &name, QWidget *parent = 0);
|
||||||
|
|
||||||
|
void getParamSerial(VByteArray &vb, const QString &name);
|
||||||
|
void setParamSerial(VByteArray &vb, const QString &name, QObject *src = 0);
|
||||||
|
|
||||||
|
QStringList getSerializeOrder() const;
|
||||||
|
void setSerializeOrder(const QStringList &serializeOrder);
|
||||||
|
void clearSerializeOrder();
|
||||||
|
|
||||||
|
void serialize(VByteArray &vb);
|
||||||
|
void deSerialize(VByteArray &vb);
|
||||||
|
|
||||||
|
void getXML(QXmlStreamWriter &stream, QString configName);
|
||||||
|
bool setXML(QXmlStreamReader &stream, QString configName);
|
||||||
|
bool saveXml(QString fileName, QString configName);
|
||||||
|
bool loadXml(QString fileName, QString configName);
|
||||||
|
QString xmlStatus();
|
||||||
|
|
||||||
|
void getParamsXML(QXmlStreamWriter &stream);
|
||||||
|
bool setParamsXML(QXmlStreamReader &stream);
|
||||||
|
bool saveParamsXml(QString fileName);
|
||||||
|
bool loadParamsXml(QString fileName);
|
||||||
|
|
||||||
|
bool saveCDefines(const QString &fileName, bool wrapIfdef = false);
|
||||||
|
|
||||||
|
QStringList checkDifference(ConfigParams *config);
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
ConfigParams& operator=(const ConfigParams &other);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void paramChangedDouble(QObject *src, QString name, double newParam);
|
||||||
|
void paramChangedInt(QObject *src, QString name, int newParam);
|
||||||
|
void paramChangedEnum(QObject *src, QString name, int newParam);
|
||||||
|
void paramChangedQString(QObject *src, QString name, QString newParam);
|
||||||
|
void paramChangedBool(QObject *src, QString name, bool newParam);
|
||||||
|
void updateRequested();
|
||||||
|
void updateRequestDefault();
|
||||||
|
void updated();
|
||||||
|
void stored();
|
||||||
|
void savingXml();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateParamDouble(QString name, double param, QObject *src = 0);
|
||||||
|
void updateParamInt(QString name, int param, QObject *src = 0);
|
||||||
|
void updateParamEnum(QString name, int param, QObject *src = 0);
|
||||||
|
void updateParamString(QString name, QString param, QObject *src = 0);
|
||||||
|
void updateParamBool(QString name, bool param, QObject *src = 0);
|
||||||
|
void requestUpdate();
|
||||||
|
void requestUpdateDefault();
|
||||||
|
void updateDone();
|
||||||
|
void storingDone();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, ConfigParam> mParams;
|
||||||
|
QStringList mParamList;
|
||||||
|
QString mUpdateOnlyName;
|
||||||
|
bool mUpdatesEnabled;
|
||||||
|
QStringList mSerializeOrder;
|
||||||
|
QString mXmlStatus;
|
||||||
|
|
||||||
|
bool almostEqual(float A, float B, float eps);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONFIGPARAMS_H
|
||||||
189
configparamsgetter.cpp
Normal file
189
configparamsgetter.cpp
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
#include "configparamsgetter.h"
|
||||||
|
|
||||||
|
//bool BmsSettingsWidget::addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName)
|
||||||
|
|
||||||
|
|
||||||
|
bool getSerialNumber(QLabel* lab, ConfigParams *params, QString paramName)
|
||||||
|
{
|
||||||
|
// (*) serial number is inside a DOUBLE value inside the BMS
|
||||||
|
// (**) But we need only the INT part of that double value
|
||||||
|
bool res = false;
|
||||||
|
QWidget *editor = params->getEditor(paramName);
|
||||||
|
QString name = params->getLongName(paramName);
|
||||||
|
if (editor && !name.isEmpty())
|
||||||
|
{
|
||||||
|
if(editor->property("type").toInt() == CFG_T_DOUBLE) // (*)
|
||||||
|
{
|
||||||
|
auto val = params->getParamDouble(paramName);
|
||||||
|
quint64 valUint64 = quint64(val); // (**)
|
||||||
|
lab->setText( QString::number(valUint64) );
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getSerialNumber(QLineEdit* edit, ConfigParams *params, QString paramName)
|
||||||
|
{
|
||||||
|
// (*) serial number is inside a DOUBLE value inside the BMS
|
||||||
|
// (**) But we need only the INT part of that double value
|
||||||
|
bool res = false;
|
||||||
|
QWidget *editor = params->getEditor(paramName);
|
||||||
|
QString name = params->getLongName(paramName);
|
||||||
|
if (editor && !name.isEmpty())
|
||||||
|
{
|
||||||
|
if(editor->property("type").toInt() == CFG_T_DOUBLE) // (*)
|
||||||
|
{
|
||||||
|
auto val = params->getParamDouble(paramName);
|
||||||
|
quint64 valUint64 = quint64(val); // (**)
|
||||||
|
edit->setText( QString::number(valUint64) );
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
QWidget *editor = params->getEditor(paramName);
|
||||||
|
//ConfigParam &p = params[paramName];
|
||||||
|
//ConfigParam &p = mParams[name];
|
||||||
|
|
||||||
|
QString name = params->getLongName(paramName);
|
||||||
|
|
||||||
|
if (editor && !name.isEmpty())
|
||||||
|
{
|
||||||
|
//int row = rowCount();
|
||||||
|
//setRowCount(row + 1);
|
||||||
|
//QTableWidgetItem *item = new QTableWidgetItem(name);
|
||||||
|
//item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||||
|
//setItem(row, 0, item);
|
||||||
|
//setCellWidget(row, 1, editor);
|
||||||
|
//edit->setText(editor->);
|
||||||
|
|
||||||
|
auto vtype = editor->property("type");
|
||||||
|
auto type = vtype.toInt();
|
||||||
|
//CFG_T_UNDEFINED = 0,
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case CFG_T_INT:
|
||||||
|
case CFG_T_ENUM:
|
||||||
|
{
|
||||||
|
auto val = params->getParamInt(paramName);
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CFG_T_DOUBLE:
|
||||||
|
{
|
||||||
|
auto val = params->getParamDouble(paramName);
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CFG_T_QSTRING:
|
||||||
|
{
|
||||||
|
auto val = params->getParamQString(paramName);
|
||||||
|
edit->setText(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CFG_T_BOOL:
|
||||||
|
{
|
||||||
|
auto val = params->getParamBool(paramName);
|
||||||
|
edit->setText(val ? "true" : "false");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
auto val = editor->property("value");
|
||||||
|
auto valString = val.toString();
|
||||||
|
edit->setText(valString.isEmpty() ? "Erro Read Value" : valString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vsuffix = editor->property("suffix");
|
||||||
|
auto suffix = vsuffix.toString();
|
||||||
|
auto veditorDecimalsDouble = editor->property("editorDecimalsDouble");
|
||||||
|
auto editorDecimalsDouble = veditorDecimalsDouble.toDouble();
|
||||||
|
auto veditAsPercentage = editor->property("editAsPercentage");
|
||||||
|
auto editAsPercentage = veditAsPercentage.toBool();
|
||||||
|
|
||||||
|
res = true;
|
||||||
|
//resizeColumnToContents(0);
|
||||||
|
//resizeRowsToContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool addParamRowEx(QLineEdit* edit, ConfigParams *params, QString paramName)
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
QWidget *editor = params->getEditor(paramName);
|
||||||
|
QString name = params->getLongName(paramName);
|
||||||
|
|
||||||
|
if (editor && !name.isEmpty()) {
|
||||||
|
//int row = rowCount();
|
||||||
|
//setRowCount(row + 1);
|
||||||
|
//QTableWidgetItem *item = new QTableWidgetItem(name);
|
||||||
|
//item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||||
|
//setItem(row, 0, item);
|
||||||
|
//setCellWidget(row, 1, editor);
|
||||||
|
//edit->setText(editor->);
|
||||||
|
|
||||||
|
auto vtype = editor->property("type");
|
||||||
|
auto type = vtype.toInt();
|
||||||
|
auto vval = editor->property("value");
|
||||||
|
//CFG_T_UNDEFINED = 0,
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case(CFG_T_INT):
|
||||||
|
case(CFG_T_ENUM):
|
||||||
|
{
|
||||||
|
auto val = vval.toInt();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CFG_T_DOUBLE):
|
||||||
|
{
|
||||||
|
auto val = vval.toDouble();
|
||||||
|
edit->setText(QString::number(val));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CFG_T_QSTRING):
|
||||||
|
{
|
||||||
|
auto val = vval.toString();
|
||||||
|
edit->setText(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(CFG_T_BOOL):
|
||||||
|
{
|
||||||
|
auto val = vval.toBool();
|
||||||
|
edit->setText(val ? "true" : "false");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
auto valString = vval.toString();
|
||||||
|
edit->setText(valString.isEmpty() ? "Erro Read Value" : valString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vsuffix = editor->property("suffix");
|
||||||
|
auto suffix = vsuffix.toString();
|
||||||
|
auto veditorDecimalsDouble = editor->property("editorDecimalsDouble");
|
||||||
|
auto editorDecimalsDouble = veditorDecimalsDouble.toDouble();
|
||||||
|
auto veditAsPercentage = editor->property("editAsPercentage");
|
||||||
|
auto editAsPercentage = veditAsPercentage.toBool();
|
||||||
|
|
||||||
|
res = true;
|
||||||
|
//resizeColumnToContents(0);
|
||||||
|
//resizeRowsToContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
18
configparamsgetter.h
Normal file
18
configparamsgetter.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CONFIGPARAMSGETTER_H
|
||||||
|
#define CONFIGPARAMSGETTER_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
#include "configparams.h"
|
||||||
|
|
||||||
|
//class SettingsWidget : public QWidget
|
||||||
|
//{
|
||||||
|
bool getSerialNumber(QLabel* lab, ConfigParams *params, QString paramName);
|
||||||
|
bool getSerialNumber(QLineEdit* edit, ConfigParams *params, QString paramName);
|
||||||
|
bool addParamRow(QLineEdit* edit, ConfigParams *params, QString paramName);
|
||||||
|
bool addParamRowEx(QLineEdit* edit, ConfigParams *params, QString paramName);
|
||||||
|
//};
|
||||||
|
|
||||||
|
#endif // CONFIGPARAMSGETTER_H
|
||||||
535
configurationpage.cpp
Normal file
535
configurationpage.cpp
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
#include "configurationpage.h"
|
||||||
|
#include "ui_configurationpage.h"
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
#include "connectandenterpage.h"
|
||||||
|
|
||||||
|
ConfigurationPage::ConfigurationPage(QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
ui(new Ui::ConfigurationPage)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
connect( ui->pbLinkSerialNumber , &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosSerialNumber ); } );
|
||||||
|
connect( ui->pbLinkConfiguration , &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosConfiguration ); } );
|
||||||
|
connect( ui->pbLinkSoc , &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosSoc ); } );
|
||||||
|
connect( ui->pbLinkRestrictions , &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosRestrictions ); } );
|
||||||
|
connect( ui->pbLinkCellsConfiguration , &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosCellsConfiguration ); } );
|
||||||
|
connect( ui->pbLinkBalancingConfiguration, &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosBalancingConfiguration); } );
|
||||||
|
connect( ui->pbLinkOutputsSetting , &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosOutputsSetting ); } );
|
||||||
|
connect( ui->pbLinkClaibrateZero , &QPushButton::clicked, this, [=]() { setPositionInPixelsToScrollTo(PosClaibrateZero ); } );
|
||||||
|
|
||||||
|
connect( ui->pbReadDefaultSettingsFromFile , &QPushButton::clicked, this, &ConfigurationPage::onPbReadDefaultSettingsFromFileClicked);
|
||||||
|
connect( ui->pbReadCurrentSettingsFromBms , &QPushButton::clicked, this, &ConfigurationPage::onPbReadCurrentSettingsFromBmsClicked);
|
||||||
|
connect( ui->pbWriteCurrentValuesToBms , &QPushButton::clicked, this, &ConfigurationPage::onPbWriteCurrentValuesToBmsClicked);
|
||||||
|
connect( ui->pbWriteToNonVolatileBmsMemory , &QPushButton::clicked, this, &ConfigurationPage::onPbWriteToNonVolatileBmsMemoryClicked);
|
||||||
|
|
||||||
|
connect(ui->bmsSettings, &BmsSettings::showStatusInfo, this, &ConfigurationPage::showStatusInfo);
|
||||||
|
connect(ui->bmsSettings, &BmsSettings::showMessageDialog, this, &ConfigurationPage::showMessageDialog);
|
||||||
|
connect(ui->bmsSettings, &BmsSettings::sendMessage, this, &ConfigurationPage::sendMessage);
|
||||||
|
connect(this, &ConfigurationPage::loadParams, ui->bmsSettings, &BmsSettings::onLoadParams);
|
||||||
|
|
||||||
|
initTimerForStatusBar();
|
||||||
|
initTimerForProgressBar();
|
||||||
|
initTimerForOneSecondDelayAfterButtonClick();
|
||||||
|
|
||||||
|
checkIfButtonTextFitsInButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMSInterface *ConfigurationPage::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
ui->bmsSettings->setDieBieMS(mDieBieMS);
|
||||||
|
|
||||||
|
// SEND_STATUS_INFO //
|
||||||
|
connect(mDieBieMS, &BMSInterface::statusMessage, this, &ConfigurationPage::showStatusInfo);
|
||||||
|
|
||||||
|
connect(mDieBieMS->bmsConfig(), &ConfigParams::updateRequested, ui->bmsSettings, &BmsSettings::onBmsconfUpdateRequested);
|
||||||
|
connect(mDieBieMS->bmsConfig(), &ConfigParams::updateRequestDefault, ui->bmsSettings, &BmsSettings::onBmsconfUpdateRequestDefault);
|
||||||
|
connect(mDieBieMS->bmsConfig(), &ConfigParams::updated, ui->bmsSettings, &BmsSettings::onBmsconfUpdated);
|
||||||
|
connect(mDieBieMS->bmsConfig(), &ConfigParams::updated, this, &ConfigurationPage::onBmsconfUpdatedOrStored);
|
||||||
|
connect(mDieBieMS->bmsConfig(), &ConfigParams::stored, ui->bmsSettings, &BmsSettings::onBmsconfStored);
|
||||||
|
connect(mDieBieMS->bmsConfig(), &ConfigParams::stored, this, &ConfigurationPage::onBmsconfUpdatedOrStored);
|
||||||
|
|
||||||
|
//connect(mDieBieMS->bmsConfig(), &ConfigParams::updated, this, &ConfigurationPage::bmsconfUpdated);
|
||||||
|
|
||||||
|
//void ConfigParams::requestUpdate() => emit updateRequested();
|
||||||
|
//void ConfigParams::requestUpdateDefault() => emit updateRequestDefault();
|
||||||
|
//void ConfigParams::updateDone() => emit updated();
|
||||||
|
//void ConfigParams::storingDone() => emit stored();
|
||||||
|
|
||||||
|
//void sigBmsconfUpdateRequested();
|
||||||
|
//void sigBmsconfUpdateRequestDefault();
|
||||||
|
//void sigBmsconfUpdated();
|
||||||
|
//void sigBmsconfStored();
|
||||||
|
|
||||||
|
//connect(ui->bmsSettings, &BmsSettings::sendMessage, this, &ConfigurationPage::sendMessage);
|
||||||
|
//connect(this, &ConfigurationPage::loadParams, ui->bmsSettings, &BmsSettings::onLoadParams);
|
||||||
|
|
||||||
|
/*
|
||||||
|
connect(mPacket, (dataToSend(QByteArray&)),this, (packetDataToSend(QByteArray&)));
|
||||||
|
connect(mPacket, (packetReceived(QByteArray&)),this, (packetReceived(QByteArray&)));
|
||||||
|
connect(mCommands, (dataToSend(QByteArray&)),this, (cmdDataToSend(QByteArray&)));
|
||||||
|
connect(mCommands, (fwVersionReceived(int,int,QString,QByteArray)),this, SLOT(fwVersionReceived(int,int,QString,QByteArray)));
|
||||||
|
connect(mCommands, (ackReceived(QString)), this, (ackReceived(QString)));
|
||||||
|
connect(mbmsConfig, (updated()), this, (bmsconfUpdated()));
|
||||||
|
connect(mbmsConfig, (stored()), this, (bmsconfStored()));
|
||||||
|
connect(mTimer, (timeout()), this, (timerSlot()));
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigurationPage::~ConfigurationPage()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::checkIfButtonTextFitsInButton()
|
||||||
|
{
|
||||||
|
int textWidth = QFontMetrics(ui->pbWriteCurrentValuesToBms->font()).width(ui->pbWriteCurrentValuesToBms->text());
|
||||||
|
int btnWidth = ui->pbWriteCurrentValuesToBms->width();
|
||||||
|
if(btnWidth <= textWidth)
|
||||||
|
ui->pbWriteCurrentValuesToBms->setText(tr("Записать текущие значения\nв BMS"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::setPositionInPixelsToScrollTo(int positionInPixelsToScrollTo)
|
||||||
|
{
|
||||||
|
if(positionInPixelsToScrollTo != PosSerialNumber)
|
||||||
|
positionInPixelsToScrollTo -= 15;
|
||||||
|
|
||||||
|
ui->scrollAreaBmsSettings->verticalScrollBar()->setValue(positionInPixelsToScrollTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//void ConfigurationPage::bmsconfUpdated()
|
||||||
|
//{
|
||||||
|
// //mMcConfRead = false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void ConfigurationPage::onTimerSlot()
|
||||||
|
{
|
||||||
|
// Update status label
|
||||||
|
if (mStatusInfoTime) {
|
||||||
|
mStatusInfoTime--;
|
||||||
|
if (!mStatusInfoTime) {
|
||||||
|
//mStatusLabel->setStyleSheet(qApp->styleSheet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*else {
|
||||||
|
QString str = mDieBieMS->getConnectedPortName();
|
||||||
|
if (str != mStatusLabel->text()) {
|
||||||
|
mStatusLabel->setText(mDieBieMS->getConnectedPortName());
|
||||||
|
static QString statusLast = "";
|
||||||
|
if (str != statusLast) {
|
||||||
|
mPageDebugPrint->printConsole("Status: " + str + "<br>");
|
||||||
|
statusLast = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* // CAN fwd
|
||||||
|
if (ui->actionCanFwd->isChecked() != mDieBieMS->commands()->getSendCan()) {
|
||||||
|
ui->actionCanFwd->setChecked(mDieBieMS->commands()->getSendCan());
|
||||||
|
}
|
||||||
|
|
||||||
|
// RT data only every 5 iterations
|
||||||
|
if (ui->actionRtData->isChecked()) {
|
||||||
|
static int values_cnt = 0;
|
||||||
|
static int cells_cnt = 0;
|
||||||
|
|
||||||
|
values_cnt++;
|
||||||
|
if (values_cnt >= 5) {
|
||||||
|
values_cnt = 0;
|
||||||
|
mDieBieMS->commands()->getValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
cells_cnt++;
|
||||||
|
if (cells_cnt >= 20) {
|
||||||
|
cells_cnt = 0;
|
||||||
|
mDieBieMS->commands()->getCells();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send alive command once every 10 iterations
|
||||||
|
if (ui->actionSendAlive->isChecked()) {
|
||||||
|
static int alive_cnt = 0;
|
||||||
|
alive_cnt++;
|
||||||
|
if (alive_cnt >= 10) {
|
||||||
|
alive_cnt = 0;
|
||||||
|
mDieBieMS->commands()->sendAlive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Read configuration it isn't read since starting VESC Tool
|
||||||
|
if (mDieBieMS->isPortConnected()) {
|
||||||
|
static int conf_cnt = 0;
|
||||||
|
conf_cnt++;
|
||||||
|
if (conf_cnt >= 20) {
|
||||||
|
conf_cnt = 0;
|
||||||
|
if (!mMcConfRead) {
|
||||||
|
mDieBieMS->commands()->getBMSconf();
|
||||||
|
mMcConfRead = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* // Disable all data streaming when uploading firmware
|
||||||
|
if (mDieBieMS->commands()->getFirmwareUploadProgress() > 0.1) {
|
||||||
|
ui->actionSendAlive->setChecked(false);
|
||||||
|
ui->actionRtData->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run startup checks
|
||||||
|
static bool has_run_start_checks = false;
|
||||||
|
if (!has_run_start_checks) {
|
||||||
|
has_run_start_checks = true;
|
||||||
|
checkUdev();
|
||||||
|
Utility::checkVersion(mDieBieMS);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
// connect(mTimer, SIGNAL(timeout()),this, SLOT(timerSlot()));
|
||||||
|
connect(mDieBieMS, &BMSInterface::statusMessage, this, &ConnectAndEnterPage::showStatusInfo);
|
||||||
|
connect(mDieBieMS, &BMSInterface::messageDialog, this, &ConnectAndEnterPage::showMessageDialog);
|
||||||
|
connect(mDieBieMS, &BMSInterface::serialPortNotWritable, this, &ConnectAndEnterPage::serialPortNotWritable);
|
||||||
|
connect(mDieBieMS->commands(), &Commands::bmsConfigCheckResult, this, &ConnectAndEnterPage::bmsConfigCheckResult);
|
||||||
|
// connect(ui->actionAboutQt, SIGNAL(triggered(bool)),qApp, SLOT(aboutQt()));
|
||||||
|
|
||||||
|
// Remove the menu with the option to hide the toolbar
|
||||||
|
// ui->mainToolBar->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||||
|
|
||||||
|
mDieBieMS->bmsConfig()->loadParamsXml("://res/config.xml");
|
||||||
|
mDieBieMS->infoConfig()->loadParamsXml("://res/info.xml");
|
||||||
|
// reloadPages();
|
||||||
|
|
||||||
|
connect(mDieBieMS->bmsConfig(), SIGNAL(updated()), this, SLOT(bmsconfUpdated()));
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
|
||||||
|
|
||||||
|
void ConfigurationPage::onTimerSlot()
|
||||||
|
{
|
||||||
|
// Update status label
|
||||||
|
if (mStatusInfoTime) {
|
||||||
|
mStatusInfoTime--;
|
||||||
|
if (!mStatusInfoTime) {
|
||||||
|
// clear Status Label
|
||||||
|
ui->lbStatus->setText("");
|
||||||
|
ui->lbStatus->setStyleSheet(qApp->styleSheet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::showStatusInfo(QString info, bool isGood)
|
||||||
|
{
|
||||||
|
if (isGood) {
|
||||||
|
ui->lbStatus->setStyleSheet("QLabel { background-color : lightgreen; color : black; }");
|
||||||
|
mPageDebugPrint->printConsole("Status: " + info + "<br>");
|
||||||
|
} else {
|
||||||
|
ui->lbStatus->setStyleSheet("QLabel { background-color : red; color : black; }");
|
||||||
|
mPageDebugPrint->printConsole("<font color=\"red\">Status: " + info + "</font><br>");
|
||||||
|
}
|
||||||
|
|
||||||
|
mStatusInfoTime = 160;
|
||||||
|
ui->lbStatus->setText(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pbLoadSettingsFromFile
|
||||||
|
//void ConfigurationPage::on_pbLoadSettingsFromFile_clicked()
|
||||||
|
//{
|
||||||
|
// bool NOTHING_IS_CONNECTED_HERE_ACCORDING_SPECIFICATION_FROM_CUSTOMER = true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
//// pbLoadCurrentSettingsFromBms
|
||||||
|
//void ConfigurationPage::on_pbLoadCurrentSettingsFromBms_clicked()
|
||||||
|
//{
|
||||||
|
// // Загрузить настройки из файла
|
||||||
|
// // Загрузить текущие настройки\nиз BMS
|
||||||
|
// // actionReadBMScconf
|
||||||
|
// mDieBieMS->commands()->getBMSconf();
|
||||||
|
// // ? // mDieBieMS->commands()->getBMSconfDefault();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//// pbWriteToNonVolatileBmsMemory
|
||||||
|
//void ConfigurationPage::on_pbWriteToNonVolatileBmsMemory_clicked()
|
||||||
|
//{
|
||||||
|
// // Записать в энергонезависимую\nпамять BMS
|
||||||
|
// // actionStoreBMScconf
|
||||||
|
// mDieBieMS->commands()->storeBMSConfig();
|
||||||
|
//}
|
||||||
|
|
||||||
|
// pbWriteCurrentValuesToBms
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*
|
||||||
|
start 0 12 = Default that is not in bms it's in somekind of real offline file (we do NOT have connection to bms but there parameters show up somehow)
|
||||||
|
connect 8 8 Config updated with default params not from file, but from default params of bms
|
||||||
|
deflt bms edit | bms edit
|
||||||
|
^ - 8 8 7 | 8 8 read bms conf
|
||||||
|
-> - 8 7 7 | 7 8 read default 8 is defaul - that was on the start
|
||||||
|
v - 8 8 7 | 7 7 write bms config
|
||||||
|
S - 8 ? ? | ? ? save currect config from bms into outside file to the flash card
|
||||||
|
before | after
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void ConfigurationPage::onPbReadDefaultSettingsFromFileClicked()
|
||||||
|
{
|
||||||
|
if(mIsOneSedondPassed)
|
||||||
|
{
|
||||||
|
mOneSecondWait->start();
|
||||||
|
mIsOneSedondPassed = false;
|
||||||
|
if(mIsOperationFinished)
|
||||||
|
{
|
||||||
|
mIsOperationFinished = false;
|
||||||
|
|
||||||
|
onStartPercents();
|
||||||
|
// bms edit | bms edit
|
||||||
|
//-> - 7 7 | 7 8 read default 8 is defaul - that was on the start
|
||||||
|
// Загрузить настройки\nпо умолчанию
|
||||||
|
mDieBieMS->commands()->getBMSconfDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::onPbReadCurrentSettingsFromBmsClicked()
|
||||||
|
{
|
||||||
|
if(mIsOneSedondPassed)
|
||||||
|
{
|
||||||
|
mOneSecondWait->start();
|
||||||
|
mIsOneSedondPassed = false;
|
||||||
|
|
||||||
|
if(mIsOperationFinished)
|
||||||
|
{
|
||||||
|
mIsOperationFinished = false;
|
||||||
|
|
||||||
|
onStartPercents();
|
||||||
|
// bms edit | bms edit
|
||||||
|
//^ - 7 8 | 7 7 read bms conf
|
||||||
|
mDieBieMS->commands()->getBMSconf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// pbLoadCurrentSettingsFromBms
|
||||||
|
void ConfigurationPage::onPbWriteCurrentValuesToBmsClicked()
|
||||||
|
{
|
||||||
|
if(mIsOneSedondPassed)
|
||||||
|
{
|
||||||
|
mOneSecondWait->start();
|
||||||
|
mIsOneSedondPassed = false;
|
||||||
|
|
||||||
|
if(mIsOperationFinished)
|
||||||
|
{
|
||||||
|
mIsOperationFinished = false;
|
||||||
|
|
||||||
|
onStartPercents();
|
||||||
|
// Записать текущие значения в BMS
|
||||||
|
// actionWriteBMScconf
|
||||||
|
mDieBieMS->commands()->setBMSconf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//// pbWriteToNonVolatileBmsMemory
|
||||||
|
void ConfigurationPage::onPbWriteToNonVolatileBmsMemoryClicked()
|
||||||
|
{
|
||||||
|
if(mIsOneSedondPassed)
|
||||||
|
{
|
||||||
|
mOneSecondWait->start();
|
||||||
|
mIsOneSedondPassed = false;
|
||||||
|
|
||||||
|
if(mIsOperationFinished)
|
||||||
|
{
|
||||||
|
mIsOperationFinished = false;
|
||||||
|
|
||||||
|
onStartPercents();
|
||||||
|
// Записать в энергонезависимую\nпамять BMS
|
||||||
|
// actionStoreBMScconf
|
||||||
|
mDieBieMS->commands()->storeBMSConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
void ConfigurationPage::onPbReadDefaultSettingsFromFileClicked()
|
||||||
|
{
|
||||||
|
// bms edit | bms edit
|
||||||
|
//-> - 7 7 | 7 8 read default 8 is defaul - that was on the start
|
||||||
|
// Загрузить настройки\nпо умолчанию
|
||||||
|
mDieBieMS->commands()->getBMSconfDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::onPbReadCurrentSettingsFromBmsClicked()
|
||||||
|
{
|
||||||
|
// bms edit | bms edit
|
||||||
|
//^ - 7 8 | 7 7 read bms conf
|
||||||
|
mDieBieMS->commands()->getBMSconf();
|
||||||
|
}
|
||||||
|
|
||||||
|
//// pbLoadCurrentSettingsFromBms
|
||||||
|
void ConfigurationPage::onPbWriteCurrentValuesToBmsClicked()
|
||||||
|
{
|
||||||
|
// Записать текущие значения в BMS
|
||||||
|
// actionWriteBMScconf
|
||||||
|
mDieBieMS->commands()->setBMSconf();
|
||||||
|
}
|
||||||
|
|
||||||
|
//// pbWriteToNonVolatileBmsMemory
|
||||||
|
void ConfigurationPage::onPbWriteToNonVolatileBmsMemoryClicked()
|
||||||
|
{
|
||||||
|
// Записать в энергонезависимую\nпамять BMS
|
||||||
|
// actionStoreBMScconf
|
||||||
|
mDieBieMS->commands()->storeBMSConfig();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
void ConfigurationPage::onBmsconfUpdatedOrStored()
|
||||||
|
{
|
||||||
|
mIsOperationFinished = true;
|
||||||
|
//onFinishPercents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::initTimerForStatusBar()
|
||||||
|
{
|
||||||
|
mTimer = new QTimer(this);
|
||||||
|
connect(mTimer, &QTimer::timeout, this, &ConfigurationPage::onTimerSlot);
|
||||||
|
mTimer->start(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::initTimerForProgressBar()
|
||||||
|
{
|
||||||
|
mTimerProgress = new QTimer(this);
|
||||||
|
mTimerProgress->setSingleShot(false);
|
||||||
|
mTimerProgress->setInterval(100);
|
||||||
|
connect(mTimerProgress, &QTimer::timeout, this, &ConfigurationPage::processPercents);
|
||||||
|
// timer->start(1000);
|
||||||
|
ui->progressBar->setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::initTimerForOneSecondDelayAfterButtonClick()
|
||||||
|
{
|
||||||
|
mOneSecondWait = new QTimer(this);
|
||||||
|
mOneSecondWait->setSingleShot(true);
|
||||||
|
mOneSecondWait->setInterval(10000);
|
||||||
|
connect(mOneSecondWait, &QTimer::timeout, this, [this]()
|
||||||
|
{
|
||||||
|
mIsOneSedondPassed = true;
|
||||||
|
});
|
||||||
|
mIsOneSedondPassed = true;
|
||||||
|
mIsOperationFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::processPercents()
|
||||||
|
{
|
||||||
|
mSeconds++;
|
||||||
|
int percents = mSeconds * (100.0 / mMaxSecs);
|
||||||
|
ui->progressBar->setValue(percents);
|
||||||
|
|
||||||
|
auto val = ui->progressBar->value();
|
||||||
|
if (val >= 0 && val < 50)
|
||||||
|
{
|
||||||
|
ui->progressBar->setStyleSheet("QProgressBar::chunk { background-color:lime; };");
|
||||||
|
}
|
||||||
|
else if (val >= 50 && val < 85)
|
||||||
|
{
|
||||||
|
if(mIsOperationFinished)
|
||||||
|
{
|
||||||
|
mIsOneSedondPassed = true;
|
||||||
|
mIsOperationFinished = true;
|
||||||
|
|
||||||
|
onStopPercents();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->progressBar->setStyleSheet("QProgressBar::chunk { background-color:yellow; };");
|
||||||
|
}
|
||||||
|
else if (val >= 85 && val < 95)
|
||||||
|
{
|
||||||
|
ui->progressBar->setStyleSheet("QProgressBar::chunk { background-color:red; };");
|
||||||
|
}
|
||||||
|
else if (val >= 95)
|
||||||
|
{
|
||||||
|
ui->progressBar->setStyleSheet("QProgressBar::chunk { background-color:red; };");
|
||||||
|
mIsOneSedondPassed = true;
|
||||||
|
mIsOperationFinished = true;
|
||||||
|
|
||||||
|
onStopPercents();
|
||||||
|
showStatusInfo("ERROR! SOMETHING WENT WRONG", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (ui->progressBar->value() == 100)
|
||||||
|
// onFinishPercents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::onStartPercents()
|
||||||
|
{
|
||||||
|
onStopPercents();
|
||||||
|
mTimerProgress->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::onStopPercents()
|
||||||
|
{
|
||||||
|
mSeconds = 0;
|
||||||
|
mTimerProgress->stop();
|
||||||
|
ui->progressBar->setValue(0);
|
||||||
|
|
||||||
|
//mIsOneSedondPassed = true;
|
||||||
|
//mIsOperationFinished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationPage::onFinishPercents()
|
||||||
|
{
|
||||||
|
mTimerProgress->stop();
|
||||||
|
mSeconds = 0;
|
||||||
|
ui->progressBar->setValue(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
119
configurationpage.h
Normal file
119
configurationpage.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#ifndef CONFIGURATIONPAGE_H
|
||||||
|
#define CONFIGURATIONPAGE_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
#include "debugprintpage.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ConfigurationPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigurationPage : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConfigurationPage(QWidget *parent = nullptr);
|
||||||
|
~ConfigurationPage();
|
||||||
|
|
||||||
|
enum ElementsPixelsPositions {
|
||||||
|
PosSerialNumber = 0
|
||||||
|
,PosConfiguration = 240
|
||||||
|
,PosSoc = 490
|
||||||
|
,PosRestrictions = 770
|
||||||
|
,PosCellsConfiguration = 1150
|
||||||
|
,PosBalancingConfiguration = 1580
|
||||||
|
,PosOutputsSetting = 1860
|
||||||
|
,PosClaibrateZero = 2840
|
||||||
|
};
|
||||||
|
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
void setDebugPrintPage(DebugPrintPage *page) {
|
||||||
|
mPageDebugPrint = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loadParams();
|
||||||
|
void sendMessage(QString message);
|
||||||
|
|
||||||
|
void showMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText);
|
||||||
|
|
||||||
|
//void sigBmsconfUpdateRequested();
|
||||||
|
//void sigBmsconfUpdateRequestDefault();
|
||||||
|
//void sigBmsconfUpdated();
|
||||||
|
//void sigBmsconfStored();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void showStatusInfo(QString info, bool isGood);
|
||||||
|
void onTimerSlot();
|
||||||
|
|
||||||
|
void onBmsconfUpdatedOrStored();
|
||||||
|
|
||||||
|
void onPbReadDefaultSettingsFromFileClicked();
|
||||||
|
void onPbReadCurrentSettingsFromBmsClicked();
|
||||||
|
void onPbWriteCurrentValuesToBmsClicked();
|
||||||
|
void onPbWriteToNonVolatileBmsMemoryClicked();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
//void on_pbLoadSettingsFromFile_clicked();
|
||||||
|
//void on_pbLoadCurrentSettingsFromBms_clicked();
|
||||||
|
void on_pbWriteToNonVolatileBmsMemory_clicked();
|
||||||
|
//void on_pbWriteCurrentValuesToBms_clicked();
|
||||||
|
|
||||||
|
//void bmsconfUpdated();
|
||||||
|
|
||||||
|
void on_pbReadDefaultSettingsFromFile_clicked();
|
||||||
|
|
||||||
|
void on_pbReadCurrentSettingsFromBms_clicked();
|
||||||
|
|
||||||
|
void on_pbWriteCurrentValuesToBms_clicked();
|
||||||
|
*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::ConfigurationPage *ui;
|
||||||
|
|
||||||
|
BMSInterface *mDieBieMS;
|
||||||
|
|
||||||
|
DebugPrintPage *mPageDebugPrint;
|
||||||
|
|
||||||
|
void initTimerForStatusBar();
|
||||||
|
void initTimerForProgressBar();
|
||||||
|
void initTimerForOneSecondDelayAfterButtonClick();
|
||||||
|
|
||||||
|
void onStartPercents();
|
||||||
|
void onStopPercents();
|
||||||
|
void onFinishPercents();
|
||||||
|
|
||||||
|
void processPercents();
|
||||||
|
double mSeconds = 0;
|
||||||
|
const double mMaxSecs = 200;
|
||||||
|
QTimer *mTimer;
|
||||||
|
int mStatusInfoTime = 0;
|
||||||
|
QTimer *mTimerProgress;
|
||||||
|
QTimer *mOneSecondWait;
|
||||||
|
bool mIsOneSedondPassed = true;
|
||||||
|
bool mIsOperationFinished = true;
|
||||||
|
|
||||||
|
void setPositionInPixelsToScrollTo(int positionInPixelsToScrollTo);
|
||||||
|
void checkIfButtonTextFitsInButton();
|
||||||
|
|
||||||
|
/*
|
||||||
|
DebugPrintPage *mPageDebugPrint;
|
||||||
|
|
||||||
|
QTimer *mTimer;
|
||||||
|
int mStatusInfoTime;
|
||||||
|
|
||||||
|
bool mMcConfRead = false;
|
||||||
|
|
||||||
|
void setPositionInPixelsToScrollTo(int positionInPixelsToScrollTo);
|
||||||
|
void checkIfButtonTextFitsInButton();
|
||||||
|
*/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONFIGURATIONPAGE_H
|
||||||
707
configurationpage.ui
Normal file
707
configurationpage.ui
Normal file
@@ -0,0 +1,707 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigurationPage</class>
|
||||||
|
<widget class="QFrame" name="ConfigurationPage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1084</width>
|
||||||
|
<height>755</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">/* background-color: #f7f8fc;*/
|
||||||
|
|
||||||
|
QScrollArea#scrollAreaBmsSettings, #bmsSettings
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc; /*COLOR OF THE LEFT PART WITH GROUPBOXES*/
|
||||||
|
}
|
||||||
|
QScrollArea#scrollAreaBmsSettings, #bmsSettings
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc; /*COLOR OF THE RIGHT PART WITH BUTTONS*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QLabel#lbIconLogo
|
||||||
|
{
|
||||||
|
/*background-image: url(:/images/cubo-verde-logo.png);*/
|
||||||
|
border-image: url(:/res/cubo-verde-logo-white.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#lbHeaderLanguageIcon
|
||||||
|
{
|
||||||
|
/*background-image: url(:/images/cubo-verde-logo.png);*/
|
||||||
|
border-image: url(:/res/language-russ.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbMainMenuBarHideMenu,
|
||||||
|
#pbMainMenuBarAkbMonitor,
|
||||||
|
#pbMainMenuBarCellsMonitor,
|
||||||
|
#pbMainMenuBarConfiguration,
|
||||||
|
#pbMainMenuBarVisualization,
|
||||||
|
#pbMainMenuBarHistory,
|
||||||
|
#pbMainMenuBarSeriveOfBms,
|
||||||
|
#pbMainMenuBarExit
|
||||||
|
{
|
||||||
|
color: #FFFFFF;
|
||||||
|
background-color: #009352;
|
||||||
|
border: 0px solid black;
|
||||||
|
background:#009352;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 85px;
|
||||||
|
font-size:17px;
|
||||||
|
}
|
||||||
|
QPushButton#pbMainMenuBarHideMenu
|
||||||
|
{
|
||||||
|
font-size:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbMainMenuBarHideMenu:hover,
|
||||||
|
#pbMainMenuBarAkbMonitor:hover,
|
||||||
|
#pbMainMenuBarCellsMonitor:hover,
|
||||||
|
#pbMainMenuBarConfiguration:hover,
|
||||||
|
#pbMainMenuBarVisualization:hover,
|
||||||
|
#pbMainMenuBarHistory:hover,
|
||||||
|
#pbMainMenuBarSeriveOfBms:hover,
|
||||||
|
#pbMainMenuBarExit:hover
|
||||||
|
{
|
||||||
|
background-color: #01673a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------*/
|
||||||
|
|
||||||
|
QPushButton#pbConnect,
|
||||||
|
#pbWriteCurrentValuesToBms,
|
||||||
|
#pbReadDefaultSettingsFromFile,
|
||||||
|
#pbReadCurrentSettingsFromBms
|
||||||
|
{
|
||||||
|
color:black;
|
||||||
|
background-color: #f7f8fc; /* white;*/
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 14px;
|
||||||
|
border-color: #009352;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbConnect:hover:pressed,
|
||||||
|
#pbWriteCurrentValuesToBms:hover:pressed,
|
||||||
|
#pbReadDefaultSettingsFromFile:hover:pressed,
|
||||||
|
#pbReadCurrentSettingsFromBms:hover:pressed
|
||||||
|
{
|
||||||
|
background-color:lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbConnect:hover:!pressed,
|
||||||
|
#pbWriteCurrentValuesToBms:hover:!pressed,
|
||||||
|
#pbReadDefaultSettingsFromFile:hover:!pressed,
|
||||||
|
#pbReadCurrentSettingsFromBms:hover:!pressed
|
||||||
|
{
|
||||||
|
/* background-color: #0FF73a;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*pbWriteCurrentValuesToBms*/
|
||||||
|
QPushButton#pbWriteToNonVolatileBmsMemory
|
||||||
|
{
|
||||||
|
background-color:#009352;
|
||||||
|
color:white;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 14px;
|
||||||
|
border-color: #009352;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbWriteToNonVolatileBmsMemory:hover:pressed
|
||||||
|
{
|
||||||
|
background-color:#01673a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbWriteToNonVolatileBmsMemory:hover:!pressed
|
||||||
|
{
|
||||||
|
/* background-color: #01673a;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbLinkSerialNumber,
|
||||||
|
#pbLinkSoc,
|
||||||
|
#pbLinkRestrictions,
|
||||||
|
#pbLinkClaibrateZero,
|
||||||
|
#pbLinkCellsConfiguration,
|
||||||
|
#pbLinkOutputsSetting,
|
||||||
|
#pbLinkBalancingConfiguration,
|
||||||
|
#pbLinkConfiguration
|
||||||
|
{
|
||||||
|
color:#009352;
|
||||||
|
text-decoration: none;
|
||||||
|
background: transparent;
|
||||||
|
border-color:transparent;
|
||||||
|
text-align:left;
|
||||||
|
border-radius: 1px;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbLinkSerialNumber:hover:!pressed,
|
||||||
|
#pbLinkSoc:hover:!pressed,
|
||||||
|
#pbLinkRestrictions:hover:!pressed,
|
||||||
|
#pbLinkClaibrateZero:hover:!pressed,
|
||||||
|
#pbLinkCellsConfiguration:hover:!pressed,
|
||||||
|
#pbLinkOutputsSetting:hover:!pressed,
|
||||||
|
#pbLinkBalancingConfiguration:hover:!pressed,
|
||||||
|
#pbLinkConfiguration:hover:!pressed
|
||||||
|
{
|
||||||
|
/* text-decoration: underline;*/
|
||||||
|
color:#01673a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbLinkSerialNumber:hover:pressed,
|
||||||
|
#pbLinkSoc:hover:pressed,
|
||||||
|
#pbLinkRestrictions:hover:pressed,
|
||||||
|
#pbLinkClaibrateZero:hover:pressed,
|
||||||
|
#pbLinkCellsConfiguration:hover:pressed,
|
||||||
|
#pbLinkOutputsSetting:hover:pressed,
|
||||||
|
#pbLinkBalancingConfiguration:hover:pressed,
|
||||||
|
#pbLinkConfiguration:hover:pressed
|
||||||
|
{
|
||||||
|
color:#0093FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QComboBox#cboxComConnections
|
||||||
|
{
|
||||||
|
background-color:white;
|
||||||
|
border-radius:10px;
|
||||||
|
border-color: lightgrey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------*/
|
||||||
|
|
||||||
|
QGroupBox#gbSerialNumber,
|
||||||
|
QGroupBox#gbConfiguration,
|
||||||
|
QGroupBox#gbSoc,
|
||||||
|
QGroupBox#gbRestrictions,
|
||||||
|
QGroupBox#gbCellsConfiguration,
|
||||||
|
QGroupBox#gbBalancingConfiguration,
|
||||||
|
QGroupBox#gbOutputsSettings,
|
||||||
|
QGroupBox#gbZeroPoint {
|
||||||
|
background-color:white;
|
||||||
|
border-radius:10px;
|
||||||
|
border-color: lightgrey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------*/
|
||||||
|
|
||||||
|
QScrollBar {
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #e8e9f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::vertical {
|
||||||
|
width: 10px;
|
||||||
|
margin: 0px 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------*/
|
||||||
|
QScrollBar::sub-page:horizontal {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-left-radius: 9px;
|
||||||
|
border-bottom-left-radius: 9px;
|
||||||
|
}
|
||||||
|
QScrollBar::add-page:horizontal {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-right-radius: 9px;
|
||||||
|
border-bottom-right-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::sub-page:vertical {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-left-radius: 9px;
|
||||||
|
border-top-right-radius: 9px;
|
||||||
|
}
|
||||||
|
QScrollBar::add-page:vertical {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-bottom-left-radius: 9px;
|
||||||
|
border-bottom-right-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------*/
|
||||||
|
QScrollBar::up-arrow,
|
||||||
|
QScrollBar::sub-line,
|
||||||
|
QScrollBar::add-line {
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::handle {
|
||||||
|
background: #009352;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="lbIconLogo">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>80</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>111</width>
|
||||||
|
<height>111</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::NoContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderLanguageIcon">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1300</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>31</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:#0A72BA;
|
||||||
|
font-weight:bold;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkSerialNumber">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>100</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Серийный номер</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkConfiguration">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>140</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Конфигурация</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkSoc">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>180</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>SOC</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkRestrictions">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>220</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Ограничения</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkCellsConfiguration">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>260</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Конфигурация ячеек</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkBalancingConfiguration">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>300</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Конфигурация балансировки</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkOutputsSetting">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>340</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Настройка выходов</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbLinkClaibrateZero">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>380</y>
|
||||||
|
<width>261</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
<underline>true</underline>
|
||||||
|
<strikeout>false</strikeout>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Значение датчика точка "0"</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbReadDefaultSettingsFromFile">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>440</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Загрузить настройки
|
||||||
|
по умолчанию</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbReadCurrentSettingsFromBms">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>500</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Загрузить текущие настройки
|
||||||
|
из BMS</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbWriteCurrentValuesToBms">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>560</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Записать текущие значения в BMS</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="pbWriteToNonVolatileBmsMemory">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>620</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Записать в энергонезависимую
|
||||||
|
память BMS</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QScrollArea" name="scrollAreaBmsSettings">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>731</width>
|
||||||
|
<height>753</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="BmsSettings" name="bmsSettings">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>729</width>
|
||||||
|
<height>751</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">/*#content
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* background-color: #f7f8fc;*/
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="hLayoutLeftAndRight">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbStatus">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>680</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>41</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>13</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: #e8e8e8</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>770</x>
|
||||||
|
<y>720</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>7</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QProgressBar::chunk { background-color:lime; };</string>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>24</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<zorder>lbIconLogo</zorder>
|
||||||
|
<zorder>scrollAreaBmsSettings</zorder>
|
||||||
|
<zorder>pbLinkSerialNumber</zorder>
|
||||||
|
<zorder>pbReadDefaultSettingsFromFile</zorder>
|
||||||
|
<zorder>pbReadCurrentSettingsFromBms</zorder>
|
||||||
|
<zorder>pbLinkSoc</zorder>
|
||||||
|
<zorder>pbLinkRestrictions</zorder>
|
||||||
|
<zorder>pbLinkClaibrateZero</zorder>
|
||||||
|
<zorder>pbWriteCurrentValuesToBms</zorder>
|
||||||
|
<zorder>pbLinkCellsConfiguration</zorder>
|
||||||
|
<zorder>pbLinkOutputsSetting</zorder>
|
||||||
|
<zorder>pbLinkBalancingConfiguration</zorder>
|
||||||
|
<zorder>pbWriteToNonVolatileBmsMemory</zorder>
|
||||||
|
<zorder>lbHeaderLanguageIcon</zorder>
|
||||||
|
<zorder>pbLinkConfiguration</zorder>
|
||||||
|
<zorder>lbStatus</zorder>
|
||||||
|
<zorder>progressBar</zorder>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>BmsSettings</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">bmssettings.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
384
connectandenterpage.cpp
Normal file
384
connectandenterpage.cpp
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
#include "connectandenterpage.h"
|
||||||
|
#include "ui_connectandenterpage.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "widgets/paramdialog.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QAbstractItemView>
|
||||||
|
#include <QListView>
|
||||||
|
|
||||||
|
ConnectAndEnterPage::ConnectAndEnterPage(QWidget *parent)
|
||||||
|
: QWidget(parent),
|
||||||
|
// QDialog(parent),
|
||||||
|
ui(new Ui::ConnectAndEnterPage),
|
||||||
|
mDieBieMS(nullptr),
|
||||||
|
mIsConnected(false)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
on_pbSerialRefresh_clicked();
|
||||||
|
|
||||||
|
ui->lbIconLogo->show();
|
||||||
|
|
||||||
|
// hide buttons: HIDE - EXPAND - CLOSE
|
||||||
|
//setWindowFlags(Qt::CustomizeWindowHint);
|
||||||
|
connect(ui->cboxSerialPort, &HoverableComboBox::opened, this, &ConnectAndEnterPage::onComboBoxSerialPortOpened);
|
||||||
|
connect(ui->cboxSerialPort, &HoverableComboBox::closed, this, &ConnectAndEnterPage::onComboBoxSerialPortClosed);
|
||||||
|
|
||||||
|
ui->cboxSerialPort->setView(new QListView());
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectAndEnterPage::~ConnectAndEnterPage()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::prepareWindowBeforeShow()
|
||||||
|
{
|
||||||
|
ui->lbStatus->setStyleSheet("QLabel { background-color : white; color : white; }");
|
||||||
|
ui->lbStatus->clear();
|
||||||
|
|
||||||
|
mIsConnected = false;
|
||||||
|
if(mDieBieMS) {
|
||||||
|
//if(mDieBieMS->isPortConnected())
|
||||||
|
mDieBieMS->disconnectPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
on_pbSerialRefresh_clicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool ConnectAndEnterPage::isConnectionPrepared()
|
||||||
|
{
|
||||||
|
// return true;
|
||||||
|
return mIsConnected;
|
||||||
|
}
|
||||||
|
QString ConnectAndEnterPage::portToConnect()
|
||||||
|
{
|
||||||
|
return ui->cboxSerialPort->currentText();
|
||||||
|
}
|
||||||
|
void ConnectAndEnterPage::clearPortToConnect()
|
||||||
|
{
|
||||||
|
ui->cboxSerialPort->clear();
|
||||||
|
}
|
||||||
|
//*
|
||||||
|
void ConnectAndEnterPage::initDieBieMS(BMSInterface* dieBieBms)
|
||||||
|
{
|
||||||
|
// mVersion = QString::number(DT_VERSION);
|
||||||
|
//mDieBieMS = new BMSInterface(this);
|
||||||
|
mDieBieMS = dieBieBms;
|
||||||
|
|
||||||
|
mStatusInfoTime = 0;
|
||||||
|
// mStatusLabel = new QLabel(this);
|
||||||
|
// ui->lbStatusBar = (mStatusLabel);
|
||||||
|
|
||||||
|
// mTimer = new QTimer(this);
|
||||||
|
mKeyLeft = false;
|
||||||
|
mKeyRight = false;
|
||||||
|
mMcConfRead = false;
|
||||||
|
|
||||||
|
// SEND_STATUS_INFO //
|
||||||
|
connect(mDieBieMS, &BMSInterface::statusMessage, this, &ConnectAndEnterPage::showStatusInfo);
|
||||||
|
connect(mDieBieMS, &BMSInterface::messageDialog, this, &ConnectAndEnterPage::showMessageDialog);
|
||||||
|
connect(mDieBieMS, &BMSInterface::serialPortNotWritable, this, &ConnectAndEnterPage::serialPortNotWritable);
|
||||||
|
connect(mDieBieMS->commands(), &Commands::bmsConfigCheckResult, this, &ConnectAndEnterPage::bmsConfigCheckResult);
|
||||||
|
// connect(ui->actionAboutQt, SIGNAL(triggered(bool)),qApp, SLOT(aboutQt()));
|
||||||
|
// connect(mTimer, SIGNAL(timeout()),this, SLOT(timerSlot()));
|
||||||
|
|
||||||
|
// Remove the menu with the option to hide the toolbar
|
||||||
|
// ui->mainToolBar->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||||
|
|
||||||
|
mDieBieMS->bmsConfig()->loadParamsXml("://res/config.xml");
|
||||||
|
mDieBieMS->infoConfig()->loadParamsXml("://res/info.xml");
|
||||||
|
// reloadPages();
|
||||||
|
|
||||||
|
connect(mDieBieMS->bmsConfig(), SIGNAL(updated()), this, SLOT(bmsconfUpdated()));
|
||||||
|
|
||||||
|
on_pbSerialRefresh_clicked();
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::setDebugPrintPage(DebugPrintPage *page)
|
||||||
|
{
|
||||||
|
mPageDebugPrint = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::showStatusInfo(QString info, bool isGood)
|
||||||
|
{
|
||||||
|
if (isGood) {
|
||||||
|
ui->lbStatus->setStyleSheet("QLabel { background-color : lightgreen; color : black; }");
|
||||||
|
mPageDebugPrint->printConsole("Status: " + info + "<br>");
|
||||||
|
} else {
|
||||||
|
ui->lbStatus->setStyleSheet("QLabel { background-color : red; color : black; }");
|
||||||
|
mPageDebugPrint->printConsole("<font color=\"red\">Status: " + info + "</font><br>");
|
||||||
|
}
|
||||||
|
|
||||||
|
mStatusInfoTime = 80;
|
||||||
|
ui->lbStatus->setText(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectAndEnterPage::waitProcess(QProcess &process, bool block, int timeoutMs)
|
||||||
|
{
|
||||||
|
bool wasEnables = isEnabled();
|
||||||
|
bool killed = false;
|
||||||
|
|
||||||
|
if (block) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.waitForStarted();
|
||||||
|
|
||||||
|
QEventLoop loop;
|
||||||
|
QTimer timeoutTimer;
|
||||||
|
timeoutTimer.setSingleShot(true);
|
||||||
|
timeoutTimer.start(timeoutMs);
|
||||||
|
connect(&process, SIGNAL(finished(int)), &loop, SLOT(quit()));
|
||||||
|
connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||||
|
loop.exec();
|
||||||
|
|
||||||
|
if (process.state() == QProcess::Running) {
|
||||||
|
process.kill();
|
||||||
|
process.waitForFinished();
|
||||||
|
killed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEnabled(wasEnables);
|
||||||
|
|
||||||
|
return !killed;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ConnectAndEnterPage::runCmd(QString cmd, QStringList args)
|
||||||
|
{
|
||||||
|
QProcess process;
|
||||||
|
process.setEnvironment(QProcess::systemEnvironment());
|
||||||
|
process.start(cmd, args);
|
||||||
|
waitProcess(process);
|
||||||
|
QString res = process.readAllStandardOutput();
|
||||||
|
process.close();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::serialPortNotWritable(const QString &port)
|
||||||
|
{
|
||||||
|
(void)port;
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QMessageBox::StandardButton reply;
|
||||||
|
reply = QMessageBox::warning(this, tr("Connect Serial Port"),
|
||||||
|
tr("The serial port is not writable. This can usually be fixed by "
|
||||||
|
"adding your user to the dialout, uucp and/or lock groups. Would "
|
||||||
|
"you like to do that?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
QString name = qgetenv("USER");
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = qgetenv("USERNAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasDialout = !runCmd("getent",
|
||||||
|
QStringList() << "group"
|
||||||
|
<< "dialout")
|
||||||
|
.isEmpty();
|
||||||
|
bool hasUucp = !runCmd("getent",
|
||||||
|
QStringList() << "group"
|
||||||
|
<< "uucp")
|
||||||
|
.isEmpty();
|
||||||
|
bool hasLock = !runCmd("getent",
|
||||||
|
QStringList() << "group"
|
||||||
|
<< "lock")
|
||||||
|
.isEmpty();
|
||||||
|
|
||||||
|
QString grps;
|
||||||
|
if (hasDialout) {
|
||||||
|
grps += "dialout";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasUucp) {
|
||||||
|
if (!grps.isEmpty()) {
|
||||||
|
grps += ",";
|
||||||
|
}
|
||||||
|
grps += "uucp";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLock) {
|
||||||
|
if (!grps.isEmpty()) {
|
||||||
|
grps += ",";
|
||||||
|
}
|
||||||
|
grps += "lock";
|
||||||
|
}
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
process.setEnvironment(QProcess::systemEnvironment());
|
||||||
|
process.start("pkexec",
|
||||||
|
QStringList() << "usermod"
|
||||||
|
<< "-aG" << grps << name);
|
||||||
|
waitProcess(process);
|
||||||
|
if (process.exitCode() == 0) {
|
||||||
|
showMessageDialog(tr("Command Result"),
|
||||||
|
tr("Result from command:\n\n"
|
||||||
|
"%1\n"
|
||||||
|
"You have to reboot for this "
|
||||||
|
"change to take effect.")
|
||||||
|
.arg(QString(process.readAllStandardOutput())),
|
||||||
|
true, false);
|
||||||
|
} else {
|
||||||
|
showMessageDialog(tr("Command Result"), tr("Running command failed."), false, false);
|
||||||
|
}
|
||||||
|
process.close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::bmsconfUpdated()
|
||||||
|
{
|
||||||
|
mMcConfRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::bmsConfigCheckResult(QStringList paramsNotSet)
|
||||||
|
{
|
||||||
|
if (!paramsNotSet.isEmpty()) {
|
||||||
|
ParamDialog::showParams(tr("Parameters truncated"),
|
||||||
|
tr("The following parameters were truncated because they were set outside "
|
||||||
|
"of their allowed limits."),
|
||||||
|
mDieBieMS->bmsConfig(), paramsNotSet, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::showMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText)
|
||||||
|
{
|
||||||
|
(void)richText;
|
||||||
|
|
||||||
|
mIsConnected = isGood;
|
||||||
|
if (isGood) {
|
||||||
|
QMessageBox::information(this, title, msg);
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(this, title, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit sigConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
BMSInterface *ConnectAndEnterPage::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::setDieBieMSEx(BMSInterface *dieBieMS)
|
||||||
|
{
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
|
||||||
|
connect(mDieBieMS->bleDevice(), SIGNAL(scanDone(QVariantMap, bool)), this, SLOT(bleScanDone(QVariantMap, bool)));
|
||||||
|
|
||||||
|
QString lastBleAddr = QSettings().value("ble_addr").toString();
|
||||||
|
if (lastBleAddr != "") {
|
||||||
|
QString setName = mDieBieMS->getBleName(lastBleAddr);
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
if (!setName.isEmpty()) {
|
||||||
|
name += setName;
|
||||||
|
name += " [";
|
||||||
|
name += lastBleAddr;
|
||||||
|
name += "]";
|
||||||
|
} else {
|
||||||
|
name = lastBleAddr;
|
||||||
|
}
|
||||||
|
// ui->bleDevBox->insertItem(0, name, lastBleAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
on_pbSerialRefresh_clicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::on_pbSerialRefresh_clicked()
|
||||||
|
{
|
||||||
|
ui->pbSerialRefresh->setChecked(false);
|
||||||
|
|
||||||
|
if (mDieBieMS) {
|
||||||
|
ui->cboxSerialPort->clear();
|
||||||
|
QList<VSerialInfo_t> ports = mDieBieMS->listSerialPorts();
|
||||||
|
foreach (const VSerialInfo_t &port, ports) {
|
||||||
|
ui->cboxSerialPort->addItem(port.name, port.systemPath);
|
||||||
|
}
|
||||||
|
ui->cboxSerialPort->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::on_pbConnect_clicked()
|
||||||
|
{
|
||||||
|
// Big Connect Button on Wellcome page
|
||||||
|
// Utility::autoconnectBlockingWithProgress(mDieBieMS, this);
|
||||||
|
|
||||||
|
// Simple Connect Button on Connection Page
|
||||||
|
mIsConnected = false;
|
||||||
|
if (mDieBieMS) {
|
||||||
|
mIsConnected = mDieBieMS->connectSerial(ui->cboxSerialPort->currentData().toString(),
|
||||||
|
SERIAL_BAUD_DEFAULT_VAL // ui->spinboxSerialPort->value()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mIsConnected)
|
||||||
|
emit sigConnected();
|
||||||
|
//*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::on_pbExit_clicked()
|
||||||
|
{
|
||||||
|
if(mDieBieMS)
|
||||||
|
mDieBieMS->disconnectPort();
|
||||||
|
//mDieBieMS->tcpInputDisconnected();
|
||||||
|
|
||||||
|
mIsConnected = false;
|
||||||
|
clearPortToConnect();
|
||||||
|
|
||||||
|
emit sigReject();
|
||||||
|
//close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::onComboBoxSerialPortOpened()
|
||||||
|
{
|
||||||
|
//ui->pbSerialRefresh->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::onComboBoxSerialPortClosed()
|
||||||
|
{
|
||||||
|
//ui->pbSerialRefresh->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::on_gbWindow_clicked()
|
||||||
|
{
|
||||||
|
int a = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectAndEnterPage::on_gbHeader_clicked()
|
||||||
|
{
|
||||||
|
int a = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void ConnectAndEnterPage::ShowContextMenu(const QPoint &pos)
|
||||||
|
{
|
||||||
|
QMenu contextMenu(tr("Context menu"), this);
|
||||||
|
|
||||||
|
QAction action1("Remove Data Point", this);
|
||||||
|
connect(&action1, SIGNAL(triggered()), this, SLOT(removeDataPoint()));
|
||||||
|
contextMenu.addAction(&action1);
|
||||||
|
|
||||||
|
contextMenu.exec(mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void ConnectAndEnterPage::on_pbLanguage_clicked()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
94
connectandenterpage.h
Normal file
94
connectandenterpage.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#ifndef CONNECTANDENTERPAGE_H
|
||||||
|
#define CONNECTANDENTERPAGE_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
|
||||||
|
#include "debugprintpage.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ConnectAndEnterPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
//class ConnectAndEnterPage : public QDialog
|
||||||
|
class ConnectAndEnterPage : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConnectAndEnterPage(QWidget *parent = nullptr);
|
||||||
|
~ConnectAndEnterPage();
|
||||||
|
|
||||||
|
void initDieBieMS(BMSInterface *);
|
||||||
|
|
||||||
|
void prepareWindowBeforeShow();
|
||||||
|
|
||||||
|
bool isConnectionPrepared();
|
||||||
|
QString portToConnect();
|
||||||
|
|
||||||
|
static const int SERIAL_BAUD_DEFAULT_VAL = 115200;
|
||||||
|
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
void setDieBieMSEx(BMSInterface *dieBieMS);
|
||||||
|
void setDebugPrintPage(DebugPrintPage *page);
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sigConnected();
|
||||||
|
void sigReject();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_pbExit_clicked();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void showStatusInfo(QString info, bool isGood);
|
||||||
|
void showMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText);
|
||||||
|
void serialPortNotWritable(const QString &port);
|
||||||
|
void bmsconfUpdated();
|
||||||
|
void bmsConfigCheckResult(QStringList paramsNotSet);
|
||||||
|
|
||||||
|
void on_pbConnect_clicked();
|
||||||
|
void on_pbSerialRefresh_clicked();
|
||||||
|
|
||||||
|
void onComboBoxSerialPortOpened();
|
||||||
|
void onComboBoxSerialPortClosed();
|
||||||
|
|
||||||
|
void on_gbWindow_clicked();
|
||||||
|
|
||||||
|
void on_gbHeader_clicked();
|
||||||
|
|
||||||
|
void on_pbLanguage_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::ConnectAndEnterPage *ui;
|
||||||
|
BMSInterface * mDieBieMS;
|
||||||
|
bool mIsConnected;
|
||||||
|
// QString mPortForConnection;
|
||||||
|
|
||||||
|
// QLabel *mStatusLabel;
|
||||||
|
DebugPrintPage *mPageDebugPrint;
|
||||||
|
|
||||||
|
|
||||||
|
int mStatusInfoTime;
|
||||||
|
bool mKeyLeft;
|
||||||
|
bool mKeyRight;
|
||||||
|
bool mMcConfRead;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool waitProcess(QProcess &process, bool block = true, int timeoutMs = 300000);
|
||||||
|
QString runCmd(QString cmd, QStringList args);
|
||||||
|
|
||||||
|
void clearPortToConnect();
|
||||||
|
|
||||||
|
void ShowContextMenu(const QPoint &pos);
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONNECTANDENTERPAGE_H
|
||||||
733
connectandenterpage.ui
Normal file
733
connectandenterpage.ui
Normal file
@@ -0,0 +1,733 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConnectAndEnterPage</class>
|
||||||
|
<widget class="QWidget" name="ConnectAndEnterPage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1366</width>
|
||||||
|
<height>738</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">/*#ConnectAndEnterPage
|
||||||
|
{
|
||||||
|
background-color:#F7F8FC;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
QLabel { font-family:"Artifakt Element"; }
|
||||||
|
QPushButton { font-family:"Artifakt Element"; }
|
||||||
|
QComboBox { font-family:"Artifakt Element"; }
|
||||||
|
|
||||||
|
QLabel#lbIconLogo
|
||||||
|
{
|
||||||
|
/*background-image: url(:/images/cubo-verde-logo.png);*/
|
||||||
|
border-image: url(:/res/cubo-verde-logo-green.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#lbHeaderLanguageIcon
|
||||||
|
{
|
||||||
|
/*background-image: url(:/images/cubo-verde-logo.png);*/
|
||||||
|
border-image: url(:/res/language-russ.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#lbChooseComPort
|
||||||
|
{
|
||||||
|
font-weight: bold;
|
||||||
|
/*font-family: "DejaVu Sans";*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
QComboBox#cboxComConnections
|
||||||
|
{
|
||||||
|
background-color:white;
|
||||||
|
border-radius:10px;
|
||||||
|
border-color: lightgrey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QGroupBox" name="gbWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>637</width>
|
||||||
|
<height>433</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>637</width>
|
||||||
|
<height>433</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>637</width>
|
||||||
|
<height>433</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QGroupBox#gbWindow
|
||||||
|
{
|
||||||
|
background-color:white;
|
||||||
|
border-radius:10px;
|
||||||
|
border-color: lightgrey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="gbHeader">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>71</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QGroupBox#gbHeader
|
||||||
|
{
|
||||||
|
background-color:white;
|
||||||
|
border-top-left-radius:10px;
|
||||||
|
border-top-right-radius:10px;
|
||||||
|
border-bottom-left-radius:0px;
|
||||||
|
border-bottom-right-radius:0px;
|
||||||
|
border-color: lightgrey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
margin-left: -1px;
|
||||||
|
margin-right: -1px;
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>140</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lbIconLogo">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>50</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>50</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::NoContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="midLineWidth">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="res.qrc">:/res/cubo-verde-logo-green.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>215</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="LanguageSelectorButton" name="pbLanguage">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Artifakt Element</family>
|
||||||
|
<pointsize>-1</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::RightToLeft</enum>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">
|
||||||
|
|
||||||
|
color:#0A72BA;
|
||||||
|
background-color:#ffffff;
|
||||||
|
border-color: #ffffff;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 7px;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 16px;
|
||||||
|
/* font-family: "Times New Roman";*/
|
||||||
|
/*font-family: "Artifakt Element";*/
|
||||||
|
qproperty-icon: url(:/res/language-russ.png) 0 0 0 0 stretch stretch;
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Рус</string>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>27</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>150</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>150</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lbChooseComPort">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Artifakt Element</family>
|
||||||
|
<pointsize>24</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Выберите COM-порт</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="HoverableComboBox" name="cboxSerialPort">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>61</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Artifakt Element</family>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">
|
||||||
|
/*QComboBox QAbstractItemView::item
|
||||||
|
{
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
QListView::item
|
||||||
|
{
|
||||||
|
color:black;
|
||||||
|
height:50px;
|
||||||
|
padding-left:15px;
|
||||||
|
font-size:16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
QListView
|
||||||
|
{
|
||||||
|
color:black;
|
||||||
|
height:50px;
|
||||||
|
padding-left:15px;
|
||||||
|
font-size:16px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
QComboBox {
|
||||||
|
color:black;
|
||||||
|
border: 1px solid lightgray;
|
||||||
|
border-radius: 7px;
|
||||||
|
padding-left:15px;
|
||||||
|
/*padding: 1px 18px 1px 3px;*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
QComboBox {
|
||||||
|
color:gray;
|
||||||
|
border: 1px solid lightgray;
|
||||||
|
border-radius: 7px;
|
||||||
|
padding: 1px 18px 1px 3px;
|
||||||
|
min-width: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
QComboBox:editable {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*not opened*/
|
||||||
|
/*QComboBox:!editable, QComboBox::drop-down:editable {
|
||||||
|
background: white;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* QComboBox gets the "on" state when the popup is open */
|
||||||
|
/*QComboBox:!editable:on, QComboBox::drop-down:editable:on {
|
||||||
|
background: #CCE9DC;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* shift the text when the popup opens */
|
||||||
|
/*QComboBox:on {
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* QComboBox gets the "on" state when the popup is open */
|
||||||
|
QComboBox:!editable:on, QComboBox::drop-down:editable:on {
|
||||||
|
background: #CCE9DC;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shift the text when the popup opens */
|
||||||
|
/*QComboBox:on {
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*area around the /* V */
|
||||||
|
QComboBox::drop-down {
|
||||||
|
subcontrol-origin: padding;
|
||||||
|
subcontrol-position: top right;
|
||||||
|
width: 50px;
|
||||||
|
|
||||||
|
/*background: red;*/
|
||||||
|
|
||||||
|
/*border-left-width: 1px;
|
||||||
|
border-left-color: darkgray;
|
||||||
|
border-left-style: solid; /* just a single line */
|
||||||
|
border-top-right-radius: 3px; /* same radius as the QComboBox */
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
/*padding-right: 10px; /* V */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QComboBox QAbstractItemView {
|
||||||
|
/*no mouse over text*/
|
||||||
|
color: black;
|
||||||
|
/*no mouse over white*/
|
||||||
|
background-color: white;
|
||||||
|
/*mouse over text*/
|
||||||
|
selection-color: black;
|
||||||
|
/*mouse over blue*/
|
||||||
|
selection-background-color: #F0F1F4; /* blue */
|
||||||
|
/*selection-background-color: #FFF1F4; /* red */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QComboBox QAbstractItemView:pressed {
|
||||||
|
/*no mouse over text green*/
|
||||||
|
color: #CCE9DC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QComboBox::item:pressed {
|
||||||
|
/*pressed element text green*/
|
||||||
|
color: #CCE9DC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/*area around the /* V */
|
||||||
|
QComboBox::drop-down {
|
||||||
|
subcontrol-origin: padding;
|
||||||
|
subcontrol-position: top right;
|
||||||
|
width: 50px;
|
||||||
|
|
||||||
|
/*background: red;*/
|
||||||
|
|
||||||
|
/*border-left-width: 1px;
|
||||||
|
border-left-color: darkgray;
|
||||||
|
border-left-style: solid; /* just a single line */
|
||||||
|
border-top-right-radius: 3px; /* same radius as the QComboBox */
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
/*padding-right: 10px; /* V */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QComboBox::down-arrow {
|
||||||
|
image: url(:/res/cbox-arrow-down-black.png);
|
||||||
|
}
|
||||||
|
QComboBox::down-arrow:on { /*QComboBox::up-arrow {*/
|
||||||
|
image: url(:/res/cbox-arrow-up-green.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shift the arrow when popup is open */
|
||||||
|
/*QComboBox::down-arrow:on {
|
||||||
|
top: 1px;
|
||||||
|
left: 1px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
QComboBox QAbstractItemView {
|
||||||
|
/* color: black; /*rgb(85, 170, 255);*/
|
||||||
|
/* background-color: white; /* #373e4e;*/
|
||||||
|
/* padding: 10px;
|
||||||
|
selection-background-color: #CCE9DC; /*rgb(39, 44, 54);*/
|
||||||
|
|
||||||
|
/*selected green
|
||||||
|
background: #CCE9DC;
|
||||||
|
mouse over blue
|
||||||
|
background: #F0F1F4;
|
||||||
|
*/
|
||||||
|
/*}
|
||||||
|
|
||||||
|
/*
|
||||||
|
QGroupBox#gbSerialNumberLocal,
|
||||||
|
#gbBatteryModulesCellsAkbBmsParameters,
|
||||||
|
#gbCellMinMaxVoltageNumberAmperageParameters
|
||||||
|
{
|
||||||
|
background-color:white;
|
||||||
|
border-radius:10px;
|
||||||
|
border-color: lightgrey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="currentText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maxVisibleItems">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="modelColumn">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pbSerialRefresh">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>61</width>
|
||||||
|
<height>61</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>61</width>
|
||||||
|
<height>61</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">
|
||||||
|
QPushButton#pbSerialRefresh
|
||||||
|
{
|
||||||
|
color:white;
|
||||||
|
background-color:#FFFFFF;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 14px;
|
||||||
|
border-color: #009352;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 7px;
|
||||||
|
padding:15px;
|
||||||
|
image: url(:/res/icons/Restart-97-Black.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
QPushButton#pbSerialRefresh:hover:pressed
|
||||||
|
{
|
||||||
|
background-color:#009352;
|
||||||
|
border-color: #009352;
|
||||||
|
image: url(:/res/icons/Restart-97-White.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
QPushButton#pbSerialRefresh:checked
|
||||||
|
{
|
||||||
|
background-color:#009352;
|
||||||
|
border-color: #009352;
|
||||||
|
image: url(:/res/icons/Restart-97-White.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*background-color:#01673a;*/
|
||||||
|
/*QPushButton#pbSerialRefresh:hover:pressed
|
||||||
|
{
|
||||||
|
background-color:lightgrey;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pbConnect">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>281</width>
|
||||||
|
<height>61</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QPushButton#pbConnect
|
||||||
|
{
|
||||||
|
color:white;
|
||||||
|
background-color:#009352;
|
||||||
|
border-color: #009352;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 7px;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 16px;
|
||||||
|
/* font-family: "Times New Roman";*/
|
||||||
|
font-family: "Artifakt Element";
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbConnect:hover:pressed
|
||||||
|
{
|
||||||
|
background-color:#01673a;
|
||||||
|
}
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Подключиться</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pbExit">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>281</width>
|
||||||
|
<height>61</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QPushButton#pbExit
|
||||||
|
{
|
||||||
|
color:#000000;
|
||||||
|
background-color:#FFFFFF;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 16px;
|
||||||
|
border-color: #009352;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbExit:hover:pressed
|
||||||
|
{
|
||||||
|
/*background-color:#01673a;*/
|
||||||
|
background-color:lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Закрыть</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lbStatus">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Artifakt Element</family>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>HoverableComboBox</class>
|
||||||
|
<extends>QComboBox</extends>
|
||||||
|
<header location="global">hoverablecombobox.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>LanguageSelectorButton</class>
|
||||||
|
<extends>QPushButton</extends>
|
||||||
|
<header location="global">languageselectorbutton.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
76
customlefttabbarbutton.cpp
Normal file
76
customlefttabbarbutton.cpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include "customlefttabbarbutton.h"
|
||||||
|
|
||||||
|
CustomLeftTabBarButton::CustomLeftTabBarButton(QWidget* parent) : QPushButton(parent)
|
||||||
|
{
|
||||||
|
QIcon i = this->icon();
|
||||||
|
QPixmap p = i.pixmap(5, 5);
|
||||||
|
m_pixmap = this->icon().pixmap(this->icon().actualSize(QSize(5, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomLeftTabBarButton::~CustomLeftTabBarButton()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize CustomLeftTabBarButton::sizeHint() const
|
||||||
|
{
|
||||||
|
const auto parentHint = QPushButton::sizeHint();
|
||||||
|
// add margins here if needed
|
||||||
|
return QSize
|
||||||
|
(
|
||||||
|
parentHint.width() + m_pixmap.width() ,
|
||||||
|
std::max(parentHint.height(), m_pixmap.height())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomLeftTabBarButton::setPixmap(const QPixmap& pixmap)
|
||||||
|
{
|
||||||
|
m_pixmap = pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomLeftTabBarButton::setPos(const QSize& pos)
|
||||||
|
{
|
||||||
|
m_pixmapPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomLeftTabBarButton::setIconStringForButton(QString iconString)
|
||||||
|
{
|
||||||
|
QIcon i = QIcon(iconString); //":/res/lock-icon-closed.png");
|
||||||
|
int sz = 20;
|
||||||
|
QSize size (sz , sz);
|
||||||
|
//= iconSize();
|
||||||
|
i.actualSize(size);
|
||||||
|
QPixmap p = i.pixmap(sz);
|
||||||
|
m_pixmap = p;
|
||||||
|
this->setPixmap(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CustomLeftTabBarButton::paintEvent(QPaintEvent* e)
|
||||||
|
{
|
||||||
|
// Draw the button first
|
||||||
|
QPushButton::paintEvent(e);
|
||||||
|
|
||||||
|
if (!m_pixmap.isNull())
|
||||||
|
{
|
||||||
|
bool isTextEmpty = (text()=="");
|
||||||
|
|
||||||
|
{
|
||||||
|
//const int y = (height() - m_pixmap.height()) / 2; // add margin if needed
|
||||||
|
int h_btn_half = height() / 2;
|
||||||
|
int h_icon_half = m_pixmap.height() / 2;
|
||||||
|
int w_btn_half = width() / 2;
|
||||||
|
int w_icon_half = m_pixmap.width() / 2;
|
||||||
|
int w_btn_tenth = width() / 10;
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.drawPixmap
|
||||||
|
(
|
||||||
|
isTextEmpty
|
||||||
|
? w_btn_half - w_icon_half
|
||||||
|
: 40
|
||||||
|
, h_btn_half - h_icon_half
|
||||||
|
, m_pixmap
|
||||||
|
); // hardcoded horizontal margin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
customlefttabbarbutton.h
Normal file
32
customlefttabbarbutton.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef CUSTOMLEFTTABBARBUTTON_H
|
||||||
|
#define CUSTOMLEFTTABBARBUTTON_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
class CustomLeftTabBarButton : public QPushButton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CustomLeftTabBarButton(QWidget* parent = nullptr);
|
||||||
|
virtual ~CustomLeftTabBarButton();
|
||||||
|
|
||||||
|
void setPos(const QSize& pos);
|
||||||
|
void setPixmap(const QPixmap& pixmap);
|
||||||
|
void setIconStringForButton(QString iconString);
|
||||||
|
|
||||||
|
void setStringForButton(QString String);
|
||||||
|
virtual QSize sizeHint() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void paintEvent(QPaintEvent* e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPixmap m_pixmap;
|
||||||
|
QSize m_pixmapPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CUSTOMLEFTTABBARBUTTON_H
|
||||||
469
datatypes.h
Normal file
469
datatypes.h
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATATYPES_H
|
||||||
|
#define DATATYPES_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVector>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
QString name;
|
||||||
|
QString systemPath;
|
||||||
|
bool isVesc;
|
||||||
|
} VSerialInfo_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CFG_T_UNDEFINED = 0,
|
||||||
|
CFG_T_DOUBLE,
|
||||||
|
CFG_T_INT,
|
||||||
|
CFG_T_QSTRING,
|
||||||
|
CFG_T_ENUM,
|
||||||
|
CFG_T_BOOL
|
||||||
|
} CFG_T;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VESC_TX_UNDEFINED = 0,
|
||||||
|
VESC_TX_UINT8,
|
||||||
|
VESC_TX_INT8,
|
||||||
|
VESC_TX_UINT16,
|
||||||
|
VESC_TX_INT16,
|
||||||
|
VESC_TX_UINT32,
|
||||||
|
VESC_TX_INT32,
|
||||||
|
VESC_TX_DOUBLE16,
|
||||||
|
VESC_TX_DOUBLE32,
|
||||||
|
VESC_TX_DOUBLE32_AUTO
|
||||||
|
} VESC_TX_T;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FAULT_CODE_NONE = 0,
|
||||||
|
FAULT_CODE_PACK_OVER_VOLTAGE,
|
||||||
|
FAULT_CODE_PACK_UNDER_VOLTAGE,
|
||||||
|
FAULT_CODE_LOAD_OVER_VOLTAGE,
|
||||||
|
FAULT_CODE_LOAD_UNDER_VOLTAGE,
|
||||||
|
FAULT_CODE_CHARGER_OVER_VOLTAGE,
|
||||||
|
FAULT_CODE_CHARGER_UNDER_VOLTAGE,
|
||||||
|
FAULT_CODE_CELL_HARD_OVER_VOLTAGE,
|
||||||
|
FAULT_CODE_CELL_HARD_UNDER_VOLTAGE,
|
||||||
|
FAULT_CODE_CELL_SOFT_OVER_VOLTAGE,
|
||||||
|
FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE,
|
||||||
|
FAULT_CODE_MAX_UVP_OVP_ERRORS,
|
||||||
|
FAULT_CODE_MAX_UVT_OVT_ERRORS,
|
||||||
|
FAULT_CODE_OVER_CURRENT,
|
||||||
|
FAULT_CODE_OVER_TEMP_BMS,
|
||||||
|
FAULT_CODE_UNDER_TEMP_BMS,
|
||||||
|
FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS,
|
||||||
|
FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS,
|
||||||
|
FAULT_CODE_CHARGE_OVER_TEMP_CELLS,
|
||||||
|
FAULT_CODE_CHARGE_UNDER_TEMP_CELLS,
|
||||||
|
FAULT_CODE_PRECHARGE_TIMEOUT,
|
||||||
|
FAULT_CODE_DISCHARGE_RETRY,
|
||||||
|
FAULT_CODE_CHARGE_RETRY,
|
||||||
|
FAULT_CODE_CHARGER_DISCONNECT
|
||||||
|
} bms_fault_code;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DISP_POS_MODE_NONE = 0,
|
||||||
|
DISP_POS_MODE_INDUCTANCE,
|
||||||
|
DISP_POS_MODE_OBSERVER,
|
||||||
|
DISP_POS_MODE_ENCODER,
|
||||||
|
DISP_POS_MODE_PID_POS,
|
||||||
|
DISP_POS_MODE_PID_POS_ERROR,
|
||||||
|
DISP_POS_MODE_ENCODER_OBSERVER_ERROR
|
||||||
|
} disp_pos_mode;
|
||||||
|
|
||||||
|
struct MC_VALUES {
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
Q_PROPERTY(double v_in MEMBER v_in)
|
||||||
|
Q_PROPERTY(double temp_mos MEMBER temp_mos)
|
||||||
|
Q_PROPERTY(double temp_motor MEMBER temp_motor)
|
||||||
|
Q_PROPERTY(double current_motor MEMBER current_motor)
|
||||||
|
Q_PROPERTY(double current_in MEMBER current_in)
|
||||||
|
Q_PROPERTY(double id MEMBER id)
|
||||||
|
Q_PROPERTY(double iq MEMBER iq)
|
||||||
|
Q_PROPERTY(double rpm MEMBER rpm)
|
||||||
|
Q_PROPERTY(double duty_now MEMBER duty_now)
|
||||||
|
Q_PROPERTY(double amp_hours MEMBER amp_hours)
|
||||||
|
Q_PROPERTY(double amp_hours_charged MEMBER amp_hours_charged)
|
||||||
|
Q_PROPERTY(double watt_hours MEMBER watt_hours)
|
||||||
|
Q_PROPERTY(double watt_hours_charged MEMBER watt_hours_charged)
|
||||||
|
Q_PROPERTY(int tachometer MEMBER tachometer)
|
||||||
|
Q_PROPERTY(int tachometer_abs MEMBER tachometer_abs)
|
||||||
|
Q_PROPERTY(double position MEMBER position)
|
||||||
|
//Q_PROPERTY(mc_fault_code fault_code MEMBER fault_code)
|
||||||
|
Q_PROPERTY(QString fault_str MEMBER fault_str)
|
||||||
|
|
||||||
|
public:
|
||||||
|
MC_VALUES() {
|
||||||
|
v_in = 0.0;
|
||||||
|
temp_mos = 0.0;
|
||||||
|
temp_mos_1 = 0.0;
|
||||||
|
temp_mos_2 = 0.0;
|
||||||
|
temp_mos_3 = 0.0;
|
||||||
|
temp_motor = 0.0;
|
||||||
|
current_motor = 0.0;
|
||||||
|
current_in = 0.0;
|
||||||
|
id = 0.0;
|
||||||
|
iq = 0.0;
|
||||||
|
rpm = 0.0;
|
||||||
|
duty_now = 0.0;
|
||||||
|
amp_hours = 0.0;
|
||||||
|
amp_hours_charged = 0.0;
|
||||||
|
watt_hours = 0.0;
|
||||||
|
watt_hours_charged = 0.0;
|
||||||
|
tachometer = 0;
|
||||||
|
tachometer_abs = 0;
|
||||||
|
position = 0.0;
|
||||||
|
//fault_code = FAULT_CODE_NONE;
|
||||||
|
vesc_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double v_in;
|
||||||
|
double temp_mos;
|
||||||
|
double temp_mos_1;
|
||||||
|
double temp_mos_2;
|
||||||
|
double temp_mos_3;
|
||||||
|
double temp_motor;
|
||||||
|
double current_motor;
|
||||||
|
double current_in;
|
||||||
|
double id;
|
||||||
|
double iq;
|
||||||
|
double rpm;
|
||||||
|
double duty_now;
|
||||||
|
double amp_hours;
|
||||||
|
double amp_hours_charged;
|
||||||
|
double watt_hours;
|
||||||
|
double watt_hours_charged;
|
||||||
|
int tachometer;
|
||||||
|
int tachometer_abs;
|
||||||
|
double position;
|
||||||
|
//mc_fault_code fault_code;
|
||||||
|
int vesc_id;
|
||||||
|
QString fault_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(MC_VALUES)
|
||||||
|
|
||||||
|
struct BMS_VALUES {
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
Q_PROPERTY(double packVoltage MEMBER packVoltage)
|
||||||
|
Q_PROPERTY(double packCurrent MEMBER packCurrent)
|
||||||
|
Q_PROPERTY(int soC MEMBER soC)
|
||||||
|
Q_PROPERTY(double cVHigh MEMBER cVHigh)
|
||||||
|
Q_PROPERTY(double cVAverage MEMBER cVAverage)
|
||||||
|
Q_PROPERTY(double cVLow MEMBER cVLow)
|
||||||
|
Q_PROPERTY(double cVMisMatch MEMBER cVMisMatch)
|
||||||
|
Q_PROPERTY(double loadLCVoltage MEMBER loadLCVoltage)
|
||||||
|
Q_PROPERTY(double loadLCCurrent MEMBER loadLCCurrent)
|
||||||
|
Q_PROPERTY(double loadHCVoltage MEMBER loadHCVoltage)
|
||||||
|
Q_PROPERTY(double loadHCCurrent MEMBER loadHCCurrent)
|
||||||
|
Q_PROPERTY(double chargerVoltage MEMBER chargerVoltage)
|
||||||
|
Q_PROPERTY(double auxVoltage MEMBER auxVoltage)
|
||||||
|
Q_PROPERTY(double auxCurrent MEMBER auxCurrent)
|
||||||
|
Q_PROPERTY(double tempBattHigh MEMBER tempBattHigh)
|
||||||
|
Q_PROPERTY(double tempBattAverage MEMBER tempBattAverage)
|
||||||
|
Q_PROPERTY(double tempBattLow MEMBER tempBattLow)
|
||||||
|
Q_PROPERTY(double tempBMSHigh MEMBER tempBMSHigh)
|
||||||
|
Q_PROPERTY(double tempBMSAverage MEMBER tempBMSAverage)
|
||||||
|
Q_PROPERTY(double tempBMSLow MEMBER tempBMSLow)
|
||||||
|
Q_PROPERTY(double humidity MEMBER humidity)
|
||||||
|
Q_PROPERTY(QString opState MEMBER opState)
|
||||||
|
Q_PROPERTY(int balanceActive MEMBER balanceActive)
|
||||||
|
Q_PROPERTY(QString faultState MEMBER faultState)
|
||||||
|
|
||||||
|
public:
|
||||||
|
BMS_VALUES(){
|
||||||
|
packVoltage = 0.0;
|
||||||
|
packCurrent =0.0;
|
||||||
|
soC = 0;
|
||||||
|
cVHigh = 0.0;
|
||||||
|
cVAverage =0.0;
|
||||||
|
cVLow = 0.0;
|
||||||
|
cVMisMatch = 0.0;
|
||||||
|
loadLCVoltage = 0.0;
|
||||||
|
loadLCCurrent = 0.0;
|
||||||
|
loadHCVoltage = 0.0;
|
||||||
|
loadHCCurrent = 0.0;
|
||||||
|
chargerVoltage =0.0;
|
||||||
|
auxVoltage = 0.0;
|
||||||
|
auxCurrent = 0.0;
|
||||||
|
tempBattHigh = 0.0;
|
||||||
|
tempBattAverage = 0.0;
|
||||||
|
tempBattLow = 0.0;
|
||||||
|
tempBMSHigh = 0.0;
|
||||||
|
tempBMSAverage = 0.0;
|
||||||
|
tempBMSLow = 0.0;
|
||||||
|
humidity = 0.0;
|
||||||
|
balanceActive = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double packVoltage;
|
||||||
|
double packCurrent;
|
||||||
|
int soC;
|
||||||
|
double cVHigh;
|
||||||
|
double cVAverage;
|
||||||
|
double cVLow;
|
||||||
|
double cVMisMatch;
|
||||||
|
double loadLCVoltage;
|
||||||
|
double loadLCCurrent;
|
||||||
|
double loadHCVoltage;
|
||||||
|
double loadHCCurrent;
|
||||||
|
double chargerVoltage;
|
||||||
|
double auxVoltage;
|
||||||
|
double auxCurrent;
|
||||||
|
double tempBattHigh;
|
||||||
|
double tempBattAverage;
|
||||||
|
double tempBattLow;
|
||||||
|
double tempBMSHigh;
|
||||||
|
double tempBMSAverage;
|
||||||
|
double tempBMSLow;
|
||||||
|
double humidity;
|
||||||
|
QString opState;
|
||||||
|
int balanceActive;
|
||||||
|
QString faultState;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(BMS_VALUES)
|
||||||
|
|
||||||
|
struct MCCONF_TEMP {
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
Q_PROPERTY(double current_min_scale MEMBER current_min_scale)
|
||||||
|
Q_PROPERTY(double current_max_scale MEMBER current_max_scale)
|
||||||
|
Q_PROPERTY(double erpm_or_speed_min MEMBER erpm_or_speed_min)
|
||||||
|
Q_PROPERTY(double erpm_or_speed_max MEMBER erpm_or_speed_max)
|
||||||
|
Q_PROPERTY(double duty_min MEMBER duty_min)
|
||||||
|
Q_PROPERTY(double duty_max MEMBER duty_max)
|
||||||
|
Q_PROPERTY(double watt_min MEMBER watt_min)
|
||||||
|
Q_PROPERTY(double watt_max MEMBER watt_max)
|
||||||
|
Q_PROPERTY(QString name MEMBER name)
|
||||||
|
|
||||||
|
public:
|
||||||
|
double current_min_scale;
|
||||||
|
double current_max_scale;
|
||||||
|
double erpm_or_speed_min;
|
||||||
|
double erpm_or_speed_max;
|
||||||
|
double duty_min;
|
||||||
|
double duty_max;
|
||||||
|
double watt_min;
|
||||||
|
double watt_max;
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(MCCONF_TEMP)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DEBUG_SAMPLING_OFF = 0,
|
||||||
|
DEBUG_SAMPLING_NOW,
|
||||||
|
DEBUG_SAMPLING_START,
|
||||||
|
DEBUG_SAMPLING_TRIGGER_START,
|
||||||
|
DEBUG_SAMPLING_TRIGGER_FAULT,
|
||||||
|
DEBUG_SAMPLING_TRIGGER_START_NOSEND,
|
||||||
|
DEBUG_SAMPLING_TRIGGER_FAULT_NOSEND,
|
||||||
|
DEBUG_SAMPLING_SEND_LAST_SAMPLES
|
||||||
|
} debug_sampling_mode;
|
||||||
|
|
||||||
|
// Communication commands
|
||||||
|
typedef enum {
|
||||||
|
COMM_FW_VERSION = 0,
|
||||||
|
COMM_JUMP_TO_BOOTLOADER,
|
||||||
|
COMM_ERASE_NEW_APP,
|
||||||
|
COMM_WRITE_NEW_APP_DATA,
|
||||||
|
COMM_GET_VALUES,
|
||||||
|
COMM_SET_DUTY,
|
||||||
|
COMM_SET_CURRENT,
|
||||||
|
COMM_SET_CURRENT_BRAKE,
|
||||||
|
COMM_SET_RPM,
|
||||||
|
COMM_SET_POS,
|
||||||
|
COMM_SET_HANDBRAKE,
|
||||||
|
COMM_SET_DETECT,
|
||||||
|
COMM_SET_SERVO_POS,
|
||||||
|
COMM_SET_MCCONF,
|
||||||
|
COMM_GET_MCCONF,
|
||||||
|
COMM_GET_MCCONF_DEFAULT,
|
||||||
|
COMM_SET_APPCONF,
|
||||||
|
COMM_GET_APPCONF,
|
||||||
|
COMM_GET_APPCONF_DEFAULT,
|
||||||
|
COMM_SAMPLE_PRINT,
|
||||||
|
COMM_TERMINAL_CMD,
|
||||||
|
COMM_PRINT,
|
||||||
|
COMM_ROTOR_POSITION,
|
||||||
|
COMM_EXPERIMENT_SAMPLE,
|
||||||
|
COMM_DETECT_MOTOR_PARAM,
|
||||||
|
COMM_DETECT_MOTOR_R_L,
|
||||||
|
COMM_DETECT_MOTOR_FLUX_LINKAGE,
|
||||||
|
COMM_DETECT_ENCODER,
|
||||||
|
COMM_DETECT_HALL_FOC,
|
||||||
|
COMM_REBOOT,
|
||||||
|
COMM_ALIVE,
|
||||||
|
COMM_GET_DECODED_PPM,
|
||||||
|
COMM_GET_DECODED_ADC,
|
||||||
|
COMM_GET_DECODED_CHUK,
|
||||||
|
COMM_FORWARD_CAN,
|
||||||
|
COMM_SET_CHUCK_DATA,
|
||||||
|
COMM_CUSTOM_APP_DATA,
|
||||||
|
COMM_NRF_START_PAIRING,
|
||||||
|
COMM_GPD_SET_FSW,
|
||||||
|
COMM_GPD_BUFFER_NOTIFY,
|
||||||
|
COMM_GPD_BUFFER_SIZE_LEFT,
|
||||||
|
COMM_GPD_FILL_BUFFER,
|
||||||
|
COMM_GPD_OUTPUT_SAMPLE,
|
||||||
|
COMM_GPD_SET_MODE,
|
||||||
|
COMM_GPD_FILL_BUFFER_INT8,
|
||||||
|
COMM_GPD_FILL_BUFFER_INT16,
|
||||||
|
COMM_GPD_SET_BUFFER_INT_SCALE,
|
||||||
|
COMM_GET_VALUES_SETUP,
|
||||||
|
COMM_SET_MCCONF_TEMP,
|
||||||
|
COMM_SET_MCCONF_TEMP_SETUP,
|
||||||
|
COMM_GET_VALUES_SELECTIVE,
|
||||||
|
COMM_GET_VALUES_SETUP_SELECTIVE,
|
||||||
|
COMM_EXT_NRF_PRESENT,
|
||||||
|
COMM_EXT_NRF_ESB_SET_CH_ADDR,
|
||||||
|
COMM_EXT_NRF_ESB_SEND_DATA,
|
||||||
|
COMM_EXT_NRF_ESB_RX_DATA,
|
||||||
|
COMM_EXT_NRF_SET_ENABLED,
|
||||||
|
COMM_DETECT_MOTOR_FLUX_LINKAGE_OPENLOOP,
|
||||||
|
COMM_DETECT_APPLY_ALL_FOC,
|
||||||
|
COMM_JUMP_TO_BOOTLOADER_ALL_CAN,
|
||||||
|
COMM_ERASE_NEW_APP_ALL_CAN,
|
||||||
|
COMM_WRITE_NEW_APP_DATA_ALL_CAN,
|
||||||
|
COMM_PING_CAN,
|
||||||
|
COMM_APP_DISABLE_OUTPUT,
|
||||||
|
COMM_TERMINAL_CMD_SYNC,
|
||||||
|
COMM_GET_IMU_DATA,
|
||||||
|
COMM_BM_CONNECT,
|
||||||
|
COMM_BM_ERASE_FLASH_ALL,
|
||||||
|
COMM_BM_WRITE_FLASH,
|
||||||
|
COMM_BM_REBOOT,
|
||||||
|
COMM_BM_DISCONNECT,
|
||||||
|
COMM_BM_MAP_PINS_DEFAULT,
|
||||||
|
COMM_BM_MAP_PINS_NRF5X,
|
||||||
|
COMM_ERASE_BOOTLOADER,
|
||||||
|
COMM_ERASE_BOOTLOADER_ALL_CAN,
|
||||||
|
COMM_PLOT_INIT,
|
||||||
|
COMM_PLOT_DATA,
|
||||||
|
COMM_PLOT_ADD_GRAPH,
|
||||||
|
COMM_PLOT_SET_GRAPH,
|
||||||
|
COMM_GET_DECODED_BALANCE,
|
||||||
|
COMM_BM_MEM_READ,
|
||||||
|
COMM_WRITE_NEW_APP_DATA_LZO,
|
||||||
|
COMM_WRITE_NEW_APP_DATA_ALL_CAN_LZO,
|
||||||
|
COMM_BM_WRITE_FLASH_LZO,
|
||||||
|
COMM_SET_CURRENT_REL,
|
||||||
|
COMM_CAN_FWD_FRAME,
|
||||||
|
COMM_SET_BATTERY_CUT,
|
||||||
|
COMM_SET_BLE_NAME,
|
||||||
|
COMM_SET_BLE_PIN,
|
||||||
|
COMM_SET_CAN_MODE,
|
||||||
|
COMM_GET_IMU_CALIBRATION,
|
||||||
|
COMM_GET_MCCONF_TEMP,
|
||||||
|
|
||||||
|
// Custom configuration for hardware
|
||||||
|
COMM_GET_CUSTOM_CONFIG_XML,
|
||||||
|
COMM_GET_CUSTOM_CONFIG,
|
||||||
|
COMM_GET_CUSTOM_CONFIG_DEFAULT,
|
||||||
|
COMM_SET_CUSTOM_CONFIG,
|
||||||
|
|
||||||
|
// BMS commands
|
||||||
|
COMM_BMS_GET_VALUES,
|
||||||
|
COMM_BMS_SET_CHARGE_ALLOWED,
|
||||||
|
COMM_BMS_SET_BALANCE_OVERRIDE,
|
||||||
|
COMM_BMS_RESET_COUNTERS,
|
||||||
|
COMM_BMS_FORCE_BALANCE,
|
||||||
|
COMM_BMS_ZERO_CURRENT_OFFSET,
|
||||||
|
|
||||||
|
// FW updates commands for different HW types
|
||||||
|
COMM_JUMP_TO_BOOTLOADER_HW,
|
||||||
|
COMM_ERASE_NEW_APP_HW,
|
||||||
|
COMM_WRITE_NEW_APP_DATA_HW,
|
||||||
|
COMM_ERASE_BOOTLOADER_HW,
|
||||||
|
COMM_JUMP_TO_BOOTLOADER_ALL_CAN_HW,
|
||||||
|
COMM_ERASE_NEW_APP_ALL_CAN_HW,
|
||||||
|
COMM_WRITE_NEW_APP_DATA_ALL_CAN_HW,
|
||||||
|
COMM_ERASE_BOOTLOADER_ALL_CAN_HW,
|
||||||
|
|
||||||
|
COMM_SET_ODOMETER,
|
||||||
|
|
||||||
|
// ENNOID-BMS specific
|
||||||
|
COMM_STORE_BMS_CONF = 150,
|
||||||
|
COMM_GET_BMS_CELLS,
|
||||||
|
COMM_GET_BMS_AUX,
|
||||||
|
COMM_GET_BMS_EXP_TEMP
|
||||||
|
} COMM_PACKET_ID;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int js_x;
|
||||||
|
int js_y;
|
||||||
|
int acc_x;
|
||||||
|
int acc_y;
|
||||||
|
int acc_z;
|
||||||
|
bool bt_c;
|
||||||
|
bool bt_z;
|
||||||
|
} chuck_data;
|
||||||
|
|
||||||
|
struct bldc_detect {
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
Q_PROPERTY(double cycle_int_limit MEMBER cycle_int_limit)
|
||||||
|
Q_PROPERTY(double bemf_coupling_k MEMBER bemf_coupling_k)
|
||||||
|
Q_PROPERTY(QVector<int> hall_table MEMBER hall_table)
|
||||||
|
Q_PROPERTY(int hall_res MEMBER hall_res)
|
||||||
|
|
||||||
|
public:
|
||||||
|
double cycle_int_limit;
|
||||||
|
double bemf_coupling_k;
|
||||||
|
QVector<int> hall_table;
|
||||||
|
int hall_res;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(bldc_detect)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NRF_PAIR_STARTED = 0,
|
||||||
|
NRF_PAIR_OK,
|
||||||
|
NRF_PAIR_FAIL
|
||||||
|
} NRF_PAIR_RES;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OP_STATE_INIT = 0, // 0
|
||||||
|
OP_STATE_CHARGING, // 1
|
||||||
|
OP_STATE_PRE_CHARGE, // 2
|
||||||
|
OP_STATE_LOAD_ENABLED, // 3
|
||||||
|
OP_STATE_BATTERY_DEAD, // 4
|
||||||
|
OP_STATE_POWER_DOWN, // 5
|
||||||
|
OP_STATE_EXTERNAL, // 6
|
||||||
|
OP_STATE_ERROR, // 7
|
||||||
|
OP_STATE_ERROR_PRECHARGE, // 8
|
||||||
|
OP_STATE_BALANCING, // 9
|
||||||
|
OP_STATE_CHARGED, // 10
|
||||||
|
OP_STATE_FORCEON, // 11
|
||||||
|
} OperationalStateTypedef;
|
||||||
|
|
||||||
|
#endif // DATATYPES_H
|
||||||
58
debugprintpage.cpp
Normal file
58
debugprintpage.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include "debugprintpage.h"
|
||||||
|
#include "ui_debugprintpage.h"
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QTextCursor>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
DebugPrintPage *DebugPrintPage::currentMsgHandler = 0;
|
||||||
|
|
||||||
|
DebugPrintPage::DebugPrintPage(QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
ui(new Ui::DebugPrintPage)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
currentMsgHandler = this;
|
||||||
|
|
||||||
|
connect(ui->clearButton, &QPushButton::clicked, this, &DebugPrintPage::on_clearButton_clicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugPrintPage::~DebugPrintPage()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPrintPage::on_clearButton_clicked()
|
||||||
|
{
|
||||||
|
clearConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPrintPage::clearConsole()
|
||||||
|
{
|
||||||
|
ui->consoleBrowser->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
BMSInterface *DebugPrintPage::bms() const
|
||||||
|
{
|
||||||
|
return mDieBieMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugPrintPage::setDieBieMS(BMSInterface *dieBieMS)
|
||||||
|
{
|
||||||
|
mDieBieMS = dieBieMS;
|
||||||
|
|
||||||
|
if (mDieBieMS) {
|
||||||
|
connect(mDieBieMS->commands(), SIGNAL(printReceived(QString)),
|
||||||
|
this, SLOT(printReceived(QString)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DebugPrintPage::printConsole(QString str)
|
||||||
|
{
|
||||||
|
ui->consoleBrowser->moveCursor(QTextCursor::End);
|
||||||
|
ui->consoleBrowser->insertHtml(QDateTime::currentDateTime().
|
||||||
|
toString("yyyy-MM-dd hh:mm:ss: ")
|
||||||
|
+ str);
|
||||||
|
ui->consoleBrowser->moveCursor(QTextCursor::End);
|
||||||
|
}
|
||||||
39
debugprintpage.h
Normal file
39
debugprintpage.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef DEBUGPRINTPAGE_H
|
||||||
|
#define DEBUGPRINTPAGE_H
|
||||||
|
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QButtonGroup>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class DebugPrintPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DebugPrintPage : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DebugPrintPage(QWidget *parent = nullptr);
|
||||||
|
~DebugPrintPage();
|
||||||
|
|
||||||
|
static DebugPrintPage* currentMsgHandler;
|
||||||
|
|
||||||
|
void clearConsole();
|
||||||
|
|
||||||
|
BMSInterface *bms() const;
|
||||||
|
void setDieBieMS(BMSInterface *dieBieMS);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void printConsole(QString str);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_clearButton_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::DebugPrintPage *ui;
|
||||||
|
BMSInterface *mDieBieMS;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEBUGPRINTPAGE_H
|
||||||
233
debugprintpage.ui
Normal file
233
debugprintpage.ui
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DebugPrintPage</class>
|
||||||
|
<widget class="QFrame" name="DebugPrintPage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1071</width>
|
||||||
|
<height>755</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">
|
||||||
|
QWidget#DebugPrintPage
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage
|
||||||
|
{
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
border-top-left-radius: 15px;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
font-size: 18px;
|
||||||
|
border-right-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarAmperage
|
||||||
|
{
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
/* border-top-left-radius: 20px;*/
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
font-size: 18px;
|
||||||
|
border-left-color: white;
|
||||||
|
border-right-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarTemperature
|
||||||
|
{
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
font-size: 18px;
|
||||||
|
border-left-color: white;
|
||||||
|
border-right-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage:hover:checked,
|
||||||
|
#pbVisualizationMenuBarAmperage:hover:checked,
|
||||||
|
#pbVisualizationMenuBarTemperature:hover:checked
|
||||||
|
{
|
||||||
|
/*background-color: #01673a;*/
|
||||||
|
border-bottom-color:#009352;
|
||||||
|
color:#009352;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage:!hover:checked,
|
||||||
|
#pbVisualizationMenuBarAmperage:!hover:checked,
|
||||||
|
#pbVisualizationMenuBarTemperature:!hover:checked
|
||||||
|
{
|
||||||
|
/*background-color: #01673a;*/
|
||||||
|
border-bottom-color: #009352;
|
||||||
|
color:#009352;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbVisualizationMenuBarVoltage:hover:!checked,
|
||||||
|
#pbVisualizationMenuBarAmperage:hover:!checked,
|
||||||
|
#pbVisualizationMenuBarTemperature:hover:!checked
|
||||||
|
{
|
||||||
|
/*background-color: #009352;*/
|
||||||
|
/*background-color: #028249;*/
|
||||||
|
border-bottom-color: lightgrey;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QLabel" name="lbCenterTabName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>50</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>931</width>
|
||||||
|
<height>41</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>26</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Вывод информации</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="labConsoleBrowserBackground">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>53</x>
|
||||||
|
<y>90</y>
|
||||||
|
<width>991</width>
|
||||||
|
<height>581</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"> background-color:#FFFFFF;
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
border-top-left-radius: 15px;
|
||||||
|
border-top-right-radius: 15px;
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="VTextBrowser" name="consoleBrowser">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>53</x>
|
||||||
|
<y>91</y>
|
||||||
|
<width>991</width>
|
||||||
|
<height>581</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>DejaVu Sans Mono</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"> background-color:transparent;
|
||||||
|
border: 2px solid lightgrey;
|
||||||
|
border-top-left-radius: 15px;
|
||||||
|
border-top-right-radius: 15px;
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="clearButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1000</x>
|
||||||
|
<y>680</y>
|
||||||
|
<width>44</width>
|
||||||
|
<height>40</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Clear terminal</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Delete-96.png</normaloff>:/res/icons/Delete-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLineEdit" name="consoleEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>60</x>
|
||||||
|
<y>680</y>
|
||||||
|
<width>931</width>
|
||||||
|
<height>39</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<zorder>labConsoleBrowserBackground</zorder>
|
||||||
|
<zorder>lbCenterTabName</zorder>
|
||||||
|
<zorder>consoleBrowser</zorder>
|
||||||
|
<zorder>clearButton</zorder>
|
||||||
|
<zorder>consoleEdit</zorder>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>VTextBrowser</class>
|
||||||
|
<extends>QTextEdit</extends>
|
||||||
|
<header>widgets/vtextbrowser.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
313
digitalfiltering.cpp
Normal file
313
digitalfiltering.cpp
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
/*
|
||||||
|
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 "digitalfiltering.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
DigitalFiltering::DigitalFiltering()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found at http://paulbourke.net/miscellaneous//dft/
|
||||||
|
// Dir: 0: Forward, != 0: Reverse
|
||||||
|
// m: 2^m points
|
||||||
|
// real: Real part
|
||||||
|
// imag: Imaginary part
|
||||||
|
void DigitalFiltering::fft(int dir, int m, double *real, double *imag)
|
||||||
|
{
|
||||||
|
long n,i,i1,j,k,i2,l,l1,l2;
|
||||||
|
double c1,c2,tx,ty,t1,t2,u1,u2,z;
|
||||||
|
|
||||||
|
// Calculate the number of points
|
||||||
|
n = 1 << m;
|
||||||
|
|
||||||
|
// Do the bit reversal
|
||||||
|
i2 = n >> 1;
|
||||||
|
j = 0;
|
||||||
|
for (i=0;i<n-1;i++) {
|
||||||
|
if (i < j) {
|
||||||
|
tx = real[i];
|
||||||
|
ty = imag[i];
|
||||||
|
real[i] = real[j];
|
||||||
|
imag[i] = imag[j];
|
||||||
|
real[j] = tx;
|
||||||
|
imag[j] = ty;
|
||||||
|
}
|
||||||
|
k = i2;
|
||||||
|
while (k <= j) {
|
||||||
|
j -= k;
|
||||||
|
k >>= 1;
|
||||||
|
}
|
||||||
|
j += k;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the FFT
|
||||||
|
c1 = -1.0;
|
||||||
|
c2 = 0.0;
|
||||||
|
l2 = 1;
|
||||||
|
for (l=0;l<m;l++) {
|
||||||
|
l1 = l2;
|
||||||
|
l2 <<= 1;
|
||||||
|
u1 = 1.0;
|
||||||
|
u2 = 0.0;
|
||||||
|
for (j=0;j < l1;j++) {
|
||||||
|
for (i=j;i < n;i += l2) {
|
||||||
|
i1 = i + l1;
|
||||||
|
t1 = u1 * real[i1] - u2 * imag[i1];
|
||||||
|
t2 = u1 * imag[i1] + u2 * real[i1];
|
||||||
|
real[i1] = real[i] - t1;
|
||||||
|
imag[i1] = imag[i] - t2;
|
||||||
|
real[i] += t1;
|
||||||
|
imag[i] += t2;
|
||||||
|
}
|
||||||
|
z = u1 * c1 - u2 * c2;
|
||||||
|
u2 = u1 * c2 + u2 * c1;
|
||||||
|
u1 = z;
|
||||||
|
}
|
||||||
|
c2 = sqrt((1.0 - c1) / 2.0);
|
||||||
|
if (dir) {
|
||||||
|
c2 = -c2;
|
||||||
|
}
|
||||||
|
c1 = sqrt((1.0 + c1) / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scaling for reverse transform
|
||||||
|
if (dir) {
|
||||||
|
for (i=0;i < n;i++) {
|
||||||
|
real[i] /= n;
|
||||||
|
imag[i] /= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found at http://paulbourke.net/miscellaneous//dft/
|
||||||
|
void DigitalFiltering::dft(int dir, int len, double *real, double *imag) {
|
||||||
|
long i,k;
|
||||||
|
double arg;
|
||||||
|
double cosarg, sinarg;
|
||||||
|
|
||||||
|
if(dir) {
|
||||||
|
dir = 1;
|
||||||
|
} else {
|
||||||
|
dir = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double *x2 = new double[len];
|
||||||
|
double *y2 = new double[len];
|
||||||
|
|
||||||
|
for (i=0;i < len;i++) {
|
||||||
|
x2[i] = 0;
|
||||||
|
y2[i] = 0;
|
||||||
|
arg = -(double)dir * 2.0 * M_PI * (double)i / (double)len;
|
||||||
|
for (k=0;k<len;k++) {
|
||||||
|
cosarg = cos(k * arg);
|
||||||
|
sinarg = sin(k * arg);
|
||||||
|
x2[i] += (real[k] * cosarg - imag[k] * sinarg);
|
||||||
|
y2[i] += (real[k] * sinarg + imag[k] * cosarg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the data back
|
||||||
|
if (dir == 1) {
|
||||||
|
for (i=0;i<len;i++) {
|
||||||
|
real[i] = x2[i] / (double)len;
|
||||||
|
imag[i] = y2[i] / (double)len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i=0;i<len;i++) {
|
||||||
|
real[i] = x2[i];
|
||||||
|
imag[i] = y2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] x2;
|
||||||
|
delete[] y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitalFiltering::fftshift(double *data, int len)
|
||||||
|
{
|
||||||
|
for (int i = 0;i < (len / 2);i++) {
|
||||||
|
double r1 = data[i];
|
||||||
|
double r2 = data[len/2 + i];
|
||||||
|
|
||||||
|
data[i] = r2;
|
||||||
|
data[len / 2 + i] = r1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitalFiltering::hamming(double *data, int len)
|
||||||
|
{
|
||||||
|
if (len % 2 == 0) {
|
||||||
|
for (int i = 0;i < (len / 2);i++) {
|
||||||
|
double val = 0.54 - 0.46 * cos((2.0 * M_PI * (double)i)/(double)(len - 1));
|
||||||
|
data[i] *= val;
|
||||||
|
data[len - i - 1] *= val;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0;i < len;i++) {
|
||||||
|
data[i] *= 0.54 - 0.46 * cos((2.0 * M_PI * (double)i)/(double)(len - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitalFiltering::zeroPad(double *data, double *result, int dataLen, int resultLen)
|
||||||
|
{
|
||||||
|
for (int i = 0;i < resultLen;i++) {
|
||||||
|
if (i < dataLen) {
|
||||||
|
result[i] = data[i];
|
||||||
|
} else {
|
||||||
|
result[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DigitalFiltering::whichPowerOfTwo(unsigned int number)
|
||||||
|
{
|
||||||
|
unsigned int powersOfTwo[32] =
|
||||||
|
{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,
|
||||||
|
65536,131072,262144,524288,1048576,2097152,4194304,8388608,
|
||||||
|
16777216,33554432,67108864,134217728,268435456,536870912,
|
||||||
|
1073741824UL,2147483648UL};
|
||||||
|
|
||||||
|
int exponent = 0;
|
||||||
|
while (powersOfTwo[exponent] < number && exponent < 31) {
|
||||||
|
exponent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<double> DigitalFiltering::filterSignal(const QVector<double> &signal, const QVector<double> &filter, bool padAfter)
|
||||||
|
{
|
||||||
|
QVector<double> result;
|
||||||
|
int taps = filter.size();
|
||||||
|
|
||||||
|
for (int i = 0;i < taps / 2;i++) {
|
||||||
|
result.append(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!padAfter) {
|
||||||
|
for (int i = 0;i < taps / 2;i++) {
|
||||||
|
result.append(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0;i < signal.size() - taps;i++) {
|
||||||
|
double coeff = 0;
|
||||||
|
for (int j = 0;j < taps;j++) {
|
||||||
|
coeff += signal[i + j] * filter[j];
|
||||||
|
}
|
||||||
|
result.append(coeff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (padAfter) {
|
||||||
|
for (int i = 0;i < taps / 2;i++) {
|
||||||
|
result.append(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<double> DigitalFiltering::generateFirFilter(double f_break, int bits, bool useHamming)
|
||||||
|
{
|
||||||
|
int taps = 1 << bits;
|
||||||
|
double imag[taps];
|
||||||
|
double filter_vector[taps];
|
||||||
|
|
||||||
|
for(int i = 0;i < taps;i++) {
|
||||||
|
if (i < (int)((double)taps * f_break)) {
|
||||||
|
filter_vector[i] = 1.0;
|
||||||
|
} else {
|
||||||
|
filter_vector[i] = 0.0;
|
||||||
|
}
|
||||||
|
imag[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0;i < taps / 2;i++) {
|
||||||
|
filter_vector[taps - i - 1] = filter_vector[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
fft(1, bits, filter_vector, imag);
|
||||||
|
fftshift(filter_vector, taps);
|
||||||
|
|
||||||
|
if (useHamming) {
|
||||||
|
hamming(filter_vector, taps);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<double> result;
|
||||||
|
for(int i = 0;i < taps;i++) {
|
||||||
|
result.append(filter_vector[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<double> DigitalFiltering::fftWithShift(QVector<double> &signal, int resultBits, bool scaleByLen)
|
||||||
|
{
|
||||||
|
QVector<double> result;
|
||||||
|
int taps = signal.size();
|
||||||
|
int resultLen = 1 << resultBits;
|
||||||
|
|
||||||
|
double *signal_vector = new double[resultLen];
|
||||||
|
double *imag = new double[resultLen];
|
||||||
|
|
||||||
|
if (resultLen < taps) {
|
||||||
|
int sizeDiffHalf = (taps - resultLen) / 2;
|
||||||
|
signal.remove(0, sizeDiffHalf);
|
||||||
|
signal.resize(resultLen);
|
||||||
|
|
||||||
|
for(int i = 0;i < resultLen;i++) {
|
||||||
|
signal_vector[i] = signal[i];
|
||||||
|
imag[i] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int sizeDiffHalf = (resultLen - taps) / 2;
|
||||||
|
for(int i = 0;i < resultLen;i++) {
|
||||||
|
if (i < sizeDiffHalf) {
|
||||||
|
signal_vector[i] = 0;
|
||||||
|
} else if (i < (taps + sizeDiffHalf)) {
|
||||||
|
signal_vector[i] = signal[i - sizeDiffHalf];
|
||||||
|
} else {
|
||||||
|
signal_vector[i] = 0;
|
||||||
|
}
|
||||||
|
imag[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fftshift(signal_vector, resultLen);
|
||||||
|
fft(0, resultBits, signal_vector, imag);
|
||||||
|
|
||||||
|
double div_factor = scaleByLen ? (double)taps : 1.0;
|
||||||
|
for(int i = 0;i < resultLen;i++) {
|
||||||
|
result.append(fabs(signal_vector[i]) / div_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] signal_vector;
|
||||||
|
delete[] imag;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
48
digitalfiltering.h
Normal file
48
digitalfiltering.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DIGITALFILTERING_H
|
||||||
|
#define DIGITALFILTERING_H
|
||||||
|
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
class DigitalFiltering
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DigitalFiltering();
|
||||||
|
|
||||||
|
static void fft(int dir,int m,double *real,double *imag);
|
||||||
|
static void dft(int dir, int len, double *real, double *imag);
|
||||||
|
static void fftshift(double *data, int len);
|
||||||
|
static void hamming(double *data, int len);
|
||||||
|
static void zeroPad(double *data, double *result, int dataLen, int resultLen);
|
||||||
|
static int whichPowerOfTwo(unsigned int number);
|
||||||
|
|
||||||
|
static QVector<double> filterSignal(const QVector<double> &signal, const QVector<double> &filter, bool padAfter = false);
|
||||||
|
static QVector<double> generateFirFilter(double f_break, int bits, bool useHamming);
|
||||||
|
static QVector<double> fftWithShift(QVector<double> &signal, int resultBits, bool scaleByLen = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DIGITALFILTERING_H
|
||||||
108
historylineeditbox.cpp
Normal file
108
historylineeditbox.cpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "historylineeditbox.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
HistoryLineEditBox::HistoryLineEditBox(QWidget *parent) :
|
||||||
|
QLineEdit(parent)
|
||||||
|
{
|
||||||
|
mIndexNow = 0;
|
||||||
|
installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryLineEditBox::eventFilter(QObject *object, QEvent *e)
|
||||||
|
{
|
||||||
|
Q_UNUSED(object);
|
||||||
|
|
||||||
|
if (e->type() == QEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
|
||||||
|
/*
|
||||||
|
switch(keyEvent->key()) {
|
||||||
|
case Qt::Key_Up:
|
||||||
|
case Qt::Key_Down:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case Qt::Key_Return:
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
emit enterClicked();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
bool retval = false;
|
||||||
|
|
||||||
|
switch(keyEvent->key()) {
|
||||||
|
case Qt::Key_Up: {
|
||||||
|
if (mIndexNow == 0) {
|
||||||
|
mCurrentText = text();
|
||||||
|
}
|
||||||
|
|
||||||
|
mIndexNow--;
|
||||||
|
|
||||||
|
int ind = mHistory.size() + mIndexNow;
|
||||||
|
if (ind >= 0 && ind < mHistory.size()) {
|
||||||
|
setText(mHistory.at(ind));
|
||||||
|
} else {
|
||||||
|
mIndexNow++;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Qt::Key_Down:
|
||||||
|
mIndexNow++;
|
||||||
|
|
||||||
|
if (mIndexNow >= 0) {
|
||||||
|
if (mIndexNow == 0) {
|
||||||
|
setText(mCurrentText);
|
||||||
|
}
|
||||||
|
mIndexNow = 0;
|
||||||
|
} else {
|
||||||
|
int ind = mHistory.size() + mIndexNow;
|
||||||
|
if (ind >= 0 && ind < mHistory.size()) {
|
||||||
|
setText(mHistory.at(ind));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt::Key_Return:
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
if (!text().isEmpty()) {
|
||||||
|
if (mHistory.isEmpty() || mHistory.last() != text()) {
|
||||||
|
mHistory.append(text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIndexNow = 0;
|
||||||
|
mCurrentText.clear();
|
||||||
|
retval = false;
|
||||||
|
|
||||||
|
emit enterClicked();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
48
historylineeditbox.h
Normal file
48
historylineeditbox.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HISTORYLINEEDITBOX_H
|
||||||
|
#define HISTORYLINEEDITBOX_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
class HistoryLineEditBox : public QLineEdit
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
HistoryLineEditBox(QWidget *parent = nullptr);
|
||||||
|
bool eventFilter(QObject *object, QEvent *e);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void enterClicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList mHistory;
|
||||||
|
int mIndexNow;
|
||||||
|
QString mCurrentText;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HISTORYLINEEDITBOX_H
|
||||||
9
hoverablecombobox.cpp
Normal file
9
hoverablecombobox.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "hoverablecombobox.h"
|
||||||
|
|
||||||
|
HoverableComboBox::HoverableComboBox(QWidget* parent) : QComboBox (parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverableComboBox::~HoverableComboBox()
|
||||||
|
{
|
||||||
|
}
|
||||||
35
hoverablecombobox.h
Normal file
35
hoverablecombobox.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef HOVERABLECOMBOBOX_H
|
||||||
|
#define HOVERABLECOMBOBOX_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
class HoverableComboBox : public QComboBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
HoverableComboBox(QWidget *parent = nullptr);
|
||||||
|
~HoverableComboBox() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void hidePopup() override
|
||||||
|
{
|
||||||
|
QComboBox::hidePopup();
|
||||||
|
emit closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showPopup() override
|
||||||
|
{
|
||||||
|
QComboBox::showPopup();
|
||||||
|
emit opened();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void opened();
|
||||||
|
void closed();
|
||||||
|
};
|
||||||
|
|
||||||
|
//HoverableComboBox(QObject *parent) : QComboBox (parent) { }
|
||||||
|
|
||||||
|
#endif // HOVERABLECOMBOBOX_H
|
||||||
BIN
images/IMAGE01.png
Normal file
BIN
images/IMAGE01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
BIN
images/IMAGE02.png
Normal file
BIN
images/IMAGE02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
39
languageselectorbutton.cpp
Normal file
39
languageselectorbutton.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include "languageselectorbutton.h"
|
||||||
|
|
||||||
|
LanguageSelectorButton::LanguageSelectorButton(QWidget* parent) : QPushButton (parent)
|
||||||
|
{
|
||||||
|
contextmenu = new QMenu(this);
|
||||||
|
|
||||||
|
actRuss = new QAction(QIcon(":/res/language-russ.png"), tr("Рус"), this);
|
||||||
|
actEng = new QAction(QIcon(":/res/language-eng.png"), tr("Анг"), this);
|
||||||
|
|
||||||
|
actRuss->setCheckable(true);
|
||||||
|
actEng->setCheckable(true);
|
||||||
|
|
||||||
|
actRuss->setChecked(true);
|
||||||
|
|
||||||
|
contextmenu->addAction(actRuss);
|
||||||
|
contextmenu->addAction(actEng);
|
||||||
|
|
||||||
|
contextmenu->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
|
connect(contextmenu, &QMenu::triggered, this, &LanguageSelectorButton::onActActivated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LanguageSelectorButton::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
contextmenu->exec(QCursor::pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LanguageSelectorButton::onActActivated(QAction* _pAction)
|
||||||
|
{
|
||||||
|
if (_pAction == actRuss)
|
||||||
|
{
|
||||||
|
emit sigSetRussianLanguage();
|
||||||
|
}
|
||||||
|
else if (_pAction == actEng)
|
||||||
|
{
|
||||||
|
emit sigSetEnglishLanguage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
32
languageselectorbutton.h
Normal file
32
languageselectorbutton.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef LANGUAGESELECTORBUTTON_H
|
||||||
|
#define LANGUAGESELECTORBUTTON_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
class LanguageSelectorButton : public QPushButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
LanguageSelectorButton(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QMouseEvent*event);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sigSetRussianLanguage();
|
||||||
|
void sigSetEnglishLanguage();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onActActivated(QAction* act);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMenu *contextmenu;
|
||||||
|
QAction* actRuss;
|
||||||
|
QAction* actEng;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LANGUAGESELECTORBUTTON_H
|
||||||
146
main.cpp
Normal file
146
main.cpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
Original copyright 2018 Benjamin Vedder benjamin@vedder.se and the VESC Tool project (
|
||||||
|
https://github.com/vedderb/vesc_tool ) Now forked to: Danny Bokma github@diebie.nl
|
||||||
|
|
||||||
|
This file is part of 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 "mainwindow.h"
|
||||||
|
#include "mainwindownew.h"
|
||||||
|
#include "connectandenterpage.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QFontDatabase>
|
||||||
|
|
||||||
|
#include "mobile/qmlui.h"
|
||||||
|
|
||||||
|
#define NEW_GUI 1
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
constexpr char const *APP_NAME = "ENNOID-BMS Tool";
|
||||||
|
// Settings
|
||||||
|
QCoreApplication::setOrganizationName("DieBie");
|
||||||
|
QCoreApplication::setOrganizationDomain("diebie.nl");
|
||||||
|
QCoreApplication::setApplicationName(APP_NAME);
|
||||||
|
|
||||||
|
// DPI settings
|
||||||
|
// TODO: http://www.qcustomplot.com/index.php/support/forum/1344
|
||||||
|
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
|
||||||
|
#ifdef USE_MOBILE
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
#else
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_Use96Dpi);
|
||||||
|
|
||||||
|
QSettings set;
|
||||||
|
bool scaleAuto = true;
|
||||||
|
double scale = 1.0;
|
||||||
|
|
||||||
|
if (set.contains("app_scale_auto")) {
|
||||||
|
scaleAuto = set.value("app_scale_auto").toBool();
|
||||||
|
} else {
|
||||||
|
set.setValue("app_scale_auto", scaleAuto);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scaleAuto) {
|
||||||
|
QApplication tmp(argc, argv);
|
||||||
|
QRect rec = tmp.desktop()->screenGeometry();
|
||||||
|
int height = rec.height();
|
||||||
|
int width = rec.width();
|
||||||
|
double ptFont = tmp.font().pointSizeF();
|
||||||
|
if (ptFont < 0.0) {
|
||||||
|
ptFont = tmp.font().pixelSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width > 3000 && height > 1700) {
|
||||||
|
scale = 1.5;
|
||||||
|
} else {
|
||||||
|
if (ptFont > 11.0) {
|
||||||
|
scale = ptFont / 11.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set.setValue("app_scale_factor", scale);
|
||||||
|
} else if (set.contains("app_scale_factor")) {
|
||||||
|
scale = set.value("app_scale_factor").toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
set.setValue("app_scale_factor", scale);
|
||||||
|
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
scale = 1.0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (scale > 1.01) {
|
||||||
|
qputenv("QT_SCALE_FACTOR", QString::number(scale).toLocal8Bit());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
|
#if NEW_GUI
|
||||||
|
// Fonts
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/Artifakt-Element.ttf");
|
||||||
|
|
||||||
|
qApp->setFont(QFont("Artifakt Element", 12));
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Fonts
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans.ttf");
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans-Bold.ttf");
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans-BoldOblique.ttf");
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSans-Oblique.ttf");
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono.ttf");
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono-Bold.ttf");
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono-BoldOblique.ttf");
|
||||||
|
QFontDatabase::addApplicationFont("://res/fonts/DejaVuSansMono-Oblique.ttf");
|
||||||
|
|
||||||
|
qApp->setFont(QFont("DejaVu Sans", 11));
|
||||||
|
|
||||||
|
// Style
|
||||||
|
a.setStyleSheet("");
|
||||||
|
a.setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_MOBILE
|
||||||
|
QmlUi q;
|
||||||
|
q.startQmlUi();
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if NEW_GUI
|
||||||
|
|
||||||
|
MainWindowNew w;
|
||||||
|
w.setWindowTitle(APP_NAME);
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
//} else {
|
||||||
|
// a.closeAllWindows();
|
||||||
|
// return 0;
|
||||||
|
//}
|
||||||
|
#else
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
883
mainwindow.cpp
Normal file
883
mainwindow.cpp
Normal file
@@ -0,0 +1,883 @@
|
|||||||
|
/*
|
||||||
|
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 "mainwindow.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
|
{
|
||||||
|
QByteArray localMsg = msg.toLocal8Bit();
|
||||||
|
QString str;
|
||||||
|
QString typeStr;
|
||||||
|
bool isBad = false;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case QtDebugMsg: typeStr = "DEBUG"; break;
|
||||||
|
// case QtInfoMsg: typeStr = "INFO"; break;
|
||||||
|
case QtWarningMsg: typeStr = "WARNING"; isBad = true; break;
|
||||||
|
case QtCriticalMsg: typeStr = "CRITICAL"; isBad = true; break;
|
||||||
|
case QtFatalMsg: typeStr = "FATAL"; isBad = true; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
str.sprintf("%s (%s:%u %s): %s", typeStr.toLocal8Bit().data(),
|
||||||
|
context.file, context.line, context.function, localMsg.constData());
|
||||||
|
|
||||||
|
if (PageDebugPrint::currentMsgHandler) {
|
||||||
|
QString strTmp;
|
||||||
|
if (isBad) {
|
||||||
|
strTmp = "<font color=\"red\">" + str + "</font><br>";
|
||||||
|
} else {
|
||||||
|
strTmp = str + "<br>";
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(PageDebugPrint::currentMsgHandler, "printConsole",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QString, strTmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s\n", str.toLocal8Bit().data());
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
QMainWindow(parent),
|
||||||
|
ui(new Ui::MainWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
|
||||||
|
|
||||||
|
mVersion = QString::number(DT_VERSION);
|
||||||
|
mDieBieMS = new BMSInterface(this);
|
||||||
|
mStatusInfoTime = 0;
|
||||||
|
mStatusLabel = new QLabel(this);
|
||||||
|
ui->statusBar->addPermanentWidget(mStatusLabel);
|
||||||
|
mTimer = new QTimer(this);
|
||||||
|
mKeyLeft = false;
|
||||||
|
mKeyRight = false;
|
||||||
|
mbmsConfigRead = false;
|
||||||
|
|
||||||
|
connect(mTimer, SIGNAL(timeout()),this, SLOT(timerSlot()));
|
||||||
|
connect(mDieBieMS, SIGNAL(statusMessage(QString,bool)),this, SLOT(showStatusInfo(QString,bool)));
|
||||||
|
connect(mDieBieMS, SIGNAL(messageDialog(QString,QString,bool,bool)),this, SLOT(showMessageDialog(QString,QString,bool,bool)));
|
||||||
|
connect(mDieBieMS, SIGNAL(serialPortNotWritable(QString)),this, SLOT(serialPortNotWritable(QString)));
|
||||||
|
connect(mDieBieMS->commands(), SIGNAL(bmsConfigCheckResult(QStringList)),this, SLOT(bmsConfigCheckResult(QStringList)));
|
||||||
|
connect(ui->actionAboutQt, SIGNAL(triggered(bool)),qApp, SLOT(aboutQt()));
|
||||||
|
|
||||||
|
// Remove the menu with the option to hide the toolbar
|
||||||
|
ui->mainToolBar->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||||
|
ui->actionCanFwd->setVisible(false);
|
||||||
|
ui->pageLabel->setVisible(false);
|
||||||
|
ui->menuTerminal->menuAction()->setVisible(false);
|
||||||
|
ui->menuTools->menuAction()->setVisible(false);
|
||||||
|
ui->menuHelp->menuAction()->setVisible(false);
|
||||||
|
|
||||||
|
mDieBieMS->bmsConfig()->loadParamsXml("://res/config.xml");
|
||||||
|
mDieBieMS->infoConfig()->loadParamsXml("://res/info.xml");
|
||||||
|
reloadPages();
|
||||||
|
|
||||||
|
connect(mDieBieMS->bmsConfig(), SIGNAL(updated()),this, SLOT(bmsconfUpdated()));
|
||||||
|
|
||||||
|
qInstallMessageHandler(myMessageOutput);
|
||||||
|
|
||||||
|
mTimer->start(20);
|
||||||
|
|
||||||
|
// Restore size and position
|
||||||
|
if (mSettings.contains("mainwindow/size")) {
|
||||||
|
resize(mSettings.value("mainwindow/size").toSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSettings.contains("mainwindow/position")) {
|
||||||
|
move(mSettings.value("mainwindow/position").toPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSettings.contains("mainwindow/maximized")) {
|
||||||
|
bool maximized = mSettings.value("mainwindow/maximized").toBool();
|
||||||
|
if (maximized) {
|
||||||
|
showMaximized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mPageDebugPrint->printConsole("ENNOID-BMS Tool " + mVersion + " started<br>");
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
// Save settings
|
||||||
|
mSettings.setValue("version", mVersion);
|
||||||
|
mSettings.setValue("mainwindow/position", pos());
|
||||||
|
mSettings.setValue("mainwindow/maximized", isMaximized());
|
||||||
|
|
||||||
|
if (!isMaximized()) {
|
||||||
|
mSettings.setValue("mainwindow/size", size());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::timerSlot()
|
||||||
|
{
|
||||||
|
// Update status label
|
||||||
|
if (mStatusInfoTime) {
|
||||||
|
mStatusInfoTime--;
|
||||||
|
if (!mStatusInfoTime) {
|
||||||
|
mStatusLabel->setStyleSheet(qApp->styleSheet());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString str = mDieBieMS->getConnectedPortName();
|
||||||
|
if (str != mStatusLabel->text()) {
|
||||||
|
mStatusLabel->setText(mDieBieMS->getConnectedPortName());
|
||||||
|
static QString statusLast = "";
|
||||||
|
if (str != statusLast) {
|
||||||
|
mPageDebugPrint->printConsole("Status: " + str + "<br>");
|
||||||
|
statusLast = str;
|
||||||
|
if ( str != "Not connected" )
|
||||||
|
{
|
||||||
|
ui->actionRtData->setChecked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAN fwd
|
||||||
|
if (ui->actionCanFwd->isChecked() != mDieBieMS->commands()->getSendCan()) {
|
||||||
|
ui->actionCanFwd->setChecked(mDieBieMS->commands()->getSendCan());
|
||||||
|
}
|
||||||
|
|
||||||
|
// RT value data only every 5 iterations. Cells, aux & expansion_temp only every 20 iterations
|
||||||
|
if (ui->actionRtData->isChecked()) {
|
||||||
|
static int values_cnt = 0;
|
||||||
|
static int cells_cnt = 0;
|
||||||
|
static int aux_cnt = 0;
|
||||||
|
static int exp_temp_cnt = 0;
|
||||||
|
|
||||||
|
values_cnt++;
|
||||||
|
if(values_cnt >= 5) {
|
||||||
|
values_cnt = 0;
|
||||||
|
mDieBieMS->commands()->getValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
cells_cnt++;
|
||||||
|
if(cells_cnt >= 20) {
|
||||||
|
cells_cnt = 0;
|
||||||
|
mDieBieMS->commands()->getCells();
|
||||||
|
}
|
||||||
|
|
||||||
|
aux_cnt++;
|
||||||
|
if(aux_cnt >= 20) {
|
||||||
|
aux_cnt = 0;
|
||||||
|
mDieBieMS->commands()->getAux();
|
||||||
|
}
|
||||||
|
|
||||||
|
exp_temp_cnt++;
|
||||||
|
if(exp_temp_cnt >= 20) {
|
||||||
|
exp_temp_cnt = 0;
|
||||||
|
mDieBieMS->commands()->getExpansionTemp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send alive command once every 10 iterations
|
||||||
|
if (ui->actionSendAlive->isChecked()) {
|
||||||
|
static int alive_cnt = 0;
|
||||||
|
alive_cnt++;
|
||||||
|
if (alive_cnt >= 10) {
|
||||||
|
alive_cnt = 0;
|
||||||
|
mDieBieMS->commands()->sendAlive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read configuration it isn't read since starting ENNOID-BMS Tool
|
||||||
|
if (mDieBieMS->isPortConnected()) {
|
||||||
|
static int conf_cnt = 0;
|
||||||
|
conf_cnt++;
|
||||||
|
if (conf_cnt >= 20) {
|
||||||
|
conf_cnt = 0;
|
||||||
|
if (!mbmsConfigRead) {
|
||||||
|
mDieBieMS->commands()->getBMSconf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable all data streaming when uploading firmware
|
||||||
|
if (mDieBieMS->commands()->getFirmwareUploadProgress() > 0.1) {
|
||||||
|
ui->actionSendAlive->setChecked(false);
|
||||||
|
ui->actionRtData->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run startup checks
|
||||||
|
static bool has_run_start_checks = false;
|
||||||
|
if (!has_run_start_checks) {
|
||||||
|
has_run_start_checks = true;
|
||||||
|
checkUdev();
|
||||||
|
Utility::checkVersion(mDieBieMS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::showStatusInfo(QString info, bool isGood)
|
||||||
|
{
|
||||||
|
if (isGood) {
|
||||||
|
mStatusLabel->setStyleSheet("QLabel { background-color : lightgreen; color : black; }");
|
||||||
|
mPageDebugPrint->printConsole("Status: " + info + "<br>");
|
||||||
|
} else {
|
||||||
|
mStatusLabel->setStyleSheet("QLabel { background-color : red; color : black; }");
|
||||||
|
mPageDebugPrint->printConsole("<font color=\"red\">Status: " + info + "</font><br>");
|
||||||
|
}
|
||||||
|
|
||||||
|
mStatusInfoTime = 80;
|
||||||
|
mStatusLabel->setText(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::showMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText)
|
||||||
|
{
|
||||||
|
(void)richText;
|
||||||
|
|
||||||
|
if (isGood) {
|
||||||
|
QMessageBox::information(this, title, msg);
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(this, title, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::serialPortNotWritable(const QString &port)
|
||||||
|
{
|
||||||
|
(void)port;
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QMessageBox::StandardButton reply;
|
||||||
|
reply = QMessageBox::warning(this,
|
||||||
|
tr("Connect Serial Port"),
|
||||||
|
tr("The serial port is not writable. This can usually be fixed by "
|
||||||
|
"adding your user to the dialout, uucp and/or lock groups. Would "
|
||||||
|
"you like to do that?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
QString name = qgetenv("USER");
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = qgetenv("USERNAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasDialout = !runCmd("getent", QStringList() << "group" << "dialout").isEmpty();
|
||||||
|
bool hasUucp = !runCmd("getent", QStringList() << "group" << "uucp").isEmpty();
|
||||||
|
bool hasLock = !runCmd("getent", QStringList() << "group" << "lock").isEmpty();
|
||||||
|
|
||||||
|
QString grps;
|
||||||
|
if (hasDialout) {
|
||||||
|
grps += "dialout";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasUucp) {
|
||||||
|
if (!grps.isEmpty()) {
|
||||||
|
grps += ",";
|
||||||
|
}
|
||||||
|
grps += "uucp";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLock) {
|
||||||
|
if (!grps.isEmpty()) {
|
||||||
|
grps += ",";
|
||||||
|
}
|
||||||
|
grps += "lock";
|
||||||
|
}
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
process.setEnvironment(QProcess::systemEnvironment());
|
||||||
|
process.start("pkexec", QStringList() << "usermod" << "-aG" << grps << name);
|
||||||
|
waitProcess(process);
|
||||||
|
if (process.exitCode() == 0) {
|
||||||
|
showMessageDialog(tr("Command Result"),
|
||||||
|
tr("Result from command:\n\n"
|
||||||
|
"%1\n"
|
||||||
|
"You have to reboot for this "
|
||||||
|
"change to take effect.").
|
||||||
|
arg(QString(process.readAllStandardOutput())),
|
||||||
|
true, false);
|
||||||
|
} else {
|
||||||
|
showMessageDialog(tr("Command Result"),
|
||||||
|
tr("Running command failed."),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
process.close();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::bmsconfUpdated()
|
||||||
|
{
|
||||||
|
mbmsConfigRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::bmsConfigCheckResult(QStringList paramsNotSet)
|
||||||
|
{
|
||||||
|
if (!paramsNotSet.isEmpty()) {
|
||||||
|
ParamDialog::showParams(tr("Parameters truncated"),
|
||||||
|
tr("The following parameters were truncated because they were set outside "
|
||||||
|
"of their allowed limits."),
|
||||||
|
mDieBieMS->bmsConfig(),
|
||||||
|
paramsNotSet,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionReconnect_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->reconnectLastPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionDisconnect_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->disconnectPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionReboot_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionReadBMScconf_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->getBMSconf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionReadBMScconfDefault_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->getBMSconfDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionWriteBMScconf_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->setBMSconf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionSaveBMSConfXml_triggered()
|
||||||
|
{
|
||||||
|
QString path;
|
||||||
|
path = QFileDialog::getSaveFileName(this,
|
||||||
|
tr("Choose where to save the motor configuration XML file"),
|
||||||
|
".",
|
||||||
|
tr("Xml files (*.xml)"));
|
||||||
|
|
||||||
|
if (path.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path.toLower().endsWith(".xml")) {
|
||||||
|
path += ".xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = mDieBieMS->bmsConfig()->saveXml(path, "bmsConfiguration");
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
showStatusInfo("Saved motor configuration", true);
|
||||||
|
} else {
|
||||||
|
showMessageDialog(tr("Save motor configuration"),
|
||||||
|
tr("Could not save motor configuration:<BR>"
|
||||||
|
"%1").arg(mDieBieMS->bmsConfig()->xmlStatus()),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionLoadBMSConfXml_triggered()
|
||||||
|
{
|
||||||
|
QString path;
|
||||||
|
path = QFileDialog::getOpenFileName(this,
|
||||||
|
tr("Choose motor configuration file to load"),
|
||||||
|
".",
|
||||||
|
tr("Xml files (*.xml)"));
|
||||||
|
|
||||||
|
if (path.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = mDieBieMS->bmsConfig()->loadXml(path, "bmsConfiguration");
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
showStatusInfo("Loaded motor configuration", true);
|
||||||
|
} else {
|
||||||
|
showMessageDialog(tr("Load motor configuration"),
|
||||||
|
tr("Could not load motor configuration:<BR>"
|
||||||
|
"%1").arg(mDieBieMS->bmsConfig()->xmlStatus()),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionExit_triggered()
|
||||||
|
{
|
||||||
|
qApp->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionAbout_triggered()
|
||||||
|
{
|
||||||
|
QMessageBox::about(this, "ENNOID-BMS Tool", Utility::aboutText());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionLibrariesUsed_triggered()
|
||||||
|
{
|
||||||
|
QMessageBox::about(this, "Libraries Used",
|
||||||
|
tr("<b>Icons<br>"
|
||||||
|
"<a href=\"https://icons8.com/\">https://icons8.com/</a><br><br>"
|
||||||
|
"<b>Plotting<br>"
|
||||||
|
"<a href=\"http://qcustomplot.com/\">http://qcustomplot.com/</a>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::addPageItem(QString name, QString icon, QString groupIcon, bool bold, bool indented)
|
||||||
|
{
|
||||||
|
QListWidgetItem *item = new QListWidgetItem();
|
||||||
|
ui->pageList->addItem(item);
|
||||||
|
PageListItem *li = new PageListItem(name, icon, groupIcon, this);
|
||||||
|
li->setBold(bold);
|
||||||
|
li->setIndented(indented);
|
||||||
|
ui->pageList->setItemWidget(item, li);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::saveParamFileDialog(QString conf, bool wrapIfdef)
|
||||||
|
{
|
||||||
|
ConfigParams *params = 0;
|
||||||
|
|
||||||
|
if (conf.toLower() == "bmsconf") {
|
||||||
|
params = mDieBieMS->bmsConfig();
|
||||||
|
} else {
|
||||||
|
qWarning() << "Invalid conf" << conf;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path;
|
||||||
|
path = QFileDialog::getSaveFileName(this,tr("Choose where to save the configuration header file"),".",tr("h files (*.h)"));
|
||||||
|
|
||||||
|
if (path.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.contains(" ")) {
|
||||||
|
showMessageDialog(tr("Save header"),tr("Spaces are not allowed in the filename."),false, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path.toLower().endsWith(".h")) {
|
||||||
|
path += ".h";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = params->saveCDefines(path, wrapIfdef);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
showStatusInfo("Saved C header", true);
|
||||||
|
} else {
|
||||||
|
showMessageDialog(tr("Save header"),
|
||||||
|
tr("Could not save header"),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::showPage(const QString &name)
|
||||||
|
{
|
||||||
|
for (int i = 0;i < ui->pageList->count();i++) {
|
||||||
|
PageListItem *p = (PageListItem*)(ui->pageList->itemWidget(ui->pageList->item(i)));
|
||||||
|
if (p->name() == name) {
|
||||||
|
ui->pageList->setCurrentRow(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::reloadPages()
|
||||||
|
{
|
||||||
|
// Remove pages (if any)
|
||||||
|
ui->pageList->clear();
|
||||||
|
while (ui->pageWidget->count() != 0) {
|
||||||
|
QWidget* widget = ui->pageWidget->widget(0);
|
||||||
|
ui->pageWidget->removeWidget(widget);
|
||||||
|
widget->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
mPageWelcome = new PageWelcome(this);
|
||||||
|
mPageWelcome->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageWelcome);
|
||||||
|
addPageItem(tr("Welcome"), "://res/icons/Home-96.png", "", true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mPageConnection = new PageConnection(this);
|
||||||
|
mPageConnection->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageConnection);
|
||||||
|
addPageItem(tr("Connection"), "://res/icons/Connected-96.png", "", true);
|
||||||
|
|
||||||
|
mPageFirmware = new PageFirmware(this);
|
||||||
|
mPageFirmware->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageFirmware);
|
||||||
|
addPageItem(tr("Firmware"), "://res/icons/Electronics-96.png", "", true);
|
||||||
|
|
||||||
|
mPageMasterSettings = new PageMasterSettings(this);
|
||||||
|
mPageMasterSettings->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageMasterSettings);
|
||||||
|
addPageItem(tr("Settings"), "://res/icons/Outgoing Data-96.png", "", true);
|
||||||
|
|
||||||
|
#if 0 // disable
|
||||||
|
mPageMasterGeneral = new PageMasterGeneral(this);
|
||||||
|
mPageMasterGeneral->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageMasterGeneral);
|
||||||
|
addPageItem(tr("General"), "://res/icons/Horizontal Settings Mixer-96.png","", false, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0 // disable
|
||||||
|
mPageMasterCell = new PageMasterCell(this);
|
||||||
|
mPageMasterCell->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageMasterCell);
|
||||||
|
addPageItem(tr("Cell Management"), "://res/icons/batteries-96.png","", false, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0 // disable
|
||||||
|
mPageMasterSwitch = new PageMasterSwitch(this);
|
||||||
|
mPageMasterSwitch->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageMasterSwitch);
|
||||||
|
addPageItem(tr("Switch"), "://res/icons/Toggle Off-96_2.png","", false, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0 // disable
|
||||||
|
mPageMasterSignals = new PageMasterSignals(this);
|
||||||
|
mPageMasterSignals->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageMasterSignals);
|
||||||
|
addPageItem(tr("Signals"), "://res/icons/bldc.png","", false, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
mPageMasterDisplay = new PageMasterDisplay(this);
|
||||||
|
mPageMasterDisplay->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageMasterDisplay);
|
||||||
|
addPageItem(tr("Display"), "://res/icons/Calculator-96.png","", false, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
mSlaveSettings = new PageSlaveSettings(this);
|
||||||
|
mSlaveSettings->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mSlaveSettings);
|
||||||
|
addPageItem(tr("Expansion Board Settings"), "://res/icons/Outgoing Data-96.png", "", true);
|
||||||
|
|
||||||
|
mPageSlaveGeneral = new PageSlaveGeneral(this);
|
||||||
|
mPageSlaveGeneral->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageSlaveGeneral);
|
||||||
|
addPageItem(tr("General"), "://res/icons/Horizontal Settings Mixer-96.png","", false, true);
|
||||||
|
|
||||||
|
mPageSlaveSwitch = new PageSlaveSwitch(this);
|
||||||
|
mPageSlaveSwitch->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageSlaveSwitch);
|
||||||
|
addPageItem(tr("Switch"), "://res/icons/Toggle Off-96_2.png","", false, true);
|
||||||
|
|
||||||
|
mPageSlaveIO = new PageSlaveIO(this);
|
||||||
|
mPageSlaveIO->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageSlaveIO);
|
||||||
|
addPageItem(tr("IO"), "://res/icons/Rs 232 Male-96.png","", false, true);
|
||||||
|
|
||||||
|
mPageSlaveFANs = new PageSlaveFAN(this);
|
||||||
|
mPageSlaveFANs->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageSlaveFANs);
|
||||||
|
addPageItem(tr("FANs"), "://res/icons/fan-96.png","", false, true);
|
||||||
|
*/
|
||||||
|
mPageDataAnalysis = new PageDataAnalysis(this);
|
||||||
|
mPageDataAnalysis->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageDataAnalysis);
|
||||||
|
addPageItem(tr("Data Analysis"), "://res/icons/Line Chart-96.png", "", true);
|
||||||
|
|
||||||
|
mPageRtData = new PageRtData(this);
|
||||||
|
mPageRtData->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageRtData);
|
||||||
|
addPageItem(tr("Realtime Data"), "://res/icons/rt_off.png", "", false, true);
|
||||||
|
|
||||||
|
mPageTerminal = new PageTerminal(this);
|
||||||
|
mPageTerminal->setDieBieMS(mDieBieMS);
|
||||||
|
ui->pageWidget->addWidget(mPageTerminal);
|
||||||
|
addPageItem(tr("Terminal"), "://res/icons/Console-96.png", "", true);
|
||||||
|
|
||||||
|
mPageDebugPrint = new PageDebugPrint(this);
|
||||||
|
ui->pageWidget->addWidget(mPageDebugPrint);
|
||||||
|
#if 0
|
||||||
|
addPageItem(tr("Debug Console"), "://res/icons/Bug-96.png", "", true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
mPageSettings = new PageSettings(this);
|
||||||
|
ui->pageWidget->addWidget(mPageSettings);
|
||||||
|
addPageItem(tr("Tool Settings"), "://res/icons/Settings-96.png", "", true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Adjust sizes
|
||||||
|
QFontMetrics fm(this->font());
|
||||||
|
int width = fm.width("Welcome & Wizards++++++");
|
||||||
|
int height = fm.height();
|
||||||
|
|
||||||
|
for(int i = 0; i < ui->pageList->count(); i++) {
|
||||||
|
QListWidgetItem *item = ui->pageList->item(i);
|
||||||
|
item->setSizeHint(QSize(item->sizeHint().width(), height));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->pageList->setMinimumWidth(width);
|
||||||
|
ui->pageList->setMaximumWidth(width);
|
||||||
|
ui->pageLabel->setMaximumWidth(width);
|
||||||
|
ui->pageLabel->setMaximumHeight((394 * width) / 1549);
|
||||||
|
|
||||||
|
ui->pageList->setCurrentRow(0);
|
||||||
|
ui->pageWidget->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::checkUdev()
|
||||||
|
{
|
||||||
|
// Check if udev rules for modemmanager are installed
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QFileInfo fi_mm("/lib/udev/rules.d/77-mm-usb-device-blacklist.rules");
|
||||||
|
if (fi_mm.exists()) {
|
||||||
|
QFileInfo fi_vesc("/lib/udev/rules.d/45-vesc.rules");
|
||||||
|
if (!fi_vesc.exists()) {
|
||||||
|
QMessageBox::StandardButton reply;
|
||||||
|
reply = QMessageBox::information(this,
|
||||||
|
tr("Modemmenager"),
|
||||||
|
tr("It looks like modemmanager is installed on your system, and that "
|
||||||
|
"there are no ENNOID-BMS udev rules installed. This will cause a delay "
|
||||||
|
"from when you plug in the ENNOID-BMS until you can use it. Would you like "
|
||||||
|
"to add a udev rule to prevent modemmanager from grabbing the ENNOID-BMS?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
QFile f_vesc(QDir::temp().absoluteFilePath(fi_vesc.fileName()));
|
||||||
|
if (!f_vesc.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
showMessageDialog(tr("Create File Error"),
|
||||||
|
f_vesc.errorString(),
|
||||||
|
false, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_vesc.write("# Prevent modemmanager from grabbing the ENNOID-BMS\n"
|
||||||
|
"ATTRS{idVendor}==\"0483\", ATTRS{idProduct}==\"5740\", ENV{ID_MM_DEVICE_IGNORE}=\"1\"\n");
|
||||||
|
f_vesc.close();
|
||||||
|
|
||||||
|
QFileInfo fi_new(f_vesc);
|
||||||
|
QProcess process;
|
||||||
|
process.setEnvironment(QProcess::systemEnvironment());
|
||||||
|
process.start("pkexec", QStringList() <<
|
||||||
|
"mv" <<
|
||||||
|
fi_new.absoluteFilePath() <<
|
||||||
|
fi_vesc.absolutePath());
|
||||||
|
waitProcess(process);
|
||||||
|
|
||||||
|
if (process.exitCode() == 0) {
|
||||||
|
QMessageBox::StandardButton reply;
|
||||||
|
reply = QMessageBox::information(this,
|
||||||
|
tr("Modemmenager"),
|
||||||
|
tr("The udev rule was created successfully. Would you like "
|
||||||
|
"to reload udev to apply the new rule?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
QProcess process;
|
||||||
|
process.setEnvironment(QProcess::systemEnvironment());
|
||||||
|
process.start("pkexec", QStringList() <<
|
||||||
|
"udevadm" <<
|
||||||
|
"control" <<
|
||||||
|
"--reload-rules");
|
||||||
|
waitProcess(process);
|
||||||
|
|
||||||
|
if (process.exitCode() == 0) {
|
||||||
|
showMessageDialog(tr("Command Result"),
|
||||||
|
tr("Reloaded udev rules sucessfully."),
|
||||||
|
true, false);
|
||||||
|
} else {
|
||||||
|
QString out = process.readAll();
|
||||||
|
|
||||||
|
if (out.isEmpty()) {
|
||||||
|
showMessageDialog(tr("Command Result"),
|
||||||
|
tr("Could not reload udev rules. A reboot is probably "
|
||||||
|
"required for this change to take effect."),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showMessageDialog(tr("Command Result"),
|
||||||
|
tr("Could not move rules file:\n\n"
|
||||||
|
"%1").
|
||||||
|
arg(QString(process.readAllStandardOutput())),
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
process.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::waitProcess(QProcess &process, bool block, int timeoutMs)
|
||||||
|
{
|
||||||
|
bool wasEnables = isEnabled();
|
||||||
|
bool killed = false;
|
||||||
|
|
||||||
|
if (block) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.waitForStarted();
|
||||||
|
|
||||||
|
QEventLoop loop;
|
||||||
|
QTimer timeoutTimer;
|
||||||
|
timeoutTimer.setSingleShot(true);
|
||||||
|
timeoutTimer.start(timeoutMs);
|
||||||
|
connect(&process, SIGNAL(finished(int)), &loop, SLOT(quit()));
|
||||||
|
connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||||
|
loop.exec();
|
||||||
|
|
||||||
|
if (process.state() == QProcess::Running) {
|
||||||
|
process.kill();
|
||||||
|
process.waitForFinished();
|
||||||
|
killed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEnabled(wasEnables);
|
||||||
|
|
||||||
|
return !killed;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MainWindow::runCmd(QString cmd, QStringList args)
|
||||||
|
{
|
||||||
|
QProcess process;
|
||||||
|
process.setEnvironment(QProcess::systemEnvironment());
|
||||||
|
process.start(cmd, args);
|
||||||
|
waitProcess(process);
|
||||||
|
QString res = process.readAllStandardOutput();
|
||||||
|
process.close();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_pageList_currentRowChanged(int currentRow)
|
||||||
|
{
|
||||||
|
if (currentRow >= 0) {
|
||||||
|
ui->pageWidget->setCurrentIndex(currentRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionParameterEditorBMScconf_triggered()
|
||||||
|
{
|
||||||
|
ParameterEditor *p = new ParameterEditor(this);
|
||||||
|
p->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
p->setParams(mDieBieMS->bmsConfig());
|
||||||
|
p->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionParameterEditorInfo_triggered()
|
||||||
|
{
|
||||||
|
ParameterEditor *p = new ParameterEditor(this);
|
||||||
|
p->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
p->setParams(mDieBieMS->infoConfig());
|
||||||
|
p->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionSaveBMSConfigurationHeader_triggered()
|
||||||
|
{
|
||||||
|
saveParamFileDialog("bmsconf", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionSaveBMSConfigurationHeaderWrap_triggered()
|
||||||
|
{
|
||||||
|
saveParamFileDialog("bmsconf", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionTerminalPrintFaults_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->sendTerminalCmd("faults");
|
||||||
|
showPage("DieBieMS Terminal");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionTerminalShowHelp_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->sendTerminalCmd("help");
|
||||||
|
showPage("DieBieMS Terminal");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionTerminalClear_triggered()
|
||||||
|
{
|
||||||
|
mPageTerminal->clearTerminal();
|
||||||
|
showPage("DieBieMS Terminal");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionTerminalPrintThreads_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->sendTerminalCmd("threads");
|
||||||
|
showPage("DieBieMS Terminal");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionCanFwd_toggled(bool arg1)
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->setSendCan(arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionSafetyInformation_triggered()
|
||||||
|
{
|
||||||
|
HelpDialog::showHelp(this, mDieBieMS->infoConfig(), "wizard_startup_usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionWarrantyStatement_triggered()
|
||||||
|
{
|
||||||
|
HelpDialog::showHelp(this, mDieBieMS->infoConfig(), "wizard_startup_warranty");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionDieBieMSToolChangelog_triggered()
|
||||||
|
{
|
||||||
|
HelpDialog::showHelp(this, "ENNOID-BMS Tool Changelog", Utility::vescToolChangeLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionFirmwareChangelog_triggered()
|
||||||
|
{
|
||||||
|
HelpDialog::showHelp(this, "Firmware Changelog", Utility::fwChangeLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionLicense_triggered()
|
||||||
|
{
|
||||||
|
HelpDialog::showHelp(this, mDieBieMS->infoConfig(), "gpl_text");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionStoreBMScconf_triggered()
|
||||||
|
{
|
||||||
|
mDieBieMS->commands()->storeBMSConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionCalibrateZero_triggered()
|
||||||
|
{
|
||||||
|
if ( mDieBieMS == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !mDieBieMS->isPortConnected() ) {
|
||||||
|
QMessageBox::critical(this,
|
||||||
|
tr("Connection Error"),
|
||||||
|
tr("The ENNOID-BMS is not connected. Please connect it."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDieBieMS->commands()->sendTerminalCmd("setZeroCurrent");
|
||||||
|
QTimer::singleShot(1000, [this](){
|
||||||
|
this->mDieBieMS->commands()->sendTerminalCmd("config_write");
|
||||||
|
});
|
||||||
|
}
|
||||||
170
mainwindow.h
Normal file
170
mainwindow.h
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <cmath>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
#include "parametereditor.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
#include "widgets/pagelistitem.h"
|
||||||
|
#include "widgets/helpdialog.h"
|
||||||
|
#include "widgets/paramdialog.h"
|
||||||
|
#include "pages/pagewelcome.h"
|
||||||
|
#include "pages/pageconnection.h"
|
||||||
|
#include "pages/pagedataanalysis.h"
|
||||||
|
#include "pages/pagertdata.h"
|
||||||
|
#include "pages/pageterminal.h"
|
||||||
|
#include "pages/pagefirmware.h"
|
||||||
|
#include "pages/pagedebugprint.h"
|
||||||
|
#include "pages/pagemastersettings.h"
|
||||||
|
#include "pages/pagemastergeneral.h"
|
||||||
|
#include "pages/pagemasterswitch.h"
|
||||||
|
#include "pages/pagemastercell.h"
|
||||||
|
#include "pages/pagemastersignals.h"
|
||||||
|
#include "pages/pagemasterdisplay.h"
|
||||||
|
#include "pages/pageslavesettings.h"
|
||||||
|
#include "pages/pageslavegeneral.h"
|
||||||
|
#include "pages/pageslaveswitch.h"
|
||||||
|
#include "pages/pageslaveio.h"
|
||||||
|
#include "pages/pageslavefan.h"
|
||||||
|
|
||||||
|
#include "pages/pagesettings.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget *parent = 0);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void timerSlot();
|
||||||
|
void showStatusInfo(QString info, bool isGood);
|
||||||
|
void showMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText);
|
||||||
|
void serialPortNotWritable(const QString &port);
|
||||||
|
void bmsconfUpdated();
|
||||||
|
void bmsConfigCheckResult(QStringList paramsNotSet);
|
||||||
|
void on_actionReconnect_triggered();
|
||||||
|
void on_actionDisconnect_triggered();
|
||||||
|
void on_actionReboot_triggered();
|
||||||
|
void on_actionReadBMScconf_triggered();
|
||||||
|
void on_actionReadBMScconfDefault_triggered();
|
||||||
|
void on_actionWriteBMScconf_triggered();
|
||||||
|
void on_actionSaveBMSConfXml_triggered();
|
||||||
|
void on_actionLoadBMSConfXml_triggered();
|
||||||
|
void on_actionExit_triggered();
|
||||||
|
void on_actionAbout_triggered();
|
||||||
|
void on_actionLibrariesUsed_triggered();
|
||||||
|
void on_pageList_currentRowChanged(int currentRow);
|
||||||
|
void on_actionParameterEditorBMScconf_triggered();
|
||||||
|
void on_actionParameterEditorInfo_triggered();
|
||||||
|
void on_actionSaveBMSConfigurationHeader_triggered();
|
||||||
|
void on_actionSaveBMSConfigurationHeaderWrap_triggered();
|
||||||
|
void on_actionTerminalPrintFaults_triggered();
|
||||||
|
void on_actionTerminalShowHelp_triggered();
|
||||||
|
void on_actionTerminalClear_triggered();
|
||||||
|
void on_actionTerminalPrintThreads_triggered();
|
||||||
|
void on_actionCanFwd_toggled(bool arg1);
|
||||||
|
void on_actionSafetyInformation_triggered();
|
||||||
|
void on_actionWarrantyStatement_triggered();
|
||||||
|
void on_actionDieBieMSToolChangelog_triggered();
|
||||||
|
void on_actionFirmwareChangelog_triggered();
|
||||||
|
void on_actionLicense_triggered();
|
||||||
|
|
||||||
|
void on_actionStoreBMScconf_triggered();
|
||||||
|
|
||||||
|
void on_actionCalibrateZero_triggered();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
|
QSettings mSettings;
|
||||||
|
QString mVersion;
|
||||||
|
BMSInterface *mDieBieMS;
|
||||||
|
QTimer *mTimer;
|
||||||
|
QLabel *mStatusLabel;
|
||||||
|
int mStatusInfoTime;
|
||||||
|
bool mKeyLeft;
|
||||||
|
bool mKeyRight;
|
||||||
|
bool mbmsConfigRead;
|
||||||
|
|
||||||
|
PageWelcome *mPageWelcome;
|
||||||
|
PageConnection *mPageConnection;
|
||||||
|
PageDataAnalysis *mPageDataAnalysis;
|
||||||
|
PageRtData *mPageRtData;
|
||||||
|
PageTerminal *mPageTerminal;
|
||||||
|
PageFirmware *mPageFirmware;
|
||||||
|
PageDebugPrint *mPageDebugPrint;
|
||||||
|
PageMasterSettings *mPageMasterSettings;
|
||||||
|
PageMasterGeneral *mPageMasterGeneral;
|
||||||
|
PageMasterSwitch *mPageMasterSwitch;
|
||||||
|
PageMasterCell *mPageMasterCell;
|
||||||
|
PageMasterSignals *mPageMasterSignals;
|
||||||
|
PageMasterDisplay *mPageMasterDisplay;
|
||||||
|
PageSlaveSettings *mSlaveSettings;
|
||||||
|
PageSlaveGeneral *mPageSlaveGeneral;
|
||||||
|
PageSlaveSwitch *mPageSlaveSwitch;
|
||||||
|
PageSlaveIO *mPageSlaveIO;
|
||||||
|
PageSlaveFAN *mPageSlaveFANs;
|
||||||
|
PageSettings *mPageSettings;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void addPageItem(QString name, QString icon = "", QString groupIcon = "", bool bold = false, bool indented = false);
|
||||||
|
void saveParamFileDialog(QString conf, bool wrapIfdef);
|
||||||
|
void showPage(const QString &name);
|
||||||
|
void reloadPages();
|
||||||
|
void checkUdev();
|
||||||
|
bool waitProcess(QProcess &process, bool block = true, int timeoutMs = 300000);
|
||||||
|
QString runCmd(QString cmd, QStringList args);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
550
mainwindow.ui
Normal file
550
mainwindow.ui
Normal file
@@ -0,0 +1,550 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1054</width>
|
||||||
|
<height>642</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>ENNOID-BMS Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Car Battery-96.png</normaloff>:/res/icons/Car Battery-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout" stretch="1">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="pageLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>220</width>
|
||||||
|
<height>56</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="res.qrc">:/res/logo.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="pageList">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>220</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>220</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QStackedWidget" name="pageWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1054</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionSaveBMSConfXml"/>
|
||||||
|
<addaction name="actionLoadBMSConfXml"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSaveBMSConfigurationHeader"/>
|
||||||
|
<addaction name="actionSaveBMSConfigurationHeaderWrap"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionExit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuHelp">
|
||||||
|
<property name="title">
|
||||||
|
<string>Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionDieBieMSToolChangelog"/>
|
||||||
|
<addaction name="actionFirmwareChangelog"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionAbout"/>
|
||||||
|
<addaction name="actionLibrariesUsed"/>
|
||||||
|
<addaction name="actionAboutQt"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSafetyInformation"/>
|
||||||
|
<addaction name="actionWarrantyStatement"/>
|
||||||
|
<addaction name="actionLicense"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuTools">
|
||||||
|
<property name="title">
|
||||||
|
<string>Developer</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionParameterEditorBMScconf"/>
|
||||||
|
<addaction name="actionParameterEditorInfo"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuTerminal">
|
||||||
|
<property name="title">
|
||||||
|
<string>Terminal</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionTerminalShowHelp"/>
|
||||||
|
<addaction name="actionTerminalPrintFaults"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionTerminalClear"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuCommands">
|
||||||
|
<property name="title">
|
||||||
|
<string>Commands</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionReboot"/>
|
||||||
|
<addaction name="actionCalibrateZero"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuCommands"/>
|
||||||
|
<addaction name="menuTerminal"/>
|
||||||
|
<addaction name="menuTools"/>
|
||||||
|
<addaction name="menuHelp"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolBar" name="mainToolBar">
|
||||||
|
<property name="movable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolButtonStyle">
|
||||||
|
<enum>Qt::ToolButtonIconOnly</enum>
|
||||||
|
</property>
|
||||||
|
<property name="floatable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>RightToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionReconnect"/>
|
||||||
|
<addaction name="actionDisconnect"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionReadBMScconf"/>
|
||||||
|
<addaction name="actionReadBMScconfDefault"/>
|
||||||
|
<addaction name="actionWriteBMScconf"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionStoreBMScconf"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionRtData"/>
|
||||||
|
<addaction name="actionSendAlive"/>
|
||||||
|
<addaction name="actionCanFwd"/>
|
||||||
|
<addaction name="actionCalibrateZero"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
|
<action name="actionReadBMScconf">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/motor_up.png</normaloff>:/res/icons/motor_up.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>readBMScconf</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Read BMS Configuration</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReadBMScconfDefault">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/motor_default.png</normaloff>:/res/icons/motor_default.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>readBMScconfDefault</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Read default BMS configuration</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionWriteBMScconf">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/motor_down.png</normaloff>:/res/icons/motor_down.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>writeBMScconf</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Write BMS configuration</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSaveBMSConfXml">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Save as-96.png</normaloff>:/res/icons/Save as-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save BMS Configuration XML as...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionLoadBMSConfXml">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Open Folder-96.png</normaloff>:/res/icons/Open Folder-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Load BMS Configuration XML</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDisconnect">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Disconnected-96.png</normaloff>:/res/icons/Disconnected-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>disconnect</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Disconnect</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReboot">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Restart-96.png</normaloff>:/res/icons/Restart-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reboot</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reboot</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCanFwd">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/can_off.png</normaloff>
|
||||||
|
<normalon>:/res/icons/can_on.png</normalon>:/res/icons/can_off.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>canFwd</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Forward communication over CAN-bus</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReconnect">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Connected-96.png</normaloff>:/res/icons/Connected-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>reconnect</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reconnect last connection</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRtData">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/rt_off.png</normaloff>
|
||||||
|
<normalon>:/res/icons/rt_on.png</normalon>:/res/icons/rt_off.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>rtData</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Stream realtime data</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExit">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Shutdown-96.png</normaloff>:/res/icons/Shutdown-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Exit</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>About ENNOID-BMS Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>About ENNOID-BMS Tool</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionParameterEditorBMScconf">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Horizontal Settings Mixer-96.png</normaloff>:/res/icons/Horizontal Settings Mixer-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Parameter Editor Config</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSaveBMSConfigurationHeader">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Save as-96.png</normaloff>:/res/icons/Save as-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save BMS Configuration C Header as...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSaveBMSConfigurationHeaderWrap">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Save as-96.png</normaloff>:/res/icons/Save as-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save BMS Configuration C Header (ifdef wrapped) as...</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Save BMS Configuration C Header (ifdef wrapped) as</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRtDataApp">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/rt_app_off.png</normaloff>
|
||||||
|
<normalon>:/res/icons/rt_app_on.png</normalon>:/res/icons/rt_app_off.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>rtDataApp</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Stream realtime app data</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTerminalPrintFaults">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Console-96.png</normaloff>:/res/icons/Console-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Print Faults</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Print Faults</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTerminalShowHelp">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Help-96.png</normaloff>:/res/icons/Help-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Show Help</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTerminalClear">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Delete-96.png</normaloff>:/res/icons/Delete-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear Terminal</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTerminalPrintThreads">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Electronics-96.png</normaloff>:/res/icons/Electronics-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Print Threads</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Print Threads</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSendAlive">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/alive_off.png</normaloff>
|
||||||
|
<normalon>:/res/icons/alive_on.png</normalon>:/res/icons/alive_off.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Send Alive Commands</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Send alive packets periodically to prevent timeout</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionLibrariesUsed">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>About Libraries Used</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAboutQt">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>About Qt</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Show the Qt library's About box</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionParameterEditorInfo">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Horizontal Settings Mixer-96.png</normaloff>:/res/icons/Horizontal Settings Mixer-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Parameter Editor Info</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSafetyInformation">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Safety Information</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionWarrantyStatement">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Limited Warranty Statement</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Limited Warranty Statement</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDieBieMSToolChangelog">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>ENNOID-BMS Tool Changelog</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>ENNOID-BMS Tool Changelog</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionFirmwareChangelog">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Firmware Changelog</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionLicense">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/About-96.png</normaloff>:/res/icons/About-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>License</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionStoreBMScconf">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Save-96.png</normaloff>:/res/icons/Save-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>writeBMScconf</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Store BMS configuration to Flash</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCalibrateZero">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="res.qrc">
|
||||||
|
<normaloff>:/res/icons/Potentiometer-96.png</normaloff>:/res/icons/Potentiometer-96.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Calibrate Zero</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Calibrate zero current of BMS</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources>
|
||||||
|
<include location="res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
2272
mainwindownew.cpp
Normal file
2272
mainwindownew.cpp
Normal file
File diff suppressed because it is too large
Load Diff
209
mainwindownew.h
Normal file
209
mainwindownew.h
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
#ifndef MAINWINDOWNEW_H
|
||||||
|
#define MAINWINDOWNEW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QParallelAnimationGroup>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QButtonGroup>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <cmath>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
#include "bmsinterface.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
#include "parametereditor.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
#include "utility.h"
|
||||||
|
#include "customlefttabbarbutton.h"
|
||||||
|
#include "connectandenterpage.h"
|
||||||
|
#include "debugprintpage.h"
|
||||||
|
|
||||||
|
// RELEASE_VERSION = true => fixed window size and no window header pannel with |hide|expand|close buttons
|
||||||
|
#define RELEASE_VERSION true
|
||||||
|
|
||||||
|
/*
|
||||||
|
start 0 12 = Default that is not in bms it's in somekind of real offline file (we do NOT have connection to bms but there parameters show up somehow)
|
||||||
|
connect 8 8 Config updated with default params not from file, but from default params of bms
|
||||||
|
bms edit | bms edit
|
||||||
|
^ - 8 7 | 8 8 read bms conf
|
||||||
|
-> - 7 7 | 7 8 read default 8 is defaul - that was on the start
|
||||||
|
v - 8 7 | 7 7 write bms config
|
||||||
|
S - | save currect config from bms into outside file to the flash card
|
||||||
|
before | after
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindowNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindowNew : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MainWindowNew(QWidget *parent = nullptr);
|
||||||
|
~MainWindowNew();
|
||||||
|
private:
|
||||||
|
Ui::MainWindowNew *ui;
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum TabWidgetPage
|
||||||
|
{
|
||||||
|
ConnectWindow = 0,
|
||||||
|
AkbMonitor,
|
||||||
|
CellsMonitor,
|
||||||
|
Configuration,
|
||||||
|
Visualization,
|
||||||
|
History,
|
||||||
|
SeriveOfBms,
|
||||||
|
SettingsExtra,
|
||||||
|
};
|
||||||
|
|
||||||
|
TabWidgetPage m_currentPageIndex = AkbMonitor;
|
||||||
|
TabWidgetPage m_prevPageIndex = AkbMonitor;
|
||||||
|
|
||||||
|
bool isConnectWindowActivated() const;
|
||||||
|
|
||||||
|
|
||||||
|
void initAnimationForLeftTabsBar();
|
||||||
|
|
||||||
|
void setAnimParams(QParallelAnimationGroup *group, QPropertyAnimation *a, int sec, int from, int to);
|
||||||
|
void setAnimParamsMin(QParallelAnimationGroup *group, QPropertyAnimation *a, int sec, CustomLeftTabBarButton *btn);
|
||||||
|
void setAnimParamsMax(QParallelAnimationGroup *group, QPropertyAnimation *a, int sec, CustomLeftTabBarButton *btn);
|
||||||
|
void setAnimParamsMin(QParallelAnimationGroup *group, QPropertyAnimation *a, int sec, QLabel *btn);
|
||||||
|
void setAnimParamsMax(QParallelAnimationGroup *group, QPropertyAnimation *a, int sec, QLabel *btn);
|
||||||
|
void setAnimLogoMin(QParallelAnimationGroup *group, QPropertyAnimation *a, int sec, QLabel *btn);
|
||||||
|
void setAnimLogoMax(QParallelAnimationGroup *group, QPropertyAnimation *a, int sec, QLabel *btn);
|
||||||
|
int m_logoWay;
|
||||||
|
|
||||||
|
void clearBtnText(CustomLeftTabBarButton *btn);
|
||||||
|
void clearAllBtnsText();
|
||||||
|
void restoreBtnText(CustomLeftTabBarButton *btn);
|
||||||
|
void restoreAllBtnsText();
|
||||||
|
|
||||||
|
bool m_minimize;
|
||||||
|
QParallelAnimationGroup *m_animgroupMin;
|
||||||
|
QParallelAnimationGroup *m_animgroupMax;
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sendStatusLabelStyleSheet(QString s);
|
||||||
|
|
||||||
|
void sigShowConnectWindow();
|
||||||
|
void loadParams();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onAnyLeftTabBarButtonClicked();
|
||||||
|
|
||||||
|
void timerSlot();
|
||||||
|
void showStatusInfo(QString info, bool isGood);
|
||||||
|
void showMessageDialog(const QString &title, const QString &msg, bool isGood, bool richText);
|
||||||
|
void serialPortNotWritable(const QString &port);
|
||||||
|
void bmsconfUpdated();
|
||||||
|
void bmsConfigCheckResult(QStringList paramsNotSet);
|
||||||
|
|
||||||
|
|
||||||
|
///void bmsconfUpdated();
|
||||||
|
///void showStatusInfo(QString info, bool isGood);
|
||||||
|
///void onTimerSlot();
|
||||||
|
|
||||||
|
void onShrink();
|
||||||
|
//void onMainMenuBarButtonClicked();
|
||||||
|
//void onHideThisAndShowConnectWindow();
|
||||||
|
//void onShowConnectWindow();
|
||||||
|
|
||||||
|
void onShowConnectWindow();
|
||||||
|
void onHideConnectWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int mWidth = 1366;
|
||||||
|
const int mHeight = 738;
|
||||||
|
|
||||||
|
const int mWidthConnectPage = 637;
|
||||||
|
const int mHeightConnectPage = 433;
|
||||||
|
|
||||||
|
void moveApplicationToTheCenter();
|
||||||
|
|
||||||
|
void setAppSizeForFullView();
|
||||||
|
void setAppSizeForConnectionPage();
|
||||||
|
|
||||||
|
QSettings mSettings;
|
||||||
|
QString mVersion;
|
||||||
|
QString mStatusLabelText;
|
||||||
|
//QLabel *mStatusLabel;
|
||||||
|
bool mKeyLeft;
|
||||||
|
bool mKeyRight;
|
||||||
|
QTimer *mTimer;
|
||||||
|
int mStatusInfoTime;
|
||||||
|
bool mMcConfRead;
|
||||||
|
|
||||||
|
BMSInterface *mDieBieMS; // Business logic class
|
||||||
|
|
||||||
|
DebugPrintPage *mPageDebugPrint;
|
||||||
|
|
||||||
|
// UI
|
||||||
|
QButtonGroup* m_btnGroupMainMenuBar;
|
||||||
|
|
||||||
|
//ConnectAndEnterPage mConnect;
|
||||||
|
bool mIsConnectionPrepared;
|
||||||
|
QString mComPortToConnect;
|
||||||
|
|
||||||
|
void setAllMainMenuBarButtonsVisible(bool val);
|
||||||
|
void setLeftTopWidgetsVisible(bool value);
|
||||||
|
void unselectAllLeftTabBarButtons();
|
||||||
|
void selectCurrentLeftTabBarButton();
|
||||||
|
|
||||||
|
void onSelectCurrentLeftTabBarButton();
|
||||||
|
|
||||||
|
void reloadPages();
|
||||||
|
void initDieBieMs();
|
||||||
|
bool addParamRow(ConfigParams *params, QString paramName);
|
||||||
|
|
||||||
|
void checkUdev();
|
||||||
|
|
||||||
|
//
|
||||||
|
void showWindowInOneStaticPlaceWithoutHideResizeCloseButtons();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// To make Window move on MOUSE CLICK MOVE
|
||||||
|
///
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QMouseEvent *evt)
|
||||||
|
{
|
||||||
|
oldPos = evt->globalPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseMoveEvent(QMouseEvent *evt)
|
||||||
|
{
|
||||||
|
const QPoint delta = evt->globalPos() - oldPos;
|
||||||
|
move(x()+delta.x(), y()+delta.y());
|
||||||
|
oldPos = evt->globalPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPoint oldPos;
|
||||||
|
///
|
||||||
|
/// To make Window move on MOUSE CLICK MOVE
|
||||||
|
///
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MAINWINDOWNEW_H
|
||||||
930
mainwindownew.ui
Normal file
930
mainwindownew.ui
Normal file
@@ -0,0 +1,930 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindowNew</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindowNew">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1366</width>
|
||||||
|
<height>738</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindowNew</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QMainWindow#MainWindowNew
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabAkbMonitor,
|
||||||
|
#tabCellsMonitor,
|
||||||
|
#tabConfiguration,
|
||||||
|
#tabVisualization,
|
||||||
|
#tabHistory,
|
||||||
|
#tabSeriveOfBms,
|
||||||
|
#tabSettingsExtra
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc; /*ConfigurationPage*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
QWidget#centralwidget
|
||||||
|
{
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
QScrollArea#scrollArea_2
|
||||||
|
{
|
||||||
|
background-color: #f7f8fc
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
QLabel#lbIconLogo
|
||||||
|
{
|
||||||
|
/*background-image: url(:/images/cubo-verde-logo.png);*/
|
||||||
|
border-image: url(:/res/cubo-verde-logo-white.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#lbHeaderLanguageIcon
|
||||||
|
{
|
||||||
|
/*background-image: url(:/images/cubo-verde-logo.png);*/
|
||||||
|
border-image: url(:/res/language-russ.png) 0 0 0 0 stretch stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#mStatusLabel
|
||||||
|
{
|
||||||
|
font-size:11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbMainMenuBarHideMenu,
|
||||||
|
#pbMainMenuBarAkbMonitor,
|
||||||
|
#pbMainMenuBarCellsMonitor,
|
||||||
|
#pbMainMenuBarConfiguration,
|
||||||
|
#pbMainMenuBarVisualization,
|
||||||
|
#pbMainMenuBarHistory,
|
||||||
|
#pbMainMenuBarSeriveOfBms,
|
||||||
|
#pbMainMenuBarSettingsExtra,
|
||||||
|
#pbMainMenuBarExit
|
||||||
|
{
|
||||||
|
color: #FFFFFF;
|
||||||
|
background-color: #009352;
|
||||||
|
border: 0px solid black;
|
||||||
|
background:#009352;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 85px;
|
||||||
|
font-size:17px;
|
||||||
|
}
|
||||||
|
QPushButton#pbMainMenuBarHideMenu
|
||||||
|
{
|
||||||
|
font-size:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*QPushButton:pressed {
|
||||||
|
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 186, 162, 255), stop:1 rgba(98, 211, 162, 255))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
QPushButton#pbMainMenuBarAkbMonitor:hover:checked,
|
||||||
|
#pbMainMenuBarCellsMonitor:hover:checked,
|
||||||
|
#pbMainMenuBarConfiguration:hover:checked,
|
||||||
|
#pbMainMenuBarVisualization:hover:checked,
|
||||||
|
#pbMainMenuBarHistory:hover:checked,
|
||||||
|
#pbMainMenuBarSeriveOfBms:hover:checked,
|
||||||
|
#pbMainMenuBarSettingsExtra:hover:checked
|
||||||
|
{
|
||||||
|
background-color: #01673a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbMainMenuBarAkbMonitor:!hover:checked,
|
||||||
|
#pbMainMenuBarAkbMonitor:!hover:checked,
|
||||||
|
#pbMainMenuBarCellsMonitor:!hover:checked,
|
||||||
|
#pbMainMenuBarConfiguration:!hover:checked,
|
||||||
|
#pbMainMenuBarVisualization:!hover:checked,
|
||||||
|
#pbMainMenuBarHistory:!hover:checked,
|
||||||
|
#pbMainMenuBarSeriveOfBms:!hover:checked,
|
||||||
|
#pbMainMenuBarSettingsExtra:!hover:checked
|
||||||
|
{
|
||||||
|
background-color: #01673a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbMainMenuBarHideMenu:hover:!checked,
|
||||||
|
#pbMainMenuBarAkbMonitor:hover:!checked,
|
||||||
|
#pbMainMenuBarCellsMonitor:hover:!checked,
|
||||||
|
#pbMainMenuBarConfiguration:hover:!checked,
|
||||||
|
#pbMainMenuBarVisualization:hover:!checked,
|
||||||
|
#pbMainMenuBarHistory:hover:!checked,
|
||||||
|
#pbMainMenuBarSeriveOfBms:hover:!checked,
|
||||||
|
#pbMainMenuBarSettingsExtra:hover:!checked,
|
||||||
|
#pbMainMenuBarExit:hover:!checked
|
||||||
|
{
|
||||||
|
/*background-color: #009352;*/
|
||||||
|
background-color: #028249;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*QPushButton#pbMainMenuBarExit:hover:!pressed
|
||||||
|
{
|
||||||
|
background-color: #01673a;
|
||||||
|
}*/
|
||||||
|
QPushButton#pbMainMenuBarHideMenu:hover:pressed,
|
||||||
|
QPushButton#pbMainMenuBarExit:hover:pressed
|
||||||
|
{
|
||||||
|
background-color: #01673a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------*/
|
||||||
|
|
||||||
|
QPushButton#pbConnect,
|
||||||
|
#pbWriteToNonVolatileBmsMemory,
|
||||||
|
#pbLoadCurrentSettingsFromBms,
|
||||||
|
#pbLoadSettingsFromFile,
|
||||||
|
QPushButton#pbConnect:hover:pressed,
|
||||||
|
#pbWriteToNonVolatileBmsMemory:hover:pressed,
|
||||||
|
#pbLoadCurrentSettingsFromBms:hover:pressed,
|
||||||
|
#pbLoadSettingsFromFile:hover:pressed
|
||||||
|
{
|
||||||
|
color:black;
|
||||||
|
background-color:white;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 14px;
|
||||||
|
border-color: #009352;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbConnect:hover:!pressed,
|
||||||
|
#pbWriteToNonVolatileBmsMemory:hover:!pressed,
|
||||||
|
#pbLoadCurrentSettingsFromBms:hover:!pressed,
|
||||||
|
#pbLoadSettingsFromFile:hover:!pressed
|
||||||
|
{
|
||||||
|
background-color: #0FF73a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbWriteCurrentValuesToBms,
|
||||||
|
QPushButton#pbWriteCurrentValuesToBms:hover:pressed
|
||||||
|
{
|
||||||
|
background-color:#009352;
|
||||||
|
color:white;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size: 14px;
|
||||||
|
border-color: #009352;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbWriteCurrentValuesToBms:hover:!pressed
|
||||||
|
{
|
||||||
|
background-color: #01673a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QPushButton#pbLinkSerialNumber,
|
||||||
|
#pbLinkSoc,
|
||||||
|
#pbLinkRestrictions,
|
||||||
|
#pbLinkClaibrateZero,
|
||||||
|
#pbLinkCellsConfiguration,
|
||||||
|
#pbLinkOutputsSetting,
|
||||||
|
#pbLinkBalancingConfiguration,
|
||||||
|
#pbLinkConfiguration
|
||||||
|
{
|
||||||
|
color:#009352;
|
||||||
|
text-decoration: none;
|
||||||
|
background: transparent;
|
||||||
|
border-color:transparent;
|
||||||
|
text-align:left;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbLinkSerialNumber:hover:!pressed,
|
||||||
|
#pbLinkSoc:hover:!pressed,
|
||||||
|
#pbLinkRestrictions:hover:!pressed,
|
||||||
|
#pbLinkClaibrateZero:hover:!pressed,
|
||||||
|
#pbLinkCellsConfiguration:hover:!pressed,
|
||||||
|
#pbLinkOutputsSetting:hover:!pressed,
|
||||||
|
#pbLinkBalancingConfiguration:hover:!pressed,
|
||||||
|
#pbLinkConfiguration:hover:!pressed
|
||||||
|
{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#pbLinkSerialNumber:hover:pressed,
|
||||||
|
#pbLinkSoc:hover:pressed,
|
||||||
|
#pbLinkRestrictions:hover:pressed,
|
||||||
|
#pbLinkClaibrateZero:hover:pressed,
|
||||||
|
#pbLinkCellsConfiguration:hover:pressed,
|
||||||
|
#pbLinkOutputsSetting:hover:pressed,
|
||||||
|
#pbLinkBalancingConfiguration:hover:pressed,
|
||||||
|
#pbLinkConfiguration:hover:pressed
|
||||||
|
{
|
||||||
|
color:#0093FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------*/
|
||||||
|
/*
|
||||||
|
QGroupBox#gbSerialNumber,
|
||||||
|
#gbConfiguration,
|
||||||
|
#gbSoc
|
||||||
|
{
|
||||||
|
border-radius:10px;
|
||||||
|
border-color: grey;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*-----------------------*/
|
||||||
|
|
||||||
|
QScrollBar {
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #e8e9f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::vertical {
|
||||||
|
width: 10px;
|
||||||
|
margin: 0px 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------*/
|
||||||
|
QScrollBar::sub-page:horizontal {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-left-radius: 9px;
|
||||||
|
border-bottom-left-radius: 9px;
|
||||||
|
}
|
||||||
|
QScrollBar::add-page:horizontal {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-right-radius: 9px;
|
||||||
|
border-bottom-right-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::sub-page:vertical {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-top-left-radius: 9px;
|
||||||
|
border-top-right-radius: 9px;
|
||||||
|
}
|
||||||
|
QScrollBar::add-page:vertical {
|
||||||
|
background: #e8e9f1;
|
||||||
|
border-bottom-left-radius: 9px;
|
||||||
|
border-bottom-right-radius: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------*/
|
||||||
|
QScrollBar::up-arrow,
|
||||||
|
QScrollBar::sub-line,
|
||||||
|
QScrollBar::add-line {
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::handle {
|
||||||
|
background: #009352;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/* border: 1px solid black;*/
|
||||||
|
QTabWidget
|
||||||
|
{
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTabBar::tab
|
||||||
|
{
|
||||||
|
height: 0px;
|
||||||
|
background: #f7f8fc;
|
||||||
|
}
|
||||||
|
QTabWidget::pane
|
||||||
|
{
|
||||||
|
background: #f7f8fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
QTabWidget
|
||||||
|
{
|
||||||
|
background: #f7f8fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QTabWidget::tab-bar
|
||||||
|
{
|
||||||
|
background: #f7f8fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTabBar::tab
|
||||||
|
{
|
||||||
|
height: 0px;
|
||||||
|
background: #f7f8fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTabBar::tab
|
||||||
|
{
|
||||||
|
background: #48555E;
|
||||||
|
color: white;
|
||||||
|
border-color: #48555E;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarAkbMonitor">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>270</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Монитор АКБ</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarExit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>620</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Выход</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarHideMenu">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>170</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>СКРЫТЬ МЕНЮ</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarVisualization">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>420</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Визуализация</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarSeriveOfBms">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>520</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Сервис BMS</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="labLeftTabListBackground">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>-10</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>753</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>14</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: rgb(255, 255, 255);
|
||||||
|
background-color:#009352;
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarHistory">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>470</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>История</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbIconLogo">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>80</x>
|
||||||
|
<y>40</y>
|
||||||
|
<width>111</width>
|
||||||
|
<height>111</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::NoContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarCellsMonitor">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>320</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Монитор ячеек</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarConfiguration">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>370</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Конфигурация</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTabWidget" name="tabWidgetPagesContent">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>280</x>
|
||||||
|
<y>-10</y>
|
||||||
|
<width>1084</width>
|
||||||
|
<height>751</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="ConnectAndEnterPage" name="tabConnect">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Страница</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="AkbMonitorPage" name="tabAkbMonitor">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Tab 1</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="CellsMonitorPage" name="tabCellsMonitor">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Tab 2</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="ConfigurationPage" name="tabConfiguration">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Страница</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="VisualizationPage" name="tabVisualization">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Страница</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="DebugPrintPage" name="tabHistory">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Страница</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="BmsServicePage" name="tabSeriveOfBms">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Страница</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="SettingsExtraPage" name="tabSettingsExtra">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Страница</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderSerialNumberValue">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1130</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>121</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:black;
|
||||||
|
font-weight:bold;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderConnectionName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>990</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:rgba(54, 70, 84, 0.6);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Подключено</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderSerialNumberName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>990</x>
|
||||||
|
<y>50</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:rgba(54, 70, 84, 0.6);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Серийный номер:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="labHeaderSeparator">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1250</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>16</width>
|
||||||
|
<height>61</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>38</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: rgba(54, 70, 84, 0.4);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>|</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderLanguageIcon">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1320</x>
|
||||||
|
<y>35</y>
|
||||||
|
<width>31</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:#0A72BA;
|
||||||
|
font-weight:bold;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderLanguageName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1270</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>41</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:#0A72BA;
|
||||||
|
font-weight:bold;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>РУС</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderBmsVersion">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1160</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>91</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:rgba(54, 70, 84, 0.6);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>BMS v.2.1</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="lbHeaderConnectionIndicator">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>1130</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>21</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Segoe WP SemiLight</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"> color: #009352;
|
||||||
|
background-color: #009352;
|
||||||
|
border-color:#009352;
|
||||||
|
border-width: 0px;
|
||||||
|
border-style: solid;
|
||||||
|
/* border-radius MUST BE width/2 and height/2 */
|
||||||
|
border-radius: 10px;
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>O</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="mStatusLabel">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>6</x>
|
||||||
|
<y>672</y>
|
||||||
|
<width>271</width>
|
||||||
|
<height>61</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TEXT IN STATUS LABEL</string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::AutoText</enum>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="CustomLeftTabBarButton" name="pbMainMenuBarSettingsExtra">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>570</y>
|
||||||
|
<width>281</width>
|
||||||
|
<height>51</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Прочие настройки</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<zorder>labLeftTabListBackground</zorder>
|
||||||
|
<zorder>pbMainMenuBarCellsMonitor</zorder>
|
||||||
|
<zorder>pbMainMenuBarExit</zorder>
|
||||||
|
<zorder>pbMainMenuBarSeriveOfBms</zorder>
|
||||||
|
<zorder>lbIconLogo</zorder>
|
||||||
|
<zorder>pbMainMenuBarVisualization</zorder>
|
||||||
|
<zorder>pbMainMenuBarHideMenu</zorder>
|
||||||
|
<zorder>pbMainMenuBarConfiguration</zorder>
|
||||||
|
<zorder>pbMainMenuBarHistory</zorder>
|
||||||
|
<zorder>pbMainMenuBarAkbMonitor</zorder>
|
||||||
|
<zorder>mStatusLabel</zorder>
|
||||||
|
<zorder>pbMainMenuBarSettingsExtra</zorder>
|
||||||
|
<zorder>tabWidgetPagesContent</zorder>
|
||||||
|
<zorder>lbHeaderLanguageIcon</zorder>
|
||||||
|
<zorder>labHeaderSeparator</zorder>
|
||||||
|
<zorder>lbHeaderConnectionIndicator</zorder>
|
||||||
|
<zorder>lbHeaderSerialNumberValue</zorder>
|
||||||
|
<zorder>lbHeaderSerialNumberName</zorder>
|
||||||
|
<zorder>lbHeaderLanguageName</zorder>
|
||||||
|
<zorder>lbHeaderBmsVersion</zorder>
|
||||||
|
<zorder>lbHeaderConnectionName</zorder>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>CustomLeftTabBarButton</class>
|
||||||
|
<extends>QPushButton</extends>
|
||||||
|
<header location="global">customlefttabbarbutton.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>ConfigurationPage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">configurationpage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>CellsMonitorPage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">cellsmonitorpage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>AkbMonitorPage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">akbmonitorpage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>VisualizationPage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">visualizationpage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>BmsServicePage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">bmsservicepage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>ConnectAndEnterPage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">connectandenterpage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>DebugPrintPage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">debugprintpage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>SettingsExtraPage</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">settingsextrapage.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
219
mobile/AdcMap.qml
Normal file
219
mobile/AdcMap.qml
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int parentWidth: 10
|
||||||
|
property real vMin: 0.0
|
||||||
|
property real vMax: 0.0
|
||||||
|
property real vCenter: 0.0
|
||||||
|
property real vNow: 0.0
|
||||||
|
property real valueNow: 0.5
|
||||||
|
property real vMin2: 0.0
|
||||||
|
property real vMax2: 0.0
|
||||||
|
property real vNow2: 0.0
|
||||||
|
property real valueNow2: 0.5
|
||||||
|
property bool resetDone: true
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mAppConf: VescIf.appConfig()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay() {
|
||||||
|
resultArea.text =
|
||||||
|
"Value : " + parseFloat(valueNow).toFixed(2) + "\n" +
|
||||||
|
"Value2 : " + parseFloat(valueNow2).toFixed(2) + "\n\n" +
|
||||||
|
"Now : " + parseFloat(vNow).toFixed(2) + " V\n" +
|
||||||
|
"Min : " + parseFloat(vMin).toFixed(2) + " V\n" +
|
||||||
|
"Max : " + parseFloat(vMax).toFixed(2) + " V\n" +
|
||||||
|
"Center : " + parseFloat(vCenter).toFixed(2) + " V\n\n" +
|
||||||
|
"Now2 : " + parseFloat(vNow2).toFixed(2) + " V\n" +
|
||||||
|
"Min2 : " + parseFloat(vMin2).toFixed(2) + " V\n" +
|
||||||
|
"Max2 : " + parseFloat(vMax2).toFixed(2) + " V"
|
||||||
|
|
||||||
|
valueBar.value = valueNow
|
||||||
|
valueBar2.value = valueNow2
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog
|
||||||
|
standardButtons: Dialog.Close
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
height: Math.min(implicitHeight, column.height - 40)
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: 10
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
contentWidth: parent.width
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: resultArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 300
|
||||||
|
readOnly: true
|
||||||
|
wrapMode: TextEdit.WordWrap
|
||||||
|
font.family: "DejaVu Sans Mono"
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar {
|
||||||
|
id: valueBar
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.bottomMargin: 5
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
value: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar {
|
||||||
|
id: valueBar2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
value: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: "Help"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
mInfoConf.getLongName("app_adc_mapping_help"),
|
||||||
|
mInfoConf.getDescription("app_adc_mapping_help"),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Reset"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
vMin = 0.0
|
||||||
|
vMax = 0.0
|
||||||
|
vCenter = 0.0
|
||||||
|
vMin2 = 0.0
|
||||||
|
vMax2 = 0.0
|
||||||
|
resetDone = true
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Apply & Write"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
mAppConf.updateParamDouble("app_adc_conf.voltage_start", vMin)
|
||||||
|
mAppConf.updateParamDouble("app_adc_conf.voltage_end", vMax)
|
||||||
|
mAppConf.updateParamDouble("app_adc_conf.voltage_center", vCenter)
|
||||||
|
mAppConf.updateParamDouble("app_adc_conf.voltage2_start", vMin2)
|
||||||
|
mAppConf.updateParamDouble("app_adc_conf.voltage2_end", vMax2)
|
||||||
|
VescIf.emitStatusMessage("Start, End and Center ADC Voltages Applied", true)
|
||||||
|
mCommands.setAppConf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: rtTimer
|
||||||
|
interval: 50
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
if (VescIf.isPortConnected() && dialog.visible) {
|
||||||
|
mCommands.getDecodedAdc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onDecodedAdcReceived: {
|
||||||
|
valueNow = value
|
||||||
|
vNow = voltage
|
||||||
|
valueNow2 = value2
|
||||||
|
vNow2 = voltage2
|
||||||
|
|
||||||
|
if (resetDone) {
|
||||||
|
resetDone = false
|
||||||
|
vMin = vNow
|
||||||
|
vMax = vNow
|
||||||
|
vMin2 = vNow2
|
||||||
|
vMax2 = vNow2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vNow < vMin) {
|
||||||
|
vMin = vNow
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vNow > vMax) {
|
||||||
|
vMax = vNow
|
||||||
|
}
|
||||||
|
|
||||||
|
var range = vMax - vMin
|
||||||
|
var pos = vNow - vMin
|
||||||
|
|
||||||
|
if (pos > (range / 4.0) && pos < ((3.0 * range) / 4.0)) {
|
||||||
|
vCenter = vNow
|
||||||
|
} else {
|
||||||
|
vCenter = range / 2.0 + vMin
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vNow2 < vMin2) {
|
||||||
|
vMin2 = vNow2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vNow2 > vMax2) {
|
||||||
|
vMax2 = vNow2
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
286
mobile/ConfigPageCell.qml
Normal file
286
mobile/ConfigPageCell.qml
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property var editorsVisible: []
|
||||||
|
property bool isHorizontal: width > height
|
||||||
|
|
||||||
|
ParamEditors {
|
||||||
|
id: editors
|
||||||
|
}
|
||||||
|
|
||||||
|
onIsHorizontalChanged: {
|
||||||
|
//updateEditors()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSeparator(text) {
|
||||||
|
editorsVisible.push(editors.createSeparator(scrollCol, text))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.columnSpan = isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyEditors() {
|
||||||
|
for (var i = 0;i < editorsVisible.length;i++) {
|
||||||
|
editorsVisible[i].destroy();
|
||||||
|
}
|
||||||
|
editorsVisible = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditorMc(param) {
|
||||||
|
editorsVisible.push(editors.createEditorMc(scrollCol, param))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.preferredWidth = 500
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.fillsWidth = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEditors() {
|
||||||
|
destroyEditors()
|
||||||
|
|
||||||
|
switch (pageBox.currentText) {
|
||||||
|
case "Specifications":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "Pack configuration":
|
||||||
|
createEditorMc("cellMonitorICCount")
|
||||||
|
createEditorMc("cellMonitorICType")
|
||||||
|
createEditorMc("noOfParallelModules")
|
||||||
|
createEditorMc("noOfCellsSeries")
|
||||||
|
break;
|
||||||
|
case "SOC - Pack capacity":
|
||||||
|
createEditorMc("noOfCellsParallel")
|
||||||
|
createEditorMc("batteryCapacity")
|
||||||
|
break;
|
||||||
|
case "Cell specifications":
|
||||||
|
createEditorMc("cellTechnology")
|
||||||
|
createEditorMc("cellHardOverVoltage")
|
||||||
|
createEditorMc("cellHardUnderVoltage")
|
||||||
|
createEditorMc("cellLCSoftUnderVoltage")
|
||||||
|
createEditorMc("cellSoftOverVoltage")
|
||||||
|
createEditorMc("maxUnderAndOverVoltageErrorCount")
|
||||||
|
createEditorMc("hysteresisDischarge")
|
||||||
|
createEditorMc("hysteresisCharge")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Balancing":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "Balancing configuration":
|
||||||
|
createEditorMc("cellBalanceStart")
|
||||||
|
createEditorMc("cellBalanceDifferenceThreshold")
|
||||||
|
createEditorMc("cellBalanceUpdateInterval")
|
||||||
|
createEditorMc("cellBalanceAllTime")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Throttling":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "Discharge":
|
||||||
|
createEditorMc("cellThrottleLowerStart")
|
||||||
|
createEditorMc("cellThrottleLowerMargin")
|
||||||
|
createEditorMc("throttleDisChargeIncreaseRate")
|
||||||
|
break;
|
||||||
|
case "Charge":
|
||||||
|
createEditorMc("cellThrottleUpperStart")
|
||||||
|
createEditorMc("cellThrottleUpperMargin")
|
||||||
|
createEditorMc("throttleChargeIncreaseRate")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "SoC":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "SoC general":
|
||||||
|
createEditorMc("stateOfChargeMethod")
|
||||||
|
createEditorMc("stateOfChargeStoreInterval")
|
||||||
|
createEditorMc("timeoutChargeCompleted")
|
||||||
|
createEditorMc("timeoutChargingCompletedMinimalMismatch")
|
||||||
|
createEditorMc("maxMismatchThreshold")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
rowSpacing: -5
|
||||||
|
ComboBox {
|
||||||
|
id: pageBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: [
|
||||||
|
"Specifications",
|
||||||
|
"Balancing",
|
||||||
|
"Throttling",
|
||||||
|
"SoC"
|
||||||
|
]
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
var tabTextOld = tabBox.currentText
|
||||||
|
|
||||||
|
switch(currentText) {
|
||||||
|
case "Specifications":
|
||||||
|
tabBox.model = [
|
||||||
|
"Pack configuration",
|
||||||
|
"SOC - Pack capacity",
|
||||||
|
"Cell specifications"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Balancing":
|
||||||
|
tabBox.model = [
|
||||||
|
"Balancing configuration"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Throttling":
|
||||||
|
tabBox.model = [
|
||||||
|
"Discharge",
|
||||||
|
"Charge"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "SoC":
|
||||||
|
tabBox.model = [
|
||||||
|
"SoC general"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabBox.visible = tabBox.currentText.length !== 0
|
||||||
|
|
||||||
|
if (tabTextOld === tabBox.currentText) {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: tabBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: scroll
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
contentWidth: column.width
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: scrollCol
|
||||||
|
anchors.fill: parent
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Write"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setBMSconf(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Read"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.getBMSconf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "..."
|
||||||
|
onClicked: menu.open()
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: menu
|
||||||
|
width: 500
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Read Default Settings"
|
||||||
|
onTriggered: {
|
||||||
|
mCommands.getBMSconfDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
// TODO: For some reason this does not work
|
||||||
|
onBmsConfigCheckResult: {
|
||||||
|
if (paramsNotSet.length > 0) {
|
||||||
|
var notUpdated = "The following parameters were truncated because " +
|
||||||
|
"they were beyond the hardware limits:\n"
|
||||||
|
|
||||||
|
for (var i = 0;i < paramsNotSet.length;i++) {
|
||||||
|
notUpdated += mbmsConf.getLongName(paramsNotSet[i]) + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
VescIf.emitMessageDialog("Parameters truncated", notUpdated, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
203
mobile/ConfigPageDisplay.qml
Normal file
203
mobile/ConfigPageDisplay.qml
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property var editorsVisible: []
|
||||||
|
property bool isHorizontal: width > height
|
||||||
|
|
||||||
|
ParamEditors {
|
||||||
|
id: editors
|
||||||
|
}
|
||||||
|
|
||||||
|
onIsHorizontalChanged: {
|
||||||
|
//updateEditors()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSeparator(text) {
|
||||||
|
editorsVisible.push(editors.createSeparator(scrollCol, text))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.columnSpan = isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyEditors() {
|
||||||
|
for (var i = 0;i < editorsVisible.length;i++) {
|
||||||
|
editorsVisible[i].destroy();
|
||||||
|
}
|
||||||
|
editorsVisible = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditorMc(param) {
|
||||||
|
editorsVisible.push(editors.createEditorMc(scrollCol, param))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.preferredWidth = 500
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.fillsWidth = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEditors() {
|
||||||
|
destroyEditors()
|
||||||
|
|
||||||
|
switch (pageBox.currentText) {
|
||||||
|
case "Duration":
|
||||||
|
createEditorMc("displayTimeoutBatteryDead")
|
||||||
|
createEditorMc("displayTimeoutBatteryError")
|
||||||
|
createEditorMc("displayTimeoutBatteryErrorPreCharge")
|
||||||
|
createEditorMc("displayTimeoutSplashScreen")
|
||||||
|
break;
|
||||||
|
case "Custom":
|
||||||
|
createEditorMc("displayStyle")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
rowSpacing: -5
|
||||||
|
ComboBox {
|
||||||
|
id: pageBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: [
|
||||||
|
"Duration",
|
||||||
|
"Custom"
|
||||||
|
]
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
var tabTextOld = tabBox.currentText
|
||||||
|
|
||||||
|
switch(currentText) {
|
||||||
|
case "Duration":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
case "Custom":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabBox.visible = tabBox.currentText.length !== 0
|
||||||
|
|
||||||
|
if (tabTextOld === tabBox.currentText) {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: tabBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: scroll
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
contentWidth: column.width
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: scrollCol
|
||||||
|
anchors.fill: parent
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Write"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setBMSconf(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Read"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.getBMSconf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "..."
|
||||||
|
onClicked: menu.open()
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: menu
|
||||||
|
width: 500
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Read Default Settings"
|
||||||
|
onTriggered: {
|
||||||
|
mCommands.getBMSconfDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
// TODO: For some reason this does not work
|
||||||
|
onBmsConfigCheckResult: {
|
||||||
|
if (paramsNotSet.length > 0) {
|
||||||
|
var notUpdated = "The following parameters were truncated because " +
|
||||||
|
"they were beyond the hardware limits:\n"
|
||||||
|
|
||||||
|
for (var i = 0;i < paramsNotSet.length;i++) {
|
||||||
|
notUpdated += mbmsConf.getLongName(paramsNotSet[i]) + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
VescIf.emitMessageDialog("Parameters truncated", notUpdated, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
308
mobile/ConfigPageGeneral.qml
Normal file
308
mobile/ConfigPageGeneral.qml
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property var editorsVisible: []
|
||||||
|
property bool isHorizontal: width > height
|
||||||
|
|
||||||
|
ParamEditors {
|
||||||
|
id: editors
|
||||||
|
}
|
||||||
|
|
||||||
|
onIsHorizontalChanged: {
|
||||||
|
//updateEditors()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSeparator(text) {
|
||||||
|
editorsVisible.push(editors.createSeparator(scrollCol, text))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.columnSpan = isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyEditors() {
|
||||||
|
for (var i = 0;i < editorsVisible.length;i++) {
|
||||||
|
editorsVisible[i].destroy();
|
||||||
|
}
|
||||||
|
editorsVisible = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditorMc(param) {
|
||||||
|
editorsVisible.push(editors.createEditorMc(scrollCol, param))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.preferredWidth = 500
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.fillsWidth = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEditors() {
|
||||||
|
destroyEditors()
|
||||||
|
|
||||||
|
switch (pageBox.currentText) {
|
||||||
|
case "Power State":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "Onstate":
|
||||||
|
createEditorMc("pulseToggleButton")
|
||||||
|
createEditorMc("notUsedCurrentThreshold")
|
||||||
|
createEditorMc("notUsedTimeout")
|
||||||
|
createEditorMc("powerDownDelay")
|
||||||
|
createEditorMc("allowForceOn")
|
||||||
|
break;
|
||||||
|
case "Jump to":
|
||||||
|
createEditorMc("extEnableState")
|
||||||
|
createEditorMc("chargeEnableState")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Limits":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "Current":
|
||||||
|
createEditorMc("maxAllowedCurrent")
|
||||||
|
break;
|
||||||
|
case "Temperature discharging":
|
||||||
|
createEditorMc("allowedTempBattDischargingMax")
|
||||||
|
createEditorMc("allowedTempBattDischargingMin")
|
||||||
|
break;
|
||||||
|
case "Temperature charging":
|
||||||
|
createEditorMc("allowedTempBattChargingMax")
|
||||||
|
createEditorMc("allowedTempBattChargingMin")
|
||||||
|
break;
|
||||||
|
case "Temperature cooling/heating":
|
||||||
|
createEditorMc("allowedTempBattCoolingMax")
|
||||||
|
createEditorMc("allowedTempBattCoolingMin")
|
||||||
|
break;
|
||||||
|
case "Temperature Master board":
|
||||||
|
createEditorMc("allowedTempBMSMax")
|
||||||
|
createEditorMc("allowedTempBMSMin")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "CAN":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "CAN configuration":
|
||||||
|
createEditorMc("CANID")
|
||||||
|
createEditorMc("CANIDStyle")
|
||||||
|
createEditorMc("CANBaudRate")
|
||||||
|
break;
|
||||||
|
case "CAN messaging":
|
||||||
|
createEditorMc("emitStatusOverCAN")
|
||||||
|
createEditorMc("emitStatusProtocolType")
|
||||||
|
createEditorMc("useCANSafetyInput")
|
||||||
|
createEditorMc("useCANDelayedPowerDown")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Sensors":
|
||||||
|
switch(tabBox.currentText) {
|
||||||
|
case "NTC specifications battery":
|
||||||
|
createEditorMc("tempEnableMaskBattery")
|
||||||
|
createEditorMc("noOfTempSensorPerModule")
|
||||||
|
createEditorMc("NTCLTC25Deg")
|
||||||
|
createEditorMc("NTCLTCBeta")
|
||||||
|
break;
|
||||||
|
case "NTC specifications expansion Board":
|
||||||
|
createEditorMc("tempEnableMaskExpansion")
|
||||||
|
createEditorMc("noOfExpansionBoard")
|
||||||
|
createEditorMc("noOfTempSensorPerExpansionBoard")
|
||||||
|
createEditorMc("NTCEXP25Deg")
|
||||||
|
createEditorMc("NTCEXPBeta")
|
||||||
|
break;
|
||||||
|
case "NTC advanced settings":
|
||||||
|
createEditorMc("maxUnderAndOverTemperatureErrorCount")
|
||||||
|
createEditorMc("humidityICType")
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
rowSpacing: -5
|
||||||
|
ComboBox {
|
||||||
|
id: pageBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: [
|
||||||
|
"Power State",
|
||||||
|
"Limits",
|
||||||
|
"CAN",
|
||||||
|
"Sensors"
|
||||||
|
]
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
var tabTextOld = tabBox.currentText
|
||||||
|
|
||||||
|
switch(currentText) {
|
||||||
|
case "Power State":
|
||||||
|
tabBox.model = [
|
||||||
|
"Onstate",
|
||||||
|
"Jump to"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Limits":
|
||||||
|
tabBox.model = [
|
||||||
|
"Current",
|
||||||
|
"Temperature discharging",
|
||||||
|
"Temperature charging",
|
||||||
|
"Temperature cooling/heating",
|
||||||
|
"Temperature Master board"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "CAN":
|
||||||
|
tabBox.model = [
|
||||||
|
"CAN configuration",
|
||||||
|
"CAN messaging"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Sensors":
|
||||||
|
tabBox.model = [
|
||||||
|
"NTC specifications battery",
|
||||||
|
"NTC enable",
|
||||||
|
"NTC specifications expansion Board"
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabBox.visible = tabBox.currentText.length !== 0
|
||||||
|
|
||||||
|
if (tabTextOld === tabBox.currentText) {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: tabBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: scroll
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
contentWidth: column.width
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: scrollCol
|
||||||
|
anchors.fill: parent
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Write"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setBMSconf(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Read"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.getBMSconf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "..."
|
||||||
|
onClicked: menu.open()
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: menu
|
||||||
|
width: 500
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Read Default Settings"
|
||||||
|
onTriggered: {
|
||||||
|
mCommands.getBMSconfDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
// TODO: For some reason this does not work
|
||||||
|
onBmsConfigCheckResult: {
|
||||||
|
if (paramsNotSet.length > 0) {
|
||||||
|
var notUpdated = "The following parameters were truncated because " +
|
||||||
|
"they were beyond the hardware limits:\n"
|
||||||
|
|
||||||
|
for (var i = 0;i < paramsNotSet.length;i++) {
|
||||||
|
notUpdated += mbmsConf.getLongName(paramsNotSet[i]) + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
VescIf.emitMessageDialog("Parameters truncated", notUpdated, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
244
mobile/ConfigPageSignal.qml
Normal file
244
mobile/ConfigPageSignal.qml
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property var editorsVisible: []
|
||||||
|
property bool isHorizontal: width > height
|
||||||
|
|
||||||
|
ParamEditors {
|
||||||
|
id: editors
|
||||||
|
}
|
||||||
|
|
||||||
|
onIsHorizontalChanged: {
|
||||||
|
// updateEditors()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSeparator(text) {
|
||||||
|
editorsVisible.push(editors.createSeparator(scrollCol, text))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.columnSpan = isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyEditors() {
|
||||||
|
for (var i = 0;i < editorsVisible.length;i++) {
|
||||||
|
editorsVisible[i].destroy();
|
||||||
|
}
|
||||||
|
editorsVisible = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditorMc(param) {
|
||||||
|
editorsVisible.push(editors.createEditorMc(scrollCol, param))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.preferredWidth = 500
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.fillsWidth = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEditors() {
|
||||||
|
destroyEditors()
|
||||||
|
|
||||||
|
switch (pageBox.currentText) {
|
||||||
|
case "Discharge Current":
|
||||||
|
createEditorMc("shuntLCFactor")
|
||||||
|
break;
|
||||||
|
case "Pack Voltage":
|
||||||
|
createEditorMc("voltageLCFactor")
|
||||||
|
createEditorMc("voltageLCOffset")
|
||||||
|
break;
|
||||||
|
case "Load Voltage":
|
||||||
|
createEditorMc("loadVoltageFactor")
|
||||||
|
createEditorMc("loadVoltageOffset")
|
||||||
|
break;
|
||||||
|
case "Charger Voltage":
|
||||||
|
createEditorMc("chargerVoltageFactor")
|
||||||
|
createEditorMc("chargerVoltageOffset")
|
||||||
|
break;
|
||||||
|
case "Data Source":
|
||||||
|
createEditorMc("packVoltageDataSource")
|
||||||
|
createEditorMc("packCurrentDataSource")
|
||||||
|
break;
|
||||||
|
case "Buzzer Control":
|
||||||
|
createEditorMc("buzzerSignalSource")
|
||||||
|
createEditorMc("buzzerPersistent")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
rowSpacing: -5
|
||||||
|
ComboBox {
|
||||||
|
id: pageBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: [
|
||||||
|
"Discharge Current",
|
||||||
|
"Pack Voltage",
|
||||||
|
"Load Voltage",
|
||||||
|
"Charger Voltage",
|
||||||
|
"Data Source",
|
||||||
|
"Buzzer Control"
|
||||||
|
]
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
var tabTextOld = tabBox.currentText
|
||||||
|
|
||||||
|
switch(currentText) {
|
||||||
|
case "Discharge Current":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
case "Pack Voltage":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
case "Load Voltage":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Charger Voltage":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Data Source":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Buzzer Control":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabBox.visible = tabBox.currentText.length !== 0
|
||||||
|
|
||||||
|
if (tabTextOld === tabBox.currentText) {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: tabBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: scroll
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
contentWidth: column.width
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: scrollCol
|
||||||
|
anchors.fill: parent
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Write"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setBMSconf(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Read"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.getBMSconf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "..."
|
||||||
|
onClicked: menu.open()
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: menu
|
||||||
|
width: 500
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Read Default Settings"
|
||||||
|
onTriggered: {
|
||||||
|
mCommands.getBMSconfDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
// TODO: For some reason this does not work
|
||||||
|
onBmsConfigCheckResult: {
|
||||||
|
if (paramsNotSet.length > 0) {
|
||||||
|
var notUpdated = "The following parameters were truncated because " +
|
||||||
|
"they were beyond the hardware limits:\n"
|
||||||
|
|
||||||
|
for (var i = 0;i < paramsNotSet.length;i++) {
|
||||||
|
notUpdated += mbmsConf.getLongName(paramsNotSet[i]) + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
VescIf.emitMessageDialog("Parameters truncated", notUpdated, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
209
mobile/ConfigPageSwitch.qml
Normal file
209
mobile/ConfigPageSwitch.qml
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property var editorsVisible: []
|
||||||
|
property bool isHorizontal: width > height
|
||||||
|
|
||||||
|
ParamEditors {
|
||||||
|
id: editors
|
||||||
|
}
|
||||||
|
|
||||||
|
onIsHorizontalChanged: {
|
||||||
|
// updateEditors()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSeparator(text) {
|
||||||
|
editorsVisible.push(editors.createSeparator(scrollCol, text))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.columnSpan = isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyEditors() {
|
||||||
|
for (var i = 0;i < editorsVisible.length;i++) {
|
||||||
|
editorsVisible[i].destroy();
|
||||||
|
}
|
||||||
|
editorsVisible = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditorMc(param) {
|
||||||
|
editorsVisible.push(editors.createEditorMc(scrollCol, param))
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.preferredWidth = 500
|
||||||
|
editorsVisible[editorsVisible.length - 1].Layout.fillsWidth = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEditors() {
|
||||||
|
destroyEditors()
|
||||||
|
|
||||||
|
switch (pageBox.currentText) {
|
||||||
|
case "Discharge":
|
||||||
|
createEditorMc("LCUseDischarge")
|
||||||
|
createEditorMc("LCUsePrecharge")
|
||||||
|
createEditorMc("minimalPrechargePercentage")
|
||||||
|
createEditorMc("timeoutLCPreCharge")
|
||||||
|
createEditorMc("timeoutDischargeRetry")
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Charge":
|
||||||
|
createEditorMc("chargerEnabledThreshold")
|
||||||
|
createEditorMc("timeoutChargerDisconnected")
|
||||||
|
createEditorMc("allowChargingDuringDischarge")
|
||||||
|
createEditorMc("timeoutChargeRetry")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
rowSpacing: -5
|
||||||
|
ComboBox {
|
||||||
|
id: pageBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: [
|
||||||
|
"Discharge",
|
||||||
|
"Charge"
|
||||||
|
]
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
var tabTextOld = tabBox.currentText
|
||||||
|
|
||||||
|
switch(currentText) {
|
||||||
|
case "Discharge":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Charge":
|
||||||
|
tabBox.model = [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabBox.visible = tabBox.currentText.length !== 0
|
||||||
|
|
||||||
|
if (tabTextOld === tabBox.currentText) {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: tabBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onCurrentTextChanged: {
|
||||||
|
updateEditors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: scroll
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
contentWidth: column.width
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: scrollCol
|
||||||
|
anchors.fill: parent
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Write"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setBMSconf(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Read"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.getBMSconf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "..."
|
||||||
|
onClicked: menu.open()
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: menu
|
||||||
|
width: 500
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Read Default Settings"
|
||||||
|
onTriggered: {
|
||||||
|
mCommands.getBMSconfDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
// TODO: For some reason this does not work
|
||||||
|
onBmsConfigCheckResult: {
|
||||||
|
if (paramsNotSet.length > 0) {
|
||||||
|
var notUpdated = "The following parameters were truncated because " +
|
||||||
|
"they were beyond the hardware limits:\n"
|
||||||
|
|
||||||
|
for (var i = 0;i < paramsNotSet.length;i++) {
|
||||||
|
notUpdated += mbmsConf.getLongName(paramsNotSet[i]) + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
VescIf.emitMessageDialog("Parameters truncated", notUpdated, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
393
mobile/ConnectBle.qml
Normal file
393
mobile/ConnectBle.qml
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 - 2019 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Ennoid.bmsinterface 1.0
|
||||||
|
import Ennoid.bleuart 1.0
|
||||||
|
import Ennoid.commands 1.0
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: topItem
|
||||||
|
|
||||||
|
property BleUart mBle: VescIf.bleDevice()
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property alias disconnectButton: disconnectButton
|
||||||
|
property bool isHorizontal: width > height
|
||||||
|
signal requestOpenControls()
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
contentWidth: parent.width
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: grid
|
||||||
|
anchors.fill: parent
|
||||||
|
columns: isHorizontal ? 2 : 1
|
||||||
|
columnSpacing: 5
|
||||||
|
anchors.topMargin: 10
|
||||||
|
rowSpacing: 30
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
Layout.columnSpan: isHorizontal ? 2 : 1
|
||||||
|
Layout.preferredWidth: Math.min(topItem.width, topItem.height)
|
||||||
|
Layout.preferredHeight: (sourceSize.height * Layout.preferredWidth) / sourceSize.width
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
source: "qrc:/res/logo_white.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupBox {
|
||||||
|
id: bleConnBox
|
||||||
|
title: qsTr("BLE Connection")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.columnSpan: 1
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
anchors.topMargin: -5
|
||||||
|
anchors.bottomMargin: -5
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
clip: false
|
||||||
|
visible: true
|
||||||
|
rowSpacing: -10
|
||||||
|
columnSpacing: 5
|
||||||
|
rows: 5
|
||||||
|
columns: 6
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: setNameButton
|
||||||
|
text: qsTr("Name")
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
Layout.fillWidth: true
|
||||||
|
enabled: bleBox.count > 0
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (bleItems.rowCount() > 0) {
|
||||||
|
bleNameDialog.open()
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog("Set BLE Device Name",
|
||||||
|
"No device selected.",
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Pair"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
pairDialog.openDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: scanButton
|
||||||
|
text: qsTr("Scan")
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
scanButton.enabled = false
|
||||||
|
mBle.startScan()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: bleBox
|
||||||
|
Layout.columnSpan: 6
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
|
transformOrigin: Item.Center
|
||||||
|
|
||||||
|
textRole: "key"
|
||||||
|
model: ListModel {
|
||||||
|
id: bleItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: disconnectButton
|
||||||
|
text: qsTr("Disconnect")
|
||||||
|
enabled: false
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.columnSpan: 3
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
VescIf.disconnectPort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: connectButton
|
||||||
|
text: qsTr("Connect")
|
||||||
|
enabled: false
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.columnSpan: 3
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (bleItems.rowCount() > 0) {
|
||||||
|
connectButton.enabled = false
|
||||||
|
VescIf.connectBle(bleItems.get(bleBox.currentIndex).value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GroupBox {
|
||||||
|
id: canFwdBox
|
||||||
|
title: qsTr("CAN Forwarding")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.topMargin: -5
|
||||||
|
anchors.bottomMargin: -5
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: -10
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: canIdBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
textRole: "key"
|
||||||
|
model: ListModel {
|
||||||
|
id: canItems
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
if (fwdCanBox.checked && canItems.rowCount() > 0) {
|
||||||
|
mCommands.setCanSendId(canItems.get(canIdBox.currentIndex).value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: fwdCanBox
|
||||||
|
text: qsTr("Activate")
|
||||||
|
enabled: canIdBox.currentIndex >= 0 && canIdBox.count > 0
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setSendCan(fwdCanBox.checked, canItems.get(canIdBox.currentIndex).value)
|
||||||
|
canScanButton.enabled = !checked
|
||||||
|
canAllButton.enabled = !checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar {
|
||||||
|
id: canScanBar
|
||||||
|
visible: false
|
||||||
|
Layout.fillWidth: true
|
||||||
|
indeterminate: true
|
||||||
|
Layout.preferredHeight: canAllButton.height
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: canButtonLayout
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: canAllButton
|
||||||
|
text: "List All (no Scan)"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
canItems.clear()
|
||||||
|
for (var i = 0;i < 255;i++) {
|
||||||
|
var name = "ENNOID-BMS " + i
|
||||||
|
canItems.append({ key: name, value: i })
|
||||||
|
}
|
||||||
|
canIdBox.currentIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: canScanButton
|
||||||
|
text: "Scan CAN Bus"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
canScanBar.indeterminate = true
|
||||||
|
canButtonLayout.visible = false
|
||||||
|
canScanBar.visible = true
|
||||||
|
canItems.clear()
|
||||||
|
enabled = false
|
||||||
|
canAllButton.enabled = false
|
||||||
|
mCommands.pingCan()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PairingDialog {
|
||||||
|
id: pairDialog
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 500
|
||||||
|
running: !scanButton.enabled
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
property int dots: 0
|
||||||
|
onTriggered: {
|
||||||
|
var text = "S"
|
||||||
|
for (var i = 0;i < dots;i++) {
|
||||||
|
text = "-" + text + "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
dots++;
|
||||||
|
if (dots > 3) {
|
||||||
|
dots = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
scanButton.text = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 100
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
connectButton.enabled = (bleItems.rowCount() > 0) && !VescIf.isPortConnected() && !mBle.isConnecting()
|
||||||
|
disconnectButton.enabled = VescIf.isPortConnected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mBle
|
||||||
|
onScanDone: {
|
||||||
|
if (done) {
|
||||||
|
scanButton.enabled = true
|
||||||
|
scanButton.text = qsTr("Scan")
|
||||||
|
}
|
||||||
|
|
||||||
|
bleItems.clear()
|
||||||
|
|
||||||
|
for (var addr in devs) {
|
||||||
|
var name = devs[addr]
|
||||||
|
var name2 = name + " [" + addr + "]"
|
||||||
|
var setName = VescIf.getBleName(addr)
|
||||||
|
if (setName.length > 0) {
|
||||||
|
setName += " [" + addr + "]"
|
||||||
|
bleItems.insert(0, { key: setName, value: addr })
|
||||||
|
} else if (name.indexOf("ENNOID-BMS") !== -1) {
|
||||||
|
bleItems.insert(0, { key: name2, value: addr })
|
||||||
|
} else {
|
||||||
|
bleItems.append({ key: name2, value: addr })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectButton.enabled = (bleItems.rowCount() > 0) && !VescIf.isPortConnected()
|
||||||
|
|
||||||
|
bleBox.currentIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
onBleError: {
|
||||||
|
VescIf.emitMessageDialog("BLE Error", info, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onPingCanRx: {
|
||||||
|
canItems.clear()
|
||||||
|
for (var i = 0;i < devs.length;i++) {
|
||||||
|
var name = "ENNOID-BMS " + devs[i]
|
||||||
|
canItems.append({ key: name, value: devs[i] })
|
||||||
|
}
|
||||||
|
canScanButton.enabled = true
|
||||||
|
canAllButton.enabled = true
|
||||||
|
canIdBox.currentIndex = 0
|
||||||
|
canButtonLayout.visible = true
|
||||||
|
canScanBar.visible = false
|
||||||
|
canScanBar.indeterminate = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: bleNameDialog
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
title: "Set BLE Device Name"
|
||||||
|
|
||||||
|
width: parent.width - 20
|
||||||
|
height: 200
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: Math.max(parent.height / 4 - height / 2, 20)
|
||||||
|
parent: ApplicationWindow.overlay
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
height: stringInput.implicitHeight + 14
|
||||||
|
border.width: 2
|
||||||
|
border.color: "#8d8d8d"
|
||||||
|
color: "#33a8a8a8"
|
||||||
|
radius: 3
|
||||||
|
TextInput {
|
||||||
|
id: stringInput
|
||||||
|
color: "#ffffff"
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 7
|
||||||
|
font.pointSize: 12
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
if (stringInput.text.length > 0) {
|
||||||
|
var addr = bleItems.get(bleBox.currentIndex).value
|
||||||
|
var setName = stringInput.text + " [" + addr + "]"
|
||||||
|
|
||||||
|
VescIf.storeBleName(addr, stringInput.text)
|
||||||
|
VescIf.storeSettings()
|
||||||
|
|
||||||
|
bleItems.set(bleBox.currentIndex, { key: setName, value: addr })
|
||||||
|
bleBox.currentText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
110
mobile/ConnectBle2.qml
Normal file
110
mobile/ConnectBle2.qml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.4
|
||||||
|
import Ennoid.bmsinterface 1.0
|
||||||
|
import Ennoid.bleuart 1.0
|
||||||
|
import Ennoid.commands 1.0
|
||||||
|
|
||||||
|
ConnectBleForm {
|
||||||
|
property BleUart mBle: VescIf.bleDevice()
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
|
||||||
|
scanButton.onClicked: {
|
||||||
|
mBle.startScan()
|
||||||
|
scanButton.enabled = false
|
||||||
|
scanButton.text = "Scanning"
|
||||||
|
}
|
||||||
|
|
||||||
|
connectButton.onClicked: {
|
||||||
|
if (bleItems.rowCount() > 0) {
|
||||||
|
connectButton.enabled = false
|
||||||
|
VescIf.connectBle(bleItems.get(bleBox.currentIndex).value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectButton.onClicked: {
|
||||||
|
VescIf.disconnectPort()
|
||||||
|
}
|
||||||
|
|
||||||
|
fwdCanBox.onClicked: {
|
||||||
|
mCommands.setSendCan(fwdCanBox.checked, canIdBox.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
canIdBox.onValueChanged: {
|
||||||
|
mCommands.setCanSendId(canIdBox.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 500
|
||||||
|
running: !scanButton.enabled
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
property int dots: 0
|
||||||
|
onTriggered: {
|
||||||
|
var text = "Scanning"
|
||||||
|
for (var i = 0;i < dots;i++) {
|
||||||
|
text = "-" + text + "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
dots++;
|
||||||
|
if (dots > 3) {
|
||||||
|
dots = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
scanButton.text = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 100
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
connectButton.enabled = (bleItems.rowCount() > 0) && !VescIf.isPortConnected() && !mBle.isConnecting()
|
||||||
|
disconnectButton.enabled = VescIf.isPortConnected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mBle
|
||||||
|
onScanDone: {
|
||||||
|
if (done) {
|
||||||
|
scanButton.enabled = true
|
||||||
|
scanButton.text = qsTr("Scan")
|
||||||
|
}
|
||||||
|
|
||||||
|
bleItems.clear()
|
||||||
|
|
||||||
|
for (var name in devs) {
|
||||||
|
var name2 = name + " [" + devs[name] + "]"
|
||||||
|
if (name.indexOf("VESC") !== -1) {
|
||||||
|
bleItems.insert(0, { key: name2, value: devs[name] })
|
||||||
|
} else {
|
||||||
|
bleItems.append({ key: name2, value: devs[name] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectButton.enabled = (bleItems.rowCount() > 0) && !VescIf.isPortConnected()
|
||||||
|
|
||||||
|
bleBox.currentIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
159
mobile/ConnectBleForm.ui.qml
Normal file
159
mobile/ConnectBleForm.ui.qml
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property alias scanButton: scanButton
|
||||||
|
property alias connectButton: connectButton
|
||||||
|
property alias disconnectButton: disconnectButton
|
||||||
|
property alias bleItems: bleItems
|
||||||
|
property alias canIdBox: canIdBox
|
||||||
|
property alias fwdCanBox: fwdCanBox
|
||||||
|
|
||||||
|
id: item1
|
||||||
|
width: 400
|
||||||
|
height: 400
|
||||||
|
|
||||||
|
property alias bleBox: bleBox
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
Layout.preferredWidth: Math.min(parent.width, parent.height)
|
||||||
|
Layout.preferredHeight: (300 * Layout.preferredWidth) / 1549
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
source: "../res/logo_white.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
// Spacer
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
clip: false
|
||||||
|
visible: true
|
||||||
|
rowSpacing: 0
|
||||||
|
columnSpacing: 5
|
||||||
|
rows: 4
|
||||||
|
columns: 2
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: connectionName
|
||||||
|
text: "BLE Connection"
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.bottomMargin: 5
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: bleBox
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.preferredHeight: 48
|
||||||
|
Layout.fillHeight: false
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
|
transformOrigin: Item.Center
|
||||||
|
|
||||||
|
textRole: "key"
|
||||||
|
model: ListModel {
|
||||||
|
id: bleItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: scanButton
|
||||||
|
text: qsTr("Scan")
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
Layout.preferredHeight: 48
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: connectButton
|
||||||
|
text: qsTr("Connect")
|
||||||
|
enabled: false
|
||||||
|
Layout.preferredHeight: 48
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: disconnectButton
|
||||||
|
text: qsTr("Disconnect")
|
||||||
|
enabled: false
|
||||||
|
Layout.preferredHeight: 48
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: fwdCanBox
|
||||||
|
text: qsTr("CAN Forward")
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
id: canIdBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: element
|
||||||
|
// Spacer
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
scale: 1.2
|
||||||
|
// Spacer
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
scale: 1.2
|
||||||
|
// Spacer
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
456
mobile/Controls.qml
Normal file
456
mobile/Controls.qml
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int parentWidth: 10
|
||||||
|
property int parentHeight: 10
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mbmsConfig: VescIf.bmsConfig()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
opacitySlider.value = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function testConnected() {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
"Connection Error",
|
||||||
|
"The BMS is not connected. Please connect it to run detection.",
|
||||||
|
false, false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog
|
||||||
|
standardButtons: Dialog.Close
|
||||||
|
modal: false
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 40
|
||||||
|
height: parentHeight - 40
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 20
|
||||||
|
y: 10
|
||||||
|
background.opacity: opacitySlider.value
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
SwipeView {
|
||||||
|
id: swipeView
|
||||||
|
currentIndex: tabBar.currentIndex
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Page {
|
||||||
|
background: Rectangle {
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: currentBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 1
|
||||||
|
prefix: "I: "
|
||||||
|
suffix: " A"
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 500.0
|
||||||
|
realValue: 3.0
|
||||||
|
realStepSize: 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: maintainCurrentBox
|
||||||
|
text: "Continue after release"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
text: "Set REV"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setCurrent(-currentBox.realValue)
|
||||||
|
} else if (!maintainCurrentBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
text: "Set FWD"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setCurrent(currentBox.realValue)
|
||||||
|
} else if (!maintainCurrentBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Brake"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setCurrentBrake(currentBox.realValue)
|
||||||
|
} else if (!maintainCurrentBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Release"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Page {
|
||||||
|
background: Rectangle {
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: dutyBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
prefix: "D: "
|
||||||
|
decimals: 3
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 1.0
|
||||||
|
realValue: 0.1
|
||||||
|
realStepSize: 0.01
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: maintainDutyBox
|
||||||
|
text: "Continue after release"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
text: "Set REV"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setDutyCycle(-dutyBox.realValue)
|
||||||
|
} else if (!maintainDutyBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
text: "Set FWD"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setDutyCycle(dutyBox.realValue)
|
||||||
|
} else if (!maintainDutyBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "0 Duty (brake)"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setDutyCycle(0.0)
|
||||||
|
} else if (!maintainDutyBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Release"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Page {
|
||||||
|
background: Rectangle {
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: speedBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
prefix: "\u03C9: "
|
||||||
|
suffix: " ERPM"
|
||||||
|
decimals: 1
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 500000
|
||||||
|
realValue: 3000
|
||||||
|
realStepSize: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: maintainSpeedBox
|
||||||
|
text: "Continue after release"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
text: "Set REV"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setRpm(-speedBox.realValue)
|
||||||
|
} else if (!maintainSpeedBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
text: "Set FWD"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setRpm(speedBox.realValue)
|
||||||
|
} else if (!maintainSpeedBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "0 ERPM (brake)"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setRpm(0.0)
|
||||||
|
} else if (!maintainSpeedBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Release"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Page {
|
||||||
|
background: Rectangle {
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: posBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
prefix: "P: "
|
||||||
|
suffix: " \u00B0"
|
||||||
|
decimals: 3
|
||||||
|
realFrom: 0
|
||||||
|
realTo: 360
|
||||||
|
realValue: 20
|
||||||
|
realStepSize: 0.1
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: maintainPosBox
|
||||||
|
text: "Continue after release"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Set"
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (pressed) {
|
||||||
|
mCommands.setPos(posBox.realValue)
|
||||||
|
} else if (!maintainPosBox.checked) {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Release"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
mCommands.setCurrent(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
color: "white"
|
||||||
|
text: qsTr("Opacity")
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: opacitySlider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 0.1
|
||||||
|
to: 1.0
|
||||||
|
value: 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header: Rectangle {
|
||||||
|
color: "#dbdbdb"
|
||||||
|
height: tabBar.height
|
||||||
|
|
||||||
|
TabBar {
|
||||||
|
id: tabBar
|
||||||
|
currentIndex: swipeView.currentIndex
|
||||||
|
anchors.fill: parent
|
||||||
|
implicitWidth: 0
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
opacity: 1
|
||||||
|
color: "#4f4f4f"
|
||||||
|
}
|
||||||
|
|
||||||
|
property int buttons: 4
|
||||||
|
property int buttonWidth: 120
|
||||||
|
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("Current")
|
||||||
|
width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons)
|
||||||
|
}
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("Duty")
|
||||||
|
width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons)
|
||||||
|
}
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("RPM")
|
||||||
|
width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons)
|
||||||
|
}
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("Position")
|
||||||
|
width: Math.max(tabBar.buttonWidth, tabBar.width / tabBar.buttons)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: aliveTimer
|
||||||
|
interval: 200
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
if (VescIf.isPortConnected() && dialog.visible) {
|
||||||
|
mCommands.sendAlive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
217
mobile/CustomGauge.qml
Normal file
217
mobile/CustomGauge.qml
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 - 2019 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Extras 1.4
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property alias minimumValue: gauge.minimumValue
|
||||||
|
property alias maximumValue: gauge.maximumValue
|
||||||
|
property alias value: gauge.value
|
||||||
|
property string unitText: ""
|
||||||
|
property string typeText: ""
|
||||||
|
property string tickmarkSuffix: ""
|
||||||
|
property double labelStep: 10
|
||||||
|
property double tickmarkScale: 1
|
||||||
|
property color traceColor: "#606060"
|
||||||
|
property double maxAngle: 144
|
||||||
|
property double minAngle: -144
|
||||||
|
|
||||||
|
CircularGauge {
|
||||||
|
id: gauge
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Behavior on value {
|
||||||
|
NumberAnimation {
|
||||||
|
easing.type: Easing.OutCirc
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
style: CircularGaugeStyle {
|
||||||
|
id: style
|
||||||
|
labelStepSize: labelStep
|
||||||
|
tickmarkStepSize: labelStep
|
||||||
|
labelInset: outerRadius * 0.28
|
||||||
|
tickmarkInset: 2
|
||||||
|
minorTickmarkInset: 2
|
||||||
|
minimumValueAngle: minAngle
|
||||||
|
maximumValueAngle: maxAngle
|
||||||
|
|
||||||
|
background:
|
||||||
|
Canvas {
|
||||||
|
property double value: gauge.value
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
onValueChanged: requestPaint()
|
||||||
|
|
||||||
|
function d2r(degrees) {
|
||||||
|
return degrees * (Math.PI / 180.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPaint: {
|
||||||
|
var ctx = getContext("2d");
|
||||||
|
ctx.reset();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
var gradient = ctx.createRadialGradient(outerRadius, outerRadius, 0,
|
||||||
|
outerRadius, outerRadius, outerRadius)
|
||||||
|
gradient.addColorStop(0.7, Material.background)
|
||||||
|
gradient.addColorStop(1, traceColor)
|
||||||
|
ctx.fillStyle = gradient
|
||||||
|
ctx.arc(outerRadius, outerRadius, outerRadius, 0, Math.PI * 2)
|
||||||
|
ctx.fill()
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = Material.background
|
||||||
|
ctx.lineWidth = outerRadius
|
||||||
|
ctx.arc(outerRadius,
|
||||||
|
outerRadius,
|
||||||
|
outerRadius / 2,
|
||||||
|
d2r(valueToAngle(Math.max(gauge.value, 0)) - 90),
|
||||||
|
d2r(valueToAngle(gauge.maximumValue + 1) - 90));
|
||||||
|
ctx.arc(outerRadius,
|
||||||
|
outerRadius,
|
||||||
|
outerRadius / 2,
|
||||||
|
d2r(valueToAngle(gauge.minimumValue) - 90),
|
||||||
|
d2r(valueToAngle(Math.min(gauge.value, 0)) - 90));
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(outerRadius,
|
||||||
|
outerRadius,
|
||||||
|
outerRadius / 2,
|
||||||
|
d2r(valueToAngle(gauge.maximumValue) - 90),
|
||||||
|
d2r(valueToAngle(gauge.minimumValue) - 90));
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = "darkGray"
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
ctx.arc(outerRadius,
|
||||||
|
outerRadius,
|
||||||
|
outerRadius - 0.5,
|
||||||
|
0, 2 * Math.PI);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
needle: Item {
|
||||||
|
y: -outerRadius * 0.82
|
||||||
|
height: outerRadius * 0.18
|
||||||
|
Rectangle {
|
||||||
|
id: needle
|
||||||
|
height: parent.height
|
||||||
|
color: "red"
|
||||||
|
width: height * 0.13
|
||||||
|
antialiasing: true
|
||||||
|
radius: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Glow {
|
||||||
|
anchors.fill: needle
|
||||||
|
radius: 5
|
||||||
|
samples: 10
|
||||||
|
spread: 0.6
|
||||||
|
color: "darkred"
|
||||||
|
source: needle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreground: Item {
|
||||||
|
Text {
|
||||||
|
id: speedLabel
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: gauge.value.toFixed(0)
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
font.pixelSize: outerRadius * 0.3
|
||||||
|
color: "white"
|
||||||
|
antialiasing: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: speedLabelUnit
|
||||||
|
text: unitText
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: speedLabel.bottom
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
font.pixelSize: outerRadius * 0.15
|
||||||
|
color: "white"
|
||||||
|
antialiasing: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: typeLabel
|
||||||
|
text: typeText
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: speedLabel.top
|
||||||
|
anchors.bottomMargin: outerRadius * 0.1
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
font.pixelSize: outerRadius * 0.15
|
||||||
|
color: "white"
|
||||||
|
antialiasing: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCovered(value) {
|
||||||
|
var res = false
|
||||||
|
if (gauge.value > 0) {
|
||||||
|
if (value <= gauge.value && value >= 0) {
|
||||||
|
res = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value >= gauge.value && value <= 0) {
|
||||||
|
res = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
tickmarkLabel: Text {
|
||||||
|
font.pixelSize: outerRadius * 0.15
|
||||||
|
text: parseFloat(styleData.value * tickmarkScale).toFixed(0) + tickmarkSuffix
|
||||||
|
color: isCovered(styleData.value) ? "white" : "darkGray"
|
||||||
|
antialiasing: true
|
||||||
|
}
|
||||||
|
|
||||||
|
tickmark: Rectangle {
|
||||||
|
implicitWidth: 2
|
||||||
|
implicitHeight: outerRadius * 0.09
|
||||||
|
|
||||||
|
antialiasing: true
|
||||||
|
smooth: true
|
||||||
|
color: isCovered(styleData.value) ? "white" : "darkGray"
|
||||||
|
}
|
||||||
|
|
||||||
|
minorTickmark: Rectangle {
|
||||||
|
implicitWidth: 1.5
|
||||||
|
implicitHeight: outerRadius * 0.05
|
||||||
|
|
||||||
|
antialiasing: true
|
||||||
|
smooth: true
|
||||||
|
color: isCovered(styleData.value) ? "white" : "darkGray"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
262
mobile/DetectBldc.qml
Normal file
262
mobile/DetectBldc.qml
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Vedder.vesc.bmsinterface 1.0
|
||||||
|
import Vedder.vesc.commands 1.0
|
||||||
|
import Vedder.vesc.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int parentWidth: 10
|
||||||
|
property real intLim: 0.0
|
||||||
|
property real coupling: 0.0
|
||||||
|
property var hallTable: []
|
||||||
|
property int hallRes: -4
|
||||||
|
property bool resultReceived: false
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mbmsConfig: VescIf.bmsConfig()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay() {
|
||||||
|
var txt = ""
|
||||||
|
|
||||||
|
txt +=
|
||||||
|
"Integrator limit : " + parseFloat(intLim).toFixed(2) + "\n" +
|
||||||
|
"BEMF Coupling : " + parseFloat(coupling).toFixed(2) + "\n"
|
||||||
|
|
||||||
|
if (hallRes == 0) {
|
||||||
|
txt += "Detected hall sensor table:\n"
|
||||||
|
for (var i = 0;i < hallTable.length;i++) {
|
||||||
|
txt += "" + hallTable[i]
|
||||||
|
|
||||||
|
if (i != hallTable.length - 1) {
|
||||||
|
txt += ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (hallRes == -1) {
|
||||||
|
txt += "Hall sensor detection failed:\n"
|
||||||
|
for (var i = 0;i < hallTable.length;i++) {
|
||||||
|
txt += "" + hallTable[i]
|
||||||
|
|
||||||
|
if (i != hallTable.length - 1) {
|
||||||
|
txt += ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (hallRes == -2) {
|
||||||
|
txt += "WS2811 enabled. Hall sensors cannot be used."
|
||||||
|
} else if (hallRes == -3) {
|
||||||
|
txt += "Encoder enabled. Hall sensors cannot be used."
|
||||||
|
} else if (hallRes == -4) {
|
||||||
|
txt += "Detected hall sensor table:"
|
||||||
|
} else {
|
||||||
|
txt += "Unknown hall error: " + hallRes
|
||||||
|
}
|
||||||
|
|
||||||
|
resultArea.text = txt
|
||||||
|
}
|
||||||
|
|
||||||
|
function testConnected() {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
"Connection Error",
|
||||||
|
"The VESC is not connected. Please connect it to run detection.",
|
||||||
|
false, false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog
|
||||||
|
standardButtons: Dialog.Close
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
height: Math.min(implicitHeight, column.height - 40)
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: 10
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
contentWidth: parent.width
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: currentBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 2
|
||||||
|
realValue: 5.0
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 200.0
|
||||||
|
prefix: "I: "
|
||||||
|
suffix: " A"
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: dutyBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 2
|
||||||
|
realValue: 0.05
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 1.0
|
||||||
|
realStepSize: 0.01
|
||||||
|
prefix: "D: "
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: erpmBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 1
|
||||||
|
realValue: 450.0
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 20000.0
|
||||||
|
realStepSize: 10.0
|
||||||
|
prefix: "\u03C9: "
|
||||||
|
suffix: " ERPM"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: "Help"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
mInfoConf.getLongName("help_bldc_detect"),
|
||||||
|
mInfoConf.getDescription("help_bldc_detect"),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Detect"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (!testConnected()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
detectDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: resultArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 180
|
||||||
|
readOnly: true
|
||||||
|
font.family: "DejaVu Sans Mono"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Apply & Close"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (!resultReceived) {
|
||||||
|
VescIf.emitMessageDialog("Apply Detection Result",
|
||||||
|
"Detection result not received. Make sure to run the detection first.",
|
||||||
|
false, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mbmsConfig.updateParamDouble("sl_bemf_coupling_k", coupling)
|
||||||
|
mbmsConfig.updateParamDouble("sl_cycle_int_limit", intLim)
|
||||||
|
|
||||||
|
if (hallRes == 0) {
|
||||||
|
for(var i = 0;i < 7;i++) {
|
||||||
|
mbmsConfig.updateParamInt("hall_table_" + i, hallTable[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: detectDialog
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Detect BLDC Parameters"
|
||||||
|
|
||||||
|
x: 10
|
||||||
|
y: dialog.y + dialog.height / 2 - height / 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: detectLabel
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text:
|
||||||
|
"This is going to spin up the motor. Make " +
|
||||||
|
"sure that nothing is in the way."
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
mCommands.detectMotorParam(currentBox.realValue, erpmBox.realValue, dutyBox.realValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onBldcDetectReceived: {
|
||||||
|
if (param.cycle_int_limit < 0.01 && param.bemf_coupling_k < 0.01) {
|
||||||
|
VescIf.emitStatusMessage("Bad Detection Result Received", false)
|
||||||
|
VescIf.emitMessageDialog("BLDC Detection",
|
||||||
|
"Bad Detection Result Received",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
VescIf.emitStatusMessage("Detection Result Received", true)
|
||||||
|
intLim = param.cycle_int_limit
|
||||||
|
coupling = param.bemf_coupling_k
|
||||||
|
hallTable = param.hall_table
|
||||||
|
hallRes = param.hall_res
|
||||||
|
resultReceived = true
|
||||||
|
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
194
mobile/DetectFocEncoder.qml
Normal file
194
mobile/DetectFocEncoder.qml
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Vedder.vesc.bmsinterface 1.0
|
||||||
|
import Vedder.vesc.commands 1.0
|
||||||
|
import Vedder.vesc.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int parentWidth: 10
|
||||||
|
property real mOffset: 0.0
|
||||||
|
property real mRatio: 0.0
|
||||||
|
property bool mInverted: false
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mbmsConfig: VescIf.bmsConfig()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay() {
|
||||||
|
resultArea.text =
|
||||||
|
"Offset : " + parseFloat(mOffset).toFixed(1) + "\n" +
|
||||||
|
"Ratio : " + parseFloat(mRatio).toFixed(1) + "\n" +
|
||||||
|
"Inverted : " + mInverted
|
||||||
|
}
|
||||||
|
|
||||||
|
function testConnected() {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
"Connection Error",
|
||||||
|
"The VESC is not connected. Please connect it to run detection.",
|
||||||
|
false, false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog
|
||||||
|
standardButtons: Dialog.Close
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
height: Math.min(implicitHeight, column.height - 40)
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: 10
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
contentWidth: parent.width
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: currentBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 2
|
||||||
|
realValue: 10.0
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 200.0
|
||||||
|
prefix: "I: "
|
||||||
|
suffix: " A"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: "Help"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
mInfoConf.getLongName("help_foc_encoder_detect"),
|
||||||
|
mInfoConf.getDescription("help_foc_encoder_detect"),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Detect"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (!testConnected()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
detectDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: resultArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 200
|
||||||
|
readOnly: true
|
||||||
|
wrapMode: TextEdit.WordWrap
|
||||||
|
font.family: "DejaVuSansMono"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Apply & Close"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
mbmsConfig.updateParamDouble("foc_encoder_offset", mOffset)
|
||||||
|
mbmsConfig.updateParamDouble("foc_encoder_ratio", mRatio)
|
||||||
|
mbmsConfig.updateParamBool("foc_encoder_inverted", mInverted)
|
||||||
|
|
||||||
|
VescIf.emitStatusMessage("Encoder Parameters Applied", true)
|
||||||
|
|
||||||
|
dialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: detectDialog
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Detect FOC Encoder Parameters"
|
||||||
|
|
||||||
|
x: 10
|
||||||
|
y: dialog.y + dialog.height / 2 - height / 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: detectLambdaLabel
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text:
|
||||||
|
"This is going to turn the motor slowly. Make " +
|
||||||
|
"sure that nothing is in the way."
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
mCommands.measureEncoder(currentBox.realValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onEncoderParamReceived: {
|
||||||
|
if (offset > 1000.0) {
|
||||||
|
VescIf.emitStatusMessage("Encoder not enabled in firmware", false)
|
||||||
|
VescIf.emitMessageDialog("Error",
|
||||||
|
"Encoder support is not enabled. Enable it in the general settings.",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
VescIf.emitStatusMessage("Encoder Result Received", true)
|
||||||
|
mOffset = offset
|
||||||
|
mRatio = ratio
|
||||||
|
mInverted = inverted
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
204
mobile/DetectFocHall.qml
Normal file
204
mobile/DetectFocHall.qml
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Vedder.vesc.bmsinterface 1.0
|
||||||
|
import Vedder.vesc.commands 1.0
|
||||||
|
import Vedder.vesc.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int parentWidth: 10
|
||||||
|
property var table: []
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mbmsConfig: VescIf.bmsConfig()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay() {
|
||||||
|
var txt = "Hall Table:\n"
|
||||||
|
|
||||||
|
for (var i = 0;i < table.length;i++) {
|
||||||
|
txt += "" + table[i]
|
||||||
|
|
||||||
|
if (i != table.length - 1) {
|
||||||
|
txt += ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultArea.text = txt
|
||||||
|
}
|
||||||
|
|
||||||
|
function testConnected() {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
"Connection Error",
|
||||||
|
"The VESC is not connected. Please connect it to run detection.",
|
||||||
|
false, false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog
|
||||||
|
standardButtons: Dialog.Close
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
height: Math.min(implicitHeight, column.height - 40)
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: 10
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
contentWidth: parent.width
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: currentBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 2
|
||||||
|
realValue: 10.0
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 200.0
|
||||||
|
prefix: "I: "
|
||||||
|
suffix: " A"
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: "Help"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
mInfoConf.getLongName("help_foc_hall_detect"),
|
||||||
|
mInfoConf.getDescription("help_foc_hall_detect"),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Detect"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (!testConnected()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
detectDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: resultArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 200
|
||||||
|
readOnly: true
|
||||||
|
wrapMode: TextEdit.WordWrap
|
||||||
|
font.family: "DejaVuSansMono"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Apply & Close"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (table.length != 8) {
|
||||||
|
VescIf.emitMessageDialog("Apply Error",
|
||||||
|
"Hall table is empty.",
|
||||||
|
false, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i = 0;i < 7;i++) {
|
||||||
|
mbmsConfig.updateParamInt("foc_hall_table_" + i, table[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
VescIf.emitStatusMessage("Hall Sensor Parameters Applied", true)
|
||||||
|
|
||||||
|
dialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: detectDialog
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Detect FOC Hall Sensor Parameters"
|
||||||
|
|
||||||
|
x: 10
|
||||||
|
y: dialog.y + dialog.height / 2 - height / 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: detectLambdaLabel
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text:
|
||||||
|
"This is going to turn the motor slowly. Make " +
|
||||||
|
"sure that nothing is in the way."
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
mCommands.measureHallFoc(currentBox.realValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onFocHallTableReceived: {
|
||||||
|
if (res !== 0) {
|
||||||
|
VescIf.emitStatusMessage("Bad FOC Hall Detection Result Received", false)
|
||||||
|
VescIf.emitMessageDialog("Bad FOC Hall Detection Result Received",
|
||||||
|
"Could not detect hall sensors. Make sure that everything " +
|
||||||
|
"is connected properly.",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
table = hall_table
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
367
mobile/DetectFocParam.qml
Normal file
367
mobile/DetectFocParam.qml
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Vedder.vesc.bmsinterface 1.0
|
||||||
|
import Vedder.vesc.commands 1.0
|
||||||
|
import Vedder.vesc.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int parentWidth: 10
|
||||||
|
property real res: 0.0
|
||||||
|
property real ind: 0.0
|
||||||
|
property real lambda: 0.0
|
||||||
|
property real kp: 0.0
|
||||||
|
property real ki: 0.0
|
||||||
|
property real gain: 0.0
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mbmsConfig: VescIf.bmsConfig()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay() {
|
||||||
|
resultArea.text =
|
||||||
|
"R : " + parseFloat(res * 1e3).toFixed(2) + " m\u03A9\n" +
|
||||||
|
"L : " + parseFloat(ind * 1e6).toFixed(2) + " µH\n" +
|
||||||
|
"\u03BB : " + parseFloat(lambda * 1e3).toFixed(3) + " mWb\n" +
|
||||||
|
"KP : " + parseFloat(kp).toFixed(4) + "\n" +
|
||||||
|
"KI : " + parseFloat(ki).toFixed(2) + "\n" +
|
||||||
|
"Gain : " + parseFloat(gain).toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcKpKi() {
|
||||||
|
if (res < 1e-10) {
|
||||||
|
VescIf.emitMessageDialog("Calculate Error",
|
||||||
|
"R is 0. Please measure it first.",
|
||||||
|
false, false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ind < 1e-10) {
|
||||||
|
VescIf.emitMessageDialog("Calculate Error",
|
||||||
|
"L is 0. Please measure it first.",
|
||||||
|
false, false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://e2e.ti.com/blogs_/b/motordrivecontrol/archive/2015/07/20/teaching-your-pi-controller-to-behave-part-ii
|
||||||
|
var tc = tcBox.realValue * 1e-6
|
||||||
|
var bw = 1.0 / tc
|
||||||
|
kp = ind * bw;
|
||||||
|
ki = res * bw;
|
||||||
|
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcGain() {
|
||||||
|
if (lambda < 1e-10) {
|
||||||
|
VescIf.emitMessageDialog("Calculate Error",
|
||||||
|
"\u03BB is 0. Please measure it first.",
|
||||||
|
false, false)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gain = 0.001 / (lambda * lambda)
|
||||||
|
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
function testConnected() {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
"Connection Error",
|
||||||
|
"The VESC is not connected. Please connect it to run detection.",
|
||||||
|
false, false)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog
|
||||||
|
standardButtons: Dialog.Close
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
height: Math.min(implicitHeight, column.height - 40)
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: 10
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
contentWidth: parent.width
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: currentBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 2
|
||||||
|
realValue: 5.0
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 200.0
|
||||||
|
prefix: "I: "
|
||||||
|
suffix: " A"
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: dutyBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 2
|
||||||
|
realValue: 0.5
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 1.0
|
||||||
|
realStepSize: 0.1
|
||||||
|
prefix: "D: "
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: erpmBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 1
|
||||||
|
realValue: 450.0
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 20000.0
|
||||||
|
realStepSize: 10.0
|
||||||
|
prefix: "\u03C9: "
|
||||||
|
suffix: " ERPM"
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: tcBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
decimals: 1
|
||||||
|
realValue: 1000.0
|
||||||
|
realFrom: 0.0
|
||||||
|
realTo: 1000000.0
|
||||||
|
realStepSize: 100.0
|
||||||
|
prefix: "T: "
|
||||||
|
suffix: " µS"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Help"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
mInfoConf.getLongName("help_foc_detect"),
|
||||||
|
mInfoConf.getDescription("help_foc_detect"),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: "Detect R&L"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (!testConnected()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
detectRlDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "DETECT \u03BB"
|
||||||
|
font.capitalization: Font.MixedCase
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (!testConnected()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res < 1e-9) {
|
||||||
|
VescIf.emitMessageDialog("Detect",
|
||||||
|
"R is 0. Please measure it first.",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
detectLambdaDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "CALCULATE KP, KI AND \u03BB"
|
||||||
|
font.capitalization: Font.MixedCase
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
calcKpKi()
|
||||||
|
calcGain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: resultArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 200
|
||||||
|
readOnly: true
|
||||||
|
font.family: "DejaVu Sans Mono"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Apply & Close"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (res < 1e-10) {
|
||||||
|
VescIf.emitMessageDialog("Apply Error",
|
||||||
|
"R is 0. Please measure it first.",
|
||||||
|
false, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ind < 1e-10) {
|
||||||
|
VescIf.emitMessageDialog("Apply Error",
|
||||||
|
"L is 0. Please measure it first.",
|
||||||
|
false, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lambda < 1e-10) {
|
||||||
|
VescIf.emitMessageDialog("Apply Error",
|
||||||
|
"\u03BB is 0. Please measure it first.",
|
||||||
|
false, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
calcKpKi()
|
||||||
|
calcGain()
|
||||||
|
|
||||||
|
mbmsConfig.updateParamDouble("foc_motor_r", res)
|
||||||
|
mbmsConfig.updateParamDouble("foc_motor_l", ind)
|
||||||
|
mbmsConfig.updateParamDouble("foc_motor_flux_linkage", lambda)
|
||||||
|
mbmsConfig.updateParamDouble("foc_current_kp", kp)
|
||||||
|
mbmsConfig.updateParamDouble("foc_current_ki", ki)
|
||||||
|
mbmsConfig.updateParamDouble("foc_observer_gain", gain * 1e6)
|
||||||
|
|
||||||
|
dialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: detectRlDialog
|
||||||
|
standardButtons: Dialog.Ok
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Measure R & L"
|
||||||
|
|
||||||
|
x: 10
|
||||||
|
y: dialog.y + dialog.height / 2 - height / 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: detectRlLabel
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text:
|
||||||
|
"When measuring R & L the motor is going to make some noises, but " +
|
||||||
|
"not rotate. These noises are completely normal, so don't unplug " +
|
||||||
|
"anything unless you see smoke."
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
mCommands.measureRL()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: detectLambdaDialog
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Warning"
|
||||||
|
|
||||||
|
x: 10
|
||||||
|
y: dialog.y + dialog.height / 2 - height / 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: detectLambdaLabel
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text:
|
||||||
|
"<font color=\"red\">Warning: </font>" +
|
||||||
|
"This is going to spin up the motor. Make " +
|
||||||
|
"sure that nothing is in the way."
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
mCommands.measureLinkage(currentBox.realValue, erpmBox.realValue, dutyBox.realValue, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onMotorRLReceived: {
|
||||||
|
if (r < 1e-9 && l < 1e-9) {
|
||||||
|
VescIf.emitStatusMessage("Bad FOC Detection Result Received", false)
|
||||||
|
VescIf.emitMessageDialog("Bad Detection Result",
|
||||||
|
"Could not measure the motor resistance and inductance.",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
VescIf.emitStatusMessage("FOC Detection Result Received", true)
|
||||||
|
res = r
|
||||||
|
ind = l * 1e-6
|
||||||
|
calcKpKi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMotorLinkageReceived: {
|
||||||
|
if (flux_linkage < 1e-9) {
|
||||||
|
VescIf.emitStatusMessage("Bad FOC Detection Result Received", false)
|
||||||
|
VescIf.emitMessageDialog("Bad Detection Result",
|
||||||
|
"Could not measure the flux linkage properly. Adjust " +
|
||||||
|
"the start parameters according to the help text and try again.",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
VescIf.emitStatusMessage("FOC Detection Result Received", true)
|
||||||
|
lambda = flux_linkage
|
||||||
|
calcGain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
mobile/DoubleSpinBox.qml
Normal file
69
mobile/DoubleSpinBox.qml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Based on https://stackoverflow.com/questions/43406830/how-to-use-float-in-a-qml-spinbox
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: spinbox.implicitHeight
|
||||||
|
|
||||||
|
property int decimals: 2
|
||||||
|
property real realValue: 0.0
|
||||||
|
property real realFrom: 0.0
|
||||||
|
property real realTo: 100.0
|
||||||
|
property real realStepSize: 1.0
|
||||||
|
property string suffix: ""
|
||||||
|
property string prefix: ""
|
||||||
|
|
||||||
|
SpinBox{
|
||||||
|
id: spinbox
|
||||||
|
anchors.fill: parent
|
||||||
|
editable: true
|
||||||
|
// wheelEnabled: true
|
||||||
|
|
||||||
|
property real factor: Math.pow(10, decimals)
|
||||||
|
stepSize: realStepSize * factor
|
||||||
|
value: Math.round(realValue * factor)
|
||||||
|
to : realTo * factor
|
||||||
|
from : realFrom * factor
|
||||||
|
|
||||||
|
validator: DoubleValidator {
|
||||||
|
bottom: Math.min(spinbox.from, spinbox.to)*spinbox.factor
|
||||||
|
top: Math.max(spinbox.from, spinbox.to)*spinbox.factor
|
||||||
|
}
|
||||||
|
|
||||||
|
textFromValue: function(value, locale) {
|
||||||
|
return prefix + parseFloat(value * 1.0 / factor).toFixed(decimals) + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueFromText: function(text, locale) {
|
||||||
|
return Math.round(parseFloat(text.replace(",", ".").
|
||||||
|
replace(suffix, "").
|
||||||
|
replace(prefix, "")) * factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
if (Math.round(realValue * factor) !== value) {
|
||||||
|
realValue = value * 1.0 / factor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
214
mobile/FilePicker.qml
Normal file
214
mobile/FilePicker.qml
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
/**
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Andrey Semenov
|
||||||
|
Copyright (c) 2017 Benjamin Vedder: Added cancel button, embedded configuration colors.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 1.4 as OldControls
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import Qt.labs.folderlistmodel 2.1
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Window 2.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id:picker
|
||||||
|
signal fileSelected(string fileName)
|
||||||
|
readonly property real textmargin: 8
|
||||||
|
readonly property real textSize: 10
|
||||||
|
readonly property real headerTextSize: 12
|
||||||
|
readonly property real buttonHeight: 24
|
||||||
|
readonly property real rowHeight: 36
|
||||||
|
readonly property real toolbarHeight: 48
|
||||||
|
property bool showDotAndDotDot: false
|
||||||
|
property bool showHidden: true
|
||||||
|
property bool showDirsFirst: true
|
||||||
|
property string folder: "file:///sdcard"
|
||||||
|
property string nameFilters: "*.*"
|
||||||
|
|
||||||
|
function currentFolder() {
|
||||||
|
return folderListModel.folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFolder(fileName) {
|
||||||
|
return folderListModel.isFolder(folderListModel.indexOf(folderListModel.folder + "/" + fileName));
|
||||||
|
}
|
||||||
|
function canMoveUp() {
|
||||||
|
return folderListModel.folder.toString() !== "file:///"
|
||||||
|
}
|
||||||
|
|
||||||
|
function onItemClick(fileName) {
|
||||||
|
if(!isFolder(fileName)) {
|
||||||
|
fileSelected(fileName)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(fileName === ".." && canMoveUp()) {
|
||||||
|
folderListModel.folder = folderListModel.parentFolder
|
||||||
|
} else if(fileName !== "." && fileName !== "..") {
|
||||||
|
if(folderListModel.folder.toString() === "file:///") {
|
||||||
|
folderListModel.folder += fileName
|
||||||
|
} else {
|
||||||
|
folderListModel.folder += "/" + fileName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: toolbar
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
height: toolbarHeight
|
||||||
|
color: "#3c3c3c"
|
||||||
|
Button {
|
||||||
|
id: button
|
||||||
|
text: ".."
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: buttonHeight
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.top: parent.top
|
||||||
|
enabled: canMoveUp()
|
||||||
|
flat: true
|
||||||
|
onClicked: {
|
||||||
|
if(canMoveUp) {
|
||||||
|
folderListModel.folder = folderListModel.parentFolder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: filePath
|
||||||
|
color: "white"
|
||||||
|
text: folderListModel.folder.toString().replace("file:///", "►").replace("/", "►").replace("/", "►").replace("/", "►").replace("/", "►")
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
elide: Text.ElideMiddle
|
||||||
|
anchors.right: button.left
|
||||||
|
font.italic: true
|
||||||
|
font.bold: true
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: buttonHeight
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.top: parent.top
|
||||||
|
font.pixelSize: textSize
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FolderListModel {
|
||||||
|
id: folderListModel
|
||||||
|
showDotAndDotDot: picker.showDotAndDotDot
|
||||||
|
showHidden: picker.showHidden
|
||||||
|
showDirsFirst: picker.showDirsFirst
|
||||||
|
folder: picker.folder
|
||||||
|
nameFilters: picker.nameFilters
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.top: toolbar.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
OldControls.TableView {
|
||||||
|
id: view
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: folderListModel
|
||||||
|
headerDelegate:headerDelegate
|
||||||
|
rowDelegate: Rectangle {
|
||||||
|
height: rowHeight
|
||||||
|
color: "#6f6f6f"
|
||||||
|
}
|
||||||
|
|
||||||
|
OldControls.TableViewColumn {
|
||||||
|
title: qsTr("FileName")
|
||||||
|
role: "fileName"
|
||||||
|
resizable: true
|
||||||
|
delegate: fileDelegate
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: fileDelegate
|
||||||
|
Item {
|
||||||
|
height: rowHeight
|
||||||
|
Rectangle {
|
||||||
|
color: "#6f6f6f"
|
||||||
|
anchors.fill: parent
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
onItemClick(fileNameText.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: fileNameText
|
||||||
|
color: "white"
|
||||||
|
height: width
|
||||||
|
anchors.left: image.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
text: styleData.value !== undefined ? styleData.value : ""
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
height: buttonHeight
|
||||||
|
width: height
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: textmargin
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
source: isFolder(fileNameText.text) ? "qrc:/res/icons/ic_folder_open_black_48dp.png" :
|
||||||
|
"qrc:/res/icons/ic_insert_drive_file_black_48dp.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component {
|
||||||
|
id: headerDelegate
|
||||||
|
Rectangle {
|
||||||
|
height: rowHeight
|
||||||
|
color: "#535353"
|
||||||
|
Text {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
height: headerTextSize
|
||||||
|
font.bold: true
|
||||||
|
elide: Text.ElideMiddle
|
||||||
|
color: "white"
|
||||||
|
text: styleData.value !== undefined ? styleData.value : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Cancel"
|
||||||
|
Layout.margins: 10
|
||||||
|
Layout.topMargin: -5
|
||||||
|
Layout.bottomMargin: 0
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
picker.enabled = false
|
||||||
|
picker.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
601
mobile/FwUpdate.qml
Normal file
601
mobile/FwUpdate.qml
Normal file
@@ -0,0 +1,601 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
173
mobile/NrfPair.qml
Normal file
173
mobile/NrfPair.qml
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int parentWidth: 10
|
||||||
|
property real pairCnt: 0.0
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: dialog
|
||||||
|
standardButtons: Dialog.Close
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parentWidth - 20
|
||||||
|
height: Math.min(implicitHeight, column.height - 40)
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: 10
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
contentWidth: parent.width
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: timeBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
realFrom: 1.0
|
||||||
|
realTo: 30.0
|
||||||
|
realValue: 10.0
|
||||||
|
decimals: 1
|
||||||
|
prefix: "Time: "
|
||||||
|
suffix: " s"
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar {
|
||||||
|
id: cntBar
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.bottomMargin: 5
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
value: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: "Help"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
mInfoConf.getLongName("help_nrf_pair"),
|
||||||
|
mInfoConf.getDescription("help_nrf_pair"),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: startButton
|
||||||
|
text: "Start"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
mCommands.pairNrf(timeBox.realValue * 1000.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: cntTimer
|
||||||
|
interval: 100
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
if (pairCnt > 0.01) {
|
||||||
|
pairCnt -= 0.1
|
||||||
|
|
||||||
|
if (pairCnt <= 0.01) {
|
||||||
|
startButton.enabled = true
|
||||||
|
pairCnt = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
cntBar.value = pairCnt / timeBox.realValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onNrfPairingRes: {
|
||||||
|
if (!dialog.visible) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (res) {
|
||||||
|
case 0:
|
||||||
|
pairCnt = timeBox.realValue
|
||||||
|
cntBar.value = 1
|
||||||
|
startButton.enabled = false
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
startButton.enabled = true
|
||||||
|
pairCnt = 0.0
|
||||||
|
cntBar.value = 0
|
||||||
|
VescIf.emitStatusMessage("Pairing NRF Sucessful", true)
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
"NRF Pairing",
|
||||||
|
"Pairing was successful.",
|
||||||
|
true, false)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
startButton.enabled = true
|
||||||
|
pairCnt = 0.0
|
||||||
|
cntBar.value = 0
|
||||||
|
VescIf.emitStatusMessage("Pairing NRF Timed Out", false)
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
"NRF Pairing",
|
||||||
|
"Pairing timed out. Make sure to put your device (e.g. NRF nunchuk) " +
|
||||||
|
"in pairing mode before the time runs out." +
|
||||||
|
"<br><br>" +
|
||||||
|
"To put the NRF nunchuk in " +
|
||||||
|
"pairing mode, just switch it on using any of the buttons. Then it " +
|
||||||
|
"will enter pairing mode if it was switched off previously.",
|
||||||
|
false, false)
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
358
mobile/PairingDialog.qml
Normal file
358
mobile/PairingDialog.qml
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.utility 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
loadUuids()
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadUuids() {
|
||||||
|
pairModel.clear()
|
||||||
|
var uuids = VescIf.getPairedUuids()
|
||||||
|
for (var i = 0;i < uuids.length;i++) {
|
||||||
|
pairModel.append({"uuid": uuids[i]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
//property ConfigParams mAppConf: VescIf.appConfig()
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
|
||||||
|
id: dialog
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parent.width - 20
|
||||||
|
height: parent.height - 60
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: 50
|
||||||
|
parent: ApplicationWindow.overlay
|
||||||
|
padding: 10
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: text
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: "white"
|
||||||
|
text: qsTr("These are the BMS paired to this instance of BMS Tool.")
|
||||||
|
font.bold: true
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: pairModel
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: pairList
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
focus: true
|
||||||
|
clip: true
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: pairDelegate
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
property variant modelData: model
|
||||||
|
|
||||||
|
width: pairList.width
|
||||||
|
height: 60
|
||||||
|
color: "#30000000"
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
Layout.preferredWidth: 40
|
||||||
|
Layout.preferredHeight: 40
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.leftMargin: 10
|
||||||
|
source: "qrc:/res/icon.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: "white"
|
||||||
|
text: uuid
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.rightMargin: 10
|
||||||
|
text: "Delete"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
deleteDialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: deleteDialog
|
||||||
|
property int indexNow: 0
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parent.width - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Delete paired BMS"
|
||||||
|
x: 10
|
||||||
|
y: 10 + parent.height / 2 - height / 2
|
||||||
|
parent: ApplicationWindow.overlay
|
||||||
|
|
||||||
|
Text {
|
||||||
|
color: "#ffffff"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text: "This is going to delete this BMS from the paired list. If that BMS " +
|
||||||
|
"has the pairing flag set you won't be able to connect to it over BLE " +
|
||||||
|
"any more. Are you sure?"
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
VescIf.deletePairedUuid(uuid)
|
||||||
|
VescIf.storeSettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: pairModel
|
||||||
|
delegate: pairDelegate
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "..."
|
||||||
|
onClicked: menu.open()
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: menu
|
||||||
|
width: 500
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Add current without pairing"
|
||||||
|
onTriggered: {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
VescIf.addPairedUuid(VescIf.getConnectedUuid());
|
||||||
|
VescIf.storeSettings()
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog("Add UUID",
|
||||||
|
"You are not connected to the BMS. Connect in order to add it.",
|
||||||
|
false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Add from UUID"
|
||||||
|
onTriggered: {
|
||||||
|
uuidEnter.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Unpair connected"
|
||||||
|
onTriggered: {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
if (mCommands.isLimitedMode()) {
|
||||||
|
VescIf.emitMessageDialog("Unpair BMS",
|
||||||
|
"The fiwmare must be updated to unpair this BMS.",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
unpairConnectedDialog.open()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog("Unpair BMS",
|
||||||
|
"You are not connected to the BMS. Connect in order to unpair it.",
|
||||||
|
false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: pairConnectedButton
|
||||||
|
text: "Pair BMS"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
if (VescIf.isPortConnected()) {
|
||||||
|
if (mCommands.isLimitedMode()) {
|
||||||
|
VescIf.emitMessageDialog("Pair BMS",
|
||||||
|
"The fiwmare must be updated to pair this BMS.",
|
||||||
|
false, false)
|
||||||
|
} else {
|
||||||
|
pairConnectedDialog.open()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog("Pair BMS",
|
||||||
|
"You are not connected to the BMS. Connect in order to pair it.",
|
||||||
|
false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Close"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
dialog.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: pairConnectedDialog
|
||||||
|
property int indexNow: 0
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parent.width - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Pair connected BMS"
|
||||||
|
x: 10
|
||||||
|
y: 10 + Math.max((parent.height - height) / 2, 10)
|
||||||
|
parent: ApplicationWindow.overlay
|
||||||
|
|
||||||
|
Text {
|
||||||
|
color: "#ffffff"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text: "This is going to pair the connected BMS with this instance of BMS Tool. BMS Tool instances " +
|
||||||
|
"that are not paired with this BMS will not be able to connect over bluetooth any more. Continue?"
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
VescIf.addPairedUuid(VescIf.getConnectedUuid());
|
||||||
|
VescIf.storeSettings()
|
||||||
|
mAppConf.updateParamBool("pairing_done", true, 0)
|
||||||
|
mCommands.setAppConf()
|
||||||
|
if (Utility.waitSignal(mCommands, "2ackReceived(QString)", 2000)) {
|
||||||
|
VescIf.emitMessageDialog("Pairing Successful!",
|
||||||
|
"Pairing is done! Please note the UUID if this BMS (or take a screenshot) in order " +
|
||||||
|
"to add it to BMS Tool instances that are not paired in the future. The UUID is:\n" +
|
||||||
|
VescIf.getConnectedUuid(),
|
||||||
|
true, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: unpairConnectedDialog
|
||||||
|
property int indexNow: 0
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
width: parent.width - 20
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
title: "Unpair connected BMS"
|
||||||
|
x: 10
|
||||||
|
y: 10 + parent.height / 2 - height / 2
|
||||||
|
parent: ApplicationWindow.overlay
|
||||||
|
|
||||||
|
Text {
|
||||||
|
color: "#ffffff"
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text: "This is going to unpair the connected BMS. Continue?"
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
VescIf.deletePairedUuid(VescIf.getConnectedUuid());
|
||||||
|
VescIf.storeSettings()
|
||||||
|
mAppConf.updateParamBool("pairing_done", false, 0)
|
||||||
|
mCommands.setAppConf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: uuidEnter
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
title: "Add UUID"
|
||||||
|
|
||||||
|
width: parent.width - 20
|
||||||
|
height: 200
|
||||||
|
closePolicy: Popup.CloseOnEscape
|
||||||
|
x: 10
|
||||||
|
y: parent.height / 2 - height / 2
|
||||||
|
parent: ApplicationWindow.overlay
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
height: 20
|
||||||
|
border.width: 2
|
||||||
|
border.color: "#8d8d8d"
|
||||||
|
color: "#33a8a8a8"
|
||||||
|
radius: 3
|
||||||
|
TextInput {
|
||||||
|
id: stringInput
|
||||||
|
color: "#ffffff"
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 7
|
||||||
|
font.pointSize: 12
|
||||||
|
focus: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
if (stringInput.text.length > 0) {
|
||||||
|
VescIf.addPairedUuid(stringInput.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: VescIf
|
||||||
|
|
||||||
|
onPairingListUpdated: {
|
||||||
|
loadUuids()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
139
mobile/ParamEditBool.qml
Normal file
139
mobile/ParamEditBool.qml
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Ennoid.bmsinterface 1.0
|
||||||
|
import Ennoid.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: editor
|
||||||
|
property string paramName: ""
|
||||||
|
property ConfigParams params: null
|
||||||
|
height: 140
|
||||||
|
Layout.fillWidth: true
|
||||||
|
property real maxVal: 1.0
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (params !== null) {
|
||||||
|
nameText.text = params.getLongName(paramName)
|
||||||
|
boolSwitch.checked = params.getParamBool(paramName)
|
||||||
|
|
||||||
|
if (params.getParamTransmittable(paramName)) {
|
||||||
|
nowButton.visible = true
|
||||||
|
defaultButton.visible = true
|
||||||
|
} else {
|
||||||
|
nowButton.visible = false
|
||||||
|
defaultButton.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#4c5a5a5a"
|
||||||
|
radius: 5
|
||||||
|
border.color: "#919191"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: 10
|
||||||
|
anchors.margins: 5
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: nameText
|
||||||
|
color: "white"
|
||||||
|
text: paramName
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Switch {
|
||||||
|
id: boolSwitch
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (params !== null) {
|
||||||
|
if (params.getUpdateOnly() !== paramName) {
|
||||||
|
params.setUpdateOnly("")
|
||||||
|
}
|
||||||
|
params.updateParamBool(paramName, checked, editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
id: nowButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Current"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: defaultButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Default"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdateDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: helpButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Help"
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
params.getLongName(paramName),
|
||||||
|
params.getDescription(paramName),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: params
|
||||||
|
|
||||||
|
onParamChangedBool: {
|
||||||
|
if (src !== editor && name == paramName) {
|
||||||
|
boolSwitch.checked = newParam
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
200
mobile/ParamEditDouble.qml
Normal file
200
mobile/ParamEditDouble.qml
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Ennoid.bmsinterface 1.0
|
||||||
|
import Ennoid.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: editor
|
||||||
|
property string paramName: ""
|
||||||
|
property ConfigParams params: null
|
||||||
|
height: 140
|
||||||
|
Layout.fillWidth: true
|
||||||
|
property real maxVal: 1.0
|
||||||
|
property bool createReady: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (params !== null) {
|
||||||
|
if (Math.abs(params.getParamMaxDouble(paramName)) > params.getParamMinDouble(paramName)) {
|
||||||
|
maxVal = Math.abs(params.getParamMaxDouble(paramName))
|
||||||
|
} else {
|
||||||
|
maxVal = Math.abs(params.getParamMinDouble(paramName))
|
||||||
|
}
|
||||||
|
|
||||||
|
nameText.text = params.getLongName(paramName)
|
||||||
|
valueBox.decimals = params.getParamDecimalsDouble(paramName)
|
||||||
|
valueBox.realFrom = params.getParamMinDouble(paramName) * params.getParamEditorScale(paramName)
|
||||||
|
valueBox.realTo = params.getParamMaxDouble(paramName) * params.getParamEditorScale(paramName)
|
||||||
|
valueBox.realValue = params.getParamDouble(paramName) * params.getParamEditorScale(paramName)
|
||||||
|
valueBox.realStepSize = params.getParamStepDouble(paramName)
|
||||||
|
valueBox.visible = !params.getParamEditAsPercentage(paramName)
|
||||||
|
valueBox.suffix = params.getParamSuffix(paramName)
|
||||||
|
|
||||||
|
var p = (params.getParamDouble(paramName) * 100.0) / maxVal
|
||||||
|
percentageBox.from = (100.0 * params.getParamMinDouble(paramName)) / maxVal
|
||||||
|
percentageBox.to = (100.0 * params.getParamMaxDouble(paramName)) / maxVal
|
||||||
|
percentageBox.value = p
|
||||||
|
percentageBox.visible = params.getParamEditAsPercentage(paramName)
|
||||||
|
|
||||||
|
if (params.getParamTransmittable(paramName)) {
|
||||||
|
nowButton.visible = true
|
||||||
|
defaultButton.visible = true
|
||||||
|
} else {
|
||||||
|
nowButton.visible = false
|
||||||
|
defaultButton.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
createReady = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay(value) {
|
||||||
|
// TODO: No display for now...
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#4c5a5a5a"
|
||||||
|
radius: 5
|
||||||
|
border.color: "#919191"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: 10
|
||||||
|
anchors.margins: 5
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: nameText
|
||||||
|
color: "white"
|
||||||
|
text: paramName
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: valueBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onRealValueChanged: {
|
||||||
|
if (!params.getParamEditAsPercentage(paramName)) {
|
||||||
|
var val = realValue / params.getParamEditorScale(paramName)
|
||||||
|
|
||||||
|
if (params !== null && createReady) {
|
||||||
|
if (params.getUpdateOnly() !== paramName) {
|
||||||
|
params.setUpdateOnly("")
|
||||||
|
}
|
||||||
|
params.updateParamDouble(paramName, val, editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
id: percentageBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
editable: true
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
if (params.getParamEditAsPercentage(paramName)) {
|
||||||
|
var val = (value / 100.0) * maxVal
|
||||||
|
|
||||||
|
if (params !== null && createReady) {
|
||||||
|
if (params.getUpdateOnly() !== paramName) {
|
||||||
|
params.setUpdateOnly("")
|
||||||
|
}
|
||||||
|
params.updateParamDouble(paramName, val, editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textFromValue: function(value, locale) {
|
||||||
|
return Number(value).toLocaleString(locale, 'f', 0) + " %"
|
||||||
|
}
|
||||||
|
|
||||||
|
valueFromText: function(text, locale) {
|
||||||
|
return Number.fromLocaleString(locale, text.replace("%", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
id: nowButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Current"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: defaultButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Default"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdateDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: helpButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Help"
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
params.getLongName(paramName),
|
||||||
|
params.getDescription(paramName),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: params
|
||||||
|
|
||||||
|
onParamChangedDouble: {
|
||||||
|
if (src !== editor && name == paramName) {
|
||||||
|
valueBox.realValue = newParam * params.getParamEditorScale(paramName)
|
||||||
|
percentageBox.value = Math.round((100.0 * newParam) / maxVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
151
mobile/ParamEditEnum.qml
Normal file
151
mobile/ParamEditEnum.qml
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Ennoid.bmsinterface 1.0
|
||||||
|
import Ennoid.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: editor
|
||||||
|
property string paramName: ""
|
||||||
|
property ConfigParams params: null
|
||||||
|
height: 140
|
||||||
|
Layout.fillWidth: true
|
||||||
|
property real maxVal: 1.0
|
||||||
|
property bool createReady: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (params !== null) {
|
||||||
|
nameText.text = params.getLongName(paramName)
|
||||||
|
enumBox.model = params.getParamEnumNames(paramName)
|
||||||
|
enumBox.currentIndex = params.getParamEnum(paramName)
|
||||||
|
|
||||||
|
if (params.getParamTransmittable(paramName)) {
|
||||||
|
nowButton.visible = true
|
||||||
|
defaultButton.visible = true
|
||||||
|
} else {
|
||||||
|
nowButton.visible = false
|
||||||
|
defaultButton.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
createReady = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#4c5a5a5a"
|
||||||
|
radius: 5
|
||||||
|
border.color: "#919191"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.bottomMargin: 2
|
||||||
|
anchors.margins: 10
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: nameText
|
||||||
|
color: "white"
|
||||||
|
text: paramName
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: enumBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
implicitHeight: 35
|
||||||
|
color: enumBox.pressed ? "#606060" : "#505050"
|
||||||
|
border.color: enumBox.hovered ? "#81D4FA" : "#000dc3ff"
|
||||||
|
border.width: enumBox.visualFocus ? 2 : 2
|
||||||
|
radius: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
if (params !== null && createReady) {
|
||||||
|
if (params.getUpdateOnly() !== paramName) {
|
||||||
|
params.setUpdateOnly("")
|
||||||
|
}
|
||||||
|
params.updateParamEnum(paramName, currentIndex, editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
id: nowButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Current"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: defaultButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Default"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdateDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: helpButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Help"
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
params.getLongName(paramName),
|
||||||
|
params.getDescription(paramName),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: params
|
||||||
|
|
||||||
|
onParamChangedEnum: {
|
||||||
|
if (src !== editor && name == paramName) {
|
||||||
|
enumBox.currentIndex = newParam
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
210
mobile/ParamEditInt.qml
Normal file
210
mobile/ParamEditInt.qml
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Ennoid.bmsinterface 1.0
|
||||||
|
import Ennoid.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: editor
|
||||||
|
property string paramName: ""
|
||||||
|
property ConfigParams params: null
|
||||||
|
height: 140
|
||||||
|
Layout.fillWidth: true
|
||||||
|
property real maxVal: 1.0
|
||||||
|
property bool createReady: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (params !== null) {
|
||||||
|
if (Math.abs(params.getParamMaxInt(paramName)) > params.getParamMinInt(paramName)) {
|
||||||
|
maxVal = Math.abs(params.getParamMaxInt(paramName))
|
||||||
|
} else {
|
||||||
|
maxVal = Math.abs(params.getParamMinInt(paramName))
|
||||||
|
}
|
||||||
|
|
||||||
|
nameText.text = params.getLongName(paramName)
|
||||||
|
valueBox.from = params.getParamMinInt(paramName) * params.getParamEditorScale(paramName)
|
||||||
|
valueBox.to = params.getParamMaxInt(paramName) * params.getParamEditorScale(paramName)
|
||||||
|
valueBox.value = params.getParamInt(paramName) * params.getParamEditorScale(paramName)
|
||||||
|
valueBox.stepSize = params.getParamStepInt(paramName)
|
||||||
|
valueBox.visible = !params.getParamEditAsPercentage(paramName)
|
||||||
|
valueBox.suffix = params.getParamSuffix(paramName)
|
||||||
|
|
||||||
|
var p = (params.getParamInt(paramName) * 100.0) / maxVal
|
||||||
|
percentageBox.from = (100.0 * params.getParamMinInt(paramName)) / maxVal
|
||||||
|
percentageBox.to = (100.0 * params.getParamMaxInt(paramName)) / maxVal
|
||||||
|
percentageBox.value = p
|
||||||
|
percentageBox.visible = params.getParamEditAsPercentage(paramName)
|
||||||
|
|
||||||
|
if (params.getParamTransmittable(paramName)) {
|
||||||
|
nowButton.visible = true
|
||||||
|
defaultButton.visible = true
|
||||||
|
} else {
|
||||||
|
nowButton.visible = false
|
||||||
|
defaultButton.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
createReady = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay(value) {
|
||||||
|
// TODO: No display for now...
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#4c5a5a5a"
|
||||||
|
radius: 5
|
||||||
|
border.color: "#919191"
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: 10
|
||||||
|
anchors.margins: 5
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: nameText
|
||||||
|
color: "white"
|
||||||
|
text: paramName
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
id: valueBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
property string suffix: ""
|
||||||
|
editable: true
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
if (!params.getParamEditAsPercentage(paramName)) {
|
||||||
|
var val = value / params.getParamEditorScale(paramName)
|
||||||
|
|
||||||
|
if (params !== null && createReady) {
|
||||||
|
if (params.getUpdateOnly() !== paramName) {
|
||||||
|
params.setUpdateOnly("")
|
||||||
|
}
|
||||||
|
params.updateParamInt(paramName, val, editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textFromValue: function(value, locale) {
|
||||||
|
return Number(value).toLocaleString(locale, 'f', 0) + suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
valueFromText: function(text, locale) {
|
||||||
|
return Number.fromLocaleString(locale, text.replace(suffix, ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinBox {
|
||||||
|
id: percentageBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
editable: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
if (params.getParamEditAsPercentage(paramName)) {
|
||||||
|
var val = (value / 100.0) * maxVal
|
||||||
|
|
||||||
|
if (params !== null && createReady) {
|
||||||
|
if (params.getUpdateOnly() !== paramName) {
|
||||||
|
params.setUpdateOnly("")
|
||||||
|
}
|
||||||
|
params.updateParamInt(paramName, val, editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textFromValue: function(value, locale) {
|
||||||
|
return Number(value).toLocaleString(locale, 'f', 0) + " %"
|
||||||
|
}
|
||||||
|
|
||||||
|
valueFromText: function(text, locale) {
|
||||||
|
return Number.fromLocaleString(locale, text.replace("%", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
id: nowButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Current"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: defaultButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Default"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdateDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: helpButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Help"
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
params.getLongName(paramName),
|
||||||
|
params.getDescription(paramName),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: params
|
||||||
|
|
||||||
|
onParamChangedInt: {
|
||||||
|
if (src !== editor && name == paramName) {
|
||||||
|
valueBox.value = newParam * params.getParamEditorScale(paramName)
|
||||||
|
percentageBox.value = Math.round((100.0 * newParam) / maxVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
mobile/ParamEditSeparator.qml
Normal file
48
mobile/ParamEditSeparator.qml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: name.implicitHeight + 8
|
||||||
|
|
||||||
|
property string sepName: ""
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#9e0000"
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: "white"
|
||||||
|
id: name
|
||||||
|
text: sepName
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: 12
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
148
mobile/ParamEditString.qml
Normal file
148
mobile/ParamEditString.qml
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import Ennoid.bmsinterface 1.0
|
||||||
|
import Ennoid.configparams 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: editor
|
||||||
|
property string paramName: ""
|
||||||
|
property ConfigParams params: null
|
||||||
|
height: column.implicitHeight + 2 * column.anchors.margins
|
||||||
|
Layout.fillWidth: true
|
||||||
|
property real maxVal: 1.0
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (params !== null) {
|
||||||
|
nameText.text = params.getLongName(paramName)
|
||||||
|
stringInput.text = params.getParamQString(paramName)
|
||||||
|
|
||||||
|
if (params.getParamTransmittable(paramName)) {
|
||||||
|
nowButton.visible = true
|
||||||
|
defaultButton.visible = true
|
||||||
|
} else {
|
||||||
|
nowButton.visible = false
|
||||||
|
defaultButton.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: rect
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#4cbfbfbf"
|
||||||
|
radius: 10
|
||||||
|
border.color: "#4c000000"
|
||||||
|
border.width: 3
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 10
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: nameText
|
||||||
|
text: paramName
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
font.pointSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: stringInput.implicitHeight + 14
|
||||||
|
border.width: 2
|
||||||
|
border.color: "#8d8d8d"
|
||||||
|
color: "#33a8a8a8"
|
||||||
|
radius: 3
|
||||||
|
TextInput {
|
||||||
|
id: stringInput
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 7
|
||||||
|
font.pointSize: 12
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
if (params !== null) {
|
||||||
|
if (params.getUpdateOnly() !== paramName) {
|
||||||
|
params.setUpdateOnly("")
|
||||||
|
}
|
||||||
|
params.updateParamString(paramName, text, editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
id: nowButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Current"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: defaultButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Default"
|
||||||
|
onClicked: {
|
||||||
|
params.setUpdateOnly(paramName)
|
||||||
|
params.requestUpdateDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: helpButton
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 500
|
||||||
|
flat: true
|
||||||
|
text: "Help"
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
params.getLongName(paramName),
|
||||||
|
params.getDescription(paramName),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: params
|
||||||
|
|
||||||
|
onParamChangedQString: {
|
||||||
|
if (src !== editor && name == paramName) {
|
||||||
|
stringInput.text = newParam
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
mobile/ParamEditors.qml
Normal file
72
mobile/ParamEditors.qml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property ConfigParams mbmsConfig: VescIf.bmsConfig()
|
||||||
|
|
||||||
|
function createEditor(parent, name, conf) {
|
||||||
|
if (conf.hasParam(name)) {
|
||||||
|
if (conf.isParamDouble(name)) {
|
||||||
|
var component = Qt.createComponent("ParamEditDouble.qml");
|
||||||
|
return component.createObject(parent, {"params": conf, "paramName": name});
|
||||||
|
} else if (conf.isParamInt(name)) {
|
||||||
|
var component2 = Qt.createComponent("ParamEditInt.qml");
|
||||||
|
return component2.createObject(parent, {"params": conf, "paramName": name});
|
||||||
|
} else if (conf.isParamEnum(name)) {
|
||||||
|
var component3 = Qt.createComponent("ParamEditEnum.qml");
|
||||||
|
return component3.createObject(parent, {"params": conf, "paramName": name});
|
||||||
|
} else if (conf.isParamBool(name)) {
|
||||||
|
var component4 = Qt.createComponent("ParamEditBool.qml");
|
||||||
|
return component4.createObject(parent, {"params": conf, "paramName": name});
|
||||||
|
} else if (conf.isParamQString(name)) {
|
||||||
|
var component5 = Qt.createComponent("ParamEditString.qml");
|
||||||
|
return component5.createObject(parent, {"params": conf, "paramName": name});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Parameter " + name + " not found.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEditorMc(parent, name) {
|
||||||
|
return createEditor(parent, name, mbmsConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createSeparator(parent, text) {
|
||||||
|
var component = Qt.createComponent("ParamEditSeparator.qml");
|
||||||
|
return component.createObject(parent, {"sepName": text});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSpacer(parent) {
|
||||||
|
return Qt.createQmlObject(
|
||||||
|
'import QtQuick 2.7; import QtQuick.Layouts 1.3; Rectangle {Layout.fillHeight: true}',
|
||||||
|
parent,
|
||||||
|
"spacer1")
|
||||||
|
}
|
||||||
|
}
|
||||||
193
mobile/PpmMap.qml
Normal file
193
mobile/PpmMap.qml
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Item {
|
||||||
|
implicitHeight: column.implicitHeight
|
||||||
|
|
||||||
|
property real msMin: 0.0
|
||||||
|
property real msMax: 0.0
|
||||||
|
property real msCenter: 0.0
|
||||||
|
property real msNow: 0.0
|
||||||
|
property real valueNow: 0.5
|
||||||
|
property bool resetDone: true
|
||||||
|
|
||||||
|
property Commands mCommands: VescIf.commands()
|
||||||
|
property ConfigParams mInfoConf: VescIf.infoConfig()
|
||||||
|
|
||||||
|
function openDialog() {
|
||||||
|
dialog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDisplay() {
|
||||||
|
resultArea.text =
|
||||||
|
"Value : " + parseFloat(valueNow).toFixed(2) + "\n\n" +
|
||||||
|
"Now : " + parseFloat(msNow).toFixed(4) + " ms\n" +
|
||||||
|
"Min : " + parseFloat(msMin).toFixed(4) + " ms\n" +
|
||||||
|
"Max : " + parseFloat(msMax).toFixed(4) + " ms\n" +
|
||||||
|
"Center : " + parseFloat(msCenter).toFixed(4) + " ms"
|
||||||
|
|
||||||
|
valueBar.value = valueNow
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValid() {
|
||||||
|
return (msMax - msMin) > 0.4
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyMapping() {
|
||||||
|
if (isValid()) {
|
||||||
|
mAppConf.updateParamDouble("app_ppm_conf.pulse_start", msMin)
|
||||||
|
mAppConf.updateParamDouble("app_ppm_conf.pulse_end", msMax)
|
||||||
|
mAppConf.updateParamDouble("app_ppm_conf.pulse_center", msCenter)
|
||||||
|
VescIf.emitStatusMessage("Start, End and Center Pulselengths Applied", true)
|
||||||
|
mCommands.setAppConf()
|
||||||
|
} else {
|
||||||
|
VescIf.emitMessageDialog("Apply Mapping",
|
||||||
|
"Mapped values are not valid. Move the throttle to min, " +
|
||||||
|
"then to max and then leave it in the center.",
|
||||||
|
false,
|
||||||
|
false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
msMin = 0.0
|
||||||
|
msMax = 0.0
|
||||||
|
msCenter = 0.0
|
||||||
|
resetDone = true
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: column
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: resultArea
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 200
|
||||||
|
readOnly: true
|
||||||
|
wrapMode: TextEdit.WordWrap
|
||||||
|
font.family: "DejaVu Sans Mono"
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressBar {
|
||||||
|
id: valueBar
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: -1.0
|
||||||
|
to: 1.0
|
||||||
|
value: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Button {
|
||||||
|
text: "Help"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
flat: true
|
||||||
|
onClicked: {
|
||||||
|
VescIf.emitMessageDialog(
|
||||||
|
mInfoConf.getLongName("app_ppm_mapping_help"),
|
||||||
|
mInfoConf.getDescription("app_ppm_mapping_help"),
|
||||||
|
true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Reset"
|
||||||
|
Layout.preferredWidth: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
flat: true
|
||||||
|
onClicked: {
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Apply & Write"
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
|
||||||
|
applyMapping()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: rtTimer
|
||||||
|
interval: 50
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
if (VescIf.isPortConnected() && visible) {
|
||||||
|
mCommands.getDecodedPpm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mCommands
|
||||||
|
|
||||||
|
onDecodedPpmReceived: {
|
||||||
|
valueNow = value
|
||||||
|
msNow = last_len
|
||||||
|
|
||||||
|
if (resetDone) {
|
||||||
|
resetDone = false
|
||||||
|
msMin = msNow
|
||||||
|
msMax = msNow
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msNow < msMin) {
|
||||||
|
msMin = msNow
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msNow > msMax) {
|
||||||
|
msMax = msNow
|
||||||
|
}
|
||||||
|
|
||||||
|
var range = msMax - msMin
|
||||||
|
var pos = msNow - msMin
|
||||||
|
|
||||||
|
if (pos > (range / 4.0) && pos < ((3.0 * range) / 4.0)) {
|
||||||
|
msCenter = msNow
|
||||||
|
} else {
|
||||||
|
msCenter = range / 2.0 + msMin
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user