#![deny(warnings, missing_docs)]
use std::{
fmt::Display,
sync::{Arc, Mutex},
};
use instrumentrs::{InstrumentError, InstrumentInterface};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum InterlockStatus {
Ready,
Interlocked,
}
impl Display for InterlockStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InterlockStatus::Ready => write!(f, "Instrument is ready"),
InterlockStatus::Interlocked => write!(
f,
"Instrument is interlocked and not ready to activate any channel."
),
}
}
}
impl From<&str> for InterlockStatus {
fn from(value: &str) -> Self {
match value {
"0" => InterlockStatus::Ready,
_ => InterlockStatus::Interlocked,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum SoftwareControlStatus {
Ready,
LockedOut,
}
impl Display for SoftwareControlStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SoftwareControlStatus::Ready => write!(f, "Software control is possible."),
SoftwareControlStatus::LockedOut => {
write!(f, "Software is locked out from controlling the instrument.")
}
}
}
}
impl From<&str> for SoftwareControlStatus {
fn from(value: &str) -> Self {
match value {
"0" => SoftwareControlStatus::Ready,
_ => SoftwareControlStatus::LockedOut,
}
}
}
pub struct DigOutBox<T: InstrumentInterface> {
interface: Arc<Mutex<T>>,
num_channels: usize,
}
impl<T: InstrumentInterface> DigOutBox<T> {
pub fn new(interface: T) -> Self {
DigOutBox {
interface: Arc::new(Mutex::new(interface)),
num_channels: 16, }
}
pub fn get_channel(&mut self, idx: usize) -> Result<Channel<T>, InstrumentError> {
if idx >= self.num_channels {
return Err(InstrumentError::ChannelIndexOutOfRange {
idx,
nof_channels: self.num_channels,
});
}
Ok(Channel::new(idx, Arc::clone(&self.interface)))
}
pub fn all_off(&mut self) -> Result<(), InstrumentError> {
self.sendcmd("ALLOFF")?;
Ok(())
}
pub fn get_all_outputs(&mut self) -> Result<Vec<bool>, InstrumentError> {
let resp = self.query("ALLDO?")?;
let outputs: Vec<bool> = resp.split(',').map(|s| s.trim() == "1").collect();
Ok(outputs)
}
pub fn get_interlock_status(&mut self) -> Result<InterlockStatus, InstrumentError> {
let resp = self.query("INTERLOCKS?")?;
Ok(InterlockStatus::from(resp.as_ref()))
}
pub fn get_name(&mut self) -> Result<String, InstrumentError> {
Ok(self.query("*IDN?")?.trim().to_string())
}
pub fn set_num_channels(&mut self, num: usize) -> Result<(), InstrumentError> {
if num == 0 {
return Err(InstrumentError::InvalidArgument(
"Number of channels must be greater than 0".to_string(),
));
}
self.num_channels = num;
Ok(())
}
pub fn get_software_control_status(
&mut self,
) -> Result<SoftwareControlStatus, InstrumentError> {
let resp = self.query("SWL?")?;
Ok(SoftwareControlStatus::from(resp.as_ref()))
}
fn sendcmd(&mut self, cmd: &str) -> Result<(), InstrumentError> {
{
self.interface
.lock()
.expect("Mutext should not be poisoned")
.sendcmd(cmd)?;
}
Ok(())
}
fn query(&mut self, cmd: &str) -> Result<String, InstrumentError> {
self.interface
.lock()
.expect("Mutex should not be poisoned")
.query(cmd)
}
}
impl<T: InstrumentInterface> Clone for DigOutBox<T> {
fn clone(&self) -> Self {
Self {
interface: self.interface.clone(),
num_channels: self.num_channels,
}
}
}
pub struct Channel<T: InstrumentInterface> {
idx: usize,
interface: Arc<Mutex<T>>,
}
impl<T: InstrumentInterface> Channel<T> {
pub fn get_output(&mut self) -> Result<bool, InstrumentError> {
let val = self.query("DO")?;
Ok(val == "1")
}
pub fn set_output(&mut self, value: bool) -> Result<(), InstrumentError> {
let value_send = if value { "1" } else { "0" };
self.sendcmd("DO", value_send)
}
fn new(idx: usize, interface: Arc<Mutex<T>>) -> Self {
Channel { idx, interface }
}
fn sendcmd(&mut self, cmd: &str, value: &str) -> Result<(), InstrumentError> {
{
self.interface
.lock()
.expect("Mutex should not be poisoned")
.sendcmd(&format!("{cmd}{0} {value}", self.idx))?;
}
Ok(())
}
fn query(&mut self, cmd: &str) -> Result<String, InstrumentError> {
self.interface
.lock()
.expect("Mutex should not be poisoned")
.query(&format!("{cmd}{0}?", self.idx))
}
}
impl<T: InstrumentInterface> Clone for Channel<T> {
fn clone(&self) -> Self {
Self {
idx: self.idx,
interface: self.interface.clone(),
}
}
}