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