autd3-rs-core 0.9.0

Core types and link abstraction shared across the AUTD3 phased-array sdk crates.
Documentation
use crate::error::EncodeError;
use crate::params::{
    FOCUS_COORD_MAX_X, FOCUS_COORD_MAX_Y, FOCUS_COORD_MAX_Z, FOCUS_COORD_MIN_X, FOCUS_COORD_MIN_Y,
    FOCUS_COORD_MIN_Z,
};

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[doc(hidden)]
pub struct Focus {
    pub x: i32,
    pub y: i32,
    pub z: i32,
    pub intensity_or_offset: u8,
}

impl Focus {
    pub fn encode(self) -> Result<u64, EncodeError> {
        for (name, v, min, max) in [
            ("x", self.x, FOCUS_COORD_MIN_X, FOCUS_COORD_MAX_X),
            ("y", self.y, FOCUS_COORD_MIN_Y, FOCUS_COORD_MAX_Y),
            ("z", self.z, FOCUS_COORD_MIN_Z, FOCUS_COORD_MAX_Z),
        ] {
            if !(min..=max).contains(&v) {
                return Err(EncodeError::FocusOutOfRange {
                    axis: name,
                    value: v,
                    min,
                    max,
                });
            }
        }
        let mask = |v: i32| u64::from(u32::from_le_bytes(v.to_le_bytes())) & 0x3_FFFF;
        Ok(mask(self.x)
            | mask(self.y) << 18
            | mask(self.z) << 36
            | u64::from(self.intensity_or_offset) << 54)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn focus_encodes_legacy_bit_layout() {
        let f = Focus {
            x: -1,
            y: 2,
            z: -131_072,
            intensity_or_offset: 0xAB,
        };
        let v = f.encode().unwrap();
        assert_eq!(v & 0x3_FFFF, 0x3_FFFF, "x = -1 sign-extends to all ones");
        assert_eq!((v >> 18) & 0x3_FFFF, 2);
        assert_eq!((v >> 36) & 0x3_FFFF, 0x2_0000, "z = i18::MIN");
        assert_eq!((v >> 54) & 0xFF, 0xAB);
    }

    #[test]
    fn focus_x_y_lower_bound_is_narrowed() {
        use crate::params::{
            FOCUS_COORD_MIN, FOCUS_COORD_MIN_X, FOCUS_COORD_MIN_Y, FOCUS_COORD_MIN_Z,
        };

        const {
            assert!(FOCUS_COORD_MIN_X > FOCUS_COORD_MIN);
            assert!(FOCUS_COORD_MIN_Y > FOCUS_COORD_MIN);
            assert!(FOCUS_COORD_MIN_Z == FOCUS_COORD_MIN);
        }

        let at = |x, y, z| {
            Focus {
                x,
                y,
                z,
                intensity_or_offset: 0,
            }
            .encode()
        };

        assert!(at(FOCUS_COORD_MIN_X, 0, 0).is_ok());
        assert!(at(FOCUS_COORD_MIN_X - 1, 0, 0).is_err());
        assert!(at(0, FOCUS_COORD_MIN_Y, 0).is_ok());
        assert!(at(0, FOCUS_COORD_MIN_Y - 1, 0).is_err());
        assert!(at(0, 0, FOCUS_COORD_MIN_Z).is_ok());
        assert!(at(0, 0, FOCUS_COORD_MIN_Z - 1).is_err());
    }
}