1use serde::{Deserialize, Serialize};
2
3pub use nanonis_rs::bias::PulseMode;
5pub use nanonis_rs::motor::{
6 Amplitude, Frequency, MotorAxis, MotorDirection, MotorDisplacement, MotorGroup, MotorMovement,
7 MovementMode, Position3D, StepCount,
8};
9pub use nanonis_rs::oscilloscope::{
10 OsciTriggerMode, OscilloscopeIndex, OversamplingIndex, SampleCount, TimebaseIndex,
11 TriggerConfig, TriggerLevel, TriggerMode, TriggerSlope,
12};
13pub use nanonis_rs::scan::{ScanAction, ScanConfig, ScanDirection, ScanFrame};
14pub use nanonis_rs::signals::SignalFrame;
15pub use nanonis_rs::tcplog::TCPLogStatus;
16pub use nanonis_rs::z_ctrl::ZControllerHold;
17pub use nanonis_rs::Position;
18use std::time::{Duration, Instant};
21
22#[derive(Debug, Clone)]
27pub struct SignalStats {
28 pub mean: f64,
29 pub std_dev: f64,
30 pub relative_std: f64,
31 pub window_size: usize,
32 pub stability_method: String,
33}
34
35#[derive(Debug, Clone)]
39pub struct OsciData {
40 pub t0: f64,
41 pub dt: f64,
42 pub size: i32,
43 pub data: Vec<f64>,
44 pub signal_stats: Option<SignalStats>,
45 pub is_stable: bool,
46 pub fallback_value: Option<f64>,
47}
48
49impl OsciData {
50 pub fn new_stable(t0: f64, dt: f64, size: i32, data: Vec<f64>) -> Self {
52 Self {
53 t0,
54 dt,
55 size,
56 data,
57 signal_stats: None,
58 is_stable: true,
59 fallback_value: None,
60 }
61 }
62
63 pub fn new_with_stats(t0: f64, dt: f64, size: i32, data: Vec<f64>, stats: SignalStats) -> Self {
65 Self {
66 t0,
67 dt,
68 size,
69 data,
70 signal_stats: Some(stats),
71 is_stable: true,
72 fallback_value: None,
73 }
74 }
75
76 pub fn new_unstable_with_fallback(
78 t0: f64,
79 dt: f64,
80 size: i32,
81 data: Vec<f64>,
82 fallback_value: f64,
83 ) -> Self {
84 Self {
85 t0,
86 dt,
87 size,
88 data,
89 signal_stats: None,
90 is_stable: false,
91 fallback_value: Some(fallback_value),
92 }
93 }
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
98pub enum TipShape {
99 #[default]
100 Blunt,
101 Sharp,
102 Stable,
103}
104
105#[derive(Debug, Clone)]
107pub struct SessionMetadata {
108 pub session_id: String,
109 pub signal_names: Vec<String>, pub active_indices: Vec<usize>, pub primary_signal_index: usize, pub session_start: f64, }
114
115#[derive(Debug, Clone, Copy, PartialEq)]
117pub enum DataToGet {
118 Current,
119 NextTrigger,
120 Wait2Triggers,
121 Stable { readings: u32, timeout: Duration },
122}
123
124#[derive(Debug, Clone)]
126pub struct TimestampedSignalFrame {
127 pub signal_frame: SignalFrame,
129 pub timestamp: Instant,
131 pub relative_time: Duration,
133}
134
135impl TimestampedSignalFrame {
136 pub fn new(signal_frame: SignalFrame, start_time: Instant) -> Self {
139 let timestamp = Instant::now();
140 Self {
141 signal_frame,
142 timestamp,
143 relative_time: timestamp.duration_since(start_time),
144 }
145 }
146}
147
148#[derive(Debug)]
153pub struct ExperimentData {
154 pub action_result: crate::actions::ActionResult,
156 pub signal_frames: Vec<TimestampedSignalFrame>,
158 pub tcp_config: crate::action_driver::TCPReaderConfig,
160 pub action_start: Instant,
162 pub action_end: Instant,
164 pub total_duration: Duration,
166}
167
168#[derive(Debug)]
170pub struct ChainExperimentData {
171 pub action_results: Vec<crate::actions::ActionResult>,
173 pub signal_frames: Vec<TimestampedSignalFrame>,
175 pub tcp_config: crate::action_driver::TCPReaderConfig,
177 pub action_timings: Vec<(Instant, Instant)>,
179 pub chain_start: Instant,
181 pub chain_end: Instant,
183 pub total_duration: Duration,
185}
186
187impl ExperimentData {
188 pub fn data_during_action(&self) -> Vec<&TimestampedSignalFrame> {
190 self.signal_frames
191 .iter()
192 .filter(|frame| {
193 frame.timestamp >= self.action_start && frame.timestamp <= self.action_end
194 })
195 .collect()
196 }
197
198 pub fn data_before_action(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
200 let cutoff = self.action_start - duration;
201 self.signal_frames
202 .iter()
203 .filter(|frame| frame.timestamp >= cutoff && frame.timestamp < self.action_start)
204 .collect()
205 }
206
207 pub fn data_after_action(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
209 let cutoff = self.action_end + duration;
210 self.signal_frames
211 .iter()
212 .filter(|frame| frame.timestamp > self.action_end && frame.timestamp <= cutoff)
213 .collect()
214 }
215}
216
217impl ChainExperimentData {
218 pub fn data_during_action(&self, action_index: usize) -> Vec<&TimestampedSignalFrame> {
226 if let Some((start, end)) = self.action_timings.get(action_index) {
227 self.signal_frames
228 .iter()
229 .filter(|frame| frame.timestamp >= *start && frame.timestamp <= *end)
230 .collect()
231 } else {
232 Vec::new()
233 }
234 }
235
236 pub fn data_between_actions(
245 &self,
246 action1_index: usize,
247 action2_index: usize,
248 ) -> Vec<&TimestampedSignalFrame> {
249 if let (Some((_, end1)), Some((start2, _))) = (
250 self.action_timings.get(action1_index),
251 self.action_timings.get(action2_index),
252 ) {
253 self.signal_frames
254 .iter()
255 .filter(|frame| frame.timestamp > *end1 && frame.timestamp < *start2)
256 .collect()
257 } else {
258 Vec::new()
259 }
260 }
261
262 pub fn data_before_chain(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
270 let cutoff = self.chain_start - duration;
271 self.signal_frames
272 .iter()
273 .filter(|frame| frame.timestamp >= cutoff && frame.timestamp < self.chain_start)
274 .collect()
275 }
276
277 pub fn data_after_chain(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
285 let cutoff = self.chain_end + duration;
286 self.signal_frames
287 .iter()
288 .filter(|frame| frame.timestamp > self.chain_end && frame.timestamp <= cutoff)
289 .collect()
290 }
291
292 pub fn data_for_entire_chain(&self) -> Vec<&TimestampedSignalFrame> {
297 self.signal_frames
298 .iter()
299 .filter(|frame| {
300 frame.timestamp >= self.chain_start && frame.timestamp <= self.chain_end
301 })
302 .collect()
303 }
304
305 pub fn action_timing(&self, action_index: usize) -> Option<(Instant, Instant, Duration)> {
313 self.action_timings
314 .get(action_index)
315 .map(|(start, end)| (*start, *end, end.duration_since(*start)))
316 }
317
318 pub fn chain_summary(&self) -> (usize, usize, usize, Duration) {
323 let total_actions = self.action_results.len();
324 let successful_actions = self
325 .action_results
326 .iter()
327 .filter(|result| matches!(result, crate::actions::ActionResult::Success))
328 .count();
329 let total_frames = self.signal_frames.len();
330
331 (
332 total_actions,
333 successful_actions,
334 total_frames,
335 self.total_duration,
336 )
337 }
338}
339
340#[derive(Debug, Clone, PartialEq, Eq)]
342pub enum AutoApproachResult {
343 Success,
345 Timeout,
347 Failed(String),
349 AlreadyRunning,
351 Cancelled,
353}
354
355impl AutoApproachResult {
356 pub fn is_success(&self) -> bool {
358 matches!(self, AutoApproachResult::Success)
359 }
360
361 pub fn is_failure(&self) -> bool {
363 matches!(
364 self,
365 AutoApproachResult::Failed(_) | AutoApproachResult::Timeout
366 )
367 }
368
369 pub fn error_message(&self) -> Option<&str> {
371 match self {
372 AutoApproachResult::Failed(msg) => Some(msg),
373 AutoApproachResult::Timeout => Some("Auto-approach timed out"),
374 AutoApproachResult::AlreadyRunning => Some("Auto-approach already running"),
375 AutoApproachResult::Cancelled => Some("Auto-approach was cancelled"),
376 AutoApproachResult::Success => None,
377 }
378 }
379}
380
381#[derive(Debug, Clone, PartialEq, Eq)]
383pub enum AutoApproachStatus {
384 Idle,
386 Running,
388 Unknown,
390}