autd3_firmware_emulator/fpga/emulator/stm/
foci.rs1use autd3_core::firmware::{Drive, Intensity, Phase, Segment};
2
3use super::super::{super::params::*, FPGAEmulator};
4
5pub struct STMFocus(u64);
6
7impl STMFocus {
8 fn x(&self) -> i32 {
9 let x = (self.0 & 0x3_FFFF) as u32;
10 if x & 0x2_0000 != 0 {
11 (x | 0xFFFC_0000) as i32
12 } else {
13 x as i32
14 }
15 }
16
17 fn y(&self) -> i32 {
18 let y = ((self.0 >> 18) & 0x3_FFFF) as u32;
19 if y & 0x2_0000 != 0 {
20 (y | 0xFFFC_0000) as i32
21 } else {
22 y as i32
23 }
24 }
25
26 fn z(&self) -> i32 {
27 let z = ((self.0 >> 36) & 0x3_FFFF) as u32;
28 if z & 0x2_0000 != 0 {
29 (z | 0xFFFC_0000) as i32
30 } else {
31 z as i32
32 }
33 }
34
35 fn intensity(&self) -> u8 {
36 ((self.0 >> 54) & 0xFF) as u8
37 }
38}
39
40impl FPGAEmulator {
41 #[must_use]
42 pub fn sound_speed(&self, segment: Segment) -> u16 {
43 self.mem
44 .controller_bram
45 .read(ADDR_STM_SOUND_SPEED0 + segment as usize)
46 }
47
48 #[must_use]
49 pub fn num_foci(&self, segment: Segment) -> u8 {
50 self.mem
51 .controller_bram
52 .read(ADDR_STM_NUM_FOCI0 + segment as usize) as u8
53 }
54
55 pub(crate) fn foci_stm_drives_inplace(
56 &self,
57 segment: Segment,
58 idx: usize,
59 phase_corr_buf: *mut Phase,
60 output_mask_buf: *mut bool,
61 dst: *mut Drive,
62 ) {
63 let bram = &self.mem.stm_bram[&segment];
64 let sound_speed = self.sound_speed(segment);
65 let num_foci = self.num_foci(segment) as usize;
66
67 unsafe {
68 self.phase_correction_inplace(phase_corr_buf);
69 self.output_mask_inplace(segment, output_mask_buf)
70 };
71
72 self.local_tr_pos()
73 .iter()
74 .take(self.mem.num_transducers)
75 .enumerate()
76 .for_each(|(i, tr)| {
77 let tr_z = ((tr >> 32) & 0xFFFF) as i16 as i32;
78 let tr_x = ((tr >> 16) & 0xFFFF) as i16 as i32;
79 let tr_y = (tr & 0xFFFF) as i16 as i32;
80 let mut intensity = 0x00;
81 let (sin, cos) = (0..num_foci).fold((0, 0), |acc, i| {
82 let f = bram.read_bram_as::<STMFocus>(
83 size_of::<STMFocus>() / size_of::<u16>() * (idx * num_foci + i),
84 );
85 let x = f.x();
86 let y = f.y();
87 let z = f.z();
88 let intensity_or_offset = f.intensity();
89 let offset = if i == 0 {
90 intensity = intensity_or_offset;
91 0x00
92 } else {
93 intensity_or_offset
94 };
95
96 let d2 =
97 (x - tr_x) * (x - tr_x) + (y - tr_y) * (y - tr_y) + (z - tr_z) * (z - tr_z);
98 let dist = d2.isqrt() as u32;
99 let q = ((dist << 14) / sound_speed as u32) as usize;
100 let q = q + offset as usize;
101 (
102 acc.0 + self.mem.sin_table[q % 256] as u16,
103 acc.1 + self.mem.sin_table[(q + 64) % 256] as u16,
104 )
105 });
106 let sin = ((sin / num_foci as u16) >> 1) as usize;
107 let cos = ((cos / num_foci as u16) >> 1) as usize;
108 let phase = self.mem.atan_table[(sin << 7) | cos];
109 unsafe {
110 let p = phase_corr_buf.add(i).read();
111 let mask = output_mask_buf.add(i).read();
112 dst.add(i).write(Drive {
113 phase: Phase(phase) + p,
114 intensity: Intensity(if mask { intensity } else { 0x00 }),
115 })
116 };
117 });
118 }
119
120 #[must_use]
121 pub fn local_tr_pos(&self) -> &[u64] {
122 self.mem.tr_pos.mem.as_slice()
123 }
124
125 #[must_use]
126 pub fn local_tr_pos_at(&self, idx: usize) -> u64 {
127 self.mem.tr_pos[idx]
128 }
129}