Skip to main content

nanonis_rs/client/scan/
types.rs

1use crate::error::NanonisError;
2use crate::types::Position;
3
4// ==================== Scan Types ====================
5
6#[derive(Debug, Clone, Copy)]
7pub struct ScanFrame {
8    pub center: Position,
9    pub width_m: f32,
10    pub height_m: f32,
11    pub angle_deg: f32,
12}
13
14impl ScanFrame {
15    pub fn new(center: Position, width_m: f32, height_m: f32, angle_deg: f32) -> Self {
16        Self {
17            center,
18            width_m,
19            height_m,
20            angle_deg,
21        }
22    }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum ScanAction {
27    Start = 0,
28    Stop = 1,
29    Pause = 2,
30    Resume = 3,
31    Freeze = 4,
32    Unfreeze = 5,
33    GoToCenter = 6,
34}
35
36impl From<ScanAction> for u16 {
37    fn from(action: ScanAction) -> Self {
38        action as u16
39    }
40}
41
42impl TryFrom<u16> for ScanAction {
43    type Error = NanonisError;
44
45    fn try_from(value: u16) -> Result<Self, Self::Error> {
46        match value {
47            0 => Ok(ScanAction::Start),
48            1 => Ok(ScanAction::Stop),
49            2 => Ok(ScanAction::Pause),
50            3 => Ok(ScanAction::Resume),
51            4 => Ok(ScanAction::Freeze),
52            5 => Ok(ScanAction::Unfreeze),
53            6 => Ok(ScanAction::GoToCenter),
54            _ => Err(NanonisError::Protocol(format!(
55                "Invalid scan action: {}",
56                value
57            ))),
58        }
59    }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum ScanDirection {
64    Down = 0,
65    Up = 1,
66}
67
68impl From<ScanDirection> for u32 {
69    fn from(direction: ScanDirection) -> Self {
70        direction as u32
71    }
72}
73
74impl TryFrom<u32> for ScanDirection {
75    type Error = NanonisError;
76
77    fn try_from(value: u32) -> Result<Self, Self::Error> {
78        match value {
79            0 => Ok(ScanDirection::Down),
80            1 => Ok(ScanDirection::Up),
81            _ => Err(NanonisError::Protocol(format!(
82                "Invalid scan direction: {}",
83                value
84            ))),
85        }
86    }
87}
88
89#[derive(Debug, Clone, Copy)]
90pub struct ScanConfig {
91    pub forward_linear_speed_m_s: f32,
92    pub backward_linear_speed_m_s: f32,
93    pub forward_time_per_line_s: f32,
94    pub backward_time_per_line_s: f32,
95    pub keep_parameter_constant: u16,
96    pub speed_ratio: f32,
97}
98
99#[derive(Debug, Clone)]
100pub struct ScanProps {
101    /// Continuous scan: whether scan continues after frame completion
102    pub continuous_scan: bool,
103    /// Bouncy scan: whether scan direction changes after frame completion
104    pub bouncy_scan: bool,
105    /// Autosave mode: All, Next, or Off
106    pub autosave: AutosaveMode,
107    /// Base name for saved images
108    pub series_name: String,
109    /// Comment saved in file
110    pub comment: String,
111    /// Module names whose parameters are saved in image header
112    pub modules_names: Vec<String>,
113    /// Number of parameters per module (read-only, returned by GET)
114    pub num_params_per_module: Vec<i32>,
115    /// Parameters for each module - 2D array: rows = modules, columns = parameters (read-only, returned by GET)
116    pub parameters: Vec<Vec<String>>,
117    /// Autopaste mode: All, Next, or Off
118    pub autopaste: AutopasteMode,
119}
120
121impl ScanProps {
122    /// Create a builder for modifying scan properties.
123    /// Use this to set only the properties you want to change.
124    pub fn to_builder(&self) -> ScanPropsBuilder {
125        ScanPropsBuilder {
126            continuous_scan: None,
127            bouncy_scan: None,
128            autosave: None,
129            series_name: None,
130            comment: None,
131            modules_names: None,
132            autopaste: None,
133        }
134    }
135}
136
137/// Builder for setting scan properties.
138/// Use `None` for fields that should not be changed.
139#[derive(Debug, Clone, Default)]
140pub struct ScanPropsBuilder {
141    /// Continuous scan: None = no change, Some(true) = On, Some(false) = Off
142    pub continuous_scan: Option<bool>,
143    /// Bouncy scan: None = no change, Some(true) = On, Some(false) = Off
144    pub bouncy_scan: Option<bool>,
145    /// Autosave mode: None = no change
146    pub autosave: Option<AutosaveMode>,
147    /// Base name for saved images: None = no change
148    pub series_name: Option<String>,
149    /// Comment saved in file: None = no change
150    pub comment: Option<String>,
151    /// Module names whose parameters are saved in image header: None = no change
152    pub modules_names: Option<Vec<String>>,
153    /// Autopaste mode: None = no change
154    pub autopaste: Option<AutopasteMode>,
155}
156
157impl ScanPropsBuilder {
158    /// Create a new builder with all fields set to None (no changes)
159    pub fn new() -> Self {
160        Self::default()
161    }
162
163    /// Set continuous scan mode
164    pub fn continuous_scan(mut self, value: bool) -> Self {
165        self.continuous_scan = Some(value);
166        self
167    }
168
169    /// Set bouncy scan mode
170    pub fn bouncy_scan(mut self, value: bool) -> Self {
171        self.bouncy_scan = Some(value);
172        self
173    }
174
175    /// Set autosave mode
176    pub fn autosave(mut self, mode: AutosaveMode) -> Self {
177        self.autosave = Some(mode);
178        self
179    }
180
181    /// Set series name
182    pub fn series_name(mut self, name: impl Into<String>) -> Self {
183        self.series_name = Some(name.into());
184        self
185    }
186
187    /// Set comment
188    pub fn comment(mut self, comment: impl Into<String>) -> Self {
189        self.comment = Some(comment.into());
190        self
191    }
192
193    /// Set modules names
194    pub fn modules_names(mut self, names: Vec<String>) -> Self {
195        self.modules_names = Some(names);
196        self
197    }
198
199    /// Set autopaste mode
200    pub fn autopaste(mut self, mode: AutopasteMode) -> Self {
201        self.autopaste = Some(mode);
202        self
203    }
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub enum AutosaveMode {
208    /// Save all future images automatically
209    All = 0,
210    /// Save only the next frame
211    Next = 1,
212    /// Autosave is disabled
213    Off = 2,
214}
215
216impl From<AutosaveMode> for u32 {
217    fn from(mode: AutosaveMode) -> Self {
218        // For SET: 0=no change, 1=All, 2=Next, 3=Off
219        match mode {
220            AutosaveMode::All => 1,
221            AutosaveMode::Next => 2,
222            AutosaveMode::Off => 3,
223        }
224    }
225}
226
227impl TryFrom<u32> for AutosaveMode {
228    type Error = NanonisError;
229
230    fn try_from(value: u32) -> Result<Self, Self::Error> {
231        // For GET: 0=All, 1=Next, 2=Off
232        match value {
233            0 => Ok(AutosaveMode::All),
234            1 => Ok(AutosaveMode::Next),
235            2 => Ok(AutosaveMode::Off),
236            _ => Err(NanonisError::Protocol(format!(
237                "Invalid autosave mode: {}",
238                value
239            ))),
240        }
241    }
242}
243
244#[derive(Debug, Clone, Copy, PartialEq, Eq)]
245pub enum AutopasteMode {
246    /// Paste all future images automatically
247    All = 0,
248    /// Paste only the next frame
249    Next = 1,
250    /// Autopaste is disabled
251    Off = 2,
252}
253
254impl From<AutopasteMode> for u32 {
255    fn from(mode: AutopasteMode) -> Self {
256        // For SET: 0=no change, 1=All, 2=Next, 3=Off
257        match mode {
258            AutopasteMode::All => 1,
259            AutopasteMode::Next => 2,
260            AutopasteMode::Off => 3,
261        }
262    }
263}
264
265impl TryFrom<u32> for AutopasteMode {
266    type Error = NanonisError;
267
268    fn try_from(value: u32) -> Result<Self, Self::Error> {
269        // For GET: 0=All, 1=Next, 2=Off
270        match value {
271            0 => Ok(AutopasteMode::All),
272            1 => Ok(AutopasteMode::Next),
273            2 => Ok(AutopasteMode::Off),
274            _ => Err(NanonisError::Protocol(format!(
275                "Invalid autopaste mode: {}",
276                value
277            ))),
278        }
279    }
280}