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}