Added project implementation
This commit is contained in:
287
sources/DataController.cpp
Normal file
287
sources/DataController.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
#include "DataController.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QtEndian>
|
||||
#include <QDateTime>
|
||||
#include <QSettings>
|
||||
#include <QSerialPort>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
DataController::DataController(QObject* parent)
|
||||
: QObject{parent}
|
||||
, serialPort_(new QSerialPort)
|
||||
{
|
||||
connect(serialPort_.data(), &QSerialPort::readyRead, this, &DataController::serialReadyRead);
|
||||
connect(serialPort_.data(), &QSerialPort::errorOccurred, this, &DataController::serialError);
|
||||
|
||||
// for correct qApp->exit();
|
||||
QTimer::singleShot(0, this, [this]{ openSerialPort(); });
|
||||
}
|
||||
|
||||
DataController::~DataController()
|
||||
{
|
||||
}
|
||||
|
||||
QObject* DataController::qmlInstance(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/)
|
||||
{
|
||||
return new DataController;
|
||||
}
|
||||
|
||||
void DataController::serialReadyRead()
|
||||
{
|
||||
const auto data = serialPort_->readAll();
|
||||
qDebug() << "Serial data received (HEX):" << QDateTime::currentDateTime() << data.toHex();
|
||||
|
||||
serialData_ += data;
|
||||
parseSerialData();
|
||||
}
|
||||
|
||||
void DataController::serialError()
|
||||
{
|
||||
const auto error = serialPort_->error();
|
||||
if (error == QSerialPort::NoError)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
qCritical() << "A serial port error has occurred. Port:" << serialPort_->portName() << "Error:" << serialPort_->errorString();
|
||||
qApp->exit(1);
|
||||
}
|
||||
|
||||
QVariantMap DataController::readSettings()
|
||||
{
|
||||
QSettings settings("settings.ini", QSettings::IniFormat);
|
||||
|
||||
const auto keys = settings.allKeys();
|
||||
if (keys.isEmpty())
|
||||
{
|
||||
qCritical() << "File settings.ini is empty. Please put the file next to the executable file.";
|
||||
qApp->exit(1);
|
||||
}
|
||||
|
||||
|
||||
QVariantMap settingsMap;
|
||||
for (const auto& key: keys)
|
||||
{
|
||||
settingsMap[key] = settings.value(key);
|
||||
}
|
||||
|
||||
return settingsMap;
|
||||
}
|
||||
|
||||
void DataController::openSerialPort()
|
||||
{
|
||||
const auto settings = readSettings();
|
||||
if (settings.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto portName = settings["name"].toString();
|
||||
|
||||
// for testing
|
||||
if (portName == "fake")
|
||||
{
|
||||
mockSerialData();
|
||||
parseSerialData();
|
||||
return;
|
||||
}
|
||||
|
||||
serialPort_->setPortName(portName);
|
||||
|
||||
if (settings.contains("baudRate"))
|
||||
{
|
||||
serialPort_->setBaudRate(settings["baudRate"].toInt());
|
||||
}
|
||||
|
||||
if (settings.contains("dataBits"))
|
||||
{
|
||||
serialPort_->setDataBits((QSerialPort::DataBits)settings["dataBits"].toInt());
|
||||
}
|
||||
|
||||
if (settings.contains("parity"))
|
||||
{
|
||||
serialPort_->setParity((QSerialPort::Parity)settings["parity"].toInt());
|
||||
}
|
||||
|
||||
if (settings.contains("stopBits"))
|
||||
{
|
||||
serialPort_->setStopBits((QSerialPort::StopBits)settings["stopBits"].toInt());
|
||||
}
|
||||
|
||||
if (settings.contains("flowControl"))
|
||||
{
|
||||
serialPort_->setFlowControl((QSerialPort::FlowControl)settings["flowControl"].toInt());
|
||||
}
|
||||
|
||||
if (!serialPort_->open(QIODevice::ReadOnly))
|
||||
{
|
||||
qCritical() << "Can't open serial port. Port:" << serialPort_->portName() << "Error:" << serialPort_->errorString();
|
||||
qApp->exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void DataController::parseSerialData()
|
||||
{
|
||||
const char* startBytes = "\xD0\x0D";
|
||||
const auto startPosition = serialData_.indexOf(startBytes);
|
||||
if (startPosition == -1)
|
||||
{
|
||||
serialData_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (startPosition > 0)
|
||||
{
|
||||
serialData_ = serialData_.mid(startPosition);
|
||||
}
|
||||
|
||||
if (serialData_.size() < 35)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto extractInt = [](const QByteArray& array, int start, int length) -> uint32_t
|
||||
{
|
||||
uint32_t result = 0;
|
||||
if (length > 4)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// reversed byte order
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
memcpy(reinterpret_cast<char*>(&result) + i, array.data() + start + length - i - 1, 1);
|
||||
}
|
||||
|
||||
// same byte order
|
||||
// memcpy(&result, array.data() + start, length);
|
||||
return result;
|
||||
};
|
||||
|
||||
auto statusToString = [](uint32_t status) -> QString
|
||||
{
|
||||
auto hexStatus = "0x" + QString("%1").arg(status, 2, 16, QLatin1Char('0')).toUpper();
|
||||
if (hexStatus.compare("0xFF", Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
hexStatus = " — ";
|
||||
}
|
||||
|
||||
return hexStatus;
|
||||
};
|
||||
|
||||
auto shortIntToString = [](uint16_t parameter) -> QString
|
||||
{
|
||||
return parameter == std::numeric_limits<uint16_t>::max() ? " — " : QString::number(parameter);
|
||||
};
|
||||
|
||||
auto shortDoubleToString = [](uint16_t parameter) -> QString
|
||||
{
|
||||
return parameter == std::numeric_limits<uint16_t>::max() ? " — " : QString::number(parameter / 10.0, 'f', 1);
|
||||
};
|
||||
|
||||
const auto package = serialData_.mid(0, 35);
|
||||
serialData_ = serialData_.mid(35);
|
||||
|
||||
quint16 calculatedChecksum = 0;
|
||||
for (int i = 0; i < 33; ++i)
|
||||
{
|
||||
calculatedChecksum += static_cast<quint8>(package.at(i));
|
||||
}
|
||||
|
||||
const auto checksum = extractInt(package, 33, 2);
|
||||
if (calculatedChecksum != checksum)
|
||||
{
|
||||
qWarning() << "incorrect checksum";
|
||||
return;
|
||||
}
|
||||
|
||||
setProperty("ipbsFirstVoltage", shortDoubleToString(extractInt(package, 2, 2)));
|
||||
setProperty("ipbsFirstCurrent", shortDoubleToString(extractInt(package, 4, 2)));
|
||||
|
||||
setProperty("ipbsSecondVoltage", shortDoubleToString(extractInt(package, 6, 2)));
|
||||
setProperty("ipbsSecondCurrent", shortDoubleToString(extractInt(package, 8, 2)));
|
||||
|
||||
setProperty("ipbsThirdVoltage", shortDoubleToString(extractInt(package, 10, 2)));
|
||||
setProperty("ipbsThirdCurrent", shortDoubleToString(extractInt(package, 12, 2)));
|
||||
|
||||
setProperty("mainVoltage", shortIntToString(extractInt(package, 14, 2)));
|
||||
setProperty("ipbsMode", extractInt(package, 16, 1));
|
||||
|
||||
setProperty("firstStatus", statusToString(extractInt(package, 17, 1)));
|
||||
setProperty("secondStatus", statusToString(extractInt(package, 18, 1)));
|
||||
|
||||
setProperty("ainFirstVoltage", shortIntToString(extractInt(package, 19, 2)));
|
||||
setProperty("ainFirstCurrent", shortDoubleToString(extractInt(package, 21, 2)));
|
||||
|
||||
setProperty("ainSecondVoltage", shortIntToString(extractInt(package, 23, 2)));
|
||||
setProperty("ainSecondCurrent", shortDoubleToString(extractInt(package, 25, 2)));
|
||||
|
||||
setProperty("ainThirdVoltage", shortIntToString(extractInt(package, 27, 2)));
|
||||
setProperty("ainThirdCurrent", shortDoubleToString(extractInt(package, 29, 2)));
|
||||
|
||||
setProperty("psnInputVoltage", shortIntToString(extractInt(package, 31, 2)));
|
||||
}
|
||||
|
||||
void DataController::mockSerialData()
|
||||
{
|
||||
serialData_.clear();
|
||||
|
||||
serialData_.append((char)0xD0);
|
||||
serialData_.append((char)0x0D);
|
||||
|
||||
uint16_t voltage1 = qToBigEndian((uint16_t)1102);
|
||||
uint16_t current1 = qToBigEndian((uint16_t)955);
|
||||
serialData_.append(reinterpret_cast<char*>(&voltage1), 2);
|
||||
serialData_.append(reinterpret_cast<char*>(¤t1), 2);
|
||||
|
||||
uint16_t voltage2 = qToBigEndian((uint16_t)1097);
|
||||
uint16_t current2 = qToBigEndian((uint16_t)831);
|
||||
serialData_.append(reinterpret_cast<char*>(&voltage2), 2);
|
||||
serialData_.append(reinterpret_cast<char*>(¤t2), 2);
|
||||
|
||||
uint16_t voltage3 = qToBigEndian((uint16_t)1222);
|
||||
uint16_t current3 = qToBigEndian((uint16_t)353);
|
||||
serialData_.append(reinterpret_cast<char*>(&voltage3), 2);
|
||||
serialData_.append(reinterpret_cast<char*>(¤t3), 2);
|
||||
|
||||
uint16_t mainVoltage = qToBigEndian((uint16_t)384);
|
||||
char mode = 0;
|
||||
serialData_.append(reinterpret_cast<char*>(&mainVoltage), 2);
|
||||
serialData_.append(mode);
|
||||
|
||||
char status1 = 0x0;
|
||||
char status2 = 0x0;
|
||||
serialData_.append(status1);
|
||||
serialData_.append(status2);
|
||||
|
||||
uint16_t voltage4 = qToBigEndian((uint16_t)380);
|
||||
uint16_t current4 = qToBigEndian((uint16_t)535);
|
||||
serialData_.append(reinterpret_cast<char*>(&voltage4), 2);
|
||||
serialData_.append(reinterpret_cast<char*>(¤t4), 2);
|
||||
|
||||
uint16_t voltage5 = qToBigEndian((uint16_t)381);
|
||||
uint16_t current5 = qToBigEndian((uint16_t)527);
|
||||
serialData_.append(reinterpret_cast<char*>(&voltage5), 2);
|
||||
serialData_.append(reinterpret_cast<char*>(¤t5), 2);
|
||||
|
||||
uint16_t voltage6 = qToBigEndian((uint16_t)383);
|
||||
uint16_t current6 = qToBigEndian((uint16_t)729);
|
||||
serialData_.append(reinterpret_cast<char*>(&voltage6), 2);
|
||||
serialData_.append(reinterpret_cast<char*>(¤t6), 2);
|
||||
|
||||
uint16_t inputVoltage = qToBigEndian((uint16_t)3010);
|
||||
serialData_.append(reinterpret_cast<char*>(&inputVoltage), 2);
|
||||
|
||||
quint16 checksum = 0;
|
||||
for (int i = 0; i < serialData_.size(); ++i)
|
||||
{
|
||||
checksum += static_cast<quint8>(serialData_.at(i));
|
||||
}
|
||||
|
||||
checksum = qToBigEndian(checksum);
|
||||
serialData_.append(reinterpret_cast<char*>(&checksum), 2);
|
||||
}
|
||||
97
sources/DataController.h
Normal file
97
sources/DataController.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef DATACONTROLLER_H
|
||||
#define DATACONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QQmlEngine;
|
||||
class QJSEngine;
|
||||
class QSerialPort;
|
||||
|
||||
class DataController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString ipbsFirstVoltage MEMBER ipbsFirstVoltage_ NOTIFY ipbsFirstVoltageChanged)
|
||||
Q_PROPERTY(QString ipbsFirstCurrent MEMBER ipbsFirstCurrent_ NOTIFY ipbsFirstCurrentChanged)
|
||||
|
||||
Q_PROPERTY(QString ipbsSecondVoltage MEMBER ipbsSecondVoltage_ NOTIFY ipbsSecondVoltageChanged)
|
||||
Q_PROPERTY(QString ipbsSecondCurrent MEMBER ipbsSecondCurrent_ NOTIFY ipbsSecondCurrentChanged)
|
||||
|
||||
Q_PROPERTY(QString ipbsThirdVoltage MEMBER ipbsThirdVoltage_ NOTIFY ipbsThirdVoltageChanged)
|
||||
Q_PROPERTY(QString ipbsThirdCurrent MEMBER ipbsThirdCurrent_ NOTIFY ipbsThirdCurrentChanged)
|
||||
|
||||
Q_PROPERTY(QString mainVoltage MEMBER mainVoltage_ NOTIFY mainVoltageChanged)
|
||||
Q_PROPERTY(int ipbsMode MEMBER ipbsMode_ NOTIFY ipbsModeChanged)
|
||||
|
||||
Q_PROPERTY(QString firstStatus MEMBER firstStatus_ NOTIFY firstStatusChanged)
|
||||
Q_PROPERTY(QString secondStatus MEMBER secondStatus_ NOTIFY secondStatusChanged)
|
||||
|
||||
Q_PROPERTY(QString ainFirstVoltage MEMBER ainFirstVoltage_ NOTIFY ainFirstVoltageChanged)
|
||||
Q_PROPERTY(QString ainFirstCurrent MEMBER ainFirstCurrent_ NOTIFY ainFirstCurrentChanged)
|
||||
|
||||
Q_PROPERTY(QString ainSecondVoltage MEMBER ainSecondVoltage_ NOTIFY ainSecondVoltageChanged)
|
||||
Q_PROPERTY(QString ainSecondCurrent MEMBER ainSecondCurrent_ NOTIFY ainSecondCurrentChanged)
|
||||
|
||||
Q_PROPERTY(QString ainThirdVoltage MEMBER ainThirdVoltage_ NOTIFY ainThirdVoltageChanged)
|
||||
Q_PROPERTY(QString ainThirdCurrent MEMBER ainThirdCurrent_ NOTIFY ainThirdCurrentChanged)
|
||||
|
||||
Q_PROPERTY(QString psnInputVoltage MEMBER psnInputVoltage_ NOTIFY psnInputVoltageChanged)
|
||||
|
||||
public:
|
||||
explicit DataController(QObject* parent = nullptr);
|
||||
~DataController();
|
||||
|
||||
static QObject* qmlInstance(QQmlEngine* engine, QJSEngine* scriptEngine);
|
||||
|
||||
signals:
|
||||
void ipbsFirstVoltageChanged();
|
||||
void ipbsFirstCurrentChanged();
|
||||
void ipbsSecondVoltageChanged();
|
||||
void ipbsSecondCurrentChanged();
|
||||
void ipbsThirdVoltageChanged();
|
||||
void ipbsThirdCurrentChanged();
|
||||
void mainVoltageChanged();
|
||||
void ipbsModeChanged();
|
||||
void firstStatusChanged();
|
||||
void secondStatusChanged();
|
||||
void ainFirstVoltageChanged();
|
||||
void ainFirstCurrentChanged();
|
||||
void ainSecondVoltageChanged();
|
||||
void ainSecondCurrentChanged();
|
||||
void ainThirdVoltageChanged();
|
||||
void ainThirdCurrentChanged();
|
||||
void psnInputVoltageChanged();
|
||||
|
||||
private slots:
|
||||
void serialReadyRead();
|
||||
void serialError();
|
||||
|
||||
private:
|
||||
QVariantMap readSettings();
|
||||
void openSerialPort();
|
||||
void parseSerialData();
|
||||
void mockSerialData();
|
||||
|
||||
QString ipbsFirstVoltage_;
|
||||
QString ipbsFirstCurrent_;
|
||||
QString ipbsSecondVoltage_;
|
||||
QString ipbsSecondCurrent_;
|
||||
QString ipbsThirdVoltage_;
|
||||
QString ipbsThirdCurrent_;
|
||||
QString mainVoltage_;
|
||||
int ipbsMode_ = 0;
|
||||
QString firstStatus_ = " — ";
|
||||
QString secondStatus_ = " — ";
|
||||
QString ainFirstVoltage_;
|
||||
QString ainFirstCurrent_;
|
||||
QString ainSecondVoltage_;
|
||||
QString ainSecondCurrent_;
|
||||
QString ainThirdVoltage_;
|
||||
QString ainThirdCurrent_;
|
||||
QString psnInputVoltage_;
|
||||
|
||||
QByteArray serialData_;
|
||||
QScopedPointer<QSerialPort> serialPort_;
|
||||
};
|
||||
|
||||
#endif // DATACONTROLLER_H
|
||||
72
sources/main.cpp
Normal file
72
sources/main.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <QLocale>
|
||||
#include <QTranslator>
|
||||
#include <QFontDatabase>
|
||||
|
||||
#include "DataController.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
//#endif
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QCoreApplication::setOrganizationName("Tksi");
|
||||
QCoreApplication::setOrganizationDomain("Tksi.rus");
|
||||
QCoreApplication::setApplicationName("Tksi monitor");
|
||||
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Black.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-BlackItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Bold.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-BoldItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Italic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Light.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-LightItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Medium.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-MediumItalic.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Regular.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Thin.ttf");
|
||||
QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-ThinItalic.ttf");
|
||||
|
||||
QTranslator translator;
|
||||
const auto uiLanguages = QLocale::system().uiLanguages();
|
||||
for (const auto& locale : uiLanguages)
|
||||
{
|
||||
const auto baseName = "TksiMonitor_" + QLocale(locale).name();
|
||||
if (translator.load(":/i18n/" + baseName))
|
||||
{
|
||||
app.installTranslator(&translator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
qmlRegisterSingletonType<DataController>("Tksi", 1, 0, "DataController", &DataController::qmlInstance);
|
||||
|
||||
auto isDebug = false;
|
||||
#ifdef QT_DEBUG
|
||||
isDebug = true;
|
||||
#endif
|
||||
engine.rootContext()->setContextProperty("isDebug", isDebug);
|
||||
|
||||
const QUrl url(QStringLiteral("qrc:/main.qml"));
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app,
|
||||
[url](QObject *obj, const QUrl &objUrl)
|
||||
{
|
||||
if (!obj && url == objUrl)
|
||||
{
|
||||
QCoreApplication::exit(-1);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
engine.addImportPath(QStringLiteral("qrc:/"));
|
||||
engine.load(url);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
Reference in New Issue
Block a user