nanonis_rs/client/safe_tip.rs
1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5impl NanonisClient {
6 /// Switch the Safe Tip feature on or off.
7 ///
8 /// The Safe Tip feature provides automatic tip protection by monitoring specific signals
9 /// and triggering safety actions when dangerous conditions are detected. This prevents
10 /// tip crashes and damage during scanning and approach operations.
11 ///
12 /// # Arguments
13 /// * `safe_tip_on` - `true` to enable Safe Tip, `false` to disable
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 /// // Enable Safe Tip protection
25 /// client.safe_tip_on_off_set(true)?;
26 /// println!("Safe Tip protection enabled");
27 ///
28 /// // Disable for manual operations
29 /// client.safe_tip_on_off_set(false)?;
30 /// # Ok::<(), Box<dyn std::error::Error>>(())
31 /// ```
32 pub fn safe_tip_on_off_set(
33 &mut self,
34 safe_tip_on: bool,
35 ) -> Result<(), NanonisError> {
36 let status = if safe_tip_on { 1u16 } else { 2u16 };
37
38 self.quick_send(
39 "SafeTip.OnOffSet",
40 vec![NanonisValue::U16(status)],
41 vec!["H"],
42 vec![],
43 )?;
44 Ok(())
45 }
46
47 /// Get the current on-off status of the Safe Tip feature.
48 ///
49 /// Returns whether the Safe Tip protection is currently active. This is essential
50 /// for verifying tip safety status before starting potentially dangerous operations.
51 ///
52 /// # Returns
53 /// `true` if Safe Tip is enabled, `false` if disabled.
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 /// if client.safe_tip_on_off_get()? {
65 /// println!("Safe Tip protection is active");
66 /// } else {
67 /// println!("Warning: Safe Tip protection is disabled");
68 /// }
69 /// # Ok::<(), Box<dyn std::error::Error>>(())
70 /// ```
71 pub fn safe_tip_on_off_get(&mut self) -> Result<bool, NanonisError> {
72 let result =
73 self.quick_send("SafeTip.OnOffGet", vec![], vec![], vec!["H"])?;
74
75 match result.first() {
76 Some(value) => Ok(value.as_u16()? == 1),
77 None => Err(NanonisError::Protocol(
78 "No Safe Tip status returned".to_string(),
79 )),
80 }
81 }
82
83 /// Get the current Safe Tip signal value.
84 ///
85 /// Returns the current value of the signal being monitored by the Safe Tip system.
86 /// This allows real-time monitoring of the safety-critical parameter.
87 ///
88 /// # Returns
89 /// Current signal value being monitored by Safe Tip.
90 ///
91 /// # Errors
92 /// Returns `NanonisError` if communication fails or protocol error occurs.
93 ///
94 /// # Examples
95 /// ```no_run
96 /// use nanonis_rs::NanonisClient;
97 ///
98 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
99 ///
100 /// let signal_value = client.safe_tip_signal_get()?;
101 /// println!("Safe Tip signal: {:.3e}", signal_value);
102 ///
103 /// // Check if approaching threshold
104 /// let (_, _, threshold) = client.safe_tip_props_get()?;
105 /// if signal_value.abs() > threshold * 0.8 {
106 /// println!("Warning: Approaching Safe Tip threshold!");
107 /// }
108 /// # Ok::<(), Box<dyn std::error::Error>>(())
109 /// ```
110 pub fn safe_tip_signal_get(&mut self) -> Result<f32, NanonisError> {
111 let result =
112 self.quick_send("SafeTip.SignalGet", vec![], vec![], vec!["f"])?;
113
114 match result.first() {
115 Some(value) => Ok(value.as_f32()?),
116 None => Err(NanonisError::Protocol(
117 "No Safe Tip signal value returned".to_string(),
118 )),
119 }
120 }
121
122 /// Set the Safe Tip configuration parameters.
123 ///
124 /// Configures the behavior of the Safe Tip protection system including automatic
125 /// recovery and scan pause features. These settings determine how the system
126 /// responds to safety threshold violations.
127 ///
128 /// # Arguments
129 /// * `auto_recovery` - Enable automatic Z-controller recovery after Safe Tip event
130 /// * `auto_pause_scan` - Enable automatic scan pause/hold on Safe Tip events
131 /// * `threshold` - Signal threshold value that triggers Safe Tip protection
132 ///
133 /// # Errors
134 /// Returns `NanonisError` if communication fails or invalid parameters provided.
135 ///
136 /// # Examples
137 /// ```no_run
138 /// use nanonis_rs::NanonisClient;
139 ///
140 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
141 ///
142 /// // Configure Safe Tip with automatic recovery and scan pause
143 /// client.safe_tip_props_set(true, true, 1e-9)?; // 1 nA threshold
144 ///
145 /// // Conservative settings for delicate samples
146 /// client.safe_tip_props_set(true, true, 500e-12)?; // 500 pA threshold
147 /// # Ok::<(), Box<dyn std::error::Error>>(())
148 /// ```
149 pub fn safe_tip_props_set(
150 &mut self,
151 auto_recovery: bool,
152 auto_pause_scan: bool,
153 threshold: f32,
154 ) -> Result<(), NanonisError> {
155 let recovery_flag = if auto_recovery { 1u16 } else { 0u16 };
156 let pause_flag = if auto_pause_scan { 1u16 } else { 0u16 };
157
158 self.quick_send(
159 "SafeTip.PropsSet",
160 vec![
161 NanonisValue::U16(recovery_flag),
162 NanonisValue::U16(pause_flag),
163 NanonisValue::F32(threshold),
164 ],
165 vec!["H", "H", "f"],
166 vec![],
167 )?;
168 Ok(())
169 }
170
171 /// Get the current Safe Tip configuration.
172 ///
173 /// Returns all Safe Tip protection parameters including automatic recovery settings,
174 /// scan pause behavior, and the safety threshold value.
175 ///
176 /// # Returns
177 /// A tuple containing:
178 /// - `bool` - Auto recovery enabled/disabled
179 /// - `bool` - Auto pause scan enabled/disabled
180 /// - `f32` - Threshold value for triggering Safe Tip protection
181 ///
182 /// # Errors
183 /// Returns `NanonisError` if communication fails or protocol error occurs.
184 ///
185 /// # Examples
186 /// ```no_run
187 /// use nanonis_rs::NanonisClient;
188 ///
189 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
190 ///
191 /// let (auto_recovery, auto_pause, threshold) = client.safe_tip_props_get()?;
192 ///
193 /// println!("Safe Tip Configuration:");
194 /// println!(" Auto recovery: {}", if auto_recovery { "On" } else { "Off" });
195 /// println!(" Auto pause scan: {}", if auto_pause { "On" } else { "Off" });
196 /// println!(" Threshold: {:.3e}", threshold);
197 ///
198 /// // Convert threshold to more readable units
199 /// if threshold < 1e-9 {
200 /// println!(" Threshold: {:.1} pA", threshold * 1e12);
201 /// } else {
202 /// println!(" Threshold: {:.1} nA", threshold * 1e9);
203 /// }
204 /// # Ok::<(), Box<dyn std::error::Error>>(())
205 /// ```
206 pub fn safe_tip_props_get(&mut self) -> Result<(bool, bool, f32), NanonisError> {
207 let result = self.quick_send(
208 "SafeTip.PropsGet",
209 vec![],
210 vec![],
211 vec!["H", "H", "f"],
212 )?;
213
214 if result.len() >= 3 {
215 let auto_recovery = result[0].as_u16()? == 1;
216 let auto_pause_scan = result[1].as_u16()? == 1;
217 let threshold = result[2].as_f32()?;
218 Ok((auto_recovery, auto_pause_scan, threshold))
219 } else {
220 Err(NanonisError::Protocol(
221 "Invalid Safe Tip properties response".to_string(),
222 ))
223 }
224 }
225
226 /// Set the tip lift distance for safety operations.
227 ///
228 /// Sets the distance the tip is lifted when safety procedures are triggered.
229 /// This is part of the Z-controller tip safety system and works in conjunction
230 /// with Safe Tip to provide comprehensive tip protection.
231 ///
232 /// **Note**: This function is part of the Z-controller system but included here
233 /// for safety-related operations.
234 ///
235 /// # Arguments
236 /// * `tip_lift_m` - Tip lift distance in meters (positive = away from surface)
237 ///
238 /// # Errors
239 /// Returns `NanonisError` if communication fails or invalid lift distance.
240 ///
241 /// # Examples
242 /// ```no_run
243 /// use nanonis_rs::NanonisClient;
244 ///
245 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
246 ///
247 /// // Set conservative lift distance for safety
248 /// client.z_ctrl_tip_lift_set(100e-9)?; // 100 nm lift
249 ///
250 /// // Set larger lift for problematic areas
251 /// client.z_ctrl_tip_lift_set(500e-9)?; // 500 nm lift
252 /// # Ok::<(), Box<dyn std::error::Error>>(())
253 /// ```
254 pub fn z_ctrl_tip_lift_set(
255 &mut self,
256 tip_lift_m: f32,
257 ) -> Result<(), NanonisError> {
258 self.quick_send(
259 "ZCtrl.TipLiftSet",
260 vec![NanonisValue::F32(tip_lift_m)],
261 vec!["f"],
262 vec![],
263 )?;
264 Ok(())
265 }
266
267 /// Get the current tip lift distance setting.
268 ///
269 /// Returns the distance the tip will be lifted during safety operations.
270 /// This helps verify that adequate safety margins are configured.
271 ///
272 /// # Returns
273 /// Current tip lift distance in meters.
274 ///
275 /// # Errors
276 /// Returns `NanonisError` if communication fails or protocol error occurs.
277 ///
278 /// # Examples
279 /// ```no_run
280 /// use nanonis_rs::NanonisClient;
281 ///
282 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
283 ///
284 /// let tip_lift = client.z_ctrl_tip_lift_get()?;
285 /// println!("Tip lift distance: {:.1} nm", tip_lift * 1e9);
286 ///
287 /// // Check if lift distance is adequate
288 /// if tip_lift < 50e-9 {
289 /// println!("Warning: Tip lift may be too small for safe operation");
290 /// }
291 /// # Ok::<(), Box<dyn std::error::Error>>(())
292 /// ```
293 pub fn z_ctrl_tip_lift_get(&mut self) -> Result<f32, NanonisError> {
294 let result =
295 self.quick_send("ZCtrl.TipLiftGet", vec![], vec![], vec!["f"])?;
296
297 match result.first() {
298 Some(value) => Ok(value.as_f32()?),
299 None => Err(NanonisError::Protocol(
300 "No tip lift distance returned".to_string(),
301 )),
302 }
303 }
304
305 /// Perform a comprehensive safety check of all tip protection systems.
306 ///
307 /// This convenience method checks the status of all major tip safety systems
308 /// and returns a summary. Use this before starting critical operations to ensure
309 /// all safety measures are properly configured.
310 ///
311 /// # Returns
312 /// A tuple containing safety status information:
313 /// - `bool` - Safe Tip enabled
314 /// - `f32` - Current Safe Tip signal value
315 /// - `f32` - Safe Tip threshold
316 /// - `f32` - Tip lift distance (m)
317 /// - `bool` - Z-controller status
318 ///
319 /// # Errors
320 /// Returns `NanonisError` if any safety system check fails.
321 ///
322 /// # Examples
323 /// ```no_run
324 /// use nanonis_rs::NanonisClient;
325 ///
326 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
327 ///
328 /// let (safe_tip_on, signal_val, threshold, tip_lift, z_ctrl_on) =
329 /// client.safety_status_comprehensive()?;
330 ///
331 /// println!("=== Tip Safety Status ===");
332 /// println!("Safe Tip: {}", if safe_tip_on { "ENABLED" } else { "DISABLED" });
333 /// println!("Signal: {:.2e} / Threshold: {:.2e}", signal_val, threshold);
334 /// println!("Tip Lift: {:.1} nm", tip_lift * 1e9);
335 /// println!("Z-Controller: {}", if z_ctrl_on { "ON" } else { "OFF" });
336 ///
337 /// if !safe_tip_on {
338 /// println!("WARNING: Safe Tip protection is disabled!");
339 /// }
340 /// # Ok::<(), Box<dyn std::error::Error>>(())
341 /// ```
342 pub fn safety_status_comprehensive(
343 &mut self,
344 ) -> Result<(bool, f32, f32, f32, bool), NanonisError> {
345 let safe_tip_on = self.safe_tip_on_off_get()?;
346 let signal_value = self.safe_tip_signal_get()?;
347 let (_, _, threshold) = self.safe_tip_props_get()?;
348 let tip_lift = self.z_ctrl_tip_lift_get()?;
349 let z_ctrl_on = self.z_ctrl_on_off_get()?;
350
351 Ok((safe_tip_on, signal_value, threshold, tip_lift, z_ctrl_on))
352 }
353}