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}