Skip to main content

nanonis_rs/client/
gen_swp.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// Generic sweeper properties configuration.
6#[derive(Debug, Clone)]
7pub struct GenSwpProps {
8    /// Initial settling time in milliseconds
9    pub initial_settling_time_ms: f32,
10    /// Maximum slew rate in units/s
11    pub max_slew_rate: f32,
12    /// Number of sweep steps
13    pub num_steps: i32,
14    /// Period in milliseconds
15    pub period_ms: u16,
16    /// Autosave enabled
17    pub autosave: bool,
18    /// Show save dialog
19    pub save_dialog: bool,
20    /// Settling time in milliseconds
21    pub settling_time_ms: f32,
22}
23
24impl Default for GenSwpProps {
25    fn default() -> Self {
26        Self {
27            initial_settling_time_ms: 100.0,
28            max_slew_rate: 1.0,
29            num_steps: 100,
30            period_ms: 50,
31            autosave: true,
32            save_dialog: false,
33            settling_time_ms: 10.0,
34        }
35    }
36}
37
38/// Result data from a generic sweep measurement.
39#[derive(Debug, Clone)]
40pub struct GenSwpResult {
41    /// Names of recorded channels
42    pub channel_names: Vec<String>,
43    /// 2D data array `[rows][columns]`
44    pub data: Vec<Vec<f32>>,
45}
46
47impl NanonisClient {
48    /// Open the Generic Sweeper module.
49    ///
50    /// # Errors
51    /// Returns `NanonisError` if communication fails.
52    ///
53    /// # Examples
54    /// ```no_run
55    /// use nanonis_rs::NanonisClient;
56    ///
57    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
58    /// client.gen_swp_open()?;
59    /// # Ok::<(), Box<dyn std::error::Error>>(())
60    /// ```
61    pub fn gen_swp_open(&mut self) -> Result<(), NanonisError> {
62        self.quick_send("GenSwp.Open", vec![], vec![], vec![])?;
63        Ok(())
64    }
65
66    /// Set the list of recorded channels for the Generic Sweeper.
67    ///
68    /// # Arguments
69    /// * `channel_indexes` - Indexes of channels to record
70    /// * `channel_names` - Names of channels to record
71    ///
72    /// # Errors
73    /// Returns `NanonisError` if communication fails.
74    pub fn gen_swp_acq_chs_set(
75        &mut self,
76        channel_indexes: &[i32],
77        channel_names: &[String],
78    ) -> Result<(), NanonisError> {
79        self.quick_send(
80            "GenSwp.AcqChsSet",
81            vec![
82                NanonisValue::ArrayI32(channel_indexes.to_vec()),
83                NanonisValue::ArrayString(channel_names.to_vec()),
84            ],
85            vec!["+*i", "*+c"],
86            vec![],
87        )?;
88        Ok(())
89    }
90
91    /// Get the list of recorded channels for the Generic Sweeper.
92    ///
93    /// # Returns
94    /// A tuple of (channel_indexes, channel_names).
95    ///
96    /// # Errors
97    /// Returns `NanonisError` if communication fails.
98    pub fn gen_swp_acq_chs_get(&mut self) -> Result<(Vec<i32>, Vec<String>), NanonisError> {
99        let result = self.quick_send(
100            "GenSwp.AcqChsGet",
101            vec![],
102            vec![],
103            vec!["i", "*i", "i", "i", "*+c"],
104        )?;
105
106        if result.len() >= 5 {
107            let indexes = result[1].as_i32_array()?.to_vec();
108            let names = result[4].as_string_array()?.to_vec();
109            Ok((indexes, names))
110        } else {
111            Err(NanonisError::Protocol("Invalid response".to_string()))
112        }
113    }
114
115    /// Set the sweep signal for the Generic Sweeper.
116    ///
117    /// # Arguments
118    /// * `signal_name` - Name of the signal to sweep
119    ///
120    /// # Errors
121    /// Returns `NanonisError` if communication fails.
122    ///
123    /// # Examples
124    /// ```no_run
125    /// use nanonis_rs::NanonisClient;
126    ///
127    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
128    /// client.gen_swp_swp_signal_set("Bias (V)")?;
129    /// # Ok::<(), Box<dyn std::error::Error>>(())
130    /// ```
131    pub fn gen_swp_swp_signal_set(&mut self, signal_name: &str) -> Result<(), NanonisError> {
132        self.quick_send(
133            "GenSwp.SwpSignalSet",
134            vec![NanonisValue::String(signal_name.to_string())],
135            vec!["+*c"],
136            vec![],
137        )?;
138        Ok(())
139    }
140
141    /// Get the selected sweep signal for the Generic Sweeper.
142    ///
143    /// # Returns
144    /// The name of the sweep signal.
145    ///
146    /// # Errors
147    /// Returns `NanonisError` if communication fails.
148    pub fn gen_swp_swp_signal_get(&mut self) -> Result<String, NanonisError> {
149        let result = self.quick_send("GenSwp.SwpSignalGet", vec![], vec![], vec!["i", "*-c"])?;
150
151        if result.len() >= 2 {
152            Ok(result[1].as_string()?.to_string())
153        } else {
154            Err(NanonisError::Protocol("Invalid response".to_string()))
155        }
156    }
157
158    /// Get the list of available sweep signals for the Generic Sweeper.
159    ///
160    /// # Returns
161    /// A vector of available signal names.
162    ///
163    /// # Errors
164    /// Returns `NanonisError` if communication fails.
165    pub fn gen_swp_swp_signal_list_get(&mut self) -> Result<Vec<String>, NanonisError> {
166        let result =
167            self.quick_send("GenSwp.SwpSignalListGet", vec![], vec![], vec!["i", "i", "*+c"])?;
168
169        if result.len() >= 3 {
170            Ok(result[2].as_string_array()?.to_vec())
171        } else {
172            Err(NanonisError::Protocol("Invalid response".to_string()))
173        }
174    }
175
176    /// Set the sweep limits for the Generic Sweeper.
177    ///
178    /// # Arguments
179    /// * `lower_limit` - Lower limit of sweep range
180    /// * `upper_limit` - Upper limit of sweep range
181    ///
182    /// # Errors
183    /// Returns `NanonisError` if communication fails.
184    pub fn gen_swp_limits_set(
185        &mut self,
186        lower_limit: f32,
187        upper_limit: f32,
188    ) -> Result<(), NanonisError> {
189        self.quick_send(
190            "GenSwp.LimitsSet",
191            vec![
192                NanonisValue::F32(lower_limit),
193                NanonisValue::F32(upper_limit),
194            ],
195            vec!["f", "f"],
196            vec![],
197        )?;
198        Ok(())
199    }
200
201    /// Get the sweep limits for the Generic Sweeper.
202    ///
203    /// # Returns
204    /// A tuple of (lower_limit, upper_limit).
205    ///
206    /// # Errors
207    /// Returns `NanonisError` if communication fails.
208    pub fn gen_swp_limits_get(&mut self) -> Result<(f32, f32), NanonisError> {
209        let result = self.quick_send("GenSwp.LimitsGet", vec![], vec![], vec!["f", "f"])?;
210
211        if result.len() >= 2 {
212            Ok((result[0].as_f32()?, result[1].as_f32()?))
213        } else {
214            Err(NanonisError::Protocol("Invalid response".to_string()))
215        }
216    }
217
218    /// Set the Generic Sweeper properties.
219    ///
220    /// # Arguments
221    /// * `props` - A [`GenSwpProps`] struct with configuration
222    ///
223    /// # Errors
224    /// Returns `NanonisError` if communication fails.
225    ///
226    /// # Examples
227    /// ```no_run
228    /// use nanonis_rs::NanonisClient;
229    /// use nanonis_rs::gen_swp::GenSwpProps;
230    ///
231    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
232    /// let props = GenSwpProps {
233    ///     num_steps: 200,
234    ///     period_ms: 100,
235    ///     ..Default::default()
236    /// };
237    /// client.gen_swp_props_set(&props)?;
238    /// # Ok::<(), Box<dyn std::error::Error>>(())
239    /// ```
240    pub fn gen_swp_props_set(&mut self, props: &GenSwpProps) -> Result<(), NanonisError> {
241        let autosave_flag = if props.autosave { 1i32 } else { 2i32 };
242        let dialog_flag = if props.save_dialog { 1i32 } else { 2i32 };
243
244        self.quick_send(
245            "GenSwp.PropsSet",
246            vec![
247                NanonisValue::F32(props.initial_settling_time_ms),
248                NanonisValue::F32(props.max_slew_rate),
249                NanonisValue::I32(props.num_steps),
250                NanonisValue::U16(props.period_ms),
251                NanonisValue::I32(autosave_flag),
252                NanonisValue::I32(dialog_flag),
253                NanonisValue::F32(props.settling_time_ms),
254            ],
255            vec!["f", "f", "i", "H", "i", "i", "f"],
256            vec![],
257        )?;
258        Ok(())
259    }
260
261    /// Get the Generic Sweeper properties.
262    ///
263    /// # Returns
264    /// A [`GenSwpProps`] struct with current configuration.
265    ///
266    /// # Errors
267    /// Returns `NanonisError` if communication fails.
268    pub fn gen_swp_props_get(&mut self) -> Result<GenSwpProps, NanonisError> {
269        let result = self.quick_send(
270            "GenSwp.PropsGet",
271            vec![],
272            vec![],
273            vec!["f", "f", "i", "H", "I", "I", "f"],
274        )?;
275
276        if result.len() >= 7 {
277            Ok(GenSwpProps {
278                initial_settling_time_ms: result[0].as_f32()?,
279                max_slew_rate: result[1].as_f32()?,
280                num_steps: result[2].as_i32()?,
281                period_ms: result[3].as_u16()?,
282                autosave: result[4].as_u32()? != 0,
283                save_dialog: result[5].as_u32()? != 0,
284                settling_time_ms: result[6].as_f32()?,
285            })
286        } else {
287            Err(NanonisError::Protocol("Invalid response".to_string()))
288        }
289    }
290
291    /// Start a sweep in the Generic Sweeper.
292    ///
293    /// # Arguments
294    /// * `get_data` - If true, returns measurement data
295    /// * `sweep_direction` - `true` = lower to upper, `false` = upper to lower
296    /// * `save_base_name` - Base filename for saving (empty for no change)
297    /// * `reset_signal` - Reset signal after sweep
298    /// * `z_controller` - Z-controller behavior: 0=no change, 1=turn off, 2=don't turn off
299    ///
300    /// # Returns
301    /// A [`GenSwpResult`] with channel names and 2D data.
302    ///
303    /// # Errors
304    /// Returns `NanonisError` if communication fails.
305    ///
306    /// # Examples
307    /// ```no_run
308    /// use nanonis_rs::NanonisClient;
309    ///
310    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
311    /// let result = client.gen_swp_start(true, true, "sweep_001", false, 0)?;
312    /// println!("Channels: {:?}", result.channel_names);
313    /// # Ok::<(), Box<dyn std::error::Error>>(())
314    /// ```
315    pub fn gen_swp_start(
316        &mut self,
317        get_data: bool,
318        sweep_direction: bool,
319        save_base_name: &str,
320        reset_signal: bool,
321        z_controller: u16,
322    ) -> Result<GenSwpResult, NanonisError> {
323        let get_data_flag = if get_data { 1u32 } else { 0u32 };
324        let direction_flag = if sweep_direction { 1u32 } else { 0u32 };
325        let reset_flag = if reset_signal { 1u32 } else { 0u32 };
326
327        let result = self.quick_send(
328            "GenSwp.Start",
329            vec![
330                NanonisValue::U32(get_data_flag),
331                NanonisValue::U32(direction_flag),
332                NanonisValue::String(save_base_name.to_string()),
333                NanonisValue::U32(reset_flag),
334                NanonisValue::U16(z_controller),
335            ],
336            vec!["I", "I", "+*c", "I", "H"],
337            vec!["i", "i", "*+c", "i", "i", "2f"],
338        )?;
339
340        if result.len() >= 6 {
341            let channel_names = result[2].as_string_array()?.to_vec();
342            let rows = result[3].as_i32()? as usize;
343            let cols = result[4].as_i32()? as usize;
344
345            let flat_data = result[5].as_f32_array()?;
346            let mut data_2d = Vec::with_capacity(rows);
347            for row in 0..rows {
348                let start_idx = row * cols;
349                let end_idx = start_idx + cols;
350                if end_idx <= flat_data.len() {
351                    data_2d.push(flat_data[start_idx..end_idx].to_vec());
352                }
353            }
354
355            Ok(GenSwpResult {
356                channel_names,
357                data: data_2d,
358            })
359        } else {
360            Ok(GenSwpResult {
361                channel_names: vec![],
362                data: vec![],
363            })
364        }
365    }
366
367    /// Stop the sweep in the Generic Sweeper.
368    ///
369    /// # Errors
370    /// Returns `NanonisError` if communication fails.
371    pub fn gen_swp_stop(&mut self) -> Result<(), NanonisError> {
372        self.quick_send("GenSwp.Stop", vec![], vec![], vec![])?;
373        Ok(())
374    }
375}