autd3-driver 38.1.0

AUTD3 driver
Documentation
mod boxed;

use autd3_core::gain::{Gain, GainCalculatorGenerator};
pub use boxed::BoxedGain;

#[cfg(test)]
pub mod tests {
    use std::collections::HashMap;

    use autd3_core::{
        derive::*,
        geometry::{Point3, UnitQuaternion},
    };

    use crate::datagram::with_segment::WithSegmentInspectionResult;

    #[derive(Gain, Clone, Debug)]
    pub struct TestGain {
        pub data: HashMap<usize, Vec<Drive>>,
    }

    impl TestGain {
        pub fn new<'a, FT: Fn(&'a Transducer) -> Drive, F: Fn(&'a Device) -> FT>(
            f: F,
            geometry: &'a Geometry,
        ) -> Self {
            Self {
                data: geometry
                    .iter()
                    .map(|dev| (dev.idx(), dev.iter().map(f(dev)).collect()))
                    .collect(),
            }
        }

        pub fn null() -> Self {
            Self {
                data: HashMap::new(),
            }
        }
    }

    pub struct Impl {
        data: Vec<Drive>,
    }

    impl GainCalculator<'_> for Impl {
        fn calc(&self, tr: &Transducer) -> Drive {
            self.data[tr.idx()]
        }
    }

    impl GainCalculatorGenerator<'_> for TestGain {
        type Calculator = Impl;

        fn generate(&mut self, device: &Device) -> Self::Calculator {
            Impl {
                data: self.data.remove(&device.idx()).unwrap(),
            }
        }
    }

    impl Gain<'_> for TestGain {
        type G = Self;

        fn init(
            self,
            _: &Geometry,
            _env: &Environment,
            _: &TransducerMask,
        ) -> Result<Self::G, GainError> {
            Ok(self)
        }
    }

    pub fn create_geometry(num_dev: usize, num_trans: usize) -> Geometry {
        Geometry::new(
            (0..num_dev)
                .map(|_| {
                    Device::new(
                        UnitQuaternion::identity(),
                        (0..num_trans)
                            .map(|_| Transducer::new(Point3::origin()))
                            .collect(),
                    )
                })
                .collect(),
        )
    }

    const NUM_TRANSDUCERS: usize = 2;

    #[rstest::rstest]
    #[case::serial(
        [
            (0, vec![Drive { phase: Phase(0x01), intensity: Intensity(0x01) }; NUM_TRANSDUCERS]),
            (1, vec![Drive { phase: Phase(0x02), intensity: Intensity(0x02) }; NUM_TRANSDUCERS])
        ].into_iter().collect(),
        2)]
    #[case::parallel(
        [
            (0, vec![Drive { phase: Phase(0x01), intensity: Intensity(0x01) }; NUM_TRANSDUCERS]),
            (1, vec![Drive { phase: Phase(0x02), intensity: Intensity(0x02) }; NUM_TRANSDUCERS]),
            (2, vec![Drive { phase: Phase(0x03), intensity: Intensity(0x03) }; NUM_TRANSDUCERS]),
            (3, vec![Drive { phase: Phase(0x04), intensity: Intensity(0x04) }; NUM_TRANSDUCERS]),
            (4, vec![Drive { phase: Phase(0x05), intensity: Intensity(0x05) }; NUM_TRANSDUCERS]),
        ].into_iter().collect(),
        5)]
    fn gain(
        #[case] expect: HashMap<usize, Vec<Drive>>,
        #[case] n: usize,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let geometry = create_geometry(n, NUM_TRANSDUCERS);

        let g = TestGain::new(
            |dev| {
                move |_| Drive {
                    phase: Phase(dev.idx() as u8 + 1),
                    intensity: Intensity(dev.idx() as u8 + 1),
                }
            },
            &geometry,
        );
        let mut f = g.init(&geometry, &Environment::new(), &TransducerMask::AllEnabled)?;
        assert_eq!(
            expect,
            geometry
                .iter()
                .map(|dev| {
                    let f = f.generate(dev);
                    (dev.idx(), dev.iter().map(|tr| f.calc(tr)).collect())
                })
                .collect()
        );

        Ok(())
    }

    #[test]
    fn inspect() -> Result<(), Box<dyn std::error::Error>> {
        let geometry = create_geometry(2, 1);

        TestGain::new(
            |_dev| {
                |_| Drive {
                    phase: Phase(0xFF),
                    intensity: Intensity(0xFF),
                }
            },
            &geometry,
        )
        .inspect(&geometry, &Environment::default(), &DeviceMask::AllEnabled)?
        .iter()
        .for_each(|r| {
            assert_eq!(
                &Some(GainInspectionResult {
                    data: vec![
                        Drive {
                            phase: Phase(0xFF),
                            intensity: Intensity(0xFF),
                        };
                        1
                    ],
                }),
                r
            );
        });

        Ok(())
    }

    #[test]
    fn inspect_with_segment() -> Result<(), Box<dyn std::error::Error>> {
        let geometry = create_geometry(2, 1);

        crate::datagram::WithSegment {
            inner: TestGain::new(
                |_dev| {
                    |_| Drive {
                        phase: Phase(0xFF),
                        intensity: Intensity(0xFF),
                    }
                },
                &geometry,
            ),
            segment: Segment::S1,
            transition_mode: transition_mode::Later,
        }
        .inspect(&geometry, &Environment::default(), &DeviceMask::AllEnabled)?
        .iter()
        .for_each(|r| {
            assert_eq!(
                &Some(WithSegmentInspectionResult {
                    inner: GainInspectionResult {
                        data: vec![
                            Drive {
                                phase: Phase(0xFF),
                                intensity: Intensity(0xFF),
                            };
                            1
                        ],
                    },
                    segment: Segment::S1,
                    transition_mode: transition_mode::Later,
                }),
                r
            );
        });

        Ok(())
    }
}