autd3_firmware_emulator/fpga/emulator/stm/
mod.rs1use std::num::NonZeroU16;
2
3use autd3_core::{
4 datagram::{GPIOIn, LoopBehavior, Segment, TransitionMode},
5 gain::{Drive, Phase},
6};
7use autd3_driver::ethercat::DcSysTime;
8
9use super::{super::params::*, FPGAEmulator};
10
11mod foci;
12mod gain;
13
14impl FPGAEmulator {
15 #[must_use]
16 pub fn is_stm_gain_mode(&self, segment: Segment) -> bool {
17 self.mem
18 .controller_bram
19 .read(ADDR_STM_MODE0 + segment as usize)
20 == STM_MODE_GAIN
21 }
22
23 #[must_use]
24 pub fn stm_freq_divide(&self, segment: Segment) -> u16 {
25 self.mem
26 .controller_bram
27 .read(ADDR_STM_FREQ_DIV0 + segment as usize)
28 }
29
30 #[must_use]
31 pub fn stm_cycle(&self, segment: Segment) -> usize {
32 self.mem
33 .controller_bram
34 .read(ADDR_STM_CYCLE0 + segment as usize) as usize
35 + 1
36 }
37
38 #[must_use]
39 pub fn stm_loop_behavior(&self, segment: Segment) -> LoopBehavior {
40 match self
41 .mem
42 .controller_bram
43 .read(ADDR_STM_REP0 + segment as usize)
44 {
45 0xFFFF => LoopBehavior::Infinite,
46 v => LoopBehavior::Finite(NonZeroU16::new(v + 1).unwrap()),
47 }
48 }
49
50 #[must_use]
51 pub fn stm_transition_mode(&self) -> TransitionMode {
52 match self.mem.controller_bram.read(ADDR_STM_TRANSITION_MODE) as u8 {
53 TRANSITION_MODE_SYNC_IDX => TransitionMode::SyncIdx,
54 TRANSITION_MODE_SYS_TIME => TransitionMode::SysTime(
55 DcSysTime::ZERO
56 + std::time::Duration::from_nanos(
57 self.mem
58 .controller_bram
59 .read_bram_as::<u64>(ADDR_STM_TRANSITION_VALUE_0),
60 ),
61 ),
62 TRANSITION_MODE_GPIO => TransitionMode::GPIO(
63 match self
64 .mem
65 .controller_bram
66 .read_bram_as::<u64>(ADDR_STM_TRANSITION_VALUE_0)
67 {
68 0 => GPIOIn::I0,
69 1 => GPIOIn::I1,
70 2 => GPIOIn::I2,
71 3 => GPIOIn::I3,
72 _ => unreachable!(),
73 },
74 ),
75 TRANSITION_MODE_EXT => TransitionMode::Ext,
76 TRANSITION_MODE_IMMEDIATE => TransitionMode::Immediate,
77 _ => unreachable!(),
78 }
79 }
80
81 #[must_use]
82 pub fn req_stm_segment(&self) -> Segment {
83 match self.mem.controller_bram.read(ADDR_STM_REQ_RD_SEGMENT) {
84 0 => Segment::S0,
85 1 => Segment::S1,
86 _ => unreachable!(),
87 }
88 }
89
90 #[must_use]
91 pub fn drives(&self) -> Vec<Drive> {
92 self.drives_at(self.current_stm_segment(), self.current_stm_idx())
93 }
94
95 #[must_use]
96 pub fn drives_at(&self, segment: Segment, idx: usize) -> Vec<Drive> {
97 let mut phase_corr_buf = vec![Phase::ZERO; self.mem.num_transducers];
98 let mut output_mask_buf = vec![false; self.mem.num_transducers];
99 let mut dst = vec![Drive::NULL; self.mem.num_transducers];
100 self.drives_at_inplace(
101 segment,
102 idx,
103 &mut phase_corr_buf,
104 &mut output_mask_buf,
105 &mut dst,
106 );
107 dst
108 }
109
110 pub fn drives_at_inplace(
111 &self,
112 segment: Segment,
113 idx: usize,
114 phase_corr_buf: &mut [Phase],
115 output_mask_buf: &mut [bool],
116 dst: &mut [Drive],
117 ) {
118 if self.is_stm_gain_mode(segment) {
119 self.gain_stm_drives_inplace(segment, idx, phase_corr_buf, output_mask_buf, dst)
120 } else {
121 self.foci_stm_drives_inplace(segment, idx, phase_corr_buf, output_mask_buf, dst)
122 }
123 }
124}