Skip to main content

nanonis_rs/client/oscilloscope/
osci_hr.rs

1use super::super::NanonisClient;
2use super::*;
3use crate::error::NanonisError;
4use crate::types::NanonisValue;
5use crate::client::signals::SignalIndex;
6
7impl NanonisClient {
8    /// Set the measured signal index of the selected channel from the Oscilloscope High Resolution
9    pub fn osci_hr_ch_set(
10        &mut self,
11        osci_index: impl Into<OscilloscopeIndex>,
12        signal: impl Into<SignalIndex>,
13    ) -> Result<(), NanonisError> {
14        self.quick_send(
15            "OsciHR.ChSet",
16            vec![
17                NanonisValue::I32(osci_index.into().into()),
18                NanonisValue::I32(signal.into().into()),
19            ],
20            vec!["i", "i"],
21            vec![],
22        )?;
23        Ok(())
24    }
25
26    /// Get the measured signal index of the selected channel from the Oscilloscope High Resolution
27    pub fn osci_hr_ch_get(
28        &mut self,
29        osci_index: impl Into<OscilloscopeIndex>,
30    ) -> Result<SignalIndex, NanonisError> {
31        let result = self.quick_send(
32            "OsciHR.ChGet",
33            vec![NanonisValue::I32(osci_index.into().into())],
34            vec!["i"],
35            vec!["i"],
36        )?;
37        match result.first() {
38            Some(value) => Ok(SignalIndex::new(value.as_i32()? as u8)),
39            None => Err(NanonisError::Protocol(
40                "No signal index returned".to_string(),
41            )),
42        }
43    }
44
45    /// Set the oversampling index of the Oscilloscope High Resolution
46    pub fn osci_hr_oversampl_set(&mut self, oversampling_index: i32) -> Result<(), NanonisError> {
47        self.quick_send(
48            "OsciHR.OversamplSet",
49            vec![NanonisValue::I32(oversampling_index)],
50            vec!["i"],
51            vec![],
52        )?;
53        Ok(())
54    }
55
56    /// Get the oversampling index of the Oscilloscope High Resolution
57    pub fn osci_hr_oversampl_get(&mut self) -> Result<i32, NanonisError> {
58        let result = self.quick_send("OsciHR.OversamplGet", vec![], vec![], vec!["i"])?;
59        match result.first() {
60            Some(value) => Ok(value.as_i32()?),
61            None => Err(NanonisError::Protocol(
62                "No oversampling index returned".to_string(),
63            )),
64        }
65    }
66
67    /// Set the calibration mode of the selected channel from the Oscilloscope High Resolution
68    /// calibration_mode: 0 = Raw values, 1 = Calibrated values
69    pub fn osci_hr_calibr_mode_set(
70        &mut self,
71        osci_index: i32,
72        calibration_mode: u16,
73    ) -> Result<(), NanonisError> {
74        self.quick_send(
75            "OsciHR.CalibrModeSet",
76            vec![
77                NanonisValue::I32(osci_index),
78                NanonisValue::U16(calibration_mode),
79            ],
80            vec!["i", "H"],
81            vec![],
82        )?;
83        Ok(())
84    }
85
86    /// Get the calibration mode of the selected channel from the Oscilloscope High Resolution
87    /// Returns: 0 = Raw values, 1 = Calibrated values
88    pub fn osci_hr_calibr_mode_get(&mut self, osci_index: i32) -> Result<u16, NanonisError> {
89        let result = self.quick_send(
90            "OsciHR.CalibrModeGet",
91            vec![NanonisValue::I32(osci_index)],
92            vec!["i"],
93            vec!["H"],
94        )?;
95        match result.first() {
96            Some(value) => Ok(value.as_u16()?),
97            None => Err(NanonisError::Protocol(
98                "No calibration mode returned".to_string(),
99            )),
100        }
101    }
102
103    /// Set the number of samples to acquire in the Oscilloscope High Resolution
104    pub fn osci_hr_samples_set(
105        &mut self,
106        number_of_samples: impl Into<SampleCount>,
107    ) -> Result<(), NanonisError> {
108        self.quick_send(
109            "OsciHR.SamplesSet",
110            vec![NanonisValue::I32(number_of_samples.into().into())],
111            vec!["i"],
112            vec![],
113        )?;
114        Ok(())
115    }
116
117    /// Get the number of samples to acquire in the Oscilloscope High Resolution
118    pub fn osci_hr_samples_get(&mut self) -> Result<SampleCount, NanonisError> {
119        let result = self.quick_send("OsciHR.SamplesGet", vec![], vec![], vec!["i"])?;
120        match result.first() {
121            Some(value) => Ok(SampleCount::new(value.as_i32()?)),
122            None => Err(NanonisError::Protocol(
123                "No sample count returned".to_string(),
124            )),
125        }
126    }
127
128    /// Set the Pre-Trigger Samples or Seconds in the Oscilloscope High Resolution
129    pub fn osci_hr_pre_trig_set(
130        &mut self,
131        pre_trigger_samples: u32,
132        pre_trigger_s: f64,
133    ) -> Result<(), NanonisError> {
134        self.quick_send(
135            "OsciHR.PreTrigSet",
136            vec![
137                NanonisValue::U32(pre_trigger_samples),
138                NanonisValue::F64(pre_trigger_s),
139            ],
140            vec!["I", "d"],
141            vec![],
142        )?;
143        Ok(())
144    }
145
146    /// Get the Pre-Trigger Samples in the Oscilloscope High Resolution
147    pub fn osci_hr_pre_trig_get(&mut self) -> Result<i32, NanonisError> {
148        let result = self.quick_send("OsciHR.PreTrigGet", vec![], vec![], vec!["i"])?;
149        match result.first() {
150            Some(value) => Ok(value.as_i32()?),
151            None => Err(NanonisError::Protocol(
152                "No pre-trigger samples returned".to_string(),
153            )),
154        }
155    }
156
157    /// Start the Oscilloscope High Resolution module
158    pub fn osci_hr_run(&mut self) -> Result<(), NanonisError> {
159        self.quick_send("OsciHR.Run", vec![], vec![], vec![])?;
160        Ok(())
161    }
162
163    /// Get the graph data of the selected channel from the Oscilloscope High Resolution
164    /// data_to_get: 0 = Current returns the currently displayed data, 1 = Next trigger waits for the next trigger
165    /// Returns: (timestamp, time_delta, data_values, timeout_occurred)
166    pub fn osci_hr_osci_data_get(
167        &mut self,
168        osci_index: i32,
169        data_to_get: u16,
170        timeout_s: f64,
171    ) -> Result<(String, f64, Vec<f32>, bool), NanonisError> {
172        let result = self.quick_send(
173            "OsciHR.OsciDataGet",
174            vec![
175                NanonisValue::I32(osci_index),
176                NanonisValue::U16(data_to_get),
177                NanonisValue::F64(timeout_s),
178            ],
179            vec!["i", "H", "d"],
180            vec!["i", "*-c", "d", "i", "*f", "I"],
181        )?;
182
183        if result.len() >= 6 {
184            let timestamp = result[1].as_string()?.to_string();
185            let time_delta = result[2].as_f64()?;
186            let data_values = result[4].as_f32_array()?.to_vec();
187            let timeout_occurred = result[5].as_u32()? == 1;
188            Ok((timestamp, time_delta, data_values, timeout_occurred))
189        } else {
190            Err(NanonisError::Protocol(
191                "Invalid oscilloscope data response".to_string(),
192            ))
193        }
194    }
195
196    /// Set the trigger mode in the Oscilloscope High Resolution
197    pub fn osci_hr_trig_mode_set(
198        &mut self,
199        trigger_mode: impl Into<TriggerMode>,
200    ) -> Result<(), NanonisError> {
201        self.quick_send(
202            "OsciHR.TrigModeSet",
203            vec![NanonisValue::U16(trigger_mode.into().into())],
204            vec!["H"],
205            vec![],
206        )?;
207        Ok(())
208    }
209
210    /// Get the trigger mode in the Oscilloscope High Resolution
211    pub fn osci_hr_trig_mode_get(&mut self) -> Result<TriggerMode, NanonisError> {
212        let result = self.quick_send("OsciHR.TrigModeGet", vec![], vec![], vec!["H"])?;
213        match result.first() {
214            Some(value) => {
215                let mode_val = value.as_u16()?;
216                match mode_val {
217                    0 => Ok(TriggerMode::Immediate),
218                    1 => Ok(TriggerMode::Level),
219                    2 => Ok(TriggerMode::Digital),
220                    _ => Err(NanonisError::Protocol(format!(
221                        "Unknown trigger mode: {}",
222                        mode_val
223                    ))),
224                }
225            }
226            None => Err(NanonisError::Protocol(
227                "No trigger mode returned".to_string(),
228            )),
229        }
230    }
231
232    /// Set the Level Trigger Channel index in the Oscilloscope High Resolution
233    pub fn osci_hr_trig_lev_ch_set(
234        &mut self,
235        level_trigger_channel_index: i32,
236    ) -> Result<(), NanonisError> {
237        self.quick_send(
238            "OsciHR.TrigLevChSet",
239            vec![NanonisValue::I32(level_trigger_channel_index)],
240            vec!["i"],
241            vec![],
242        )?;
243        Ok(())
244    }
245
246    /// Get the Level Trigger Channel index in the Oscilloscope High Resolution
247    pub fn osci_hr_trig_lev_ch_get(&mut self) -> Result<i32, NanonisError> {
248        let result = self.quick_send("OsciHR.TrigLevChGet", vec![], vec![], vec!["i"])?;
249        match result.first() {
250            Some(value) => Ok(value.as_i32()?),
251            None => Err(NanonisError::Protocol(
252                "No level trigger channel returned".to_string(),
253            )),
254        }
255    }
256
257    /// Set the Level Trigger value in the Oscilloscope High Resolution
258    pub fn osci_hr_trig_lev_val_set(
259        &mut self,
260        level_trigger_value: impl Into<TriggerLevel>,
261    ) -> Result<(), NanonisError> {
262        self.quick_send(
263            "OsciHR.TrigLevValSet",
264            vec![NanonisValue::F64(level_trigger_value.into().into())],
265            vec!["d"],
266            vec![],
267        )?;
268        Ok(())
269    }
270
271    /// Get the Level Trigger value in the Oscilloscope High Resolution
272    pub fn osci_hr_trig_lev_val_get(&mut self) -> Result<TriggerLevel, NanonisError> {
273        let result = self.quick_send("OsciHR.TrigLevValGet", vec![], vec![], vec!["d"])?;
274        match result.first() {
275            Some(value) => Ok(TriggerLevel(value.as_f64()?)),
276            None => Err(NanonisError::Protocol(
277                "No level trigger value returned".to_string(),
278            )),
279        }
280    }
281
282    /// Set the Trigger Arming Mode in the Oscilloscope High Resolution
283    pub fn osci_hr_trig_arm_mode_set(
284        &mut self,
285        trigger_arming_mode: u16,
286    ) -> Result<(), NanonisError> {
287        self.quick_send(
288            "OsciHR.TrigArmModeSet",
289            vec![NanonisValue::U16(trigger_arming_mode)],
290            vec!["H"],
291            vec![],
292        )?;
293        Ok(())
294    }
295
296    /// Get the Trigger Arming Mode in the Oscilloscope High Resolution
297    pub fn osci_hr_trig_arm_mode_get(&mut self) -> Result<u16, NanonisError> {
298        let result = self.quick_send("OsciHR.TrigArmModeGet", vec![], vec![], vec!["H"])?;
299        match result.first() {
300            Some(value) => Ok(value.as_u16()?),
301            None => Err(NanonisError::Protocol(
302                "No trigger arming mode returned".to_string(),
303            )),
304        }
305    }
306
307    /// Set the Level Trigger Hysteresis in the Oscilloscope High Resolution
308    pub fn osci_hr_trig_lev_hyst_set(&mut self, hysteresis: f64) -> Result<(), NanonisError> {
309        self.quick_send(
310            "OsciHR.TrigLevHystSet",
311            vec![NanonisValue::F64(hysteresis)],
312            vec!["d"],
313            vec![],
314        )?;
315        Ok(())
316    }
317
318    /// Get the Level Trigger Hysteresis in the Oscilloscope High Resolution
319    pub fn osci_hr_trig_lev_hyst_get(&mut self) -> Result<f64, NanonisError> {
320        let result = self.quick_send("OsciHR.TrigLevHystGet", vec![], vec![], vec!["d"])?;
321        match result.first() {
322            Some(value) => Ok(value.as_f64()?),
323            None => Err(NanonisError::Protocol(
324                "No trigger hysteresis returned".to_string(),
325            )),
326        }
327    }
328
329    /// Set the Level Trigger Slope in the Oscilloscope High Resolution
330    pub fn osci_hr_trig_lev_slope_set(&mut self, slope: u16) -> Result<(), NanonisError> {
331        self.quick_send(
332            "OsciHR.TrigLevSlopeSet",
333            vec![NanonisValue::U16(slope)],
334            vec!["H"],
335            vec![],
336        )?;
337        Ok(())
338    }
339
340    /// Get the Level Trigger Slope in the Oscilloscope High Resolution
341    pub fn osci_hr_trig_lev_slope_get(&mut self) -> Result<u16, NanonisError> {
342        let result = self.quick_send("OsciHR.TrigLevSlopeGet", vec![], vec![], vec!["H"])?;
343        match result.first() {
344            Some(value) => Ok(value.as_u16()?),
345            None => Err(NanonisError::Protocol(
346                "No trigger slope returned".to_string(),
347            )),
348        }
349    }
350
351    /// Set the Digital Trigger Channel index in the Oscilloscope High Resolution.
352    ///
353    /// # Arguments
354    /// * `digital_trigger_channel` - Digital trigger channel index
355    ///
356    /// # Errors
357    /// Returns `NanonisError` if communication fails.
358    pub fn osci_hr_trig_dig_ch_set(
359        &mut self,
360        digital_trigger_channel: i32,
361    ) -> Result<(), NanonisError> {
362        self.quick_send(
363            "OsciHR.TrigDigChSet",
364            vec![NanonisValue::I32(digital_trigger_channel)],
365            vec!["i"],
366            vec![],
367        )?;
368        Ok(())
369    }
370
371    /// Get the Digital Trigger Channel index in the Oscilloscope High Resolution.
372    ///
373    /// # Returns
374    /// Digital trigger channel index.
375    ///
376    /// # Errors
377    /// Returns `NanonisError` if communication fails.
378    pub fn osci_hr_trig_dig_ch_get(&mut self) -> Result<i32, NanonisError> {
379        let result = self.quick_send("OsciHR.TrigDigChGet", vec![], vec![], vec!["i"])?;
380        match result.first() {
381            Some(value) => Ok(value.as_i32()?),
382            None => Err(NanonisError::Protocol(
383                "No digital trigger channel returned".to_string(),
384            )),
385        }
386    }
387
388    /// Set the Digital Trigger Slope in the Oscilloscope High Resolution.
389    ///
390    /// # Arguments
391    /// * `slope` - Digital trigger slope (0 = Rising, 1 = Falling, 2 = Both)
392    ///
393    /// # Errors
394    /// Returns `NanonisError` if communication fails.
395    pub fn osci_hr_trig_dig_slope_set(&mut self, slope: u16) -> Result<(), NanonisError> {
396        self.quick_send(
397            "OsciHR.TrigDigSlopeSet",
398            vec![NanonisValue::U16(slope)],
399            vec!["H"],
400            vec![],
401        )?;
402        Ok(())
403    }
404
405    /// Get the Digital Trigger Slope in the Oscilloscope High Resolution.
406    ///
407    /// # Returns
408    /// Digital trigger slope (0 = Rising, 1 = Falling, 2 = Both).
409    ///
410    /// # Errors
411    /// Returns `NanonisError` if communication fails.
412    pub fn osci_hr_trig_dig_slope_get(&mut self) -> Result<u16, NanonisError> {
413        let result = self.quick_send("OsciHR.TrigDigSlopeGet", vec![], vec![], vec!["H"])?;
414        match result.first() {
415            Some(value) => Ok(value.as_u16()?),
416            None => Err(NanonisError::Protocol(
417                "No digital trigger slope returned".to_string(),
418            )),
419        }
420    }
421
422    /// Rearm the trigger in the Oscilloscope High Resolution.
423    ///
424    /// # Errors
425    /// Returns `NanonisError` if communication fails.
426    pub fn osci_hr_trig_rearm(&mut self) -> Result<(), NanonisError> {
427        self.quick_send("OsciHR.TrigRearm", vec![], vec![], vec![])?;
428        Ok(())
429    }
430
431    /// Show the PSD (Power Spectral Density) view in the Oscilloscope High Resolution.
432    ///
433    /// # Errors
434    /// Returns `NanonisError` if communication fails.
435    pub fn osci_hr_psd_show(&mut self) -> Result<(), NanonisError> {
436        self.quick_send("OsciHR.PSDShow", vec![], vec![], vec![])?;
437        Ok(())
438    }
439
440    /// Set the PSD weighting mode in the Oscilloscope High Resolution.
441    ///
442    /// # Arguments
443    /// * `osci_index` - Oscilloscope channel index
444    /// * `weighting` - Weighting mode (0 = None, 1 = A-weighting, 2 = C-weighting)
445    ///
446    /// # Errors
447    /// Returns `NanonisError` if communication fails.
448    pub fn osci_hr_psd_weight_set(
449        &mut self,
450        osci_index: i32,
451        weighting: u16,
452    ) -> Result<(), NanonisError> {
453        self.quick_send(
454            "OsciHR.PSDWeightSet",
455            vec![
456                NanonisValue::I32(osci_index),
457                NanonisValue::U16(weighting),
458            ],
459            vec!["i", "H"],
460            vec![],
461        )?;
462        Ok(())
463    }
464
465    /// Get the PSD weighting mode in the Oscilloscope High Resolution.
466    ///
467    /// # Arguments
468    /// * `osci_index` - Oscilloscope channel index
469    ///
470    /// # Returns
471    /// Weighting mode (0 = None, 1 = A-weighting, 2 = C-weighting).
472    ///
473    /// # Errors
474    /// Returns `NanonisError` if communication fails.
475    pub fn osci_hr_psd_weight_get(&mut self, osci_index: i32) -> Result<u16, NanonisError> {
476        let result = self.quick_send(
477            "OsciHR.PSDWeightGet",
478            vec![NanonisValue::I32(osci_index)],
479            vec!["i"],
480            vec!["H"],
481        )?;
482        match result.first() {
483            Some(value) => Ok(value.as_u16()?),
484            None => Err(NanonisError::Protocol(
485                "No PSD weighting returned".to_string(),
486            )),
487        }
488    }
489
490    /// Set the PSD window function in the Oscilloscope High Resolution.
491    ///
492    /// # Arguments
493    /// * `osci_index` - Oscilloscope channel index
494    /// * `window` - Window function (0 = None, 1 = Hann, 2 = Hamming, 3 = Blackman-Harris, 4 = Flat Top)
495    ///
496    /// # Errors
497    /// Returns `NanonisError` if communication fails.
498    pub fn osci_hr_psd_window_set(
499        &mut self,
500        osci_index: i32,
501        window: u16,
502    ) -> Result<(), NanonisError> {
503        self.quick_send(
504            "OsciHR.PSDWindowSet",
505            vec![
506                NanonisValue::I32(osci_index),
507                NanonisValue::U16(window),
508            ],
509            vec!["i", "H"],
510            vec![],
511        )?;
512        Ok(())
513    }
514
515    /// Get the PSD window function in the Oscilloscope High Resolution.
516    ///
517    /// # Arguments
518    /// * `osci_index` - Oscilloscope channel index
519    ///
520    /// # Returns
521    /// Window function (0 = None, 1 = Hann, 2 = Hamming, 3 = Blackman-Harris, 4 = Flat Top).
522    ///
523    /// # Errors
524    /// Returns `NanonisError` if communication fails.
525    pub fn osci_hr_psd_window_get(&mut self, osci_index: i32) -> Result<u16, NanonisError> {
526        let result = self.quick_send(
527            "OsciHR.PSDWindowGet",
528            vec![NanonisValue::I32(osci_index)],
529            vec!["i"],
530            vec!["H"],
531        )?;
532        match result.first() {
533            Some(value) => Ok(value.as_u16()?),
534            None => Err(NanonisError::Protocol(
535                "No PSD window returned".to_string(),
536            )),
537        }
538    }
539
540    /// Set the PSD averaging type in the Oscilloscope High Resolution.
541    ///
542    /// # Arguments
543    /// * `osci_index` - Oscilloscope channel index
544    /// * `averaging_type` - Averaging type (0 = None, 1 = Linear, 2 = Exponential)
545    ///
546    /// # Errors
547    /// Returns `NanonisError` if communication fails.
548    pub fn osci_hr_psd_avrg_type_set(
549        &mut self,
550        osci_index: i32,
551        averaging_type: u16,
552    ) -> Result<(), NanonisError> {
553        self.quick_send(
554            "OsciHR.PSDAvrgTypeSet",
555            vec![
556                NanonisValue::I32(osci_index),
557                NanonisValue::U16(averaging_type),
558            ],
559            vec!["i", "H"],
560            vec![],
561        )?;
562        Ok(())
563    }
564
565    /// Get the PSD averaging type in the Oscilloscope High Resolution.
566    ///
567    /// # Arguments
568    /// * `osci_index` - Oscilloscope channel index
569    ///
570    /// # Returns
571    /// Averaging type (0 = None, 1 = Linear, 2 = Exponential).
572    ///
573    /// # Errors
574    /// Returns `NanonisError` if communication fails.
575    pub fn osci_hr_psd_avrg_type_get(&mut self, osci_index: i32) -> Result<u16, NanonisError> {
576        let result = self.quick_send(
577            "OsciHR.PSDAvrgTypeGet",
578            vec![NanonisValue::I32(osci_index)],
579            vec!["i"],
580            vec!["H"],
581        )?;
582        match result.first() {
583            Some(value) => Ok(value.as_u16()?),
584            None => Err(NanonisError::Protocol(
585                "No PSD averaging type returned".to_string(),
586            )),
587        }
588    }
589
590    /// Set the PSD averaging count in the Oscilloscope High Resolution.
591    ///
592    /// # Arguments
593    /// * `osci_index` - Oscilloscope channel index
594    /// * `count` - Number of averages
595    ///
596    /// # Errors
597    /// Returns `NanonisError` if communication fails.
598    pub fn osci_hr_psd_avrg_count_set(
599        &mut self,
600        osci_index: i32,
601        count: i32,
602    ) -> Result<(), NanonisError> {
603        self.quick_send(
604            "OsciHR.PSDAvrgCountSet",
605            vec![
606                NanonisValue::I32(osci_index),
607                NanonisValue::I32(count),
608            ],
609            vec!["i", "i"],
610            vec![],
611        )?;
612        Ok(())
613    }
614
615    /// Get the PSD averaging count in the Oscilloscope High Resolution.
616    ///
617    /// # Arguments
618    /// * `osci_index` - Oscilloscope channel index
619    ///
620    /// # Returns
621    /// Number of averages.
622    ///
623    /// # Errors
624    /// Returns `NanonisError` if communication fails.
625    pub fn osci_hr_psd_avrg_count_get(&mut self, osci_index: i32) -> Result<i32, NanonisError> {
626        let result = self.quick_send(
627            "OsciHR.PSDAvrgCountGet",
628            vec![NanonisValue::I32(osci_index)],
629            vec!["i"],
630            vec!["i"],
631        )?;
632        match result.first() {
633            Some(value) => Ok(value.as_i32()?),
634            None => Err(NanonisError::Protocol(
635                "No PSD averaging count returned".to_string(),
636            )),
637        }
638    }
639
640    /// Restart PSD averaging in the Oscilloscope High Resolution.
641    ///
642    /// # Arguments
643    /// * `osci_index` - Oscilloscope channel index
644    ///
645    /// # Errors
646    /// Returns `NanonisError` if communication fails.
647    pub fn osci_hr_psd_avrg_restart(&mut self, osci_index: i32) -> Result<(), NanonisError> {
648        self.quick_send(
649            "OsciHR.PSDAvrgRestart",
650            vec![NanonisValue::I32(osci_index)],
651            vec!["i"],
652            vec![],
653        )?;
654        Ok(())
655    }
656
657    /// Get the PSD data from the Oscilloscope High Resolution.
658    ///
659    /// # Arguments
660    /// * `osci_index` - Oscilloscope channel index
661    /// * `data_to_get` - 0 = Current data, 1 = Wait for next acquisition
662    /// * `timeout_s` - Timeout in seconds
663    ///
664    /// # Returns
665    /// Tuple of (frequency_start, frequency_delta, psd_data, timeout_occurred).
666    ///
667    /// # Errors
668    /// Returns `NanonisError` if communication fails.
669    pub fn osci_hr_psd_data_get(
670        &mut self,
671        osci_index: i32,
672        data_to_get: u16,
673        timeout_s: f64,
674    ) -> Result<(f64, f64, Vec<f32>, bool), NanonisError> {
675        let result = self.quick_send(
676            "OsciHR.PSDDataGet",
677            vec![
678                NanonisValue::I32(osci_index),
679                NanonisValue::U16(data_to_get),
680                NanonisValue::F64(timeout_s),
681            ],
682            vec!["i", "H", "d"],
683            vec!["d", "d", "i", "*f", "I"],
684        )?;
685
686        if result.len() >= 5 {
687            let frequency_start = result[0].as_f64()?;
688            let frequency_delta = result[1].as_f64()?;
689            let psd_data = result[3].as_f32_array()?.to_vec();
690            let timeout_occurred = result[4].as_u32()? == 1;
691            Ok((frequency_start, frequency_delta, psd_data, timeout_occurred))
692        } else {
693            Err(NanonisError::Protocol(
694                "Invalid PSD data response".to_string(),
695            ))
696        }
697    }
698}