autd3_driver/firmware/fpga/
pulse_width.rs

1use getset::CopyGetters;
2use num::Zero;
3
4#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, CopyGetters)]
5/// The pulse width.
6pub struct PulseWidth<T: Copy, const BITS: usize> {
7    #[getset(get_copy = "pub")]
8    /// The pulse width in period of 2^`BITS`.
9    pulse_width: T,
10}
11
12impl<T, const BITS: usize> PulseWidth<T, BITS>
13where
14    T: Copy + TryFrom<usize> + Zero + PartialOrd,
15{
16    /// Creates a new [`PulseWidth`].
17    pub fn new(pulse_width: T) -> Option<Self> {
18        if pulse_width < T::zero()
19            || T::try_from(1 << BITS)
20                .map(|period| period <= pulse_width)
21                .unwrap_or(false)
22        {
23            return None;
24        }
25        Some(Self { pulse_width })
26    }
27
28    /// Creates a new [`PulseWidth`] from duty ratio.
29    #[must_use]
30    pub fn from_duty(duty: f32) -> Option<Self> {
31        if !(0.0..=1.0).contains(&duty) {
32            return None;
33        } else {
34            duty
35        };
36        Self::new(T::try_from(((1 << BITS) as f32 * duty).round() as usize).ok()?)
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[rstest::rstest]
45    #[case(Some(0), 0)]
46    #[case(Some(256), 256)]
47    #[case(Some(511), 511)]
48    #[case(None, 512)]
49    #[test]
50    fn test_pulse_width_new(#[case] expected: Option<u16>, #[case] pulse_width: u16) {
51        let pulse_width = PulseWidth::<u16, 9>::new(pulse_width);
52        assert_eq!(expected, pulse_width.map(|p| p.pulse_width()));
53    }
54
55    #[rstest::rstest]
56    #[case(Some(0), 0.0)]
57    #[case(Some(256), 0.5)]
58    #[case(Some(511), 511.0 / 512.0)]
59    #[case(None, -0.5)]
60    #[case(None, 1.0)]
61    #[case(None, 1.5)]
62    #[test]
63    fn test_pulse_width_from_duty(#[case] expected: Option<u16>, #[case] duty: f32) {
64        let pulse_width = PulseWidth::<u16, 9>::from_duty(duty);
65        assert_eq!(expected, pulse_width.map(|p| p.pulse_width()));
66    }
67
68    #[rstest::rstest]
69    #[case(Some(0), 0)]
70    #[case(Some(255), 255)]
71    #[test]
72    fn test_pulse_width_new_u8(#[case] expected: Option<u8>, #[case] pulse_width: u8) {
73        let pulse_width = PulseWidth::<u8, 8>::new(pulse_width);
74        assert_eq!(expected, pulse_width.map(|p| p.pulse_width()));
75    }
76
77    #[rstest::rstest]
78    #[case(Some(0), 0.0)]
79    #[case(Some(128), 0.5)]
80    #[case(Some(255), 255.0 / 256.0)]
81    #[case(None, -0.5)]
82    #[case(None, 1.0)]
83    #[case(None, 1.5)]
84    #[test]
85    fn test_pulse_width_from_duty_u8(#[case] expected: Option<u8>, #[case] duty: f32) {
86        let pulse_width = PulseWidth::<u8, 8>::from_duty(duty);
87        assert_eq!(expected, pulse_width.map(|p| p.pulse_width()));
88    }
89}