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