✨ feat(serial): add version test via 'ver()' command
- 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
This commit is contained in:
@@ -441,6 +441,15 @@ class MainWindow(ctk.CTk):
|
|||||||
)
|
)
|
||||||
read_btn.grid(row=2, column=0, padx=PADDING, pady=PADDING_SMALL)
|
read_btn.grid(row=2, column=0, padx=PADDING, pady=PADDING_SMALL)
|
||||||
|
|
||||||
|
# Test version button
|
||||||
|
self._test_version_btn = ctk.CTkButton(
|
||||||
|
panel,
|
||||||
|
text="Test Version",
|
||||||
|
font=FONT_BODY,
|
||||||
|
command=self._test_serial_version,
|
||||||
|
)
|
||||||
|
self._test_version_btn.grid(row=3, column=0, padx=PADDING, pady=PADDING_SMALL)
|
||||||
|
|
||||||
def _build_status_panel(self, parent: ctk.CTkFrame) -> None:
|
def _build_status_panel(self, parent: ctk.CTkFrame) -> None:
|
||||||
"""Build the status display panel."""
|
"""Build the status display panel."""
|
||||||
panel = ctk.CTkFrame(parent, corner_radius=CORNER_RADIUS)
|
panel = ctk.CTkFrame(parent, corner_radius=CORNER_RADIUS)
|
||||||
@@ -972,6 +981,46 @@ class MainWindow(ctk.CTk):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log_message(f" Error: {e}")
|
self._log_message(f" Error: {e}")
|
||||||
|
|
||||||
|
def _test_serial_version(self) -> None:
|
||||||
|
"""Test serial port by sending 'ver()' command and parsing response."""
|
||||||
|
port = self._port_var.get()
|
||||||
|
if not port:
|
||||||
|
self._log_message("No serial port selected")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._log_message(f"Testing version on {port}...")
|
||||||
|
self._test_version_btn.configure(state="disabled", text="Testing...")
|
||||||
|
|
||||||
|
# Run in background thread
|
||||||
|
def test_version_thread():
|
||||||
|
try:
|
||||||
|
from serial_monitor import test_serial_version
|
||||||
|
|
||||||
|
success, message, version = test_serial_version(
|
||||||
|
port,
|
||||||
|
self._config.serial_baudrate if self._config else 115200,
|
||||||
|
)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
if version:
|
||||||
|
self._log_message(f" ✓ {message}")
|
||||||
|
self._log_message(f" ✓ Version detected: {version}")
|
||||||
|
self._status.set_status(f"Version: {version}", "success")
|
||||||
|
else:
|
||||||
|
self._log_message(f" ✓ {message}")
|
||||||
|
self._status.set_status("Port responded", "info")
|
||||||
|
else:
|
||||||
|
self._log_message(f" ✗ {message}")
|
||||||
|
self._status.set_status(message, "error")
|
||||||
|
except Exception as e:
|
||||||
|
self._log_message(f" ✗ Error: {e}")
|
||||||
|
self._status.set_status(f"Error: {e}", "error")
|
||||||
|
finally:
|
||||||
|
# Re-enable button
|
||||||
|
self.after(0, lambda: self._test_version_btn.configure(state="normal", text="Test Version"))
|
||||||
|
|
||||||
|
threading.Thread(target=test_version_thread, daemon=True).start()
|
||||||
|
|
||||||
# ── Vitis Check ────────────────────────────────────────────
|
# ── Vitis Check ────────────────────────────────────────────
|
||||||
|
|
||||||
def _check_vitis(self) -> None:
|
def _check_vitis(self) -> None:
|
||||||
|
|||||||
@@ -192,3 +192,96 @@ def read_serial_stream(
|
|||||||
if line_callback:
|
if line_callback:
|
||||||
line_callback(line)
|
line_callback(line)
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def test_serial_version(
|
||||||
|
port: str,
|
||||||
|
baudrate: int = 115200,
|
||||||
|
timeout: float = 5.0,
|
||||||
|
) -> tuple[bool, str, str]:
|
||||||
|
"""Test serial port by sending 'ver()' command and parsing response.
|
||||||
|
|
||||||
|
Sends 'ver\\r\\n' to the serial port and reads the response.
|
||||||
|
Attempts to parse version string from the response.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
port: Serial port device path (e.g., '/dev/ttyUSB0').
|
||||||
|
baudrate: Baud rate for serial communication.
|
||||||
|
timeout: Read timeout in seconds.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (success, message, version_string).
|
||||||
|
- (True, "Version: x.y.z", "x.y.z") — version detected
|
||||||
|
- (True, "Port responded", "") — port responded but no version
|
||||||
|
- (False, "Error message", "") — error occurred
|
||||||
|
"""
|
||||||
|
import serial
|
||||||
|
|
||||||
|
try:
|
||||||
|
with serial.Serial(port, baudrate, timeout=timeout) as ser:
|
||||||
|
# Clear buffers
|
||||||
|
ser.reset_input_buffer()
|
||||||
|
ser.reset_output_buffer()
|
||||||
|
|
||||||
|
# Send ver() command
|
||||||
|
ser.write(b"ver()\r\n")
|
||||||
|
|
||||||
|
# Read response
|
||||||
|
response = b""
|
||||||
|
start_time = __import__("time").time()
|
||||||
|
while __import__("time").time() - start_time < timeout:
|
||||||
|
if ser.in_waiting:
|
||||||
|
data = ser.read(ser.in_waiting)
|
||||||
|
response += data
|
||||||
|
# Check if we have a complete response
|
||||||
|
if b"\n" in data or b"\r" in data:
|
||||||
|
break
|
||||||
|
__import__("time").sleep(0.1)
|
||||||
|
|
||||||
|
# Decode response
|
||||||
|
response_str = response.decode("utf-8", errors="replace").strip()
|
||||||
|
|
||||||
|
if not response_str:
|
||||||
|
return False, "Port responded but no data received", ""
|
||||||
|
|
||||||
|
# Parse version from response
|
||||||
|
version = _parse_version_from_response(response_str)
|
||||||
|
|
||||||
|
if version:
|
||||||
|
return True, f"Version: {version}", version
|
||||||
|
else:
|
||||||
|
return True, f"Port responded: {response_str[:100]}", ""
|
||||||
|
|
||||||
|
except serial.SerialException as e:
|
||||||
|
return False, f"Serial error: {e}", ""
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"Error: {e}", ""
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_version_from_response(response: str) -> str:
|
||||||
|
"""Parse version string from serial response.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
response: Response string from serial port.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Version string if found, empty string otherwise.
|
||||||
|
"""
|
||||||
|
# Common version patterns
|
||||||
|
version_patterns = [
|
||||||
|
re.compile(r"([Vv]ersion[:\s]+)?([^\s;,\n]+v\d+\.\d+\.\d+[^\s;,\n]*)", re.IGNORECASE),
|
||||||
|
re.compile(r"(?:^|[\s:=])(v\d+\.\d+\.\d+)(?:\s|$)", re.IGNORECASE),
|
||||||
|
re.compile(r"(\d+\.\d+\.\d+)", re.IGNORECASE),
|
||||||
|
]
|
||||||
|
|
||||||
|
for pattern in version_patterns:
|
||||||
|
match = pattern.search(response)
|
||||||
|
if match:
|
||||||
|
# Return the version part (group 1 or group 2)
|
||||||
|
version = match.group(1) if match.lastindex and match.lastindex >= 1 else match.group(0)
|
||||||
|
# Clean up version string
|
||||||
|
version = version.strip().strip("';\"")
|
||||||
|
if version and len(version) > 2: # Basic validation
|
||||||
|
return version
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|||||||
Reference in New Issue
Block a user