autd3_firmware_emulator/fpga/emulator/stm/
foci.rs1use autd3_driver::firmware::fpga::{Drive, EmitIntensity, Phase, Segment};
2
3use super::super::{super::params::*, FPGAEmulator};
4
5#[bitfield_struct::bitfield(u64)]
6struct STMFocus {
7 #[bits(18)]
8 pub x: i32,
9 #[bits(18)]
10 pub y: i32,
11 #[bits(18)]
12 pub z: i32,
13 #[bits(8)]
14 pub intensity: u8,
15 #[bits(2)]
16 __: u8,
17}
18
19impl FPGAEmulator {
20 #[must_use]
21 pub fn sound_speed(&self, segment: Segment) -> u16 {
22 self.mem.controller_bram.borrow()[match segment {
23 Segment::S0 => ADDR_STM_SOUND_SPEED0,
24 Segment::S1 => ADDR_STM_SOUND_SPEED1,
25 }]
26 }
27
28 #[must_use]
29 pub fn num_foci(&self, segment: Segment) -> u8 {
30 self.mem.controller_bram.borrow()[match segment {
31 Segment::S0 => ADDR_STM_NUM_FOCI0,
32 Segment::S1 => ADDR_STM_NUM_FOCI1,
33 }] as u8
34 }
35
36 pub(crate) fn foci_stm_drives_inplace(&self, segment: Segment, idx: usize, dst: &mut [Drive]) {
37 let bram = &self.mem.stm_bram.borrow()[&segment];
38 let sound_speed = self.sound_speed(segment);
39
40 self.mem
41 .tr_pos
42 .iter()
43 .zip(self.phase_correction().iter())
44 .take(self.mem.num_transducers)
45 .enumerate()
46 .for_each(|(i, (&tr, &p))| {
47 let tr_z = ((tr >> 32) & 0xFFFF) as i16 as i32;
48 let tr_x = ((tr >> 16) & 0xFFFF) as i16 as i32;
49 let tr_y = (tr & 0xFFFF) as i16 as i32;
50 let mut intensity = 0x00;
51 let (sin, cos) = (0..self.num_foci(segment) as usize).fold((0, 0), |acc, i| {
52 let f = unsafe {
53 (bram[32 * idx + 4 * i..].as_ptr() as *const STMFocus).read_unaligned()
54 };
55 let x = f.x();
56 let y = f.y();
57 let z = f.z();
58 let intensity_or_offset = f.intensity();
59 let offset = if i == 0 {
60 intensity = intensity_or_offset;
61 0x00
62 } else {
63 intensity_or_offset
64 };
65
66 let d2 =
67 (x - tr_x) * (x - tr_x) + (y - tr_y) * (y - tr_y) + (z - tr_z) * (z - tr_z);
68 let dist = d2.isqrt() as u32;
69 let q = ((dist << 14) / sound_speed as u32) as usize;
70 let q = q + offset as usize;
71 (
72 acc.0 + self.mem.sin_table[q % 256] as u16,
73 acc.1 + self.mem.sin_table[(q + 64) % 256] as u16,
74 )
75 });
76 let sin = ((sin / self.num_foci(segment) as u16) >> 1) as usize;
77 let cos = ((cos / self.num_foci(segment) as u16) >> 1) as usize;
78 let phase = self.mem.atan_table[(sin << 7) | cos];
79 dst[i] = Drive {
80 phase: Phase(phase) + p,
81 intensity: EmitIntensity(intensity),
82 };
83 });
84 }
85
86 #[must_use]
87 pub fn local_tr_pos(&self) -> &[u64] {
88 &self.mem.tr_pos
89 }
90}