Async I/O (Rust)¶
Enable the tokio feature for a full async API that mirrors the sync stack: AsyncScpiSession, AsyncDiscovery, AsyncDeviceCatalog, and typed classes (AsyncDmm, AsyncDcPowerSupply, AsyncFunctionGenerator, AsyncOscilloscope, AsyncSwitch, AsyncCounter).
Sync remains the default. Async is additive behind tokio.
Enable¶
[dependencies]
instrument-components = { version = "0.1", features = ["visa", "tokio"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
The published crates.io 0.1.0 tag does not include this async API. Use git/latest until 0.2.0.
Feature chain:
instrument-components/tokio
→ instrument-core/async
instrument-components/visa + tokio
→ instrument-visa/tokio → visa-rs/tokio
Default (features = ["visa"] only) does not pull in tokio.
Mock quick start (no VISA)¶
use instrument::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
let fixture = ScriptedFixture::builder()
.idn("Acme", "DMM1", "SN1", "1.0")
.kinds([InstrumentKind::Dmm])
.on_query(":MEAS:VOLT:DC?", "1.0")
.build();
let catalog = AsyncDeviceCatalog::from_fixture("mock://dmm", fixture).await?;
let mut dmm = catalog.open_dmm("mock://dmm").await?;
let volts = dmm.measure_voltage_dc(None).await?;
println!("{volts} V");
Ok(())
}
cargo run -p instrument-components --example mock_fixture_ci_async --features tokio --no-default-features
Hardware quick start¶
VISA session open is sync (visa-rs limitation); read/write after open are async.
use instrument::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
let catalog = AsyncDiscovery::visa()?.scan().await?;
let mut dmm = catalog
.open_dmm(&catalog.devices_by_kind(InstrumentKind::Dmm)[0].address.raw)
.await?;
let volts = dmm.measure_voltage_dc(None).await?;
println!("{volts} V");
Ok(())
}
Async type map¶
| Sync | Async |
|---|---|
Transport |
AsyncTransport |
ScpiSession |
AsyncScpiSession |
InstrumentSession |
AsyncInstrumentSession |
Discovery::scan() |
AsyncDiscovery::scan().await |
DeviceCatalog |
AsyncDeviceCatalog |
DeviceRef |
AsyncDeviceRef |
Dmm |
AsyncDmm |
DcPowerSupply |
AsyncDcPowerSupply |
FunctionGenerator |
AsyncFunctionGenerator |
Oscilloscope |
AsyncOscilloscope |
Switch |
AsyncSwitch |
Counter |
AsyncCounter |
VisaTransport |
VisaAsyncTransport |
VisaSessionOpener |
VisaAsyncSessionOpener |
Low-level adapter¶
InstrumentTokioAdapter from visa-rs is still re-exported for raw byte I/O without SCPI framing:
use instrument::prelude::*;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
async fn raw_idn(adapter: &mut InstrumentTokioAdapter) -> std::io::Result<()> {
adapter.write_all(b"*IDN?\n").await?;
let mut buf = vec![0u8; 256];
let n = adapter.read(&mut buf).await?;
println!("{}", String::from_utf8_lossy(&buf[..n]));
Ok(())
}
Prefer AsyncScpiSession / typed classes for framing, retries, and diagnostics.