Skip to main content

instrument/classes/
switch.rs

1use super::dialect_io;
2use instrument_core::error::{Error, Result};
3use instrument_core::kind::InstrumentKind;
4use instrument_core::scpi_commands;
5use instrument_core::InstrumentSession;
6
7/// Switch / matrix session view (IVI-inspired / SCPI :ROUTe).
8///
9/// Path model: routes are matrix channel pairs `(ch1, ch2)`. Use [`Self::path_label`]
10/// for a stable human-readable name; IVI "ClosePath" maps to [`Self::close_route`].
11pub struct Switch {
12    session: InstrumentSession,
13}
14
15impl Switch {
16    pub fn new(session: InstrumentSession) -> Self {
17        Self { session }
18    }
19
20    pub fn session(&self) -> &InstrumentSession {
21        &self.session
22    }
23
24    pub fn session_mut(&mut self) -> &mut InstrumentSession {
25        &mut self.session
26    }
27
28    fn dialect(&self) -> &'static instrument_core::DialectProfile {
29        self.session.dialect_for(InstrumentKind::Switch)
30    }
31
32    fn cmd(&self, key: &str, vars: &[(&str, String)], fallback: String) -> String {
33        dialect_io::try_formatted(self.dialect(), key, vars, fallback)
34    }
35
36    /// Formats a matrix path label for channels `ch1` and `ch2` (1-based).
37    ///
38    /// Equivalent naming to IVI `ClosePath` / `OpenPath` path strings.
39    pub fn path_label(ch1: u32, ch2: u32) -> String {
40        format!("(@({ch1},{ch2}))")
41    }
42
43    /// Closes a route between two channels (1-based). IVI ClosePath equivalent.
44    pub fn close_route(&mut self, ch1: u32, ch2: u32) -> Result<()> {
45        let cmd = self.cmd(
46            "close_route",
47            &[("ch1", ch1.to_string()), ("ch2", ch2.to_string())],
48            scpi_commands::switch_close_route(ch1, ch2),
49        );
50        self.session.scpi_mut().write(&cmd)
51    }
52
53    /// Opens a route between two channels (1-based). IVI OpenPath equivalent.
54    pub fn open_route(&mut self, ch1: u32, ch2: u32) -> Result<()> {
55        let cmd = self.cmd(
56            "open_route",
57            &[("ch1", ch1.to_string()), ("ch2", ch2.to_string())],
58            scpi_commands::switch_open_route(ch1, ch2),
59        );
60        self.session.scpi_mut().write(&cmd)
61    }
62
63    /// Returns whether a route is closed.
64    pub fn is_closed(&mut self, ch1: u32, ch2: u32) -> Result<bool> {
65        let cmd = self.cmd(
66            "is_closed",
67            &[("ch1", ch1.to_string()), ("ch2", ch2.to_string())],
68            scpi_commands::switch_is_closed(ch1, ch2),
69        );
70        let resp = self.session.scpi_mut().query(&cmd)?;
71        parse_closed(&resp)
72    }
73
74    /// Opens all routes.
75    pub fn open_all(&mut self) -> Result<()> {
76        let cmd =
77            dialect_io::try_command(self.dialect(), "open_all", scpi_commands::SWITCH_OPEN_ALL);
78        self.session.scpi_mut().write(cmd)
79    }
80}
81
82pub(crate) fn parse_closed(response: &str) -> Result<bool> {
83    let trimmed = response.trim();
84    match trimmed.to_ascii_uppercase().as_str() {
85        "1" | "ON" | "CLOSED" => Ok(true),
86        "0" | "OFF" | "OPEN" => Ok(false),
87        _ => Err(Error::Parse(format!(
88            "expected route state, got '{response}'"
89        ))),
90    }
91}