hwcheck.rs (3107B)
1 //! Headless hardware check for Valentine's core ops (the TUI needs a real TTY, 2 //! so this exercises scarlett-core directly). Read-modify-read-restore on a 3 //! couple of safe controls, plus a meter snapshot. Run with Focusrite Control 4 //! quit: cargo run -p spike --bin hwcheck 5 //! 6 //! It is careful: it records each switch's original value and restores it, so 7 //! your device ends up exactly as it started. 8 9 use scarlett_core::controls::InputSwitch; 10 use scarlett_core::model::S18I20_GEN3; 11 use scarlett_core::{Scarlett, UsbTransport}; 12 13 fn main() { 14 if let Err(e) = run() { 15 eprintln!("\x1b[31mHWCHECK FAILED:\x1b[0m {e}"); 16 eprintln!("(If access/busy: quit Focusrite Control first.)"); 17 std::process::exit(1); 18 } 19 } 20 21 fn run() -> Result<(), Box<dyn std::error::Error>> { 22 let mut dev = Scarlett::new(UsbTransport::open_default()?); 23 let fw = dev.init()?; 24 println!("connected: {} firmware {}", S18I20_GEN3.name, fw); 25 println!("clock locked: {}", dev.get_sync()?); 26 27 // --- Read the full input strip --- 28 let before = dev.read_input_state()?; 29 println!("\ninput strip read back:"); 30 println!(" air: {:?}", before.air); 31 println!(" pad: {:?}", before.pad); 32 println!(" inst: {:?}", before.inst); 33 println!(" phantom: {:?}", before.phantom); 34 35 // --- Monitor + master volume --- 36 let mon = dev.read_monitor_state()?; 37 println!("\nmonitor: master {} dB, mute {}, dim {}", mon.master_db, mon.mute, mon.dim); 38 39 // --- Round-trip test: toggle AIR on input 1, verify, restore --- 40 let orig_air1 = dev.get_input_switch(InputSwitch::Air, 0)?; 41 println!("\nround-trip AIR input 1 (currently {orig_air1}):"); 42 dev.set_input_switch(InputSwitch::Air, 0, !orig_air1)?; 43 let flipped = dev.get_input_switch(InputSwitch::Air, 0)?; 44 println!(" after toggle -> {flipped} (expected {})", !orig_air1); 45 let ok_air = flipped == !orig_air1; 46 dev.set_input_switch(InputSwitch::Air, 0, orig_air1)?; // restore 47 let restored = dev.get_input_switch(InputSwitch::Air, 0)?; 48 println!(" restored -> {restored} (expected {orig_air1})"); 49 50 // --- Mixer: read bus A, report the first few crosspoints in dB --- 51 let inputs = S18I20_GEN3.mixer_inputs() as usize; 52 let bus0 = dev.get_mix(0, inputs)?; 53 let db: Vec<f32> = bus0 54 .iter() 55 .take(4) 56 .map(|&v| scarlett_core::matrix::mixer_value_to_db(v)) 57 .collect(); 58 println!("\nmix bus A, first 4 inputs (dB): {db:?}"); 59 60 // --- Meters snapshot --- 61 let meters = dev.get_meters(S18I20_GEN3.meter_count)?; 62 let peak = meters.iter().copied().max().unwrap_or(0); 63 let nonzero = meters.iter().filter(|&&m| m > 0).count(); 64 println!( 65 "\nmeters: {} points, {nonzero} nonzero, peak raw {peak}", 66 meters.len() 67 ); 68 69 let verdict = ok_air && restored == orig_air1; 70 if verdict { 71 println!("\n\x1b[32mHWCHECK PASSED\x1b[0m — read/write/restore all correct."); 72 } else { 73 println!("\n\x1b[33mHWCHECK INCOMPLETE\x1b[0m — air round-trip mismatch (see above)."); 74 } 75 Ok(()) 76 }