//! The driver against the simulated instrument: command bytes, measurement //! sequences, supply handling, timeouts and cancellation. use hpcs6500::protocol::{self, cmd}; use hpcs6500::sim::Simulator; use hpcs6500::{Error, Hpcs6500, Mode}; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; fn dev() -> Hpcs6500 { Hpcs6500::with_transport(Simulator::sample(), "sim") } fn cmds(d: &Hpcs6500) -> Vec { d.transport().log.iter().map(|f| f[1]).collect() } #[test] fn identify_and_supply_commands() { let mut d = dev(); assert_eq!(d.identify().unwrap(), "HPCS6500"); d.set_mode(Mode::Dc).unwrap(); d.set_dc_voltage(12.0).unwrap(); d.set_dc_current(1.5).unwrap(); d.set_ac_voltage(230.0).unwrap(); d.set_ac_frequency(60.0).unwrap(); d.set_integration_time(500.0).unwrap(); let s = d.read_psu_settings().unwrap(); assert_eq!( ( s.mode, s.dc_voltage, s.dc_current, s.ac_voltage, s.ac_frequency ), (Mode::Dc, 12.0, 1.5, 230.0, 60.0) ); let log = &d.transport().log; assert_eq!(log[1], vec![0x8C, 0x7A, 0x01]); assert_eq!(log[2], protocol::frame_f32(cmd::SET_DC, 1, 12.0)); assert_eq!(log[3], protocol::frame_f32(cmd::SET_DC, 0, 1.5)); assert_eq!(log[6], vec![0x8C, 0x01, 0x20, 0xA1, 0x07, 0x00]); // 500 000 us d.psu_on().unwrap(); assert!(d.transport().output_on); d.psu_off().unwrap(); assert!(!d.transport().output_on); } #[test] fn single_reading_follows_the_vendor_sequence() { let mut d = dev(); d.send_test_config(false).unwrap(); let r = d.take_single_reading().unwrap(); assert_eq!(r.device, "HPCS6500"); assert!((r.flux_lm() - 483.7375).abs() < 1e-3); assert!(r.electrical.is_some()); // 2B 2B, trigger (0E 02), polls, 13, 77, reset let c = cmds(&d); assert_eq!(&c[..3], &[cmd::TEST_CONFIG, cmd::TEST_CONFIG, cmd::START]); assert_eq!(d.transport().log[2], vec![0x8C, 0x0E, 0x02]); assert!(c[3..c.len() - 3].iter().all(|&x| x == cmd::POLL_STATE)); assert_eq!( &c[c.len() - 3..], &[cmd::READ_MEASUREMENT, cmd::READ_ELECTRICAL, cmd::RESET] ); assert!(!d.transport().output_on, "the supply is not touched"); } #[test] fn continuous_reading_switches_the_supply_around_it() { let mut d = dev(); let r = d.take_reading(true).unwrap(); assert_eq!(r.spectrum.len(), 350); let c = cmds(&d); assert_eq!(c[0], cmd::PSU_OUTPUT); assert_eq!(d.transport().log[0], vec![0x8C, 0x72, 0x00]); assert_eq!(d.transport().log[1], vec![0x8C, 0x0E, 0x01]); assert_eq!( &c[c.len() - 4..], &[ cmd::READ_MEASUREMENT, cmd::READ_ELECTRICAL, cmd::START, cmd::PSU_OUTPUT ] ); assert_eq!(d.transport().log.last().unwrap(), &vec![0x8C, 0x72, 0x01]); assert!(!d.transport().output_on); } #[test] fn silent_instrument_times_out_and_the_supply_still_goes_off() { let mut d = dev(); d.transport_mut().mute = vec![cmd::POLL_STATE]; let mut sim = Simulator::sample(); sim.mute = vec![cmd::IDENTIFY]; let mut quiet = Hpcs6500::with_transport(sim, "sim"); let t = Instant::now(); assert!(matches!( quiet.identify(), Err(Error::BadResponse { cmd: 0, .. }) )); assert!(t.elapsed() >= Duration::from_secs(2) && t.elapsed() < Duration::from_secs(4)); // a reading whose data never arrives: cancel it instead of waiting 30 s let stop = Arc::new(AtomicBool::new(false)); d.set_cancel_flag(stop.clone()); let s2 = stop.clone(); std::thread::spawn(move || { std::thread::sleep(Duration::from_millis(300)); s2.store(true, Ordering::SeqCst); }); let t = Instant::now(); let r = d.take_reading(true); assert!(matches!(r, Err(Error::Cancelled)), "{r:?}"); assert!(t.elapsed() < Duration::from_secs(8)); assert!( !d.transport().output_on, "supply off after the failed reading" ); assert_eq!(d.transport().log.last().unwrap(), &vec![0x8C, 0x72, 0x01]); } #[test] fn missing_ack_is_an_error() { let mut sim = Simulator::sample(); sim.mute = vec![cmd::PSU_OUTPUT]; let mut d = Hpcs6500::with_transport(sim, "sim"); assert!(matches!(d.psu_on(), Err(Error::NoAck { cmd: 0x72, .. }))); } #[test] fn passive_read_and_replay_cycle_through_readings() { let mut sim = Simulator::sample(); sim.polls_to_ready = 0; let mut d = Hpcs6500::with_transport(sim, "sim"); let a = d.read_current().unwrap(); let b = d.take_single_reading().unwrap(); assert_eq!(a, b); assert_eq!(d.transport().served, 1); }