1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! # `niexpctrl_backend` - NI Experiment Control and Streaming
//!
//! `niexpctrl_backend` provides a seamless interface to control and stream experiments involving
//! National Instruments (NI) devices. It extends the foundational functionalities of the [`nicompiler_backend`] crate
//! to define interaction behavior with NI hardware, while maintaining an optimized and user-friendly
//! interface for its users.
//!
//! ## Core Functionalities:
//!
//! - **NI Device Streaming and Control:** With the `experiment` module, users can access a refined
//! version of the `Experiment` struct from `nicompiler_backend` that incorporates NI-specific
//! functionalities, enabling direct streaming to NI devices and their resets.
//!
//! - **NI-DAQmx Specific Operations:** The `nidaqmx` module offers a suite of functionalities
//! that interfaces with the NI-DAQmx C library, translating Rust calls into NI-DAQmx specific tasks.
//!
//! - **Utilities and Helpers:** The `utils` module provides additional utilities and helper functions.
//!
//!
//! ## Integration with `nicompiler_backend`:
//!
//! This crate is designed to be a natural extension of [`nicompiler_backend`].
//! The primary [`Experiment`] struct depends on, and extends its counterpart
//! in `nicompiler_backend`, maintaining general experiment behaviors and additionally introducing methods
//! specific to NI device management.
//! **Refer to [`nicompiler_backend`] for general implementations unrelated to NI streaming behavior**.
//!
//! ## Where to Start:
//! - **Experiment Design and Control:** The [`experiment`] module provides implementation of how device tasks
//! are concurrently streamed.
//!
//! - **Device Management:** The [`device`] module implements streaming and synchronization behavior.
//!
//! - **NI-DAQmx Operations:** The [`nidaqmx`] module provides Rust wrapper methods for calling the
//! NI-DAQmx C library, translating functionalities for seamless NI device operations.
//!
//! - **Utilities:** For general utilities and helper functionalities, explore the [`utils`] module.
//!
//! ## Example usage with streaming
//! ### Rust
//! Recall the same example snippet from [`nicompiler_backend`].
//!
//! We additionally call `exp.stream_exp(50., 2);` after the experiment has been designed and compiled to
//! stream the experiment with a streaming buffer of 50ms, and two repetitions.
//! Refer to [`StreamableDevice::stream_task`] for more detailed information on streaming behavior.
//! ```ignore
//! use niexpctrl_backend::*;
//! let mut exp = Experiment::new();
//! // Define devices and associated channels
//! exp.add_ao_device("PXI1Slot3", 1e6);
//! exp.add_ao_channel("PXI1Slot3", 0);
//!
//! exp.add_ao_device("PXI1Slot4", 1e6);
//! exp.add_ao_channel("PXI1Slot4", 0);
//!
//! exp.add_do_device("PXI1Slot6", 1e7);
//! exp.add_do_channel("PXI1Slot6", 0, 0);
//! exp.add_do_channel("PXI1Slot6", 0, 4);
//!
//! // Define synchronization behavior:
//! exp.device_cfg_trig("PXI1Slot3", "PXI1_Trig0", true);
//! exp.device_cfg_ref_clk("PXI1Slot3", "PXI1_Trig7", 1e7, true);
//!
//! exp.device_cfg_trig("PXI1Slot4", "PXI1_Trig0", false);
//! exp.device_cfg_ref_clk("PXI1Slot4", "PXI1_Trig7", 1e7, false);
//!
//! exp.device_cfg_samp_clk_src("PXI1Slot6", "PXI1_Trig7");
//! exp.device_cfg_trig("PXI1Slot6", "PXI1_Trig0", false);
//!
//! // PXI1Slot3/ao0 starts with a 1s-long 7Hz sine wave with offset 1
//! // and unit amplitude, zero phase. Does not keep its value.
//! exp.sine("PXI1Slot3", "ao0", 0., 1., false, 7., None, None, Some(1.));
//! // Ends with a half-second long 1V constant signal which returns to zero
//! exp.constant("PXI1Slot3", "ao0", 9., 0.5, 1., false);
//!
//! // We can also leave a defined channel empty: the device / channel will simply not be compiled
//!
//! // Both lines of PXI1Slot6 start with a one-second "high" at t=0 and a half-second high at t=9
//! exp.high("PXI1Slot6", "port0/line0", 0., 1.);
//! exp.high("PXI1Slot6", "port0/line0", 9., 0.5);
//! // Alternatively, we can also define the same behavior via go_high/go_low
//! exp.go_high("PXI1Slot6", "port0/line4", 0.);
//! exp.go_low("PXI1Slot6", "port0/line4", 1.);
//!
//! exp.go_high("PXI1Slot6", "port0/line4", 9.);
//! exp.go_low("PXI1Slot6", "port0/line4", 9.5);
//!
//! exp.compile_with_stoptime(10.); // Experiment signal will stop at t=10 now
//! assert_eq!(exp.compiled_stop_time(), 10.);
//!
//! exp.stream_exp(50., 2);
//! ```
//!
//! ### Python
//! Functionally the same code, additionally samples and plots the signal for `PXI1Slot6/port0/line4`.
//! The primary goal of the `Experiment` object is to expose a complete set of fast rust-implemented methods
//! for interfacing with a NI experiment. One may easily customize syntactic sugar and higher-level abstractions
//! by wrapping `nicompiler_backend` module in another layer of python code,
//! see our [project page](https://github.com/nlyu1/NI-experiment-control) for one such example.
//! ```ignore
//! # Instantiate experiment, define devices and channels
//! from nicompiler_backend import Experiment
//! import matplotlib.pyplot as plt
//!
//! exp = Experiment()
//! exp.add_ao_device(name="PXI1Slot3", samp_rate=1e6)
//! exp.add_ao_channel(name="PXI1Slot3", channel_id=0)
//!
//! ...
//!
//! # Define synchronization behavior
//! exp.device_cfg_trig(name="PXI1Slot3", trig_line="PXI1_Trig0", export_trig=True)
//! exp.device_cfg_ref_clk(name="PXI1Slot3", ref_clk_line="PXI1_Trig7",
//! ref_clk_rate=1e7, export_ref_clk=True)
//! ...
//!
//! # Define signal
//! # Arguments of "option" type in rust is converted to optional arguments in python
//! exp.sine(dev_name="PXI1Slot3", chan_name="ao0", t=0., duration=1., keep_val=False,
//! freq=7., dc_offset=1.)
//! ...
//!
//! exp.compile_with_stoptime(10.)
//! exp.stream_exp(50., 2)
//! ```
use *;
pub use crate*;
pub use crateExperiment;
pub use crate*;
pub use crate*;
pub use *;