nanonis_rs/client/bias/mod.rs
1mod types;
2pub use types::*;
3
4use super::NanonisClient;
5use crate::error::NanonisError;
6use crate::types::NanonisValue;
7
8impl NanonisClient {
9 /// Set the bias voltage applied to the scanning probe tip.
10 ///
11 /// This corresponds to the Nanonis `Bias.Set` command and is fundamental
12 /// for tip-sample interaction control.
13 ///
14 /// # Arguments
15 /// * `voltage` - The bias voltage to apply (in volts)
16 ///
17 /// # Errors
18 /// Returns `NanonisError` if:
19 /// - The command fails or communication times out
20 /// - The voltage is outside the instrument's safe operating range
21 ///
22 /// # Examples
23 /// ```no_run
24 /// use nanonis_rs::NanonisClient;
25 ///
26 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
27 ///
28 /// // Set bias to 1.5V
29 /// client.bias_set(1.5)?;
30 ///
31 /// // Set bias to -0.5V
32 /// client.bias_set(-0.5)?;
33 /// # Ok::<(), Box<dyn std::error::Error>>(())
34 /// ```
35 pub fn bias_set(&mut self, voltage: f32) -> Result<(), NanonisError> {
36 self.quick_send(
37 "Bias.Set",
38 vec![NanonisValue::F32(voltage)],
39 vec!["f"],
40 vec![],
41 )?;
42 Ok(())
43 }
44
45 /// Get the current bias voltage applied to the scanning probe tip.
46 ///
47 /// This corresponds to the Nanonis `Bias.Get` command.
48 ///
49 /// # Returns
50 /// The current bias voltage in volts.
51 ///
52 /// # Errors
53 /// Returns `NanonisError` if:
54 /// - The command fails or communication times out
55 /// - The server returns invalid or missing data
56 ///
57 /// # Examples
58 /// ```no_run
59 /// use nanonis_rs::NanonisClient;
60 ///
61 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
62 ///
63 /// let current_bias = client.bias_get()?;
64 /// println!("Current bias voltage: {:.3}V", current_bias);
65 /// # Ok::<(), Box<dyn std::error::Error>>(())
66 /// ```
67 pub fn bias_get(&mut self) -> Result<f32, NanonisError> {
68 let result = self.quick_send("Bias.Get", vec![], vec![], vec!["f"])?;
69 match result.first() {
70 Some(value) => Ok(value.as_f32()?),
71 None => {
72 Err(NanonisError::Protocol("No bias value returned".to_string()))
73 }
74 }
75 }
76
77 /// Set the range of the bias voltage, if different ranges are available.
78 ///
79 /// Sets the bias voltage range by selecting from available ranges.
80 /// Use `bias_range_get()` first to retrieve the list of available ranges.
81 ///
82 /// # Arguments
83 /// * `bias_range_index` - Index from the list of ranges (0-based)
84 ///
85 /// # Errors
86 /// Returns `NanonisError` if:
87 /// - Invalid range index is provided
88 /// - Communication timeout or protocol error
89 ///
90 /// # Examples
91 /// ```no_run
92 /// use nanonis_rs::NanonisClient;
93 ///
94 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
95 ///
96 /// // First get available ranges
97 /// let (ranges, current_index) = client.bias_range_get()?;
98 /// println!("Available ranges: {:?}", ranges);
99 ///
100 /// // Set to range index 1
101 /// client.bias_range_set(1)?;
102 /// # Ok::<(), Box<dyn std::error::Error>>(())
103 /// ```
104 pub fn bias_range_set(
105 &mut self,
106 bias_range_index: u16,
107 ) -> Result<(), NanonisError> {
108 self.quick_send(
109 "Bias.RangeSet",
110 vec![NanonisValue::U16(bias_range_index)],
111 vec!["H"],
112 vec![],
113 )?;
114 Ok(())
115 }
116
117 /// Get the selectable ranges of bias voltage and the index of the selected one.
118 ///
119 /// Returns all available bias voltage ranges and which one is currently selected.
120 /// This information is needed for `bias_range_set()` and `bias_calibr_set/get()`.
121 ///
122 /// # Returns
123 /// A tuple containing:
124 /// - `Vec<String>` - Array of available bias range descriptions
125 /// - `u16` - Index of currently selected range
126 ///
127 /// # Errors
128 /// Returns `NanonisError` if communication fails or protocol error occurs.
129 ///
130 /// # Examples
131 /// ```no_run
132 /// use nanonis_rs::NanonisClient;
133 ///
134 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
135 ///
136 /// let (ranges, current_index) = client.bias_range_get()?;
137 /// println!("Current range: {} (index {})", ranges[current_index as usize], current_index);
138 ///
139 /// for (i, range) in ranges.iter().enumerate() {
140 /// println!("Range {}: {}", i, range);
141 /// }
142 /// # Ok::<(), Box<dyn std::error::Error>>(())
143 /// ```
144 pub fn bias_range_get(&mut self) -> Result<(Vec<String>, u16), NanonisError> {
145 let result = self.quick_send(
146 "Bias.RangeGet",
147 vec![],
148 vec![],
149 vec!["i", "i", "*+c", "H"],
150 )?;
151 if result.len() >= 4 {
152 let ranges = result[2].as_string_array()?.to_vec();
153 let current_index = result[3].as_u16()?;
154 Ok((ranges, current_index))
155 } else {
156 Err(NanonisError::Protocol(
157 "Invalid bias range response".to_string(),
158 ))
159 }
160 }
161
162 /// Set the calibration and offset of bias voltage.
163 ///
164 /// Sets the calibration parameters for the currently selected bias range.
165 /// If multiple ranges are available, this affects only the selected range.
166 ///
167 /// # Arguments
168 /// * `calibration` - Calibration factor (typically in V/V or similar units)
169 /// * `offset` - Offset value in the same units as calibration
170 ///
171 /// # Errors
172 /// Returns `NanonisError` if communication fails or invalid parameters provided.
173 ///
174 /// # Examples
175 /// ```no_run
176 /// use nanonis_rs::NanonisClient;
177 ///
178 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
179 ///
180 /// // Set calibration factor and offset for current range
181 /// client.bias_calibr_set(1.0, 0.0)?;
182 ///
183 /// // Apply a small offset correction
184 /// client.bias_calibr_set(0.998, 0.005)?;
185 /// Ok::<(), Box<dyn std::error::Error>>(())
186 /// ```
187 pub fn bias_calibr_set(
188 &mut self,
189 calibration: f32,
190 offset: f32,
191 ) -> Result<(), NanonisError> {
192 self.quick_send(
193 "Bias.CalibrSet",
194 vec![NanonisValue::F32(calibration), NanonisValue::F32(offset)],
195 vec!["f", "f"],
196 vec![],
197 )?;
198 Ok(())
199 }
200
201 /// Get the calibration and offset of bias voltage.
202 ///
203 /// Returns the calibration parameters for the currently selected bias range.
204 /// If multiple ranges are available, this returns values for the selected range.
205 ///
206 /// # Returns
207 /// A tuple containing:
208 /// - `f32` - Calibration factor
209 /// - `f32` - Offset value
210 ///
211 /// # Errors
212 /// Returns `NanonisError` if communication fails or protocol error occurs.
213 ///
214 /// # Examples
215 /// ```no_run
216 /// use nanonis_rs::NanonisClient;
217 ///
218 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
219 ///
220 /// let (calibration, offset) = client.bias_calibr_get()?;
221 /// println!("Bias calibration: {:.6}, offset: {:.6}", calibration, offset);
222 /// Ok::<(), Box<dyn std::error::Error>>(())
223 /// ```
224 pub fn bias_calibr_get(&mut self) -> Result<(f32, f32), NanonisError> {
225 let result =
226 self.quick_send("Bias.CalibrGet", vec![], vec![], vec!["f", "f"])?;
227 if result.len() >= 2 {
228 let calibration = result[0].as_f32()?;
229 let offset = result[1].as_f32()?;
230 Ok((calibration, offset))
231 } else {
232 Err(NanonisError::Protocol(
233 "Invalid bias calibration response".to_string(),
234 ))
235 }
236 }
237
238 /// Generate one bias pulse.
239 ///
240 /// Applies a bias voltage pulse for a specified duration. This is useful for
241 /// tunneling spectroscopy, tip conditioning, or sample manipulation experiments.
242 ///
243 /// # Arguments
244 /// * `wait_until_done` - If true, function waits until pulse completes
245 /// * `pulse_width_s` - Pulse duration in seconds
246 /// * `bias_value_v` - Bias voltage during pulse (in volts)
247 /// * `z_controller_hold` - Z-controller behavior: 0=no change, 1=hold, 2=don't hold
248 /// * `pulse_mode` - Pulse mode: 0=no change, 1=relative to current, 2=absolute value
249 ///
250 /// # Errors
251 /// Returns `NanonisError` if:
252 /// - Invalid pulse parameters (negative duration, etc.)
253 /// - Bias voltage exceeds safety limits
254 /// - Communication timeout or protocol error
255 ///
256 /// # Examples
257 /// ```no_run
258 /// use nanonis_rs::NanonisClient;
259 ///
260 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
261 ///
262 /// // Apply a 100ms pulse at +2V, holding Z-controller, absolute voltage
263 /// client.bias_pulse(true, 0.1, 2.0, 1, 2)?;
264 ///
265 /// // Quick +0.5V pulse relative to current bias, don't wait
266 /// client.bias_pulse(false, 0.01, 0.5, 0, 1)?;
267 ///
268 /// // Long conditioning pulse at -3V absolute, hold Z-controller
269 /// client.bias_pulse(true, 1.0, -3.0, 1, 2)?;
270 /// # Ok::<(), Box<dyn std::error::Error>>(())
271 /// ```
272 pub fn bias_pulse(
273 &mut self,
274 wait_until_done: bool,
275 pulse_width_s: f32,
276 bias_value_v: f32,
277 z_controller_hold: u16,
278 pulse_mode: u16,
279 ) -> Result<(), NanonisError> {
280 let wait_flag = if wait_until_done { 1u32 } else { 0u32 };
281
282 self.quick_send(
283 "Bias.Pulse",
284 vec![
285 NanonisValue::U32(wait_flag),
286 NanonisValue::F32(pulse_width_s),
287 NanonisValue::F32(bias_value_v),
288 NanonisValue::U16(z_controller_hold),
289 NanonisValue::U16(pulse_mode),
290 ],
291 vec!["I", "f", "f", "H", "H"],
292 vec![],
293 )?;
294 Ok(())
295 }
296}