diff options
| -rw-r--r-- | demo/Main.qml | 29 | ||||
| -rw-r--r-- | mock-server/MockServer.cpp | 356 | ||||
| -rw-r--r-- | mock-server/MockServer.h | 77 | ||||
| -rw-r--r-- | mock-server/main.cpp | 4 | ||||
| -rw-r--r-- | src/Xpl2Client.cpp | 204 | ||||
| -rw-r--r-- | src/Xpl2Client.h | 35 |
6 files changed, 397 insertions, 308 deletions
diff --git a/demo/Main.qml b/demo/Main.qml index 9b9223f..6aca201 100644 --- a/demo/Main.qml +++ b/demo/Main.qml @@ -31,8 +31,9 @@ ApplicationWindow { Connections { function onConnectedChanged() { - debugConsole.appendLog(Xpl2Client.connected ? "Connected" : - "Disconnected"); + debugConsole.appendLog(Xpl2Client.connected + ? "Controller connected" : + "Controller disconnected"); } function onErrorOccurred(error: string) { @@ -43,6 +44,12 @@ ApplicationWindow { statusPage.lastJcStatus = status; } + function onListeningChanged() { + debugConsole.appendLog(Xpl2Client.listening + ? "Listening on ports 9110/9111/9112" : + "Stopped listening"); + } + function onPhStatusReceived(status) { statusPage.lastPhStatus = status; } @@ -95,26 +102,22 @@ ApplicationWindow { anchors.fill: parent Label { - text: "Host:" + text: Xpl2Client.connected ? "Controller connected" : + "Waiting for controller…" } - TextField { - id: hostField - + Item { Layout.fillWidth: true - text: Xpl2Client.host - - onEditingFinished: Xpl2Client.host = text } Button { - text: Xpl2Client.connected ? "Disconnect" : "Connect" + text: Xpl2Client.listening ? "Stop" : "Listen" onClicked: { - if (Xpl2Client.connected) - Xpl2Client.disconnectFromServer(); + if (Xpl2Client.listening) + Xpl2Client.stopListening(); else - Xpl2Client.connectToServer(); + Xpl2Client.startListening(); } } } diff --git a/mock-server/MockServer.cpp b/mock-server/MockServer.cpp index 87279b4..08eb116 100644 --- a/mock-server/MockServer.cpp +++ b/mock-server/MockServer.cpp @@ -1,11 +1,10 @@ /** * @file MockServer.cpp - * @brief Mock XPL2 server — listens on all three protocol ports. + * @brief Mock XPL2 server — connects out to the client on three protocol + * ports. */ #include "MockServer.h" -#include <QTcpSocket> - bool MockServer::s_wireDebug = false; void @@ -14,19 +13,22 @@ MockServer::enableWireDebug () s_wireDebug = true; } -MockServer::MockServer (QObject *parent) : QObject (parent) +MockServer::MockServer (const QString &host, QObject *parent) + : QObject (parent), m_host (host) { setupPort (m_command, "Command", 9110); setupPort (m_imaging, "Imaging", 9111); setupPort (m_status, "Status", 9112); - connect (&m_pingTimer, &QTimer::timeout, this, &MockServer::sendKaPing); - m_pingTimer.start (1000); + connect (&m_tickTimer, &QTimer::timeout, this, &MockServer::tick); + m_tickTimer.start (1000); connect (&m_jcStatusTimer, &QTimer::timeout, this, &MockServer::sendJcStatusMsg); connect (&m_phStatusTimer, &QTimer::timeout, this, &MockServer::sendPhStatusMsg); + + connectAll (); } void @@ -35,81 +37,102 @@ MockServer::setupPort (Port &port, const char *name, quint16 number) port.name = name; port.number = number; - connect (&port.server, &QTcpServer::newConnection, this, - &MockServer::onNewConnection); + connect (&port.socket, &QTcpSocket::connected, this, + &MockServer::onSocketConnected); + connect (&port.socket, &QTcpSocket::disconnected, this, + &MockServer::onSocketDisconnected); + connect (&port.socket, &QTcpSocket::readyRead, this, + &MockServer::onSocketMessageReady); + connect (&port.socket, &QAbstractSocket::errorOccurred, this, + [this, &port] (QAbstractSocket::SocketError) + { + qDebug ("%s Connection error: %s", + qPrintable (logTag (&port.socket)), + qPrintable (port.socket.errorString ())); + }); +} - if (!port.server.listen (QHostAddress::Any, number)) - qCritical ("%s Failed to listen: %s", qPrintable (logTag (number)), - qPrintable (port.server.errorString ())); - else - qInfo ("%s Listening", qPrintable (logTag (number))); +void +MockServer::connectAll () +{ + for (auto *port : { &m_command, &m_imaging, &m_status }) + if (port->socket.state () == QAbstractSocket::UnconnectedState) + port->socket.connectToHost (m_host, port->number); } QString -MockServer::logTag (quint16 localPort) const +MockServer::logTag (const QTcpSocket *socket) const { const char *name = "Unknown"; - if (localPort == m_command.number) - name = m_command.name; - else if (localPort == m_imaging.number) - name = m_imaging.name; - else if (localPort == m_status.number) - name = m_status.name; + quint16 number = 0; + if (socket == &m_command.socket) + { + name = m_command.name; + number = m_command.number; + } + else if (socket == &m_imaging.socket) + { + name = m_imaging.name; + number = m_imaging.number; + } + else if (socket == &m_status.socket) + { + name = m_status.name; + number = m_status.number; + } /* Fixed-width tag: "[Command:9110]" = 14 chars, left-padded to 15. */ - return QStringLiteral ("[%1:%2]").arg (name).arg (localPort).leftJustified ( - 15); + return QStringLiteral ("[%1:%2]").arg (name).arg (number).leftJustified (15); } void -MockServer::onNewConnection () +MockServer::onSocketConnected () { - auto *server = qobject_cast<QTcpServer *> (sender ()); - while (auto *sock = server->nextPendingConnection ()) - { - quint16 lp = sock->localPort (); - qInfo ("%s Client connected", qPrintable (logTag (lp))); - m_clients.append (sock); - connect (sock, &QTcpSocket::readyRead, this, - &MockServer::onClientMessageReady); - connect (sock, &QTcpSocket::disconnected, this, - &MockServer::onClientDisconnected); - } + auto *socket = qobject_cast<QTcpSocket *> (sender ()); + qInfo ("%s Connected to client", qPrintable (logTag (socket))); } void -MockServer::onClientMessageReady () +MockServer::onSocketDisconnected () { - auto *sock = qobject_cast<QTcpSocket *> (sender ()); - while (sock->canReadLine ()) - { - QByteArray line = sock->readLine (); - handleCommand (sock, line); - } + auto *socket = qobject_cast<QTcpSocket *> (sender ()); + qInfo ("%s Disconnected from client", qPrintable (logTag (socket))); } void -MockServer::onClientDisconnected () +MockServer::onSocketMessageReady () { - auto *sock = qobject_cast<QTcpSocket *> (sender ()); - quint16 lp = sock->localPort (); - qInfo ("%s Client disconnected", qPrintable (logTag (lp))); - m_clients.removeOne (sock); - sock->deleteLater (); + auto *socket = qobject_cast<QTcpSocket *> (sender ()); + Port *port = nullptr; + if (socket == &m_command.socket) + port = &m_command; + else if (socket == &m_imaging.socket) + port = &m_imaging; + else + port = &m_status; + + while (socket->canReadLine ()) + { + QByteArray line = socket->readLine (); + handleCommand (*port, line); + } } void -MockServer::sendKaPing () +MockServer::tick () { - for (auto *client : m_clients) + /* Send KA_PING on connected sockets, retry connection on disconnected. */ + for (auto *port : { &m_command, &m_imaging, &m_status }) { - if (client->state () == QAbstractSocket::ConnectedState) - sendReply (client, "KA_PING\n"); + if (port->socket.state () == QAbstractSocket::ConnectedState) + sendReply (port->socket, "KA_PING\n"); + else if (port->socket.state () == QAbstractSocket::UnconnectedState) + port->socket.connectToHost (m_host, port->number); } } void -MockServer::handleCommand (QTcpSocket *client, const QByteArray &line) +MockServer::handleCommand (Port &port, const QByteArray &line) { QByteArray trimmed = line.trimmed (); if (trimmed.isEmpty ()) @@ -121,37 +144,37 @@ MockServer::handleCommand (QTcpSocket *client, const QByteArray &line) QByteArray params = (comma >= 0) ? trimmed.mid (comma + 1) : QByteArray (); if (cmd == "KA_PING") - handleKaPing (client, params); + handleKaPing (port, params); else if (cmd == "GS_JC_VERSION") - handleGsJcVersion (client); + handleGsJcVersion (port.socket); else if (cmd == "GS_PH_VERSION") - handleGsPhVersion (client, params); + handleGsPhVersion (port.socket, params); /* CN_ JC success shape (no params needed) */ else if (cmd == "CN_JETTING_ALL_ON" || cmd == "CN_JETTING_ON" || cmd == "CN_JETTING_OFF" || cmd == "CN_JC_ID_LED_ON" || cmd == "CN_JC_ID_LED_OFF" || cmd == "CN_JC_CALIBRATION" || cmd == "CN_JC_RESET_FAULT_CODES") - handleCnJcSuccess (client, cmd); + handleCnJcSuccess (port.socket, cmd); /* CN_ PH success shape (params carry printheadId) */ else if (cmd == "CN_PH_JETTING_ON" || cmd == "CN_PH_JETTING_OFF" || cmd == "CN_PH_ID_LED_ON" || cmd == "CN_PH_ID_LED_OFF" || cmd == "CN_PH_CALIBRATION" || cmd == "CN_PH_RESET_FAULT_CODES" || cmd == "CN_PH_NOZZLES_DISABLED") - handleCnPhSuccess (client, cmd, params); + handleCnPhSuccess (port.socket, cmd, params); /* CN_ custom-shape commands */ else if (cmd == "CN_PH_CALIBRATION_DATA") - handleCnPhCalibrationData (client, params); + handleCnPhCalibrationData (port.socket, params); else if (cmd == "CN_PH_CALIBRATION_RAW_DATA") - handleCnPhCalibrationRawData (client, params); + handleCnPhCalibrationRawData (port.socket, params); else if (cmd == "CN_PH_CALIBRATED_BASE_FREQUENCY") - handleCnPhCalibratedBaseFrequency (client, params); + handleCnPhCalibratedBaseFrequency (port.socket, params); /* CN_ status messaging (arrives on status port) */ else if (cmd == "CN_JC_STATUS_MESSAGING_START" || cmd == "CN_PH_STATUS_MESSAGING_START") - handleCnStatusMessagingStart (client, cmd, params); + handleCnStatusMessagingStart (port.socket, cmd, params); else if (cmd == "CN_JC_STATUS_MESSAGING_STOP" || cmd == "CN_PH_STATUS_MESSAGING_STOP") - handleCnStatusMessagingStop (client, cmd); + handleCnStatusMessagingStop (port.socket, cmd); /* CF_ JC success shape */ else if (cmd == "CF_PH_DEASSIGN_ID" || cmd == "CF_JC_SAVE_CALIBRATION" || cmd == "CF_JC_RESET_CALIBRATION" @@ -161,152 +184,151 @@ MockServer::handleCommand (QTcpSocket *client, const QByteArray &line) || cmd == "CF_JC_RESET_CONTROLLER_SOFTWARE" || cmd == "CF_JC_RESTART" || cmd == "CF_JC_SHUTDOWN" || cmd == "CF_JC_SAVE_ALL_PRINTHEAD_SETTINGS") - handleCnJcSuccess (client, cmd); + handleCnJcSuccess (port.socket, cmd); /* CF_ PH success shape */ else if (cmd == "CF_PH_SET_ID" || cmd == "CF_PH_SAVE_CALIBRATION" || cmd == "CF_PH_RESET_CALIBRATION" || cmd == "CF_PH_RESET_ALL_SETTINGS" || cmd == "CF_PH_REBOOT" || cmd == "CF_PH_SAVE_SETTINGS") - handleCnPhSuccess (client, cmd, params); + handleCnPhSuccess (port.socket, cmd, params); /* CF_ custom-shape commands */ else if (cmd == "CF_JC_SET_PURGE_SETTINGS") - handleCfJcSetPurgeSettings (client, params); + handleCfJcSetPurgeSettings (port.socket, params); else if (cmd == "CF_JC_SET_JETTING_PARAMS") - handleCfJcSetJettingParams (client, params); + handleCfJcSetJettingParams (port.socket, params); else if (cmd == "CF_PH_SET_JETTING_PARAMS") - handleCfPhJettingParams (client, cmd, params); + handleCfPhJettingParams (port.socket, cmd, params); else if (cmd == "CF_PH_GET_JETTING_PARAMS") - handleCfPhJettingParams (client, cmd, params); + handleCfPhJettingParams (port.socket, cmd, params); else if (cmd == "CF_JC_SETTER") - handleCfJcSetter (client, params); + handleCfJcSetter (port.socket, params); else if (cmd == "CF_PH_SETTER") - handleCfPhSetter (client, params); + handleCfPhSetter (port.socket, params); else if (cmd == "CF_JC_GETTER") - handleCfJcGetter (client, params); + handleCfJcGetter (port.socket, params); else if (cmd == "CF_PH_GETTER") - handleCfPhGetter (client, params); + handleCfPhGetter (port.socket, params); /* Imaging commands (port 2) */ else if (cmd == "m2") - handleImagingStart (client, params); + handleImagingStart (port.socket, params); else if (cmd == "m4") - handleImagingStop (client); + handleImagingStop (port.socket); else if (cmd == "m0" || cmd == "m5") - handleImagingMaskStart (client, cmd, params); + handleImagingMaskStart (port.socket, cmd, params); else if (cmd == "m1" || cmd == "m6") - handleImagingMaskEnd (client, cmd, params); + handleImagingMaskEnd (port.socket, cmd, params); else if (cmd == "m3") - handleImageCount (client); + handleImageCount (port.socket); else - qWarning ("%s Unknown command: %s", - qPrintable (logTag (client->localPort ())), cmd.constData ()); + qWarning ("%s Unknown command: %s", qPrintable (logTag (&port.socket)), + cmd.constData ()); } void -MockServer::sendReply (QTcpSocket *client, const QByteArray &data) +MockServer::sendReply (QTcpSocket &socket, const QByteArray &data) { - client->write (data); + socket.write (data); QByteArray trimmed = data.trimmed (); int comma = trimmed.indexOf (','); QByteArray cmd = (comma >= 0) ? trimmed.left (comma) : trimmed; QByteArray wire; if (s_wireDebug) wire = " >> " + trimmed; - qDebug ("%s TX %s%s", qPrintable (logTag (client->localPort ())), - cmd.constData (), wire.constData ()); + qDebug ("%s TX %s%s", qPrintable (logTag (&socket)), cmd.constData (), + wire.constData ()); } void -MockServer::handleKaPing (QTcpSocket *client, const QByteArray ¶ms) +MockServer::handleKaPing (Port &port, const QByteArray ¶ms) { QByteArray wire; if (s_wireDebug) wire = " << KA_PING," + params; - qDebug ("%s RX KA_PING ACK%s", qPrintable (logTag (client->localPort ())), + qDebug ("%s RX KA_PING ACK%s", qPrintable (logTag (&port.socket)), wire.constData ()); } void -MockServer::handleGsJcVersion (QTcpSocket *client) +MockServer::handleGsJcVersion (QTcpSocket &socket) { - qDebug ("%s RX GS_JC_VERSION", qPrintable (logTag (client->localPort ()))); - sendReply (client, "GS_JC_VERSION,1,\"1.05\",\"2.00\",15\n"); + qDebug ("%s RX GS_JC_VERSION", qPrintable (logTag (&socket))); + sendReply (socket, "GS_JC_VERSION,1,\"1.05\",\"2.00\",15\n"); } void -MockServer::handleGsPhVersion (QTcpSocket *client, const QByteArray ¶ms) +MockServer::handleGsPhVersion (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX GS_PH_VERSION,%s", qPrintable (logTag (client->localPort ())), + qDebug ("%s RX GS_PH_VERSION,%s", qPrintable (logTag (&socket)), params.constData ()); /* Echo back canned version info for whatever printhead ID was requested. */ - sendReply (client, QByteArray ("GS_PH_VERSION,1,") + params + sendReply (socket, QByteArray ("GS_PH_VERSION,1,") + params + ",\"3.10\",\"1.00\",\"Standard\"," "\"2.05\",\"1.02\",\"0.9.1\"\n"); } void -MockServer::handleCnJcSuccess (QTcpSocket *client, const QByteArray &cmd) +MockServer::handleCnJcSuccess (QTcpSocket &socket, const QByteArray &cmd) { - qDebug ("%s RX %s", qPrintable (logTag (client->localPort ())), - cmd.constData ()); - sendReply (client, cmd + ",1,1\n"); + qDebug ("%s RX %s", qPrintable (logTag (&socket)), cmd.constData ()); + sendReply (socket, cmd + ",1,1\n"); } void -MockServer::handleCnPhSuccess (QTcpSocket *client, const QByteArray &cmd, +MockServer::handleCnPhSuccess (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms) { - qDebug ("%s RX %s,%s", qPrintable (logTag (client->localPort ())), - cmd.constData (), params.constData ()); + qDebug ("%s RX %s,%s", qPrintable (logTag (&socket)), cmd.constData (), + params.constData ()); /* Extract printhead ID (first field before any comma). */ int comma = params.indexOf (','); QByteArray phId = (comma >= 0) ? params.left (comma) : params; - sendReply (client, cmd + ",1," + phId + ",1\n"); + sendReply (socket, cmd + ",1," + phId + ",1\n"); } void -MockServer::handleCnPhCalibrationData (QTcpSocket *client, +MockServer::handleCnPhCalibrationData (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CN_PH_CALIBRATION_DATA,%s", - qPrintable (logTag (client->localPort ())), params.constData ()); + qDebug ("%s RX CN_PH_CALIBRATION_DATA,%s", qPrintable (logTag (&socket)), + params.constData ()); /* Reply: controllerId, phId, then 48 floats (-1 = uncalibrated). */ QByteArray reply = "CN_PH_CALIBRATION_DATA,1," + params; for (int i = 0; i < 48; ++i) reply += ",-1"; reply += '\n'; - sendReply (client, reply); + sendReply (socket, reply); } void -MockServer::handleCnPhCalibrationRawData (QTcpSocket *client, +MockServer::handleCnPhCalibrationRawData (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CN_PH_CALIBRATION_RAW_DATA,%s", - qPrintable (logTag (client->localPort ())), params.constData ()); + qDebug ("%s RX CN_PH_CALIBRATION_RAW_DATA,%s", qPrintable (logTag (&socket)), + params.constData ()); QByteArray reply = "CN_PH_CALIBRATION_RAW_DATA,1," + params; for (int i = 0; i < 48; ++i) reply += ",-1"; reply += '\n'; - sendReply (client, reply); + sendReply (socket, reply); } void -MockServer::handleCnPhCalibratedBaseFrequency (QTcpSocket *client, +MockServer::handleCnPhCalibratedBaseFrequency (QTcpSocket &socket, const QByteArray ¶ms) { qDebug ("%s RX CN_PH_CALIBRATED_BASE_FREQUENCY,%s", - qPrintable (logTag (client->localPort ())), params.constData ()); - sendReply (client, + qPrintable (logTag (&socket)), params.constData ()); + sendReply (socket, "CN_PH_CALIBRATED_BASE_FREQUENCY,1," + params + ",10.0,10.0\n"); } void -MockServer::handleCnStatusMessagingStart (QTcpSocket *client, +MockServer::handleCnStatusMessagingStart (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms) { - qDebug ("%s RX %s,%s", qPrintable (logTag (client->localPort ())), - cmd.constData (), params.constData ()); + qDebug ("%s RX %s,%s", qPrintable (logTag (&socket)), cmd.constData (), + params.constData ()); /* Parse level and interval from params: "level,interval" */ QList<QByteArray> parts = params.split (','); @@ -324,89 +346,91 @@ MockServer::handleCnStatusMessagingStart (QTcpSocket *client, m_phStatusTimer.start (interval); } - sendReply (client, cmd + ",1," + params + ",1\n"); + sendReply (socket, cmd + ",1," + params + ",1\n"); } void -MockServer::handleCnStatusMessagingStop (QTcpSocket *client, +MockServer::handleCnStatusMessagingStop (QTcpSocket &socket, const QByteArray &cmd) { - qDebug ("%s RX %s", qPrintable (logTag (client->localPort ())), - cmd.constData ()); + qDebug ("%s RX %s", qPrintable (logTag (&socket)), cmd.constData ()); if (cmd == "CN_JC_STATUS_MESSAGING_STOP") m_jcStatusTimer.stop (); else m_phStatusTimer.stop (); - sendReply (client, cmd + ",1,1\n"); + sendReply (socket, cmd + ",1,1\n"); } void -MockServer::handleCfJcSetPurgeSettings (QTcpSocket *client, +MockServer::handleCfJcSetPurgeSettings (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CF_JC_SET_PURGE_SETTINGS,%s", - qPrintable (logTag (client->localPort ())), params.constData ()); - sendReply (client, "CF_JC_SET_PURGE_SETTINGS,1," + params + ",1\n"); + qDebug ("%s RX CF_JC_SET_PURGE_SETTINGS,%s", qPrintable (logTag (&socket)), + params.constData ()); + sendReply (socket, "CF_JC_SET_PURGE_SETTINGS,1," + params + ",1\n"); } void -MockServer::handleCfJcSetJettingParams (QTcpSocket *client, +MockServer::handleCfJcSetJettingParams (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CF_JC_SET_JETTING_PARAMS,%s", - qPrintable (logTag (client->localPort ())), params.constData ()); - sendReply (client, "CF_JC_SET_JETTING_PARAMS,1," + params + ",1\n"); + qDebug ("%s RX CF_JC_SET_JETTING_PARAMS,%s", qPrintable (logTag (&socket)), + params.constData ()); + sendReply (socket, "CF_JC_SET_JETTING_PARAMS,1," + params + ",1\n"); } void -MockServer::handleCfPhJettingParams (QTcpSocket *client, const QByteArray &cmd, +MockServer::handleCfPhJettingParams (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms) { - qDebug ("%s RX %s,%s", qPrintable (logTag (client->localPort ())), - cmd.constData (), params.constData ()); + qDebug ("%s RX %s,%s", qPrintable (logTag (&socket)), cmd.constData (), + params.constData ()); if (cmd == "CF_PH_GET_JETTING_PARAMS") - sendReply (client, cmd + ",1," + params + ",0,0,0,0,0,1\n"); + sendReply (socket, cmd + ",1," + params + ",0,0,0,0,0,1\n"); else - sendReply (client, cmd + ",1," + params + ",1\n"); + sendReply (socket, cmd + ",1," + params + ",1\n"); } void -MockServer::handleCfJcSetter (QTcpSocket *client, const QByteArray ¶ms) +MockServer::handleCfJcSetter (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CF_JC_SETTER,%s", qPrintable (logTag (client->localPort ())), + qDebug ("%s RX CF_JC_SETTER,%s", qPrintable (logTag (&socket)), params.constData ()); - sendReply (client, "CF_JC_SETTER,1," + params + ",1\n"); + sendReply (socket, "CF_JC_SETTER,1," + params + ",1\n"); } void -MockServer::handleCfPhSetter (QTcpSocket *client, const QByteArray ¶ms) +MockServer::handleCfPhSetter (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CF_PH_SETTER,%s", qPrintable (logTag (client->localPort ())), + qDebug ("%s RX CF_PH_SETTER,%s", qPrintable (logTag (&socket)), params.constData ()); - sendReply (client, "CF_PH_SETTER,1," + params + ",1\n"); + sendReply (socket, "CF_PH_SETTER,1," + params + ",1\n"); } void -MockServer::handleCfJcGetter (QTcpSocket *client, const QByteArray ¶ms) +MockServer::handleCfJcGetter (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CF_JC_GETTER,%s", qPrintable (logTag (client->localPort ())), + qDebug ("%s RX CF_JC_GETTER,%s", qPrintable (logTag (&socket)), params.constData ()); - sendReply (client, "CF_JC_GETTER,1," + params + ",\"0\",1\n"); + sendReply (socket, "CF_JC_GETTER,1," + params + ",\"0\",1\n"); } void -MockServer::handleCfPhGetter (QTcpSocket *client, const QByteArray ¶ms) +MockServer::handleCfPhGetter (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX CF_PH_GETTER,%s", qPrintable (logTag (client->localPort ())), + qDebug ("%s RX CF_PH_GETTER,%s", qPrintable (logTag (&socket)), params.constData ()); - sendReply (client, "CF_PH_GETTER,1," + params + ",\"0\",1\n"); + sendReply (socket, "CF_PH_GETTER,1," + params + ",\"0\",1\n"); } void MockServer::sendJcStatusMsg () { + if (m_status.socket.state () != QAbstractSocket::ConnectedState) + return; + static int tick = 0; ++tick; bool odd = (tick % 2) != 0; @@ -432,15 +456,15 @@ MockServer::sendJcStatusMsg () } base += '\n'; - for (auto *client : m_clients) - if (client->state () == QAbstractSocket::ConnectedState - && client->localPort () == m_status.number) - sendReply (client, base); + sendReply (m_status.socket, base); } void MockServer::sendPhStatusMsg () { + if (m_status.socket.state () != QAbstractSocket::ConnectedState) + return; + static int tick = 0; ++tick; bool odd = (tick % 2) != 0; @@ -475,47 +499,43 @@ MockServer::sendPhStatusMsg () } base += '\n'; - for (auto *client : m_clients) - if (client->state () == QAbstractSocket::ConnectedState - && client->localPort () == m_status.number) - sendReply (client, base); + sendReply (m_status.socket, base); } void -MockServer::handleImagingStart (QTcpSocket *client, const QByteArray ¶ms) +MockServer::handleImagingStart (QTcpSocket &socket, const QByteArray ¶ms) { - qDebug ("%s RX m2,%s", qPrintable (logTag (client->localPort ())), - params.constData ()); - sendReply (client, "n,\"A\"\n"); + qDebug ("%s RX m2,%s", qPrintable (logTag (&socket)), params.constData ()); + sendReply (socket, "n,\"A\"\n"); } void -MockServer::handleImagingStop (QTcpSocket *client) +MockServer::handleImagingStop (QTcpSocket &socket) { - qDebug ("%s RX m4", qPrintable (logTag (client->localPort ()))); - sendReply (client, "m4,1\n"); + qDebug ("%s RX m4", qPrintable (logTag (&socket))); + sendReply (socket, "m4,1\n"); } void -MockServer::handleImagingMaskStart (QTcpSocket *client, const QByteArray &cmd, +MockServer::handleImagingMaskStart (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms) { - qDebug ("%s RX %s,%s", qPrintable (logTag (client->localPort ())), - cmd.constData (), params.constData ()); + qDebug ("%s RX %s,%s", qPrintable (logTag (&socket)), cmd.constData (), + params.constData ()); } void -MockServer::handleImagingMaskEnd (QTcpSocket *client, const QByteArray &cmd, +MockServer::handleImagingMaskEnd (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms) { - qDebug ("%s RX %s,%s", qPrintable (logTag (client->localPort ())), - cmd.constData (), params.constData ()); - sendReply (client, "n,\"A\"\n"); + qDebug ("%s RX %s,%s", qPrintable (logTag (&socket)), cmd.constData (), + params.constData ()); + sendReply (socket, "n,\"A\"\n"); } void -MockServer::handleImageCount (QTcpSocket *client) +MockServer::handleImageCount (QTcpSocket &socket) { - qDebug ("%s RX m3", qPrintable (logTag (client->localPort ()))); - sendReply (client, "n,\"0\"\n"); + qDebug ("%s RX m3", qPrintable (logTag (&socket))); + sendReply (socket, "n,\"0\"\n"); } diff --git a/mock-server/MockServer.h b/mock-server/MockServer.h index 74b2731..242cb32 100644 --- a/mock-server/MockServer.h +++ b/mock-server/MockServer.h @@ -1,88 +1,87 @@ /** * @file MockServer.h - * @brief Mock XPL2 server — listens on all three protocol ports. + * @brief Mock XPL2 server — connects out to the client on three protocol + * ports. */ #pragma once -#include <QList> #include <QObject> -#include <QTcpServer> +#include <QTcpSocket> #include <QTimer> -class QTcpSocket; - class MockServer : public QObject { Q_OBJECT public: - explicit MockServer (QObject *parent = nullptr); + explicit MockServer (const QString &host, QObject *parent = nullptr); static void enableWireDebug (); private slots: - void onNewConnection (); - void onClientMessageReady (); - void onClientDisconnected (); - /* Send KA_PING keepalive to all connected clients. */ - void sendKaPing (); + void onSocketConnected (); + void onSocketDisconnected (); + void onSocketMessageReady (); + /* Send KA_PING on connected sockets, retry connection on disconnected. */ + void tick (); void sendJcStatusMsg (); void sendPhStatusMsg (); private: struct Port { - QTcpServer server; + QTcpSocket socket; const char *name = nullptr; quint16 number = 0; }; void setupPort (Port &port, const char *name, quint16 number); + void connectAll (); /* Return a fixed-width "[Name:port]" tag for log lines. */ - QString logTag (quint16 localPort) const; + QString logTag (const QTcpSocket *socket) const; /* Parse incoming line, log RX, and dispatch to the matching handler. */ - void handleCommand (QTcpSocket *client, const QByteArray &line); - void sendReply (QTcpSocket *client, const QByteArray &data); - void handleKaPing (QTcpSocket *client, const QByteArray ¶ms); - void handleGsJcVersion (QTcpSocket *client); - void handleGsPhVersion (QTcpSocket *client, const QByteArray ¶ms); + void handleCommand (Port &port, const QByteArray &line); + void sendReply (QTcpSocket &socket, const QByteArray &data); + void handleKaPing (Port &port, const QByteArray ¶ms); + void handleGsJcVersion (QTcpSocket &socket); + void handleGsPhVersion (QTcpSocket &socket, const QByteArray ¶ms); /* CN_ control command handlers */ - void handleCnJcSuccess (QTcpSocket *client, const QByteArray &cmd); - void handleCnPhSuccess (QTcpSocket *client, const QByteArray &cmd, + void handleCnJcSuccess (QTcpSocket &socket, const QByteArray &cmd); + void handleCnPhSuccess (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms); - void handleCnPhCalibrationData (QTcpSocket *client, + void handleCnPhCalibrationData (QTcpSocket &socket, const QByteArray ¶ms); - void handleCnPhCalibrationRawData (QTcpSocket *client, + void handleCnPhCalibrationRawData (QTcpSocket &socket, const QByteArray ¶ms); - void handleCnPhCalibratedBaseFrequency (QTcpSocket *client, + void handleCnPhCalibratedBaseFrequency (QTcpSocket &socket, const QByteArray ¶ms); - void handleCnStatusMessagingStart (QTcpSocket *client, const QByteArray &cmd, + void handleCnStatusMessagingStart (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms); - void handleCnStatusMessagingStop (QTcpSocket *client, const QByteArray &cmd); + void handleCnStatusMessagingStop (QTcpSocket &socket, const QByteArray &cmd); /* CF_ configuration command handlers */ - void handleCfJcSetPurgeSettings (QTcpSocket *client, + void handleCfJcSetPurgeSettings (QTcpSocket &socket, const QByteArray ¶ms); - void handleCfJcSetJettingParams (QTcpSocket *client, + void handleCfJcSetJettingParams (QTcpSocket &socket, const QByteArray ¶ms); - void handleCfPhJettingParams (QTcpSocket *client, const QByteArray &cmd, + void handleCfPhJettingParams (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms); - void handleCfJcSetter (QTcpSocket *client, const QByteArray ¶ms); - void handleCfPhSetter (QTcpSocket *client, const QByteArray ¶ms); - void handleCfJcGetter (QTcpSocket *client, const QByteArray ¶ms); - void handleCfPhGetter (QTcpSocket *client, const QByteArray ¶ms); + void handleCfJcSetter (QTcpSocket &socket, const QByteArray ¶ms); + void handleCfPhSetter (QTcpSocket &socket, const QByteArray ¶ms); + void handleCfJcGetter (QTcpSocket &socket, const QByteArray ¶ms); + void handleCfPhGetter (QTcpSocket &socket, const QByteArray ¶ms); /* Imaging command handlers */ - void handleImagingStart (QTcpSocket *client, const QByteArray ¶ms); - void handleImagingStop (QTcpSocket *client); - void handleImagingMaskStart (QTcpSocket *client, const QByteArray &cmd, + void handleImagingStart (QTcpSocket &socket, const QByteArray ¶ms); + void handleImagingStop (QTcpSocket &socket); + void handleImagingMaskStart (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms); - void handleImagingMaskEnd (QTcpSocket *client, const QByteArray &cmd, + void handleImagingMaskEnd (QTcpSocket &socket, const QByteArray &cmd, const QByteArray ¶ms); - void handleImageCount (QTcpSocket *client); + void handleImageCount (QTcpSocket &socket); + QString m_host; Port m_command; Port m_imaging; Port m_status; - QList<QTcpSocket *> m_clients; - QTimer m_pingTimer; + QTimer m_tickTimer; QTimer m_jcStatusTimer; QTimer m_phStatusTimer; int m_jcStatusLevel = 1; diff --git a/mock-server/main.cpp b/mock-server/main.cpp index 5613462..9a55463 100644 --- a/mock-server/main.cpp +++ b/mock-server/main.cpp @@ -16,13 +16,15 @@ main (int argc, char *argv[]) QCommandLineParser parser; parser.addOption ({ "wire-debug", "Log raw wire TX/RX to dev log" }); + parser.addOption ({ "host", "Target host to connect to (default 127.0.0.1)", + "address", "127.0.0.1" }); parser.addHelpOption (); parser.process (app); if (parser.isSet ("wire-debug")) MockServer::enableWireDebug (); - new MockServer (&app); + new MockServer (parser.value ("host"), &app); return app.exec (); } diff --git a/src/Xpl2Client.cpp b/src/Xpl2Client.cpp index d3a6da2..4fa502e 100644 --- a/src/Xpl2Client.cpp +++ b/src/Xpl2Client.cpp @@ -5,6 +5,7 @@ #include "Xpl2Client.h" #include <QDebug> +#include <QTcpSocket> bool Xpl2Client::s_wireDebug = false; @@ -157,36 +158,19 @@ Xpl2Client::s_responseTable = { Xpl2Client::Xpl2Client (QObject *parent) : QObject (parent) { - for (auto *socket : { &m_commandSocket, &m_imagingSocket, &m_statusSocket }) - { - connect (socket, &QTcpSocket::connected, this, - &Xpl2Client::onSocketConnected); - connect (socket, &QTcpSocket::disconnected, this, - &Xpl2Client::onSocketDisconnected); - connect (socket, &QTcpSocket::readyRead, this, - &Xpl2Client::onSocketMessageReady); - connect (socket, &QAbstractSocket::errorOccurred, this, - &Xpl2Client::onSocketError); - } + setupServer (m_commandServer, m_commandPort); + setupServer (m_imagingServer, m_imagingPort); + setupServer (m_statusServer, m_statusPort); } /* ------------------------------------------------------------------ */ /* Properties */ /* ------------------------------------------------------------------ */ -QString -Xpl2Client::host () const -{ - return m_host; -} - -void -Xpl2Client::setHost (const QString &host) +bool +Xpl2Client::isListening () const { - if (m_host == host) - return; - m_host = host; - emit hostChanged (); + return m_listening; } bool @@ -230,25 +214,78 @@ Xpl2Client::enableWireDebug () /* ------------------------------------------------------------------ */ void -Xpl2Client::connectToServer () +Xpl2Client::setupServer (QTcpServer &server, quint16 port) +{ + Q_UNUSED (port) + connect (&server, &QTcpServer::newConnection, this, + &Xpl2Client::onNewConnection); +} + +void +Xpl2Client::startListening () { - if (m_connected) + if (m_listening) { - emit statusMessage (QStringLiteral ("Already connected")); + emit statusMessage (QStringLiteral ("Already listening")); return; } - emit statusMessage (QStringLiteral ("Connecting to %1…").arg (m_host)); - m_commandSocket.connectToHost (m_host, m_commandPort); - m_imagingSocket.connectToHost (m_host, m_imagingPort); - m_statusSocket.connectToHost (m_host, m_statusPort); + if (!m_commandServer.listen (QHostAddress::Any, m_commandPort) + || !m_imagingServer.listen (QHostAddress::Any, m_imagingPort) + || !m_statusServer.listen (QHostAddress::Any, m_statusPort)) + { + emit errorOccurred (QStringLiteral ("Failed to listen: %1 / %2 / %3") + .arg (m_commandServer.errorString ()) + .arg (m_imagingServer.errorString ()) + .arg (m_statusServer.errorString ())); + m_commandServer.close (); + m_imagingServer.close (); + m_statusServer.close (); + return; + } + m_listening = true; + emit listeningChanged (); + emit statusMessage (QStringLiteral ("Listening on ports %1/%2/%3…") + .arg (m_commandPort) + .arg (m_imagingPort) + .arg (m_statusPort)); } void -Xpl2Client::disconnectFromServer () +Xpl2Client::stopListening () +{ + m_commandServer.close (); + m_imagingServer.close (); + m_statusServer.close (); + + auto cleanup = [] (QTcpSocket *&sock) + { + if (sock) + { + sock->disconnectFromHost (); + sock->deleteLater (); + sock = nullptr; + } + }; + cleanup (m_commandSocket); + cleanup (m_imagingSocket); + cleanup (m_statusSocket); + + if (m_listening) + { + m_listening = false; + emit listeningChanged (); + } + updateConnectedState (); +} + +QTcpSocket *& +Xpl2Client::socketForServer (QTcpServer *server) { - m_commandSocket.disconnectFromHost (); - m_imagingSocket.disconnectFromHost (); - m_statusSocket.disconnectFromHost (); + if (server == &m_commandServer) + return m_commandSocket; + if (server == &m_imagingServer) + return m_imagingSocket; + return m_statusSocket; } void @@ -609,22 +646,22 @@ Xpl2Client::imageCount () /* ------------------------------------------------------------------ */ void -Xpl2Client::sendCommand (QTcpSocket &socket, const QByteArray &command, +Xpl2Client::sendCommand (QTcpSocket *socket, const QByteArray &command, const QVariantList ¶ms) { - if (socket.state () != QAbstractSocket::ConnectedState) + if (!socket || socket->state () != QAbstractSocket::ConnectedState) { emit errorOccurred (QStringLiteral ("Not connected for %1") .arg (QString::fromUtf8 (command))); return; } QByteArray data = Xpl2Protocol::buildMessage (command, params); - socket.write (data); + socket->write (data); QByteArray wire; if (s_wireDebug) wire = " >> " + data.trimmed (); - qDebug ("%s TX %s%s", qPrintable (logTag (&socket)), command.constData (), + qDebug ("%s TX %s%s", qPrintable (logTag (socket)), command.constData (), wire.constData ()); } @@ -639,8 +676,8 @@ Xpl2Client::dispatchCommandMessage (const Xpl2Protocol::ParsedMessage &msg) handleGsJcVersion (msg.params); else if (msg.command == "GS_PH_VERSION") handleGsPhVersion (msg.params); - else if (!dispatchResponse (msg.command, msg.params, &m_commandSocket)) - qWarning ("%s Unknown command: %s", qPrintable (logTag (&m_commandSocket)), + else if (!dispatchResponse (msg.command, msg.params, m_commandSocket)) + qWarning ("%s Unknown command: %s", qPrintable (logTag (m_commandSocket)), msg.command.constData ()); } @@ -656,7 +693,7 @@ Xpl2Client::dispatchImagingMessage (const Xpl2Protocol::ParsedMessage &msg) int lines = 0; if (!msg.params.isEmpty ()) lines = msg.params[0].toString ().toInt (nullptr, 16); - qDebug ("%s n imageLines=%d", qPrintable (logTag (&m_imagingSocket)), + qDebug ("%s n imageLines=%d", qPrintable (logTag (m_imagingSocket)), lines); emit statusMessage (QStringLiteral ("RX n: imageLines=%1").arg (lines)); emit imagingReply (lines); @@ -664,13 +701,13 @@ Xpl2Client::dispatchImagingMessage (const Xpl2Protocol::ParsedMessage &msg) else if (msg.command == "m4") { bool ok = !msg.params.isEmpty () && msg.params[0].toInt () == 1; - qDebug ("%s m4 success=%d", qPrintable (logTag (&m_imagingSocket)), + qDebug ("%s m4 success=%d", qPrintable (logTag (m_imagingSocket)), ok); emit statusMessage (QStringLiteral ("RX m4: success=%1").arg (ok)); emit imagingStopResult (ok); } - else if (!dispatchResponse (msg.command, msg.params, &m_imagingSocket)) - qWarning ("%s Unknown command: %s", qPrintable (logTag (&m_imagingSocket)), + else if (!dispatchResponse (msg.command, msg.params, m_imagingSocket)) + qWarning ("%s Unknown command: %s", qPrintable (logTag (m_imagingSocket)), msg.command.constData ()); } @@ -685,13 +722,13 @@ Xpl2Client::dispatchStatusMessage (const Xpl2Protocol::ParsedMessage &msg) handleEvStatusMsgJc (msg.params); else if (msg.command == "EV_STATUS_MSG_PH") handleEvStatusMsgPh (msg.params); - else if (!dispatchResponse (msg.command, msg.params, &m_statusSocket)) - qWarning ("%s Unknown command: %s", qPrintable (logTag (&m_statusSocket)), + else if (!dispatchResponse (msg.command, msg.params, m_statusSocket)) + qWarning ("%s Unknown command: %s", qPrintable (logTag (m_statusSocket)), msg.command.constData ()); } void -Xpl2Client::handleKaPing (QTcpSocket &socket) +Xpl2Client::handleKaPing (QTcpSocket *socket) { sendCommand (socket, "KA_PING", { 1 }); } @@ -709,7 +746,7 @@ Xpl2Client::handleGsJcVersion (const QVariantList ¶ms) m_hardwareVersion = params[2].toString (); m_printheadCount = params[3].toInt (); qDebug ("%s controller=%d fw=%s hw=%s phCount=%d", - qPrintable (logTag (&m_commandSocket)), m_controllerId, + qPrintable (logTag (m_commandSocket)), m_controllerId, qPrintable (m_firmwareVersion), qPrintable (m_hardwareVersion), m_printheadCount); emit statusMessage ( @@ -739,7 +776,7 @@ Xpl2Client::handleGsPhVersion (const QVariantList ¶ms) QString bootVer = params[7].toString (); qDebug ("%s PH[%d] mcuFw=%s mcuHw=%s mcuFwVar=%s fpgaFw=%s fpgaHw=%s " "boot=%s", - qPrintable (logTag (&m_commandSocket)), phId, qPrintable (mcuFw), + qPrintable (logTag (m_commandSocket)), phId, qPrintable (mcuFw), qPrintable (mcuHw), qPrintable (mcuFwVar), qPrintable (fpgaFw), qPrintable (fpgaHw), qPrintable (bootVer)); emit statusMessage ( @@ -905,7 +942,7 @@ Xpl2Client::handleEvStatusMsgJc (const QVariantList ¶ms) { Xpl2JcStatus status = Xpl2JcStatus::fromParams (params); qDebug ("%s EV_STATUS_MSG_JC controller=%d level=%d temp=%.1f cpu=%.1f%%", - qPrintable (logTag (&m_statusSocket)), status.controllerId, + qPrintable (logTag (m_statusSocket)), status.controllerId, status.statusLevel, status.temperature, status.cpuPercentageBusy); emit statusMessage ( QStringLiteral ("RX EV_STATUS_MSG_JC: controller=%1 level=%2") @@ -919,7 +956,7 @@ Xpl2Client::handleEvStatusMsgPh (const QVariantList ¶ms) { Xpl2PhStatus status = Xpl2PhStatus::fromParams (params); qDebug ("%s EV_STATUS_MSG_PH controller=%d level=%d ph=%d temp=%.1f", - qPrintable (logTag (&m_statusSocket)), status.controllerId, + qPrintable (logTag (m_statusSocket)), status.controllerId, status.statusLevel, status.printheadId, status.temperature); emit statusMessage ( QStringLiteral ("RX EV_STATUS_MSG_PH: controller=%1 level=%2 ph=%3") @@ -937,9 +974,12 @@ void Xpl2Client::updateConnectedState () { bool allConnected - = m_commandSocket.state () == QAbstractSocket::ConnectedState - && m_imagingSocket.state () == QAbstractSocket::ConnectedState - && m_statusSocket.state () == QAbstractSocket::ConnectedState; + = m_commandSocket + && m_commandSocket->state () == QAbstractSocket::ConnectedState + && m_imagingSocket + && m_imagingSocket->state () == QAbstractSocket::ConnectedState + && m_statusSocket + && m_statusSocket->state () == QAbstractSocket::ConnectedState; if (m_connected == allConnected) return; m_connected = allConnected; @@ -951,17 +991,17 @@ Xpl2Client::logTag (const QTcpSocket *socket) const { const char *name = "Unknown"; quint16 port = 0; - if (socket == &m_commandSocket) + if (socket == m_commandSocket) { name = "Command"; port = m_commandPort; } - else if (socket == &m_imagingSocket) + else if (socket == m_imagingSocket) { name = "Imaging"; port = m_imagingPort; } - else if (socket == &m_statusSocket) + else if (socket == m_statusSocket) { name = "Status"; port = m_statusPort; @@ -975,26 +1015,46 @@ Xpl2Client::logTag (const QTcpSocket *socket) const /* ------------------------------------------------------------------ */ void -Xpl2Client::onSocketConnected () +Xpl2Client::onNewConnection () { - auto *socket = qobject_cast<QTcpSocket *> (sender ()); - qInfo ("%s Connected", qPrintable (logTag (socket))); - updateConnectedState (); + auto *server = qobject_cast<QTcpServer *> (sender ()); + QTcpSocket *&slot = socketForServer (server); + + while (auto *pending = server->nextPendingConnection ()) + { + if (slot) + { + qWarning ("%s Rejected extra connection", + qPrintable (logTag (slot))); + pending->deleteLater (); + continue; + } + slot = pending; + connect (slot, &QTcpSocket::readyRead, this, + &Xpl2Client::onSocketMessageReady); + connect (slot, &QTcpSocket::disconnected, this, + &Xpl2Client::onSocketDisconnected); + connect (slot, &QAbstractSocket::errorOccurred, this, + &Xpl2Client::onSocketError); + qInfo ("%s Controller connected", qPrintable (logTag (slot))); + updateConnectedState (); + } } void Xpl2Client::onSocketDisconnected () { auto *socket = qobject_cast<QTcpSocket *> (sender ()); - if (!socket) - { - /* Identify by elimination — which socket just left ConnectedState? */ - for (auto *s : { &m_commandSocket, &m_imagingSocket, &m_statusSocket }) - if (s->state () != QAbstractSocket::ConnectedState) - qInfo ("%s Disconnected", qPrintable (logTag (s))); - } - else - qInfo ("%s Disconnected", qPrintable (logTag (socket))); + qInfo ("%s Controller disconnected", qPrintable (logTag (socket))); + + if (socket == m_commandSocket) + m_commandSocket = nullptr; + else if (socket == m_imagingSocket) + m_imagingSocket = nullptr; + else if (socket == m_statusSocket) + m_statusSocket = nullptr; + + socket->deleteLater (); updateConnectedState (); } @@ -1014,9 +1074,9 @@ Xpl2Client::onSocketMessageReady () qDebug ("%s RX %s%s", qPrintable (logTag (socket)), msg.command.constData (), wire.constData ()); - if (socket == &m_commandSocket) + if (socket == m_commandSocket) dispatchCommandMessage (msg); - else if (socket == &m_imagingSocket) + else if (socket == m_imagingSocket) dispatchImagingMessage (msg); else dispatchStatusMessage (msg); diff --git a/src/Xpl2Client.h b/src/Xpl2Client.h index 838c344..44edb65 100644 --- a/src/Xpl2Client.h +++ b/src/Xpl2Client.h @@ -11,17 +11,19 @@ #include <QHash> #include <QObject> #include <QQmlEngine> -#include <QTcpSocket> +#include <QTcpServer> #include <functional> +class QTcpSocket; + class Xpl2Client : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON - Q_PROPERTY (QString host READ host WRITE setHost NOTIFY hostChanged) + Q_PROPERTY (bool listening READ isListening NOTIFY listeningChanged) Q_PROPERTY (bool connected READ isConnected NOTIFY connectedChanged) Q_PROPERTY (int controllerId READ controllerId NOTIFY jcVersionReceived) Q_PROPERTY ( @@ -33,9 +35,7 @@ class Xpl2Client : public QObject public: explicit Xpl2Client (QObject *parent = nullptr); - QString host () const; - void setHost (const QString &host); - + bool isListening () const; bool isConnected () const; int controllerId () const; @@ -45,8 +45,8 @@ public: static void enableWireDebug (); - Q_INVOKABLE void connectToServer (); - Q_INVOKABLE void disconnectFromServer (); + Q_INVOKABLE void startListening (); + Q_INVOKABLE void stopListening (); /** Get the just connected Jetting Controller ID and Software Version. */ Q_INVOKABLE void getJcVersion (); /** Query the specified printhead's version info. */ @@ -177,7 +177,7 @@ public: Q_INVOKABLE void imageCount (); signals: - void hostChanged (); + void listeningChanged (); void connectedChanged (); void errorOccurred (const QString &error); void statusMessage (const QString &message); @@ -286,18 +286,20 @@ signals: void imagingStopResult (bool success); private slots: - void onSocketConnected (); + void onNewConnection (); void onSocketDisconnected (); void onSocketMessageReady (); void onSocketError (QAbstractSocket::SocketError error); private: - void sendCommand (QTcpSocket &socket, const QByteArray &command, + void setupServer (QTcpServer &server, quint16 port); + QTcpSocket *&socketForServer (QTcpServer *server); + void sendCommand (QTcpSocket *socket, const QByteArray &command, const QVariantList ¶ms = {}); void dispatchCommandMessage (const Xpl2Protocol::ParsedMessage &msg); void dispatchImagingMessage (const Xpl2Protocol::ParsedMessage &msg); void dispatchStatusMessage (const Xpl2Protocol::ParsedMessage &msg); - void handleKaPing (QTcpSocket &socket); + void handleKaPing (QTcpSocket *socket); void handleGsJcVersion (const QVariantList ¶ms); void handleGsPhVersion (const QVariantList ¶ms); enum class ResponseShape @@ -335,13 +337,16 @@ private: void updateConnectedState (); QString logTag (const QTcpSocket *socket) const; - QTcpSocket m_commandSocket; - QTcpSocket m_imagingSocket; - QTcpSocket m_statusSocket; - QString m_host = QStringLiteral ("127.0.0.1"); + QTcpServer m_commandServer; + QTcpServer m_imagingServer; + QTcpServer m_statusServer; + QTcpSocket *m_commandSocket = nullptr; + QTcpSocket *m_imagingSocket = nullptr; + QTcpSocket *m_statusSocket = nullptr; quint16 m_commandPort = 9110; quint16 m_imagingPort = 9111; quint16 m_statusPort = 9112; + bool m_listening = false; bool m_connected = false; static bool s_wireDebug; int m_controllerId = 0; |
