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#[derive(CopyGetters)]
12pub struct Auto {
13 #[getset(get_copy = "pub")]
14 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}