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