Clean up JSON::Generator

This commit is contained in:
Alex Spataru 2022-01-02 00:46:20 -05:00
parent b8263646a2
commit 735ec2e868
5 changed files with 33 additions and 222 deletions

View File

@ -65,8 +65,28 @@ DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x050F00
CONFIG += c++11
CONFIG += silent
*g++*: {
QMAKE_CXXFLAGS_RELEASE -= -O1
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE *= -O3
QMAKE_CXXFLAGS_RELEASE *= -Ofast
QMAKE_CXXFLAGS_RELEASE *= -flto
}
*clang*: {
QMAKE_CXXFLAGS_RELEASE -= -O1
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE *= -O3
QMAKE_CXXFLAGS_RELEASE *= -Ofast
QMAKE_CXXFLAGS_RELEASE *= -flto
}
*msvc*: {
QMAKE_CXXFLAGS *= -MP
QMAKE_CXXFLAGS_RELEASE -= /O
QMAKE_CXXFLAGS_RELEASE *= /O2
QMAKE_CXXFLAGS_RELEASE *= /GL
INCLUDEPATH += $$OUT_PWD
INCLUDEPATH += $$OUT_PWD/debug
INCLUDEPATH += $$OUT_PWD/release

View File

@ -110,7 +110,6 @@ Item {
property alias endSequence: settings.endSequence
property alias startSequence: settings.startSequence
property alias separatorSequence: settings.separatorSequence
property alias multithreadedFrameProcessing: settings.multithreadedFrameProcessing
}
//

View File

@ -37,7 +37,6 @@ Control {
property alias startSequence: _startSequence.text
property alias windowShadows: _windowShadows.checked
property alias separatorSequence: _separatorSequence.text
property alias multithreadedFrameProcessing: _multithreadedFrameProcessing.checked
//
// Layout
@ -152,22 +151,6 @@ Control {
}
}
//
// Multi-threaded frame processing
//
Label {
text: qsTr("Multithreaded frame parsing") + ": "
} Switch {
id: _multithreadedFrameProcessing
Layout.leftMargin: -app.spacing
Layout.alignment: Qt.AlignLeft
checked: Cpp_JSON_Generator.processFramesInSeparateThread
onCheckedChanged: {
if (checked != Cpp_JSON_Generator.processFramesInSeparateThread)
Cpp_JSON_Generator.processFramesInSeparateThread = checked
}
}
//
// Window shadows
//

View File

@ -39,13 +39,15 @@
JSON::Generator::Generator()
: m_frameCount(0)
, m_opMode(kAutomatic)
, m_processInSeparateThread(false)
{
const auto io = &IO::Manager::instance();
const auto cp = &CSV::Player::instance();
connect(cp, SIGNAL(openChanged()), this, SLOT(reset()));
connect(io, SIGNAL(deviceChanged()), this, SLOT(reset()));
connect(io, SIGNAL(frameReceived(QByteArray)), this, SLOT(readData(QByteArray)));
// clang-format off
connect(&CSV::Player::instance(), &CSV::Player::openChanged,
this, &JSON::Generator::reset);
connect(&IO::Manager::instance(), &IO::Manager::deviceChanged,
this, &JSON::Generator::reset);
connect(&IO::Manager::instance(), &IO::Manager::frameReceived,
this, &JSON::Generator::readData);
// clang-format on
readSettings();
}
@ -103,14 +105,6 @@ JSON::Generator::OperationMode JSON::Generator::operationMode() const
return m_opMode;
}
/**
* Returns @c true if JSON frames shall be generated in a separate thread
*/
bool JSON::Generator::processFramesInSeparateThread() const
{
return m_processInSeparateThread;
}
/**
* Creates a file dialog & lets the user select the JSON file map
*/
@ -203,15 +197,6 @@ void JSON::Generator::setOperationMode(const JSON::Generator::OperationMode &mod
Q_EMIT operationModeChanged();
}
/**
* Enables or disables multi-threaded frame processing
*/
void JSON::Generator::setProcessFramesInSeparateThread(const bool threaded)
{
m_processInSeparateThread = threaded;
Q_EMIT processFramesInSeparateThreadChanged();
}
/**
* Loads the last saved JSON map file (if any)
*/
@ -222,25 +207,6 @@ void JSON::Generator::readSettings()
loadJsonMap(path);
}
/**
* 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 JSON::Generator::loadJFI(const JFI_Object &info)
{
const bool csvOpen = CSV::Player::instance().isOpen();
const bool devOpen = IO::Manager::instance().connected();
const bool mqttSub = MQTT::Client::instance().isSubscribed();
if (csvOpen || devOpen || mqttSub)
Q_EMIT jsonChanged(info);
else
reset();
}
/**
* Saves the location of the last valid JSON map file that was opened (if any)
*/
@ -249,16 +215,6 @@ void JSON::Generator::writeSettings(const QString &path)
m_settings.setValue("json_map_location", path);
}
/**
* Create a new JFI event with the given @a JSON document and increment the frame count
*/
void JSON::Generator::loadJSON(const QJsonDocument &json)
{
m_frameCount++;
auto jfi = JFI_CreateNew(m_frameCount, QDateTime::currentDateTime(), json);
loadJFI(jfi);
}
/**
* Resets all the statistics related to the current device and the JSON map file
*/
@ -289,29 +245,7 @@ void JSON::Generator::readData(const QByteArray &data)
// Increment received frames and process frame
m_frameCount++;
// Create new worker thread to read JSON data
if (processFramesInSeparateThread())
{
// clang-format off
QThread *thread = new QThread;
Worker *worker = new Worker(data,
m_frameCount,
QDateTime::currentDateTime());
worker->moveToThread(thread);
// clang-format on
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, &JSON::Worker::jsonReady, this, &JSON::Generator::loadJFI);
thread->start();
}
// Process frames in main thread
else
processFrame(data, m_frameCount, QDateTime::currentDateTime());
processFrame(data, m_frameCount, QDateTime::currentDateTime());
}
/**
@ -321,6 +255,10 @@ void JSON::Generator::readData(const QByteArray &data)
void JSON::Generator::processFrame(const QByteArray &data, const quint64 frame,
const QDateTime &time)
{
//
// TODO: Re-write this function because it leaks memory
//
// Serial device sends JSON (auto mode)
if (operationMode() == JSON::Generator::kAutomatic)
m_jfi.jsonDocument = QJsonDocument::fromJson(data, &m_error);
@ -387,97 +325,6 @@ void JSON::Generator::processFrame(const QByteArray &data, const quint64 frame,
}
}
//----------------------------------------------------------------------------------------
// JSON worker object (executed for each frame on a new thread)
//----------------------------------------------------------------------------------------
/**
* Constructor function, stores received frame data & the date/time that the frame data
* was received.
*/
JSON::Worker::Worker(const QByteArray &data, const quint64 frame, const QDateTime &time)
: m_time(time)
, m_data(data)
, m_frame(frame)
{
}
/**
* Reads the frame & inserts its values on the JSON map, and/or extracts the JSON frame
* directly from the serial data.
*/
void JSON::Worker::process()
{
// Init variables
QJsonParseError error;
QJsonDocument document;
// Serial device sends JSON (auto mode)
if (Generator::instance().operationMode() == Generator::kAutomatic)
document = QJsonDocument::fromJson(m_data, &error);
// We need to use a map file, check if its loaded & replace values into map
else
{
// Empty JSON map data
if (Generator::instance().jsonMapData().isEmpty())
return;
// Separate incoming data & add it to the JSON map
auto json = Generator::instance().jsonMapData();
const auto sepr = IO::Manager::instance().separatorSequence();
const auto list = QString::fromUtf8(m_data).split(sepr);
for (int i = 0; i < list.count(); ++i)
json.replace(QString("\"%%1\"").arg(i + 1), "\"" + list.at(i) + "\"");
// Create json document
const auto jsonData = json.toUtf8();
const auto jsonDocument = QJsonDocument::fromJson(jsonData, &error);
// Calculate dynamically generated values
auto root = jsonDocument.object();
auto groups = JFI_Value(root, "groups", "g").toArray();
for (int i = 0; i < groups.count(); ++i)
{
// Get group
auto group = groups.at(i).toObject();
// Evaluate each dataset of the current group
auto datasets = JFI_Value(group, "datasets", "d").toArray();
for (int j = 0; j < datasets.count(); ++j)
{
auto dataset = datasets.at(j).toObject();
auto value = JFI_Value(dataset, "value", "v").toString();
dataset.remove("v");
dataset.remove("value");
dataset.insert("value", value);
datasets.replace(j, dataset);
}
// Replace group datasets
group.remove("d");
group.remove("datasets");
group.insert("datasets", datasets);
groups.replace(i, group);
}
// Replace root document group objects
root.remove("g");
root.remove("groups");
root.insert("groups", groups);
// Create JSON document
document = QJsonDocument(root);
}
// No parse error, update UI & reset error counter
if (error.error == QJsonParseError::NoError)
Q_EMIT jsonReady(JFI_CreateNew(m_frame, m_time, document));
// Delete object
Q_EMIT finished();
}
#ifdef SERIAL_STUDIO_INCLUDE_MOC
# include "moc_Generator.cpp"
#endif

View File

@ -24,7 +24,6 @@
#include <QFile>
#include <QObject>
#include <QThread>
#include <QSettings>
#include <QJsonArray>
#include <QJsonValue>
@ -36,33 +35,6 @@
namespace JSON
{
/**
* Generates a JSON document by combining the JSON map file and the received
* data from the microcontroller device.
*
* This code is executed on another thread in order to avoid blocking the
* user interface.
*/
class Worker : public QObject
{
Q_OBJECT
Q_SIGNALS:
void finished();
void jsonReady(const JFI_Object &info);
public:
Worker(const QByteArray &data, const quint64 frame, const QDateTime &time);
public Q_SLOTS:
void process();
private:
QDateTime m_time;
QByteArray m_data;
quint64 m_frame;
};
/**
* @brief The Generator class
*
@ -99,17 +71,12 @@ class Generator : public QObject
READ operationMode
WRITE setOperationMode
NOTIFY operationModeChanged)
Q_PROPERTY(bool processFramesInSeparateThread
READ processFramesInSeparateThread
WRITE setProcessFramesInSeparateThread
NOTIFY processFramesInSeparateThreadChanged)
// clang-format on
Q_SIGNALS:
void jsonFileMapChanged();
void operationModeChanged();
void jsonChanged(const JFI_Object &info);
void processFramesInSeparateThreadChanged();
private:
explicit Generator();
@ -132,19 +99,15 @@ public:
QString jsonMapFilename() const;
QString jsonMapFilepath() const;
OperationMode operationMode() const;
bool processFramesInSeparateThread() const;
public Q_SLOTS:
void loadJsonMap();
void loadJsonMap(const QString &path);
void setProcessFramesInSeparateThread(const bool threaded);
void setOperationMode(const JSON::Generator::OperationMode &mode);
public Q_SLOTS:
void readSettings();
void loadJFI(const JFI_Object &object);
void writeSettings(const QString &path);
void loadJSON(const QJsonDocument &json);
private Q_SLOTS:
void reset();
@ -159,6 +122,5 @@ private:
QString m_jsonMapData;
OperationMode m_opMode;
QJsonParseError m_error;
bool m_processInSeparateThread;
};
}