diff --git a/cue/Cargo.lock b/cue/Cargo.lock index f6eed4f..74a4326 100644 --- a/cue/Cargo.lock +++ b/cue/Cargo.lock @@ -54,28 +54,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "alsa" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" -dependencies = [ - "alsa-sys", - "bitflags 2.11.0", - "cfg-if", - "libc", -] - -[[package]] -name = "alsa-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" -dependencies = [ - "libc", - "pkg-config", -] - [[package]] name = "android-activity" version = "0.6.0" @@ -639,27 +617,6 @@ dependencies = [ "libc", ] -[[package]] -name = "coremidi" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964eb3e10ea8b0d29c797086aab3ca730f75e06dced0cb980642fd274a5cca30" -dependencies = [ - "block", - "core-foundation", - "core-foundation-sys", - "coremidi-sys", -] - -[[package]] -name = "coremidi-sys" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9504310988d938e49fff1b5f1e56e3dafe39bb1bae580c19660b58b83a191e" -dependencies = [ - "core-foundation-sys", -] - [[package]] name = "cosmic-text" version = "0.12.1" @@ -764,7 +721,6 @@ dependencies = [ "dirs-next", "futures", "iced", - "midir", "muda", "rusqlite", "serde", @@ -1393,7 +1349,7 @@ dependencies = [ "presser", "thiserror 1.0.69", "winapi", - "windows 0.52.0", + "windows", ] [[package]] @@ -2013,23 +1969,6 @@ dependencies = [ "paste", ] -[[package]] -name = "midir" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73f8737248ad37b88291a2108d9df5f991dc8555103597d586b5a29d4d703c0" -dependencies = [ - "alsa", - "bitflags 1.3.2", - "coremidi", - "js-sys", - "libc", - "parking_lot 0.12.5", - "wasm-bindgen", - "web-sys", - "windows 0.56.0", -] - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -4222,17 +4161,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" -dependencies = [ - "windows-core 0.56.0", + "windows-core", "windows-targets 0.52.6", ] @@ -4245,55 +4174,12 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-implement" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-interface" -version = "0.56.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.45.0" diff --git a/cue/Cargo.toml b/cue/Cargo.toml index bb7185f..1cf210d 100644 --- a/cue/Cargo.toml +++ b/cue/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] iced = { version = "0.13", features = ["canvas", "tokio"] } -midir = "0.10" tokio = { version = "1", features = ["full"] } futures = "0.3" muda = { version = "0.17", default-features = false } diff --git a/cue/src/app.rs b/cue/src/app.rs index 71e56f8..4a5ffba 100644 --- a/cue/src/app.rs +++ b/cue/src/app.rs @@ -9,7 +9,6 @@ use std::fmt::Write; use std::time::Duration; use tokio::sync::mpsc; -use crate::ble::BleEvent; use crate::native_menu::{MenuAction, NativeMenu}; use crate::protocol::{ self, AmpPoint, ClPoint, ClResult, Electrode, EisMessage, EisPoint, LpRtia, LsvPoint, @@ -18,12 +17,6 @@ use crate::protocol::{ use crate::storage::{self, Session, Storage}; use crate::udp::UdpEvent; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum TransportMode { - Midi, - Udp, -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Tab { Eis, @@ -58,9 +51,9 @@ impl std::fmt::Display for SessionItem { #[derive(Debug, Clone)] pub enum Message { - BleReady(mpsc::UnboundedSender>), - BleStatus(String), - BleData(EisMessage), + DeviceReady(mpsc::UnboundedSender>), + DeviceStatus(String), + DeviceData(EisMessage), TabSelected(Tab), PaneResized(pane_grid::ResizeEvent), DataAction(text_editor::Action), @@ -132,9 +125,7 @@ pub enum Message { BrowseDeleteMeasurement(i64), BrowseBack, /* Misc */ - OpenMidiSetup, - RefreshMidi, - ToggleTransport, + Reconnect, UdpAddrChanged(String), } @@ -142,7 +133,7 @@ pub struct App { tab: Tab, status: String, cmd_tx: Option>>, - ble_connected: bool, + connected: bool, panes: pane_grid::State, native_menu: NativeMenu, show_sysinfo: bool, @@ -239,8 +230,7 @@ pub struct App { /* Global */ temp_c: f32, - midi_gen: u64, - transport: TransportMode, + conn_gen: u64, udp_addr: String, } @@ -379,7 +369,7 @@ impl App { tab: Tab::Eis, status: "Starting...".into(), cmd_tx: None, - ble_connected: false, + connected: false, panes: pane_grid::State::with_configuration(pane_grid::Configuration::Split { axis: pane_grid::Axis::Horizontal, ratio: 0.55, @@ -469,8 +459,7 @@ impl App { cal_cell_constant: None, temp_c: 25.0, - midi_gen: 0, - transport: TransportMode::Midi, + conn_gen: 0, udp_addr: crate::udp::load_addr(), }, Task::none()) } @@ -567,20 +556,20 @@ impl App { pub fn update(&mut self, message: Message) -> Task { match message { - Message::BleReady(tx) => { + Message::DeviceReady(tx) => { self.cmd_tx = Some(tx); - self.ble_connected = true; + self.connected = true; self.send_cmd(&protocol::build_sysex_get_config()); self.send_cmd(&protocol::build_sysex_get_cell_k()); } - Message::BleStatus(s) => { - if s.contains("Reconnecting") || s.contains("Looking") { - self.ble_connected = false; + Message::DeviceStatus(s) => { + if s.contains("Reconnecting") || s.contains("Connecting") { + self.connected = false; self.cmd_tx = None; } self.status = s; } - Message::BleData(msg) => match msg { + Message::DeviceData(msg) => match msg { EisMessage::SweepStart { num_points, freq_start, freq_stop } => { if self.collecting_refs { /* ref collection: clear temp buffer */ @@ -1079,30 +1068,11 @@ impl App { self.browse_measurements.clear(); } } - Message::OpenMidiSetup => { - let _ = std::process::Command::new("open") - .arg("-a") - .arg("Audio MIDI Setup") - .spawn(); - } - Message::RefreshMidi => { - self.midi_gen += 1; + Message::Reconnect => { + self.conn_gen += 1; self.cmd_tx = None; - self.ble_connected = false; - self.status = "Looking for MIDI device...".into(); - } - Message::ToggleTransport => { - self.transport = match self.transport { - TransportMode::Midi => TransportMode::Udp, - TransportMode::Udp => TransportMode::Midi, - }; - self.midi_gen += 1; - self.cmd_tx = None; - self.ble_connected = false; - self.status = match self.transport { - TransportMode::Midi => "Looking for MIDI device...".into(), - TransportMode::Udp => format!("Connecting UDP to {}...", self.udp_addr), - }; + self.connected = false; + self.status = format!("Connecting to {}...", self.udp_addr); } Message::UdpAddrChanged(s) => { self.udp_addr = s; @@ -1112,71 +1082,39 @@ impl App { } pub fn subscription(&self) -> Subscription { - let use_udp = self.transport == TransportMode::Udp; let udp_addr = self.udp_addr.clone(); let transport = Subscription::run_with_id( - self.midi_gen, + self.conn_gen, iced::stream::channel(100, move |mut output| async move { - if use_udp { - let addr = udp_addr.clone(); - loop { - let (udp_tx, mut udp_rx) = mpsc::unbounded_channel::(); - let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::>(); + let addr = udp_addr.clone(); + loop { + let (udp_tx, mut udp_rx) = mpsc::unbounded_channel::(); + let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::>(); - let tx = udp_tx.clone(); - let a = addr.clone(); - tokio::spawn(async move { - if let Err(e) = crate::udp::connect_and_run(tx, cmd_rx, a).await { - eprintln!("UDP: {e}"); - } - }); - - let mut ready_sent = false; - while let Some(ev) = udp_rx.recv().await { - let msg = match ev { - UdpEvent::Status(ref s) if s == "Connected" && !ready_sent => { - ready_sent = true; - let _ = output.send(Message::BleReady(cmd_tx.clone())).await; - Message::BleStatus(s.clone()) - } - UdpEvent::Status(s) => Message::BleStatus(s), - UdpEvent::Data(m) => Message::BleData(m), - }; - let _ = output.send(msg).await; + let tx = udp_tx.clone(); + let a = addr.clone(); + tokio::spawn(async move { + if let Err(e) = crate::udp::connect_and_run(tx, cmd_rx, a).await { + eprintln!("UDP: {e}"); } + }); - let _ = output.send(Message::BleStatus("Reconnecting UDP...".into())).await; - tokio::time::sleep(Duration::from_millis(500)).await; - } - } else { - loop { - let (ble_tx, mut ble_rx) = mpsc::unbounded_channel::(); - let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::>(); - - let tx = ble_tx.clone(); - tokio::spawn(async move { - if let Err(e) = crate::ble::connect_and_run(tx, cmd_rx).await { - eprintln!("BLE: {e}"); + let mut ready_sent = false; + while let Some(ev) = udp_rx.recv().await { + let msg = match ev { + UdpEvent::Status(ref s) if s == "Connected" && !ready_sent => { + ready_sent = true; + let _ = output.send(Message::DeviceReady(cmd_tx.clone())).await; + Message::DeviceStatus(s.clone()) } - }); - - let mut ready_sent = false; - while let Some(ev) = ble_rx.recv().await { - let msg = match ev { - BleEvent::Status(ref s) if s == "Connected" && !ready_sent => { - ready_sent = true; - let _ = output.send(Message::BleReady(cmd_tx.clone())).await; - Message::BleStatus(s.clone()) - } - BleEvent::Status(s) => Message::BleStatus(s), - BleEvent::Data(m) => Message::BleData(m), - }; - let _ = output.send(msg).await; - } - - let _ = output.send(Message::BleStatus("Reconnecting...".into())).await; - tokio::time::sleep(Duration::from_millis(500)).await; + UdpEvent::Status(s) => Message::DeviceStatus(s), + UdpEvent::Data(m) => Message::DeviceData(m), + }; + let _ = output.send(msg).await; } + + let _ = output.send(Message::DeviceStatus("Reconnecting...".into())).await; + tokio::time::sleep(Duration::from_millis(500)).await; } }), ); @@ -1208,14 +1146,6 @@ impl App { ] .spacing(4) .align_y(iced::Alignment::Center); - if self.transport == TransportMode::Midi { - tabs = tabs.push( - button(text("MIDI Setup").size(13)) - .style(style_neutral()) - .padding([6, 14]) - .on_press(Message::OpenMidiSetup), - ); - } tabs = tabs .push(iced::widget::horizontal_space()) .push(text("Clean").size(12)) @@ -1295,36 +1225,21 @@ impl App { ref_row = ref_row.push(text("REF").size(11)); } - let connected = self.ble_connected; - let transport_label = match self.transport { - TransportMode::Midi => "MIDI", - TransportMode::Udp => "UDP", - }; let mut status_row = row![text(&self.status).size(16)].spacing(6) .align_y(iced::Alignment::Center); status_row = status_row.push( - button(text(transport_label).size(11)) - .style(style_neutral()) - .padding([4, 10]) - .on_press(Message::ToggleTransport), + text_input("IP:port", &self.udp_addr) + .size(12) + .width(160) + .on_input(Message::UdpAddrChanged) + .on_submit(Message::Reconnect), + ); + status_row = status_row.push( + button(text("Reconnect").size(11)) + .style(style_apply()) + .padding([4, 10]) + .on_press(Message::Reconnect), ); - if self.transport == TransportMode::Udp { - status_row = status_row.push( - text_input("IP:port", &self.udp_addr) - .size(12) - .width(160) - .on_input(Message::UdpAddrChanged) - .on_submit(Message::ToggleTransport), // reconnect on enter - ); - } - if !connected && self.transport == TransportMode::Midi { - status_row = status_row.push( - button(text("Refresh MIDI").size(11)) - .style(style_apply()) - .padding([4, 10]) - .on_press(Message::RefreshMidi), - ); - } status_row = status_row .push(iced::widget::horizontal_space()) .push(ref_row) diff --git a/cue/src/ble.rs b/cue/src/ble.rs deleted file mode 100644 index 892d22e..0000000 --- a/cue/src/ble.rs +++ /dev/null @@ -1,93 +0,0 @@ -use midir::{MidiInput, MidiOutput, MidiInputConnection, MidiOutputConnection}; -use std::sync::mpsc as std_mpsc; -use tokio::sync::mpsc; - -use crate::protocol::{self, EisMessage}; - -const DEVICE_NAME: &str = "EIS4"; - -#[derive(Debug, Clone)] -pub enum BleEvent { - Status(String), - Data(EisMessage), -} - -pub async fn connect_and_run( - tx: mpsc::UnboundedSender, - mut cmd_rx: mpsc::UnboundedReceiver>, -) -> Result<(), Box> { - let _ = tx.send(BleEvent::Status("Looking for MIDI device...".into())); - - let (midi_in, in_port, midi_out, out_port) = loop { - if let Some(found) = find_midi_ports() { - break found; - } - tokio::time::sleep(std::time::Duration::from_millis(500)).await; - }; - - let _ = tx.send(BleEvent::Status("Connecting MIDI...".into())); - - let (sysex_tx, sysex_rx) = std_mpsc::channel::>(); - - let _in_conn: MidiInputConnection<()> = midi_in.connect( - &in_port, "cue-in", - move |_ts, data, _| { - if let Some(sysex) = extract_sysex(data) { - let _ = sysex_tx.send(sysex); - } - }, - (), - ).map_err(|e| format!("MIDI input connect: {e}"))?; - - let mut out_conn: MidiOutputConnection = midi_out.connect( - &out_port, "cue-out", - ).map_err(|e| format!("MIDI output connect: {e}"))?; - - let _ = tx.send(BleEvent::Status("Connected".into())); - - loop { - while let Ok(sysex) = sysex_rx.try_recv() { - if let Some(msg) = protocol::parse_sysex(&sysex) { - let _ = tx.send(BleEvent::Data(msg)); - } - } - - loop { - match cmd_rx.try_recv() { - Ok(pkt) => { - if let Err(e) = out_conn.send(&pkt) { - eprintln!("MIDI send error: {e}"); - } - } - Err(mpsc::error::TryRecvError::Disconnected) => return Ok(()), - Err(mpsc::error::TryRecvError::Empty) => break, - } - } - - tokio::time::sleep(std::time::Duration::from_millis(5)).await; - } -} - -fn find_midi_ports() -> Option<( - MidiInput, midir::MidiInputPort, - MidiOutput, midir::MidiOutputPort, -)> { - let midi_in = MidiInput::new("cue-in").ok()?; - let midi_out = MidiOutput::new("cue-out").ok()?; - - let in_port = midi_in.ports().into_iter().find(|p| { - midi_in.port_name(p).map_or(false, |n| n.contains(DEVICE_NAME)) - })?; - - let out_port = midi_out.ports().into_iter().find(|p| { - midi_out.port_name(p).map_or(false, |n| n.contains(DEVICE_NAME)) - })?; - - Some((midi_in, in_port, midi_out, out_port)) -} - -fn extract_sysex(data: &[u8]) -> Option> { - if data.first() != Some(&0xF0) { return None; } - let end = data.iter().position(|&b| b == 0xF7)?; - Some(data[1..end].to_vec()) -} diff --git a/cue/src/main.rs b/cue/src/main.rs index a062931..95fb1da 100644 --- a/cue/src/main.rs +++ b/cue/src/main.rs @@ -1,5 +1,4 @@ mod app; -mod ble; mod native_menu; mod plot; mod protocol;