nanonis_rs/client/util.rs
1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// Version information returned by the Nanonis software.
6///
7/// Contains detailed version and release information about both the
8/// host application and RT Engine components of the Nanonis system.
9#[derive(Debug, Clone, PartialEq)]
10pub struct VersionInfo {
11 /// Product line name (e.g., "Nanonis SPM Control Software" or "Nanonis Tramea Software")
12 pub product_line: String,
13 /// Software version string (e.g., "Generic 5")
14 pub version: String,
15 /// Host application release number
16 pub host_app_release: u32,
17 /// RT Engine application release number
18 pub rt_engine_release: u32,
19}
20
21impl NanonisClient {
22 /// Get the session path from the Nanonis software.
23 ///
24 /// Returns the current session path where Nanonis stores configuration
25 /// and data files for the active session.
26 ///
27 /// # Returns
28 /// The session path as a String.
29 ///
30 /// # Errors
31 /// Returns `NanonisError` if communication fails or protocol error occurs.
32 ///
33 /// # Examples
34 /// ```no_run
35 /// use nanonis_rs::NanonisClient;
36 ///
37 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
38 ///
39 /// let session_path = client.util_session_path_get()?;
40 /// println!("Session path: {}", session_path);
41 /// # Ok::<(), Box<dyn std::error::Error>>(())
42 /// ```
43 pub fn util_session_path_get(&mut self) -> Result<String, NanonisError> {
44 let result = self.quick_send("Util.SessionPathGet", vec![], vec![], vec!["i", "*-c"])?;
45
46 match result.get(1) {
47 Some(value) => Ok(value.as_string()?.to_string()),
48 None => Err(NanonisError::Protocol(
49 "No session path returned".to_string(),
50 )),
51 }
52 }
53
54 /// Load settings from a specified .ini file.
55 ///
56 /// Loads the Nanonis configuration settings from the specified file path.
57 /// Can also automatically load settings from the session file.
58 ///
59 /// # Arguments
60 /// * `settings_file_path` - Path to the settings file to load
61 /// * `load_session_settings` - If true, automatically loads from session file (bypasses path argument)
62 ///
63 /// # Errors
64 /// Returns `NanonisError` if the file doesn't exist, can't be read, or communication fails.
65 ///
66 /// # Examples
67 /// ```no_run
68 /// use nanonis_rs::NanonisClient;
69 ///
70 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
71 ///
72 /// // Load from specific file
73 /// client.util_settings_load("/path/to/settings.ini", false)?;
74 ///
75 /// // Or load from session file
76 /// client.util_settings_load("", true)?;
77 /// # Ok::<(), Box<dyn std::error::Error>>(())
78 /// ```
79 pub fn util_settings_load(
80 &mut self,
81 settings_file_path: &str,
82 load_session_settings: bool,
83 ) -> Result<(), NanonisError> {
84 self.quick_send(
85 "Util.SettingsLoad",
86 vec![
87 NanonisValue::String(settings_file_path.to_string()),
88 NanonisValue::U32(if load_session_settings { 1 } else { 0 }),
89 ],
90 vec!["+*c", "I"],
91 vec![],
92 )?;
93 Ok(())
94 }
95
96 /// Save current settings to a specified .ini file.
97 ///
98 /// Saves the current Nanonis configuration settings to the specified file path.
99 /// Can also automatically save to the session file.
100 ///
101 /// # Arguments
102 /// * `settings_file_path` - Path where the settings file will be saved
103 /// * `save_session_settings` - If true, automatically saves to session file (bypasses path argument)
104 ///
105 /// # Errors
106 /// Returns `NanonisError` if the file can't be written or communication fails.
107 ///
108 /// # Examples
109 /// ```no_run
110 /// use nanonis_rs::NanonisClient;
111 ///
112 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
113 ///
114 /// // Save to specific file
115 /// client.util_settings_save("/path/to/settings.ini", false)?;
116 ///
117 /// // Or save to session file
118 /// client.util_settings_save("", true)?;
119 /// # Ok::<(), Box<dyn std::error::Error>>(())
120 /// ```
121 pub fn util_settings_save(
122 &mut self,
123 settings_file_path: &str,
124 save_session_settings: bool,
125 ) -> Result<(), NanonisError> {
126 self.quick_send(
127 "Util.SettingsSave",
128 vec![
129 NanonisValue::String(settings_file_path.to_string()),
130 NanonisValue::U32(if save_session_settings { 1 } else { 0 }),
131 ],
132 vec!["+*c", "I"],
133 vec![],
134 )?;
135 Ok(())
136 }
137
138 /// Load a layout from a specified .ini file.
139 ///
140 /// Loads the Nanonis UI layout configuration from the specified file path.
141 /// Can also automatically load the layout from the session file.
142 ///
143 /// # Arguments
144 /// * `layout_file_path` - Path to the layout file to load
145 /// * `load_session_layout` - If true, automatically loads from session file (bypasses path argument)
146 ///
147 /// # Errors
148 /// Returns `NanonisError` if the file doesn't exist, can't be read, or communication fails.
149 ///
150 /// # Examples
151 /// ```no_run
152 /// use nanonis_rs::NanonisClient;
153 ///
154 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
155 ///
156 /// // Load from specific file
157 /// client.util_layout_load("/path/to/layout.ini", false)?;
158 ///
159 /// // Or load from session file
160 /// client.util_layout_load("", true)?;
161 /// # Ok::<(), Box<dyn std::error::Error>>(())
162 /// ```
163 pub fn util_layout_load(
164 &mut self,
165 layout_file_path: &str,
166 load_session_layout: bool,
167 ) -> Result<(), NanonisError> {
168 self.quick_send(
169 "Util.LayoutLoad",
170 vec![
171 NanonisValue::String(layout_file_path.to_string()),
172 NanonisValue::U32(if load_session_layout { 1 } else { 0 }),
173 ],
174 vec!["+*c", "I"],
175 vec![],
176 )?;
177 Ok(())
178 }
179
180 /// Save current layout to a specified .ini file.
181 ///
182 /// Saves the current Nanonis UI layout configuration to the specified file path.
183 /// Can also automatically save to the session file.
184 ///
185 /// # Arguments
186 /// * `layout_file_path` - Path where the layout file will be saved
187 /// * `save_session_layout` - If true, automatically saves to session file (bypasses path argument)
188 ///
189 /// # Errors
190 /// Returns `NanonisError` if the file can't be written or communication fails.
191 ///
192 /// # Examples
193 /// ```no_run
194 /// use nanonis_rs::NanonisClient;
195 ///
196 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
197 ///
198 /// // Save to specific file
199 /// client.util_layout_save("/path/to/layout.ini", false)?;
200 ///
201 /// // Or save to session file
202 /// client.util_layout_save("", true)?;
203 /// # Ok::<(), Box<dyn std::error::Error>>(())
204 /// ```
205 pub fn util_layout_save(
206 &mut self,
207 layout_file_path: &str,
208 save_session_layout: bool,
209 ) -> Result<(), NanonisError> {
210 self.quick_send(
211 "Util.LayoutSave",
212 vec![
213 NanonisValue::String(layout_file_path.to_string()),
214 NanonisValue::U32(if save_session_layout { 1 } else { 0 }),
215 ],
216 vec!["+*c", "I"],
217 vec![],
218 )?;
219 Ok(())
220 }
221
222 /// Lock the Nanonis software interface.
223 ///
224 /// Launches a lock modal window that prevents user interaction with the
225 /// Nanonis software until it is unlocked manually or through `util_unlock()`.
226 /// This is useful for automated experiments where you want to prevent
227 /// accidental user interference.
228 ///
229 /// # Errors
230 /// Returns `NanonisError` if communication fails or protocol error occurs.
231 ///
232 /// # Examples
233 /// ```no_run
234 /// use nanonis_rs::NanonisClient;
235 /// use std::thread;
236 /// use std::time::Duration;
237 ///
238 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
239 ///
240 /// // Lock the interface during automated experiment
241 /// client.util_lock()?;
242 ///
243 /// // Perform automated operations
244 /// thread::sleep(Duration::from_secs(5));
245 ///
246 /// // Unlock when done
247 /// client.util_unlock()?;
248 /// # Ok::<(), Box<dyn std::error::Error>>(())
249 /// ```
250 pub fn util_lock(&mut self) -> Result<(), NanonisError> {
251 self.quick_send("Util.Lock", vec![], vec![], vec![])?;
252 Ok(())
253 }
254
255 /// Unlock the Nanonis software interface.
256 ///
257 /// Closes the lock modal window that prevents user interaction with the
258 /// Nanonis software. Use this after `util_lock()` when automated operations
259 /// are complete.
260 ///
261 /// # Errors
262 /// Returns `NanonisError` if communication fails or protocol error occurs.
263 ///
264 /// # Examples
265 /// ```no_run
266 /// use nanonis_rs::NanonisClient;
267 ///
268 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
269 ///
270 /// // Unlock the interface
271 /// client.util_unlock()?;
272 /// # Ok::<(), Box<dyn std::error::Error>>(())
273 /// ```
274 pub fn util_unlock(&mut self) -> Result<(), NanonisError> {
275 self.quick_send("Util.UnLock", vec![], vec![], vec![])?;
276 Ok(())
277 }
278
279 /// Set the Real Time controller frequency.
280 ///
281 /// Configures the frequency of the Real Time (RT) controller which determines
282 /// the speed at which the feedback loop and other real-time operations run.
283 ///
284 /// # Arguments
285 /// * `rt_frequency` - RT frequency in Hz
286 ///
287 /// # Errors
288 /// Returns `NanonisError` if invalid frequency provided or communication fails.
289 ///
290 /// # Examples
291 /// ```no_run
292 /// use nanonis_rs::NanonisClient;
293 ///
294 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
295 ///
296 /// // Set RT frequency to 20 kHz
297 /// client.util_rt_freq_set(20000.0)?;
298 /// # Ok::<(), Box<dyn std::error::Error>>(())
299 /// ```
300 pub fn util_rt_freq_set(&mut self, rt_frequency: f32) -> Result<(), NanonisError> {
301 self.quick_send(
302 "Util.RTFreqSet",
303 vec![NanonisValue::F32(rt_frequency)],
304 vec!["f"],
305 vec![],
306 )?;
307 Ok(())
308 }
309
310 /// Get the Real Time controller frequency.
311 ///
312 /// Returns the current frequency of the Real Time (RT) controller.
313 ///
314 /// # Returns
315 /// RT frequency in Hz.
316 ///
317 /// # Errors
318 /// Returns `NanonisError` if communication fails or protocol error occurs.
319 ///
320 /// # Examples
321 /// ```no_run
322 /// use nanonis_rs::NanonisClient;
323 ///
324 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
325 ///
326 /// let frequency = client.util_rt_freq_get()?;
327 /// println!("RT frequency: {} Hz", frequency);
328 /// # Ok::<(), Box<dyn std::error::Error>>(())
329 /// ```
330 pub fn util_rt_freq_get(&mut self) -> Result<f32, NanonisError> {
331 let result = self.quick_send("Util.RTFreqGet", vec![], vec![], vec!["f"])?;
332
333 match result.first() {
334 Some(value) => Ok(value.as_f32()?),
335 None => Err(NanonisError::Protocol(
336 "No RT frequency returned".to_string(),
337 )),
338 }
339 }
340
341 /// Set the Acquisition Period in the TCP Receiver.
342 ///
343 /// Configures the period at which data is acquired and transmitted
344 /// via the TCP interface.
345 ///
346 /// # Arguments
347 /// * `acquisition_period` - Acquisition period in seconds
348 ///
349 /// # Errors
350 /// Returns `NanonisError` if invalid period provided or communication fails.
351 ///
352 /// # Examples
353 /// ```no_run
354 /// use nanonis_rs::NanonisClient;
355 ///
356 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
357 ///
358 /// // Set acquisition period to 100 ms
359 /// client.util_acq_period_set(0.1)?;
360 /// # Ok::<(), Box<dyn std::error::Error>>(())
361 /// ```
362 pub fn util_acq_period_set(&mut self, acquisition_period: f32) -> Result<(), NanonisError> {
363 self.quick_send(
364 "Util.AcqPeriodSet",
365 vec![NanonisValue::F32(acquisition_period)],
366 vec!["f"],
367 vec![],
368 )?;
369 Ok(())
370 }
371
372 /// Get the Acquisition Period from the TCP Receiver.
373 ///
374 /// Returns the current acquisition period configured in the TCP Receiver.
375 ///
376 /// # Returns
377 /// Acquisition period in seconds.
378 ///
379 /// # Errors
380 /// Returns `NanonisError` if communication fails or protocol error occurs.
381 ///
382 /// # Examples
383 /// ```no_run
384 /// use nanonis_rs::NanonisClient;
385 ///
386 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
387 ///
388 /// let period = client.util_acq_period_get()?;
389 /// println!("Acquisition period: {} s ({} ms)", period, period * 1000.0);
390 /// # Ok::<(), Box<dyn std::error::Error>>(())
391 /// ```
392 pub fn util_acq_period_get(&mut self) -> Result<f32, NanonisError> {
393 let result = self.quick_send("Util.AcqPeriodGet", vec![], vec![], vec!["f"])?;
394
395 match result.first() {
396 Some(value) => Ok(value.as_f32()?),
397 None => Err(NanonisError::Protocol(
398 "No acquisition period returned".to_string(),
399 )),
400 }
401 }
402
403 /// Set the Real-time oversampling in the TCP Receiver.
404 ///
405 /// Configures the oversampling factor for the 24 signals on the RT engine
406 /// before they are sent to the host. The oversampling affects the maximum
407 /// Spectrum Analyzer frequency and other displays.
408 ///
409 /// # Arguments
410 /// * `rt_oversampling` - RT oversampling factor
411 ///
412 /// # Errors
413 /// Returns `NanonisError` if invalid oversampling value or communication fails.
414 ///
415 /// # Examples
416 /// ```no_run
417 /// use nanonis_rs::NanonisClient;
418 ///
419 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
420 ///
421 /// // Set oversampling to 10x
422 /// client.util_rt_oversampl_set(10)?;
423 /// # Ok::<(), Box<dyn std::error::Error>>(())
424 /// ```
425 pub fn util_rt_oversampl_set(&mut self, rt_oversampling: i32) -> Result<(), NanonisError> {
426 self.quick_send(
427 "Util.RTOversamplSet",
428 vec![NanonisValue::I32(rt_oversampling)],
429 vec!["i"],
430 vec![],
431 )?;
432 Ok(())
433 }
434
435 /// Get the Real-time oversampling from the TCP Receiver.
436 ///
437 /// Returns the current oversampling factor configured for RT engine signals.
438 ///
439 /// # Returns
440 /// RT oversampling factor.
441 ///
442 /// # Errors
443 /// Returns `NanonisError` if communication fails or protocol error occurs.
444 ///
445 /// # Examples
446 /// ```no_run
447 /// use nanonis_rs::NanonisClient;
448 ///
449 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
450 ///
451 /// let oversampling = client.util_rt_oversampl_get()?;
452 /// println!("RT oversampling: {}x", oversampling);
453 /// # Ok::<(), Box<dyn std::error::Error>>(())
454 /// ```
455 pub fn util_rt_oversampl_get(&mut self) -> Result<i32, NanonisError> {
456 let result = self.quick_send("Util.RTOversamplGet", vec![], vec![], vec!["i"])?;
457
458 match result.first() {
459 Some(value) => Ok(value.as_i32()?),
460 None => Err(NanonisError::Protocol(
461 "No RT oversampling returned".to_string(),
462 )),
463 }
464 }
465
466 /// Quit the Nanonis software with options to save settings, layout, and signals.
467 ///
468 /// Provides the same functionality as the dialog that appears when quitting
469 /// through the File menu. Can save settings, layout, and signal configurations
470 /// before exiting.
471 ///
472 /// **Warning**: This will close the Nanonis software and terminate the TCP connection.
473 ///
474 /// # Arguments
475 /// * `use_stored_values` - If true, uses stored quit preferences (ignores other arguments)
476 /// * `settings_name` - Name of settings file to save (empty string = don't save)
477 /// * `layout_name` - Name of layout file to save (empty string = don't save)
478 /// * `save_signals` - If true, saves signal configuration
479 ///
480 /// # Errors
481 /// Returns `NanonisError` if communication fails before quit completes.
482 ///
483 /// # Examples
484 /// ```no_run
485 /// use nanonis_rs::NanonisClient;
486 ///
487 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
488 ///
489 /// // Quit without saving anything
490 /// client.util_quit(false, "", "", false)?;
491 ///
492 /// // Quit and save everything with stored preferences
493 /// // client.util_quit(true, "", "", false)?;
494 ///
495 /// // Quit and save specific settings and layout
496 /// // client.util_quit(false, "my_settings", "my_layout", true)?;
497 /// # Ok::<(), Box<dyn std::error::Error>>(())
498 /// ```
499 pub fn util_quit(
500 &mut self,
501 use_stored_values: bool,
502 settings_name: &str,
503 layout_name: &str,
504 save_signals: bool,
505 ) -> Result<(), NanonisError> {
506 self.quick_send(
507 "Util.Quit",
508 vec![
509 NanonisValue::U32(if use_stored_values { 1 } else { 0 }),
510 NanonisValue::String(settings_name.to_string()),
511 NanonisValue::String(layout_name.to_string()),
512 NanonisValue::U32(if save_signals { 1 } else { 0 }),
513 ],
514 vec!["I", "+*c", "+*c", "I"],
515 vec![],
516 )?;
517 Ok(())
518 }
519
520 /// Get version information from the Nanonis software.
521 ///
522 /// Returns detailed version information about the Nanonis system including
523 /// product line, version string, and release numbers for both host application
524 /// and RT Engine.
525 ///
526 /// # Returns
527 /// A `VersionInfo` struct containing all version details.
528 ///
529 /// # Errors
530 /// Returns `NanonisError` if communication fails or protocol error occurs.
531 ///
532 /// # Examples
533 /// ```no_run
534 /// use nanonis_rs::NanonisClient;
535 ///
536 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
537 ///
538 /// let version = client.util_version_get()?;
539 /// println!("Product: {}", version.product_line);
540 /// println!("Version: {}", version.version);
541 /// println!("Host release: {}", version.host_app_release);
542 /// println!("RT Engine release: {}", version.rt_engine_release);
543 /// # Ok::<(), Box<dyn std::error::Error>>(())
544 /// ```
545 pub fn util_version_get(&mut self) -> Result<VersionInfo, NanonisError> {
546 let result = self.quick_send(
547 "Util.VersionGet",
548 vec![],
549 vec![],
550 vec!["+*c", "+*c", "I", "I"],
551 )?;
552
553 if result.len() >= 4 {
554 Ok(VersionInfo {
555 product_line: result[0].as_string()?.to_string(),
556 version: result[1].as_string()?.to_string(),
557 host_app_release: result[2].as_u32()?,
558 rt_engine_release: result[3].as_u32()?,
559 })
560 } else {
561 Err(NanonisError::Protocol(
562 "Invalid version info response".to_string(),
563 ))
564 }
565 }
566}