fix: avoid serial port conflict between workflow and UART window

Flow execution's _start_uart_monitor() now checks if a UART window
is already monitoring before starting its own UartMonitor instance.
This prevents two UartMonitor threads from fighting over the same
serial port.

Changes:
- UartMonitorWindow: add is_monitoring property
- MainWindow._uart_window: store reference to open UART window
- _start_uart_monitor(): skip if UART window already monitoring
- _on_close(): destroy UART window on main window close
This commit is contained in:
Jeremy Shen
2026-06-10 15:23:28 +08:00
parent 2695180c8f
commit a47e3b78ae
2 changed files with 16 additions and 1 deletions
+11 -1
View File
@@ -82,6 +82,7 @@ class MainWindow(ctk.CTk):
self._zynq_jtag_present: bool = False self._zynq_jtag_present: bool = False
self._zynq_jtag_info = None self._zynq_jtag_info = None
self._uart_monitor: UartMonitor | None = None self._uart_monitor: UartMonitor | None = None
self._uart_window: UartMonitorWindow | None = None
self._flash_phase: str = "" self._flash_phase: str = ""
# StringVar references for config sync # StringVar references for config sync
@@ -1148,6 +1149,12 @@ class MainWindow(ctk.CTk):
def _start_uart_monitor(self) -> None: def _start_uart_monitor(self) -> None:
"""Start background serial monitoring if UART is available.""" """Start background serial monitoring if UART is available."""
# If UART window is already monitoring, don't start a second instance
if (self._uart_window
and self._uart_window.winfo_exists()
and self._uart_window.is_monitoring):
self._log_message(" [UART] Already monitoring via UART window")
return
if not self._uart_available or not self._config: if not self._uart_available or not self._config:
return return
port = self._config.serial_port port = self._config.serial_port
@@ -1191,6 +1198,9 @@ class MainWindow(ctk.CTk):
def _on_close(self) -> None: def _on_close(self) -> None:
"""Handle window close event: save config and cleanup.""" """Handle window close event: save config and cleanup."""
self._stop_uart_monitor() self._stop_uart_monitor()
if self._uart_window and self._uart_window.winfo_exists():
self._uart_window.destroy()
self._uart_window = None
if self._config: if self._config:
self._sync_config_from_ui() # Sync UI values first self._sync_config_from_ui() # Sync UI values first
# Save to user config file (config.yaml) # Save to user config file (config.yaml)
@@ -1206,7 +1216,7 @@ class MainWindow(ctk.CTk):
"""Open the UART Monitor window.""" """Open the UART Monitor window."""
port = self._port_var.get() port = self._port_var.get()
baudrate = self._config.serial_baudrate if self._config else 115200 baudrate = self._config.serial_baudrate if self._config else 115200
UartMonitorWindow(self, port=port, baudrate=baudrate) self._uart_window = UartMonitorWindow(self, port=port, baudrate=baudrate)
def _test_serial_version(self) -> None: def _test_serial_version(self) -> None:
"""Test serial port by sending 'ver()' command and parsing response.""" """Test serial port by sending 'ver()' command and parsing response."""
+5
View File
@@ -1024,6 +1024,11 @@ class UartMonitorWindow(ctk.CTkToplevel):
# ── Window Close ─────────────────────────────────────────── # ── Window Close ───────────────────────────────────────────
@property
def is_monitoring(self) -> bool:
"""True if the UART monitor thread is currently running."""
return self._monitor is not None and self._monitor.is_running()
def _on_close(self) -> None: def _on_close(self) -> None:
"""Cleanup UartMonitor and destroy window.""" """Cleanup UartMonitor and destroy window."""
if self._monitor: if self._monitor: