Skip to content

refactor(warnings): unify startup warning checks into a shared state machine#7498

Draft
raphaelcoeffic wants to merge 6 commits into
mainfrom
model-load-state-machine
Draft

refactor(warnings): unify startup warning checks into a shared state machine#7498
raphaelcoeffic wants to merge 6 commits into
mainfrom
model-load-state-machine

Conversation

@raphaelcoeffic

@raphaelcoeffic raphaelcoeffic commented Jun 26, 2026

Copy link
Copy Markdown
Member

Background

While investigating the #7499 HardFault — the top-bar telemetry widget gets repainted against a half-swapped model during a blocking warning loop — it became clear the post-model-load warning checks were spread across several entry points as parallel blocking loops that re-enter the LVGL / MainWindow::run stack.

The minimal, targeted fix for #7499 is #7500 (pause widget refresh during model load, by @philmoz). This PR is the follow-up refactor that removes the underlying re-entrant blocking machinery and unifies all the startup/safety warning checks behind one state machine. It does not itself close #7499.

What this does

Replace the scattered nested-blocking warning loops with a single core-owned, GUI-agnostic state machine (radio/src/warning_checks.{h,cpp}), polled once per perMain() — flat stack, no re-entrant lv_timer_handler. Every entry point routes through it via a WarningCheckContext, each with its own terminal action:

  • MODEL_SWITCH — runtime model switch; terminal restarts pulses + runs the model-load tail (postModelLoadFinish).
  • BOOT — full sequence after a small blocking pre-step (checkBootSpecificWarnings: keys-stuck, RTC battery, ext. antenna); the boot pulsesStart() is deferred to the terminal.
  • FLIGHT_RESET — full sequence; pulses were never stopped, so the terminal does nothing.
  • STICK_MODE — throttle check only; terminal restarts the mixer.

The machine walks SD / throttle / switches / failsafe / multi / checklist and runs the context-specific terminal only once all are cleared, so pulses stay stopped until then — the existing "RX holds failsafe while a warning is shown" guarantee is preserved.

Each GUI is now a thin view over the same machine:

  • COLORLCD: gui/colorlcd/warning_checks_view.*
  • B&W: gui/common/stdlcd/warning_checks_view.* (gates guiMain off while a warning is shown; drawSwitchWarningScreen() extracted from the old blocking loop)

Warning predicates are now pure reads, decoupled from input refresh: refreshInputsForWarnings() (getADC + evalInputs + getMovedSwitch) is called once per tick by the driver; the views just render the predicates.

Cleanup

  • Deletes the now-unused blocking path: checkAll, both checkThrottleStick, both checkSwitches, checkFailsafe, checkMultiLowPower, checkSDfreeStorage, the B&W readModelNotes (→ setModelChecklistFilename helper) and the COLORLCD readChecklist.
  • Moves the warning-check functions (isThrottleWarningAlertNeeded, isFailsafeWarningRequired, isMultiLowPowerWarningRequired, refreshInputsForWarnings, checkAlarm, checkBootSpecificWarnings / checkRTCBattery) out of the catch-all edgetx.cpp into warning_checks.cpp, with their declarations in warning_checks.h.

Scope / notes

  • Both GUIs (COLORLCD and B&W).
  • The keys-stuck check is dropped from the model-switch sequence (you just pressed a key to select the model); it still runs at boot.

Testing

  • Native (simulator) and ARM firmware builds pass.
  • SDL simulator: model switch with throttle up shows the warning, UI stays live, the dialog dismisses on lowering the throttle or a keypress, and pulses restart only after the last warning clears.

Relationship to #7499 / #7500

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a unified, state-machine-driven warning flow for model loading, boot/alarms handling, flight reset, stick-mode changes, and checklist warnings.
    • ColorLCD and standard LCD now synchronize full-screen warning dialogs to the active warning state, including press-to-skip and LED error indication.
    • Model checklist/help now opens non-blocking.
  • Bug Fixes
    • Warning conditions refresh more reliably and dismiss promptly when the condition clears.
    • Flight reset (and related mixer/pulse actions) is deferred until the warning sequence is idle.
    • Throttle and switch warnings no longer depend on display-only event handling; switch warning checks avoid side effects.

…ne (#7499)

On a model switch, postModelLoad() ran the throttle/switch warning checks
synchronously from inside an LVGL event callback, each spinning
MainWindow::blockUntilClose() which re-enters lv_timer_handler() from deep in
the call chain. On hardware that re-entrant stack overflows the menus task and
hard-faults (intermittent freeze on TX16S internal MPM); the simulator's larger
stack hid it.

Replace the nested blocking loop on COLORLCD with a core-owned, GUI-agnostic
state machine (model_load_sm) polled once per perMain() (flat stack, no
re-entrancy). It walks the post-load checks (SD / throttle / switches /
failsafe / multi / checklist) and only once all are cleared runs the deferred
model-load tail (postModelLoadFinish: pulsesStart + ...). Pulses stay stopped
until then, preserving the failsafe-hold safety guarantee. A thin COLORLCD view
(model_load_view) mirrors the active state into the existing warning dialogs and
feeds key presses back as an acknowledge.

Decouple the warning predicates from input refresh so they are pure reads:
refreshInputsForWarnings() (getADC + evalInputs + getMovedSwitch) is now called
by the drivers (state machine tick and the boot/flightReset blocking loops), and
the warning dialogs become display-only views. Boot and flightReset keep their
non-re-entrant blocking checkAll() and reuse the same predicates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@raphaelcoeffic
raphaelcoeffic force-pushed the model-load-state-machine branch from 1c8721b to 269ac63 Compare June 26, 2026 10:23
@raphaelcoeffic raphaelcoeffic changed the title fix(color): run post-model-load warnings via a flat-stack state machine (#5011) fix(color): run post-model-load warnings via a flat-stack state machine (#7499) Jun 26, 2026
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f26121ee-c72c-490d-82ea-18bf4f201f2e

📥 Commits

Reviewing files that changed from the base of the PR and between 7bb1ebc and 075ef7c.

📒 Files selected for processing (3)
  • radio/src/gui/common/stdlcd/menus_common.h
  • radio/src/gui/common/stdlcd/warning_checks_view.cpp
  • radio/src/switches.cpp
💤 Files with no reviewable changes (2)
  • radio/src/gui/common/stdlcd/menus_common.h
  • radio/src/switches.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • radio/src/gui/common/stdlcd/warning_checks_view.cpp

📝 Walkthrough

Walkthrough

A warning-check state machine replaces blocking warning handling. It separates warning predicates from input refresh, routes warning display through platform-specific view sync helpers, and updates startup, model-load, and stick-mode flows to arm and advance the new sequence.

Changes

Model-load warning flow

Layer / File(s) Summary
Warning-check API and state machine
radio/src/CMakeLists.txt, radio/src/edgetx.*, radio/src/main.cpp, radio/src/storage/*, radio/src/warning_checks.*
The warning-check enums, entry points, and completion hook are added, and boot/reset paths arm or finish the sequence through the new state machine.
Predicate refactor and alert screens
radio/src/edgetx.cpp, radio/src/switches.cpp, radio/src/gui/colorlcd/controls/switch_warn_dialog.*
Throttle, switch, failsafe, and multimodule checks use refreshed inputs, and the switch/throttle warning screens stop managing their own close decisions.
ColorLCD warning view sync
radio/src/gui/colorlcd/CMakeLists.txt, radio/src/gui/colorlcd/libui/view_text.*, radio/src/gui/colorlcd/warning_checks_view.*, radio/src/main.cpp
ColorLCD compiles the warning-view sync module and the non-blocking checklist helper, and perMain() runs the warning sync around the UI loop.
StdLCD warning view sync
radio/src/gui/common/stdlcd/CMakeLists.txt, radio/src/gui/common/stdlcd/menus_common.h, radio/src/gui/common/stdlcd/view_text.cpp, radio/src/gui/common/stdlcd/warning_checks_view.*, radio/src/main.cpp
StdLCD compiles the warning-view sync module, builds the checklist filename, and routes main-loop warning handling through the view helper.
Stick-mode warning start
radio/src/gui/128x64/radio_setup.cpp, radio/src/gui/212x64/radio_setup.cpp, radio/src/gui/colorlcd/radio/radio_setup.cpp
Stick-mode setup handlers now start the warning-check sequence instead of calling throttle checks, mixer restarts, and key waits directly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Suggested labels

enhancement ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: consolidating startup warning checks into a shared state machine.
Description check ✅ Passed The description is thorough and covers background, behavior changes, cleanup, scope, testing, and issue relationship.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch model-load-state-machine

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@3djc

3djc commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Tested ok on a previously failing test hardware (TX16S with exact sequence from #5011). Doesn't hardfault with this branch

@3djc
3djc requested a review from philmoz June 26, 2026 10:30
@philmoz

philmoz commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Seems like overkill - why not just pause widget refresh in selectModel:

      // Pause widget refresh
      MainWindow::instance()->enableWidgetRefresh(false);
      // Delete old main view layout
      LayoutFactory::deleteCustomScreens();

      loadModel(g_eeGeneral.currModelFilename, true);
      modelslist.setCurrentModel(model);

      // Load new main view layout
      LayoutFactory::loadCustomScreens();
      // Enable widget refresh
      MainWindow::instance()->enableWidgetRefresh(true);

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
radio/src/switches.cpp (1)

880-910: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

bad_pots is only assigned when potsWarnMode is set.

The out-param is left untouched when g_model.potsWarnMode is false, so it relies on every caller pre-initializing it. All current callers do (= 0), but a future caller passing an uninitialized variable would read garbage. A one-line guarantee at the top keeps the predicate self-contained.

🛡️ Initialize unconditionally
 bool isSwitchWarningRequired(uint16_t &bad_pots)
 {
   bool warn = false;
+  bad_pots = 0;
   for (int i = 0; i < switchGetMaxAllSwitches(); i++) {

Then drop the redundant bad_pots = 0; inside the potsWarnMode block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@radio/src/switches.cpp` around lines 880 - 910, The out-parameter bad_pots in
isSwitchWarningRequired() is only initialized when g_model.potsWarnMode is
enabled, so make the predicate self-contained by setting bad_pots to 0 at the
start of the function regardless of mode. Then remove the redundant reset inside
the potsWarnMode block and keep the rest of the switch/pot warning logic
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@radio/src/gui/colorlcd/model_load_view.cpp`:
- Around line 58-66: The widget-refresh guard in modelLoadViewSync() is
currently applied too late and the MainWindow refresh toggle is only a boolean,
so it can briefly render swapped model data and be clobbered by other users like
standalone_lua.cpp. Move the guard logic so it runs before
MainWindow::instance()->run() in perMain(), and update
MainWindow::enableWidgetRefresh()/widgetRefreshEnabled() to use a
reference-counted state instead of a simple flag so multiple callers can
independently disable and restore refresh safely.

In `@radio/src/model_load_sm.cpp`:
- Around line 172-181: The MLS_START_PULSES flow in model_load_sm.cpp has the
silence window starting too late, so audio triggered by postModelLoadFinish()
can escape unmuted; move START_SILENCE_PERIOD() to run before
postModelLoadFinish() while keeping PLAY_MODEL_NAME() first, and leave the state
transitions in the same MLS_START_PULSES branch.

---

Outside diff comments:
In `@radio/src/switches.cpp`:
- Around line 880-910: The out-parameter bad_pots in isSwitchWarningRequired()
is only initialized when g_model.potsWarnMode is enabled, so make the predicate
self-contained by setting bad_pots to 0 at the start of the function regardless
of mode. Then remove the redundant reset inside the potsWarnMode block and keep
the rest of the switch/pot warning logic unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f664f8b6-5e76-4bfd-8728-e25002742246

📥 Commits

Reviewing files that changed from the base of the PR and between eae6aa1 and 269ac63.

📒 Files selected for processing (16)
  • radio/src/CMakeLists.txt
  • radio/src/edgetx.cpp
  • radio/src/edgetx.h
  • radio/src/gui/colorlcd/CMakeLists.txt
  • radio/src/gui/colorlcd/controls/switch_warn_dialog.cpp
  • radio/src/gui/colorlcd/controls/switch_warn_dialog.h
  • radio/src/gui/colorlcd/libui/view_text.cpp
  • radio/src/gui/colorlcd/libui/view_text.h
  • radio/src/gui/colorlcd/model_load_view.cpp
  • radio/src/gui/colorlcd/model_load_view.h
  • radio/src/main.cpp
  • radio/src/model_load_sm.cpp
  • radio/src/model_load_sm.h
  • radio/src/storage/storage.h
  • radio/src/storage/storage_common.cpp
  • radio/src/switches.cpp

Comment thread radio/src/gui/colorlcd/warning_checks_view.cpp
Comment thread radio/src/model_load_sm.cpp Outdated
@3djc

3djc commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Seems like overkill - why not just pause widget refresh in selectModel:

      // Pause widget refresh
      MainWindow::instance()->enableWidgetRefresh(false);
      // Delete old main view layout
      LayoutFactory::deleteCustomScreens();

      loadModel(g_eeGeneral.currModelFilename, true);
      modelslist.setCurrentModel(model);

      // Load new main view layout
      LayoutFactory::loadCustomScreens();
      // Enable widget refresh
      MainWindow::instance()->enableWidgetRefresh(true);

This seems indeed much simpler (and carry less risk) and does also fix the issue in my testing

@raphaelcoeffic

Copy link
Copy Markdown
Member Author

Seems like overkill - why not just pause widget refresh in selectModel

@philmoz Absolutely! This PR was not really intended as a fix only for this bug. So I would highly prefer your minimal patch as the fix, and continue with this PR to get rid of the deep re-entrant LVGL warning that have been a pain from my point of view for a long time.

@philmoz

philmoz commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Seems like overkill - why not just pause widget refresh in selectModel

@philmoz Absolutely! This PR was not really intended as a fix only for this bug. So I would highly prefer your minimal patch as the fix, and continue with this PR to get rid of the deep re-entrant LVGL warning that have been a pain from my point of view for a long time.

I'm not against a state machine; but I think it goes beyond just the model switch.
The whole radio startup, USB SD card, and model select is a mess and hard to understand.
It's also easy to break (like the mixer).

@raphaelcoeffic

Copy link
Copy Markdown
Member Author

Seems like overkill - why not just pause widget refresh in selectModel

@philmoz Absolutely! This PR was not really intended as a fix only for this bug. So I would highly prefer your minimal patch as the fix, and continue with this PR to get rid of the deep re-entrant LVGL warning that have been a pain from my point of view for a long time.

I'm not against a state machine; but I think it goes beyond just the model switch. The whole radio startup, USB SD card, and model select is a mess and hard to understand. It's also easy to break (like the mixer).

Agreed. IMHO, the way LVGL is used in these scenarios is not correct: we have to by-pass a few things to make it work, and the call stack gets very deep, which is a permanent risk of hitting a stack overflow. For my part, I find state-machines simpler to reason with than deeply nested calls. Also, I have the feeling we have quite some duplicated logic btw. colour and b&w here that we could unify.

raphaelcoeffic and others added 2 commits June 27, 2026 08:40
…y points

The post-model-load warning state machine (PR #7498) only covered the
COLORLCD runtime model switch. Generalise it into one shared "warning
checks" state machine driving every entry point on both GUIs, and delete
the parallel blocking implementation entirely.

State machine (radio/src/warning_checks.{h,cpp}, renamed from
model_load_sm): add WarningCheckContext (MODEL_SWITCH / BOOT /
FLIGHT_RESET / STICK_MODE) with a per-context terminal action - restart
pulses + model-load tail, start pulses, nothing, or restart the mixer.
STICK_MODE runs the throttle check only. Terminal state renamed
MLS_START_PULSES -> WCS_COMPLETE (it no longer always starts pulses).

- B&W GUI is now a second view (gui/common/stdlcd/warning_checks_view.*)
  over the same machine, driven from the !COLORLCD perMain block and
  gating guiMain off while a warning is shown. drawSwitchWarningScreen()
  extracted from the old blocking checkSwitches() loop.
- Storage dispatch generalised: every runtime switch (both GUIs) arms the
  machine instead of running the blocking checkAll().
- Boot routes through the machine (WCC_BOOT) after a small blocking
  checkBootSpecificWarnings() pre-step (keys-stuck, RTC battery, ext.
  antenna); the boot pulsesStart() is deferred to the terminal.
- flightReset and the radio-setup stick-mode change (all 3 GUIs) route
  through the machine too; the latter removes a re-entrant LVGL call.

Delete the now-unused blocking path: checkAll, both checkThrottleStick,
both checkSwitches, checkFailsafe, checkMultiLowPower, checkSDfreeStorage,
the B&W readModelNotes (-> setModelChecklistFilename helper) and the
COLORLCD readChecklist.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Relocate the warning-check functions out of the catch-all edgetx.cpp into
warning_checks.cpp, next to the state machine that drives them:

  - refreshInputsForWarnings()
  - isThrottleWarningAlertNeeded(), isFailsafeWarningRequired(),
    isMultiLowPowerWarningRequired() (the pure predicates the SM queries)
  - checkAlarm()
  - checkBootSpecificWarnings() (was static; now exposed via the header so
    edgeTxInit() can still call it) and its static helper checkRTCBattery()

Declarations move from edgetx.h to warning_checks.h. Pure code move, no
behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@raphaelcoeffic raphaelcoeffic changed the title fix(color): run post-model-load warnings via a flat-stack state machine (#7499) refactor(warnings): unify startup warning checks into a shared state machine Jun 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@radio/src/gui/colorlcd/warning_checks_view.cpp`:
- Around line 43-46: Keep teardown suppression enabled until the dialog close
callback has actually run. In warning_checks_view.cpp, update the teardown flow
around onShownClosed() and the code that calls deleteLater() so s_tearingDown is
not cleared immediately after scheduling deletion; instead clear it only after
the close callback has completed. This ensures onShownClosed() can still
distinguish view-initiated teardown and avoids calling acknowledgeWarningCheck()
or clearing s_shown after a replacement dialog is installed.

In `@radio/src/gui/common/stdlcd/warning_checks_view.cpp`:
- Around line 102-104: The warning acknowledgement in warningChecksRun()
currently uses a raw truthy event_t check, which allows non-key events like
EVT_ENTRY to dismiss the warning. Update warning_checks_view.cpp to gate
acknowledgeWarningCheck() behind the existing key-event predicate(s) used by the
view contract, so only actual user key presses can acknowledge the warning.

In `@radio/src/main.cpp`:
- Around line 561-564: The COLORLCD flow in guiMain currently keeps refreshing
widgets even when a warning check is active, unlike the B&W path. Update guiMain
(and the related event-handling path it shares with the
MainWindow::instance()->run() call) so it mirrors the existing
activeWarningCheck() guard used in the non-COLORLCD branch and skips guiMain(0)
while warnings are non-idle; apply the same change in the other referenced
COLORLCD block as well.

In `@radio/src/warning_checks.cpp`:
- Around line 53-58: The switch-warning refresh lost the flight-mode/mix update
that used to happen in the old predicate, so `refreshInputsForWarnings()` must
now perform that same refresh before `getMovedSwitch()` when
`mixerTaskRunning()` is false. Update `refreshInputsForWarnings()` to invoke the
existing flight-mode/mix evaluation logic alongside
`evalInputs(e_perout_mode_notrainer)` so warning checks see current switch state
during model load and mixer توقف conditions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 957c53d7-7049-4de8-afde-991fd02c46da

📥 Commits

Reviewing files that changed from the base of the PR and between 269ac63 and 697d05f.

📒 Files selected for processing (22)
  • radio/src/CMakeLists.txt
  • radio/src/edgetx.cpp
  • radio/src/edgetx.h
  • radio/src/gui/128x64/radio_setup.cpp
  • radio/src/gui/212x64/radio_setup.cpp
  • radio/src/gui/colorlcd/CMakeLists.txt
  • radio/src/gui/colorlcd/libui/view_text.cpp
  • radio/src/gui/colorlcd/libui/view_text.h
  • radio/src/gui/colorlcd/radio/radio_setup.cpp
  • radio/src/gui/colorlcd/warning_checks_view.cpp
  • radio/src/gui/colorlcd/warning_checks_view.h
  • radio/src/gui/common/stdlcd/CMakeLists.txt
  • radio/src/gui/common/stdlcd/menus_common.h
  • radio/src/gui/common/stdlcd/view_text.cpp
  • radio/src/gui/common/stdlcd/warning_checks_view.cpp
  • radio/src/gui/common/stdlcd/warning_checks_view.h
  • radio/src/main.cpp
  • radio/src/storage/storage.h
  • radio/src/storage/storage_common.cpp
  • radio/src/switches.cpp
  • radio/src/warning_checks.cpp
  • radio/src/warning_checks.h
💤 Files with no reviewable changes (2)
  • radio/src/edgetx.h
  • radio/src/gui/colorlcd/libui/view_text.cpp
✅ Files skipped from review due to trivial changes (1)
  • radio/src/gui/common/stdlcd/CMakeLists.txt
🚧 Files skipped from review as they are similar to previous changes (2)
  • radio/src/storage/storage.h
  • radio/src/gui/colorlcd/libui/view_text.h

Comment thread radio/src/gui/colorlcd/warning_checks_view.cpp
Comment thread radio/src/gui/common/stdlcd/warning_checks_view.cpp
Comment thread radio/src/main.cpp
Comment thread radio/src/warning_checks.cpp
raphaelcoeffic and others added 3 commits June 27, 2026 09:05
The WCS_COMPLETE terminal called PLAY_MODEL_NAME() before
START_SILENCE_PERIOD(), inverting the pre-refactor order where checkAll()
ended with START_SILENCE_PERIOD() and the caller then ran PLAY_MODEL_NAME()
and the model-load restart. playModelName() is not gated by the silence
period so this was benign, but reorder it to keep the sequence identical to
the old blocking path (silence period, then model name, then terminal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rdering)

Two small fixes from the CodeRabbit review of #7498:

- isSwitchWarningRequired(): initialise the bad_pots out-param at the top so
  the predicate is self-contained regardless of potsWarnMode (drop the
  redundant reset inside the potsWarnMode block). No behaviour change for
  the current sole caller, which already pre-zeroed it.

- COLORLCD: suspend main-view widget refresh *before* MainWindow::run()
  instead of after. Split the edge-triggered enable/disable out of
  warningChecksViewSync() into warningChecksViewUpdateRefresh() and call it
  from perMain() ahead of run(), so the main view is never repainted for the
  tick on which a warning sequence becomes active.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The full-screen switch/pot warning rendering was B&W view code (already
fenced !COLORLCD) stranded in the GUI-agnostic switches.cpp. Move it to
its only caller in gui/common/stdlcd/warning_checks_view.cpp as a
file-local function, alongside the B&W layout macros it needs. The dead
COLORLCD branch of SWITCH_WARNING_LIST_X/Y and the public declaration in
menus_common.h are dropped. No behavioural change; symmetric with the
COLORLCD view owning its own rendering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@philmoz

philmoz commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Seems ok - will take a closer look soon.

@raphaelcoeffic - do you think some checks should run after exiting SD storage mode?
Currently no checks are done, even though the model is reloaded (and could have changed).

@raphaelcoeffic

Copy link
Copy Markdown
Member Author

Seems ok - will take a closer look soon.

Wait a bit, I refactored a bit more to get rid of the re-entrant LVGL main loop altogether. That should unify more between B&W and color UI as well.

@raphaelcoeffic - do you think some checks should run after exiting SD storage mode? Currently no checks are done, even though the model is reloaded (and could have changed).

Good question, I should look into that as well. No checks after reload seems inconsistent to me as well.

@raphaelcoeffic
raphaelcoeffic marked this pull request as draft July 1, 2026 10:21
@gagarinlg

Copy link
Copy Markdown
Member

It should behave like a full model switch. Nobody knows what happened to the model file.

@pfeerick pfeerick added the house keeping 🧹 Cleanup of code and house keeping label Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

house keeping 🧹 Cleanup of code and house keeping

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hard-fault / freeze when switching models with a throttle or switch warning active (color radios)

5 participants