Skip to content

Espressif-IDE is not clearing serial port before trying to upload (IEP-1398) #1168

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

sigmaaa
Copy link
Collaborator

@sigmaaa sigmaaa commented Mar 3, 2025

Description

clean-up the code and use try-with-resources for better resource management. Also, forcing closing terminal before re-opening it to avoid "port is not available" issue

Fixes # (IEP-1398)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

How has this been tested?

Open serial monitor with different conditions.

Test Configuration:

  • ESP-IDF Version:
  • OS (Windows,Linux and macOS):

Dependent components impacted by this PR:

  • Serial monitor

Checklist

  • PR Self Reviewed
  • Applied Code formatting
  • Added Documentation
  • Added Unit Test
  • Verified on all platforms - Windows,Linux and macOS

Summary by CodeRabbit

  • Refactor

    • Streamlined error handling and connection management for serial operations to maintain functionality while enhancing overall reliability.
    • Simplified management of serial port connections and improved thread safety.
  • Style

    • Improved code formatting and consistent brace placement for cleaner, more maintainable implementation.

@sigmaaa sigmaaa self-assigned this Mar 3, 2025
Copy link

coderabbitai bot commented Mar 3, 2025

Walkthrough

The changes involve the removal of exception handling for the pause() and resume() methods in the SerialFlashLaunch and SerialConnector classes, simplifying the control flow. Method signature formatting was standardized across several classes, particularly regarding brace placement. Additionally, the SerialPortHandler class was refactored to use a ConcurrentHashMap for managing active serial port handlers, enhancing thread safety and streamlining the logic for opening and closing connections. Overall, these modifications maintain core functionality while clarifying the code structure.

Changes

File(s) Change Summary
bundles/com.espressif.idf.launch.serial.core/.../SerialFlashLaunch.java Removed try-catch blocks for pause() and resume() in start() and handleDebugEvents() methods.
bundles/com.espressif.idf.terminal.connector.serial/.../SerialConnector.java Reformatted method signatures with braces adjusted; removed try-catch in doDisconnect() when calling serialPort.close().
bundles/com.espressif.idf.terminal.connector.serial/.../SerialPortHandler.java Updated openPorts from a WeakReference hashmap to a ConcurrentHashMap of handlers; removed adjustPortName; simplified open/close logic using computeIfAbsent/computeIfPresent and consolidated exception handling in the input thread.
bundles/com.espressif.idf.terminal.connector.serial/.../SerialLauncherDelegate.java Adjusted brace placement for method and conditional declarations without affecting control flow.

Possibly related PRs

Suggested reviewers

  • kolipakakondal
  • alirana01
  • AndriiFilippov

Poem

In the code garden, I hop with delight,
Skipping old traps and bugs out of sight.
Braces aligned like carrots in a row,
Error traps removed to let clarity grow.
With twitching whiskers and a joyful spree,
I'm a coding rabbit, proud and bug-free!
Hop on, dear coder, to a world of glee!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8a53a8 and ad9f295.

📒 Files selected for processing (1)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build_macos
  • GitHub Check: build

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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)
bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (1)

109-130: Improved resource management with try-with-resources

The thread implementation has been enhanced with try-with-resources for proper resource cleanup. This ensures that the InputStream is properly closed regardless of how the thread terminates (normal completion or exception). The exception handling has also been simplified with a single catch block for all exceptions.

Additionally, the finally block ensures that the serial connector is properly disconnected and the terminal state is updated, improving reliability of the serial port handling.

Consider explicitly handling InterruptedException separately to restore the thread's interrupted status:

 catch (Exception e)
 {
     Activator.log(e);
+    if (e instanceof InterruptedException) {
+        Thread.currentThread().interrupt();
+    }
 } finally
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5becd2 and c489bab.

📒 Files selected for processing (4)
  • bundles/com.espressif.idf.launch.serial.core/src/com/espressif/idf/launch/serial/internal/SerialFlashLaunch.java (2 hunks)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialConnector.java (3 hunks)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (10 hunks)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/launcher/SerialLauncherDelegate.java (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/launcher/SerialLauncherDelegate.java
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build_macos
🔇 Additional comments (14)
bundles/com.espressif.idf.launch.serial.core/src/com/espressif/idf/launch/serial/internal/SerialFlashLaunch.java (2)

69-71:

✅ Verification successful

Exception handling removed for serial port resume operation

The try-catch block that previously handled IOExceptions during serialPort.resume() has been removed. This improves code simplicity but shifts exception handling responsibility to the caller. This change supports the PR objective of ensuring proper port management during upload operations by ensuring port resume operations aren't silently failing.


🏁 Script executed:

#!/bin/bash
# Confirm the SerialPortHandler.resume() signature matches this change
rg -A 2 "public void resume\(\)" bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java

Length of output: 220


Verified: Removal of Exception Handling in serialPort.resume() is Acceptable

  • The output confirms that SerialPortHandler.resume() has the signature public void resume() without any declared exceptions.
  • Removing the try-catch block in SerialFlashLaunch.java (lines 69-71) is valid since the method does not propagate exceptions, effectively shifting the exception management responsibility to the caller.
  • This change aligns with the PR’s objective of ensuring proper port management during upload operations.

54-55:

❓ Verification inconclusive

Exception handling removed for serial port pause operation

The try-catch block that previously handled IOExceptions during the serialPort.pause() call has been removed. This change improves code clarity but shifts exception handling responsibility to the caller. This aligns with the PR objective of ensuring proper port management but ensure that exceptions are properly handled higher in the call stack.


🏁 Script executed:

#!/bin/bash
# Check for exception handling higher in the call stack
rg -A 2 -B 2 "catch.*IOException" bundles/com.espressif.idf.launch.serial.core/src/com/espressif/idf/launch

Length of output: 1452


Attention: Confirm Upstream IOException Handling

The removal of the try-catch block around serialPort.pause() in SerialFlashLaunch.java streamlines the code by shifting exception handling responsibility to the caller. Our search confirms that exceptions are caught in higher-level components—noticeable in:

  • SerialFlashLaunchConfigDelegate.java: Contains a catch for IOException that logs the exception.
  • ESPFlashUtil.java: Similarly catches and logs IOException.

Please ensure these handlers correctly capture exceptions thrown from serialPort.pause() and manage them appropriately.

bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialConnector.java (5)

30-46: Code formatting standardized

The opening braces have been moved to the same line as method/class declarations, improving code consistency. This is a stylistic change that enhances readability without affecting functionality.


48-63: Consistent formatting applied to getter methods

Method formatting has been standardized with opening braces on the same line. This improves code style consistency across the codebase.


65-75: Consistent formatting applied to persistence methods

Method formatting has been standardized with opening braces on the same line for the load and save methods. This improves code style consistency without affecting functionality.


77-91: Formatting changes to connect method and conditional logic

The formatting has been standardized with opening braces on the same line for both the method declaration and the conditional statement. While this is primarily a stylistic change, it ensures better code consistency.


105-112:

✅ Verification successful

Exception handling removed during port disconnection

The try-catch block around serialPort.close() has been removed, which aligns with similar changes in other files. This improves code clarity and ensures that port closure exceptions are properly propagated rather than being silently logged. This change directly supports the PR objective of ensuring serial ports are properly cleared before upload operations.


🏁 Script executed:

#!/bin/bash
# Verify the SerialPortHandler.close() method no longer throws IOException
rg "public synchronized void close\(\)" bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java

Length of output: 208


Confirmed: Exception Handling Removal Works as Intended

The try-catch block around serialPort.close() has been intentionally removed. Our verification shows that SerialPortHandler.close() no longer specifies any exception (e.g., no throws IOException), aligning with the similar changes in other files. This update improves code clarity and ensures that any exceptions during port closure are properly propagated, directly supporting the PR objective of clearing serial ports before upload operations.

bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (7)

7-8: Improved thread safety with ConcurrentHashMap and direct references

The code has been enhanced in two important ways:

  1. Changed from HashMap to ConcurrentHashMap for improved thread safety
  2. Removed WeakReferences, now storing SerialPortHandler instances directly

This change ensures better thread safety when accessing the openPorts map from multiple threads and simplifies the code by removing the need to check for expired WeakReferences. This directly supports the PR objective by providing more reliable port management.

Also applies to: 25-26


140-142: Simplified port tracking with computeIfAbsent

The code now uses computeIfAbsent for cleaner map operations. This approach ensures that the list is created only if needed and the operation is atomic, which is important for thread safety. This improvement directly addresses the PR objective by ensuring more reliable port tracking.


144-145: Exception handling responsibility shifted

The close method signature has been updated to no longer throw IOException. This shifts the responsibility of exception handling to the method implementation rather than propagating it to callers. This change is consistent with the changes in other files and helps ensure that ports are always properly closed even in exception scenarios.


160-163: Improved clean-up of inactive ports with computeIfPresent

The code now uses computeIfPresent for cleaner map operations during port removal. If the list becomes empty after removing this handler, the entire map entry is removed. This prevents memory leaks and ensures that the openPorts map stays clean. This improvement addresses the PR objective by ensuring more reliable port tracking and cleanup.


182-183: Exception handling responsibility shifted in pause method

The pause method signature has been updated to no longer throw IOException. This shifts the responsibility of exception handling to the method implementation rather than propagating it to callers. This change is consistent with the overall approach of simplifying exception handling.


204-205: Exception handling responsibility shifted in resume method

The resume method signature has been updated to no longer throw IOException. This change is consistent with the modifications to the pause and close methods, creating a coherent approach to exception handling throughout the class. This addresses the PR objective by ensuring that the resume operation completes properly.


40-65:

❓ Verification inconclusive

Simplified port handling logic

The get method has been refactored to:

  1. Remove the adjustPortName method, eliminating OS-specific port name adjustments
  2. Simplify the synchronization approach by locking only on the specific list rather than the entire map
  3. Use direct SerialPortHandler references instead of WeakReferences

These changes improve concurrency by using fine-grained locking and simplify the logic by removing the need to dereference WeakReferences. This contributes to more reliable port management as required by the PR objective.


🏁 Script executed:

#!/bin/bash
# Check if there were any OS-specific port name handling that might still be needed
rg "adjustPortName|COM|/dev/tty" bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/

Length of output: 145


Refactored port handling logic verified – please manually confirm absence of any lingering OS-specific dependencies.

The updated get method now:

  • Eliminates any OS-specific port name adjustments (the removal of adjustPortName is consistent; our search for references to adjustPortName, COM, or /dev/tty returned no evidence of residual usage).
  • Uses fine-grained locking by synchronizing on the individual port list.
  • Employs direct SerialPortHandler references instead of weak references, simplifying the code and improving reliability.

Please manually verify that no external code path depends on the previous OS-specific behavior before merging.

Copy link

@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)
bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (1)

109-131: Greatly improved resource management and error handling

The use of try-with-resources ensures proper cleanup of the input stream, even in exceptional cases. The simplified exception handling with a dedicated finally block guarantees that the serial connector will always be disconnected and resources released properly.

Consider adding a debug log entry at the beginning of this thread to aid in troubleshooting port connection issues:

 thread = new Thread(() -> {
+    Logger.log("Starting serial port handler thread for port: " + portName);
     try (InputStream targetIn = process.getInputStream())
     {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4aaa693 and 73d6915.

📒 Files selected for processing (1)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (10 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build_macos
  • GitHub Check: build
🔇 Additional comments (10)
bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (10)

7-7: Good addition of ConcurrentHashMap import

This import supports the change to thread-safe collection implementation for managing port handlers.


25-25: Improved thread safety by switching to ConcurrentHashMap

Replacing HashMap with ConcurrentHashMap enhances thread safety without requiring explicit synchronization on the map itself. Also, removing WeakReference simplifies memory management by ensuring port handlers remain in the collection until explicitly removed.


42-46: Simplified retrieval logic with improved null checking

The code now performs a cleaner null check on the retrieved list of handlers. This simplifies the control flow and makes the code more readable.


48-54: Better synchronization granularity

Synchronizing on the list itself rather than the entire map reduces lock contention and improves concurrency. The simplified handler retrieval (without WeakReference unwrapping) also makes the code more maintainable.


69-69: Direct port name assignment

Simplified constructor by directly using the provided port name without unnecessary processing, which improves code clarity.


142-142: Improved thread safety with computeIfAbsent

Using computeIfAbsent provides atomic operation for checking and initializing the list if needed. This is more concise and thread-safe than separate check-then-act operations.


145-145: Accurate method signature

Removing the throws IOException declaration aligns with the actual behavior of the method, which doesn't throw checked exceptions.


161-164: Elegant cleanup with computeIfPresent

Using computeIfPresent for removing the handler and cleaning up empty lists is an elegant approach that maintains thread safety. The lambda function handles both removal and map cleanup in a concise way.


183-183: Consistent method signatures

Removing the throws IOException declarations from pause() and resume() methods creates consistency with their actual behavior. These methods don't throw checked exceptions, so the signatures now accurately reflect their behavior.

Also applies to: 205-205


110-128: Addresses the core PR objective of port availability issues

The improved cleanup in the finally block (lines 125-130) ensures that the serial port is always properly disconnected, even when exceptions occur. This directly addresses the PR objective of fixing "port is not available" errors by ensuring resources are released properly before attempting to reuse the port.

Copy link

@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)
bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (1)

205-217: Potential redundancy in resume method

The code sets isOpen = true at line 215, but this seems redundant since open() at line 214 should already set this flag.

  public void resume()
  {
      synchronized (pauseMutex)
      {
          if (!isPaused)
          {
              return;
          }
          isPaused = false;
          open();
-         isOpen = true;
          pauseMutex.notifyAll();
      }
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73d6915 and aa96b37.

📒 Files selected for processing (1)
  • bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (10 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build
  • GitHub Check: build_macos
🔇 Additional comments (13)
bundles/com.espressif.idf.terminal.connector.serial/src/com/espressif/idf/terminal/connector/serial/connector/SerialPortHandler.java (13)

7-7: Good addition of ConcurrentHashMap import

This import is needed for the updated thread-safe implementation of the openPorts map.


25-25: Improved thread safety with ConcurrentHashMap

The change from a regular HashMap to ConcurrentHashMap provides better thread safety. Additionally, removing WeakReferences simplifies memory management and prevents potential garbage collection issues, which could have been contributing to the "port is not available" error.


42-46: Simplified null check with early return

The code now performs an early return if the list is null, making the flow more straightforward and easier to follow.


48-54: Improved synchronization model

This change correctly moves synchronization from the map to the list level, which is more granular and reduces contention. Direct access to SerialPortHandler objects instead of weak references also simplifies the code.


64-64: Consistent return null placement

Moving the return statement outside the synchronized block ensures consistent behavior and cleaner code structure.


69-69: Simplified port name handling

Direct assignment of the port name parameter eliminates unnecessary complexity and potential points of failure.


81-81: Simplified variable declaration

Minor readability improvement by declaring the variable on a single line.


109-131: Significantly improved resource management with try-with-resources

This is an excellent enhancement that:

  1. Uses try-with-resources to automatically close the input stream
  2. Simplifies exception handling
  3. Adds a crucial finally block that ensures the serial connector is always disconnected and the process is forcibly terminated

This directly addresses the PR objective of clearing the serial port before trying to upload by ensuring proper cleanup.


142-142: More robust port management with computeIfAbsent

Using computeIfAbsent is a clean, thread-safe way to handle the creation and population of the port list. This approach is more concise and less error-prone than manual list creation and management.


145-145: Simplified method signature

Removing the throws IOException declaration is appropriate since the method no longer throws this exception directly. This makes the API clearer and more consistent.


154-154: More definitive process termination

Using destroyForcibly() instead of destroy() ensures a more aggressive termination of the process, which helps prevent lingering processes that could block the serial port.


161-164: Elegant port list cleanup with computeIfPresent

The use of computeIfPresent is a clean, functional approach to:

  1. Remove the current handler from the list
  2. Remove the entire list if it becomes empty
  3. Do all this in a thread-safe manner

This helps prevent memory leaks and ensures proper cleanup of resources.


183-183: Simplified pause method signature

Removing the throws IOException declaration is appropriate since the method no longer throws this exception, making the API more consistent.

Copy link
Collaborator

@alirana01 alirana01 left a comment

Choose a reason for hiding this comment

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

LGTM!
@AndriiFilippov kindly test the openocd gdb debugging with this PR as well.

Copy link
Collaborator

@kolipakakondal kolipakakondal left a comment

Choose a reason for hiding this comment

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

Hi @sigmaaa Thanks for the PR! Since this PR includes multiple changes—code cleanup, refactoring, and WebSocket closure—could you keep only the WebSocket-related closing changes in this PR to avoid impacting other areas? The refactoring changes you’ve made could be moved to a separate PR. Also, I looked at the code, but I’m not entirely sure what specifically helped fix the issue. Keeping the changes isolated and testing them separately would be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Espressif-IDE is not clearing serial port before trying to upload (IEP-1398)
3 participants