autd3_driver/firmware/fpga/
pulse_width.rs1use getset::CopyGetters;
2use num::Zero;
3
4#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, CopyGetters)]
5pub struct PulseWidth<T: Copy, const BITS: usize> {
7 #[getset(get_copy = "pub")]
8 pulse_width: T,
10}
11
12impl<T, const BITS: usize> PulseWidth<T, BITS>
13where
14 T: Copy + TryFrom<usize> + Zero + PartialOrd,
15{
16 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 #[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}