feat: initial Zynq XC7Z100 Flasher GUI project

Add cross-platform GUI application for programming Zynq devices
with step-by-step workflow:

- CustomTkinter GUI with dark/light theme support
- 4-step workflow: Check Env → Flash → Bootloader → Main Program
- YAML configuration with relative path resolution
- Serial monitoring and boot log parsing
- TFTP upload with CRC32 verification
- SSH/serial reboot management
- Vivado/Impact tool auto-detection

Project structure:
- app.py: Entry point
- src/: Core modules (config, flash, bitstream, tftp, serial, gui)
- config/: Default configuration template
- .flasher_env/: Python virtual environment
This commit is contained in:
Jeremy Shen
2026-06-08 11:33:50 +08:00
commit bd39023ba7
19 changed files with 3859 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
"""Vitis/Vivado tool detection for Zynq Flasher GUI.
Checks for the presence and accessibility of required Xilinx tools
(bootgen, impact, etc.) on the system.
"""
from __future__ import annotations
import os
import platform
import subprocess
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from config_manager import Config
@dataclass
class ToolStatus:
"""Status of a single Vitis/Vivado tool."""
name: str
found: bool
path: str = ""
version: str = ""
error: str = ""
@dataclass
class VitisCheckResult:
"""Result of a complete Vitis/Vivado environment check."""
system: str
vitis_path: str
tools: dict[str, ToolStatus]
is_ready: bool
errors: list[str]
def check_vitis(config: Config) -> VitisCheckResult:
"""Check for Vitis/Vivado tools availability.
Scans the configured vitis_path and system PATH for required tools:
bootgen (boot image generator), impact (JTAG controller).
Args:
config: Application configuration with vitis_path setting.
Returns:
VitisCheckResult with details on each tool's status.
"""
system = platform.system().lower()
vitis_path = config.vitis_path or ""
tools: dict[str, ToolStatus] = {}
errors: list[str] = []
required_tools = ["bootgen", "impact"]
for tool_name in required_tools:
status = _check_tool(tool_name, vitis_path, system)
tools[tool_name] = status
if not status.found:
errors.append(f"{tool_name}: {status.error or 'not found'}")
return VitisCheckResult(
system=system,
vitis_path=vitis_path,
tools=tools,
is_ready=len(errors) == 0,
errors=errors,
)
def _check_tool(
tool_name: str, vitis_path: str, system: str
) -> ToolStatus:
"""Check if a single tool is available.
Args:
tool_name: Name of the tool to check.
vitis_path: Vitis installation path to search.
system: Platform identifier (linux, windows, darwin).
Returns:
ToolStatus with detection results.
"""
# Search in vitis_path/bin first, then system PATH
search_dirs: list[str] = []
if vitis_path:
bin_dir = Path(vitis_path) / "bin"
if bin_dir.exists():
search_dirs.append(str(bin_dir))
# Add system PATH components
path_env = os.environ.get("PATH", "")
search_dirs.extend(path_env.split(os.pathsep))
exec_name = f"{tool_name}.exe" if system == "windows" else tool_name
for search_dir in search_dirs:
candidate = Path(search_dir) / exec_name
if candidate.exists() and candidate.is_file():
version = _get_tool_version(str(candidate), tool_name, system)
return ToolStatus(
name=tool_name,
found=True,
path=str(candidate),
version=version,
)
return ToolStatus(
name=tool_name,
found=False,
error=f"Could not locate {exec_name} in PATH or {vitis_path}/bin",
)
def _get_tool_version(tool_path: str, tool_name: str, system: str) -> str:
"""Get version string from a tool executable.
Args:
tool_path: Absolute path to the tool executable.
tool_name: Name of the tool.
system: Platform identifier.
Returns:
Version string or empty string if unavailable.
"""
try:
flag = "-h" if tool_name == "impact" else "-h"
result = subprocess.run(
[tool_path, flag],
capture_output=True,
text=True,
timeout=10,
)
output = (result.stdout + result.stderr).strip()
if output:
first_line = output.split("\n")[0]
return first_line[:120]
except (subprocess.TimeoutExpired, OSError, FileNotFoundError):
pass
return ""
def get_tool_status_dict(result: VitisCheckResult) -> dict[str, Any]:
"""Convert a VitisCheckResult to a serializable dictionary.
Args:
result: VitisCheckResult from check_vitis().
Returns:
Dictionary suitable for JSON serialization or GUI display.
"""
return {
"system": result.system,
"vitis_path": result.vitis_path,
"is_ready": result.is_ready,
"tools": {
name: {
"found": status.found,
"path": status.path,
"version": status.version,
"error": status.error,
}
for name, status in result.tools.items()
},
"errors": result.errors,
}