Merge pull request #8 from walidb212/fix/gui-settings-validation
fix(gui): validate radar settings before usb send
This commit is contained in:
@@ -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"""
|
||||||
|
|||||||
Reference in New Issue
Block a user