Skip to main content

nanonis_rs/client/
hs_swp.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// Comparison condition for auto-reverse.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum ReverseCondition {
8    /// Signal greater than threshold
9    #[default]
10    GreaterThan = 0,
11    /// Signal less than threshold
12    LessThan = 1,
13}
14
15impl From<ReverseCondition> for i32 {
16    fn from(c: ReverseCondition) -> Self {
17        c as i32
18    }
19}
20
21impl TryFrom<i32> for ReverseCondition {
22    type Error = NanonisError;
23
24    fn try_from(value: i32) -> Result<Self, Self::Error> {
25        match value {
26            0 => Ok(ReverseCondition::GreaterThan),
27            1 => Ok(ReverseCondition::LessThan),
28            _ => Err(NanonisError::Protocol(format!(
29                "Invalid ReverseCondition value: {}",
30                value
31            ))),
32        }
33    }
34}
35
36/// Linkage mode for second auto-reverse condition.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
38pub enum ConditionLinkage {
39    /// No second condition
40    #[default]
41    Off = 0,
42    /// Either condition 1 or 2 must be met
43    Or = 1,
44    /// Both conditions must be met simultaneously
45    And = 2,
46    /// Condition 1 must be met first, then condition 2
47    Then = 3,
48}
49
50impl From<ConditionLinkage> for i32 {
51    fn from(l: ConditionLinkage) -> Self {
52        l as i32
53    }
54}
55
56impl TryFrom<i32> for ConditionLinkage {
57    type Error = NanonisError;
58
59    fn try_from(value: i32) -> Result<Self, Self::Error> {
60        match value {
61            0 => Ok(ConditionLinkage::Off),
62            1 => Ok(ConditionLinkage::Or),
63            2 => Ok(ConditionLinkage::And),
64            3 => Ok(ConditionLinkage::Then),
65            _ => Err(NanonisError::Protocol(format!(
66                "Invalid ConditionLinkage value: {}",
67                value
68            ))),
69        }
70    }
71}
72
73/// Auto-reverse configuration for high-speed sweeper.
74#[derive(Debug, Clone, Copy, Default)]
75pub struct HSSwpAutoReverse {
76    /// Enable auto-reverse
77    pub enabled: bool,
78    /// First condition comparison type
79    pub condition: ReverseCondition,
80    /// First condition signal index
81    pub signal_index: i32,
82    /// First condition threshold
83    pub threshold: f32,
84    /// Linkage to second condition
85    pub linkage: ConditionLinkage,
86    /// Second condition comparison type
87    pub condition2: ReverseCondition,
88    /// Second condition signal index
89    pub signal2_index: i32,
90    /// Second condition threshold
91    pub threshold2: f32,
92}
93
94/// Sweep timing parameters.
95#[derive(Debug, Clone, Copy, Default)]
96pub struct HSSwpTiming {
97    /// Initial settling time in seconds
98    pub initial_settling_s: f32,
99    /// Settling time in seconds
100    pub settling_s: f32,
101    /// Integration time in seconds
102    pub integration_s: f32,
103    /// Maximum slew rate in units/s
104    pub max_slew_rate: f32,
105}
106
107/// Sweep channel limits configuration.
108#[derive(Debug, Clone, Copy, Default)]
109pub struct HSSwpLimits {
110    /// Use relative limits (vs absolute)
111    pub relative: bool,
112    /// Start value
113    pub start: f32,
114    /// Stop value
115    pub stop: f32,
116}
117
118/// Z-controller behavior during sweep.
119#[derive(Debug, Clone, Copy, Default)]
120pub struct HSSwpZCtrl {
121    /// Whether to switch off Z-controller during sweep
122    pub switch_off: bool,
123    /// Z-controller index (1 = tip 1, 2-4 for multiprobe)
124    pub controller_index: i32,
125    /// Time to average Z position before switch-off
126    pub averaging_time_s: f32,
127    /// Z offset for tip retraction
128    pub z_offset_m: f32,
129    /// Time to wait after switching back on
130    pub control_time_s: f32,
131}
132
133/// Available channels information.
134#[derive(Debug, Clone, Default)]
135pub struct HSSwpAvailableChannels {
136    /// Currently selected channel indices
137    pub selected_indices: Vec<u32>,
138    /// Names of available channels
139    pub available_names: Vec<String>,
140    /// Indices of available channels
141    pub available_indices: Vec<i32>,
142}
143
144/// Sweep signal information.
145#[derive(Debug, Clone, Default)]
146pub struct HSSwpSignalList {
147    /// Signal names
148    pub names: Vec<String>,
149    /// Signal indices
150    pub indices: Vec<i32>,
151}
152
153/// Save options configuration.
154#[derive(Debug, Clone, Default)]
155pub struct HSSwpSaveOptions {
156    /// Comment for file header
157    pub comment: String,
158    /// Module names for parameters to save
159    pub modules: Vec<String>,
160}
161
162impl NanonisClient {
163    /// Set the acquisition channels for the high-speed sweeper.
164    ///
165    /// # Arguments
166    /// * `channel_indices` - Indices of channels to record
167    ///
168    /// # Errors
169    /// Returns `NanonisError` if communication fails.
170    pub fn hs_swp_acq_chs_set(&mut self, channel_indices: &[i32]) -> Result<(), NanonisError> {
171        self.quick_send(
172            "HSSwp.AcqChsSet",
173            vec![NanonisValue::ArrayI32(channel_indices.to_vec())],
174            vec!["+*i"],
175            vec![],
176        )?;
177        Ok(())
178    }
179
180    /// Get the acquisition channels for the high-speed sweeper.
181    ///
182    /// # Returns
183    /// An [`HSSwpAvailableChannels`] struct with channel information.
184    ///
185    /// # Errors
186    /// Returns `NanonisError` if communication fails.
187    pub fn hs_swp_acq_chs_get(&mut self) -> Result<HSSwpAvailableChannels, NanonisError> {
188        let result = self.quick_send(
189            "HSSwp.AcqChsGet",
190            vec![],
191            vec![],
192            vec!["i", "*I", "i", "i", "*+c", "i", "*i"],
193        )?;
194
195        if result.len() >= 7 {
196            Ok(HSSwpAvailableChannels {
197                selected_indices: result[1].as_u32_array()?.to_vec(),
198                available_names: result[4].as_string_array()?.to_vec(),
199                available_indices: result[6].as_i32_array()?.to_vec(),
200            })
201        } else {
202            Err(NanonisError::Protocol("Invalid response".to_string()))
203        }
204    }
205
206    /// Set the auto-reverse configuration.
207    ///
208    /// # Arguments
209    /// * `config` - Auto-reverse configuration
210    ///
211    /// # Errors
212    /// Returns `NanonisError` if communication fails.
213    pub fn hs_swp_auto_reverse_set(
214        &mut self,
215        config: &HSSwpAutoReverse,
216    ) -> Result<(), NanonisError> {
217        let on_off = if config.enabled { 1i32 } else { 0i32 };
218        self.quick_send(
219            "HSSwp.AutoReverseSet",
220            vec![
221                NanonisValue::I32(on_off),
222                NanonisValue::I32(config.condition.into()),
223                NanonisValue::I32(config.signal_index),
224                NanonisValue::F32(config.threshold),
225                NanonisValue::I32(config.linkage.into()),
226                NanonisValue::I32(config.condition2.into()),
227                NanonisValue::I32(config.signal2_index),
228                NanonisValue::F32(config.threshold2),
229            ],
230            vec!["i", "i", "i", "f", "i", "i", "i", "f"],
231            vec![],
232        )?;
233        Ok(())
234    }
235
236    /// Get the auto-reverse configuration.
237    ///
238    /// # Returns
239    /// An [`HSSwpAutoReverse`] struct with current configuration.
240    ///
241    /// # Errors
242    /// Returns `NanonisError` if communication fails.
243    pub fn hs_swp_auto_reverse_get(&mut self) -> Result<HSSwpAutoReverse, NanonisError> {
244        let result = self.quick_send(
245            "HSSwp.AutoReverseGet",
246            vec![],
247            vec![],
248            vec!["i", "i", "i", "f", "i", "i", "i", "f"],
249        )?;
250
251        if result.len() >= 8 {
252            Ok(HSSwpAutoReverse {
253                enabled: result[0].as_i32()? != 0,
254                condition: result[1].as_i32()?.try_into()?,
255                signal_index: result[2].as_i32()?,
256                threshold: result[3].as_f32()?,
257                linkage: result[4].as_i32()?.try_into()?,
258                condition2: result[5].as_i32()?.try_into()?,
259                signal2_index: result[6].as_i32()?,
260                threshold2: result[7].as_f32()?,
261            })
262        } else {
263            Err(NanonisError::Protocol("Invalid response".to_string()))
264        }
265    }
266
267    /// Set the end settling time.
268    ///
269    /// # Arguments
270    /// * `time_s` - End settling time in seconds
271    ///
272    /// # Errors
273    /// Returns `NanonisError` if communication fails.
274    pub fn hs_swp_end_settl_set(&mut self, time_s: f32) -> Result<(), NanonisError> {
275        self.quick_send(
276            "HSSwp.EndSettlSet",
277            vec![NanonisValue::F32(time_s)],
278            vec!["f"],
279            vec![],
280        )?;
281        Ok(())
282    }
283
284    /// Get the end settling time.
285    ///
286    /// # Returns
287    /// End settling time in seconds.
288    ///
289    /// # Errors
290    /// Returns `NanonisError` if communication fails.
291    pub fn hs_swp_end_settl_get(&mut self) -> Result<f32, NanonisError> {
292        let result = self.quick_send("HSSwp.EndSettlGet", vec![], vec![], vec!["f"])?;
293
294        if !result.is_empty() {
295            Ok(result[0].as_f32()?)
296        } else {
297            Err(NanonisError::Protocol("Invalid response".to_string()))
298        }
299    }
300
301    /// Set the number of sweeps.
302    ///
303    /// # Arguments
304    /// * `num_sweeps` - Number of sweeps (ignored if continuous)
305    /// * `continuous` - Enable continuous sweep mode
306    ///
307    /// # Errors
308    /// Returns `NanonisError` if communication fails.
309    pub fn hs_swp_num_sweeps_set(
310        &mut self,
311        num_sweeps: u32,
312        continuous: bool,
313    ) -> Result<(), NanonisError> {
314        let cont_flag = if continuous { 1i32 } else { 0i32 };
315        self.quick_send(
316            "HSSwp.NumSweepsSet",
317            vec![NanonisValue::U32(num_sweeps), NanonisValue::I32(cont_flag)],
318            vec!["I", "i"],
319            vec![],
320        )?;
321        Ok(())
322    }
323
324    /// Get the number of sweeps.
325    ///
326    /// # Returns
327    /// Tuple of (number of sweeps, continuous mode enabled).
328    ///
329    /// # Errors
330    /// Returns `NanonisError` if communication fails.
331    pub fn hs_swp_num_sweeps_get(&mut self) -> Result<(u32, bool), NanonisError> {
332        let result = self.quick_send("HSSwp.NumSweepsGet", vec![], vec![], vec!["I", "i"])?;
333
334        if result.len() >= 2 {
335            Ok((result[0].as_u32()?, result[1].as_i32()? != 0))
336        } else {
337            Err(NanonisError::Protocol("Invalid response".to_string()))
338        }
339    }
340
341    /// Set whether signals are reset at sweep end.
342    ///
343    /// # Arguments
344    /// * `reset` - True to reset signals at sweep end
345    ///
346    /// # Errors
347    /// Returns `NanonisError` if communication fails.
348    pub fn hs_swp_reset_signals_set(&mut self, reset: bool) -> Result<(), NanonisError> {
349        let flag = if reset { 1i32 } else { 0i32 };
350        self.quick_send(
351            "HSSwp.ResetSignalsSet",
352            vec![NanonisValue::I32(flag)],
353            vec!["i"],
354            vec![],
355        )?;
356        Ok(())
357    }
358
359    /// Get whether signals are reset at sweep end.
360    ///
361    /// # Returns
362    /// True if signals are reset at sweep end.
363    ///
364    /// # Errors
365    /// Returns `NanonisError` if communication fails.
366    pub fn hs_swp_reset_signals_get(&mut self) -> Result<bool, NanonisError> {
367        let result = self.quick_send("HSSwp.ResetSignalsGet", vec![], vec![], vec!["i"])?;
368
369        if !result.is_empty() {
370            Ok(result[0].as_i32()? != 0)
371        } else {
372            Err(NanonisError::Protocol("Invalid response".to_string()))
373        }
374    }
375
376    /// Set the save basename and path.
377    ///
378    /// # Arguments
379    /// * `basename` - Base name for saved files
380    /// * `path` - Directory path for saved files
381    ///
382    /// # Errors
383    /// Returns `NanonisError` if communication fails.
384    pub fn hs_swp_save_basename_set(
385        &mut self,
386        basename: &str,
387        path: &str,
388    ) -> Result<(), NanonisError> {
389        self.quick_send(
390            "HSSwp.SaveBasenameSet",
391            vec![
392                NanonisValue::String(basename.to_string()),
393                NanonisValue::String(path.to_string()),
394            ],
395            vec!["+*c", "+*c"],
396            vec![],
397        )?;
398        Ok(())
399    }
400
401    /// Get the save basename and path.
402    ///
403    /// # Returns
404    /// Tuple of (basename, path).
405    ///
406    /// # Errors
407    /// Returns `NanonisError` if communication fails.
408    pub fn hs_swp_save_basename_get(&mut self) -> Result<(String, String), NanonisError> {
409        let result =
410            self.quick_send("HSSwp.SaveBasenameGet", vec![], vec![], vec!["i", "*-c", "*-c"])?;
411
412        if result.len() >= 3 {
413            Ok((
414                result[1].as_string()?.to_string(),
415                result[2].as_string()?.to_string(),
416            ))
417        } else {
418            Err(NanonisError::Protocol("Invalid response".to_string()))
419        }
420    }
421
422    /// Set whether data is saved.
423    ///
424    /// # Arguments
425    /// * `save` - True to save data
426    ///
427    /// # Errors
428    /// Returns `NanonisError` if communication fails.
429    pub fn hs_swp_save_data_set(&mut self, save: bool) -> Result<(), NanonisError> {
430        let flag = if save { 1i32 } else { 0i32 };
431        self.quick_send(
432            "HSSwp.SaveDataSet",
433            vec![NanonisValue::I32(flag)],
434            vec!["i"],
435            vec![],
436        )?;
437        Ok(())
438    }
439
440    /// Get whether data is saved.
441    ///
442    /// # Returns
443    /// True if data is being saved.
444    ///
445    /// # Errors
446    /// Returns `NanonisError` if communication fails.
447    pub fn hs_swp_save_data_get(&mut self) -> Result<bool, NanonisError> {
448        let result = self.quick_send("HSSwp.SaveDataGet", vec![], vec![], vec!["i"])?;
449
450        if !result.is_empty() {
451            Ok(result[0].as_i32()? != 0)
452        } else {
453            Err(NanonisError::Protocol("Invalid response".to_string()))
454        }
455    }
456
457    /// Set save options.
458    ///
459    /// # Arguments
460    /// * `options` - Save options configuration
461    ///
462    /// # Errors
463    /// Returns `NanonisError` if communication fails.
464    pub fn hs_swp_save_options_set(&mut self, options: &HSSwpSaveOptions) -> Result<(), NanonisError> {
465        self.quick_send(
466            "HSSwp.SaveOptionsSet",
467            vec![
468                NanonisValue::String(options.comment.clone()),
469                NanonisValue::ArrayString(options.modules.clone()),
470            ],
471            vec!["+*c", "+*c"],
472            vec![],
473        )?;
474        Ok(())
475    }
476
477    /// Get save options.
478    ///
479    /// # Returns
480    /// An [`HSSwpSaveOptions`] struct with current options.
481    ///
482    /// # Errors
483    /// Returns `NanonisError` if communication fails.
484    pub fn hs_swp_save_options_get(&mut self) -> Result<HSSwpSaveOptions, NanonisError> {
485        let result = self.quick_send(
486            "HSSwp.SaveOptionsGet",
487            vec![],
488            vec![],
489            vec!["i", "*-c", "i", "i", "*+c"],
490        )?;
491
492        if result.len() >= 5 {
493            Ok(HSSwpSaveOptions {
494                comment: result[1].as_string()?.to_string(),
495                modules: result[4].as_string_array()?.to_vec(),
496            })
497        } else {
498            Err(NanonisError::Protocol("Invalid response".to_string()))
499        }
500    }
501
502    /// Start a high-speed sweep.
503    ///
504    /// # Arguments
505    /// * `wait_until_done` - Wait for sweep to complete before returning
506    /// * `timeout_ms` - Timeout in milliseconds (-1 for indefinite)
507    ///
508    /// # Errors
509    /// Returns `NanonisError` if communication fails.
510    pub fn hs_swp_start(&mut self, wait_until_done: bool, timeout_ms: i32) -> Result<(), NanonisError> {
511        let wait_flag = if wait_until_done { 1i32 } else { 0i32 };
512        self.quick_send(
513            "HSSwp.Start",
514            vec![NanonisValue::I32(wait_flag), NanonisValue::I32(timeout_ms)],
515            vec!["i", "i"],
516            vec![],
517        )?;
518        Ok(())
519    }
520
521    /// Stop the high-speed sweep.
522    ///
523    /// # Errors
524    /// Returns `NanonisError` if communication fails.
525    pub fn hs_swp_stop(&mut self) -> Result<(), NanonisError> {
526        self.quick_send("HSSwp.Stop", vec![], vec![], vec![])?;
527        Ok(())
528    }
529
530    /// Get the sweep status.
531    ///
532    /// # Returns
533    /// True if sweep is running.
534    ///
535    /// # Errors
536    /// Returns `NanonisError` if communication fails.
537    pub fn hs_swp_status_get(&mut self) -> Result<bool, NanonisError> {
538        let result = self.quick_send("HSSwp.StatusGet", vec![], vec![], vec!["I"])?;
539
540        if !result.is_empty() {
541            Ok(result[0].as_u32()? != 0)
542        } else {
543            Err(NanonisError::Protocol("Invalid response".to_string()))
544        }
545    }
546
547    /// Get the list of available sweep signals.
548    ///
549    /// # Returns
550    /// An [`HSSwpSignalList`] struct with signal information.
551    ///
552    /// # Errors
553    /// Returns `NanonisError` if communication fails.
554    pub fn hs_swp_swp_ch_sig_list_get(&mut self) -> Result<HSSwpSignalList, NanonisError> {
555        let result =
556            self.quick_send("HSSwp.SwpChSigListGet", vec![], vec![], vec!["+*c", "+*i"])?;
557
558        if result.len() >= 2 {
559            Ok(HSSwpSignalList {
560                names: result[0].as_string_array()?.to_vec(),
561                indices: result[1].as_i32_array()?.to_vec(),
562            })
563        } else {
564            Err(NanonisError::Protocol("Invalid response".to_string()))
565        }
566    }
567
568    /// Set the sweep channel signal.
569    ///
570    /// # Arguments
571    /// * `signal_index` - Index of sweep signal
572    /// * `timed_sweep` - Use timed sweep mode (ignores signal)
573    ///
574    /// # Errors
575    /// Returns `NanonisError` if communication fails.
576    pub fn hs_swp_swp_ch_signal_set(
577        &mut self,
578        signal_index: i32,
579        timed_sweep: bool,
580    ) -> Result<(), NanonisError> {
581        let timed_flag = if timed_sweep { 1i32 } else { 0i32 };
582        self.quick_send(
583            "HSSwp.SwpChSignalSet",
584            vec![NanonisValue::I32(signal_index), NanonisValue::I32(timed_flag)],
585            vec!["i", "i"],
586            vec![],
587        )?;
588        Ok(())
589    }
590
591    /// Get the sweep channel signal.
592    ///
593    /// # Returns
594    /// Tuple of (signal index, timed sweep enabled).
595    ///
596    /// # Errors
597    /// Returns `NanonisError` if communication fails.
598    pub fn hs_swp_swp_ch_signal_get(&mut self) -> Result<(i32, bool), NanonisError> {
599        let result = self.quick_send("HSSwp.SwpChSignalGet", vec![], vec![], vec!["i", "i"])?;
600
601        if result.len() >= 2 {
602            Ok((result[0].as_i32()?, result[1].as_i32()? != 0))
603        } else {
604            Err(NanonisError::Protocol("Invalid response".to_string()))
605        }
606    }
607
608    /// Set the sweep channel limits.
609    ///
610    /// # Arguments
611    /// * `limits` - Limits configuration
612    ///
613    /// # Errors
614    /// Returns `NanonisError` if communication fails.
615    pub fn hs_swp_swp_ch_limits_set(&mut self, limits: &HSSwpLimits) -> Result<(), NanonisError> {
616        let rel_flag = if limits.relative { 1i32 } else { 0i32 };
617        self.quick_send(
618            "HSSwp.SwpChLimitsSet",
619            vec![
620                NanonisValue::I32(rel_flag),
621                NanonisValue::F32(limits.start),
622                NanonisValue::F32(limits.stop),
623            ],
624            vec!["i", "f", "f"],
625            vec![],
626        )?;
627        Ok(())
628    }
629
630    /// Get the sweep channel limits.
631    ///
632    /// # Returns
633    /// An [`HSSwpLimits`] struct with current limits.
634    ///
635    /// # Errors
636    /// Returns `NanonisError` if communication fails.
637    pub fn hs_swp_swp_ch_limits_get(&mut self) -> Result<HSSwpLimits, NanonisError> {
638        let result = self.quick_send("HSSwp.SwpChLimitsGet", vec![], vec![], vec!["i", "f", "f"])?;
639
640        if result.len() >= 3 {
641            Ok(HSSwpLimits {
642                relative: result[0].as_i32()? != 0,
643                start: result[1].as_f32()?,
644                stop: result[2].as_f32()?,
645            })
646        } else {
647            Err(NanonisError::Protocol("Invalid response".to_string()))
648        }
649    }
650
651    /// Set the number of sweep points.
652    ///
653    /// # Arguments
654    /// * `num_points` - Number of points in sweep
655    ///
656    /// # Errors
657    /// Returns `NanonisError` if communication fails.
658    pub fn hs_swp_swp_ch_num_pts_set(&mut self, num_points: u32) -> Result<(), NanonisError> {
659        self.quick_send(
660            "HSSwp.SwpChNumPtsSet",
661            vec![NanonisValue::U32(num_points)],
662            vec!["I"],
663            vec![],
664        )?;
665        Ok(())
666    }
667
668    /// Get the number of sweep points.
669    ///
670    /// # Returns
671    /// Number of points in sweep.
672    ///
673    /// # Errors
674    /// Returns `NanonisError` if communication fails.
675    pub fn hs_swp_swp_ch_num_pts_get(&mut self) -> Result<i32, NanonisError> {
676        let result = self.quick_send("HSSwp.SwpChNumPtsGet", vec![], vec![], vec!["i"])?;
677
678        if !result.is_empty() {
679            Ok(result[0].as_i32()?)
680        } else {
681            Err(NanonisError::Protocol("Invalid response".to_string()))
682        }
683    }
684
685    /// Set the sweep timing parameters.
686    ///
687    /// # Arguments
688    /// * `timing` - Timing configuration
689    ///
690    /// # Errors
691    /// Returns `NanonisError` if communication fails.
692    pub fn hs_swp_swp_ch_timing_set(&mut self, timing: &HSSwpTiming) -> Result<(), NanonisError> {
693        self.quick_send(
694            "HSSwp.SwpChTimingSet",
695            vec![
696                NanonisValue::F32(timing.initial_settling_s),
697                NanonisValue::F32(timing.settling_s),
698                NanonisValue::F32(timing.integration_s),
699                NanonisValue::F32(timing.max_slew_rate),
700            ],
701            vec!["f", "f", "f", "f"],
702            vec![],
703        )?;
704        Ok(())
705    }
706
707    /// Get the sweep timing parameters.
708    ///
709    /// # Returns
710    /// An [`HSSwpTiming`] struct with current timing.
711    ///
712    /// # Errors
713    /// Returns `NanonisError` if communication fails.
714    pub fn hs_swp_swp_ch_timing_get(&mut self) -> Result<HSSwpTiming, NanonisError> {
715        let result =
716            self.quick_send("HSSwp.SwpChTimingGet", vec![], vec![], vec!["f", "f", "f", "f"])?;
717
718        if result.len() >= 4 {
719            Ok(HSSwpTiming {
720                initial_settling_s: result[0].as_f32()?,
721                settling_s: result[1].as_f32()?,
722                integration_s: result[2].as_f32()?,
723                max_slew_rate: result[3].as_f32()?,
724            })
725        } else {
726            Err(NanonisError::Protocol("Invalid response".to_string()))
727        }
728    }
729
730    /// Set whether backward sweep is enabled.
731    ///
732    /// # Arguments
733    /// * `enabled` - Enable backward sweep
734    ///
735    /// # Errors
736    /// Returns `NanonisError` if communication fails.
737    pub fn hs_swp_swp_ch_bwd_sw_set(&mut self, enabled: bool) -> Result<(), NanonisError> {
738        let flag = if enabled { 1u32 } else { 0u32 };
739        self.quick_send(
740            "HSSwp.SwpChBwdSwSet",
741            vec![NanonisValue::U32(flag)],
742            vec!["I"],
743            vec![],
744        )?;
745        Ok(())
746    }
747
748    /// Get whether backward sweep is enabled.
749    ///
750    /// # Returns
751    /// True if backward sweep is enabled.
752    ///
753    /// # Errors
754    /// Returns `NanonisError` if communication fails.
755    pub fn hs_swp_swp_ch_bwd_sw_get(&mut self) -> Result<bool, NanonisError> {
756        let result = self.quick_send("HSSwp.SwpChBwdSwGet", vec![], vec![], vec!["I"])?;
757
758        if !result.is_empty() {
759            Ok(result[0].as_u32()? != 0)
760        } else {
761            Err(NanonisError::Protocol("Invalid response".to_string()))
762        }
763    }
764
765    /// Set the backward sweep delay.
766    ///
767    /// # Arguments
768    /// * `delay_s` - Delay between forward and backward sweep in seconds
769    ///
770    /// # Errors
771    /// Returns `NanonisError` if communication fails.
772    pub fn hs_swp_swp_ch_bwd_delay_set(&mut self, delay_s: f32) -> Result<(), NanonisError> {
773        self.quick_send(
774            "HSSwp.SwpChBwdDelaySet",
775            vec![NanonisValue::F32(delay_s)],
776            vec!["f"],
777            vec![],
778        )?;
779        Ok(())
780    }
781
782    /// Get the backward sweep delay.
783    ///
784    /// # Returns
785    /// Delay in seconds.
786    ///
787    /// # Errors
788    /// Returns `NanonisError` if communication fails.
789    pub fn hs_swp_swp_ch_bwd_delay_get(&mut self) -> Result<f32, NanonisError> {
790        let result = self.quick_send("HSSwp.SwpChBwdDelayGet", vec![], vec![], vec!["f"])?;
791
792        if !result.is_empty() {
793            Ok(result[0].as_f32()?)
794        } else {
795            Err(NanonisError::Protocol("Invalid response".to_string()))
796        }
797    }
798
799    /// Set the Z-controller behavior during sweep.
800    ///
801    /// # Arguments
802    /// * `config` - Z-controller configuration
803    ///
804    /// # Errors
805    /// Returns `NanonisError` if communication fails.
806    pub fn hs_swp_z_ctrl_off_set(&mut self, config: &HSSwpZCtrl) -> Result<(), NanonisError> {
807        let switch_off = if config.switch_off { 0i32 } else { 1i32 }; // 0=switch off, 1=don't switch
808        self.quick_send(
809            "HSSwp.ZCtrlOffSet",
810            vec![
811                NanonisValue::I32(switch_off),
812                NanonisValue::I32(config.controller_index),
813                NanonisValue::F32(config.averaging_time_s),
814                NanonisValue::F32(config.z_offset_m),
815                NanonisValue::F32(config.control_time_s),
816            ],
817            vec!["i", "i", "f", "f", "f"],
818            vec![],
819        )?;
820        Ok(())
821    }
822
823    /// Get the Z-controller behavior during sweep.
824    ///
825    /// # Returns
826    /// An [`HSSwpZCtrl`] struct with current configuration.
827    ///
828    /// # Errors
829    /// Returns `NanonisError` if communication fails.
830    pub fn hs_swp_z_ctrl_off_get(&mut self) -> Result<HSSwpZCtrl, NanonisError> {
831        let result =
832            self.quick_send("HSSwp.ZCtrlOffGet", vec![], vec![], vec!["i", "i", "f", "f", "f"])?;
833
834        if result.len() >= 5 {
835            Ok(HSSwpZCtrl {
836                switch_off: result[0].as_i32()? == 0, // 0=switch off, 1=don't switch
837                controller_index: result[1].as_i32()?,
838                averaging_time_s: result[2].as_f32()?,
839                z_offset_m: result[3].as_f32()?,
840                control_time_s: result[4].as_f32()?,
841            })
842        } else {
843            Err(NanonisError::Protocol("Invalid response".to_string()))
844        }
845    }
846}