use crate::scpi::ScpiSession;
use std::time::Duration;
pub const PROBE_TIMEOUT: Duration = Duration::from_millis(800);
pub const DMM_READONLY_COMMANDS: &[&str] = &[":SENS:FUNC?", "SENS:FUNC?", ":FUNC?", "FUNC?"];
pub const PSU_READONLY_COMMANDS: &[&str] = &[":OUTP? 1", "OUTP? 1"];
pub const FGEN_READONLY_COMMANDS: &[&str] = &[":SOUR:FUNC?", "SOUR:FUNC?"];
pub const SCOPE_READONLY_COMMANDS: &[&str] = &[
":TIMebase:SCALe?",
"TIMebase:SCALe?",
":CHAN1:SCALe?",
"CHAN1:SCALe?",
":WAVeform:SOURce?",
"WAVeform:SOURce?",
];
pub const SWITCH_READONLY_COMMANDS: &[&str] =
&[":ROUTe:CLOS?", "ROUT:CLOS?", ":ROUTe:CAT?", "ROUT:CAT?"];
pub const COUNTER_READONLY_COMMANDS: &[&str] = &[
":COUNter:DATA?",
"COUN:DATA?",
":COUNter:A:DATA?",
"COUN:A:DATA?",
];
pub const PWRMETER_READONLY_COMMANDS: &[&str] = &[
":UNIT:POW?",
"UNIT:POW?",
":SENS:POW:RANG:AUTO?",
"SENS:POW:RANG:AUTO?",
];
pub const SPECAN_READONLY_COMMANDS: &[&str] = &[
":FREQ:CENT?",
"FREQ:CENT?",
":FREQ:SPAN?",
"FREQ:SPAN?",
":BAND?",
"BAND?",
];
pub const DMM_ACQUISITION_COMMANDS: &[&str] = &[":MEAS:VOLT:DC?", "MEAS:VOLT:DC?"];
pub fn valid_probe_reply(command: &str, response: &str) -> bool {
let cmd = command.trim_start_matches(':').to_ascii_uppercase();
let reply = response.trim().trim_matches('"').to_ascii_uppercase();
if reply.is_empty() || crate::scpi::is_syst_err_supported_reply(&reply) {
return false;
}
if cmd.contains("FUNC") {
return if cmd.starts_with("SOUR") {
["SIN", "SQU", "RAMP", "PULS", "NOIS", "DC", "ARB", "USER"].contains(&reply.as_str())
} else {
[
"VOLT", "VOLT:DC", "VOLT:AC", "CURR", "CURR:DC", "CURR:AC", "RES", "FRES", "FREQ",
"PER", "CONT", "DIOD", "TEMP", "CAP",
]
.contains(&reply.as_str())
};
}
if cmd.starts_with("OUTP") || cmd.contains("AUTO?") {
return ["0", "1", "OFF", "ON"].contains(&reply.as_str());
}
if cmd.starts_with("UNIT") {
return ["DBM", "W", "WATT"].contains(&reply.as_str());
}
if cmd.starts_with("WAV") {
return reply
.strip_prefix("CHAN")
.and_then(|s| s.parse::<u32>().ok())
.is_some_and(|n| n > 0);
}
if cmd.starts_with("ROUT") {
return ["0", "1"].contains(&reply.as_str())
|| reply
.strip_prefix("(@")
.and_then(|s| s.strip_suffix(')'))
.is_some_and(|s| {
s.chars()
.all(|c| c.is_ascii_digit() || [',', ':', ' '].contains(&c))
});
}
let signed_voltage = matches!(cmd.as_str(), "MEAS:VOLT:DC?" | "VOLT? (@1)");
reply
.parse::<f64>()
.is_ok_and(|n| n.is_finite() && (signed_voltage || n >= 0.0))
}
pub fn probe_any(session: &mut ScpiSession, commands: &[&str], timeout: Duration) -> bool {
commands.iter().any(|cmd| {
session
.query_with_timeout(cmd, timeout)
.is_ok_and(|reply| valid_probe_reply(cmd, &reply))
}) && (commands != PSU_READONLY_COMMANDS
|| session
.query_with_timeout(":VOLT? (@1)", timeout)
.is_ok_and(|reply| valid_probe_reply(":VOLT? (@1)", &reply)))
}