Compare commits
35 Commits
release/0.
...
release1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ab8a2b92a | ||
|
|
a83ecbb042 | ||
|
|
649c9ed2a0 | ||
|
|
960dd6ba88 | ||
|
|
0daea7162a | ||
|
|
7c732215ec | ||
|
|
92c3e42039 | ||
|
|
eb89c386a3 | ||
|
|
c231735900 | ||
|
|
2595c7bb65 | ||
|
|
868a810eda | ||
|
|
7be70e1ade | ||
|
|
1d77dcbfcd | ||
|
|
dd63a2bf4c | ||
|
|
12c4535e06 | ||
|
|
4dd1f95193 | ||
|
|
d28efef208 | ||
|
|
3d0f39f846 | ||
|
|
1fc06361f8 | ||
|
|
86b73ca662 | ||
|
|
46dedab567 | ||
|
|
e31c509341 | ||
|
|
545977a4b7 | ||
|
|
4a0f78c247 | ||
|
|
2a960893d0 | ||
|
|
fdaca40a06 | ||
|
|
046d1f55ce | ||
|
|
6ae4386b37 | ||
|
|
79518df613 | ||
|
|
d1ba61acd8 | ||
|
|
8abae06275 | ||
|
|
eda44940d3 | ||
|
|
4a5a0bcb3a | ||
|
|
a4196df821 | ||
|
|
dce22c65d6 |
192
CUBO-BMS-Tool.pro
Normal file
@@ -0,0 +1,192 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2016-08-12T21:55:19
|
||||
#
|
||||
#-------------------------------------------------
|
||||
INCLUDEPATH += $$PWD
|
||||
# Version
|
||||
DT_VERSION = 2.0
|
||||
DEFINES += DT_VERSION=$$DT_VERSION
|
||||
|
||||
!android: {
|
||||
# Serial port available
|
||||
DEFINES += HAS_SERIALPORT
|
||||
}
|
||||
|
||||
CONFIG += c++14
|
||||
|
||||
# Options
|
||||
#Build mobile GUI
|
||||
#CONFIG += build_mobile
|
||||
|
||||
|
||||
# Bluetooth available
|
||||
#DEFINES += HAS_BLUETOOTH
|
||||
|
||||
QT += core gui xml svg
|
||||
#QT += widgets
|
||||
#QT += printsupport
|
||||
QT += network
|
||||
#QT += bluetooth
|
||||
QT += quick
|
||||
QT += quickcontrols2
|
||||
QT += charts
|
||||
|
||||
contains(DEFINES, HAS_SERIALPORT) {
|
||||
QT += serialport
|
||||
}
|
||||
|
||||
android: QT += androidextras
|
||||
|
||||
TARGET = CUBO-BMS-Tool
|
||||
|
||||
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 \
|
||||
translator.cpp \
|
||||
firmwareupdatehelper.cpp \
|
||||
currenttablemodel.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 \
|
||||
translator.h \
|
||||
firmwareupdatehelper.h \
|
||||
currenttablemodel.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 \
|
||||
translations/translations.qrc
|
||||
|
||||
RESOURCES += qml/qml_icons.qrc \
|
||||
qml/qml_items.qrc
|
||||
|
||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||
QML_IMPORT_PATH *= $$PWD/qml
|
||||
QML2_IMPORT_PATH *= $$PWD/qml
|
||||
|
||||
TRANSLATIONS = translations/cubo_en.ts \
|
||||
translations/cubo_ru.ts \
|
||||
translations/cubo_it.ts
|
||||
|
||||
RC_ICONS = qml/Icons/cubo-icon.ico
|
||||
|
||||
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
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# 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
|
||||
|
||||
@@ -89,8 +89,11 @@ BMSInterface::BMSInterface(QObject *parent) : QObject(parent)
|
||||
|
||||
// BLE
|
||||
|
||||
#ifdef HAS_BLUETOOTH
|
||||
mBleUart = new BleUart(this);
|
||||
mLastBleAddr = QSettings().value("ble_addr").toString();
|
||||
connect(mBleUart, SIGNAL(dataRx(QByteArray)), this, SLOT(bleDataRx(QByteArray)));
|
||||
#endif
|
||||
|
||||
int size = mSettings.beginReadArray("bleNames");
|
||||
for (int i = 0; i < size; ++i) {
|
||||
@@ -101,8 +104,6 @@ BMSInterface::BMSInterface(QObject *parent) : QObject(parent)
|
||||
}
|
||||
mSettings.endArray();
|
||||
|
||||
connect(mBleUart, SIGNAL(dataRx(QByteArray)), this, SLOT(bleDataRx(QByteArray)));
|
||||
|
||||
mCommands->setbmsConfig(mbmsConfig);
|
||||
|
||||
// Other signals/slots
|
||||
@@ -112,8 +113,8 @@ BMSInterface::BMSInterface(QObject *parent) : QObject(parent)
|
||||
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()));
|
||||
connect(mbmsConfig, SIGNAL(updated()), this, SLOT(bmsConfUpdated()));
|
||||
connect(mbmsConfig, SIGNAL(stored()), this, SLOT(bmsConfStored()));
|
||||
}
|
||||
|
||||
BMSInterface::~BMSInterface()
|
||||
@@ -280,9 +281,11 @@ bool BMSInterface::isPortConnected()
|
||||
res = true;
|
||||
}
|
||||
|
||||
#ifdef HAS_BLUETOOTH
|
||||
if (mBleUart->isConnected()) {
|
||||
res = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -301,10 +304,12 @@ void BMSInterface::disconnectPort()
|
||||
updateFwRx(false);
|
||||
}
|
||||
|
||||
#ifdef HAS_BLUETOOTH
|
||||
if (mBleUart->isConnected()) {
|
||||
mBleUart->disconnectBle();
|
||||
updateFwRx(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
mFwRetries = 0;
|
||||
}
|
||||
@@ -321,8 +326,12 @@ bool BMSInterface::reconnectLastPort()
|
||||
connectTcp(mLastTcpServer, mLastTcpPort);
|
||||
return true;
|
||||
} else if (mLastConnType == CONN_BLE) {
|
||||
#ifdef HAS_BLUETOOTH
|
||||
mBleUart->startConnect(mLastBleAddr);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef HAS_SERIALPORT
|
||||
QList<VSerialInfo_t> ports = listSerialPorts();
|
||||
@@ -408,10 +417,12 @@ QString BMSInterface::getConnectedPortName()
|
||||
connected = true;
|
||||
}
|
||||
|
||||
#ifdef HAS_BLUETOOTH
|
||||
if (mBleUart->isConnected()) {
|
||||
res = tr("Connected (BLE) to %1").arg(mLastBleAddr);
|
||||
connected = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (connected && mCommands->isLimitedMode()) {
|
||||
res += tr(", limited mode");
|
||||
@@ -429,7 +440,7 @@ bool BMSInterface::connectSerial(QString port, int baudrate)
|
||||
|
||||
bool found = false;
|
||||
for (VSerialInfo_t ser: listSerialPorts()) {
|
||||
if (ser.systemPath == port) {
|
||||
if (ser.name == port) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -517,6 +528,16 @@ QList<VSerialInfo_t> BMSInterface::listSerialPorts()
|
||||
return res;
|
||||
}
|
||||
|
||||
QStringList BMSInterface::serialPortNames()
|
||||
{
|
||||
QStringList names;
|
||||
for (const auto& info: listSerialPorts())
|
||||
{
|
||||
names.append(info.name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
void BMSInterface::connectTcp(QString server, int port)
|
||||
{
|
||||
mLastTcpServer = server;
|
||||
@@ -541,10 +562,12 @@ void BMSInterface::connectTcp(QString server, int port)
|
||||
|
||||
void BMSInterface::connectBle(QString address)
|
||||
{
|
||||
#ifdef HAS_BLUETOOTH
|
||||
mBleUart->startConnect(address);
|
||||
mLastConnType = CONN_BLE;
|
||||
mLastBleAddr = address;
|
||||
setLastConnectionType(CONN_BLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BMSInterface::isAutoconnectOngoing() const
|
||||
@@ -605,7 +628,6 @@ void BMSInterface::ignoreCanChange(bool ignore)
|
||||
#ifdef HAS_SERIALPORT
|
||||
void BMSInterface::serialDataAvailable()
|
||||
{
|
||||
bool b = true;
|
||||
while (mSerialPort->bytesAvailable() > 0) {
|
||||
mPacket->processData(mSerialPort->readAll());
|
||||
}
|
||||
@@ -619,7 +641,7 @@ void BMSInterface::serialPortError(QSerialPort::SerialPortError error)
|
||||
break;
|
||||
|
||||
default:
|
||||
message = "Serial port error: " + mSerialPort->errorString();
|
||||
message = tr("Serial port error: ") + mSerialPort->errorString();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -637,7 +659,6 @@ void BMSInterface::serialPortError(QSerialPort::SerialPortError error)
|
||||
|
||||
void BMSInterface::tcpInputConnected()
|
||||
{
|
||||
bool b = true;
|
||||
mTcpConnected = true;
|
||||
updateFwRx(false);
|
||||
}
|
||||
@@ -650,7 +671,6 @@ void BMSInterface::tcpInputDisconnected()
|
||||
|
||||
void BMSInterface::tcpInputDataAvailable()
|
||||
{
|
||||
bool b = true;
|
||||
while (mTcpSocket->bytesAvailable() > 0) {
|
||||
mPacket->processData(mTcpSocket->readAll());
|
||||
}
|
||||
@@ -725,9 +745,13 @@ void BMSInterface::timerSlot()
|
||||
if (mIsUploadingFw) {
|
||||
updateFwRx(false);
|
||||
mFwRetries = 0;
|
||||
if (fwStatus.compare("FW Upload Done") == 0) {
|
||||
if (mCommands->getFirmwareUploadSuccess())
|
||||
{
|
||||
disconnectPort();
|
||||
emit fwUploadStatus(fwStatus, 1.0, false);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
emit fwUploadStatus(fwStatus, 0.0, false);
|
||||
}
|
||||
}
|
||||
@@ -752,9 +776,11 @@ void BMSInterface::packetDataToSend(QByteArray &data)
|
||||
mTcpSocket->write(data);
|
||||
}
|
||||
|
||||
#ifdef HAS_BLUETOOTH
|
||||
if (mBleUart->isConnected()) {
|
||||
mBleUart->writeData(data);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BMSInterface::packetReceived(QByteArray &data)
|
||||
@@ -771,7 +797,7 @@ void BMSInterface::fwVersionReceived(int major, int minor, QString hw, QByteArra
|
||||
{
|
||||
QList<QPair<int, int> > fwPairs = getSupportedFirmwarePairs();
|
||||
|
||||
QString strUuid = Utility::uuid2Str(uuid, true);
|
||||
QString strUuid = uuid.toHex().toUpper();
|
||||
|
||||
if (fwPairs.isEmpty()) {
|
||||
emit messageDialog(tr("Not Supported Firmwares"),
|
||||
@@ -836,16 +862,7 @@ void BMSInterface::fwVersionReceived(int major, int minor, QString hw, QByteArra
|
||||
}
|
||||
}
|
||||
|
||||
QString fwStr;
|
||||
fwStr.sprintf("ENNOID-BMS Firmware Version %d.%d", major, minor);
|
||||
if (!hw.isEmpty()) {
|
||||
fwStr += ", Hardware: " + hw;
|
||||
}
|
||||
|
||||
if (!strUuid.isEmpty()) {
|
||||
fwStr += ", UUID: " + strUuid;
|
||||
}
|
||||
|
||||
auto fwStr = tr("Firmware version: %1.%2, Hardware: %3, UUID: %4").arg(major).arg(minor).arg(hw).arg(strUuid);
|
||||
emit statusMessage(fwStr, true);
|
||||
#if 0
|
||||
}
|
||||
@@ -864,13 +881,15 @@ void BMSInterface::fwVersionReceived(int major, int minor, QString hw, QByteArra
|
||||
}
|
||||
}
|
||||
|
||||
void BMSInterface::bmsconfUpdated()
|
||||
void BMSInterface::bmsConfUpdated()
|
||||
{
|
||||
emit statusMessage(tr("BMS configuration updated"), true);
|
||||
emit bmsConfigurationUpdated();
|
||||
}
|
||||
|
||||
void BMSInterface::bmsconfStored() {
|
||||
void BMSInterface::bmsConfStored() {
|
||||
emit statusMessage(tr("BMS configuration stored to Flash"), true);
|
||||
emit bmsConfigurationStored();
|
||||
}
|
||||
|
||||
void BMSInterface::ackReceived(QString ackType)
|
||||
|
||||
@@ -106,8 +106,9 @@ public:
|
||||
Q_INVOKABLE bool reconnectLastPort();
|
||||
Q_INVOKABLE bool autoconnect();
|
||||
Q_INVOKABLE QString getConnectedPortName();
|
||||
bool connectSerial(QString port, int baudrate = 115200);
|
||||
Q_INVOKABLE bool connectSerial(QString port, int baudrate = 115200);
|
||||
QList<VSerialInfo_t> listSerialPorts();
|
||||
Q_INVOKABLE QStringList serialPortNames();
|
||||
Q_INVOKABLE void connectTcp(QString server, int port);
|
||||
Q_INVOKABLE void connectBle(QString address);
|
||||
Q_INVOKABLE bool isAutoconnectOngoing() const;
|
||||
@@ -126,6 +127,8 @@ signals:
|
||||
void autoConnectProgressUpdated(double progress, bool isOngoing);
|
||||
void autoConnectFinished();
|
||||
void pairingListUpdated();
|
||||
void bmsConfigurationUpdated();
|
||||
void bmsConfigurationStored();
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -140,15 +143,17 @@ private slots:
|
||||
void tcpInputDataAvailable();
|
||||
void tcpInputError(QAbstractSocket::SocketError socketError);
|
||||
|
||||
#ifdef HAS_BLUETOOTH
|
||||
void bleDataRx(QByteArray data);
|
||||
#endif
|
||||
|
||||
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 bmsConfUpdated();
|
||||
void bmsConfStored();
|
||||
void ackReceived(QString ackType);
|
||||
|
||||
private:
|
||||
|
||||
179
commands.cpp
@@ -39,6 +39,8 @@ Commands::Commands(QObject *parent) : QObject(parent)
|
||||
mFimwarePtr = 0;
|
||||
mFirmwareTimer = 0;
|
||||
mFirmwareRetries = 0;
|
||||
mFirmwareIsBootloader = false;
|
||||
mFirmwareUploadSuccess = false;
|
||||
mFirmwareUploadStatus = "FW Upload Status";
|
||||
mCheckNextbmsConfig = false;
|
||||
|
||||
@@ -159,7 +161,7 @@ void Commands::processPacket(QByteArray data)
|
||||
|
||||
values.opState = opStateToStr((OperationalStateTypedef)vb.vbPopFrontUint8());
|
||||
values.balanceActive = vb.vbPopFrontUint8();
|
||||
values.faultState = faultStateToStr((bms_fault_code)vb.vbPopFrontUint8());
|
||||
values.faultState = faultStateToString((bms_fault_code)vb.vbPopFrontUint8());
|
||||
emit valuesReceived(values);
|
||||
} break;
|
||||
|
||||
@@ -234,7 +236,7 @@ void Commands::processPacket(QByteArray data)
|
||||
break;
|
||||
|
||||
case COMM_SET_MCCONF:
|
||||
emit ackReceived("BMS Write OK");
|
||||
emit ackReceived(tr("BMS configuration is set"));
|
||||
break;
|
||||
|
||||
case COMM_STORE_BMS_CONF:
|
||||
@@ -252,6 +254,29 @@ void Commands::processPacket(QByteArray data)
|
||||
emit pingCanRx(devs, false);
|
||||
} break;
|
||||
|
||||
case COMM_GET_BMS_NET_SETTINGS:
|
||||
case COMM_GET_BMS_NET_DEFAULT_SETTINGS:
|
||||
{
|
||||
QStringList settings;
|
||||
settings << vb.mid(0, 250);
|
||||
settings << vb.mid(250, 250);
|
||||
settings << vb.mid(500, 50);
|
||||
settings << vb.mid(550, 50);
|
||||
settings << vb.mid(600, 50);
|
||||
emit netSettingsReceived(settings);
|
||||
break;
|
||||
}
|
||||
case COMM_SET_BMS_NET_SETTINGS:
|
||||
{
|
||||
emit ackReceived(tr("Network settings applied successfully"));
|
||||
break;
|
||||
}
|
||||
case COMM_GET_FAULT_STATE:
|
||||
{
|
||||
const auto state = static_cast<bms_fault_code>(vb.vbPopFrontUint16());
|
||||
emit faultStateReceived(faultStateToType(state), faultStateToString(state));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -321,6 +346,40 @@ void Commands::getExpansionTemp()
|
||||
vb.vbAppendInt8(COMM_GET_BMS_EXP_TEMP);
|
||||
emitData(vb);
|
||||
}
|
||||
|
||||
void Commands::getNetSettings()
|
||||
{
|
||||
VByteArray vb;
|
||||
vb.vbAppendInt8(COMM_GET_BMS_NET_SETTINGS);
|
||||
emitData(vb);
|
||||
}
|
||||
|
||||
void Commands::getNetDefaultSettings()
|
||||
{
|
||||
VByteArray vb;
|
||||
vb.vbAppendInt8(COMM_GET_BMS_NET_DEFAULT_SETTINGS);
|
||||
emitData(vb);
|
||||
}
|
||||
|
||||
void Commands::setNetSettings(QStringList settings)
|
||||
{
|
||||
VByteArray vb;
|
||||
vb.vbAppendInt8(COMM_SET_BMS_NET_SETTINGS);
|
||||
vb.append(settings.at(0).leftJustified(250, '\0', true));
|
||||
vb.append(settings.at(1).leftJustified(250, '\0', true));
|
||||
vb.append(settings.at(2).leftJustified(50, '\0', true));
|
||||
vb.append(settings.at(3).leftJustified(50, '\0', true));
|
||||
vb.append(settings.at(4).leftJustified(50, '\0', true));
|
||||
emitData(vb);
|
||||
}
|
||||
|
||||
void Commands::getFaultState()
|
||||
{
|
||||
VByteArray vb;
|
||||
vb.vbAppendInt8(COMM_GET_FAULT_STATE);
|
||||
emitData(vb);
|
||||
}
|
||||
|
||||
void Commands::sendTerminalCmd(QString cmd)
|
||||
{
|
||||
VByteArray vb;
|
||||
@@ -457,12 +516,12 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
|
||||
const int timeout = 350;
|
||||
|
||||
if (mFirmwareState == 0) {
|
||||
mFirmwareUploadStatus = "Buffer Erase";
|
||||
mFirmwareUploadStatus = tr("Buffer erase");
|
||||
if (isTimeout) {
|
||||
// Erase timed out, abort.
|
||||
mFirmwareIsUploading = false;
|
||||
mFimwarePtr = 0;
|
||||
mFirmwareUploadStatus = "Buffer Erase Timeout";
|
||||
mFirmwareUploadStatus = tr("Buffer erase timeout");
|
||||
} else {
|
||||
mFirmwareState++;
|
||||
mFirmwareRetries = retries;
|
||||
@@ -470,7 +529,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
|
||||
firmwareUploadUpdate(true);
|
||||
}
|
||||
} else if (mFirmwareState == 1) {
|
||||
mFirmwareUploadStatus = "CRC/Size Write";
|
||||
mFirmwareUploadStatus = tr("CRC/Size write");
|
||||
if (isTimeout) {
|
||||
if (mFirmwareRetries > 0) {
|
||||
mFirmwareRetries--;
|
||||
@@ -479,7 +538,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
|
||||
mFirmwareIsUploading = false;
|
||||
mFimwarePtr = 0;
|
||||
mFirmwareState = 0;
|
||||
mFirmwareUploadStatus = "CRC/Size Write Timeout";
|
||||
mFirmwareUploadStatus = tr("CRC/Size write timeout");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -498,7 +557,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
|
||||
firmwareUploadUpdate(true);
|
||||
}
|
||||
} else if (mFirmwareState == 2) {
|
||||
mFirmwareUploadStatus = "FW Data Write";
|
||||
mFirmwareUploadStatus = tr("Firmware data write");
|
||||
if (isTimeout) {
|
||||
if (mFirmwareRetries > 0) {
|
||||
mFirmwareRetries--;
|
||||
@@ -507,7 +566,7 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
|
||||
mFirmwareIsUploading = false;
|
||||
mFimwarePtr = 0;
|
||||
mFirmwareState = 0;
|
||||
mFirmwareUploadStatus = "FW Data Write Timeout";
|
||||
mFirmwareUploadStatus = tr("Firmware data write timeout");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -534,7 +593,8 @@ void Commands::firmwareUploadUpdate(bool isTimeout)
|
||||
mFirmwareIsUploading = false;
|
||||
mFimwarePtr = 0;
|
||||
mFirmwareState = 0;
|
||||
mFirmwareUploadStatus = "FW Upload Done";
|
||||
mFirmwareUploadSuccess = true;
|
||||
mFirmwareUploadStatus = tr("Firmware update completed!\n\nReconnect to the board if you want to continue working with it.");
|
||||
|
||||
// Upload done. Enter bootloader!
|
||||
if (!mFirmwareIsBootloader) {
|
||||
@@ -568,34 +628,67 @@ QString Commands::opStateToStr(OperationalStateTypedef fault)
|
||||
}
|
||||
}
|
||||
|
||||
QString Commands::faultStateToStr(bms_fault_code fault)
|
||||
QString Commands::faultStateToString(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";
|
||||
switch (fault)
|
||||
{
|
||||
case FAULT_CODE_NONE: return tr("System ok");
|
||||
case FAULT_CODE_PACK_OVER_VOLTAGE: return tr("Pack overvoltage");
|
||||
case FAULT_CODE_PACK_UNDER_VOLTAGE: return tr("Pack undervoltage");
|
||||
case FAULT_CODE_LOAD_OVER_VOLTAGE: return tr("Load overvoltage");
|
||||
case FAULT_CODE_LOAD_UNDER_VOLTAGE: return tr("Load undervoltage");
|
||||
case FAULT_CODE_CHARGER_OVER_VOLTAGE: return tr("Charger overvoltage");
|
||||
case FAULT_CODE_CHARGER_UNDER_VOLTAGE: return tr("Charger undervoltgae");
|
||||
case FAULT_CODE_CELL_HARD_OVER_VOLTAGE: return tr("Cell hard overvoltage");
|
||||
case FAULT_CODE_CELL_HARD_UNDER_VOLTAGE: return tr("Cell hard undervoltage");
|
||||
case FAULT_CODE_CELL_SOFT_OVER_VOLTAGE: return tr("Cell soft overvoltage");
|
||||
case FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE: return tr("Cell soft undervoltage");
|
||||
case FAULT_CODE_MAX_UVP_OVP_ERRORS: return tr("Too high or too low voltage");
|
||||
case FAULT_CODE_MAX_UVT_OVT_ERRORS: return tr("Too high or too low temperature");
|
||||
case FAULT_CODE_OVER_CURRENT: return tr("Over current");
|
||||
case FAULT_CODE_OVER_TEMP_BMS: return tr("Over temperature BMS");
|
||||
case FAULT_CODE_UNDER_TEMP_BMS: return tr("Under temperature BMS");
|
||||
case FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS: return tr("Discharge over temperature cell");
|
||||
case FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS: return tr("Discharge under temperature cell");
|
||||
case FAULT_CODE_CHARGE_OVER_TEMP_CELLS: return tr("Charge over temperature cell");
|
||||
case FAULT_CODE_CHARGE_UNDER_TEMP_CELLS: return tr("Charge under temperature cell");
|
||||
case FAULT_CODE_PRECHARGE_TIMEOUT: return tr("Precharge timeout");
|
||||
case FAULT_CODE_DISCHARGE_RETRY: return tr("Discharge retry");
|
||||
case FAULT_CODE_CHARGE_RETRY: return tr("Charge retry");
|
||||
case FAULT_CODE_CHARGER_DISCONNECT: return tr("Charge retry");
|
||||
default: return tr("Unknown state");
|
||||
}
|
||||
}
|
||||
|
||||
DataTypes::StateType Commands::faultStateToType(bms_fault_code fault)
|
||||
{
|
||||
switch (fault)
|
||||
{
|
||||
case FAULT_CODE_NONE: return DataTypes::StateType::Good;
|
||||
case FAULT_CODE_PACK_OVER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_PACK_UNDER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_LOAD_OVER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_LOAD_UNDER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CHARGER_OVER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CHARGER_UNDER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CELL_HARD_OVER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CELL_HARD_UNDER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CELL_SOFT_OVER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CELL_SOFT_UNDER_VOLTAGE: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_MAX_UVP_OVP_ERRORS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_MAX_UVT_OVT_ERRORS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_OVER_CURRENT: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_OVER_TEMP_BMS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_UNDER_TEMP_BMS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_DISCHARGE_OVER_TEMP_CELLS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_DISCHARGE_UNDER_TEMP_CELLS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CHARGE_OVER_TEMP_CELLS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_CHARGE_UNDER_TEMP_CELLS: return DataTypes::StateType::Error;
|
||||
case FAULT_CODE_PRECHARGE_TIMEOUT: return DataTypes::StateType::Warning;
|
||||
case FAULT_CODE_DISCHARGE_RETRY: return DataTypes::StateType::Info;
|
||||
case FAULT_CODE_CHARGE_RETRY: return DataTypes::StateType::Info;
|
||||
case FAULT_CODE_CHARGER_DISCONNECT: return DataTypes::StateType::Info;
|
||||
default: return DataTypes::StateType::Info;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,7 +709,8 @@ void Commands::startFirmwareUpload(QByteArray &newFirmware, bool isBootloader)
|
||||
mFirmwareRetries = 5;
|
||||
mNewFirmware.clear();
|
||||
mNewFirmware.append(newFirmware);
|
||||
mFirmwareUploadStatus = "Buffer Erase";
|
||||
mFirmwareUploadSuccess = false;
|
||||
mFirmwareUploadStatus = tr("Buffer erase");
|
||||
|
||||
if (mFirmwareIsBootloader) {
|
||||
firmwareUploadUpdate(true);
|
||||
@@ -628,7 +722,12 @@ void Commands::startFirmwareUpload(QByteArray &newFirmware, bool isBootloader)
|
||||
}
|
||||
}
|
||||
|
||||
double Commands::getFirmwareUploadProgress()
|
||||
bool Commands::getFirmwareUploadSuccess() const
|
||||
{
|
||||
return mFirmwareUploadSuccess;
|
||||
}
|
||||
|
||||
double Commands::getFirmwareUploadProgress() const
|
||||
{
|
||||
if (mFirmwareIsUploading) {
|
||||
return (double)mFimwarePtr / (double)mNewFirmware.size();
|
||||
@@ -637,7 +736,7 @@ double Commands::getFirmwareUploadProgress()
|
||||
}
|
||||
}
|
||||
|
||||
QString Commands::getFirmwareUploadStatus()
|
||||
QString Commands::getFirmwareUploadStatus() const
|
||||
{
|
||||
return mFirmwareUploadStatus;
|
||||
}
|
||||
@@ -648,7 +747,7 @@ void Commands::cancelFirmwareUpload()
|
||||
mFirmwareIsUploading = false;
|
||||
mFimwarePtr = 0;
|
||||
mFirmwareState = 0;
|
||||
mFirmwareUploadStatus = "Cancelled";
|
||||
mFirmwareUploadStatus = tr("Cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
17
commands.h
@@ -47,11 +47,12 @@ public:
|
||||
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 double getFirmwareUploadProgress() const;
|
||||
Q_INVOKABLE QString getFirmwareUploadStatus() const;
|
||||
Q_INVOKABLE bool getFirmwareUploadSuccess() const;
|
||||
Q_INVOKABLE void cancelFirmwareUpload();
|
||||
void checkbmsConfig();
|
||||
void storeBMSConfig();
|
||||
Q_INVOKABLE void storeBMSConfig();
|
||||
Q_INVOKABLE void emitEmptyValues();
|
||||
Q_INVOKABLE void emitEmptySetupValues();
|
||||
|
||||
@@ -70,6 +71,8 @@ signals:
|
||||
void bmsConfigCheckResult(QStringList paramsNotSet);
|
||||
void valuesSetupReceived(BMS_VALUES values);
|
||||
void pingCanRx(QVector<int> devs, bool isTimeout);
|
||||
void netSettingsReceived(QStringList settings);
|
||||
void faultStateReceived(DataTypes::StateType faultType, QString faultString);
|
||||
|
||||
public slots:
|
||||
void processPacket(QByteArray data);
|
||||
@@ -79,6 +82,10 @@ public slots:
|
||||
void getCells();
|
||||
void getAux();
|
||||
void getExpansionTemp();
|
||||
void getNetSettings();
|
||||
void getNetDefaultSettings();
|
||||
void setNetSettings(QStringList settings);
|
||||
void getFaultState();
|
||||
void sendTerminalCmd(QString cmd);
|
||||
void setDetect(disp_pos_mode mode);
|
||||
void samplePrint(debug_sampling_mode mode, int sample_len, int dec);
|
||||
@@ -97,7 +104,8 @@ private:
|
||||
void emitData(QByteArray data);
|
||||
void firmwareUploadUpdate(bool isTimeout);
|
||||
QString opStateToStr(OperationalStateTypedef fault);
|
||||
QString faultStateToStr(bms_fault_code fault);
|
||||
QString faultStateToString(bms_fault_code fault);
|
||||
DataTypes::StateType faultStateToType(bms_fault_code fault);
|
||||
|
||||
QTimer *mTimer;
|
||||
bool mSendCan;
|
||||
@@ -112,6 +120,7 @@ private:
|
||||
int mFirmwareTimer;
|
||||
int mFirmwareRetries;
|
||||
bool mFirmwareIsBootloader;
|
||||
bool mFirmwareUploadSuccess;
|
||||
QString mFirmwareUploadStatus;
|
||||
|
||||
ConfigParams *mbmsConfig;
|
||||
|
||||
154
configparams.cpp
@@ -575,102 +575,102 @@ void ConfigParams::setParamValue(const QString &name, QVariant val)
|
||||
}
|
||||
|
||||
|
||||
QWidget *ConfigParams::getEditor(const QString &name, QWidget *parent)
|
||||
{
|
||||
QWidget *retVal = 0;
|
||||
//QWidget *ConfigParams::getEditor(const QString &name, QWidget *parent)
|
||||
//{
|
||||
// QWidget *retVal = 0;
|
||||
|
||||
if (mParams.contains(name)) {
|
||||
ConfigParam &p = mParams[name];
|
||||
// if (mParams.contains(name)) {
|
||||
// ConfigParam &p = mParams[name];
|
||||
|
||||
switch (p.type) {
|
||||
case CFG_T_DOUBLE: {
|
||||
ParamEditDouble *edit = new ParamEditDouble(parent);
|
||||
edit->setName(name);
|
||||
edit->setSuffix(p.suffix);
|
||||
edit->setDecimals(p.editorDecimalsDouble);
|
||||
edit->setShowAsPercentage(p.editAsPercentage);
|
||||
edit->showDisplay(p.showDisplay);
|
||||
// switch (p.type) {
|
||||
// case CFG_T_DOUBLE: {
|
||||
// ParamEditDouble *edit = new ParamEditDouble(parent);
|
||||
// edit->setName(name);
|
||||
// edit->setSuffix(p.suffix);
|
||||
// edit->setDecimals(p.editorDecimalsDouble);
|
||||
// edit->setShowAsPercentage(p.editAsPercentage);
|
||||
// edit->showDisplay(p.showDisplay);
|
||||
|
||||
edit->setProperty("type", int(p.type));
|
||||
edit->setProperty("suffix", p.suffix);
|
||||
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
edit->setProperty("value", p.valDouble);
|
||||
// edit->setProperty("type", int(p.type));
|
||||
// edit->setProperty("suffix", p.suffix);
|
||||
// edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
// edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
// edit->setProperty("value", p.valDouble);
|
||||
|
||||
edit->setConfig(this);
|
||||
retVal = edit;
|
||||
} break;
|
||||
// edit->setConfig(this);
|
||||
// retVal = edit;
|
||||
// } break;
|
||||
|
||||
case CFG_T_INT: {
|
||||
ParamEditInt *edit = new ParamEditInt(parent);
|
||||
edit->setName(name);
|
||||
edit->setSuffix(p.suffix);
|
||||
edit->setShowAsPercentage(p.editAsPercentage);
|
||||
edit->showDisplay(p.showDisplay);
|
||||
// case CFG_T_INT: {
|
||||
// ParamEditInt *edit = new ParamEditInt(parent);
|
||||
// edit->setName(name);
|
||||
// edit->setSuffix(p.suffix);
|
||||
// edit->setShowAsPercentage(p.editAsPercentage);
|
||||
// edit->showDisplay(p.showDisplay);
|
||||
|
||||
edit->setProperty("type", int(p.type));
|
||||
edit->setProperty("suffix", p.suffix);
|
||||
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
edit->setProperty("value", p.valInt);
|
||||
// edit->setProperty("type", int(p.type));
|
||||
// edit->setProperty("suffix", p.suffix);
|
||||
// edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
// edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
// edit->setProperty("value", p.valInt);
|
||||
|
||||
edit->setConfig(this);
|
||||
retVal = edit;
|
||||
} break;
|
||||
// edit->setConfig(this);
|
||||
// retVal = edit;
|
||||
// } break;
|
||||
|
||||
case CFG_T_QSTRING: {
|
||||
ParamEditString *edit = new ParamEditString(parent);
|
||||
edit->setName(name);
|
||||
// case CFG_T_QSTRING: {
|
||||
// ParamEditString *edit = new ParamEditString(parent);
|
||||
// edit->setName(name);
|
||||
|
||||
edit->setProperty("type", int(p.type));
|
||||
edit->setProperty("suffix", p.suffix);
|
||||
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
edit->setProperty("value", p.valString);
|
||||
// edit->setProperty("type", int(p.type));
|
||||
// edit->setProperty("suffix", p.suffix);
|
||||
// edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
// edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
// edit->setProperty("value", p.valString);
|
||||
|
||||
edit->setConfig(this);
|
||||
retVal = edit;
|
||||
} break;
|
||||
// edit->setConfig(this);
|
||||
// retVal = edit;
|
||||
// } break;
|
||||
|
||||
case CFG_T_ENUM: {
|
||||
ParamEditEnum *edit = new ParamEditEnum(parent);
|
||||
edit->setName(name);
|
||||
// case CFG_T_ENUM: {
|
||||
// ParamEditEnum *edit = new ParamEditEnum(parent);
|
||||
// edit->setName(name);
|
||||
|
||||
edit->setProperty("type", int(p.type));
|
||||
edit->setProperty("suffix", p.suffix);
|
||||
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
edit->setProperty("value", p.valInt);
|
||||
// edit->setProperty("type", int(p.type));
|
||||
// edit->setProperty("suffix", p.suffix);
|
||||
// edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
// edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
// edit->setProperty("value", p.valInt);
|
||||
|
||||
edit->setConfig(this);
|
||||
retVal = edit;
|
||||
} break;
|
||||
// edit->setConfig(this);
|
||||
// retVal = edit;
|
||||
// } break;
|
||||
|
||||
case CFG_T_BOOL: {
|
||||
ParamEditBool *edit = new ParamEditBool(parent);
|
||||
edit->setName(name);
|
||||
// case CFG_T_BOOL: {
|
||||
// ParamEditBool *edit = new ParamEditBool(parent);
|
||||
// edit->setName(name);
|
||||
|
||||
edit->setProperty("type", int(p.type));
|
||||
edit->setProperty("suffix", p.suffix);
|
||||
edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
edit->setProperty("value", p.valInt);
|
||||
// edit->setProperty("type", int(p.type));
|
||||
// edit->setProperty("suffix", p.suffix);
|
||||
// edit->setProperty("editorDecimalsDouble", p.editorDecimalsDouble);
|
||||
// edit->setProperty("editAsPercentage", p.editAsPercentage);
|
||||
// edit->setProperty("value", p.valInt);
|
||||
|
||||
edit->setConfig(this);
|
||||
retVal = edit;
|
||||
} break;
|
||||
// edit->setConfig(this);
|
||||
// retVal = edit;
|
||||
// } break;
|
||||
|
||||
default:
|
||||
qWarning() << "no editor for" << name << "could be created";
|
||||
break;
|
||||
}
|
||||
// default:
|
||||
// qWarning() << "no editor for" << name << "could be created";
|
||||
// break;
|
||||
// }
|
||||
|
||||
} else {
|
||||
qWarning() << name << "not found";
|
||||
}
|
||||
// } else {
|
||||
// qWarning() << name << "not found";
|
||||
// }
|
||||
|
||||
return retVal;
|
||||
}
|
||||
// return retVal;
|
||||
//}
|
||||
|
||||
/*
|
||||
QWidget *ConfigParams::getEditor(const QString &name, QWidget *parent)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QVariant>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QXmlStreamReader>
|
||||
#include "configparam.h"
|
||||
@@ -50,7 +51,7 @@ public:
|
||||
Q_INVOKABLE bool hasParam(const QString &name);
|
||||
ConfigParam *getParam(const QString &name);
|
||||
ConfigParam getParamCopy(const QString &name) const;
|
||||
void setParamValue(const QString &name, QVariant val);
|
||||
Q_INVOKABLE void setParamValue(const QString &name, QVariant val);
|
||||
|
||||
Q_INVOKABLE bool isParamDouble(const QString &name);
|
||||
Q_INVOKABLE bool isParamInt(const QString &name);
|
||||
@@ -83,7 +84,7 @@ public:
|
||||
QStringList getParamOrder() const;
|
||||
void setParamOrder(const QStringList &order);
|
||||
|
||||
QWidget *getEditor(const QString &name, QWidget *parent = 0);
|
||||
// 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);
|
||||
@@ -97,14 +98,14 @@ public:
|
||||
|
||||
void getXML(QXmlStreamWriter &stream, QString configName);
|
||||
bool setXML(QXmlStreamReader &stream, QString configName);
|
||||
bool saveXml(QString fileName, QString configName);
|
||||
bool loadXml(QString fileName, QString configName);
|
||||
QString xmlStatus();
|
||||
Q_INVOKABLE bool saveXml(QString fileName, QString configName);
|
||||
Q_INVOKABLE bool loadXml(QString fileName, QString configName);
|
||||
Q_INVOKABLE QString xmlStatus();
|
||||
|
||||
void getParamsXML(QXmlStreamWriter &stream);
|
||||
bool setParamsXML(QXmlStreamReader &stream);
|
||||
bool saveParamsXml(QString fileName);
|
||||
bool loadParamsXml(QString fileName);
|
||||
Q_INVOKABLE bool saveParamsXml(QString fileName);
|
||||
Q_INVOKABLE bool loadParamsXml(QString fileName);
|
||||
|
||||
bool saveCDefines(const QString &fileName, bool wrapIfdef = false);
|
||||
|
||||
|
||||
63
currenttablemodel.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "currenttablemodel.h"
|
||||
|
||||
CurrentTableModel::CurrentTableModel(QObject* parent) :
|
||||
QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
CurrentTableModel::~CurrentTableModel()
|
||||
{
|
||||
}
|
||||
|
||||
void CurrentTableModel::setCurrentData(const QVariantList& data)
|
||||
{
|
||||
beginResetModel();
|
||||
data_.clear();
|
||||
|
||||
for (const auto& row: data)
|
||||
{
|
||||
QList<float> rowData;
|
||||
for (const auto& column: row.toList())
|
||||
{
|
||||
rowData.push_back(column.toFloat());
|
||||
}
|
||||
data_.push_back(rowData);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CurrentTableModel::setCurrentData(const QList<QList<float>>& data)
|
||||
{
|
||||
beginResetModel();
|
||||
data_ = data;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int CurrentTableModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
int CurrentTableModel::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return data_.empty() ? 0 : data_.at(0).size();
|
||||
}
|
||||
|
||||
QVariant CurrentTableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return QString::number(data_.at(index.row()).at(index.column()));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> CurrentTableModel::roleNames() const
|
||||
{
|
||||
return { {Qt::DisplayRole, "display"} };
|
||||
}
|
||||
27
currenttablemodel.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef CURRENTTABLEMODEL_H
|
||||
#define CURRENTTABLEMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class CurrentTableModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CurrentTableModel(QObject* parent = nullptr);
|
||||
~CurrentTableModel();
|
||||
|
||||
Q_INVOKABLE void setCurrentData(const QVariantList& data);
|
||||
void setCurrentData(const QList<QList<float>>& data);
|
||||
|
||||
int rowCount(const QModelIndex& = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
QList<QList<float>> data_;
|
||||
};
|
||||
|
||||
#endif // CURRENTTABLEMODEL_H
|
||||
23
datatypes.h
@@ -84,6 +84,8 @@ typedef enum {
|
||||
FAULT_CODE_PRECHARGE_TIMEOUT,
|
||||
FAULT_CODE_DISCHARGE_RETRY,
|
||||
FAULT_CODE_CHARGE_RETRY,
|
||||
FAULT_CODE_CAN_DELAYED_POWER_DOWN,
|
||||
FAULT_CODE_NOT_USED_TIMEOUT,
|
||||
FAULT_CODE_CHARGER_DISCONNECT
|
||||
} bms_fault_code;
|
||||
|
||||
@@ -415,7 +417,11 @@ typedef enum {
|
||||
COMM_STORE_BMS_CONF = 150,
|
||||
COMM_GET_BMS_CELLS,
|
||||
COMM_GET_BMS_AUX,
|
||||
COMM_GET_BMS_EXP_TEMP
|
||||
COMM_GET_BMS_EXP_TEMP,
|
||||
COMM_GET_BMS_NET_SETTINGS,
|
||||
COMM_GET_BMS_NET_DEFAULT_SETTINGS,
|
||||
COMM_SET_BMS_NET_SETTINGS,
|
||||
COMM_GET_FAULT_STATE,
|
||||
} COMM_PACKET_ID;
|
||||
|
||||
typedef struct {
|
||||
@@ -466,4 +472,19 @@ typedef enum {
|
||||
OP_STATE_FORCEON, // 11
|
||||
} OperationalStateTypedef;
|
||||
|
||||
namespace DataTypes
|
||||
{
|
||||
Q_NAMESPACE
|
||||
|
||||
enum class StateType
|
||||
{
|
||||
Neutral,
|
||||
Info,
|
||||
Good,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
Q_ENUM_NS(StateType);
|
||||
}
|
||||
|
||||
#endif // DATATYPES_H
|
||||
|
||||
29
firmwareupdatehelper.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "firmwareupdatehelper.h"
|
||||
|
||||
#include "bmsinterface.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QByteArray>
|
||||
|
||||
|
||||
FirmwareUpdateHelper::FirmwareUpdateHelper(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool FirmwareUpdateHelper::uploadFirmware(QString filename, BMSInterface *interface)
|
||||
{
|
||||
QFile file(filename);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
interface->emitMessageDialog(tr("Upload error"),
|
||||
tr("Could not open file. Make sure that the path is valid."),
|
||||
false);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto data = file.readAll();
|
||||
interface->commands()->startFirmwareUpload(data, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
17
firmwareupdatehelper.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef FIRMWAREUPDATEHELPER_H
|
||||
#define FIRMWAREUPDATEHELPER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class BMSInterface;
|
||||
|
||||
class FirmwareUpdateHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FirmwareUpdateHelper(QObject *parent = nullptr);
|
||||
Q_INVOKABLE bool uploadFirmware(QString filename, BMSInterface *interface);
|
||||
};
|
||||
|
||||
#endif // FIRMWAREUPDATEHELPER_H
|
||||
155
main.cpp
@@ -18,129 +18,72 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "mainwindownew.h"
|
||||
#include "connectandenterpage.h"
|
||||
#include "bmsinterface.h"
|
||||
#include "utility.h"
|
||||
#include "translator.h"
|
||||
#include "firmwareupdatehelper.h"
|
||||
#include "currenttablemodel.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QStyleFactory>
|
||||
#include <QSettings>
|
||||
#include <QDesktopWidget>
|
||||
#include <QFontDatabase>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtSvg>
|
||||
|
||||
#include "mobile/qmlui.h"
|
||||
QObject *bmsInterfaceSingletontypeProvider(QQmlEngine */*engine*/, QJSEngine */*scriptEngine*/)
|
||||
{
|
||||
auto *bmsInterface = new BMSInterface();
|
||||
bmsInterface->bmsConfig()->loadParamsXml("://res/config.xml");
|
||||
bmsInterface->infoConfig()->loadParamsXml("://res/info.xml");
|
||||
return bmsInterface;
|
||||
}
|
||||
|
||||
#define NEW_GUI 1
|
||||
QObject *utilitySingletontypeProvider(QQmlEngine */*engine*/, QJSEngine */*scriptEngine*/)
|
||||
{
|
||||
auto *utility = new Utility();
|
||||
return utility;
|
||||
}
|
||||
|
||||
QObject *translatorSingletontypeProvider(QQmlEngine *engine, QJSEngine */*scriptEngine*/)
|
||||
{
|
||||
auto *translator = new Translator(engine);
|
||||
return translator;
|
||||
}
|
||||
|
||||
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);
|
||||
Q_INIT_RESOURCE(res);
|
||||
Q_INIT_RESOURCE(translations);
|
||||
Q_INIT_RESOURCE(qml_icons);
|
||||
Q_INIT_RESOURCE(qml_items);
|
||||
|
||||
// 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);
|
||||
QCoreApplication::setOrganizationName("Cubo");
|
||||
QCoreApplication::setOrganizationDomain("Cubo.rus");
|
||||
QCoreApplication::setApplicationName("Cubo Verde BMS Tool");
|
||||
|
||||
QSettings set;
|
||||
bool scaleAuto = true;
|
||||
double scale = 1.0;
|
||||
QApplication app(argc, argv);
|
||||
|
||||
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));
|
||||
QFont font("Artifakt Element", 16, QFont::Normal);
|
||||
font.setStyleStrategy(QFont::PreferAntialias);
|
||||
app.setFont(font);
|
||||
|
||||
#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");
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
qApp->setFont(QFont("DejaVu Sans", 11));
|
||||
qmlRegisterSingletonType<BMSInterface>("Cubo", 1, 0, "BmsInterface", bmsInterfaceSingletontypeProvider);
|
||||
qmlRegisterSingletonType<Utility>("Cubo", 1, 0, "Utility", utilitySingletontypeProvider);
|
||||
qmlRegisterSingletonType<Translator>("Cubo", 1, 0, "Translator", translatorSingletontypeProvider);
|
||||
qmlRegisterType<Commands>("Cubo", 1, 0, "Commands");
|
||||
qmlRegisterType<ConfigParams>("Cubo", 1, 0, "ConfigParams");
|
||||
qmlRegisterType<FirmwareUpdateHelper>("Cubo", 1, 0, "FirmwareUpdateHelper");
|
||||
qmlRegisterType<CurrentTableModel>("Cubo", 1, 0, "CurrentTableModel");
|
||||
|
||||
// Style
|
||||
a.setStyleSheet("");
|
||||
a.setStyle(QStyleFactory::create("Fusion"));
|
||||
#endif
|
||||
qmlRegisterUncreatableMetaObject(DataTypes::staticMetaObject, "Cubo", 1, 0, "DataTypes", "Error: only enums");
|
||||
qRegisterMetaType<DataTypes::StateType>("DataTypes::StateType");
|
||||
|
||||
#ifdef USE_MOBILE
|
||||
QmlUi q;
|
||||
q.startQmlUi();
|
||||
#else
|
||||
engine.addImportPath(QStringLiteral("qrc:/"));
|
||||
engine.load(QUrl(QStringLiteral("qrc:/MainWindow.qml")));
|
||||
|
||||
#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();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>qtquickcontrols2.conf</file>
|
||||
</qresource>
|
||||
<qresource prefix="/"/>
|
||||
<qresource prefix="/mobile">
|
||||
<file>main.qml</file>
|
||||
<file>ConnectBle.qml</file>
|
||||
|
||||
14
qml/Controls/AvailabilityIndicator.qml
Normal file
@@ -0,0 +1,14 @@
|
||||
import QtQuick 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Rectangle {
|
||||
property bool enabled: false
|
||||
property bool neutral: true
|
||||
|
||||
implicitWidth: 18
|
||||
implicitHeight: 18
|
||||
radius: implicitWidth / 2
|
||||
color: enabled ? Palette.goodColor :
|
||||
(neutral ? Palette.borderColor : Palette.invalidColor)
|
||||
}
|
||||
57
qml/Controls/BusyIndicator.qml
Normal file
@@ -0,0 +1,57 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
BusyIndicator {
|
||||
id: control
|
||||
running: true
|
||||
implicitWidth: 86
|
||||
implicitHeight: 86
|
||||
|
||||
contentItem: Item {
|
||||
id: item
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
opacity: control.running ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
OpacityAnimator {
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
|
||||
RotationAnimator {
|
||||
target: item
|
||||
running: control.visible && control.running
|
||||
from: 0
|
||||
to: 360
|
||||
loops: Animation.Infinite
|
||||
duration: 5000
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: 6
|
||||
|
||||
Rectangle {
|
||||
x: item.width / 2 - width / 2
|
||||
y: item.height / 2 - height / 2
|
||||
implicitWidth: 12
|
||||
implicitHeight: 12
|
||||
radius: 6
|
||||
color: Palette.alternativeBackgroundColor
|
||||
transform: [
|
||||
Translate {
|
||||
y: -Math.min(item.width, item.height) * 0.5 + 6
|
||||
},
|
||||
Rotation {
|
||||
angle: index / repeater.count * 360
|
||||
origin.x: 6
|
||||
origin.y: 6
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
qml/Controls/Button.qml
Normal file
@@ -0,0 +1,30 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Button {
|
||||
id: control
|
||||
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
opacity: enabled ? 1.0 : 0.3
|
||||
color: Palette.alternativeTextColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 2
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 200
|
||||
implicitHeight: 52
|
||||
opacity: enabled ? 1 : 0.3
|
||||
color: control.pressed ? Palette.pressedButtonColor :
|
||||
control.hovered ? Palette.hoveredButtonColor : Palette.buttonColor
|
||||
radius: 5
|
||||
}
|
||||
}
|
||||
208
qml/Controls/ChartView.qml
Normal file
@@ -0,0 +1,208 @@
|
||||
import QtQuick 2.12
|
||||
import QtCharts 2.3
|
||||
import QtQuick.Shapes 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Utils 1.0
|
||||
|
||||
ChartView {
|
||||
id: chart
|
||||
|
||||
antialiasing: true
|
||||
backgroundColor: Palette.backgroundColor
|
||||
margins.left: 20
|
||||
|
||||
legend.visible: false
|
||||
legend.alignment: Qt.AlignRight
|
||||
legend.markerShape: Legend.MarkerShapeCircle
|
||||
|
||||
property AbstractAxis xAxis: valueAxisX
|
||||
property AbstractAxis yAxis: valueAxisY
|
||||
|
||||
property int defaultXMax: 10
|
||||
property int defaultYMax: 1
|
||||
property bool autoScaling: true
|
||||
property int selectedSeriesIndex: 0
|
||||
|
||||
property string infoXMark: ""
|
||||
property string infoYMark: ""
|
||||
|
||||
ValueAxis {
|
||||
id: valueAxisX
|
||||
min: 0
|
||||
max: chart.defaultXMax
|
||||
tickCount: 8
|
||||
gridVisible: false
|
||||
gridLineColor: Palette.borderColor
|
||||
labelsColor: Palette.contentTextColor
|
||||
labelsFont.pixelSize: 18
|
||||
color: Palette.borderColor
|
||||
titleVisible: false
|
||||
}
|
||||
|
||||
ValueAxis {
|
||||
id: valueAxisY
|
||||
min: 0
|
||||
max: chart.defaultYMax
|
||||
tickCount: 6
|
||||
labelsColor: Palette.contentTextColor
|
||||
labelsFont.pixelSize: 18
|
||||
color: Palette.borderColor
|
||||
titleVisible: false
|
||||
}
|
||||
|
||||
Shape {
|
||||
id: currentPointLine
|
||||
implicitWidth: 1
|
||||
implicitHeight: chart.plotArea.height
|
||||
x: chart.plotArea.x
|
||||
y: chart.plotArea.y
|
||||
|
||||
ShapePath {
|
||||
strokeColor: Palette.borderColor
|
||||
strokeStyle: ShapePath.SolidLine
|
||||
startX: 0
|
||||
startY: 0
|
||||
PathLine { x: 0; y: currentPointLine.height }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: currentPointInfo
|
||||
|
||||
width: currentPointInfoLabel.width
|
||||
height: currentPointInfoLabel.height
|
||||
color: Palette.backgroundColor
|
||||
border.width: 1
|
||||
border.color: Palette.borderColor
|
||||
opacity: 0.9
|
||||
radius: 6
|
||||
visible: false
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: currentPointInfoLabel
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.centerIn: parent
|
||||
padding: 10
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: chartMouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
|
||||
property real lastMouseX: 0
|
||||
property real lastMouseY: 0
|
||||
|
||||
property real scrollThreshold: 0
|
||||
|
||||
onMouseXChanged: {
|
||||
if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
|
||||
if (mouseX - lastMouseX > scrollThreshold) {
|
||||
chart.scrollLeft(mouseX - lastMouseX)
|
||||
} else if (mouseX - lastMouseX < scrollThreshold) {
|
||||
chart.scrollRight(lastMouseX - mouseX)
|
||||
}
|
||||
lastMouseX = mouseX
|
||||
chart.autoScaling = false
|
||||
}
|
||||
|
||||
updatePointInfo()
|
||||
}
|
||||
onMouseYChanged: {
|
||||
|
||||
if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
|
||||
if (mouseY - lastMouseY > scrollThreshold) {
|
||||
chart.scrollUp(mouseY - lastMouseY)
|
||||
} else if (mouseY - lastMouseY < scrollThreshold) {
|
||||
chart.scrollDown(lastMouseY - mouseY)
|
||||
}
|
||||
lastMouseY = mouseY
|
||||
chart.autoScaling = false
|
||||
}
|
||||
|
||||
updatePointInfo()
|
||||
}
|
||||
onPressed: {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
lastMouseX = mouseX
|
||||
lastMouseY = mouseY
|
||||
}
|
||||
}
|
||||
onWheel: {
|
||||
var scaleFactor = 0.75
|
||||
var area = chart.plotArea
|
||||
chart.autoScaling = false
|
||||
|
||||
var yAxisPosition = mouseX <= chart.plotArea.x
|
||||
if (yAxisPosition) {
|
||||
if (wheel.angleDelta.y > 0) {
|
||||
chart.zoomIn(Qt.rect(area.x, area.y + Math.round(area.height * (1 - scaleFactor) / 2), area.width, Math.round(area.height * scaleFactor)))
|
||||
} else {
|
||||
chart.zoomIn(Qt.rect(area.x, area.y - Math.round((area.height / scaleFactor) * (1 - scaleFactor) / 2), area.width, Math.round(area.height / scaleFactor)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var xAxisPosition = mouseY >= (chart.plotArea.y + chart.plotArea.height)
|
||||
if (xAxisPosition) {
|
||||
if (wheel.angleDelta.y > 0) {
|
||||
chart.zoomIn(Qt.rect(area.x + area.width * (1 - scaleFactor) / 2, area.y, Math.round(area.width * scaleFactor), area.height))
|
||||
} else {
|
||||
chart.zoomIn(Qt.rect(area.x - (area.width / scaleFactor) * (1 - scaleFactor) / 2, area.y, Math.round(area.width / scaleFactor), area.height))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (wheel.angleDelta.y > 0) {
|
||||
let zoomedInArea = Qt.rect(area.x + Math.round((mouseX - area.x) * (1 - scaleFactor)),
|
||||
area.y + Math.round((mouseY - area.y) * (1 - scaleFactor)),
|
||||
Math.round(area.width * scaleFactor),
|
||||
Math.round(area.height * scaleFactor))
|
||||
chart.zoomIn(zoomedInArea)
|
||||
} else {
|
||||
let zoomedOutArea = Qt.rect(area.x - Math.floor((mouseX - area.x) * (1 - scaleFactor)),
|
||||
area.y - Math.floor((mouseY - area.y) * (1 - scaleFactor)),
|
||||
Math.round(area.width * (1 + (1 - scaleFactor))),
|
||||
Math.round(area.height * (1 + (1 - scaleFactor))))
|
||||
chart.zoomIn(zoomedOutArea)
|
||||
}
|
||||
|
||||
updatePointInfo()
|
||||
}
|
||||
|
||||
function updatePointInfo() {
|
||||
let currentPointVisibility = mouseX >= chart.plotArea.x && mouseX <= chart.plotArea.x + chart.plotArea.width &&
|
||||
mouseY >= chart.plotArea.y && mouseY <= chart.plotArea.y + chart.plotArea.height
|
||||
|
||||
currentPointInfo.visible = currentPointVisibility
|
||||
currentPointInfo.x = mouseX + 5
|
||||
currentPointInfo.y = mouseY - currentPointInfo.height - 5
|
||||
|
||||
let currentX = mapToValue(Qt.point(mouseX, mouseY), chart.series(selectedSeriesIndex)).x
|
||||
let selectedPoint = Qt.point(0, 0)
|
||||
|
||||
for(let i = 0; i < chart.series(selectedSeriesIndex).count; ++i) {
|
||||
let point = chart.series(selectedSeriesIndex).at(i)
|
||||
if (point.x > currentX || i === chart.series(selectedSeriesIndex).count - 1) {
|
||||
selectedPoint = chart.series(selectedSeriesIndex).at(i)
|
||||
currentPointInfoLabel.text = selectedPoint.x + " " + infoXMark + ", " + selectedPoint.y + " " + infoYMark
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (chart.series(selectedSeriesIndex).count === 0) {
|
||||
currentPointInfo.visible = false
|
||||
}
|
||||
|
||||
currentPointLine.visible = currentPointVisibility
|
||||
currentPointLine.x = mouseX
|
||||
}
|
||||
}
|
||||
|
||||
onSeriesAdded: if (count === 1) {
|
||||
series.pointAdded.connect(function (index){ chartMouseArea.updatePointInfo() })
|
||||
}
|
||||
}
|
||||
37
qml/Controls/CheckBox.qml
Normal file
@@ -0,0 +1,37 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
CheckBox {
|
||||
id: control
|
||||
implicitHeight: 25
|
||||
spacing: 15
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: control.implicitHeight
|
||||
implicitHeight: control.implicitHeight
|
||||
x: control.leftPadding
|
||||
y: parent.height / 2 - height / 2
|
||||
radius: 5
|
||||
border.color: Palette.borderColor
|
||||
border.width: 1
|
||||
color: control.checked ? Palette.alternativeBackgroundColor : Palette.backgroundColor
|
||||
|
||||
Image {
|
||||
source: "qrc:/Icons/check-indicator.svg"
|
||||
anchors.centerIn: parent
|
||||
visible: control.checked
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
color: Palette.textColor
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
leftPadding: control.indicator.width + control.spacing
|
||||
}
|
||||
}
|
||||
113
qml/Controls/ComboBox.qml
Normal file
@@ -0,0 +1,113 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Utils 1.0
|
||||
|
||||
ComboBox {
|
||||
id: control
|
||||
|
||||
leftPadding: 16
|
||||
rightPadding: 16
|
||||
font.pixelSize: 16
|
||||
|
||||
delegate: ItemDelegate {
|
||||
width: control.width
|
||||
leftPadding: control.leftPadding
|
||||
clip: true
|
||||
|
||||
contentItem: Text {
|
||||
text: modelData
|
||||
color: pressed ? Palette.selectedTextColor : Palette.textColor
|
||||
font: control.font
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: control.currentIndex === index ?
|
||||
Palette.selectedBackgroundColor :
|
||||
(highlighted ? Palette.hoveredBackgroundColor : Palette.backgroundColor)
|
||||
}
|
||||
|
||||
highlighted: control.highlightedIndex === index
|
||||
}
|
||||
|
||||
indicator: Canvas {
|
||||
id: canvas
|
||||
x: control.width - width - control.rightPadding
|
||||
y: control.topPadding + (control.availableHeight - height) / 2
|
||||
width: 8
|
||||
height: 5
|
||||
contextType: "2d"
|
||||
|
||||
Connections {
|
||||
target: control
|
||||
onDownChanged: canvas.requestPaint()
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
var context = getContext("2d")
|
||||
context.reset()
|
||||
|
||||
if (control.down) {
|
||||
context.moveTo(0, height);
|
||||
context.lineTo(width, height);
|
||||
context.lineTo(width / 2, 0);
|
||||
} else {
|
||||
context.moveTo(0, 0);
|
||||
context.lineTo(width, 0);
|
||||
context.lineTo(width / 2, height);
|
||||
}
|
||||
|
||||
context.closePath();
|
||||
context.fillStyle = control.down ? Palette.selectedTextColor : Palette.textColor;
|
||||
context.fill();
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
rightPadding: control.indicator.width + 8
|
||||
|
||||
text: control.displayText
|
||||
font: control.font
|
||||
color: control.down ? Palette.selectedTextColor : Palette.textColor
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 120
|
||||
implicitHeight: 46
|
||||
color: control.enabled
|
||||
? (control.down ? Palette.selectedBackgroundColor : Palette.backgroundColor)
|
||||
: Palette.hoveredBackgroundColor
|
||||
|
||||
border.color: Palette.borderColor
|
||||
border.width: 1
|
||||
radius: 5
|
||||
}
|
||||
|
||||
popup: Popup {
|
||||
y: control.height + 2
|
||||
width: control.width
|
||||
implicitHeight: contentItem.implicitHeight
|
||||
padding: 1
|
||||
|
||||
contentItem: ListView {
|
||||
clip: true
|
||||
implicitHeight: contentHeight
|
||||
model: control.popup.visible ? control.delegateModel : null
|
||||
currentIndex: control.highlightedIndex
|
||||
|
||||
ScrollBar.vertical: Controls.ScrollBar {}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.backgroundColor
|
||||
border.color: Palette.borderColor
|
||||
border.width: 1
|
||||
radius: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
11
qml/Controls/ContentLabel.qml
Normal file
@@ -0,0 +1,11 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Label {
|
||||
color: Palette.contentTextColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Normal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
8
qml/Controls/DialogBackground.qml
Normal file
@@ -0,0 +1,8 @@
|
||||
import QtQuick 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Rectangle {
|
||||
color: Palette.screenBackgroundColor
|
||||
radius: 6
|
||||
}
|
||||
75
qml/Controls/DialogHeader.qml
Normal file
@@ -0,0 +1,75 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Utils 1.0
|
||||
|
||||
Rectangle {
|
||||
color: Qt.darker(Palette.hoveredBackgroundColor, 1.05)
|
||||
height: 50
|
||||
radius: 6
|
||||
|
||||
property Dialog dialog: undefined
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: root.title
|
||||
leftPadding: 20
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: parent.height
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
property int lastX: 0
|
||||
property int lastY: 0
|
||||
|
||||
onPressed: {
|
||||
lastX = mouse.x
|
||||
lastY = mouse.y
|
||||
}
|
||||
|
||||
onPositionChanged:{
|
||||
var deltaX = mouse.x - lastX
|
||||
dialog.x += deltaX
|
||||
lastX = mouse.x - deltaX
|
||||
|
||||
var deltaY = mouse.y - lastY
|
||||
dialog.y += deltaY
|
||||
lastY = mouse.y - deltaY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: closeImage
|
||||
source: "qrc:/Icons/close.svg"
|
||||
sourceSize.width: 36
|
||||
sourceSize.height: 36
|
||||
Layout.rightMargin: 10
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
|
||||
onPressed: {
|
||||
closeImage.sourceSize.width = 32
|
||||
closeImage.sourceSize.height = 32
|
||||
}
|
||||
onReleased: {
|
||||
closeImage.sourceSize.width = 36
|
||||
closeImage.sourceSize.height = 36
|
||||
}
|
||||
onClicked: {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
qml/Controls/DotSeparator.qml
Normal file
@@ -0,0 +1,19 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Shapes 1.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Shape {
|
||||
id: shape
|
||||
implicitHeight: 1
|
||||
|
||||
ShapePath {
|
||||
strokeColor: Palette.contentTextColor
|
||||
strokeWidth: 1
|
||||
strokeStyle: ShapePath.DashLine
|
||||
dashPattern: [1, 3]
|
||||
startX: 0
|
||||
startY: 0
|
||||
PathLine { x: shape.width; y: 0 }
|
||||
}
|
||||
}
|
||||
13
qml/Controls/Frame.qml
Normal file
@@ -0,0 +1,13 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Frame {
|
||||
background: Rectangle {
|
||||
color: Palette.backgroundColor
|
||||
border.color: Palette.borderColor
|
||||
border.width: 1
|
||||
radius: 8
|
||||
}
|
||||
}
|
||||
27
qml/Controls/ImageButton.qml
Normal file
@@ -0,0 +1,27 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Button {
|
||||
id: control
|
||||
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
|
||||
contentItem: Image {
|
||||
source: control.icon.source
|
||||
sourceSize.width: control.icon.width
|
||||
sourceSize.height: control.icon.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 44
|
||||
implicitHeight: 44
|
||||
opacity: enabled ? 1 : 0.3
|
||||
color: control.pressed ? Palette.pressedButtonColor :
|
||||
control.hovered ? Palette.hoveredButtonColor : Palette.buttonColor
|
||||
radius: 5
|
||||
}
|
||||
}
|
||||
18
qml/Controls/LabelWithBackground.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Label {
|
||||
color: Palette.textColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.hoveredBackgroundColor
|
||||
radius: 8
|
||||
}
|
||||
}
|
||||
19
qml/Controls/LineSeparator.qml
Normal file
@@ -0,0 +1,19 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Shapes 1.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Shape {
|
||||
id: shape
|
||||
implicitWidth: 1
|
||||
implicitHeight: 1
|
||||
property bool horizontal: true
|
||||
|
||||
ShapePath {
|
||||
strokeColor: Palette.borderColor
|
||||
strokeStyle: ShapePath.SolidLine
|
||||
startX: 0
|
||||
startY: 0
|
||||
PathLine { x: horizontal ? shape.width : 0; y: horizontal ? 0 : shape.height }
|
||||
}
|
||||
}
|
||||
22
qml/Controls/LinkLabel.qml
Normal file
@@ -0,0 +1,22 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Label {
|
||||
id: control
|
||||
color: Palette.selectedTextColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Normal
|
||||
font.underline : true
|
||||
elide: Text.ElideRight
|
||||
|
||||
signal clicked()
|
||||
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: control.clicked()
|
||||
}
|
||||
}
|
||||
63
qml/Controls/MenuItemDelegate.qml
Normal file
@@ -0,0 +1,63 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
ItemDelegate {
|
||||
id: control
|
||||
implicitHeight: 52
|
||||
padding: 0
|
||||
leftPadding: control.minimized ? 0 : 40
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
icon.color: "transparent"
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
|
||||
property bool minimized: false
|
||||
property bool mirroredIcon: false
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: control.minimized ? 0 : 25
|
||||
|
||||
Item {
|
||||
visible: control.minimized
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Image {
|
||||
source: control.icon.source
|
||||
sourceSize.width: control.icon.width
|
||||
sourceSize.height: control.icon.height
|
||||
mirror: control.mirroredIcon
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: parent
|
||||
source: parent
|
||||
color: icon.color
|
||||
visible: icon.color !== "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: control.text
|
||||
font: control.font
|
||||
color: Palette.alternativeTextColor
|
||||
visible: !control.minimized
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: control.pressed || control.highlighted ?
|
||||
Palette.pressedButtonColor : control.hovered ?
|
||||
Palette.hoveredButtonColor : Palette.buttonColor
|
||||
}
|
||||
}
|
||||
33
qml/Controls/OutlineButton.qml
Normal file
@@ -0,0 +1,33 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Button {
|
||||
id: control
|
||||
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
opacity: enabled ? 1.0 : 0.7
|
||||
color: control.hovered ? Palette.alternativeTextColor : Palette.textColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 2
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 200
|
||||
implicitHeight: 52
|
||||
opacity: enabled ? 1 : 0.7
|
||||
color: control.pressed ? Palette.pressedButtonColor :
|
||||
control.hovered ? Palette.hoveredButtonColor : Palette.outlineButtonColor
|
||||
border.color: control.pressed ? Palette.pressedButtonColor :
|
||||
control.hovered ? Palette.hoveredButtonColor : Palette.buttonColor
|
||||
border.width: 1
|
||||
radius: 5
|
||||
}
|
||||
}
|
||||
38
qml/Controls/OutlineImageButton.qml
Normal file
@@ -0,0 +1,38 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Button {
|
||||
id: control
|
||||
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
|
||||
contentItem: Image {
|
||||
source: control.icon.source
|
||||
sourceSize.width: control.icon.width
|
||||
sourceSize.height: control.icon.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: parent
|
||||
source: parent
|
||||
color: "#FFFFFF"
|
||||
visible: control.hovered
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 44
|
||||
implicitHeight: 44
|
||||
color: control.enabled ? (control.pressed ? Palette.pressedButtonColor :
|
||||
control.hovered ? Palette.hoveredButtonColor : Palette.backgroundColor) :
|
||||
Palette.hoveredBackgroundColor
|
||||
border.color: control.pressed ? Palette.pressedButtonColor :
|
||||
control.hovered ? Palette.hoveredButtonColor : Palette.borderColor
|
||||
border.width: 1
|
||||
radius: 5
|
||||
}
|
||||
}
|
||||
38
qml/Controls/ProgressBar.qml
Normal file
@@ -0,0 +1,38 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
ProgressBar {
|
||||
id: control
|
||||
padding: 2
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 250
|
||||
implicitHeight: 26
|
||||
border.width: 1
|
||||
border.color: Palette.borderColor
|
||||
color: Palette.screenBackgroundColor
|
||||
radius: 5
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
implicitWidth: 250
|
||||
implicitHeight: 24
|
||||
|
||||
Rectangle {
|
||||
width: control.visualPosition * parent.width
|
||||
height: parent.height
|
||||
radius: 5
|
||||
color: Palette.alternativeBackgroundColor
|
||||
}
|
||||
|
||||
Text {
|
||||
text: Math.floor((control.value / control.to) * 100) + '%'
|
||||
anchors.centerIn: parent
|
||||
color: Palette.textColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
}
|
||||
}
|
||||
42
qml/Controls/RadioButton.qml
Normal file
@@ -0,0 +1,42 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
RadioButton {
|
||||
id: control
|
||||
implicitHeight: 30
|
||||
spacing: 15
|
||||
leftPadding: 0
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: control.implicitHeight
|
||||
implicitHeight: control.implicitHeight
|
||||
x: control.leftPadding
|
||||
y: parent.height / 2 - height / 2
|
||||
radius: implicitWidth / 2
|
||||
border.color: Palette.borderColor
|
||||
|
||||
Rectangle {
|
||||
property int spacing: 10
|
||||
width: parent.implicitWidth - spacing
|
||||
height: parent.implicitHeight - spacing
|
||||
x: spacing / 2
|
||||
y: spacing / 2
|
||||
radius: width / 2
|
||||
color: Palette.alternativeBackgroundColor
|
||||
visible: control.checked
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
color: Palette.textColor
|
||||
maximumLineCount: 2
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
leftPadding: control.indicator.width + control.spacing
|
||||
}
|
||||
}
|
||||
40
qml/Controls/ScrollBar.qml
Normal file
@@ -0,0 +1,40 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
ScrollBar {
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 2
|
||||
visible: control.policy !== ScrollBar.AlwaysOff
|
||||
minimumSize: orientation == Qt.Horizontal ? height / width : width / height
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: control.interactive ? 6 : 2
|
||||
implicitHeight: control.interactive ? 6 : 2
|
||||
|
||||
radius: width / 2
|
||||
color: control.pressed ? Palette.alternativeBackgroundColor : Qt.lighter(Palette.alternativeBackgroundColor, 1.1)
|
||||
opacity: 0.0
|
||||
|
||||
states: State {
|
||||
name: "active"
|
||||
when: control.policy === ScrollBar.AlwaysOn || (control.active && control.size < 1.0)
|
||||
PropertyChanges { target: control.contentItem; opacity: 0.75 }
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
from: "active"
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 450 }
|
||||
NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
qml/Controls/ScrollIndicator.qml
Normal file
@@ -0,0 +1,40 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
ScrollIndicator {
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 2
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: 2
|
||||
implicitHeight: 2
|
||||
|
||||
color: Palette.alternativeBackgroundColor
|
||||
visible: control.size < 1.0
|
||||
opacity: 0.0
|
||||
|
||||
states: State {
|
||||
name: "active"
|
||||
when: control.active
|
||||
PropertyChanges { target: control.contentItem; opacity: 0.75 }
|
||||
}
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "active"
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 450 }
|
||||
NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
11
qml/Controls/SubtitleLabel.qml
Normal file
@@ -0,0 +1,11 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Label {
|
||||
color: Palette.textColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
20
qml/Controls/TabBar.qml
Normal file
@@ -0,0 +1,20 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
TabBar {
|
||||
id: control
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.backgroundColor
|
||||
|
||||
Rectangle {
|
||||
height: 1
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: Palette.borderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
46
qml/Controls/TabButton.qml
Normal file
@@ -0,0 +1,46 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
TabButton {
|
||||
id: control
|
||||
|
||||
contentItem: Text {
|
||||
text: control.text
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
opacity: enabled ? 1.0 : 0.3
|
||||
color: control.checked ? Palette.selectedTextColor : Palette.textColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 2
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
background: Item {
|
||||
implicitWidth: 150
|
||||
implicitHeight: 58
|
||||
|
||||
Rectangle {
|
||||
property bool selected: control.checked
|
||||
|
||||
height: 2
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
color: Palette.alternativeBackgroundColor
|
||||
visible: selected
|
||||
|
||||
// Behavior on selected {
|
||||
// PropertyAnimation {
|
||||
// properties: "selected";
|
||||
// easing.type: Easing.OutElastic;
|
||||
// easing.amplitude: 0.2;
|
||||
// easing.period: 0.2
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
11
qml/Controls/TextArea.qml
Normal file
@@ -0,0 +1,11 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
TextArea {
|
||||
color: Palette.textColor
|
||||
selectByMouse: true
|
||||
selectionColor: Palette.selectedTextBackgroundColor
|
||||
font.pixelSize: 16
|
||||
}
|
||||
21
qml/Controls/TextField.qml
Normal file
@@ -0,0 +1,21 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
TextField {
|
||||
implicitHeight: 58
|
||||
font.pixelSize: 16
|
||||
color: Palette.textColor
|
||||
selectByMouse: true
|
||||
selectionColor: Palette.selectedTextBackgroundColor
|
||||
leftPadding: 16
|
||||
rightPadding: 16
|
||||
|
||||
background: Rectangle {
|
||||
color: enabled ? Palette.backgroundColor : Palette.hoveredBackgroundColor
|
||||
border.color: Palette.borderColor
|
||||
border.width: 1
|
||||
radius: 8
|
||||
}
|
||||
}
|
||||
11
qml/Controls/TitleLabel.qml
Normal file
@@ -0,0 +1,11 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Utils 1.0
|
||||
|
||||
Label {
|
||||
color: Palette.selectedTextColor
|
||||
font.pixelSize: 28
|
||||
font.weight: Font.Bold
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
29
qml/Controls/qmldir
Normal file
@@ -0,0 +1,29 @@
|
||||
module Controls
|
||||
ComboBox 1.0 ComboBox.qml
|
||||
ScrollBar 1.0 ScrollBar.qml
|
||||
Button 1.0 Button.qml
|
||||
OutlineButton 1.0 OutlineButton.qml
|
||||
TextField 1.0 TextField.qml
|
||||
Frame 1.0 Frame.qml
|
||||
TitleLabel 1.0 TitleLabel.qml
|
||||
SubtitleLabel 1.0 SubtitleLabel.qml
|
||||
ContentLabel 1.0 ContentLabel.qml
|
||||
DotSeparator 1.0 DotSeparator.qml
|
||||
AvailabilityIndicator 1.0 AvailabilityIndicator.qml
|
||||
LabelWithBackground 1.0 LabelWithBackground.qml
|
||||
CheckBox 1.0 CheckBox.qml
|
||||
LineSeparator 1.0 LineSeparator.qml
|
||||
LinkLabel 1.0 LinkLabel.qml
|
||||
TabButton 1.0 TabButton.qml
|
||||
TabBar 1.0 TabBar.qml
|
||||
ChartView 1.0 ChartView.qml
|
||||
TextArea 1.0 TextArea.qml
|
||||
DialogHeader 1.0 DialogHeader.qml
|
||||
DialogBackground 1.0 DialogBackground.qml
|
||||
BusyIndicator 1.0 BusyIndicator.qml
|
||||
MenuItemDelegate 1.0 MenuItemDelegate.qml
|
||||
ScrollIndicator 1.0 ScrollIndicator.qml
|
||||
OutlineImageButton 1.0 OutlineImageButton.qml
|
||||
ImageButton 1.0 ImageButton.qml
|
||||
ProgressBar 1.0 ProgressBar.qml
|
||||
RadioButton 1.0 RadioButton.qml
|
||||
4
qml/Icons/akb-monitor.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22 11.6154V16.9231H2V3H7.71429V1H1.71429C1.25963 1 0.823594 1.1864 0.502103 1.5182C0.180612 1.84999 0 2.3 0 2.76923V17.2308C0 17.7 0.180612 18.15 0.502103 18.4818C0.823594 18.8136 1.25963 19 1.71429 19H8.57143V22.2308H5.14286V24H18.8571V22.2308H15.4286V19H22.2857C22.7404 19 23.1764 18.8136 23.4979 18.4818C23.8194 18.15 24 17.7 24 17.2308V11.6154H22ZM13.7143 22.2308H10.2857V19H13.7143V22.2308Z" fill="white"/>
|
||||
<path d="M13.2632 15H13.2542C13.0614 14.9977 12.8744 14.926 12.7211 14.7953C12.5678 14.6647 12.4563 14.4822 12.4033 14.275L10.7991 8.00005H7V6.00007H11.4737C11.6682 5.99995 11.8574 6.07065 12.0127 6.20146C12.168 6.33228 12.2809 6.51609 12.3344 6.72506L13.2954 10.485L15.9876 0.705106C16.0457 0.502156 16.1595 0.324815 16.3129 0.198262C16.4663 0.0717101 16.6515 0.00237827 16.8421 0.000110855C17.0306 -0.00305764 17.215 0.0617711 17.368 0.184981C17.5209 0.308191 17.6343 0.48322 17.6912 0.684106L19.2758 6.00007H24V8.00005H18.6316C18.4437 8.0001 18.2606 7.93406 18.1082 7.8113C17.9558 7.68853 17.8418 7.51526 17.7825 7.31606L16.8761 4.27608L14.1185 14.294C14.0623 14.4985 13.9488 14.6774 13.7949 14.8044C13.6409 14.9315 13.4545 15 13.2632 15Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
5
qml/Icons/bms-configuration.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 10V4.22222C20 2.99492 18.9767 2 17.7143 2H6.28571C5.02335 2 4 2.99492 4 4.22222V19.7778C4 21.0051 5.02335 22 6.28571 22H9" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 14H13.3333M8 7H16H8ZM8 10.5H16H8Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M21.1046 13.0108C21.2559 13.0039 21.4068 13.03 21.547 13.0872C21.6871 13.1444 21.813 13.2314 21.9159 13.3421L22.6921 14.1259C22.8895 14.3271 23 14.5973 23 14.8787C23 15.16 22.8895 15.4302 22.6921 15.6315L21.2452 17.0725L18.9464 14.7723L20.3933 13.3313C20.5823 13.1388 20.835 13.0211 21.1046 13V13.0108ZM18.9464 14.7723L21.2452 17.0617L17.2724 21.0291L16.1067 22.1954C16.0513 22.2593 15.9806 22.3083 15.9012 22.3381L13.4672 22.9872C13.4043 23.0042 13.338 23.0043 13.275 22.9875C13.212 22.9708 13.1546 22.9378 13.1085 22.8919C13.0624 22.846 13.0293 22.7888 13.0125 22.7261C12.9957 22.6634 12.9958 22.5974 13.0128 22.5347L13.6619 20.1106C13.693 20.0301 13.7442 19.9587 13.8106 19.9032L14.2569 19.4588L18.9464 14.7723Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
4
qml/Icons/bms-service.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9998 1C12.5514 1 13.0951 1.04086 13.6246 1.11943L14.4229 3.53782C15.1222 3.73739 15.7869 4.02181 16.4028 4.38009L18.6971 3.27382C19.5095 3.89767 20.2323 4.63308 20.842 5.4565L19.6949 7.73032C20.0422 8.3526 20.3156 9.02201 20.5026 9.726L22.9068 10.5636C23.0393 11.5803 23.0303 12.6104 22.8801 13.6247L20.4617 14.4229C20.2635 15.1151 19.9806 15.7801 19.6195 16.4029L20.7257 18.6971C20.101 19.5098 19.3665 20.2317 18.5431 20.8421L16.2693 19.695C15.647 20.0423 14.9776 20.3157 14.2736 20.5027L13.4361 22.9069C12.4194 23.0394 11.3892 23.0304 10.375 22.8802L9.57675 20.4618C8.88462 20.2636 8.21961 19.9807 7.5968 19.6196L5.30258 20.7258C4.48995 20.1011 3.76806 19.3666 3.15763 18.5431L4.30475 16.2693C3.95434 15.6399 3.68306 14.9696 3.49705 14.2736L1.09283 13.4345C0.960511 12.4183 0.9695 11.3887 1.11955 10.375L3.53791 9.57672C3.73747 8.87745 4.0219 8.21274 4.38017 7.59675L3.27392 5.3025C3.8986 4.48986 4.63318 3.76797 5.45657 3.15754L7.73037 4.30466C8.35264 3.95738 9.02205 3.68396 9.72603 3.49696L10.5651 1.09271C11.035 1.03143 11.5143 1 11.9998 1Z" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M11.9999 16C14.209 16 15.9999 14.2091 15.9999 12C15.9999 9.79086 14.209 8 11.9999 8C9.79074 8 7.99988 9.79086 7.99988 12C7.99988 14.2091 9.79074 16 11.9999 16Z" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
18
qml/Icons/cell-monitor.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1_973_566" fill="white">
|
||||
<rect x="1" y="1" width="9" height="13" rx="1"/>
|
||||
</mask>
|
||||
<rect x="1" y="1" width="9" height="13" rx="1" stroke="white" stroke-width="2" mask="url(#path-1-inside-1_973_566)"/>
|
||||
<mask id="path-2-inside-2_973_566" fill="white">
|
||||
<rect x="13" y="1" width="9" height="7" rx="1"/>
|
||||
</mask>
|
||||
<rect x="13" y="1" width="9" height="7" rx="1" stroke="white" stroke-width="2" mask="url(#path-2-inside-2_973_566)"/>
|
||||
<mask id="path-3-inside-3_973_566" fill="white">
|
||||
<rect x="13" y="11" width="9" height="12" rx="1"/>
|
||||
</mask>
|
||||
<rect x="13" y="11" width="9" height="12" rx="1" stroke="white" stroke-width="2" mask="url(#path-3-inside-3_973_566)"/>
|
||||
<mask id="path-4-inside-4_973_566" fill="white">
|
||||
<rect x="1" y="17" width="9" height="6" rx="1"/>
|
||||
</mask>
|
||||
<rect x="1" y="17" width="9" height="6" rx="1" stroke="white" stroke-width="2" mask="url(#path-4-inside-4_973_566)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1003 B |
3
qml/Icons/check-indicator.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.7203 7.19847C20.0643 7.48676 20.0953 7.98339 19.7895 8.30772L10.9006 17.7363C10.7425 17.904 10.5158 18 10.2778 18C10.0397 18 9.81308 17.904 9.65494 17.7363L5.2105 13.022C4.90474 12.6977 4.93572 12.201 5.27971 11.9128C5.62369 11.6245 6.15042 11.6537 6.45618 11.978L10.2778 16.0316L18.5438 7.26372C18.8496 6.93939 19.3763 6.91018 19.7203 7.19847Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 477 B |
1
qml/Icons/close.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g data-name="Layer 2"><g data-name="close"><rect width="24" height="24" transform="rotate(180 12 12)" opacity="0"/><path d="M13.41 12l4.3-4.29a1 1 0 1 0-1.42-1.42L12 10.59l-4.29-4.3a1 1 0 0 0-1.42 1.42l4.3 4.29-4.3 4.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l4.29-4.3 4.29 4.3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 411 B |
3
qml/Icons/connection.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="#000" stroke-width="2" d="M10,21 C7.50000053,23.5 5.00000002,23 3,21 C0.999999977,19 0.500000114,16.5 3.00000004,14 C5.49999997,11.5 5.99999998,11 5.99999998,11 L13.0000005,18 C13.0000005,18 12.4999995,18.5 10,21 Z M14.0003207,3 C16.5,0.499999776 19,0.999999776 21.001068,3 C23.002136,5.00000022 23.5,7.49999978 21.001068,10 C18.5021359,12.5000002 18.0007478,13 18.0007478,13 L11,6 C11,6 11.5006414,5.50000022 14.0003207,3 Z M11,9.9999 L8.5,12.4999999 L11,9.9999 Z M14,13 L11.5,15.5 L14,13 Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 618 B |
BIN
qml/Icons/cubo-icon.ico
Normal file
|
After Width: | Height: | Size: 98 KiB |
15
qml/Icons/cubo-logo.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<svg width="115" height="115" viewBox="0 0 115 115" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M91.0183 45.5542C91.0183 51.3591 86.0875 56.038 80.0087 56.038C73.9189 56.038 68.999 51.3591 68.999 45.5542C68.999 39.782 73.9189 35.0977 80.0087 35.0977C86.0875 35.1031 91.0183 39.782 91.0183 45.5542ZM86.0328 45.5542C86.0328 42.3456 83.3323 39.7493 80.0087 39.7493C76.6741 39.7493 73.9845 42.3456 73.9845 45.5542C73.9845 48.7955 76.6741 51.3919 80.0087 51.3919C83.3323 51.3919 86.0328 48.7955 86.0328 45.5542Z" fill="white"/>
|
||||
<path d="M64.2045 44.6847C65.839 45.8817 66.8121 47.6965 66.8121 49.7298C66.8121 53.3101 63.8 56.1634 59.5361 56.1634H50.9263V42.0282C50.9263 37.8958 54.2171 35.0098 58.3225 35.0098C62.3295 35.0098 65.44 37.956 65.44 41.5581C65.4291 42.8043 64.9808 43.8757 64.2045 44.6847ZM61.4166 49.7298C61.4166 48.3852 60.2632 47.5379 58.6943 47.5379H55.9992V51.9272H58.6943C60.2577 51.9326 61.4166 51.0854 61.4166 49.7298ZM58.5303 43.2744C59.5962 43.2744 60.378 42.3671 60.378 41.3066C60.378 40.0768 59.4705 39.2678 58.2187 39.2678C56.9067 39.2678 55.9938 40.0768 55.9938 41.4269V43.2744H58.5303Z" fill="white"/>
|
||||
<path d="M46.9142 35.3159V47.4396C46.9142 51.9163 44.5144 56.3875 38.3973 56.3875C32.1709 56.3875 29.9187 52.2497 29.6945 47.8441C29.6891 47.7074 29.6836 47.5762 29.6836 47.4396V35.3159H34.7566V47.6965C34.7566 49.5659 35.3633 51.8179 38.3699 51.8179C41.2071 51.8179 41.8357 49.5331 41.8357 47.6965V35.3159H46.9142Z" fill="white"/>
|
||||
<path d="M26.7753 40.4541L23.4626 42.1541L22.4841 42.657C22.331 42.4001 22.1014 42.0885 21.921 41.8644C21.5055 41.3615 20.9808 40.9242 20.4505 40.5853C20.0077 40.3394 19.472 40.0825 18.9691 39.9567C18.5263 39.8365 17.9906 39.7764 17.4876 39.7764C16.9956 39.7764 16.4599 39.8419 16.0171 39.9567C15.5142 40.0825 14.9785 40.3394 14.5357 40.5853C14 40.8969 13.4752 41.367 13.0652 41.8371C12.2561 42.9357 11.8133 44.3077 11.786 45.6851C11.7532 47.1828 12.3709 48.4838 13.1198 49.7136C13.5353 50.1837 14.071 50.621 14.6013 50.9325C15.0441 51.1785 15.5798 51.4026 16.0827 51.5338C16.5255 51.6541 17.0503 51.7142 17.5587 51.7142C18.0616 51.7142 18.5973 51.6158 19.0401 51.501C19.5431 51.3753 20.0788 51.1293 20.5216 50.8724C21.0464 50.5281 21.5821 50.058 21.9921 49.5606C22.1725 49.3365 22.3474 49.0905 22.495 48.8336L23.4735 49.3365L26.7862 51.0364C25.9608 52.4794 24.78 53.7311 23.4134 54.6713C22.9706 54.9829 22.4349 55.2999 21.9319 55.5131C21.4891 55.7372 20.9644 55.9176 20.4614 56.0815C19.5103 56.3275 18.5317 56.486 17.4931 56.486C16.4927 56.486 15.4541 56.3549 14.5357 56.0815C14.0328 55.923 13.5572 55.77 13.1144 55.5459C12.6224 55.3218 12.0265 54.9501 11.5783 54.6713C8.70287 52.7582 6.84424 49.4676 6.84424 45.7398C6.84424 42.012 8.70287 38.7542 11.5783 36.8411C13.262 35.7534 15.3338 35.0264 17.4931 35.0264C19.6852 35.0264 21.7953 35.7206 23.479 36.8739C24.8292 37.7976 25.9499 39.0166 26.7753 40.4541Z" fill="white"/>
|
||||
<path d="M11.3816 76.7814L6.78418 58.8473H9.74705C11.0645 58.8473 12.2125 59.7437 12.535 61.0173L15.968 74.6988C16.0609 75.0431 16.3725 75.2345 16.7825 75.2345C17.1925 75.2345 17.4713 75.0431 17.5642 74.6988L21.5767 58.8418H26.7808L22.4896 75.8576C21.2104 80.378 21.4783 80.0009 17.0886 79.9681C12.1906 79.9407 12.3109 80.4545 11.3816 76.7814Z" fill="white"/>
|
||||
<path d="M34.8547 64.6359V67.3907H44.7984V71.6215H34.8547V74.5021C34.8547 75.2509 35.385 75.7538 36.1721 75.7538H46.903V79.9845H36.1721C32.4768 79.9845 29.7817 80.2906 29.7817 73.9063V65.2262C29.7817 61.717 32.4768 59.1479 36.1721 59.1479H46.903V63.3787H36.1721C35.3904 63.3841 34.8547 63.887 34.8547 64.6359Z" fill="white"/>
|
||||
<path d="M50.7682 67.019C50.7682 62.4767 54.6221 58.8418 59.3889 58.8418C64.1503 58.8418 67.9714 62.4767 67.9714 67.019C67.9714 69.5552 66.7797 71.6269 64.5548 72.9387L68.3158 79.9899H62.9914L59.3124 72.6927C58.9953 72.0641 59.2413 71.2825 59.8754 70.9764C61.9582 69.9761 62.893 68.7025 62.893 67.019C62.893 65.1059 61.3569 63.5754 59.3835 63.5754C57.41 63.5754 55.8411 65.1113 55.8411 67.019V79.9899H50.7627V67.019H50.7682Z" fill="white"/>
|
||||
<path d="M78.4942 59.1533H71.6665V79.9898H78.4942C84.5731 79.9898 89.4602 75.3219 89.4602 69.5552C89.4602 63.8268 84.5731 59.1533 78.4942 59.1533ZM78.4942 75.7646H76.7395V63.3895H78.4942C81.7523 63.3895 84.3872 66.1444 84.3872 69.5607C84.3817 73.0043 81.7523 75.7646 78.4942 75.7646Z" fill="white"/>
|
||||
<path d="M107.243 42.3945C106.505 42.3945 105.925 42.8263 105.794 43.4659L105.472 45.062L105.149 43.4659C105.018 42.8263 104.439 42.3945 103.701 42.3945C102.902 42.3945 102.279 42.9193 102.279 43.5861V48.1339H103.493V43.6736C103.493 43.608 103.602 43.5643 103.706 43.5643C103.744 43.5643 103.93 43.5697 103.958 43.7173L104.925 48.1394H106.007L106.981 43.7119C107.008 43.5697 107.194 43.5643 107.232 43.5643C107.336 43.5643 107.445 43.608 107.445 43.6736V48.1339H108.659V43.5861C108.659 42.9193 108.036 42.3945 107.243 42.3945Z" fill="white"/>
|
||||
<path d="M97.6382 43.5535H99.0978V48.134H100.311V43.5535H101.771V42.4712H97.6382V43.5535Z" fill="white"/>
|
||||
<path d="M96.5667 64.6031V67.358H106.51V71.5887H96.5667V74.4693C96.5667 75.2182 97.097 75.7211 97.8842 75.7211H108.615V79.9518H97.8842C94.1888 79.9518 91.4883 80.2633 91.4883 73.8735V65.1935C91.4883 61.6843 94.1833 59.1152 97.8842 59.1152H108.615V63.3459H97.8842C97.097 63.3459 96.5667 63.8488 96.5667 64.6031Z" fill="white"/>
|
||||
<path d="M2.93554 0C1.31744 0 0 1.31185 0 2.93526V5.07795V17.3H5.07843V5.07795H17.3017V0H2.93554Z" fill="white"/>
|
||||
<path d="M109.921 97.7056V109.928H97.6982V115H112.064C113.682 115 115 113.688 115 112.065V109.922V97.7056H109.921Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
53
qml/Icons/english-flag.svg
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<path style="fill:#41479B;" d="M473.655,88.276H38.345C17.167,88.276,0,105.443,0,126.621V385.38
|
||||
c0,21.177,17.167,38.345,38.345,38.345h435.31c21.177,0,38.345-17.167,38.345-38.345V126.621
|
||||
C512,105.443,494.833,88.276,473.655,88.276z"/>
|
||||
<path style="fill:#F5F5F5;" d="M511.469,120.282c-3.022-18.159-18.797-32.007-37.814-32.007h-9.977l-163.54,107.147V88.276h-88.276
|
||||
v107.147L48.322,88.276h-9.977c-19.017,0-34.792,13.847-37.814,32.007l139.778,91.58H0v88.276h140.309L0.531,391.717
|
||||
c3.022,18.159,18.797,32.007,37.814,32.007h9.977l163.54-107.147v107.147h88.276V316.577l163.54,107.147h9.977
|
||||
c19.017,0,34.792-13.847,37.814-32.007l-139.778-91.58H512v-88.276H371.691L511.469,120.282z"/>
|
||||
<g>
|
||||
<polygon style="fill:#FF4B55;" points="282.483,88.276 229.517,88.276 229.517,229.517 0,229.517 0,282.483 229.517,282.483
|
||||
229.517,423.724 282.483,423.724 282.483,282.483 512,282.483 512,229.517 282.483,229.517 "/>
|
||||
<path style="fill:#FF4B55;" d="M24.793,421.252l186.583-121.114h-32.428L9.224,410.31
|
||||
C13.377,415.157,18.714,418.955,24.793,421.252z"/>
|
||||
<path style="fill:#FF4B55;" d="M346.388,300.138H313.96l180.716,117.305c5.057-3.321,9.277-7.807,12.287-13.075L346.388,300.138z"
|
||||
/>
|
||||
<path style="fill:#FF4B55;" d="M4.049,109.475l157.73,102.387h32.428L15.475,95.842C10.676,99.414,6.749,104.084,4.049,109.475z"/>
|
||||
<path style="fill:#FF4B55;" d="M332.566,211.862l170.035-110.375c-4.199-4.831-9.578-8.607-15.699-10.86L300.138,211.862H332.566z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
12
qml/Icons/error-state.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1401_2121)">
|
||||
<circle cx="12" cy="12.5" r="11" stroke="#CF3200" stroke-width="2"/>
|
||||
<path d="M12 6.5L12 14.5" stroke="#CF3200" stroke-width="2"/>
|
||||
<path d="M12 16L12 18" stroke="#CF3200" stroke-width="2" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1401_2121">
|
||||
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 492 B |
4
qml/Icons/exit.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.4001 3.60017C20.7183 3.60017 21.0235 3.72659 21.2485 3.95165C21.4736 4.17669 21.6001 4.48191 21.6001 4.80017V19.2002C21.6001 19.5184 21.4736 19.8237 21.2485 20.0487C21.0235 20.2737 20.7183 20.4002 20.4001 20.4002C20.0817 20.4002 19.7766 20.2737 19.5515 20.0487C19.3265 19.8237 19.2001 19.5184 19.2001 19.2002V4.80017C19.2001 4.48191 19.3265 4.17669 19.5515 3.95165C19.7766 3.72659 20.0817 3.60017 20.4001 3.60017ZM8.04841 14.7518C8.267 14.9781 8.38795 15.2812 8.38522 15.5959C8.38248 15.9105 8.25629 16.2115 8.0338 16.4339C7.81131 16.6564 7.51033 16.7827 7.19569 16.7853C6.88106 16.7881 6.57793 16.6671 6.35161 16.4486L2.75161 12.8486C2.52665 12.6236 2.40027 12.3183 2.40027 12.0002C2.40027 11.682 2.52665 11.3768 2.75161 11.1518L6.35161 7.55177C6.46231 7.43716 6.59472 7.34574 6.74113 7.28284C6.88753 7.21996 7.045 7.18685 7.20433 7.18547C7.36367 7.18409 7.52168 7.21445 7.66916 7.27479C7.81663 7.33512 7.95061 7.42422 8.06328 7.53689C8.17595 7.64957 8.26506 7.78355 8.3254 7.93103C8.38573 8.07851 8.4161 8.23652 8.41471 8.39585C8.41333 8.55519 8.38023 8.71269 8.31733 8.85909C8.25444 9.00549 8.16303 9.13792 8.04841 9.24857L6.49681 10.8002H15.6001C15.9183 10.8002 16.2235 10.9266 16.4485 11.1516C16.6736 11.3767 16.8001 11.6819 16.8001 12.0002C16.8001 12.3184 16.6736 12.6237 16.4485 12.8487C16.2235 13.0737 15.9183 13.2002 15.6001 13.2002H6.49681L8.04841 14.7518Z" fill="white"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
12
qml/Icons/good-state.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1401_2104)">
|
||||
<path d="M6 12.95L9.85714 17L18 8" stroke="#009352" stroke-width="2" stroke-linejoin="round"/>
|
||||
<circle cx="12" cy="12.5" r="11" stroke="#009352" stroke-width="2"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1401_2104">
|
||||
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 443 B |
4
qml/Icons/hide-menu.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 19L11 10L20 1" stroke="white" stroke-width="2"/>
|
||||
<path d="M11 19L2 10L11 1" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 226 B |
3
qml/Icons/history.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 4.66667V11.2792C12 11.7097 12.2754 12.0918 12.6838 12.2279L17.5 13.8333M12 23C14.9174 23 17.7153 21.8411 19.7782 19.7782C21.8411 17.7153 23 14.9174 23 12C23 9.08262 21.8411 6.28473 19.7782 4.22183C17.7153 2.15893 14.9174 1 12 1C9.08262 1 6.28473 2.15893 4.22183 4.22183C2.15893 6.28473 1 9.08262 1 12C1 14.9174 2.15893 17.7153 4.22183 19.7782C6.28473 21.8411 9.08262 23 12 23Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 528 B |
12
qml/Icons/info-state.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1401_2130)">
|
||||
<path d="M12 23.5V24.5V23.5ZM12 1.5V0.5V1.5ZM1 12.5H0H1ZM2.65602 18.3044L3.60879 18.6081C3.69622 18.3338 3.66119 18.0351 3.51265 17.7885L2.65602 18.3044ZM1 23.5L0.0472261 23.1963C-0.0638084 23.5447 0.0241315 23.9259 0.276556 24.1904C0.52898 24.4549 0.905642 24.5606 1.25881 24.4659L1 23.5ZM6.5 22.0263L6.99158 21.1555C6.76354 21.0268 6.49412 20.9926 6.24119 21.0604L6.5 22.0263ZM2.5 18.0453L1.63627 18.5495L1.64336 18.5612L2.5 18.0453ZM6.68517 22.1308L6.19357 23.0017L6.20203 23.0064L6.68517 22.1308ZM12 24.5C15.1826 24.5 18.2348 23.2357 20.4853 20.9853L19.0711 19.5711C17.1957 21.4464 14.6522 22.5 12 22.5V24.5ZM20.4853 20.9853C22.7357 18.7348 24 15.6826 24 12.5H22C22 15.1522 20.9464 17.6957 19.0711 19.5711L20.4853 20.9853ZM24 12.5C24 9.3174 22.7357 6.26516 20.4853 4.01472L19.0711 5.42893C20.9464 7.3043 22 9.84783 22 12.5H24ZM20.4853 4.01472C18.2348 1.76428 15.1826 0.5 12 0.5V2.5C14.6522 2.5 17.1957 3.55357 19.0711 5.42893L20.4853 4.01472ZM12 0.5C8.8174 0.5 5.76516 1.76428 3.51472 4.01472L4.92893 5.42893C6.8043 3.55357 9.34784 2.5 12 2.5V0.5ZM3.51472 4.01472C1.26428 6.26516 0 9.3174 0 12.5H2C2 9.84784 3.05357 7.3043 4.92893 5.42893L3.51472 4.01472ZM1.70324 18.0007L0.0472261 23.1963L1.95277 23.8037L3.60879 18.6081L1.70324 18.0007ZM1.25881 24.4659L6.75881 22.9922L6.24119 21.0604L0.741187 22.5341L1.25881 24.4659ZM0 12.5C0 14.6441 0.573832 16.729 1.63635 18.5494L3.36365 17.5412C2.47814 16.0241 2 14.2867 2 12.5H0ZM6.20203 23.0064C7.96181 23.9775 9.95397 24.5 12 24.5V22.5C10.295 22.5 8.63494 22.0646 7.16831 21.2553L6.20203 23.0064ZM1.64336 18.5612L1.79938 18.8203L3.51265 17.7885L3.35664 17.5294L1.64336 18.5612ZM6.00842 22.8971L6.19359 23.0017L7.17675 21.26L6.99158 21.1555L6.00842 22.8971Z" fill="#0A72BA"/>
|
||||
<path d="M7.25 10.75H16.75" stroke="#0A72BA" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M7.25 14.25H13.75" stroke="#0A72BA" stroke-width="2" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1401_2130">
|
||||
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
9
qml/Icons/info.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<g transform="translate(0 -1028.4)">
|
||||
<path d="m22 12a10 10 0 1 1 -20 0 10 10 0 1 1 20 0z" transform="translate(0 1029.4)" fill="#2980b9"/>
|
||||
<path d="m22 12a10 10 0 1 1 -20 0 10 10 0 1 1 20 0z" transform="translate(0 1028.4)" fill="#3498db"/>
|
||||
<path d="m11 1035.4v2h2v-2h-2zm-1 4-1 1h2v6h-2v1h1 4 1v-1h-2v-7h-3z" fill="#2980b9"/>
|
||||
<path d="m11 6v2h2v-2h-2zm-1 4l-1 1h2v6h-2v1h1 4 1v-1h-2v-7h-3z" transform="translate(0 1028.4)" fill="#ecf0f1"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 762 B |
40
qml/Icons/italian-flag.svg
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<path style="fill:#73AF00;" d="M38.345,88.273C17.167,88.273,0,105.44,0,126.618v258.759c0,21.177,17.167,38.345,38.345,38.345
|
||||
h132.322V88.273H38.345z"/>
|
||||
<rect x="170.67" y="88.277" style="fill:#F5F5F5;" width="170.67" height="335.45"/>
|
||||
<path style="fill:#FF4B55;" d="M473.655,88.273H341.333v335.448h132.322c21.177,0,38.345-17.167,38.345-38.345V126.618
|
||||
C512,105.44,494.833,88.273,473.655,88.273z"/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 894 B |
12
qml/Icons/neutral-state.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1401_2140)">
|
||||
<circle cx="12" cy="12.5" r="11" stroke="#838D97" stroke-width="2"/>
|
||||
<path d="M12 18L12 10" stroke="#838D97" stroke-width="2"/>
|
||||
<path d="M12 8.5L12 6.5" stroke="#838D97" stroke-width="2" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1401_2140">
|
||||
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 491 B |
3
qml/Icons/refresh.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.8316 19.7618L15.3483 18.8863L15.8316 19.7618ZM6.16651 2.25214L5.68325 1.37666L6.16651 2.25214ZM1.39134 8.23348L0.430573 7.95614H0.430573L1.39134 8.23348ZM2.24424 15.8395L1.36876 16.3227H1.36876L2.24424 15.8395ZM20.2444 6.95135L20.0588 7.93397C20.3246 7.98418 20.5994 7.92457 20.8205 7.76874C21.0416 7.61291 21.1901 7.37416 21.2322 7.10695L20.2444 6.95135ZM7.94823 21.5754C10.7512 22.3845 13.7607 22.0471 16.3148 20.6372L15.3483 18.8863C13.2586 20.0398 10.7962 20.3159 8.50293 19.6539L7.94823 21.5754ZM16.3148 20.6372C18.8689 19.2274 20.7584 16.8607 21.5675 14.0578L19.646 13.5031C18.984 15.7964 17.4381 17.7328 15.3483 18.8863L16.3148 20.6372ZM20.6293 5.69116C19.2195 3.13705 16.8528 1.2476 14.0499 0.438477L13.4952 2.36002C15.7885 3.02203 17.7249 4.56794 18.8784 6.65767L20.6293 5.69116ZM14.0499 0.438477C11.2469 -0.370648 8.23736 -0.0331718 5.68325 1.37666L6.64976 3.12762C8.73949 1.97412 11.2018 1.69801 13.4952 2.36002L14.0499 0.438477ZM5.68325 1.37666C3.12914 2.7865 1.2397 5.1532 0.430573 7.95614L2.35211 8.51083C3.01412 6.21752 4.56003 4.28113 6.64976 3.12762L5.68325 1.37666ZM0.430573 7.95614C-0.378552 10.7591 -0.0410769 13.7686 1.36876 16.3227L3.11972 15.3562C1.96622 13.2665 1.6901 10.8041 2.35211 8.51083L0.430573 7.95614ZM1.36876 16.3227C2.77859 18.8769 5.1453 20.7663 7.94823 21.5754L8.50293 19.6539C6.20962 18.9919 4.27322 17.446 3.11972 15.3562L1.36876 16.3227ZM14.6458 6.9115L20.0588 7.93397L20.43 5.96872L15.017 4.94625L14.6458 6.9115ZM21.2322 7.10695L22.0398 1.98023L20.0642 1.66902L19.2566 6.79574L21.2322 7.10695Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
40
qml/Icons/russian-flag.svg
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<path style="fill:#F5F5F5;" d="M473.655,88.276H38.345C17.167,88.276,0,105.443,0,126.621v73.471h512v-73.471
|
||||
C512,105.443,494.833,88.276,473.655,88.276z"/>
|
||||
<path style="fill:#FF4B55;" d="M0,385.379c0,21.177,17.167,38.345,38.345,38.345h435.31c21.177,0,38.345-17.167,38.345-38.345
|
||||
v-73.471H0V385.379z"/>
|
||||
<rect y="200.09" style="fill:#41479B;" width="512" height="111.81"/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 867 B |
46
qml/Icons/temperature.svg
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 250.189 250.189" style="enable-background:new 0 0 250.189 250.189;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M159.845,147.251V34.744C159.845,15.586,144.255,0,125.093,0c-19.159,0-34.746,15.586-34.746,34.744v112.506
|
||||
c-14.234,10.843-22.617,27.59-22.617,45.575c0,31.631,25.732,57.364,57.363,57.364c31.633,0,57.367-25.733,57.367-57.364
|
||||
C182.46,174.842,174.077,158.095,159.845,147.251z M125.093,235.189c-23.359,0-42.363-19.004-42.363-42.364
|
||||
c0-14.294,7.188-27.537,19.228-35.425c2.115-1.386,3.39-3.745,3.39-6.273V34.744c0-10.887,8.858-19.744,19.746-19.744
|
||||
c10.892,0,19.752,8.857,19.752,19.744v116.383c0,2.529,1.274,4.887,3.39,6.273c12.038,7.889,19.226,21.132,19.226,35.425
|
||||
C167.46,216.185,148.454,235.189,125.093,235.189z"/>
|
||||
<path d="M132.595,169.042V69.924c0-4.142-3.357-7.5-7.5-7.5s-7.5,3.358-7.5,7.5v99.118c-10.104,3.183-17.43,12.622-17.43,23.783
|
||||
c0,13.767,11.16,24.931,24.93,24.931c13.773,0,24.932-11.164,24.932-24.931C150.026,181.663,142.7,172.223,132.595,169.042z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
4
qml/Icons/visualization.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 2V21H23" stroke="white" stroke-width="2"/>
|
||||
<path d="M21 8L16.4181 11.7419C16.1572 11.955 15.8065 12.0224 15.4851 11.9211L11.0391 10.5206C10.6751 10.406 10.2776 10.5085 10.0145 10.7848L6 15" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 339 B |
12
qml/Icons/warning-state.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1401_2112)">
|
||||
<path d="M12 23.5V24.5V23.5ZM12 1.5V0.5V1.5ZM1 12.5H0H1ZM2.65602 18.3044L3.60879 18.6081C3.69622 18.3338 3.66119 18.0351 3.51265 17.7885L2.65602 18.3044ZM1 23.5L0.0472261 23.1963C-0.0638084 23.5447 0.0241315 23.9259 0.276556 24.1904C0.52898 24.4549 0.905642 24.5606 1.25881 24.4659L1 23.5ZM6.5 22.0263L6.99158 21.1555C6.76354 21.0268 6.49412 20.9926 6.24119 21.0604L6.5 22.0263ZM2.5 18.0453L1.63627 18.5495L1.64336 18.5612L2.5 18.0453ZM6.68517 22.1308L6.19357 23.0017L6.20203 23.0064L6.68517 22.1308ZM12 24.5C15.1826 24.5 18.2348 23.2357 20.4853 20.9853L19.0711 19.5711C17.1957 21.4464 14.6522 22.5 12 22.5V24.5ZM20.4853 20.9853C22.7357 18.7348 24 15.6826 24 12.5H22C22 15.1522 20.9464 17.6957 19.0711 19.5711L20.4853 20.9853ZM24 12.5C24 9.3174 22.7357 6.26516 20.4853 4.01472L19.0711 5.42893C20.9464 7.3043 22 9.84783 22 12.5H24ZM20.4853 4.01472C18.2348 1.76428 15.1826 0.5 12 0.5V2.5C14.6522 2.5 17.1957 3.55357 19.0711 5.42893L20.4853 4.01472ZM12 0.5C8.8174 0.5 5.76516 1.76428 3.51472 4.01472L4.92893 5.42893C6.8043 3.55357 9.34784 2.5 12 2.5V0.5ZM3.51472 4.01472C1.26428 6.26516 0 9.3174 0 12.5H2C2 9.84784 3.05357 7.3043 4.92893 5.42893L3.51472 4.01472ZM1.70324 18.0007L0.0472261 23.1963L1.95277 23.8037L3.60879 18.6081L1.70324 18.0007ZM1.25881 24.4659L6.75881 22.9922L6.24119 21.0604L0.741187 22.5341L1.25881 24.4659ZM0 12.5C0 14.6441 0.573832 16.729 1.63635 18.5494L3.36365 17.5412C2.47814 16.0241 2 14.2867 2 12.5H0ZM6.20203 23.0064C7.96181 23.9775 9.95397 24.5 12 24.5V22.5C10.295 22.5 8.63494 22.0646 7.16831 21.2553L6.20203 23.0064ZM1.64336 18.5612L1.79938 18.8203L3.51265 17.7885L3.35664 17.5294L1.64336 18.5612ZM6.00842 22.8971L6.19359 23.0017L7.17675 21.26L6.99158 21.1555L6.00842 22.8971Z" fill="#E6C207"/>
|
||||
<path d="M12 6.5L12 14.5" stroke="#E6C207" stroke-width="2"/>
|
||||
<path d="M12 16L12 18" stroke="#E6C207" stroke-width="2" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1401_2112">
|
||||
<rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
8
qml/Icons/warning.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<g transform="translate(0 -1028.4)">
|
||||
<path d="m12 1031.4c-0.985-0.1-1.715 0.7-2.0313 1.6-2.6053 5.2-5.2088 10.4-7.8125 15.6-0.6178 1.3 0.5802 2.9 2 2.8h7.8438 7.844c1.42 0.1 2.618-1.5 2-2.8-2.604-5.2-5.207-10.4-7.813-15.6-0.316-0.9-1.046-1.7-2.031-1.6z" fill="#f39c12"/>
|
||||
<path d="m12 2c-0.985-0.0372-1.715 0.7682-2.0312 1.625-2.6054 5.2106-5.2089 10.418-7.8126 15.625-0.6178 1.307 0.5802 2.919 2 2.75 2.6101-0.003 5.2337-0.001 7.8438 0 2.61-0.001 5.234-0.003 7.844 0 1.42 0.169 2.618-1.443 2-2.75-2.604-5.207-5.207-10.414-7.813-15.625-0.316-0.8568-1.046-1.6622-2.031-1.625z" transform="translate(0 1028.4)" fill="#f1c40f"/>
|
||||
<path d="m12 8c-0.552 0-1 0.4477-1 1l0.5 7h1l0.5-7c0-0.5523-0.448-1-1-1zm0 9c-0.552 0-1 0.448-1 1s0.448 1 1 1 1-0.448 1-1-0.448-1-1-1z" transform="translate(0 1028.4)" fill="#34495e"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
607
qml/MainWindow.qml
Normal file
@@ -0,0 +1,607 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Screens 1.0 as Screens
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
title: qsTr("Cubo Verde BMS")
|
||||
width: 1366
|
||||
height: 768
|
||||
visible: true
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
id: pane
|
||||
color: Palette.alternativeBackgroundColor
|
||||
implicitWidth: 300
|
||||
|
||||
property bool minimized: false
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 40
|
||||
}
|
||||
|
||||
Image {
|
||||
source: "qrc:/Icons/cubo-logo.svg"
|
||||
sourceSize.width: pane.minimized ? 70 : 115
|
||||
sourceSize.height: pane.minimized ? 70 : 115
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: pane.minimized ? 85 : 40
|
||||
}
|
||||
|
||||
Controls.MenuItemDelegate {
|
||||
text: qsTr("Hide menu")
|
||||
font.weight: Font.Normal
|
||||
icon.source: "qrc:/Icons/hide-menu.svg"
|
||||
minimized: pane.minimized
|
||||
mirroredIcon: pane.minimized
|
||||
|
||||
onClicked: if (pane.implicitWidth === 300) {
|
||||
animation.from = 300
|
||||
animation.to = 100
|
||||
animation.running = true
|
||||
pane.minimized = true
|
||||
} else {
|
||||
animation.from = 100
|
||||
animation.to = 300
|
||||
animation.running = true
|
||||
pane.minimized = false
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 40
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: menuView
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
property var menuModel: [
|
||||
{"text": qsTr("AKB monitor"), "icon": "qrc:/Icons/akb-monitor.svg"},
|
||||
{"text": qsTr("Cell monitor"), "icon": "qrc:/Icons/cell-monitor.svg"},
|
||||
{"text": qsTr("Temperature monitor"), "icon": "qrc:/Icons/temperature.svg"},
|
||||
{"text": qsTr("Configuration"), "icon": "qrc:/Icons/bms-configuration.svg"},
|
||||
{"text": qsTr("Visualization"), "icon": "qrc:/Icons/visualization.svg"},
|
||||
{"text": qsTr("History"), "icon": "qrc:/Icons/history.svg"},
|
||||
{"text": qsTr("BMS service"), "icon": "qrc:/Icons/bms-service.svg"}
|
||||
]
|
||||
|
||||
model: menuModel.length
|
||||
|
||||
delegate: Controls.MenuItemDelegate {
|
||||
width: ListView.view.width
|
||||
text: menuView.menuModel[modelData].text
|
||||
icon.source: menuView.menuModel[modelData].icon
|
||||
icon.color: "white"
|
||||
highlighted: ListView.isCurrentItem
|
||||
minimized: pane.minimized
|
||||
onClicked: menuView.currentIndex = index
|
||||
}
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.MenuItemDelegate {
|
||||
text: qsTr("Connection")
|
||||
icon.source: "qrc:/Icons/connection.svg"
|
||||
icon.color: "#FFFFFF"
|
||||
minimized: pane.minimized
|
||||
onClicked: connectionDialog.open()
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 40
|
||||
}
|
||||
}
|
||||
|
||||
PropertyAnimation {
|
||||
id: animation
|
||||
target: pane
|
||||
property: "implicitWidth"
|
||||
duration: 200
|
||||
easing.type: Easing.InQuad
|
||||
}
|
||||
|
||||
Layout.preferredWidth: implicitWidth
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id: topBar
|
||||
|
||||
Label {
|
||||
text: stack.itemAt(stack.currentIndex).title
|
||||
font.pixelSize: 38
|
||||
font.weight: Font.Bold
|
||||
color: Palette.textColor
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 5
|
||||
|
||||
RowLayout {
|
||||
spacing: 7
|
||||
|
||||
Controls.ContentLabel {
|
||||
id: connectionStatusLabel
|
||||
text: qsTr("Disconnected")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Controls.AvailabilityIndicator {
|
||||
id: connectionStatusIndicator
|
||||
enabled: false
|
||||
neutral: false
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.ContentLabel {
|
||||
id: firmwareLabel
|
||||
text: "-"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 5
|
||||
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Serial number") + ":"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: serialLabel
|
||||
text: "-"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
|
||||
Layout.topMargin: 15
|
||||
Layout.bottomMargin: 15
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Controls.LineSeparator {
|
||||
horizontal: false
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: 15
|
||||
Layout.bottomMargin: 15
|
||||
}
|
||||
|
||||
Item {
|
||||
RowLayout {
|
||||
id: languagesLayout
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Controls.ContentLabel {
|
||||
text: Translator.currentLanguageName
|
||||
}
|
||||
|
||||
Image {
|
||||
source: Translator.currentLanguageIcon
|
||||
sourceSize.width: 30
|
||||
sourceSize.height: 26
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: languagesPopup.open()
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: languagesPopup
|
||||
width: 90
|
||||
contentHeight: languagesList.contentHeight
|
||||
padding: 1
|
||||
x: -(width - languagesLayout.width) / 2
|
||||
y: languagesLayout.height + 2
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.backgroundColor
|
||||
radius: 6
|
||||
border.width: 1
|
||||
border.color: Palette.borderColor
|
||||
}
|
||||
|
||||
contentItem: ListView {
|
||||
id: languagesList
|
||||
model: [Translator.Russian, Translator.English, Translator.Italian]
|
||||
width: languagesPopup.width
|
||||
height: 120
|
||||
clip: true
|
||||
spacing: 0
|
||||
|
||||
delegate: Rectangle {
|
||||
width: ListView.view.width
|
||||
height: 40
|
||||
color: Palette.backgroundColor
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Controls.ContentLabel {
|
||||
text: Translator.languageName(modelData)
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 10
|
||||
}
|
||||
|
||||
Image {
|
||||
source: Translator.languageIcon(modelData)
|
||||
sourceSize.width: 30
|
||||
sourceSize.height: 26
|
||||
Layout.rightMargin: 10
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onPressed: parent.color = Palette.selectedBackgroundColor
|
||||
onReleased: parent.color = Palette.backgroundColor
|
||||
onEntered: parent.color = Palette.hoveredBackgroundColor
|
||||
onExited: parent.color = Palette.backgroundColor
|
||||
onClicked: {
|
||||
languagesPopup.close()
|
||||
Translator.currentLanguage = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layout.preferredWidth: languagesLayout.implicitWidth
|
||||
Layout.preferredHeight: languagesLayout.implicitHeight
|
||||
}
|
||||
}
|
||||
|
||||
Layout.leftMargin: 45
|
||||
Layout.rightMargin: 45
|
||||
Layout.maximumHeight: 90
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: stack
|
||||
currentIndex: menuView.currentIndex
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 45
|
||||
Layout.rightMargin: 45
|
||||
Layout.bottomMargin: 30
|
||||
|
||||
Screens.AkbMonitorScreen {
|
||||
property string title: qsTr("AKB monitor")
|
||||
}
|
||||
|
||||
Screens.CellMonitorScreen {
|
||||
property string title: qsTr("Cell monitor")
|
||||
}
|
||||
|
||||
Screens.TemperatureMonitorScreen {
|
||||
property string title: qsTr("Temperature monitor")
|
||||
}
|
||||
|
||||
Screens.BmsSettingsScreen {
|
||||
property string title: qsTr("BMS settings")
|
||||
onNeedWait: {
|
||||
if (active) {
|
||||
busyPopup.text = text
|
||||
busyPopup.open()
|
||||
} else {
|
||||
busyPopup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Screens.VisualizationScreen {
|
||||
property string title: qsTr("Visualization")
|
||||
}
|
||||
|
||||
Screens.DebugInformationScreen {
|
||||
id: debugScreen
|
||||
property string title: qsTr("Information output")
|
||||
}
|
||||
|
||||
Screens.BmsServiceScreen {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
|
||||
onPortConnectedChanged: {
|
||||
connectionStatusLabel.text = Qt.binding(function(){ return BmsInterface.isPortConnected() ? qsTr("Connected") : qsTr("Disconnected") })
|
||||
connectionStatusIndicator.enabled = BmsInterface.isPortConnected()
|
||||
faultStateTimer.running = BmsInterface.isPortConnected()
|
||||
|
||||
if (BmsInterface.isPortConnected()) {
|
||||
BmsInterface.commands().getBMSconf()
|
||||
BmsInterface.commands().getFaultState()
|
||||
} else {
|
||||
serialLabel.text = "-"
|
||||
firmwareLabel.text = "-"
|
||||
statusPopup.queue = []
|
||||
faultStatePopup.lastState = ""
|
||||
}
|
||||
}
|
||||
|
||||
onMessageDialog: {
|
||||
if (!messageDialog.visible) {
|
||||
messageDialog.title = title
|
||||
messageDialog.description = msg
|
||||
messageDialog.good = isGood
|
||||
messageDialog.open()
|
||||
} else {
|
||||
messageDialog.queue.push({"title": title, "description": msg, "good": isGood})
|
||||
}
|
||||
}
|
||||
|
||||
onStatusMessage: {
|
||||
for (var i = 0; i < statusPopup.filteredStatuses.length; ++i) {
|
||||
if (msg === statusPopup.filteredStatuses[i]) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!statusPopup.visible) {
|
||||
statusPopup.text = msg
|
||||
statusPopup.good = isGood
|
||||
statusPopup.open()
|
||||
} else {
|
||||
if (statusPopup.text !== msg) {
|
||||
statusPopup.queue.push({"text": msg, "good": isGood})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onFwUploadStatus: {
|
||||
if (isOngoing) {
|
||||
if (!progressPopup.opened) {
|
||||
progressPopup.open()
|
||||
}
|
||||
|
||||
progressPopup.text = status
|
||||
progressPopup.progress = progress
|
||||
} else {
|
||||
progressPopup.close()
|
||||
BmsInterface.emitMessageDialog(qsTr("Firmware update"), status, true)
|
||||
}
|
||||
}
|
||||
|
||||
onBmsConfigurationStored: busyPopup.close()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.bmsConfig()
|
||||
onUpdated: {
|
||||
serialLabel.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
onFwVersionReceived: {
|
||||
firmwareLabel.text = major + "." + minor
|
||||
}
|
||||
onFaultStateReceived: {
|
||||
if (faultStatePopup.lastState != faultString) {
|
||||
faultStatePopup.close()
|
||||
faultStatePopup.lastState = faultString
|
||||
faultStatePopup.text = faultString
|
||||
faultStatePopup.type = faultType
|
||||
faultStatePopup.open()
|
||||
|
||||
Qt.callLater(debugScreen.printMessage, faultString, faultStatePopup.color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Screens.ConnectionDialog {
|
||||
id: connectionDialog
|
||||
}
|
||||
|
||||
Screens.MessageDialog {
|
||||
id: messageDialog
|
||||
property var queue: []
|
||||
onClosed: {
|
||||
if (queue.length > 0) {
|
||||
var message = queue.pop()
|
||||
messageDialog.title = message.title
|
||||
messageDialog.description = message.description
|
||||
messageDialog.good = message.good
|
||||
messageDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Screens.StatusPopup {
|
||||
id: statusPopup
|
||||
|
||||
property var filteredStatuses: []
|
||||
property var queue: []
|
||||
|
||||
onClosed: {
|
||||
if (queue.length > 0) {
|
||||
var message = queue.pop()
|
||||
statusPopup.text = message.text
|
||||
statusPopup.good = message.good
|
||||
statusPopup.open()
|
||||
}
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
hideStatusTimer.start()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hideStatusTimer
|
||||
interval: 3000
|
||||
onTriggered: statusPopup.close()
|
||||
}
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: busyPopup
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
modal: true
|
||||
closePolicy: Popup.NoAutoClose
|
||||
|
||||
property string text: ""
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Controls.BusyIndicator {
|
||||
running: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: busyPopup.text
|
||||
color: Palette.alternativeTextColor
|
||||
maximumLineCount: 3
|
||||
wrapMode: Text.Wrap
|
||||
font.pixelSize: 20
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.textColor
|
||||
opacity: 0.3
|
||||
radius: 6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onOpened: hideBusyTimer.start()
|
||||
onClosed: hideBusyTimer.stop()
|
||||
|
||||
Timer {
|
||||
id: hideBusyTimer
|
||||
interval: 30000
|
||||
onTriggered: busyPopup.close()
|
||||
}
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: progressPopup
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
modal: true
|
||||
closePolicy: Popup.NoAutoClose
|
||||
|
||||
property alias text: progressText.text
|
||||
property alias progress: progressBar.value
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Controls.ProgressBar {
|
||||
id: progressBar
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredWidth: 500
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: "asdfzasdf"
|
||||
id: progressText
|
||||
color: Palette.alternativeTextColor
|
||||
maximumLineCount: 3
|
||||
wrapMode: Text.Wrap
|
||||
font.pixelSize: 20
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.textColor
|
||||
opacity: 0.3
|
||||
radius: 6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Screens.StatePopup {
|
||||
id: faultStatePopup
|
||||
x: parent.width - width - 45
|
||||
y: 18
|
||||
|
||||
property var lastState: ""
|
||||
|
||||
onOpened: {
|
||||
hideStateTimer.start()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hideStateTimer
|
||||
interval: 3000
|
||||
onTriggered: faultStatePopup.close()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: faultStateTimer
|
||||
interval: 50000
|
||||
repeat: true
|
||||
onTriggered: BmsInterface.commands().getFaultState()
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: Palette.screenBackgroundColor
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
connectionDialog.open()
|
||||
Qt.callLater(debugScreen.printMessage, qsTr("Tool started"))
|
||||
}
|
||||
}
|
||||
329
qml/Screens/AkbMonitorScreen.qml
Normal file
@@ -0,0 +1,329 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 15
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
implicitWidth: parent.width
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
spacing: 70
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.TitleLabel {
|
||||
text: qsTr("Serial number")
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.spacing) / 2
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: serialNumberField
|
||||
enabled: false
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.spacing) / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
implicitWidth: parent.width
|
||||
Layout.fillWidth: true
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
columnSpacing: 70
|
||||
rowSpacing: 20
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Battery charge level, %")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: batteryChargeLevelLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Number of modules")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: numberOfModulesLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Battery voltage, V")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: batteryVoltageLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Number of cells")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: numberOfCellsLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Nominal capacity, A/h")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: nominalCapacityLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Actual capacity, A/h")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: actualCapacityLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Battery temperature, °C")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: batteryTemperatureLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
// RowLayout {
|
||||
// spacing: 10
|
||||
// Controls.ContentLabel {
|
||||
// text: qsTr("BMS temperature, °C")
|
||||
// }
|
||||
|
||||
// Controls.DotSeparator {
|
||||
// Layout.fillWidth: true
|
||||
// }
|
||||
|
||||
// Controls.SubtitleLabel {
|
||||
// id: bmsTemperatureLabel
|
||||
// text: "-"
|
||||
// }
|
||||
|
||||
// Layout.fillWidth: true
|
||||
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
implicitWidth: parent.width
|
||||
Layout.fillWidth: true
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
columnSpacing: 70
|
||||
rowSpacing: 20
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Maximum cell voltage, V")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: maximumCellVoltageLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Minimum cell voltage, V")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: minimumCellVoltageLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Current")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: currentLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
enabled: root.visible
|
||||
|
||||
onValuesReceived: {
|
||||
batteryChargeLevelLabel.text = values.soC
|
||||
batteryVoltageLabel.text = MathHelper.roundDouble(values.packVoltage)
|
||||
|
||||
batteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattHigh)
|
||||
// bmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSHigh)
|
||||
|
||||
maximumCellVoltageLabel.text = MathHelper.roundDouble(values.cVHigh)
|
||||
minimumCellVoltageLabel.text = MathHelper.roundDouble(values.cVLow)
|
||||
|
||||
currentLabel.text = MathHelper.roundDouble(values.packCurrent)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.bmsConfig()
|
||||
onUpdated: {
|
||||
serialNumberField.text = Number(BmsInterface.bmsConfig().getParamDouble("notUsedCurrentThreshold")).toFixed()
|
||||
|
||||
numberOfModulesLabel.text = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount")
|
||||
numberOfCellsLabel.text = BmsInterface.bmsConfig().getParamInt("noOfCellsSeries")
|
||||
|
||||
nominalCapacityLabel.text = MathHelper.roundDouble(BmsInterface.bmsConfig().getParamDouble("batteryCapacity"))
|
||||
actualCapacityLabel.text = nominalCapacityLabel.text // TODO
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
onPortConnectedChanged: getValues()
|
||||
}
|
||||
|
||||
onVisibleChanged: getValues()
|
||||
|
||||
Timer {
|
||||
id: refreshValuesTimer
|
||||
interval: 1000
|
||||
onTriggered: getValues()
|
||||
}
|
||||
|
||||
function getValues() {
|
||||
if (BmsInterface.isPortConnected() && visible) {
|
||||
BmsInterface.commands().getValues()
|
||||
refreshValuesTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
68
qml/Screens/BmsServiceScreen.qml
Normal file
@@ -0,0 +1,68 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Screens 1.0 as Screens
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
property string title: stack.itemAt(stack.currentIndex).title
|
||||
|
||||
StackLayout {
|
||||
id: stack
|
||||
|
||||
Screens.TerminalScreen {
|
||||
id: terminalScreen
|
||||
property string title: qsTr("Terminal")
|
||||
}
|
||||
|
||||
Screens.FirmwareUpdateScreen {
|
||||
id: firmwareUpdateScreen
|
||||
property string title: qsTr("Firmware update")
|
||||
}
|
||||
|
||||
Screens.NetworkSettingsScreen {
|
||||
id: networkSettingsScreen
|
||||
property string title: qsTr("Network settings")
|
||||
}
|
||||
|
||||
Screens.TimeSettingsScreen {
|
||||
id: timeSettingsScreen
|
||||
property string title: qsTr("Time settings")
|
||||
}
|
||||
|
||||
// Screens.CanSettingsScreen {
|
||||
// id: canSettingsScreen
|
||||
// property string title: qsTr("CAN settings")
|
||||
// }
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
terminalScreen.title,
|
||||
firmwareUpdateScreen.title,
|
||||
networkSettingsScreen.title,
|
||||
timeSettingsScreen.title,
|
||||
// canSettingsScreen.title
|
||||
]
|
||||
delegate: Controls.LinkLabel {
|
||||
text: modelData
|
||||
onClicked: stack.currentIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Layout.minimumWidth: 180
|
||||
Layout.maximumWidth: 180
|
||||
}
|
||||
}
|
||||
1061
qml/Screens/BmsSettingsScreen.qml
Normal file
102
qml/Screens/CanSettingsScreen.qml
Normal file
@@ -0,0 +1,102 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 1.4 as OldControls
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 10
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
topPadding: 20
|
||||
bottomPadding: 20
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.TitleLabel {
|
||||
text: qsTr("CAN availability state")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
|
||||
Controls.AvailabilityIndicator {
|
||||
neutral: false
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("External CAN")
|
||||
}
|
||||
|
||||
Controls.AvailabilityIndicator {
|
||||
neutral: false
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Charging CAN")
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Controls.CheckBox {
|
||||
leftPadding: 0
|
||||
text: qsTr("External CAN")
|
||||
}
|
||||
|
||||
Controls.CheckBox {
|
||||
leftPadding: 0
|
||||
text: qsTr("Charging CAN")
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Apply")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
topPadding: 20
|
||||
bottomPadding: 20
|
||||
|
||||
OldControls.TableView {
|
||||
id: currentTable
|
||||
anchors.fill: parent
|
||||
// columnSpacing: 1
|
||||
// rowSpacing: 1
|
||||
clip: true
|
||||
|
||||
property var currentModel: CurrentTableModel{}
|
||||
|
||||
model: currentModel
|
||||
|
||||
// delegate: Rectangle {
|
||||
// implicitWidth: 100
|
||||
// implicitHeight: 50
|
||||
// border.width: 1
|
||||
|
||||
// Text {
|
||||
// text: display
|
||||
// anchors.centerIn: parent
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
currentTable.currentModel.setCurrentData([[0.2, 0.5, 1],[0.2, 0.7, 1],[0.2, 0.6, 1]])
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
208
qml/Screens/CellMonitorScreen.qml
Normal file
@@ -0,0 +1,208 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
Component {
|
||||
id: cellListHeader
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
width: ListView.view.width
|
||||
|
||||
Rectangle {
|
||||
id: numberTab
|
||||
color: Palette.tableHeaderBackgroundColor
|
||||
Layout.preferredHeight: 60
|
||||
Layout.fillWidth: true
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: indexTitleLabel
|
||||
text: qsTr("#")
|
||||
color: Palette.tableHeaderTextColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: voltageTab
|
||||
color: Palette.tableHeaderBackgroundColor
|
||||
Layout.preferredHeight: 60
|
||||
Layout.fillWidth: true
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: voltageTitleLabel
|
||||
text: qsTr("Voltage")
|
||||
color: Palette.tableHeaderTextColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: balancingTab
|
||||
color: Palette.tableHeaderBackgroundColor
|
||||
Layout.preferredHeight: 60
|
||||
Layout.fillWidth: true
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: balancingTitleLabel
|
||||
text: qsTr("Balancing")
|
||||
color: Palette.tableHeaderTextColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: cellListDelegate
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
width: ListView.view.width
|
||||
height: 36
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width / 6 - 24
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: indexLabel
|
||||
color: Palette.tableHeaderTextColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.preferredWidth: 25
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: modelData.voltage + " " + qsTr("V")
|
||||
color: Palette.tableHeaderTextColor
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.AvailabilityIndicator {
|
||||
enabled: modelData.balancing
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width / 6 - 24
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
indexLabel.text = index + ListView.view.indexOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.Frame {
|
||||
padding: 1
|
||||
|
||||
ListView {
|
||||
id: firstCellGroup
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
model: []
|
||||
spacing: 0
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
property int indexOffset: 1
|
||||
|
||||
header: cellListHeader
|
||||
delegate: cellListDelegate
|
||||
ScrollBar.vertical: Controls.ScrollBar {}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 1
|
||||
visible: secondCellGroup.model.length > 0
|
||||
|
||||
ListView {
|
||||
id: secondCellGroup
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
model: []
|
||||
spacing: 0
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
property int indexOffset: 17
|
||||
|
||||
header: cellListHeader
|
||||
delegate: cellListDelegate
|
||||
ScrollBar.vertical: Controls.ScrollBar {}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
enabled: root.visible
|
||||
|
||||
onCellsReceived: {
|
||||
firstCellGroup.model = []
|
||||
var firstModel = []
|
||||
|
||||
for (var i = 0; i < Math.min(cellCount, 16); ++i) {
|
||||
firstModel.push({"voltage": Math.abs(MathHelper.roundDouble(cellVoltageArray[i], 3)), "balancing": cellVoltageArray[i] < 0})
|
||||
}
|
||||
firstCellGroup.model = firstModel
|
||||
|
||||
if (cellCount > 16) {
|
||||
secondCellGroup.model = []
|
||||
var secondModel = []
|
||||
|
||||
for (var j = 16; j < Math.min(cellCount, 32); ++j) {
|
||||
secondModel.push({"voltage": Math.abs(MathHelper.roundDouble(cellVoltageArray[j], 3)), "balancing": cellVoltageArray[i] < 0})
|
||||
}
|
||||
secondCellGroup.model = secondModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
onPortConnectedChanged: getValues()
|
||||
}
|
||||
|
||||
onVisibleChanged: getValues()
|
||||
|
||||
Timer {
|
||||
id: refreshValuesTimer
|
||||
interval: 1000
|
||||
onTriggered: getValues()
|
||||
}
|
||||
|
||||
function getValues() {
|
||||
if (BmsInterface.isPortConnected() && visible) {
|
||||
BmsInterface.commands().getCells()
|
||||
refreshValuesTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
103
qml/Screens/ConnectionDialog.qml
Normal file
@@ -0,0 +1,103 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
title: qsTr("Connection screen")
|
||||
width: 470
|
||||
height: 320
|
||||
modal: true
|
||||
closePolicy: Popup.CloseOnEscape
|
||||
|
||||
|
||||
header: Controls.DialogHeader {
|
||||
dialog: root
|
||||
}
|
||||
|
||||
contentItem: Rectangle {
|
||||
color: Palette.screenBackgroundColor
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 45
|
||||
anchors.rightMargin: 45
|
||||
spacing: 20
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Select serial port")
|
||||
maximumLineCount: 2
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 15
|
||||
|
||||
Controls.ComboBox {
|
||||
id: serialBox
|
||||
model: BmsInterface.serialPortNames()
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.OutlineImageButton {
|
||||
id: refreshButton
|
||||
icon.source: "qrc:/Icons/refresh.svg"
|
||||
icon.width: 30
|
||||
icon.height: 30
|
||||
onClicked: serialBox.model = BmsInterface.serialPortNames()
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
id: connectButton
|
||||
text: qsTr("Connect")
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||
onClicked: {
|
||||
if (BmsInterface.isPortConnected()) {
|
||||
BmsInterface.disconnectPort()
|
||||
} else {
|
||||
var currentPort = BmsInterface.serialPortNames()[serialBox.currentIndex]
|
||||
if (BmsInterface.connectSerial(currentPort)) {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Controls.DialogBackground {}
|
||||
|
||||
onVisibleChanged: {
|
||||
x = Qt.binding(function() { return (parent.width - width) / 2})
|
||||
y = Qt.binding(function() { return (parent.height - height) / 2})
|
||||
serialBox.model = BmsInterface.serialPortNames()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
onPortConnectedChanged: {
|
||||
connectButton.text = Qt.binding(function() { return BmsInterface.isPortConnected() ? qsTr("Disconnect") : qsTr("Connect") })
|
||||
serialBox.enabled = !BmsInterface.isPortConnected()
|
||||
refreshButton.enabled = !BmsInterface.isPortConnected()
|
||||
}
|
||||
}
|
||||
}
|
||||
56
qml/Screens/DebugInformationScreen.qml
Normal file
@@ -0,0 +1,56 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
Controls.Frame {
|
||||
Flickable {
|
||||
id: outputFlickable
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
TextArea.flickable: Controls.TextArea {
|
||||
id: outputArea
|
||||
textFormat: Text.RichText
|
||||
}
|
||||
|
||||
ScrollBar.horizontal: Controls.ScrollBar { }
|
||||
ScrollBar.vertical: Controls.ScrollBar { }
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Clear")
|
||||
Layout.preferredWidth: 120
|
||||
onClicked: outputArea.clear()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
onStatusMessage: printMessage(msg, isGood ? Palette.textColor : Palette.invalidColor)
|
||||
onPortConnectedChanged: printMessage(BmsInterface.getConnectedPortName())
|
||||
}
|
||||
|
||||
function printMessage(msg, color = Palette.textColor) {
|
||||
var message = "<font color=\"" + color + "\">"
|
||||
|
||||
message += new Date().toLocaleString(Qt.locale("en-US"), "dd.MM.yyyy hh:mm:ss") + ": " + msg
|
||||
message += "</font>"
|
||||
message += "<br>"
|
||||
|
||||
outputArea.insert(outputArea.length, message)
|
||||
outputArea.cursorPosition = outputArea.length
|
||||
|
||||
outputFlickable.contentX = 0
|
||||
}
|
||||
}
|
||||
126
qml/Screens/FirmwareUpdateScreen.qml
Normal file
@@ -0,0 +1,126 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Dialogs 1.2
|
||||
import Qt.labs.settings 1.1
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.TitleLabel {
|
||||
text: qsTr("Board information")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Firmware")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.ContentLabel {
|
||||
id: firmwareLabel
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Hardware")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.ContentLabel {
|
||||
id: hardwareLabel
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("UUID")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.ContentLabel {
|
||||
id: uuidLabel
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Upload firmware")
|
||||
onClicked: firmwareFileDialog.open()
|
||||
|
||||
FileDialog {
|
||||
id: firmwareFileDialog
|
||||
title: qsTr("Select firmware file")
|
||||
folder: shortcuts.documents
|
||||
nameFilters: [ qsTr("Firmware files (*.bin)"), qsTr("All files (*)") ]
|
||||
onAccepted: {
|
||||
if (BmsInterface.isPortConnected()) {
|
||||
updateHelper.uploadFirmware(firmwareFileDialog.fileUrl.toString().replace(/^(file:\/{3})/, ""), BmsInterface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
category: "firmwareUpdate"
|
||||
property alias folder: firmwareFileDialog.folder
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
FirmwareUpdateHelper {
|
||||
id: updateHelper
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
onFwVersionReceived: {
|
||||
firmwareLabel.text = major + "." + minor
|
||||
hardwareLabel.text = hw
|
||||
uuidLabel.text = bufferToHex(uuid)
|
||||
}
|
||||
}
|
||||
|
||||
function bufferToHex(buffer) {
|
||||
return [...new Uint8Array(buffer)]
|
||||
.map(b => b.toString(16).padStart(2, "0"))
|
||||
.join("").toUpperCase();
|
||||
}
|
||||
}
|
||||
65
qml/Screens/MessageDialog.qml
Normal file
@@ -0,0 +1,65 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Utils 1.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
width: 500
|
||||
height: 350
|
||||
modal: true
|
||||
closePolicy: Popup.CloseOnEscape
|
||||
bottomPadding: 0
|
||||
|
||||
property string description: ""
|
||||
property bool good: true
|
||||
|
||||
header: Controls.DialogHeader {
|
||||
dialog: root
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
Image {
|
||||
source: good ? "qrc:/Icons/info.svg" : "qrc:/Icons/warning.svg"
|
||||
sourceSize.width: 52
|
||||
sourceSize.height: 48
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: root.description
|
||||
maximumLineCount: 10
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Controls.Button {
|
||||
text: qsTr("Ok")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredWidth: 100
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
background: Controls.DialogBackground {}
|
||||
|
||||
onVisibleChanged: {
|
||||
x = Qt.binding(function() { return (parent.width - width) / 2})
|
||||
y = Qt.binding(function() { return (parent.height - height) / 2})
|
||||
}
|
||||
}
|
||||
221
qml/Screens/NetworkSettingsScreen.qml
Normal file
@@ -0,0 +1,221 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 10
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
topPadding: 20
|
||||
bottomPadding: 20
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: firstUrlLabel
|
||||
text: qsTr("Url 1")
|
||||
|
||||
TextMetrics {
|
||||
id: firstUrlMetrics
|
||||
font: firstUrlLabel.font
|
||||
text: firstUrlLabel.text
|
||||
}
|
||||
|
||||
Layout.preferredWidth: getMaxLabelWidth()
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: firstUrlField
|
||||
validator: RegExpValidator { regExp: /.{0,250}/ }
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
topPadding: 20
|
||||
bottomPadding: 20
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: secondUrlLabel
|
||||
text: qsTr("Url 2")
|
||||
|
||||
TextMetrics {
|
||||
id: secondUrlMetrics
|
||||
font: secondUrlLabel.font
|
||||
text: secondUrlLabel.text
|
||||
}
|
||||
|
||||
Layout.preferredWidth: getMaxLabelWidth()
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: secondUrlField
|
||||
validator: RegExpValidator { regExp: /.{0,250}/ }
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
topPadding: 20
|
||||
bottomPadding: 20
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: apnLabel
|
||||
text: qsTr("APN")
|
||||
|
||||
TextMetrics {
|
||||
id: apnMetrics
|
||||
font: apnLabel.font
|
||||
text: apnLabel.text
|
||||
}
|
||||
|
||||
Layout.preferredWidth: getMaxLabelWidth()
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: apnField
|
||||
validator: RegExpValidator { regExp: /.{0,50}/ }
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
topPadding: 20
|
||||
bottomPadding: 20
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: userLabel
|
||||
text: qsTr("User")
|
||||
|
||||
TextMetrics {
|
||||
id: userMetrics
|
||||
font: userLabel.font
|
||||
text: userLabel.text
|
||||
}
|
||||
|
||||
Layout.preferredWidth: getMaxLabelWidth()
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: userField
|
||||
validator: RegExpValidator { regExp: /.{0,50}/ }
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
padding: 35
|
||||
topPadding: 20
|
||||
bottomPadding: 20
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 20
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: passwordLabel
|
||||
text: qsTr("Password")
|
||||
|
||||
TextMetrics {
|
||||
id: passwordMetrics
|
||||
font: passwordLabel.font
|
||||
text: passwordLabel.text
|
||||
}
|
||||
|
||||
Layout.preferredWidth: getMaxLabelWidth()
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: passwordField
|
||||
validator: RegExpValidator { regExp: /.{0,50}/ }
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
Controls.OutlineButton {
|
||||
text: qsTr("Default")
|
||||
onClicked: BmsInterface.commands().getNetDefaultSettings()
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Apply")
|
||||
onClicked: {
|
||||
if (!BmsInterface.isPortConnected())
|
||||
return
|
||||
|
||||
var settings = [
|
||||
firstUrlField.text,
|
||||
secondUrlField.text,
|
||||
apnField.text,
|
||||
userField.text,
|
||||
passwordField.text,
|
||||
]
|
||||
|
||||
BmsInterface.commands().setNetSettings(settings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
onNetSettingsReceived: {
|
||||
if (settings.length < 5) {
|
||||
return
|
||||
}
|
||||
|
||||
firstUrlField.text = settings[0]
|
||||
secondUrlField.text = settings[1]
|
||||
apnField.text = settings[2]
|
||||
userField.text = settings[3]
|
||||
passwordField.text = settings[4]
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: if (visible) {
|
||||
if (BmsInterface.isPortConnected()) {
|
||||
BmsInterface.commands().getNetSettings()
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxLabelWidth() {
|
||||
return Math.max(firstUrlMetrics.width, secondUrlMetrics.width, apnMetrics.width, userMetrics.width, passwordMetrics.width)
|
||||
}
|
||||
}
|
||||
97
qml/Screens/StatePopup.qml
Normal file
@@ -0,0 +1,97 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
closePolicy: Popup.NoAutoClose
|
||||
|
||||
property string text: ""
|
||||
property var type: DataTypes.StateType.Info
|
||||
property color color: switch (type) {
|
||||
case DataTypes.StateType.Info:
|
||||
return "#0A72BA"
|
||||
case DataTypes.StateType.Good:
|
||||
return "#009352"
|
||||
case DataTypes.StateType.Warning:
|
||||
return "#E5C207"
|
||||
case DataTypes.StateType.Error:
|
||||
return "#CF3200"
|
||||
case DataTypes.StateType.Neutral:
|
||||
default:
|
||||
return "#838D97"
|
||||
}
|
||||
|
||||
property var icon: switch (type) {
|
||||
case DataTypes.StateType.Info:
|
||||
return "qrc:/Icons/info-state.svg"
|
||||
case DataTypes.StateType.Good:
|
||||
return "qrc:/Icons/good-state.svg"
|
||||
case DataTypes.StateType.Warning:
|
||||
return "qrc:/Icons/warning-state.svg"
|
||||
case DataTypes.StateType.Error:
|
||||
return "qrc:/Icons/error-state.svg"
|
||||
case DataTypes.StateType.Neutral:
|
||||
default:
|
||||
return "qrc:/Icons/neutral-state.svg"
|
||||
}
|
||||
|
||||
|
||||
|
||||
RowLayout {
|
||||
spacing: 15
|
||||
|
||||
Image {
|
||||
source: root.icon
|
||||
Layout.leftMargin: 5
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: label
|
||||
text: root.text
|
||||
maximumLineCount: 10
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
radius: 6
|
||||
color: "#F7F8FC"
|
||||
|
||||
Rectangle {
|
||||
radius: 6
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(root.color.r, root.color.g, root.color.b, 0.1)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
radius: 6
|
||||
width: 4
|
||||
height: parent.height
|
||||
anchors.left: parent.left
|
||||
color: root.color
|
||||
}
|
||||
}
|
||||
|
||||
enter: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
|
||||
exit: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 1.0
|
||||
to: 0.0
|
||||
duration: 2500
|
||||
}
|
||||
}
|
||||
}
|
||||
46
qml/Screens/StatusPopup.qml
Normal file
@@ -0,0 +1,46 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Utils 1.0
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
x: (parent.width - width) / 2
|
||||
y: parent.height - height - 20
|
||||
closePolicy: Popup.NoAutoClose
|
||||
|
||||
property string text: ""
|
||||
property bool good: true
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: label
|
||||
text: root.text
|
||||
maximumLineCount: 10
|
||||
wrapMode: Text.Wrap
|
||||
color: Palette.alternativeTextColor
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
radius: 6
|
||||
color: good ? Palette.informationColor : Palette.invalidColor
|
||||
}
|
||||
|
||||
enter: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
|
||||
exit: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 1.0
|
||||
to: 0.0
|
||||
duration: 2500
|
||||
}
|
||||
}
|
||||
}
|
||||
287
qml/Screens/TemperatureMonitorScreen.qml
Normal file
@@ -0,0 +1,287 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var numberOfBoards: 0
|
||||
property var auxSensorsModel: []
|
||||
property var expSensorsModel: []
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 15
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.Frame {
|
||||
padding: 25
|
||||
implicitWidth: parent.width
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 10
|
||||
|
||||
GridLayout {
|
||||
columns: 1 // 2
|
||||
columnSpacing: 70
|
||||
rowSpacing: 15
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Minimum battery temperature, °C")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: minBatteryTemperatureLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
// RowLayout {
|
||||
// spacing: 10
|
||||
// Controls.ContentLabel {
|
||||
// text: qsTr("Minimum BMS temperature, °C")
|
||||
// }
|
||||
|
||||
// Controls.DotSeparator {
|
||||
// Layout.fillWidth: true
|
||||
// }
|
||||
|
||||
// Controls.SubtitleLabel {
|
||||
// id: minBmsTemperatureLabel
|
||||
// text: "-"
|
||||
// }
|
||||
|
||||
// Layout.fillWidth: true
|
||||
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
// }
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Average battery temperature, °C")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: avgBatteryTemperatureLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
// RowLayout {
|
||||
// spacing: 10
|
||||
// Controls.ContentLabel {
|
||||
// text: qsTr("Average BMS temperature, °C")
|
||||
// }
|
||||
|
||||
// Controls.DotSeparator {
|
||||
// Layout.fillWidth: true
|
||||
// }
|
||||
|
||||
// Controls.SubtitleLabel {
|
||||
// id: avgBmsTemperatureLabel
|
||||
// text: "-"
|
||||
// }
|
||||
|
||||
// Layout.fillWidth: true
|
||||
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
// }
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Maximum battery temperature, °C")
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
id: maxBatteryTemperatureLabel
|
||||
text: "-"
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
|
||||
|
||||
|
||||
// RowLayout {
|
||||
// spacing: 10
|
||||
// Controls.ContentLabel {
|
||||
// text: qsTr("Maximum BMS temperature, °C")
|
||||
// }
|
||||
|
||||
// Controls.DotSeparator {
|
||||
// Layout.fillWidth: true
|
||||
// }
|
||||
|
||||
// Controls.SubtitleLabel {
|
||||
// id: maxBmsTemperatureLabel
|
||||
// text: "-"
|
||||
// }
|
||||
|
||||
// Layout.fillWidth: true
|
||||
// Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: settingsFlickable
|
||||
clip: true
|
||||
contentWidth: width - rightMargin - leftMargin
|
||||
contentHeight: boardsLayout.height
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
rightMargin: 10
|
||||
|
||||
GridLayout {
|
||||
id: boardsLayout
|
||||
width: parent.width
|
||||
columns: 2
|
||||
rowSpacing: 15
|
||||
columnSpacing: 15
|
||||
|
||||
Repeater {
|
||||
model: numberOfBoards
|
||||
|
||||
Controls.Frame {
|
||||
padding: 25
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
|
||||
ColumnLayout {
|
||||
id: sensorsLayout
|
||||
anchors.fill: parent
|
||||
spacing: 15
|
||||
|
||||
property var boardIndex: index
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: index === 0 ? qsTr("Sensors for master board") : qsTr("Sensors for slave board #") + index
|
||||
maximumLineCount: 2
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: 4
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
opacity: (sensorsLayout.boardIndex === 0 && (index === 2 || index === 3)) ? 0 : 1
|
||||
Controls.ContentLabel {
|
||||
text: qsTr("Sensor #") + (index + 1) + ", °C"
|
||||
}
|
||||
|
||||
Controls.DotSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: {
|
||||
var value = auxSensorsModel[sensorsLayout.boardIndex * 4 + index]
|
||||
return value ? value : 0
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: (parent.width - parent.columnSpacing) / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: Controls.ScrollBar {}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
enabled: root.visible
|
||||
|
||||
onValuesReceived: {
|
||||
maxBatteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattHigh)
|
||||
avgBatteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattAverage)
|
||||
minBatteryTemperatureLabel.text = MathHelper.roundDouble(values.tempBattLow)
|
||||
|
||||
// maxBmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSHigh)
|
||||
// avgBmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSAverage)
|
||||
// minBmsTemperatureLabel.text = MathHelper.roundDouble(values.tempBMSLow)
|
||||
}
|
||||
|
||||
onAuxReceived: {
|
||||
let tempModel = []
|
||||
for (let temperature of auxVoltageArray) {
|
||||
tempModel.push(temperature)
|
||||
}
|
||||
|
||||
auxSensorsModel = []
|
||||
auxSensorsModel = tempModel
|
||||
}
|
||||
|
||||
onExpTempReceived: {
|
||||
let tempModel = []
|
||||
for (let temperature of expTempVoltageArray) {
|
||||
tempModel.push(temperature)
|
||||
}
|
||||
|
||||
expSensorsModel = []
|
||||
expSensorsModel = tempModel
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.bmsConfig()
|
||||
onUpdated: {
|
||||
numberOfBoards = BmsInterface.bmsConfig().getParamInt("cellMonitorICCount")
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
onPortConnectedChanged: getValues()
|
||||
}
|
||||
|
||||
onVisibleChanged: getValues()
|
||||
|
||||
Timer {
|
||||
id: refreshValuesTimer
|
||||
interval: 1000
|
||||
onTriggered: getValues()
|
||||
}
|
||||
|
||||
function getValues() {
|
||||
if (BmsInterface.isPortConnected() && visible) {
|
||||
BmsInterface.commands().getValues()
|
||||
BmsInterface.commands().getAux()
|
||||
// BmsInterface.commands().getExpansionTemp()
|
||||
refreshValuesTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
76
qml/Screens/TerminalScreen.qml
Normal file
@@ -0,0 +1,76 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 20
|
||||
|
||||
Keys.onReturnPressed: sendButton.clicked()
|
||||
Keys.onEnterPressed: sendButton.clicked()
|
||||
|
||||
Controls.Frame {
|
||||
Flickable {
|
||||
id: outputFlickable
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
TextArea.flickable: Controls.TextArea {
|
||||
id: outputArea
|
||||
}
|
||||
|
||||
ScrollBar.horizontal: Controls.ScrollBar {}
|
||||
ScrollBar.vertical: Controls.ScrollBar {}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Clear")
|
||||
Layout.preferredWidth: 120
|
||||
onClicked: outputArea.clear()
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: commandField
|
||||
implicitHeight: 52
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
id: sendButton
|
||||
text: qsTr("Send")
|
||||
Layout.preferredWidth: 120
|
||||
onClicked: {
|
||||
BmsInterface.commands().sendTerminalCmd(commandField.text)
|
||||
commandField.clear()
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Help")
|
||||
Layout.preferredWidth: 120
|
||||
onClicked: BmsInterface.commands().sendTerminalCmd("help")
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
enabled: root.visible
|
||||
onPrintReceived: {
|
||||
outputArea.append(str)
|
||||
outputArea.cursorPosition = outputArea.length
|
||||
}
|
||||
}
|
||||
}
|
||||
278
qml/Screens/TimeSettingsScreen.qml
Normal file
@@ -0,0 +1,278 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 20
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
rowSpacing: 20
|
||||
columnSpacing: 20
|
||||
|
||||
Controls.TitleLabel {
|
||||
text: qsTr("Date")
|
||||
}
|
||||
|
||||
Controls.TitleLabel {
|
||||
text: qsTr("Time")
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
columns: 3
|
||||
columnSpacing: 10
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Day")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Month")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Year")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.LineSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.LineSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.LineSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Tumbler {
|
||||
id: dayTumbler
|
||||
model: {
|
||||
switch (monthTumbler.currentIndex) {
|
||||
case 0: return range(1, 31)
|
||||
case 1: return range(1, yearTumbler.model[yearTumbler.currentIndex] % 4 || monthTumbler.currentIndex !== 1 ? 28 : 29)
|
||||
case 2: return range(1, 31)
|
||||
case 3: return range(1, 30)
|
||||
case 4: return range(1, 31)
|
||||
case 5: return range(1, 30)
|
||||
case 6: return range(1, 31)
|
||||
case 7: return range(1, 31)
|
||||
case 8: return range(1, 30)
|
||||
case 9: return range(1, 31)
|
||||
case 10: return range(1, 30)
|
||||
case 11: return range(1, 31)
|
||||
default: return range(1, 0)
|
||||
}
|
||||
}
|
||||
delegate: tumblerComponent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Tumbler {
|
||||
id: monthTumbler
|
||||
model: [
|
||||
qsTr("January"),
|
||||
qsTr("February"),
|
||||
qsTr("March"),
|
||||
qsTr("April"),
|
||||
qsTr("May"),
|
||||
qsTr("June"),
|
||||
qsTr("July"),
|
||||
qsTr("August"),
|
||||
qsTr("September"),
|
||||
qsTr("October"),
|
||||
qsTr("November"),
|
||||
qsTr("December")
|
||||
]
|
||||
delegate: tumblerComponent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Tumbler {
|
||||
id: yearTumbler
|
||||
model: range(2000, 200)
|
||||
delegate: tumblerComponent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.Frame {
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
columns: 3
|
||||
columnSpacing: 10
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Hour")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Minute")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Second")
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Controls.LineSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.LineSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Controls.LineSeparator {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Tumbler {
|
||||
id: hoursTumbler
|
||||
model: 24
|
||||
delegate: tumblerComponent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Tumbler {
|
||||
id: minutesTumbler
|
||||
model: 60
|
||||
delegate: tumblerComponent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Tumbler {
|
||||
id: secondsTumbler
|
||||
model: 60
|
||||
delegate: tumblerComponent
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
Controls.OutlineButton {
|
||||
text: qsTr("Read from board")
|
||||
onClicked: BmsInterface.commands().sendTerminalCmd("checkUnixTime")
|
||||
}
|
||||
|
||||
Controls.OutlineButton {
|
||||
text: qsTr("Read from computer")
|
||||
onClicked: {
|
||||
const date = new Date()
|
||||
|
||||
yearTumbler.currentIndex = date.getFullYear() - 2000
|
||||
monthTumbler.currentIndex = date.getMonth()
|
||||
dayTumbler.currentIndex = date.getDate() - 1
|
||||
|
||||
hoursTumbler.currentIndex = date.getHours()
|
||||
minutesTumbler.currentIndex = date.getMinutes()
|
||||
secondsTumbler.currentIndex = date.getSeconds()
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Write to board")
|
||||
onClicked: {
|
||||
const date = new Date()
|
||||
|
||||
date.setFullYear(yearTumbler.model[yearTumbler.currentIndex])
|
||||
date.setMonth(monthTumbler.currentIndex)
|
||||
date.setDate(dayTumbler.currentIndex + 1)
|
||||
|
||||
date.setHours(hoursTumbler.currentIndex)
|
||||
date.setMinutes(minutesTumbler.currentIndex)
|
||||
date.setSeconds(secondsTumbler.currentIndex)
|
||||
|
||||
const localTimestamp = (Math.round(date / 1000) - date.getTimezoneOffset() * 60).toString(16)
|
||||
BmsInterface.commands().sendTerminalCmd("setUnixTime " + localTimestamp)
|
||||
Qt.callLater(BmsInterface.emitStatusMessage, qsTr("Time settings applied successfully"), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tumblerComponent
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: modelData
|
||||
opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
enabled: root.visible
|
||||
onPrintReceived: {
|
||||
const lines = str.split(/\r?\n/)
|
||||
for (const line of lines) {
|
||||
if (line.includes("Year")) {
|
||||
const value = extractValue(line)
|
||||
if (value.length === 0) contine
|
||||
yearTumbler.currentIndex = parseInt(value)
|
||||
} else if (line.includes("Month")) {
|
||||
const value = extractValue(line)
|
||||
if (value.length === 0) contine
|
||||
monthTumbler.currentIndex = parseInt(value) - 1
|
||||
} else if (line.includes("Day")) {
|
||||
const value = extractValue(line)
|
||||
if (value.length === 0) contine
|
||||
dayTumbler.currentIndex = parseInt(value) - 1
|
||||
} else if (line.includes("Hours")) {
|
||||
const value = extractValue(line)
|
||||
if (value.length === 0) contine
|
||||
hoursTumbler.currentIndex = parseInt(value)
|
||||
} else if (line.includes("Minutes")) {
|
||||
const value = extractValue(line)
|
||||
if (value.length === 0) contine
|
||||
minutesTumbler.currentIndex = parseInt(value)
|
||||
} else if (line.includes("Seconds")) {
|
||||
const value = extractValue(line)
|
||||
if (value.length === 0) contine
|
||||
secondsTumbler.currentIndex = parseInt(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractValue(valueHolder) {
|
||||
const values = valueHolder.split(":")
|
||||
return values.length < 2 ? "" : values[1].trim()
|
||||
}
|
||||
}
|
||||
|
||||
function range(startAt, size) {
|
||||
return [...Array(size).keys()].map(i => i + startAt);
|
||||
}
|
||||
|
||||
onVisibleChanged: if (visible) {
|
||||
BmsInterface.commands().sendTerminalCmd("checkUnixTime")
|
||||
}
|
||||
}
|
||||
625
qml/Screens/VisualizationScreen.qml
Normal file
@@ -0,0 +1,625 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtCharts 2.3
|
||||
|
||||
import Controls 1.0 as Controls
|
||||
import Cubo 1.0
|
||||
import Utils 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 20
|
||||
|
||||
property real currentTime: 0
|
||||
|
||||
property var voltageData: []
|
||||
property var currentData: []
|
||||
property var batteryTemperatureData: []
|
||||
property var bmsTemperatureData: []
|
||||
property var cellVoltageData: []
|
||||
property var cellListData: []
|
||||
|
||||
// https://htmlcolorcodes.com/color-chart/
|
||||
property var chartColors: [
|
||||
"#c62828", "#6a1b9a", "#283593", "#0277bd", "#00695c", "#558b2f", "#f9a825", "#ef6c00",
|
||||
"#4e342e", "#37474f", "#ad1457", "#4527a0", "#1565c0", "#00838f", "#2e7d32", "#9e9d24",
|
||||
"#ff8f00", "#d84315", "#424242", "#ef5350", "#ab47bc", "#5c6bc0", "#29b6f6", "#26a69a",
|
||||
"#9ccc65", "#ffee58", "#ffa726", "#8d6e63", "#78909c", "#ec407a", "#7e57c2", "#42a5f5",
|
||||
]
|
||||
|
||||
Controls.Frame {
|
||||
padding: 20
|
||||
leftPadding: 1
|
||||
rightPadding: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.TabBar {
|
||||
id: bar
|
||||
implicitWidth: 300
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Voltage")
|
||||
width: bar.width / 6 * 0.9
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Current")
|
||||
width: bar.width / 6 * 0.8
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Battery temperature")
|
||||
width: bar.width / 6 * 1.3
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("BMS temperature")
|
||||
width: bar.width / 6 * 1.1
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Cell voltage")
|
||||
width: bar.width / 6 * 1
|
||||
}
|
||||
|
||||
Controls.TabButton {
|
||||
text: qsTr("Cell list")
|
||||
width: bar.width / 6 * 0.85
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
width: parent.width
|
||||
currentIndex: bar.currentIndex
|
||||
|
||||
Component {
|
||||
id: legendDelegate
|
||||
|
||||
RowLayout {
|
||||
width: ListView.view ? ListView.view.width : 200
|
||||
height: 60
|
||||
|
||||
property Controls.ChartView chartItem: undefined
|
||||
property color seriesColor: "black"
|
||||
property bool horizontal: true
|
||||
property bool selected: false
|
||||
|
||||
Controls.CheckBox {
|
||||
id: checkSeries
|
||||
checked: true
|
||||
spacing: 10
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
chartItem.series(modelData).opacity = 1
|
||||
} else {
|
||||
chartItem.series(modelData).opacity = 0
|
||||
}
|
||||
}
|
||||
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
chartItem.series(modelData).style = Qt.DashLine
|
||||
} else {
|
||||
chartItem.series(modelData).style = Qt.SolidLine
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: !horizontal
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: seriesColor
|
||||
radius: width / 2
|
||||
border.width: selected ? 2 : 0
|
||||
border.color: "black"
|
||||
Layout.preferredWidth: selected ? 21 : 18
|
||||
Layout.preferredHeight: selected ? 21 : 18
|
||||
Layout.rightMargin: 20
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: if (!selected) selected = true
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
chartItem = ListView.view ? ListView.view.chartItem : parent.chartItem
|
||||
horizontal = !ListView.view
|
||||
seriesColor = chartItem.series(modelData).color
|
||||
checkSeries.text = Qt.binding(function(){ return chartItem.series(modelData).name })
|
||||
|
||||
selectedChanged.connect(function (){ if (selected) chartItem.selectedSeriesIndex = index })
|
||||
chartItem.selectedSeriesIndexChanged.connect(function (){ if (typeof(selected) != "undefined") selected = chartItem.selectedSeriesIndex === index })
|
||||
selected = chartItem.selectedSeriesIndex === index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: chartComponent
|
||||
|
||||
RowLayout {
|
||||
property string xLabel: ""
|
||||
property string yLabel: ""
|
||||
property string infoXLabel: ""
|
||||
property string infoYLabel: ""
|
||||
property Controls.ChartView chart: chartView
|
||||
property int seriesCount: 0
|
||||
property bool horizontalLegend: true
|
||||
|
||||
ColumnLayout {
|
||||
spacing: -20
|
||||
|
||||
Controls.ContentLabel {
|
||||
z: 1
|
||||
text: yLabel
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 30
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
}
|
||||
|
||||
Controls.ChartView {
|
||||
id: chartView
|
||||
infoXMark: infoXLabel
|
||||
infoYMark: infoYLabel
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Controls.ContentLabel {
|
||||
z: 1
|
||||
text: xLabel
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.rightMargin: 30
|
||||
Layout.bottomMargin: 10
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: horizontalLegend
|
||||
spacing: 0
|
||||
|
||||
property Controls.ChartView chartItem: chart
|
||||
|
||||
Repeater {
|
||||
model: seriesCount
|
||||
delegate: legendDelegate
|
||||
}
|
||||
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 20
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
ListView {
|
||||
clip: true
|
||||
model: seriesCount
|
||||
delegate: legendDelegate
|
||||
visible: !horizontalLegend
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
ScrollBar.vertical: Controls.ScrollBar {}
|
||||
|
||||
property Controls.ChartView chartItem: chart
|
||||
|
||||
Layout.preferredWidth: 200
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: voltageLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
|
||||
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
|
||||
item.infoYLabel = Qt.binding(function() { return qsTr("V") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: currentLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Current, A") })
|
||||
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
|
||||
item.infoYLabel = Qt.binding(function() { return qsTr("A") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: batteryTemperatureLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Temperature, °C") })
|
||||
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
|
||||
item.infoYLabel = Qt.binding(function() { return qsTr("°C") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: bmsTemperatureLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Temperature, °C") })
|
||||
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
|
||||
item.infoYLabel = Qt.binding(function() { return qsTr("°C") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: cellVoltageLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
|
||||
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
|
||||
item.infoYLabel = Qt.binding(function() { return qsTr("V") })
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: cellListLoader
|
||||
sourceComponent: chartComponent
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Component.onCompleted: {
|
||||
item.xLabel = Qt.binding(function() { return qsTr("Time, s") })
|
||||
item.yLabel = Qt.binding(function() { return qsTr("Voltage, V") })
|
||||
item.infoXLabel = Qt.binding(function() { return qsTr("s") })
|
||||
item.infoYLabel = Qt.binding(function() { return qsTr("V") })
|
||||
item.horizontalLegend = false
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
||||
Controls.Button {
|
||||
id: resetZoomButton
|
||||
text: qsTr("Reset zoom")
|
||||
onClicked: {
|
||||
resetChartZoom(voltageData, voltageLoader)
|
||||
resetChartZoom(currentData, currentLoader)
|
||||
resetChartZoom(batteryTemperatureData, batteryTemperatureLoader)
|
||||
resetChartZoom(bmsTemperatureData, bmsTemperatureLoader)
|
||||
resetChartZoom(cellVoltageData, cellVoltageLoader)
|
||||
resetChartZoom(cellListData, cellListLoader)
|
||||
}
|
||||
|
||||
function resetChartZoom(dataObject, chartObject) {
|
||||
chartObject.item.chart.zoomReset()
|
||||
chartObject.item.chart.autoScaling = true
|
||||
chartObject.item.chart.axes[1].min = closestMinValue(getMinValue(dataObject), 0.05)
|
||||
chartObject.item.chart.axes[1].max = closestMaxValue(getMaxValue(dataObject), 0.05)
|
||||
chartObject.item.chart.axes[0].min = 0
|
||||
chartObject.item.chart.axes[0].max = Math.max(chartObject.item.chart.defaultXMax, chartObject.item.chart.series(0).at(chartObject.item.chart.series(0).count - 1).x)
|
||||
}
|
||||
|
||||
function getMaxValue(dataObject, seriesIndex) {
|
||||
if (dataObject.length === 0 || dataObject[0].length === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
var max = dataObject[0][0].y
|
||||
for (var i = 0; i < dataObject.length; ++i) {
|
||||
for (var j = 0; j < dataObject[i].length; ++j) {
|
||||
if (dataObject[i][j].y > max) {
|
||||
max = dataObject[i][j].y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
|
||||
function getMinValue(dataObject) {
|
||||
if (dataObject.length === 0 || dataObject[0].length === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
var min = dataObject[0][0].y
|
||||
for (var i = 0; i < dataObject.length; ++i) {
|
||||
for (var j = 0; j < dataObject[i].length; ++j) {
|
||||
if (dataObject[i][j].y < min) {
|
||||
min = dataObject[i][j].y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return min
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
property string pauseText: qsTr("Pause data collection")
|
||||
property string resumeText: qsTr("Resume data collection")
|
||||
text: pauseText
|
||||
onClicked: {
|
||||
if (timer.running) {
|
||||
text = resumeText
|
||||
timer.stop()
|
||||
} else {
|
||||
text = pauseText
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: qsTr("Clear data")
|
||||
onClicked: {
|
||||
currentTime = 0
|
||||
|
||||
clearData(voltageData, voltageLoader)
|
||||
clearData(currentData, currentLoader)
|
||||
clearData(batteryTemperatureData, batteryTemperatureLoader)
|
||||
clearData(bmsTemperatureData, bmsTemperatureLoader)
|
||||
clearData(cellVoltageData, cellVoltageLoader)
|
||||
clearData(cellListData, cellListLoader)
|
||||
|
||||
resetZoomButton.clicked()
|
||||
}
|
||||
|
||||
function clearData(dataObject, chartObject) {
|
||||
for (var i = 0; i < dataObject.length; ++i) {
|
||||
dataObject[i].splice(0, dataObject[i].length)
|
||||
var series = chartObject.item.chart.series(i)
|
||||
series.removePoints(0, series.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
|
||||
Controls.SubtitleLabel {
|
||||
text: qsTr("Interval, s")
|
||||
}
|
||||
|
||||
Controls.TextField {
|
||||
id: intervalField
|
||||
validator: DoubleValidator { bottom: 0.1; top: 100; decimals: 1; locale: "en-US" }
|
||||
text: "1"
|
||||
onEditingFinished: timer.interval = parseFloat(text) * 1000
|
||||
Layout.preferredHeight: 44
|
||||
}
|
||||
|
||||
Controls.ImageButton {
|
||||
icon.source: "qrc:/Icons/check-indicator.svg"
|
||||
icon.width: 32
|
||||
icon.height: 32
|
||||
Layout.preferredWidth: 42
|
||||
Layout.preferredHeight: 42
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Translator
|
||||
onCurrentLanguageChanged: {
|
||||
for (var i = 0; i < cellListLoader.item.chart.count; ++i) {
|
||||
cellListLoader.item.chart.series(i).name = qsTr("Cell #") + (i + 1).toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface.commands()
|
||||
enabled: root.visible
|
||||
|
||||
onValuesReceived: {
|
||||
addValueToChart(values.packVoltage, voltageData, voltageLoader, 0, 0.05)
|
||||
addValueToChart(values.packCurrent, currentData, currentLoader, 0, 0.05)
|
||||
|
||||
addValueToChart(values.tempBMSHigh, batteryTemperatureData, batteryTemperatureLoader, 0, 0.05)
|
||||
addValueToChart(values.tempBMSAverage, batteryTemperatureData, batteryTemperatureLoader, 1, 0.05)
|
||||
addValueToChart(values.tempBMSLow, batteryTemperatureData, batteryTemperatureLoader, 2, 0.05)
|
||||
|
||||
addValueToChart(values.tempBattHigh, bmsTemperatureData, bmsTemperatureLoader, 0, 0.05)
|
||||
addValueToChart(values.tempBattAverage, bmsTemperatureData, bmsTemperatureLoader, 1, 0.05)
|
||||
addValueToChart(values.tempBattLow, bmsTemperatureData, bmsTemperatureLoader, 2, 0.05)
|
||||
|
||||
addValueToChart(values.cVHigh, cellVoltageData, cellVoltageLoader, 0, 0.05)
|
||||
addValueToChart(values.cVAverage, cellVoltageData, cellVoltageLoader, 1, 0.05)
|
||||
addValueToChart(values.cVLow, cellVoltageData, cellVoltageLoader, 2, 0.05)
|
||||
}
|
||||
|
||||
onCellsReceived: {
|
||||
for (var i = cellListLoader.item.chart.count; i < cellCount; ++i) {
|
||||
cellListLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Cell #") + (i + 1).toString(),
|
||||
cellListLoader.item.chart.xAxis, cellListLoader.item.chart.yAxis)
|
||||
if (i < chartColors.length) {
|
||||
cellListLoader.item.chart.series(i).color = chartColors[i]
|
||||
}
|
||||
cellListLoader.item.chart.axes[0].max = 10
|
||||
cellListLoader.item.seriesCount = cellListLoader.item.chart.count
|
||||
}
|
||||
|
||||
for (var j = 0; j < cellCount; ++j) {
|
||||
addValueToChart(cellVoltageArray[j], cellListData, cellListLoader, j, 0.05)
|
||||
}
|
||||
|
||||
currentTime = Math.round((timer.interval / 1000 + currentTime + Number.EPSILON) * 10) / 10
|
||||
}
|
||||
}
|
||||
|
||||
function addValueToChart(value, dataObject, chartObject, seriesIndex, yScale) {
|
||||
if (seriesIndex >= dataObject.length) {
|
||||
for (var i = dataObject.length; i <= seriesIndex; ++i) {
|
||||
dataObject.push([])
|
||||
}
|
||||
}
|
||||
|
||||
var seriesData = dataObject[seriesIndex]
|
||||
seriesData.push(Qt.point(currentTime, value))
|
||||
chartObject.item.chart.series(seriesIndex).append(currentTime, value)
|
||||
|
||||
if (currentTime > chartObject.item.chart.defaultXMax && chartObject.item.chart.autoScaling) {
|
||||
chartObject.item.chart.axes[0].max = currentTime
|
||||
}
|
||||
|
||||
if (seriesData.length < 2 || (value >= chartObject.item.chart.axes[1].max && chartObject.item.chart.autoScaling)) {
|
||||
chartObject.item.chart.axes[1].max = closestMaxValue(value, yScale)
|
||||
}
|
||||
|
||||
if (seriesData.length < 2 || (value <= chartObject.item.chart.axes[1].min && chartObject.item.chart.autoScaling)) {
|
||||
chartObject.item.chart.axes[1].min = closestMinValue(value, yScale)
|
||||
}
|
||||
}
|
||||
|
||||
function closestMaxValue(value, scale) {
|
||||
return value === 0 ? 1 : Math.ceil(value * (value > 0 ? (1 + scale) : (1 - scale)))
|
||||
}
|
||||
|
||||
function closestMinValue(value, scale) {
|
||||
return value === 0 ? -1 : Math.floor(value * (value > 0 ? (1 - scale) : (1 + scale)))
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
running: true
|
||||
interval: 1000
|
||||
triggeredOnStart: true
|
||||
|
||||
onTriggered: {
|
||||
BmsInterface.commands().getValues()
|
||||
BmsInterface.commands().getCells()
|
||||
Qt.callLater(start)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: BmsInterface
|
||||
onPortConnectedChanged: getValues()
|
||||
}
|
||||
|
||||
onVisibleChanged: getValues()
|
||||
|
||||
function getValues() {
|
||||
if (BmsInterface.isPortConnected() && visible) {
|
||||
timer.start()
|
||||
} else {
|
||||
timer.stop()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
voltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Voltage indicator"),
|
||||
voltageLoader.item.chart.xAxis, voltageLoader.item.chart.yAxis)
|
||||
voltageLoader.item.chart.series(0).name = Qt.binding(function(){ return qsTr("Voltage indicator") })
|
||||
voltageLoader.item.chart.series(0).color = "#fbc02d"
|
||||
voltageLoader.item.chart.axes[0].max = 10
|
||||
voltageLoader.item.seriesCount = voltageLoader.item.chart.count
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
currentLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Current indicator"),
|
||||
currentLoader.item.chart.xAxis, currentLoader.item.chart.yAxis)
|
||||
currentLoader.item.chart.series(0).name = Qt.binding(function(){ return qsTr("Current indicator") })
|
||||
currentLoader.item.chart.series(0).color = "#e64a19"
|
||||
currentLoader.item.chart.axes[0].max = 10
|
||||
currentLoader.item.seriesCount = currentLoader.item.chart.count
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum temperature"),
|
||||
batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
|
||||
batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average temperature"),
|
||||
batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
|
||||
batteryTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum temperature"),
|
||||
batteryTemperatureLoader.item.chart.xAxis, batteryTemperatureLoader.item.chart.yAxis)
|
||||
|
||||
batteryTemperatureLoader.item.chart.series(0).name = Qt.binding(function(){ return qsTr("Maximum temperature") })
|
||||
batteryTemperatureLoader.item.chart.series(1).name = Qt.binding(function(){ return qsTr("Average temperature") })
|
||||
batteryTemperatureLoader.item.chart.series(2).name = Qt.binding(function(){ return qsTr("Minimum temperature") })
|
||||
batteryTemperatureLoader.item.chart.series(0).color = "#e64a19"
|
||||
batteryTemperatureLoader.item.chart.series(1).color = "#fbc02d"
|
||||
batteryTemperatureLoader.item.chart.series(2).color = "#388e3c"
|
||||
|
||||
batteryTemperatureLoader.item.chart.axes[0].max = 10
|
||||
batteryTemperatureLoader.item.seriesCount = batteryTemperatureLoader.item.chart.count
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum temperature"),
|
||||
bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
|
||||
bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average temperature"),
|
||||
bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
|
||||
bmsTemperatureLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum temperature"),
|
||||
bmsTemperatureLoader.item.chart.xAxis, bmsTemperatureLoader.item.chart.yAxis)
|
||||
|
||||
bmsTemperatureLoader.item.chart.series(0).name = Qt.binding(function(){ return qsTr("Maximum temperature") })
|
||||
bmsTemperatureLoader.item.chart.series(1).name = Qt.binding(function(){ return qsTr("Average temperature") })
|
||||
bmsTemperatureLoader.item.chart.series(2).name = Qt.binding(function(){ return qsTr("Minimum temperature") })
|
||||
bmsTemperatureLoader.item.chart.series(0).color = "#e64a19"
|
||||
bmsTemperatureLoader.item.chart.series(1).color = "#fbc02d"
|
||||
bmsTemperatureLoader.item.chart.series(2).color = "#388e3c"
|
||||
|
||||
bmsTemperatureLoader.item.chart.axes[0].max = 10
|
||||
bmsTemperatureLoader.item.seriesCount = bmsTemperatureLoader.item.chart.count
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Maximum voltage"),
|
||||
cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
|
||||
cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Average voltage"),
|
||||
cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
|
||||
cellVoltageLoader.item.chart.createSeries(ChartView.SeriesTypeLine, qsTr("Minimum voltage"),
|
||||
cellVoltageLoader.item.chart.xAxis, cellVoltageLoader.item.chart.yAxis)
|
||||
cellVoltageLoader.item.chart.series(0).color = "#e64a19"
|
||||
cellVoltageLoader.item.chart.series(1).color = "#fbc02d"
|
||||
cellVoltageLoader.item.chart.series(2).color = "#388e3c"
|
||||
|
||||
cellVoltageLoader.item.chart.series(0).name = Qt.binding(function(){ return qsTr("Maximum voltage") })
|
||||
cellVoltageLoader.item.chart.series(1).name = Qt.binding(function(){ return qsTr("Average voltage") })
|
||||
cellVoltageLoader.item.chart.series(2).name = Qt.binding(function(){ return qsTr("Minimum voltage") })
|
||||
|
||||
cellVoltageLoader.item.chart.axes[0].max = 10
|
||||
cellVoltageLoader.item.seriesCount = cellVoltageLoader.item.chart.count
|
||||
}
|
||||
}
|
||||
17
qml/Screens/qmldir
Normal file
@@ -0,0 +1,17 @@
|
||||
module Screens
|
||||
AkbMonitorScreen 1.0 AkbMonitorScreen.qml
|
||||
CellMonitorScreen 1.0 CellMonitorScreen.qml
|
||||
BmsSettingsScreen 1.0 BmsSettingsScreen.qml
|
||||
VisualizationScreen 1.0 VisualizationScreen.qml
|
||||
BmsServiceScreen 1.0 BmsServiceScreen.qml
|
||||
DebugInformationScreen 1.0 DebugInformationScreen.qml
|
||||
ConnectionDialog 1.0 ConnectionDialog.qml
|
||||
MessageDialog 1.0 MessageDialog.qml
|
||||
StatusPopup 1.0 StatusPopup.qml
|
||||
TerminalScreen 1.0 TerminalScreen.qml
|
||||
FirmwareUpdateScreen 1.0 FirmwareUpdateScreen.qml
|
||||
NetworkSettingsScreen 1.0 NetworkSettingsScreen.qml
|
||||
TimeSettingsScreen 1.0 TimeSettingsScreen.qml
|
||||
CanSettingsScreen 1.0 CanSettingsScreen.qml
|
||||
TemperatureMonitorScreen 1.0 TemperatureMonitorScreen.qml
|
||||
StatePopup 1.0 StatePopup.qml
|
||||
9
qml/Utils/MathHelper.qml
Normal file
@@ -0,0 +1,9 @@
|
||||
pragma Singleton
|
||||
import QtQuick 2.12
|
||||
|
||||
QtObject {
|
||||
function roundDouble(value, decimals = 2) {
|
||||
var factor = Math.pow(10, decimals)
|
||||
return Math.round((value + Number.EPSILON) * factor) / factor
|
||||
}
|
||||
}
|
||||
30
qml/Utils/Palette.qml
Normal file
@@ -0,0 +1,30 @@
|
||||
pragma Singleton
|
||||
import QtQuick 2.12
|
||||
|
||||
QtObject {
|
||||
property color textColor: "#000000"
|
||||
property color selectedTextColor: "#009352"
|
||||
property color contentTextColor: "#869098"
|
||||
property color alternativeTextColor: "#FFFFFF"
|
||||
property color tableHeaderTextColor: "#838D97"
|
||||
|
||||
property color backgroundColor: "#FFFFFF"
|
||||
property color hoveredBackgroundColor: "#F0F1F4"
|
||||
property color selectedBackgroundColor: "#CCE9DC"
|
||||
property color alternativeBackgroundColor: "#009352"
|
||||
property color screenBackgroundColor: "#F7F8FC"
|
||||
property color tableHeaderBackgroundColor: "#F0F1F4"
|
||||
property color selectedTextBackgroundColor: "#009150"
|
||||
|
||||
property color borderColor: "#DFE0EB"
|
||||
|
||||
property color buttonColor: "#009352"
|
||||
property color outlineButtonColor: "#F7F8FC"
|
||||
property color hoveredButtonColor: "#03AC61"
|
||||
property color pressedButtonColor: "#057845"
|
||||
|
||||
property color informationColor: "#4C68ED"
|
||||
property color invalidColor: "#A31C00"
|
||||
property color goodColor: "#009352"
|
||||
property color neutralColor: "#DFE0EB"
|
||||
}
|
||||
3
qml/Utils/qmldir
Normal file
@@ -0,0 +1,3 @@
|
||||
module utils
|
||||
singleton Palette 1.0 Palette.qml
|
||||
singleton MathHelper 1.0 MathHelper.qml
|
||||
28
qml/qml_icons.qrc
Normal file
@@ -0,0 +1,28 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>Icons/akb-monitor.svg</file>
|
||||
<file>Icons/bms-configuration.svg</file>
|
||||
<file>Icons/bms-service.svg</file>
|
||||
<file>Icons/cell-monitor.svg</file>
|
||||
<file>Icons/cubo-logo.svg</file>
|
||||
<file>Icons/exit.svg</file>
|
||||
<file>Icons/hide-menu.svg</file>
|
||||
<file>Icons/history.svg</file>
|
||||
<file>Icons/visualization.svg</file>
|
||||
<file>Icons/check-indicator.svg</file>
|
||||
<file>Icons/connection.svg</file>
|
||||
<file>Icons/close.svg</file>
|
||||
<file>Icons/info.svg</file>
|
||||
<file>Icons/warning.svg</file>
|
||||
<file>Icons/english-flag.svg</file>
|
||||
<file>Icons/italian-flag.svg</file>
|
||||
<file>Icons/russian-flag.svg</file>
|
||||
<file>Icons/refresh.svg</file>
|
||||
<file>Icons/temperature.svg</file>
|
||||
<file>Icons/error-state.svg</file>
|
||||
<file>Icons/good-state.svg</file>
|
||||
<file>Icons/info-state.svg</file>
|
||||
<file>Icons/neutral-state.svg</file>
|
||||
<file>Icons/warning-state.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
54
qml/qml_items.qrc
Normal file
@@ -0,0 +1,54 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>MainWindow.qml</file>
|
||||
<file>Screens/ConnectionDialog.qml</file>
|
||||
<file>Screens/AkbMonitorScreen.qml</file>
|
||||
<file>Screens/CellMonitorScreen.qml</file>
|
||||
<file>Controls/ComboBox.qml</file>
|
||||
<file>Utils/Palette.qml</file>
|
||||
<file>Controls/qmldir</file>
|
||||
<file>Screens/qmldir</file>
|
||||
<file>Utils/qmldir</file>
|
||||
<file>Controls/ScrollBar.qml</file>
|
||||
<file>Controls/OutlineButton.qml</file>
|
||||
<file>Controls/Button.qml</file>
|
||||
<file>Controls/TextField.qml</file>
|
||||
<file>Controls/Frame.qml</file>
|
||||
<file>Controls/TitleLabel.qml</file>
|
||||
<file>Controls/SubtitleLabel.qml</file>
|
||||
<file>Controls/ContentLabel.qml</file>
|
||||
<file>Controls/DotSeparator.qml</file>
|
||||
<file>Controls/AvailabilityIndicator.qml</file>
|
||||
<file>Screens/BmsSettingsScreen.qml</file>
|
||||
<file>Controls/LabelWithBackground.qml</file>
|
||||
<file>Controls/CheckBox.qml</file>
|
||||
<file>Controls/LineSeparator.qml</file>
|
||||
<file>Controls/LinkLabel.qml</file>
|
||||
<file>Screens/VisualizationScreen.qml</file>
|
||||
<file>Controls/TabButton.qml</file>
|
||||
<file>Controls/TabBar.qml</file>
|
||||
<file>Controls/ChartView.qml</file>
|
||||
<file>Screens/BmsServiceScreen.qml</file>
|
||||
<file>Controls/TextArea.qml</file>
|
||||
<file>Screens/DebugInformationScreen.qml</file>
|
||||
<file>Controls/DialogHeader.qml</file>
|
||||
<file>Controls/DialogBackground.qml</file>
|
||||
<file>Screens/MessageDialog.qml</file>
|
||||
<file>Screens/StatusPopup.qml</file>
|
||||
<file>Utils/MathHelper.qml</file>
|
||||
<file>Controls/BusyIndicator.qml</file>
|
||||
<file>Controls/MenuItemDelegate.qml</file>
|
||||
<file>Controls/ScrollIndicator.qml</file>
|
||||
<file>Controls/OutlineImageButton.qml</file>
|
||||
<file>Controls/ImageButton.qml</file>
|
||||
<file>Screens/TerminalScreen.qml</file>
|
||||
<file>Screens/FirmwareUpdateScreen.qml</file>
|
||||
<file>Controls/ProgressBar.qml</file>
|
||||
<file>Screens/NetworkSettingsScreen.qml</file>
|
||||
<file>Screens/TimeSettingsScreen.qml</file>
|
||||
<file>Controls/RadioButton.qml</file>
|
||||
<file>Screens/TemperatureMonitorScreen.qml</file>
|
||||
<file>Screens/CanSettingsScreen.qml</file>
|
||||
<file>Screens/StatePopup.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
193
res/config.xml
@@ -2486,6 +2486,186 @@ p, li { white-space: pre-wrap; }
|
||||
<suffix>ms</suffix>
|
||||
<vTx>5</vTx>
|
||||
</AUX1TurnOffDelay>
|
||||
<chargeBatteryOutputChecked>
|
||||
<longName>Charge Battery Output Checked</longName>
|
||||
<type>5</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Charge Battery Output Checked Description</description>
|
||||
<cDefine>CHARGE_BATTERY_OUTPUT_CHECKED</cDefine>
|
||||
<valInt>0</valInt>
|
||||
</chargeBatteryOutputChecked>
|
||||
<brushOrShuntOutputChecked>
|
||||
<longName>Brush Or Shunt Output Checked</longName>
|
||||
<type>5</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Brush Or Shunt Output Checked Description</description>
|
||||
<cDefine>BRUSH_OR_SHUNT_OUTPUT_CHECKED</cDefine>
|
||||
<valInt>0</valInt>
|
||||
</brushOrShuntOutputChecked>
|
||||
<brushOrShuntMode>
|
||||
<longName>Brush Or Shunt Mode</longName>
|
||||
<type>5</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Brush Or Shunt Mode Description</description>
|
||||
<cDefine>BRUSH_OR_SHUNT_MODE</cDefine>
|
||||
<valInt>1</valInt>
|
||||
</brushOrShuntMode>
|
||||
<brushUsageSocThreshold>
|
||||
<longName>Brush Usage Soc Threshold</longName>
|
||||
<type>2</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Brush Usage Soc Threshold Description</description>
|
||||
<cDefine>BRUSH_USAGE_SOC_THRESHOLD</cDefine>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxInt>100</maxInt>
|
||||
<minInt>0</minInt>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepInt>1</stepInt>
|
||||
<valInt>10</valInt>
|
||||
<suffix>°C</suffix>
|
||||
<vTx>3</vTx>
|
||||
</brushUsageSocThreshold>
|
||||
<shuntChargingContactorDelay>
|
||||
<longName>Shunt Charging Contactor Delay</longName>
|
||||
<type>2</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Shunt Charging Contactor Delay Description</description>
|
||||
<cDefine>SHUNT_CHARGING_CONTRACTOR_DELAY</cDefine>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxInt>65535</maxInt>
|
||||
<minInt>0</minInt>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepInt>1</stepInt>
|
||||
<valInt>10</valInt>
|
||||
<suffix>Sec</suffix>
|
||||
<vTx>3</vTx>
|
||||
</shuntChargingContactorDelay>
|
||||
<coolingOutputChecked>
|
||||
<longName>Cooling Output Checked</longName>
|
||||
<type>5</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Cooling Output Checked Description</description>
|
||||
<cDefine>COOLING_OUTPUT_CHECKED</cDefine>
|
||||
<valInt>0</valInt>
|
||||
</coolingOutputChecked>
|
||||
<coolingStartThreshold>
|
||||
<longName>Cooling Start Threshold</longName>
|
||||
<type>2</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Cooling Start Threshold Description</description>
|
||||
<cDefine>COOLING_START_THRESHOLD</cDefine>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxInt>32767</maxInt>
|
||||
<minInt>-32768</minInt>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepInt>1</stepInt>
|
||||
<valInt>50</valInt>
|
||||
<suffix>°C</suffix>
|
||||
<vTx>4</vTx>
|
||||
</coolingStartThreshold>
|
||||
<coolingStopThreshold>
|
||||
<longName>Cooling Stop Threshold</longName>
|
||||
<type>2</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Cooling Stop Threshold Description</description>
|
||||
<cDefine>COOLING_STOP_THRESHOLD</cDefine>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxInt>32767</maxInt>
|
||||
<minInt>-32768</minInt>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepInt>1</stepInt>
|
||||
<valInt>40</valInt>
|
||||
<suffix>°C</suffix>
|
||||
<vTx>4</vTx>
|
||||
</coolingStopThreshold>
|
||||
<heatingOutputChecked>
|
||||
<longName>Heating Output Checked</longName>
|
||||
<type>5</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Heating Output Checked Description</description>
|
||||
<cDefine>HEATING_OUTPUT_CHECKED</cDefine>
|
||||
<valInt>0</valInt>
|
||||
</heatingOutputChecked>
|
||||
<heatingStartThreshold>
|
||||
<longName>Heating Start Threshold</longName>
|
||||
<type>2</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Heating Start Threshold Description</description>
|
||||
<cDefine>HEATING_START_THRESHOLD</cDefine>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxInt>32767</maxInt>
|
||||
<minInt>-32768</minInt>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepInt>1</stepInt>
|
||||
<valInt>0</valInt>
|
||||
<suffix>°C</suffix>
|
||||
<vTx>4</vTx>
|
||||
</heatingStartThreshold>
|
||||
<heatingStopThreshold>
|
||||
<longName>Heating Stop Threshold</longName>
|
||||
<type>2</type>
|
||||
<transmittable>1</transmittable>
|
||||
<description>Heating Stop Threshold Description</description>
|
||||
<cDefine>HEATING_STOP_THRESHOLD</cDefine>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxInt>32767</maxInt>
|
||||
<minInt>-32768</minInt>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepInt>1</stepInt>
|
||||
<valInt>20</valInt>
|
||||
<suffix>°C</suffix>
|
||||
<vTx>4</vTx>
|
||||
</heatingStopThreshold>
|
||||
<floatCurrentK1>
|
||||
<longName>Current factor K1</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;">Current factor K1.</p></body></html></description>
|
||||
<cDefine>FLOAT_CURRENT_K1</cDefine>
|
||||
<editorDecimalsDouble>6</editorDecimalsDouble>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxDouble>1.17549e-38</maxDouble>
|
||||
<minDouble>3.40282e+38</minDouble>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepDouble>0.05</stepDouble>
|
||||
<valDouble>0</valDouble>
|
||||
<vTxDoubleScale>100000</vTxDoubleScale>
|
||||
<suffix></suffix>
|
||||
<vTx>9</vTx>
|
||||
</floatCurrentK1>
|
||||
<floatCurrentK2>
|
||||
<longName>Current factor K2</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;">Current factor K2.</p></body></html></description>
|
||||
<cDefine>FLOAT_CURRENT_K1</cDefine>
|
||||
<editorDecimalsDouble>6</editorDecimalsDouble>
|
||||
<editorScale>1</editorScale>
|
||||
<editAsPercentage>0</editAsPercentage>
|
||||
<maxDouble>1.17549e-38</maxDouble>
|
||||
<minDouble>3.40282e+38</minDouble>
|
||||
<showDisplay>0</showDisplay>
|
||||
<stepDouble>0.05</stepDouble>
|
||||
<valDouble>0</valDouble>
|
||||
<vTxDoubleScale>100000</vTxDoubleScale>
|
||||
<suffix></suffix>
|
||||
<vTx>9</vTx>
|
||||
</floatCurrentK2>
|
||||
</Params>
|
||||
<SerOrder>
|
||||
<ser>noOfCellsSeries</ser>
|
||||
@@ -2582,5 +2762,18 @@ p, li { white-space: pre-wrap; }
|
||||
<ser>chargeEnableState</ser>
|
||||
<ser>powerDownDelay</ser>
|
||||
<ser>humidityICType</ser>
|
||||
<ser>chargeBatteryOutputChecked</ser>
|
||||
<ser>brushOrShuntOutputChecked</ser>
|
||||
<ser>brushOrShuntMode</ser>
|
||||
<ser>brushUsageSocThreshold</ser>
|
||||
<ser>shuntChargingContactorDelay</ser>
|
||||
<ser>coolingOutputChecked</ser>
|
||||
<ser>coolingStartThreshold</ser>
|
||||
<ser>coolingStopThreshold</ser>
|
||||
<ser>heatingOutputChecked</ser>
|
||||
<ser>heatingStartThreshold</ser>
|
||||
<ser>heatingStopThreshold</ser>
|
||||
<ser>floatCurrentK1</ser>
|
||||
<ser>floatCurrentK2</ser>
|
||||
</SerOrder>
|
||||
</ConfigParams>
|
||||
|
||||