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_HIGHLIGHT = "#4e5254"
DARK_BORDER = "#555555" DARK_BORDER = "#555555"
DARK_TEXT = "#cccccc" DARK_TEXT = "#cccccc"
DARK_BUTTON = "#3c3f41" DARK_BUTTON = "#3c3f41"
DARK_BUTTON_HOVER = "#4e5254" DARK_BUTTON_HOVER = "#4e5254"
DARK_TREEVIEW = "#3c3f41" DARK_TREEVIEW = "#3c3f41"
DARK_TREEVIEW_ALT = "#404040" 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 @dataclass
class RadarTarget: 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 = ttk.Label(info_frame, text="No GPS data received yet", font=('Arial', 10))
self.map_info_label.pack() self.map_info_label.pack()
def setup_settings_tab(self): def setup_settings_tab(self):
"""Setup the settings tab with additional chirp durations and map size""" """Setup the settings tab with additional chirp durations and map size"""
settings_frame = ttk.Frame(self.tab_settings) settings_frame = ttk.Frame(self.tab_settings)
settings_frame.pack(fill='both', expand=True, padx=10, pady=10) settings_frame.pack(fill='both', expand=True, padx=10, pady=10)
entries = [ entries = [
('System Frequency (Hz):', 'system_frequency', 10e9), ('System Frequency (Hz):', 'system_frequency', 10e9),
@@ -1153,8 +1166,40 @@ class RadarGUI:
entry.grid(row=i, column=1, padx=5, pady=5) entry.grid(row=i, column=1, padx=5, pady=5)
self.settings_vars[attr] = var self.settings_vars[attr] = var
ttk.Button(settings_frame, text="Apply Settings", ttk.Button(settings_frame, text="Apply Settings",
command=self.apply_settings).grid(row=len(entries), column=0, columnspan=2, pady=10) 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): def apply_pitch_correction(self, raw_elevation, pitch_angle):
""" """
@@ -1262,29 +1307,28 @@ class RadarGUI:
logging.info("Radar system stopped") logging.info("Radar system stopped")
def apply_settings(self): def apply_settings(self):
"""Step 13: Apply and send radar settings via USB""" """Step 13: Apply and send radar settings via USB"""
try: try:
self.settings.system_frequency = float(self.settings_vars['system_frequency'].get()) parsed_settings = self._parse_settings_from_form()
self.settings.chirp_duration_1 = float(self.settings_vars['chirp_duration_1'].get()) self.google_maps_api_key = self.settings_vars['google_maps_api_key'].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 = parsed_settings
self.settings.freq_min = float(self.settings_vars['freq_min'].get())
self.settings.freq_max = float(self.settings_vars['freq_max'].get()) if self.stm32_usb_interface.is_open:
self.settings.prf1 = float(self.settings_vars['prf1'].get()) if not self.stm32_usb_interface.send_settings(self.settings):
self.settings.prf2 = float(self.settings_vars['prf2'].get()) messagebox.showerror("Error", "Failed to send settings to STM32 via USB")
self.settings.max_distance = float(self.settings_vars['max_distance'].get()) logging.error("Radar settings validation passed, but USB send failed")
self.settings.map_size = float(self.settings_vars['map_size'].get()) return
self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get()
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB")
if self.stm32_usb_interface.is_open: logging.info("Radar settings applied and sent via USB")
self.stm32_usb_interface.send_settings(self.settings) else:
messagebox.showinfo("Success", "Settings applied locally")
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB") logging.info("Radar settings applied locally; STM32 USB is not connected")
logging.info("Radar settings applied via USB")
except ValueError as e:
except ValueError as e: messagebox.showerror("Error", f"Invalid setting value: {e}")
messagebox.showerror("Error", f"Invalid setting value: {e}")
def start_background_threads(self): def start_background_threads(self):
"""Start background data processing threads""" """Start background data processing threads"""