lasp/cpp_src/device/lasp_daqconfig.h

372 lines
9.8 KiB
C++

#pragma once
#include "lasp_config.h"
#include "lasp_types.h"
#include <map>
#include <vector>
/** \addtogroup device
* @{
*/
using std::string;
using std::to_string;
using boolvec = std::vector<bool>;
using dvec = std::vector<double>;
using usvec = std::vector<us>;
/**
* @brief Descriptor for data types containing more detailed information.
*/
class DataTypeDescriptor {
public:
/**
* @brief Basic data types coming from a DAQ that we can deal with. The naming
* will be self-explainging.
*/
enum class DataType {
dtype_fl32 = 0,
dtype_fl64 = 1,
dtype_int8 = 2,
dtype_int16 = 3,
dtype_int32 = 4
};
/**
* @brief Name of the datatype
*/
string name;
/**
* @brief Sample width of a single sample, in bytes
*/
unsigned sw;
/**
* @brief Whether the datatype is a floating point Y/N
*/
bool is_floating;
/**
* @brief The number from the enumeration
*/
DataType dtype;
/**
* @brief Down-cast a DataTypeDescriptor to a datatype
*
* @return The descriptor as an enum
*/
operator DataType() { return dtype; }
/**
* @brief Compare two data type descriptors. Returns true if the DataType
* enumerator is the same.
*
* @param o
*
* @return
*/
bool operator==(const DataTypeDescriptor &o) noexcept {
return dtype == o.dtype;
}
};
const DataTypeDescriptor dtype_desc_fl32 = {
.name = "32-bits floating point",
.sw = 4,
.is_floating = true,
.dtype = DataTypeDescriptor::DataType::dtype_fl32};
const DataTypeDescriptor dtype_desc_fl64 = {
.name = "64-bits floating point",
.sw = 8,
.is_floating = true,
.dtype = DataTypeDescriptor::DataType::dtype_fl64};
const DataTypeDescriptor dtype_desc_int8 = {
.name = "8-bits integer",
.sw = 1,
.is_floating = false,
.dtype = DataTypeDescriptor::DataType::dtype_int8};
const DataTypeDescriptor dtype_desc_int16 = {
.name = "16-bits integer",
.sw = 2,
.is_floating = false,
.dtype = DataTypeDescriptor::DataType::dtype_int16};
const DataTypeDescriptor dtype_desc_int32 = {
.name = "32-bits integer",
.sw = 4,
.is_floating = false,
.dtype = DataTypeDescriptor::DataType::dtype_int32};
const std::map<DataTypeDescriptor::DataType, const DataTypeDescriptor>
dtype_map = {
{DataTypeDescriptor::DataType::dtype_fl32, dtype_desc_fl32},
{DataTypeDescriptor::DataType::dtype_fl64, dtype_desc_fl64},
{DataTypeDescriptor::DataType::dtype_int8, dtype_desc_int8},
{DataTypeDescriptor::DataType::dtype_int16, dtype_desc_int16},
{DataTypeDescriptor::DataType::dtype_int32, dtype_desc_int32},
};
/**
* @brief Class that specifies API related information. An API configuration is
* part of the DAQConfiguration and used to address a certain physical device.
* For that, a specific backend needs to be compiled in. Examples of API's are
* RtAudio and UlDaq.
*/
class DaqApi {
public:
string apiname = "Invalid API";
int apicode = -1;
unsigned api_specific_subcode = 0;
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
: apiname(apiname), apicode(apicode),
api_specific_subcode(api_specific_subcode) {}
DaqApi() {}
bool operator==(const DaqApi &other) const {
return (apiname == other.apiname && apicode == other.apicode &&
api_specific_subcode == other.api_specific_subcode);
}
operator string() const { return apiname; }
static std::vector<DaqApi> getAvailableApis();
};
#if LASP_HAS_ULDAQ == 1
const us LASP_ULDAQ_APICODE = 0;
const DaqApi uldaqapi("UlDaq", 0);
#endif
#if LASP_HAS_RTAUDIO == 1
#include "RtAudio.h"
const us LASP_RTAUDIO_APICODE = 1;
const DaqApi rtaudioAlsaApi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
const DaqApi rtaudioPulseaudioApi("RtAudio Linux Pulseaudio", LASP_RTAUDIO_APICODE,
RtAudio::Api::LINUX_PULSE);
const DaqApi rtaudioWasapiApi("RtAudio Windows Wasapi", LASP_RTAUDIO_APICODE,
RtAudio::Api::WINDOWS_WASAPI);
const DaqApi rtaudioDsApi("RtAudio Windows DirectSound", LASP_RTAUDIO_APICODE,
RtAudio::Api::WINDOWS_DS);
const DaqApi rtaudioAsioApi("RtAudio Windows ASIO", LASP_RTAUDIO_APICODE,
RtAudio::Api::WINDOWS_ASIO);
#endif
#if LASP_HAS_PORTAUDIO == 1
const us LASP_PORTAUDIO_APICODE = 2;
const DaqApi portaudioApi("PortAudio Linux ALSA", LASP_PORTAUDIO_APICODE, 0);
#endif
class DeviceInfo;
/**
* @brief Stores channel configuration data for each channel. I.e. the physical
* quantity measured, sensitivity, device-specific channel settings, a channel
* name and others.
*/
class DaqChannel {
public:
/**
* @brief Possible physical quantities that are recorded.
*/
enum class Qty { Number, AcousticPressure, Voltage, UserDefined };
DaqChannel() {}
/**
* @brief Whether the channel is enabled.
*/
bool enabled = false;
string name = "";
/**
* @brief The conversion between recorded physical unit and stored /
* outputed number, i.e. Number/Volt or Number/Pa. Converting stored numbers
* to physical qty, *divide* by the sensitivity.
*/
double sensitivity = 1;
/**
* @brief For input-only: enable IEPE constant current power supply for
* this channel. Only for hardware that is capable of doing so.
*/
bool IEPEEnabled = false;
/**
* @brief Whether to enable HW AC-coupling for this channel.
*/
bool ACCouplingMode = false;
/**
* @brief Index in possible ranges for input / output
*/
int rangeIndex = 0;
/**
* @brief The physical quantity that is inputed / outputed
*/
Qty qty = Qty::Number;
/**
* @brief Whether to enable a digital high pass on the signal before
* passing the result in case of input, or outputing the result in case of
* output.
*/
double digitalHighPassCutOn = -1;
/**
* @brief Compare two channels to eachother. They are equal when the name,
* sensitivity and quantity are the same.
*
* @param other The DaqChannel to compare with
*
* @return true if equal
*/
bool operator==(const DaqChannel &other) const {
return other.name == name && other.sensitivity == sensitivity &&
other.qty == qty;
}
};
/**
* @brief Configuration of a DAQ device
*/
class DaqConfiguration {
public:
/**
* @brief Export the class to TOML markup language.
*
* @return String with TOML exported data.
*/
std::string toTOML() const;
/**
* @brief Load in a DAQConfiguration from TOML.
*
* @param toml String containing TOML data
*
* @return DaqConfiguration object
*/
static DaqConfiguration fromTOML(const std::string &toml);
DaqApi api;
/**
* @brief The internal device name this DAQ configuration applies to.
*/
string device_name;
/**
* @brief Channel configuration for input channels
*/
std::vector<DaqChannel> inchannel_config;
/**
* @brief Return list of enabled input channels
*
* @param include_monitor If set to true and a monitor channel is available,
* the first indices in the array will correspond to the monitor channel(s).
*
* @return That.
*/
std::vector<DaqChannel>
enabledInChannels(const bool include_monitor = true) const;
/**
* @brief Channel configuration for output channels
*/
std::vector<DaqChannel> outchannel_config;
/**
* @brief Index in list of sample rates that are available for the device.
*/
int sampleRateIndex = 0; //
/**
* @brief Required datatype for output, should be present in the list
*/
int dataTypeIndex = 0;
/**
* @brief The index in the array of frames per block that can be used for the
* device.
*/
int framesPerBlockIndex = 0;
/**
* @brief If set to true and if the device has this capability, the output
* channels are added as input channels as well.
*/
bool monitorOutput = false;
/**
* @brief Create a default configuration, with all channels disabled on both
* input and output, and default channel names
*
* @param deviceinfo DeviceInfo structure
*/
DaqConfiguration(const DeviceInfo &deviceinfo);
DaqConfiguration() {}
/**
* @brief Check to see whether the DAQ configuration matches with the device.
* This means, some basic checks are done on channels, sampling rate, etc,
* and that the name corresponds with the device name.
*
* @param devinfo The DeviceInfo to check
*
* @return true if it matches. Otherwise false.
*/
bool match(const DeviceInfo &devinfo) const;
/**
* @brief Get the enabled highest channel number from the list of enabled
* input channels.
*
* @return Index to the highest input channel. -1 if no input channels are
* enabled.
*/
int getHighestEnabledInChannel() const;
/**
* @brief Get the highest channel number from the list of enabled output
* channels.
*
* @return Index to the highest input channel. -1 if no output channels are
* enabled.
*/
int getHighestEnabledOutChannel() const;
/**
* @brief Get the lowest channel number from the list of enabled input
* channels.
*
* @return Index to the lowest input channel. -1 if no input channels are
* enabled.
*/
int getLowestEnabledInChannel() const;
/**
* @brief Get the lowest channel number from the list of enabled output
* channels.
*
* @return Index to the lowest output channel. -1 if no output channels are
* enabled.
*/
int getLowestEnabledOutChannel() const;
/**
* @brief Set all input channels to enabled / disabled state.
*
* @param val true if enabled, false if disabled.
*/
void setAllInputEnabled(bool val) {
for (auto &ch : inchannel_config) {
ch.enabled = val;
}
}
/**
* @brief Set all output channels to enabled / disabled state.
*
* @param val true if enabled, false if disabled.
*/
void setAllOutputEnabled(bool val) {
for (auto &ch : outchannel_config) {
ch.enabled = val;
}
}
};
/**
* @}
*/