instrument_core/
session.rs1use crate::address::ResourceAddress;
2use crate::connect::ConnectOptions;
3use crate::diagnostics::Diagnostics;
4use crate::error::{Error, Result};
5use crate::identity::{DeviceIdentity, Idn};
6use crate::ieee4882::Ieee4882;
7use crate::kind::InstrumentKind;
8use crate::scpi::ScpiSession;
9use crate::transport::DynTransport;
10use std::sync::{Arc, Mutex};
11
12pub trait SessionOpener: Send + Sync {
14 fn open(&self, address: &ResourceAddress, opts: &ConnectOptions) -> Result<DynTransport>;
15}
16
17pub struct InstrumentSession {
19 pub address: ResourceAddress,
20 pub scpi: ScpiSession,
21 identity: DeviceIdentity,
22}
23
24impl InstrumentSession {
25 pub fn new(
26 address: ResourceAddress,
27 transport: DynTransport,
28 opts: ConnectOptions,
29 identity: DeviceIdentity,
30 ) -> Result<Self> {
31 Self::new_with_diagnostics(address, transport, opts, identity, None)
32 }
33
34 pub fn new_with_diagnostics(
35 address: ResourceAddress,
36 transport: DynTransport,
37 opts: ConnectOptions,
38 identity: DeviceIdentity,
39 diagnostics: Option<Diagnostics>,
40 ) -> Result<Self> {
41 let mut scpi = ScpiSession::new(transport, opts)?;
42 if let Some(diag) = diagnostics {
43 scpi = scpi.with_diagnostics(diag);
44 }
45 Ok(Self {
46 address,
47 scpi,
48 identity,
49 })
50 }
51
52 pub fn address_str(&self) -> &str {
53 &self.address.raw
54 }
55
56 pub fn identity(&self) -> &DeviceIdentity {
57 &self.identity
58 }
59
60 pub fn scpi(&self) -> &ScpiSession {
61 &self.scpi
62 }
63
64 pub fn scpi_mut(&mut self) -> &mut ScpiSession {
65 &mut self.scpi
66 }
67
68 pub fn idn(&mut self) -> Result<Idn> {
69 self.scpi_comm("idn", |scpi| Ieee4882::new(scpi).idn())
70 }
71
72 fn scpi_comm<T>(
73 &mut self,
74 command: &str,
75 f: impl FnOnce(&mut ScpiSession) -> Result<T>,
76 ) -> Result<T> {
77 match f(&mut self.scpi) {
78 Ok(v) => Ok(v),
79 Err(e) => Err(e.with_comm_context(&self.address.raw, Some(command), 1)),
80 }
81 }
82
83 pub fn reset(&mut self) -> Result<()> {
84 self.scpi_comm("*RST", |scpi| Ieee4882::new(scpi).reset())
85 }
86
87 pub fn clear_status(&mut self) -> Result<()> {
88 self.scpi_comm("*CLS", |scpi| Ieee4882::new(scpi).clear_status())
89 }
90
91 pub fn wait_complete(&mut self) -> Result<()> {
92 self.scpi_comm("*OPC?", |scpi| Ieee4882::new(scpi).wait_complete())
93 }
94
95 pub fn check_errors(&mut self) -> Result<Vec<String>> {
96 self.scpi_comm("SYST:ERR?", |scpi| scpi.check_errors())
97 }
98}
99
100pub struct SessionPool {
102 session: Arc<Mutex<InstrumentSession>>,
103}
104
105impl SessionPool {
106 pub fn new(session: InstrumentSession) -> Self {
107 Self {
108 session: Arc::new(Mutex::new(session)),
109 }
110 }
111
112 pub fn session(&self) -> Arc<Mutex<InstrumentSession>> {
113 self.session.clone()
114 }
115
116 pub fn open_session(&self) -> Result<PooledSession> {
117 Ok(PooledSession {
118 session: self.session.clone(),
119 })
120 }
121}
122
123pub struct PooledSession {
125 session: Arc<Mutex<InstrumentSession>>,
126}
127
128impl PooledSession {
129 pub fn lock(&self) -> std::sync::MutexGuard<'_, InstrumentSession> {
130 self.session.lock().unwrap()
131 }
132}
133
134pub fn ensure_kind_supported(
136 address: &ResourceAddress,
137 kind: InstrumentKind,
138 supported: &[InstrumentKind],
139) -> Result<()> {
140 if supported.contains(&kind) {
141 return Ok(());
142 }
143 Err(Error::UnsupportedKind {
144 address: address.raw.clone(),
145 kind,
146 supported: supported.to_vec(),
147 })
148}