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