mirror of
https://github.com/Serial-Studio/Serial-Studio.git
synced 2025-01-15 05:22:53 +08:00
Architectural changes to allow using JSON maps to reduce MCU serial usage
This commit is contained in:
parent
9d7ee95446
commit
ba03e7b91e
@ -66,10 +66,18 @@ Widgets.Window {
|
||||
id: commAuto
|
||||
checked: true
|
||||
text: qsTr("Auto (JSON from serial device)")
|
||||
onCheckedChanged: {
|
||||
if (checked)
|
||||
CppJsonParser.setOperationMode(CppJsonParser.kAutomatic)
|
||||
}
|
||||
} RadioButton {
|
||||
id: commManual
|
||||
checked: false
|
||||
text: qsTr("Manual (use JSON map file)")
|
||||
onCheckedChanged: {
|
||||
if (checked)
|
||||
CppJsonParser.setOperationMode(CppJsonParser.kManual)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@ -79,8 +87,10 @@ Widgets.Window {
|
||||
Layout.fillWidth: true
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: commManual.checked
|
||||
text: qsTr("Select map file") + "..."
|
||||
onClicked: CppJsonParser.loadJsonMap()
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
text: CppJsonParser.jsonMapFilename.length ? qsTr("Change map file (%1)").arg(CppJsonParser.jsonMapFilename) :
|
||||
qsTr("Select map file") + "..."
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -23,17 +23,40 @@
|
||||
#include "JsonParser.h"
|
||||
#include "SerialManager.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
/*
|
||||
* Only instance of the class
|
||||
*/
|
||||
static JsonParser *INSTANCE = nullptr;
|
||||
|
||||
/**
|
||||
* Shows a macOS-like message box with the given properties
|
||||
*/
|
||||
static int NiceMessageBox(QString text, QString informativeText, QString windowTitle = qAppName(),
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok)
|
||||
{
|
||||
auto icon = QPixmap(":/images/icon.png").scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
QMessageBox box;
|
||||
box.setIconPixmap(icon);
|
||||
box.setWindowTitle(windowTitle);
|
||||
box.setStandardButtons(buttons);
|
||||
box.setText("<h3>" + text + "</h3>");
|
||||
box.setInformativeText(informativeText);
|
||||
|
||||
return box.exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the JSON Parser class and connects
|
||||
* appropiate SIGNALS/SLOTS
|
||||
*/
|
||||
JsonParser::JsonParser()
|
||||
{
|
||||
m_opMode = kAutomatic;
|
||||
auto sm = SerialManager::getInstance();
|
||||
connect(sm, SIGNAL(packetReceived(QByteArray)), this, SLOT(readData(QByteArray)));
|
||||
}
|
||||
@ -49,16 +72,147 @@ JsonParser *JsonParser::getInstance()
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON map data from the loaded file as a string
|
||||
*/
|
||||
QByteArray JsonParser::jsonMapData() const
|
||||
{
|
||||
return m_jsonMapData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parsed JSON document from the received packet
|
||||
*/
|
||||
QJsonDocument JsonParser::document()
|
||||
QJsonDocument JsonParser::document() const
|
||||
{
|
||||
return m_document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse the given data as a JSON document.
|
||||
* Returns the file name (e.g. "JsonMap.json") of the loaded JSON
|
||||
* map file
|
||||
*/
|
||||
QString JsonParser::jsonMapFilename() const
|
||||
{
|
||||
if (m_jsonMap.isOpen())
|
||||
{
|
||||
auto fileInfo = QFileInfo(m_jsonMap.fileName());
|
||||
return fileInfo.fileName();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file path of the loaded JSON map file
|
||||
*/
|
||||
QString JsonParser::jsonMapFilepath() const
|
||||
{
|
||||
if (m_jsonMap.isOpen())
|
||||
{
|
||||
auto fileInfo = QFileInfo(m_jsonMap.fileName());
|
||||
return fileInfo.filePath();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operation mode
|
||||
*/
|
||||
JsonParser::OperationMode JsonParser::operationMode() const
|
||||
{
|
||||
return m_opMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file dialog & lets the user select the JSON file map
|
||||
*/
|
||||
void JsonParser::loadJsonMap()
|
||||
{
|
||||
auto file = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Select JSON map file"), QDir::homePath(),
|
||||
tr("JSON files (*.json)"));
|
||||
if (!file.isEmpty())
|
||||
loadJsonMap(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens, validates & loads into memory the JSON file in the given @a path.
|
||||
*/
|
||||
void JsonParser::loadJsonMap(const QString &path)
|
||||
{
|
||||
// Validate path
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
// Close previous file (if open)
|
||||
if (m_jsonMap.isOpen())
|
||||
{
|
||||
m_jsonMap.close();
|
||||
emit jsonFileMapChanged();
|
||||
}
|
||||
|
||||
// Try to open the file (read only mode)
|
||||
m_jsonMap.setFileName(path);
|
||||
if (m_jsonMap.open(QFile::ReadOnly))
|
||||
{
|
||||
// Read data & validate JSON from file
|
||||
QJsonParseError error;
|
||||
auto data = m_jsonMap.readAll();
|
||||
auto document = QJsonDocument::fromJson(data, &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
m_jsonMap.close();
|
||||
NiceMessageBox(tr("JSON parse error"), error.errorString());
|
||||
}
|
||||
|
||||
// JSON contains no errors
|
||||
else
|
||||
{
|
||||
m_jsonMapData = data;
|
||||
NiceMessageBox(tr("JSON map file loaded successfully!"),
|
||||
tr("File \"%1\" loaded into memory").arg(jsonMapFilename()));
|
||||
}
|
||||
}
|
||||
|
||||
// Open error
|
||||
else
|
||||
{
|
||||
NiceMessageBox(tr("Cannot read file contents"),
|
||||
tr("Failed to read contents of \"%1\", check file permissions").arg(jsonMapFilename()));
|
||||
m_jsonMap.close();
|
||||
}
|
||||
|
||||
// Update UI
|
||||
emit jsonFileMapChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the operation mode of the JSON parser. There are two possible op. modes:
|
||||
*
|
||||
* @c kManual serial data only contains the comma-separated values, and we need
|
||||
* to use a JSON map file (given by the user) to know what each value means.
|
||||
* This method is recommended when we need to transfer & display a large amount
|
||||
* of information from the microcontroller unit to the computer.
|
||||
*
|
||||
* @c kAuto serial data contains the JSON data frame, good for simple applications or
|
||||
* for prototyping.
|
||||
*/
|
||||
void JsonParser::setOperationMode(const OperationMode mode)
|
||||
{
|
||||
m_opMode = mode;
|
||||
emit operationModeChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse the given data as a JSON document according to the selected
|
||||
* operation mode.
|
||||
*
|
||||
* Possible operation modes:
|
||||
* - Auto: serial data contains the JSON data frame
|
||||
* - Manual: serial data only contains the comma-separated values, and we need
|
||||
* to use a JSON map file (given by the user) to know what each value means
|
||||
*
|
||||
* If JSON parsing is successfull, then the class shall notify the rest of the
|
||||
* application in order to process packet data.
|
||||
*/
|
||||
|
@ -23,7 +23,9 @@
|
||||
#ifndef JSON_PARSER_H
|
||||
#define JSON_PARSER_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonObject>
|
||||
@ -32,13 +34,36 @@
|
||||
class JsonParser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString jsonMapFilename READ jsonMapFilename NOTIFY jsonFileMapChanged)
|
||||
Q_PROPERTY(QString jsonMapFilepath READ jsonMapFilepath NOTIFY jsonFileMapChanged)
|
||||
Q_PROPERTY(OperationMode operationMode READ operationMode WRITE setOperationMode NOTIFY operationModeChanged)
|
||||
|
||||
signals:
|
||||
void packetReceived();
|
||||
void jsonFileMapChanged();
|
||||
void operationModeChanged();
|
||||
|
||||
public:
|
||||
enum OperationMode
|
||||
{
|
||||
kManual,
|
||||
kAutomatic,
|
||||
};
|
||||
Q_ENUMS(OperationMode)
|
||||
|
||||
public:
|
||||
static JsonParser *getInstance();
|
||||
QJsonDocument document();
|
||||
|
||||
QByteArray jsonMapData() const;
|
||||
QJsonDocument document() const;
|
||||
QString jsonMapFilename() const;
|
||||
QString jsonMapFilepath() const;
|
||||
OperationMode operationMode() const;
|
||||
|
||||
public slots:
|
||||
void loadJsonMap();
|
||||
void loadJsonMap(const QString &path);
|
||||
void setOperationMode(const OperationMode mode);
|
||||
|
||||
private:
|
||||
JsonParser();
|
||||
@ -47,7 +72,10 @@ private slots:
|
||||
void readData(const QByteArray &data);
|
||||
|
||||
private:
|
||||
QFile m_jsonMap;
|
||||
OperationMode m_opMode;
|
||||
QJsonDocument m_document;
|
||||
QByteArray m_jsonMapData;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "AppInfo.h"
|
||||
#include "Widgets.h"
|
||||
#include "QmlBridge.h"
|
||||
#include "JsonParser.h"
|
||||
#include "GraphProvider.h"
|
||||
#include "SerialManager.h"
|
||||
|
||||
@ -64,6 +65,7 @@ int main(int argc, char **argv)
|
||||
auto widgets = Widgets::getInstance();
|
||||
auto csvExport = Export::getInstance();
|
||||
auto qmlBridge = QmlBridge::getInstance();
|
||||
auto jsonParser = JsonParser::getInstance();
|
||||
auto updater = QSimpleUpdater::getInstance();
|
||||
auto graphProvider = GraphProvider::getInstance();
|
||||
auto serialManager = SerialManager::getInstance();
|
||||
@ -78,6 +80,7 @@ int main(int argc, char **argv)
|
||||
engine.rootContext()->setContextProperty("CppWidgets", widgets);
|
||||
engine.rootContext()->setContextProperty("CppExport", csvExport);
|
||||
engine.rootContext()->setContextProperty("CppQmlBridge", qmlBridge);
|
||||
engine.rootContext()->setContextProperty("CppJsonParser", jsonParser);
|
||||
engine.rootContext()->setContextProperty("CppGraphProvider", graphProvider);
|
||||
engine.rootContext()->setContextProperty("CppSerialManager", serialManager);
|
||||
engine.rootContext()->setContextProperty("CppAppName", app.applicationName());
|
||||
|
Loading…
x
Reference in New Issue
Block a user