diff --git a/interface/Cargo.lock b/interface/Cargo.lock index d4ba41f..f61a546 100644 --- a/interface/Cargo.lock +++ b/interface/Cargo.lock @@ -1571,12 +1571,48 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -1625,6 +1661,7 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -2179,6 +2216,7 @@ dependencies = [ "home", "image", "libloading", + "ping-rs", "pitch-detection", "postcard", "rust-music-theory", @@ -2470,6 +2508,18 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + [[package]] name = "mio" version = "1.0.3" @@ -3049,6 +3099,19 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "ping-rs" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d873f038f84371f9c7fa13f6afea4d5f1fbcd5070ba8eb7af2a6d41c768eff8b" +dependencies = [ + "futures", + "mio 0.8.11", + "paste", + "socket2 0.4.10", + "windows 0.43.0", +] + [[package]] name = "piper" version = "0.2.4" @@ -3671,6 +3734,16 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.8" @@ -3926,11 +3999,11 @@ dependencies = [ "backtrace", "bytes", "libc", - "mio", + "mio 1.0.3", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -4515,6 +4588,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows" version = "0.54.0" @@ -4632,6 +4720,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 938e360..42161cc 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -25,3 +25,4 @@ libloading = "0.8.6" emath = "0.31.1" dashmap = { version = "6.1.0", features = ["serde"] } directories = "6.0.0" +ping-rs = "0.1.2" diff --git a/interface/src/gui.rs b/interface/src/gui.rs index 09f1a1e..44416e5 100644 --- a/interface/src/gui.rs +++ b/interface/src/gui.rs @@ -6,11 +6,11 @@ use image::ImageFormat; use tokio::{runtime::Runtime, sync::{mpsc, watch::{self, Receiver}}}; use egui_toast::{Toast, Toasts}; -use crate::{auto::Configurable, auto_impl::CONFIGS, storage::StorageManager, POWER_THRESHOLD, RECONNECT}; +use crate::{auto::Configurable, auto_impl::CONFIGS, storage::StorageManager, PingData, POWER_THRESHOLD, RECONNECT}; pub const GUI: OnceCell = OnceCell::new(); -pub fn gui(data: Receiver, toasts: mpsc::Receiver, executor: Runtime, autoconf: watch::Receiver<&'static [Configurable]>, storage: StorageManager, auto_allowed: Arc, auto_enabled: Arc) -> eframe::Result { +pub fn gui(data: Receiver, toasts: mpsc::Receiver, executor: Runtime, autoconf: watch::Receiver<&'static [Configurable]>, storage: StorageManager, auto_allowed: Arc, auto_enabled: Arc, ping: PingData) -> eframe::Result { let icon = egui::include_image!("../assets/lizard.png"); let icon = image::load_from_memory_with_format(include_bytes!("../assets/lizard.png"), ImageFormat::Png).unwrap(); @@ -35,7 +35,7 @@ pub fn gui(data: Receiver, toasts: mpsc::Receiver, executor: Run // This gives us image support: egui_extras::install_image_loaders(&cc.egui_ctx); - Ok(Box::new(GUI::with_receivers(data, toasts, executor, storage, autoconf, auto_allowed, auto_enabled))) + Ok(Box::new(GUI::with_receivers(data, toasts, executor, storage, autoconf, auto_allowed, auto_enabled, ping))) }), ) } @@ -65,10 +65,11 @@ struct GUI { storage: StorageManager, auto_allowed: Arc, auto_enabled: Arc, + ping: PingData, } impl GUI { - fn with_receivers(data: Receiver, toasts: mpsc::Receiver, executor: Runtime, storage: StorageManager, autoconf: watch::Receiver<&'static [Configurable]>, auto_allowed: Arc, auto_enabled: Arc) -> Self { + fn with_receivers(data: Receiver, toasts: mpsc::Receiver, executor: Runtime, storage: StorageManager, autoconf: watch::Receiver<&'static [Configurable]>, auto_allowed: Arc, auto_enabled: Arc, ping: PingData) -> Self { Self { data, toasts, @@ -78,6 +79,7 @@ impl GUI { storage, auto_allowed, auto_enabled, + ping, } } } @@ -111,11 +113,21 @@ impl eframe::App for GUI { } } + if let Ok(ping) = self.ping.try_read() { + ui.horizontal(|ui| { + ui.label(format!("router: {}", if let Some(rtt) = ping.0 {format!("✅ {rtt}ms")} else {"❌".into()})); + ui.label(format!("robot: {}", if let Some(rtt) = ping.1 {format!("✅ {rtt}ms")} else {"❌".into()})); + }); + } + + if let Some(ref command) = self.data.borrow().last_command { ui.label(format!("sending {command:?}")); } - ui.label(format!("auto authorized: {}", if self.auto_allowed.load(Ordering::Acquire) {"✅"} else {"❌"})); - ui.label(format!("auto running: {}", if self.auto_enabled.load(Ordering::Acquire) {"✅ zoom vroom"} else {"❌"})); + ui.horizontal(|ui| { + ui.label(format!("auto authorized: {}", if self.auto_allowed.load(Ordering::Acquire) {"✅"} else {"❌"})); + ui.label(format!("auto running: {}", if self.auto_enabled.load(Ordering::Acquire) {"✅ zoom vroom"} else {"❌"})); + }); if let Some(ref telem) = self.data.borrow().telemetry { ui.label(format!("Left tof: {}", if let Some(tof) = telem.sensors.tof_l {format!("✅ {tof}mm")} else {"❌".into()})); diff --git a/interface/src/lib.rs b/interface/src/lib.rs index e6c0a5b..176b520 100644 --- a/interface/src/lib.rs +++ b/interface/src/lib.rs @@ -1,9 +1,10 @@ #![feature(iter_collect_into)] -use std::sync::atomic::AtomicBool; +use std::sync::{atomic::AtomicBool, Arc}; use atomic_float::AtomicF32; use gui::DEFAULT_VOLUME_THRESHOLD; +use tokio::sync::RwLock; pub mod gui; pub mod combatlog; @@ -14,3 +15,5 @@ pub mod storage; pub const POWER_THRESHOLD: AtomicF32 = AtomicF32::new(DEFAULT_VOLUME_THRESHOLD); pub static RECONNECT: AtomicBool = AtomicBool::new(false); + +pub type PingData = Arc, Option)>>; diff --git a/interface/src/main.rs b/interface/src/main.rs index 9bf7060..047e7b7 100644 --- a/interface/src/main.rs +++ b/interface/src/main.rs @@ -1,16 +1,16 @@ -use std::{fmt::format, ops::ControlFlow, path::Path, result, sync::{atomic::{AtomicBool, Ordering}, Arc}, thread::{self, sleep}, time::Duration}; +use std::{fmt::format, net::{IpAddr, Ipv4Addr}, ops::ControlFlow, path::Path, result, sync::{atomic::{AtomicBool, Ordering}, Arc}, thread::{self, sleep}, time::Duration}; use anyhow::{anyhow, Context, Ok, Result}; use atomic_float::AtomicF32; use directories::ProjectDirs; -use interface::{auto::{get_confs, Auto, AutoInterface}, auto_impl::{self, CONFIGS}, combatlog::{combat_logger, CombatData}, storage::StorageManager, POWER_THRESHOLD, RECONNECT}; +use interface::{auto::{get_confs, Auto, AutoInterface}, auto_impl::{self, CONFIGS}, combatlog::{combat_logger, CombatData}, storage::StorageManager, PingData, POWER_THRESHOLD, RECONNECT}; use common::{ControlPacket, TelemetryPacket}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use egui_toast::{Toast, ToastKind}; use interface::gui::{gui, GUIData, DEFAULT_VOLUME_THRESHOLD, GUI}; use pitch_detection::{detector::{mcleod::McLeodDetector, PitchDetector}, utils}; use rust_music_theory::note::{Note, NoteLetter, Pitch, Tuning}; -use tokio::{io::{AsyncReadExt, AsyncWriteExt, BufWriter, WriteHalf}, net::{tcp::{OwnedReadHalf, OwnedWriteHalf}, TcpStream}, spawn, sync::{self, broadcast, mpsc, watch, RwLock}, time::timeout}; +use tokio::{io::{AsyncReadExt, AsyncWriteExt, BufWriter, WriteHalf}, join, net::{tcp::{OwnedReadHalf, OwnedWriteHalf}, TcpStream}, spawn, sync::{self, broadcast, mpsc, watch, RwLock}, time::{sleep_until, timeout, Instant}}; fn main() -> Result<()> { @@ -24,6 +24,8 @@ fn main() -> Result<()> { let (auto_telem_sender, auto_telem) = watch::channel(TelemetryPacket::default()); let (interface, _auto_command, auto_enabled) = AutoInterface::new(auto_telem.clone(), storage.clone(), auto_allowed.clone()); + let ping: PingData = Arc::new(RwLock::new((None, None))); + println!("name: {}", auto.name()); for config in auto.configs().iter() { @@ -101,8 +103,42 @@ fn main() -> Result<()> { let spawner = executor.handle().clone(); let auto_allowed_ = auto_allowed.clone(); let interface_ = interface.clone(); + let ping_ = ping.clone(); thread::spawn(move || { spawner.block_on(async { + tokio::spawn(async move { + let robot: IpAddr = "192.168.1.2".parse().unwrap(); + let router: IpAddr = "192.168.1.1".parse().unwrap(); + + loop { + let start = Instant::now(); + let (robot, router) = join!( + ping_rs::send_ping_async(&robot, + Duration::from_millis(250), + Arc::new(&[0,1,2,3]), + None, + ), + ping_rs::send_ping_async(&router, + Duration::from_millis(250), + Arc::new(&[0,1,2,3]), + None, + ), + ); + + let robot = robot.ok().map(|r| r.rtt); + let router = router.ok().map(|r| r.rtt); + + let mut ping = ping_.write().await; + + ping.0 = router; + ping.1 = robot; + + drop(ping); + + sleep_until(start + Duration::from_millis(500)).await; + + } + }); let log_toasts = toast_sender.clone(); tokio::spawn(async move { @@ -134,7 +170,7 @@ fn main() -> Result<()> { println!("launching gui"); let (_conf_sender, conf) = watch::channel(CONFIGS); - gui(gui_data, toasts, executor, conf, storage.clone(), auto_allowed, auto_enabled).unwrap(); + gui(gui_data, toasts, executor, conf, storage.clone(), auto_allowed, auto_enabled, ping.clone()).unwrap(); drop(stream);