autd3-rs 0.1.0

Core async client library for the AUTD3 phased-array kit.
Documentation
use crate::error::{Error, PayloadError};
use crate::geometry::Autd3;
use crate::protocol::{Cmd, PAYLOAD_BYTES};

use super::{Distribution, Operation};

#[derive(Clone, Copy, Debug)]
pub struct SetOutputMask<'a> {
    pub masks: &'a [Vec<bool>],
}

impl Operation for SetOutputMask<'_> {
    fn frames(&self) -> usize {
        1
    }

    fn distribution(&self) -> Distribution {
        Distribution::PerDevice
    }

    fn encode(
        &self,
        device: usize,
        _frame: usize,
        out: &mut [u8; PAYLOAD_BYTES],
    ) -> Result<Cmd, Error> {
        let mask = self.masks.get(device).ok_or(Error::InvalidPayload(
            PayloadError::EmissionsDeviceOutOfRange {
                device,
                len: self.masks.len(),
            },
        ))?;
        if mask.len() != Autd3::NUM_TRANSDUCERS {
            return Err(Error::InvalidPayload(
                PayloadError::TransducerCountMismatch {
                    device,
                    got: mask.len(),
                    expected: Autd3::NUM_TRANSDUCERS,
                },
            ));
        }
        for (i, &on) in mask.iter().enumerate() {
            if on {
                out[i / 8] |= 1 << (i % 8);
            }
        }
        Ok(Cmd::SetOutputMask)
    }
}

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

    #[test]
    fn output_mask_packs_bits() {
        let mut mask = vec![false; Autd3::NUM_TRANSDUCERS];
        mask[0] = true;
        mask[3] = true;
        mask[8] = true;
        mask[Autd3::NUM_TRANSDUCERS - 1] = true;
        let data = vec![mask];
        let mut out = [0u8; PAYLOAD_BYTES];
        let cmd = SetOutputMask { masks: &data }
            .encode(0, 0, &mut out)
            .unwrap();
        assert_eq!(cmd, Cmd::SetOutputMask);
        assert_eq!(out[0], 0b0000_1001);
        assert_eq!(out[1], 0b0000_0001);
        assert_eq!(
            out[(Autd3::NUM_TRANSDUCERS - 1) / 8],
            1 << ((Autd3::NUM_TRANSDUCERS - 1) % 8)
        );
    }

    #[test]
    fn output_mask_rejects_device_out_of_range() {
        let data = vec![vec![true; Autd3::NUM_TRANSDUCERS]];
        let mut out = [0u8; PAYLOAD_BYTES];
        assert!(matches!(
            SetOutputMask { masks: &data }.encode(1, 0, &mut out),
            Err(Error::InvalidPayload(_))
        ));
    }

    #[test]
    fn output_mask_rejects_wrong_transducer_count() {
        let data = vec![vec![true; Autd3::NUM_TRANSDUCERS + 1]];
        let mut out = [0u8; PAYLOAD_BYTES];
        assert!(matches!(
            SetOutputMask { masks: &data }.encode(0, 0, &mut out),
            Err(Error::InvalidPayload(
                PayloadError::TransducerCountMismatch { .. }
            ))
        ));
    }
}