nanonis_rs/client/z_spectr.rs
1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// Return type for Z spectroscopy start operation (channel names, data, bias values)
6pub type ZSpectroscopyResult = (Vec<String>, Vec<Vec<f32>>, Vec<f32>);
7
8impl NanonisClient {
9 /// Open the Z Spectroscopy module.
10 ///
11 /// Opens and initializes the Z Spectroscopy module for distance-dependent
12 /// measurements. This must be called before performing spectroscopy operations.
13 ///
14 /// # Errors
15 /// Returns `NanonisError` if communication fails or module cannot be opened.
16 ///
17 /// # Examples
18 /// ```no_run
19 /// use nanonis_rs::NanonisClient;
20 ///
21 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
22 ///
23 /// // Open Z spectroscopy module
24 /// client.z_spectr_open()?;
25 /// println!("Z Spectroscopy module opened");
26 /// # Ok::<(), Box<dyn std::error::Error>>(())
27 /// ```
28 pub fn z_spectr_open(&mut self) -> Result<(), NanonisError> {
29 self.quick_send("ZSpectr.Open", vec![], vec![], vec![])?;
30 Ok(())
31 }
32
33 /// Start a Z spectroscopy measurement.
34 ///
35 /// Initiates a Z spectroscopy measurement with the configured parameters.
36 /// The tip is moved through a range of Z positions while recording selected channels.
37 ///
38 /// # Arguments
39 /// * `get_data` - If `true`, returns measurement data; if `false`, only starts measurement
40 /// * `save_base_name` - Base filename for saving data (empty for no change)
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 /// - `Vec<f32>` - Fixed parameters and settings
47 ///
48 /// # Errors
49 /// Returns `NanonisError` if communication fails or measurement cannot start.
50 ///
51 /// # Examples
52 /// ```no_run
53 /// use nanonis_rs::NanonisClient;
54 ///
55 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
56 ///
57 /// // Start measurement and get data
58 /// let (channels, data, params) = client.z_spectr_start(true, "approach_001")?;
59 /// println!("Recorded {} channels with {} points", channels.len(), data.len());
60 ///
61 /// // Just start measurement without getting data
62 /// let (_, _, _) = client.z_spectr_start(false, "")?;
63 /// # Ok::<(), Box<dyn std::error::Error>>(())
64 /// ```
65 pub fn z_spectr_start(
66 &mut self,
67 get_data: bool,
68 save_base_name: &str,
69 ) -> Result<ZSpectroscopyResult, NanonisError> {
70 let get_data_flag = if get_data { 1u32 } else { 0u32 };
71
72 let result = self.quick_send(
73 "ZSpectr.Start",
74 vec![
75 NanonisValue::U32(get_data_flag),
76 NanonisValue::String(save_base_name.to_string()),
77 ],
78 vec!["I", "+*c"],
79 vec!["i", "i", "*+c", "i", "i", "2f", "i", "*f"],
80 )?;
81
82 if result.len() >= 8 {
83 let channel_names = result[2].as_string_array()?.to_vec();
84 let rows = result[3].as_i32()? as usize;
85 let cols = result[4].as_i32()? as usize;
86
87 // Parse 2D data array
88 let flat_data = result[5].as_f32_array()?;
89 let mut data_2d = Vec::with_capacity(rows);
90 for row in 0..rows {
91 let start_idx = row * cols;
92 let end_idx = start_idx + cols;
93 data_2d.push(flat_data[start_idx..end_idx].to_vec());
94 }
95
96 let parameters = result[7].as_f32_array()?.to_vec();
97 Ok((channel_names, data_2d, parameters))
98 } else {
99 Err(NanonisError::Protocol(
100 "Invalid Z spectroscopy start response".to_string(),
101 ))
102 }
103 }
104
105 /// Stop the current Z spectroscopy measurement.
106 ///
107 /// Immediately stops any running Z spectroscopy measurement and returns
108 /// the tip to its original position.
109 ///
110 /// # Errors
111 /// Returns `NanonisError` if communication fails.
112 ///
113 /// # Examples
114 /// ```no_run
115 /// use nanonis_rs::NanonisClient;
116 ///
117 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
118 ///
119 /// // Start a measurement
120 /// let (_, _, _) = client.z_spectr_start(false, "")?;
121 ///
122 /// // Stop it after some condition
123 /// client.z_spectr_stop()?;
124 /// println!("Z spectroscopy stopped");
125 /// # Ok::<(), Box<dyn std::error::Error>>(())
126 /// ```
127 pub fn z_spectr_stop(&mut self) -> Result<(), NanonisError> {
128 self.quick_send("ZSpectr.Stop", vec![], vec![], vec![])?;
129 Ok(())
130 }
131
132 /// Get the status of Z spectroscopy measurement.
133 ///
134 /// Returns whether a Z spectroscopy measurement is currently running.
135 ///
136 /// # Returns
137 /// `true` if measurement is running, `false` if stopped.
138 ///
139 /// # Errors
140 /// Returns `NanonisError` if communication fails.
141 ///
142 /// # Examples
143 /// ```no_run
144 /// use nanonis_rs::NanonisClient;
145 ///
146 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
147 ///
148 /// if client.z_spectr_status_get()? {
149 /// println!("Z spectroscopy is running");
150 /// } else {
151 /// println!("Z spectroscopy is stopped");
152 /// }
153 /// # Ok::<(), Box<dyn std::error::Error>>(())
154 /// ```
155 pub fn z_spectr_status_get(&mut self) -> Result<bool, NanonisError> {
156 let result =
157 self.quick_send("ZSpectr.StatusGet", vec![], vec![], vec!["I"])?;
158
159 match result.first() {
160 Some(value) => Ok(value.as_u32()? == 1),
161 None => Err(NanonisError::Protocol(
162 "No Z spectroscopy status returned".to_string(),
163 )),
164 }
165 }
166
167 /// Set the channels to record during Z spectroscopy.
168 ///
169 /// Configures which signals will be recorded during the Z spectroscopy measurement.
170 /// Channel indexes correspond to the 24 signals assigned in the Signals Manager (0-23).
171 ///
172 /// # Arguments
173 /// * `channel_indexes` - Vector of channel indexes to record (0-23)
174 ///
175 /// # Errors
176 /// Returns `NanonisError` if communication fails or invalid channel indexes provided.
177 ///
178 /// # Examples
179 /// ```no_run
180 /// use nanonis_rs::NanonisClient;
181 ///
182 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
183 ///
184 /// // Record current (0), Z position (1), and bias voltage (2)
185 /// client.z_spectr_chs_set(vec![0, 1, 2])?;
186 ///
187 /// // Record more comprehensive dataset
188 /// client.z_spectr_chs_set(vec![0, 1, 2, 3, 4, 5])?;
189 /// # Ok::<(), Box<dyn std::error::Error>>(())
190 /// ```
191 pub fn z_spectr_chs_set(
192 &mut self,
193 channel_indexes: Vec<i32>,
194 ) -> Result<(), NanonisError> {
195 self.quick_send(
196 "ZSpectr.ChsSet",
197 vec![NanonisValue::ArrayI32(channel_indexes)],
198 vec!["+*i"],
199 vec![],
200 )?;
201 Ok(())
202 }
203
204 /// Get the channels configured for Z spectroscopy recording.
205 ///
206 /// Returns the channel indexes and names that will be recorded during measurements.
207 ///
208 /// # Returns
209 /// A tuple containing:
210 /// - `Vec<i32>` - Channel indexes (0-23 for Signals Manager slots)
211 /// - `Vec<String>` - Channel names corresponding to the indexes
212 ///
213 /// # Errors
214 /// Returns `NanonisError` if communication fails.
215 ///
216 /// # Examples
217 /// ```no_run
218 /// use nanonis_rs::NanonisClient;
219 ///
220 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
221 ///
222 /// let (indexes, names) = client.z_spectr_chs_get()?;
223 /// println!("Recording {} channels:", indexes.len());
224 /// for (idx, name) in indexes.iter().zip(names.iter()) {
225 /// println!(" Channel {}: {}", idx, name);
226 /// }
227 /// # Ok::<(), Box<dyn std::error::Error>>(())
228 /// ```
229 pub fn z_spectr_chs_get(
230 &mut self,
231 ) -> Result<(Vec<i32>, Vec<String>), NanonisError> {
232 let result = self.quick_send(
233 "ZSpectr.ChsGet",
234 vec![],
235 vec![],
236 vec!["i", "*i", "i", "i", "*+c"],
237 )?;
238
239 if result.len() >= 5 {
240 let channel_indexes = result[1].as_i32_array()?.to_vec();
241 let channel_names = result[4].as_string_array()?.to_vec();
242 Ok((channel_indexes, channel_names))
243 } else {
244 Err(NanonisError::Protocol(
245 "Invalid Z spectroscopy channels response".to_string(),
246 ))
247 }
248 }
249
250 /// Set the Z range for spectroscopy measurements.
251 ///
252 /// Configures the Z offset and sweep distance for the spectroscopy measurement.
253 /// The tip will move from (offset - distance/2) to (offset + distance/2).
254 ///
255 /// # Arguments
256 /// * `z_offset_m` - Z offset position in meters (center of sweep)
257 /// * `z_sweep_distance_m` - Total sweep distance in meters
258 ///
259 /// # Errors
260 /// Returns `NanonisError` if communication fails or invalid range parameters.
261 ///
262 /// # Examples
263 /// ```no_run
264 /// use nanonis_rs::NanonisClient;
265 ///
266 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
267 ///
268 /// // Sweep ±5 nm around current position
269 /// client.z_spectr_range_set(0.0, 10e-9)?;
270 ///
271 /// // Sweep from current position up to +20 nm
272 /// client.z_spectr_range_set(10e-9, 20e-9)?;
273 /// # Ok::<(), Box<dyn std::error::Error>>(())
274 /// ```
275 pub fn z_spectr_range_set(
276 &mut self,
277 z_offset_m: f32,
278 z_sweep_distance_m: f32,
279 ) -> Result<(), NanonisError> {
280 self.quick_send(
281 "ZSpectr.RangeSet",
282 vec![
283 NanonisValue::F32(z_offset_m),
284 NanonisValue::F32(z_sweep_distance_m),
285 ],
286 vec!["f", "f"],
287 vec![],
288 )?;
289 Ok(())
290 }
291
292 /// Get the current Z range configuration for spectroscopy.
293 ///
294 /// Returns the configured Z offset and sweep distance.
295 ///
296 /// # Returns
297 /// A tuple containing:
298 /// - `f32` - Z offset in meters (center position)
299 /// - `f32` - Z sweep distance in meters (total range)
300 ///
301 /// # Errors
302 /// Returns `NanonisError` if communication fails.
303 ///
304 /// # Examples
305 /// ```no_run
306 /// use nanonis_rs::NanonisClient;
307 ///
308 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
309 ///
310 /// let (offset, distance) = client.z_spectr_range_get()?;
311 /// println!("Z sweep: {:.1} nm ± {:.1} nm", offset * 1e9, distance * 1e9 / 2.0);
312 /// # Ok::<(), Box<dyn std::error::Error>>(())
313 /// ```
314 pub fn z_spectr_range_get(&mut self) -> Result<(f32, f32), NanonisError> {
315 let result =
316 self.quick_send("ZSpectr.RangeGet", vec![], vec![], vec!["f", "f"])?;
317
318 if result.len() >= 2 {
319 Ok((result[0].as_f32()?, result[1].as_f32()?))
320 } else {
321 Err(NanonisError::Protocol(
322 "Invalid Z spectroscopy range response".to_string(),
323 ))
324 }
325 }
326
327 /// Set the timing parameters for Z spectroscopy.
328 ///
329 /// Configures timing-related parameters that control the speed and quality
330 /// of the Z spectroscopy measurement.
331 ///
332 /// # Arguments
333 /// * `z_averaging_time_s` - Time to average signals at each Z position
334 /// * `initial_settling_time_s` - Initial settling time before measurement
335 /// * `maximum_slew_rate_vdivs` - Maximum slew rate in V/s
336 /// * `settling_time_s` - Settling time between measurement points
337 /// * `integration_time_s` - Integration time for each measurement point
338 /// * `end_settling_time_s` - Settling time at the end of sweep
339 ///
340 /// # Errors
341 /// Returns `NanonisError` if communication fails or invalid timing parameters.
342 ///
343 /// # Examples
344 /// ```no_run
345 /// use nanonis_rs::NanonisClient;
346 ///
347 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
348 ///
349 /// // Fast spectroscopy settings
350 /// client.z_spectr_timing_set(0.01, 0.1, 1000.0, 0.01, 0.01, 0.1)?;
351 ///
352 /// // High-quality slow spectroscopy
353 /// client.z_spectr_timing_set(0.1, 0.5, 100.0, 0.05, 0.05, 0.2)?;
354 /// # Ok::<(), Box<dyn std::error::Error>>(())
355 /// ```
356 pub fn z_spectr_timing_set(
357 &mut self,
358 z_averaging_time_s: f32,
359 initial_settling_time_s: f32,
360 maximum_slew_rate_vdivs: f32,
361 settling_time_s: f32,
362 integration_time_s: f32,
363 end_settling_time_s: f32,
364 ) -> Result<(), NanonisError> {
365 self.quick_send(
366 "ZSpectr.TimingSet",
367 vec![
368 NanonisValue::F32(z_averaging_time_s),
369 NanonisValue::F32(initial_settling_time_s),
370 NanonisValue::F32(maximum_slew_rate_vdivs),
371 NanonisValue::F32(settling_time_s),
372 NanonisValue::F32(integration_time_s),
373 NanonisValue::F32(end_settling_time_s),
374 ],
375 vec!["f", "f", "f", "f", "f", "f"],
376 vec![],
377 )?;
378 Ok(())
379 }
380
381 /// Get the current timing parameters for Z spectroscopy.
382 ///
383 /// Returns all timing-related configuration parameters.
384 ///
385 /// # Returns
386 /// A tuple containing:
387 /// - `f32` - Z averaging time (s)
388 /// - `f32` - Initial settling time (s)
389 /// - `f32` - Maximum slew rate (V/s)
390 /// - `f32` - Settling time (s)
391 /// - `f32` - Integration time (s)
392 /// - `f32` - End settling time (s)
393 ///
394 /// # Errors
395 /// Returns `NanonisError` if communication fails.
396 ///
397 /// # Examples
398 /// ```no_run
399 /// use nanonis_rs::NanonisClient;
400 ///
401 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
402 ///
403 /// let (z_avg, init_settle, slew_rate, settle, integrate, end_settle) =
404 /// client.z_spectr_timing_get()?;
405 /// println!("Integration time: {:.3} s, settling: {:.3} s", integrate, settle);
406 /// # Ok::<(), Box<dyn std::error::Error>>(())
407 /// ```
408 pub fn z_spectr_timing_get(
409 &mut self,
410 ) -> Result<(f32, f32, f32, f32, f32, f32), NanonisError> {
411 let result = self.quick_send(
412 "ZSpectr.TimingGet",
413 vec![],
414 vec![],
415 vec!["f", "f", "f", "f", "f", "f"],
416 )?;
417
418 if result.len() >= 6 {
419 Ok((
420 result[0].as_f32()?,
421 result[1].as_f32()?,
422 result[2].as_f32()?,
423 result[3].as_f32()?,
424 result[4].as_f32()?,
425 result[5].as_f32()?,
426 ))
427 } else {
428 Err(NanonisError::Protocol(
429 "Invalid Z spectroscopy timing response".to_string(),
430 ))
431 }
432 }
433
434 /// Set the retraction parameters for tip protection during Z spectroscopy.
435 ///
436 /// Configures automatic tip retraction based on signal thresholds to prevent
437 /// tip crashes during approach spectroscopy.
438 ///
439 /// # Arguments
440 /// * `enable` - Enable/disable automatic retraction
441 /// * `threshold` - Signal threshold value for retraction trigger
442 /// * `signal_index` - Index of signal to monitor (0-23)
443 /// * `comparison` - Comparison type: 0=greater than, 1=less than
444 ///
445 /// # Errors
446 /// Returns `NanonisError` if communication fails or invalid parameters.
447 ///
448 /// # Examples
449 /// ```no_run
450 /// use nanonis_rs::NanonisClient;
451 ///
452 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
453 ///
454 /// // Enable retraction when current exceeds 1 nA (signal 0, greater than)
455 /// client.z_spectr_retract_set(true, 1e-9, 0, 0)?;
456 ///
457 /// // Disable retraction
458 /// client.z_spectr_retract_set(false, 0.0, 0, 0)?;
459 /// # Ok::<(), Box<dyn std::error::Error>>(())
460 /// ```
461 pub fn z_spectr_retract_set(
462 &mut self,
463 enable: bool,
464 threshold: f32,
465 signal_index: i32,
466 comparison: u16,
467 ) -> Result<(), NanonisError> {
468 let enable_flag = if enable { 1u16 } else { 0u16 };
469
470 self.quick_send(
471 "ZSpectr.RetractSet",
472 vec![
473 NanonisValue::U16(enable_flag),
474 NanonisValue::F32(threshold),
475 NanonisValue::I32(signal_index),
476 NanonisValue::U16(comparison),
477 ],
478 vec!["H", "f", "i", "H"],
479 vec![],
480 )?;
481 Ok(())
482 }
483
484 /// Get the current retraction configuration for Z spectroscopy.
485 ///
486 /// Returns the tip protection settings that prevent crashes during measurements.
487 ///
488 /// # Returns
489 /// A tuple containing:
490 /// - `bool` - Retraction enabled/disabled
491 /// - `f32` - Threshold value for retraction
492 /// - `i32` - Signal index being monitored
493 /// - `u16` - Comparison type (0=greater, 1=less than)
494 ///
495 /// # Errors
496 /// Returns `NanonisError` if communication fails.
497 ///
498 /// # Examples
499 /// ```no_run
500 /// use nanonis_rs::NanonisClient;
501 ///
502 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
503 ///
504 /// let (enabled, threshold, signal_idx, comparison) = client.z_spectr_retract_get()?;
505 /// if enabled {
506 /// let comp_str = if comparison == 0 { ">" } else { "<" };
507 /// println!("Retraction: signal[{}] {} {:.3e}", signal_idx, comp_str, threshold);
508 /// }
509 /// # Ok::<(), Box<dyn std::error::Error>>(())
510 /// ```
511 pub fn z_spectr_retract_get(
512 &mut self,
513 ) -> Result<(bool, f32, i32, u16), NanonisError> {
514 let result = self.quick_send(
515 "ZSpectr.RetractGet",
516 vec![],
517 vec![],
518 vec!["H", "f", "i", "H"],
519 )?;
520
521 if result.len() >= 4 {
522 let enabled = result[0].as_u16()? == 1;
523 let threshold = result[1].as_f32()?;
524 let signal_index = result[2].as_i32()?;
525 let comparison = result[3].as_u16()?;
526 Ok((enabled, threshold, signal_index, comparison))
527 } else {
528 Err(NanonisError::Protocol(
529 "Invalid Z spectroscopy retract response".to_string(),
530 ))
531 }
532 }
533
534 /// Set the Z spectroscopy properties.
535 ///
536 /// # Arguments
537 /// * `backward_sweep` - 0=no change, 1=enable backward sweep, 2=disable
538 /// * `num_points` - Number of points (0=no change)
539 /// * `num_sweeps` - Number of sweeps to average (0=no change)
540 /// * `autosave` - 0=no change, 1=enable autosave, 2=disable
541 /// * `show_save_dialog` - 0=no change, 1=show dialog, 2=don't show
542 /// * `save_all` - 0=no change, 1=save individual sweeps, 2=don't save
543 ///
544 /// # Errors
545 /// Returns `NanonisError` if communication fails.
546 pub fn z_spectr_props_set(
547 &mut self,
548 backward_sweep: u16,
549 num_points: i32,
550 num_sweeps: u16,
551 autosave: u16,
552 show_save_dialog: u16,
553 save_all: u16,
554 ) -> Result<(), NanonisError> {
555 self.quick_send(
556 "ZSpectr.PropsSet",
557 vec![
558 NanonisValue::U16(backward_sweep),
559 NanonisValue::I32(num_points),
560 NanonisValue::U16(num_sweeps),
561 NanonisValue::U16(autosave),
562 NanonisValue::U16(show_save_dialog),
563 NanonisValue::U16(save_all),
564 ],
565 vec!["H", "i", "H", "H", "H", "H"],
566 vec![],
567 )?;
568 Ok(())
569 }
570
571 /// Get the Z spectroscopy properties.
572 ///
573 /// Returns the current property configuration.
574 ///
575 /// # Returns
576 /// A tuple containing:
577 /// - `bool` - Backward sweep enabled
578 /// - `i32` - Number of points
579 /// - `u16` - Number of sweeps to average
580 /// - `bool` - Autosave enabled
581 /// - `bool` - Show save dialog
582 /// - `bool` - Save all individual sweeps
583 ///
584 /// # Errors
585 /// Returns `NanonisError` if communication fails.
586 ///
587 /// # Examples
588 /// ```no_run
589 /// use nanonis_rs::NanonisClient;
590 ///
591 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
592 ///
593 /// let (backward, points, sweeps, autosave, dialog, save_all) =
594 /// client.z_spectr_props_get()?;
595 /// println!("Points: {}, Sweeps: {}, Backward: {}", points, sweeps, backward);
596 /// # Ok::<(), Box<dyn std::error::Error>>(())
597 /// ```
598 pub fn z_spectr_props_get(
599 &mut self,
600 ) -> Result<(bool, i32, u16, bool, bool, bool), NanonisError> {
601 let result = self.quick_send(
602 "ZSpectr.PropsGet",
603 vec![],
604 vec![],
605 vec!["H", "i", "H", "I", "I", "I"],
606 )?;
607
608 if result.len() >= 6 {
609 Ok((
610 result[0].as_u16()? != 0,
611 result[1].as_i32()?,
612 result[2].as_u16()?,
613 result[3].as_u32()? != 0,
614 result[4].as_u32()? != 0,
615 result[5].as_u32()? != 0,
616 ))
617 } else {
618 Err(NanonisError::Protocol(
619 "Invalid Z spectroscopy props response".to_string(),
620 ))
621 }
622 }
623
624 /// Set the advanced Z spectroscopy properties.
625 ///
626 /// # Arguments
627 /// * `time_between_sweeps_s` - Time between forward and backward sweep
628 /// * `record_final_z` - 0=no change, 1=on, 2=off
629 /// * `lockin_run` - 0=no change, 1=on, 2=off
630 /// * `reset_z` - 0=no change, 1=on, 2=off
631 ///
632 /// # Errors
633 /// Returns `NanonisError` if communication fails.
634 pub fn z_spectr_adv_props_set(
635 &mut self,
636 time_between_sweeps_s: f32,
637 record_final_z: u16,
638 lockin_run: u16,
639 reset_z: u16,
640 ) -> Result<(), NanonisError> {
641 self.quick_send(
642 "ZSpectr.AdvPropsSet",
643 vec![
644 NanonisValue::F32(time_between_sweeps_s),
645 NanonisValue::U16(record_final_z),
646 NanonisValue::U16(lockin_run),
647 NanonisValue::U16(reset_z),
648 ],
649 vec!["f", "H", "H", "H"],
650 vec![],
651 )?;
652 Ok(())
653 }
654
655 /// Get the advanced Z spectroscopy properties.
656 ///
657 /// # Returns
658 /// Tuple of (time_between_sweeps, record_final_z, lockin_run, reset_z).
659 ///
660 /// # Errors
661 /// Returns `NanonisError` if communication fails.
662 pub fn z_spectr_adv_props_get(&mut self) -> Result<(f32, bool, bool, bool), NanonisError> {
663 let result = self.quick_send(
664 "ZSpectr.AdvPropsGet",
665 vec![],
666 vec![],
667 vec!["f", "H", "H", "H"],
668 )?;
669
670 Ok((
671 result[0].as_f32()?,
672 result[1].as_u16()? != 0,
673 result[2].as_u16()? != 0,
674 result[3].as_u16()? != 0,
675 ))
676 }
677
678 /// Set the retract delay.
679 ///
680 /// # Arguments
681 /// * `delay_s` - Delay in seconds between forward and backward sweep
682 ///
683 /// # Errors
684 /// Returns `NanonisError` if communication fails.
685 pub fn z_spectr_retract_delay_set(&mut self, delay_s: f32) -> Result<(), NanonisError> {
686 self.quick_send(
687 "ZSpectr.RetractDelaySet",
688 vec![NanonisValue::F32(delay_s)],
689 vec!["f"],
690 vec![],
691 )?;
692 Ok(())
693 }
694
695 /// Get the retract delay.
696 ///
697 /// # Returns
698 /// Delay in seconds.
699 ///
700 /// # Errors
701 /// Returns `NanonisError` if communication fails.
702 pub fn z_spectr_retract_delay_get(&mut self) -> Result<f32, NanonisError> {
703 let result = self.quick_send("ZSpectr.RetractDelayGet", vec![], vec![], vec!["f"])?;
704 result[0].as_f32()
705 }
706
707 /// Set the second retraction condition.
708 ///
709 /// # Arguments
710 /// * `condition` - 0=no change, 1=disabled, 2=OR, 3=AND, 4=THEN
711 /// * `threshold` - Threshold value
712 /// * `signal_index` - Signal index (0-127, -1 for no change)
713 /// * `comparison` - 0=greater than, 1=less than, 2=no change
714 ///
715 /// # Errors
716 /// Returns `NanonisError` if communication fails.
717 pub fn z_spectr_retract_second_set(
718 &mut self,
719 condition: i32,
720 threshold: f32,
721 signal_index: i32,
722 comparison: u16,
723 ) -> Result<(), NanonisError> {
724 self.quick_send(
725 "ZSpectr.RetractSecondSet",
726 vec![
727 NanonisValue::I32(condition),
728 NanonisValue::F32(threshold),
729 NanonisValue::I32(signal_index),
730 NanonisValue::U16(comparison),
731 ],
732 vec!["i", "f", "i", "H"],
733 vec![],
734 )?;
735 Ok(())
736 }
737
738 /// Get the second retraction condition.
739 ///
740 /// # Returns
741 /// Tuple of (condition, threshold, signal_index, comparison).
742 ///
743 /// # Errors
744 /// Returns `NanonisError` if communication fails.
745 pub fn z_spectr_retract_second_get(&mut self) -> Result<(i32, f32, i32, u16), NanonisError> {
746 let result = self.quick_send(
747 "ZSpectr.RetractSecondGet",
748 vec![],
749 vec![],
750 vec!["i", "f", "i", "H"],
751 )?;
752
753 Ok((
754 result[0].as_i32()?,
755 result[1].as_f32()?,
756 result[2].as_i32()?,
757 result[3].as_u16()?,
758 ))
759 }
760
761 /// Set the digital synchronization mode.
762 ///
763 /// # Arguments
764 /// * `dig_sync` - 0=no change, 1=off, 2=TTL sync, 3=pulse sequence
765 ///
766 /// # Errors
767 /// Returns `NanonisError` if communication fails.
768 pub fn z_spectr_dig_sync_set(&mut self, dig_sync: u16) -> Result<(), NanonisError> {
769 self.quick_send(
770 "ZSpectr.DigSyncSet",
771 vec![NanonisValue::U16(dig_sync)],
772 vec!["H"],
773 vec![],
774 )?;
775 Ok(())
776 }
777
778 /// Get the digital synchronization mode.
779 ///
780 /// # Returns
781 /// Sync mode (0=off, 1=TTL sync, 2=pulse sequence).
782 ///
783 /// # Errors
784 /// Returns `NanonisError` if communication fails.
785 pub fn z_spectr_dig_sync_get(&mut self) -> Result<u16, NanonisError> {
786 let result = self.quick_send("ZSpectr.DigSyncGet", vec![], vec![], vec!["H"])?;
787 result[0].as_u16()
788 }
789
790 /// Set the TTL synchronization parameters.
791 ///
792 /// # Arguments
793 /// * `ttl_line` - 0=no change, 1-4=HS line number
794 /// * `polarity` - 0=no change, 1=low active, 2=high active
795 /// * `time_to_on_s` - Time to wait before activation
796 /// * `on_duration_s` - Duration of activation
797 ///
798 /// # Errors
799 /// Returns `NanonisError` if communication fails.
800 pub fn z_spectr_ttl_sync_set(
801 &mut self,
802 ttl_line: u16,
803 polarity: u16,
804 time_to_on_s: f32,
805 on_duration_s: f32,
806 ) -> Result<(), NanonisError> {
807 self.quick_send(
808 "ZSpectr.TTLSyncSet",
809 vec![
810 NanonisValue::U16(ttl_line),
811 NanonisValue::U16(polarity),
812 NanonisValue::F32(time_to_on_s),
813 NanonisValue::F32(on_duration_s),
814 ],
815 vec!["H", "H", "f", "f"],
816 vec![],
817 )?;
818 Ok(())
819 }
820
821 /// Get the TTL synchronization parameters.
822 ///
823 /// # Returns
824 /// Tuple of (ttl_line, polarity, time_to_on_s, on_duration_s).
825 ///
826 /// # Errors
827 /// Returns `NanonisError` if communication fails.
828 pub fn z_spectr_ttl_sync_get(&mut self) -> Result<(u16, u16, f32, f32), NanonisError> {
829 let result = self.quick_send(
830 "ZSpectr.TTLSyncGet",
831 vec![],
832 vec![],
833 vec!["H", "H", "f", "f"],
834 )?;
835
836 Ok((
837 result[0].as_u16()?,
838 result[1].as_u16()?,
839 result[2].as_f32()?,
840 result[3].as_f32()?,
841 ))
842 }
843
844 /// Set the pulse sequence synchronization.
845 ///
846 /// # Arguments
847 /// * `pulse_seq_nr` - Pulse sequence number (0=no change)
848 /// * `num_periods` - Number of periods
849 ///
850 /// # Errors
851 /// Returns `NanonisError` if communication fails.
852 pub fn z_spectr_pulse_seq_sync_set(
853 &mut self,
854 pulse_seq_nr: u16,
855 num_periods: u32,
856 ) -> Result<(), NanonisError> {
857 self.quick_send(
858 "ZSpectr.PulseSeqSyncSet",
859 vec![
860 NanonisValue::U16(pulse_seq_nr),
861 NanonisValue::U32(num_periods),
862 ],
863 vec!["H", "I"],
864 vec![],
865 )?;
866 Ok(())
867 }
868
869 /// Get the pulse sequence synchronization.
870 ///
871 /// # Returns
872 /// Tuple of (pulse_seq_nr, num_periods).
873 ///
874 /// # Errors
875 /// Returns `NanonisError` if communication fails.
876 pub fn z_spectr_pulse_seq_sync_get(&mut self) -> Result<(u16, u32), NanonisError> {
877 let result = self.quick_send(
878 "ZSpectr.PulseSeqSyncGet",
879 vec![],
880 vec![],
881 vec!["H", "I"],
882 )?;
883
884 Ok((result[0].as_u16()?, result[1].as_u32()?))
885 }
886}