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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use thiserror::Error;

#[derive(Error, Debug, Clone)]
pub enum FormatError {}

pub trait Payload {
    fn new(batches: usize, data: &[u8]) -> Result<Self, FormatError>
    where
        Self: Sized;
    fn traces(&self) -> &[Vec<f32>];
    fn traces_mut(&mut self) -> &mut [Vec<f32>];
    fn labels(&self) -> &[&str];
}

pub struct AdcDac {
    traces: [Vec<f32>; 4],
}

impl Payload for AdcDac {
    /// Extract AdcDacData from a binary data block in the stream.
    ///
    /// # Args
    /// * `batch_size` - The size of each batch in samples.
    /// * `data` - The binary data composing the stream frame.
    fn new(batches: usize, data: &[u8]) -> Result<Self, FormatError> {
        const CHANNELS: usize = 4;
        const BATCH_SIZE: usize = 8;

        // The DAC output range in bipolar mode (including the external output op-amp) is +/- 4.096
        // V with 16-bit resolution. The anti-aliasing filter has an additional gain of 2.5.
        const DAC_VOLT_PER_LSB: f32 = 4.096 * 2.5 / (1u16 << 15) as f32;
        // The ADC has a differential input with a range of +/- 4.096 V and 16-bit resolution.
        // The gain into the two inputs is 1/5.
        const ADC_VOLT_PER_LSB: f32 = 5.0 / 2.0 * 4.096 / (1u16 << 15) as f32;
        assert_eq!(DAC_VOLT_PER_LSB, ADC_VOLT_PER_LSB);

        let v = Vec::with_capacity(data.len() * BATCH_SIZE);
        let mut traces = [v.clone(), v.clone(), v.clone(), v];
        let data: &[[[[u8; 2]; BATCH_SIZE]; CHANNELS]] = bytemuck::cast_slice(data);
        assert_eq!(data.len(), batches);
        for b in data.iter() {
            traces[0].extend(
                b[0].into_iter()
                    .map(|x| i16::from_le_bytes(x) as f32 * ADC_VOLT_PER_LSB),
            );
            traces[1].extend(
                b[1].into_iter()
                    .map(|x| i16::from_le_bytes(x) as f32 * ADC_VOLT_PER_LSB),
            );
            traces[2].extend(
                b[2].into_iter().map(|x| {
                    i16::from_le_bytes(x).wrapping_add(i16::MIN) as f32 * DAC_VOLT_PER_LSB
                }),
            );
            traces[3].extend(
                b[3].into_iter().map(|x| {
                    i16::from_le_bytes(x).wrapping_add(i16::MIN) as f32 * DAC_VOLT_PER_LSB
                }),
            );
        }
        Ok(Self { traces })
    }

    fn traces(&self) -> &[Vec<f32>] {
        &self.traces
    }

    fn traces_mut(&mut self) -> &mut [Vec<f32>] {
        &mut self.traces
    }
    fn labels(&self) -> &[&str] {
        &["ADC0", "ADC1", "DAC0", "DAC1"]
    }
}

pub struct Fls {
    traces: [Vec<f32>; 4],
}

impl Payload for Fls {
    fn new(batches: usize, data: &[u8]) -> Result<Self, FormatError> {
        let data: &[[[i32; 6]; 2]] = bytemuck::cast_slice(data);
        // demod_re, demod_im, wraps, ftw, pow_amp, pll
        assert_eq!(batches, data.len());
        let traces: [Vec<f32>; 4] = [
            data.iter()
                .map(|b| {
                    ((b[0][0] as f32).powi(2) + (b[0][1] as f32).powi(2)).sqrt() / (i32::MAX as f32)
                })
                .collect(),
            data.iter()
                .map(|b| (b[0][1] as f32).atan2(b[0][0] as f32))
                .collect(),
            data.iter()
                .map(|b| b[1][0] as f32 / i32::MAX as f32)
                .collect(),
            data.iter()
                .map(|b| b[1][1] as f32 / i32::MAX as f32)
                .collect(),
        ];
        Ok(Self { traces })
    }

    fn labels(&self) -> &[&str] {
        &["AR", "AP", "BI", "BQ"]
    }

    fn traces(&self) -> &[Vec<f32>] {
        &self.traces
    }
    fn traces_mut(&mut self) -> &mut [Vec<f32>] {
        &mut self.traces
    }
}