autd3_rs/datagram/
frame.rs1use 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}