LASP 1.0
Library for Acoustic Signal Processing
Loading...
Searching...
No Matches
lasp_daqconfig.cpp
Go to the documentation of this file.
1/* #define DEBUGTRACE_ENABLED */
2#include "debugtrace.hpp"
3
4#include "lasp_daqconfig.h"
5#include "lasp_deviceinfo.h"
6#include <algorithm>
7#include <cassert>
8#include <stdexcept>
9
10using std::vector;
11
12vector<DaqApi> DaqApi::getAvailableApis() {
13
14 vector<DaqApi> apis;
15#if LASP_HAS_ULDAQ == 1
16 apis.push_back(uldaqapi);
17#endif
18#if LASP_HAS_RTAUDIO == 1
19 apis.push_back(rtaudioAlsaApi);
20 apis.push_back(rtaudioPulseaudioApi);
21 apis.push_back(rtaudioWasapiApi);
22 apis.push_back(rtaudioDsApi);
23 apis.push_back(rtaudioAsioApi);
24#endif
25 return apis;
26}
27
29
30 api = device.api;
31 device_name = device.device_name;
32
33 inchannel_config.resize(device.ninchannels);
34 outchannel_config.resize(device.noutchannels);
35 us i = 0;
36 for (auto &inch : inchannel_config) {
37 inch.name = "Unnamed input channel " + std::to_string(i);
38 i++;
39 }
40
41 i = 0;
42 for (auto &outch : outchannel_config) {
43 outch.name = "Unnamed output channel " + std::to_string(i);
44 i++;
45 }
46
50
51 monitorOutput = false;
52
53 assert(match(device));
54}
55
56bool DaqConfiguration::match(const DeviceInfo &dev) const {
57 return (dev.device_name == device_name && dev.api == api);
58}
59
61 for (int i = inchannel_config.size() - 1; i > -1; i--) {
62 if (inchannel_config.at(i).enabled)
63 return i;
64 }
65 return -1;
66}
67
69 for (us i = outchannel_config.size() - 1; i >= 0; i--) {
70 if (outchannel_config.at(i).enabled)
71 return i;
72 }
73 return -1;
74}
76 for (us i = 0; i < inchannel_config.size(); i++) {
77 if (inchannel_config.at(i).enabled)
78 return i;
79 }
80 return -1;
81}
83 for (us i = 0; i < outchannel_config.size(); i++) {
84 if (outchannel_config.at(i).enabled)
85 return i;
86 }
87 return -1;
88}
89vector<DaqChannel> DaqConfiguration::enabledInChannels(const bool include_monitor) const {
90 vector<DaqChannel> res;
91 if(monitorOutput && include_monitor) {
92 DaqChannel ch;
93 ch.name = "Internal output monitor (loopback)";
94 ch.enabled = true;
95 ch.sensitivity = 1;
97 res.emplace_back(std::move(ch));
98
99 }
100 for(auto& ch: inchannel_config) {
101 if(ch.enabled) { res.push_back(ch);}
102 }
103 return res;
104}
105
106#include "toml++/toml.h"
107#include <sstream>
108
109toml::table daqChannelToTOML(const DaqChannel &ch) {
110 DEBUGTRACE_ENTER;
111 toml::table tbl;
112 tbl.emplace("enabled", ch.enabled);
113 tbl.emplace("name", ch.name);
114 tbl.emplace("sensitivity", ch.sensitivity);
115 tbl.emplace("IEPEEnabled", ch.IEPEEnabled);
116 tbl.emplace("ACCouplingMode", ch.ACCouplingMode);
117 tbl.emplace("rangeIndex", ch.rangeIndex);
118 tbl.emplace("qty", static_cast<int>(ch.qty));
119 tbl.emplace("digitalHighpassCutOn", ch.digitalHighPassCutOn);
120
121 return tbl;
122}
123
125
126 DEBUGTRACE_ENTER;
127 toml::table apitbl{
128 {"apiname", api.apiname}, // Api name
129 {"apicode", api.apicode}, // Api code
130 {"api_specific_subcode", api.api_specific_subcode} // Subcode
131 };
132
133 toml::table tbl{{"daqapi", apitbl}};
134
135 tbl.emplace("device_name", device_name);
136 tbl.emplace("sampleRateIndex", sampleRateIndex);
137 tbl.emplace("dataTypeIndex", dataTypeIndex);
138 tbl.emplace("framesPerBlockIndex", framesPerBlockIndex);
139 tbl.emplace("monitorOutput", monitorOutput);
140
141 toml::array inchannel_config_tbl;
142 for (const auto &ch : inchannel_config) {
143 inchannel_config_tbl.emplace_back(daqChannelToTOML(ch));
144 }
145 tbl.emplace("inchannel_config", inchannel_config_tbl);
146
147 toml::array outchannel_config_tbl;
148 for (const auto &ch : outchannel_config) {
149 outchannel_config_tbl.emplace_back(daqChannelToTOML(ch));
150 }
151 tbl.emplace("outchannel_config", outchannel_config_tbl);
152
153 std::stringstream str;
154
155 str << tbl;
156
157 return str.str();
158}
159
160template <typename T,typename R> T getValue(R &tbl, const char* key) {
161 using std::runtime_error;
162
163 DEBUGTRACE_ENTER;
164
165 // Yeah, weird syntax quirck of C++
166 std::optional<T> val = tbl[key].template value<T>();
167 if (!val) {
168 throw runtime_error(string("Error while parsing Daq configuration. Table "
169 "does not contain key: ") +
170 key);
171 }
172 return val.value();
173}
174template<typename T> DaqChannel TOMLToDaqChannel(T& node) {
175 DEBUGTRACE_ENTER;
176 DaqChannel d;
177 toml::table& tbl = *node.as_table();
178 d.enabled = getValue<bool>(tbl, "enabled");
179 d.name = getValue<string>(tbl, "name");
180 d.sensitivity = getValue<double>(tbl, "sensitivity");
181 d.IEPEEnabled = getValue<bool>(tbl, "IEPEEnabled");
182 d.ACCouplingMode = getValue<bool>(tbl, "ACCouplingMode");
183 d.rangeIndex = getValue<bool>(tbl, "rangeIndex");
184 d.qty = static_cast<DaqChannel::Qty>(getValue<int64_t>(tbl, "qty"));
185 d.digitalHighPassCutOn = getValue<double>(tbl, "digitalHighpassCutOn");
186
187 return d;
188}
189
190DaqConfiguration DaqConfiguration::fromTOML(const std::string &tomlstr) {
191
192 DEBUGTRACE_ENTER;
193
194 using std::runtime_error;
195
196 try {
197 toml::table tbl = toml::parse(tomlstr);
198 DaqConfiguration config;
199
200 auto daqapi = tbl["daqapi"];
201 DaqApi api;
202 api.apicode = getValue<int64_t>(daqapi, "apicode");
203 api.api_specific_subcode = getValue<int64_t>(daqapi, "api_specific_subcode");
204 api.apiname = getValue<string>(daqapi, "apiname");
205 config.api = api;
206
207 config.device_name = getValue<string>(tbl, "device_name");
208 config.sampleRateIndex = getValue<int64_t>(tbl, "sampleRateIndex");
209 config.dataTypeIndex = getValue<int>(tbl, "dataTypeIndex");
210 config.framesPerBlockIndex = getValue<int64_t>(tbl, "framesPerBlockIndex");
211 config.monitorOutput = getValue<bool>(tbl, "monitorOutput");
212
213 if(toml::array* in_arr = tbl["inchannel_config"].as_array()) {
214 for(auto& el: *in_arr) {
215 config.inchannel_config.push_back(TOMLToDaqChannel(el));
216 }
217
218 } else {
219 throw runtime_error("inchannel_config is not an array");
220 }
221
222 if(toml::array* out_arr = tbl["outchannel_config"].as_array()) {
223 for(auto& el: *out_arr) {
224 config.outchannel_config.push_back(TOMLToDaqChannel(el));
225 }
226 } else {
227 throw runtime_error("outchannel_config is not an array");
228 }
229
230
231 return config;
232
233 } catch (const toml::parse_error &e) {
234 throw std::runtime_error(string("Error parsing TOML DaqConfiguration: ") +
235 e.what());
236 }
237}
Class that specifies API related information. An API configuration is part of the DAQConfiguration an...
unsigned api_specific_subcode
static std::vector< DaqApi > getAvailableApis()
string apiname
Stores channel configuration data for each channel. I.e. the physical quantity measured,...
Qty
Possible physical quantities that are recorded.
double sensitivity
The conversion between recorded physical unit and stored / outputed number, i.e. Number/Volt or Numbe...
double digitalHighPassCutOn
Whether to enable a digital high pass on the signal before passing the result in case of input,...
bool IEPEEnabled
For input-only: enable IEPE constant current power supply for this channel. Only for hardware that is...
int rangeIndex
Index in possible ranges for input / output.
bool ACCouplingMode
Whether to enable HW AC-coupling for this channel.
Qty qty
The physical quantity that is inputed / outputed.
bool enabled
Whether the channel is enabled.
Configuration of a DAQ device.
static DaqConfiguration fromTOML(const std::string &toml)
Load in a DAQConfiguration from TOML.
std::vector< DaqChannel > enabledInChannels(const bool include_monitor=true) const
Return list of enabled input channels.
int framesPerBlockIndex
The index in the array of frames per block that can be used for the device.
int dataTypeIndex
Required datatype for output, should be present in the list.
std::vector< DaqChannel > inchannel_config
Channel configuration for input channels.
bool monitorOutput
If set to true and if the device has this capability, the output channels are added as input channels...
int getHighestEnabledOutChannel() const
Get the highest channel number from the list of enabled output channels.
int getHighestEnabledInChannel() const
Get the enabled highest channel number from the list of enabled input channels.
string device_name
The internal device name this DAQ configuration applies to.
std::string toTOML() const
Export the class to TOML markup language.
int sampleRateIndex
Index in list of sample rates that are available for the device.
int getLowestEnabledInChannel() const
Get the lowest channel number from the list of enabled input channels.
std::vector< DaqChannel > outchannel_config
Channel configuration for output channels.
bool match(const DeviceInfo &devinfo) const
Check to see whether the DAQ configuration matches with the device. This means, some basic checks are...
int getLowestEnabledOutChannel() const
Get the lowest channel number from the list of enabled output channels.
Structure containing device info parameters.
unsigned ninchannels
The number of input channels available for the device.
unsigned noutchannels
The number of output channels available for the device.
string device_name
The name of the device.
int prefDataTypeIndex
The device's prefferd data type.
DaqApi api
Backend API corresponding to device.
us prefFramesPerBlockIndex
Preffered number of frames per callback.
int prefSampleRateIndex
Preferred setting for the sample rate.
toml::table daqChannelToTOML(const DaqChannel &ch)
T getValue(R &tbl, const char *key)
DaqChannel TOMLToDaqChannel(T &node)
size_t us
We often use boolean values.
Definition lasp_types.h:29