autd3/
controller.rs

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
17/// A controller for the AUTD devices.
18///
19/// All operations to the devices are done through this struct.
20pub struct Controller<L: Link, V: Driver> {
21    link: L,
22    #[doc(hidden)]
23    driver: V,
24    geometry: Geometry,
25    /// THe environment where the devices are placed.
26    pub environment: Environment,
27    msg_id: MsgId,
28    sent_flags: smallvec::SmallVec<[bool; 32]>,
29    rx_buf: Vec<RxMessage>,
30    /// The default sender option used for [`send`](Controller::send).
31    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    /// Equivalent to [`Self::open_with_option`] with default [`SenderOption`], [`FixedSchedule`] and [`Auto`] diver.
50    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    /// Equivalent to [`Self::open_with_option`] with default [`SenderOption`] and [`FixedSchedule`].
60    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    /// Opens a controller with a [`SenderOption`].
68    ///
69    /// Opens link, and then initialize and synchronize the devices. The `timeout` is used to send data for initialization and synchronization.
70    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    /// Returns the [`Sender`] to send data to the devices.
142    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    /// Returns the inspection result.
160    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    /// Closes the controller.
173    pub fn close(mut self) -> Result<(), AUTDDriverError> {
174        self.close_impl(self.default_sender_option, FixedSchedule::default())
175    }
176
177    /// Returns the firmware version of the devices.
178    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    /// Returns the FPGA state of the devices.
184    ///
185    /// To get the state of devices, enable reads FPGA state mode by [`ReadsFPGAState`] before calling this method.
186    /// The returned value is [`None`] if the reads FPGA state mode is disabled for the device.
187    ///
188    /// # Examples
189    ///
190    /// ```
191    /// # use autd3::prelude::*;
192    /// # fn main() -> Result<(), AUTDDriverError> {
193    /// let mut autd = Controller::open([AUTD3::default()], Nop::new())?;
194    ///
195    /// autd.send(ReadsFPGAState::new(|_| true))?;
196    ///
197    /// let states = autd.fpga_state()?;
198    /// Ok(())
199    /// # }
200    /// ```
201    ///
202    /// [`ReadsFPGAState`]: autd3_driver::datagram::ReadsFPGAState
203    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    /// Converts `Controller<L>` into a `Controller<Box<dyn Link>>`.
244    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    /// Converts `Controller<Box<dyn Link>>` into a `Controller<L>`.
267    ///
268    /// # Safety
269    ///
270    /// This function must be used only when converting an instance created by [`Controller::into_boxed_link`] back to the original [`Controller`].
271    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
303// The following implementations are necessary because Rust does not have associated traits.
304// https://github.com/rust-lang/rfcs/issues/2190
305
306impl<L: Link> Controller<L, firmware::v12_1::V12_1> {
307    /// Sends a data to the devices. This is a shortcut for [`Sender::send`].
308    ///
309    /// [`Sender::send`]: autd3_driver::firmware::v12_1::transmission::Sender::send
310    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    /// Sends a data to the devices. This is a shortcut for [`Sender::send`].
324    ///
325    /// [`Sender::send`]: autd3_driver::firmware::v12::transmission::Sender::send
326    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    /// Sends a data to the devices. This is a shortcut for [`Sender::send`].
340    ///
341    /// [`Sender::send`]: autd3_driver::firmware::v11::transmission::Sender::send
342    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    /// Sends a data to the devices. This is a shortcut for [`Sender::send`].
356    ///
357    /// [`Sender::send`]: autd3_driver::firmware::v10::transmission::Sender::send
358    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    /// Sends a data to the devices. This is a shortcut for [`Sender::send`].
372    ///
373    /// [`Sender::send`]: autd3_driver::firmware::auto::transmission::Sender::send
374    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}