From 5b4f2ac984a620c865d8bafc3bccb5e2a5c4ce16 Mon Sep 17 00:00:00 2001 From: vasilito Date: Tue, 7 Jul 2026 19:55:40 +0300 Subject: [PATCH] =?UTF-8?q?USB:=20P3=20=E2=80=94=20wire=20scheme=20into=20?= =?UTF-8?q?main=20loop=20for=20ecmd=20+=20usbaudiod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit redbear-ecmd: scheme loop replaces stdout on Redox (/scheme/net/usbECM_), notification reader kept for CDC link state / speed change events on both paths. redbear-usbaudiod: scheme loop replaces stdout on Redox (/scheme/audio/usbAudio_), stdin→isoch_OUT playback thread kept for host stdout path only. All 4 class drivers now fully wired: acmd → scheme event loop active on Redox ✅ ftdi → scheme event loop active on Redox ✅ ecmd → scheme event loop active on Redox ✅ usbaudiod → scheme event loop active on Redox ✅ --- .../system/redbear-ecmd/source/src/main.rs | 88 +++++++++++-------- .../redbear-usbaudiod/source/src/main.rs | 35 +++++--- 2 files changed, 77 insertions(+), 46 deletions(-) diff --git a/local/recipes/system/redbear-ecmd/source/src/main.rs b/local/recipes/system/redbear-ecmd/source/src/main.rs index fda4cb00b9..5ef943dcec 100644 --- a/local/recipes/system/redbear-ecmd/source/src/main.rs +++ b/local/recipes/system/redbear-ecmd/source/src/main.rs @@ -168,67 +168,83 @@ fn main() { log::info!("CDC ECM ready on {} port {} — bulk_in={} bulk_out={} int={} filter={:04X}", scheme, port_id, bulk_in_num, bulk_out_num, int_num, filter); - // Spawn stdin→bulk OUT writer thread for Ethernet Tx. + // ── Scheme IPC path (Redox) ── + #[cfg(target_os = "redox")] + { + use redox_scheme::scheme::SchemeSync; + use redox_scheme::{Socket, SignalBehavior}; + let scheme_name = format!("net/usbECM_{}", port_id); + log::info!("ECM: registering /scheme/{}", scheme_name); + let socket = Socket::create().expect("ECM: scheme socket"); + let mut scheme_state = redox_scheme::scheme::SchemeState::new(); + let mut ecm_scheme = crate::scheme::EcmScheme::new(dev.bulk_in, dev.bulk_out); + socket.register(&scheme_name).expect("ECM: scheme register"); + if let Some(mut int_ep) = dev.int_ep { + thread::spawn(move || { + let mut buf = [0u8; 16]; + loop { + match int_ep.transfer_read(&mut buf) { + Ok(s) if s.bytes_transferred >= 8 => { + let b = buf[1]; + match b { + CDC_NOTIFY_NETWORK_CONNECTION => log::info!("ECM: link {}", if u16::from_le_bytes([buf[2],buf[3]]) != 0 { "UP" } else { "DOWN" }), + CDC_NOTIFY_SPEED_CHANGE => log::info!("ECM: speed up={} down={}", u32::from_le_bytes([buf[8],buf[9],buf[10],buf[11]]), u32::from_le_bytes([buf[12],buf[13],buf[14],buf[15]])), + _ => log::debug!("ECM: notify type={:02X}", b), + } + } + Ok(_) => {} + Err(e) => log::warn!("ECM: int: {}", e), + } + thread::sleep(time::Duration::from_millis(100)); + } + }); + } + loop { + let req = socket.next_request(SignalBehavior::Restart).expect("ECM: scheme request"); + if let Err(e) = req.handle_scheme_mut(&mut ecm_scheme, &mut scheme_state) { + log::warn!("ECM: scheme error: {}", e); + } + } + } + + // ── Stdout path (host/Linux testing) ── + #[cfg(not(target_os = "redox"))] + { let mut bulk_out = dev.bulk_out; let _tx_thread = thread::spawn(move || { let mut buf = [0u8; 2048]; loop { match io::stdin().read(&mut buf) { - Ok(0) => break, - Ok(n) => { let _ = bulk_out.transfer_write(&buf[..n]); } + Ok(0) => break, Ok(n) => { let _ = bulk_out.transfer_write(&buf[..n]); } Err(e) => { log::warn!("ECM: stdin: {}", e); break; } } } }); - - // Optional: spawn notification reader for network connection / speed changes. if let Some(mut int_ep) = dev.int_ep { thread::spawn(move || { let mut buf = [0u8; 16]; loop { match int_ep.transfer_read(&mut buf) { - Ok(status) if status.bytes_transferred >= 8 => { - let bm_request_type = buf[0]; - let b_notification = buf[1]; - let w_value = u16::from_le_bytes([buf[2], buf[3]]); - let w_index = u16::from_le_bytes([buf[4], buf[5]]); - let w_length = u16::from_le_bytes([buf[6], buf[7]]); - match b_notification { - CDC_NOTIFY_NETWORK_CONNECTION => { - let connected = w_value != 0; - log::info!("ECM: network connection: {}", if connected { "UP" } else { "DOWN" }); - } - CDC_NOTIFY_SPEED_CHANGE => { - let up: u32 = u32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]); - let down: u32 = u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]); - log::info!("ECM: speed change: up={}bps down={}bps", up, down); - } - _ => { - log::debug!("ECM: notification type={:02X} request_type={:02X} value={:04X} index={:04X} len={}", - b_notification, bm_request_type, w_value, w_index, w_length); - } + Ok(s) if s.bytes_transferred >= 8 => { + match buf[1] { + CDC_NOTIFY_NETWORK_CONNECTION => log::info!("ECM: link {}", if u16::from_le_bytes([buf[2],buf[3]]) != 0 { "UP" } else { "DOWN" }), + CDC_NOTIFY_SPEED_CHANGE => log::info!("ECM: speed up={} down={}", u32::from_le_bytes([buf[8],buf[9],buf[10],buf[11]]), u32::from_le_bytes([buf[12],buf[13],buf[14],buf[15]])), + _ => {} } } - Ok(_) => {} - Err(e) => log::warn!("ECM: interrupt: {}", e), + Ok(_) => {} Err(e) => log::warn!("ECM: int: {}", e), } thread::sleep(time::Duration::from_millis(100)); } }); } - - // Main loop: bulk IN → stdout (Ethernet Rx). let mut buf = [0u8; 2048]; loop { match dev.bulk_in.transfer_read(&mut buf) { - Ok(status) if status.bytes_transferred > 0 => { - let n = status.bytes_transferred as usize; - let _ = io::stdout().write_all(&buf[..n]); - let _ = io::stdout().flush(); - } - Ok(_) => {} - Err(e) => log::warn!("ECM: read: {}", e), + Ok(status) if status.bytes_transferred > 0 => { let _ = io::stdout().write_all(&buf[..status.bytes_transferred as usize]); let _ = io::stdout().flush(); } + Ok(_) => {} Err(e) => log::warn!("ECM: read: {}", e), } thread::sleep(time::Duration::from_millis(1)); } + } } diff --git a/local/recipes/system/redbear-usbaudiod/source/src/main.rs b/local/recipes/system/redbear-usbaudiod/source/src/main.rs index c0d8fa6a3c..3e02da7109 100644 --- a/local/recipes/system/redbear-usbaudiod/source/src/main.rs +++ b/local/recipes/system/redbear-usbaudiod/source/src/main.rs @@ -248,7 +248,28 @@ fn main() { let _ = dev.set_mute(0, false); log::info!("UAC: sample rate={} unmuted", sample_rate); - // Spawn stdin→isoch OUT writer thread for playback + // ── Scheme IPC path (Redox) ── + #[cfg(target_os = "redox")] + { + use redox_scheme::scheme::SchemeSync; + use redox_scheme::{Socket, SignalBehavior}; + let scheme_name = format!("audio/usbAudio_{}", port_id); + log::info!("UAC: registering /scheme/{}", scheme_name); + let socket = Socket::create().expect("UAC: scheme socket"); + let mut scheme_state = redox_scheme::scheme::SchemeState::new(); + let mut audio_scheme = crate::scheme::AudioScheme::new(dev.isoch_in, dev.isoch_out); + socket.register(&scheme_name).expect("UAC: scheme register"); + loop { + let req = socket.next_request(SignalBehavior::Restart).expect("UAC: scheme request"); + if let Err(e) = req.handle_scheme_mut(&mut audio_scheme, &mut scheme_state) { + log::warn!("UAC: scheme error: {}", e); + } + } + } + + // ── Stdout path (host/Linux testing) ── + #[cfg(not(target_os = "redox"))] + { let frame_size = dev.frame_size(); if let Some(isoch_out) = dev.isoch_out { let mut isoch_out = isoch_out; @@ -263,20 +284,14 @@ fn main() { } }); } - - // Main loop: isoch IN → stdout (recording) let buf_size = frame_size * 480; let mut buf = vec![0u8; buf_size]; loop { match dev.isoch_in.transfer_read(&mut buf) { - Ok(status) if status.bytes_transferred > 0 => { - let n = status.bytes_transferred as usize; - let _ = io::stdout().write_all(&buf[..n]); - let _ = io::stdout().flush(); - } - Ok(_) => {} - Err(e) => log::warn!("UAC: read: {}", e), + Ok(s) if s.bytes_transferred > 0 => { let _ = io::stdout().write_all(&buf[..s.bytes_transferred as usize]); let _ = io::stdout().flush(); } + Ok(_) => {} Err(e) => log::warn!("UAC: read: {}", e), } thread::sleep(time::Duration::from_millis(1)); } + } }