Skip to main content

nanonis_rs/client/oscilloscope/
osci_hr.rs

1use super::super::NanonisClient;
2use super::*;
3use crate::client::signals::SignalIndex;
4use crate::error::NanonisError;
5use crate::types::NanonisValue;
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![NanonisValue::I32(osci_index), NanonisValue::U16(weighting)],
456            vec!["i", "H"],
457            vec![],
458        )?;
459        Ok(())
460    }
461
462    /// Get the PSD weighting mode in the Oscilloscope High Resolution.
463    ///
464    /// # Arguments
465    /// * `osci_index` - Oscilloscope channel index
466    ///
467    /// # Returns
468    /// Weighting mode (0 = None, 1 = A-weighting, 2 = C-weighting).
469    ///
470    /// # Errors
471    /// Returns `NanonisError` if communication fails.
472    pub fn osci_hr_psd_weight_get(&mut self, osci_index: i32) -> Result<u16, NanonisError> {
473        let result = self.quick_send(
474            "OsciHR.PSDWeightGet",
475            vec![NanonisValue::I32(osci_index)],
476            vec!["i"],
477            vec!["H"],
478        )?;
479        match result.first() {
480            Some(value) => Ok(value.as_u16()?),
481            None => Err(NanonisError::Protocol(
482                "No PSD weighting returned".to_string(),
483            )),
484        }
485    }
486
487    /// Set the PSD window function in the Oscilloscope High Resolution.
488    ///
489    /// # Arguments
490    /// * `osci_index` - Oscilloscope channel index
491    /// * `window` - Window function (0 = None, 1 = Hann, 2 = Hamming, 3 = Blackman-Harris, 4 = Flat Top)
492    ///
493    /// # Errors
494    /// Returns `NanonisError` if communication fails.
495    pub fn osci_hr_psd_window_set(
496        &mut self,
497        osci_index: i32,
498        window: u16,
499    ) -> Result<(), NanonisError> {
500        self.quick_send(
501            "OsciHR.PSDWindowSet",
502            vec![NanonisValue::I32(osci_index), NanonisValue::U16(window)],
503            vec!["i", "H"],
504            vec![],
505        )?;
506        Ok(())
507    }
508
509    /// Get the PSD window function in the Oscilloscope High Resolution.
510    ///
511    /// # Arguments
512    /// * `osci_index` - Oscilloscope channel index
513    ///
514    /// # Returns
515    /// Window function (0 = None, 1 = Hann, 2 = Hamming, 3 = Blackman-Harris, 4 = Flat Top).
516    ///
517    /// # Errors
518    /// Returns `NanonisError` if communication fails.
519    pub fn osci_hr_psd_window_get(&mut self, osci_index: i32) -> Result<u16, NanonisError> {
520        let result = self.quick_send(
521            "OsciHR.PSDWindowGet",
522            vec![NanonisValue::I32(osci_index)],
523            vec!["i"],
524            vec!["H"],
525        )?;
526        match result.first() {
527            Some(value) => Ok(value.as_u16()?),
528            None => Err(NanonisError::Protocol("No PSD window returned".to_string())),
529        }
530    }
531
532    /// Set the PSD averaging type in the Oscilloscope High Resolution.
533    ///
534    /// # Arguments
535    /// * `osci_index` - Oscilloscope channel index
536    /// * `averaging_type` - Averaging type (0 = None, 1 = Linear, 2 = Exponential)
537    ///
538    /// # Errors
539    /// Returns `NanonisError` if communication fails.
540    pub fn osci_hr_psd_avrg_type_set(
541        &mut self,
542        osci_index: i32,
543        averaging_type: u16,
544    ) -> Result<(), NanonisError> {
545        self.quick_send(
546            "OsciHR.PSDAvrgTypeSet",
547            vec![
548                NanonisValue::I32(osci_index),
549                NanonisValue::U16(averaging_type),
550            ],
551            vec!["i", "H"],
552            vec![],
553        )?;
554        Ok(())
555    }
556
557    /// Get the PSD averaging type in the Oscilloscope High Resolution.
558    ///
559    /// # Arguments
560    /// * `osci_index` - Oscilloscope channel index
561    ///
562    /// # Returns
563    /// Averaging type (0 = None, 1 = Linear, 2 = Exponential).
564    ///
565    /// # Errors
566    /// Returns `NanonisError` if communication fails.
567    pub fn osci_hr_psd_avrg_type_get(&mut self, osci_index: i32) -> Result<u16, NanonisError> {
568        let result = self.quick_send(
569            "OsciHR.PSDAvrgTypeGet",
570            vec![NanonisValue::I32(osci_index)],
571            vec!["i"],
572            vec!["H"],
573        )?;
574        match result.first() {
575            Some(value) => Ok(value.as_u16()?),
576            None => Err(NanonisError::Protocol(
577                "No PSD averaging type returned".to_string(),
578            )),
579        }
580    }
581
582    /// Set the PSD averaging count in the Oscilloscope High Resolution.
583    ///
584    /// # Arguments
585    /// * `osci_index` - Oscilloscope channel index
586    /// * `count` - Number of averages
587    ///
588    /// # Errors
589    /// Returns `NanonisError` if communication fails.
590    pub fn osci_hr_psd_avrg_count_set(
591        &mut self,
592        osci_index: i32,
593        count: i32,
594    ) -> Result<(), NanonisError> {
595        self.quick_send(
596            "OsciHR.PSDAvrgCountSet",
597            vec![NanonisValue::I32(osci_index), NanonisValue::I32(count)],
598            vec!["i", "i"],
599            vec![],
600        )?;
601        Ok(())
602    }
603
604    /// Get the PSD averaging count in the Oscilloscope High Resolution.
605    ///
606    /// # Arguments
607    /// * `osci_index` - Oscilloscope channel index
608    ///
609    /// # Returns
610    /// Number of averages.
611    ///
612    /// # Errors
613    /// Returns `NanonisError` if communication fails.
614    pub fn osci_hr_psd_avrg_count_get(&mut self, osci_index: i32) -> Result<i32, NanonisError> {
615        let result = self.quick_send(
616            "OsciHR.PSDAvrgCountGet",
617            vec![NanonisValue::I32(osci_index)],
618            vec!["i"],
619            vec!["i"],
620        )?;
621        match result.first() {
622            Some(value) => Ok(value.as_i32()?),
623            None => Err(NanonisError::Protocol(
624                "No PSD averaging count returned".to_string(),
625            )),
626        }
627    }
628
629    /// Restart PSD averaging in the Oscilloscope High Resolution.
630    ///
631    /// # Arguments
632    /// * `osci_index` - Oscilloscope channel index
633    ///
634    /// # Errors
635    /// Returns `NanonisError` if communication fails.
636    pub fn osci_hr_psd_avrg_restart(&mut self, osci_index: i32) -> Result<(), NanonisError> {
637        self.quick_send(
638            "OsciHR.PSDAvrgRestart",
639            vec![NanonisValue::I32(osci_index)],
640            vec!["i"],
641            vec![],
642        )?;
643        Ok(())
644    }
645
646    /// Get the PSD data from the Oscilloscope High Resolution.
647    ///
648    /// # Arguments
649    /// * `osci_index` - Oscilloscope channel index
650    /// * `data_to_get` - 0 = Current data, 1 = Wait for next acquisition
651    /// * `timeout_s` - Timeout in seconds
652    ///
653    /// # Returns
654    /// Tuple of (frequency_start, frequency_delta, psd_data, timeout_occurred).
655    ///
656    /// # Errors
657    /// Returns `NanonisError` if communication fails.
658    pub fn osci_hr_psd_data_get(
659        &mut self,
660        osci_index: i32,
661        data_to_get: u16,
662        timeout_s: f64,
663    ) -> Result<(f64, f64, Vec<f32>, bool), NanonisError> {
664        let result = self.quick_send(
665            "OsciHR.PSDDataGet",
666            vec![
667                NanonisValue::I32(osci_index),
668                NanonisValue::U16(data_to_get),
669                NanonisValue::F64(timeout_s),
670            ],
671            vec!["i", "H", "d"],
672            vec!["d", "d", "i", "*f", "I"],
673        )?;
674
675        if result.len() >= 5 {
676            let frequency_start = result[0].as_f64()?;
677            let frequency_delta = result[1].as_f64()?;
678            let psd_data = result[3].as_f32_array()?.to_vec();
679            let timeout_occurred = result[4].as_u32()? == 1;
680            Ok((frequency_start, frequency_delta, psd_data, timeout_occurred))
681        } else {
682            Err(NanonisError::Protocol(
683                "Invalid PSD data response".to_string(),
684            ))
685        }
686    }
687}