use serde::{Deserialize, Serialize};
pub use nanonis_rs::motor::{
Amplitude, Frequency, MotorAxis, MotorDirection, MotorDisplacement, MotorGroup,
MotorMovement, MovementMode, Position3D, StepCount,
};
pub use nanonis_rs::oscilloscope::{
OsciData, OsciTriggerMode, OscilloscopeIndex, OversamplingIndex, SampleCount, SignalStats,
TimebaseIndex, TriggerConfig, TriggerLevel, TriggerMode, TriggerSlope,
};
pub use nanonis_rs::Position;
pub use nanonis_rs::bias::PulseMode;
pub use nanonis_rs::scan::{ScanAction, ScanConfig, ScanDirection, ScanFrame};
pub use nanonis_rs::signals::SignalFrame;
pub use nanonis_rs::tcplog::{TCPLogStatus, TCPLoggerData};
pub use nanonis_rs::z_ctrl::ZControllerHold;
use std::time::{Duration, Instant};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum TipShape {
Blunt,
Sharp,
Stable,
}
#[derive(Debug, Clone)]
pub struct SessionMetadata {
pub session_id: String,
pub signal_names: Vec<String>, pub active_indices: Vec<usize>, pub primary_signal_index: usize, pub session_start: f64, }
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DataToGet {
Current,
NextTrigger,
Wait2Triggers,
Stable { readings: u32, timeout: Duration },
}
#[derive(Debug, Clone)]
pub struct TimestampedSignalFrame {
pub signal_frame: SignalFrame,
pub timestamp: Instant,
pub relative_time: Duration,
}
impl TimestampedSignalFrame {
pub fn new(signal_frame: SignalFrame, start_time: Instant) -> Self {
let timestamp = Instant::now();
Self {
signal_frame,
timestamp,
relative_time: timestamp.duration_since(start_time),
}
}
}
#[derive(Debug)]
pub struct ExperimentData {
pub action_result: crate::actions::ActionResult,
pub signal_frames: Vec<TimestampedSignalFrame>,
pub tcp_config: crate::action_driver::TCPReaderConfig,
pub action_start: Instant,
pub action_end: Instant,
pub total_duration: Duration,
}
#[derive(Debug)]
pub struct ChainExperimentData {
pub action_results: Vec<crate::actions::ActionResult>,
pub signal_frames: Vec<TimestampedSignalFrame>,
pub tcp_config: crate::action_driver::TCPReaderConfig,
pub action_timings: Vec<(Instant, Instant)>,
pub chain_start: Instant,
pub chain_end: Instant,
pub total_duration: Duration,
}
impl ExperimentData {
pub fn data_during_action(&self) -> Vec<&TimestampedSignalFrame> {
self.signal_frames
.iter()
.filter(|frame| {
frame.timestamp >= self.action_start && frame.timestamp <= self.action_end
})
.collect()
}
pub fn data_before_action(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
let cutoff = self.action_start - duration;
self.signal_frames
.iter()
.filter(|frame| frame.timestamp >= cutoff && frame.timestamp < self.action_start)
.collect()
}
pub fn data_after_action(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
let cutoff = self.action_end + duration;
self.signal_frames
.iter()
.filter(|frame| frame.timestamp > self.action_end && frame.timestamp <= cutoff)
.collect()
}
pub fn get_tcp_logger_data(&self) -> Vec<TCPLoggerData> {
self.signal_frames
.iter()
.map(|frame| TCPLoggerData {
num_channels: self.tcp_config.channels.len() as u32,
oversampling: self.tcp_config.oversampling as f32,
counter: frame.signal_frame.counter,
state: TCPLogStatus::Running,
data: frame.signal_frame.data.clone(),
})
.collect()
}
}
impl ChainExperimentData {
pub fn data_during_action(&self, action_index: usize) -> Vec<&TimestampedSignalFrame> {
if let Some((start, end)) = self.action_timings.get(action_index) {
self.signal_frames
.iter()
.filter(|frame| frame.timestamp >= *start && frame.timestamp <= *end)
.collect()
} else {
Vec::new()
}
}
pub fn data_between_actions(
&self,
action1_index: usize,
action2_index: usize,
) -> Vec<&TimestampedSignalFrame> {
if let (Some((_, end1)), Some((start2, _))) = (
self.action_timings.get(action1_index),
self.action_timings.get(action2_index),
) {
self.signal_frames
.iter()
.filter(|frame| frame.timestamp > *end1 && frame.timestamp < *start2)
.collect()
} else {
Vec::new()
}
}
pub fn data_before_chain(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
let cutoff = self.chain_start - duration;
self.signal_frames
.iter()
.filter(|frame| frame.timestamp >= cutoff && frame.timestamp < self.chain_start)
.collect()
}
pub fn data_after_chain(&self, duration: Duration) -> Vec<&TimestampedSignalFrame> {
let cutoff = self.chain_end + duration;
self.signal_frames
.iter()
.filter(|frame| frame.timestamp > self.chain_end && frame.timestamp <= cutoff)
.collect()
}
pub fn data_for_entire_chain(&self) -> Vec<&TimestampedSignalFrame> {
self.signal_frames
.iter()
.filter(|frame| {
frame.timestamp >= self.chain_start && frame.timestamp <= self.chain_end
})
.collect()
}
pub fn action_timing(&self, action_index: usize) -> Option<(Instant, Instant, Duration)> {
self.action_timings
.get(action_index)
.map(|(start, end)| (*start, *end, end.duration_since(*start)))
}
pub fn chain_summary(&self) -> (usize, usize, usize, Duration) {
let total_actions = self.action_results.len();
let successful_actions = self
.action_results
.iter()
.filter(|result| matches!(result, crate::actions::ActionResult::Success))
.count();
let total_frames = self.signal_frames.len();
(
total_actions,
successful_actions,
total_frames,
self.total_duration,
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AutoApproachResult {
Success,
Timeout,
Failed(String),
AlreadyRunning,
Cancelled,
}
impl AutoApproachResult {
pub fn is_success(&self) -> bool {
matches!(self, AutoApproachResult::Success)
}
pub fn is_failure(&self) -> bool {
matches!(
self,
AutoApproachResult::Failed(_) | AutoApproachResult::Timeout
)
}
pub fn error_message(&self) -> Option<&str> {
match self {
AutoApproachResult::Failed(msg) => Some(msg),
AutoApproachResult::Timeout => Some("Auto-approach timed out"),
AutoApproachResult::AlreadyRunning => Some("Auto-approach already running"),
AutoApproachResult::Cancelled => Some("Auto-approach was cancelled"),
AutoApproachResult::Success => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AutoApproachStatus {
Idle,
Running,
Unknown,
}