Replace 'Read Serial' button with 'Open UART' that opens a new
UART Monitor window (CTkToplevel) with:
- Title bar with status indicator (● connecting/ready/monitoring/error)
- Port info display + Start/Stop/Clear buttons
- Large scrollable log area (CTkTextbox) with monospace font
- Auto-scroll to bottom, line counter in status bar
- Boot info parsing (IP, version) shown as [BOOT] prefix
- Background serial monitoring via UartMonitor class
UART unavailable handling:
- On init, tries to open serial port in background thread
- If port can't open → shows 'UART 不可用' state with error message
- If port opens → shows 'Ready', user clicks Start to begin monitoring
Window features:
- Modal (grab_set) — focus stays on monitor window
- Clean up UartMonitor on close (WM_DELETE_WINDOW handler)
- Thread-safe UI updates via after(0, ...)
- Reuses existing UartMonitor from serial_monitor.py
Configuration panel now has a 'Xilinx Kit:' row at the top with:
- Entry field showing current path
- [Browse] button using system directory dialog (cross-platform)
- Select root directory (e.g. /data/xilinx or C:/Xilinx)
vitis_checker.py now scans xilinx_root subdirectories:
1. System PATH (shutil.which) — works on all platforms
2. Legacy vitis_path/bin
3. xilinx_root/Vitis/*/bin and Vivado/*/bin (all versions, newest first)
4. Common install paths (Windows: C:/Xilinx, Linux: /data/xilinx, /opt/xilinx)
Multi-version: scans all version directories under Vitis/ and Vivado/,
picks the newest version for each tool.
Config: xilinx_path replaces vitis_path (backward compat kept)
1. SubStepFrame defaults to expanded (▼), not collapsed
2. erase_all checkbox has command=_on_erase_toggle → immediate config update
3. _deferred_init runs _check_vitis/_refresh_ports in background thread
Fixes UI freeze during startup (subprocess.run for tool versions)
4. Sub-step colors now match StepHeader:
- pending: gray ACCENT_PENDING (#888888)
- running: blue CIRCLE_RUNNING (#0078D4) with pulse animation
- complete: green ACCENT_COMPLETE (#107C10)
- error: red ACCENT_ERROR (#D13438)
- Running sub-step pulses between light/dark blue like StepHeader
SubStepFrame now uses default CustomTkinter label colors (white
in dark mode, black in light mode) instead of manually set
CIRCLE_*/ACCENT_* colors that were unreadable on dark backgrounds.
Simplified grid layout — no nested sub-frames.
Based on real hardware timing data from XC7Z100 testing:
UART Monitoring:
- New UartMonitor class in serial_monitor.py: background thread reads
serial output continuously, parses for IP/version/boot messages
- GUI starts monitor when workflow runs, stops on completion/close
- Serial lines flow into log display in real time
Step Timing:
- New step_timeouts config (experience × 2):
check_env:30s flash_erase:120s flash_program:600s
bitstream:60s elf_download:60s tftp_reboot:120s
- GUI shows estimated timeout before each step
- Shows actual elapsed time after each step completes
- All subprocess calls now use config-driven timeouts
Non-blocking Output:
- New subprocess_utils.py: run_streaming() uses Popen + threaded
stdout/stderr readers, parses WARNING/ERROR/progress% in real time
- flash_programmer and bitstream_programmer use it
- Callbacks receive categorized events (out/err/warn/error/progress/done)
Fixes found during real hardware test:
bitstream_programmer.py:
- _program_with_xsct: use TCL file instead of xsct -eval (quit→exit fix)
- _run_elf_with_xsct: add reconnect + source ps7_init.tcl after PL config,
use target ID 2 instead of name filter, TCL file instead of -eval
- _find_ps7_init_tcl: auto-detect ps7_init.tcl from BIT file directory
- run_elf: remove Vivado fallback (program_hw_cpu is xsct, not Vivado)
- Remove dead _run_elf_with_vivado (Vivado HM can't program PS CPU)
flash_programmer.py:
- wipe_flash: -erase_only without -erase_all (s25fl256s1 compat fix)
- _find_config() and _get_user_config_path() now use parent.parent.parent
to navigate from src/gui/main_window.py to project root
- User config now saves to /data/work/prj/Zynq_Flasher/config.yaml
- _find_config() now looks for config.yaml at project root first
- _get_user_config_path() returns project root config.yaml
- config/default_config.yaml remains as template (not for saving)
- _find_config() now looks for config.yaml first, then default_config.yaml
- _load_config() sets save path to config.yaml when loading from default
- _save_config() always saves to config/config.yaml
- _on_close() saves to config.yaml on window close
- Added _get_user_config_path() helper method
Config save fix:
- Add _sync_config_from_ui() to sync UI values to Config object
- Store _ip_string_var reference for IP field sync
- Call _sync_config_from_ui() before every save operation
- Fix _on_close to sync before saving
UI freeze fix:
- Defer _check_vitis() and _refresh_ports_initial() to _deferred_init()
- Use self.after(100, ...) to defer until window is displayed
- Window now appears immediately, blocking ops run in background
- Add test_serial_version() to serial_monitor.py
- Sends 'ver()' command and parses version response
- Add 'Test Version' button in serial panel
- Displays version in status and log
- Add dedicated UART warning label that doesn't get overwritten
- _show_uart_notification now uses persistent label instead of status display
- Warning message stays visible throughout workflow execution
- Remove dependency chain that prevented steps 2,3,4 from running
- All steps now have can_run=True
- Steps can be executed individually without running previous steps
- Add missing 'import time' for _run_steps_worker
- Fix left panel layout: remove rowspan=2 to prevent overflow
- Left panel now correctly occupies only lower half of window
- Remove IP check from Step 1 environment check
- Add PS (ARM DAP) and PL detection to zynq_checker
- Log detailed JTAG chain information in Step 1
- Show PS/PL detection status in GUI logs
- Display JTAG chain devices with type classification
- Add zynq_checker.py module to detect Zynq devices on JTAG chain
- Connects to hw_server via Vivado batch mode
- Parses JTAG device names to extract part number (e.g. XC7Z100)
- Integrates into Step 1 environment check in main_window.py
- Shows JTAG status in header (JTAG: XC7Z100 ✓)
- vitis_checker: shutil.which() + xsct fallback for impact detection
- flash_programmer: _get_impact_path now checks xsct as fallback
- bitstream_programmer: _get_impact_path now checks xsct as fallback
- GUI: show '(via xsct)' alias note when xsct replaces impact
- ToolStatus: add 'alias' field for tracking which executable was found
- Fix 6 overlapping widget bugs in StepHeader (title/desc, btn/icon,
run/rerun) with proper 5-column grid layout
- Merge run/rerun buttons into single _action_btn with state-driven text
- Fix DARK_CARD NameError (undefined import → STEP_CARD_BG)
- Replace fragile vertical connector lines with full-width dividers
- Add panel.grid_columnconfigure(0, weight=1) for horizontal scaling
- Unify button text across all states (▶ pending/disabled, ↻ retry)
- Tighten padding and reduce whitespace between steps
- Replace Segoe UI with Roboto for cross-platform compatibility
- Increase font sizes for better readability (9→11, 11→12, 14→15)
- Update dark theme to VS Code-like colors (#1E1E1E bg)
- Brighten accent colors and improve contrast ratios
- Fix StepHeader: number circle background, status icon positioning
- Enlarge accent bar (4→5px) and buttons (28→32px)
- Simplify status text (Completed → Done)
- Improve connector line sizing and alignment
- Rename bit_path -> bootloader_bit_path for clarity
- Rename elf_path -> bootloader_elf_path for clarity
- Split single bin_path into bootloader_bin_path (flash) and
firmware_bin_path (TFTP upload)
- Reorder Configuration panel: BIT -> ELF -> Bootloader BIN ->
Firmware BIN
- Update display names with file extensions and context labels
- Update all step references (Step 2 flash, Step 3 bootloader,
Step 4 TFTP) to use new field names