feat(uart): add UART availability check, inter-step delays, and post-download Zynq status verification

- Add check_uart_available() to serial_monitor.py — detects port availability
- Add verify_zynq_status() to boot_verifier.py — lightweight post-download check
- Add uart_delay / inter_step_delay config fields (defaults: 3s / 2s)
- Step 1: Check UART availability, show non-blocking 'UART 不可用' notification
- Step 4: Add post-download Zynq status check (ping + serial) after TFTP
- _run_steps_worker: Add configurable inter-step delays between all steps
- Update step labels (4a→4b→4c→4d) for clarity
This commit is contained in:
Jeremy Shen
2026-06-09 17:53:48 +08:00
parent 91a7843dbe
commit 3a9bc5d9ed
4 changed files with 209 additions and 7 deletions
+59 -7
View File
@@ -21,8 +21,8 @@ from bitstream_programmer import full_bitstream_program, BitstreamResult
from ip_verifier import ping_ip
from tftp_manager import tftp_upload_verify, TftpResult
from reboot_manager import reboot_zynq, RebootResult
from boot_verifier import verify_boot, BootVerificationResult
from serial_monitor import detect_serial_ports, parse_boot_output
from boot_verifier import verify_boot, verify_zynq_status, BootVerificationResult
from serial_monitor import detect_serial_ports, parse_boot_output, check_uart_available
from gui.styles import (
WINDOW_WIDTH,
WINDOW_HEIGHT,
@@ -73,6 +73,8 @@ class MainWindow(ctk.CTk):
self._step_statuses: dict[int, str] = {}
self._is_running = False
self._worker_thread: threading.Thread | None = None
self._uart_available: bool = False
self._uart_message: str = ""
self._load_config()
self._build_ui()
@@ -471,7 +473,7 @@ class MainWindow(ctk.CTk):
# ── Step Implementations ───────────────────────────────────
def _run_step_1_check_environment(self) -> bool:
"""Step 1: Check environment (Vitis/Vivado tools + Zynq IP)."""
"""Step 1: Check environment (Vitis/Vivado tools + Zynq IP + UART)."""
self._log_message("Step 1: Checking environment...")
if not self._config:
@@ -507,8 +509,35 @@ class MainWindow(ctk.CTk):
self._ip_status.configure(text=f"IP: {ip}", text_color=DANGER_COLOR)
return False
# Check UART availability
self._log_message(" Checking UART serial port...")
port = self._config.serial_port
if port:
available, reason = check_uart_available(port, self._config.serial_baudrate)
self._uart_available = available
self._uart_message = reason
if available:
self._log_message(f" ✓ UART available: {reason}")
else:
self._log_message(f" ✗ UART unavailable: {reason}")
self._show_uart_notification(reason)
else:
self._uart_available = False
self._uart_message = "No serial port configured"
self._log_message(" ✗ No serial port configured")
self._show_uart_notification(self._uart_message)
return True
def _show_uart_notification(self, reason: str) -> None:
"""Show a non-blocking UART unavailable notification in the status panel.
Args:
reason: Why UART is unavailable.
"""
msg = f"UART 不可用 ({reason}),日志分析及检查将禁用"
self.after(0, lambda: self._status.set_status(msg, "warning"))
def _run_step_2_program_flash(self) -> bool:
"""Step 2: Program and verify Flash."""
if not self._config:
@@ -606,8 +635,21 @@ class MainWindow(ctk.CTk):
self._log_message(" Skipping reboot & boot verify (TFTP failed)")
return False
# 4b: Reboot
self._log_message("Step 4b: Rebooting Zynq...")
# 4a2: Post-download Zynq status check
self._log_message("Step 4b: Checking Zynq status after download...")
try:
zynq_status = verify_zynq_status(
self._config,
uart_available=self._uart_available,
callback=self._zynq_status_callback,
)
status = "" if zynq_status.success else ""
self._log_message(f" {status} {zynq_status.message}")
except Exception as e:
self._log_message(f" ✗ Zynq status check error: {e}")
# 4c: Reboot
self._log_message("Step 4c: Rebooting Zynq...")
try:
reboot_result = reboot_zynq(
self._config,
@@ -625,8 +667,8 @@ class MainWindow(ctk.CTk):
self._log_message(" Skipping boot verify (reboot failed)")
return False
# 4c: Verify boot
self._log_message("Step 4c: Verifying boot...")
# 4d: Verify boot
self._log_message("Step 4d: Verifying boot...")
try:
boot_result = verify_boot(
self._config,
@@ -659,6 +701,10 @@ class MainWindow(ctk.CTk):
"""Callback for boot verification progress."""
self._log_message(f" [{status}] {message}")
def _zynq_status_callback(self, status: str, message: str) -> None:
"""Callback for post-download Zynq status check."""
self._log_message(f" [{status}] {message}")
# ── Run All Steps ──────────────────────────────────────────
def _update_step_dependencies(self) -> None:
@@ -781,6 +827,12 @@ class MainWindow(ctk.CTk):
if start_index == 0 and not success:
break
# Inter-step delay (skip after last step)
if i < len(step_funcs) - 1:
delay = self._config.inter_step_delay if self._config else 2
self._log_message(f" ⏳ Waiting {delay}s before next step...")
time.sleep(delay)
self._progress.set_value(1.0)
self._is_running = False
self._run_btn.configure(state="normal", text="▶ Run All Steps")