aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThomas Vanbesien <tvanbesi@proton.me>2026-03-11 11:02:24 +0100
committerThomas Vanbesien <tvanbesi@proton.me>2026-03-11 11:09:40 +0100
commit35309337aacac2eac7d7215e526bddcf7647b8cf (patch)
tree3626e5e5e17e23122deab1bf3ade0502872873f3 /src
downloadQtXpl2-35309337aacac2eac7d7215e526bddcf7647b8cf.tar.gz
QtXpl2-35309337aacac2eac7d7215e526bddcf7647b8cf.zip
Initial project setup: Qt 6.10.2 TCP client library for Alchemie XPL2 protocol
- Static library (src/) with QML singleton Xpl2Client for TCP communication - Qt Quick demo app (demo/) with connection UI, command input, and response log
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt17
-rw-r--r--src/Xpl2Client.cpp86
-rw-r--r--src/Xpl2Client.h53
3 files changed, 156 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..3339013
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,17 @@
+qt_add_library(QtXpl2 STATIC)
+
+qt_add_qml_module(
+ QtXpl2
+ URI
+ Xpl2
+ VERSION
+ 1.0
+ SOURCES
+ Xpl2Client.h
+ Xpl2Client.cpp
+ OUTPUT_DIRECTORY
+ "${PROJECT_BINARY_DIR}/qml/Xpl2")
+
+target_compile_features(QtXpl2 PRIVATE cxx_std_17)
+
+target_link_libraries(QtXpl2 PRIVATE Qt6::Core Qt6::Network Qt6::Quick)
diff --git a/src/Xpl2Client.cpp b/src/Xpl2Client.cpp
new file mode 100644
index 0000000..db53792
--- /dev/null
+++ b/src/Xpl2Client.cpp
@@ -0,0 +1,86 @@
+/**
+ * @file Xpl2Client.cpp
+ * @brief TCP client for the Alchemie XPL2 printhead protocol.
+ */
+#include "Xpl2Client.h"
+
+Xpl2Client::Xpl2Client(QObject *parent) : QObject(parent) {
+ connect(&m_socket, &QTcpSocket::connected, this, &Xpl2Client::onConnected);
+ connect(&m_socket, &QTcpSocket::disconnected, this,
+ &Xpl2Client::onDisconnected);
+ connect(&m_socket, &QTcpSocket::readyRead, this, &Xpl2Client::onReadyRead);
+ connect(&m_socket, &QAbstractSocket::errorOccurred, this,
+ &Xpl2Client::onErrorOccurred);
+}
+
+QString Xpl2Client::host() const { return m_host; }
+
+void Xpl2Client::setHost(const QString &host) {
+ if (m_host == host)
+ return;
+ m_host = host;
+ emit hostChanged();
+}
+
+quint16 Xpl2Client::port() const { return m_port; }
+
+void Xpl2Client::setPort(quint16 port) {
+ if (m_port == port)
+ return;
+ m_port = port;
+ emit portChanged();
+}
+
+bool Xpl2Client::isConnected() const {
+ return m_socket.state() == QAbstractSocket::ConnectedState;
+}
+
+void Xpl2Client::connectToServer() {
+ if (isConnected()) {
+ emit statusMessage(QStringLiteral("Already connected"));
+ return;
+ }
+ emit statusMessage(
+ QStringLiteral("Connecting to %1:%2…").arg(m_host).arg(m_port));
+ m_socket.connectToHost(m_host, m_port);
+}
+
+void Xpl2Client::disconnectFromServer() {
+ if (!isConnected())
+ return;
+ m_socket.disconnectFromHost();
+}
+
+void Xpl2Client::sendCommand(const QString &command) {
+ if (!isConnected()) {
+ emit errorOccurred(QStringLiteral("Not connected"));
+ return;
+ }
+ QByteArray data = command.toUtf8() + '\n';
+ m_socket.write(data);
+ emit statusMessage(QStringLiteral("Sent: %1").arg(command));
+}
+
+void Xpl2Client::onConnected() {
+ emit connectedChanged();
+ emit statusMessage(QStringLiteral("Connected to %1:%2")
+ .arg(m_socket.peerName())
+ .arg(m_socket.peerPort()));
+}
+
+void Xpl2Client::onDisconnected() {
+ emit connectedChanged();
+ emit statusMessage(QStringLiteral("Disconnected"));
+}
+
+void Xpl2Client::onReadyRead() {
+ while (m_socket.canReadLine()) {
+ QString line = QString::fromUtf8(m_socket.readLine()).trimmed();
+ emit responseReceived(line);
+ }
+}
+
+void Xpl2Client::onErrorOccurred(QAbstractSocket::SocketError error) {
+ Q_UNUSED(error)
+ emit errorOccurred(m_socket.errorString());
+}
diff --git a/src/Xpl2Client.h b/src/Xpl2Client.h
new file mode 100644
index 0000000..f052962
--- /dev/null
+++ b/src/Xpl2Client.h
@@ -0,0 +1,53 @@
+/**
+ * @file Xpl2Client.h
+ * @brief TCP client for the Alchemie XPL2 printhead protocol.
+ */
+#pragma once
+
+#include <QObject>
+#include <QQmlEngine>
+#include <QTcpSocket>
+
+class Xpl2Client : public QObject {
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
+ Q_PROPERTY(QString host READ host WRITE setHost NOTIFY hostChanged)
+ Q_PROPERTY(quint16 port READ port WRITE setPort NOTIFY portChanged)
+ Q_PROPERTY(bool connected READ isConnected NOTIFY connectedChanged)
+
+public:
+ explicit Xpl2Client(QObject *parent = nullptr);
+
+ QString host() const;
+ void setHost(const QString &host);
+
+ quint16 port() const;
+ void setPort(quint16 port);
+
+ bool isConnected() const;
+
+ Q_INVOKABLE void connectToServer();
+ Q_INVOKABLE void disconnectFromServer();
+ Q_INVOKABLE void sendCommand(const QString &command);
+
+signals:
+ void hostChanged();
+ void portChanged();
+ void connectedChanged();
+ void responseReceived(const QString &response);
+ void errorOccurred(const QString &error);
+ void statusMessage(const QString &message);
+
+private slots:
+ void onConnected();
+ void onDisconnected();
+ void onReadyRead();
+ void onErrorOccurred(QAbstractSocket::SocketError error);
+
+private:
+ QTcpSocket m_socket;
+ QString m_host = QStringLiteral("127.0.0.1");
+ quint16 m_port = 5000;
+};