Skip to main content

nanonis_rs/client/
folme.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::{NanonisValue, Position};
4
5/// Follow Me speed configuration.
6#[derive(Debug, Clone, Copy, Default)]
7pub struct FolMeSpeed {
8    /// Speed in m/s
9    pub speed_m_s: f32,
10    /// True if using custom speed, false if using scan speed
11    pub custom_speed: bool,
12}
13
14/// Follow Me oversampling configuration.
15#[derive(Debug, Clone, Copy, Default)]
16pub struct FolMeOversampling {
17    /// Oversampling factor
18    pub oversampling: i32,
19    /// Sampling rate in samples/s
20    pub sampling_rate: f32,
21}
22
23/// Point & Shoot experiment configuration.
24#[derive(Debug, Clone, Default)]
25pub struct FolMePSExperiment {
26    /// Selected experiment index
27    pub selected: u16,
28    /// List of available experiments
29    pub experiments: Vec<String>,
30}
31
32/// Point & Shoot properties.
33#[derive(Debug, Clone, Default)]
34pub struct FolMePSProps {
35    /// True if scan resumes after experiment
36    pub auto_resume: bool,
37    /// True to use experiment's basename, false for P&S basename
38    pub use_own_basename: bool,
39    /// Basename for Point & Shoot files
40    pub basename: String,
41    /// Path to external VI
42    pub external_vi_path: String,
43    /// Delay before measurement in seconds
44    pub pre_measure_delay_s: f32,
45}
46
47/// Auto resume mode for Point & Shoot.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
49pub enum PSAutoResume {
50    #[default]
51    NoChange = 0,
52    Resume = 1,
53    DontResume = 2,
54}
55
56impl From<PSAutoResume> for u32 {
57    fn from(mode: PSAutoResume) -> Self {
58        mode as u32
59    }
60}
61
62/// Basename mode for Point & Shoot.
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
64pub enum PSBasenameMode {
65    #[default]
66    NoChange = 0,
67    UseExperimentBasename = 1,
68    UsePSBasename = 2,
69}
70
71impl From<PSBasenameMode> for u32 {
72    fn from(mode: PSBasenameMode) -> Self {
73        mode as u32
74    }
75}
76
77impl NanonisClient {
78    // ==================== Follow Me ====================
79
80    /// Get the current x-y position.
81    ///
82    /// # Arguments
83    /// * `wait_for_newest_data` - If true, waits for newest data
84    ///
85    /// # Returns
86    /// Current position.
87    ///
88    /// # Errors
89    /// Returns `NanonisError` if communication fails.
90    pub fn folme_xy_pos_get(
91        &mut self,
92        wait_for_newest_data: bool,
93    ) -> Result<Position, NanonisError> {
94        let wait_flag = if wait_for_newest_data { 1u32 } else { 0u32 };
95        let result = self.quick_send(
96            "FolMe.XYPosGet",
97            vec![NanonisValue::U32(wait_flag)],
98            vec!["I"],
99            vec!["d", "d"],
100        )?;
101
102        if result.len() >= 2 {
103            Ok(Position {
104                x: result[0].as_f64()?,
105                y: result[1].as_f64()?,
106            })
107        } else {
108            Err(NanonisError::Protocol(
109                "Invalid position response".to_string(),
110            ))
111        }
112    }
113
114    /// Set the x-y position.
115    ///
116    /// # Arguments
117    /// * `position` - Target position
118    /// * `wait_until_finished` - If true, waits until move completes
119    ///
120    /// # Errors
121    /// Returns `NanonisError` if communication fails.
122    pub fn folme_xy_pos_set(
123        &mut self,
124        position: Position,
125        wait_until_finished: bool,
126    ) -> Result<(), NanonisError> {
127        let wait_flag = if wait_until_finished { 1u32 } else { 0u32 };
128        self.quick_send(
129            "FolMe.XYPosSet",
130            vec![
131                NanonisValue::F64(position.x),
132                NanonisValue::F64(position.y),
133                NanonisValue::U32(wait_flag),
134            ],
135            vec!["d", "d", "I"],
136            vec![],
137        )?;
138        Ok(())
139    }
140
141    /// Set the tip speed when moving in Follow Me mode.
142    ///
143    /// # Arguments
144    /// * `speed_m_s` - Speed in m/s
145    /// * `custom_speed` - True to use custom speed, false for scan speed
146    ///
147    /// # Errors
148    /// Returns `NanonisError` if communication fails.
149    pub fn folme_speed_set(&mut self, speed_m_s: f32, custom_speed: bool) -> Result<(), NanonisError> {
150        let custom_speed_flag = if custom_speed { 1u32 } else { 0u32 };
151        self.quick_send(
152            "FolMe.SpeedSet",
153            vec![
154                NanonisValue::F32(speed_m_s),
155                NanonisValue::U32(custom_speed_flag),
156            ],
157            vec!["f", "I"],
158            vec![],
159        )?;
160        Ok(())
161    }
162
163    /// Get the tip speed configuration for Follow Me mode.
164    ///
165    /// # Returns
166    /// Speed configuration.
167    ///
168    /// # Errors
169    /// Returns `NanonisError` if communication fails.
170    pub fn folme_speed_get(&mut self) -> Result<FolMeSpeed, NanonisError> {
171        let result = self.quick_send("FolMe.SpeedGet", vec![], vec![], vec!["f", "I"])?;
172
173        Ok(FolMeSpeed {
174            speed_m_s: result[0].as_f32()?,
175            custom_speed: result[1].as_u32()? != 0,
176        })
177    }
178
179    /// Set the oversampling for data acquisition in Follow Me mode.
180    ///
181    /// # Arguments
182    /// * `oversampling` - Oversampling factor
183    ///
184    /// # Errors
185    /// Returns `NanonisError` if communication fails.
186    pub fn folme_oversampl_set(&mut self, oversampling: i32) -> Result<(), NanonisError> {
187        self.quick_send(
188            "FolMe.OversamplSet",
189            vec![NanonisValue::I32(oversampling)],
190            vec!["i"],
191            vec![],
192        )?;
193        Ok(())
194    }
195
196    /// Get the oversampling and sampling rate for Follow Me mode.
197    ///
198    /// # Returns
199    /// Oversampling configuration including sampling rate.
200    ///
201    /// # Errors
202    /// Returns `NanonisError` if communication fails.
203    pub fn folme_oversampl_get(&mut self) -> Result<FolMeOversampling, NanonisError> {
204        let result = self.quick_send("FolMe.OversamplGet", vec![], vec![], vec!["i", "f"])?;
205
206        Ok(FolMeOversampling {
207            oversampling: result[0].as_i32()?,
208            sampling_rate: result[1].as_f32()?,
209        })
210    }
211
212    /// Stop the tip movement in Follow Me mode.
213    ///
214    /// # Errors
215    /// Returns `NanonisError` if communication fails.
216    pub fn folme_stop(&mut self) -> Result<(), NanonisError> {
217        self.quick_send("FolMe.Stop", vec![], vec![], vec![])?;
218        Ok(())
219    }
220
221    /// Get the Point & Shoot status in Follow Me mode.
222    ///
223    /// # Returns
224    /// True if Point & Shoot is enabled.
225    ///
226    /// # Errors
227    /// Returns `NanonisError` if communication fails.
228    pub fn folme_ps_on_off_get(&mut self) -> Result<bool, NanonisError> {
229        let result = self.quick_send("FolMe.PSOnOffGet", vec![], vec![], vec!["I"])?;
230
231        Ok(result[0].as_u32()? != 0)
232    }
233
234    /// Enable or disable Point & Shoot in Follow Me mode.
235    ///
236    /// # Arguments
237    /// * `enabled` - True to enable, false to disable
238    ///
239    /// # Errors
240    /// Returns `NanonisError` if communication fails.
241    pub fn folme_ps_on_off_set(&mut self, enabled: bool) -> Result<(), NanonisError> {
242        self.quick_send(
243            "FolMe.PSOnOffSet",
244            vec![NanonisValue::U32(if enabled { 1 } else { 0 })],
245            vec!["I"],
246            vec![],
247        )?;
248        Ok(())
249    }
250
251    /// Get the Point & Shoot experiment configuration.
252    ///
253    /// # Returns
254    /// Selected experiment and list of available experiments.
255    ///
256    /// # Errors
257    /// Returns `NanonisError` if communication fails.
258    pub fn folme_ps_exp_get(&mut self) -> Result<FolMePSExperiment, NanonisError> {
259        let result = self.quick_send(
260            "FolMe.PSExpGet",
261            vec![],
262            vec![],
263            vec!["H", "i", "i", "*+c"],
264        )?;
265
266        Ok(FolMePSExperiment {
267            selected: result[0].as_u16()?,
268            experiments: result[3].as_string_array()?.to_vec(),
269        })
270    }
271
272    /// Set the Point & Shoot experiment.
273    ///
274    /// # Arguments
275    /// * `experiment_index` - Index of the experiment to select
276    ///
277    /// # Errors
278    /// Returns `NanonisError` if communication fails.
279    pub fn folme_ps_exp_set(&mut self, experiment_index: u16) -> Result<(), NanonisError> {
280        self.quick_send(
281            "FolMe.PSExpSet",
282            vec![NanonisValue::U16(experiment_index)],
283            vec!["H"],
284            vec![],
285        )?;
286        Ok(())
287    }
288
289    /// Get the Point & Shoot properties.
290    ///
291    /// # Returns
292    /// Point & Shoot configuration.
293    ///
294    /// # Errors
295    /// Returns `NanonisError` if communication fails.
296    pub fn folme_ps_props_get(&mut self) -> Result<FolMePSProps, NanonisError> {
297        let result = self.quick_send(
298            "FolMe.PSPropsGet",
299            vec![],
300            vec![],
301            vec!["I", "I", "i", "*-c", "i", "*-c", "f"],
302        )?;
303
304        Ok(FolMePSProps {
305            auto_resume: result[0].as_u32()? != 0,
306            use_own_basename: result[1].as_u32()? != 0,
307            basename: result[3].as_string()?.to_string(),
308            external_vi_path: result[5].as_string()?.to_string(),
309            pre_measure_delay_s: result[6].as_f32()?,
310        })
311    }
312
313    /// Set the Point & Shoot properties.
314    ///
315    /// # Arguments
316    /// * `auto_resume` - Resume mode after experiment
317    /// * `basename_mode` - Basename selection mode
318    /// * `basename` - Basename for Point & Shoot files
319    /// * `external_vi_path` - Path to external VI
320    /// * `pre_measure_delay_s` - Delay before measurement in seconds
321    ///
322    /// # Errors
323    /// Returns `NanonisError` if communication fails.
324    pub fn folme_ps_props_set(
325        &mut self,
326        auto_resume: PSAutoResume,
327        basename_mode: PSBasenameMode,
328        basename: &str,
329        external_vi_path: &str,
330        pre_measure_delay_s: f32,
331    ) -> Result<(), NanonisError> {
332        self.quick_send(
333            "FolMe.PSPropsSet",
334            vec![
335                NanonisValue::U32(auto_resume.into()),
336                NanonisValue::U32(basename_mode.into()),
337                NanonisValue::String(basename.to_string()),
338                NanonisValue::String(external_vi_path.to_string()),
339                NanonisValue::F32(pre_measure_delay_s),
340            ],
341            vec!["I", "I", "+*c", "+*c", "f"],
342            vec![],
343        )?;
344        Ok(())
345    }
346}