Skip to main content

nanonis_rs/client/
current.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5impl NanonisClient {
6    /// Get the current tunneling current value.
7    ///
8    /// Returns the instantaneous tunneling current measurement from the current amplifier.
9    /// This is one of the most fundamental measurements in STM, providing direct information
10    /// about the tip-sample conductance.
11    ///
12    /// # Returns
13    /// Current value in Amperes (A).
14    ///
15    /// # Errors
16    /// Returns `NanonisError` if communication fails or protocol error occurs.
17    ///
18    /// # Examples
19    /// ```no_run
20    /// use nanonis_rs::NanonisClient;
21    ///
22    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
23    ///
24    /// let current = client.current_get()?;
25    /// println!("Tunneling current: {:.3e} A", current);
26    ///
27    /// // Convert to more convenient units
28    /// if current.abs() < 1e-9 {
29    ///     println!("Current: {:.1} pA", current * 1e12);
30    /// } else {
31    ///     println!("Current: {:.1} nA", current * 1e9);
32    /// }
33    /// # Ok::<(), Box<dyn std::error::Error>>(())
34    /// ```
35    pub fn current_get(&mut self) -> Result<f32, NanonisError> {
36        let result = self.quick_send("Current.Get", vec![], vec![], vec!["f"])?;
37
38        match result.first() {
39            Some(value) => Ok(value.as_f32()?),
40            None => Err(NanonisError::Protocol(
41                "No current value returned".to_string(),
42            )),
43        }
44    }
45
46    /// Get the current value from the "Current 100" module.
47    ///
48    /// Returns the tunneling current from the specialized Current 100 module,
49    /// which may have different gain or filtering characteristics than the main
50    /// current amplifier.
51    ///
52    /// # Returns
53    /// Current 100 value in Amperes (A).
54    ///
55    /// # Errors
56    /// Returns `NanonisError` if communication fails or protocol error occurs.
57    ///
58    /// # Examples
59    /// ```no_run
60    /// use nanonis_rs::NanonisClient;
61    ///
62    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
63    ///
64    /// let current_100 = client.current_100_get()?;
65    /// println!("Current 100 module: {:.3e} A", current_100);
66    /// # Ok::<(), Box<dyn std::error::Error>>(())
67    /// ```
68    pub fn current_100_get(&mut self) -> Result<f32, NanonisError> {
69        let result = self.quick_send("Current.100Get", vec![], vec![], vec!["f"])?;
70
71        match result.first() {
72            Some(value) => Ok(value.as_f32()?),
73            None => Err(NanonisError::Protocol(
74                "No current 100 value returned".to_string(),
75            )),
76        }
77    }
78
79    /// Get the BEEM current value from the corresponding module.
80    ///
81    /// Returns the Ballistic Electron Emission Microscopy (BEEM) current value
82    /// in systems equipped with BEEM capabilities. BEEM measures hot electrons
83    /// transmitted through thin metal films.
84    ///
85    /// # Returns
86    /// BEEM current value in Amperes (A).
87    ///
88    /// # Errors
89    /// Returns `NanonisError` if:
90    /// - BEEM module is not available or not configured
91    /// - Communication fails or protocol error occurs
92    ///
93    /// # Examples
94    /// ```no_run
95    /// use nanonis_rs::NanonisClient;
96    ///
97    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
98    ///
99    /// let beem_current = client.current_beem_get()?;
100    /// println!("BEEM current: {:.3e} A", beem_current);
101    /// # Ok::<(), Box<dyn std::error::Error>>(())
102    /// ```
103    pub fn current_beem_get(&mut self) -> Result<f32, NanonisError> {
104        let result = self.quick_send("Current.BEEMGet", vec![], vec![], vec!["f"])?;
105
106        match result.first() {
107            Some(value) => Ok(value.as_f32()?),
108            None => Err(NanonisError::Protocol(
109                "No BEEM current value returned".to_string(),
110            )),
111        }
112    }
113
114    /// Set the gain and filter of the current amplifier.
115    ///
116    /// Configures the current amplifier's gain and filtering characteristics.
117    /// Use `current_gains_get()` to retrieve the available gain and filter options
118    /// before setting specific indices.
119    ///
120    /// # Arguments
121    /// * `gain_index` - Index from the list of available gains
122    /// * `filter_index` - Index from the list of available filters
123    ///
124    /// # Errors
125    /// Returns `NanonisError` if:
126    /// - Invalid gain or filter index provided
127    /// - Communication fails or protocol error occurs
128    ///
129    /// # Examples
130    /// ```no_run
131    /// use nanonis_rs::NanonisClient;
132    ///
133    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
134    ///
135    /// // Get available options first
136    /// let (gains, current_gain_idx, filters, current_filter_idx) = client.current_gains_get()?;
137    /// println!("Available gains: {:?}", gains);
138    /// println!("Available filters: {:?}", filters);
139    ///
140    /// // Set to high gain (index 3) with medium filtering (index 1)
141    /// client.current_gain_set(3, 1)?;
142    /// # Ok::<(), Box<dyn std::error::Error>>(())
143    /// ```
144    pub fn current_gain_set(
145        &mut self,
146        gain_index: i32,
147        filter_index: i32,
148    ) -> Result<(), NanonisError> {
149        self.quick_send(
150            "Current.GainSet",
151            vec![
152                NanonisValue::I32(gain_index),
153                NanonisValue::I32(filter_index),
154            ],
155            vec!["i", "i"],
156            vec![],
157        )?;
158        Ok(())
159    }
160
161    /// Get the available gains and filters of the current amplifier.
162    ///
163    /// Returns all selectable gains and filters for the current amplifier, along with
164    /// the currently selected indices. This information is needed for `current_gain_set()`.
165    ///
166    /// # Returns
167    /// A tuple containing:
168    /// - `Vec<String>` - Array of available gain descriptions
169    /// - `u16` - Index of currently selected gain
170    /// - `Vec<String>` - Array of available filter descriptions  
171    /// - `i32` - Index of currently selected filter
172    ///
173    /// # Errors
174    /// Returns `NanonisError` if communication fails or protocol error occurs.
175    ///
176    /// # Examples
177    /// ```no_run
178    /// use nanonis_rs::NanonisClient;
179    ///
180    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
181    ///
182    /// let (gains, gain_idx, filters, filter_idx) = client.current_gains_get()?;
183    ///
184    /// println!("Current gain: {} (index {})", gains[gain_idx as usize], gain_idx);
185    /// println!("Current filter: {} (index {})", filters[filter_idx as usize], filter_idx);
186    ///
187    /// // List all available options
188    /// for (i, gain) in gains.iter().enumerate() {
189    ///     println!("Gain {}: {}", i, gain);
190    /// }
191    /// # Ok::<(), Box<dyn std::error::Error>>(())
192    /// ```
193    pub fn current_gains_get(
194        &mut self,
195    ) -> Result<(Vec<String>, u16, Vec<String>, i32), NanonisError> {
196        let result = self.quick_send(
197            "Current.GainsGet",
198            vec![],
199            vec![],
200            vec!["i", "i", "*+c", "i", "i", "i", "*+c", "i"],
201        )?;
202
203        if result.len() >= 8 {
204            let gains = result[2].as_string_array()?.to_vec();
205            let gain_index = result[3].as_u16()?;
206            let filters = result[6].as_string_array()?.to_vec();
207            let filter_index = result[7].as_i32()?;
208            Ok((gains, gain_index, filters, filter_index))
209        } else {
210            Err(NanonisError::Protocol(
211                "Invalid current gains response".to_string(),
212            ))
213        }
214    }
215
216    /// Set the calibration and offset for a specific gain in the Current module.
217    ///
218    /// Configures the calibration parameters for accurate current measurements.
219    /// Each gain setting can have its own calibration and offset values.
220    ///
221    /// # Arguments
222    /// * `gain_index` - Index of the gain to calibrate (-1 for currently selected gain)
223    /// * `calibration` - Calibration factor (typically A/V or similar)
224    /// * `offset` - Offset value in the same units
225    ///
226    /// # Errors
227    /// Returns `NanonisError` if communication fails or invalid parameters provided.
228    ///
229    /// # Examples
230    /// ```no_run
231    /// use nanonis_rs::NanonisClient;
232    ///
233    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
234    ///
235    /// // Calibrate currently selected gain
236    /// client.current_calibr_set(-1, 1.0e-9, 0.0)?;
237    ///
238    /// // Calibrate specific gain (index 2) with offset correction
239    /// client.current_calibr_set(2, 9.87e-10, -1.5e-12)?;
240    /// # Ok::<(), Box<dyn std::error::Error>>(())
241    /// ```
242    pub fn current_calibr_set(
243        &mut self,
244        gain_index: i32,
245        calibration: f64,
246        offset: f64,
247    ) -> Result<(), NanonisError> {
248        self.quick_send(
249            "Current.CalibrSet",
250            vec![
251                NanonisValue::I32(gain_index),
252                NanonisValue::F64(calibration),
253                NanonisValue::F64(offset),
254            ],
255            vec!["i", "d", "d"],
256            vec![],
257        )?;
258        Ok(())
259    }
260
261    /// Get the calibration and offset for a specific gain in the Current module.
262    ///
263    /// Returns the calibration parameters for the specified gain setting.
264    ///
265    /// # Arguments
266    /// * `gain_index` - Index of the gain to query (-1 for currently selected gain)
267    ///
268    /// # Returns
269    /// A tuple containing:
270    /// - `f64` - Calibration factor
271    /// - `f64` - Offset value
272    ///
273    /// # Errors
274    /// Returns `NanonisError` if communication fails or invalid gain index.
275    ///
276    /// # Examples
277    /// ```no_run
278    /// use nanonis_rs::NanonisClient;
279    ///
280    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
281    ///
282    /// // Get calibration for currently selected gain
283    /// let (calibration, offset) = client.current_calibr_get(-1)?;
284    /// println!("Current calibration: {:.3e}, offset: {:.3e}", calibration, offset);
285    ///
286    /// // Check calibration for specific gain
287    /// let (cal, off) = client.current_calibr_get(2)?;
288    /// # Ok::<(), Box<dyn std::error::Error>>(())
289    /// ```
290    pub fn current_calibr_get(&mut self, gain_index: i32) -> Result<(f64, f64), NanonisError> {
291        let result = self.quick_send(
292            "Current.CalibrGet",
293            vec![NanonisValue::I32(gain_index)],
294            vec!["i"],
295            vec!["d", "d"],
296        )?;
297
298        if result.len() >= 2 {
299            let calibration = result[0].as_f64()?;
300            let offset = result[1].as_f64()?;
301            Ok((calibration, offset))
302        } else {
303            Err(NanonisError::Protocol(
304                "Invalid current calibration response".to_string(),
305            ))
306        }
307    }
308}