use crate::error::NanonisError;
use crate::types::Position;
#[derive(Debug, Clone, Copy)]
pub struct ScanFrame {
pub center: Position,
pub width_m: f32,
pub height_m: f32,
pub angle_deg: f32,
}
impl ScanFrame {
pub fn new(center: Position, width_m: f32, height_m: f32, angle_deg: f32) -> Self {
Self {
center,
width_m,
height_m,
angle_deg,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScanAction {
Start = 0,
Stop = 1,
Pause = 2,
Resume = 3,
Freeze = 4,
Unfreeze = 5,
GoToCenter = 6,
}
impl From<ScanAction> for u16 {
fn from(action: ScanAction) -> Self {
action as u16
}
}
impl TryFrom<u16> for ScanAction {
type Error = NanonisError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
0 => Ok(ScanAction::Start),
1 => Ok(ScanAction::Stop),
2 => Ok(ScanAction::Pause),
3 => Ok(ScanAction::Resume),
4 => Ok(ScanAction::Freeze),
5 => Ok(ScanAction::Unfreeze),
6 => Ok(ScanAction::GoToCenter),
_ => Err(NanonisError::Protocol(format!(
"Invalid scan action: {}",
value
))),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScanDirection {
Down = 0,
Up = 1,
}
impl From<ScanDirection> for u32 {
fn from(direction: ScanDirection) -> Self {
direction as u32
}
}
impl TryFrom<u32> for ScanDirection {
type Error = NanonisError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(ScanDirection::Down),
1 => Ok(ScanDirection::Up),
_ => Err(NanonisError::Protocol(format!(
"Invalid scan direction: {}",
value
))),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ScanConfig {
pub forward_linear_speed_m_s: f32,
pub backward_linear_speed_m_s: f32,
pub forward_time_per_line_s: f32,
pub backward_time_per_line_s: f32,
pub keep_parameter_constant: u16,
pub speed_ratio: f32,
}
#[derive(Debug, Clone)]
pub struct ScanProps {
pub continuous_scan: bool,
pub bouncy_scan: bool,
pub autosave: AutosaveMode,
pub series_name: String,
pub comment: String,
pub modules_names: Vec<String>,
pub num_params_per_module: Vec<i32>,
pub parameters: Vec<Vec<String>>,
pub autopaste: AutopasteMode,
}
impl ScanProps {
pub fn to_builder(&self) -> ScanPropsBuilder {
ScanPropsBuilder {
continuous_scan: None,
bouncy_scan: None,
autosave: None,
series_name: None,
comment: None,
modules_names: None,
autopaste: None,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ScanPropsBuilder {
pub continuous_scan: Option<bool>,
pub bouncy_scan: Option<bool>,
pub autosave: Option<AutosaveMode>,
pub series_name: Option<String>,
pub comment: Option<String>,
pub modules_names: Option<Vec<String>>,
pub autopaste: Option<AutopasteMode>,
}
impl ScanPropsBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn continuous_scan(mut self, value: bool) -> Self {
self.continuous_scan = Some(value);
self
}
pub fn bouncy_scan(mut self, value: bool) -> Self {
self.bouncy_scan = Some(value);
self
}
pub fn autosave(mut self, mode: AutosaveMode) -> Self {
self.autosave = Some(mode);
self
}
pub fn series_name(mut self, name: impl Into<String>) -> Self {
self.series_name = Some(name.into());
self
}
pub fn comment(mut self, comment: impl Into<String>) -> Self {
self.comment = Some(comment.into());
self
}
pub fn modules_names(mut self, names: Vec<String>) -> Self {
self.modules_names = Some(names);
self
}
pub fn autopaste(mut self, mode: AutopasteMode) -> Self {
self.autopaste = Some(mode);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AutosaveMode {
All,
Next,
Off,
}
impl From<AutosaveMode> for u32 {
fn from(mode: AutosaveMode) -> Self {
match mode {
AutosaveMode::All => 1,
AutosaveMode::Next => 2,
AutosaveMode::Off => 3,
}
}
}
impl TryFrom<u32> for AutosaveMode {
type Error = NanonisError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(AutosaveMode::All),
1 => Ok(AutosaveMode::Next),
2 => Ok(AutosaveMode::Off),
_ => Err(NanonisError::Protocol(format!(
"Invalid autosave mode: {}",
value
))),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AutopasteMode {
All,
Next,
Off,
}
impl From<AutopasteMode> for u32 {
fn from(mode: AutopasteMode) -> Self {
match mode {
AutopasteMode::All => 1,
AutopasteMode::Next => 2,
AutopasteMode::Off => 3,
}
}
}
impl TryFrom<u32> for AutopasteMode {
type Error = NanonisError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(AutopasteMode::All),
1 => Ok(AutopasteMode::Next),
2 => Ok(AutopasteMode::Off),
_ => Err(NanonisError::Protocol(format!(
"Invalid autopaste mode: {}",
value
))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scan_action_roundtrip() {
for (action, val) in [
(ScanAction::Start, 0),
(ScanAction::Stop, 1),
(ScanAction::Pause, 2),
(ScanAction::Resume, 3),
(ScanAction::Freeze, 4),
(ScanAction::Unfreeze, 5),
(ScanAction::GoToCenter, 6),
] {
assert_eq!(u16::from(action), val);
assert_eq!(ScanAction::try_from(val).unwrap(), action);
}
assert!(ScanAction::try_from(7u16).is_err());
}
#[test]
fn scan_direction_roundtrip() {
assert_eq!(u32::from(ScanDirection::Down), 0);
assert_eq!(u32::from(ScanDirection::Up), 1);
assert_eq!(ScanDirection::try_from(0u32).unwrap(), ScanDirection::Down);
assert_eq!(ScanDirection::try_from(1u32).unwrap(), ScanDirection::Up);
assert!(ScanDirection::try_from(2u32).is_err());
}
#[test]
fn autosave_get_decoding() {
assert_eq!(AutosaveMode::try_from(0u32).unwrap(), AutosaveMode::All);
assert_eq!(AutosaveMode::try_from(1u32).unwrap(), AutosaveMode::Next);
assert_eq!(AutosaveMode::try_from(2u32).unwrap(), AutosaveMode::Off);
assert!(AutosaveMode::try_from(3u32).is_err());
}
#[test]
fn autosave_set_encoding() {
assert_eq!(u32::from(AutosaveMode::All), 1);
assert_eq!(u32::from(AutosaveMode::Next), 2);
assert_eq!(u32::from(AutosaveMode::Off), 3);
}
#[test]
fn autosave_get_set_offset() {
for get_val in 0..3u32 {
let mode = AutosaveMode::try_from(get_val).unwrap();
let set_val = u32::from(mode);
assert_eq!(set_val, get_val + 1);
}
}
#[test]
fn autopaste_get_set_offset() {
for get_val in 0..3u32 {
let mode = AutopasteMode::try_from(get_val).unwrap();
assert_eq!(u32::from(mode), get_val + 1);
}
assert!(AutopasteMode::try_from(3u32).is_err());
}
#[test]
fn scan_props_builder_defaults_none() {
let b = ScanPropsBuilder::new();
assert!(b.continuous_scan.is_none());
assert!(b.autosave.is_none());
assert!(b.series_name.is_none());
}
#[test]
fn scan_props_builder_chain() {
let b = ScanPropsBuilder::new()
.continuous_scan(true)
.autosave(AutosaveMode::Off)
.series_name("test");
assert_eq!(b.continuous_scan, Some(true));
assert_eq!(b.autosave, Some(AutosaveMode::Off));
assert_eq!(b.series_name.unwrap(), "test");
}
}