Skip to main content

instrument/
device.rs

1use crate::classes::{
2    Counter, DcPowerSupply, Dmm, FunctionGenerator, Oscilloscope, PowerMeter, SpectrumAnalyzer,
3    Switch,
4};
5use instrument_core::connect::ConnectOptions;
6use instrument_core::diagnostics::{CommsObserver, DeviceHealth, Diagnostics};
7use instrument_core::error::Result;
8use instrument_core::kind::InstrumentKind;
9use instrument_core::session::{
10    ensure_kind_supported, InstrumentSession, SessionOpener, SessionPool,
11};
12use instrument_core::DiscoveredDevice;
13use std::sync::{Arc, Mutex};
14
15/// Handle to a catalog device — cheap to clone, opens sessions on demand.
16#[derive(Clone)]
17pub struct DeviceRef {
18    pub(crate) device: DiscoveredDevice,
19    pub(crate) opener: Arc<dyn SessionOpener>,
20    pub(crate) connect_options: ConnectOptions,
21    pub(crate) health: Arc<Mutex<DeviceHealth>>,
22    pub(crate) observer: Option<Arc<dyn CommsObserver>>,
23}
24
25impl DeviceRef {
26    pub fn discovered(&self) -> &DiscoveredDevice {
27        &self.device
28    }
29
30    pub fn address(&self) -> &instrument_core::ResourceAddress {
31        &self.device.address
32    }
33
34    pub fn supported_kinds(&self) -> &[InstrumentKind] {
35        &self.device.supported_kinds
36    }
37
38    pub fn connect_options(&self) -> &ConnectOptions {
39        &self.connect_options
40    }
41
42    pub fn health(&self) -> DeviceHealth {
43        self.health.lock().unwrap().clone()
44    }
45
46    pub fn with_connect_options(mut self, opts: ConnectOptions) -> Self {
47        self.connect_options = opts;
48        self
49    }
50
51    fn diagnostics(&self) -> Diagnostics {
52        let mut diag = Diagnostics::new(&self.device.address.raw).with_health(self.health.clone());
53        if let Some(observer) = &self.observer {
54            diag = diag.with_observer(observer.clone());
55        }
56        diag
57    }
58
59    /// Opens a new independent session to this device.
60    pub fn open_session(&self) -> Result<InstrumentSession> {
61        let transport = self
62            .opener
63            .open(&self.device.address, &self.connect_options)?;
64        InstrumentSession::new_with_diagnostics(
65            self.device.address.clone(),
66            transport,
67            self.connect_options.clone(),
68            self.device.identity.clone(),
69            Some(self.diagnostics()),
70        )
71    }
72
73    pub fn session_pool(&self) -> Result<SessionPool> {
74        Ok(SessionPool::new(self.open_session()?))
75    }
76
77    pub fn open_dmm(&self) -> Result<Dmm> {
78        ensure_kind_supported(
79            &self.device.address,
80            InstrumentKind::Dmm,
81            &self.device.supported_kinds,
82        )?;
83        Ok(Dmm::new(self.open_session()?))
84    }
85
86    pub fn open_dc_power_supply(&self) -> Result<DcPowerSupply> {
87        ensure_kind_supported(
88            &self.device.address,
89            InstrumentKind::DcPowerSupply,
90            &self.device.supported_kinds,
91        )?;
92        Ok(DcPowerSupply::new(self.open_session()?))
93    }
94
95    pub fn open_function_generator(&self) -> Result<FunctionGenerator> {
96        ensure_kind_supported(
97            &self.device.address,
98            InstrumentKind::FunctionGenerator,
99            &self.device.supported_kinds,
100        )?;
101        Ok(FunctionGenerator::new(self.open_session()?))
102    }
103
104    pub fn open_oscilloscope(&self) -> Result<Oscilloscope> {
105        ensure_kind_supported(
106            &self.device.address,
107            InstrumentKind::Oscilloscope,
108            &self.device.supported_kinds,
109        )?;
110        Ok(Oscilloscope::new(self.open_session()?))
111    }
112
113    pub fn open_switch(&self) -> Result<Switch> {
114        ensure_kind_supported(
115            &self.device.address,
116            InstrumentKind::Switch,
117            &self.device.supported_kinds,
118        )?;
119        Ok(Switch::new(self.open_session()?))
120    }
121
122    pub fn open_counter(&self) -> Result<Counter> {
123        ensure_kind_supported(
124            &self.device.address,
125            InstrumentKind::Counter,
126            &self.device.supported_kinds,
127        )?;
128        Ok(Counter::new(self.open_session()?))
129    }
130
131    pub fn open_power_meter(&self) -> Result<PowerMeter> {
132        ensure_kind_supported(
133            &self.device.address,
134            InstrumentKind::PowerMeter,
135            &self.device.supported_kinds,
136        )?;
137        Ok(PowerMeter::new(self.open_session()?))
138    }
139
140    pub fn open_spectrum_analyzer(&self) -> Result<SpectrumAnalyzer> {
141        ensure_kind_supported(
142            &self.device.address,
143            InstrumentKind::SpectrumAnalyzer,
144            &self.device.supported_kinds,
145        )?;
146        Ok(SpectrumAnalyzer::new(self.open_session()?))
147    }
148
149    pub fn open_untyped(&self) -> Result<InstrumentSession> {
150        self.open_session()
151    }
152}