Initial calibration page

- Fetch spectrometer status upon connection
- Display appropriate page depending on the status

TODO:
- Write calibration instructions
- Timer for periodic status fetch
This commit is contained in:
2024-02-15 22:48:31 -03:00
parent 56c16b8908
commit c3776f5908
11 changed files with 202 additions and 91 deletions

View File

@@ -9,8 +9,15 @@
* *
*/ */
#include <QJsonDocument>
#include "Backend.hpp" #include "Backend.hpp"
enum MsgType {
MSG_STATUS,
MSG_UNKNOWN,
};
void Backend::registerTypes(const char *uri) { void Backend::registerTypes(const char *uri) {
qmlRegisterType<Backend>(uri, 0, 1, "Backend"); qmlRegisterType<Backend>(uri, 0, 1, "Backend");
} }
@@ -25,6 +32,8 @@ Backend::Backend(QObject *parent) : QObject(parent) {
&Backend::brokerStateChanged); &Backend::brokerStateChanged);
connect(this->m_client, &QMqttClient::stateChanged, this, connect(this->m_client, &QMqttClient::stateChanged, this,
&Backend::onBrokerStateChanged); &Backend::onBrokerStateChanged);
connect(this->m_client, &QMqttClient::messageReceived, this,
&Backend::onMqttMessage);
} }
void Backend::connectToBroker() { this->m_client->connectToHost(); } void Backend::connectToBroker() { this->m_client->connectToHost(); }
@@ -56,8 +65,63 @@ void Backend::onBrokerStateChanged(const QMqttClient::ClientState &state) {
return; return;
this->m_client->subscribe(QMqttTopicFilter("/spec"), 1); this->m_client->subscribe(QMqttTopicFilter("/spec"), 1);
this->m_client->publish(QMqttTopicName("/status"));
} }
const Spec::SpecStatus Backend::specStatus() const { const Spec::SpecStatus Backend::specStatus() const {
return this->m_specStatus; return this->m_specStatus;
}
const QString Backend::specStatusReason() const {
return this->m_specStatusReason;
}
void Backend::onMqttMessage(const QByteArray &message,
const QMqttTopicName &topic) {
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(message, &err);
if (err.error != err.NoError) {
qWarning() << "Failed to parse json message, ignoring."
<< err.errorString();
return;
} else if (doc.isObject() == false) {
qWarning() << "Wrong json format received, ignoring.";
return;
}
QJsonObject o = doc.object();
if (o.contains("type") == false) {
qWarning() << "Wrong json message received, ignoring.";
return;
}
MsgType type = (MsgType)o["type"].toInt();
switch (type) {
case MSG_STATUS:
this->handleStatus(o);
break;
default:
qWarning() << "Unknown message type received, ignoring.";
return;
}
}
void Backend::handleStatus(QJsonObject o) {
if (o.contains("status") == false) {
qWarning() << "Invalid status message received, ignoring.";
return;
}
this->m_specStatus = (Spec::SpecStatus)o["status"].toInt();
if (o.contains("reason") == false)
this->m_specStatusReason = "";
else
this->m_specStatusReason = o["reason"].toString();
emit this->specStatusChanged();
} }

View File

@@ -52,6 +52,8 @@ class Backend : public QObject {
// Spectrometer properties // Spectrometer properties
Q_PROPERTY( Q_PROPERTY(
Spec::SpecStatus specStatus READ specStatus NOTIFY specStatusChanged) Spec::SpecStatus specStatus READ specStatus NOTIFY specStatusChanged)
Q_PROPERTY(
QString specStatusReason READ specStatusReason NOTIFY specStatusChanged)
QML_EXTENDED_NAMESPACE(Spec) QML_EXTENDED_NAMESPACE(Spec)
@@ -77,6 +79,7 @@ public:
const QMqttClient::ClientState brokerState() const; const QMqttClient::ClientState brokerState() const;
const Spec::SpecStatus specStatus() const; const Spec::SpecStatus specStatus() const;
const QString specStatusReason() const;
signals: signals:
void brokerHostChanged(); void brokerHostChanged();
@@ -86,9 +89,13 @@ signals:
private slots: private slots:
void onBrokerStateChanged(const QMqttClient::ClientState &state); void onBrokerStateChanged(const QMqttClient::ClientState &state);
void onMqttMessage(const QByteArray &message, const QMqttTopicName &topic);
private: private:
Q_DISABLE_COPY(Backend) Q_DISABLE_COPY(Backend)
QMqttClient *m_client; QMqttClient *m_client;
Spec::SpecStatus m_specStatus = Spec::SPEC_UNKNOWN; Spec::SpecStatus m_specStatus = Spec::SPEC_UNKNOWN;
QString m_specStatusReason = "";
void handleStatus(QJsonObject o);
}; };

5
src/Gui/AppPage.qml Normal file
View File

@@ -0,0 +1,5 @@
import QtQuick.Controls
Page {
}

View File

@@ -0,0 +1,40 @@
import QtQuick
import QtQuick.Layouts
import "../PStyle"
import ".."
ColumnLayout {
spacing: 64
ColumnLayout {
PText {
text: qsTr("Spectrometer needs calibration")
wrapMode: Text.WordWrap
font: PStyle.getFont(24)
}
PText {
text: qsTr("Reason: ") + App.specStatusReason
}
}
PText {
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: 886
Layout.preferredWidth: mainWindow.width * 0.7
font: PStyle.getFont(10)
text: qsTr(
"This is needed so the system knows where the diffraction grating " +
"is pointing at.\naaaa"
)
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignJustify
}
PTextButton {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Continue")
}
}

29
src/Gui/Loading.qml Normal file
View File

@@ -0,0 +1,29 @@
import QtQuick.Layouts
import "PStyle"
ColumnLayout {
property string title: ""
property string description: ""
spacing: 64
PText {
Layout.alignment: Qt.AlignHCenter
visible: title
text: title
font: PStyle.getFont(24)
}
PBusyIndicator {
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: 48
running: true
}
PText {
Layout.alignment: Qt.AlignHCenter
visible: description
text: description
}
}

View File

@@ -72,7 +72,7 @@ ColumnLayout {
PTextButton { PTextButton {
id: btn id: btn
text: qsTr("Connect") text: qsTr("Next")
Layout.fillWidth: true Layout.fillWidth: true
enabled: false enabled: false

View File

@@ -1,20 +0,0 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import "../PStyle"
ColumnLayout {
spacing: 24
PBusyIndicator {
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: 48
running: true
}
PText {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Trying to connect...")
}
}

View File

@@ -6,34 +6,8 @@ import QtQml
import "../PStyle" import "../PStyle"
import ".." import ".."
PStackView { BrokerInput {
id: login onTryConnect: (url, user, pass) => {
initialItem: brokerInput App.tryConnect(url, user, pass)
property var instanceInfo
Component {
id: brokerInput
PBackground {
BrokerInput {
anchors.centerIn: parent
onTryConnect: (url, user, pass) => {
App.tryConnect(url, user, pass)
login.push(loadInstance)
}
}
}
}
Component {
id: loadInstance
PBackground {
LoadingInfo {
anchors.centerIn: parent
}
}
} }
} }

View File

@@ -2,25 +2,52 @@ import QtQuick
import QtQuick.Window import QtQuick.Window
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls import QtQuick.Controls
import QtQml
import "PStyle" import "PStyle"
import "Login" import "Login"
import "." import "."
ApplicationWindow { ApplicationWindow {
id: mainWindow
visible: true visible: true
width: 640
height: 480
title: Qt.application.displayName title: Qt.application.displayName
minimumWidth: 840
minimumHeight: 640
property string loadingTitle: qsTr("Loading application...")
property string loadingDesc
Component.onCompleted: { Component.onCompleted: {
App.setup() App.setup()
loadingTimer.running = true loadingTimer.running = true
}
App.brokerStateChanged.connect(() => { Connections {
if (App.brokerState == 2) target: App
connectTimer.running = true
}) function onBrokerStateChanged() {
switch (App.brokerState) {
case App.BROKER_CONNECTING:
showLoading("Connecting to broker...")
break;
case App.BROKER_CONNECTED:
showLoading("Getting spectrometer...")
break;
}
}
function onSpecStatusChanged() {
switch (App.specStatus) {
case App.SPEC_NEEDS_CALIBRATION:
loader.setSource(
"qrc:/Calibration/Calibration.qml",
)
break;
}
}
} }
Timer { Timer {
@@ -41,50 +68,35 @@ ApplicationWindow {
running: false running: false
repeat: false repeat: false
interval: 750 interval: 500
onTriggered: loader.sourceComponent = mainPane onTriggered: loader.sourceComponent = mainPane
} }
Loader { Loader {
id: loader id: loader
anchors.fill: parent anchors.centerIn: parent
sourceComponent: loadingComponent sourceComponent: loadingComponent
} }
Component { Component {
id: loadingComponent id: loadingComponent
PBackground { Loading {
ColumnLayout { id: loading
anchors.centerIn: parent title: loadingTitle
spacing: 24 description: loadingDesc
PBusyIndicator {
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: 48
running: true
}
PText {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Loading application...")
}
}
} }
} }
Component { function showLoading(title, desc = "") {
id: mainPane loadingTitle = title
loadingDesc = desc
PBackground { loader.sourceComponent = loadingComponent
PText {
anchors.centerIn: parent
text: qsTr("YAAAAY I AM CONNECTED")
}
}
} }
background: PBackground {}
footer: ToolBar { footer: ToolBar {
visible: false visible: false
@@ -101,7 +113,7 @@ ApplicationWindow {
RowLayout { RowLayout {
PText { PText {
font: PStyle.getFont(10) font: PStyle.getFont(10)
text: qsTr("Connection status:") text: qsTr("Connection:")
} }
Rectangle { Rectangle {
@@ -128,7 +140,7 @@ ApplicationWindow {
PText { PText {
font: PStyle.getFont(10) font: PStyle.getFont(10)
text: qsTr("Spectrometer status:") text: qsTr("Spectrometer:")
} }
Rectangle { Rectangle {

View File

@@ -11,10 +11,7 @@ QtObject {
property double animationDuration: 100 property double animationDuration: 100
property font font: Qt.font({ property font font: getFont()
family: "HackGen Console",
pointSize: 12,
})
function getFont(size = 12) { function getFont(size = 12) {
return Qt.font({ return Qt.font({

View File

@@ -2,15 +2,18 @@
<qresource prefix="/"> <qresource prefix="/">
<file alias="Splash.qml">Gui/Splash.qml</file> <file alias="Splash.qml">Gui/Splash.qml</file>
<file alias="App.qml">Gui/App.qml</file> <file alias="App.qml">Gui/App.qml</file>
<file alias="Loading.qml">Gui/Loading.qml</file>
<file alias="qmldir">Gui/qmldir</file> <file alias="qmldir">Gui/qmldir</file>
<!-- login --> <!-- login -->
<file alias="Login/Login.qml">Gui/Login/Login.qml</file> <file alias="Login/Login.qml">Gui/Login/Login.qml</file>
<file alias="Login/BrokerInput.qml">Gui/Login/BrokerInput.qml</file> <file alias="Login/BrokerInput.qml">Gui/Login/BrokerInput.qml</file>
<file alias="Login/LoadingInfo.qml">Gui/Login/LoadingInfo.qml</file>
<!-- settings --> <!-- settings -->
<file alias="Settings/Settings.qml">Gui/Settings/Settings.qml</file> <file alias="Settings/Settings.qml">Gui/Settings/Settings.qml</file>
<file alias="Settings/qmldir">Gui/Settings/qmldir</file> <file alias="Settings/qmldir">Gui/Settings/qmldir</file>
<!-- calibration -->
<file alias="Calibration/Calibration.qml">Gui/Calibration/Calibration.qml</file>
</qresource> </qresource>
</RCC> </RCC>