autd3_driver/firmware/auto/
driver.rs

1use autd3_core::{link::Link, sleep::Sleep};
2
3use crate::{
4    error::AUTDDriverError,
5    firmware::driver::{Driver, FixedSchedule, Sender, TimerStrategy, Version},
6};
7
8use getset::CopyGetters;
9
10/// A driver with firmware version auto-detection.
11#[derive(CopyGetters)]
12pub struct Auto {
13    #[getset(get_copy = "pub")]
14    /// The estimated firmware version.
15    pub(crate) version: Version,
16}
17
18impl<'a, L: Link, S: Sleep, T: TimerStrategy<S>> Sender<'a, L, S, T>
19    for super::transmission::Sender<'a, L, S, T>
20{
21    fn initialize_devices(self) -> Result<(), crate::error::AUTDDriverError> {
22        match self.version {
23            Version::V10 => super::super::v10::V10
24                .sender(
25                    self.msg_id,
26                    self.link,
27                    self.geometry,
28                    self.sent_flags,
29                    self.rx,
30                    self.option,
31                    self.timer_strategy,
32                )
33                .initialize_devices(),
34            Version::V11 => super::super::v11::V11
35                .sender(
36                    self.msg_id,
37                    self.link,
38                    self.geometry,
39                    self.sent_flags,
40                    self.rx,
41                    self.option,
42                    self.timer_strategy,
43                )
44                .initialize_devices(),
45            Version::V12 => super::super::v12::V12
46                .sender(
47                    self.msg_id,
48                    self.link,
49                    self.geometry,
50                    self.sent_flags,
51                    self.rx,
52                    self.option,
53                    self.timer_strategy,
54                )
55                .initialize_devices(),
56        }
57    }
58
59    fn firmware_version(
60        self,
61    ) -> Result<Vec<crate::firmware::version::FirmwareVersion>, crate::error::AUTDDriverError> {
62        match self.version {
63            Version::V10 => super::super::v10::V10
64                .sender(
65                    self.msg_id,
66                    self.link,
67                    self.geometry,
68                    self.sent_flags,
69                    self.rx,
70                    self.option,
71                    self.timer_strategy,
72                )
73                .firmware_version(),
74            Version::V11 => super::super::v11::V11
75                .sender(
76                    self.msg_id,
77                    self.link,
78                    self.geometry,
79                    self.sent_flags,
80                    self.rx,
81                    self.option,
82                    self.timer_strategy,
83                )
84                .firmware_version(),
85            Version::V12 => super::super::v12::V12
86                .sender(
87                    self.msg_id,
88                    self.link,
89                    self.geometry,
90                    self.sent_flags,
91                    self.rx,
92                    self.option,
93                    self.timer_strategy,
94                )
95                .firmware_version(),
96        }
97    }
98
99    fn close(self) -> Result<(), crate::error::AUTDDriverError> {
100        match self.version {
101            Version::V10 => super::super::v10::V10
102                .sender(
103                    self.msg_id,
104                    self.link,
105                    self.geometry,
106                    self.sent_flags,
107                    self.rx,
108                    self.option,
109                    self.timer_strategy,
110                )
111                .close(),
112            Version::V11 => super::super::v11::V11
113                .sender(
114                    self.msg_id,
115                    self.link,
116                    self.geometry,
117                    self.sent_flags,
118                    self.rx,
119                    self.option,
120                    self.timer_strategy,
121                )
122                .close(),
123            Version::V12 => super::super::v12::V12
124                .sender(
125                    self.msg_id,
126                    self.link,
127                    self.geometry,
128                    self.sent_flags,
129                    self.rx,
130                    self.option,
131                    self.timer_strategy,
132                )
133                .close(),
134        }
135    }
136}
137
138impl Driver for Auto {
139    type Sender<'a, L, S, T>
140        = super::transmission::Sender<'a, L, S, T>
141    where
142        L: Link + 'a,
143        S: Sleep,
144        T: TimerStrategy<S>;
145    type FPGAState = super::super::latest::fpga::FPGAState;
146
147    fn new() -> Self {
148        Self {
149            version: Version::V12,
150        }
151    }
152
153    fn detect_version<'a, L>(
154        &mut self,
155        msg_id: &'a mut autd3_core::link::MsgId,
156        link: &'a mut L,
157        geometry: &'a autd3_core::derive::Geometry,
158        sent_flags: &'a mut [bool],
159        rx: &'a mut [autd3_core::link::RxMessage],
160    ) -> Result<(), AUTDDriverError>
161    where
162        L: autd3_core::link::Link + 'a,
163    {
164        let mut sender = self.sender(
165            msg_id,
166            link,
167            geometry,
168            sent_flags,
169            rx,
170            crate::firmware::driver::SenderOption {
171                timeout: Some(std::time::Duration::from_secs(1)),
172                ..Default::default()
173            },
174            FixedSchedule::default(),
175        );
176        let _ = sender.send(crate::datagram::ReadsFPGAState::new(|_| false));
177
178        let version_list = sender.firmware_version()?;
179        self.version = check_firmware_version(&version_list)?;
180
181        Ok(())
182    }
183
184    fn sender<'a, L, S, T>(
185        &self,
186        msg_id: &'a mut autd3_core::link::MsgId,
187        link: &'a mut L,
188        geometry: &'a autd3_core::derive::Geometry,
189        sent_flags: &'a mut [bool],
190        rx: &'a mut [autd3_core::link::RxMessage],
191        option: crate::firmware::driver::SenderOption,
192        timer_strategy: T,
193    ) -> Self::Sender<'a, L, S, T>
194    where
195        L: Link + 'a,
196        S: Sleep,
197        T: TimerStrategy<S>,
198    {
199        Self::Sender {
200            msg_id,
201            link,
202            geometry,
203            sent_flags,
204            rx,
205            option,
206            timer_strategy,
207            _phantom: std::marker::PhantomData,
208            version: self.version,
209            limits: self.firmware_limits(),
210        }
211    }
212
213    fn firmware_limits(&self) -> autd3_core::derive::FirmwareLimits {
214        match self.version {
215            Version::V10 => super::super::v10::V10.firmware_limits(),
216            Version::V11 => super::super::v11::V11.firmware_limits(),
217            Version::V12 => super::super::v12::V12.firmware_limits(),
218        }
219    }
220}
221
222fn check_firmware_version(
223    version_list: &[crate::firmware::version::FirmwareVersion],
224) -> Result<Version, AUTDDriverError> {
225    if version_list.is_empty() {
226        return Err(AUTDDriverError::FirmwareVersionMismatch);
227    }
228
229    let version = version_list[0];
230    if version_list
231        .iter()
232        .skip(1)
233        .any(|v| v.cpu.major != version.cpu.major || v.fpga.major != version.fpga.major)
234    {
235        return Err(AUTDDriverError::FirmwareVersionMismatch);
236    }
237
238    match version.cpu.major.0 {
239        0xA2..=0xA2 => Ok(Version::V10),
240        0xA3..=0xA3 => Ok(Version::V11),
241        0xA4..=0xA4 => Ok(Version::V12),
242        _ => Err(AUTDDriverError::UnsupportedFirmware),
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use super::*;
249
250    use crate::firmware::version::{CPUVersion, FPGAVersion, FirmwareVersion, Major, Minor};
251
252    #[rstest::rstest]
253    #[case::v10(
254        Ok(Version::V10),
255        vec![FirmwareVersion {
256            idx: 0,
257            cpu: CPUVersion {
258                major: Major(0xA2),
259                minor: Minor(0x00),
260            },
261            fpga: FPGAVersion {
262                major: Major(0xA2),
263                minor: Minor(0x00),
264                function_bits: 0,
265            },
266        }]
267    )]
268    #[case::v11(
269        Ok(Version::V11),
270        vec![FirmwareVersion {
271            idx: 0,
272            cpu: CPUVersion {
273                major: Major(0xA3),
274                minor: Minor(0x00),
275            },
276            fpga: FPGAVersion {
277                major: Major(0xA3),
278                minor: Minor(0x00),
279                function_bits: 0,
280            },
281        }]
282    )]
283    #[case::v12(
284        Ok(Version::V12),
285        vec![FirmwareVersion {
286            idx: 0,
287            cpu: CPUVersion {
288                major: Major(0xA4),
289                minor: Minor(0x00),
290            },
291            fpga: FPGAVersion {
292                major: Major(0xA4),
293                minor: Minor(0x00),
294                function_bits: 0,
295            },
296        }]
297    )]
298    #[case::empty(
299        Err(AUTDDriverError::FirmwareVersionMismatch),
300        vec![]
301    )]
302    #[case::mismatch(
303        Err(AUTDDriverError::FirmwareVersionMismatch),
304        vec![
305            FirmwareVersion {
306                idx: 0,
307                cpu: CPUVersion {
308                    major: Major(0xA2),
309                    minor: Minor(0x00),
310                },
311                fpga: FPGAVersion {
312                    major: Major(0xA2),
313                    minor: Minor(0x00),
314                    function_bits: 0,
315                },
316            },
317            FirmwareVersion {
318                idx: 1,
319                cpu: CPUVersion {
320                    major: Major(0xA3),
321                    minor: Minor(0x00),
322                },
323                fpga: FPGAVersion {
324                    major: Major(0xA3),
325                    minor: Minor(0x00),
326                    function_bits: 0,
327                },
328            }
329        ]
330    )]
331    #[case::unsupported(
332        Err(AUTDDriverError::UnsupportedFirmware),
333        vec![FirmwareVersion {
334            idx: 0,
335            cpu: CPUVersion {
336                major: Major(0xA5),
337                minor: Minor(0x00),
338            },
339            fpga: FPGAVersion {
340                major: Major(0xA5),
341                minor: Minor(0x00),
342                function_bits: 0,
343            },
344        }]
345    )]
346    #[test]
347    fn check_firmware_version(
348        #[case] expect: Result<Version, AUTDDriverError>,
349        #[case] version_list: Vec<crate::firmware::version::FirmwareVersion>,
350    ) {
351        assert_eq!(expect, super::check_firmware_version(&version_list));
352    }
353}