Skip to content

Conversation

@haslinghuis
Copy link
Member

@haslinghuis haslinghuis commented Oct 3, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Prevents flashing when permission is denied, cancelled, no valid port, firmware not loaded, or connection errors occur.
    • UI reliably returns to idle after errors/cancellations and re-enables controls; shows a neutral "not loaded" message when appropriate.
  • Refactor

    • Centralized error/state reset for consistent recovery and UI unlocking after failures.
    • Preserves and restores pre-flash progress messages so users don’t lose context during flashing.

@haslinghuis haslinghuis added this to the 2025.12 milestone Oct 3, 2025
@haslinghuis haslinghuis self-assigned this Oct 3, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Walkthrough

Preserves and restores pre-flash UI state in firmware_flasher (adds preFlashingMessage/preFlashingMessageType, preserve/reset methods), centralizes STM32 protocol error handling via STM32Protocol.handleError(resetRebootMode = true) to unlock GUI and restore flasher UI state, and guards AutoDetect.verifyBoard when no port is available. (38 words)

Changes

Cohort / File(s) Summary
Firmware flashing UI
src/js/tabs/firmware_flasher.js
Removed public isFlashing; added preFlashingMessage and preFlashingMessageType; added preservePreFlashingState() and resetFlashingState(); call preservePreFlashingState() before DFU/UF2 flows and call resetFlashingState() on error/cleanup paths instead of toggling isFlashing.
STM32 protocol error handling
src/js/protocols/webstm32.js
Added STM32Protocol.handleError(resetRebootMode = true) and onMSPConnectionError(); consolidated timeout/failure/permission-failure/disconnect error paths to call handleError() which releases GUI connect lock, optionally resets rebootMode, and calls TABS.firmware_flasher.resetFlashingState().
Auto-detection guard
src/js/utils/AutoDetect.js
Added guard in verifyBoard() to return early and log a firmware-flasher no-valid-port message when PortHandler.portAvailable is false; replaced a console.log with gui_log for the "Releases not loaded yet" path.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Firmware UI
  participant DFU as DFU Prompt
  participant STM as STM32Protocol

  User->>UI: Click "Flash Firmware"
  UI->>UI: preservePreFlashingState()
  UI->>DFU: requestPermission()
  alt Permission granted
    DFU-->>UI: device.path
    UI->>STM: connect (DFU/UF2)
    alt connect success
      STM-->>UI: flashing progress / success
      UI->>UI: resetFlashingState()
    else connect error
      STM->>STM: handleError()
      note right of STM #D6EAF8: unlock GUI.connect_lock\noptional rebootMode reset\nreset flasher UI state
      STM-->>UI: error
      UI-->>User: show error, ready to retry
    end
  else Permission canceled / error
    DFU-->>UI: canceled / error
    UI->>UI: resetFlashingState()
    UI-->>User: ready to retry
  end
Loading
sequenceDiagram
  autonumber
  participant STM as STM32Protocol
  participant GUI as GUI State
  participant FFS as firmware_flasher

  STM->>STM: on timeout/failure -> handleError(resetRebootMode = true)
  STM-->>GUI: unlock connect_lock
  STM-->>FFS: resetFlashingState()
  note right of FFS #FDEBD0: restore pre-flash message or show not-loaded
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • KarateBrot
  • VitroidFPV
  • nerdCopter

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The addition of a port availability guard and logging adjustments in AutoDetect.js are unrelated to the flashing-state recovery objectives of issue #4646 and thus fall outside the scope of the intended fix. Consider isolating the AutoDetect.js port-guard and logging changes into a separate pull request to keep this fix focused solely on the flashing state issue.
Description Check ⚠️ Warning The pull request description consists only of a brief issue link and does not follow the repository’s required template or include sections for summarizing changes, testing, or other context, leaving it incomplete and uninformative. Please expand the description using the project’s PR template by adding a summary of changes, motivation, testing steps, and any relevant implementation details to meet the repository guidelines.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title “Fix flash state” clearly and concisely summarizes the primary change of correcting the firmware flashing UI state handling across success and error paths without extraneous details, making it immediately understandable to reviewers scanning the history.
Linked Issues Check ✅ Passed The changes implement the alternative solution from issue #4646 by preserving and restoring the pre-flash UI state and resetting the Flash Firmware button on error, enabling users to retry flashing without reloading or unplugging as requested.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4415fcf and 511f27a.

📒 Files selected for processing (2)
  • src/js/protocols/webstm32.js (4 hunks)
  • src/js/utils/AutoDetect.js (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-02T07:45:48.606Z
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.

Applied to files:

  • src/js/utils/AutoDetect.js
🧬 Code graph analysis (2)
src/js/protocols/webstm32.js (2)
src/js/gui_log.js (1)
  • gui_log (7-21)
src/js/gui.js (2)
  • GUI (465-465)
  • TABS (8-8)
src/js/utils/AutoDetect.js (2)
src/js/port_handler.js (1)
  • PortHandler (16-50)
src/js/gui_log.js (1)
  • gui_log (7-21)
🔇 Additional comments (7)
src/js/utils/AutoDetect.js (2)

40-43: LGTM! Port availability guard prevents invalid connection attempts.

The guard correctly checks PortHandler.portAvailable and logs a user-facing message before returning early. This prevents the flashing process from getting stuck when no valid port is available, aligning with the PR objective to fix flash state issues.


45-46: LGTM! Consistent user-facing logging.

Replacing console.log with gui_log ensures the "Releases not loaded yet" message appears in the UI log, improving visibility for users. This aligns with the logging pattern used throughout the file.

src/js/protocols/webstm32.js (5)

28-31: LGTM! Centralized MSP connection error handling.

The global function provides a single entry point for MSP connection errors, logging the failure and delegating to STM32.handleError() for state cleanup. This improves maintainability and consistency.


81-91: LGTM! Centralized error handling improves maintainability.

The handleError method consolidates scattered error-handling logic:

  • Releases GUI connection lock
  • Optionally resets reboot mode (configurable via parameter)
  • Restores flashing UI state via TABS.firmware_flasher.resetFlashingState()

This pattern eliminates code duplication and ensures consistent state restoration across all error paths, directly addressing the PR objective to fix stuck flash state.


123-123: LGTM! DFU permission errors now use centralized error handling.

Replacing direct state mutations with handleError() calls ensures consistent cleanup when DFU permission is denied or fails. Both call sites correctly use the default behavior (resetting reboot mode).

Also applies to: 128-128


133-133: LGTM! Correct parameter usage for non-reboot disconnect.

Calling handleError(false) in the else branch correctly preserves the reboot mode (already 0) while still unlocking the GUI and restoring flashing state. This is the appropriate behavior for disconnections that don't involve rebooting.


254-255: LGTM! MSP connection callbacks use centralized error handler.

Using onMSPConnectionError for both timeout and error callbacks ensures consistent error handling for MSP connection failures, preventing stuck flash state by properly cleaning up and restoring UI state.


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 and usage tips.

@haslinghuis haslinghuis moved this to App in 2025.12.0 Oct 3, 2025
@nerdCopter
Copy link
Member

does not continue / does not enable flash-button

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/js/tabs/firmware_flasher.js (1)

827-827: Minor: Trailing whitespace.

Line 827 has trailing whitespace that could be removed for consistency.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c28ed48 and d1a79fe.

📒 Files selected for processing (1)
  • src/js/tabs/firmware_flasher.js (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.
📚 Learning: 2025-09-02T07:45:48.606Z
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.

Applied to files:

  • src/js/tabs/firmware_flasher.js
🧬 Code graph analysis (1)
src/js/tabs/firmware_flasher.js (5)
src/js/port_handler.js (1)
  • PortHandler (16-50)
src/js/localization.js (1)
  • i18n (7-7)
src/js/gui.js (1)
  • GUI (465-465)
src/js/Analytics.js (1)
  • tracking (7-7)
src/js/protocols/webstm32.js (1)
  • STM32 (1007-1007)
🔇 Additional comments (4)
src/js/tabs/firmware_flasher.js (4)

783-792: LGTM! Centralized state restoration.

The resetFlashingState helper correctly restores all UI state after errors: re-enables buttons, clears the flashing flag, displays a neutral message, and resumes the sponsor interval.


798-803: LGTM! Proper error handling for DFU connection.

The try/catch wrapper correctly handles DFU connection failures by logging the error and invoking resetFlashingState to restore the UI, preventing the stuck state described in the issue.


818-823: LGTM! Consistent error handling for STM32 connection.

The try/catch wrapper mirrors the DFU error handling pattern, ensuring consistent state restoration across both connection types.


828-834: LGTM! Key fix for the reported issue.

The catch handler correctly addresses the issue described in #4646: when the user cancels the DFU permission request or uses the "I can't find my DFU device" flow, the state is properly restored via resetFlashingState, allowing the user to retry without reloading or unplugging.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/js/tabs/firmware_flasher.js (1)

823-830: LGTM! Permission rejection handling fixes the core issue.

The rejection handler correctly addresses the stuck-state bug described in issue #4646 by restoring UI state when the user cancels DFU permission or when permission fails. The explanatory comment is helpful.

Nitpick: Remove trailing whitespace.

Line 823 has trailing whitespace (empty line with spaces). Apply this diff to clean it up:

-                
+
                 DFU.requestPermission().then((device) => {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1a79fe and 9780339.

📒 Files selected for processing (1)
  • src/js/tabs/firmware_flasher.js (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.
📚 Learning: 2025-09-02T07:45:48.606Z
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.

Applied to files:

  • src/js/tabs/firmware_flasher.js
🧬 Code graph analysis (1)
src/js/tabs/firmware_flasher.js (5)
src/js/port_handler.js (1)
  • PortHandler (16-50)
src/js/localization.js (1)
  • i18n (7-7)
src/js/gui.js (1)
  • GUI (465-465)
src/js/Analytics.js (1)
  • tracking (7-7)
src/js/protocols/webstm32.js (1)
  • STM32 (1007-1007)
🔇 Additional comments (3)
src/js/tabs/firmware_flasher.js (3)

783-792: LGTM! Centralizing state restoration improves maintainability.

The resetFlashingState helper function correctly restores all flashing-related UI state and resumes sponsor intervals. This centralization ensures consistent state restoration across error paths and directly addresses the stuck-state issue described in the PR objectives.


798-801: LGTM! DFU connection error handling properly restores state.

The rejection handler correctly logs the error and invokes resetFlashingState(), ensuring the flash button is re-enabled if DFU connection fails.


816-819: LGTM! STM32 connection error handling properly restores state.

The rejection handler correctly logs the error and invokes resetFlashingState(), ensuring consistent state restoration for serial flash failures.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/js/tabs/firmware_flasher.js (1)

823-823: Remove trailing whitespace.

Line 823 has trailing whitespace.

Apply this diff:

-                
+
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9780339 and d024ab5.

📒 Files selected for processing (1)
  • src/js/tabs/firmware_flasher.js (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.
🧬 Code graph analysis (1)
src/js/tabs/firmware_flasher.js (5)
src/js/port_handler.js (1)
  • PortHandler (16-50)
src/js/localization.js (1)
  • i18n (7-7)
src/js/gui.js (1)
  • GUI (465-465)
src/js/Analytics.js (1)
  • tracking (7-7)
src/js/protocols/webstm32.js (1)
  • STM32 (1007-1007)
🔇 Additional comments (4)
src/js/tabs/firmware_flasher.js (4)

798-801: LGTM!

The error handler correctly restores the flashing state when DFU connection fails, preventing the stuck state described in issue #4646.


816-819: LGTM!

The error handler correctly restores the flashing state when STM32 connection fails, maintaining consistency with the DFU error handling.


824-833: LGTM! This fixes the core issue.

The dual error handlers correctly address the issue described in #4646:

  • If permission is granted but connection fails, state is restored
  • If permission is denied or user cancels, state is restored

This allows users to retry flashing without reloading or unplugging.


783-792: No cleanup needed for GUI.connect_lock
GUI.connect_lock isn’t set during the flash flow, so resetFlashingState doesn’t need to clear it.

Likely an incorrect or invalid review comment.

@nerdCopter

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/js/tabs/firmware_flasher.js (1)

1533-1548: LGTM with optional improvement suggestion.

The preservePreFlashingState method correctly captures both the message content and its type by checking CSS classes. The logic comprehensively covers all four FLASH_MESSAGE_TYPES values with an appropriate default.

Consider adding JSDoc comments to both new methods to document their purpose, especially since they're part of the public API of firmware_flasher:

+/**
+ * Resets the flashing state and UI elements after a flash operation completes or fails.
+ * Restores pre-flashing message if firmware is loaded, enables appropriate buttons.
+ */
 firmware_flasher.resetFlashingState = function () {
+/**
+ * Preserves the current firmware message and its display type before flashing starts.
+ * This state is restored by resetFlashingState() if needed.
+ */
 firmware_flasher.preservePreFlashingState = function () {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 870f1e5 and 0de4728.

📒 Files selected for processing (1)
  • src/js/tabs/firmware_flasher.js (4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.
📚 Learning: 2025-09-02T07:45:48.606Z
Learnt from: blckmn
PR: betaflight/betaflight-configurator#4583
File: src/js/tabs/firmware_flasher.js:949-961
Timestamp: 2025-09-02T07:45:48.606Z
Learning: In src/js/tabs/firmware_flasher.js, the config file loading code path after firmware loading (in the load_file click handler) cannot be reached when UF2 firmware is loaded, according to the maintainer blckmn. This code is maintained for backward compatibility with unified target settings and will be refactored in a future PR.

Applied to files:

  • src/js/tabs/firmware_flasher.js
🧬 Code graph analysis (1)
src/js/tabs/firmware_flasher.js (3)
src/js/port_handler.js (1)
  • PortHandler (16-50)
src/js/localization.js (1)
  • i18n (7-7)
src/js/gui.js (1)
  • GUI (465-465)
🔇 Additional comments (4)
src/js/tabs/firmware_flasher.js (4)

41-43: LGTM!

The new state preservation properties are well-named and properly initialized. The comment clearly explains their purpose.


810-819: LGTM!

The refactored error handling now uses centralized state restoration via resetFlashingState(), which aligns with the PR objective to properly restore UI state when DFU permission is denied or the user cancels.


1391-1392: LGTM!

Preserving the pre-flashing state before flashing begins ensures the UI can be correctly restored if the flash operation is interrupted or fails. The placement is appropriate.


1513-1531: LGTM!

The resetFlashingState method properly restores UI state by re-enabling buttons, restoring the pre-flash message when firmware is loaded, and resuming intervals. The conditional logic correctly handles both firmware-loaded and not-loaded states.

Copy link
Member

@nerdCopter nerdCopter left a comment

Choose a reason for hiding this comment

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

🚀 , friggen awesome! 🙌 💪

@nerdCopter
Copy link
Member

recording-2025-10-03_12.59.34.mp4

@sonarqubecloud
Copy link

sonarqubecloud bot commented Oct 3, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Oct 3, 2025

Preview URL: https://pr4653.betaflight-app.pages.dev

@haslinghuis haslinghuis merged commit f6aba04 into betaflight:master Oct 3, 2025
8 checks passed
@github-project-automation github-project-automation bot moved this from App to Done in 2025.12.0 Oct 3, 2025
@haslinghuis haslinghuis deleted the fix-flash-state branch October 3, 2025 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[feature request] resume flashing when DFU-Selector missed.

3 participants