autd3_driver/firmware/transmission/
sender.rs

1use std::time::{Duration, Instant};
2
3use super::SenderOption;
4use crate::{
5    error::AUTDDriverError,
6    firmware::{
7        cpu::{check_firmware_err, check_if_msg_is_processed},
8        operation::{Operation, OperationGenerator, OperationHandler},
9        version::FirmwareVersion,
10    },
11};
12
13use autd3_core::{
14    datagram::{Datagram, DeviceMask},
15    environment::Environment,
16    geometry::Geometry,
17    link::{Link, MsgId, RxMessage, TxMessage},
18    sleep::Sleeper,
19};
20
21/// A struct to send the [`Datagram`] to the devices.
22pub struct Sender<'a, L: Link, S: Sleeper> {
23    pub(crate) msg_id: &'a mut MsgId,
24    pub(crate) link: &'a mut L,
25    pub(crate) geometry: &'a Geometry,
26    pub(crate) sent_flags: &'a mut [bool],
27    pub(crate) rx: &'a mut [RxMessage],
28    pub(crate) env: &'a Environment,
29    pub(crate) option: SenderOption,
30    pub(crate) sleeper: S,
31}
32
33impl<'a, L: Link, S: Sleeper> Sender<'a, L, S> {
34    #[doc(hidden)]
35    #[allow(clippy::too_many_arguments)]
36    pub fn new(
37        msg_id: &'a mut autd3_core::link::MsgId,
38        link: &'a mut L,
39        geometry: &'a autd3_core::geometry::Geometry,
40        sent_flags: &'a mut [bool],
41        rx: &'a mut [autd3_core::link::RxMessage],
42        env: &'a Environment,
43        option: SenderOption,
44        sleeper: S,
45    ) -> Self {
46        Self {
47            msg_id,
48            link,
49            geometry,
50            sent_flags,
51            rx,
52            env,
53            option,
54            sleeper,
55        }
56    }
57
58    /// Send the [`Datagram`] to the devices.
59    pub fn send<D: Datagram<'a>>(&mut self, s: D) -> Result<(), AUTDDriverError>
60    where
61        AUTDDriverError: From<D::Error>,
62        D::G: OperationGenerator<'a>,
63        AUTDDriverError: From<<<D::G as OperationGenerator<'a>>::O1 as Operation<'a>>::Error>
64            + From<<<D::G as OperationGenerator<'a>>::O2 as Operation<'a>>::Error>,
65    {
66        let timeout = self.option.timeout.unwrap_or(s.option().timeout);
67        let parallel_threshold = s.option().parallel_threshold;
68
69        let mut g = s.operation_generator(self.geometry, self.env, &DeviceMask::AllEnabled)?;
70        let mut operations = self
71            .geometry
72            .iter()
73            .map(|dev| g.generate(dev))
74            .collect::<Vec<_>>();
75
76        self.send_impl(timeout, parallel_threshold, &mut operations)
77    }
78
79    #[doc(hidden)]
80    pub fn initialize_devices(mut self) -> Result<(), AUTDDriverError> {
81        const V12_1: u8 = 0xA5;
82
83        let r = self._initialize_devices();
84        if r.is_err()
85            && let Ok(list) = self.firmware_version()
86            && list.into_iter().all(|f| f.cpu.major.0 < V12_1)
87        {
88            return Err(AUTDDriverError::UnsupportedFirmware);
89        }
90        r
91    }
92
93    fn _initialize_devices(&mut self) -> Result<(), AUTDDriverError> {
94        use crate::datagram::{Clear, Nop, Synchronize};
95
96        // If the device is used continuously without powering off, the first data may be ignored because the first msg_id equals to the remaining msg_id in the device.
97        // Therefore, send a meaningless data.
98        self.send(Nop)?;
99
100        self.send((Clear::new(), Synchronize::new()))
101    }
102
103    #[doc(hidden)]
104    pub fn firmware_version(mut self) -> Result<Vec<FirmwareVersion>, AUTDDriverError> {
105        use crate::{
106            datagram::FirmwareVersionType::*,
107            firmware::version::{CPUVersion, FPGAVersion, Major, Minor},
108        };
109
110        let cpu_major = self.fetch_firminfo(CPUMajor)?;
111        let cpu_minor = self.fetch_firminfo(CPUMinor)?;
112        let fpga_major = self.fetch_firminfo(FPGAMajor)?;
113        let fpga_minor = self.fetch_firminfo(FPGAMinor)?;
114        let fpga_functions = self.fetch_firminfo(FPGAFunctions)?;
115        self.fetch_firminfo(Clear)?;
116
117        Ok(self
118            .geometry
119            .iter()
120            .map(|dev| FirmwareVersion {
121                idx: dev.idx(),
122                cpu: CPUVersion {
123                    major: Major(cpu_major[dev.idx()]),
124                    minor: Minor(cpu_minor[dev.idx()]),
125                },
126                fpga: FPGAVersion {
127                    major: Major(fpga_major[dev.idx()]),
128                    minor: Minor(fpga_minor[dev.idx()]),
129                    function_bits: fpga_functions[dev.idx()],
130                },
131            })
132            .collect())
133    }
134
135    #[doc(hidden)]
136    pub fn close(mut self) -> Result<(), AUTDDriverError> {
137        use crate::datagram::{
138            Clear, FixedCompletionSteps, Silencer,
139            implements::{Null, Static},
140        };
141
142        [
143            self.send(Silencer {
144                config: FixedCompletionSteps {
145                    strict: false,
146                    ..Default::default()
147                },
148            }),
149            self.send((Static::default(), Null)),
150            self.send(Clear {}),
151            Ok(self.link.close()?),
152        ]
153        .into_iter()
154        .try_fold((), |_, x| x)
155    }
156}
157
158impl<'a, L: Link, S: Sleeper> Sender<'a, L, S> {
159    pub(crate) fn send_impl<O1, O2>(
160        &mut self,
161        timeout: Duration,
162        parallel_threshold: usize,
163        operations: &mut [Option<(O1, O2)>],
164    ) -> Result<(), AUTDDriverError>
165    where
166        O1: Operation<'a>,
167        O2: Operation<'a>,
168        AUTDDriverError: From<O1::Error> + From<O2::Error>,
169    {
170        operations
171            .iter()
172            .zip(self.sent_flags.iter_mut())
173            .for_each(|(op, flag)| {
174                *flag = op.is_some();
175            });
176
177        let num_enabled = self.sent_flags.iter().filter(|x| **x).count();
178        let parallel = self
179            .option
180            .parallel
181            .is_parallel(num_enabled, parallel_threshold);
182
183        self.link.ensure_is_open()?;
184        self.link.update(self.geometry)?;
185
186        let mut send_timing = Instant::now();
187        loop {
188            let mut tx = self.link.alloc_tx_buffer()?;
189
190            self.msg_id.increment();
191            OperationHandler::pack(*self.msg_id, operations, self.geometry, &mut tx, parallel)?;
192
193            self.send_receive(tx, timeout)?;
194
195            if OperationHandler::is_done(operations) {
196                return Ok(());
197            }
198
199            if let Some(interval) = self.option.send_interval {
200                let next = send_timing + interval;
201                self.sleeper
202                    .sleep(next.saturating_duration_since(Instant::now()));
203                send_timing = next;
204            }
205        }
206    }
207
208    fn send_receive(
209        &mut self,
210        tx: Vec<TxMessage>,
211        timeout: Duration,
212    ) -> Result<(), AUTDDriverError> {
213        self.link.ensure_is_open()?;
214        self.link.send(tx)?;
215        self.wait_msg_processed(timeout)
216    }
217
218    fn wait_msg_processed(&mut self, timeout: Duration) -> Result<(), AUTDDriverError> {
219        let start = Instant::now();
220        let mut receive_timing = Instant::now();
221        loop {
222            self.link.ensure_is_open()?;
223            self.link.receive(self.rx)?;
224
225            if check_if_msg_is_processed(*self.msg_id, self.rx)
226                .zip(self.sent_flags.iter())
227                .filter_map(|(r, sent)| sent.then_some(r))
228                .all(std::convert::identity)
229            {
230                break;
231            }
232
233            if start.elapsed() > timeout {
234                return Err(AUTDDriverError::ConfirmResponseFailed);
235            }
236
237            if let Some(interval) = self.option.receive_interval {
238                let next = receive_timing + interval;
239                self.sleeper
240                    .sleep(next.saturating_duration_since(Instant::now()));
241                receive_timing = next;
242            }
243        }
244
245        self.rx
246            .iter()
247            .try_fold((), |_, r| check_firmware_err(r.ack()))
248    }
249
250    pub(crate) fn fetch_firminfo(
251        &mut self,
252        ty: crate::datagram::FirmwareVersionType,
253    ) -> Result<Vec<u8>, AUTDDriverError> {
254        self.send(ty).map_err(|_| {
255            AUTDDriverError::ReadFirmwareVersionFailed(
256                check_if_msg_is_processed(*self.msg_id, self.rx).collect(),
257            )
258        })?;
259        Ok(self.rx.iter().map(|rx| rx.data()).collect())
260    }
261}