Skip to main content

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}