nanonis_rs/client/scan/mod.rs
1mod types;
2pub use types::*;
3
4use super::NanonisClient;
5use crate::error::NanonisError;
6use crate::types::{NanonisValue, Position};
7use std::time::Duration;
8
9impl NanonisClient {
10 /// Start, stop, pause or resume a scan
11 pub fn scan_action(
12 &mut self,
13 scan_action: ScanAction,
14 scan_direction: ScanDirection,
15 ) -> Result<(), NanonisError> {
16 self.quick_send(
17 "Scan.Action",
18 vec![
19 NanonisValue::U16(scan_action.into()),
20 NanonisValue::U32(scan_direction.into()),
21 ],
22 vec!["H", "I"],
23 vec![],
24 )?;
25 Ok(())
26 }
27
28 /// Configure the scan frame parameters
29 pub fn scan_frame_set(&mut self, frame: ScanFrame) -> Result<(), NanonisError> {
30 self.quick_send(
31 "Scan.FrameSet",
32 vec![
33 NanonisValue::F32(frame.center.x as f32),
34 NanonisValue::F32(frame.center.y as f32),
35 NanonisValue::F32(frame.width_m),
36 NanonisValue::F32(frame.height_m),
37 NanonisValue::F32(frame.angle_deg),
38 ],
39 vec!["f", "f", "f", "f", "f"],
40 vec![],
41 )?;
42 Ok(())
43 }
44
45 /// Get the scan frame parameters
46 pub fn scan_frame_get(&mut self) -> Result<ScanFrame, NanonisError> {
47 let result = self.quick_send(
48 "Scan.FrameGet",
49 vec![],
50 vec![],
51 vec!["f", "f", "f", "f", "f"],
52 )?;
53 if result.len() >= 5 {
54 let center_x = result[0].as_f32()? as f64;
55 let center_y = result[1].as_f32()? as f64;
56 let width = result[2].as_f32()?;
57 let height = result[3].as_f32()?;
58 let angle = result[4].as_f32()?;
59
60 Ok(ScanFrame::new(
61 Position::new(center_x, center_y),
62 width,
63 height,
64 angle,
65 ))
66 } else {
67 Err(NanonisError::Protocol(
68 "Invalid scan frame response".to_string(),
69 ))
70 }
71 }
72
73 /// Get the scan buffer parameters
74 /// Returns: (channel_indexes, pixels, lines)
75 pub fn scan_buffer_get(&mut self) -> Result<(Vec<i32>, i32, i32), NanonisError> {
76 let result =
77 self.quick_send("Scan.BufferGet", vec![], vec![], vec!["i", "*i", "i", "i"])?;
78 if result.len() >= 4 {
79 let channel_indexes = result[1].as_i32_array()?.to_vec();
80 let pixels = result[2].as_i32()?;
81 let lines = result[3].as_i32()?;
82 Ok((channel_indexes, pixels, lines))
83 } else {
84 Err(NanonisError::Protocol(
85 "Invalid scan buffer response".to_string(),
86 ))
87 }
88 }
89
90 /// Get the current scan status.
91 ///
92 /// Returns whether a scan is currently running or not.
93 ///
94 /// # Returns
95 /// `true` if scan is running, `false` if scan is not running.
96 ///
97 /// # Errors
98 /// Returns `NanonisError` if communication fails or protocol error occurs.
99 ///
100 /// # Examples
101 /// ```no_run
102 /// use nanonis_rs::NanonisClient;
103 ///
104 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
105 ///
106 /// if client.scan_status_get()? {
107 /// println!("Scan is currently running");
108 /// } else {
109 /// println!("Scan is stopped");
110 /// }
111 /// # Ok::<(), Box<dyn std::error::Error>>(())
112 /// ```
113 pub fn scan_status_get(&mut self) -> Result<bool, NanonisError> {
114 let result = self.quick_send("Scan.StatusGet", vec![], vec![], vec!["I"])?;
115
116 match result.first() {
117 Some(value) => Ok(value.as_u32()? == 1),
118 None => Err(NanonisError::Protocol(
119 "No scan status returned".to_string(),
120 )),
121 }
122 }
123
124 /// Configure the scan buffer parameters.
125 ///
126 /// Sets which channels to record during scanning and the scan resolution.
127 /// The channel indexes refer to the 24 signals assigned in the Signals Manager (0-23).
128 ///
129 /// **Important**: The number of pixels is coerced to the closest multiple of 16
130 /// because scan data is sent in packages of 16 pixels.
131 ///
132 /// # Arguments
133 /// * `channel_indexes` - Indexes of channels to record (0-23 for signals in Signals Manager)
134 /// * `pixels` - Number of pixels per line (coerced to multiple of 16)
135 /// * `lines` - Number of scan lines
136 ///
137 /// # Errors
138 /// Returns `NanonisError` if communication fails or invalid parameters provided.
139 ///
140 /// # Examples
141 /// ```no_run
142 /// use nanonis_rs::NanonisClient;
143 ///
144 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
145 ///
146 /// // Record channels 0, 1, and 2 with 512x512 resolution
147 /// client.scan_buffer_set(vec![0, 1, 2], 512, 512)?;
148 ///
149 /// // High resolution scan with multiple channels
150 /// client.scan_buffer_set(vec![0, 1, 2, 3, 4], 1024, 1024)?;
151 /// # Ok::<(), Box<dyn std::error::Error>>(())
152 /// ```
153 pub fn scan_buffer_set(
154 &mut self,
155 channel_indexes: Vec<i32>,
156 pixels: i32,
157 lines: i32,
158 ) -> Result<(), NanonisError> {
159 self.quick_send(
160 "Scan.BufferSet",
161 vec![
162 NanonisValue::ArrayI32(channel_indexes),
163 NanonisValue::I32(pixels),
164 NanonisValue::I32(lines),
165 ],
166 vec!["+*i", "i", "i"],
167 vec![],
168 )?;
169 Ok(())
170 }
171
172 /// Configure scan speed parameters.
173 ///
174 /// Sets the tip scanning speeds for both forward and backward scan directions.
175 /// You can specify either linear speed or time per line, and set speed ratios
176 /// between forward and backward scanning.
177 ///
178 /// # Arguments
179 /// * `forward_linear_speed_m_s` - Forward linear speed in m/s
180 /// * `backward_linear_speed_m_s` - Backward linear speed in m/s
181 /// * `forward_time_per_line_s` - Forward time per line in seconds
182 /// * `backward_time_per_line_s` - Backward time per line in seconds
183 /// * `keep_parameter_constant` - Which parameter to keep constant: 0=no change, 1=linear speed, 2=time per line
184 /// * `speed_ratio` - Backward tip speed relative to forward speed
185 ///
186 /// # Errors
187 /// Returns `NanonisError` if communication fails or invalid parameters provided.
188 ///
189 /// # Examples
190 /// ```no_run
191 /// use nanonis_rs::NanonisClient;
192 /// use nanonis_rs::scan::ScanConfig;
193 ///
194 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
195 ///
196 /// // Set 1 μm/s forward, 2 μm/s backward, keep linear speed constant
197 /// let config = ScanConfig {
198 /// forward_linear_speed_m_s: 1e-6,
199 /// backward_linear_speed_m_s: 2e-6,
200 /// forward_time_per_line_s: 0.1,
201 /// backward_time_per_line_s: 0.05,
202 /// keep_parameter_constant: 1,
203 /// speed_ratio: 2.0,
204 /// };
205 /// client.scan_config_set(config)?;
206 /// # Ok::<(), Box<dyn std::error::Error>>(())
207 /// ```
208 pub fn scan_config_set(&mut self, config: ScanConfig) -> Result<(), NanonisError> {
209 self.quick_send(
210 "Scan.SpeedSet",
211 vec![
212 NanonisValue::F32(config.forward_linear_speed_m_s),
213 NanonisValue::F32(config.backward_linear_speed_m_s),
214 NanonisValue::F32(config.forward_time_per_line_s),
215 NanonisValue::F32(config.backward_time_per_line_s),
216 NanonisValue::U16(config.keep_parameter_constant),
217 NanonisValue::F32(config.speed_ratio),
218 ],
219 vec!["f", "f", "f", "f", "H", "f"],
220 vec![],
221 )?;
222 Ok(())
223 }
224
225 /// Get the current scan speed parameters.
226 ///
227 /// Returns all scan speed configuration values including linear speeds,
228 /// time per line, and speed ratio settings.
229 ///
230 /// # Returns
231 /// A tuple containing:
232 /// - `f32` - Forward linear speed (m/s)
233 /// - `f32` - Backward linear speed (m/s)
234 /// - `f32` - Forward time per line (s)
235 /// - `f32` - Backward time per line (s)
236 /// - `u16` - Keep parameter constant (0=linear speed, 1=time per line)
237 /// - `f32` - Speed ratio (backward relative to forward)
238 ///
239 /// # Errors
240 /// Returns `NanonisError` if communication fails or protocol error occurs.
241 ///
242 /// # Examples
243 /// ```no_run
244 /// use nanonis_rs::NanonisClient;
245 ///
246 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
247 ///
248 /// let config = client.scan_speed_get()?;
249 ///
250 /// println!("Forward speed: {:.2e} m/s", config.forward_linear_speed_m_s);
251 /// println!("Backward speed: {:.2e} m/s", config.backward_linear_speed_m_s);
252 /// println!("Speed ratio: {:.1}", config.speed_ratio);
253 /// # Ok::<(), Box<dyn std::error::Error>>(())
254 /// ```
255 pub fn scan_speed_get(&mut self) -> Result<ScanConfig, NanonisError> {
256 let result = self.quick_send(
257 "Scan.SpeedGet",
258 vec![],
259 vec![],
260 vec!["f", "f", "f", "f", "H", "f"],
261 )?;
262
263 if result.len() >= 6 {
264 Ok(ScanConfig {
265 forward_linear_speed_m_s: result[0].as_f32()?,
266 backward_linear_speed_m_s: result[1].as_f32()?,
267 forward_time_per_line_s: result[2].as_f32()?,
268 backward_time_per_line_s: result[3].as_f32()?,
269 keep_parameter_constant: result[4].as_u16()?,
270 speed_ratio: result[5].as_f32()?,
271 })
272 } else {
273 Err(NanonisError::Protocol(
274 "Invalid scan speed response".to_string(),
275 ))
276 }
277 }
278
279 /// Get the current XY position during scanning.
280 ///
281 /// Returns the current values of the X and Y signals, useful for monitoring
282 /// tip position during scanning operations.
283 ///
284 /// # Arguments
285 /// * `wait_newest_data` - If `true`, discards first value and waits for fresh data
286 ///
287 /// # Returns
288 /// A tuple containing (X position in m, Y position in m)
289 ///
290 /// # Errors
291 /// Returns `NanonisError` if communication fails or protocol error occurs.
292 ///
293 /// # Examples
294 /// ```no_run
295 /// use nanonis_rs::NanonisClient;
296 ///
297 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
298 ///
299 /// // Get current position immediately
300 /// let (x, y) = client.scan_xy_pos_get(false)?;
301 /// println!("Current position: ({:.6}, {:.6}) m", x, y);
302 ///
303 /// // Wait for fresh position data
304 /// let (x, y) = client.scan_xy_pos_get(true)?;
305 /// # Ok::<(), Box<dyn std::error::Error>>(())
306 /// ```
307 pub fn scan_xy_pos_get(&mut self, wait_newest_data: bool) -> Result<(f32, f32), NanonisError> {
308 let wait_flag = if wait_newest_data { 1u32 } else { 0u32 };
309
310 let result = self.quick_send(
311 "Scan.XYPosGet",
312 vec![NanonisValue::U32(wait_flag)],
313 vec!["I"],
314 vec!["f", "f"],
315 )?;
316
317 if result.len() >= 2 {
318 Ok((result[0].as_f32()?, result[1].as_f32()?))
319 } else {
320 Err(NanonisError::Protocol(
321 "Invalid XY position response".to_string(),
322 ))
323 }
324 }
325
326 /// Save the current scan data buffer to file.
327 ///
328 /// Saves the current scan data into a file. If `wait_until_saved` is true,
329 /// the function waits for the save operation to complete before returning.
330 ///
331 /// # Arguments
332 /// * `wait_until_saved` - If `true`, waits for save completion before returning
333 /// * `timeout_ms` - Timeout in milliseconds (-1 for indefinite wait)
334 ///
335 /// # Returns
336 /// `true` if timeout occurred while waiting for save completion, `false` otherwise
337 ///
338 /// # Errors
339 /// Returns `NanonisError` if communication fails or protocol error occurs.
340 ///
341 /// # Examples
342 /// ```no_run
343 /// use nanonis_rs::NanonisClient;
344 ///
345 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
346 ///
347 /// // Save immediately without waiting
348 /// let timed_out = client.scan_save(false, 5000)?;
349 ///
350 /// // Save and wait up to 30 seconds for completion
351 /// let timed_out = client.scan_save(true, 30000)?;
352 /// if timed_out {
353 /// println!("Save operation timed out");
354 /// }
355 /// # Ok::<(), Box<dyn std::error::Error>>(())
356 /// ```
357 pub fn scan_save(
358 &mut self,
359 wait_until_saved: bool,
360 timeout_ms: i32,
361 ) -> Result<bool, NanonisError> {
362 let wait_flag = if wait_until_saved { 1u32 } else { 0u32 };
363
364 let result = self.quick_send(
365 "Scan.Save",
366 vec![NanonisValue::U32(wait_flag), NanonisValue::I32(timeout_ms)],
367 vec!["I", "i"],
368 vec!["I"],
369 )?;
370
371 match result.first() {
372 Some(value) => Ok(value.as_u32()? == 1),
373 None => Err(NanonisError::Protocol(
374 "No save status returned".to_string(),
375 )),
376 }
377 }
378
379 /// Get scan frame data for a specific channel and direction.
380 ///
381 /// Returns the complete 2D scan data array for the selected channel.
382 /// The channel must be one of the channels configured in the scan buffer.
383 ///
384 /// # Arguments
385 /// * `channel_index` - Index of channel to retrieve data from (must be in acquired channels)
386 /// * `data_direction` - Data direction: `true` for forward, `false` for backward
387 ///
388 /// # Returns
389 /// A tuple containing:
390 /// - `String` - Channel name
391 /// - `Vec<Vec<f32>>` - 2D scan data array \[rows\]\[columns\]
392 /// - `bool` - Scan direction: `true` for up, `false` for down
393 ///
394 /// # Errors
395 /// Returns `NanonisError` if:
396 /// - Invalid channel index (not in acquired channels)
397 /// - Communication fails or protocol error occurs
398 ///
399 /// # Examples
400 /// ```no_run
401 /// use nanonis_rs::NanonisClient;
402 ///
403 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
404 ///
405 /// // Get forward scan data for channel 0
406 /// let (channel_name, data, scan_up) = client.scan_frame_data_grab(0, true)?;
407 /// println!("Channel: {}, Direction: {}", channel_name, if scan_up { "up" } else { "down" });
408 /// println!("Data size: {}x{}", data.len(), data[0].len());
409 ///
410 /// // Get backward scan data
411 /// let (_, back_data, _) = client.scan_frame_data_grab(0, false)?;
412 /// # Ok::<(), Box<dyn std::error::Error>>(())
413 /// ```
414 pub fn scan_frame_data_grab(
415 &mut self,
416 channel_index: u32,
417 data_direction: bool,
418 ) -> Result<(String, Vec<Vec<f32>>, bool), NanonisError> {
419 let direction_flag = if data_direction { 1u32 } else { 0u32 };
420
421 let result = self.quick_send(
422 "Scan.FrameDataGrab",
423 vec![
424 NanonisValue::U32(channel_index),
425 NanonisValue::U32(direction_flag),
426 ],
427 vec!["I", "I"],
428 vec!["i", "*-c", "i", "i", "2f", "I"],
429 )?;
430
431 if result.len() >= 6 {
432 let channel_name = result[1].as_string()?.to_string();
433
434 // The protocol layer already parses "2f" into a 2D array
435 let data_2d = result[4].as_f32_2d_array()?.clone();
436
437 let scan_direction = result[5].as_u32()? == 1;
438 Ok((channel_name, data_2d, scan_direction))
439 } else {
440 Err(NanonisError::Protocol(
441 "Invalid frame data response".to_string(),
442 ))
443 }
444 }
445
446 /// Wait for the End-of-Scan.
447 ///
448 /// Waits for the current scan to complete or timeout to occur, whichever comes first.
449 /// This is useful for synchronizing operations with scan completion.
450 ///
451 /// # Arguments
452 /// * `timeout` - Timeout duration (-1 for indefinite wait)
453 ///
454 /// # Returns
455 /// A tuple containing:
456 /// - `bool` - `true` if timeout occurred, `false` if scan completed normally
457 /// - `String` - File path where data was auto-saved (empty if no auto-save)
458 ///
459 /// # Errors
460 /// Returns `NanonisError` if communication fails or protocol error occurs.
461 ///
462 /// # Examples
463 /// ```no_run
464 /// use nanonis_rs::NanonisClient;
465 /// use nanonis_rs::scan::{ScanAction, ScanDirection};
466 /// use std::time::Duration;
467 ///
468 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
469 ///
470 /// // Start a scan
471 /// client.scan_action(ScanAction::Start, ScanDirection::Up)?;
472 ///
473 /// // Wait for scan to complete (up to 5 minutes)
474 /// let (timed_out, file_path) = client.scan_wait_end_of_scan(Duration::from_secs(300))?;
475 ///
476 /// if timed_out {
477 /// println!("Scan timed out after 5 minutes");
478 /// } else {
479 /// println!("Scan completed");
480 /// if !file_path.is_empty() {
481 /// println!("Data saved to: {}", file_path);
482 /// }
483 /// }
484 /// # Ok::<(), Box<dyn std::error::Error>>(())
485 /// ```
486 pub fn scan_wait_end_of_scan(
487 &mut self,
488 timeout: Duration,
489 ) -> Result<(bool, String), NanonisError> {
490 let result = self.quick_send(
491 "Scan.WaitEndOfScan",
492 vec![NanonisValue::I32(timeout.as_millis() as i32)],
493 vec!["i"],
494 vec!["I", "I", "*-c"],
495 )?;
496
497 if result.len() >= 3 {
498 let timeout_occurred = result[0].as_u32()? == 1;
499 let file_path = result[2].as_string()?.to_string();
500 Ok((timeout_occurred, file_path))
501 } else {
502 Err(NanonisError::Protocol(
503 "Invalid scan wait response".to_string(),
504 ))
505 }
506 }
507
508 /// Get scan properties configuration.
509 ///
510 /// Returns current scan properties including continuous scan, bouncy scan,
511 /// autosave, series name, comment, modules names, and autopaste settings.
512 ///
513 /// # Returns
514 /// `ScanProps` structure containing all scan property settings
515 ///
516 /// # Errors
517 /// Returns `NanonisError` if communication fails or protocol error occurs.
518 ///
519 /// # Examples
520 /// ```no_run
521 /// use nanonis_rs::NanonisClient;
522 ///
523 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
524 ///
525 /// let props = client.scan_props_get()?;
526 /// println!("Continuous scan: {:?}", props.continuous_scan);
527 /// println!("Bouncy scan: {:?}", props.bouncy_scan);
528 /// println!("Series name: {}", props.series_name);
529 /// # Ok::<(), Box<dyn std::error::Error>>(())
530 /// ```
531 pub fn scan_props_get(&mut self) -> Result<ScanProps, NanonisError> {
532 let result = self.quick_send(
533 "Scan.PropsGet",
534 vec![],
535 vec![],
536 vec!["I", "I", "I", "i", "*-c", "i", "*-c", "i", "i", "*+c", "i", "*+i", "i", "i", "*+c", "I"],
537 )?;
538
539 if result.len() >= 16 {
540 // Index 0: Continuous scan (0=Off, 1=On)
541 let continuous_scan = result[0].as_u32()? == 1;
542
543 // Index 1: Bouncy scan (0=Off, 1=On)
544 let bouncy_scan = result[1].as_u32()? == 1;
545
546 // Index 2: Autosave (0=All, 1=Next, 2=Off)
547 let autosave = AutosaveMode::try_from(result[2].as_u32()?)?;
548
549 // Index 3: series_name size (i)
550 // Index 4: series_name string (*-c)
551 let series_name = result[4].as_string()?.to_string();
552
553 // Index 5: comment size (i)
554 // Index 6: comment string (*-c)
555 let comment = result[6].as_string()?.to_string();
556
557 // Index 7: modules_names size (i)
558 // Index 8: modules_names count (i)
559 // Index 9: modules_names array (*+c)
560 let modules_names = result[9].as_string_array()?.to_vec();
561
562 // Index 10: num_params_per_module array size (i)
563 // Index 11: num_params_per_module array (*+i)
564 let num_params_per_module = result[11].as_i32_array()?.to_vec();
565
566 // Index 12: parameters rows (i)
567 let rows = result[12].as_i32()?;
568 // Index 13: parameters columns (i)
569 let cols = result[13].as_i32()?;
570 // Index 14: parameters 2D array (*+c)
571 let params_flat = result[14].as_string_array()?;
572
573 // Convert flat array to 2D (rows x cols)
574 let mut parameters = Vec::new();
575 for row in 0..rows as usize {
576 let mut row_params = Vec::new();
577 for col in 0..cols as usize {
578 let idx = row * (cols as usize) + col;
579 if idx < params_flat.len() {
580 row_params.push(params_flat[idx].clone());
581 }
582 }
583 parameters.push(row_params);
584 }
585
586 // Index 15: Autopaste (0=All, 1=Next, 2=Off)
587 let autopaste = AutopasteMode::try_from(result[15].as_u32()?)?;
588
589 Ok(ScanProps {
590 continuous_scan,
591 bouncy_scan,
592 autosave,
593 series_name,
594 comment,
595 modules_names,
596 num_params_per_module,
597 parameters,
598 autopaste,
599 })
600 } else {
601 Err(NanonisError::Protocol(format!(
602 "Invalid scan props response: expected 16 values, got {}",
603 result.len()
604 )))
605 }
606 }
607
608 /// Set scan properties configuration.
609 ///
610 /// Configures scan parameters including continuous scan, bouncy scan,
611 /// autosave behavior, series name, comment, and autopaste settings.
612 /// Use `ScanPropsBuilder` to set only the properties you want to change.
613 ///
614 /// # Arguments
615 /// * `builder` - Builder with properties to set. Fields set to `None` will not be changed.
616 ///
617 /// # Errors
618 /// Returns `NanonisError` if communication fails or invalid parameters provided.
619 ///
620 /// # Examples
621 /// ```no_run
622 /// use nanonis_rs::NanonisClient;
623 /// use nanonis_rs::scan::{ScanPropsBuilder, AutosaveMode, AutopasteMode};
624 ///
625 /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
626 ///
627 /// // Set only specific properties using the builder
628 /// let builder = ScanPropsBuilder::new()
629 /// .continuous_scan(true) // Enable continuous scan
630 /// .bouncy_scan(true) // Enable bouncy scan
631 /// .autosave(AutosaveMode::Off); // Disable autosave
632 ///
633 /// client.scan_props_set(builder)?;
634 /// # Ok::<(), Box<dyn std::error::Error>>(())
635 /// ```
636 pub fn scan_props_set(&mut self, builder: ScanPropsBuilder) -> Result<(), NanonisError> {
637 // Convert boolean options to u32 (0=no change, 1=On, 2=Off)
638 let continuous_flag = match builder.continuous_scan {
639 None => 0u32,
640 Some(true) => 1u32,
641 Some(false) => 2u32,
642 };
643
644 let bouncy_flag = match builder.bouncy_scan {
645 None => 0u32,
646 Some(true) => 1u32,
647 Some(false) => 2u32,
648 };
649
650 let autosave_flag = match builder.autosave {
651 None => 0u32,
652 Some(mode) => mode.into(),
653 };
654
655 let autopaste_flag = match builder.autopaste {
656 None => 0u32,
657 Some(mode) => mode.into(),
658 };
659
660 // For strings/arrays: empty string/array means no change
661 let series_name = builder.series_name.unwrap_or_default();
662 let comment = builder.comment.unwrap_or_default();
663 let modules_names = builder.modules_names.unwrap_or_default();
664
665 self.quick_send(
666 "Scan.PropsSet",
667 vec![
668 NanonisValue::U32(continuous_flag),
669 NanonisValue::U32(bouncy_flag),
670 NanonisValue::U32(autosave_flag),
671 NanonisValue::String(series_name),
672 NanonisValue::String(comment),
673 NanonisValue::ArrayString(modules_names),
674 NanonisValue::U32(autopaste_flag),
675 ],
676 vec!["I", "I", "I", "+*c", "+*c", "+*c", "I"],
677 vec![],
678 )?;
679
680 Ok(())
681 }
682
683 /// Paste background image at specified location.
684 ///
685 /// Pastes a previously copied background image to the scan buffer at the
686 /// specified position. This is used for background subtraction operations.
687 ///
688 /// # Arguments
689 /// * `x` - X position in meters for paste location
690 /// * `y` - Y position in meters for paste location
691 ///
692 /// # Errors
693 /// Returns `NanonisError` if communication fails or no background is available.
694 pub fn scan_background_paste(&mut self, x: f64, y: f64) -> Result<(), NanonisError> {
695 self.quick_send(
696 "Scan.BackgroundPaste",
697 vec![NanonisValue::F64(x), NanonisValue::F64(y)],
698 vec!["d", "d"],
699 vec![],
700 )?;
701 Ok(())
702 }
703
704 /// Delete the stored background image.
705 ///
706 /// Removes the background image from memory, freeing resources and
707 /// disabling background subtraction until a new background is captured.
708 ///
709 /// # Errors
710 /// Returns `NanonisError` if communication fails.
711 pub fn scan_background_delete(&mut self) -> Result<(), NanonisError> {
712 self.quick_send("Scan.BackgroundDelete", vec![], vec![], vec![])?;
713 Ok(())
714 }
715}