From c0f7219d30cd16992a149f63ef8a721dedbc0741 Mon Sep 17 00:00:00 2001 From: Jeremy Shen Date: Fri, 12 Jun 2026 17:46:11 +0800 Subject: [PATCH] fix: replace Popen readline loop with subprocess.run for Windows pipe reliability; add close_hw before quit in TCL; revert console=True --- src/bitstream_programmer.py | 2 ++ src/zynq_checker.py | 47 +++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/bitstream_programmer.py b/src/bitstream_programmer.py index 4a3464c..f5cacd3 100644 --- a/src/bitstream_programmer.py +++ b/src/bitstream_programmer.py @@ -277,6 +277,8 @@ open_hw_target current_hw_device [lindex [get_hw_devices] 0] program_hw_device -file "{bit_path}" refresh_hw_device +close_hw +disconnect_hw_server quit """ tcl_path = bit_path.parent / "temp_program.tcl" diff --git a/src/zynq_checker.py b/src/zynq_checker.py index 991291c..e512bb8 100644 --- a/src/zynq_checker.py +++ b/src/zynq_checker.py @@ -125,7 +125,7 @@ def check_zynq_jtag( if callback: callback("progress", "Scanning JTAG chain...") - # ── 3. Run Vivado TCL (stream output to callback) ────────── + # ── 3. Run Vivado TCL ────────────────────────────────────── tcl = _build_jtag_query_tcl() python_timeout = config.step_timeouts.get("check_env", 120) @@ -141,31 +141,27 @@ def check_zynq_jtag( output_lines: list[str] = [] try: - proc = subprocess.Popen( - build_tool_command(vivado_path, *vivado_args), - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + cmd = build_tool_command(vivado_path, *vivado_args) + # Use run() with communicate() under the hood — reliably + # drains pipes on Windows even when .bat wrappers are involved + result = subprocess.run( + cmd, + capture_output=True, text=True, + timeout=python_timeout, + ) + output = result.stdout + result.stderr + for line in output.splitlines(): + stripped = line.strip() + if stripped: + output_lines.append(stripped) + if callback: + callback("progress", stripped) + except subprocess.TimeoutExpired: + return _fail( + f"JTAG scan timed out after {python_timeout}s", + hw_server_url, ) - # Read line by line so user sees real-time progress - deadline = time.monotonic() + python_timeout - while True: - line = proc.stdout.readline() if proc.stdout else "" - if not line: - if proc.poll() is not None: - break - if time.monotonic() > deadline: - proc.kill() - proc.wait() - return _fail( - f"JTAG scan timed out after {python_timeout}s", - hw_server_url, - ) - time.sleep(0.1) - continue - line = line.rstrip("\n\r") - output_lines.append(line) - if callback and line.strip(): - callback("progress", line) except OSError as e: return _fail(f"Failed to run Vivado: {e}", hw_server_url) finally: @@ -173,7 +169,6 @@ def check_zynq_jtag( Path(tcl).unlink(missing_ok=True) except Exception: pass - # Clean up Vivado temp files we redirected for f in ("vivado_jtag.jou", "vivado_jtag.log"): try: (Path(tmp) / f).unlink(missing_ok=True) @@ -267,6 +262,8 @@ foreach dev [get_hw_devices] { puts "DEVICE:$name IDCODE:$idcode" } puts "===JTAG_END===" +close_hw +disconnect_hw_server quit """ import os