Added first project implementation

This commit is contained in:
Yury Shuvakin
2024-01-22 18:45:09 +09:00
parent 065decd584
commit 9e957f29fe
12 changed files with 893 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
CMakeLists.txt.user

52
CMakeLists.txt Normal file
View File

@@ -0,0 +1,52 @@
cmake_minimum_required(VERSION 3.5)
project(M1300LogViewer VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 REQUIRED COMPONENTS Widgets Charts)
set(PROJECT_SOURCES
main.cpp
MainWindow.cpp
MainWindow.h
MainWindow.ui
DataTypes.h
DataTypes.cpp
LogParser.h
LogParser.cpp
InteractiveChartView.h
InteractiveChartView.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_executable(M1300LogViewer
${PROJECT_SOURCES}
)
target_link_libraries(M1300LogViewer PRIVATE Qt5::Widgets Qt5::Charts)
set_target_properties(M1300LogViewer PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
set(CMAKE_INSTALL_PREFIX ../M1300LogViewerDeploy)
# deploy commands
install(CODE "execute_process(COMMAND ${CMAKE_PREFIX_PATH}/bin/windeployqt.exe --dir ${CMAKE_INSTALL_PREFIX} --no-quick-import --no-translations ${CMAKE_BINARY_DIR}/M1300LogViewer.exe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})")
install(CODE "file(COPY ${CMAKE_BINARY_DIR}/M1300LogViewer.exe DESTINATION ${CMAKE_INSTALL_PREFIX})")
install(CODE "message(\"Installation finished!\")")

120
DataTypes.cpp Normal file
View File

@@ -0,0 +1,120 @@
#include "DataTypes.h"
#include <QObject>
QString DataTypes::messageString(MessageType type)
{
switch (type)
{
case MessageType::LTM_REASON_NONE:
return QObject::tr("No reason", "DataTypes");
case MessageType::LTM_REASON_AFTER_POWER_ON:
return QObject::tr("M1300 Enabling", "DataTypes");
case MessageType::LTM_REASON_NO_CANBUS_WITH_CONTROL_BOARD:
return QObject::tr("No CAN Bus link with PWR", "DataTypes");
case MessageType::LTM_REASON_NO_CANBUS:
return QObject::tr("CAN Bus error with PWR", "DataTypes");
case MessageType::LTM_REASON_NO_INPUT_LONG_TIME:
return QObject::tr("No input voltage long time", "DataTypes");
case MessageType::LTM_REASON_MAS_SHUTDOWN:
return QObject::tr("On any M1300 disabling", "DataTypes");
case MessageType::LTM_REASON_ANY_UNDERVOLTAGE:
return QObject::tr("On any under-voltage", "DataTypes");
case MessageType::LTM_REASON_ANY_OVERVOLTAGE:
return QObject::tr("On any over-voltage", "DataTypes");
case MessageType::LTM_REASON_NOT_ALLOWED_TO_START_INPUT_VOLTAGE_OUT_OF_RANGE:
return QObject::tr("Voltage out of range", "DataTypes");
case MessageType::LTM_REASON_FIRST_START:
return QObject::tr("M1300 First start", "DataTypes");
case MessageType::LTM_REASON_CHECK_BE_K1:
return QObject::tr("K1 Feedback error", "DataTypes");
case MessageType::LTM_REASON_K1_NO_CONTROL_FEEDBACK:
return QObject::tr("K1 Feedback exists without control", "DataTypes");
case MessageType::LTM_REASON_K1_NO_FEEDBACK:
return QObject::tr("K1 Feedback error", "DataTypes");
case MessageType::LTM_REASON_TURN_OFF_DUE_K1_VS_DC_LINK:
return QObject::tr("K1 Enabled, no DC-Link", "DataTypes");
case MessageType::LTM_REASON_K2_WRONG_WAY_WORK:
return QObject::tr("K2 enabled if K1 enabled", "DataTypes");
case MessageType::LTM_REASON_CHECK_BE_K2:
return QObject::tr("K2 Feedback error", "DataTypes");
case MessageType::LTM_REASON_CHECK_TR_FEEDBACK:
return QObject::tr("Protection Block feedback error", "DataTypes");
case MessageType::LTM_REASON_TR_NO_FEEDBACK:
return QObject::tr("Protection Block no feedback", "DataTypes");
case MessageType::LTM_REASON_TR_TEST_FAULT:
return QObject::tr("Protection Block test error", "DataTypes");
case MessageType::LTM_REASON_LOCKED_DUE_TR:
return QObject::tr("Protection Block error", "DataTypes");
case MessageType::LTM_REASON_TURN_OFF_DUE_TR:
return QObject::tr("Protection Block error", "DataTypes");
case MessageType::LTM_REASON_TR_CONNECT_RESISTORS_DUE_LOW_VOLTAGE:
return QObject::tr("Charge resistors enabling on under-voltage", "DataTypes");
case MessageType::LTM_REASON_TURN_OFF_DUE_HIGH_INPUT_VOLTAGE_LONG_TIME:
return QObject::tr("System disabling on over-voltage long time", "DataTypes");
case MessageType::LTM_REASON_TR_CONNECT_RESISTORS_DUE_HIGH_INPUT_VOLTAGE_FAST:
return QObject::tr("Charge resistors enabling on fast over-voltage", "DataTypes");
case MessageType::LTM_REASON_TR_CONNECT_RESISTORS_DUE_HIGH_INPUT_VOLTAGE:
return QObject::tr("Charge resistors enabling on over-voltage", "DataTypes");
case MessageType::LTM_REASON_TURN_OFF_DUE_RESISTORS_ENERGY:
return QObject::tr("System disabling on Charge Resistors over-energy", "DataTypes");
case MessageType::LTM_REASON_TR_CONNECT_RESISTORS_DUE_HIGH_INPUT_CURRENT:
return QObject::tr("Charge resistors enabling on over-current", "DataTypes");
case MessageType::LTM_REASON_TURN_OFF_DUE_INPUT_CURRENT:
return QObject::tr("System disabling on over-current", "DataTypes");
case MessageType::LTM_REASON_HUR_NO_CONNECTION:
return QObject::tr("No CAN Bus link with HUR", "DataTypes");
case MessageType::LTM_REASON_HBU_LOCK_CAUSE_HUR:
return QObject::tr("LTM_REASON_NONE", "DataTypes");
case MessageType::LTM_REASON_HURS_TEMP_HIGH:
return QObject::tr("HUR Slave over-temperature", "DataTypes");
case MessageType::LTM_REASON_HURS_TEMP_DEFEKT:
return QObject::tr("HUR Slave temp sensor fault", "DataTypes");
case MessageType::LTM_REASON_HURM_TEMP_HIGH:
return QObject::tr("HUR Master over-temperature", "DataTypes");
case MessageType::LTM_REASON_HURM_TEMP_DEFEKT:
return QObject::tr("HUR Master temp sensor fault", "DataTypes");
case MessageType::LTM_REASON_HURM_HSS_DEFEKT:
return QObject::tr("HUR Master HSS fault", "DataTypes");
case MessageType::LTM_REASON_HURM_WR_DEFEKT:
return QObject::tr("HUR Master WR fault", "DataTypes");
case MessageType::LTM_REASON_HURS_HSS_DEFEKT:
return QObject::tr("HUR Slave HSS fault", "DataTypes");
case MessageType::LTM_REASON_HURS_WR_DEFEKT:
return QObject::tr("HUR Slave WR fault", "DataTypes");
case MessageType::LTM_REASON_HBU_LOCK_CAUSE_PWR:
return QObject::tr("PWR Fault", "DataTypes");
case MessageType::LTM_REASON_PWR_OVERHEATING:
return QObject::tr("PWR overheat", "DataTypes");
case MessageType::LTM_REASON_PWR_OVERCURRENT_FAST:
return QObject::tr("PWR fast over-current", "DataTypes");
case MessageType::LTM_REASON_PWR_OVERCURRENT_LONG_TIME:
return QObject::tr("PWR long over-current", "DataTypes");
case MessageType::LTM_REASON_PWR_FAULT_1:
return QObject::tr("PWR Phase A Fault", "DataTypes");
case MessageType::LTM_REASON_PWR_FAULT_2:
return QObject::tr("PWR Phase B Fault", "DataTypes");
case MessageType::LTM_REASON_PWR_FAULT_3:
return QObject::tr("PWR Phase C Fault", "DataTypes");
case MessageType::LTM_REASON_PWR_LOCKED:
return QObject::tr("PWR Locked", "DataTypes");
case MessageType::LTM_PARAMS_MSG:
return QObject::tr("Params Msg Status", "DataTypes");
case MessageType::LTM_PARAMS_OUT:
return QObject::tr("Params Msg Outs", "DataTypes");
case MessageType::LTM_PARAMS_ADC:
return QObject::tr("Params Msg ADC", "DataTypes");
default:
break;
}
return {};
}
bool DataTypes::isErrorMessage(MessageType type)
{
return type != MessageType::LTM_REASON_NONE &&
type != MessageType::LTM_PARAMS_MSG &&
type != MessageType::LTM_PARAMS_OUT &&
type != MessageType::LTM_PARAMS_ADC;
}

77
DataTypes.h Normal file
View File

@@ -0,0 +1,77 @@
#ifndef DATATYPES_H
#define DATATYPES_H
#include <QDateTime>
namespace DataTypes
{
enum class MessageType
{
LTM_REASON_NONE = 0, ///< No reason
LTM_REASON_AFTER_POWER_ON = 1, ///< [Unused] M1300 Enabling
LTM_REASON_NO_CANBUS_WITH_CONTROL_BOARD = 2, ///< No CAN Bus link with PWR
LTM_REASON_NO_CANBUS = 3, ///< CAN Bus error with PWR
LTM_REASON_NO_INPUT_LONG_TIME = 4, ///< No input voltage long time
LTM_REASON_MAS_SHUTDOWN = 5, ///< On any M1300 disabling
LTM_REASON_ANY_UNDERVOLTAGE = 6, ///< On any under-voltage
LTM_REASON_ANY_OVERVOLTAGE = 7, ///< On any over-voltage
LTM_REASON_NOT_ALLOWED_TO_START_INPUT_VOLTAGE_OUT_OF_RANGE = 8, ///< Voltage out of range
LTM_REASON_FIRST_START = 9, ///< M1300 First start
LTM_REASON_CHECK_BE_K1 = 10, ///< K1 Feedback error
LTM_REASON_K1_NO_CONTROL_FEEDBACK = 11, ///< K1 Feedback exists without control
LTM_REASON_K1_NO_FEEDBACK = 12, ///< K1 Feedback error
LTM_REASON_TURN_OFF_DUE_K1_VS_DC_LINK = 13, ///< K1 Enabled, no DC-Link
LTM_REASON_K2_WRONG_WAY_WORK = 14, ///< K2 enabled if K1 enabled
LTM_REASON_CHECK_BE_K2 = 15, ///< K2 Feedback error
LTM_REASON_CHECK_TR_FEEDBACK = 16, ///< Protection Block feedback error
LTM_REASON_TR_NO_FEEDBACK = 17, ///< Protection Block no feedback
LTM_REASON_TR_TEST_FAULT = 18, ///< Protection Block test error
LTM_REASON_LOCKED_DUE_TR = 19, ///< [Unused] Protection Block error
LTM_REASON_TURN_OFF_DUE_TR = 20, ///< Protection Block error
LTM_REASON_TR_CONNECT_RESISTORS_DUE_LOW_VOLTAGE = 21, ///< Charge resistors enabling on under-voltage
LTM_REASON_TURN_OFF_DUE_HIGH_INPUT_VOLTAGE_LONG_TIME = 22, ///< System disabling on over-voltage long time
LTM_REASON_TR_CONNECT_RESISTORS_DUE_HIGH_INPUT_VOLTAGE_FAST = 23, ///< Charge resistors enabling on fast over-voltage
LTM_REASON_TR_CONNECT_RESISTORS_DUE_HIGH_INPUT_VOLTAGE = 24, ///< Charge resistors enabling on over-voltage
LTM_REASON_TURN_OFF_DUE_RESISTORS_ENERGY = 25, ///< System disabling on Charge Resistors over-energy
LTM_REASON_TR_CONNECT_RESISTORS_DUE_HIGH_INPUT_CURRENT = 26, ///< Charge resistors enabling on over-current
LTM_REASON_TURN_OFF_DUE_INPUT_CURRENT = 27, ///< System disabling on over-current
LTM_REASON_HUR_NO_CONNECTION = 28, ///< No CAN Bus link with HUR
LTM_REASON_HBU_LOCK_CAUSE_HUR = 29, ///< HUR fault
LTM_REASON_HURS_TEMP_HIGH = 30, ///< HUR Slave over-temperature
LTM_REASON_HURS_TEMP_DEFEKT = 31, ///< HUR Slave temp sensor fault
LTM_REASON_HURM_TEMP_HIGH = 32, ///< HUR Master over-temperature
LTM_REASON_HURM_TEMP_DEFEKT = 33, ///< HUR Master temp sensor fault
LTM_REASON_HURM_HSS_DEFEKT = 34, ///< HUR Master HSS fault
LTM_REASON_HURM_WR_DEFEKT = 35, ///< HUR Master WR fault
LTM_REASON_HURS_HSS_DEFEKT = 36, ///< HUR Slave HSS fault
LTM_REASON_HURS_WR_DEFEKT = 37, ///< HUR Slave WR fault
LTM_REASON_HBU_LOCK_CAUSE_PWR = 38, ///< PWR Fault
LTM_REASON_PWR_OVERHEATING = 39, ///< PWR overheat
LTM_REASON_PWR_OVERCURRENT_FAST = 40, ///< PWR fast over-current
LTM_REASON_PWR_OVERCURRENT_LONG_TIME = 41, ///< PWR long over-current
LTM_REASON_PWR_FAULT_1 = 42, ///< PWR Phase A Fault
LTM_REASON_PWR_FAULT_2 = 43, ///< PWR Phase B Fault
LTM_REASON_PWR_FAULT_3 = 44, ///< PWR Phase C Fault
LTM_REASON_PWR_LOCKED = 45, ///< PWR Locked
LTM_PARAMS_MSG = 0xFF-3, // Params Msg Status
LTM_PARAMS_OUT = 0xFF-2, // Params Msg Outs
LTM_PARAMS_ADC = 0xFF-1, // Params Msg ADC
};
struct LogMessage
{
QDateTime dateTime;
quint64 startupTime;
MessageType type;
qint64 f1;
qint64 f2;
qint64 f3;
qint64 f4;
};
QString messageString(MessageType type);
bool isErrorMessage(MessageType type);
}
#endif // DATATYPES_H

22
InteractiveChartView.cpp Normal file
View File

@@ -0,0 +1,22 @@
#include "InteractiveChartView.h"
void InteractiveChartView::wheelEvent(QWheelEvent* event)
{
qreal factor;
if (event->delta() > 0)
factor = 2.0;
else
factor = 0.5;
QRectF r = QRectF(chart()->plotArea().left(),
chart()->plotArea().top(),
chart()->plotArea().width() / factor,
chart()->plotArea().height() / factor);
QPointF mousePos = mapFromGlobal(QCursor::pos());
r.moveCenter(mousePos);
chart()->zoomIn(r);
QPointF delta = chart()->plotArea().center() - mousePos;
chart()->scroll(delta.x(), -delta.y());
QChartView::wheelEvent(event);
}

19
InteractiveChartView.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef INTERACTIVECHARTVIEW_H
#define INTERACTIVECHARTVIEW_H
#include <QChartView>
class InteractiveChartView : public QtCharts::QChartView
{
Q_OBJECT
public:
using QChartView::QChartView;
protected:
void wheelEvent(QWheelEvent* event) override;
private:
qreal factor = 1.0;
};
#endif // INTERACTIVECHARTVIEW_H

112
LogParser.cpp Normal file
View File

@@ -0,0 +1,112 @@
#include "LogParser.h"
#include <QDir>
#include <QFile>
#include <QDebug>
LogParser::LogParser(QObject* parent)
: QObject{parent}
{
logFolder = "C:/Users/Yury/Documents/M1300LogFolder";
}
LogParser::~LogParser()
{
}
void LogParser::setLogFolder(const QString& folder)
{
logFolder = folder;
}
void LogParser::setStartDateTime(const QDateTime& dateTime)
{
startDateTime = dateTime;
}
void LogParser::setEndDateTime(const QDateTime& dateTime)
{
endDateTime = dateTime;
}
QString LogParser::getLogFolder() const
{
return logFolder;
}
QDateTime LogParser::getStartDateTime() const
{
return startDateTime;
}
QDateTime LogParser::getEndDateTime() const
{
return endDateTime;
}
QStringList LogParser::logFilesByDateTime() const
{
QStringList files;
for (const auto& fileInfo: QDir(logFolder).entryInfoList())
{
const auto fileTime = fileInfo.baseName();
auto date = QDateTime::fromString(fileTime, "yyMMdd_hhmmss");
if (date.date().year() < 2000)
{
date = date.addYears(100);
}
if (date.isValid() && date >= startDateTime && date <= endDateTime)
{
files.append(fileInfo.absoluteFilePath());
}
}
return files;
}
QList<DataTypes::LogMessage> LogParser::logMessagesByDateTime() const
{
QList<DataTypes::LogMessage> logMessages;
const auto logFiles = logFilesByDateTime();
for (const auto& logFile: logFiles)
{
QFile file(logFile);
if (!file.open(QFile::ReadOnly))
{
qWarning() << "Can't open" << logFile;
continue;
}
while (!file.atEnd())
{
const auto line = QString::fromUtf8(file.readLine());
if (line.startsWith("RTC"))
{
continue;
}
const auto parameters = line.split(';');
if (parameters.size() < 7)
{
continue;
}
DataTypes::LogMessage message;
message.dateTime = QDateTime::fromSecsSinceEpoch(parameters.at(0).toULongLong());
message.startupTime = parameters.at(1).toULongLong();
message.type = static_cast<DataTypes::MessageType>(parameters.at(2).toUInt());
message.f1 = parameters.at(3).toLongLong();
message.f2 = parameters.at(4).toLongLong();
message.f3 = parameters.at(5).toLongLong();
message.f4 = parameters.at(6).toLongLong();
// qDebug() << message.dateTime << message.startupTime << int(message.type);
logMessages.append(message);
}
}
return logMessages;
}

33
LogParser.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef LOGPARSER_H
#define LOGPARSER_H
#include <QObject>
#include "DataTypes.h"
class LogParser : public QObject
{
Q_OBJECT
public:
explicit LogParser(QObject* parent = nullptr);
~LogParser();
public slots:
void setLogFolder(const QString& folder);
void setStartDateTime(const QDateTime& dateTime);
void setEndDateTime(const QDateTime& dateTime);
public:
QString getLogFolder() const;
QDateTime getStartDateTime() const;
QDateTime getEndDateTime() const;
QStringList logFilesByDateTime() const;
QList<DataTypes::LogMessage> logMessagesByDateTime() const;
private:
QString logFolder;
QDateTime startDateTime;
QDateTime endDateTime;
};
#endif // LOGPARSER_H

211
MainWindow.cpp Normal file
View File

@@ -0,0 +1,211 @@
#include "MainWindow.h"
#include "./ui_MainWindow.h"
#include "LogParser.h"
#include <QStandardItemModel>
#include <QStorageInfo>
#include <QFileDialog>
#include <QChart>
#include <QLineSeries>
#include <QDebug>
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, logParser(new LogParser)
, logItemModel(new QStandardItemModel)
, inputChart(new QtCharts::QChart)
, outputChart(new QtCharts::QChart)
, adcChart(new QtCharts::QChart)
{
ui->setupUi(this);
for (const auto& volume: QStorageInfo::mountedVolumes())
{
if (volume.displayName().contains("Drive"))
{
logParser->setLogFolder(volume.rootPath());
}
qDebug() << volume.device() << volume.displayName() << volume.fileSystemType()
<< volume.name() << volume.rootPath() << volume.subvolume();
}
if (logParser->getLogFolder().isEmpty())
{
logParser->setLogFolder(QDir::homePath());
}
ui->startDateTimeEdit->setDateTime(QDateTime::currentDateTime().addMonths(-3));
ui->endDateTimeEdit->setDateTime(QDateTime::currentDateTime());
logParser->setStartDateTime(ui->startDateTimeEdit->dateTime());
logParser->setEndDateTime(ui->endDateTimeEdit->dateTime());
const QStringList labels =
{
tr("Date"), tr("Startup time"), tr("Type"), tr("F1"), tr("F2"), tr("F3"), tr("F4"), tr("Description")
};
logItemModel->setHorizontalHeaderLabels(labels);
ui->logTableView->setModel(logItemModel.get());
ui->logTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->logTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->logTableView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->inputChartView->setRenderHint(QPainter::Antialiasing);
ui->inputChartView->setChart(inputChart.data());
ui->inputChartView->setRubberBand(QtCharts::QChartView::RectangleRubberBand);
ui->outputChartView->setRenderHint(QPainter::Antialiasing);
ui->outputChartView->setChart(outputChart.data());
ui->outputChartView->setRubberBand(QtCharts::QChartView::RectangleRubberBand);
ui->adcChartView->setRenderHint(QPainter::Antialiasing);
ui->adcChartView->setChart(adcChart.data());
ui->adcChartView->setRubberBand(QtCharts::QChartView::RectangleRubberBand);
ui->pathLineEdit->setText(logParser->getLogFolder());
ui->pathLineEdit->setReadOnly(true);
connect(ui->applyDateTimeButton, &QPushButton::clicked, this, &MainWindow::applyDateTimeFilter);
connect(ui->browseButton, &QPushButton::clicked, this, &MainWindow::changePath);
updateLogMessages();
}
MainWindow::~MainWindow()
{
}
void MainWindow::changePath()
{
const auto directory = QFileDialog::getExistingDirectory(this, tr("Choose log folder"));
if (directory.isEmpty())
{
return;
}
ui->pathLineEdit->setText(directory);
logParser->setLogFolder(directory);
updateLogMessages();
}
void MainWindow::applyDateTimeFilter()
{
logParser->setStartDateTime(ui->startDateTimeEdit->dateTime());
logParser->setEndDateTime(ui->endDateTimeEdit->dateTime());
updateLogMessages();
}
void MainWindow::updateLogMessages()
{
logMessages = logParser->logMessagesByDateTime();
updateLogTable();
updateCharts();
}
void MainWindow::updateLogTable()
{
logItemModel->removeRows(0, logItemModel->rowCount());
for (const auto& message: qAsConst(logMessages))
{
if (!DataTypes::isErrorMessage(message.type))
{
continue;
}
auto dateItem = new QStandardItem();
dateItem->setData(message.dateTime, Qt::DisplayRole);
auto startupItem = new QStandardItem();
startupItem->setData(message.startupTime, Qt::DisplayRole);
auto typeItem = new QStandardItem();
typeItem->setData(static_cast<int>(message.type), Qt::DisplayRole);
auto f1Item = new QStandardItem();
f1Item->setData(message.f1, Qt::DisplayRole);
auto f2Item = new QStandardItem();
f2Item->setData(message.f2, Qt::DisplayRole);
auto f3Item = new QStandardItem();
f3Item->setData(message.f3, Qt::DisplayRole);
auto f4Item = new QStandardItem();
f4Item->setData(message.f4, Qt::DisplayRole);
auto descriptionItem = new QStandardItem();
descriptionItem->setData(DataTypes::messageString(message.type), Qt::DisplayRole);
logItemModel->appendRow({dateItem, startupItem, typeItem, f1Item, f2Item, f3Item, f4Item, descriptionItem});
}
ui->logTableView->resizeColumnsToContents();
}
void MainWindow::updateCharts()
{
updateChart(inputChart.get(), [](const DataTypes::LogMessage& message){ return message.type == DataTypes::MessageType::LTM_PARAMS_MSG; });
updateChart(outputChart.get(), [](const DataTypes::LogMessage& message){ return message.type == DataTypes::MessageType::LTM_PARAMS_OUT; });
updateChart(adcChart.get(), [](const DataTypes::LogMessage& message){ return message.type == DataTypes::MessageType::LTM_PARAMS_ADC; });
}
void MainWindow::updateChart(QtCharts::QChart* chart, std::function<bool (const DataTypes::LogMessage&)> condition)
{
QList<QPointF> voltagePoints;
QList<QPointF> currentPoints;
for (const auto& message: qAsConst(logMessages))
{
if (condition(message))
{
voltagePoints.append({static_cast<qreal>(message.startupTime), static_cast<qreal>(message.f1)});
currentPoints.append({static_cast<qreal>(message.startupTime), static_cast<qreal>(message.f2)});
}
}
QPen yellowPen(Qt::yellow);
yellowPen.setWidth(3);
QPen redPen(Qt::red);
redPen.setWidth(3);
auto voltageSeries = new QtCharts::QLineSeries();
voltageSeries->setPen(yellowPen);
voltageSeries->append(voltagePoints);
voltageSeries->setName(tr("Voltage"));
auto currentSeries = new QtCharts::QLineSeries();
currentSeries->setPen(redPen);
currentSeries->append(currentPoints);
currentSeries->setName(tr("Current"));
clearChart(chart);
chart->addSeries(voltageSeries);
chart->addSeries(currentSeries);
chart->createDefaultAxes();
}
void MainWindow::clearChart(QtCharts::QChart* chart)
{
for (auto series: chart->series())
{
chart->removeSeries(series);
delete series;
}
for (auto axis: chart->axes())
{
chart->removeAxis(axis);
delete axis;
}
}

50
MainWindow.h Normal file
View File

@@ -0,0 +1,50 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "DataTypes.h"
class QStandardItemModel;
class LogParser;
namespace QtCharts
{
class QChart;
}
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void changePath();
void applyDateTimeFilter();
void updateLogMessages();
void updateLogTable();
void updateCharts();
private:
void updateChart(QtCharts::QChart* chart, std::function<bool(const DataTypes::LogMessage&)> condition);
void clearChart(QtCharts::QChart* chart);
QScopedPointer<Ui::MainWindow> ui;
QScopedPointer<LogParser> logParser;
QScopedPointer<QStandardItemModel> logItemModel;
QList<DataTypes::LogMessage> logMessages;
QScopedPointer<QtCharts::QChart> inputChart;
QScopedPointer<QtCharts::QChart> outputChart;
QScopedPointer<QtCharts::QChart> adcChart;
};
#endif // MAINWINDOW_H

184
MainWindow.ui Normal file
View File

@@ -0,0 +1,184 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>M1300 Log Viewer</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_2" rowstretch="1,1">
<property name="spacing">
<number>10</number>
</property>
<item row="0" column="0" rowspan="2">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Date and time range</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="spacing">
<number>10</number>
</property>
<item row="1" column="1">
<widget class="QDateTimeEdit" name="endDateTimeEdit">
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>End:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="applyDateTimeButton">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Start:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDateTimeEdit" name="startDateTimeEdit">
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Log location</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="spacing">
<number>10</number>
</property>
<item row="0" column="1">
<widget class="QLineEdit" name="pathLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="browseButton">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Path:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QTableView" name="logTableView"/>
</item>
<item row="1" column="1">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="inputTab">
<attribute name="title">
<string>Input parameters</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="InteractiveChartView" name="inputChartView"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="outputTab">
<attribute name="title">
<string>Output parameters</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="InteractiveChartView" name="outputChartView"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="adcTab">
<attribute name="title">
<string>ADC data</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="InteractiveChartView" name="adcChartView"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>InteractiveChartView</class>
<extends>QGraphicsView</extends>
<header>InteractiveChartView.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

11
main.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}