S1005403_RisCC/target_simulator/gui/settings_window.py
2025-10-02 14:37:38 +02:00

184 lines
7.8 KiB
Python

# target_simulator/gui/settings_window.py
"""
A Toplevel window for configuring connection settings (Serial or TFTP).
"""
import tkinter as tk
from tkinter import ttk, messagebox
from typing import Dict, Any
from core.serial_communicator import SerialCommunicator, SERIAL_PARAMS
from core.tftp_communicator import TFTPCommunicator
from target_simulator.utils.config_manager import ConfigManager
class SettingsWindow(tk.Toplevel):
"""A dialog window for connection settings."""
def __init__(self, master, config_manager: ConfigManager, current_config: Dict[str, Any]):
super().__init__(master)
self.master_view = master
self.config_manager = config_manager
self.title("Connection Settings")
self.transient(master)
self.grab_set()
self.resizable(False, False)
# --- Variables ---
self.comm_type_var = tk.StringVar(value=current_config.get("type", "serial"))
self.serial_config_vars = self._setup_serial_vars(current_config.get("serial", {}))
self.tftp_config_vars = self._setup_tftp_vars(current_config.get("tftp", {}))
# --- UI Creation ---
main_frame = ttk.Frame(self, padding="10")
main_frame.pack(fill=tk.BOTH, expand=True)
self._create_type_selector(main_frame)
# --- Configuration Frames ---
self.serial_frame = self._create_serial_frame(main_frame)
self.tftp_frame = self._create_tftp_frame(main_frame)
self._create_buttons(main_frame)
# --- Initial State ---
self._on_comm_type_change()
self.protocol("WM_DELETE_WINDOW", self.destroy)
self.wait_window(self)
def _setup_serial_vars(self, config: Dict) -> Dict[str, tk.StringVar]:
return {
"port": tk.StringVar(value=config.get("port", "")),
"baudrate": tk.StringVar(value=config.get("baudrate", "115200")),
"bytesize": tk.StringVar(value=config.get("bytesize", "8")),
"parity": tk.StringVar(value=config.get("parity", "N")),
"stopbits": tk.StringVar(value=config.get("stopbits", "1")),
}
def _setup_tftp_vars(self, config: Dict) -> Dict[str, tk.StringVar]:
return {
"ip": tk.StringVar(value=config.get("ip", "127.0.0.1")),
"port": tk.StringVar(value=config.get("port", "69")),
}
def _create_type_selector(self, parent):
frame = ttk.LabelFrame(parent, text="Communication Type", padding=10)
frame.pack(fill=tk.X, pady=(0, 10))
ttk.Radiobutton(
frame, text="Serial", variable=self.comm_type_var, value="serial", command=self._on_comm_type_change
).pack(side=tk.LEFT, padx=10)
ttk.Radiobutton(
frame, text="TFTP", variable=self.comm_type_var, value="tftp", command=self._on_comm_type_change
).pack(side=tk.LEFT, padx=10)
def _create_serial_frame(self, parent) -> ttk.Frame:
frame = ttk.LabelFrame(parent, text="Serial Port Settings", padding=10)
# Grid layout for alignment
frame.columnconfigure(1, weight=1)
# Port
ttk.Label(frame, text="Port:").grid(row=0, column=0, sticky=tk.W, pady=2)
port_combo = ttk.Combobox(frame, textvariable=self.serial_config_vars["port"], state="readonly")
port_combo.grid(row=0, column=1, sticky=tk.EW, padx=5, pady=2)
self._populate_ports(port_combo)
# Baudrate
ttk.Label(frame, text="Baud Rate:").grid(row=1, column=0, sticky=tk.W, pady=2)
baud_combo = ttk.Combobox(frame, textvariable=self.serial_config_vars["baudrate"], values=SERIAL_PARAMS['baudrates'], state="readonly")
baud_combo.grid(row=1, column=1, sticky=tk.EW, padx=5, pady=2)
# Parity
ttk.Label(frame, text="Parity:").grid(row=2, column=0, sticky=tk.W, pady=2)
parity_combo = ttk.Combobox(frame, textvariable=self.serial_config_vars["parity"], values=list(SERIAL_PARAMS['parities']), state="readonly")
parity_combo.grid(row=2, column=1, sticky=tk.EW, padx=5, pady=2)
return frame
def _create_tftp_frame(self, parent) -> ttk.Frame:
frame = ttk.LabelFrame(parent, text="TFTP Server Settings", padding=10)
frame.columnconfigure(1, weight=1)
# IP Address
ttk.Label(frame, text="Server IP:").grid(row=0, column=0, sticky=tk.W, pady=2)
ttk.Entry(frame, textvariable=self.tftp_config_vars["ip"]).grid(row=0, column=1, sticky=tk.EW, padx=5, pady=2)
# Port
ttk.Label(frame, text="Server Port:").grid(row=1, column=0, sticky=tk.W, pady=2)
ttk.Entry(frame, textvariable=self.tftp_config_vars["port"]).grid(row=1, column=1, sticky=tk.EW, padx=5, pady=2)
return frame
def _create_buttons(self, parent):
frame = ttk.Frame(parent, padding=(0, 10, 0, 0))
frame.pack(fill=tk.X)
ttk.Button(frame, text="Test Connection", command=self._on_test_connection).pack(side=tk.LEFT, padx=(0, 10))
# Right-align Save and Cancel
ttk.Button(frame, text="Cancel", command=self.destroy).pack(side=tk.RIGHT)
ttk.Button(frame, text="Save", command=self._on_save).pack(side=tk.RIGHT, padx=5)
def _on_comm_type_change(self):
"""Show/hide frames based on the selected communication type."""
selected_type = self.comm_type_var.get()
if selected_type == "serial":
self.tftp_frame.pack_forget()
self.serial_frame.pack(fill=tk.X, expand=True)
elif selected_type == "tftp":
self.serial_frame.pack_forget()
self.tftp_frame.pack(fill=tk.X, expand=True)
def _populate_ports(self, combobox: ttk.Combobox):
"""Fetches and displays available serial ports."""
available_ports = SerialCommunicator.list_available_ports()
if available_ports:
combobox['values'] = available_ports
if not self.serial_config_vars["port"].get():
self.serial_config_vars["port"].set(available_ports[0])
else:
combobox['values'] = ['No ports found']
self.serial_config_vars["port"].set('No ports found')
def _on_test_connection(self):
"""Tests the connection for the currently selected mode."""
comm_type = self.comm_type_var.get()
is_success = False
config = {}
if comm_type == "serial":
config = {key: var.get() for key, var in self.serial_config_vars.items()}
is_success = SerialCommunicator.test_connection(config)
else: # tftp
config = {key: var.get() for key, var in self.tftp_config_vars.items()}
is_success = TFTPCommunicator.test_connection(config)
if is_success:
messagebox.showinfo("Success", f"Connection test successful for {comm_type.upper()}.", parent=self)
else:
messagebox.showerror("Failure", f"Failed to connect using {comm_type.upper()} settings.", parent=self)
def _on_save(self):
"""Saves the selected settings and closes the window."""
comm_type = self.comm_type_var.get()
# Recupera la configurazione corrente
current = self.master_view.connection_config if hasattr(self.master_view, 'connection_config') else {}
serial_conf = current.get("serial", {})
tftp_conf = current.get("tftp", {})
if comm_type == "serial":
serial_conf = {key: var.get() for key, var in self.serial_config_vars.items()}
else:
tftp_conf = {key: var.get() for key, var in self.tftp_config_vars.items()}
full_config = {
"type": comm_type,
"serial": serial_conf,
"tftp": tftp_conf
}
self.master_view.update_connection_settings(full_config)
self.destroy()