Struct nicompiler_backend::device::Device
source · pub struct Device { /* private fields */ }
Expand description
Represents a National Instruments (NI) device.
A Device
is the primary structure used to interact with NI hardware. It groups multiple
channels, each of which corresponds to a physical channel on an NI device. This struct provides
easy access to various properties of the device, such as its physical name, task type, and
several clock and trigger configurations.
For editing and compiling behavior of devices, see the BaseDevice
trait.
Fields
channels
: A collection of channels associated with this device.name
: Name of the device as seen by the NI driver.task_type
: Specifies the task type associated with the device.samp_rate
: The sampling rate of the device in Hz.samp_clk_src
: Optional source of the sampling clock; supplyNone
for on-board clock source.trig_line
: Optional identifier for the port through which to import/export the task start trigger. SupplyNone
for trivial triggering behavior.export_trig
: Optional Boolean indicating if the device exports its start trigger. Iftrue
, the device exports the start trigger of the NI-task associated with this device throughtrig_line
. Iffalse
orNone
, the device is set to import the start trigger. In case that any device in an experiment has nontrivial triggering behavior, one and only one of the devices must haveexport_trig
set totrue
.ref_clk_line
: Optional source of the reference clock to phase-lock the device clock to.export_ref_clk
: Optional indicator of whether to export the reference clock. Iftrue
, the device exports its reference clock. Iffalse
orNone
, it imports the reference clock. UseNone
for trivial behavior.ref_clk_rate
: Optional rate of the reference clock in Hz.
Synchronization Methods
For experiments that do not require synchronization between devices, set all optional fields of Device
to None
.
However, for more accurate and cohesive experiments, we recommend at least implementing start-trigger synchronization.
Start-trigger Synchronization
Relevant fields: trig_line
, export_trig
.
Refer to the official NI documentation on start-trigger synchronization.
This method designates one device to export its start trigger and others to import. When the experiment begins, tasks on
devices with export_trig
set to false
are set to wait for a digital edge trigger from the trig_line
channel. The device with export_trig
set to true
exports its start trigger to trig_line
.
Note: It’s essential to physically connect the device that exports its trigger (where export_trig
is true
) to the corresponding lines on devices that import the trigger.
For PCIe devices, use a PFI
label. For PXIe devices, use the label PXI_Trig
followed by a number in the range 0-7.
This backend crate ensures task synchronization such that threads handling tasks set to import the trigger always start listening for triggers before the exporting task begins.
For PXIe devices linked to a chassis, ensure that you configure trigger bus routing using NI-MAX (on Windows) or the NI Hardware Configuration Utilities (on Linux) when specifying backplane trigger lines. Detailed information can be found here.
It’s important to note that after starting, each device’s task utilizes its internal clock, which may result in incremental drifts between devices over time. For longer signals, it’s advisable to use additional synchronization methods to ensure clock alignment.
Example:
Here, the device PXI1Slot6
exports its start trigger to PXI1_Trig0
, while PXI1Slot7
imports its start
trigger from the same line.
let mut exp = Experiment::new();
exp.add_do_device("PXI1Slot6", 1e6);
exp.add_do_device("PXI1Slot7", 1e6);
exp.device_cfg_trig("PXI1Slot6", "PXI1_Trig0", true);
exp.device_cfg_trig("PXI1Slot7", "PXI1_Trig0", false);
The compiler will panic if more than one device exports trigger
let mut exp = Experiment::new();
exp.add_do_device("PXI1Slot6", 1e6);
exp.add_do_device("PXI1Slot7", 1e6);
exp.device_cfg_trig("PXI1Slot6", "PXI1_Trig0", true);
exp.device_cfg_trig("PXI1Slot7", "PXI1_Trig0", true);
The compiler will panic if some device is expecting a start trigger yet no device exports one.
let mut exp = Experiment::new();
exp.add_do_device("PXI1Slot6", 1e6);
exp.add_do_channel("PXI1Slot6", 0, 4);
exp.device_cfg_trig("PXI1Slot6", "PXI1_Trig0", false);
exp.go_high("PXI1Slot6", "port0/line4", 0.5);
exp.compile_with_stoptime(1.); // Panics here
Phase-lock to Reference Clock
Relevant fields: ref_clk_line
, ref_clk_rate
, export_ref_clk
.
Refer to the NI documentation on phase-lock synchronization.
A subset of NI devices support this flexible synchronization method, which allows devices synchronized in this manner
to operate at different sampling rates. Devices phase-lock their on-board oscillators to an external reference at ref_clk_line
and indicate its frequency via ref_clk_rate
. A device can optionally export its 10MHz onboard reference clock to ref_clk_line
by setting export_ref_clk
to true
.
Note: Devices phase-locked in this manner still require start-trigger synchronization to ensure synchronized start times.
Example:
The device PXI1Slot6
exports its start trigger signal to PXI1_Trig0
and its 10MHz reference clock to PXI1_Trig7
.
The device PXI1Slot4
acts accordingly.
use nicompiler_backend::*;
let mut exp = Experiment::new();
exp.add_ao_device("PXI1Slot3", 1e6);
exp.device_cfg_trig("PXI1Slot3", "PXI1_Trig0", true);
exp.device_cfg_ref_clk("PXI1Slot3", "PXI1_Trig7", 1e7, true);
exp.add_ao_device("PXI1Slot4", 1e6);
exp.device_cfg_trig("PXI1Slot4", "PXI1_Trig0", false);
exp.device_cfg_ref_clk("PXI1Slot4", "PXI1_Trig7", 1e7, false);
Importing Sample Clock
Relevant fields: samp_clk_src
.
Check out the NI documentation on sample clock synchronization.
Some NI devices do not support reference clock synchronization. As an alternative, they can directly use external clock signals for their sampling clock. However, this constrains them to operate at the same rate as the imported sample clock.
Example:
Building on the previous example, an additional PXI1Slot6
sources its sample clock from the 10MHz signal exported by PXI1Slot3
.
use nicompiler_backend::*;
let mut exp = Experiment::new();
exp.add_ao_device("PXI1Slot3", 1e6);
exp.device_cfg_trig("PXI1Slot3", "PXI1_Trig0", true);
exp.device_cfg_ref_clk("PXI1Slot3", "PXI1_Trig7", 1e7, true);
exp.add_ao_device("PXI1Slot4", 1e6);
exp.device_cfg_trig("PXI1Slot4", "PXI1_Trig0", false);
exp.device_cfg_ref_clk("PXI1Slot4", "PXI1_Trig7", 1e7, false);
exp.add_do_device("PXI1Slot6", 1e7);
exp.device_cfg_samp_clk_src("PXI1Slot6", "PXI1_Trig7");
exp.device_cfg_trig("PXI1Slot6", "PXI1_Trig0", false);
Implementations§
source§impl Device
impl Device
sourcepub fn new(name: &str, task_type: TaskType, samp_rate: f64) -> Self
pub fn new(name: &str, task_type: TaskType, samp_rate: f64) -> Self
Constructs a new Device
instance.
This constructor initializes a device with the provided parameters. The channels
field
is initialized as an empty collection. All synchronization fields are initialized to None
by default. For nontrivial synchronization behavior, use the methods BaseDevice::cfg_samp_clk_src
,
BaseDevice::cfg_trig
, and BaseDevice::cfg_ref_clk
.
Arguments
name
: Name of the device as seen by the NI driver.task_type
: The type of task associated with the device.samp_rate
: Desired sampling rate in Hz.
Returns
A new instance of Device
with the specified configurations and all synchronization-related fields set to None
.
Trait Implementations§
source§impl BaseDevice for Device
impl BaseDevice for Device
fn channels(&self) -> &HashMap<String, Channel>
fn name(&self) -> &str
fn task_type(&self) -> TaskType
fn samp_rate(&self) -> f64
fn samp_clk_src(&self) -> Option<&str>
fn trig_line(&self) -> Option<&str>
fn export_trig(&self) -> Option<bool>
fn ref_clk_line(&self) -> Option<&str>
fn export_ref_clk(&self) -> Option<bool>
fn ref_clk_rate(&self) -> Option<f64>
fn channels_(&mut self) -> &mut HashMap<String, Channel>
fn samp_clk_src_(&mut self) -> &mut Option<String>
fn trig_line_(&mut self) -> &mut Option<String>
fn export_trig_(&mut self) -> &mut Option<bool>
fn ref_clk_line_(&mut self) -> &mut Option<String>
fn export_ref_clk_(&mut self) -> &mut Option<bool>
fn ref_clk_rate_(&mut self) -> &mut Option<f64>
source§fn cfg_samp_clk_src(&mut self, src: &str)
fn cfg_samp_clk_src(&mut self, src: &str)
source§fn cfg_trig(&mut self, trig_line: &str, export_trig: bool)
fn cfg_trig(&mut self, trig_line: &str, export_trig: bool)
source§fn cfg_ref_clk(
&mut self,
ref_clk_line: &str,
ref_clk_rate: f64,
export_ref_clk: bool
)
fn cfg_ref_clk( &mut self, ref_clk_line: &str, ref_clk_rate: f64, export_ref_clk: bool )
source§fn editable_channels(&self) -> Vec<&Channel>
fn editable_channels(&self) -> Vec<&Channel>
source§fn editable_channels_(&mut self) -> Vec<&mut Channel>
fn editable_channels_(&mut self) -> Vec<&mut Channel>
source§fn add_channel(&mut self, name: &str)
fn add_channel(&mut self, name: &str)
source§fn is_compiled(&self) -> bool
fn is_compiled(&self) -> bool
BaseChannel::is_compiled
source§fn is_edited(&self) -> bool
fn is_edited(&self) -> bool
BaseChannel::is_edited
source§fn is_fresh_compiled(&self) -> bool
fn is_fresh_compiled(&self) -> bool
BaseChannel::is_fresh_compiled
source§fn clear_edit_cache(&mut self)
fn clear_edit_cache(&mut self)
BaseChannel::clear_edit_cache
source§fn clear_compile_cache(&mut self)
fn clear_compile_cache(&mut self)
BaseChannel::clear_compile_cache