Skip to main content

nanonis_rs/client/user_out/
mod.rs

1mod types;
2pub use types::*;
3
4use super::NanonisClient;
5use crate::error::NanonisError;
6
7impl NanonisClient {
8    /// Set the mode (User Output, Monitor, Calculated signal) of the selected user output channel.
9    ///
10    /// # Arguments
11    /// * `output_index` - Output to be used (1 to number of available outputs)
12    /// * `output_mode` - Output mode to set
13    ///
14    /// # Errors
15    /// Returns `NanonisError` if:
16    /// - Invalid output index is provided
17    /// - Communication timeout or protocol error
18    ///
19    /// # Examples
20    /// ```no_run
21    /// use nanonis_rs::{NanonisClient, user_out::OutputMode};
22    ///
23    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
24    ///
25    /// // Set output 1 to Monitor mode
26    /// client.user_out_mode_set(1, OutputMode::Monitor)?;
27    /// # Ok::<(), Box<dyn std::error::Error>>(())
28    /// ```
29    pub fn user_out_mode_set(
30        &mut self,
31        output_index: i32,
32        output_mode: OutputMode,
33    ) -> Result<(), NanonisError> {
34        self.quick_send(
35            "UserOut.ModeSet",
36            vec![output_index.into(), output_mode.into()],
37            vec!["i", "H"],
38            vec![],
39        )?;
40        Ok(())
41    }
42
43    /// Get the mode (User Output, Monitor, Calculated signal) of the selected user output channel.
44    ///
45    /// # Arguments
46    /// * `output_index` - Output to query (1 to number of available outputs)
47    ///
48    /// # Returns
49    /// The current output mode (UserOutput, Monitor, CalcSignal, or Override)
50    ///
51    /// # Errors
52    /// Returns `NanonisError` if communication fails or invalid response received.
53    ///
54    /// # Examples
55    /// ```no_run
56    /// use nanonis_rs::NanonisClient;
57    ///
58    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
59    ///
60    /// let mode = client.user_out_mode_get(1)?;
61    /// println!("Output 1 mode: {:?}", mode);
62    /// # Ok::<(), Box<dyn std::error::Error>>(())
63    /// ```
64    pub fn user_out_mode_get(&mut self, output_index: i32) -> Result<OutputMode, NanonisError> {
65        let result = self.quick_send(
66            "UserOut.ModeGet",
67            vec![output_index.into()],
68            vec!["i"],
69            vec!["H"],
70        )?;
71        match result.first() {
72            Some(value) => {
73                let mode_val = value.as_u16()?;
74                OutputMode::try_from(mode_val)
75            }
76            None => Err(NanonisError::Protocol(
77                "No output mode value returned".to_string(),
78            )),
79        }
80    }
81
82    /// Set the monitor channel of the selected output channel.
83    ///
84    /// # Arguments
85    /// * `output_index` - Output to configure (1 to number of available outputs)
86    /// * `monitor_channel_index` - Index of the channel to monitor (0-127)
87    ///
88    /// # Errors
89    /// Returns `NanonisError` if invalid indices provided or communication fails.
90    ///
91    /// # Examples
92    /// ```no_run
93    /// use nanonis_rs::NanonisClient;
94    ///
95    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
96    ///
97    /// // Set output 1 to monitor channel 5
98    /// client.user_out_monitor_ch_set(1, 5)?;
99    /// # Ok::<(), Box<dyn std::error::Error>>(())
100    /// ```
101    pub fn user_out_monitor_ch_set(
102        &mut self,
103        output_index: i32,
104        monitor_channel_index: i32,
105    ) -> Result<(), NanonisError> {
106        self.quick_send(
107            "UserOut.MonitorChSet",
108            vec![output_index.into(), monitor_channel_index.into()],
109            vec!["i", "i"],
110            vec![],
111        )?;
112        Ok(())
113    }
114
115    /// Get the monitor channel of the selected output channel.
116    ///
117    /// # Arguments
118    /// * `output_index` - Output to query (1 to number of available outputs)
119    ///
120    /// # Returns
121    /// The monitor channel index (0-127)
122    ///
123    /// # Errors
124    /// Returns `NanonisError` if communication fails or invalid response received.
125    ///
126    /// # Examples
127    /// ```no_run
128    /// use nanonis_rs::NanonisClient;
129    ///
130    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
131    ///
132    /// let channel = client.user_out_monitor_ch_get(1)?;
133    /// println!("Output 1 is monitoring channel {}", channel);
134    /// # Ok::<(), Box<dyn std::error::Error>>(())
135    /// ```
136    pub fn user_out_monitor_ch_get(&mut self, output_index: i32) -> Result<i32, NanonisError> {
137        let result = self.quick_send(
138            "UserOut.MonitorChGet",
139            vec![output_index.into()],
140            vec!["i"],
141            vec!["i"],
142        )?;
143        match result.first() {
144            Some(value) => Ok(value.as_i32()?),
145            None => Err(NanonisError::Protocol(
146                "No monitor channel value returned".to_string(),
147            )),
148        }
149    }
150
151    /// Set the value of the selected user output channel.
152    ///
153    /// # Arguments
154    /// * `output_index` - Output to set (1 to number of available outputs)
155    /// * `output_value` - Value to apply in physical units
156    ///
157    /// # Errors
158    /// Returns `NanonisError` if invalid output index or communication fails.
159    ///
160    /// # Examples
161    /// ```no_run
162    /// use nanonis_rs::NanonisClient;
163    ///
164    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
165    ///
166    /// // Set output 1 to 2.5V (or appropriate physical unit)
167    /// client.user_out_val_set(1, 2.5)?;
168    /// # Ok::<(), Box<dyn std::error::Error>>(())
169    /// ```
170    pub fn user_out_val_set(
171        &mut self,
172        output_index: i32,
173        output_value: f32,
174    ) -> Result<(), NanonisError> {
175        self.quick_send(
176            "UserOut.ValSet",
177            vec![output_index.into(), output_value.into()],
178            vec!["i", "f"],
179            vec![],
180        )?;
181        Ok(())
182    }
183
184    /// Set the calibration of the selected user output or monitor channel.
185    ///
186    /// # Arguments
187    /// * `output_index` - Output to configure (1 to number of available outputs)
188    /// * `calibration_per_volt` - Calibration factor per volt
189    /// * `offset_in_physical_units` - Offset in physical units
190    ///
191    /// # Errors
192    /// Returns `NanonisError` if invalid parameters or communication fails.
193    ///
194    /// # Examples
195    /// ```no_run
196    /// use nanonis_rs::NanonisClient;
197    ///
198    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
199    ///
200    /// // Set calibration for output 1: 10 units/V with 0.5 unit offset
201    /// client.user_out_calibr_set(1, 10.0, 0.5)?;
202    /// # Ok::<(), Box<dyn std::error::Error>>(())
203    /// ```
204    pub fn user_out_calibr_set(
205        &mut self,
206        output_index: i32,
207        calibration_per_volt: f32,
208        offset_in_physical_units: f32,
209    ) -> Result<(), NanonisError> {
210        self.quick_send(
211            "UserOut.CalibrSet",
212            vec![
213                output_index.into(),
214                calibration_per_volt.into(),
215                offset_in_physical_units.into(),
216            ],
217            vec!["i", "f", "f"],
218            vec![],
219        )?;
220        Ok(())
221    }
222
223    /// Set the Calculated Signal name of the selected output channel.
224    ///
225    /// # Arguments
226    /// * `output_index` - Output to configure (1 to number of available outputs)
227    /// * `calculated_signal_name` - Name of the calculated signal
228    ///
229    /// # Errors
230    /// Returns `NanonisError` if invalid output index or communication fails.
231    ///
232    /// # Examples
233    /// ```no_run
234    /// use nanonis_rs::NanonisClient;
235    ///
236    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
237    ///
238    /// client.user_out_calc_signal_name_set(1, "MyCalcSignal".to_string())?;
239    /// # Ok::<(), Box<dyn std::error::Error>>(())
240    /// ```
241    pub fn user_out_calc_signal_name_set(
242        &mut self,
243        output_index: i32,
244        calculated_signal_name: String,
245    ) -> Result<(), NanonisError> {
246        self.quick_send(
247            "UserOut.CalcSignalNameSet",
248            vec![output_index.into(), calculated_signal_name.into()],
249            vec!["i", "+*c"],
250            vec![],
251        )?;
252        Ok(())
253    }
254
255    /// Get the Calculated Signal name of the selected output channel.
256    ///
257    /// # Arguments
258    /// * `output_index` - Output to query (1 to number of available outputs)
259    ///
260    /// # Returns
261    /// The calculated signal name
262    ///
263    /// # Errors
264    /// Returns `NanonisError` if communication fails or invalid response received.
265    ///
266    /// # Examples
267    /// ```no_run
268    /// use nanonis_rs::NanonisClient;
269    ///
270    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
271    ///
272    /// let name = client.user_out_calc_signal_name_get(1)?;
273    /// println!("Calculated signal name: {}", name);
274    /// # Ok::<(), Box<dyn std::error::Error>>(())
275    /// ```
276    pub fn user_out_calc_signal_name_get(
277        &mut self,
278        output_index: i32,
279    ) -> Result<String, NanonisError> {
280        let result = self.quick_send(
281            "UserOut.CalcSignalNameGet",
282            vec![output_index.into()],
283            vec!["i"],
284            vec!["i", "*-c"],
285        )?;
286        if result.len() >= 2 {
287            Ok(result[1].as_string()?.to_string())
288        } else {
289            Err(NanonisError::Protocol(
290                "Invalid calc signal name response".to_string(),
291            ))
292        }
293    }
294
295    /// Set the configuration of the Calculated Signal for the selected output channel.
296    ///
297    /// The configuration is a math operation between 2 signals, or the logarithmic value of one signal.
298    ///
299    /// # Arguments
300    /// * `output_index` - Output to configure (1 to number of available outputs)
301    /// * `config` - Calculated signal configuration
302    ///
303    /// # Errors
304    /// Returns `NanonisError` if invalid parameters or communication fails.
305    ///
306    /// # Examples
307    /// ```no_run
308    /// use nanonis_rs::{NanonisClient, user_out::{CalcSignalConfig, CalcOperation}};
309    ///
310    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
311    ///
312    /// // Configure output 1 to add signals 5 and 10
313    /// let config = CalcSignalConfig::new(5, CalcOperation::Add, 10);
314    /// client.user_out_calc_signal_config_set(1, config)?;
315    /// # Ok::<(), Box<dyn std::error::Error>>(())
316    /// ```
317    pub fn user_out_calc_signal_config_set(
318        &mut self,
319        output_index: i32,
320        config: CalcSignalConfig,
321    ) -> Result<(), NanonisError> {
322        self.quick_send(
323            "UserOut.CalcSignalConfigSet",
324            vec![
325                output_index.into(),
326                config.signal_1.into(),
327                config.operation.into(),
328                config.signal_2.into(),
329            ],
330            vec!["i", "H", "H", "H"],
331            vec![],
332        )?;
333        Ok(())
334    }
335
336    /// Get the configuration of the Calculated Signal for the selected output channel.
337    ///
338    /// # Arguments
339    /// * `output_index` - Output to query (1 to number of available outputs)
340    ///
341    /// # Returns
342    /// The calculated signal configuration
343    ///
344    /// # Errors
345    /// Returns `NanonisError` if communication fails or invalid response received.
346    ///
347    /// # Examples
348    /// ```no_run
349    /// use nanonis_rs::NanonisClient;
350    ///
351    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
352    ///
353    /// let config = client.user_out_calc_signal_config_get(1)?;
354    /// println!("Signal 1: {}, Operation: {:?}, Signal 2: {}",
355    ///          config.signal_1, config.operation, config.signal_2);
356    /// # Ok::<(), Box<dyn std::error::Error>>(())
357    /// ```
358    pub fn user_out_calc_signal_config_get(
359        &mut self,
360        output_index: i32,
361    ) -> Result<CalcSignalConfig, NanonisError> {
362        let result = self.quick_send(
363            "UserOut.CalcSignalConfigGet",
364            vec![output_index.into()],
365            vec!["i"],
366            vec!["H", "H", "H"],
367        )?;
368        if result.len() >= 3 {
369            let signal_1 = result[0].as_u16()?;
370            let operation = CalcOperation::try_from(result[1].as_u16()?)?;
371            let signal_2 = result[2].as_u16()?;
372            Ok(CalcSignalConfig::new(signal_1, operation, signal_2))
373        } else {
374            Err(NanonisError::Protocol(
375                "Invalid calc signal config response".to_string(),
376            ))
377        }
378    }
379
380    /// Set the physical limits (in calibrated units) of the selected output channel.
381    ///
382    /// # Arguments
383    /// * `output_index` - Output to configure (1 to number of available outputs)
384    /// * `upper_limit` - Upper physical limit of the user output
385    /// * `lower_limit` - Lower physical limit of the user output
386    /// * `raw_limits` - Whether to set physical limits (false) or raw limits (true)
387    ///
388    /// # Errors
389    /// Returns `NanonisError` if invalid parameters or communication fails.
390    ///
391    /// # Examples
392    /// ```no_run
393    /// use nanonis_rs::NanonisClient;
394    ///
395    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
396    ///
397    /// // Set physical limits: -10V to +10V
398    /// client.user_out_limits_set(1, 10.0, -10.0, false)?;
399    /// # Ok::<(), Box<dyn std::error::Error>>(())
400    /// ```
401    pub fn user_out_limits_set(
402        &mut self,
403        output_index: i32,
404        upper_limit: f32,
405        lower_limit: f32,
406        raw_limits: bool,
407    ) -> Result<(), NanonisError> {
408        let raw_flag = if raw_limits { 1u32 } else { 0u32 };
409        self.quick_send(
410            "UserOut.LimitsSet",
411            vec![
412                output_index.into(),
413                upper_limit.into(),
414                lower_limit.into(),
415                raw_flag.into(),
416            ],
417            vec!["i", "f", "f", "I"],
418            vec![],
419        )?;
420        Ok(())
421    }
422
423    /// Get the physical limits (in calibrated units) of the selected output channel.
424    ///
425    /// # Arguments
426    /// * `output_index` - Output to query (1 to number of available outputs)
427    /// * `raw_limits` - Whether to get physical limits (false) or raw limits (true)
428    ///
429    /// # Returns
430    /// A tuple containing (upper_limit, lower_limit)
431    ///
432    /// # Errors
433    /// Returns `NanonisError` if communication fails or invalid response received.
434    ///
435    /// # Examples
436    /// ```no_run
437    /// use nanonis_rs::NanonisClient;
438    ///
439    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
440    ///
441    /// let (upper, lower) = client.user_out_limits_get(1, false)?;
442    /// println!("Limits: {} to {}", lower, upper);
443    /// # Ok::<(), Box<dyn std::error::Error>>(())
444    /// ```
445    pub fn user_out_limits_get(
446        &mut self,
447        output_index: i32,
448        raw_limits: bool,
449    ) -> Result<(f32, f32), NanonisError> {
450        let raw_flag = if raw_limits { 1u32 } else { 0u32 };
451        let result = self.quick_send(
452            "UserOut.LimitsGet",
453            vec![output_index.into(), raw_flag.into()],
454            vec!["i", "I"],
455            vec!["f", "f"],
456        )?;
457        if result.len() >= 2 {
458            let upper_limit = result[0].as_f32()?;
459            let lower_limit = result[1].as_f32()?;
460            Ok((upper_limit, lower_limit))
461        } else {
462            Err(NanonisError::Protocol(
463                "Invalid limits response".to_string(),
464            ))
465        }
466    }
467}