autd3_firmware_emulator/fpga/emulator/
pwe.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
use autd3_driver::firmware::fpga::EmitIntensity;

use super::FPGAEmulator;

impl FPGAEmulator {
    pub fn pulse_width_encoder_table_at(&self, idx: usize) -> u8 {
        let v = self.mem.duty_table_bram()[idx >> 1];
        let v = if idx % 2 == 0 { v & 0xFF } else { v >> 8 };
        v as u8
    }

    pub fn pulse_width_encoder_table(&self) -> Vec<u8> {
        let mut dst = vec![0; 256];
        self.pulse_width_encoder_table_inplace(&mut dst);
        dst
    }

    pub fn pulse_width_encoder_table_inplace(&self, dst: &mut [u8]) {
        self.mem
            .duty_table_bram()
            .iter()
            .flat_map(|&d| vec![(d & 0xFF) as u8, (d >> 8) as u8])
            .enumerate()
            .for_each(|(i, v)| dst[i] = v);
    }

    pub fn to_pulse_width(&self, a: EmitIntensity, b: u8) -> u8 {
        let key = (a.value() as usize * b as usize) / 255;
        self.pulse_width_encoder_table_at(key)
    }
}

#[cfg(test)]

mod tests {
    use super::*;

    static ASIN_TABLE: &[u8; 256] = include_bytes!("asin.dat");

    fn to_pulse_width_actual(a: u8, b: u8) -> u8 {
        let idx = (a as usize * b as usize) / 255;
        ASIN_TABLE[idx]
    }

    #[test]
    #[cfg_attr(miri, ignore)]
    fn test_to_pulse_width() {
        let fpga = FPGAEmulator::new(249);
        itertools::iproduct!(0x00..=0xFF, 0x00..=0xFF).for_each(|(a, b)| {
            assert_eq!(
                to_pulse_width_actual(a, b),
                fpga.to_pulse_width(a.into(), b)
            );
        });
    }
}