From a571abb35b7b2038f0e8e7c4aca4fe26aae08750 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 16 Oct 2026 06:49:45 +0700 Subject: [PATCH 1/4] fix(studio): copy full field diagnostics and retain firmware verification reason --- apps/arstack_studio/qml/FirmwarePanel.qml | 9 ++- apps/arstack_studio/qml/Main.qml | 1 + apps/arstack_studio/qml/WorkflowBar.qml | 6 +- .../src/DeterministicSessionHarness.cpp | 18 +++++ .../src/SmartSessionController.cpp | 74 +++++++++++++++++++ .../src/SmartSessionController.hpp | 5 ++ 6 files changed, 109 insertions(+), 4 deletions(-) diff --git a/apps/arstack_studio/qml/FirmwarePanel.qml b/apps/arstack_studio/qml/FirmwarePanel.qml index a151ce9db..3779883ec 100644 --- a/apps/arstack_studio/qml/FirmwarePanel.qml +++ b/apps/arstack_studio/qml/FirmwarePanel.qml @@ -344,9 +344,16 @@ SurfacePanel { text: panel.technicalDetailsVisible ? "Hide technical details" : "Technical details" onClicked: panel.technicalDetailsVisible = !panel.technicalDetailsVisible } + CalmButton { + theme: panel.theme + uiFont: panel.uiFont + text: "Copy diagnostics" + enabled: panel.session !== null + onClicked: panel.session.copyDiagnostics() + } Label { Layout.fillWidth: true - text: "Protocol, target revision, SHA-256 and firmware-service log" + text: "Review/redact device identifiers and logs before sharing" color: panel.theme.muted font.family: panel.uiFont font.pixelSize: 9 diff --git a/apps/arstack_studio/qml/Main.qml b/apps/arstack_studio/qml/Main.qml index 775ac6adf..089e6d7f9 100644 --- a/apps/arstack_studio/qml/Main.qml +++ b/apps/arstack_studio/qml/Main.qml @@ -410,6 +410,7 @@ ApplicationWindow { font.pixelSize: 9 } Item { Layout.fillWidth: true } + CalmButton { theme: studioTheme; uiFont: root.uiFont; text: "Copy diagnostics"; onClicked: workflowBar.session.copyDiagnostics() } CalmButton { theme: studioTheme; uiFont: root.uiFont; text: "Clear"; onClicked: device.clearLog() } } ScrollView { diff --git a/apps/arstack_studio/qml/WorkflowBar.qml b/apps/arstack_studio/qml/WorkflowBar.qml index 7ad54c4df..c4e75cf88 100644 --- a/apps/arstack_studio/qml/WorkflowBar.qml +++ b/apps/arstack_studio/qml/WorkflowBar.qml @@ -146,9 +146,9 @@ SurfacePanel { controller.showMessage("Firmware installed and verified successfully.", false) } else { ribbon.firmwareResultTitle = "Firmware installation not completed" - ribbon.firmwareResultMessage = FirmwareService.status.length > 0 - ? FirmwareService.status - : "Studio could not verify the firmware installation. Keep the board connected and try again." + ribbon.firmwareResultMessage = smartSession.firmwareUpdateResult.length > 0 + ? smartSession.firmwareUpdateResult + : "Studio could not verify the firmware installation. Open Advanced > Firmware > Copy diagnostics." controller.showMessage("Firmware installation was not verified.", true) } Qt.callLater(resultDialog.open) diff --git a/apps/arstack_studio/src/DeterministicSessionHarness.cpp b/apps/arstack_studio/src/DeterministicSessionHarness.cpp index 5829964cc..9f82fc3c0 100644 --- a/apps/arstack_studio/src/DeterministicSessionHarness.cpp +++ b/apps/arstack_studio/src/DeterministicSessionHarness.cpp @@ -33,6 +33,7 @@ class DeterministicSessionHarness final { {"same version stale build -> READY with update suggestion", sameVersionStaleBuildOffersUpdate()}, {"optional bootloader wait -> cancel restores supervisor", optionalBootloaderWaitCanCancel()}, {"firmware stage projection -> supervisor-owned", firmwareStageProjectionIsExplicit()}, + {"firmware verification failure remains copyable after READY", firmwareFailureRemainsDiagnosable()}, {"fragmented espflash progress -> monotonic", fragmentedEspflashProgressIsMonotonic()}, {"trusted ESP32-P4 identity timeout -> firmware required", automaticIdentityTimeoutOffersFirmwareRecovery()}, {"single visible COM without metadata -> firmware required", singleVisibleTimeoutWithoutRecommendationOffersFirmwareRecovery()}, @@ -941,6 +942,23 @@ class DeterministicSessionHarness final { !device.healthProbeOutstanding_; } + static bool firmwareFailureRemainsDiagnosable() { + Fixture fixture; + if (!fixture.profileReady) return false; + auto& session = fixture.session; + session.updateWasOptional_ = true; + session.updateRequested_ = true; + session.updateStage_ = SmartSessionController::UpdateStage::reconnecting; + session.latchFirmwareFailure(QStringLiteral( + "Firmware was written, but reconnect reported a different build.")); + const QString report = session.diagnosticsText(); + return !session.updateRequested_ && !session.setupError_ && + session.firmwareUpdateResult().contains(QStringLiteral("different build")) && + report.contains(QStringLiteral("Last firmware update result: Firmware was written")) && + report.contains(QStringLiteral("Bundled build ID: 0123456789abcdef")) && + report.contains(QStringLiteral("Exact bundled build match: NOT VERIFIED")); + } + static bool workerTeardownCompletes() { bool profileReady = false; { diff --git a/apps/arstack_studio/src/SmartSessionController.cpp b/apps/arstack_studio/src/SmartSessionController.cpp index ef337feaf..c3df34122 100644 --- a/apps/arstack_studio/src/SmartSessionController.cpp +++ b/apps/arstack_studio/src/SmartSessionController.cpp @@ -7,6 +7,9 @@ #include "SclProfileModel.hpp" #include +#include +#include +#include #include #include @@ -478,6 +481,7 @@ bool SmartSessionController::beginFirmwareOperation(const QString& portName) { resetProfileSync(true); setupError_ = false; setupErrorStatus_.clear(); + lastFirmwareUpdateResult_.clear(); if (device_->running()) { updateStage_ = UpdateStage::stopping; @@ -503,6 +507,7 @@ bool SmartSessionController::retryFirmwareUpdate() { if (device_ == nullptr || firmware_ == nullptr || updatePort_.isEmpty() || firmware_->busy()) return false; setupError_ = false; setupErrorStatus_.clear(); + lastFirmwareUpdateResult_.clear(); blankBoardDetected_ = false; updateRequested_ = true; updateReconnectAttempts_ = 0; @@ -861,6 +866,71 @@ void SmartSessionController::clearBlankBoardContext() { setupErrorStatus_.clear(); } +QString SmartSessionController::diagnosticsText() const { + // Operator-triggered read-only snapshot; does not touch serial ownership. + QStringList rows; + auto add = [&rows](const QString& key, const QString& value) { + rows << key + QStringLiteral(": ") + (value.isEmpty() ? QStringLiteral("-") : value); + }; + rows << QStringLiteral("ARStack Studio field diagnostics") + << QStringLiteral("Device telemetry is reported, not independently verified on wire."); + add(QStringLiteral("Studio version"), expectedFirmwareVersion()); + add(QStringLiteral("Session state"), state_); + add(QStringLiteral("Session status"), statusText_); + add(QStringLiteral("Session generation"), QString::number(sessionGeneration_)); + add(QStringLiteral("Serial owner"), portOwner_ == PortOwner::deviceSession + ? QStringLiteral("device session") : portOwner_ == PortOwner::firmwareTool + ? QStringLiteral("firmware tool") : QStringLiteral("none")); + add(QStringLiteral("Firmware update stage"), firmwareUpdateStage()); + add(QStringLiteral("Last firmware update result"), lastFirmwareUpdateResult_); + add(QStringLiteral("Setup error"), setupErrorStatus_); + if (firmware_ != nullptr) { + add(QStringLiteral("Bundled firmware version"), firmware_->firmwareVersion()); + add(QStringLiteral("Bundled build ID"), firmware_->firmwareBuildId()); + add(QStringLiteral("Bundled firmware SHA256"), firmware_->firmwareSha256()); + add(QStringLiteral("Firmware service status"), firmware_->status()); + add(QStringLiteral("Firmware target"), firmware_->targetChip()); + add(QStringLiteral("Firmware operation busy"), firmware_->busy() ? QStringLiteral("yes") : QStringLiteral("no")); + } + if (device_ != nullptr) { + add(QStringLiteral("Device verified"), device_->deviceVerified() ? QStringLiteral("yes") : QStringLiteral("no")); + add(QStringLiteral("COM port"), device_->portName()); + add(QStringLiteral("Device product"), device_->deviceProduct()); + add(QStringLiteral("Device target"), device_->deviceTarget()); + add(QStringLiteral("Device ID"), device_->deviceId()); + add(QStringLiteral("Device firmware version"), device_->firmwareVersion()); + add(QStringLiteral("Device firmware build ID"), device_->firmwareBuildId()); + add(QStringLiteral("Device protocol"), device_->protocolVersion()); + add(QStringLiteral("Device capabilities"), device_->capabilities().join(QStringLiteral(", "))); + add(QStringLiteral("Exact bundled build match"), firmwareIsCurrent() ? QStringLiteral("yes") : QStringLiteral("NOT VERIFIED")); + add(QStringLiteral("Firmware protocol compatible"), firmwareIsCompatible() ? QStringLiteral("yes") : QStringLiteral("no")); + add(QStringLiteral("Profile generation"), device_->profileGeneration()); + add(QStringLiteral("Profile armed"), device_->profileArmed() ? QStringLiteral("yes") : QStringLiteral("no")); + add(QStringLiteral("SMV running"), device_->running() ? QStringLiteral("yes") : QStringLiteral("no")); + add(QStringLiteral("SMV FPS reported"), device_->fps()); + add(QStringLiteral("SMV missed reported"), device_->missed()); + add(QStringLiteral("SMV TX failures reported"), device_->txFailures()); + add(QStringLiteral("PTP status reported"), device_->ptpStatus()); + add(QStringLiteral("PTP role reported"), device_->ptpRole()); + add(QStringLiteral("PTP discipline reported"), device_->ptpDiscipline()); + add(QStringLiteral("SMPSYNCH value reported"), device_->smpSynchValue()); + add(QStringLiteral("Device last error"), device_->lastError()); + rows << QStringLiteral("--- Device serial log, last 12000 chars ---") + << device_->logText().right(12000); + } + if (firmware_ != nullptr) { + rows << QStringLiteral("--- Firmware service log, last 12000 chars ---") + << firmware_->logText().right(12000); + } + rows << QStringLiteral("Review and redact site identifiers or addresses before sharing."); + return rows.join(QLatin1Char('\n')); +} + +void SmartSessionController::copyDiagnostics() const { + if (auto* clipboard = QGuiApplication::clipboard(); clipboard != nullptr) + clipboard->setText(diagnosticsText()); +} + void SmartSessionController::latchFirmwareFailure(QString message) { reconnectTimer_.stop(); const bool optionalOperation = updateWasOptional_; @@ -872,6 +942,9 @@ void SmartSessionController::latchFirmwareFailure(QString message) { blankBoardDetected_ = false; if (portOwner_ == PortOwner::firmwareTool) setPortOwner(PortOwner::none); message = message.trimmed(); + lastFirmwareUpdateResult_ = message.isEmpty() + ? QStringLiteral("Firmware verification failed; inspect the firmware-service log.") + : message; setupError_ = !optionalOperation; setupErrorStatus_ = optionalOperation ? QString{} : (message.isEmpty() ? QStringLiteral("Firmware setup did not complete. Retry explicitly when the board is ready.") @@ -1143,6 +1216,7 @@ void SmartSessionController::reconcile() { updateRequested_ = false; updateWasOptional_ = false; updateStage_ = UpdateStage::idle; + lastFirmwareUpdateResult_ = QStringLiteral("Exact bundled firmware build verified after reconnect."); clearBlankBoardContext(); emit firmwareUpdateFinished(true); } diff --git a/apps/arstack_studio/src/SmartSessionController.hpp b/apps/arstack_studio/src/SmartSessionController.hpp index 8b00a16ec..eae0de0c2 100644 --- a/apps/arstack_studio/src/SmartSessionController.hpp +++ b/apps/arstack_studio/src/SmartSessionController.hpp @@ -42,6 +42,7 @@ class SmartSessionController : public QObject { Q_PROPERTY(QString expectedFirmwareBuildId READ expectedFirmwareBuildId NOTIFY stateChanged) Q_PROPERTY(QString deviceFirmwareVersion READ deviceFirmwareVersion NOTIFY stateChanged) Q_PROPERTY(QString deviceFirmwareBuildId READ deviceFirmwareBuildId NOTIFY stateChanged) + Q_PROPERTY(QString firmwareUpdateResult READ firmwareUpdateResult NOTIFY stateChanged) Q_PROPERTY(qulonglong sessionGeneration READ sessionGeneration NOTIFY stateChanged) Q_PROPERTY(PortOwner portOwner READ portOwner NOTIFY stateChanged) @@ -205,6 +206,9 @@ class SmartSessionController : public QObject { Q_INVOKABLE bool retryFirmwareSetup(); Q_INVOKABLE bool retryIdentification(); Q_INVOKABLE bool retryProfileSync(); + Q_INVOKABLE QString diagnosticsText() const; + Q_INVOKABLE void copyDiagnostics() const; + [[nodiscard]] QString firmwareUpdateResult() const { return lastFirmwareUpdateResult_; } signals: void dependenciesChanged(); @@ -380,6 +384,7 @@ class SmartSessionController : public QObject { QString updatePort_; QString blankBoardPort_; QString setupErrorStatus_; + QString lastFirmwareUpdateResult_; QString profileSyncBaselineGeneration_; QString profileSyncBootId_; QString profileSyncError_; From 4886b0c42a9c31964a4dad49c310680008518fd1 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 16 Oct 2026 06:56:00 +0700 Subject: [PATCH 2/4] build(studio): link QtGui clipboard dependency in deterministic harness --- apps/arstack_studio/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/arstack_studio/CMakeLists.txt b/apps/arstack_studio/CMakeLists.txt index d6dfe913c..a15e08519 100644 --- a/apps/arstack_studio/CMakeLists.txt +++ b/apps/arstack_studio/CMakeLists.txt @@ -149,6 +149,7 @@ target_link_libraries(arstack_studio PRIVATE target_link_libraries(arstack_session_harness PRIVATE Qt6::Core + Qt6::Gui Qt6::SerialPort ARIEC61850::core ) From e5d16a08c76a32ae12ca2e1c14f1270bac5d4ae3 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 16 Oct 2026 07:03:46 +0700 Subject: [PATCH 3/4] refactor(studio): isolate clipboard in GUI singleton; report offline identity as unknown --- apps/arstack_studio/CMakeLists.txt | 3 ++- apps/arstack_studio/qml/FirmwarePanel.qml | 3 ++- apps/arstack_studio/qml/Main.qml | 2 +- .../src/DeterministicSessionHarness.cpp | 3 ++- apps/arstack_studio/src/SmartSessionController.cpp | 11 +++-------- apps/arstack_studio/src/SmartSessionController.hpp | 1 - apps/arstack_studio/src/StudioClipboard.cpp | 10 ++++++++++ apps/arstack_studio/src/StudioClipboard.hpp | 13 +++++++++++++ apps/arstack_studio/src/main.cpp | 3 +++ 9 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 apps/arstack_studio/src/StudioClipboard.cpp create mode 100644 apps/arstack_studio/src/StudioClipboard.hpp diff --git a/apps/arstack_studio/CMakeLists.txt b/apps/arstack_studio/CMakeLists.txt index a15e08519..ddfed8eb6 100644 --- a/apps/arstack_studio/CMakeLists.txt +++ b/apps/arstack_studio/CMakeLists.txt @@ -36,6 +36,8 @@ set(ARSTACK_STUDIO_CORE_SOURCES qt_add_executable(arstack_studio src/main.cpp + src/StudioClipboard.cpp + src/StudioClipboard.hpp ${ARSTACK_STUDIO_CORE_SOURCES} ) @@ -149,7 +151,6 @@ target_link_libraries(arstack_studio PRIVATE target_link_libraries(arstack_session_harness PRIVATE Qt6::Core - Qt6::Gui Qt6::SerialPort ARIEC61850::core ) diff --git a/apps/arstack_studio/qml/FirmwarePanel.qml b/apps/arstack_studio/qml/FirmwarePanel.qml index 3779883ec..8e77f54f9 100644 --- a/apps/arstack_studio/qml/FirmwarePanel.qml +++ b/apps/arstack_studio/qml/FirmwarePanel.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import ARStack.Studio 1.0 SurfacePanel { id: panel @@ -349,7 +350,7 @@ SurfacePanel { uiFont: panel.uiFont text: "Copy diagnostics" enabled: panel.session !== null - onClicked: panel.session.copyDiagnostics() + onClicked: StudioClipboard.copyText(panel.session.diagnosticsText()) } Label { Layout.fillWidth: true diff --git a/apps/arstack_studio/qml/Main.qml b/apps/arstack_studio/qml/Main.qml index 089e6d7f9..4da38730e 100644 --- a/apps/arstack_studio/qml/Main.qml +++ b/apps/arstack_studio/qml/Main.qml @@ -410,7 +410,7 @@ ApplicationWindow { font.pixelSize: 9 } Item { Layout.fillWidth: true } - CalmButton { theme: studioTheme; uiFont: root.uiFont; text: "Copy diagnostics"; onClicked: workflowBar.session.copyDiagnostics() } + CalmButton { theme: studioTheme; uiFont: root.uiFont; text: "Copy diagnostics"; onClicked: StudioClipboard.copyText(workflowBar.session.diagnosticsText()) } CalmButton { theme: studioTheme; uiFont: root.uiFont; text: "Clear"; onClicked: device.clearLog() } } ScrollView { diff --git a/apps/arstack_studio/src/DeterministicSessionHarness.cpp b/apps/arstack_studio/src/DeterministicSessionHarness.cpp index 9f82fc3c0..586380e55 100644 --- a/apps/arstack_studio/src/DeterministicSessionHarness.cpp +++ b/apps/arstack_studio/src/DeterministicSessionHarness.cpp @@ -956,7 +956,8 @@ class DeterministicSessionHarness final { session.firmwareUpdateResult().contains(QStringLiteral("different build")) && report.contains(QStringLiteral("Last firmware update result: Firmware was written")) && report.contains(QStringLiteral("Bundled build ID: 0123456789abcdef")) && - report.contains(QStringLiteral("Exact bundled build match: NOT VERIFIED")); + report.contains(QStringLiteral("Exact bundled build match: NOT VERIFIED")) && + report.contains(QStringLiteral("Firmware protocol compatible: UNKNOWN")); } static bool workerTeardownCompletes() { diff --git a/apps/arstack_studio/src/SmartSessionController.cpp b/apps/arstack_studio/src/SmartSessionController.cpp index c3df34122..b5f1b2f31 100644 --- a/apps/arstack_studio/src/SmartSessionController.cpp +++ b/apps/arstack_studio/src/SmartSessionController.cpp @@ -7,8 +7,6 @@ #include "SclProfileModel.hpp" #include -#include -#include #include #include @@ -903,7 +901,9 @@ QString SmartSessionController::diagnosticsText() const { add(QStringLiteral("Device protocol"), device_->protocolVersion()); add(QStringLiteral("Device capabilities"), device_->capabilities().join(QStringLiteral(", "))); add(QStringLiteral("Exact bundled build match"), firmwareIsCurrent() ? QStringLiteral("yes") : QStringLiteral("NOT VERIFIED")); - add(QStringLiteral("Firmware protocol compatible"), firmwareIsCompatible() ? QStringLiteral("yes") : QStringLiteral("no")); + add(QStringLiteral("Firmware protocol compatible"), !device_->deviceVerified() + ? QStringLiteral("UNKNOWN (identity not verified)") + : firmwareIsCompatible() ? QStringLiteral("yes") : QStringLiteral("no")); add(QStringLiteral("Profile generation"), device_->profileGeneration()); add(QStringLiteral("Profile armed"), device_->profileArmed() ? QStringLiteral("yes") : QStringLiteral("no")); add(QStringLiteral("SMV running"), device_->running() ? QStringLiteral("yes") : QStringLiteral("no")); @@ -926,11 +926,6 @@ QString SmartSessionController::diagnosticsText() const { return rows.join(QLatin1Char('\n')); } -void SmartSessionController::copyDiagnostics() const { - if (auto* clipboard = QGuiApplication::clipboard(); clipboard != nullptr) - clipboard->setText(diagnosticsText()); -} - void SmartSessionController::latchFirmwareFailure(QString message) { reconnectTimer_.stop(); const bool optionalOperation = updateWasOptional_; diff --git a/apps/arstack_studio/src/SmartSessionController.hpp b/apps/arstack_studio/src/SmartSessionController.hpp index eae0de0c2..b31d2a673 100644 --- a/apps/arstack_studio/src/SmartSessionController.hpp +++ b/apps/arstack_studio/src/SmartSessionController.hpp @@ -207,7 +207,6 @@ class SmartSessionController : public QObject { Q_INVOKABLE bool retryIdentification(); Q_INVOKABLE bool retryProfileSync(); Q_INVOKABLE QString diagnosticsText() const; - Q_INVOKABLE void copyDiagnostics() const; [[nodiscard]] QString firmwareUpdateResult() const { return lastFirmwareUpdateResult_; } signals: diff --git a/apps/arstack_studio/src/StudioClipboard.cpp b/apps/arstack_studio/src/StudioClipboard.cpp new file mode 100644 index 000000000..ee2e3c2fd --- /dev/null +++ b/apps/arstack_studio/src/StudioClipboard.cpp @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +#include "StudioClipboard.hpp" + +#include +#include + +void StudioClipboard::copyText(const QString& text) const { + if (auto* clipboard = QGuiApplication::clipboard(); clipboard != nullptr) + clipboard->setText(text); +} diff --git a/apps/arstack_studio/src/StudioClipboard.hpp b/apps/arstack_studio/src/StudioClipboard.hpp new file mode 100644 index 000000000..35c105ccb --- /dev/null +++ b/apps/arstack_studio/src/StudioClipboard.hpp @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include +#include + +// GUI-only clipboard adapter. The shared session supervisor stays QtCore-only. +class StudioClipboard final : public QObject { + Q_OBJECT +public: + using QObject::QObject; + Q_INVOKABLE void copyText(const QString& text) const; +}; diff --git a/apps/arstack_studio/src/main.cpp b/apps/arstack_studio/src/main.cpp index 14e3389c5..f208cd705 100644 --- a/apps/arstack_studio/src/main.cpp +++ b/apps/arstack_studio/src/main.cpp @@ -5,6 +5,7 @@ #include "SclProfileModel.hpp" #include "SingleInstanceGuard.hpp" #include "SmartSessionController.hpp" +#include "StudioClipboard.hpp" #include "StudioDeviceController.hpp" #include @@ -462,6 +463,8 @@ int main(int argc, char* argv[]) { qmlRegisterType("ARStack.Studio", 1, 0, "DeviceController"); qmlRegisterType("ARStack.Studio", 1, 0, "SmartSessionController"); qmlRegisterSingletonInstance("ARStack.Studio", 1, 0, "FirmwareService", &firmwareService); + StudioClipboard clipboard; + qmlRegisterSingletonInstance("ARStack.Studio", 1, 0, "StudioClipboard", &clipboard); QQmlApplicationEngine engine; QObject::connect( From 34485139b136b67e00bf90d9ab386936c7c416d9 Mon Sep 17 00:00:00 2001 From: Ari Sulistiono Date: Fri, 16 Oct 2026 07:09:04 +0700 Subject: [PATCH 4/4] fix(studio): show terminal firmware verification error in Advanced and copy SV profile evidence --- apps/arstack_studio/qml/FirmwarePanel.qml | 19 +++++++++++++------ .../src/DeterministicSessionHarness.cpp | 2 ++ .../src/SmartSessionController.cpp | 8 ++++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/arstack_studio/qml/FirmwarePanel.qml b/apps/arstack_studio/qml/FirmwarePanel.qml index 8e77f54f9..c0b36c5ee 100644 --- a/apps/arstack_studio/qml/FirmwarePanel.qml +++ b/apps/arstack_studio/qml/FirmwarePanel.qml @@ -12,6 +12,13 @@ SurfacePanel { property string uiFont: "Inter" property string monoFont: "Inter" property bool technicalDetailsVisible: false + readonly property string firmwareDisplayStatus: + panel.session && panel.session.firmwareUpdateResult.length > 0 && + !panel.session.updatingFirmware + ? panel.session.firmwareUpdateResult : panel.firmware.status + readonly property bool verificationFailed: + panel.session && panel.session.firmwareUpdateResult.length > 0 && + !panel.session.firmwareUpdateResult.startsWith("Exact bundled firmware build verified") readonly property bool hasPort: firmwarePort.currentText.length > 0 @@ -318,17 +325,17 @@ SurfacePanel { Rectangle { Layout.fillWidth: true - implicitHeight: panel.firmware.status.length > 0 ? 52 : 0 - visible: panel.firmware.status.length > 0 + implicitHeight: panel.firmwareDisplayStatus.length > 0 ? 52 : 0 + visible: panel.firmwareDisplayStatus.length > 0 radius: 7 - color: panel.firmware.targetVerified ? "#10251d" : (panel.firmware.bootloaderHelpNeeded ? "#261f13" : "#171d25") + color: panel.verificationFailed ? "#2a171c" : (panel.firmware.targetVerified ? "#10251d" : (panel.firmware.bootloaderHelpNeeded ? "#261f13" : "#171d25")) border.width: 1 - border.color: panel.firmware.targetVerified ? "#2c674e" : (panel.firmware.bootloaderHelpNeeded ? "#705827" : panel.theme.lineSoft) + border.color: panel.verificationFailed ? panel.theme.red : (panel.firmware.targetVerified ? "#2c674e" : (panel.firmware.bootloaderHelpNeeded ? "#705827" : panel.theme.lineSoft)) Label { anchors.fill: parent anchors.margins: 11 - text: panel.firmware.status - color: panel.firmware.targetVerified ? panel.theme.green : (panel.firmware.bootloaderHelpNeeded ? panel.theme.amber : panel.theme.textSoft) + text: panel.firmwareDisplayStatus + color: panel.verificationFailed ? panel.theme.red : (panel.firmware.targetVerified ? panel.theme.green : (panel.firmware.bootloaderHelpNeeded ? panel.theme.amber : panel.theme.textSoft)) font.family: panel.uiFont font.pixelSize: 10 wrapMode: Text.WordWrap diff --git a/apps/arstack_studio/src/DeterministicSessionHarness.cpp b/apps/arstack_studio/src/DeterministicSessionHarness.cpp index 586380e55..cc2111514 100644 --- a/apps/arstack_studio/src/DeterministicSessionHarness.cpp +++ b/apps/arstack_studio/src/DeterministicSessionHarness.cpp @@ -956,6 +956,8 @@ class DeterministicSessionHarness final { session.firmwareUpdateResult().contains(QStringLiteral("different build")) && report.contains(QStringLiteral("Last firmware update result: Firmware was written")) && report.contains(QStringLiteral("Bundled build ID: 0123456789abcdef")) && + report.contains(QStringLiteral("Configured SV ID: ARSTACK_SV01")) && + report.contains(QStringLiteral("Configured publisher fps: 4000")) && report.contains(QStringLiteral("Exact bundled build match: NOT VERIFIED")) && report.contains(QStringLiteral("Firmware protocol compatible: UNKNOWN")); } diff --git a/apps/arstack_studio/src/SmartSessionController.cpp b/apps/arstack_studio/src/SmartSessionController.cpp index b5f1b2f31..d1646d2d0 100644 --- a/apps/arstack_studio/src/SmartSessionController.cpp +++ b/apps/arstack_studio/src/SmartSessionController.cpp @@ -890,6 +890,14 @@ QString SmartSessionController::diagnosticsText() const { add(QStringLiteral("Firmware target"), firmware_->targetChip()); add(QStringLiteral("Firmware operation busy"), firmware_->busy() ? QStringLiteral("yes") : QStringLiteral("no")); } + if (profiles_ != nullptr && profiles_->hasProfiles()) { + const QVariantMap profile = profiles_->selectedProfile(); + add(QStringLiteral("Configured SV ID"), profile.value(QStringLiteral("svId")).toString()); + add(QStringLiteral("Configured APPID"), profile.value(QStringLiteral("appId")).toString()); + add(QStringLiteral("Configured publisher fps"), profile.value(QStringLiteral("publisherRate")).toString()); + add(QStringLiteral("Configured counter wrap"), profile.value(QStringLiteral("counterModulus")).toString()); + add(QStringLiteral("Configured payload bytes"), profile.value(QStringLiteral("payloadBytes")).toString()); + } if (device_ != nullptr) { add(QStringLiteral("Device verified"), device_->deviceVerified() ? QStringLiteral("yes") : QStringLiteral("no")); add(QStringLiteral("COM port"), device_->portName());