1use serde::{Deserialize, Serialize};
2
3pub use nanonis_rs::motor::{
5 Amplitude, Frequency, MotorAxis, MotorDirection, MotorDisplacement, MotorGroup,
6 MotorMovement, MovementMode, Position3D, StepCount,
7};
8pub use nanonis_rs::oscilloscope::{
9 OsciData, OsciTriggerMode, OscilloscopeIndex, OversamplingIndex, SampleCount, SignalStats,
10 TimebaseIndex, TriggerConfig, TriggerLevel, TriggerMode, TriggerSlope,
11};
12pub use nanonis_rs::Position;
13pub use nanonis_rs::bias::PulseMode;
14pub use nanonis_rs::scan::{ScanAction, ScanConfig, ScanDirection, ScanFrame};
15pub use nanonis_rs::signals::SignalFrame;
16pub use nanonis_rs::tcplog::{TCPLogStatus, TCPLoggerData};
17pub use nanonis_rs::z_ctrl::ZControllerHold;
18use std::time::{Duration, Instant};
21
22#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
24pub enum TipShape {
25 Blunt,
26 Sharp,
27 Stable,
28}
29
30#[derive(Debug, Clone)]
32pub struct SessionMetadata {
33 pub session_id: String,
34 pub signal_names: Vec<String>, pub active_indices: Vec<usize>, pub primary_signal_index: usize, pub session_start: f64, }
39
40#[derive(Debug, Clone, Copy, PartialEq)]
42pub enum DataToGet {
43 Current,
44 NextTrigger,
45 Wait2Triggers,
46 Stable { readings: u32, timeout: Duration },
47}
48
49#[derive(Debug, Clone)]
51pub struct TimestampedSignalFrame {
52 pub signal_frame: SignalFrame,
54 pub timestamp: Instant,
56 pub relative_time: Duration,
58}
59
60impl TimestampedSignalFrame {
61 pub fn new(signal_frame: SignalFrame, start_time: Instant) -> Self {
64 let timestamp = Instant::now();
65 Self {
66 signal_frame,
67 timestamp,
68 relative_time: timestamp.duration_since(start_time),
69 }
70 }
71}
72
73#[derive(Debug)]
78pub struct ExperimentData {
79 pub action_result: crate::actions::ActionResult,
81 pub signal_frames: Vec<TimestampedSignalFrame>,
83 pub tcp_config: crate::action_driver::TCPReaderConfig,
85 pub action_start: Instant,
87 pub action_end: Instant,
89 pub total_duration: Duration,
91}
92
93#[derive(Debug)]
95pub struct ChainExperimentData {
96 pub action_results: Vec<crate::actions::ActionResult>,
98 pub signal_frames: Vec<TimestampedSignalFrame>,
100 pub tcp_config: crate::action_driver::TCPReaderConfig,
102 pub action_timings: Vec<(Instant, Instant)>,
104 pub chain_start: Instant,
106 pub chain_end: Instant,
108 pub total_duration: Duration,
110}
111
112impl ExperimentData {
113 pub fn data_during_action(&self) -> Vec<&TimestampedSignalFrame> {
115 self.signal_frames
116 .iter()
117 .filter(|frame| {
118 frame.timestamp >= self.action_start && frame.timestamp <= self.action_end
119 })
120 .collect()
121 }
122
123 pub fn data_before_action(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
125 let cutoff = self.action_start - duration;
126 self.signal_frames
127 .iter()
128 .filter(|frame| frame.timestamp >= cutoff && frame.timestamp < self.action_start)
129 .collect()
130 }
131
132 pub fn data_after_action(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
134 let cutoff = self.action_end + duration;
135 self.signal_frames
136 .iter()
137 .filter(|frame| frame.timestamp > self.action_end && frame.timestamp <= cutoff)
138 .collect()
139 }
140
141 pub fn get_tcp_logger_data(&self) -> Vec<TCPLoggerData> {
144 self.signal_frames
145 .iter()
146 .map(|frame| TCPLoggerData {
147 num_channels: self.tcp_config.channels.len() as u32,
148 oversampling: self.tcp_config.oversampling as f32,
149 counter: frame.signal_frame.counter,
150 state: TCPLogStatus::Running,
151 data: frame.signal_frame.data.clone(),
152 })
153 .collect()
154 }
155}
156
157impl ChainExperimentData {
158 pub fn data_during_action(&self, action_index: usize) -> Vec<&TimestampedSignalFrame> {
166 if let Some((start, end)) = self.action_timings.get(action_index) {
167 self.signal_frames
168 .iter()
169 .filter(|frame| frame.timestamp >= *start && frame.timestamp <= *end)
170 .collect()
171 } else {
172 Vec::new()
173 }
174 }
175
176 pub fn data_between_actions(
185 &self,
186 action1_index: usize,
187 action2_index: usize,
188 ) -> Vec<&TimestampedSignalFrame> {
189 if let (Some((_, end1)), Some((start2, _))) = (
190 self.action_timings.get(action1_index),
191 self.action_timings.get(action2_index),
192 ) {
193 self.signal_frames
194 .iter()
195 .filter(|frame| frame.timestamp > *end1 && frame.timestamp < *start2)
196 .collect()
197 } else {
198 Vec::new()
199 }
200 }
201
202 pub fn data_before_chain(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
210 let cutoff = self.chain_start - duration;
211 self.signal_frames
212 .iter()
213 .filter(|frame| frame.timestamp >= cutoff && frame.timestamp < self.chain_start)
214 .collect()
215 }
216
217 pub fn data_after_chain(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
225 let cutoff = self.chain_end + duration;
226 self.signal_frames
227 .iter()
228 .filter(|frame| frame.timestamp > self.chain_end && frame.timestamp <= cutoff)
229 .collect()
230 }
231
232 pub fn data_for_entire_chain(&self) -> Vec<&TimestampedSignalFrame> {
237 self.signal_frames
238 .iter()
239 .filter(|frame| {
240 frame.timestamp >= self.chain_start && frame.timestamp <= self.chain_end
241 })
242 .collect()
243 }
244
245 pub fn action_timing(&self, action_index: usize) -> Option<(Instant, Instant, Duration)> {
253 self.action_timings
254 .get(action_index)
255 .map(|(start, end)| (*start, *end, end.duration_since(*start)))
256 }
257
258 pub fn chain_summary(&self) -> (usize, usize, usize, Duration) {
263 let total_actions = self.action_results.len();
264 let successful_actions = self
265 .action_results
266 .iter()
267 .filter(|result| matches!(result, crate::actions::ActionResult::Success))
268 .count();
269 let total_frames = self.signal_frames.len();
270
271 (
272 total_actions,
273 successful_actions,
274 total_frames,
275 self.total_duration,
276 )
277 }
278}
279
280#[derive(Debug, Clone, PartialEq, Eq)]
282pub enum AutoApproachResult {
283 Success,
285 Timeout,
287 Failed(String),
289 AlreadyRunning,
291 Cancelled,
293}
294
295impl AutoApproachResult {
296 pub fn is_success(&self) -> bool {
298 matches!(self, AutoApproachResult::Success)
299 }
300
301 pub fn is_failure(&self) -> bool {
303 matches!(
304 self,
305 AutoApproachResult::Failed(_) | AutoApproachResult::Timeout
306 )
307 }
308
309 pub fn error_message(&self) -> Option<&str> {
311 match self {
312 AutoApproachResult::Failed(msg) => Some(msg),
313 AutoApproachResult::Timeout => Some("Auto-approach timed out"),
314 AutoApproachResult::AlreadyRunning => Some("Auto-approach already running"),
315 AutoApproachResult::Cancelled => Some("Auto-approach was cancelled"),
316 AutoApproachResult::Success => None,
317 }
318 }
319}
320
321#[derive(Debug, Clone, PartialEq, Eq)]
323pub enum AutoApproachStatus {
324 Idle,
326 Running,
328 Unknown,
330}
331