nanonis_rs/client/oscilloscope/
types.rs1use crate::error::NanonisError;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct OscilloscopeIndex(pub i32);
7
8impl From<OscilloscopeIndex> for i32 {
9 fn from(osci: OscilloscopeIndex) -> Self {
10 osci.0
11 }
12}
13
14impl From<i32> for OscilloscopeIndex {
15 fn from(index: i32) -> Self {
16 OscilloscopeIndex(index)
17 }
18}
19
20impl From<usize> for OscilloscopeIndex {
21 fn from(index: usize) -> Self {
22 OscilloscopeIndex(index as i32)
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum TriggerMode {
28 Immediate = 0,
29 Level = 1,
30 Digital = 2,
31}
32
33impl From<TriggerMode> for u16 {
34 fn from(mode: TriggerMode) -> Self {
35 mode as u16
36 }
37}
38
39impl From<u16> for TriggerMode {
40 fn from(value: u16) -> Self {
41 match value {
42 0 => TriggerMode::Immediate,
43 1 => TriggerMode::Level,
44 2 => TriggerMode::Digital,
45 _ => TriggerMode::Immediate,
46 }
47 }
48}
49
50impl From<i32> for TriggerMode {
51 fn from(value: i32) -> Self {
52 TriggerMode::from(value as u16)
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum TriggerSlope {
58 Falling = 0,
59 Rising = 1,
60}
61
62impl From<TriggerSlope> for u16 {
63 fn from(slope: TriggerSlope) -> Self {
64 slope as u16
65 }
66}
67
68impl TryFrom<u16> for TriggerSlope {
69 type Error = NanonisError;
70
71 fn try_from(value: u16) -> Result<Self, Self::Error> {
72 match value {
73 0 => Ok(TriggerSlope::Falling),
74 1 => Ok(TriggerSlope::Rising),
75 _ => Err(NanonisError::Protocol(format!(
76 "Invalid trigger slope: {}",
77 value
78 ))),
79 }
80 }
81}
82
83#[derive(Debug, Clone, Copy)]
84pub struct TriggerLevel(pub f64);
85
86impl From<TriggerLevel> for f64 {
87 fn from(level: TriggerLevel) -> Self {
88 level.0
89 }
90}
91
92impl From<f64> for TriggerLevel {
93 fn from(level: f64) -> Self {
94 TriggerLevel(level)
95 }
96}
97
98impl From<f32> for TriggerLevel {
99 fn from(level: f32) -> Self {
100 TriggerLevel(level as f64)
101 }
102}
103
104#[derive(Debug, Clone, Copy)]
105pub struct SampleCount(pub i32);
106
107impl SampleCount {
108 pub fn new(count: i32) -> Self {
109 Self(count)
110 }
111}
112
113impl From<SampleCount> for i32 {
114 fn from(samples: SampleCount) -> Self {
115 samples.0
116 }
117}
118
119impl From<i32> for SampleCount {
120 fn from(count: i32) -> Self {
121 SampleCount(count)
122 }
123}
124
125impl From<u32> for SampleCount {
126 fn from(count: u32) -> Self {
127 SampleCount(count as i32)
128 }
129}
130
131impl From<usize> for SampleCount {
132 fn from(count: usize) -> Self {
133 SampleCount(count as i32)
134 }
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138pub enum OsciTriggerMode {
139 Immediate = 0,
140 Level = 1,
141 Auto = 2,
142}
143
144impl From<OsciTriggerMode> for u16 {
145 fn from(mode: OsciTriggerMode) -> Self {
146 mode as u16
147 }
148}
149
150impl TryFrom<u16> for OsciTriggerMode {
151 type Error = NanonisError;
152
153 fn try_from(value: u16) -> Result<Self, Self::Error> {
154 match value {
155 0 => Ok(OsciTriggerMode::Immediate),
156 1 => Ok(OsciTriggerMode::Level),
157 2 => Ok(OsciTriggerMode::Auto),
158 _ => Err(NanonisError::Protocol(format!(
159 "Invalid oscilloscope trigger mode: {}",
160 value
161 ))),
162 }
163 }
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub enum OversamplingIndex {
168 Samples50 = 0,
169 Samples20 = 1,
170 Samples10 = 2,
171 Samples5 = 3,
172 Samples2 = 4,
173 Samples1 = 5,
174}
175
176impl From<OversamplingIndex> for u16 {
177 fn from(index: OversamplingIndex) -> Self {
178 index as u16
179 }
180}
181
182impl TryFrom<u16> for OversamplingIndex {
183 type Error = NanonisError;
184
185 fn try_from(value: u16) -> Result<Self, Self::Error> {
186 match value {
187 0 => Ok(OversamplingIndex::Samples50),
188 1 => Ok(OversamplingIndex::Samples20),
189 2 => Ok(OversamplingIndex::Samples10),
190 3 => Ok(OversamplingIndex::Samples5),
191 4 => Ok(OversamplingIndex::Samples2),
192 5 => Ok(OversamplingIndex::Samples1),
193 _ => Err(NanonisError::Protocol(format!(
194 "Invalid oversampling index: {}",
195 value
196 ))),
197 }
198 }
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub struct TimebaseIndex(pub i32);
203
204impl From<TimebaseIndex> for i32 {
205 fn from(index: TimebaseIndex) -> Self {
206 index.0
207 }
208}
209
210impl From<TimebaseIndex> for u16 {
211 fn from(index: TimebaseIndex) -> Self {
212 index.0 as u16
213 }
214}
215
216impl From<i32> for TimebaseIndex {
217 fn from(value: i32) -> Self {
218 TimebaseIndex(value)
219 }
220}
221
222impl From<u16> for TimebaseIndex {
223 fn from(value: u16) -> Self {
224 TimebaseIndex(value as i32)
225 }
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub enum DataToGet {
230 Current,
231 NextTrigger,
232 Wait2Triggers,
233}
234
235#[derive(Debug, Clone, Copy)]
236pub struct TriggerConfig {
237 pub mode: OsciTriggerMode,
238 pub slope: TriggerSlope,
239 pub level: f64,
240 pub hysteresis: f64,
241}
242
243impl TriggerConfig {
244 pub fn new(mode: OsciTriggerMode, slope: TriggerSlope, level: f64, hysteresis: f64) -> Self {
245 Self {
246 mode,
247 slope,
248 level,
249 hysteresis,
250 }
251 }
252
253 pub fn immediate() -> Self {
254 Self {
255 mode: OsciTriggerMode::Immediate,
256 slope: TriggerSlope::Rising,
257 level: 0.0,
258 hysteresis: 0.0,
259 }
260 }
261
262 pub fn level_trigger(level: f64, slope: TriggerSlope) -> Self {
263 Self {
264 mode: OsciTriggerMode::Level,
265 slope,
266 level,
267 hysteresis: 0.1,
268 }
269 }
270
271 pub fn auto_trigger() -> Self {
272 Self {
273 mode: OsciTriggerMode::Auto,
274 slope: TriggerSlope::Rising,
275 level: 0.0,
276 hysteresis: 0.1,
277 }
278 }
279}
280
281#[derive(Debug, Clone)]
282pub struct SignalStats {
283 pub mean: f64,
284 pub std_dev: f64,
285 pub relative_std: f64,
286 pub window_size: usize,
287 pub stability_method: String,
288}
289
290#[derive(Debug, Clone)]
291pub struct OsciData {
292 pub t0: f64,
293 pub dt: f64,
294 pub size: i32,
295 pub data: Vec<f64>,
296 pub signal_stats: Option<SignalStats>,
297 pub is_stable: bool,
298 pub fallback_value: Option<f64>,
299}
300
301impl OsciData {
302 pub fn new(t0: f64, dt: f64, size: i32, data: Vec<f64>) -> Self {
303 Self {
304 t0,
305 dt,
306 size,
307 data,
308 signal_stats: None,
309 is_stable: true,
310 fallback_value: None,
311 }
312 }
313
314 pub fn new_with_stats(t0: f64, dt: f64, size: i32, data: Vec<f64>, stats: SignalStats) -> Self {
315 Self {
316 t0,
317 dt,
318 size,
319 data,
320 signal_stats: Some(stats),
321 is_stable: true,
322 fallback_value: None,
323 }
324 }
325
326 pub fn new_stable(t0: f64, dt: f64, size: i32, data: Vec<f64>) -> Self {
327 Self {
328 t0,
329 dt,
330 size,
331 data,
332 signal_stats: None,
333 is_stable: true,
334 fallback_value: None,
335 }
336 }
337
338 pub fn new_unstable_with_fallback(
339 t0: f64,
340 dt: f64,
341 size: i32,
342 data: Vec<f64>,
343 fallback: f64,
344 ) -> Self {
345 Self {
346 t0,
347 dt,
348 size,
349 data,
350 signal_stats: None,
351 is_stable: false,
352 fallback_value: Some(fallback),
353 }
354 }
355
356 pub fn values(&self) -> &[f64] {
357 &self.data
358 }
359
360 pub fn time_series(&self) -> Vec<(f64, f64)> {
361 self.data
362 .iter()
363 .enumerate()
364 .map(|(i, &value)| (self.t0 + i as f64 * self.dt, value))
365 .collect()
366 }
367
368 pub fn stats(&self) -> Option<&SignalStats> {
369 self.signal_stats.as_ref()
370 }
371
372 pub fn is_stable(&self) -> bool {
373 self.signal_stats.is_some()
374 }
375
376 pub fn duration(&self) -> f64 {
377 (self.size - 1) as f64 * self.dt
378 }
379
380 pub fn sample_rate(&self) -> f64 {
381 if self.dt > 0.0 {
382 1.0 / self.dt
383 } else {
384 0.0
385 }
386 }
387
388 pub fn time_points(&self) -> Vec<f64> {
389 (0..self.size)
390 .map(|i| self.t0 + i as f64 * self.dt)
391 .collect()
392 }
393}