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 = self.quick_send(
167            "GenSwp.SwpSignalListGet",
168            vec![],
169            vec![],
170            vec!["i", "i", "*+c"],
171        )?;
172
173        if result.len() >= 3 {
174            Ok(result[2].as_string_array()?.to_vec())
175        } else {
176            Err(NanonisError::Protocol("Invalid response".to_string()))
177        }
178    }
179
180    /// Set the sweep limits for the Generic Sweeper.
181    ///
182    /// # Arguments
183    /// * `lower_limit` - Lower limit of sweep range
184    /// * `upper_limit` - Upper limit of sweep range
185    ///
186    /// # Errors
187    /// Returns `NanonisError` if communication fails.
188    pub fn gen_swp_limits_set(
189        &mut self,
190        lower_limit: f32,
191        upper_limit: f32,
192    ) -> Result<(), NanonisError> {
193        self.quick_send(
194            "GenSwp.LimitsSet",
195            vec![
196                NanonisValue::F32(lower_limit),
197                NanonisValue::F32(upper_limit),
198            ],
199            vec!["f", "f"],
200            vec![],
201        )?;
202        Ok(())
203    }
204
205    /// Get the sweep limits for the Generic Sweeper.
206    ///
207    /// # Returns
208    /// A tuple of (lower_limit, upper_limit).
209    ///
210    /// # Errors
211    /// Returns `NanonisError` if communication fails.
212    pub fn gen_swp_limits_get(&mut self) -> Result<(f32, f32), NanonisError> {
213        let result = self.quick_send("GenSwp.LimitsGet", vec![], vec![], vec!["f", "f"])?;
214
215        if result.len() >= 2 {
216            Ok((result[0].as_f32()?, result[1].as_f32()?))
217        } else {
218            Err(NanonisError::Protocol("Invalid response".to_string()))
219        }
220    }
221
222    /// Set the Generic Sweeper properties.
223    ///
224    /// # Arguments
225    /// * `props` - A [`GenSwpProps`] struct with configuration
226    ///
227    /// # Errors
228    /// Returns `NanonisError` if communication fails.
229    ///
230    /// # Examples
231    /// ```no_run
232    /// use nanonis_rs::NanonisClient;
233    /// use nanonis_rs::gen_swp::GenSwpProps;
234    ///
235    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
236    /// let props = GenSwpProps {
237    ///     num_steps: 200,
238    ///     period_ms: 100,
239    ///     ..Default::default()
240    /// };
241    /// client.gen_swp_props_set(&props)?;
242    /// # Ok::<(), Box<dyn std::error::Error>>(())
243    /// ```
244    pub fn gen_swp_props_set(&mut self, props: &GenSwpProps) -> Result<(), NanonisError> {
245        let autosave_flag = if props.autosave { 1i32 } else { 2i32 };
246        let dialog_flag = if props.save_dialog { 1i32 } else { 2i32 };
247
248        self.quick_send(
249            "GenSwp.PropsSet",
250            vec![
251                NanonisValue::F32(props.initial_settling_time_ms),
252                NanonisValue::F32(props.max_slew_rate),
253                NanonisValue::I32(props.num_steps),
254                NanonisValue::U16(props.period_ms),
255                NanonisValue::I32(autosave_flag),
256                NanonisValue::I32(dialog_flag),
257                NanonisValue::F32(props.settling_time_ms),
258            ],
259            vec!["f", "f", "i", "H", "i", "i", "f"],
260            vec![],
261        )?;
262        Ok(())
263    }
264
265    /// Get the Generic Sweeper properties.
266    ///
267    /// # Returns
268    /// A [`GenSwpProps`] struct with current configuration.
269    ///
270    /// # Errors
271    /// Returns `NanonisError` if communication fails.
272    pub fn gen_swp_props_get(&mut self) -> Result<GenSwpProps, NanonisError> {
273        let result = self.quick_send(
274            "GenSwp.PropsGet",
275            vec![],
276            vec![],
277            vec!["f", "f", "i", "H", "I", "I", "f"],
278        )?;
279
280        if result.len() >= 7 {
281            Ok(GenSwpProps {
282                initial_settling_time_ms: result[0].as_f32()?,
283                max_slew_rate: result[1].as_f32()?,
284                num_steps: result[2].as_i32()?,
285                period_ms: result[3].as_u16()?,
286                autosave: result[4].as_u32()? != 0,
287                save_dialog: result[5].as_u32()? != 0,
288                settling_time_ms: result[6].as_f32()?,
289            })
290        } else {
291            Err(NanonisError::Protocol("Invalid response".to_string()))
292        }
293    }
294
295    /// Start a sweep in the Generic Sweeper.
296    ///
297    /// # Arguments
298    /// * `get_data` - If true, returns measurement data
299    /// * `sweep_direction` - `true` = lower to upper, `false` = upper to lower
300    /// * `save_base_name` - Base filename for saving (empty for no change)
301    /// * `reset_signal` - Reset signal after sweep
302    /// * `z_controller` - Z-controller behavior: 0=no change, 1=turn off, 2=don't turn off
303    ///
304    /// # Returns
305    /// A [`GenSwpResult`] with channel names and 2D data.
306    ///
307    /// # Errors
308    /// Returns `NanonisError` if communication fails.
309    ///
310    /// # Examples
311    /// ```no_run
312    /// use nanonis_rs::NanonisClient;
313    ///
314    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
315    /// let result = client.gen_swp_start(true, true, "sweep_001", false, 0)?;
316    /// println!("Channels: {:?}", result.channel_names);
317    /// # Ok::<(), Box<dyn std::error::Error>>(())
318    /// ```
319    pub fn gen_swp_start(
320        &mut self,
321        get_data: bool,
322        sweep_direction: bool,
323        save_base_name: &str,
324        reset_signal: bool,
325        z_controller: u16,
326    ) -> Result<GenSwpResult, NanonisError> {
327        let get_data_flag = if get_data { 1u32 } else { 0u32 };
328        let direction_flag = if sweep_direction { 1u32 } else { 0u32 };
329        let reset_flag = if reset_signal { 1u32 } else { 0u32 };
330
331        let result = self.quick_send(
332            "GenSwp.Start",
333            vec![
334                NanonisValue::U32(get_data_flag),
335                NanonisValue::U32(direction_flag),
336                NanonisValue::String(save_base_name.to_string()),
337                NanonisValue::U32(reset_flag),
338                NanonisValue::U16(z_controller),
339            ],
340            vec!["I", "I", "+*c", "I", "H"],
341            vec!["i", "i", "*+c", "i", "i", "2f"],
342        )?;
343
344        if result.len() >= 6 {
345            let channel_names = result[2].as_string_array()?.to_vec();
346            let rows = result[3].as_i32()? as usize;
347            let cols = result[4].as_i32()? as usize;
348
349            let flat_data = result[5].as_f32_array()?;
350            let mut data_2d = Vec::with_capacity(rows);
351            for row in 0..rows {
352                let start_idx = row * cols;
353                let end_idx = start_idx + cols;
354                if end_idx <= flat_data.len() {
355                    data_2d.push(flat_data[start_idx..end_idx].to_vec());
356                }
357            }
358
359            Ok(GenSwpResult {
360                channel_names,
361                data: data_2d,
362            })
363        } else {
364            Ok(GenSwpResult {
365                channel_names: vec![],
366                data: vec![],
367            })
368        }
369    }
370
371    /// Stop the sweep in the Generic Sweeper.
372    ///
373    /// # Errors
374    /// Returns `NanonisError` if communication fails.
375    pub fn gen_swp_stop(&mut self) -> Result<(), NanonisError> {
376        self.quick_send("GenSwp.Stop", vec![], vec![], vec![])?;
377        Ok(())
378    }
379}