From a2b1ccf17845e55caef7f69a5e68f49a55b6a166 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Fri, 13 Mar 2026 11:47:00 +0100 Subject: XPL2 protocol foundation: wire framing, typed API, KA_PING, GS_JC_VERSION Add Xpl2Protocol namespace with buildMessage/parseMessage for wire serialization. Replace raw send/receive API on Xpl2Client with typed protocol methods and internal dispatch. Auto-reply to KA_PING on all sockets (qDebug only). Add GS_JC_VERSION as first typed command with controllerId, firmwareVersion, hardwareVersion, printheadCount properties. Upgrade mock server from echo to line-based command dispatch with 1s KA_PING timer and canned GS_JC_VERSION response. Unknown commands produce qWarning instead of echo. Overhaul demo: remove raw send UI and port config, add wireDebug toggle and Get JC Version button. --- mock-server/EchoServer.cpp | 61 ++++++++++++++++++++++++++++++++++++++++------ mock-server/EchoServer.h | 13 ++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) (limited to 'mock-server') diff --git a/mock-server/EchoServer.cpp b/mock-server/EchoServer.cpp index 43fc6f9..8d86df1 100644 --- a/mock-server/EchoServer.cpp +++ b/mock-server/EchoServer.cpp @@ -1,6 +1,6 @@ /** * @file EchoServer.cpp - * @brief Simple TCP echo server for a single port. + * @brief Mock XPL2 server for a single port. */ #include "EchoServer.h" @@ -12,11 +12,16 @@ EchoServer::EchoServer (quint16 port, const char *name, QObject *parent) connect (this, &QTcpServer::newConnection, this, &EchoServer::onNewConnection); + connect (&m_pingTimer, &QTimer::timeout, this, &EchoServer::sendKaPing); + if (!listen (QHostAddress::Any, port)) qCritical ("Failed to listen on %s port %d: %s", m_name, m_port, qPrintable (errorString ())); else - qInfo ("Listening on %s port %d", m_name, m_port); + { + qInfo ("Listening on %s port %d", m_name, m_port); + m_pingTimer.start (1000); + } } void @@ -25,20 +30,23 @@ EchoServer::onNewConnection () while (auto *sock = nextPendingConnection ()) { qInfo ("[%s:%d] client connected", m_name, m_port); + m_clients.append (sock); connect (sock, &QTcpSocket::readyRead, this, - &EchoServer::onClientReadyRead); + &EchoServer::onClientMessageReady); connect (sock, &QTcpSocket::disconnected, this, &EchoServer::onClientDisconnected); } } void -EchoServer::onClientReadyRead () +EchoServer::onClientMessageReady () { auto *sock = qobject_cast (sender ()); - QByteArray data = sock->readAll (); - qInfo ("[%s:%d] echo %lld bytes", m_name, m_port, data.size ()); - sock->write (data); + while (sock->canReadLine ()) + { + QByteArray line = sock->readLine (); + handleCommand (sock, line); + } } void @@ -46,5 +54,44 @@ EchoServer::onClientDisconnected () { auto *sock = qobject_cast (sender ()); qInfo ("[%s:%d] client disconnected", m_name, m_port); + m_clients.removeOne (sock); sock->deleteLater (); } + +void +EchoServer::sendKaPing () +{ + for (auto *client : m_clients) + { + if (client->state () == QAbstractSocket::ConnectedState) + client->write ("KA_PING\n"); + } +} + +void +EchoServer::handleCommand (QTcpSocket *client, const QByteArray &line) +{ + QByteArray trimmed = line.trimmed (); + if (trimmed.isEmpty ()) + return; + + /* Split on first comma to get command token. */ + int comma = trimmed.indexOf (','); + QByteArray cmd = (comma >= 0) ? trimmed.left (comma) : trimmed; + + if (cmd == "KA_PING") + { + qDebug ("[%s:%d] KA_PING ACK received", m_name, m_port); + return; + } + + if (cmd == "GS_JC_VERSION") + { + qInfo ("[%s:%d] -> GS_JC_VERSION reply", m_name, m_port); + client->write ("GS_JC_VERSION,1,\"1.05\",\"2.00\",15\n"); + return; + } + + qWarning ("[%s:%d] Unknown command: %s", m_name, m_port, + trimmed.constData ()); +} diff --git a/mock-server/EchoServer.h b/mock-server/EchoServer.h index 2e51b1e..c0a41c9 100644 --- a/mock-server/EchoServer.h +++ b/mock-server/EchoServer.h @@ -1,10 +1,14 @@ /** * @file EchoServer.h - * @brief Simple TCP echo server for a single port. + * @brief Mock XPL2 server for a single port. */ #pragma once +#include #include +#include + +class QTcpSocket; class EchoServer : public QTcpServer { @@ -15,10 +19,15 @@ public: private slots: void onNewConnection (); - void onClientReadyRead (); + void onClientMessageReady (); void onClientDisconnected (); + void sendKaPing (); private: + void handleCommand (QTcpSocket *client, const QByteArray &line); + const char *m_name; quint16 m_port; + QList m_clients; + QTimer m_pingTimer; }; -- cgit v1.2.3