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(
150        &mut self,
151        speed_m_s: f32,
152        custom_speed: bool,
153    ) -> Result<(), NanonisError> {
154        let custom_speed_flag = if custom_speed { 1u32 } else { 0u32 };
155        self.quick_send(
156            "FolMe.SpeedSet",
157            vec![
158                NanonisValue::F32(speed_m_s),
159                NanonisValue::U32(custom_speed_flag),
160            ],
161            vec!["f", "I"],
162            vec![],
163        )?;
164        Ok(())
165    }
166
167    /// Get the tip speed configuration for Follow Me mode.
168    ///
169    /// # Returns
170    /// Speed configuration.
171    ///
172    /// # Errors
173    /// Returns `NanonisError` if communication fails.
174    pub fn folme_speed_get(&mut self) -> Result<FolMeSpeed, NanonisError> {
175        let result = self.quick_send("FolMe.SpeedGet", vec![], vec![], vec!["f", "I"])?;
176
177        Ok(FolMeSpeed {
178            speed_m_s: result[0].as_f32()?,
179            custom_speed: result[1].as_u32()? != 0,
180        })
181    }
182
183    /// Set the oversampling for data acquisition in Follow Me mode.
184    ///
185    /// # Arguments
186    /// * `oversampling` - Oversampling factor
187    ///
188    /// # Errors
189    /// Returns `NanonisError` if communication fails.
190    pub fn folme_oversampl_set(&mut self, oversampling: i32) -> Result<(), NanonisError> {
191        self.quick_send(
192            "FolMe.OversamplSet",
193            vec![NanonisValue::I32(oversampling)],
194            vec!["i"],
195            vec![],
196        )?;
197        Ok(())
198    }
199
200    /// Get the oversampling and sampling rate for Follow Me mode.
201    ///
202    /// # Returns
203    /// Oversampling configuration including sampling rate.
204    ///
205    /// # Errors
206    /// Returns `NanonisError` if communication fails.
207    pub fn folme_oversampl_get(&mut self) -> Result<FolMeOversampling, NanonisError> {
208        let result = self.quick_send("FolMe.OversamplGet", vec![], vec![], vec!["i", "f"])?;
209
210        Ok(FolMeOversampling {
211            oversampling: result[0].as_i32()?,
212            sampling_rate: result[1].as_f32()?,
213        })
214    }
215
216    /// Stop the tip movement in Follow Me mode.
217    ///
218    /// # Errors
219    /// Returns `NanonisError` if communication fails.
220    pub fn folme_stop(&mut self) -> Result<(), NanonisError> {
221        self.quick_send("FolMe.Stop", vec![], vec![], vec![])?;
222        Ok(())
223    }
224
225    /// Get the Point & Shoot status in Follow Me mode.
226    ///
227    /// # Returns
228    /// True if Point & Shoot is enabled.
229    ///
230    /// # Errors
231    /// Returns `NanonisError` if communication fails.
232    pub fn folme_ps_on_off_get(&mut self) -> Result<bool, NanonisError> {
233        let result = self.quick_send("FolMe.PSOnOffGet", vec![], vec![], vec!["I"])?;
234
235        Ok(result[0].as_u32()? != 0)
236    }
237
238    /// Enable or disable Point & Shoot in Follow Me mode.
239    ///
240    /// # Arguments
241    /// * `enabled` - True to enable, false to disable
242    ///
243    /// # Errors
244    /// Returns `NanonisError` if communication fails.
245    pub fn folme_ps_on_off_set(&mut self, enabled: bool) -> Result<(), NanonisError> {
246        self.quick_send(
247            "FolMe.PSOnOffSet",
248            vec![NanonisValue::U32(if enabled { 1 } else { 0 })],
249            vec!["I"],
250            vec![],
251        )?;
252        Ok(())
253    }
254
255    /// Get the Point & Shoot experiment configuration.
256    ///
257    /// # Returns
258    /// Selected experiment and list of available experiments.
259    ///
260    /// # Errors
261    /// Returns `NanonisError` if communication fails.
262    pub fn folme_ps_exp_get(&mut self) -> Result<FolMePSExperiment, NanonisError> {
263        let result =
264            self.quick_send("FolMe.PSExpGet", vec![], vec![], vec!["H", "i", "i", "*+c"])?;
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}