ni_fpga_interface/
irq.rs

1//! The IRQ module implements handling for interrupts to and from the FPGA.
2
3use std::{fmt::Debug, time::Duration};
4
5use crate::{error::FPGAError, nifpga_sys::*, session::Session, types::FpgaBool};
6
7// Re-excport the IRQ selection types from here for a better dev experience.
8pub use crate::types::IrqSelection;
9
10pub const IRQ0: IrqSelection = IrqSelection::new(0);
11pub const IRQ1: IrqSelection = IrqSelection::new(1);
12pub const IRQ2: IrqSelection = IrqSelection::new(2);
13pub const IRQ3: IrqSelection = IrqSelection::new(3);
14pub const IRQ4: IrqSelection = IrqSelection::new(4);
15pub const IRQ5: IrqSelection = IrqSelection::new(5);
16pub const IRQ6: IrqSelection = IrqSelection::new(6);
17pub const IRQ7: IrqSelection = IrqSelection::new(7);
18pub const IRQ8: IrqSelection = IrqSelection::new(8);
19pub const IRQ9: IrqSelection = IrqSelection::new(9);
20pub const IRQ10: IrqSelection = IrqSelection::new(10);
21pub const IRQ11: IrqSelection = IrqSelection::new(11);
22pub const IRQ12: IrqSelection = IrqSelection::new(12);
23pub const IRQ13: IrqSelection = IrqSelection::new(13);
24pub const IRQ14: IrqSelection = IrqSelection::new(14);
25pub const IRQ15: IrqSelection = IrqSelection::new(15);
26pub const IRQ16: IrqSelection = IrqSelection::new(16);
27pub const IRQ17: IrqSelection = IrqSelection::new(17);
28pub const IRQ18: IrqSelection = IrqSelection::new(18);
29pub const IRQ19: IrqSelection = IrqSelection::new(19);
30pub const IRQ20: IrqSelection = IrqSelection::new(20);
31pub const IRQ21: IrqSelection = IrqSelection::new(21);
32pub const IRQ22: IrqSelection = IrqSelection::new(22);
33pub const IRQ23: IrqSelection = IrqSelection::new(23);
34pub const IRQ24: IrqSelection = IrqSelection::new(24);
35pub const IRQ25: IrqSelection = IrqSelection::new(25);
36pub const IRQ26: IrqSelection = IrqSelection::new(26);
37pub const IRQ27: IrqSelection = IrqSelection::new(27);
38pub const IRQ28: IrqSelection = IrqSelection::new(28);
39pub const IRQ29: IrqSelection = IrqSelection::new(29);
40pub const IRQ30: IrqSelection = IrqSelection::new(30);
41pub const IRQ31: IrqSelection = IrqSelection::new(31);
42
43/// IrqContext provides a single-threaded context in which you can wait
44/// for specified IRQs.
45///
46/// This should be created from the session using [`Session::create_irq_context`].
47///
48/// The context is unreserved when it is dropped.
49pub struct IrqContext<'session> {
50    handle: IrqContextHandle,
51    session: &'session SessionHandle,
52}
53
54/// Represents the result of a wait on IRQs.
55#[derive(Debug, PartialEq, Eq, Clone, Copy)]
56pub enum IrqWaitResult {
57    /// The wait timed out.
58    TimedOut,
59    /// The wait completed and the specified IRQs were asserted.
60    IrqsAsserted(IrqSelection),
61}
62
63impl<'session> IrqContext<'session> {
64    /// Wait on the specified IRQs for the specified timeout.
65    ///
66    /// See [`IrqSelection`] for details on setting specific IRQs.
67    pub fn wait_on_irq(
68        &mut self,
69        irq: IrqSelection,
70        timeout: Duration,
71    ) -> Result<IrqWaitResult, FPGAError> {
72        let mut irqs_asserted: IrqSelection = IrqSelection::NONE;
73        let mut timed_out: FpgaBool = FpgaBool::FALSE;
74
75        unsafe {
76            let status = NiFpga_WaitOnIrqs(
77                *self.session,
78                self.handle,
79                irq,
80                timeout.as_millis() as u32,
81                &mut irqs_asserted,
82                &mut timed_out,
83            );
84
85            if status.is_error() {
86                return Err(status.into());
87            }
88        }
89
90        if timed_out == FpgaBool::TRUE {
91            Ok(IrqWaitResult::TimedOut)
92        } else {
93            Ok(IrqWaitResult::IrqsAsserted(irqs_asserted))
94        }
95    }
96}
97
98impl Drop for IrqContext<'_> {
99    fn drop(&mut self) {
100        unsafe {
101            NiFpga_UnreserveIrqContext(*self.session, self.handle);
102        }
103    }
104}
105
106impl Session {
107    /// Creates an IRQ Context for the session.
108    ///
109    /// You can create multiple contexts but each context can only be used by one thread at a time.
110    ///
111    /// The context is then used to wait on specific IRQs. See [`IrqContext`].
112    ///
113    /// To minimize jitter when first waiting on IRQs, reserve as many contexts as the application requires.
114    pub fn create_irq_context(&self) -> Result<IrqContext, FPGAError> {
115        let mut handle: IrqContextHandle = std::ptr::null();
116        unsafe {
117            let status = NiFpga_ReserveIrqContext(self.handle, &mut handle);
118
119            if status.is_error() {
120                return Err(status.into());
121            }
122        }
123        Ok(IrqContext {
124            handle,
125            session: &self.handle,
126        })
127    }
128
129    /// Acknowledge the specified IRQs. See [`IrqSelection`] for details on setting specific IRQs.
130    pub fn acknowledge_irqs(&self, irqs: IrqSelection) -> Result<(), FPGAError> {
131        unsafe {
132            let status = NiFpga_AcknowledgeIrqs(self.handle, irqs);
133
134            if status.is_error() {
135                return Err(status.into());
136            }
137        }
138        Ok(())
139    }
140}