Repository navigation
fix(p0): ESP32-P4 periodic SV lease watchdog, latched board STOP cause, Studio GUI provenance #270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: fix/p0-warm-local-evidence-20261021
Are you sure you want to change the base?
Changes from all commits
a1fccc2
e9d083a
1194e92
39532ab
81b2b99
ea447c1
03db007
bee7218
377c134
5e92a96
8ee7d6b
3971557
7f30f99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -823,6 +823,7 @@ bool DeviceController::startWithScenario(const QVariantMap& scenario) { | |
| return true; | ||
| } | ||
| bool DeviceController::stop() { | ||
| operatorStopPending_ = true; | ||
| appendLog(QStringLiteral("SVTX"), QStringLiteral( | ||
| "OPERATOR_STOP_REQUEST session=%1 boot=%2 running=%3 cfg_pending=%4") | ||
| .arg(sessionGeneration_).arg(identity_.bootId) | ||
|
|
@@ -1751,6 +1752,12 @@ void DeviceController::failScenarioStart(const QString& message) { | |
|
|
||
| void DeviceController::setRunning(const bool value) { | ||
| if (running_ == value) return; | ||
| if (!value && running_ && !operatorStopPending_ && svStopReason_.isEmpty()) { | ||
| // Do not silently turn a physical STOP into a green READY state. | ||
| // SHOW/SVLIFE will replace this interim state with the board cause. | ||
| svStopReason_ = QStringLiteral("AWAITING_BOARD_CAUSE"); | ||
| emit svStopReasonChanged(); | ||
| } | ||
| running_ = value; | ||
| emit runningChanged(); | ||
| } | ||
|
|
@@ -1918,6 +1925,11 @@ void DeviceController::processLine(const QString& rawLine) { | |
| failScenarioStart(QStringLiteral("Unexpected SV START ACK identity/hash.")); | ||
| return; | ||
| } | ||
| operatorStopPending_ = false; | ||
| if (!svStopReason_.isEmpty()) { | ||
| svStopReason_.clear(); | ||
| emit svStopReasonChanged(); | ||
| } | ||
| // Publish verified RUNNING before clearing the pending START phase. | ||
| // Otherwise QML can briefly see neither RUNNING nor STARTING and | ||
| // bounce the button back to START during a successful ACK handoff. | ||
|
|
@@ -1943,6 +1955,11 @@ void DeviceController::processLine(const QString& rawLine) { | |
| .arg(forced ? QStringLiteral("RUNTIME_FAIL_SAFE_STOP_OBSERVED") | ||
| : QStringLiteral("STOP_ACK_OBSERVED")) | ||
| .arg(sessionGeneration_).arg(identity_.bootId).arg(running_ ? 1 : 0)); | ||
| if (forced && svStopReason_ != QStringLiteral("RUNTIME_FAULT")) { | ||
| svStopReason_ = QStringLiteral("RUNTIME_FAULT"); | ||
| emit svStopReasonChanged(); | ||
| } | ||
| operatorStopPending_ = false; | ||
| setRunning(false); | ||
| } | ||
| if (line.contains(QStringLiteral("Control session lease expired"), Qt::CaseInsensitive) || | ||
|
|
@@ -1953,6 +1970,44 @@ void DeviceController::processLine(const QString& rawLine) { | |
| appendLog(QStringLiteral("SVTX"), QStringLiteral( | ||
| "FIRMWARE_STOP_CAUSE session=%1 boot=%2 detail=%3") | ||
| .arg(sessionGeneration_).arg(identity_.bootId).arg(line)); | ||
| const QString reason = line.contains(QStringLiteral("Control session lease expired"), Qt::CaseInsensitive) | ||
| ? QStringLiteral("LEASE_EXPIRED") : QStringLiteral("RUNTIME_FAULT"); | ||
| if (svLastStopCause_ != reason) { | ||
| svLastStopCause_ = reason; | ||
| emit svStopReasonChanged(); | ||
| } | ||
| if (svStopReason_ != reason) { | ||
| svStopReason_ = reason; | ||
| emit svStopReasonChanged(); | ||
|
Comment on lines
+1979
to
+1981
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the board emits AGENTS.md reference: AGENTS.md:L74-L86 Useful? React with 👍 / 👎. |
||
| } | ||
| } | ||
|
|
||
| // Board-owned latched event survives the small console log window and | ||
| // is returned with SHOW even after the operator has restarted SV. | ||
| static const QRegularExpression kSvLife( | ||
| QStringLiteral("SVLIFE state=(RUNNING|STOPPED) stop_cause=([A-Z_]+) stop_seq=(\\d+)")); | ||
| const auto svLife = kSvLife.match(line); | ||
| if (svLife.hasMatch()) { | ||
| bool seqOk = false; | ||
| const auto seq = svLife.captured(3).toULongLong(&seqOk); | ||
| if (seqOk && (seq >= lastSvStopSeq_ || !deviceVerified_)) { | ||
| lastSvStopSeq_ = seq; | ||
|
Comment on lines
+1993
to
+1994
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The firmware's AGENTS.md reference: AGENTS.md:L74-L86 Useful? React with 👍 / 👎. |
||
| const QString lastReason = svLife.captured(2); | ||
| if (seq > 0U && svLastStopCause_ != lastReason) { | ||
| svLastStopCause_ = lastReason; | ||
| emit svStopReasonChanged(); | ||
| } | ||
| const bool boardStopped = svLife.captured(1) == QStringLiteral("STOPPED"); | ||
| const QString effective = boardStopped && lastReason != QStringLiteral("OPERATOR_STOP") && | ||
| lastReason != QStringLiteral("NONE") ? lastReason : QString{}; | ||
| if (svStopReason_ != effective) { | ||
| svStopReason_ = effective; | ||
| appendLog(QStringLiteral("SVTX"), QStringLiteral( | ||
| "BOARD_STOP_READBACK session=%1 boot=%2 cause=%3 seq=%4") | ||
| .arg(sessionGeneration_).arg(identity_.bootId).arg(lastReason).arg(seq)); | ||
| emit svStopReasonChanged(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| auto match = kStateExpression.match(line); | ||
|
|
@@ -2146,6 +2201,13 @@ void DeviceController::processLine(const QString& rawLine) { | |
| } | ||
|
|
||
| void DeviceController::resetTelemetry() { | ||
| operatorStopPending_ = false; | ||
| lastSvStopSeq_ = 0; | ||
| svLastStopCause_.clear(); | ||
| if (!svStopReason_.isEmpty()) { | ||
| svStopReason_.clear(); | ||
| emit svStopReasonChanged(); | ||
| } | ||
| fps_ = QStringLiteral("—"); | ||
| missed_ = QStringLiteral("—"); | ||
| txFailures_ = QStringLiteral("—"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a normal operator STOP while
running_is true, clearingoperatorStopPending_before callingsetRunning(false)makes that method classify the transition as unsolicited and setsvStopReason_toAWAITING_BOARD_CAUSE. The UI therefore shows a red unexpected-stop warning after an intentional STOP until a laterSVLIFEreadback clears it; perform the running transition while the operator intent is still set.AGENTS.md reference: AGENTS.md:L74-L86
Useful? React with 👍 / 👎.