1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum PatternType {
8 #[default]
10 NoChange = 0,
11 Grid = 1,
13 Line = 2,
15 Cloud = 3,
17}
18
19impl From<PatternType> for u16 {
20 fn from(p: PatternType) -> Self {
21 p as u16
22 }
23}
24
25#[derive(Debug, Clone, Copy, Default)]
27pub struct GridConfig {
28 pub num_points_x: i32,
30 pub num_points_y: i32,
32 pub center_x_m: f32,
34 pub center_y_m: f32,
36 pub width_m: f32,
38 pub height_m: f32,
40 pub angle_deg: f32,
42}
43
44#[derive(Debug, Clone, Copy, Default)]
46pub struct LineConfig {
47 pub num_points: i32,
49 pub point1_x_m: f32,
51 pub point1_y_m: f32,
53 pub point2_x_m: f32,
55 pub point2_y_m: f32,
57}
58
59#[derive(Debug, Clone, Default)]
61pub struct CloudConfig {
62 pub x_coords_m: Vec<f32>,
64 pub y_coords_m: Vec<f32>,
66}
67
68#[derive(Debug, Clone)]
70pub struct PatternProps {
71 pub available_experiments: Vec<String>,
73 pub selected_experiment: String,
75 pub external_vi_path: String,
77 pub pre_measure_delay_s: f32,
79 pub save_scan_channels: bool,
81}
82
83impl Default for PatternProps {
84 fn default() -> Self {
85 Self {
86 available_experiments: vec![],
87 selected_experiment: String::new(),
88 external_vi_path: String::new(),
89 pre_measure_delay_s: 0.0,
90 save_scan_channels: false,
91 }
92 }
93}
94
95impl NanonisClient {
96 pub fn pattern_exp_open(&mut self) -> Result<(), NanonisError> {
112 self.quick_send("Pattern.ExpOpen", vec![], vec![], vec![])?;
113 Ok(())
114 }
115
116 pub fn pattern_exp_start(&mut self, pattern: PatternType) -> Result<(), NanonisError> {
127 self.quick_send(
128 "Pattern.ExpStart",
129 vec![NanonisValue::U16(pattern.into())],
130 vec!["H"],
131 vec![],
132 )?;
133 Ok(())
134 }
135
136 pub fn pattern_exp_pause(&mut self, pause: bool) -> Result<(), NanonisError> {
144 let flag = if pause { 1u32 } else { 0u32 };
145 self.quick_send(
146 "Pattern.ExpPause",
147 vec![NanonisValue::U32(flag)],
148 vec!["I"],
149 vec![],
150 )?;
151 Ok(())
152 }
153
154 pub fn pattern_exp_stop(&mut self) -> Result<(), NanonisError> {
159 self.quick_send("Pattern.ExpStop", vec![], vec![], vec![])?;
160 Ok(())
161 }
162
163 pub fn pattern_exp_status_get(&mut self) -> Result<bool, NanonisError> {
171 let result = self.quick_send("Pattern.ExpStatusGet", vec![], vec![], vec!["I"])?;
172
173 if !result.is_empty() {
174 Ok(result[0].as_u32()? != 0)
175 } else {
176 Err(NanonisError::Protocol("Invalid response".to_string()))
177 }
178 }
179
180 pub fn pattern_grid_set(
190 &mut self,
191 set_active: bool,
192 config: &GridConfig,
193 use_scan_frame: bool,
194 ) -> Result<(), NanonisError> {
195 let active_flag = if set_active { 1u32 } else { 0u32 };
196 let frame_flag = if use_scan_frame { 1u32 } else { 0u32 };
197
198 self.quick_send(
199 "Pattern.GridSet",
200 vec![
201 NanonisValue::U32(active_flag),
202 NanonisValue::I32(config.num_points_x),
203 NanonisValue::I32(config.num_points_y),
204 NanonisValue::U32(frame_flag),
205 NanonisValue::F32(config.center_x_m),
206 NanonisValue::F32(config.center_y_m),
207 NanonisValue::F32(config.width_m),
208 NanonisValue::F32(config.height_m),
209 NanonisValue::F32(config.angle_deg),
210 ],
211 vec!["I", "i", "i", "I", "f", "f", "f", "f", "f"],
212 vec![],
213 )?;
214 Ok(())
215 }
216
217 pub fn pattern_grid_get(&mut self) -> Result<GridConfig, NanonisError> {
225 let result = self.quick_send(
226 "Pattern.GridGet",
227 vec![],
228 vec![],
229 vec!["i", "i", "f", "f", "f", "f", "f"],
230 )?;
231
232 if result.len() >= 7 {
233 Ok(GridConfig {
234 num_points_x: result[0].as_i32()?,
235 num_points_y: result[1].as_i32()?,
236 center_x_m: result[2].as_f32()?,
237 center_y_m: result[3].as_f32()?,
238 width_m: result[4].as_f32()?,
239 height_m: result[5].as_f32()?,
240 angle_deg: result[6].as_f32()?,
241 })
242 } else {
243 Err(NanonisError::Protocol("Invalid response".to_string()))
244 }
245 }
246
247 pub fn pattern_line_set(
257 &mut self,
258 set_active: bool,
259 config: &LineConfig,
260 use_scan_frame: bool,
261 ) -> Result<(), NanonisError> {
262 let active_flag = if set_active { 1u32 } else { 0u32 };
263 let frame_flag = if use_scan_frame { 1u32 } else { 0u32 };
264
265 self.quick_send(
266 "Pattern.LineSet",
267 vec![
268 NanonisValue::U32(active_flag),
269 NanonisValue::I32(config.num_points),
270 NanonisValue::U32(frame_flag),
271 NanonisValue::F32(config.point1_x_m),
272 NanonisValue::F32(config.point1_y_m),
273 NanonisValue::F32(config.point2_x_m),
274 NanonisValue::F32(config.point2_y_m),
275 ],
276 vec!["I", "i", "I", "f", "f", "f", "f"],
277 vec![],
278 )?;
279 Ok(())
280 }
281
282 pub fn pattern_line_get(&mut self) -> Result<LineConfig, NanonisError> {
290 let result = self.quick_send(
291 "Pattern.LineGet",
292 vec![],
293 vec![],
294 vec!["i", "f", "f", "f", "f"],
295 )?;
296
297 if result.len() >= 5 {
298 Ok(LineConfig {
299 num_points: result[0].as_i32()?,
300 point1_x_m: result[1].as_f32()?,
301 point1_y_m: result[2].as_f32()?,
302 point2_x_m: result[3].as_f32()?,
303 point2_y_m: result[4].as_f32()?,
304 })
305 } else {
306 Err(NanonisError::Protocol("Invalid response".to_string()))
307 }
308 }
309
310 pub fn pattern_cloud_set(
319 &mut self,
320 set_active: bool,
321 config: &CloudConfig,
322 ) -> Result<(), NanonisError> {
323 let active_flag = if set_active { 1u32 } else { 0u32 };
324 let num_points = config.x_coords_m.len() as i32;
325
326 self.quick_send(
327 "Pattern.CloudSet",
328 vec![
329 NanonisValue::U32(active_flag),
330 NanonisValue::I32(num_points),
331 NanonisValue::ArrayF32(config.x_coords_m.clone()),
332 NanonisValue::ArrayF32(config.y_coords_m.clone()),
333 ],
334 vec!["I", "i", "*f", "*f"],
335 vec![],
336 )?;
337 Ok(())
338 }
339
340 pub fn pattern_cloud_get(&mut self) -> Result<CloudConfig, NanonisError> {
348 let result = self.quick_send(
349 "Pattern.CloudGet",
350 vec![],
351 vec![],
352 vec!["i", "*f", "*f"],
353 )?;
354
355 if result.len() >= 3 {
356 Ok(CloudConfig {
357 x_coords_m: result[1].as_f32_array()?.to_vec(),
358 y_coords_m: result[2].as_f32_array()?.to_vec(),
359 })
360 } else {
361 Err(NanonisError::Protocol("Invalid response".to_string()))
362 }
363 }
364
365 pub fn pattern_props_set(
377 &mut self,
378 selected_experiment: &str,
379 basename: &str,
380 external_vi_path: &str,
381 pre_measure_delay_s: f32,
382 save_scan_channels: bool,
383 ) -> Result<(), NanonisError> {
384 let save_flag = if save_scan_channels { 1u32 } else { 0u32 };
385
386 self.quick_send(
387 "Pattern.PropsSet",
388 vec![
389 NanonisValue::String(selected_experiment.to_string()),
390 NanonisValue::String(basename.to_string()),
391 NanonisValue::String(external_vi_path.to_string()),
392 NanonisValue::F32(pre_measure_delay_s),
393 NanonisValue::U32(save_flag),
394 ],
395 vec!["+*c", "+*c", "+*c", "f", "I"],
396 vec![],
397 )?;
398 Ok(())
399 }
400
401 pub fn pattern_props_get(&mut self) -> Result<PatternProps, NanonisError> {
409 let result = self.quick_send(
410 "Pattern.PropsGet",
411 vec![],
412 vec![],
413 vec!["i", "i", "*+c", "i", "*-c", "i", "*-c", "f", "I"],
414 )?;
415
416 if result.len() >= 9 {
417 Ok(PatternProps {
418 available_experiments: result[2].as_string_array()?.to_vec(),
419 selected_experiment: result[4].as_string()?.to_string(),
420 external_vi_path: result[6].as_string()?.to_string(),
421 pre_measure_delay_s: result[7].as_f32()?,
422 save_scan_channels: result[8].as_u32()? != 0,
423 })
424 } else {
425 Err(NanonisError::Protocol("Invalid response".to_string()))
426 }
427 }
428}