autd3-rs 0.5.0

Core async client library for the AUTD3 phased-array kit.
Documentation
use crate::client::MAX_DEVICES;
use crate::commands::operation::{Distribution, Operation};
use crate::error::{Error, PayloadError};
use crate::geometry::Geometry;
use crate::protocol::{Cmd, PAYLOAD_BYTES};

use super::each::{each_encode, each_frames};

#[derive(Clone, Debug)]
pub struct Datagram {
    pub cmd: Cmd,
    pub payload: [u8; PAYLOAD_BYTES],
}

impl Datagram {
    #[must_use]
    pub const fn no_payload(cmd: Cmd) -> Self {
        Self {
            cmd,
            payload: [0u8; PAYLOAD_BYTES],
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Frame<'a> {
    dist: Distribution,
    datagrams: &'a [Datagram],
}

impl<'a> Frame<'a> {
    #[must_use]
    pub fn distribution(&self) -> Distribution {
        self.dist
    }

    #[must_use]
    pub fn datagrams(&self) -> &'a [Datagram] {
        self.datagrams
    }
}

fn encode_slots(
    slots: &mut [Datagram],
    mut encode: impl FnMut(usize, &mut [u8; PAYLOAD_BYTES]) -> Result<Cmd, Error>,
) -> Result<(), Error> {
    for (device, slot) in slots.iter_mut().enumerate() {
        slot.cmd = encode(device, &mut slot.payload)?;
    }
    Ok(())
}

#[derive(Debug)]
struct FrameDesc {
    dist: Distribution,
    start: usize,
    len: usize,
}

#[derive(Debug, Default)]
pub struct Frames {
    pub(crate) payloads: Vec<Datagram>,
    frames: Vec<FrameDesc>,
}

impl Frames {
    #[must_use]
    pub fn len(&self) -> usize {
        self.frames.len()
    }

    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.frames.is_empty()
    }

    #[must_use]
    pub fn frame(&self, index: usize) -> Option<Frame<'_>> {
        self.frames.get(index).map(|desc| Frame {
            dist: desc.dist,
            datagrams: &self.payloads[desc.start..desc.start + desc.len],
        })
    }

    #[must_use]
    pub fn iter(&self) -> FrameIter<'_> {
        FrameIter {
            frames: self,
            index: 0,
        }
    }

    pub(crate) fn clear(&mut self) {
        self.payloads.clear();
        self.frames.clear();
    }

    pub(crate) fn push_op<O: Operation + ?Sized>(
        &mut self,
        op: &O,
        geometry: &Geometry,
    ) -> Result<(), Error> {
        if geometry.is_empty() {
            return Err(PayloadError::DeviceCountOutOfRange {
                got: 0,
                max: MAX_DEVICES,
            }
            .into());
        }
        let dist = op.distribution();
        let encode_devices = match dist {
            Distribution::Broadcast => 1,
            Distribution::PerDevice => geometry.num_devices(),
        };
        let start = self.payloads.len();
        self.payloads
            .resize_with(start + encode_devices, || Datagram::no_payload(Cmd::Nop));
        if let Err(e) = encode_slots(&mut self.payloads[start..], |device, payload| {
            op.encode(&geometry[device], payload)
        }) {
            self.payloads.truncate(start);
            return Err(e);
        }
        tracing::trace!(
            cmd = ?self.payloads[start].cmd,
            dist = ?dist,
            devices = encode_devices,
            "encoded frame"
        );
        self.frames.push(FrameDesc {
            dist,
            start,
            len: encode_devices,
        });
        Ok(())
    }

    pub(crate) fn push_each_step(
        &mut self,
        devices: &[Vec<Box<dyn Operation + '_>>],
        geometry: &Geometry,
    ) -> Result<(), Error> {
        let num_devices = geometry.num_devices();
        for frame in 0..each_frames(devices) {
            let start = self.payloads.len();
            self.payloads
                .resize_with(start + num_devices, || Datagram::no_payload(Cmd::Nop));
            if let Err(e) = encode_slots(&mut self.payloads[start..], |device, payload| {
                each_encode(devices, &geometry[device], frame, payload)
            }) {
                self.payloads.truncate(start);
                return Err(e);
            }
            tracing::trace!(frame, devices = num_devices, "encoded each-step frame");
            self.frames.push(FrameDesc {
                dist: Distribution::PerDevice,
                start,
                len: num_devices,
            });
        }
        Ok(())
    }
}

pub struct FrameIter<'a> {
    frames: &'a Frames,
    index: usize,
}

impl<'a> Iterator for FrameIter<'a> {
    type Item = Frame<'a>;

    fn next(&mut self) -> Option<Frame<'a>> {
        let frame = self.frames.frame(self.index)?;
        self.index += 1;
        Some(frame)
    }
}

impl<'a> IntoIterator for &'a Frames {
    type Item = Frame<'a>;
    type IntoIter = FrameIter<'a>;

    fn into_iter(self) -> FrameIter<'a> {
        self.iter()
    }
}