feat: user TCL flow + parser dedup + Python TFTP
1. bitstream_programmer — combined BIT+ELF flow (user's TCL):
- targets -set -nocase -filter {name =~ "arm*#0"}
- rst -processor (bypass BootROM, block Flash boot)
- dow fsbl → con → stop (FSBL hardware init)
- fpga -f bit (configure PL)
- dow app → con (run bootloader)
- Single xsct session, no ps7_init dependency
2. serial_monitor — parser fixes:
- Boot mode parsing: 'Boot mode is JTAG' → Boot=JTAG
- Version noise filter: rejects '3.1','update','mode','loaded'
- Deduplication: UartMonitor only emits when (boot_mode, IP, ver) changes
- Fixed false match: 'Boot mode' no longer captured as version
3. tftp_manager — pure Python TFTP client:
- _tftp_put(): RFC 1350 WRQ/DATA/ACK via UDP socket
- No external tftp command dependency
- tftp_download(): documented as not-implemented (needs PC server)
This commit is contained in:
+15
-3
@@ -78,6 +78,15 @@ def parse_boot_output(lines: list[str]) -> BootInfo:
|
||||
re.compile(r"[Ff]irm[Ww]are:?\s*([^\s;,\n]+)", re.IGNORECASE),
|
||||
re.compile(r"(?:^|[\s:=])([Vv]\d+\.\d+\.\d+[^\s;,\n]*)", re.IGNORECASE),
|
||||
]
|
||||
|
||||
def _is_valid_version(v: str) -> bool:
|
||||
"""Filter out noise like '3.1', 'mode', 'update'."""
|
||||
if len(v) < 4:
|
||||
return False
|
||||
has_digit = any(c.isdigit() for c in v)
|
||||
has_dot = "." in v or "_" in v
|
||||
noise = {"mode", "upate", "update", "done", "error", "loaded", "running"}
|
||||
return has_digit and has_dot and v.lower() not in noise
|
||||
boot_complete_patterns = [
|
||||
re.compile(r"boot\s+complete", re.IGNORECASE),
|
||||
re.compile(r"system\s+ready", re.IGNORECASE),
|
||||
@@ -101,7 +110,7 @@ def parse_boot_output(lines: list[str]) -> BootInfo:
|
||||
if not info.version:
|
||||
for pattern in version_patterns:
|
||||
match = pattern.search(line)
|
||||
if match:
|
||||
if match and _is_valid_version(match.group(1)):
|
||||
info.version = match.group(1)
|
||||
break
|
||||
|
||||
@@ -345,6 +354,7 @@ class UartMonitor:
|
||||
self._lock = threading.Lock()
|
||||
self._all_lines: list[str] = []
|
||||
self._latest_info = BootInfo(raw_lines=[])
|
||||
self._last_emitted: tuple[str, str, str] = ("", "", "")
|
||||
|
||||
# Callbacks — set these before calling start()
|
||||
self.on_line: Callable[[str], None] | None = None
|
||||
@@ -441,8 +451,10 @@ class UartMonitor:
|
||||
with self._lock:
|
||||
self._latest_info = info
|
||||
|
||||
# Notify if we have new boot info
|
||||
if info.boot_message or info.ip_address or info.version:
|
||||
# Notify only when parsed info changes (dedup)
|
||||
current = (info.boot_mode, info.ip_address, info.version)
|
||||
if current != self._last_emitted and any(current):
|
||||
self._last_emitted = current
|
||||
if self.on_boot_info:
|
||||
self.on_boot_info(info)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user