First test of QT Remote Monitor WASM
This commit is contained in:
21
CMakeLists.txt
Normal file
21
CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(wsapp VERSION 1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Core Widgets WebSockets)
|
||||||
|
|
||||||
|
add_executable(wsapp
|
||||||
|
main.cpp
|
||||||
|
GamesPanel.cpp GamesPanel.h
|
||||||
|
SettingsTree.cpp SettingsTree.h
|
||||||
|
VersionsPanel.cpp VersionsPanel.h
|
||||||
|
WebSocketController.cpp WebSocketController.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(wsapp PRIVATE
|
||||||
|
Qt6::Core
|
||||||
|
Qt6::Widgets
|
||||||
|
Qt6::WebSockets
|
||||||
|
)
|
||||||
176
WebSocketController.cpp
Normal file
176
WebSocketController.cpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#include "WebSocketController.h"
|
||||||
|
#include "GamesPanel.h"
|
||||||
|
#include "SettingsTree.h"
|
||||||
|
#include "VersionsPanel.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
WebSocketController::WebSocketController(QLineEdit *urlEdit,
|
||||||
|
QLabel *statusLabel,
|
||||||
|
QObject *parent)
|
||||||
|
: QObject(parent), m_urlEdit(urlEdit), m_statusLabel(statusLabel)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QWebSocket *WebSocketController::socket() { return &m_socket; }
|
||||||
|
|
||||||
|
void WebSocketController::addLogView(QTextEdit *log) { m_logs.append(log); }
|
||||||
|
|
||||||
|
void WebSocketController::setSettingsTree(SettingsTree *tree)
|
||||||
|
{
|
||||||
|
m_settingsTree = tree;
|
||||||
|
connect(tree, &SettingsTree::valueEdited,
|
||||||
|
this, &WebSocketController::onValueEdited);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::setGamesPanel(GamesPanel *panel) { m_gamesPanel = panel; }
|
||||||
|
void WebSocketController::setVersionsPanel(VersionsPanel *panel) { m_versionsPanel = panel; }
|
||||||
|
|
||||||
|
bool WebSocketController::isConnected() const
|
||||||
|
{
|
||||||
|
return m_socket.state() == QAbstractSocket::ConnectedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::startConnection()
|
||||||
|
{
|
||||||
|
const QUrl url(m_urlEdit->text().trimmed());
|
||||||
|
if (!url.isValid()) { broadcast("Invalid URL"); return; }
|
||||||
|
broadcast(QString("Connecting to %1").arg(url.toString()));
|
||||||
|
m_statusLabel->setText("Connecting...");
|
||||||
|
m_socket.open(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::closeConnection()
|
||||||
|
{
|
||||||
|
broadcast("Closing connection");
|
||||||
|
m_settingsKeys.clear();
|
||||||
|
m_rnpCount = -1;
|
||||||
|
if (m_versionsPanel) m_versionsPanel->reset();
|
||||||
|
m_socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::sendCommand(const QString &cmd)
|
||||||
|
{
|
||||||
|
if (!isConnected()) { broadcast("[not connected]"); return; }
|
||||||
|
m_socket.sendTextMessage(cmd);
|
||||||
|
broadcast(QString("TX: %1").arg(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::onConnected()
|
||||||
|
{
|
||||||
|
broadcast("Connected");
|
||||||
|
m_statusLabel->setText("Connected");
|
||||||
|
m_rnpCount = -1;
|
||||||
|
|
||||||
|
sendCommand(QStringLiteral("GBL List"));
|
||||||
|
sendCommand(QStringLiteral("GAM list"));
|
||||||
|
sendCommand(QStringLiteral("NAM"));
|
||||||
|
sendCommand(QStringLiteral("VER"));
|
||||||
|
sendCommand(QStringLiteral("UID"));
|
||||||
|
sendCommand(QStringLiteral("RNP"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::onDisconnected()
|
||||||
|
{
|
||||||
|
broadcast("Disconnected");
|
||||||
|
m_statusLabel->setText("Disconnected");
|
||||||
|
m_settingsKeys.clear();
|
||||||
|
m_rnpCount = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::onTextMessageReceived(const QString &msg)
|
||||||
|
{
|
||||||
|
broadcast(QString("RX: %1").arg(msg));
|
||||||
|
handleProtocol(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::onErrorOccurred(QAbstractSocket::SocketError)
|
||||||
|
{
|
||||||
|
broadcast(QString("Error: %1").arg(m_socket.errorString()));
|
||||||
|
m_statusLabel->setText("Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::onValueEdited(const QString &key, const QString &newValue)
|
||||||
|
{
|
||||||
|
sendCommand(QString("GBL %1=%2").arg(key, newValue));
|
||||||
|
sendCommand(QString("GBL %1").arg(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::handleProtocol(const QString &msg)
|
||||||
|
{
|
||||||
|
const QStringList tokens = msg.split(' ', Qt::SkipEmptyParts);
|
||||||
|
if (tokens.isEmpty()) return;
|
||||||
|
const QString cmd = tokens[0];
|
||||||
|
|
||||||
|
// NAM <name>
|
||||||
|
if (cmd == "NAM" && tokens.size() >= 2) {
|
||||||
|
if (m_versionsPanel) m_versionsPanel->setDeviceName(tokens[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// VER M <fw> or VER <n> <fw>
|
||||||
|
if (cmd == "VER" && tokens.size() >= 3) {
|
||||||
|
if (m_versionsPanel)
|
||||||
|
m_versionsPanel->setVersion(tokens[1], tokens.mid(2).join(' '));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UID M <hex> or UID <n> <hex>
|
||||||
|
if (cmd == "UID" && tokens.size() >= 3) {
|
||||||
|
if (m_versionsPanel)
|
||||||
|
m_versionsPanel->setUid(tokens[1], tokens.mid(2).join(' '));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RNP <count>
|
||||||
|
if (cmd == "RNP" && tokens.size() >= 2) {
|
||||||
|
bool ok = false;
|
||||||
|
const int count = tokens[1].toInt(&ok);
|
||||||
|
if (ok && count > 0) {
|
||||||
|
m_rnpCount = count;
|
||||||
|
if (m_versionsPanel) m_versionsPanel->setRnpCount(count);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
sendCommand(QString("VER %1").arg(i));
|
||||||
|
sendCommand(QString("UID %1").arg(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GAM list ...
|
||||||
|
if (cmd == "GAM" && tokens.size() >= 2 && tokens[1] == "list") {
|
||||||
|
if (m_gamesPanel) m_gamesPanel->loadFromResponse(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GBL List key1 key2 ...
|
||||||
|
if (cmd == "GBL" && tokens.size() > 2 && tokens[1] == "List") {
|
||||||
|
m_settingsKeys = tokens.mid(2);
|
||||||
|
if (m_settingsTree) {
|
||||||
|
m_settingsTree->loadKeys(m_settingsKeys);
|
||||||
|
for (const QString &key : m_settingsKeys)
|
||||||
|
sendCommand(QString("GBL %1").arg(key));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GBL key=value
|
||||||
|
if (cmd == "GBL" && tokens.size() >= 2 && m_settingsTree) {
|
||||||
|
const QString payload = tokens[1];
|
||||||
|
const int eqIdx = payload.indexOf('=');
|
||||||
|
if (eqIdx > 0) {
|
||||||
|
const QString key = payload.left(eqIdx);
|
||||||
|
QString value = payload.mid(eqIdx + 1);
|
||||||
|
if (tokens.size() > 2) value += ' ' + tokens.mid(2).join(' ');
|
||||||
|
m_settingsTree->setValue(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketController::broadcast(const QString &line)
|
||||||
|
{
|
||||||
|
for (auto *log : m_logs)
|
||||||
|
log->append(line);
|
||||||
|
}
|
||||||
3
build-run.sh
Normal file
3
build-run.sh
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/home/user/Qt/6.7.3/wasm_singlethread/bin/qt-cmake -S . -B build-wasm -G Ninja
|
||||||
|
cmake --build build-wasm
|
||||||
|
|
||||||
151
main.cpp
Normal file
151
main.cpp
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QTreeWidgetItem>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "GamesPanel.h"
|
||||||
|
#include "SettingsTree.h"
|
||||||
|
#include "VersionsPanel.h"
|
||||||
|
#include "WebSocketController.h"
|
||||||
|
|
||||||
|
static QWidget *makeGamesTab(WebSocketController *ctrl, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto *panel = new GamesPanel(parent);
|
||||||
|
ctrl->setGamesPanel(panel);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QWidget *makeVersionsTab(WebSocketController *ctrl, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto *panel = new VersionsPanel(parent);
|
||||||
|
ctrl->setVersionsPanel(panel);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QWidget *makeSettingsTab(WebSocketController *ctrl, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto *page = new QWidget(parent);
|
||||||
|
auto *layout = new QVBoxLayout(page);
|
||||||
|
layout->setContentsMargins(2, 2, 2, 2);
|
||||||
|
auto *tree = new SettingsTree(page);
|
||||||
|
auto *ph = new QTreeWidgetItem(tree);
|
||||||
|
ph->setText(0, "Connect to load settings...");
|
||||||
|
layout->addWidget(tree, 1);
|
||||||
|
ctrl->setSettingsTree(tree);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QWidget *makeManualTab(WebSocketController *ctrl, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto *page = new QWidget(parent);
|
||||||
|
auto *layout = new QVBoxLayout(page);
|
||||||
|
auto *row = new QHBoxLayout();
|
||||||
|
auto *cmdEdit = new QLineEdit(page);
|
||||||
|
cmdEdit->setPlaceholderText("Enter command to send...");
|
||||||
|
auto *sendBtn = new QPushButton("Send", page);
|
||||||
|
row->addWidget(new QLabel("Command:", page));
|
||||||
|
row->addWidget(cmdEdit, 1);
|
||||||
|
row->addWidget(sendBtn);
|
||||||
|
auto *log = new QTextEdit(page);
|
||||||
|
log->setReadOnly(true);
|
||||||
|
layout->addLayout(row);
|
||||||
|
layout->addWidget(log, 1);
|
||||||
|
ctrl->addLogView(log);
|
||||||
|
|
||||||
|
auto send = [cmdEdit, ctrl]() {
|
||||||
|
const QString cmd = cmdEdit->text().trimmed();
|
||||||
|
if (!cmd.isEmpty()) { ctrl->sendCommand(cmd); cmdEdit->clear(); }
|
||||||
|
};
|
||||||
|
QObject::connect(sendBtn, &QPushButton::clicked, page, send);
|
||||||
|
QObject::connect(cmdEdit, &QLineEdit::returnPressed, page, send);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QWidget *makePanelsTab(WebSocketController *ctrl, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto *page = new QWidget(parent);
|
||||||
|
auto *layout = new QVBoxLayout(page);
|
||||||
|
auto *log = new QTextEdit(page);
|
||||||
|
log->setReadOnly(true);
|
||||||
|
layout->addWidget(log, 1);
|
||||||
|
ctrl->addLogView(log);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QWidget *makePlaceholder(const QString &text, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto *page = new QWidget(parent);
|
||||||
|
auto *layout = new QVBoxLayout(page);
|
||||||
|
auto *label = new QLabel(text, page);
|
||||||
|
label->setAlignment(Qt::AlignCenter);
|
||||||
|
layout->addWidget(label);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QWidget window;
|
||||||
|
window.setWindowTitle("ESA WebSocket Client");
|
||||||
|
|
||||||
|
auto *mainLayout = new QVBoxLayout(&window);
|
||||||
|
mainLayout->setContentsMargins(6, 6, 6, 6);
|
||||||
|
mainLayout->setSpacing(4);
|
||||||
|
|
||||||
|
// --- Header bar ---
|
||||||
|
auto *headerRow = new QHBoxLayout();
|
||||||
|
auto *urlEdit = new QLineEdit(&window);
|
||||||
|
urlEdit->setPlaceholderText("ws://127.0.0.1:3491/");
|
||||||
|
urlEdit->setText("ws://127.0.0.1:3491/");
|
||||||
|
auto *connectBtn = new QPushButton("Connect", &window);
|
||||||
|
auto *disconnectBtn= new QPushButton("Disconnect", &window);
|
||||||
|
disconnectBtn->setEnabled(false);
|
||||||
|
auto *statusLabel = new QLabel("Disconnected", &window);
|
||||||
|
|
||||||
|
headerRow->addWidget(new QLabel("WebSocket URL:", &window));
|
||||||
|
headerRow->addWidget(urlEdit, 1);
|
||||||
|
headerRow->addWidget(connectBtn);
|
||||||
|
headerRow->addWidget(disconnectBtn);
|
||||||
|
headerRow->addWidget(statusLabel);
|
||||||
|
mainLayout->addLayout(headerRow);
|
||||||
|
|
||||||
|
// --- Controller ---
|
||||||
|
auto *ctrl = new WebSocketController(urlEdit, statusLabel, &window);
|
||||||
|
|
||||||
|
// --- Tabs ---
|
||||||
|
auto *tabs = new QTabWidget(&window);
|
||||||
|
tabs->addTab(makeGamesTab (ctrl, &window), "games");
|
||||||
|
tabs->addTab(makeVersionsTab(ctrl, &window), "versions");
|
||||||
|
tabs->addTab(makeManualTab (ctrl, &window), "manual");
|
||||||
|
tabs->addTab(makeSettingsTab(ctrl, &window), "settings");
|
||||||
|
tabs->addTab(makePlaceholder("Power", &window), "power");
|
||||||
|
tabs->addTab(makePanelsTab (ctrl, &window), "panels");
|
||||||
|
mainLayout->addWidget(tabs, 1);
|
||||||
|
|
||||||
|
// --- Wire up buttons ---
|
||||||
|
QObject::connect(connectBtn, &QPushButton::clicked, ctrl, &WebSocketController::startConnection);
|
||||||
|
QObject::connect(disconnectBtn, &QPushButton::clicked, ctrl, &WebSocketController::closeConnection);
|
||||||
|
|
||||||
|
QObject::connect(ctrl->socket(), &QWebSocket::connected, ctrl, &WebSocketController::onConnected);
|
||||||
|
QObject::connect(ctrl->socket(), &QWebSocket::disconnected, ctrl, &WebSocketController::onDisconnected);
|
||||||
|
QObject::connect(ctrl->socket(), &QWebSocket::textMessageReceived, ctrl, &WebSocketController::onTextMessageReceived);
|
||||||
|
QObject::connect(ctrl->socket(), &QWebSocket::errorOccurred, ctrl, &WebSocketController::onErrorOccurred);
|
||||||
|
|
||||||
|
QObject::connect(ctrl->socket(), &QWebSocket::connected, &window, [connectBtn, disconnectBtn]() {
|
||||||
|
connectBtn->setEnabled(false); disconnectBtn->setEnabled(true);
|
||||||
|
});
|
||||||
|
QObject::connect(ctrl->socket(), &QWebSocket::disconnected, &window, [connectBtn, disconnectBtn]() {
|
||||||
|
connectBtn->setEnabled(true); disconnectBtn->setEnabled(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.resize(1050, 620);
|
||||||
|
window.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user