diff --git a/autd3-driver/src/datagram/gain/boxed.rs b/autd3-driver/src/datagram/gain/boxed.rs index de4e46fd..22493f20 100644 --- a/autd3-driver/src/datagram/gain/boxed.rs +++ b/autd3-driver/src/datagram/gain/boxed.rs @@ -109,9 +109,11 @@ impl Gain for BoxedGain { }) } + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP } /// Trait to convert [`Gain`] to [`BoxedGain`]. diff --git a/autd3-driver/src/datagram/mod.rs b/autd3-driver/src/datagram/mod.rs index f51f1a79..2321ea20 100644 --- a/autd3-driver/src/datagram/mod.rs +++ b/autd3-driver/src/datagram/mod.rs @@ -60,8 +60,6 @@ use crate::{error::AUTDDriverError, firmware::operation::OperationGenerator}; #[cfg(test)] pub(crate) mod tests { - use autd3_core::datagram::DatagramOption; - use crate::firmware::operation::tests::create_device; use super::*; @@ -73,39 +71,4 @@ pub(crate) mod tests { .collect(), ) } - - #[derive(Debug)] - pub struct NullDatagram { - pub option: DatagramOption, - } - - pub struct NullOperationGenerator {} - - impl OperationGenerator for NullOperationGenerator { - type O1 = crate::firmware::operation::NullOp; - type O2 = crate::firmware::operation::NullOp; - - // GRCOV_EXCL_START - fn generate(&mut self, _device: &Device) -> (Self::O1, Self::O2) { - (Self::O1 {}, Self::O2 {}) - } - // GRCOV_EXCL_STOP - } - - impl Datagram for NullDatagram { - type G = NullOperationGenerator; - type Error = AUTDDriverError; - - fn operation_generator( - self, - _: &Geometry, - _: &DatagramOption, - ) -> Result { - Ok(NullOperationGenerator {}) - } - - fn option(&self) -> DatagramOption { - self.option - } - } } diff --git a/autd3-driver/src/datagram/silencer.rs b/autd3-driver/src/datagram/silencer.rs index 6528c6fc..5d600270 100644 --- a/autd3-driver/src/datagram/silencer.rs +++ b/autd3-driver/src/datagram/silencer.rs @@ -198,91 +198,40 @@ where } } -// #[cfg(test)] -// mod tests { -// use crate::{datagram::FociSTM, firmware::fpga::LoopBehavior, geometry::Point3}; +#[cfg(test)] +mod tests { -// use super::*; + use std::time::Duration; -// #[test] -// fn disable() { -// let s = Silencer::disable(); -// assert_eq!(1, s.config.intensity.get()); -// assert_eq!(1, s.config.phase.get()); -// assert!(s.config.strict_mode); -// assert_eq!(SilencerTarget::Intensity, s.target); -// } + use super::*; -// #[rstest::rstest] -// #[test] -// // #[case(true, 10, 10, true, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(false, 11, 10, true, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(false, 10, 11, true, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(true, 11, 10, false, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(true, 10, 11, false, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(true, 10, 10, true, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(false, 11, 10, true, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(false, 10, 11, true, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(true, 11, 10, false, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(true, 10, 11, false, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(true, 10, 10, true, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(false, 11, 10, true, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(true, 10, 11, true, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(true, 11, 10, false, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(true, 10, 11, false, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// fn fixed_completion_steps_is_valid( -// #[case] expect: bool, -// #[case] intensity: u16, -// #[case] phase: u16, -// #[case] strict_mode: bool, -// #[case] target: impl HasSamplingConfig, -// ) { -// let s = Silencer { -// config: FixedCompletionSteps { -// intensity: NonZeroU16::new(intensity).unwrap(), -// phase: NonZeroU16::new(phase).unwrap(), -// strict_mode, -// }, -// target: SilencerTarget::Intensity, -// }; -// assert_eq!(expect, s.is_valid(&target)); -// } + #[test] + fn disable() { + let s = Silencer::disable(); + assert_eq!(1, s.config.intensity.get()); + assert_eq!(1, s.config.phase.get()); + assert!(s.config.strict_mode); + assert_eq!(SilencerTarget::Intensity, s.target); + } -// #[cfg(not(feature = "dynamic_freq"))] -// #[rstest::rstest] -// #[test] -// // #[case(true, 10, 10, true, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(false, 11, 10, true, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(false, 10, 11, true, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(true, 11, 10, false, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(true, 10, 11, false, FociSTM::new(SamplingConfig::new(10).unwrap(), [Point3::origin()]).unwrap())] -// // #[case(true, 10, 10, true, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(false, 11, 10, true, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(false, 10, 11, true, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(true, 11, 10, false, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(true, 10, 11, false, GainSTM::new(SamplingConfig::new(10).unwrap(), [TestGain{ data: Default::default() }]).unwrap())] -// // #[case(true, 10, 10, true, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(false, 11, 10, true, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(true, 10, 11, true, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(true, 11, 10, false, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // #[case(true, 10, 11, false, TestModulation { config: SamplingConfig::new(10).unwrap(), loop_behavior: LoopBehavior::Infinite })] -// // fn fixed_completion_time_is_valid( -// // #[case] expect: bool, -// // #[case] intensity: u32, -// // #[case] phase: u32, -// // #[case] strict_mode: bool, -// // #[case] target: impl HasSamplingConfig, -// // ) { -// // use crate::defined::ultrasound_period; + #[test] + fn fixed_completion_steps_default() { + let s: Silencer = Silencer::default(); + assert_eq!(10, s.config.intensity.get()); + assert_eq!(40, s.config.phase.get()); + assert!(s.config.strict_mode); + assert_eq!(SilencerTarget::Intensity, s.target); + } -// // let s = Silencer { -// // config: FixedCompletionTime { -// // intensity: intensity * ultrasound_period(), -// // phase: phase * ultrasound_period(), -// // strict_mode, -// // }, -// // target: SilencerTarget::Intensity, -// // }; -// // assert_eq!(expect, s.is_valid(&target)); -// // } -// } + #[test] + fn fixed_completion_time_default() { + let s: Silencer = Silencer { + config: Default::default(), + target: Default::default(), + }; + assert_eq!(Duration::from_micros(250), s.config.intensity); + assert_eq!(Duration::from_micros(1000), s.config.phase); + assert!(s.config.strict_mode); + assert_eq!(SilencerTarget::Intensity, s.target); + } +} diff --git a/autd3-gain-holo/src/combinatorial/greedy.rs b/autd3-gain-holo/src/combinatorial/greedy.rs index fe05dc65..2d94f73d 100644 --- a/autd3-gain-holo/src/combinatorial/greedy.rs +++ b/autd3-gain-holo/src/combinatorial/greedy.rs @@ -87,9 +87,11 @@ impl GainContextGenerator for ContextGenerator { impl Gain for Greedy { type G = ContextGenerator; + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP fn init_full( self, diff --git a/autd3-gain-holo/src/linear_synthesis/gs.rs b/autd3-gain-holo/src/linear_synthesis/gs.rs index 6b0e09f5..4669b98e 100644 --- a/autd3-gain-holo/src/linear_synthesis/gs.rs +++ b/autd3-gain-holo/src/linear_synthesis/gs.rs @@ -49,9 +49,11 @@ pub struct GS> { impl> Gain for GS { type G = HoloContextGenerator; + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP fn init_full( self, diff --git a/autd3-gain-holo/src/linear_synthesis/gspat.rs b/autd3-gain-holo/src/linear_synthesis/gspat.rs index d359b7a0..c9df3294 100644 --- a/autd3-gain-holo/src/linear_synthesis/gspat.rs +++ b/autd3-gain-holo/src/linear_synthesis/gspat.rs @@ -49,9 +49,11 @@ pub struct GSPAT> { impl> Gain for GSPAT { type G = HoloContextGenerator; + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP fn init_full( self, diff --git a/autd3-gain-holo/src/linear_synthesis/naive.rs b/autd3-gain-holo/src/linear_synthesis/naive.rs index 5f885d77..881046a0 100644 --- a/autd3-gain-holo/src/linear_synthesis/naive.rs +++ b/autd3-gain-holo/src/linear_synthesis/naive.rs @@ -44,9 +44,11 @@ pub struct Naive> { impl> Gain for Naive { type G = HoloContextGenerator; + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP fn init_full( self, diff --git a/autd3-modulation-audio-file/src/wav.rs b/autd3-modulation-audio-file/src/wav.rs index 55c40bfa..dba78803 100644 --- a/autd3-modulation-audio-file/src/wav.rs +++ b/autd3-modulation-audio-file/src/wav.rs @@ -230,6 +230,7 @@ mod tests { path: path.as_path(), option: WavOption::default(), }; + assert_eq!(spec.sample_rate, m.sampling_config()?.freq().hz() as u32); assert_eq!(Ok(expect), m.calc()); Ok(()) @@ -265,6 +266,7 @@ mod tests { } .with_resample(target, resampler)?; + assert_eq!(target, m.sampling_config()?.freq()); assert_eq!(expected, *m.calc()?); Ok(()) diff --git a/autd3/src/async/controller/group.rs b/autd3/src/async/controller/group.rs index 7b491565..7ec42980 100644 --- a/autd3/src/async/controller/group.rs +++ b/autd3/src/async/controller/group.rs @@ -277,7 +277,8 @@ mod tests { controller::tests::TestGain, gain::{Null, Uniform}, modulation::{Sine, Static}, - r#async::controller::tests::create_controller, + prelude::SenderOption, + r#async::{controller::tests::create_controller, AsyncSleeper}, }; #[tokio::test] @@ -379,6 +380,106 @@ mod tests { Ok(()) } + #[tokio::test] + async fn test_group_sender() -> anyhow::Result<()> { + let mut autd = create_controller(4).await?; + + autd.send(Uniform { + intensity: EmitIntensity(0xFF), + phase: Phase::ZERO, + }) + .await?; + + autd.sender(AsyncSleeper::default(), SenderOption::default()) + .group(|dev| match dev.idx() { + 0 | 1 | 3 => Some(dev.idx()), + _ => None, + }) + .set(0, Null {})? + .set(1, (Static { intensity: 0x80 }, Null {}))? + .set( + 3, + ( + Sine { + freq: 150. * Hz, + option: Default::default(), + }, + GainSTM { + gains: vec![ + Uniform { + intensity: EmitIntensity(0x80), + phase: Phase::ZERO, + }, + Uniform { + intensity: EmitIntensity(0x81), + phase: Phase::ZERO, + }, + ], + config: 1. * Hz, + option: Default::default(), + }, + ), + )? + .send() + .await?; + + assert_eq!( + vec![Drive::NULL; autd.geometry[0].num_transducers()], + autd.link[0].fpga().drives_at(Segment::S0, 0) + ); + + assert_eq!( + vec![Drive::NULL; autd.geometry[1].num_transducers()], + autd.link[1].fpga().drives_at(Segment::S0, 0) + ); + assert_eq!( + vec![0x80, 0x80], + autd.link[1].fpga().modulation_buffer(Segment::S0) + ); + + assert_eq!( + vec![ + Drive { + phase: Phase::ZERO, + intensity: EmitIntensity(0xFF) + }; + autd.geometry[2].num_transducers() + ], + autd.link[2].fpga().drives_at(Segment::S0, 0) + ); + + assert_eq!( + *Sine { + freq: 150. * Hz, + option: Default::default(), + } + .calc()?, + autd.link[3].fpga().modulation_buffer(Segment::S0) + ); + assert_eq!( + vec![ + Drive { + phase: Phase::ZERO, + intensity: EmitIntensity(0x80) + }; + autd.geometry[3].num_transducers() + ], + autd.link[3].fpga().drives_at(Segment::S0, 0) + ); + assert_eq!( + vec![ + Drive { + phase: Phase::ZERO, + intensity: EmitIntensity(0x81) + }; + autd.geometry[3].num_transducers() + ], + autd.link[3].fpga().drives_at(Segment::S0, 1) + ); + + Ok(()) + } + #[tokio::test] async fn test_send_failed() -> anyhow::Result<()> { let mut autd = create_controller(1).await?; diff --git a/autd3/src/async/controller/mod.rs b/autd3/src/async/controller/mod.rs index 1ca52630..88c7be6a 100644 --- a/autd3/src/async/controller/mod.rs +++ b/autd3/src/async/controller/mod.rs @@ -468,7 +468,7 @@ mod tests { Ok(()) } - #[tokio::test] + #[tokio::test(flavor = "multi_thread")] async fn close() -> anyhow::Result<()> { { let mut autd = create_controller(1).await?; diff --git a/autd3/src/controller/mod.rs b/autd3/src/controller/mod.rs index e2042ef4..5bd79a00 100644 --- a/autd3/src/controller/mod.rs +++ b/autd3/src/controller/mod.rs @@ -343,9 +343,11 @@ pub(crate) mod tests { impl Gain for TestGain { type G = Null; + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP fn init_full( self, diff --git a/autd3/src/datagram/gain/cache.rs b/autd3/src/datagram/gain/cache.rs index 966bb0e2..d11268ce 100644 --- a/autd3/src/datagram/gain/cache.rs +++ b/autd3/src/datagram/gain/cache.rs @@ -101,9 +101,11 @@ impl GainContextGenerator for Cache { impl Gain for Cache { type G = Self; + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP fn init_full( self, diff --git a/autd3/src/datagram/gain/group.rs b/autd3/src/datagram/gain/group.rs index 973d4597..304ef838 100644 --- a/autd3/src/datagram/gain/group.rs +++ b/autd3/src/datagram/gain/group.rs @@ -131,9 +131,11 @@ where { type G = ContextGenerator; + // GRCOV_EXCL_START fn init(self) -> Result { unimplemented!() } + // GRCOV_EXCL_STOP fn init_full( self, @@ -346,7 +348,14 @@ mod tests { .set("test", g1.into_boxed())? .set("test2", g2.into_boxed())?; - let mut g = gain.init_full(&geometry, None, &DatagramOption::default())?; + let mut g = gain.init_full( + &geometry, + None, + &DatagramOption { + parallel_threshold: 4, + ..Default::default() + }, + )?; let drives = geometry .devices() .map(|dev| { diff --git a/autd3/src/datagram/modulation/cache.rs b/autd3/src/datagram/modulation/cache.rs index 57947ce3..f0ed6e82 100644 --- a/autd3/src/datagram/modulation/cache.rs +++ b/autd3/src/datagram/modulation/cache.rs @@ -91,6 +91,7 @@ mod tests { assert!(cache.cache().borrow().is_empty()); + assert_eq!(m.sampling_config(), cache.sampling_config()); assert_eq!(m.calc()?, cache.calc()?); Ok(()) @@ -99,7 +100,6 @@ mod tests { #[derive(Modulation, Clone, Debug)] struct TestCacheModulation { pub calc_cnt: Arc, - pub config: SamplingConfig, } impl Modulation for TestCacheModulation { @@ -108,9 +108,11 @@ mod tests { Ok(vec![0x00, 0x00]) } + // GRCOV_EXCL_START fn sampling_config(&self) -> Result { - Ok(self.config) + unimplemented!() } + // GRCOV_EXCL_STOP } #[test] @@ -120,7 +122,6 @@ mod tests { let modulation = TestCacheModulation { calc_cnt: calc_cnt.clone(), - config: SamplingConfig::DIV_10, }; assert_eq!(0, calc_cnt.load(Ordering::Relaxed)); @@ -136,7 +137,6 @@ mod tests { let modulation = TestCacheModulation { calc_cnt: calc_cnt.clone(), - config: SamplingConfig::DIV_10, } .into_cached(); assert_eq!(0, calc_cnt.load(Ordering::Relaxed)); @@ -155,7 +155,6 @@ mod tests { let modulation = TestCacheModulation { calc_cnt: calc_cnt.clone(), - config: SamplingConfig::DIV_10, } .into_cached(); assert_eq!(1, modulation.count()); diff --git a/autd3/src/datagram/modulation/fourier.rs b/autd3/src/datagram/modulation/fourier.rs index f130ef50..d08ce25d 100644 --- a/autd3/src/datagram/modulation/fourier.rs +++ b/autd3/src/datagram/modulation/fourier.rs @@ -34,10 +34,16 @@ pub struct Fourier + Clone + Debug> { impl + Clone + Debug> Modulation for Fourier { fn sampling_config(&self) -> Result { - self.components[0].sampling_config() + self.components + .first() + .ok_or(ModulationError::new( + "Components must not be empty".to_string(), + ))? + .sampling_config() } fn calc(self) -> Result, ModulationError> { + let sampling_config = self.sampling_config()?; let components = self .components .into_iter() @@ -50,16 +56,10 @@ impl + Clone + Debug> Modulation for Fourier { }) .collect::>(); tracing::trace!("Fourier components: {:?}", components); - let config = components - .first() - .ok_or(ModulationError::new( - "Components must not be empty".to_string(), - ))? - .sampling_config(); if components .iter() .skip(1) - .any(|c| c.sampling_config() != config) + .any(|c| c.sampling_config() != Ok(sampling_config)) { return Err(ModulationError::new( "All components must have the same sampling configuration".to_string(), diff --git a/autd3/src/datagram/modulation/sine.rs b/autd3/src/datagram/modulation/sine.rs index 8dfb2c38..20601c3f 100644 --- a/autd3/src/datagram/modulation/sine.rs +++ b/autd3/src/datagram/modulation/sine.rs @@ -184,7 +184,7 @@ mod tests { assert_eq!(u8::MAX, m.option.intensity); assert_eq!(0x80, m.option.offset); assert_eq!(0. * rad, m.option.phase); - assert_eq!(SamplingConfig::DIV_10, m.option.sampling_config); + assert_eq!(Ok(SamplingConfig::DIV_10), m.sampling_config()); assert_eq!(expect, m.calc()); } @@ -213,7 +213,7 @@ mod tests { assert_eq!(u8::MAX, m.option.intensity); assert_eq!(0x80, m.option.offset); assert_eq!(0. * rad, m.option.phase); - assert_eq!(SamplingConfig::DIV_10, m.option.sampling_config); + assert_eq!(Ok(SamplingConfig::DIV_10), m.sampling_config()); assert_eq!(expect, m.calc()); } diff --git a/autd3/src/datagram/modulation/square.rs b/autd3/src/datagram/modulation/square.rs index 31dbba90..9ae0d75f 100644 --- a/autd3/src/datagram/modulation/square.rs +++ b/autd3/src/datagram/modulation/square.rs @@ -170,7 +170,7 @@ mod tests { assert_eq!(u8::MIN, m.option.low); assert_eq!(u8::MAX, m.option.high); assert_eq!(0.5, m.option.duty); - assert_eq!(SamplingConfig::DIV_10, m.option.sampling_config); + assert_eq!(Ok(SamplingConfig::DIV_10), m.sampling_config()); assert_eq!(expect, m.calc()); } @@ -187,7 +187,7 @@ mod tests { Ok(vec![255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), 200.*Hz )] - fn new_nearest(#[case] expect: Result, ModulationError>, #[case] freq: Freq) { + fn into_nearest(#[case] expect: Result, ModulationError>, #[case] freq: Freq) { let m = Square { freq, option: SquareOption::default(), @@ -196,8 +196,7 @@ mod tests { assert_eq!(u8::MIN, m.option.low); assert_eq!(u8::MAX, m.option.high); assert_eq!(0.5, m.option.duty); - assert_eq!(SamplingConfig::DIV_10, m.option.sampling_config); - + assert_eq!(Ok(SamplingConfig::DIV_10), m.sampling_config()); assert_eq!(expect, m.calc()); } diff --git a/autd3/src/datagram/stm/circle.rs b/autd3/src/datagram/stm/circle.rs index faf11a8e..e98c2ec9 100644 --- a/autd3/src/datagram/stm/circle.rs +++ b/autd3/src/datagram/stm/circle.rs @@ -214,6 +214,8 @@ mod tests { n, intensity: EmitIntensity::MAX, }; + assert_eq!(4, FociSTMGenerator::len(&circle)); + assert_eq!(4, GainSTMGenerator::len(&circle)); let device = autd3_driver::autd3_device::AUTD3::default().into_device(0); { diff --git a/autd3/src/datagram/stm/line.rs b/autd3/src/datagram/stm/line.rs index 0b66a50c..18c025d4 100644 --- a/autd3/src/datagram/stm/line.rs +++ b/autd3/src/datagram/stm/line.rs @@ -166,6 +166,8 @@ mod tests { num_points: 3, intensity: EmitIntensity::MAX, }; + assert_eq!(3, FociSTMGenerator::len(&line)); + assert_eq!(3, GainSTMGenerator::len(&line)); let expect = [ Point3::new(0., -length / 2., 0.),