LASP 1.0
Library for Acoustic Signal Processing
Loading...
Searching...
No Matches
lasp_uldaq_impl.cpp
Go to the documentation of this file.
1/* #define DEBUGTRACE_ENABLED */
2#include "debugtrace.hpp"
3#include "lasp_config.h"
4
5#if LASP_HAS_ULDAQ == 1
6#include "lasp_daqconfig.h"
7#include "lasp_uldaq.h"
9#include "lasp_uldaq_impl.h"
10
11using namespace std::literals::chrono_literals;
12
14 DEBUGTRACE_ENTER;
15 UlError err;
16 if (isRunning()) {
17 DEBUGTRACE_PRINT("Stop UlDAQ from destructor");
18 stop();
19 }
20
21 if (_handle) {
22 DEBUGTRACE_PRINT("Disconnecting and releasing DaqDevice");
23 /* err = ulDisconnectDaqDevice(_handle); */
24 /* showErr(err); */
25 err = ulReleaseDaqDevice(_handle);
26 showErr(err);
27 }
28}
29DT9837A::DT9837A(const UlDaqDeviceInfo &devinfo, const DaqConfiguration &config)
30 : Daq(devinfo, config),
31 _nFramesPerBlock(availableFramesPerBlock.at(framesPerBlockIndex)) {
32
33 const DaqDeviceDescriptor &descriptor = devinfo._uldaqDescriptor;
34 DEBUGTRACE_PRINT(string("Device: ") + descriptor.productName);
35 DEBUGTRACE_PRINT(string("Product id: ") + to_string(descriptor.productId));
36 DEBUGTRACE_PRINT(string("Dev string: ") + descriptor.devString);
37 DEBUGTRACE_PRINT(string("Unique id: ") + descriptor.uniqueId);
38
39 // get a handle to the DAQ device associated with the first descriptor
40 _handle = ulCreateDaqDevice(descriptor);
41
42 if (_handle == 0) {
43 throw rte("Unable to create a handle to the specified DAQ "
44 "device. Is the device currently in use? Please make sure to set "
45 "the DAQ configuration in duplex mode if simultaneous input and "
46 "output is required.");
47 }
48
49 UlError err = ulConnectDaqDevice(_handle);
50
51 if (err != ERR_NO_ERROR) {
52 ulReleaseDaqDevice(_handle);
53 _handle = 0;
54 throw rte("Unable to connect to device: " + getErrMsg(err));
55 }
56
58 for (us ch = 0; ch < 4; ch++) {
59
60 err = ulAISetConfigDbl(_handle, AI_CFG_CHAN_SENSOR_SENSITIVITY, ch, 1.0);
61 showErr(err);
62 if (err != ERR_NO_ERROR) {
63 throw rte("Fatal: could normalize channel sensitivity");
64 }
65
66 CouplingMode cm = inchannel_config.at(ch).ACCouplingMode ? CM_AC : CM_DC;
67 err = ulAISetConfig(_handle, AI_CFG_CHAN_COUPLING_MODE, ch, cm);
68 if (err != ERR_NO_ERROR) {
69 showErr(err);
70 throw rte("Fatal: could not set AC/DC coupling mode");
71 }
72
73 IepeMode iepe =
74 inchannel_config.at(ch).IEPEEnabled ? IEPE_ENABLED : IEPE_DISABLED;
75 err = ulAISetConfig(_handle, AI_CFG_CHAN_IEPE_MODE, ch, iepe);
76 if (err != ERR_NO_ERROR) {
77 showErr(err);
78 throw rte("Fatal: could not set IEPE mode");
79 }
80 }
81}
82
83bool DT9837A::isRunning() const {
84 DEBUGTRACE_ENTER;
85 /* return _thread.joinable(); */
86 StreamStatus status = _streamStatus;
87 return status.isRunning;
88}
89void DT9837A::stop() {
90 DEBUGTRACE_ENTER;
91 StreamStatus status = _streamStatus;
92 status.isRunning = true;
93 _streamStatus = status;
94 if (!isRunning()) {
95 throw rte("No data acquisition running");
96 }
97
98 // Stop the thread and join it
99 _stopThread = true;
100 assert(_thread.joinable());
101 _thread.join();
102 _stopThread = false;
103
104 // Update stream status
105 status.isRunning = false;
106 _streamStatus = status;
107}
108
109void DT9837A::start(InDaqCallback inCallback, OutDaqCallback outCallback) {
110 DEBUGTRACE_ENTER;
111 if (isRunning()) {
112 throw rte("DAQ is already running");
113 }
114 if (neninchannels() > 0) {
115 if (!inCallback)
116 throw rte("DAQ requires a callback for input data");
117 }
118 if (nenoutchannels() > 0) {
119 if (!outCallback)
120 throw rte("DAQ requires a callback for output data");
121 }
122 assert(neninchannels() + nenoutchannels() > 0);
123 _thread = std::thread(&DT9837A::threadFcn, this, inCallback, outCallback);
124
125}
126
127void DT9837A::threadFcn(InDaqCallback inCallback, OutDaqCallback outCallback) {
128
129 DEBUGTRACE_ENTER;
130
131 try {
132
133 std::unique_ptr<OutBufHandler> obh;
134 std::unique_ptr<InBufHandler> ibh;
135
136 StreamStatus status = _streamStatus;
137 status.isRunning = true;
138 _streamStatus = status;
139
140 if (nenoutchannels() > 0) {
141 assert(outCallback);
142 obh = std::make_unique<OutBufHandler>(*this, outCallback);
143 }
144 if (neninchannels() > 0) {
145 assert(inCallback);
146 ibh = std::make_unique<InBufHandler>(*this, inCallback);
147 }
148 if (obh)
149 obh->start();
150 if (ibh)
151 ibh->start();
152
153 const double sleeptime_s =
154 static_cast<double>(_nFramesPerBlock) / (16 * samplerate());
155 const us sleeptime_us = static_cast<us>(sleeptime_s * 1e6);
156
157 while (!_stopThread) {
158 if (ibh) {
159 if (!(*ibh)()) {
160 _stopThread = true;
161 break;
162 }
163 }
164 if (obh) {
165 if (!(*obh)()) {
166 _stopThread = true;
167 break;
168 }
169 }
170
171 std::this_thread::sleep_for(std::chrono::microseconds(sleeptime_us));
172 }
173
175 status.isRunning = false;
176 _streamStatus = status;
177 _stopThread = false;
178
179 } catch (StreamException &e) {
180
181 StreamStatus status = _streamStatus;
182 // Copy over error type
183 status.errorType = e.e;
184 _streamStatus = status;
185
186 cerr << "\n******************\n";
187 cerr << "Catched error in UlDAQ thread: " << e.what() << endl;
188 cerr << "\n******************\n";
189 }
190}
191
192void DT9837A::sanityChecks() const {
193 // Some sanity checks
194 if (inchannel_config.size() != 4) {
195 throw rte("Invalid length of enabled inChannels vector");
196 }
197
198 if (outchannel_config.size() != 1) {
199 throw rte("Invalid length of enabled outChannels vector");
200 }
201
202 if (_nFramesPerBlock < 24 || _nFramesPerBlock > 8192) {
203 throw rte("Unsensible number of samples per block chosen");
204 }
205
206 if (samplerate() < ULDAQ_SAMPLERATES.at(0) ||
208 throw rte("Invalid sample rate");
209 }
210}
211
212#endif // LASP_HAS_ULDAQ
virtual void start(InDaqCallback inCallback, OutDaqCallback outCallback) override final
Start the Daq.
void stop() override final
Stop the data-acquisition.
DT9837A(const UlDaqDeviceInfo &devinfo, const DaqConfiguration &config)
Create a DT9837A instance.
bool isRunning() const
Returns true when the stream is running.
virtual ~DT9837A()
Configuration of a DAQ device.
std::vector< DaqChannel > inchannel_config
Channel configuration for input channels.
std::vector< DaqChannel > outchannel_config
Channel configuration for output channels.
Base cass for all DAQ (Data Acquisition) interfaces. A DAQ can be a custom device,...
Definition lasp_daq.h:29
std::runtime_error rte
Definition lasp_daq.h:86
us neninchannels(bool include_monitorchannels=true) const
Returns the number of enabled input channels.
Definition lasp_daq.cpp:99
double samplerate() const
Returns current sample rate.
Definition lasp_daq.cpp:78
us nenoutchannels() const
Returns the number of enabled output channels.
Definition lasp_daq.cpp:104
UlDaq-specific device information. Adds a copy of the underlying DaqDeDaqDeviceDescriptor.
DaqDeviceDescriptor _uldaqDescriptor
std::runtime_error rte
Definition lasp_daq.cpp:16
const std::vector< d > ULDAQ_SAMPLERATES
List of available sampling frequencies for DT9837A.
std::function< void(DaqData &)> OutDaqCallback
Definition lasp_daq.h:23
std::function< void(const DaqData &)> InDaqCallback
Definition lasp_daq.h:18
void showErr(UlError err)
Print error message to stderr.
string getErrMsg(UlError err)
Return a string corresponding to the UlDaq API error.
size_t us
We often use boolean values.
Definition lasp_types.h:29