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}