223 lines
6.9 KiB
Rust
223 lines
6.9 KiB
Rust
use std::{ops::Index, path::PathBuf};
|
|
|
|
use super::api::StreamApiDescr;
|
|
use super::datatype::DataType;
|
|
use super::deviceinfo::DeviceInfo;
|
|
use super::qty::Qty;
|
|
use crate::config::*;
|
|
use anyhow::Result;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// DAQ Configuration for a single channel
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
pub struct DaqChannel {
|
|
/// Whether the channel is enabled
|
|
pub enabled: bool,
|
|
/// Readable name for channel
|
|
pub name: String,
|
|
/// To convert to physical units. Divide values by this to obtain it.
|
|
pub sensitivity: Flt,
|
|
/// Enabled constant current power supply for sensor (if device supports it)
|
|
pub IEPEEnabled: bool,
|
|
/// Enabled hardware AC coupling (if)
|
|
pub ACCouplingMode: bool,
|
|
/// If supporting multiple input ranges: select the right index
|
|
pub rangeIndex: usize,
|
|
/// Physical quantity
|
|
pub qty: Qty,
|
|
}
|
|
impl Default for DaqChannel {
|
|
fn default() -> Self {
|
|
DaqChannel {
|
|
enabled: false,
|
|
name: "".into(),
|
|
sensitivity: -1.0,
|
|
IEPEEnabled: false,
|
|
ACCouplingMode: false,
|
|
rangeIndex: 0,
|
|
qty: Qty::Number,
|
|
}
|
|
}
|
|
}
|
|
impl DaqChannel {
|
|
/// Default channel configuration for audio input from a certain channel
|
|
pub fn defaultAudio(name: String) -> Self {
|
|
DaqChannel {
|
|
enabled: true,
|
|
name,
|
|
sensitivity: 1.0,
|
|
IEPEEnabled: false,
|
|
ACCouplingMode: false,
|
|
rangeIndex: 0,
|
|
qty: Qty::Number,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Configuration of a device.
|
|
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
|
pub struct DaqConfig {
|
|
/// The API
|
|
pub api: StreamApiDescr,
|
|
|
|
/// Device name. Should match when starting a stream
|
|
pub device_name: String,
|
|
|
|
/// Configuration of the input channels
|
|
pub inchannel_config: Vec<DaqChannel>,
|
|
|
|
/// Configuration of the output channels
|
|
pub outchannel_config: Vec<DaqChannel>,
|
|
/// The data type to use
|
|
pub dtype: DataType,
|
|
|
|
/// Whether to apply a digital high pass on the input. <= 0 means disabled. > 0 means, the value specifies the cut-on frequency for the first order high pass filter.
|
|
pub digitalHighPassCutOn: Flt,
|
|
|
|
/// The index to use in the list of possible sample rates
|
|
sampleRateIndex: usize,
|
|
|
|
/// The index to use in the list of possible frames per block
|
|
framesPerBlockIndex: usize,
|
|
|
|
/// Used when output channels should be monitored, i.e. reverse-looped back as input channels.
|
|
monitorOutput: bool,
|
|
}
|
|
|
|
impl DaqConfig {
|
|
/// Creates a new default device configuration for a given device as specified with
|
|
/// the DeviceInfo descriptor.
|
|
pub fn newFromDeviceInfo(devinfo: &DeviceInfo) -> DaqConfig {
|
|
let inchannel_config = (0..devinfo.iChannelCount)
|
|
.map(|_| DaqChannel::default())
|
|
.collect();
|
|
let outchannel_config = (0..devinfo.oChannelCount)
|
|
.map(|_| DaqChannel::default())
|
|
.collect();
|
|
|
|
let sampleRateIndex = devinfo
|
|
.avSampleRates
|
|
.iter()
|
|
.position(|x| x == &devinfo.prefSampleRate)
|
|
.unwrap_or(devinfo.avSampleRates.len() - 1);
|
|
// Choose 4096 when in list, otherwise choose the highes available value in list
|
|
let framesPerBlockIndex = devinfo
|
|
.avFramesPerBlock
|
|
.iter()
|
|
.position(|x| x == &4096)
|
|
.unwrap_or(devinfo.avFramesPerBlock.len() - 1);
|
|
|
|
DaqConfig {
|
|
api: devinfo.api.clone(),
|
|
device_name: devinfo.device_name.clone(),
|
|
inchannel_config,
|
|
outchannel_config,
|
|
dtype: devinfo.prefDataType,
|
|
digitalHighPassCutOn: -1.0,
|
|
sampleRateIndex,
|
|
framesPerBlockIndex,
|
|
monitorOutput: false,
|
|
}
|
|
}
|
|
|
|
/// Serialize DaqConfig object to TOML.
|
|
///
|
|
/// Args
|
|
///
|
|
/// * writer: Output writer, can be file or string, or anything that *is* std::io::Write
|
|
///
|
|
pub fn serialize_TOML(&self, writer: &mut dyn std::io::Write) -> Result<()> {
|
|
let ser_str = toml::to_string(&self)?;
|
|
writer.write_all(ser_str.as_bytes())?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Deserialize structure from TOML data
|
|
///
|
|
/// # Args
|
|
///
|
|
/// * reader: implements the Read trait, from which we read the data.
|
|
pub fn deserialize_TOML<T>(reader: &mut T) -> Result<DaqConfig>
|
|
where
|
|
T: std::io::Read,
|
|
{
|
|
let mut read_str = vec![];
|
|
reader.read_to_end(&mut read_str)?;
|
|
let read_str = String::from_utf8(read_str)?;
|
|
DaqConfig::deserialize_TOML_str(&read_str)
|
|
}
|
|
|
|
/// Deserialize from TOML string
|
|
///
|
|
/// # Args
|
|
///
|
|
/// * st: string containing TOML data.
|
|
pub fn deserialize_TOML_str(st: &String) -> Result<DaqConfig> {
|
|
let res: DaqConfig = toml::from_str(st)?;
|
|
Ok(res)
|
|
}
|
|
|
|
/// Write this configuration to a TOML file.
|
|
///
|
|
/// Args
|
|
///
|
|
/// * file: Name of file to write to
|
|
///
|
|
pub fn serialize_TOML_file(&self, file: &PathBuf) -> Result<()> {
|
|
let mut file = std::fs::File::create(file)?;
|
|
self.serialize_TOML(&mut file)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Returns a list of enabled input channel numbers as indices
|
|
/// in the list of all input channels (enabled and not)
|
|
pub fn enabledInchannelsList(&self) -> Vec<usize> {
|
|
self.inchannel_config
|
|
.iter()
|
|
.enumerate()
|
|
.filter(|(_, ch)| ch.enabled)
|
|
.map(|(i, _)| i)
|
|
.collect()
|
|
}
|
|
|
|
/// Returns the total number of channels that appear in a running input stream.
|
|
pub fn numberEnabledInChannels(&self) -> usize {
|
|
self.inchannel_config.iter().filter(|ch| ch.enabled).count()
|
|
}
|
|
/// Returns the total number of channels that appear in a running output stream.
|
|
pub fn numberEnabledOutChannels(&self) -> usize {
|
|
self.outchannel_config
|
|
.iter()
|
|
.filter(|ch| ch.enabled)
|
|
.count()
|
|
}
|
|
|
|
/// Provide samplerate, based on device and specified sample rate index
|
|
pub fn sampleRate(&self, dev: &DeviceInfo) -> Flt {
|
|
dev.avSampleRates[self.sampleRateIndex]
|
|
}
|
|
|
|
/// Provide samplerate, based on device and specified sample rate index
|
|
pub fn framesPerBlock(&self, dev: &DeviceInfo) -> usize {
|
|
dev.avFramesPerBlock[self.framesPerBlockIndex]
|
|
}
|
|
|
|
/// Returns vec of channel configuration for enabled input channels only
|
|
pub fn enabledInchannelConfig(&self) -> Vec<DaqChannel> {
|
|
self.inchannel_config
|
|
.iter()
|
|
.filter(|ch| ch.enabled)
|
|
.cloned()
|
|
.collect()
|
|
}
|
|
/// Returns vec of channel configuration for enabled output channels only
|
|
pub fn enabledOutchannelConfig(&self) -> Vec<DaqChannel> {
|
|
self.outchannel_config
|
|
.iter()
|
|
.filter(|ch| ch.enabled)
|
|
.cloned()
|
|
.collect()
|
|
}
|
|
}
|