fix: remove manual hw_server management — let Vivado handle it internally
External hw_server start via Popen was unreliable on Windows (Vivado has its own hw_server lifecycle via open_hw_manager). Simplified to just run Vivado TCL directly — tested working on Linux (6.9s). Also bumped default check_env timeout from 120s to 180s for Windows where Vivado cold-start can take significantly longer. Removed: _port_open, socket import, manual hw_server Popen/kill logic.
This commit is contained in:
@@ -35,7 +35,7 @@ DEFAULT_CONFIG: dict[str, Any] = {
|
||||
"inter_step_delay": 2,
|
||||
"boot_wait_delay": 10,
|
||||
"step_timeouts": {
|
||||
"check_env": 120,
|
||||
"check_env": 180,
|
||||
"flash_erase": 120,
|
||||
"flash_program": 600,
|
||||
"bitstream": 60,
|
||||
|
||||
+6
-70
@@ -7,16 +7,14 @@ returning device names, IDCODEs, and PS/PL presence.
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import socket
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Callable
|
||||
|
||||
from config_manager import Config
|
||||
from vitis_checker import get_vivado_path, get_hw_server_path, build_tool_command
|
||||
from vitis_checker import get_vivado_path, build_tool_command
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -68,17 +66,6 @@ _ARM_DAP_RE = re.compile(r"^arm_dap", re.IGNORECASE)
|
||||
HW_SERVER_PORT = 3121
|
||||
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────
|
||||
|
||||
def _port_open(host: str = "localhost", port: int = HW_SERVER_PORT) -> bool:
|
||||
"""Check if a TCP port is accepting connections."""
|
||||
try:
|
||||
with socket.create_connection((host, port), timeout=1):
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def _idcode_to_hex(binary_str: str) -> str:
|
||||
"""Convert Vivado's binary IDCODE to uppercase hex."""
|
||||
try:
|
||||
@@ -94,10 +81,9 @@ def check_zynq_jtag(
|
||||
) -> ZynqCheckResult:
|
||||
"""Check for Zynq devices on the JTAG chain via Vivado + hw_server.
|
||||
|
||||
Lifecycle:
|
||||
1. If hw_server is already running (port 3121 open) → reuse it
|
||||
2. If not running → start it, kill it when done
|
||||
3. Run Vivado batch TCL to enumerate JTAG devices
|
||||
Vivado manages hw_server internally — open_hw_manager auto-starts
|
||||
the hardware server and connect_hw_server connects to it. No manual
|
||||
hw_server lifecycle needed.
|
||||
|
||||
Args:
|
||||
config: Application configuration.
|
||||
@@ -112,7 +98,7 @@ def check_zynq_jtag(
|
||||
if callback:
|
||||
callback("start", "Connecting to hw_server...")
|
||||
|
||||
# ── 1. Find tools ──────────────────────────────────────────
|
||||
# ── 1. Find Vivado ──────────────────────────────────────────
|
||||
vivado_path = get_vivado_path(xilinx_root=xilinx_root)
|
||||
if not vivado_path:
|
||||
return ZynqCheckResult(
|
||||
@@ -122,46 +108,7 @@ def check_zynq_jtag(
|
||||
error="Vivado not found",
|
||||
)
|
||||
|
||||
hw_server_path = get_hw_server_path(xilinx_root=xilinx_root)
|
||||
hw_server_was_running = _port_open()
|
||||
|
||||
# ── 2. Start hw_server if needed ───────────────────────────
|
||||
hw_proc: subprocess.Popen | None = None
|
||||
if not hw_server_was_running:
|
||||
if not hw_server_path:
|
||||
return ZynqCheckResult(
|
||||
devices=[], jtag_chain=[], is_present=False,
|
||||
ps_detected=False, pl_detected=False,
|
||||
hw_server_url=hw_server_url,
|
||||
error="hw_server not found — install Vivado/Vitis",
|
||||
)
|
||||
try:
|
||||
hw_proc = subprocess.Popen(
|
||||
build_tool_command(hw_server_path),
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
# Wait for port to become available
|
||||
for _ in range(30): # 3s max
|
||||
if _port_open():
|
||||
break
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
return ZynqCheckResult(
|
||||
devices=[], jtag_chain=[], is_present=False,
|
||||
ps_detected=False, pl_detected=False,
|
||||
hw_server_url=hw_server_url,
|
||||
error="hw_server started but port 3121 not open",
|
||||
)
|
||||
except OSError as e:
|
||||
return ZynqCheckResult(
|
||||
devices=[], jtag_chain=[], is_present=False,
|
||||
ps_detected=False, pl_detected=False,
|
||||
hw_server_url=hw_server_url,
|
||||
error=f"Failed to start hw_server: {e}",
|
||||
)
|
||||
|
||||
# ── 3. Run Vivado TCL ──────────────────────────────────────
|
||||
# ── 2. Run Vivado TCL (manages hw_server internally) ────────
|
||||
try:
|
||||
tcl = _build_jtag_query_tcl()
|
||||
if callback:
|
||||
@@ -216,17 +163,6 @@ def check_zynq_jtag(
|
||||
hw_server_url=hw_server_url,
|
||||
error=f"OS error: {e}",
|
||||
)
|
||||
finally:
|
||||
# ── 4. Kill hw_server only if WE started it ────────────
|
||||
if hw_proc is not None and hw_proc.poll() is None:
|
||||
try:
|
||||
hw_proc.terminate()
|
||||
hw_proc.wait(timeout=3)
|
||||
except subprocess.TimeoutExpired:
|
||||
hw_proc.kill()
|
||||
hw_proc.wait()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
# ── TCL builder ────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user