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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use super::{PicoCoupling, PicoRange};
use num_derive::*;
use std::convert::From;

/// Pico time units
#[derive(Debug, Clone, Copy, FromPrimitive, ToPrimitive, PartialEq)]
pub enum TimeUnits {
    FS = 0,
    PS = 1,
    NS = 2,
    US = 3,
    MS = 4,
    S = 5,
}

impl From<TimeUnits> for u32 {
    fn from(value: TimeUnits) -> Self {
        num_traits::ToPrimitive::to_u32(&value).expect("Non-valid time unit")
    }
}

impl From<TimeUnits> for i16 {
    fn from(value: TimeUnits) -> Self {
        num_traits::ToPrimitive::to_i16(&value).expect("Non-valid time unit")
    }
}

impl From<i32> for TimeUnits {
    fn from(value: i32) -> Self {
        num_traits::FromPrimitive::from_i32(value).expect("Non-valid time unit")
    }
}

impl TimeUnits {
    pub fn get_multiplier(self) -> f64 {
        match self {
            TimeUnits::S => 1.0,
            TimeUnits::MS => 1e-3,
            TimeUnits::US => 1e-6,
            TimeUnits::NS => 1e-9,
            TimeUnits::PS => 1e-12,
            TimeUnits::FS => 1e-15,
        }
    }
}

/// Sample configuration
#[derive(Debug, Clone, Copy)]
pub struct SampleConfig {
    pub interval: u32,
    pub units: TimeUnits,
}

impl SampleConfig {
    pub fn new(interval: u32, units: TimeUnits) -> SampleConfig {
        SampleConfig { interval, units }
    }

    pub fn from_samples_per_second(samples_per_second: u32) -> SampleConfig {
        let interval: f64 = (1f64 / (samples_per_second as f64)) * 1_000_000_000_f64;

        SampleConfig {
            interval: interval as u32,
            units: TimeUnits::NS,
        }
    }

    pub fn get_interval(self) -> f64 {
        self.units.get_multiplier() * (self.interval as f64)
    }

    pub fn samples_per_second(self) -> u32 {
        (1f64 / self.get_interval()) as u32
    }

    pub fn with_interval(self, interval: u32) -> SampleConfig {
        SampleConfig { interval, ..self }
    }
}

impl Default for SampleConfig {
    fn default() -> Self {
        SampleConfig::new(1, TimeUnits::MS)
    }
}

#[cfg(test)]
#[allow(clippy::float_cmp)]
mod tests {
    use super::*;

    #[test]
    fn from_samples_per_second() {
        let sc = SampleConfig::from_samples_per_second(1);
        assert_eq!(sc.interval, 1_000_000_000);
        assert_eq!(sc.units, TimeUnits::NS);
        assert_eq!(sc.samples_per_second(), 1);

        let sc = SampleConfig::from_samples_per_second(1000);
        assert_eq!(sc.interval, 1_000_000);
        assert_eq!(sc.units, TimeUnits::NS);
        assert_eq!(sc.samples_per_second(), 1000);

        let sc = SampleConfig::from_samples_per_second(15657);
        assert_eq!(sc.interval, 63_869);
        assert_eq!(sc.units, TimeUnits::NS);
        assert_eq!(sc.samples_per_second(), 15657);
    }

    #[test]
    fn get_interval() {
        let sc = SampleConfig::from_samples_per_second(1000);
        assert_eq!(sc.get_interval(), 0.001);

        let sc = SampleConfig::from_samples_per_second(1234);
        assert_eq!(sc.get_interval(), 0.000_810_372_000_000_000_1);
    }
}

/// Channel configuration
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChannelConfig {
    pub coupling: PicoCoupling,
    pub range: PicoRange,
    pub offset: f64,
}

impl ChannelConfig {
    pub fn new() -> ChannelConfig {
        ChannelConfig {
            coupling: PicoCoupling::DC,
            range: PicoRange::X1_PROBE_20V,
            offset: 0.0,
        }
    }
}

impl Default for ChannelConfig {
    fn default() -> Self {
        ChannelConfig::new()
    }
}