Skip to main content

instrument/
device.rs

1use crate::classes::{DcPowerSupply, Dmm, FunctionGenerator};
2use instrument_core::connect::ConnectOptions;
3use instrument_core::diagnostics::{CommsObserver, DeviceHealth, Diagnostics};
4use instrument_core::error::Result;
5use instrument_core::kind::InstrumentKind;
6use instrument_core::session::{
7    ensure_kind_supported, InstrumentSession, SessionOpener, SessionPool,
8};
9use instrument_core::DiscoveredDevice;
10use std::sync::{Arc, Mutex};
11
12/// Handle to a catalog device — cheap to clone, opens sessions on demand.
13#[derive(Clone)]
14pub struct DeviceRef {
15    pub(crate) device: DiscoveredDevice,
16    pub(crate) opener: Arc<dyn SessionOpener>,
17    pub(crate) connect_options: ConnectOptions,
18    pub(crate) health: Arc<Mutex<DeviceHealth>>,
19    pub(crate) observer: Option<Arc<dyn CommsObserver>>,
20}
21
22impl DeviceRef {
23    pub fn discovered(&self) -> &DiscoveredDevice {
24        &self.device
25    }
26
27    pub fn address(&self) -> &instrument_core::ResourceAddress {
28        &self.device.address
29    }
30
31    pub fn supported_kinds(&self) -> &[InstrumentKind] {
32        &self.device.supported_kinds
33    }
34
35    pub fn connect_options(&self) -> &ConnectOptions {
36        &self.connect_options
37    }
38
39    pub fn health(&self) -> DeviceHealth {
40        self.health.lock().unwrap().clone()
41    }
42
43    pub fn with_connect_options(mut self, opts: ConnectOptions) -> Self {
44        self.connect_options = opts;
45        self
46    }
47
48    fn diagnostics(&self) -> Diagnostics {
49        let mut diag = Diagnostics::new(&self.device.address.raw).with_health(self.health.clone());
50        if let Some(observer) = &self.observer {
51            diag = diag.with_observer(observer.clone());
52        }
53        diag
54    }
55
56    /// Opens a new independent session to this device.
57    pub fn open_session(&self) -> Result<InstrumentSession> {
58        let transport = self
59            .opener
60            .open(&self.device.address, &self.connect_options)?;
61        InstrumentSession::new_with_diagnostics(
62            self.device.address.clone(),
63            transport,
64            self.connect_options.clone(),
65            self.device.identity.clone(),
66            Some(self.diagnostics()),
67        )
68    }
69
70    pub fn session_pool(&self) -> Result<SessionPool> {
71        Ok(SessionPool::new(self.open_session()?))
72    }
73
74    pub fn open_dmm(&self) -> Result<Dmm> {
75        ensure_kind_supported(
76            &self.device.address,
77            InstrumentKind::Dmm,
78            &self.device.supported_kinds,
79        )?;
80        Ok(Dmm::new(self.open_session()?))
81    }
82
83    pub fn open_dc_power_supply(&self) -> Result<DcPowerSupply> {
84        ensure_kind_supported(
85            &self.device.address,
86            InstrumentKind::DcPowerSupply,
87            &self.device.supported_kinds,
88        )?;
89        Ok(DcPowerSupply::new(self.open_session()?))
90    }
91
92    pub fn open_function_generator(&self) -> Result<FunctionGenerator> {
93        ensure_kind_supported(
94            &self.device.address,
95            InstrumentKind::FunctionGenerator,
96            &self.device.supported_kinds,
97        )?;
98        Ok(FunctionGenerator::new(self.open_session()?))
99    }
100
101    pub fn open_untyped(&self) -> Result<InstrumentSession> {
102        self.open_session()
103    }
104}