1use autd3_core::{
2 datagram::{Datagram, DeviceMask},
3 datagram::{Inspectable, InspectionResult},
4 environment::Environment,
5 link::{Ack, Link, MsgId, RxMessage},
6 sleep::Sleep,
7};
8pub use autd3_driver::firmware::driver::{
9 Driver, FPGAState, FixedDelay, FixedSchedule, ParallelMode, SenderOption, TimerStrategy,
10};
11use autd3_driver::{
12 error::AUTDDriverError,
13 firmware::{self, auto::Auto, driver::Sender, version::FirmwareVersion},
14 geometry::{Device, Geometry},
15};
16
17pub struct Controller<L: Link, V: Driver> {
21 link: L,
22 #[doc(hidden)]
23 driver: V,
24 geometry: Geometry,
25 pub environment: Environment,
27 msg_id: MsgId,
28 sent_flags: smallvec::SmallVec<[bool; 32]>,
29 rx_buf: Vec<RxMessage>,
30 pub default_sender_option: SenderOption,
32}
33
34impl<L: Link, V: Driver> std::ops::Deref for Controller<L, V> {
35 type Target = Geometry;
36
37 fn deref(&self) -> &Self::Target {
38 &self.geometry
39 }
40}
41
42impl<L: Link, V: Driver> std::ops::DerefMut for Controller<L, V> {
43 fn deref_mut(&mut self) -> &mut Self::Target {
44 &mut self.geometry
45 }
46}
47
48impl<L: Link> Controller<L, Auto> {
49 pub fn open<D: Into<Device>, F: IntoIterator<Item = D>>(
51 devices: F,
52 link: L,
53 ) -> Result<Self, AUTDDriverError> {
54 Self::open_with_option(devices, link, Default::default(), FixedSchedule::default())
55 }
56}
57
58impl<L: Link, V: Driver> Controller<L, V> {
59 pub fn open_with<D: Into<Device>, F: IntoIterator<Item = D>>(
61 devices: F,
62 link: L,
63 ) -> Result<Self, AUTDDriverError> {
64 Self::open_with_option(devices, link, Default::default(), FixedSchedule::default())
65 }
66
67 pub fn open_with_option<
71 D: Into<Device>,
72 F: IntoIterator<Item = D>,
73 S: Sleep,
74 T: TimerStrategy<S>,
75 >(
76 devices: F,
77 mut link: L,
78 option: SenderOption,
79 timer_strategy: T,
80 ) -> Result<Self, AUTDDriverError> {
81 let geometry = Geometry::new(devices.into_iter().map(|d| d.into()).collect());
82 let environment = Environment::default();
83
84 link.open(&geometry)?;
85
86 let mut msg_id = MsgId::new(0);
87 let mut sent_flags = smallvec::smallvec![false; geometry.len()];
88 let mut rx_buf = vec![RxMessage::new(0, Ack::new()); geometry.len()];
89
90 let mut driver = V::new();
91 driver.detect_version(
92 &mut msg_id,
93 &mut link,
94 &geometry,
95 &mut sent_flags,
96 &mut rx_buf,
97 &environment,
98 )?;
99
100 let mut cnt = Controller {
101 link,
102 driver,
103 msg_id,
104 sent_flags,
105 rx_buf,
106 geometry,
107 environment,
108 default_sender_option: option,
109 };
110
111 cnt.sender(option, timer_strategy).initialize_devices()?;
112
113 Ok(cnt)
114 }
115
116 #[doc(hidden)]
117 pub const fn geometry(&self) -> &Geometry {
118 &self.geometry
119 }
120
121 #[doc(hidden)]
122 pub fn geometry_mut(&mut self) -> &mut Geometry {
123 &mut self.geometry
124 }
125
126 #[doc(hidden)]
127 pub const fn driver(&self) -> &V {
128 &self.driver
129 }
130
131 #[doc(hidden)]
132 pub const fn link(&self) -> &L {
133 &self.link
134 }
135
136 #[doc(hidden)]
137 pub const fn link_mut(&mut self) -> &mut L {
138 &mut self.link
139 }
140
141 pub fn sender<S: Sleep, T: TimerStrategy<S>>(
143 &mut self,
144 option: SenderOption,
145 timer_strategy: T,
146 ) -> V::Sender<'_, L, S, T> {
147 self.driver.sender(
148 &mut self.msg_id,
149 &mut self.link,
150 &self.geometry,
151 &mut self.sent_flags,
152 &mut self.rx_buf,
153 &self.environment,
154 option,
155 timer_strategy,
156 )
157 }
158
159 pub fn inspect<'a, I: Inspectable<'a>>(
161 &'a self,
162 s: I,
163 ) -> Result<InspectionResult<I::Result>, I::Error> {
164 s.inspect(
165 &self.geometry,
166 &self.environment,
167 &DeviceMask::AllEnabled,
168 &self.driver.firmware_limits(),
169 )
170 }
171
172 pub fn close(mut self) -> Result<(), AUTDDriverError> {
174 self.close_impl(self.default_sender_option, FixedSchedule::default())
175 }
176
177 pub fn firmware_version(&mut self) -> Result<Vec<FirmwareVersion>, AUTDDriverError> {
179 self.sender(self.default_sender_option, FixedSchedule::default())
180 .firmware_version()
181 }
182
183 pub fn fpga_state(&mut self) -> Result<Vec<Option<V::FPGAState>>, AUTDDriverError> {
204 self.link.ensure_is_open()?;
205 self.link.receive(&mut self.rx_buf)?;
206 Ok(self.rx_buf.iter().map(V::FPGAState::from_rx).collect())
207 }
208}
209
210impl<L: Link, V: Driver> Controller<L, V> {
211 fn close_impl<S: Sleep, T: TimerStrategy<S>>(
212 &mut self,
213 option: SenderOption,
214 timer_strategy: T,
215 ) -> Result<(), AUTDDriverError> {
216 if !self.link.is_open() {
217 return Ok(());
218 }
219
220 self.sender(option, timer_strategy).close()
221 }
222}
223
224impl<'a, L: Link, V: Driver> IntoIterator for &'a Controller<L, V> {
225 type Item = &'a Device;
226 type IntoIter = std::slice::Iter<'a, Device>;
227
228 fn into_iter(self) -> Self::IntoIter {
229 self.geometry.iter()
230 }
231}
232
233impl<'a, L: Link, V: Driver> IntoIterator for &'a mut Controller<L, V> {
234 type Item = &'a mut Device;
235 type IntoIter = std::slice::IterMut<'a, Device>;
236
237 fn into_iter(self) -> Self::IntoIter {
238 self.geometry.iter_mut()
239 }
240}
241
242impl<L: Link + 'static, V: Driver> Controller<L, V> {
243 pub fn into_boxed_link(self) -> Controller<Box<dyn Link>, V> {
245 let cnt = std::mem::ManuallyDrop::new(self);
246 let msg_id = unsafe { std::ptr::read(&cnt.msg_id) };
247 let driver = unsafe { std::ptr::read(&cnt.driver) };
248 let link = unsafe { std::ptr::read(&cnt.link) };
249 let geometry = unsafe { std::ptr::read(&cnt.geometry) };
250 let environment = unsafe { std::ptr::read(&cnt.environment) };
251 let sent_flags = unsafe { std::ptr::read(&cnt.sent_flags) };
252 let rx_buf = unsafe { std::ptr::read(&cnt.rx_buf) };
253 let default_sender_option = unsafe { std::ptr::read(&cnt.default_sender_option) };
254 Controller {
255 msg_id,
256 driver,
257 link: Box::new(link) as _,
258 geometry,
259 environment,
260 sent_flags,
261 rx_buf,
262 default_sender_option,
263 }
264 }
265
266 pub unsafe fn from_boxed_link(cnt: Controller<Box<dyn Link>, V>) -> Controller<L, V> {
272 let cnt = std::mem::ManuallyDrop::new(cnt);
273 let msg_id = unsafe { std::ptr::read(&cnt.msg_id) };
274 let driver = unsafe { std::ptr::read(&cnt.driver) };
275 let link = unsafe { std::ptr::read(&cnt.link) };
276 let geometry = unsafe { std::ptr::read(&cnt.geometry) };
277 let environment = unsafe { std::ptr::read(&cnt.environment) };
278 let sent_flags = unsafe { std::ptr::read(&cnt.sent_flags) };
279 let rx_buf = unsafe { std::ptr::read(&cnt.rx_buf) };
280 let default_sender_option = unsafe { std::ptr::read(&cnt.default_sender_option) };
281 Controller {
282 msg_id,
283 driver,
284 link: unsafe { *Box::from_raw(Box::into_raw(link) as *mut L) },
285 geometry,
286 environment,
287 sent_flags,
288 rx_buf,
289 default_sender_option,
290 }
291 }
292}
293
294impl<L: Link, V: Driver> Drop for Controller<L, V> {
295 fn drop(&mut self) {
296 if !self.link.is_open() {
297 return;
298 }
299 let _ = self.close_impl(self.default_sender_option, FixedSchedule::default());
300 }
301}
302
303impl<L: Link> Controller<L, firmware::v12_1::V12_1> {
307 pub fn send<'a, D: Datagram<'a>>(&'a mut self, s: D) -> Result<(), AUTDDriverError>
311 where
312 AUTDDriverError: From<D::Error>,
313 D::G: autd3_driver::firmware::v12_1::operation::OperationGenerator<'a>,
314 AUTDDriverError: From<<<D::G as autd3_driver::firmware::v12_1::operation::OperationGenerator<'a>>::O1 as autd3_driver::firmware::driver::Operation<'a>>::Error>
315 + From<<<D::G as autd3_driver::firmware::v12_1::operation::OperationGenerator<'a>>::O2 as autd3_driver::firmware::driver::Operation<'a>>::Error>,
316 {
317 self.sender(self.default_sender_option, FixedSchedule::default())
318 .send(s)
319 }
320}
321
322impl<L: Link> Controller<L, firmware::v12::V12> {
323 pub fn send<'a, D: Datagram<'a>>(&'a mut self, s: D) -> Result<(), AUTDDriverError>
327 where
328 AUTDDriverError: From<D::Error>,
329 D::G: autd3_driver::firmware::v12::operation::OperationGenerator<'a>,
330 AUTDDriverError: From<<<D::G as autd3_driver::firmware::v12::operation::OperationGenerator<'a>>::O1 as autd3_driver::firmware::driver::Operation<'a>>::Error>
331 + From<<<D::G as autd3_driver::firmware::v12::operation::OperationGenerator<'a>>::O2 as autd3_driver::firmware::driver::Operation<'a>>::Error>,
332 {
333 self.sender(self.default_sender_option, FixedSchedule::default())
334 .send(s)
335 }
336}
337
338impl<L: Link> Controller<L, firmware::v11::V11> {
339 pub fn send<'a, D: Datagram<'a>>(&'a mut self, s: D) -> Result<(), AUTDDriverError>
343 where
344 AUTDDriverError: From<D::Error>,
345 D::G: autd3_driver::firmware::v11::operation::OperationGenerator<'a>,
346 AUTDDriverError: From<<<D::G as autd3_driver::firmware::v11::operation::OperationGenerator<'a>>::O1 as autd3_driver::firmware::driver::Operation<'a>>::Error>
347 + From<<<D::G as autd3_driver::firmware::v11::operation::OperationGenerator<'a>>::O2 as autd3_driver::firmware::driver::Operation<'a>>::Error>,
348 {
349 self.sender(self.default_sender_option, FixedSchedule::default())
350 .send(s)
351 }
352}
353
354impl<L: Link> Controller<L, firmware::v10::V10> {
355 pub fn send<'a, D: Datagram<'a>>(&'a mut self, s: D) -> Result<(), AUTDDriverError>
359 where
360 AUTDDriverError: From<D::Error>,
361 D::G: autd3_driver::firmware::v10::operation::OperationGenerator<'a>,
362 AUTDDriverError: From<<<D::G as autd3_driver::firmware::v10::operation::OperationGenerator<'a>>::O1 as autd3_driver::firmware::driver::Operation<'a>>::Error>
363 + From<<<D::G as autd3_driver::firmware::v10::operation::OperationGenerator<'a>>::O2 as autd3_driver::firmware::driver::Operation<'a>>::Error>,
364 {
365 self.sender(self.default_sender_option, FixedSchedule::default())
366 .send(s)
367 }
368}
369
370impl<L: Link> Controller<L, firmware::auto::Auto> {
371 pub fn send<'a, D: Datagram<'a>>(&'a mut self, s: D) -> Result<(), AUTDDriverError>
375 where
376 AUTDDriverError: From<D::Error>,
377 D::G: autd3_driver::firmware::auto::operation::OperationGenerator<'a>,
378 AUTDDriverError: From<<<D::G as autd3_driver::firmware::auto::operation::OperationGenerator<'a>>::O1 as autd3_driver::firmware::driver::Operation<'a>>::Error>
379 + From<<<D::G as autd3_driver::firmware::auto::operation::OperationGenerator<'a>>::O2 as autd3_driver::firmware::driver::Operation<'a>>::Error>,
380 {
381 self.sender(self.default_sender_option, FixedSchedule::default())
382 .send(s)
383 }
384}
385
386#[cfg(test)]
387pub(crate) mod tests {
388 use std::collections::HashMap;
389
390 use crate::{
391 core::{
392 firmware::{Intensity, Phase, Segment},
393 gain::{Gain, GainCalculator, GainCalculatorGenerator, TransducerMask},
394 link::LinkError,
395 modulation::{Modulation, ModulationInspectionResult},
396 },
397 driver::{
398 autd3_device::AUTD3,
399 common::Hz,
400 datagram::{GainSTM, ReadsFPGAState},
401 firmware::v12_1::V12_1,
402 },
403 gain::Uniform,
404 link::{Audit, AuditOption, audit::version},
405 modulation::{Sine, Static},
406 };
407
408 use super::*;
409
410 pub fn create_controller(
411 dev_num: usize,
412 ) -> Result<Controller<Audit<version::V12_1>, V12_1>, AUTDDriverError> {
413 Controller::open_with(
414 (0..dev_num).map(|_| AUTD3::default()),
415 Audit::<version::V12_1>::new(AuditOption::default()),
416 )
417 }
418
419 #[test]
420 fn deref_mut() -> Result<(), Box<dyn std::error::Error>> {
421 let mut autd = create_controller(1)?;
422 assert_eq!(1, autd.len());
423 autd.reconfigure(|dev| dev);
424 Ok(())
425 }
426
427 #[test]
428 fn geometry() -> Result<(), Box<dyn std::error::Error>> {
429 let mut autd = create_controller(1)?;
430 assert_eq!(1, autd.geometry().len());
431 autd.geometry_mut().reconfigure(|dev| dev);
432 Ok(())
433 }
434
435 #[test]
436 fn open_failed() {
437 assert_eq!(
438 Some(AUTDDriverError::Link(LinkError::new("broken"))),
439 Controller::<_, V12_1>::open_with(
440 [AUTD3::default()],
441 Audit::<version::V12_1>::new(AuditOption {
442 broken: true,
443 ..Default::default()
444 }),
445 )
446 .err()
447 );
448 }
449
450 #[test]
451 fn send() -> Result<(), Box<dyn std::error::Error>> {
452 let mut autd = create_controller(1)?;
453 autd.send((
454 Sine {
455 freq: 150. * Hz,
456 option: Default::default(),
457 },
458 GainSTM {
459 gains: vec![
460 Uniform {
461 intensity: Intensity(0x80),
462 phase: Phase::ZERO,
463 },
464 Uniform {
465 intensity: Intensity(0x81),
466 phase: Phase::ZERO,
467 },
468 ],
469 config: 1. * Hz,
470 option: Default::default(),
471 },
472 ))?;
473
474 autd.iter().try_for_each(|dev| {
475 assert_eq!(
476 *Sine {
477 freq: 150. * Hz,
478 option: Default::default(),
479 }
480 .calc(&V12_1.firmware_limits())?,
481 autd.link[dev.idx()].fpga().modulation_buffer(Segment::S0)
482 );
483 let f = Uniform {
484 intensity: Intensity(0x80),
485 phase: Phase::ZERO,
486 }
487 .init(
488 &autd.geometry,
489 &autd.environment,
490 &TransducerMask::AllEnabled,
491 )?
492 .generate(dev);
493 assert_eq!(
494 dev.iter().map(|tr| f.calc(tr)).collect::<Vec<_>>(),
495 autd.link[dev.idx()].fpga().drives_at(Segment::S0, 0)
496 );
497 let f = Uniform {
498 intensity: Intensity(0x81),
499 phase: Phase::ZERO,
500 }
501 .init(
502 &autd.geometry,
503 &autd.environment,
504 &TransducerMask::AllEnabled,
505 )?
506 .generate(dev);
507 assert_eq!(
508 dev.iter().map(|tr| f.calc(tr)).collect::<Vec<_>>(),
509 autd.link[dev.idx()].fpga().drives_at(Segment::S0, 1)
510 );
511 Result::<(), Box<dyn std::error::Error>>::Ok(())
512 })?;
513
514 autd.close()?;
515
516 Ok(())
517 }
518
519 #[test]
520 fn inspect() -> Result<(), Box<dyn std::error::Error>> {
521 let autd = create_controller(2)?;
522
523 let r = autd.inspect(autd3_driver::datagram::Group::new(
524 |dev| (dev.idx() == 0).then_some(()),
525 HashMap::from([((), Static::default())]),
526 ))?;
527 assert_eq!(autd.geometry.len(), r.len());
528 assert_eq!(
529 Some(ModulationInspectionResult {
530 data: vec![0xFF, 0xFF],
531 config: Static::default().sampling_config(),
532 }),
533 r[0]
534 );
535 assert_eq!(None, r[1]);
536
537 autd.close()?;
538
539 Ok(())
540 }
541
542 #[test]
543 fn firmware_version() -> Result<(), Box<dyn std::error::Error>> {
544 use autd3_driver::firmware::version::{CPUVersion, FPGAVersion};
545
546 let mut autd = create_controller(1)?;
547 assert_eq!(
548 vec![FirmwareVersion {
549 idx: 0,
550 cpu: CPUVersion {
551 major: FirmwareVersion::LATEST_VERSION_NUM_MAJOR,
552 minor: FirmwareVersion::LATEST_VERSION_NUM_MINOR
553 },
554 fpga: FPGAVersion {
555 major: FirmwareVersion::LATEST_VERSION_NUM_MAJOR,
556 minor: FirmwareVersion::LATEST_VERSION_NUM_MINOR,
557 function_bits: FPGAVersion::ENABLED_EMULATOR_BIT
558 }
559 }],
560 autd.firmware_version()?
561 );
562 Ok(())
563 }
564
565 #[test]
566 fn firmware_version_err() -> Result<(), Box<dyn std::error::Error>> {
567 let mut autd = create_controller(2)?;
568 autd.link_mut().break_down();
569 assert_eq!(
570 Err(AUTDDriverError::ReadFirmwareVersionFailed(vec![
571 false, false
572 ])),
573 autd.firmware_version()
574 );
575 Ok(())
576 }
577
578 #[test]
579 fn close() -> Result<(), Box<dyn std::error::Error>> {
580 {
581 let mut autd = create_controller(1)?;
582 autd.close_impl(SenderOption::default(), FixedSchedule::default())?;
583 autd.close()?;
584 }
585
586 {
587 let mut autd = create_controller(1)?;
588 autd.link_mut().break_down();
589 assert_eq!(
590 Err(AUTDDriverError::Link(LinkError::new("broken"))),
591 autd.close()
592 );
593 }
594
595 Ok(())
596 }
597
598 #[test]
599 fn fpga_state() -> Result<(), Box<dyn std::error::Error>> {
600 let mut autd = Controller::<_, V12_1>::open_with(
601 [AUTD3::default(), AUTD3::default()],
602 Audit::<version::V12_1>::new(AuditOption::default()),
603 )?;
604
605 autd.send(ReadsFPGAState::new(|_| true))?;
606 {
607 autd.link_mut()[0].fpga_mut().assert_thermal_sensor();
608
609 let states = autd.fpga_state()?;
610 assert_eq!(2, states.len());
611 assert!(states[0].is_some_and(|s| s.is_thermal_assert()));
612 assert!(states[1].is_some_and(|s| !s.is_thermal_assert()));
613 }
614
615 {
616 autd.link_mut()[0].fpga_mut().deassert_thermal_sensor();
617 autd.link_mut()[1].fpga_mut().assert_thermal_sensor();
618
619 let states = autd.fpga_state()?;
620 assert_eq!(2, states.len());
621 assert!(states[0].is_some_and(|s| !s.is_thermal_assert()));
622 assert!(states[1].is_some_and(|s| s.is_thermal_assert()));
623 }
624
625 autd.send(ReadsFPGAState::new(|dev| dev.idx() == 1))?;
626 {
627 let states = autd.fpga_state()?;
628 assert_eq!(2, states.len());
629 assert!(states[0].is_none());
630 assert!(states[1].is_some_and(|s| s.is_thermal_assert()));
631 }
632
633 Ok(())
634 }
635
636 #[test]
637 fn into_iter() -> Result<(), Box<dyn std::error::Error>> {
638 let mut autd = create_controller(1)?;
639 (&mut autd).into_iter().for_each(|dev| {
640 _ = dev;
641 });
642 (&autd).into_iter().for_each(|dev| {
643 _ = dev;
644 });
645 Ok(())
646 }
647
648 #[test]
649 fn with_boxed_link() -> Result<(), Box<dyn std::error::Error>> {
650 let link: Box<dyn Link> = Box::new(Audit::<version::V12_1>::new(AuditOption::default()));
651 let mut autd = Controller::<_, V12_1>::open_with([AUTD3::default()], link)?;
652
653 autd.send(Sine {
654 freq: 150. * Hz,
655 option: Default::default(),
656 })?;
657
658 autd.close()?;
659
660 Ok(())
661 }
662
663 #[test]
664 fn into_boxed_link_unsafe() -> Result<(), Box<dyn std::error::Error>> {
665 let autd = Controller::<_, V12_1>::open_with_option(
666 [AUTD3::default()],
667 Audit::<version::V12_1>::new(AuditOption::default()),
668 SenderOption::default(),
669 FixedSchedule::default(),
670 )?;
671
672 let mut autd = autd.into_boxed_link();
673
674 autd.send((
675 Sine {
676 freq: 150. * Hz,
677 option: Default::default(),
678 },
679 GainSTM {
680 gains: vec![
681 Uniform {
682 intensity: Intensity(0x80),
683 phase: Phase::ZERO,
684 },
685 Uniform {
686 intensity: Intensity(0x81),
687 phase: Phase::ZERO,
688 },
689 ],
690 config: 1. * Hz,
691 option: Default::default(),
692 },
693 ))?;
694
695 let autd = unsafe { Controller::<Audit<version::V12_1>, _>::from_boxed_link(autd) };
696
697 autd.iter().try_for_each(|dev| {
698 assert_eq!(
699 *Sine {
700 freq: 150. * Hz,
701 option: Default::default(),
702 }
703 .calc(&V12_1.firmware_limits())?,
704 autd.link[dev.idx()].fpga().modulation_buffer(Segment::S0)
705 );
706 let f = Uniform {
707 intensity: Intensity(0x80),
708 phase: Phase::ZERO,
709 }
710 .init(
711 &autd.geometry,
712 &autd.environment,
713 &TransducerMask::AllEnabled,
714 )?
715 .generate(dev);
716 assert_eq!(
717 dev.iter().map(|tr| f.calc(tr)).collect::<Vec<_>>(),
718 autd.link[dev.idx()].fpga().drives_at(Segment::S0, 0)
719 );
720 let f = Uniform {
721 intensity: Intensity(0x81),
722 phase: Phase::ZERO,
723 }
724 .init(
725 &autd.geometry,
726 &autd.environment,
727 &TransducerMask::AllEnabled,
728 )?
729 .generate(dev);
730 assert_eq!(
731 dev.iter().map(|tr| f.calc(tr)).collect::<Vec<_>>(),
732 autd.link[dev.idx()].fpga().drives_at(Segment::S0, 1)
733 );
734 Result::<(), Box<dyn std::error::Error>>::Ok(())
735 })?;
736
737 autd.close()?;
738
739 Ok(())
740 }
741
742 #[test]
743 fn into_boxed_link_close() -> Result<(), Box<dyn std::error::Error>> {
744 let autd = create_controller(1)?;
745 let autd = autd.into_boxed_link();
746
747 autd.close()?;
748
749 Ok(())
750 }
751
752 #[test]
753 fn send_boxed() -> Result<(), Box<dyn std::error::Error>> {
754 use crate::gain::Null;
755 use autd3_driver::firmware::driver::BoxedDatagram;
756
757 {
758 let mut autd = Controller::<_, firmware::v12_1::V12_1>::open_with(
759 [AUTD3::default()],
760 Audit::<version::V12_1>::new(AuditOption::default()),
761 )?;
762
763 autd.send(BoxedDatagram::new(Null))?;
764
765 autd.close()?;
766 }
767
768 {
769 let mut autd = Controller::<_, firmware::v12::V12>::open_with(
770 [AUTD3::default()],
771 Audit::<version::V12>::new(AuditOption::default()),
772 )?;
773
774 autd.send(BoxedDatagram::new(Null))?;
775
776 autd.close()?;
777 }
778
779 {
780 let mut autd = Controller::<_, firmware::v11::V11>::open_with(
781 [AUTD3::default()],
782 Audit::<version::V11>::new(AuditOption::default()),
783 )?;
784
785 autd.send(BoxedDatagram::new(Null))?;
786
787 autd.close()?;
788 }
789
790 {
791 let mut autd = Controller::<_, firmware::v10::V10>::open_with(
792 [AUTD3::default()],
793 Audit::<version::V10>::new(AuditOption::default()),
794 )?;
795
796 autd.send(BoxedDatagram::new(Null))?;
797
798 autd.close()?;
799 }
800
801 {
802 let mut autd = Controller::<_, firmware::auto::Auto>::open_with(
803 [AUTD3::default()],
804 Audit::<version::V12_1>::new(AuditOption::default()),
805 )?;
806
807 autd.send(BoxedDatagram::new(Null))?;
808
809 autd.close()?;
810 }
811
812 Ok(())
813 }
814}