Skip to main content

autd3_rs/datagram/
frame.rs

1use crate::client::MAX_DEVICES;
2use crate::commands::operation::{Distribution, Operation};
3use crate::error::{Error, PayloadError};
4use crate::geometry::Geometry;
5use crate::protocol::{Cmd, PAYLOAD_BYTES};
6
7use super::each::{each_encode, each_frames};
8
9#[derive(Clone, Debug)]
10pub struct Datagram {
11    pub cmd: Cmd,
12    pub payload: [u8; PAYLOAD_BYTES],
13}
14
15impl Datagram {
16    #[must_use]
17    pub const fn no_payload(cmd: Cmd) -> Self {
18        Self {
19            cmd,
20            payload: [0u8; PAYLOAD_BYTES],
21        }
22    }
23}
24
25#[derive(Clone, Copy, Debug)]
26pub struct Frame<'a> {
27    dist: Distribution,
28    datagrams: &'a [Datagram],
29}
30
31impl<'a> Frame<'a> {
32    #[must_use]
33    pub fn distribution(&self) -> Distribution {
34        self.dist
35    }
36
37    #[must_use]
38    pub fn datagrams(&self) -> &'a [Datagram] {
39        self.datagrams
40    }
41}
42
43fn encode_slots(
44    slots: &mut [Datagram],
45    mut encode: impl FnMut(usize, &mut [u8; PAYLOAD_BYTES]) -> Result<Cmd, Error>,
46) -> Result<(), Error> {
47    for (device, slot) in slots.iter_mut().enumerate() {
48        slot.cmd = encode(device, &mut slot.payload)?;
49    }
50    Ok(())
51}
52
53#[derive(Debug)]
54struct FrameDesc {
55    dist: Distribution,
56    start: usize,
57    len: usize,
58}
59
60#[derive(Debug, Default)]
61pub struct Frames {
62    pub(crate) payloads: Vec<Datagram>,
63    frames: Vec<FrameDesc>,
64}
65
66impl Frames {
67    #[must_use]
68    pub fn len(&self) -> usize {
69        self.frames.len()
70    }
71
72    #[must_use]
73    pub fn is_empty(&self) -> bool {
74        self.frames.is_empty()
75    }
76
77    #[must_use]
78    pub fn frame(&self, index: usize) -> Option<Frame<'_>> {
79        self.frames.get(index).map(|desc| Frame {
80            dist: desc.dist,
81            datagrams: &self.payloads[desc.start..desc.start + desc.len],
82        })
83    }
84
85    #[must_use]
86    pub fn iter(&self) -> FrameIter<'_> {
87        FrameIter {
88            frames: self,
89            index: 0,
90        }
91    }
92
93    pub(crate) fn clear(&mut self) {
94        self.payloads.clear();
95        self.frames.clear();
96    }
97
98    pub(crate) fn push_op<O: Operation + ?Sized>(
99        &mut self,
100        op: &O,
101        geometry: &Geometry,
102    ) -> Result<(), Error> {
103        if geometry.is_empty() {
104            return Err(PayloadError::DeviceCountOutOfRange {
105                got: 0,
106                max: MAX_DEVICES,
107            }
108            .into());
109        }
110        let dist = op.distribution();
111        let encode_devices = match dist {
112            Distribution::Broadcast => 1,
113            Distribution::PerDevice => geometry.num_devices(),
114        };
115        let start = self.payloads.len();
116        self.payloads
117            .resize_with(start + encode_devices, || Datagram::no_payload(Cmd::Nop));
118        if let Err(e) = encode_slots(&mut self.payloads[start..], |device, payload| {
119            op.encode(&geometry[device], payload)
120        }) {
121            self.payloads.truncate(start);
122            return Err(e);
123        }
124        tracing::trace!(
125            cmd = ?self.payloads[start].cmd,
126            dist = ?dist,
127            devices = encode_devices,
128            "encoded frame"
129        );
130        self.frames.push(FrameDesc {
131            dist,
132            start,
133            len: encode_devices,
134        });
135        Ok(())
136    }
137
138    pub(crate) fn push_each_step(
139        &mut self,
140        devices: &[Vec<Box<dyn Operation + '_>>],
141        geometry: &Geometry,
142    ) -> Result<(), Error> {
143        let num_devices = geometry.num_devices();
144        for frame in 0..each_frames(devices) {
145            let start = self.payloads.len();
146            self.payloads
147                .resize_with(start + num_devices, || Datagram::no_payload(Cmd::Nop));
148            if let Err(e) = encode_slots(&mut self.payloads[start..], |device, payload| {
149                each_encode(devices, &geometry[device], frame, payload)
150            }) {
151                self.payloads.truncate(start);
152                return Err(e);
153            }
154            tracing::trace!(frame, devices = num_devices, "encoded each-step frame");
155            self.frames.push(FrameDesc {
156                dist: Distribution::PerDevice,
157                start,
158                len: num_devices,
159            });
160        }
161        Ok(())
162    }
163}
164
165pub struct FrameIter<'a> {
166    frames: &'a Frames,
167    index: usize,
168}
169
170impl<'a> Iterator for FrameIter<'a> {
171    type Item = Frame<'a>;
172
173    fn next(&mut self) -> Option<Frame<'a>> {
174        let frame = self.frames.frame(self.index)?;
175        self.index += 1;
176        Some(frame)
177    }
178}
179
180impl<'a> IntoIterator for &'a Frames {
181    type Item = Frame<'a>;
182    type IntoIter = FrameIter<'a>;
183
184    fn into_iter(self) -> FrameIter<'a> {
185        self.iter()
186    }
187}