From ce223621d16cc61fad0a8dfaa1dc837f42741168 Mon Sep 17 00:00:00 2001 From: Andy Killorin <37423245+Speedy6451@users.noreply.github.com> Date: Sat, 8 Mar 2025 20:47:52 -0500 Subject: [PATCH] auto conf sync to gui --- interface/src/auto.rs | 31 ++++++++++++++++++++++--------- interface/src/gui.rs | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/interface/src/auto.rs b/interface/src/auto.rs index 9c84841..b43a217 100644 --- a/interface/src/auto.rs +++ b/interface/src/auto.rs @@ -1,8 +1,9 @@ -use std::{collections::VecDeque, ops::{Deref, Div, Index, Range, Sub}}; +use std::{collections::VecDeque, ops::{Deref, Div, Index, Range, Sub}, sync::Arc}; use common::{CamState, ControlPacket, SensorData, TelemetryPacket}; -use anyhow::Result; -use tokio::sync::{broadcast, mpsc, watch}; +use anyhow::{Context, Ok, Result}; +use eframe::Storage; +use tokio::sync::{self, broadcast, mpsc, watch}; pub struct AutoConfig { turn_gain: f32, @@ -10,14 +11,19 @@ pub struct AutoConfig { } #[derive(Clone)] -pub struct AutoInterface { +pub struct AutoInterface<'s> { command_sender: Option>, data_receiver: watch::Receiver, + config: &'s dyn Storage, + enabled: bool, } -impl AutoInterface { +impl<'s> AutoInterface<'s> { /// change active command, fails if not in control - pub fn run_command(&self, command: ControlPacket) -> Result<()> {unimplemented!()} + pub async fn run_command(&self, command: ControlPacket) -> Result<()> { + self.command_sender.as_ref().context("no sender")?.send(command).await?; + Ok(()) + } pub fn sensor_data(&mut self) -> SensorData { self.data_receiver.borrow_and_update().sensors.clone() } @@ -32,9 +38,16 @@ impl AutoInterface { /// disable auto pub fn disable(&self) {unimplemented!()} /// request auto enable, fails if the driver does not grant it - pub fn enable(&self) -> Result<()> {unimplemented!()} - pub fn enabled(&self) -> bool {unimplemented!()} - pub fn conf(&self, key: &'static Configurable) -> f32 {unimplemented!()} + pub fn enable(&mut self) -> Result<()> { + self.enabled = self.command_sender.is_some(); + Ok(()) + } + pub fn enabled(&self) -> bool { self.enabled} + pub fn conf(&self, key: &'static Configurable) -> f32 { + self.config.get_string(&key.name) + .map(|s| s.parse().ok()) + .flatten().unwrap_or(key.default) + } fn send_message(&self, message: String) {unimplemented!()} } diff --git a/interface/src/gui.rs b/interface/src/gui.rs index f458bf4..a06ce2a 100644 --- a/interface/src/gui.rs +++ b/interface/src/gui.rs @@ -1,13 +1,12 @@ - -use std::{cell::OnceCell, path::PathBuf, sync::atomic::Ordering, time::Duration}; +use std::{cell::OnceCell, collections::HashMap, path::PathBuf, sync::{atomic::Ordering, Arc}, time::Duration}; use common::{ControlPacket, TelemetryPacket}; -use eframe::{egui::{self, containers, Align2, Checkbox, Context, IconData, Id, ImageSource, Label}, Storage}; +use eframe::{egui::{self, containers, Align2, Checkbox, Context, IconData, Id, ImageSource, Label, Ui}, Storage}; use image::ImageFormat; use tokio::{runtime::Runtime, sync::{mpsc, watch::Receiver}}; use egui_toast::{Toast, Toasts}; -use crate::{storage_dir::storage_dir, POWER_THRESHOLD}; +use crate::{auto::Configurable, storage_dir::storage_dir, POWER_THRESHOLD}; pub const GUI: OnceCell = OnceCell::new(); @@ -88,6 +87,18 @@ impl GUI { } } +// dupe from auto crate for testing +const AUTO_GAP: Configurable = Configurable::new("auto minimum gap").range(0. .. 300.).default(140.) + .description("distance (mm) distance measurements must instantaneously drop to indicate a detection. This should line up with the size of the smallest robot you compete against"); +const AUTO_SELF_OCCLUSION: Configurable = Configurable::new("auto self occlusion").range(0. .. 200.).default(143.) + .description("distance (mm) below which measurements are considered noise in the scan phase"); + +#[unsafe(no_mangle)] +pub static CONFIGS: &[Configurable] = &[ + AUTO_GAP, + AUTO_SELF_OCCLUSION, +]; + impl eframe::App for GUI { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { let _ = GUI.set(ctx.clone()); @@ -110,6 +121,10 @@ impl eframe::App for GUI { storage.set_string("selected_auto", format!("{}",self.selected_auto)); POWER_THRESHOLD.store(self.volume_threshold, Ordering::Relaxed); + + for conf in CONFIGS { + configurator(ui, conf, storage); + } }); egui::CentralPanel::default().show(ctx, |ui| { @@ -144,3 +159,19 @@ impl eframe::App for GUI { } } } + +fn configurator(ui: &mut Ui, config: &Configurable, map: &mut dyn Storage) { + ui.add(egui::Slider::from_get_set(config.min as f64 ..= config.max as f64, |value| { + match value { + Some(value) => { + map.set_string(&config.name,format!("{value}")); + value + }, + None => map.get_string(&config.name).map(|s| s.parse().ok()).flatten().unwrap_or(config.default as f64), + } + + }).text(config.name)); + if let Some(description) = config.description { + ui.label(description); + } +}