nanonis_rs/client/pll.rs
1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// PLL excitation output range.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum PLLExcRange {
8 /// 10V range
9 #[default]
10 V10 = 0,
11 /// 1V range
12 V1 = 1,
13 /// 0.1V range
14 V01 = 2,
15 /// 0.01V range
16 V001 = 3,
17 /// 0.001V range
18 V0001 = 4,
19}
20
21impl From<PLLExcRange> for u16 {
22 fn from(r: PLLExcRange) -> Self {
23 r as u16
24 }
25}
26
27impl TryFrom<u16> for PLLExcRange {
28 type Error = NanonisError;
29
30 fn try_from(value: u16) -> Result<Self, Self::Error> {
31 match value {
32 0 => Ok(PLLExcRange::V10),
33 1 => Ok(PLLExcRange::V1),
34 2 => Ok(PLLExcRange::V01),
35 3 => Ok(PLLExcRange::V001),
36 4 => Ok(PLLExcRange::V0001),
37 _ => Err(NanonisError::Protocol(format!(
38 "Invalid PLLExcRange value: {}",
39 value
40 ))),
41 }
42 }
43}
44
45/// PLL input properties.
46#[derive(Debug, Clone, Copy, Default)]
47pub struct PLLInputProps {
48 /// Differential input enabled
49 pub differential_input: bool,
50 /// 1/10 divider enabled
51 pub divider_1_10: bool,
52}
53
54/// PLL demodulator input configuration.
55#[derive(Debug, Clone, Copy, Default)]
56pub struct PLLDemodInput {
57 /// Input selection
58 pub input: u16,
59 /// Frequency generator selection
60 pub freq_generator: u16,
61}
62
63/// PLL frequency/excitation overwrite configuration.
64#[derive(Debug, Clone, Copy, Default)]
65pub struct PLLOverwrite {
66 /// Excitation overwrite signal index (-1 for none)
67 pub excitation_signal_index: i32,
68 /// Frequency overwrite signal index (-1 for none)
69 pub frequency_signal_index: i32,
70}
71
72/// PLL amplitude controller gain parameters.
73#[derive(Debug, Clone, Copy, Default)]
74pub struct PLLAmpCtrlGain {
75 /// Proportional gain in V/m
76 pub p_gain_v_per_m: f32,
77 /// Time constant in seconds
78 pub time_constant_s: f32,
79 /// Integral gain in V/m/s (read-only, computed)
80 pub integral_gain_v_per_m_s: f32,
81}
82
83/// PLL phase controller gain parameters.
84#[derive(Debug, Clone, Copy, Default)]
85pub struct PLLPhasCtrlGain {
86 /// Proportional gain in Hz/deg
87 pub p_gain_hz_per_deg: f32,
88 /// Time constant in seconds
89 pub time_constant_s: f32,
90}
91
92impl NanonisClient {
93 // ==================== Input Configuration ====================
94
95 /// Set the input calibration of the oscillation control module.
96 ///
97 /// # Arguments
98 /// * `modulator_index` - PLL modulator index (starts from 1)
99 /// * `calibration_m_per_v` - Input calibration in m/V
100 ///
101 /// # Errors
102 /// Returns `NanonisError` if communication fails.
103 pub fn pll_inp_calibr_set(
104 &mut self,
105 modulator_index: i32,
106 calibration_m_per_v: f32,
107 ) -> Result<(), NanonisError> {
108 self.quick_send(
109 "PLL.InpCalibrSet",
110 vec![
111 NanonisValue::I32(modulator_index),
112 NanonisValue::F32(calibration_m_per_v),
113 ],
114 vec!["i", "f"],
115 vec![],
116 )?;
117 Ok(())
118 }
119
120 /// Get the input calibration of the oscillation control module.
121 ///
122 /// # Arguments
123 /// * `modulator_index` - PLL modulator index (starts from 1)
124 ///
125 /// # Returns
126 /// Input calibration in m/V.
127 ///
128 /// # Errors
129 /// Returns `NanonisError` if communication fails.
130 pub fn pll_inp_calibr_get(&mut self, modulator_index: i32) -> Result<f32, NanonisError> {
131 let result = self.quick_send(
132 "PLL.InpCalibrGet",
133 vec![NanonisValue::I32(modulator_index)],
134 vec!["i"],
135 vec!["f"],
136 )?;
137
138 if !result.is_empty() {
139 Ok(result[0].as_f32()?)
140 } else {
141 Err(NanonisError::Protocol("Invalid response".to_string()))
142 }
143 }
144
145 /// Set the input range of the oscillation control module.
146 ///
147 /// # Arguments
148 /// * `modulator_index` - PLL modulator index (starts from 1)
149 /// * `input_range_m` - Input range in meters
150 ///
151 /// # Errors
152 /// Returns `NanonisError` if communication fails.
153 pub fn pll_inp_range_set(
154 &mut self,
155 modulator_index: i32,
156 input_range_m: f32,
157 ) -> Result<(), NanonisError> {
158 self.quick_send(
159 "PLL.InpRangeSet",
160 vec![
161 NanonisValue::I32(modulator_index),
162 NanonisValue::F32(input_range_m),
163 ],
164 vec!["i", "f"],
165 vec![],
166 )?;
167 Ok(())
168 }
169
170 /// Get the input range of the oscillation control module.
171 ///
172 /// # Arguments
173 /// * `modulator_index` - PLL modulator index (starts from 1)
174 ///
175 /// # Returns
176 /// Input range in meters.
177 ///
178 /// # Errors
179 /// Returns `NanonisError` if communication fails.
180 pub fn pll_inp_range_get(&mut self, modulator_index: i32) -> Result<f32, NanonisError> {
181 let result = self.quick_send(
182 "PLL.InpRangeGet",
183 vec![NanonisValue::I32(modulator_index)],
184 vec!["i"],
185 vec!["f"],
186 )?;
187
188 if !result.is_empty() {
189 Ok(result[0].as_f32()?)
190 } else {
191 Err(NanonisError::Protocol("Invalid response".to_string()))
192 }
193 }
194
195 /// Set the input properties of the oscillation control module.
196 ///
197 /// # Arguments
198 /// * `modulator_index` - PLL modulator index (starts from 1)
199 /// * `props` - Input properties
200 ///
201 /// # Errors
202 /// Returns `NanonisError` if communication fails.
203 pub fn pll_inp_props_set(
204 &mut self,
205 modulator_index: i32,
206 props: &PLLInputProps,
207 ) -> Result<(), NanonisError> {
208 let diff_flag = if props.differential_input { 1u16 } else { 0u16 };
209 let div_flag = if props.divider_1_10 { 1u16 } else { 0u16 };
210 self.quick_send(
211 "PLL.InpPropsSet",
212 vec![
213 NanonisValue::I32(modulator_index),
214 NanonisValue::U16(diff_flag),
215 NanonisValue::U16(div_flag),
216 ],
217 vec!["i", "H", "H"],
218 vec![],
219 )?;
220 Ok(())
221 }
222
223 /// Get the input properties of the oscillation control module.
224 ///
225 /// # Arguments
226 /// * `modulator_index` - PLL modulator index (starts from 1)
227 ///
228 /// # Returns
229 /// Input properties.
230 ///
231 /// # Errors
232 /// Returns `NanonisError` if communication fails.
233 pub fn pll_inp_props_get(
234 &mut self,
235 modulator_index: i32,
236 ) -> Result<PLLInputProps, NanonisError> {
237 let result = self.quick_send(
238 "PLL.InpPropsGet",
239 vec![NanonisValue::I32(modulator_index)],
240 vec!["i"],
241 vec!["H", "H"],
242 )?;
243
244 if result.len() >= 2 {
245 Ok(PLLInputProps {
246 differential_input: result[0].as_u16()? != 0,
247 divider_1_10: result[1].as_u16()? != 0,
248 })
249 } else {
250 Err(NanonisError::Protocol("Invalid response".to_string()))
251 }
252 }
253
254 // ==================== Output Configuration ====================
255
256 /// Set the add external signal status.
257 ///
258 /// # Arguments
259 /// * `modulator_index` - PLL modulator index (starts from 1)
260 /// * `enabled` - True to add external signal to output
261 ///
262 /// # Errors
263 /// Returns `NanonisError` if communication fails.
264 pub fn pll_add_on_off_set(
265 &mut self,
266 modulator_index: i32,
267 enabled: bool,
268 ) -> Result<(), NanonisError> {
269 let flag = if enabled { 1u32 } else { 0u32 };
270 self.quick_send(
271 "PLL.AddOnOffSet",
272 vec![NanonisValue::I32(modulator_index), NanonisValue::U32(flag)],
273 vec!["i", "I"],
274 vec![],
275 )?;
276 Ok(())
277 }
278
279 /// Get the add external signal status.
280 ///
281 /// # Arguments
282 /// * `modulator_index` - PLL modulator index (starts from 1)
283 ///
284 /// # Returns
285 /// True if external signal is being added.
286 ///
287 /// # Errors
288 /// Returns `NanonisError` if communication fails.
289 pub fn pll_add_on_off_get(&mut self, modulator_index: i32) -> Result<bool, NanonisError> {
290 let result = self.quick_send(
291 "PLL.AddOnOffGet",
292 vec![NanonisValue::I32(modulator_index)],
293 vec!["i"],
294 vec!["I"],
295 )?;
296
297 if !result.is_empty() {
298 Ok(result[0].as_u32()? != 0)
299 } else {
300 Err(NanonisError::Protocol("Invalid response".to_string()))
301 }
302 }
303
304 /// Set the PLL output on/off status.
305 ///
306 /// # Arguments
307 /// * `modulator_index` - PLL modulator index (starts from 1)
308 /// * `enabled` - True to enable PLL output
309 ///
310 /// # Errors
311 /// Returns `NanonisError` if communication fails.
312 pub fn pll_out_on_off_set(
313 &mut self,
314 modulator_index: i32,
315 enabled: bool,
316 ) -> Result<(), NanonisError> {
317 let flag = if enabled { 1u32 } else { 0u32 };
318 self.quick_send(
319 "PLL.OutOnOffSet",
320 vec![NanonisValue::I32(modulator_index), NanonisValue::U32(flag)],
321 vec!["i", "I"],
322 vec![],
323 )?;
324 Ok(())
325 }
326
327 /// Get the PLL output on/off status.
328 ///
329 /// # Arguments
330 /// * `modulator_index` - PLL modulator index (starts from 1)
331 ///
332 /// # Returns
333 /// True if PLL output is enabled.
334 ///
335 /// # Errors
336 /// Returns `NanonisError` if communication fails.
337 pub fn pll_out_on_off_get(&mut self, modulator_index: i32) -> Result<bool, NanonisError> {
338 let result = self.quick_send(
339 "PLL.OutOnOffGet",
340 vec![NanonisValue::I32(modulator_index)],
341 vec!["i"],
342 vec!["I"],
343 )?;
344
345 if !result.is_empty() {
346 Ok(result[0].as_u32()? != 0)
347 } else {
348 Err(NanonisError::Protocol("Invalid response".to_string()))
349 }
350 }
351
352 // ==================== Excitation ====================
353
354 /// Set the excitation range.
355 ///
356 /// # Arguments
357 /// * `modulator_index` - PLL modulator index (starts from 1)
358 /// * `range` - Excitation output range
359 ///
360 /// # Errors
361 /// Returns `NanonisError` if communication fails.
362 pub fn pll_exc_range_set(
363 &mut self,
364 modulator_index: i32,
365 range: PLLExcRange,
366 ) -> Result<(), NanonisError> {
367 self.quick_send(
368 "PLL.ExcRangeSet",
369 vec![
370 NanonisValue::I32(modulator_index),
371 NanonisValue::U16(range.into()),
372 ],
373 vec!["i", "H"],
374 vec![],
375 )?;
376 Ok(())
377 }
378
379 /// Get the excitation range.
380 ///
381 /// # Arguments
382 /// * `modulator_index` - PLL modulator index (starts from 1)
383 ///
384 /// # Returns
385 /// Excitation output range.
386 ///
387 /// # Errors
388 /// Returns `NanonisError` if communication fails.
389 pub fn pll_exc_range_get(&mut self, modulator_index: i32) -> Result<PLLExcRange, NanonisError> {
390 let result = self.quick_send(
391 "PLL.ExcRangeGet",
392 vec![NanonisValue::I32(modulator_index)],
393 vec!["i"],
394 vec!["H"],
395 )?;
396
397 if !result.is_empty() {
398 result[0].as_u16()?.try_into()
399 } else {
400 Err(NanonisError::Protocol("Invalid response".to_string()))
401 }
402 }
403
404 /// Set the excitation value (drive amplitude).
405 ///
406 /// Only works when amplitude controller is off.
407 ///
408 /// # Arguments
409 /// * `modulator_index` - PLL modulator index (starts from 1)
410 /// * `excitation_v` - Excitation value in volts
411 ///
412 /// # Errors
413 /// Returns `NanonisError` if communication fails.
414 pub fn pll_excitation_set(
415 &mut self,
416 modulator_index: i32,
417 excitation_v: f32,
418 ) -> Result<(), NanonisError> {
419 self.quick_send(
420 "PLL.ExcitationSet",
421 vec![
422 NanonisValue::I32(modulator_index),
423 NanonisValue::F32(excitation_v),
424 ],
425 vec!["i", "f"],
426 vec![],
427 )?;
428 Ok(())
429 }
430
431 /// Get the excitation value (drive amplitude).
432 ///
433 /// # Arguments
434 /// * `modulator_index` - PLL modulator index (starts from 1)
435 ///
436 /// # Returns
437 /// Excitation value in volts.
438 ///
439 /// # Errors
440 /// Returns `NanonisError` if communication fails.
441 pub fn pll_excitation_get(&mut self, modulator_index: i32) -> Result<f32, NanonisError> {
442 let result = self.quick_send(
443 "PLL.ExcitationGet",
444 vec![NanonisValue::I32(modulator_index)],
445 vec!["i"],
446 vec!["f"],
447 )?;
448
449 if !result.is_empty() {
450 Ok(result[0].as_f32()?)
451 } else {
452 Err(NanonisError::Protocol("Invalid response".to_string()))
453 }
454 }
455
456 // ==================== Amplitude Controller ====================
457 /// Set the amplitude controller setpoint for a PLL modulator.
458 ///
459 /// Sets the amplitude controller setpoint value for the specified PLL modulator.
460 /// This controls the target oscillation amplitude for the phase-locked loop.
461 ///
462 /// # Arguments
463 /// * `modulator_index` - PLL modulator index (starts from 1)
464 /// * `setpoint_m` - Amplitude setpoint in meters
465 ///
466 /// # Errors
467 /// Returns `NanonisError` if communication fails or invalid modulator index.
468 ///
469 /// # Examples
470 /// ```no_run
471 /// use nanonis_rs::NanonisClient;
472 ///
473 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
474 ///
475 /// // Set amplitude setpoint for first PLL to 1 nanometer
476 /// client.pll_amp_ctrl_setpnt_set(1, 1e-9)?;
477 ///
478 /// // Set amplitude setpoint for second PLL to 500 picometers
479 /// client.pll_amp_ctrl_setpnt_set(2, 500e-12)?;
480 /// # Ok::<(), Box<dyn std::error::Error>>(())
481 /// ```
482 pub fn pll_amp_ctrl_setpnt_set(
483 &mut self,
484 modulator_index: i32,
485 setpoint_m: f32,
486 ) -> Result<(), NanonisError> {
487 self.quick_send(
488 "PLL.AmpCtrlSetpntSet",
489 vec![
490 NanonisValue::I32(modulator_index),
491 NanonisValue::F32(setpoint_m),
492 ],
493 vec!["i", "f"],
494 vec![],
495 )?;
496 Ok(())
497 }
498
499 /// Get the amplitude controller setpoint for a PLL modulator.
500 ///
501 /// Returns the current amplitude controller setpoint value for the specified
502 /// PLL modulator.
503 ///
504 /// # Arguments
505 /// * `modulator_index` - PLL modulator index (starts from 1)
506 ///
507 /// # Returns
508 /// * `f32` - Current amplitude setpoint in meters
509 ///
510 /// # Errors
511 /// Returns `NanonisError` if communication fails or invalid modulator index.
512 ///
513 /// # Examples
514 /// ```no_run
515 /// use nanonis_rs::NanonisClient;
516 ///
517 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
518 ///
519 /// // Get current amplitude setpoint for first PLL
520 /// let setpoint = client.pll_amp_ctrl_setpnt_get(1)?;
521 /// println!("Current amplitude setpoint: {:.2e} m", setpoint);
522 ///
523 /// // Check if setpoint is within expected range
524 /// if setpoint > 1e-9 {
525 /// println!("Amplitude setpoint is greater than 1 nm");
526 /// }
527 /// # Ok::<(), Box<dyn std::error::Error>>(())
528 /// ```
529 pub fn pll_amp_ctrl_setpnt_get(&mut self, modulator_index: i32) -> Result<f32, NanonisError> {
530 let response = self.quick_send(
531 "PLL.AmpCtrlSetpntGet",
532 vec![NanonisValue::I32(modulator_index)],
533 vec!["i"],
534 vec!["f"],
535 )?;
536
537 match response.first() {
538 Some(NanonisValue::F32(setpoint)) => Ok(*setpoint),
539 _ => Err(NanonisError::Protocol(
540 "Expected f32 amplitude setpoint".to_string(),
541 )),
542 }
543 }
544
545 /// Set the amplitude controller on/off status for a PLL modulator.
546 ///
547 /// Switches the amplitude controller for the specified PLL modulator on or off.
548 /// When enabled, the amplitude controller actively maintains the oscillation
549 /// amplitude at the setpoint value.
550 ///
551 /// # Arguments
552 /// * `modulator_index` - PLL modulator index (starts from 1)
553 /// * `status` - true to turn on, false to turn off
554 ///
555 /// # Errors
556 /// Returns `NanonisError` if communication fails or invalid modulator index.
557 ///
558 /// # Examples
559 /// ```no_run
560 /// use nanonis_rs::NanonisClient;
561 ///
562 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
563 ///
564 /// // Turn on amplitude controller for first PLL
565 /// client.pll_amp_ctrl_on_off_set(1, true)?;
566 ///
567 /// // Turn off amplitude controller for second PLL
568 /// client.pll_amp_ctrl_on_off_set(2, false)?;
569 /// # Ok::<(), Box<dyn std::error::Error>>(())
570 /// ```
571 pub fn pll_amp_ctrl_on_off_set(
572 &mut self,
573 modulator_index: i32,
574 status: bool,
575 ) -> Result<(), NanonisError> {
576 let status_u32 = if status { 1u32 } else { 0u32 };
577
578 self.quick_send(
579 "PLL.AmpCtrlOnOffSet",
580 vec![
581 NanonisValue::I32(modulator_index),
582 NanonisValue::U32(status_u32),
583 ],
584 vec!["i", "I"],
585 vec![],
586 )?;
587 Ok(())
588 }
589
590 /// Get the amplitude controller on/off status for a PLL modulator.
591 ///
592 /// Returns the current on/off status of the amplitude controller for the
593 /// specified PLL modulator.
594 ///
595 /// # Arguments
596 /// * `modulator_index` - PLL modulator index (starts from 1)
597 ///
598 /// # Returns
599 /// * `bool` - true if controller is on, false if off
600 ///
601 /// # Errors
602 /// Returns `NanonisError` if communication fails or invalid modulator index.
603 ///
604 /// # Examples
605 /// ```no_run
606 /// use nanonis_rs::NanonisClient;
607 ///
608 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
609 ///
610 /// // Check amplitude controller status for first PLL
611 /// let is_on = client.pll_amp_ctrl_on_off_get(1)?;
612 /// if is_on {
613 /// println!("Amplitude controller is active");
614 /// } else {
615 /// println!("Amplitude controller is inactive");
616 /// }
617 ///
618 /// // Enable controller if it's off
619 /// if !is_on {
620 /// client.pll_amp_ctrl_on_off_set(1, true)?;
621 /// }
622 /// # Ok::<(), Box<dyn std::error::Error>>(())
623 /// ```
624 pub fn pll_amp_ctrl_on_off_get(&mut self, modulator_index: i32) -> Result<bool, NanonisError> {
625 let response = self.quick_send(
626 "PLL.AmpCtrlOnOffGet",
627 vec![NanonisValue::I32(modulator_index)],
628 vec!["i"],
629 vec!["I"],
630 )?;
631
632 match response.first() {
633 Some(NanonisValue::U32(status)) => Ok(*status != 0),
634 _ => Err(NanonisError::Protocol(
635 "Expected u32 amplitude controller status".to_string(),
636 )),
637 }
638 }
639
640 /// Set the amplitude controller gain parameters for a PLL modulator.
641 ///
642 /// Sets the proportional gain and time constant for the amplitude controller
643 /// of the specified PLL modulator. These parameters control the response
644 /// characteristics of the amplitude control loop.
645 ///
646 /// # Arguments
647 /// * `modulator_index` - PLL modulator index (starts from 1)
648 /// * `p_gain_v_div_m` - Proportional gain in V/m
649 /// * `time_constant_s` - Time constant in seconds
650 ///
651 /// # Errors
652 /// Returns `NanonisError` if communication fails or invalid modulator index.
653 ///
654 /// # Examples
655 /// ```no_run
656 /// use nanonis_rs::NanonisClient;
657 ///
658 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
659 ///
660 /// // Set moderate gain and fast response for first PLL
661 /// client.pll_amp_ctrl_gain_set(1, 1e6, 0.01)?;
662 ///
663 /// // Set higher gain and slower response for second PLL
664 /// client.pll_amp_ctrl_gain_set(2, 5e6, 0.1)?;
665 /// # Ok::<(), Box<dyn std::error::Error>>(())
666 /// ```
667 pub fn pll_amp_ctrl_gain_set(
668 &mut self,
669 modulator_index: i32,
670 p_gain_v_div_m: f32,
671 time_constant_s: f32,
672 ) -> Result<(), NanonisError> {
673 self.quick_send(
674 "PLL.AmpCtrlGainSet",
675 vec![
676 NanonisValue::I32(modulator_index),
677 NanonisValue::F32(p_gain_v_div_m),
678 NanonisValue::F32(time_constant_s),
679 ],
680 vec!["i", "f", "f"],
681 vec![],
682 )?;
683 Ok(())
684 }
685
686 /// Get the amplitude controller gain parameters for a PLL modulator.
687 ///
688 /// Returns the current proportional gain and time constant settings for the
689 /// amplitude controller of the specified PLL modulator.
690 ///
691 /// # Arguments
692 /// * `modulator_index` - PLL modulator index (starts from 1)
693 ///
694 /// # Returns
695 /// * `(f32, f32)` - Tuple of (proportional gain in V/m, time constant in seconds)
696 ///
697 /// # Errors
698 /// Returns `NanonisError` if communication fails or invalid modulator index.
699 ///
700 /// # Examples
701 /// ```no_run
702 /// use nanonis_rs::NanonisClient;
703 ///
704 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
705 ///
706 /// // Get current gain parameters for first PLL
707 /// let (p_gain, time_const) = client.pll_amp_ctrl_gain_get(1)?;
708 /// println!("P gain: {:.2e} V/m, Time constant: {:.3} s", p_gain, time_const);
709 ///
710 /// // Check if parameters are within acceptable range
711 /// if p_gain < 1e5 {
712 /// println!("Warning: Low proportional gain");
713 /// }
714 /// if time_const > 1.0 {
715 /// println!("Warning: Slow time constant");
716 /// }
717 /// # Ok::<(), Box<dyn std::error::Error>>(())
718 /// ```
719 pub fn pll_amp_ctrl_gain_get(
720 &mut self,
721 modulator_index: i32,
722 ) -> Result<(f32, f32), NanonisError> {
723 let response = self.quick_send(
724 "PLL.AmpCtrlGainGet",
725 vec![NanonisValue::I32(modulator_index)],
726 vec!["i"],
727 vec!["f", "f"],
728 )?;
729
730 match (response.first(), response.get(1)) {
731 (Some(NanonisValue::F32(p_gain)), Some(NanonisValue::F32(time_const))) => {
732 Ok((*p_gain, *time_const))
733 }
734 _ => Err(NanonisError::Protocol(
735 "Expected f32 gain parameters (p_gain, time_constant)".to_string(),
736 )),
737 }
738 }
739
740 /// Set the amplitude controller bandwidth.
741 ///
742 /// Uses current Q factor and amplitude to excitation ratio.
743 ///
744 /// # Arguments
745 /// * `modulator_index` - PLL modulator index (starts from 1)
746 /// * `bandwidth_hz` - Bandwidth in Hz
747 ///
748 /// # Errors
749 /// Returns `NanonisError` if communication fails.
750 pub fn pll_amp_ctrl_bandwidth_set(
751 &mut self,
752 modulator_index: i32,
753 bandwidth_hz: f32,
754 ) -> Result<(), NanonisError> {
755 self.quick_send(
756 "PLL.AmpCtrlBandwidthSet",
757 vec![
758 NanonisValue::I32(modulator_index),
759 NanonisValue::F32(bandwidth_hz),
760 ],
761 vec!["i", "f"],
762 vec![],
763 )?;
764 Ok(())
765 }
766
767 /// Get the amplitude controller bandwidth.
768 ///
769 /// # Arguments
770 /// * `modulator_index` - PLL modulator index (starts from 1)
771 ///
772 /// # Returns
773 /// Bandwidth in Hz.
774 ///
775 /// # Errors
776 /// Returns `NanonisError` if communication fails.
777 pub fn pll_amp_ctrl_bandwidth_get(
778 &mut self,
779 modulator_index: i32,
780 ) -> Result<f32, NanonisError> {
781 let result = self.quick_send(
782 "PLL.AmpCtrlBandwidthGet",
783 vec![NanonisValue::I32(modulator_index)],
784 vec!["i"],
785 vec!["f"],
786 )?;
787
788 if !result.is_empty() {
789 Ok(result[0].as_f32()?)
790 } else {
791 Err(NanonisError::Protocol("Invalid response".to_string()))
792 }
793 }
794
795 // ==================== Phase Controller ====================
796
797 /// Set the phase controller on/off status.
798 ///
799 /// # Arguments
800 /// * `modulator_index` - PLL modulator index (starts from 1)
801 /// * `enabled` - True to enable phase controller
802 ///
803 /// # Errors
804 /// Returns `NanonisError` if communication fails.
805 pub fn pll_phas_ctrl_on_off_set(
806 &mut self,
807 modulator_index: i32,
808 enabled: bool,
809 ) -> Result<(), NanonisError> {
810 let flag = if enabled { 1u32 } else { 0u32 };
811 self.quick_send(
812 "PLL.PhasCtrlOnOffSet",
813 vec![NanonisValue::I32(modulator_index), NanonisValue::U32(flag)],
814 vec!["i", "I"],
815 vec![],
816 )?;
817 Ok(())
818 }
819
820 /// Get the phase controller on/off status.
821 ///
822 /// # Arguments
823 /// * `modulator_index` - PLL modulator index (starts from 1)
824 ///
825 /// # Returns
826 /// True if phase controller is enabled.
827 ///
828 /// # Errors
829 /// Returns `NanonisError` if communication fails.
830 pub fn pll_phas_ctrl_on_off_get(&mut self, modulator_index: i32) -> Result<bool, NanonisError> {
831 let result = self.quick_send(
832 "PLL.PhasCtrlOnOffGet",
833 vec![NanonisValue::I32(modulator_index)],
834 vec!["i"],
835 vec!["I"],
836 )?;
837
838 if !result.is_empty() {
839 Ok(result[0].as_u32()? != 0)
840 } else {
841 Err(NanonisError::Protocol("Invalid response".to_string()))
842 }
843 }
844
845 /// Set the phase controller gain parameters.
846 ///
847 /// # Arguments
848 /// * `modulator_index` - PLL modulator index (starts from 1)
849 /// * `p_gain_hz_per_deg` - Proportional gain in Hz/deg
850 /// * `time_constant_s` - Time constant in seconds
851 ///
852 /// # Errors
853 /// Returns `NanonisError` if communication fails.
854 pub fn pll_phas_ctrl_gain_set(
855 &mut self,
856 modulator_index: i32,
857 p_gain_hz_per_deg: f32,
858 time_constant_s: f32,
859 ) -> Result<(), NanonisError> {
860 self.quick_send(
861 "PLL.PhasCtrlGainSet",
862 vec![
863 NanonisValue::I32(modulator_index),
864 NanonisValue::F32(p_gain_hz_per_deg),
865 NanonisValue::F32(time_constant_s),
866 ],
867 vec!["i", "f", "f"],
868 vec![],
869 )?;
870 Ok(())
871 }
872
873 /// Get the phase controller gain parameters.
874 ///
875 /// # Arguments
876 /// * `modulator_index` - PLL modulator index (starts from 1)
877 ///
878 /// # Returns
879 /// Phase controller gain parameters.
880 ///
881 /// # Errors
882 /// Returns `NanonisError` if communication fails.
883 pub fn pll_phas_ctrl_gain_get(
884 &mut self,
885 modulator_index: i32,
886 ) -> Result<PLLPhasCtrlGain, NanonisError> {
887 let result = self.quick_send(
888 "PLL.PhasCtrlGainGet",
889 vec![NanonisValue::I32(modulator_index)],
890 vec!["i"],
891 vec!["f", "f"],
892 )?;
893
894 if result.len() >= 2 {
895 Ok(PLLPhasCtrlGain {
896 p_gain_hz_per_deg: result[0].as_f32()?,
897 time_constant_s: result[1].as_f32()?,
898 })
899 } else {
900 Err(NanonisError::Protocol("Invalid response".to_string()))
901 }
902 }
903
904 /// Set the phase controller bandwidth.
905 ///
906 /// Uses current Q factor.
907 ///
908 /// # Arguments
909 /// * `modulator_index` - PLL modulator index (starts from 1)
910 /// * `bandwidth_hz` - Bandwidth in Hz
911 ///
912 /// # Errors
913 /// Returns `NanonisError` if communication fails.
914 pub fn pll_phas_ctrl_bandwidth_set(
915 &mut self,
916 modulator_index: i32,
917 bandwidth_hz: f32,
918 ) -> Result<(), NanonisError> {
919 self.quick_send(
920 "PLL.PhasCtrlBandwidthSet",
921 vec![
922 NanonisValue::I32(modulator_index),
923 NanonisValue::F32(bandwidth_hz),
924 ],
925 vec!["i", "f"],
926 vec![],
927 )?;
928 Ok(())
929 }
930
931 /// Get the phase controller bandwidth.
932 ///
933 /// # Arguments
934 /// * `modulator_index` - PLL modulator index (starts from 1)
935 ///
936 /// # Returns
937 /// Bandwidth in Hz.
938 ///
939 /// # Errors
940 /// Returns `NanonisError` if communication fails.
941 pub fn pll_phas_ctrl_bandwidth_get(
942 &mut self,
943 modulator_index: i32,
944 ) -> Result<f32, NanonisError> {
945 let result = self.quick_send(
946 "PLL.PhasCtrlBandwidthGet",
947 vec![NanonisValue::I32(modulator_index)],
948 vec!["i"],
949 vec!["f"],
950 )?;
951
952 if !result.is_empty() {
953 Ok(result[0].as_f32()?)
954 } else {
955 Err(NanonisError::Protocol("Invalid response".to_string()))
956 }
957 }
958
959 // ==================== Frequency ====================
960
961 /// Set the frequency range.
962 ///
963 /// # Arguments
964 /// * `modulator_index` - PLL modulator index (starts from 1)
965 /// * `freq_range_hz` - Frequency range in Hz
966 ///
967 /// # Errors
968 /// Returns `NanonisError` if communication fails.
969 pub fn pll_freq_range_set(
970 &mut self,
971 modulator_index: i32,
972 freq_range_hz: f32,
973 ) -> Result<(), NanonisError> {
974 self.quick_send(
975 "PLL.FreqRangeSet",
976 vec![
977 NanonisValue::I32(modulator_index),
978 NanonisValue::F32(freq_range_hz),
979 ],
980 vec!["i", "f"],
981 vec![],
982 )?;
983 Ok(())
984 }
985
986 /// Get the frequency range.
987 ///
988 /// # Arguments
989 /// * `modulator_index` - PLL modulator index (starts from 1)
990 ///
991 /// # Returns
992 /// Frequency range in Hz.
993 ///
994 /// # Errors
995 /// Returns `NanonisError` if communication fails.
996 pub fn pll_freq_range_get(&mut self, modulator_index: i32) -> Result<f32, NanonisError> {
997 let result = self.quick_send(
998 "PLL.FreqRangeGet",
999 vec![NanonisValue::I32(modulator_index)],
1000 vec!["i"],
1001 vec!["f"],
1002 )?;
1003
1004 if !result.is_empty() {
1005 Ok(result[0].as_f32()?)
1006 } else {
1007 Err(NanonisError::Protocol("Invalid response".to_string()))
1008 }
1009 }
1010
1011 /// Set the center frequency.
1012 ///
1013 /// # Arguments
1014 /// * `modulator_index` - PLL modulator index (starts from 1)
1015 /// * `center_freq_hz` - Center frequency in Hz
1016 ///
1017 /// # Errors
1018 /// Returns `NanonisError` if communication fails.
1019 pub fn pll_center_freq_set(
1020 &mut self,
1021 modulator_index: i32,
1022 center_freq_hz: f64,
1023 ) -> Result<(), NanonisError> {
1024 self.quick_send(
1025 "PLL.CenterFreqSet",
1026 vec![
1027 NanonisValue::I32(modulator_index),
1028 NanonisValue::F64(center_freq_hz),
1029 ],
1030 vec!["i", "d"],
1031 vec![],
1032 )?;
1033 Ok(())
1034 }
1035
1036 /// Get the center frequency.
1037 ///
1038 /// # Arguments
1039 /// * `modulator_index` - PLL modulator index (starts from 1)
1040 ///
1041 /// # Returns
1042 /// Center frequency in Hz.
1043 ///
1044 /// # Errors
1045 /// Returns `NanonisError` if communication fails.
1046 pub fn pll_center_freq_get(&mut self, modulator_index: i32) -> Result<f64, NanonisError> {
1047 let result = self.quick_send(
1048 "PLL.CenterFreqGet",
1049 vec![NanonisValue::I32(modulator_index)],
1050 vec!["i"],
1051 vec!["d"],
1052 )?;
1053
1054 if !result.is_empty() {
1055 Ok(result[0].as_f64()?)
1056 } else {
1057 Err(NanonisError::Protocol("Invalid response".to_string()))
1058 }
1059 }
1060
1061 /// Set the frequency shift.
1062 ///
1063 /// # Arguments
1064 /// * `modulator_index` - PLL modulator index (starts from 1)
1065 /// * `freq_shift_hz` - Frequency shift in Hz
1066 ///
1067 /// # Errors
1068 /// Returns `NanonisError` if communication fails.
1069 pub fn pll_freq_shift_set(
1070 &mut self,
1071 modulator_index: i32,
1072 freq_shift_hz: f32,
1073 ) -> Result<(), NanonisError> {
1074 self.quick_send(
1075 "PLL.FreqShiftSet",
1076 vec![
1077 NanonisValue::I32(modulator_index),
1078 NanonisValue::F32(freq_shift_hz),
1079 ],
1080 vec!["i", "f"],
1081 vec![],
1082 )?;
1083 Ok(())
1084 }
1085
1086 /// Get the frequency shift.
1087 ///
1088 /// # Arguments
1089 /// * `modulator_index` - PLL modulator index (starts from 1)
1090 ///
1091 /// # Returns
1092 /// Frequency shift in Hz.
1093 ///
1094 /// # Errors
1095 /// Returns `NanonisError` if communication fails.
1096 pub fn pll_freq_shift_get(&mut self, modulator_index: i32) -> Result<f32, NanonisError> {
1097 let result = self.quick_send(
1098 "PLL.FreqShiftGet",
1099 vec![NanonisValue::I32(modulator_index)],
1100 vec!["i"],
1101 vec!["f"],
1102 )?;
1103
1104 if !result.is_empty() {
1105 Ok(result[0].as_f32()?)
1106 } else {
1107 Err(NanonisError::Protocol("Invalid response".to_string()))
1108 }
1109 }
1110
1111 /// Auto-center frequency shift.
1112 ///
1113 /// Adds current frequency shift to center frequency and sets frequency shift to zero.
1114 ///
1115 /// # Arguments
1116 /// * `modulator_index` - PLL modulator index (starts from 1)
1117 ///
1118 /// # Errors
1119 /// Returns `NanonisError` if communication fails.
1120 pub fn pll_freq_shift_auto_center(&mut self, modulator_index: i32) -> Result<(), NanonisError> {
1121 self.quick_send(
1122 "PLL.FreqShiftAutoCenter",
1123 vec![NanonisValue::I32(modulator_index)],
1124 vec!["i"],
1125 vec![],
1126 )?;
1127 Ok(())
1128 }
1129
1130 /// Set the frequency/excitation overwrite signals.
1131 ///
1132 /// Works when corresponding controller is not active.
1133 /// Use -2 for no change.
1134 ///
1135 /// # Arguments
1136 /// * `modulator_index` - PLL modulator index (starts from 1)
1137 /// * `overwrite` - Overwrite configuration
1138 ///
1139 /// # Errors
1140 /// Returns `NanonisError` if communication fails.
1141 pub fn pll_freq_exc_overwrite_set(
1142 &mut self,
1143 modulator_index: i32,
1144 overwrite: &PLLOverwrite,
1145 ) -> Result<(), NanonisError> {
1146 self.quick_send(
1147 "PLL.FreqExcOverwriteSet",
1148 vec![
1149 NanonisValue::I32(modulator_index),
1150 NanonisValue::I32(overwrite.excitation_signal_index),
1151 NanonisValue::I32(overwrite.frequency_signal_index),
1152 ],
1153 vec!["i", "i", "i"],
1154 vec![],
1155 )?;
1156 Ok(())
1157 }
1158
1159 /// Get the frequency/excitation overwrite signals.
1160 ///
1161 /// # Arguments
1162 /// * `modulator_index` - PLL modulator index (starts from 1)
1163 ///
1164 /// # Returns
1165 /// Overwrite configuration.
1166 ///
1167 /// # Errors
1168 /// Returns `NanonisError` if communication fails.
1169 pub fn pll_freq_exc_overwrite_get(
1170 &mut self,
1171 modulator_index: i32,
1172 ) -> Result<PLLOverwrite, NanonisError> {
1173 let result = self.quick_send(
1174 "PLL.FreqExcOverwriteGet",
1175 vec![NanonisValue::I32(modulator_index)],
1176 vec!["i"],
1177 vec!["i", "i"],
1178 )?;
1179
1180 if result.len() >= 2 {
1181 Ok(PLLOverwrite {
1182 excitation_signal_index: result[0].as_i32()?,
1183 frequency_signal_index: result[1].as_i32()?,
1184 })
1185 } else {
1186 Err(NanonisError::Protocol("Invalid response".to_string()))
1187 }
1188 }
1189
1190 // ==================== Demodulator ====================
1191
1192 /// Set the demodulator input and frequency generator.
1193 ///
1194 /// # Arguments
1195 /// * `demodulator_index` - Demodulator index (starts from 1)
1196 /// * `input` - Demodulator input configuration
1197 ///
1198 /// # Errors
1199 /// Returns `NanonisError` if communication fails.
1200 pub fn pll_demod_input_set(
1201 &mut self,
1202 demodulator_index: u16,
1203 input: &PLLDemodInput,
1204 ) -> Result<(), NanonisError> {
1205 self.quick_send(
1206 "PLL.DemodInputSet",
1207 vec![
1208 NanonisValue::U16(demodulator_index),
1209 NanonisValue::U16(input.input),
1210 NanonisValue::U16(input.freq_generator),
1211 ],
1212 vec!["H", "H", "H"],
1213 vec![],
1214 )?;
1215 Ok(())
1216 }
1217
1218 /// Get the demodulator input and frequency generator.
1219 ///
1220 /// # Arguments
1221 /// * `demodulator_index` - Demodulator index (starts from 1)
1222 ///
1223 /// # Returns
1224 /// Demodulator input configuration.
1225 ///
1226 /// # Errors
1227 /// Returns `NanonisError` if communication fails.
1228 pub fn pll_demod_input_get(
1229 &mut self,
1230 demodulator_index: u16,
1231 ) -> Result<PLLDemodInput, NanonisError> {
1232 let result = self.quick_send(
1233 "PLL.DemodInputGet",
1234 vec![NanonisValue::U16(demodulator_index)],
1235 vec!["H"],
1236 vec!["H", "H"],
1237 )?;
1238
1239 if result.len() >= 2 {
1240 Ok(PLLDemodInput {
1241 input: result[0].as_u16()?,
1242 freq_generator: result[1].as_u16()?,
1243 })
1244 } else {
1245 Err(NanonisError::Protocol("Invalid response".to_string()))
1246 }
1247 }
1248
1249 /// Set the demodulator harmonic.
1250 ///
1251 /// Harmonic 1 corresponds to modulation frequency.
1252 ///
1253 /// # Arguments
1254 /// * `demodulator_index` - Demodulator index (starts from 1)
1255 /// * `harmonic` - Harmonic number
1256 ///
1257 /// # Errors
1258 /// Returns `NanonisError` if communication fails.
1259 pub fn pll_demod_harmonic_set(
1260 &mut self,
1261 demodulator_index: u16,
1262 harmonic: u16,
1263 ) -> Result<(), NanonisError> {
1264 self.quick_send(
1265 "PLL.DemodHarmonicSet",
1266 vec![
1267 NanonisValue::U16(demodulator_index),
1268 NanonisValue::U16(harmonic),
1269 ],
1270 vec!["H", "H"],
1271 vec![],
1272 )?;
1273 Ok(())
1274 }
1275
1276 /// Get the demodulator harmonic.
1277 ///
1278 /// # Arguments
1279 /// * `demodulator_index` - Demodulator index (starts from 1)
1280 ///
1281 /// # Returns
1282 /// Harmonic number.
1283 ///
1284 /// # Errors
1285 /// Returns `NanonisError` if communication fails.
1286 pub fn pll_demod_harmonic_get(&mut self, demodulator_index: u16) -> Result<u16, NanonisError> {
1287 let result = self.quick_send(
1288 "PLL.DemodHarmonicGet",
1289 vec![NanonisValue::U16(demodulator_index)],
1290 vec!["H"],
1291 vec!["H"],
1292 )?;
1293
1294 if !result.is_empty() {
1295 Ok(result[0].as_u16()?)
1296 } else {
1297 Err(NanonisError::Protocol("Invalid response".to_string()))
1298 }
1299 }
1300
1301 /// Set the demodulator phase reference.
1302 ///
1303 /// # Arguments
1304 /// * `demodulator_index` - Demodulator index (starts from 1)
1305 /// * `phase_deg` - Phase reference in degrees
1306 ///
1307 /// # Errors
1308 /// Returns `NanonisError` if communication fails.
1309 pub fn pll_demod_phas_ref_set(
1310 &mut self,
1311 demodulator_index: u16,
1312 phase_deg: f32,
1313 ) -> Result<(), NanonisError> {
1314 self.quick_send(
1315 "PLL.DemodPhasRefSet",
1316 vec![
1317 NanonisValue::U16(demodulator_index),
1318 NanonisValue::F32(phase_deg),
1319 ],
1320 vec!["H", "f"],
1321 vec![],
1322 )?;
1323 Ok(())
1324 }
1325
1326 /// Get the demodulator phase reference.
1327 ///
1328 /// # Arguments
1329 /// * `demodulator_index` - Demodulator index (starts from 1)
1330 ///
1331 /// # Returns
1332 /// Phase reference in degrees.
1333 ///
1334 /// # Errors
1335 /// Returns `NanonisError` if communication fails.
1336 pub fn pll_demod_phas_ref_get(&mut self, demodulator_index: u16) -> Result<f32, NanonisError> {
1337 let result = self.quick_send(
1338 "PLL.DemodPhasRefGet",
1339 vec![NanonisValue::U16(demodulator_index)],
1340 vec!["H"],
1341 vec!["f"],
1342 )?;
1343
1344 if !result.is_empty() {
1345 Ok(result[0].as_f32()?)
1346 } else {
1347 Err(NanonisError::Protocol("Invalid response".to_string()))
1348 }
1349 }
1350
1351 /// Set the demodulator filter order.
1352 ///
1353 /// # Arguments
1354 /// * `demodulator_index` - Demodulator index (starts from 1)
1355 /// * `filter_order` - Low-pass filter order
1356 ///
1357 /// # Errors
1358 /// Returns `NanonisError` if communication fails.
1359 pub fn pll_demod_filter_set(
1360 &mut self,
1361 demodulator_index: u16,
1362 filter_order: u16,
1363 ) -> Result<(), NanonisError> {
1364 self.quick_send(
1365 "PLL.DemodFilterSet",
1366 vec![
1367 NanonisValue::U16(demodulator_index),
1368 NanonisValue::U16(filter_order),
1369 ],
1370 vec!["H", "H"],
1371 vec![],
1372 )?;
1373 Ok(())
1374 }
1375
1376 /// Get the demodulator filter order.
1377 ///
1378 /// # Arguments
1379 /// * `demodulator_index` - Demodulator index (starts from 1)
1380 ///
1381 /// # Returns
1382 /// Low-pass filter order.
1383 ///
1384 /// # Errors
1385 /// Returns `NanonisError` if communication fails.
1386 pub fn pll_demod_filter_get(&mut self, demodulator_index: u16) -> Result<u16, NanonisError> {
1387 let result = self.quick_send(
1388 "PLL.DemodFilterGet",
1389 vec![NanonisValue::U16(demodulator_index)],
1390 vec!["H"],
1391 vec!["H"],
1392 )?;
1393
1394 if !result.is_empty() {
1395 Ok(result[0].as_u16()?)
1396 } else {
1397 Err(NanonisError::Protocol("Invalid response".to_string()))
1398 }
1399 }
1400}