Add new frame identification system to address #35

This commit is contained in:
Alex Spataru 2021-02-18 00:46:21 -05:00
parent 56d9ce101a
commit 4a42742956
13 changed files with 307 additions and 124 deletions

View File

@ -147,6 +147,7 @@ HEADERS += \
src/IO/Manager.h \
src/JSON/Dataset.h \
src/JSON/Frame.h \
src/JSON/FrameInfo.h \
src/JSON/Generator.h \
src/JSON/Group.h \
src/Misc/ModuleManager.h \
@ -167,6 +168,7 @@ SOURCES += \
src/IO/Manager.cpp \
src/JSON/Dataset.cpp \
src/JSON/Frame.cpp \
src/JSON/FrameInfo.cpp \
src/JSON/Generator.cpp \
src/JSON/Group.cpp \
src/Misc/ModuleManager.cpp \

View File

@ -51,11 +51,11 @@ Export::Export()
: m_exportEnabled(true)
{
auto io = IO::Manager::getInstance();
auto jp = JSON::Generator::getInstance();
auto ge = JSON::Generator::getInstance();
auto te = Misc::TimerEvents::getInstance();
connect(io, &IO::Manager::connectedChanged, this, &Export::closeFile);
connect(jp, &JSON::Generator::jsonChanged, this, &Export::updateValues);
connect(te, &Misc::TimerEvents::timeout1Hz, this, &Export::writeValues);
connect(ge, &JSON::Generator::jsonChanged, this, &Export::registerFrame);
LOG_TRACE() << "Class initialized";
}
@ -142,25 +142,15 @@ void Export::closeFile()
*/
void Export::writeValues()
{
// Bubble-sort the JSON frames so that they are ordered from earliest to most recent
for (int i = 0; i < m_jsonList.count() - 1; ++i)
{
for (int j = 0; j < m_jsonList.count() - i - 1; ++j)
{
auto dateTimeA = m_jsonList.at(j + 0).first;
auto dateTimeB = m_jsonList.at(j + 1).first;
if (dateTimeA > dateTimeB)
m_jsonList.swapItemsAt(j, j + 1);
}
}
// Sort JSON frames so that they are ordered from least-recent to most-recent
JFI_SortList(&m_jsonList);
// Export JSON frames
for (int k = 0; k < m_jsonList.count(); ++k)
{
// Get project title & cell values
auto json = m_jsonList.first().second;
auto dateTime = m_jsonList.first().first;
auto dateTime = m_jsonList.first().rxDateTime;
auto json = m_jsonList.first().jsonDocument.object();
auto projectTitle = json.value("t").toVariant().toString();
// Validate JSON & title
@ -282,10 +272,10 @@ void Export::writeValues()
}
/**
* Obtains the latest JSON dataframe & appends it to the JSON list
* (which is later read & written to the CSV file).
* Obtains the latest JSON dataframe & appends it to the JSON list, which is later read,
* sorted and written to the CSV file by the @c writeValues() function.
*/
void Export::updateValues(const QJsonDocument &document, const QDateTime &time)
void Export::registerFrame(const JFI_Object &info)
{
// Ignore if device is not connected (we don't want to generate a CSV file when we
// are reading another CSV file don't we?)
@ -296,12 +286,7 @@ void Export::updateValues(const QJsonDocument &document, const QDateTime &time)
if (!exportEnabled())
return;
// Get & validate JSON document
auto json = document.object();
if (json.isEmpty())
return;
// Update JSON list
auto pair = qMakePair<QDateTime, QJsonObject>(time, json);
m_jsonList.append(pair);
if (JFI_Valid(info))
m_jsonList.append(info);
}

View File

@ -29,6 +29,7 @@
#include <QVariant>
#include <QTextStream>
#include <QJsonObject>
#include <JSON/FrameInfo.h>
namespace CSV
{
@ -66,13 +67,13 @@ public slots:
private slots:
void writeValues();
void updateValues(const QJsonDocument &document, const QDateTime &time);
void registerFrame(const JFI_Object &info);
private:
QFile m_csvFile;
bool m_exportEnabled;
QTextStream m_textStream;
QList<QPair<QDateTime, QJsonObject>> m_jsonList;
QList<JFI_Object> m_jsonList;
};
}

View File

@ -379,7 +379,7 @@ void Player::updateData()
// input source for the QML bridge
auto json = getJsonFrame(framePosition() + 1);
if (!json.isEmpty())
JSON::Generator::getInstance()->setJsonDocument(json);
JSON::Generator::getInstance()->loadJSON(json);
// If the user wants to 'play' the CSV, get time difference between this
// frame and the next frame & schedule an automated update

80
src/JSON/FrameInfo.cpp Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "FrameInfo.h"
/**
* Returns @c true if the given JFI @info structure has a non-empty JSON document and a
* valid frame number.
*/
bool JFI_Valid(const JFI_Object &info)
{
return info.frameNumber >= 0 && !info.jsonDocument.isEmpty();
}
/**
* Orders the given JFI @c list from least recent (first item) to most recent (last item)
* using a simple Bubble-Sort algorithm.
*/
void JFI_SortList(QList<JFI_Object> *list)
{
Q_ASSERT(list);
for (int i = 0; i < list->count() - 1; ++i)
{
for (int j = 0; j < list->count() - i - 1; ++j)
{
auto frameA = list->at(j + 0).frameNumber;
auto frameB = list->at(j + 1).frameNumber;
if (frameA >= frameB)
list->swapItemsAt(j, j + 1);
}
}
}
/**
* Creates an empty JFI structure with the current system date/time and frame number @c n
*/
JFI_Object JFI_Empty(const quint64 n)
{
JFI_Object info;
info.frameNumber = n;
info.rxDateTime = QDateTime::currentDateTime();
return info;
}
/**
* Creates a new JFI structure with the given information
*
* @param n frame number
* @param t date/time
* @param d JSON document
*/
JFI_Object JFI_CreateNew(const quint64 n, const QDateTime &t, const QJsonDocument &d)
{
JFI_Object info;
info.rxDateTime = t;
info.frameNumber = n;
info.jsonDocument = d;
return info;
}

83
src/JSON/FrameInfo.h Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef JSON_FRAME_INFO_H
#define JSON_FRAME_INFO_H
#include <QList>
#include <QDateTime>
#include <QJsonDocument>
/**
* Defines a JSON frame information structure. We need to use this in order to be able
* to correctly process all received frames in a thread-worker manner.
*
* Every time we receive a frame from the serial/network device, we generate the JSON
* in another thread in order to avoid putting to much pressure in the main (UI) thread.
*
* This results in a perceived increase of application performance. However, since each
* JSON frame is generated in a different worker thread, the main thread may not receive
* JSON data in the correct order.
*
* To mitigate this, we create this structure, which contains the following information:
* - Frame number (assigned by the JSON::Generator class when raw frame data is
* received, and before the JSON object is genereated/parsed).
* - RX date/time (assigned in the same manner as the frame number).
* - JSON document/object (which contains all the frame information + what we should
* do with it).
*
* We need to register the frame number because (in some cases), the RX date/time will be
* the same between two or more frames (e.g. if you have a very high baud rate, there is
* a chance that frames will be registered with the same rx date/time down to the
* millisecond, this was the root cause of bug #35).
*
* To mitigate this, we simply increment the frame number each time that we receive a raw
* frame. Frame numbers are registered as a uint64_t for this very reason (it would take
* about 585 years to overflow this variable, if you had a computer that was able to
* process a frame every nanosecond).
*
* Frame number is reset when the device connection state is changed.
*/
typedef struct
{
quint64 frameNumber;
QDateTime rxDateTime;
QJsonDocument jsonDocument;
} JFI_Object;
//----------------------------------------------------------------------------------------
// Convenience functions
//----------------------------------------------------------------------------------------
extern bool JFI_Valid(const JFI_Object &info);
extern void JFI_SortList(QList<JFI_Object> *list);
extern JFI_Object JFI_Empty(const quint64 n = 0);
extern JFI_Object JFI_CreateNew(const quint64 n, const QDateTime &t,
const QJsonDocument &d);
/*
* Important magic to be able to use JFI structures in Qt signals/slots
*/
Q_DECLARE_METATYPE(JFI_Object)
#endif

View File

@ -48,7 +48,8 @@ static const QRegExp UNMATCHED_VALUES_REGEX("(%\b([0-9]|[1-9][0-9])\b)");
* Initializes the JSON Parser class and connects appropiate SIGNALS/SLOTS
*/
Generator::Generator()
: m_opMode(kAutomatic)
: m_frameCount(0)
, m_opMode(kAutomatic)
{
auto io = IO::Manager::getInstance();
auto cp = CSV::Player::getInstance();
@ -79,14 +80,6 @@ QString Generator::jsonMapData() const
return m_jsonMapData;
}
/**
* Returns the parsed JSON document from the received packet
*/
QJsonDocument Generator::document() const
{
return m_document;
}
/**
* Returns the file name (e.g. "JsonMap.json") of the loaded JSON map file
*/
@ -247,22 +240,20 @@ void Generator::writeSettings(const QString &path)
}
/**
* Changes the JSON document to be used to generate the user interface.
* This function is set to public in order to allow the CSV-replay feature to
* work by replacing the data/json input source.
* Notifies the rest of the application that a new JSON frame has been received. The JFI
* also contains RX date/time and frame number.
*
* Read the "FrameInfo.h" file for more information.
*/
void Generator::setJsonDocument(const QJsonDocument &document, const QDateTime &time)
void Generator::loadJFI(const JFI_Object &info)
{
if (document.object().isEmpty())
return;
bool csvOpen = CSV::Player::getInstance()->isOpen();
bool devOpen = IO::Manager::getInstance()->connected();
if (csvOpen || devOpen)
{
m_document = document;
emit jsonChanged(document, time);
if (JFI_Valid(info))
emit jsonChanged(info);
}
else
@ -270,13 +261,22 @@ void Generator::setJsonDocument(const QJsonDocument &document, const QDateTime &
}
/**
* Resets all the statistics related to the current serial port device and
* the JSON map file
* Create a new JFI event with the given @a JSON document and increment the frame count
*/
void Generator::loadJSON(const QJsonDocument &json)
{
auto jfi = JFI_CreateNew(m_frameCount, QDateTime::currentDateTime(), json);
m_frameCount++;
loadJFI(jfi);
}
/**
* Resets all the statistics related to the current device and the JSON map file
*/
void Generator::reset()
{
m_document = QJsonDocument::fromJson(QByteArray("{}"));
emit jsonChanged(document(), QDateTime::currentDateTime());
m_frameCount = 0;
emit jsonChanged(JFI_Empty());
}
/**
@ -302,15 +302,18 @@ void Generator::readData(const QByteArray &data)
if (data.isEmpty())
return;
// Increment received frames
m_frameCount++;
// Create new worker thread to read JSON data
QThread *thread = new QThread;
JSONWorker *worker = new JSONWorker(data, QDateTime::currentDateTime());
JSONWorker *worker = new JSONWorker(data, m_frameCount, QDateTime::currentDateTime());
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(worker, &JSONWorker::jsonReady, this, &Generator::setJsonDocument);
connect(worker, &JSONWorker::jsonReady, this, &Generator::loadJFI);
thread->start();
}
@ -322,9 +325,10 @@ void Generator::readData(const QByteArray &data)
* Constructor function, stores received frame data & the date/time that the frame data
* was received.
*/
JSONWorker::JSONWorker(const QByteArray &data, const QDateTime &time)
JSONWorker::JSONWorker(const QByteArray &data, const quint64 frame, const QDateTime &time)
: m_time(time)
, m_data(data)
, m_frame(frame)
, m_engine(nullptr)
{
}
@ -436,7 +440,7 @@ void JSONWorker::process()
// No parse error, update UI & reset error counter
if (error.error == QJsonParseError::NoError)
emit jsonReady(document, m_time);
emit jsonReady(JFI_CreateNew(m_frame, m_time, document));
// Delete object in 500 ms
QTimer::singleShot(500, this, SIGNAL(finished()));

View File

@ -23,6 +23,7 @@
#ifndef JSON_GENERATOR_H
#define JSON_GENERATOR_H
#include <QPair>
#include <QFile>
#include <QTimer>
#include <QObject>
@ -37,6 +38,7 @@
#include <QJsonDocument>
#include "Frame.h"
#include "FrameInfo.h"
namespace JSON
{
@ -46,10 +48,10 @@ class JSONWorker : public QObject
signals:
void finished();
void jsonReady(const QJsonDocument &document, const QDateTime &time);
void jsonReady(const JFI_Object &info);
public:
JSONWorker(const QByteArray &data, const QDateTime &time);
JSONWorker(const QByteArray &data, const quint64 frame, const QDateTime &time);
public slots:
void process();
@ -57,6 +59,7 @@ public slots:
private:
QDateTime m_time;
QByteArray m_data;
quint64 m_frame;
QJSEngine *m_engine;
};
@ -79,7 +82,7 @@ class Generator : public QObject
signals:
void jsonFileMapChanged();
void operationModeChanged();
void jsonChanged(const QJsonDocument &document, const QDateTime &time);
void jsonChanged(const JFI_Object &info);
public:
enum OperationMode
@ -93,7 +96,6 @@ public:
static Generator *getInstance();
QString jsonMapData() const;
QJsonDocument document() const;
QString jsonMapFilename() const;
QString jsonMapFilepath() const;
OperationMode operationMode() const;
@ -108,21 +110,20 @@ private:
public slots:
void readSettings();
void loadJFI(const JFI_Object &info);
void writeSettings(const QString &path);
void setJsonDocument(const QJsonDocument &document,
const QDateTime &time = QDateTime::currentDateTime());
void loadJSON(const QJsonDocument &json);
private slots:
void reset();
void readData(const QByteArray &data);
private:
Frame m_frame;
QFile m_jsonMap;
quint64 m_frameCount;
QSettings m_settings;
QString m_jsonMapData;
OperationMode m_opMode;
QJsonDocument m_document;
QThread m_workerThread;
JSONWorker *m_jsonWorker;

View File

@ -36,6 +36,7 @@
#include <JSON/Group.h>
#include <JSON/Dataset.h>
#include <JSON/Generator.h>
#include <JSON/FrameInfo.h>
#include <IO/Manager.h>
#include <IO/Console.h>
@ -103,7 +104,7 @@ void ModuleManager::configureUpdater()
void ModuleManager::registerQmlTypes()
{
LOG_TRACE() << "Registering QML types...";
qRegisterMetaType<JSON::Frame>("Frame");
qRegisterMetaType<JFI_Object>("JFI_Object");
qmlRegisterType<JSON::Group>("SerialStudio", 1, 0, "Group");
qmlRegisterType<JSON::Dataset>("SerialStudio", 1, 0, "Dataset");
qmlRegisterType<UI::QmlPlainTextEdit>("SerialStudio", 1, 0, "QmlPlainTextEdit");

View File

@ -42,6 +42,7 @@ static DataProvider *INSTANCE = nullptr;
*/
DataProvider::DataProvider()
{
m_latestJsonFrame = JFI_Empty();
auto cp = CSV::Player::getInstance();
auto io = IO::Manager::getInstance();
auto ge = JSON::Generator::getInstance();
@ -118,8 +119,7 @@ void DataProvider::resetData()
return;
// Make latest frame invalid
m_latestJsonFrame
= qMakePair<QDateTime, QJsonObject>(QDateTime::currentDateTime(), QJsonObject());
m_latestJsonFrame = JFI_Empty();
// Update UI
emit updated();
@ -131,7 +131,7 @@ void DataProvider::resetData()
*/
void DataProvider::updateData()
{
if (m_latestFrame.read(m_latestJsonFrame.second))
if (m_latestFrame.read(m_latestJsonFrame.jsonDocument.object()))
emit updated();
}
@ -139,15 +139,14 @@ void DataProvider::updateData()
* Ensures that only the most recent JSON document will be displayed on the user
* interface.
*/
void DataProvider::selectLatestJSON(const QJsonDocument &document, const QDateTime &time)
void DataProvider::selectLatestJSON(const JFI_Object &frameInfo)
{
if (m_latestJsonFrame.first < time)
{
auto json = document.object();
if (json.isEmpty())
return;
auto frameCount = frameInfo.frameNumber;
auto currFrameCount = m_latestJsonFrame.frameNumber;
auto pair = qMakePair<QDateTime, QJsonObject>(time, json);
m_latestJsonFrame = pair;
if (currFrameCount < frameCount)
{
if (JFI_Valid(frameInfo))
m_latestJsonFrame = frameInfo;
}
}

View File

@ -25,6 +25,7 @@
#include <QObject>
#include <JSON/Frame.h>
#include <JSON/FrameInfo.h>
namespace UI
{
@ -61,11 +62,11 @@ private:
private slots:
void resetData();
void updateData();
void selectLatestJSON(const QJsonDocument &document, const QDateTime &time);
void selectLatestJSON(const JFI_Object &frameInfo);
private:
JSON::Frame m_latestFrame;
QPair<QDateTime, QJsonObject> m_latestJsonFrame;
JFI_Object m_latestJsonFrame;
};
}

View File

@ -31,6 +31,7 @@
#include <CSV/Player.h>
#include <IO/Manager.h>
#include <IO/Console.h>
#include <JSON/Generator.h>
#include <ConsoleAppender.h>
#include <Misc/TimerEvents.h>
@ -67,10 +68,12 @@ GraphProvider::GraphProvider()
// Module signals/slots
auto cp = CSV::Player::getInstance();
auto io = IO::Manager::getInstance();
auto ge = JSON::Generator::getInstance();
auto te = Misc::TimerEvents::getInstance();
connect(cp, SIGNAL(openChanged()), this, SLOT(resetData()));
connect(te, SIGNAL(timeout42Hz()), this, SLOT(drawGraphs()));
connect(io, SIGNAL(connectedChanged()), this, SLOT(resetData()));
connect(ge, &JSON::Generator::jsonChanged, this, &GraphProvider::registerFrame);
// Avoid issues when CSV player goes backwards
connect(CSV::Player::getInstance(), SIGNAL(timestampChanged()),
@ -243,59 +246,69 @@ void GraphProvider::resetData()
*/
void GraphProvider::drawGraphs()
{
// Clear dataset & latest values list
m_datasets.clear();
// Sort JSON frames so that they are ordered from least-recent to most-recent
JFI_SortList(&m_jsonList);
// Get frame, abort if frame is invalid
auto frame = DataProvider::getInstance()->latestFrame();
if (!frame->isValid())
return;
// Create list with datasets that need to be graphed
for (int i = 0; i < frame->groupCount(); ++i)
// Graph each frame
for (int f = 0; f < m_jsonList.count(); ++f)
{
auto group = frame->groups().at(i);
for (int j = 0; j < group->datasetCount(); ++j)
// Clear dataset & latest values list
m_datasets.clear();
// Get frame, abort if frame is invalid
JSON::Frame frame;
if (!frame.read(m_jsonList.at(f).jsonDocument.object()))
continue;
// Create list with datasets that need to be graphed
for (int i = 0; i < frame.groupCount(); ++i)
{
auto dataset = group->datasets().at(j);
if (dataset->graph())
m_datasets.append(dataset);
auto group = frame.groups().at(i);
for (int j = 0; j < group->datasetCount(); ++j)
{
auto dataset = group->datasets().at(j);
if (dataset->graph())
m_datasets.append(dataset);
}
}
// Create list with dataset values (converted to double)
for (int i = 0; i < graphCount(); ++i)
{
// Register dataset for this graph
if (m_points.count() < (i + 1))
{
auto vector = new QVector<double>;
m_points.append(vector);
}
// Register min. values list
if (m_minimumValues.count() < (i + 1))
m_minimumValues.append(getValue(i));
// Register max. values list
if (m_maximumValues.count() < (i + 1))
m_maximumValues.append(getValue(i));
// Update minimum value
if (minimumValue(i) > getValue(i))
m_minimumValues.replace(i, getValue(i));
// Update minimum value
if (maximumValue(i) < getValue(i))
m_maximumValues.replace(i, getValue(i));
// Remove older items
if (m_points.at(i)->count() >= displayedPoints())
m_points.at(i)->remove(0, m_points.at(i)->count() - displayedPoints());
// Add values
m_points.at(i)->append(getValue(i));
}
}
// Create list with dataset values (converted to double)
for (int i = 0; i < graphCount(); ++i)
{
// Register dataset for this graph
if (m_points.count() < (i + 1))
{
auto vector = new QVector<double>;
m_points.append(vector);
}
// Register min. values list
if (m_minimumValues.count() < (i + 1))
m_minimumValues.append(getValue(i));
// Register max. values list
if (m_maximumValues.count() < (i + 1))
m_maximumValues.append(getValue(i));
// Update minimum value
if (minimumValue(i) > getValue(i))
m_minimumValues.replace(i, getValue(i));
// Update minimum value
if (maximumValue(i) < getValue(i))
m_maximumValues.replace(i, getValue(i));
// Remove older items
if (m_points.at(i)->count() >= displayedPoints())
m_points.at(i)->remove(0, m_points.at(i)->count() - displayedPoints());
// Add values
m_points.at(i)->append(getValue(i));
}
// Clear frame list
m_jsonList.clear();
// Update UI
emit dataUpdated();
@ -351,3 +364,13 @@ void GraphProvider::updateGraph(QAbstractSeries *series, const int index)
}
}
}
/**
* Obtains the latest JSON dataframe & appends it to the JSON list, which is later read,
* sorted & graphed by the @c drawGraph() function.
*/
void GraphProvider::registerFrame(const JFI_Object &frameInfo)
{
if (JFI_Valid(frameInfo))
m_jsonList.append(frameInfo);
}

View File

@ -31,6 +31,7 @@
#include <JSON/Frame.h>
#include <JSON/Dataset.h>
#include <JSON/FrameInfo.h>
QT_CHARTS_USE_NAMESPACE
@ -79,6 +80,7 @@ private slots:
void resetData();
void drawGraphs();
void csvPlayerFixes();
void registerFrame(const JFI_Object &frameInfo);
private:
int m_prevFramePos;
@ -87,6 +89,7 @@ private:
QVector<double> m_minimumValues;
QVector<QVector<double> *> m_points;
QVector<JSON::Dataset *> m_datasets;
QList<JFI_Object> m_jsonList;
};
}