ni_fpga_interface/
types.rs

1/// Wrapper for any types shared across the interface.
2///
3use std::time::Duration;
4
5/// The representation of a boolean in the FPGA interface.
6#[repr(transparent)]
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
8pub struct FpgaBool(u8);
9
10impl FpgaBool {
11    pub const TRUE: FpgaBool = FpgaBool(1);
12    pub const FALSE: FpgaBool = FpgaBool(0);
13}
14
15impl From<bool> for FpgaBool {
16    fn from(value: bool) -> Self {
17        if value {
18            FpgaBool::TRUE
19        } else {
20            FpgaBool::FALSE
21        }
22    }
23}
24
25impl From<FpgaBool> for bool {
26    fn from(value: FpgaBool) -> Self {
27        value.0 != 0
28    }
29}
30
31/// Wrapper for the FpgaTimeout fields to handle
32/// the conversion from Duration and handling
33/// infinite timeouts.
34#[repr(transparent)]
35#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
36pub struct FpgaTimeoutMs(u32);
37
38impl FpgaTimeoutMs {
39    pub const INFINITE: FpgaTimeoutMs = FpgaTimeoutMs(0xFFFFFFFF);
40}
41
42impl From<Duration> for FpgaTimeoutMs {
43    fn from(duration: Duration) -> Self {
44        FpgaTimeoutMs(duration.as_millis() as u32)
45    }
46}
47
48impl From<Option<Duration>> for FpgaTimeoutMs {
49    fn from(duration: Option<Duration>) -> Self {
50        match duration {
51            Some(duration) => duration.into(),
52            None => FpgaTimeoutMs::INFINITE,
53        }
54    }
55}
56
57/// Represents a selection of 0 or more IRQs.
58///
59/// Internally the FPGA API expects a bitwise field to select IRQs.
60/// This type wraps that representation with functions to help make
61/// different selections and conversions.
62///
63/// For single IRQs you can use [`IrqSelection::new`] and to query if they are set use [`IrqSelection::is_irq_set`].
64///
65/// ```
66/// use ni_fpga_interface::irq::IrqSelection;
67/// let selection = IrqSelection::new(2);
68/// assert_eq!(selection.is_irq_set(2), true);
69/// ```
70///
71/// There is also an iterator method if you want to cycle through the set IRQs.
72/// ```
73/// use ni_fpga_interface::irq::IrqSelection;
74/// let mut selection = IrqSelection::new(0);
75/// selection.add_irq(2);
76/// for irq in selection.iter() {
77///    println!("IRQ: {}", irq);
78/// }
79/// ```
80///
81/// To mimic the C API the IRQs are also available as constants.
82/// ```
83/// use ni_fpga_interface::irq::{IRQ1};
84/// assert_eq!(IRQ1.is_irq_set(1), true);
85/// ```
86///
87///
88#[repr(transparent)]
89#[derive(Clone, Copy, PartialEq, Eq)]
90pub struct IrqSelection(u32);
91
92impl IrqSelection {
93    /// Represents a selection with no IRQs.
94    pub const NONE: IrqSelection = IrqSelection(0);
95
96    /// Creates a new IRQ selection with the specified IRQ included.
97    pub const fn new(irq: u8) -> IrqSelection {
98        IrqSelection(1 << irq)
99    }
100
101    /// Add an IRQ number by selection.
102    pub fn add_irq(&mut self, irq: u8) {
103        self.0 |= IrqSelection::new(irq).0;
104    }
105
106    /// Check if an IRQ number is set.
107    pub fn is_irq_set(&self, irq: u8) -> bool {
108        self.0 & IrqSelection::new(irq).0 != 0
109    }
110
111    /// Iterate over the IRQs that are set.
112    pub fn iter(&self) -> impl Iterator<Item = u8> + '_ {
113        (0..32).filter(|irq| self.is_irq_set(*irq))
114    }
115}
116
117impl Default for IrqSelection {
118    fn default() -> Self {
119        Self::NONE
120    }
121}
122
123impl std::fmt::Debug for IrqSelection {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        write!(f, "IrqSelection[")?;
126        let mut first = true;
127        for irq in self.iter() {
128            if first {
129                write!(f, "{}", irq)?;
130            } else {
131                write!(f, ", {}", irq)?;
132            }
133            first = false;
134        }
135        write!(f, "]")?;
136        Ok(())
137    }
138}
139
140impl From<u32> for IrqSelection {
141    /// Intialize an IRQ selection from a raw value.
142    fn from(value: u32) -> Self {
143        IrqSelection(value)
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn test_inifinite_timeout_representation() {
153        assert_eq!(FpgaTimeoutMs::INFINITE, FpgaTimeoutMs(0xFFFFFFFF));
154    }
155
156    #[test]
157    fn test_timeout_conversion_optional() {
158        assert_eq!(FpgaTimeoutMs::from(None), FpgaTimeoutMs(0xFFFFFFFF));
159        assert_eq!(
160            FpgaTimeoutMs::from(Some(Duration::from_millis(100))),
161            FpgaTimeoutMs(100)
162        );
163    }
164
165    #[test]
166    fn test_fpga_bool_into_bool() {
167        let bool_true: bool = FpgaBool::TRUE.into();
168        let bool_false: bool = FpgaBool::FALSE.into();
169        assert_eq!(bool_true, true);
170        assert_eq!(bool_false, false);
171    }
172
173    #[test]
174    fn test_bool_into_fpga_bool() {
175        let fpga_bool_true: FpgaBool = true.into();
176        let fpga_bool_false: FpgaBool = false.into();
177        assert_eq!(fpga_bool_true, FpgaBool::TRUE);
178        assert_eq!(fpga_bool_false, FpgaBool::FALSE);
179    }
180
181    #[test]
182    fn test_irq_selection_new() {
183        let irq = IrqSelection::new(20);
184        assert_eq!(irq.0, 1 << 20);
185    }
186
187    #[test]
188    fn test_add_irq_to_selection() {
189        let mut selection = IrqSelection::new(0);
190        selection.add_irq(2);
191        assert_eq!(selection.0, 0b101);
192    }
193
194    #[test]
195    fn test_check_if_irq_is_set() {
196        let mut selection = IrqSelection::new(0);
197        selection.add_irq(2);
198        assert_eq!(selection.is_irq_set(2), true);
199        assert_eq!(selection.is_irq_set(1), false);
200    }
201
202    #[test]
203    fn iterate_over_set_values() {
204        let mut selection = IrqSelection::new(0);
205        selection.add_irq(2);
206        let set_values = selection.iter().collect::<Vec<_>>();
207        assert_eq!(set_values, vec![0, 2])
208    }
209
210    #[test]
211    fn test_default() {
212        let selection = IrqSelection::default();
213        assert_eq!(selection.0, 0);
214    }
215
216    #[test]
217    fn test_irq_selection_display() {
218        let mut selection = IrqSelection::new(0);
219        selection.add_irq(2);
220        assert_eq!(format!("{:?}", selection), "IrqSelection[0, 2]");
221    }
222}