Skip to main content

nanonis_rs/client/
bias_sweep.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5impl NanonisClient {
6    /// Open the Bias Sweep module.
7    ///
8    /// Opens and initializes the Bias Sweep module for bias voltage sweep measurements.
9    /// This must be called before performing bias sweep operations.
10    ///
11    /// # Errors
12    /// Returns `NanonisError` if communication fails or module cannot be opened.
13    ///
14    /// # Examples
15    /// ```no_run
16    /// use nanonis_rs::NanonisClient;
17    ///
18    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
19    ///
20    /// // Open bias sweep module
21    /// client.bias_sweep_open()?;
22    /// println!("Bias Sweep module opened");
23    /// # Ok::<(), Box<dyn std::error::Error>>(())
24    /// ```
25    pub fn bias_sweep_open(&mut self) -> Result<(), NanonisError> {
26        self.quick_send("BiasSwp.Open", vec![], vec![], vec![])?;
27        Ok(())
28    }
29
30    /// Start a bias sweep measurement.
31    ///
32    /// Starts a bias voltage sweep with the configured parameters. The sweep will
33    /// step through bias voltages between the set limits while recording selected channels.
34    ///
35    /// # Arguments
36    /// * `get_data` - If `true`, returns measurement data; if `false`, only starts measurement
37    /// * `sweep_direction` - Sweep direction: `true` starts from lower limit, `false` from upper
38    /// * `z_controller_status` - Z-controller behavior: 0=no change, 1=turn off, 2=don't turn off
39    /// * `save_base_name` - Base filename for saving data (empty for no change)
40    /// * `reset_bias` - Whether to reset bias after sweep: `true` for on, `false` for off
41    ///
42    /// # Returns
43    /// If `get_data` is true, returns a tuple containing:
44    /// - `Vec<String>` - Channel names
45    /// - `Vec<Vec<f32>>` - 2D measurement data `[rows][columns]`
46    ///
47    /// # Errors
48    /// Returns `NanonisError` if communication fails or sweep cannot start.
49    ///
50    /// # Examples
51    /// ```no_run
52    /// use nanonis_rs::NanonisClient;
53    ///
54    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
55    ///
56    /// // Start sweep and get data, from lower to upper limit, turn off Z-controller
57    /// let (channels, data) = client.bias_sweep_start(
58    ///     true,           // get_data
59    ///     true,           // sweep from lower limit
60    ///     1,              // turn off Z-controller
61    ///     "bias_sweep_001", // save basename
62    ///     true            // reset bias after sweep
63    /// )?;
64    /// println!("Recorded {} channels with {} points", channels.len(), data.len());
65    ///
66    /// // Just start sweep without getting data
67    /// let (_, _) = client.bias_sweep_start(false, true, 0, "", false)?;
68    /// # Ok::<(), Box<dyn std::error::Error>>(())
69    /// ```
70    pub fn bias_sweep_start(
71        &mut self,
72        get_data: bool,
73        sweep_direction: bool,
74        z_controller_status: u32,
75        save_base_name: &str,
76        reset_bias: bool,
77    ) -> Result<(Vec<String>, Vec<Vec<f32>>), NanonisError> {
78        let get_data_flag = if get_data { 1u32 } else { 0u32 };
79        let direction_flag = if sweep_direction { 1u32 } else { 0u32 };
80        let reset_flag = if reset_bias { 1u32 } else { 0u32 };
81
82        let result = self.quick_send(
83            "BiasSwp.Start",
84            vec![
85                NanonisValue::U32(get_data_flag),
86                NanonisValue::U32(direction_flag),
87                NanonisValue::U32(z_controller_status),
88                NanonisValue::String(save_base_name.to_string()),
89                NanonisValue::U32(reset_flag),
90            ],
91            vec!["I", "I", "I", "+*c", "I"],
92            vec!["i", "i", "*+c", "i", "i", "2f"],
93        )?;
94
95        if result.len() >= 6 {
96            let channel_names = result[2].as_string_array()?.to_vec();
97            let rows = result[3].as_i32()? as usize;
98            let cols = result[4].as_i32()? as usize;
99
100            // Parse 2D data array
101            let flat_data = result[5].as_f32_array()?;
102            let mut data_2d = Vec::with_capacity(rows);
103            for row in 0..rows {
104                let start_idx = row * cols;
105                let end_idx = start_idx + cols;
106                data_2d.push(flat_data[start_idx..end_idx].to_vec());
107            }
108
109            Ok((channel_names, data_2d))
110        } else {
111            Err(NanonisError::Protocol(
112                "Invalid bias sweep start response".to_string(),
113            ))
114        }
115    }
116
117    /// Set the bias sweep configuration parameters.
118    ///
119    /// Configures the bias sweep measurement parameters including number of steps,
120    /// timing, and save behavior.
121    ///
122    /// # Arguments
123    /// * `number_of_steps` - Number of bias steps in the sweep (0 = no change)
124    /// * `period_ms` - Period between steps in milliseconds (0 = no change)
125    /// * `autosave` - Auto-save behavior: 0=no change, 1=on, 2=off
126    /// * `save_dialog_box` - Show save dialog: 0=no change, 1=on, 2=off
127    ///
128    /// # Errors
129    /// Returns `NanonisError` if communication fails or invalid parameters provided.
130    ///
131    /// # Examples
132    /// ```no_run
133    /// use nanonis_rs::NanonisClient;
134    ///
135    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
136    ///
137    /// // Configure 100 steps, 50ms per step, auto-save on, no dialog
138    /// client.bias_sweep_props_set(100, 50, 1, 2)?;
139    ///
140    /// // High resolution sweep with slower timing
141    /// client.bias_sweep_props_set(500, 100, 1, 2)?;
142    /// # Ok::<(), Box<dyn std::error::Error>>(())
143    /// ```
144    pub fn bias_sweep_props_set(
145        &mut self,
146        number_of_steps: u16,
147        period_ms: u16,
148        autosave: u16,
149        save_dialog_box: u16,
150    ) -> Result<(), NanonisError> {
151        self.quick_send(
152            "BiasSwp.PropsSet",
153            vec![
154                NanonisValue::U16(number_of_steps),
155                NanonisValue::U16(period_ms),
156                NanonisValue::U16(autosave),
157                NanonisValue::U16(save_dialog_box),
158            ],
159            vec!["H", "H", "H", "H"],
160            vec![],
161        )?;
162        Ok(())
163    }
164
165    /// Set the bias sweep voltage limits.
166    ///
167    /// Configures the voltage range for the bias sweep. The sweep will step
168    /// between these limits according to the configured number of steps.
169    ///
170    /// # Arguments
171    /// * `lower_limit` - Lower voltage limit in volts
172    /// * `upper_limit` - Upper voltage limit in volts
173    ///
174    /// # Errors
175    /// Returns `NanonisError` if communication fails or invalid limits provided.
176    ///
177    /// # Examples
178    /// ```no_run
179    /// use nanonis_rs::NanonisClient;
180    ///
181    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
182    ///
183    /// // Set sweep range from -2V to +2V
184    /// client.bias_sweep_limits_set(-2.0, 2.0)?;
185    ///
186    /// // Positive voltage sweep only
187    /// client.bias_sweep_limits_set(0.0, 5.0)?;
188    ///
189    /// // Negative voltage sweep
190    /// client.bias_sweep_limits_set(-3.0, 0.0)?;
191    /// # Ok::<(), Box<dyn std::error::Error>>(())
192    /// ```
193    pub fn bias_sweep_limits_set(
194        &mut self,
195        lower_limit: f32,
196        upper_limit: f32,
197    ) -> Result<(), NanonisError> {
198        self.quick_send(
199            "BiasSwp.LimitsSet",
200            vec![
201                NanonisValue::F32(lower_limit),
202                NanonisValue::F32(upper_limit),
203            ],
204            vec!["f", "f"],
205            vec![],
206        )?;
207        Ok(())
208    }
209
210    /// Get the current bias sweep voltage limits.
211    ///
212    /// Returns the voltage range configuration for bias sweep measurements.
213    ///
214    /// # Returns
215    /// A tuple containing:
216    /// - `f32` - Lower voltage limit in volts
217    /// - `f32` - Upper voltage limit in volts
218    ///
219    /// # Errors
220    /// Returns `NanonisError` if communication fails or protocol error occurs.
221    ///
222    /// # Examples
223    /// ```no_run
224    /// use nanonis_rs::NanonisClient;
225    ///
226    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
227    ///
228    /// let (lower, upper) = client.bias_sweep_limits_get()?;
229    /// println!("Bias sweep range: {:.2}V to {:.2}V", lower, upper);
230    /// println!("Sweep span: {:.2}V", upper - lower);
231    ///
232    /// // Check if limits are reasonable
233    /// if (upper - lower).abs() < 0.1 {
234    ///     println!("Warning: Very narrow sweep range");
235    /// }
236    /// # Ok::<(), Box<dyn std::error::Error>>(())
237    /// ```
238    pub fn bias_sweep_limits_get(&mut self) -> Result<(f32, f32), NanonisError> {
239        let result =
240            self.quick_send("BiasSwp.LimitsGet", vec![], vec![], vec!["f", "f"])?;
241
242        if result.len() >= 2 {
243            Ok((result[0].as_f32()?, result[1].as_f32()?))
244        } else {
245            Err(NanonisError::Protocol(
246                "Invalid bias sweep limits response".to_string(),
247            ))
248        }
249    }
250
251    /// Get the current bias sweep configuration parameters.
252    ///
253    /// Returns the current sweep configuration including number of steps,
254    /// timing, and save behavior.
255    ///
256    /// # Returns
257    /// A tuple containing:
258    /// - `u16` - Number of bias steps in the sweep
259    /// - `u16` - Period between steps in milliseconds
260    /// - `bool` - Autosave enabled
261    /// - `bool` - Save dialog box enabled
262    ///
263    /// # Errors
264    /// Returns `NanonisError` if communication fails or protocol error occurs.
265    ///
266    /// # Examples
267    /// ```no_run
268    /// use nanonis_rs::NanonisClient;
269    ///
270    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
271    ///
272    /// let (steps, period_ms, autosave, save_dialog) = client.bias_sweep_props_get()?;
273    /// println!("Steps: {}, Period: {}ms", steps, period_ms);
274    /// println!("Autosave: {}, Save dialog: {}", autosave, save_dialog);
275    /// # Ok::<(), Box<dyn std::error::Error>>(())
276    /// ```
277    pub fn bias_sweep_props_get(&mut self) -> Result<(u16, u16, bool, bool), NanonisError> {
278        let result = self.quick_send(
279            "BiasSwp.PropsGet",
280            vec![],
281            vec![],
282            vec!["H", "H", "I", "I"],
283        )?;
284
285        if result.len() >= 4 {
286            Ok((
287                result[0].as_u16()?,
288                result[1].as_u16()?,
289                result[2].as_u32()? != 0,
290                result[3].as_u32()? != 0,
291            ))
292        } else {
293            Err(NanonisError::Protocol(
294                "Invalid bias sweep props response".to_string(),
295            ))
296        }
297    }
298}