ni_fpga_interface/session/
data_interfaces.rs

1//! This module contains the interfaces for reading and writing data to the FPGA.
2//!
3//! There are two forms of this supported across the native data types:
4//!
5//! * Registers which are the front panel controls and indicators of the FPGA VI.
6//! * FIFOs which are the DMA FIFOs of the FPGA VI.
7
8use crate::error::{to_fpga_result, Result};
9use crate::nifpga_sys::*;
10use crate::session::Session;
11use crate::types::FpgaBool;
12use libc::size_t;
13use paste::paste;
14use std::time::Duration;
15
16/// Marker trait for the types that are supported directly by the FPGA interface.
17pub trait NativeFpgaType: Copy {}
18
19pub type RegisterAddress = u32;
20
21pub trait RegisterInterface<T: Default + Copy> {
22    fn read(&self, address: RegisterAddress) -> Result<T>;
23    fn write(&self, address: RegisterAddress, data: T) -> Result<()>;
24    fn read_array<const N: usize>(&self, address: RegisterAddress) -> Result<[T; N]> {
25        let mut array: [T; N] = [T::default(); N];
26        self.read_array_mut(address, &mut array)?;
27        Ok(array)
28    }
29    fn read_array_mut<const N: usize>(
30        &self,
31        address: RegisterAddress,
32        array: &mut [T; N],
33    ) -> Result<()>;
34    fn write_array<const N: usize>(&self, address: RegisterAddress, data: &[T; N]) -> Result<()>;
35}
36
37/// The read region is created by calling [`FifoInterface::read_no_copy`] on the FIFO interface.
38///
39/// This returns this structure where you can use elements to read the data from the FIFO.
40///
41/// When this structure is dropped the elements are released back to the FIFO automatically.
42pub struct FifoReadRegion<'session, 'data, T: NativeFpgaType> {
43    session: &'session Session,
44    fifo: FifoAddress,
45    pub elements: &'data [T],
46}
47
48impl<'s, 'd, T: NativeFpgaType> Drop for FifoReadRegion<'s, 'd, T> {
49    fn drop(&mut self) {
50        // Cant return result from drop so ignore it.
51        let _ = self
52            .session
53            .release_fifo_elements(self.fifo, self.elements.len());
54    }
55}
56
57/// The write region is created by calling [`FifoInterface::write_no_copy`] on the FIFO interface.
58///
59/// This returns this structure where you can use elements to write the data to the FIFO as a mutable slice.
60///
61/// When this structure is dropped the elements are released back to the FIFO automatically.
62pub struct FifoWriteRegion<'session, 'data, T: NativeFpgaType> {
63    session: &'session Session,
64    fifo: FifoAddress,
65    pub elements: &'data mut [T],
66}
67
68impl<'s, 'd, T: NativeFpgaType> Drop for FifoWriteRegion<'s, 'd, T> {
69    fn drop(&mut self) {
70        // Cant return result from drop so ignore it.
71        let _ = self
72            .session
73            .release_fifo_elements(self.fifo, self.elements.len());
74    }
75}
76
77pub trait FifoInterface<T: NativeFpgaType> {
78    /// Reads the elements into the provided buffer up to the size of the buffer.
79    ///
80    /// returns the number of elements left in the buffer to read.
81    fn read_fifo(
82        &self,
83        fifo: FifoAddress,
84        buffer: &mut [T],
85        timeout: Option<Duration>,
86    ) -> Result<usize>;
87
88    /// Writes the elements to the FPGA from the data slice.
89    ///
90    /// Returns the amount of free space in the FIFO.
91    fn write_fifo(&self, fifo: FifoAddress, data: &[T], timeout: Option<Duration>)
92        -> Result<usize>;
93
94    /// Provides a region of memory to read from the FIFO.
95    fn zero_copy_read(
96        &self,
97        fifo: FifoAddress,
98        elements: usize,
99        timeout: Option<Duration>,
100    ) -> Result<(FifoReadRegion<T>, usize)>;
101
102    /// Provides a region of memory to write to the FIFO.
103    fn zero_copy_write(
104        &self,
105        fifo: FifoAddress,
106        elements: usize,
107        timeout: Option<Duration>,
108    ) -> Result<(FifoWriteRegion<T>, usize)>;
109}
110
111/// First entry is the rust type, second is the text used for that type in the FPGA interface.
112macro_rules! impl_type_session_interface {
113    ($rust_type:ty, $fpga_type:literal) => {
114
115
116        paste! {
117            impl NativeFpgaType for $rust_type {}
118
119            impl RegisterInterface<$rust_type> for Session {
120                fn read(&self, address: RegisterAddress) -> Result<$rust_type> {
121                    let mut value: $rust_type = $rust_type::default();
122                    let return_code = unsafe {[< NiFpga_Read $fpga_type >](self.handle, address, &mut value)};
123                    to_fpga_result(value, return_code)
124                }
125                fn write(&self, address: RegisterAddress, value: $rust_type) -> Result<()> {
126                    let return_code = unsafe {[< NiFpga_Write $fpga_type >](self.handle, address, value)};
127                    to_fpga_result((), return_code)
128                }
129                fn read_array_mut<const N:usize>(&self, address: RegisterAddress, array: &mut [$rust_type; N]) -> Result<()> {
130                    let return_code = unsafe {[< NiFpga_ReadArray $fpga_type >](self.handle, address, array.as_mut_ptr(), N)};
131                    to_fpga_result((), return_code)
132                }
133                fn write_array<const N:usize>(&self, address: RegisterAddress, value: &[$rust_type;N]) -> Result<()> {
134                    let return_code = unsafe {[< NiFpga_WriteArray $fpga_type >](self.handle, address, value.as_ptr(), N)};
135                    to_fpga_result((), return_code)
136                }
137            }
138
139            impl FifoInterface<$rust_type> for Session {
140                fn read_fifo(&self, fifo: u32, data: &mut [$rust_type], timeout: Option<Duration>) -> Result< usize> {
141                    let mut elements_remaining: size_t = 0;
142                    let return_code = unsafe {[< NiFpga_ReadFifo $fpga_type >](self.handle, fifo, data.as_mut_ptr(), data.len(), timeout.into(), &mut elements_remaining)};
143                    to_fpga_result(elements_remaining, return_code)
144                }
145                fn write_fifo(&self, fifo: u32, data: &[$rust_type], timeout: Option<Duration>) -> Result<usize> {
146                    let mut elements_remaining: size_t = 0;
147                    let return_code = unsafe {[< NiFpga_WriteFifo $fpga_type >](self.handle, fifo, data.as_ptr(), data.len(), timeout.into(), &mut elements_remaining)};
148                    to_fpga_result(elements_remaining, return_code)
149                }
150                fn zero_copy_read(&self, fifo: u32, elements: usize, timeout: Option<Duration>) -> Result<(FifoReadRegion<$rust_type>, usize)> {
151                    let mut elements_acquired: size_t = 0;
152                    let mut elements_remaining: size_t = 0;
153                    let mut data: *const $rust_type = std::ptr::null();
154                    let return_code = unsafe {[< NiFpga_AcquireFifoReadElements $fpga_type >](self.handle, fifo, &mut data, elements, timeout.into(), &mut elements_acquired, &mut elements_remaining)};
155                    let read_region = FifoReadRegion{session: self, fifo, elements: unsafe {std::slice::from_raw_parts(data, elements_acquired)}};
156                    to_fpga_result((read_region, elements_remaining), return_code)
157                }
158                fn zero_copy_write(&self, fifo: u32, elements: usize, timeout: Option<Duration>) -> Result<(FifoWriteRegion<$rust_type>, usize)> {
159                    let mut elements_acquired: size_t = 0;
160                    let mut elements_remaining: size_t = 0;
161                    let mut data: *mut $rust_type = std::ptr::null_mut();
162                    let return_code = unsafe {[< NiFpga_AcquireFifoWriteElements $fpga_type >](self.handle, fifo, &mut data, elements, timeout.into(), &mut elements_acquired, &mut elements_remaining)};
163                    let write_region = FifoWriteRegion{session: self, fifo, elements: unsafe {std::slice::from_raw_parts_mut(data, elements_acquired)}};
164                    to_fpga_result((write_region, elements_remaining), return_code)
165                }
166            }
167        }
168    }
169}
170
171impl_type_session_interface!(u8, "U8");
172impl_type_session_interface!(u16, "U16");
173impl_type_session_interface!(u32, "U32");
174impl_type_session_interface!(u64, "U64");
175impl_type_session_interface!(i8, "I8");
176impl_type_session_interface!(i16, "I16");
177impl_type_session_interface!(i32, "I32");
178impl_type_session_interface!(i64, "I64");
179impl_type_session_interface!(f32, "Sgl");
180impl_type_session_interface!(f64, "Dbl");
181impl_type_session_interface!(FpgaBool, "Bool");