autd3_driver/firmware/auto/
driver.rs

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