1use serde::{Deserialize, Serialize};
2
3use crate::error::NanonisError;
4use std::time::Duration;
5
6#[derive(Debug, Clone)]
7pub enum NanonisValue {
8 U16(u16),
9 I16(i16),
10 U32(u32),
11 I32(i32),
12 F32(f32),
13 F64(f64),
14 String(String),
15 ArrayU16(Vec<u16>),
16 ArrayI16(Vec<i16>),
17 ArrayU32(Vec<u32>),
18 ArrayI32(Vec<i32>),
19 ArrayF32(Vec<f32>),
20 ArrayF64(Vec<f64>),
21 ArrayString(Vec<String>),
22 Array2DF32(Vec<Vec<f32>>),
23}
24
25impl From<f32> for NanonisValue {
27 fn from(value: f32) -> Self {
28 NanonisValue::F32(value)
29 }
30}
31
32impl From<f64> for NanonisValue {
33 fn from(value: f64) -> Self {
34 NanonisValue::F64(value)
35 }
36}
37
38impl From<u16> for NanonisValue {
39 fn from(value: u16) -> Self {
40 NanonisValue::U16(value)
41 }
42}
43
44impl From<u32> for NanonisValue {
45 fn from(value: u32) -> Self {
46 NanonisValue::U32(value)
47 }
48}
49
50impl From<i16> for NanonisValue {
51 fn from(value: i16) -> Self {
52 NanonisValue::I16(value)
53 }
54}
55
56impl From<i32> for NanonisValue {
57 fn from(value: i32) -> Self {
58 NanonisValue::I32(value)
59 }
60}
61
62impl From<String> for NanonisValue {
63 fn from(value: String) -> Self {
64 NanonisValue::String(value)
65 }
66}
67
68impl From<Vec<f32>> for NanonisValue {
69 fn from(value: Vec<f32>) -> Self {
70 NanonisValue::ArrayF32(value)
71 }
72}
73
74impl From<Vec<String>> for NanonisValue {
75 fn from(value: Vec<String>) -> Self {
76 NanonisValue::ArrayString(value)
77 }
78}
79
80impl From<Vec<i32>> for NanonisValue {
81 fn from(value: Vec<i32>) -> Self {
82 NanonisValue::ArrayI32(value)
83 }
84}
85
86impl TryFrom<NanonisValue> for f32 {
87 type Error = NanonisError;
88
89 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
90 match value {
91 NanonisValue::F32(v) => Ok(v),
92 _ => Err(NanonisError::Type(format!("Expected f32, got {value:?}"))),
93 }
94 }
95}
96
97impl TryFrom<NanonisValue> for f64 {
98 type Error = NanonisError;
99
100 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
101 match value {
102 NanonisValue::F64(v) => Ok(v),
103 _ => Err(NanonisError::Type(format!("Expected f64, got {value:?}"))),
104 }
105 }
106}
107
108impl TryFrom<NanonisValue> for u16 {
109 type Error = NanonisError;
110
111 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
112 match value {
113 NanonisValue::U16(v) => Ok(v),
114 _ => Err(NanonisError::Type(format!("Expected u16, got {value:?}"))),
115 }
116 }
117}
118
119impl TryFrom<NanonisValue> for u32 {
120 type Error = NanonisError;
121
122 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
123 match value {
124 NanonisValue::U32(v) => Ok(v),
125 _ => Err(NanonisError::Type(format!("Expected u32, got {value:?}"))),
126 }
127 }
128}
129
130impl TryFrom<NanonisValue> for i16 {
131 type Error = NanonisError;
132
133 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
134 match value {
135 NanonisValue::I16(v) => Ok(v),
136 _ => Err(NanonisError::Type(format!("Expected i16, got {value:?}"))),
137 }
138 }
139}
140
141impl TryFrom<NanonisValue> for i32 {
142 type Error = NanonisError;
143
144 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
145 match value {
146 NanonisValue::I32(v) => Ok(v),
147 _ => Err(NanonisError::Type(format!("Expected i32, got {value:?}"))),
148 }
149 }
150}
151
152impl TryFrom<NanonisValue> for Vec<f32> {
153 type Error = NanonisError;
154
155 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
156 match value {
157 NanonisValue::ArrayF32(v) => Ok(v),
158 _ => Err(NanonisError::Type(format!(
159 "Expected Vec<f32>, got {value:?}"
160 ))),
161 }
162 }
163}
164
165impl TryFrom<NanonisValue> for Vec<String> {
166 type Error = NanonisError;
167
168 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
169 match value {
170 NanonisValue::ArrayString(v) => Ok(v),
171 _ => Err(NanonisError::Type(format!(
172 "Expected Vec<String>, got {value:?}"
173 ))),
174 }
175 }
176}
177
178impl TryFrom<NanonisValue> for Vec<i32> {
179 type Error = NanonisError;
180
181 fn try_from(value: NanonisValue) -> Result<Self, Self::Error> {
182 match value {
183 NanonisValue::ArrayI32(v) => Ok(v),
184 _ => Err(NanonisError::Type(format!(
185 "Expected Vec<i32>, got {value:?}"
186 ))),
187 }
188 }
189}
190
191impl NanonisValue {
193 pub fn as_f32(&self) -> Result<f32, NanonisError> {
195 match self {
196 NanonisValue::F32(v) => Ok(*v),
197 _ => Err(NanonisError::Type(format!("Expected f32, got {self:?}"))),
198 }
199 }
200
201 pub fn as_f64(&self) -> Result<f64, NanonisError> {
203 match self {
204 NanonisValue::F64(v) => Ok(*v),
205 _ => Err(NanonisError::Type(format!("Expected f64, got {self:?}"))),
206 }
207 }
208
209 pub fn as_u16(&self) -> Result<u16, NanonisError> {
211 match self {
212 NanonisValue::U16(v) => Ok(*v),
213 _ => Err(NanonisError::Type(format!("Expected u16, got {self:?}"))),
214 }
215 }
216
217 pub fn as_u32(&self) -> Result<u32, NanonisError> {
219 match self {
220 NanonisValue::U32(v) => Ok(*v),
221 _ => Err(NanonisError::Type(format!("Expected u32, got {self:?}"))),
222 }
223 }
224
225 pub fn as_i16(&self) -> Result<i16, NanonisError> {
227 match self {
228 NanonisValue::I16(v) => Ok(*v),
229 _ => Err(NanonisError::Type(format!("Expected i16, got {self:?}"))),
230 }
231 }
232
233 pub fn as_i32(&self) -> Result<i32, NanonisError> {
235 match self {
236 NanonisValue::I32(v) => Ok(*v),
237 _ => Err(NanonisError::Type(format!("Expected i32, got {self:?}"))),
238 }
239 }
240
241 pub fn as_string_array(&self) -> Result<&[String], NanonisError> {
243 match self {
244 NanonisValue::ArrayString(arr) => Ok(arr),
245 _ => Err(NanonisError::Type(format!(
246 "Expected string array, got {self:?}"
247 ))),
248 }
249 }
250
251 pub fn as_f32_array(&self) -> Result<&[f32], NanonisError> {
253 match self {
254 NanonisValue::ArrayF32(arr) => Ok(arr),
255 _ => Err(NanonisError::Type(format!(
256 "Expected f32 array, got {self:?}"
257 ))),
258 }
259 }
260
261 pub fn as_f64_array(&self) -> Result<&[f64], NanonisError> {
263 match self {
264 NanonisValue::ArrayF64(arr) => Ok(arr),
265 _ => Err(NanonisError::Type(format!(
266 "Expected f64 array, got {self:?}"
267 ))),
268 }
269 }
270
271 pub fn as_i32_array(&self) -> Result<&[i32], NanonisError> {
273 match self {
274 NanonisValue::ArrayI32(arr) => Ok(arr),
275 _ => Err(NanonisError::Type(format!(
276 "Expected i32 array, got {self:?}"
277 ))),
278 }
279 }
280
281 pub fn as_string(&self) -> Result<&str, NanonisError> {
283 match self {
284 NanonisValue::String(s) => Ok(s),
285 _ => Err(NanonisError::Type(format!("Expected string, got {self:?}"))),
286 }
287 }
288
289 pub fn as_f32_2d_array(&self) -> Result<&Vec<Vec<f32>>, NanonisError> {
291 match self {
292 NanonisValue::Array2DF32(arr) => Ok(arr),
293 _ => Err(NanonisError::Type(format!(
294 "Expected 2D f32 array, got {self:?}"
295 ))),
296 }
297 }
298}
299
300#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
302pub struct SignalIndex(pub i32);
303
304impl SignalIndex {
305 pub fn new(index: i32) -> Result<Self, crate::error::NanonisError> {
306 if (0..=127).contains(&index) {
307 Ok(SignalIndex(index))
308 } else {
309 Err(crate::error::NanonisError::InvalidCommand(format!(
310 "Signal index must be 0-127, got {}",
311 index
312 )))
313 }
314 }
315}
316
317impl From<SignalIndex> for i32 {
318 fn from(signal: SignalIndex) -> Self {
319 signal.0
320 }
321}
322
323impl From<i32> for SignalIndex {
324 fn from(index: i32) -> Self {
325 SignalIndex(index)
326 }
327}
328
329impl From<usize> for SignalIndex {
330 fn from(index: usize) -> Self {
331 SignalIndex(index as i32)
332 }
333}
334
335#[derive(Debug, Clone, Copy, PartialEq, Eq)]
336pub struct ChannelIndex(pub i32);
337
338impl ChannelIndex {
339 pub fn new(index: i32) -> Result<Self, crate::error::NanonisError> {
340 if (0..=23).contains(&index) {
341 Ok(ChannelIndex(index))
342 } else {
343 Err(crate::error::NanonisError::InvalidCommand(format!(
344 "Channel index must be 0-23, got {}",
345 index
346 )))
347 }
348 }
349}
350
351impl From<ChannelIndex> for i32 {
352 fn from(channel: ChannelIndex) -> Self {
353 channel.0
354 }
355}
356
357impl From<i32> for ChannelIndex {
358 fn from(index: i32) -> Self {
359 ChannelIndex(index)
360 }
361}
362
363impl From<usize> for ChannelIndex {
364 fn from(index: usize) -> Self {
365 ChannelIndex(index as i32)
366 }
367}
368
369#[derive(Debug, Clone, Copy, PartialEq, Eq)]
370pub struct OscilloscopeIndex(pub i32);
371
372impl From<OscilloscopeIndex> for i32 {
373 fn from(osci: OscilloscopeIndex) -> Self {
374 osci.0
375 }
376}
377
378impl From<i32> for OscilloscopeIndex {
379 fn from(index: i32) -> Self {
380 OscilloscopeIndex(index)
381 }
382}
383
384impl From<usize> for OscilloscopeIndex {
385 fn from(index: usize) -> Self {
386 OscilloscopeIndex(index as i32)
387 }
388}
389
390#[derive(Debug, Clone, Copy, PartialEq, Eq)]
392pub enum MotorDirection {
393 XPlus = 0,
394 XMinus = 1,
395 YPlus = 2,
396 YMinus = 3,
397 ZPlus = 4,
398 ZMinus = 5,
399}
400
401impl From<MotorDirection> for u32 {
402 fn from(direction: MotorDirection) -> Self {
403 direction as u32
404 }
405}
406
407impl TryFrom<u32> for MotorDirection {
408 type Error = crate::error::NanonisError;
409
410 fn try_from(value: u32) -> Result<Self, Self::Error> {
411 match value {
412 0 => Ok(MotorDirection::XPlus),
413 1 => Ok(MotorDirection::XMinus),
414 2 => Ok(MotorDirection::YPlus),
415 3 => Ok(MotorDirection::YMinus),
416 4 => Ok(MotorDirection::ZPlus),
417 5 => Ok(MotorDirection::ZMinus),
418 _ => Err(crate::error::NanonisError::InvalidCommand(format!(
419 "Invalid motor direction: {}",
420 value
421 ))),
422 }
423 }
424}
425
426#[derive(Debug, Clone, Copy, PartialEq, Eq)]
427pub enum MotorGroup {
428 Group1 = 0,
429 Group2 = 1,
430 Group3 = 2,
431 Group4 = 3,
432 Group5 = 4,
433 Group6 = 5,
434}
435
436impl From<MotorGroup> for u32 {
437 fn from(group: MotorGroup) -> Self {
438 group as u32
439 }
440}
441
442impl TryFrom<u32> for MotorGroup {
443 type Error = crate::error::NanonisError;
444
445 fn try_from(value: u32) -> Result<Self, Self::Error> {
446 match value {
447 0 => Ok(MotorGroup::Group1),
448 1 => Ok(MotorGroup::Group2),
449 2 => Ok(MotorGroup::Group3),
450 3 => Ok(MotorGroup::Group4),
451 4 => Ok(MotorGroup::Group5),
452 5 => Ok(MotorGroup::Group6),
453 _ => Err(crate::error::NanonisError::InvalidCommand(format!(
454 "Invalid motor group: {}",
455 value
456 ))),
457 }
458 }
459}
460
461#[derive(Debug, Clone, Copy)]
462pub struct StepCount(pub u16);
463
464impl From<StepCount> for u16 {
465 fn from(steps: StepCount) -> Self {
466 steps.0
467 }
468}
469
470impl From<u16> for StepCount {
471 fn from(steps: u16) -> Self {
472 StepCount(steps)
473 }
474}
475
476impl From<u32> for StepCount {
477 fn from(steps: u32) -> Self {
478 StepCount(steps as u16)
479 }
480}
481
482#[derive(Debug, Clone, Copy)]
483pub struct Frequency(pub f32);
484
485impl Frequency {
486 pub fn hz(value: f32) -> Self {
487 Self(value)
488 }
489}
490
491impl From<Frequency> for f32 {
492 fn from(freq: Frequency) -> Self {
493 freq.0
494 }
495}
496
497impl From<f32> for Frequency {
498 fn from(freq: f32) -> Self {
499 Frequency(freq)
500 }
501}
502
503impl From<f64> for Frequency {
504 fn from(freq: f64) -> Self {
505 Frequency(freq as f32)
506 }
507}
508
509#[derive(Debug, Clone, Copy)]
510pub struct Amplitude(pub f32);
511
512impl Amplitude {
513 pub fn volts(value: f32) -> Self {
514 Self(value)
515 }
516}
517
518impl From<Amplitude> for f32 {
519 fn from(amp: Amplitude) -> Self {
520 amp.0
521 }
522}
523
524impl From<f32> for Amplitude {
525 fn from(amp: f32) -> Self {
526 Amplitude(amp)
527 }
528}
529
530impl From<f64> for Amplitude {
531 fn from(amp: f64) -> Self {
532 Amplitude(amp as f32)
533 }
534}
535
536#[derive(Debug, Clone, Copy, PartialEq, Eq)]
537pub enum MotorAxis {
538 All = 0,
539 X = 1,
540 Y = 2,
541 Z = 3,
542}
543
544impl From<MotorAxis> for u16 {
545 fn from(axis: MotorAxis) -> Self {
546 axis as u16
547 }
548}
549
550impl From<u16> for MotorAxis {
552 fn from(value: u16) -> Self {
553 match value {
554 0 => MotorAxis::All,
555 1 => MotorAxis::X,
556 2 => MotorAxis::Y,
557 3 => MotorAxis::Z,
558 _ => MotorAxis::All, }
560 }
561}
562
563impl From<i32> for MotorAxis {
564 fn from(value: i32) -> Self {
565 MotorAxis::from(value as u16)
566 }
567}
568
569#[derive(Debug, Clone, Copy)]
571pub struct Position3D {
572 pub x: f64,
573 pub y: f64,
574 pub z: f64,
575}
576
577impl Position3D {
578 pub fn new(x: f64, y: f64, z: f64) -> Self {
579 Self { x, y, z }
580 }
581
582 pub fn meters(x: f64, y: f64, z: f64) -> Self {
583 Self::new(x, y, z)
584 }
585}
586
587#[derive(Debug, Clone, Copy, PartialEq, Eq)]
588pub enum MovementMode {
589 Relative = 0,
590 Absolute = 1,
591}
592
593impl From<MovementMode> for u32 {
594 fn from(mode: MovementMode) -> Self {
595 mode as u32
596 }
597}
598
599impl TryFrom<u32> for MovementMode {
600 type Error = crate::error::NanonisError;
601
602 fn try_from(value: u32) -> Result<Self, Self::Error> {
603 match value {
604 0 => Ok(MovementMode::Relative),
605 1 => Ok(MovementMode::Absolute),
606 _ => Err(crate::error::NanonisError::InvalidCommand(format!(
607 "Invalid movement mode: {}",
608 value
609 ))),
610 }
611 }
612}
613
614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
616pub enum TriggerMode {
617 Immediate = 0,
618 Level = 1,
619 Digital = 2,
620}
621
622impl From<TriggerMode> for u16 {
623 fn from(mode: TriggerMode) -> Self {
624 mode as u16
625 }
626}
627
628impl From<u16> for TriggerMode {
630 fn from(value: u16) -> Self {
631 match value {
632 0 => TriggerMode::Immediate,
633 1 => TriggerMode::Level,
634 2 => TriggerMode::Digital,
635 _ => TriggerMode::Immediate, }
637 }
638}
639
640impl From<i32> for TriggerMode {
641 fn from(value: i32) -> Self {
642 TriggerMode::from(value as u16)
643 }
644}
645
646#[derive(Debug, Clone, Copy, PartialEq, Eq)]
647pub enum TriggerSlope {
648 Falling = 0,
649 Rising = 1,
650}
651
652impl From<TriggerSlope> for u16 {
653 fn from(slope: TriggerSlope) -> Self {
654 slope as u16
655 }
656}
657
658impl TryFrom<u16> for TriggerSlope {
659 type Error = crate::error::NanonisError;
660
661 fn try_from(value: u16) -> Result<Self, Self::Error> {
662 match value {
663 0 => Ok(TriggerSlope::Falling),
664 1 => Ok(TriggerSlope::Rising),
665 _ => Err(crate::error::NanonisError::InvalidCommand(format!(
666 "Invalid trigger slope: {}",
667 value
668 ))),
669 }
670 }
671}
672
673#[derive(Debug, Clone, Copy)]
674pub struct TriggerLevel(pub f64);
675
676impl From<TriggerLevel> for f64 {
677 fn from(level: TriggerLevel) -> Self {
678 level.0
679 }
680}
681
682impl From<f64> for TriggerLevel {
683 fn from(level: f64) -> Self {
684 TriggerLevel(level)
685 }
686}
687
688impl From<f32> for TriggerLevel {
689 fn from(level: f32) -> Self {
690 TriggerLevel(level as f64)
691 }
692}
693
694#[derive(Debug, Clone, Copy)]
695pub struct SampleCount(pub i32);
696
697impl SampleCount {
698 pub fn new(count: i32) -> Self {
699 Self(count)
700 }
701}
702
703impl From<SampleCount> for i32 {
704 fn from(samples: SampleCount) -> Self {
705 samples.0
706 }
707}
708
709impl From<i32> for SampleCount {
710 fn from(count: i32) -> Self {
711 SampleCount(count)
712 }
713}
714
715impl From<u32> for SampleCount {
716 fn from(count: u32) -> Self {
717 SampleCount(count as i32)
718 }
719}
720
721impl From<usize> for SampleCount {
722 fn from(count: usize) -> Self {
723 SampleCount(count as i32)
724 }
725}
726
727#[derive(Debug, Clone, Copy)]
729pub struct ScanFrame {
730 pub center: Position,
731 pub width_m: f32,
732 pub height_m: f32,
733 pub angle_deg: f32,
734}
735
736impl ScanFrame {
737 pub fn new(center: Position, width_m: f32, height_m: f32, angle_deg: f32) -> Self {
738 Self {
739 center,
740 width_m,
741 height_m,
742 angle_deg,
743 }
744 }
745}
746
747#[derive(Debug, Clone, Copy, PartialEq, Eq)]
748pub enum ScanAction {
749 Start = 0,
750 Stop = 1,
751 Pause = 2,
752 Resume = 3,
753 Freeze = 4,
754 Unfreeze = 5,
755 GoToCenter = 6,
756}
757
758impl From<ScanAction> for u16 {
759 fn from(action: ScanAction) -> Self {
760 action as u16
761 }
762}
763
764impl TryFrom<u16> for ScanAction {
765 type Error = crate::error::NanonisError;
766
767 fn try_from(value: u16) -> Result<Self, Self::Error> {
768 match value {
769 0 => Ok(ScanAction::Start),
770 1 => Ok(ScanAction::Stop),
771 2 => Ok(ScanAction::Pause),
772 3 => Ok(ScanAction::Resume),
773 4 => Ok(ScanAction::Freeze),
774 5 => Ok(ScanAction::Unfreeze),
775 6 => Ok(ScanAction::GoToCenter),
776 _ => Err(crate::error::NanonisError::InvalidCommand(format!(
777 "Invalid scan action: {}",
778 value
779 ))),
780 }
781 }
782}
783
784#[derive(Debug, Clone, Copy, PartialEq, Eq)]
785pub enum ScanDirection {
786 Down = 0,
787 Up = 1,
788}
789
790impl From<ScanDirection> for u32 {
791 fn from(direction: ScanDirection) -> Self {
792 direction as u32
793 }
794}
795
796impl TryFrom<u32> for ScanDirection {
797 type Error = crate::error::NanonisError;
798
799 fn try_from(value: u32) -> Result<Self, Self::Error> {
800 match value {
801 0 => Ok(ScanDirection::Down),
802 1 => Ok(ScanDirection::Up),
803 _ => Err(crate::error::NanonisError::InvalidCommand(format!(
804 "Invalid scan direction: {}",
805 value
806 ))),
807 }
808 }
809}
810
811#[derive(Debug, Clone, Copy, PartialEq, Eq)]
814pub enum ZControllerHold {
815 NoChange = 0,
817 Hold = 1,
819 Release = 2,
821}
822
823impl From<ZControllerHold> for u16 {
824 fn from(hold: ZControllerHold) -> Self {
825 hold as u16
826 }
827}
828
829#[derive(Debug, Clone, Copy, PartialEq, Eq)]
831pub enum PulseMode {
832 Keep = 0,
834 Relative = 1,
836 Absolute = 2,
838}
839
840impl From<PulseMode> for u16 {
841 fn from(mode: PulseMode) -> Self {
842 mode as u16
843 }
844}
845
846#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
848pub struct Position {
849 pub x: f64,
850 pub y: f64,
851}
852
853impl Position {
854 pub fn new(x: f64, y: f64) -> Self {
855 Self { x, y }
856 }
857}
858
859#[derive(Debug, Clone, Serialize, Deserialize)]
861pub struct SessionMetadata {
862 pub session_id: String,
863 pub signal_names: Vec<String>, pub active_indices: Vec<usize>, pub primary_signal_index: usize, pub session_start: f64, }
868
869#[derive(Debug, Clone)]
873pub struct MotorMovement {
874 pub direction: MotorDirection,
875 pub steps: StepCount,
876 pub group: MotorGroup,
877}
878
879impl MotorMovement {
880 pub fn new(direction: MotorDirection, steps: StepCount, group: MotorGroup) -> Self {
881 Self {
882 direction,
883 steps,
884 group,
885 }
886 }
887}
888
889#[derive(Debug, Clone, Copy, PartialEq, Eq)]
891pub enum OsciTriggerMode {
892 Immediate = 0,
893 Level = 1,
894 Auto = 2,
895}
896
897impl From<OsciTriggerMode> for u16 {
898 fn from(mode: OsciTriggerMode) -> Self {
899 mode as u16
900 }
901}
902
903impl TryFrom<u16> for OsciTriggerMode {
904 type Error = NanonisError;
905
906 fn try_from(value: u16) -> Result<Self, Self::Error> {
907 match value {
908 0 => Ok(OsciTriggerMode::Immediate),
909 1 => Ok(OsciTriggerMode::Level),
910 2 => Ok(OsciTriggerMode::Auto),
911 _ => Err(NanonisError::InvalidCommand(format!(
912 "Invalid oscilloscope trigger mode: {}",
913 value
914 ))),
915 }
916 }
917}
918
919#[derive(Debug, Clone, Copy, PartialEq, Eq)]
921pub enum OversamplingIndex {
922 Samples50 = 0,
923 Samples20 = 1,
924 Samples10 = 2,
925 Samples5 = 3,
926 Samples2 = 4,
927 Samples1 = 5,
928}
929
930impl From<OversamplingIndex> for u16 {
931 fn from(index: OversamplingIndex) -> Self {
932 index as u16
933 }
934}
935
936impl TryFrom<u16> for OversamplingIndex {
937 type Error = NanonisError;
938
939 fn try_from(value: u16) -> Result<Self, Self::Error> {
940 match value {
941 0 => Ok(OversamplingIndex::Samples50),
942 1 => Ok(OversamplingIndex::Samples20),
943 2 => Ok(OversamplingIndex::Samples10),
944 3 => Ok(OversamplingIndex::Samples5),
945 4 => Ok(OversamplingIndex::Samples2),
946 5 => Ok(OversamplingIndex::Samples1),
947 _ => Err(NanonisError::InvalidCommand(format!(
948 "Invalid oversampling index: {}",
949 value
950 ))),
951 }
952 }
953}
954
955#[derive(Debug, Clone, Copy, PartialEq, Eq)]
957pub struct TimebaseIndex(pub i32);
958
959impl From<TimebaseIndex> for i32 {
960 fn from(index: TimebaseIndex) -> Self {
961 index.0
962 }
963}
964
965impl From<TimebaseIndex> for u16 {
966 fn from(index: TimebaseIndex) -> Self {
967 index.0 as u16
968 }
969}
970
971impl From<i32> for TimebaseIndex {
972 fn from(value: i32) -> Self {
973 TimebaseIndex(value)
974 }
975}
976
977impl From<u16> for TimebaseIndex {
978 fn from(value: u16) -> Self {
979 TimebaseIndex(value as i32)
980 }
981}
982
983#[derive(Debug, Clone, Copy, PartialEq, Eq)]
989pub enum DataToGet {
990 Current,
991 NextTrigger,
992 Wait2Triggers,
993 Stable {
999 readings: u32,
1000 timeout: Duration,
1001 },
1002}
1003
1004#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1007pub enum TCPLogStatus {
1008 Disconnected = 0,
1009 Idle = 1,
1010 Start = 2,
1011 Stop = 3,
1012 Running = 4,
1013 TCPConnect = 5,
1014 TCPDisconnect = 6,
1015 BufferOverflow = 7,
1016}
1017
1018impl From<TCPLogStatus> for i32 {
1019 fn from(status: TCPLogStatus) -> Self {
1020 status as i32
1021 }
1022}
1023
1024impl TryFrom<i32> for TCPLogStatus {
1025 type Error = NanonisError;
1026
1027 fn try_from(value: i32) -> Result<Self, Self::Error> {
1028 match value {
1029 0 => Ok(TCPLogStatus::Disconnected),
1030 1 => Ok(TCPLogStatus::Idle),
1031 2 => Ok(TCPLogStatus::Start),
1032 3 => Ok(TCPLogStatus::Stop),
1033 4 => Ok(TCPLogStatus::Running),
1034 5 => Ok(TCPLogStatus::TCPConnect),
1035 6 => Ok(TCPLogStatus::TCPDisconnect),
1036 7 => Ok(TCPLogStatus::BufferOverflow),
1037 _ => Err(NanonisError::InvalidCommand(format!(
1038 "Invalid TCP Logger status: {}",
1039 value
1040 ))),
1041 }
1042 }
1043}
1044
1045impl std::fmt::Display for TCPLogStatus {
1046 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1047 let status_str = match self {
1048 TCPLogStatus::Disconnected => "Disconnected",
1049 TCPLogStatus::Idle => "Idle",
1050 TCPLogStatus::Start => "Start",
1051 TCPLogStatus::Stop => "Stop",
1052 TCPLogStatus::Running => "Running",
1053 TCPLogStatus::TCPConnect => "TCP Connect",
1054 TCPLogStatus::TCPDisconnect => "TCP Disconnect",
1055 TCPLogStatus::BufferOverflow => "Buffer Overflow",
1056 };
1057 write!(f, "{}", status_str)
1058 }
1059}
1060
1061#[derive(Debug, Clone, Copy)]
1063pub struct TriggerConfig {
1064 pub mode: OsciTriggerMode,
1065 pub slope: TriggerSlope,
1066 pub level: f64,
1067 pub hysteresis: f64,
1068}
1069
1070impl TriggerConfig {
1071 pub fn new(mode: OsciTriggerMode, slope: TriggerSlope, level: f64, hysteresis: f64) -> Self {
1072 Self {
1073 mode,
1074 slope,
1075 level,
1076 hysteresis,
1077 }
1078 }
1079
1080 pub fn immediate() -> Self {
1081 Self {
1082 mode: OsciTriggerMode::Immediate,
1083 slope: TriggerSlope::Rising,
1084 level: 0.0,
1085 hysteresis: 0.0,
1086 }
1087 }
1088
1089 pub fn level_trigger(level: f64, slope: TriggerSlope) -> Self {
1090 Self {
1091 mode: OsciTriggerMode::Level,
1092 slope,
1093 level,
1094 hysteresis: 0.1,
1095 }
1096 }
1097
1098 pub fn auto_trigger() -> Self {
1099 Self {
1100 mode: OsciTriggerMode::Auto,
1101 slope: TriggerSlope::Rising,
1102 level: 0.0,
1103 hysteresis: 0.1,
1104 }
1105 }
1106}
1107
1108#[derive(Debug, Clone)]
1110pub struct SignalStats {
1111 pub mean: f64,
1112 pub std_dev: f64,
1113 pub relative_std: f64,
1114 pub window_size: usize,
1115 pub stability_method: String,
1117}
1118
1119#[derive(Debug, Clone)]
1121pub struct OsciData {
1122 pub t0: f64,
1123 pub dt: f64,
1124 pub size: i32,
1125 pub data: Vec<f64>,
1126 pub signal_stats: Option<SignalStats>,
1127 pub is_stable: bool,
1129 pub fallback_value: Option<f64>,
1131}
1132
1133impl OsciData {
1134 pub fn new(t0: f64, dt: f64, size: i32, data: Vec<f64>) -> Self {
1135 Self {
1136 t0,
1137 dt,
1138 size,
1139 data,
1140 signal_stats: None,
1141 is_stable: true, fallback_value: None,
1143 }
1144 }
1145
1146 pub fn new_with_stats(t0: f64, dt: f64, size: i32, data: Vec<f64>, stats: SignalStats) -> Self {
1147 Self {
1148 t0,
1149 dt,
1150 size,
1151 data,
1152 signal_stats: Some(stats),
1153 is_stable: true, fallback_value: None,
1155 }
1156 }
1157
1158 pub fn new_stable(t0: f64, dt: f64, size: i32, data: Vec<f64>) -> Self {
1160 Self {
1161 t0,
1162 dt,
1163 size,
1164 data,
1165 signal_stats: None,
1166 is_stable: true,
1167 fallback_value: None,
1168 }
1169 }
1170
1171 pub fn new_unstable_with_fallback(t0: f64, dt: f64, size: i32, data: Vec<f64>, fallback: f64) -> Self {
1173 Self {
1174 t0,
1175 dt,
1176 size,
1177 data,
1178 signal_stats: None,
1179 is_stable: false,
1180 fallback_value: Some(fallback),
1181 }
1182 }
1183
1184 pub fn values(&self) -> &[f64] {
1186 &self.data
1187 }
1188
1189 pub fn time_series(&self) -> Vec<(f64, f64)> {
1191 self.data
1192 .iter()
1193 .enumerate()
1194 .map(|(i, &value)| (self.t0 + i as f64 * self.dt, value))
1195 .collect()
1196 }
1197
1198 pub fn stats(&self) -> Option<&SignalStats> {
1200 self.signal_stats.as_ref()
1201 }
1202
1203 pub fn is_stable(&self) -> bool {
1205 self.signal_stats.is_some()
1206 }
1207
1208 pub fn duration(&self) -> f64 {
1209 (self.size - 1) as f64 * self.dt
1210 }
1211
1212 pub fn sample_rate(&self) -> f64 {
1213 if self.dt > 0.0 {
1214 1.0 / self.dt
1215 } else {
1216 0.0
1217 }
1218 }
1219
1220 pub fn time_points(&self) -> Vec<f64> {
1221 (0..self.size)
1222 .map(|i| self.t0 + i as f64 * self.dt)
1223 .collect()
1224 }
1225}
1226
1227#[derive(Debug, Clone)]
1229pub struct TCPLoggerData {
1230 pub num_channels: u32,
1232 pub oversampling: f32,
1234 pub counter: u64,
1236 pub state: TCPLogStatus,
1238 pub data: Vec<f32>,
1240}
1241
1242#[derive(Debug, Clone, PartialEq, Eq)]
1244pub enum AutoApproachResult {
1245 Success,
1247 Timeout,
1249 Failed(String),
1251 AlreadyRunning,
1253 Cancelled,
1255}
1256
1257impl AutoApproachResult {
1258 pub fn is_success(&self) -> bool {
1260 matches!(self, AutoApproachResult::Success)
1261 }
1262
1263 pub fn is_failure(&self) -> bool {
1265 matches!(
1266 self,
1267 AutoApproachResult::Failed(_) | AutoApproachResult::Timeout
1268 )
1269 }
1270
1271 pub fn error_message(&self) -> Option<&str> {
1273 match self {
1274 AutoApproachResult::Failed(msg) => Some(msg),
1275 AutoApproachResult::Timeout => Some("Auto-approach timed out"),
1276 AutoApproachResult::AlreadyRunning => Some("Auto-approach already running"),
1277 AutoApproachResult::Cancelled => Some("Auto-approach was cancelled"),
1278 AutoApproachResult::Success => None,
1279 }
1280 }
1281}
1282
1283#[derive(Debug, Clone, PartialEq, Eq)]
1285pub enum AutoApproachStatus {
1286 Idle,
1288 Running,
1290 Unknown,
1292}