Merge pull request #8 from walidb212/fix/gui-settings-validation

fix(gui): validate radar settings before usb send
This commit is contained in:
NawfalMotii79
2026-03-15 00:52:05 +00:00
committed by GitHub
+77 -33
View File
@@ -47,10 +47,23 @@ DARK_ACCENT = "#3c3f41"
DARK_HIGHLIGHT = "#4e5254"
DARK_BORDER = "#555555"
DARK_TEXT = "#cccccc"
DARK_BUTTON = "#3c3f41"
DARK_BUTTON_HOVER = "#4e5254"
DARK_TREEVIEW = "#3c3f41"
DARK_TREEVIEW_ALT = "#404040"
DARK_BUTTON = "#3c3f41"
DARK_BUTTON_HOVER = "#4e5254"
DARK_TREEVIEW = "#3c3f41"
DARK_TREEVIEW_ALT = "#404040"
RADAR_SETTINGS_LIMITS = {
'system_frequency': (1e9, 100e9),
'chirp_duration_1': (1e-6, 1000e-6),
'chirp_duration_2': (0.1e-6, 10e-6),
'chirps_per_position': (1, 256),
'freq_min': (1e6, 100e6),
'freq_max': (1e6, 100e6),
'prf1': (100, 10000),
'prf2': (100, 10000),
'max_distance': (100, 100000),
'map_size': (1000, 200000),
}
@dataclass
class RadarTarget:
@@ -1125,10 +1138,10 @@ class RadarGUI:
self.map_info_label = ttk.Label(info_frame, text="No GPS data received yet", font=('Arial', 10))
self.map_info_label.pack()
def setup_settings_tab(self):
"""Setup the settings tab with additional chirp durations and map size"""
settings_frame = ttk.Frame(self.tab_settings)
settings_frame.pack(fill='both', expand=True, padx=10, pady=10)
def setup_settings_tab(self):
"""Setup the settings tab with additional chirp durations and map size"""
settings_frame = ttk.Frame(self.tab_settings)
settings_frame.pack(fill='both', expand=True, padx=10, pady=10)
entries = [
('System Frequency (Hz):', 'system_frequency', 10e9),
@@ -1153,8 +1166,40 @@ class RadarGUI:
entry.grid(row=i, column=1, padx=5, pady=5)
self.settings_vars[attr] = var
ttk.Button(settings_frame, text="Apply Settings",
command=self.apply_settings).grid(row=len(entries), column=0, columnspan=2, pady=10)
ttk.Button(settings_frame, text="Apply Settings",
command=self.apply_settings).grid(row=len(entries), column=0, columnspan=2, pady=10)
def _parse_settings_from_form(self):
"""Read settings from the UI and return a validated RadarSettings instance."""
parsed_settings = RadarSettings(
system_frequency=float(self.settings_vars['system_frequency'].get()),
chirp_duration_1=float(self.settings_vars['chirp_duration_1'].get()),
chirp_duration_2=float(self.settings_vars['chirp_duration_2'].get()),
chirps_per_position=int(self.settings_vars['chirps_per_position'].get()),
freq_min=float(self.settings_vars['freq_min'].get()),
freq_max=float(self.settings_vars['freq_max'].get()),
prf1=float(self.settings_vars['prf1'].get()),
prf2=float(self.settings_vars['prf2'].get()),
max_distance=float(self.settings_vars['max_distance'].get()),
map_size=float(self.settings_vars['map_size'].get()),
)
self._validate_radar_settings(parsed_settings)
return parsed_settings
def _validate_radar_settings(self, settings):
"""Mirror the firmware-side range checks before sending settings to STM32."""
for field_name, (minimum, maximum) in RADAR_SETTINGS_LIMITS.items():
value = getattr(settings, field_name)
if value < minimum or value > maximum:
raise ValueError(
f"{field_name} must be between {minimum:g} and {maximum:g}."
)
if settings.freq_max <= settings.freq_min:
raise ValueError("freq_max must be greater than freq_min.")
return True
def apply_pitch_correction(self, raw_elevation, pitch_angle):
"""
@@ -1262,29 +1307,28 @@ class RadarGUI:
logging.info("Radar system stopped")
def apply_settings(self):
"""Step 13: Apply and send radar settings via USB"""
try:
self.settings.system_frequency = float(self.settings_vars['system_frequency'].get())
self.settings.chirp_duration_1 = float(self.settings_vars['chirp_duration_1'].get())
self.settings.chirp_duration_2 = float(self.settings_vars['chirp_duration_2'].get())
self.settings.chirps_per_position = int(self.settings_vars['chirps_per_position'].get())
self.settings.freq_min = float(self.settings_vars['freq_min'].get())
self.settings.freq_max = float(self.settings_vars['freq_max'].get())
self.settings.prf1 = float(self.settings_vars['prf1'].get())
self.settings.prf2 = float(self.settings_vars['prf2'].get())
self.settings.max_distance = float(self.settings_vars['max_distance'].get())
self.settings.map_size = float(self.settings_vars['map_size'].get())
self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get()
if self.stm32_usb_interface.is_open:
self.stm32_usb_interface.send_settings(self.settings)
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB")
logging.info("Radar settings applied via USB")
except ValueError as e:
messagebox.showerror("Error", f"Invalid setting value: {e}")
def apply_settings(self):
"""Step 13: Apply and send radar settings via USB"""
try:
parsed_settings = self._parse_settings_from_form()
self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get()
self.settings = parsed_settings
if self.stm32_usb_interface.is_open:
if not self.stm32_usb_interface.send_settings(self.settings):
messagebox.showerror("Error", "Failed to send settings to STM32 via USB")
logging.error("Radar settings validation passed, but USB send failed")
return
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB")
logging.info("Radar settings applied and sent via USB")
else:
messagebox.showinfo("Success", "Settings applied locally")
logging.info("Radar settings applied locally; STM32 USB is not connected")
except ValueError as e:
messagebox.showerror("Error", f"Invalid setting value: {e}")
def start_background_threads(self):
"""Start background data processing threads"""