diff options
| author | Thomas Vanbesien <tvanbesi@proton.me> | 2026-03-16 16:19:49 +0100 |
|---|---|---|
| committer | Thomas Vanbesien <tvanbesi@proton.me> | 2026-03-16 16:19:49 +0100 |
| commit | fa095de6cc8ec5a5b5c14091f2b3179ad7071876 (patch) | |
| tree | aa094011263a83a4c91eb8722c2095344656c838 | |
| parent | 7830f0ae98d742467b948ed93c85e122be38fb83 (diff) | |
| download | QtXpl2-fa095de6cc8ec5a5b5c14091f2b3179ad7071876.tar.gz QtXpl2-fa095de6cc8ec5a5b5c14091f2b3179ad7071876.zip | |
EV_ events with Q_GADGET status types, mock periodic emission, tabbed demo UI
| -rw-r--r-- | demo/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | demo/CommandsPage.qml | 183 | ||||
| -rw-r--r-- | demo/DebugConsole.qml | 34 | ||||
| -rw-r--r-- | demo/Main.qml | 270 | ||||
| -rw-r--r-- | demo/StatusPage.qml | 620 | ||||
| -rw-r--r-- | mock-server/MockServer.cpp | 106 | ||||
| -rw-r--r-- | mock-server/MockServer.h | 6 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/Xpl2Client.cpp | 79 | ||||
| -rw-r--r-- | src/Xpl2Client.h | 23 | ||||
| -rw-r--r-- | src/Xpl2JcStatus.cpp | 70 | ||||
| -rw-r--r-- | src/Xpl2JcStatus.h | 73 | ||||
| -rw-r--r-- | src/Xpl2PhStatus.cpp | 149 | ||||
| -rw-r--r-- | src/Xpl2PhStatus.h | 155 |
14 files changed, 1563 insertions, 212 deletions
diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index bdee67f..aa8fd49 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -8,6 +8,9 @@ qt_add_qml_module( 1.0 QML_FILES Main.qml + CommandsPage.qml + StatusPage.qml + DebugConsole.qml # IMPORT_PATH sets QT_QML_IMPORT_PATH on the target, which qmlls reads to # resolve imports like "import Xpl2" in .qmlls.ini. IMPORT_PATH diff --git a/demo/CommandsPage.qml b/demo/CommandsPage.qml new file mode 100644 index 0000000..2e4437b --- /dev/null +++ b/demo/CommandsPage.qml @@ -0,0 +1,183 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Xpl2 + +ColumnLayout { + id: commandsPage + + required property int demoPhCount + required property ListModel phModel + + spacing: 12 + + // --- JC Version --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Jetting Controller" + + RowLayout { + anchors.fill: parent + + Button { + text: "Get JC Version" + + onClicked: Xpl2Client.getJcVersion() + } + + Label { + text: Xpl2Client.controllerId > 0 + ? "Controller: %1 | FW: %2 | HW: %3 | PHs: %4".arg( + Xpl2Client.controllerId).arg( + Xpl2Client.firmwareVersion).arg( + Xpl2Client.hardwareVersion).arg( + Xpl2Client.printheadCount) : "No version data" + } + } + } + + // --- Control --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Control" + + GridLayout { + anchors.fill: parent + columns: 4 + + Button { + text: "Jetting All On" + + onClicked: Xpl2Client.jettingAllOn() + } + + Button { + text: "Jetting Off" + + onClicked: Xpl2Client.jettingOff() + } + + Button { + text: "JC LED On" + + onClicked: Xpl2Client.jcIdLedOn() + } + + Button { + text: "JC LED Off" + + onClicked: Xpl2Client.jcIdLedOff() + } + + Button { + text: "JC Calibration" + + onClicked: Xpl2Client.jcCalibration() + } + + Button { + text: "Reset Fault Codes" + + onClicked: Xpl2Client.jcResetFaultCodes() + } + } + } + + // --- Configuration --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Configuration" + + GridLayout { + anchors.fill: parent + columns: 4 + + Button { + text: "Save All Settings" + + onClicked: Xpl2Client.jcSaveAllPrintheadSettings() + } + + Button { + text: "Reboot All PHs" + + onClicked: Xpl2Client.jcRebootAllPrintheads() + } + + Button { + text: "Restart JC" + + onClicked: Xpl2Client.jcRestart() + } + + Button { + text: "Shutdown JC" + + onClicked: Xpl2Client.jcShutdown() + } + } + } + + // --- Printheads --- + GroupBox { + Layout.fillHeight: true + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Printheads (%1)".arg(commandsPage.demoPhCount) + + ColumnLayout { + anchors.fill: parent + + Button { + text: "Get All PH Versions" + + onClicked: { + for (let i = 0; i < commandsPage.phModel.count; ++i) + Xpl2Client.getPhVersion(commandsPage.phModel.get(i).phId); + } + } + + ScrollView { + Layout.fillHeight: true + Layout.fillWidth: true + + ListView { + model: commandsPage.phModel + spacing: 4 + + delegate: RowLayout { + id: phDelegate + + required property int phId + required property string versionInfo + + width: ListView.view.width + + Label { + Layout.preferredWidth: 50 + font.bold: true + text: "PH %1".arg(phDelegate.phId) + } + + Button { + text: "Version" + + onClicked: Xpl2Client.getPhVersion(phDelegate.phId) + } + + Label { + Layout.fillWidth: true + elide: Text.ElideRight + text: phDelegate.versionInfo || "—" + } + } + } + } + } + } +} diff --git a/demo/DebugConsole.qml b/demo/DebugConsole.qml new file mode 100644 index 0000000..9a5a9ff --- /dev/null +++ b/demo/DebugConsole.qml @@ -0,0 +1,34 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls + +Rectangle { + id: debugRoot + + function appendLog(msg: string): void { + let ts = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss.zzz"); + debugLog.text += "[" + ts + "] " + msg + "\n"; + debugLog.cursorPosition = debugLog.text.length; + } + + border.color: "#444" + color: "#1e1e1e" + radius: 4 + + ScrollView { + anchors.fill: parent + anchors.margins: 4 + + TextArea { + id: debugLog + + background: null + color: "#cccccc" + font.family: "monospace" + font.pointSize: 9 + readOnly: true + wrapMode: TextEdit.Wrap + } + } +} diff --git a/demo/Main.qml b/demo/Main.qml index 394d1ba..9b9223f 100644 --- a/demo/Main.qml +++ b/demo/Main.qml @@ -39,6 +39,14 @@ ApplicationWindow { debugConsole.appendLog("ERROR: " + error); } + function onJcStatusReceived(status) { + statusPage.lastJcStatus = status; + } + + function onPhStatusReceived(status) { + statusPage.lastPhStatus = status; + } + function onPhVersionReceived(controllerId: int, printheadId: int, mcuFirmwareVersion: string, mcuHardwareVersion: string, @@ -61,6 +69,10 @@ ApplicationWindow { } } + function onShuttingDown() { + debugConsole.appendLog("SERVER SHUTTING DOWN"); + } + function onStatusMessage(message: string) { debugConsole.appendLog(message); } @@ -72,249 +84,87 @@ ApplicationWindow { anchors.fill: parent spacing: 0 - ColumnLayout { - Layout.fillHeight: true + // --- Connection (always visible) --- + GroupBox { + Layout.bottomMargin: 0 Layout.fillWidth: true Layout.margins: 16 - spacing: 12 - - // --- Connection --- - GroupBox { - Layout.fillWidth: true - title: "Connection" - - RowLayout { - anchors.fill: parent - - Label { - text: "Host:" - } - - TextField { - id: hostField - - Layout.fillWidth: true - text: Xpl2Client.host - - onEditingFinished: Xpl2Client.host = text - } + title: "Connection" - Button { - text: Xpl2Client.connected ? "Disconnect" : "Connect" + RowLayout { + anchors.fill: parent - onClicked: { - if (Xpl2Client.connected) - Xpl2Client.disconnectFromServer(); - else - Xpl2Client.connectToServer(); - } - } + Label { + text: "Host:" } - } - // --- JC Version --- - GroupBox { - Layout.fillWidth: true - enabled: Xpl2Client.connected - title: "Jetting Controller" + TextField { + id: hostField - RowLayout { - anchors.fill: parent + Layout.fillWidth: true + text: Xpl2Client.host - Button { - text: "Get JC Version" - - onClicked: Xpl2Client.getJcVersion() - } - - Label { - text: Xpl2Client.controllerId > 0 - ? "Controller: %1 | FW: %2 | HW: %3 | PHs: %4".arg( - Xpl2Client.controllerId).arg( - Xpl2Client.firmwareVersion).arg( - Xpl2Client.hardwareVersion).arg( - Xpl2Client.printheadCount) : - "No version data" - } + onEditingFinished: Xpl2Client.host = text } - } - - // --- Control --- - GroupBox { - Layout.fillWidth: true - enabled: Xpl2Client.connected - title: "Control" - - GridLayout { - anchors.fill: parent - columns: 4 - Button { - text: "Jetting All On" + Button { + text: Xpl2Client.connected ? "Disconnect" : "Connect" - onClicked: Xpl2Client.jettingAllOn() - } - - Button { - text: "Jetting Off" - - onClicked: Xpl2Client.jettingOff() - } - - Button { - text: "JC LED On" - - onClicked: Xpl2Client.jcIdLedOn() - } - - Button { - text: "JC LED Off" - - onClicked: Xpl2Client.jcIdLedOff() - } - - Button { - text: "JC Calibration" - - onClicked: Xpl2Client.jcCalibration() - } - - Button { - text: "Reset Fault Codes" - - onClicked: Xpl2Client.jcResetFaultCodes() + onClicked: { + if (Xpl2Client.connected) + Xpl2Client.disconnectFromServer(); + else + Xpl2Client.connectToServer(); } } } + } - // --- Configuration --- - GroupBox { - Layout.fillWidth: true - enabled: Xpl2Client.connected - title: "Configuration" - - GridLayout { - anchors.fill: parent - columns: 4 - - Button { - text: "Save All Settings" - - onClicked: Xpl2Client.jcSaveAllPrintheadSettings() - } - - Button { - text: "Reboot All PHs" - - onClicked: Xpl2Client.jcRebootAllPrintheads() - } - - Button { - text: "Restart JC" - - onClicked: Xpl2Client.jcRestart() - } + // --- Tab bar --- + TabBar { + id: tabBar - Button { - text: "Shutdown JC" + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 - onClicked: Xpl2Client.jcShutdown() - } - } + TabButton { + text: "Commands" } - // --- Printheads --- - GroupBox { - Layout.fillHeight: true - Layout.fillWidth: true - enabled: Xpl2Client.connected - title: "Printheads (%1)".arg(root.demoPhCount) - - ColumnLayout { - anchors.fill: parent - - Button { - text: "Get All PH Versions" - - onClicked: { - for (let i = 0; i < phModel.count; ++i) - Xpl2Client.getPhVersion(phModel.get(i).phId); - } - } - - ScrollView { - Layout.fillHeight: true - Layout.fillWidth: true - - ListView { - model: phModel - spacing: 4 - - delegate: RowLayout { - id: phDelegate + TabButton { + text: "Status" + } + } - required property int phId - required property string versionInfo + // --- Swipe view --- + SwipeView { + id: swipeView - width: ListView.view.width + Layout.fillHeight: true + Layout.fillWidth: true + Layout.margins: 16 + currentIndex: tabBar.currentIndex - Label { - Layout.preferredWidth: 50 - font.bold: true - text: "PH %1".arg(phDelegate.phId) - } + onCurrentIndexChanged: tabBar.currentIndex = currentIndex - Button { - text: "Version" + CommandsPage { + demoPhCount: root.demoPhCount + phModel: phModel + } - onClicked: Xpl2Client.getPhVersion( - phDelegate.phId) - } + StatusPage { + id: statusPage - Label { - Layout.fillWidth: true - elide: Text.ElideRight - text: phDelegate.versionInfo || "—" - } - } - } - } - } } } // --- Debug Console --- - Rectangle { + DebugConsole { id: debugConsole - function appendLog(msg: string): void { - let ts = new Date().toLocaleTimeString(Qt.locale(), - "HH:mm:ss.zzz"); - debugLog.text += "[" + ts + "] " + msg + "\n"; - debugLog.cursorPosition = debugLog.text.length; - } - Layout.fillWidth: true Layout.preferredHeight: 160 - border.color: "#444" - color: "#1e1e1e" - radius: 4 - - ScrollView { - anchors.fill: parent - anchors.margins: 4 - - TextArea { - id: debugLog - - background: null - color: "#cccccc" - font.family: "monospace" - font.pointSize: 9 - readOnly: true - wrapMode: TextEdit.Wrap - } - } } } } diff --git a/demo/StatusPage.qml b/demo/StatusPage.qml new file mode 100644 index 0000000..6a85bcc --- /dev/null +++ b/demo/StatusPage.qml @@ -0,0 +1,620 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Xpl2 + +ColumnLayout { + id: statusPage + + property var lastJcStatus: null + property var lastPhStatus: null + + spacing: 12 + + // --- Status Messaging Controls --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Status Messaging" + + GridLayout { + anchors.fill: parent + columns: 2 + + Label { + text: "Level:" + } + + ComboBox { + id: statusLevelCombo + + Layout.fillWidth: true + model: ["1 — Basic", "2 — Extended"] + } + + Label { + text: "Interval (ms):" + } + + SpinBox { + id: statusIntervalSpin + + Layout.fillWidth: true + from: 100 + stepSize: 100 + to: 10000 + value: 1000 + } + + Button { + text: "Start JC Status" + + onClicked: Xpl2Client.jcStatusMessagingStart( + statusLevelCombo.currentIndex + 1, + statusIntervalSpin.value) + } + + Button { + text: "Stop JC Status" + + onClicked: Xpl2Client.jcStatusMessagingStop() + } + + Button { + text: "Start PH Status" + + onClicked: Xpl2Client.phStatusMessagingStart( + statusLevelCombo.currentIndex + 1, + statusIntervalSpin.value) + } + + Button { + text: "Stop PH Status" + + onClicked: Xpl2Client.phStatusMessagingStop() + } + } + } + + // --- JC Status Display --- + GroupBox { + Layout.fillWidth: true + title: "JC Status" + + RowLayout { + anchors.fill: parent + + GridLayout { + Layout.fillWidth: true + columns: 4 + + Label { + font.bold: true + text: "CPU:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.cpuPercentageBusy.toFixed( + 1) + "%" : "—" + } + + Label { + font.bold: true + text: "Temp:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.temperature.toFixed(1) + + "°C" : "—" + } + + Label { + font.bold: true + text: "Rail 5V:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.rail5V.toFixed(2) + "V" : + "—" + } + + Label { + font.bold: true + text: "CAN 8V:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.railCanBus8V.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "Humidity:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.humidity.toFixed(1) + "%" : + "—" + } + + Label { + font.bold: true + text: "Bus I:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.busCurrent.toFixed(3) + "A" : + "—" + } + + Label { + font.bold: true + text: "Uptime:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.onTimeSeconds + "s" : "—" + } + } + + // --- Extended (Level 2) --- + GridLayout { + Layout.fillWidth: true + columns: 4 + visible: statusPage.lastJcStatus !== null + && statusPage.lastJcStatus.statusLevel >= 2 + + Label { + font.bold: true + text: "IP:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.ipAddress : "—" + } + + Label { + font.bold: true + text: "eFuse V:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.eFuseVoltage.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "eFuse Bus:" + } + + Label { + text: statusPage.lastJcStatus ? ( + statusPage.lastJcStatus.eFuseBusEnabled + ? "On" : "Off") : "—" + } + + Label { + font.bold: true + text: "Bus Power:" + } + + Label { + text: statusPage.lastJcStatus ? ( + statusPage.lastJcStatus.busPowerEnabled + ? "On" : "Off") : "—" + } + + Label { + font.bold: true + text: "Bus OK:" + } + + Label { + text: statusPage.lastJcStatus ? ( + statusPage.lastJcStatus.busPowerOk + ? "Yes" : "No") : "—" + } + + Label { + font.bold: true + text: "Switch:" + } + + Label { + text: statusPage.lastJcStatus ? String( + statusPage.lastJcStatus.switchValue) : + "—" + } + + Label { + font.bold: true + text: "FW:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.firmwareVersion : "—" + } + + Label { + font.bold: true + text: "HW:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.hardwareVersion : "—" + } + + Label { + font.bold: true + text: "Indicators:" + } + + Label { + Layout.columnSpan: 3 + text: statusPage.lastJcStatus + ? [statusPage.lastJcStatus.indicator0, + statusPage.lastJcStatus.indicator1, + statusPage.lastJcStatus.indicator2, + statusPage.lastJcStatus.indicator3, + statusPage.lastJcStatus.indicator4, + statusPage.lastJcStatus.indicator5].map(function ( + v) { + return v ? "1" : "0"; + }).join(" ") : "—" + } + } + } + } + + // --- PH Status Display --- + GroupBox { + Layout.fillHeight: true + Layout.fillWidth: true + title: "PH Status" + + RowLayout { + anchors.fill: parent + + GridLayout { + Layout.fillWidth: true + columns: 4 + + Label { + font.bold: true + text: "PH:" + } + + Label { + text: statusPage.lastPhStatus ? String( + statusPage.lastPhStatus.printheadId) : + "—" + } + + Label { + font.bold: true + text: "Temp:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.temperature.toFixed(1) + + "°C" : "—" + } + + Label { + font.bold: true + text: "MCU Temp:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuTemperature.toFixed(1) + + "°C" : "—" + } + + Label { + font.bold: true + text: "Humidity:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.humidity.toFixed(1) + "%" : + "—" + } + + Label { + font.bold: true + text: "PDS V:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.pdsVoltage.toFixed(2) + "V" : + "—" + } + + Label { + font.bold: true + text: "MDS V:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mdsVoltage.toFixed(2) + "V" : + "—" + } + + Label { + font.bold: true + text: "Sys V:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.systemVoltage.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "VDD:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.vdd.toFixed(2) + "V" : "—" + } + + Label { + font.bold: true + text: "eFuse I:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.eFuseCurrent.toFixed(3) + + "A" : "—" + } + + Label { + font.bold: true + text: "Nozzle I:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.nozzleCurrent.toFixed(3) + + "A" : "—" + } + + Label { + font.bold: true + text: "Duty Cycle:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.dutyCycle.toFixed(1) + "%" : + "—" + } + + Label { + font.bold: true + text: "Drive:" + } + + Label { + text: statusPage.lastPhStatus ? String( + statusPage.lastPhStatus.drive) : + "—" + } + + Label { + font.bold: true + text: "Uptime:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.onTimeSeconds + "s" : "—" + } + } + + // --- Extended (Level 2) --- + GridLayout { + Layout.fillWidth: true + columns: 4 + visible: statusPage.lastPhStatus !== null + && statusPage.lastPhStatus.statusLevel >= 2 + + Label { + font.bold: true + text: "MCU FW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuFirmwareVersion : "—" + } + + Label { + font.bold: true + text: "MCU HW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuHardwareVersion : "—" + } + + Label { + font.bold: true + text: "MCU Variant:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuFirmwareVariant : "—" + } + + Label { + font.bold: true + text: "FPGA FW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.fpgaFirmwareVersion : "—" + } + + Label { + font.bold: true + text: "FPGA HW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.fpgaHardwareVersion : "—" + } + + Label { + font.bold: true + text: "Boot:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.bootloaderVersion : "—" + } + + Label { + font.bold: true + text: "Max Temp:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.maxAllowedTemperature.toFixed( + 1) + "°C" : "—" + } + + Label { + font.bold: true + text: "eFuse Max:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.eFuseCurrentMax.toFixed(2) + + "A" : "—" + } + + Label { + font.bold: true + text: "PDS V Max:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.pdsVoltageMax.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "PDS V Min:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.pdsVoltageMin.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "MDS V Max:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mdsVoltageMax.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "MDS V Min:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mdsVoltageMin.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "Meas. HW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.measuredHardwareVersion : + "—" + } + + Label { + font.bold: true + text: "Accel ID:" + } + + Label { + text: statusPage.lastPhStatus ? String( + statusPage.lastPhStatus.accelerometerId) : + "—" + } + + Label { + font.bold: true + text: "Gyro:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.gyroX + ", " + + statusPage.lastPhStatus.gyroY + ", " + + statusPage.lastPhStatus.gyroZ : "—" + } + + Label { + font.bold: true + text: "Accel:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.accelerationX + ", " + + statusPage.lastPhStatus.accelerationY + ", " + + statusPage.lastPhStatus.accelerationZ : "—" + } + } + } + } +} diff --git a/mock-server/MockServer.cpp b/mock-server/MockServer.cpp index f2431d9..f8831da 100644 --- a/mock-server/MockServer.cpp +++ b/mock-server/MockServer.cpp @@ -22,6 +22,11 @@ MockServer::MockServer (QObject *parent) : QObject (parent) connect (&m_pingTimer, &QTimer::timeout, this, &MockServer::sendKaPing); m_pingTimer.start (1000); + + connect (&m_jcStatusTimer, &QTimer::timeout, this, + &MockServer::sendJcStatusMsg); + connect (&m_phStatusTimer, &QTimer::timeout, this, + &MockServer::sendPhStatusMsg); } void @@ -291,7 +296,23 @@ MockServer::handleCnStatusMessagingStart (QTcpSocket *client, { qDebug ("%s RX %s,%s", qPrintable (logTag (client->localPort ())), cmd.constData (), params.constData ()); - /* Echo back: controllerId, level, interval, success. */ + + /* Parse level and interval from params: "level,interval" */ + QList<QByteArray> parts = params.split (','); + int level = parts.size () > 0 ? parts[0].toInt () : 1; + int interval = parts.size () > 1 ? parts[1].toInt () : 1000; + + if (cmd == "CN_JC_STATUS_MESSAGING_START") + { + m_jcStatusLevel = level; + m_jcStatusTimer.start (interval); + } + else + { + m_phStatusLevel = level; + m_phStatusTimer.start (interval); + } + sendReply (client, cmd + ",1," + params + ",1\n"); } @@ -301,6 +322,12 @@ MockServer::handleCnStatusMessagingStop (QTcpSocket *client, { qDebug ("%s RX %s", qPrintable (logTag (client->localPort ())), cmd.constData ()); + + if (cmd == "CN_JC_STATUS_MESSAGING_STOP") + m_jcStatusTimer.stop (); + else + m_phStatusTimer.stop (); + sendReply (client, cmd + ",1,1\n"); } @@ -365,3 +392,80 @@ MockServer::handleCfPhGetter (QTcpSocket *client, const QByteArray ¶ms) params.constData ()); sendReply (client, "CF_PH_GETTER,1," + params + ",\"0\",1\n"); } + +void +MockServer::sendJcStatusMsg () +{ + static int tick = 0; + ++tick; + bool odd = (tick % 2) != 0; + + /* Alternate between two value sets so the demo visually updates. + Level 1: cid, level, cpu, rail5v, canBus8v, temp, humidity, busCurrent, + onTimeSeconds */ + QByteArray level = QByteArray::number (m_jcStatusLevel); + QByteArray base = "EV_STATUS_MSG_JC,1," + level; + if (odd) + base += ",42.5,4.98,7.95,35.2,55.0,0.12,3600"; + else + base += ",58.3,5.02,8.05,37.8,48.5,0.15,3660"; + + if (m_jcStatusLevel >= 2) + { + if (odd) + base += ",\"192.168.1.100\",23.5,1,1,1,3,\"1.05\",\"2.00\"" + ",0,0,0,0,0,0"; + else + base += ",\"192.168.1.100\",24.1,1,1,1,3,\"1.05\",\"2.00\"" + ",1,0,1,0,1,0"; + } + base += '\n'; + + for (auto *client : m_clients) + if (client->state () == QAbstractSocket::ConnectedState + && client->localPort () == m_status.number) + sendReply (client, base); +} + +void +MockServer::sendPhStatusMsg () +{ + static int tick = 0; + ++tick; + bool odd = (tick % 2) != 0; + + /* Alternate between two value sets. + Level 1: cid, level, phId, temp, humidity, mcuTemp, pdsV, mdsV, sysV, + eFuseI, nozzleI, vdd, 13×trip bools, dutyCycle, pwmFreq, drive, + nozzleDriveFreq, nozzleDriveDutyCycle, onTimeSeconds */ + QByteArray level = QByteArray::number (m_phStatusLevel); + QByteArray base = "EV_STATUS_MSG_PH,1," + level + ",1"; + if (odd) + base += ",38.5,45.0,40.2,36.0,24.0,3.3,0.05,0.02,3.3" + ",0,0,0,0,0,0,0,0,0,0,0,0,0" + ",50.0,10000.0,3,8000.0,50.0,1800"; + else + base += ",41.2,42.0,43.1,35.5,23.8,3.28,0.06,0.03,3.31" + ",0,0,0,0,0,0,0,0,0,0,0,0,0" + ",55.0,10500.0,4,8200.0,52.0,1860"; + + if (m_phStatusLevel >= 2) + { + if (odd) + base += ",0,\"MCU001\",\"FLASH001\",12345" + ",\"1.00\",\"3.10\",\"Standard\",\"1.00\",\"2.05\",\"0.9.1\"" + ",100.0,45.0,20.0,36.0,30.0,18.0,2.0,\"1.00\"" + ",0,0,0,0,0,0,0,0,0,0,0,0,0,0"; + else + base += ",0,\"MCU001\",\"FLASH001\",12345" + ",\"1.00\",\"3.10\",\"Standard\",\"1.00\",\"2.05\",\"0.9.1\"" + ",100.0,45.0,20.0,35.5,30.0,18.0,2.0,\"1.00\"" + ",1,-1,2,0,0,0,0,0,0,0,0,0,0,0"; + } + base += '\n'; + + for (auto *client : m_clients) + if (client->state () == QAbstractSocket::ConnectedState + && client->localPort () == m_status.number) + sendReply (client, base); +} diff --git a/mock-server/MockServer.h b/mock-server/MockServer.h index b14dda5..3086057 100644 --- a/mock-server/MockServer.h +++ b/mock-server/MockServer.h @@ -25,6 +25,8 @@ private slots: void onClientDisconnected (); /* Send KA_PING keepalive to all connected clients. */ void sendKaPing (); + void sendJcStatusMsg (); + void sendPhStatusMsg (); private: struct Port @@ -73,5 +75,9 @@ private: Port m_status; QList<QTcpSocket *> m_clients; QTimer m_pingTimer; + QTimer m_jcStatusTimer; + QTimer m_phStatusTimer; + int m_jcStatusLevel = 1; + int m_phStatusLevel = 1; static bool s_wireDebug; }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4d57f8a..25572a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,10 @@ qt_add_qml_module( SOURCES Xpl2Protocol.h Xpl2Protocol.cpp + Xpl2JcStatus.h + Xpl2JcStatus.cpp + Xpl2PhStatus.h + Xpl2PhStatus.cpp Xpl2Client.h Xpl2Client.cpp OUTPUT_DIRECTORY diff --git a/src/Xpl2Client.cpp b/src/Xpl2Client.cpp index d6eb28a..ac7079f 100644 --- a/src/Xpl2Client.cpp +++ b/src/Xpl2Client.cpp @@ -132,6 +132,26 @@ Xpl2Client::s_responseTable = { /* CF_ PH getter: cid, phId, savedValue, getterId, currentValue, successFlag */ { "CF_PH_GETTER", { ResponseShape::PhGetter, 6, [](auto *s, const auto &p) { emit s->phGetterResult (p[0].toInt (), p[1].toInt (), p[2].toInt () != 0, p[3].toInt (), p[4].toString (), p[5].toInt () == 1); } } }, + + /* EV_ events */ + { "EV_PH_CONNECTION_CHANGED", { ResponseShape::PhConnectionChanged, 3, + [](auto *s, const auto &p) { emit s->phConnectionChanged (p[0].toInt (), p[1].toInt (), p[2].toInt () == 1); } } }, + { "EV_JC_ERROR_CODE", { ResponseShape::ErrorCode, 3, + [](auto *s, const auto &p) { + QStringList ep; for (int i = 3; i < p.size (); ++i) ep << p[i].toString (); + emit s->jcErrorCode (p[0].toInt (), p[1].toInt (), ep); } } }, + { "EV_IMG_ERROR_CODE", { ResponseShape::ErrorCode, 3, + [](auto *s, const auto &p) { + QStringList ep; for (int i = 3; i < p.size (); ++i) ep << p[i].toString (); + emit s->imgErrorCode (p[0].toInt (), p[1].toInt (), ep); } } }, + { "EV_STATUS_ERROR_CODE", { ResponseShape::ErrorCode, 3, + [](auto *s, const auto &p) { + QStringList ep; for (int i = 3; i < p.size (); ++i) ep << p[i].toString (); + emit s->statusErrorCode (p[0].toInt (), p[1].toInt (), ep); } } }, + { "EV_PH_ERROR_CODE", { ResponseShape::PhErrorCode, 4, + [](auto *s, const auto &p) { + QStringList ep; for (int i = 4; i < p.size (); ++i) ep << p[i].toString (); + emit s->phErrorCode (p[0].toInt (), p[1].toInt (), p[2].toInt (), ep); } } }, }; // clang-format on @@ -567,6 +587,8 @@ Xpl2Client::dispatchCommandMessage (const Xpl2Protocol::ParsedMessage &msg) { if (msg.command == "KA_PING") handleKaPing (m_commandSocket); + else if (msg.command == "EV_SHUTTING_DOWN") + emit shuttingDown (); else if (msg.command == "GS_JC_VERSION") handleGsJcVersion (msg.params); else if (msg.command == "GS_PH_VERSION") @@ -581,6 +603,8 @@ Xpl2Client::dispatchImagingMessage (const Xpl2Protocol::ParsedMessage &msg) { if (msg.command == "KA_PING") handleKaPing (m_imagingSocket); + else if (msg.command == "EV_SHUTTING_DOWN") + emit shuttingDown (); else qWarning ("%s Unknown command: %s", qPrintable (logTag (&m_imagingSocket)), msg.command.constData ()); @@ -591,6 +615,12 @@ Xpl2Client::dispatchStatusMessage (const Xpl2Protocol::ParsedMessage &msg) { if (msg.command == "KA_PING") handleKaPing (m_statusSocket); + else if (msg.command == "EV_SHUTTING_DOWN") + emit shuttingDown (); + else if (msg.command == "EV_STATUS_MSG_JC") + 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)), msg.command.constData ()); @@ -778,6 +808,26 @@ Xpl2Client::dispatchResponse (const QByteArray &command, .arg (params[4].toString ()) .arg (params[5].toInt () == 1); break; + case ResponseShape::PhConnectionChanged: + logStr = QStringLiteral ("RX %1: controller=%2 ph=%3 connected=%4") + .arg (cmd) + .arg (cid) + .arg (params[1].toInt ()) + .arg (params[2].toInt () == 1); + break; + case ResponseShape::ErrorCode: + logStr = QStringLiteral ("RX %1: controller=%2 error=%3") + .arg (cmd) + .arg (cid) + .arg (params[1].toInt ()); + break; + case ResponseShape::PhErrorCode: + logStr = QStringLiteral ("RX %1: controller=%2 ph=%3 error=%4") + .arg (cmd) + .arg (cid) + .arg (params[1].toInt ()) + .arg (params[2].toInt ()); + break; } qDebug ("%s %s", qPrintable (logTag (socket)), qPrintable (logStr)); @@ -786,6 +836,35 @@ Xpl2Client::dispatchResponse (const QByteArray &command, return true; } +void +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, + status.statusLevel, status.temperature, status.cpuPercentageBusy); + emit statusMessage ( + QStringLiteral ("RX EV_STATUS_MSG_JC: controller=%1 level=%2") + .arg (status.controllerId) + .arg (status.statusLevel)); + emit jcStatusReceived (status); +} + +void +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, + status.statusLevel, status.printheadId, status.temperature); + emit statusMessage ( + QStringLiteral ("RX EV_STATUS_MSG_PH: controller=%1 level=%2 ph=%3") + .arg (status.controllerId) + .arg (status.statusLevel) + .arg (status.printheadId)); + emit phStatusReceived (status); +} + /* ------------------------------------------------------------------ */ /* Internal */ /* ------------------------------------------------------------------ */ diff --git a/src/Xpl2Client.h b/src/Xpl2Client.h index 78eca0a..724f926 100644 --- a/src/Xpl2Client.h +++ b/src/Xpl2Client.h @@ -4,6 +4,8 @@ */ #pragma once +#include "Xpl2JcStatus.h" +#include "Xpl2PhStatus.h" #include "Xpl2Protocol.h" #include <QHash> @@ -248,6 +250,20 @@ signals: void jcSaveAllPrintheadSettingsResult (int controllerId, bool success); void phSaveSettingsResult (int controllerId, int printheadId, bool success); + /* EV_ event signals */ + void shuttingDown (); + void phConnectionChanged (int controllerId, int printheadId, bool connected); + void jcErrorCode (int controllerId, int errorCode, + const QStringList ¶ms); + void phErrorCode (int controllerId, int printheadId, int errorCode, + const QStringList ¶ms); + void imgErrorCode (int controllerId, int errorCode, + const QStringList ¶ms); + void statusErrorCode (int controllerId, int errorCode, + const QStringList ¶ms); + void jcStatusReceived (const Xpl2JcStatus &status); + void phStatusReceived (const Xpl2PhStatus &status); + private slots: void onSocketConnected (); void onSocketDisconnected (); @@ -276,7 +292,10 @@ private: JcSetter, PhSetter, JcGetter, - PhGetter + PhGetter, + PhConnectionChanged, + ErrorCode, + PhErrorCode }; struct ResponseEntry @@ -290,6 +309,8 @@ private: bool dispatchResponse (const QByteArray &command, const QVariantList ¶ms, const QTcpSocket *socket); + void handleEvStatusMsgJc (const QVariantList ¶ms); + void handleEvStatusMsgPh (const QVariantList ¶ms); void updateConnectedState (); QString logTag (const QTcpSocket *socket) const; diff --git a/src/Xpl2JcStatus.cpp b/src/Xpl2JcStatus.cpp new file mode 100644 index 0000000..b800eb9 --- /dev/null +++ b/src/Xpl2JcStatus.cpp @@ -0,0 +1,70 @@ +/** + * @file Xpl2JcStatus.cpp + * @brief Structured JC status message (EV_STATUS_MSG_JC, Appendix A). + */ +#include "Xpl2JcStatus.h" + +#include <QVariant> + +Xpl2JcStatus +Xpl2JcStatus::fromParams (const QVariantList ¶ms) +{ + Xpl2JcStatus s; + int n = params.size (); + if (n < 2) + return s; + + s.controllerId = params[0].toInt (); + s.statusLevel = params[1].toInt (); + + /* Level 1: fields at indices 2-8 */ + if (n > 2) + s.cpuPercentageBusy = params[2].toFloat (); + if (n > 3) + s.rail5V = params[3].toFloat (); + if (n > 4) + s.railCanBus8V = params[4].toFloat (); + if (n > 5) + s.temperature = params[5].toFloat (); + if (n > 6) + s.humidity = params[6].toFloat (); + if (n > 7) + s.busCurrent = params[7].toFloat (); + if (n > 8) + s.onTimeSeconds = params[8].toInt (); + + /* Level 2: fields at indices 9-22 */ + if (s.statusLevel < 2 || n <= 9) + return s; + + if (n > 9) + s.ipAddress = params[9].toString (); + if (n > 10) + s.eFuseVoltage = params[10].toFloat (); + if (n > 11) + s.eFuseBusEnabled = params[11].toInt () != 0; + if (n > 12) + s.busPowerEnabled = params[12].toInt () != 0; + if (n > 13) + s.busPowerOk = params[13].toInt () != 0; + if (n > 14) + s.switchValue = params[14].toInt (); + if (n > 15) + s.firmwareVersion = params[15].toString (); + if (n > 16) + s.hardwareVersion = params[16].toString (); + if (n > 17) + s.indicator0 = params[17].toInt () != 0; + if (n > 18) + s.indicator1 = params[18].toInt () != 0; + if (n > 19) + s.indicator2 = params[19].toInt () != 0; + if (n > 20) + s.indicator3 = params[20].toInt () != 0; + if (n > 21) + s.indicator4 = params[21].toInt () != 0; + if (n > 22) + s.indicator5 = params[22].toInt () != 0; + + return s; +} diff --git a/src/Xpl2JcStatus.h b/src/Xpl2JcStatus.h new file mode 100644 index 0000000..00e2a64 --- /dev/null +++ b/src/Xpl2JcStatus.h @@ -0,0 +1,73 @@ +/** + * @file Xpl2JcStatus.h + * @brief Structured JC status message (EV_STATUS_MSG_JC, Appendix A). + */ +#pragma once + +#include <QObject> +#include <QString> + +class Xpl2JcStatus +{ + Q_GADGET + + Q_PROPERTY (int controllerId MEMBER controllerId) + Q_PROPERTY (int statusLevel MEMBER statusLevel) + + /* Level 1 fields (3-9) */ + Q_PROPERTY (float cpuPercentageBusy MEMBER cpuPercentageBusy) + Q_PROPERTY (float rail5V MEMBER rail5V) + Q_PROPERTY (float railCanBus8V MEMBER railCanBus8V) + Q_PROPERTY (float temperature MEMBER temperature) + Q_PROPERTY (float humidity MEMBER humidity) + Q_PROPERTY (float busCurrent MEMBER busCurrent) + Q_PROPERTY (int onTimeSeconds MEMBER onTimeSeconds) + + /* Level 2 fields (10-23) */ + Q_PROPERTY (QString ipAddress MEMBER ipAddress) + Q_PROPERTY (float eFuseVoltage MEMBER eFuseVoltage) + Q_PROPERTY (bool eFuseBusEnabled MEMBER eFuseBusEnabled) + Q_PROPERTY (bool busPowerEnabled MEMBER busPowerEnabled) + Q_PROPERTY (bool busPowerOk MEMBER busPowerOk) + Q_PROPERTY (int switchValue MEMBER switchValue) + Q_PROPERTY (QString firmwareVersion MEMBER firmwareVersion) + Q_PROPERTY (QString hardwareVersion MEMBER hardwareVersion) + Q_PROPERTY (bool indicator0 MEMBER indicator0) + Q_PROPERTY (bool indicator1 MEMBER indicator1) + Q_PROPERTY (bool indicator2 MEMBER indicator2) + Q_PROPERTY (bool indicator3 MEMBER indicator3) + Q_PROPERTY (bool indicator4 MEMBER indicator4) + Q_PROPERTY (bool indicator5 MEMBER indicator5) + +public: + int controllerId = 0; + int statusLevel = 0; + + /* Level 1 */ + float cpuPercentageBusy = 0; + float rail5V = 0; + float railCanBus8V = 0; + float temperature = 0; + float humidity = 0; + float busCurrent = 0; + int onTimeSeconds = 0; + + /* Level 2 */ + QString ipAddress; + float eFuseVoltage = 0; + bool eFuseBusEnabled = false; + bool busPowerEnabled = false; + bool busPowerOk = false; + int switchValue = 0; + QString firmwareVersion; + QString hardwareVersion; + bool indicator0 = false; + bool indicator1 = false; + bool indicator2 = false; + bool indicator3 = false; + bool indicator4 = false; + bool indicator5 = false; + + /** Parse from EV_STATUS_MSG_JC params (after command token). */ + static Xpl2JcStatus fromParams (const QVariantList ¶ms); +}; diff --git a/src/Xpl2PhStatus.cpp b/src/Xpl2PhStatus.cpp new file mode 100644 index 0000000..8413db4 --- /dev/null +++ b/src/Xpl2PhStatus.cpp @@ -0,0 +1,149 @@ +/** + * @file Xpl2PhStatus.cpp + * @brief Structured PH status message (EV_STATUS_MSG_PH, Appendix B). + */ +#include "Xpl2PhStatus.h" + +#include <QVariant> + +Xpl2PhStatus +Xpl2PhStatus::fromParams (const QVariantList ¶ms) +{ + Xpl2PhStatus s; + int n = params.size (); + if (n < 3) + return s; + + s.controllerId = params[0].toInt (); + s.statusLevel = params[1].toInt (); + s.printheadId = params[2].toInt (); + + /* Level 1: fields at indices 3-30 */ + if (n > 3) + s.temperature = params[3].toFloat (); + if (n > 4) + s.humidity = params[4].toFloat (); + if (n > 5) + s.mcuTemperature = params[5].toFloat (); + if (n > 6) + s.pdsVoltage = params[6].toFloat (); + if (n > 7) + s.mdsVoltage = params[7].toFloat (); + if (n > 8) + s.systemVoltage = params[8].toFloat (); + if (n > 9) + s.eFuseCurrent = params[9].toFloat (); + if (n > 10) + s.nozzleCurrent = params[10].toFloat (); + if (n > 11) + s.vdd = params[11].toFloat (); + if (n > 12) + s.temperatureTrip = params[12].toInt () != 0; + if (n > 13) + s.pdsOverVoltageTrip = params[13].toInt () != 0; + if (n > 14) + s.pdsUnderVoltageTrip = params[14].toInt () != 0; + if (n > 15) + s.pdsSupplyErrorTrip = params[15].toInt () != 0; + if (n > 16) + s.mdsOverVoltageTrip = params[16].toInt () != 0; + if (n > 17) + s.mdsUnderVoltageTrip = params[17].toInt () != 0; + if (n > 18) + s.supplyOverVoltageTrip = params[18].toInt () != 0; + if (n > 19) + s.supplyUnderVoltageTrip = params[19].toInt () != 0; + if (n > 20) + s.eFuseOverCurrentTrip = params[20].toInt () != 0; + if (n > 21) + s.eFuseInputVoltageErrorTrip = params[21].toInt () != 0; + if (n > 22) + s.eFuseFaultTrip = params[22].toInt () != 0; + if (n > 23) + s.flashFaultyTrip = params[23].toInt () != 0; + if (n > 24) + s.flashChecksumErrorTrip = params[24].toInt () != 0; + if (n > 25) + s.dutyCycle = params[25].toFloat (); + if (n > 26) + s.pwmFrequency = params[26].toFloat (); + if (n > 27) + s.drive = params[27].toInt (); + if (n > 28) + s.nozzleDriveFrequency = params[28].toFloat (); + if (n > 29) + s.nozzleDriveDutyCycle = params[29].toFloat (); + if (n > 30) + s.onTimeSeconds = params[30].toInt (); + + /* Level 2: fields at indices 31-61 */ + if (s.statusLevel < 2 || n <= 31) + return s; + + if (n > 31) + s.accelerometerId = params[31].toInt (); + if (n > 32) + s.mcuId = params[32].toString (); + if (n > 33) + s.flashMemoryId = params[33].toString (); + if (n > 34) + s.temperatureSensorSerialNumber = params[34].toInt (); + if (n > 35) + s.mcuHardwareVersion = params[35].toString (); + if (n > 36) + s.mcuFirmwareVersion = params[36].toString (); + if (n > 37) + s.mcuFirmwareVariant = params[37].toString (); + if (n > 38) + s.fpgaHardwareVersion = params[38].toString (); + if (n > 39) + s.fpgaFirmwareVersion = params[39].toString (); + if (n > 40) + s.bootloaderVersion = params[40].toString (); + if (n > 41) + s.maxAllowedTemperature = params[41].toFloat (); + if (n > 42) + s.pdsVoltageMax = params[42].toFloat (); + if (n > 43) + s.pdsVoltageMin = params[43].toFloat (); + if (n > 44) + s.pdsVoltageSetting = params[44].toFloat (); + if (n > 45) + s.mdsVoltageMax = params[45].toFloat (); + if (n > 46) + s.mdsVoltageMin = params[46].toFloat (); + if (n > 47) + s.eFuseCurrentMax = params[47].toFloat (); + if (n > 48) + s.measuredHardwareVersion = params[48].toString (); + if (n > 49) + s.gyroX = params[49].toInt (); + if (n > 50) + s.gyroY = params[50].toInt (); + if (n > 51) + s.gyroZ = params[51].toInt (); + if (n > 52) + s.accelerationX = params[52].toInt (); + if (n > 53) + s.accelerationY = params[53].toInt (); + if (n > 54) + s.accelerationZ = params[54].toInt (); + if (n > 55) + s.purge = params[55].toInt (); + if (n > 56) + s.purgeState = params[56].toInt (); + if (n > 57) + s.purgeDelay = params[57].toInt (); + if (n > 58) + s.purgeCounter = params[58].toInt (); + if (n > 59) + s.cleaningStartPeriod = params[59].toInt (); + if (n > 60) + s.cleaningEndPeriod = params[60].toInt (); + if (n > 61) + s.cleaningStepPeriod = params[61].toInt (); + if (n > 62) + s.cleaningPeriod = params[62].toInt (); + + return s; +} diff --git a/src/Xpl2PhStatus.h b/src/Xpl2PhStatus.h new file mode 100644 index 0000000..75a04a0 --- /dev/null +++ b/src/Xpl2PhStatus.h @@ -0,0 +1,155 @@ +/** + * @file Xpl2PhStatus.h + * @brief Structured PH status message (EV_STATUS_MSG_PH, Appendix B). + */ +#pragma once + +#include <QObject> +#include <QString> + +class Xpl2PhStatus +{ + Q_GADGET + + Q_PROPERTY (int controllerId MEMBER controllerId) + Q_PROPERTY (int statusLevel MEMBER statusLevel) + Q_PROPERTY (int printheadId MEMBER printheadId) + + /* Level 1 fields (4-31) */ + Q_PROPERTY (float temperature MEMBER temperature) + Q_PROPERTY (float humidity MEMBER humidity) + Q_PROPERTY (float mcuTemperature MEMBER mcuTemperature) + Q_PROPERTY (float pdsVoltage MEMBER pdsVoltage) + Q_PROPERTY (float mdsVoltage MEMBER mdsVoltage) + Q_PROPERTY (float systemVoltage MEMBER systemVoltage) + Q_PROPERTY (float eFuseCurrent MEMBER eFuseCurrent) + Q_PROPERTY (float nozzleCurrent MEMBER nozzleCurrent) + Q_PROPERTY (float vdd MEMBER vdd) + Q_PROPERTY (bool temperatureTrip MEMBER temperatureTrip) + Q_PROPERTY (bool pdsOverVoltageTrip MEMBER pdsOverVoltageTrip) + Q_PROPERTY (bool pdsUnderVoltageTrip MEMBER pdsUnderVoltageTrip) + Q_PROPERTY (bool pdsSupplyErrorTrip MEMBER pdsSupplyErrorTrip) + Q_PROPERTY (bool mdsOverVoltageTrip MEMBER mdsOverVoltageTrip) + Q_PROPERTY (bool mdsUnderVoltageTrip MEMBER mdsUnderVoltageTrip) + Q_PROPERTY (bool supplyOverVoltageTrip MEMBER supplyOverVoltageTrip) + Q_PROPERTY (bool supplyUnderVoltageTrip MEMBER supplyUnderVoltageTrip) + Q_PROPERTY (bool eFuseOverCurrentTrip MEMBER eFuseOverCurrentTrip) + Q_PROPERTY ( + bool eFuseInputVoltageErrorTrip MEMBER eFuseInputVoltageErrorTrip) + Q_PROPERTY (bool eFuseFaultTrip MEMBER eFuseFaultTrip) + Q_PROPERTY (bool flashFaultyTrip MEMBER flashFaultyTrip) + Q_PROPERTY (bool flashChecksumErrorTrip MEMBER flashChecksumErrorTrip) + Q_PROPERTY (float dutyCycle MEMBER dutyCycle) + Q_PROPERTY (float pwmFrequency MEMBER pwmFrequency) + Q_PROPERTY (int drive MEMBER drive) + Q_PROPERTY (float nozzleDriveFrequency MEMBER nozzleDriveFrequency) + Q_PROPERTY (float nozzleDriveDutyCycle MEMBER nozzleDriveDutyCycle) + Q_PROPERTY (int onTimeSeconds MEMBER onTimeSeconds) + + /* Level 2 fields (32-62) */ + Q_PROPERTY (int accelerometerId MEMBER accelerometerId) + Q_PROPERTY (QString mcuId MEMBER mcuId) + Q_PROPERTY (QString flashMemoryId MEMBER flashMemoryId) + Q_PROPERTY ( + int temperatureSensorSerialNumber MEMBER temperatureSensorSerialNumber) + Q_PROPERTY (QString mcuHardwareVersion MEMBER mcuHardwareVersion) + Q_PROPERTY (QString mcuFirmwareVersion MEMBER mcuFirmwareVersion) + Q_PROPERTY (QString mcuFirmwareVariant MEMBER mcuFirmwareVariant) + Q_PROPERTY (QString fpgaHardwareVersion MEMBER fpgaHardwareVersion) + Q_PROPERTY (QString fpgaFirmwareVersion MEMBER fpgaFirmwareVersion) + Q_PROPERTY (QString bootloaderVersion MEMBER bootloaderVersion) + Q_PROPERTY (float maxAllowedTemperature MEMBER maxAllowedTemperature) + Q_PROPERTY (float pdsVoltageMax MEMBER pdsVoltageMax) + Q_PROPERTY (float pdsVoltageMin MEMBER pdsVoltageMin) + Q_PROPERTY (float pdsVoltageSetting MEMBER pdsVoltageSetting) + Q_PROPERTY (float mdsVoltageMax MEMBER mdsVoltageMax) + Q_PROPERTY (float mdsVoltageMin MEMBER mdsVoltageMin) + Q_PROPERTY (float eFuseCurrentMax MEMBER eFuseCurrentMax) + Q_PROPERTY (QString measuredHardwareVersion MEMBER measuredHardwareVersion) + Q_PROPERTY (int gyroX MEMBER gyroX) + Q_PROPERTY (int gyroY MEMBER gyroY) + Q_PROPERTY (int gyroZ MEMBER gyroZ) + Q_PROPERTY (int accelerationX MEMBER accelerationX) + Q_PROPERTY (int accelerationY MEMBER accelerationY) + Q_PROPERTY (int accelerationZ MEMBER accelerationZ) + Q_PROPERTY (int purge MEMBER purge) + Q_PROPERTY (int purgeState MEMBER purgeState) + Q_PROPERTY (int purgeDelay MEMBER purgeDelay) + Q_PROPERTY (int purgeCounter MEMBER purgeCounter) + Q_PROPERTY (int cleaningStartPeriod MEMBER cleaningStartPeriod) + Q_PROPERTY (int cleaningEndPeriod MEMBER cleaningEndPeriod) + Q_PROPERTY (int cleaningStepPeriod MEMBER cleaningStepPeriod) + Q_PROPERTY (int cleaningPeriod MEMBER cleaningPeriod) + +public: + int controllerId = 0; + int statusLevel = 0; + int printheadId = 0; + + /* Level 1 */ + float temperature = 0; + float humidity = 0; + float mcuTemperature = 0; + float pdsVoltage = 0; + float mdsVoltage = 0; + float systemVoltage = 0; + float eFuseCurrent = 0; + float nozzleCurrent = 0; + float vdd = 0; + bool temperatureTrip = false; + bool pdsOverVoltageTrip = false; + bool pdsUnderVoltageTrip = false; + bool pdsSupplyErrorTrip = false; + bool mdsOverVoltageTrip = false; + bool mdsUnderVoltageTrip = false; + bool supplyOverVoltageTrip = false; + bool supplyUnderVoltageTrip = false; + bool eFuseOverCurrentTrip = false; + bool eFuseInputVoltageErrorTrip = false; + bool eFuseFaultTrip = false; + bool flashFaultyTrip = false; + bool flashChecksumErrorTrip = false; + float dutyCycle = 0; + float pwmFrequency = 0; + int drive = 0; + float nozzleDriveFrequency = 0; + float nozzleDriveDutyCycle = 0; + int onTimeSeconds = 0; + + /* Level 2 */ + int accelerometerId = 0; + QString mcuId; + QString flashMemoryId; + int temperatureSensorSerialNumber = 0; + QString mcuHardwareVersion; + QString mcuFirmwareVersion; + QString mcuFirmwareVariant; + QString fpgaHardwareVersion; + QString fpgaFirmwareVersion; + QString bootloaderVersion; + float maxAllowedTemperature = 0; + float pdsVoltageMax = 0; + float pdsVoltageMin = 0; + float pdsVoltageSetting = 0; + float mdsVoltageMax = 0; + float mdsVoltageMin = 0; + float eFuseCurrentMax = 0; + QString measuredHardwareVersion; + int gyroX = 0; + int gyroY = 0; + int gyroZ = 0; + int accelerationX = 0; + int accelerationY = 0; + int accelerationZ = 0; + int purge = 0; + int purgeState = 0; + int purgeDelay = 0; + int purgeCounter = 0; + int cleaningStartPeriod = 0; + int cleaningEndPeriod = 0; + int cleaningStepPeriod = 0; + int cleaningPeriod = 0; + + /** Parse from EV_STATUS_MSG_PH params (after command token). */ + static Xpl2PhStatus fromParams (const QVariantList ¶ms); +}; |
