Inbetween pybind11 commit. Nothing working.
This commit is contained in:
parent
f635cac209
commit
7eaaf43653
@ -144,8 +144,9 @@ set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
|
|||||||
|
|
||||||
set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py"
|
set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
|
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
|
||||||
"wrappers"
|
# "wrappers"
|
||||||
"lasp_daq")
|
# "lasp_device_lib")
|
||||||
|
)
|
||||||
|
|
||||||
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
|
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Data coming from / going to DAQ. Non-interleaved format, which means
|
* @brief Data coming from / going to DAQ. **Non-interleaved format**, which means
|
||||||
* data in buffer is ordered by channel: _ptr[sample+channel*nsamples]
|
* data in buffer is ordered by channel: _ptr[sample+channel*nframes]
|
||||||
*/
|
*/
|
||||||
class DaqData {
|
class DaqData {
|
||||||
protected:
|
protected:
|
||||||
@ -38,24 +38,13 @@ public:
|
|||||||
us size_bytes() const { return _data.size(); }
|
us size_bytes() const { return _data.size(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Typed DaqData, in which the type is specified
|
|
||||||
*
|
|
||||||
* @tparam T
|
|
||||||
*/
|
|
||||||
template <typename T> class TypedDaqData : public DaqData {
|
|
||||||
T *data() { return static_cast<T *>(_data.data()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Callback of DAQ. Called with arguments of a vector of data
|
* @brief Callback of DAQ. Called with arguments of a vector of data
|
||||||
* spans for each channel, and a datatype descriptor. Callback should return
|
* spans for each channel, and a datatype descriptor. Callback should return
|
||||||
* false for a stop request.
|
* false for a stop request.
|
||||||
*/
|
*/
|
||||||
using ChannelView = std::vector<gsl::span<uint8_t>>;
|
|
||||||
using DaqCallback =
|
using DaqCallback =
|
||||||
std::function<bool(ChannelView channel_data,
|
std::function<bool(std::unique_ptr<DaqData>)>;
|
||||||
const DataTypeDescriptor &dtype_descr)>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base cass for all DAQ instances
|
* @brief Base cass for all DAQ instances
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
#if LASP_HAS_RTAUDIO == 1
|
|
||||||
#include "lasp_rtaudiodaq.h"
|
#include "lasp_rtaudiodaq.h"
|
||||||
|
#if LASP_HAS_RTAUDIO == 1
|
||||||
|
#include "lasp_daqconfig.h"
|
||||||
#include <RtAudio.h>
|
#include <RtAudio.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
using std::atomic;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
using std::atomic;
|
using std::runtime_error;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
void fillRtAudioDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
void fillRtAudioDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
||||||
|
|
||||||
@ -25,6 +28,7 @@ void fillRtAudioDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
|||||||
// Device capabilities not successfully probed. Continue to next
|
// Device capabilities not successfully probed. Continue to next
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// "Our device info struct"
|
||||||
DeviceInfo d;
|
DeviceInfo d;
|
||||||
switch (api) {
|
switch (api) {
|
||||||
case RtAudio::LINUX_ALSA:
|
case RtAudio::LINUX_ALSA:
|
||||||
@ -66,19 +70,24 @@ void fillRtAudioDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
|||||||
|
|
||||||
RtAudioFormat formats = devinfo.nativeFormats;
|
RtAudioFormat formats = devinfo.nativeFormats;
|
||||||
if (formats & RTAUDIO_SINT8) {
|
if (formats & RTAUDIO_SINT8) {
|
||||||
d.availableDataTypes.push_back(dtype_int8);
|
d.availableDataTypes.push_back(
|
||||||
|
DataTypeDescriptor::DataType::dtype_int8);
|
||||||
}
|
}
|
||||||
if (formats & RTAUDIO_SINT16) {
|
if (formats & RTAUDIO_SINT16) {
|
||||||
d.availableDataTypes.push_back(dtype_int16);
|
d.availableDataTypes.push_back(
|
||||||
|
DataTypeDescriptor::DataType::dtype_int16);
|
||||||
}
|
}
|
||||||
|
/* if (formats & RTAUDIO_SINT32) { */
|
||||||
|
/* d.availableDataTypes.push_back(DataTypeDescriptor::DataType::dtype_int24);
|
||||||
|
*/
|
||||||
|
/* } */
|
||||||
if (formats & RTAUDIO_SINT32) {
|
if (formats & RTAUDIO_SINT32) {
|
||||||
d.availableDataTypes.push_back(dtype_int24);
|
d.availableDataTypes.push_back(
|
||||||
}
|
DataTypeDescriptor::DataType::dtype_fl32);
|
||||||
if (formats & RTAUDIO_SINT32) {
|
|
||||||
d.availableDataTypes.push_back(dtype_fl32);
|
|
||||||
}
|
}
|
||||||
if (formats & RTAUDIO_FLOAT64) {
|
if (formats & RTAUDIO_FLOAT64) {
|
||||||
d.availableDataTypes.push_back(dtype_fl64);
|
d.availableDataTypes.push_back(
|
||||||
|
DataTypeDescriptor::DataType::dtype_fl64);
|
||||||
}
|
}
|
||||||
if (d.availableDataTypes.size() == 0) {
|
if (d.availableDataTypes.size() == 0) {
|
||||||
std::cerr << "RtAudio: No data types found in device!" << endl;
|
std::cerr << "RtAudio: No data types found in device!" << endl;
|
||||||
@ -86,11 +95,7 @@ void fillRtAudioDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
|||||||
|
|
||||||
d.prefDataTypeIndex = d.availableDataTypes.size() - 1;
|
d.prefDataTypeIndex = d.availableDataTypes.size() - 1;
|
||||||
|
|
||||||
d.availableFramesPerBlock.push_back(512);
|
d.availableFramesPerBlock = {512, 1024, 2048, 4096, 8192};
|
||||||
d.availableFramesPerBlock.push_back(1024);
|
|
||||||
d.availableFramesPerBlock.push_back(2048);
|
|
||||||
d.availableFramesPerBlock.push_back(4096);
|
|
||||||
d.availableFramesPerBlock.push_back(8192);
|
|
||||||
d.prefFramesPerBlockIndex = 1;
|
d.prefFramesPerBlockIndex = 1;
|
||||||
|
|
||||||
devinfolist.push_back(d);
|
devinfolist.push_back(d);
|
||||||
@ -103,162 +108,206 @@ int mycallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
|
|||||||
|
|
||||||
void myerrorcallback(RtAudioError::Type, const string &errorText);
|
void myerrorcallback(RtAudioError::Type, const string &errorText);
|
||||||
|
|
||||||
class AudioDaq : public Daq {
|
class RtAudioDaq : public Daq {
|
||||||
|
|
||||||
SafeQueue<void *> *inqueue = NULL;
|
RtAudio rtaudio;
|
||||||
SafeQueue<void *> *outqueue = NULL;
|
const us nFramesPerBlock;
|
||||||
SafeQueue<void *> *outDelayqueue = NULL;
|
|
||||||
|
|
||||||
RtAudio *rtaudio = NULL;
|
RtAudioDaq(const RtAudioDaq &) = delete;
|
||||||
RtAudio::StreamParameters *instreamparams = nullptr;
|
RtAudioDaq &operator=(const RtAudioDaq &) = delete;
|
||||||
RtAudio::StreamParameters *outstreamparams = nullptr;
|
|
||||||
|
|
||||||
us nFramesPerBlock;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioDaq(const DeviceInfo &devinfo, const DaqConfiguration &config)
|
RtAudioDaq(const DeviceInfo &devinfo, const DaqConfiguration &config)
|
||||||
: Daq(devinfo, config) {
|
: Daq(devinfo, config),
|
||||||
|
rtaudio(static_cast<RtAudio::Api>(devinfo.api.api_specific_subcode)),
|
||||||
|
nFramesPerBlock(Daq::framesPerBlock()) {
|
||||||
|
|
||||||
nFramesPerBlock = this->framesPerBlock();
|
std::unique_ptr<RtAudio::StreamParameters> inParams, outParams;
|
||||||
|
// We make sure not to run RtAudio in duplex mode. This seems to be buggy
|
||||||
|
// and untested. Better to use a hardware-type loopback into the system.
|
||||||
|
if (neninchannels(false) > 0 && nenoutchannels() > 0) {
|
||||||
|
throw runtime_error("RtAudio backend cannot run in duplex mode.");
|
||||||
|
}
|
||||||
|
assert(!monitorOutput);
|
||||||
|
|
||||||
if (neninchannels(false) > 0) {
|
if (neninchannels() > 0) {
|
||||||
instreamparams = new RtAudio::StreamParameters();
|
|
||||||
instreamparams->nChannels = getHighestInChannel() + 1;
|
inParams = std::make_unique<RtAudio::StreamParameters>();
|
||||||
if (instreamparams->nChannels < 1) {
|
|
||||||
|
// +1 to get the count.
|
||||||
|
inParams->nChannels = getHighestInChannel() + 1;
|
||||||
|
if (inParams->nChannels < 1) {
|
||||||
throw runtime_error("Invalid input number of channels");
|
throw runtime_error("Invalid input number of channels");
|
||||||
}
|
}
|
||||||
instreamparams->firstChannel = 0;
|
inParams->firstChannel = 0;
|
||||||
instreamparams->deviceId = devinfo.api_specific_devindex;
|
inParams->deviceId = devinfo.api_specific_devindex;
|
||||||
}
|
|
||||||
|
|
||||||
if (nenoutchannels() > 0) {
|
} else {
|
||||||
outstreamparams = new RtAudio::StreamParameters();
|
|
||||||
outstreamparams->nChannels = getHighestOutChannel() + 1;
|
outParams = std::make_unique<RtAudio::StreamParameters>();
|
||||||
if (outstreamparams->nChannels < 1) {
|
|
||||||
|
outParams->nChannels = getHighestOutChannel() + 1;
|
||||||
|
if (outParams->nChannels < 1) {
|
||||||
throw runtime_error("Invalid output number of channels");
|
throw runtime_error("Invalid output number of channels");
|
||||||
}
|
}
|
||||||
outstreamparams->firstChannel = 0;
|
outParams->firstChannel = 0;
|
||||||
outstreamparams->deviceId = devinfo.api_specific_devindex;
|
outParams->deviceId = devinfo.api_specific_devindex;
|
||||||
}
|
}
|
||||||
|
|
||||||
RtAudio::StreamOptions streamoptions;
|
RtAudio::StreamOptions streamoptions;
|
||||||
streamoptions.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_HOG_DEVICE;
|
streamoptions.flags = RTAUDIO_HOG_DEVICE;
|
||||||
|
|
||||||
streamoptions.numberOfBuffers = 2;
|
streamoptions.numberOfBuffers = 2;
|
||||||
streamoptions.streamName = "RtAudio stream";
|
streamoptions.streamName = "RtAudio stream";
|
||||||
streamoptions.priority = 0;
|
streamoptions.priority = 0;
|
||||||
|
|
||||||
RtAudioFormat format;
|
RtAudioFormat format;
|
||||||
const DataType dtype = DataType();
|
using Dtype = DataTypeDescriptor::DataType;
|
||||||
|
const Dtype dtype = dataType();
|
||||||
switch (dtype) {
|
switch (dtype) {
|
||||||
case dtype_fl32:
|
case Dtype::dtype_fl32:
|
||||||
format = RTAUDIO_FLOAT32;
|
format = RTAUDIO_FLOAT32;
|
||||||
break;
|
break;
|
||||||
case dtype_fl64:
|
case Dtype::dtype_fl64:
|
||||||
format = RTAUDIO_FLOAT64;
|
format = RTAUDIO_FLOAT64;
|
||||||
break;
|
break;
|
||||||
case dtype_int8:
|
case Dtype::dtype_int8:
|
||||||
format = RTAUDIO_SINT8;
|
format = RTAUDIO_SINT8;
|
||||||
break;
|
break;
|
||||||
case dtype_int16:
|
case Dtype::dtype_int16:
|
||||||
format = RTAUDIO_SINT16;
|
format = RTAUDIO_SINT16;
|
||||||
break;
|
break;
|
||||||
case dtype_int32:
|
case Dtype::dtype_int32:
|
||||||
format = RTAUDIO_SINT32;
|
format = RTAUDIO_SINT32;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw runtime_error("Invalid data type");
|
throw runtime_error("Invalid data type specified for DAQ stream.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// Copy here, as it is used to return the *actual* number of frames per
|
||||||
rtaudio = new RtAudio((RtAudio::Api)devinfo.api.api_specific_subcode);
|
// block.
|
||||||
if (!rtaudio) {
|
unsigned int nFramesPerBlock_copy = nFramesPerBlock;
|
||||||
throw runtime_error("RtAudio allocation failed");
|
|
||||||
|
// Final step: open the stream.
|
||||||
|
rtaudio.openStream(&(*outParams), &(*inParams), format,
|
||||||
|
static_cast<us>(samplerate()), &nFramesPerBlock_copy,
|
||||||
|
&mycallback, (void *)this, &streamoptions,
|
||||||
|
&myerrorcallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
int streamCallback(void *outputBuffer, void *inputBuffer,
|
||||||
|
unsigned int nFrames, double streamTime,
|
||||||
|
RtAudioStreamStatus status) {
|
||||||
|
|
||||||
|
auto dtype = dataType();
|
||||||
|
us neninchannels_inc_mon = neninchannels();
|
||||||
|
us nenoutchannels = this->nenoutchannels();
|
||||||
|
|
||||||
|
us bytesperchan = dtype_map.at(dtype).sw * nFrames;
|
||||||
|
us monitorOffset = ((us)monitorOutput) * bytesperchan;
|
||||||
|
|
||||||
|
if (inputBuffer) {
|
||||||
|
|
||||||
|
u_int8_t *inbuffercpy =
|
||||||
|
(u_int8_t *)malloc(bytesperchan * neninchannels_inc_mon);
|
||||||
|
if (inputBuffer) {
|
||||||
|
us j = 0; // OUR buffer channel counter
|
||||||
|
us i = 0; // RtAudio channel counter
|
||||||
|
for (int ch = getLowestInChannel(); ch <= getHighestInChannel(); ch++) {
|
||||||
|
if (eninchannels[ch]) {
|
||||||
|
memcpy(&(inbuffercpy[monitorOffset + j * bytesperchan]),
|
||||||
|
&(inputBuffer[i * bytesperchan]), bytesperchan);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rtaudio->openStream(outstreamparams, instreamparams, format,
|
|
||||||
(us)samplerate(), (unsigned *)&nFramesPerBlock,
|
|
||||||
&mycallback, (void *)this, &streamoptions,
|
|
||||||
&myerrorcallback);
|
|
||||||
} catch (RtAudioError &e) {
|
|
||||||
if (rtaudio)
|
|
||||||
delete rtaudio;
|
|
||||||
if (instreamparams)
|
|
||||||
delete instreamparams;
|
|
||||||
if (outstreamparams)
|
|
||||||
delete outstreamparams;
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
if (monitorOutput) {
|
|
||||||
outDelayqueue = new SafeQueue<void *>();
|
if (outputBuffer) {
|
||||||
|
if (!outqueue->empty()) {
|
||||||
|
u_int8_t *outbuffercpy = (u_int8_t *)outqueue->dequeue();
|
||||||
|
us j = 0; // OUR buffer channel counter
|
||||||
|
us i = 0; // RtAudio channel counter
|
||||||
|
for (us ch = 0; ch <= daq->getHighestOutChannel(); ch++) {
|
||||||
|
/* cerr << "Copying from queue... " << endl; */
|
||||||
|
if (enoutchannels[ch]) {
|
||||||
|
memcpy(&(outputBuffer[i * bytesperchan]),
|
||||||
|
&(outbuffercpy[j * bytesperchan]), bytesperchan);
|
||||||
|
j++;
|
||||||
|
} else {
|
||||||
|
/* cerr << "unused output channel in list" << endl; */
|
||||||
|
memset(&(outputBuffer[i * bytesperchan]), 0, bytesperchan);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (!monitorOutput) {
|
||||||
|
free(outbuffercpy);
|
||||||
|
} else {
|
||||||
|
assert(outDelayqueue);
|
||||||
|
outDelayqueue->enqueue((void *)outbuffercpy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cerr << "RtAudio backend: stream output buffer underflow!" << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
start(std::optional<DaqCallback> inCallback,
|
||||||
|
std::optional<DaqCallback> outCallback) {
|
||||||
|
|
||||||
|
assert(!monitorOutput);
|
||||||
|
|
||||||
|
if (isRunning()) {
|
||||||
|
throw runtime_error("Stream already running");
|
||||||
}
|
}
|
||||||
|
|
||||||
friend int mycallback(void *outputBuffer, void *inputBuffer,
|
if (neninchannels(false) > 0 && !inqueue) {
|
||||||
unsigned int nFrames, double streamTime,
|
throw runtime_error("inqueue argument not given");
|
||||||
RtAudioStreamStatus status, void *userData);
|
}
|
||||||
|
if (nenoutchannels() > 0 && !outqueue) {
|
||||||
|
throw runtime_error("outqueue argument not given");
|
||||||
|
}
|
||||||
|
assert(rtaudio);
|
||||||
|
rtaudio->startStream();
|
||||||
|
}
|
||||||
|
|
||||||
void start(SafeQueue<void *> *inqueue, SafeQueue<void *> *outqueue) {
|
void stop() {
|
||||||
this->inqueue = inqueue;
|
if (!isRunning()) {
|
||||||
this->outqueue = outqueue;
|
cerr << "Stream is already stopped" << endl;
|
||||||
if (monitorOutput) {
|
} else {
|
||||||
this->outDelayqueue = new SafeQueue<void *>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRunning()) {
|
|
||||||
throw runtime_error("Stream already running");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (neninchannels(false) > 0 && !inqueue) {
|
|
||||||
throw runtime_error("inqueue argument not given");
|
|
||||||
}
|
|
||||||
if (nenoutchannels() > 0 && !outqueue) {
|
|
||||||
throw runtime_error("outqueue argument not given");
|
|
||||||
}
|
|
||||||
assert(rtaudio);
|
assert(rtaudio);
|
||||||
rtaudio->startStream();
|
rtaudio->stopStream();
|
||||||
}
|
}
|
||||||
|
if (inqueue) {
|
||||||
void stop() {
|
inqueue = nullptr;
|
||||||
|
|
||||||
if (!isRunning()) {
|
|
||||||
cerr << "Stream is already stopped" << endl;
|
|
||||||
} else {
|
|
||||||
assert(rtaudio);
|
|
||||||
rtaudio->stopStream();
|
|
||||||
}
|
|
||||||
if (inqueue) {
|
|
||||||
inqueue = nullptr;
|
|
||||||
}
|
|
||||||
if (outqueue) {
|
|
||||||
outqueue = nullptr;
|
|
||||||
}
|
|
||||||
if (outDelayqueue) {
|
|
||||||
delete outDelayqueue;
|
|
||||||
outDelayqueue = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool isRunning() const { return (rtaudio && rtaudio->isStreamRunning()); }
|
if (outqueue) {
|
||||||
|
outqueue = nullptr;
|
||||||
~AudioDaq() {
|
|
||||||
assert(rtaudio);
|
|
||||||
if (isRunning()) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
if (rtaudio->isStreamOpen()) {
|
|
||||||
rtaudio->closeStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rtaudio)
|
|
||||||
delete rtaudio;
|
|
||||||
if (outDelayqueue)
|
|
||||||
delete outDelayqueue;
|
|
||||||
if (instreamparams)
|
|
||||||
delete instreamparams;
|
|
||||||
if (outstreamparams)
|
|
||||||
delete outstreamparams;
|
|
||||||
}
|
}
|
||||||
};
|
if (outDelayqueue) {
|
||||||
|
delete outDelayqueue;
|
||||||
|
outDelayqueue = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool isRunning() const { return (rtaudio && rtaudio->isStreamRunning()); }
|
||||||
|
|
||||||
|
~RtAudioDaq() {
|
||||||
|
assert(rtaudio);
|
||||||
|
if (isRunning()) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
if (rtaudio->isStreamOpen()) {
|
||||||
|
rtaudio->closeStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
Daq *createRtAudioDevice(const DeviceInfo &devinfo,
|
Daq *createRtAudioDevice(const DeviceInfo &devinfo,
|
||||||
const DaqConfiguration &config) {
|
const DaqConfiguration &config) {
|
||||||
@ -280,90 +329,15 @@ int mycallback(void *outputBuffervoid, void *inputBuffervoid,
|
|||||||
unsigned int nFrames, double streamTime,
|
unsigned int nFrames, double streamTime,
|
||||||
RtAudioStreamStatus status, void *userData) {
|
RtAudioStreamStatus status, void *userData) {
|
||||||
|
|
||||||
u_int8_t *inputBuffer = (u_int8_t *)inputBuffervoid;
|
void myerrorcallback(RtAudioError::Type, const string &errorText) {
|
||||||
u_int8_t *outputBuffer = (u_int8_t *)outputBuffervoid;
|
cerr << errorText << endl;
|
||||||
|
}
|
||||||
|
int mycallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames,
|
||||||
|
double streamTime, RtAudioStreamStatus status,
|
||||||
|
void *userData) {
|
||||||
|
|
||||||
AudioDaq *daq = (AudioDaq *)userData;
|
return static_cast<RtAudioDaq *>(userData)->streamCallback(
|
||||||
DataType dtype = daq->dataType();
|
outputBuffer, inputBuffer, nFrames, streamTime, status);
|
||||||
us neninchannels_inc_mon = daq->neninchannels();
|
|
||||||
us nenoutchannels = daq->nenoutchannels();
|
|
||||||
|
|
||||||
bool monitorOutput = daq->monitorOutput;
|
|
||||||
us bytesperchan = dtype_map.at(dtype).sw * nFrames;
|
|
||||||
us monitorOffset = ((us)monitorOutput) * bytesperchan;
|
|
||||||
|
|
||||||
SafeQueue<void *> *inqueue = daq->inqueue;
|
|
||||||
SafeQueue<void *> *outqueue = daq->outqueue;
|
|
||||||
SafeQueue<void *> *outDelayqueue = daq->outDelayqueue;
|
|
||||||
|
|
||||||
const boolvec &eninchannels = daq->eninchannels;
|
|
||||||
const boolvec &enoutchannels = daq->enoutchannels;
|
|
||||||
|
|
||||||
if (inputBuffer || monitorOutput) {
|
|
||||||
|
|
||||||
u_int8_t *inbuffercpy =
|
|
||||||
(u_int8_t *)malloc(bytesperchan * neninchannels_inc_mon);
|
|
||||||
if (inputBuffer) {
|
|
||||||
us j = 0; // OUR buffer channel counter
|
|
||||||
us i = 0; // RtAudio channel counter
|
|
||||||
for (int ch = daq->getLowestInChannel(); ch <= daq->getHighestInChannel();
|
|
||||||
ch++) {
|
|
||||||
if (eninchannels[ch]) {
|
|
||||||
memcpy(&(inbuffercpy[monitorOffset + j * bytesperchan]),
|
|
||||||
&(inputBuffer[i * bytesperchan]), bytesperchan);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (monitorOutput) {
|
|
||||||
assert(outDelayqueue);
|
|
||||||
|
|
||||||
if (!daq->outDelayqueue->empty()) {
|
|
||||||
void *dat = daq->outDelayqueue->dequeue();
|
|
||||||
memcpy((void *)inbuffercpy, dat, bytesperchan);
|
|
||||||
free(dat);
|
|
||||||
} else {
|
|
||||||
cerr << "Warning: output delay queue appears empty!" << endl;
|
|
||||||
memset(inbuffercpy, 0, bytesperchan);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(inqueue);
|
|
||||||
inqueue->enqueue(inbuffercpy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputBuffer) {
|
|
||||||
assert(outqueue);
|
|
||||||
if (!outqueue->empty()) {
|
|
||||||
u_int8_t *outbuffercpy = (u_int8_t *)outqueue->dequeue();
|
|
||||||
us j = 0; // OUR buffer channel counter
|
|
||||||
us i = 0; // RtAudio channel counter
|
|
||||||
for (us ch = 0; ch <= daq->getHighestOutChannel(); ch++) {
|
|
||||||
/* cerr << "Copying from queue... " << endl; */
|
|
||||||
if (enoutchannels[ch]) {
|
|
||||||
memcpy(&(outputBuffer[i * bytesperchan]),
|
|
||||||
&(outbuffercpy[j * bytesperchan]), bytesperchan);
|
|
||||||
j++;
|
|
||||||
} else {
|
|
||||||
/* cerr << "unused output channel in list" << endl; */
|
|
||||||
memset(&(outputBuffer[i * bytesperchan]), 0, bytesperchan);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (!monitorOutput) {
|
|
||||||
free(outbuffercpy);
|
|
||||||
} else {
|
|
||||||
assert(outDelayqueue);
|
|
||||||
outDelayqueue->enqueue((void *)outbuffercpy);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cerr << "RtAudio backend: stream output buffer underflow!" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void myerrorcallback(RtAudioError::Type, const string &errorText) {
|
|
||||||
cerr << errorText << endl;
|
|
||||||
}
|
|
||||||
#endif // LASP_HAS_RTAUDIO == 1
|
#endif // LASP_HAS_RTAUDIO == 1
|
||||||
|
@ -60,9 +60,9 @@ class DT9837A : public Daq {
|
|||||||
const us _nFramesPerBlock;
|
const us _nFramesPerBlock;
|
||||||
|
|
||||||
void threadFcn(std::optional<DaqCallback> inCallback,
|
void threadFcn(std::optional<DaqCallback> inCallback,
|
||||||
std::optional<DaqCallback> outcallback);
|
std::optional<DaqCallback> outcallback);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DT9837A(const DeviceInfo &devinfo, const DaqConfiguration &config);
|
DT9837A(const DeviceInfo &devinfo, const DaqConfiguration &config);
|
||||||
|
|
||||||
~DT9837A() {
|
~DT9837A() {
|
||||||
@ -81,7 +81,7 @@ class DT9837A : public Daq {
|
|||||||
|
|
||||||
bool isRunning() const override final { return _thread.joinable(); }
|
bool isRunning() const override final { return _thread.joinable(); }
|
||||||
virtual void start(std::optional<DaqCallback> inCallback,
|
virtual void start(std::optional<DaqCallback> inCallback,
|
||||||
std::optional<DaqCallback> outCallback) override final;
|
std::optional<DaqCallback> outCallback) override final;
|
||||||
|
|
||||||
void stop() override final {
|
void stop() override final {
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
@ -100,7 +100,7 @@ class DT9837A : public Daq {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void DT9837A::start(std::optional<DaqCallback> inCallback,
|
void DT9837A::start(std::optional<DaqCallback> inCallback,
|
||||||
std::optional<DaqCallback> outCallback) {
|
std::optional<DaqCallback> outCallback) {
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
throw runtime_error("DAQ is already running");
|
throw runtime_error("DAQ is already running");
|
||||||
@ -118,37 +118,38 @@ void DT9837A::start(std::optional<DaqCallback> inCallback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BufHandler {
|
class BufHandler {
|
||||||
protected:
|
protected:
|
||||||
DaqDeviceHandle _handle;
|
DaqDeviceHandle _handle;
|
||||||
const DataTypeDescriptor dtype_descr;
|
const DataTypeDescriptor dtype_descr;
|
||||||
us nchannels, nFramesPerBlock;
|
us nchannels, nFramesPerBlock;
|
||||||
DaqCallback cb;
|
DaqCallback cb;
|
||||||
double samplerate;
|
double samplerate;
|
||||||
dvec buf;
|
dvec buf;
|
||||||
bool topenqueued, botenqueued;
|
bool topenqueued, botenqueued;
|
||||||
us increment = 0;
|
us increment = 0;
|
||||||
us totalFramesCount = 0;
|
us totalFramesCount = 0;
|
||||||
long long buffer_mid_idx;
|
long long buffer_mid_idx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BufHandler(DaqDeviceHandle handle, const DataTypeDescriptor dtype_descr,
|
BufHandler(DaqDeviceHandle handle, const DataTypeDescriptor dtype_descr,
|
||||||
const us nchannels, const us nFramesPerBlock, DaqCallback cb,
|
const us nchannels, const us nFramesPerBlock, DaqCallback cb,
|
||||||
const double samplerate)
|
const double samplerate)
|
||||||
: _handle(handle), dtype_descr(dtype_descr), nchannels(nchannels),
|
: _handle(handle), dtype_descr(dtype_descr), nchannels(nchannels),
|
||||||
nFramesPerBlock(nFramesPerBlock), cb(cb), samplerate(samplerate),
|
nFramesPerBlock(nFramesPerBlock), cb(cb), samplerate(samplerate),
|
||||||
buf(2 * nchannels *
|
buf(2 * nchannels *
|
||||||
nFramesPerBlock, // Watch the two here, the top and the bottom!
|
nFramesPerBlock, // Watch the two here, the top and the bottom!
|
||||||
0),
|
0),
|
||||||
buffer_mid_idx(nchannels * nFramesPerBlock) {
|
buffer_mid_idx(nchannels * nFramesPerBlock) {
|
||||||
assert(nchannels > 0);
|
assert(nchannels > 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
class InBufHandler : public BufHandler {
|
class InBufHandler : public BufHandler {
|
||||||
bool monitorOutput;
|
bool monitorOutput;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
InBufHandler(DT9837A &daq, DaqCallback cb)
|
InBufHandler(DT9837A &daq, DaqCallback cb)
|
||||||
: BufHandler(daq._handle, daq.dtypeDescr(), daq.neninchannels(),
|
: BufHandler(daq._handle, daq.dtypeDescr(), daq.neninchannels(),
|
||||||
daq._nFramesPerBlock, cb, daq.samplerate())
|
daq._nFramesPerBlock, cb, daq.samplerate())
|
||||||
|
|
||||||
{
|
{
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
@ -196,40 +197,45 @@ class InBufHandler : public BufHandler {
|
|||||||
assert(indescs.size() == nchannels);
|
assert(indescs.size() == nchannels);
|
||||||
DEBUGTRACE_MESSAGE("Starting input scan");
|
DEBUGTRACE_MESSAGE("Starting input scan");
|
||||||
err = ulDaqInScan(_handle, indescs.data(), nchannels,
|
err = ulDaqInScan(_handle, indescs.data(), nchannels,
|
||||||
2 * nFramesPerBlock, // Watch the 2 here!
|
2 * nFramesPerBlock, // Watch the 2 here!
|
||||||
&samplerate, scanoptions, inscanflags, buf.data());
|
&samplerate, scanoptions, inscanflags, buf.data());
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
throw std::runtime_error("Could not start input DAQ");
|
throw std::runtime_error("Could not start input DAQ");
|
||||||
}
|
}
|
||||||
|
|
||||||
botenqueued = false;
|
botenqueued = false;
|
||||||
topenqueued = false;
|
topenqueued = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()() {
|
bool operator()() {
|
||||||
|
|
||||||
ChannelView cv(nchannels);
|
|
||||||
|
|
||||||
auto runCallback = ([&](us totalOffset) {
|
auto runCallback = ([&](us totalOffset) {
|
||||||
us monitoroffset = monitorOutput ? 1 : 0;
|
us monitoroffset = monitorOutput ? 1 : 0;
|
||||||
for (us channel = monitoroffset; channel < (nchannels - monitoroffset);
|
|
||||||
channel++) {
|
|
||||||
cv[channel] =
|
|
||||||
gsl::span(reinterpret_cast<uint8_t *>(
|
|
||||||
&buf[totalOffset + channel * nFramesPerBlock]),
|
|
||||||
nFramesPerBlock * sizeof(double));
|
|
||||||
}
|
|
||||||
if (monitorOutput) {
|
|
||||||
|
|
||||||
cv[0] = gsl::span(
|
DaqData data(nchannels, nFramesPerBlock,
|
||||||
reinterpret_cast<uint8_t *>(
|
DataTypeDescriptor::DataType::dtype_fl64);
|
||||||
&buf[totalOffset + (nchannels - 1) * nFramesPerBlock]),
|
us ch_no = 0;
|
||||||
nFramesPerBlock * sizeof(double));
|
if (monitorOutput) {
|
||||||
}
|
|
||||||
cb(cv, dtype_descr);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
reinterpret_cast<uint8_t *>(
|
||||||
|
&buf[totalOffset + (nchannels - 1) * nFramesPerBlock]),
|
||||||
|
nFramesPerBlock * sizeof(double));
|
||||||
|
}
|
||||||
|
/* if(mon */
|
||||||
|
|
||||||
|
/* for (us channel = monitoroffset; channel < (nchannels - monitoroffset);
|
||||||
|
*/
|
||||||
|
/* channel++) { */
|
||||||
|
/* cv[channel] = */
|
||||||
|
/* gsl::span(reinterpret_cast<uint8_t *>( */
|
||||||
|
/* &buf[totalOffset + channel * nFramesPerBlock]), */
|
||||||
|
/* nFramesPerBlock * sizeof(double)); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* cv[0] = gsl::span( */
|
||||||
|
/* cb(cv, dtype_descr); */
|
||||||
|
});
|
||||||
|
|
||||||
ScanStatus status;
|
ScanStatus status;
|
||||||
TransferStatus transferStatus;
|
TransferStatus transferStatus;
|
||||||
@ -240,124 +246,123 @@ class InBufHandler : public BufHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
increment = transferStatus.currentTotalCount - totalFramesCount;
|
increment = transferStatus.currentTotalCount - totalFramesCount;
|
||||||
totalFramesCount += increment;
|
totalFramesCount += increment;
|
||||||
|
|
||||||
if (increment > nFramesPerBlock) {
|
if (increment > nFramesPerBlock) {
|
||||||
cerr << "Error: overrun for input of DAQ!" << endl;
|
cerr << "Error: overrun for input of DAQ!" << endl;
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
assert(status == SS_RUNNING);
|
|
||||||
|
|
||||||
if (transferStatus.currentIndex < (long long)buffer_mid_idx) {
|
|
||||||
topenqueued = false;
|
|
||||||
if (!botenqueued) {
|
|
||||||
runCallback(nchannels * nFramesPerBlock);
|
|
||||||
botenqueued = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
assert(status == SS_RUNNING);
|
||||||
botenqueued = false;
|
|
||||||
if (!topenqueued) {
|
if (transferStatus.currentIndex < (long long)buffer_mid_idx) {
|
||||||
runCallback(0);
|
topenqueued = false;
|
||||||
topenqueued = true;
|
if (!botenqueued) {
|
||||||
|
runCallback(nchannels * nFramesPerBlock);
|
||||||
|
botenqueued = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
botenqueued = false;
|
||||||
|
if (!topenqueued) {
|
||||||
|
runCallback(0);
|
||||||
|
topenqueued = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
~InBufHandler() {
|
||||||
~InBufHandler() {
|
// At exit of the function, stop scanning.
|
||||||
// At exit of the function, stop scanning.
|
DEBUGTRACE_ENTER;
|
||||||
DEBUGTRACE_ENTER;
|
UlError err = ulDaqInScanStop(_handle);
|
||||||
UlError err = ulDaqInScanStop(_handle);
|
if (err != ERR_NO_ERROR) {
|
||||||
if (err != ERR_NO_ERROR) {
|
showErr(err);
|
||||||
showErr(err);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OutBufHandler : public BufHandler {
|
class OutBufHandler : public BufHandler {
|
||||||
public:
|
public:
|
||||||
OutBufHandler(DT9837A &daq, DaqCallback cb)
|
OutBufHandler(DT9837A &daq, DaqCallback cb)
|
||||||
: BufHandler(daq._handle, daq.dtypeDescr(), daq.neninchannels(),
|
: BufHandler(daq._handle, daq.dtypeDescr(), daq.neninchannels(),
|
||||||
daq._nFramesPerBlock, cb, daq.samplerate()) {
|
daq._nFramesPerBlock, cb, daq.samplerate()) {
|
||||||
|
|
||||||
DEBUGTRACE_MESSAGE("Starting output scan");
|
DEBUGTRACE_MESSAGE("Starting output scan");
|
||||||
AOutScanFlag outscanflags = AOUTSCAN_FF_DEFAULT;
|
AOutScanFlag outscanflags = AOUTSCAN_FF_DEFAULT;
|
||||||
ScanOption scanoptions = SO_CONTINUOUS;
|
ScanOption scanoptions = SO_CONTINUOUS;
|
||||||
UlError err =
|
UlError err =
|
||||||
ulAOutScan(_handle, 0, 0, BIP10VOLTS,
|
ulAOutScan(_handle, 0, 0, BIP10VOLTS,
|
||||||
2 * nFramesPerBlock, // Watch the 2 here!
|
2 * nFramesPerBlock, // Watch the 2 here!
|
||||||
&samplerate, scanoptions, outscanflags, buf.data());
|
&samplerate, scanoptions, outscanflags, buf.data());
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
throw runtime_error("Unable to start output on DAQ");
|
throw runtime_error("Unable to start output on DAQ");
|
||||||
}
|
}
|
||||||
|
|
||||||
botenqueued = false, topenqueued = true;
|
botenqueued = false, topenqueued = true;
|
||||||
|
|
||||||
// Run callback to first fill top part
|
// Run callback to first fill top part
|
||||||
ChannelView cv{gsl::span(reinterpret_cast<uint8_t *>(&buf[0]),
|
ChannelView cv{gsl::span(reinterpret_cast<uint8_t *>(&buf[0]),
|
||||||
nFramesPerBlock * sizeof(double))};
|
nFramesPerBlock * sizeof(double))};
|
||||||
cb(cv, dtype_descr);
|
cb(cv, dtype_descr);
|
||||||
}
|
}
|
||||||
void operator()() {
|
void operator()() {
|
||||||
|
|
||||||
assert(_handle != 0);
|
assert(_handle != 0);
|
||||||
|
|
||||||
UlError err = ERR_NO_ERROR;
|
UlError err = ERR_NO_ERROR;
|
||||||
|
|
||||||
ScanStatus status;
|
ScanStatus status;
|
||||||
TransferStatus transferStatus;
|
TransferStatus transferStatus;
|
||||||
|
|
||||||
err = ulAOutScanStatus(_handle, &status, &transferStatus);
|
err = ulAOutScanStatus(_handle, &status, &transferStatus);
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (status != SS_RUNNING) {
|
if (status != SS_RUNNING) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
increment = transferStatus.currentTotalCount - totalFramesCount;
|
increment = transferStatus.currentTotalCount - totalFramesCount;
|
||||||
totalFramesCount += increment;
|
totalFramesCount += increment;
|
||||||
|
|
||||||
if (increment > nFramesPerBlock) {
|
if (increment > nFramesPerBlock) {
|
||||||
cerr << "Error: underrun for output of DAQ!" << endl;
|
cerr << "Error: underrun for output of DAQ!" << endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transferStatus.currentIndex < buffer_mid_idx) {
|
if (transferStatus.currentIndex < buffer_mid_idx) {
|
||||||
topenqueued = false;
|
topenqueued = false;
|
||||||
if (!botenqueued) {
|
if (!botenqueued) {
|
||||||
|
|
||||||
ChannelView cv{
|
ChannelView cv{
|
||||||
gsl::span(reinterpret_cast<uint8_t *>(&buf[buffer_mid_idx]),
|
gsl::span(reinterpret_cast<uint8_t *>(&buf[buffer_mid_idx]),
|
||||||
nFramesPerBlock * sizeof(double))};
|
nFramesPerBlock * sizeof(double))};
|
||||||
cb(cv, dtype_descr);
|
cb(cv, dtype_descr);
|
||||||
botenqueued = true;
|
botenqueued = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
botenqueued = false;
|
botenqueued = false;
|
||||||
if (!topenqueued) {
|
if (!topenqueued) {
|
||||||
|
|
||||||
ChannelView cv{gsl::span(reinterpret_cast<uint8_t *>(&buf[0]),
|
ChannelView cv{gsl::span(reinterpret_cast<uint8_t *>(&buf[0]),
|
||||||
nFramesPerBlock * sizeof(double))};
|
nFramesPerBlock * sizeof(double))};
|
||||||
cb(cv, dtype_descr);
|
cb(cv, dtype_descr);
|
||||||
|
|
||||||
topenqueued = true;
|
topenqueued = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~OutBufHandler() {
|
~OutBufHandler() {
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
UlError err = ulAOutScanStop(_handle);
|
UlError err = ulAOutScanStop(_handle);
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void DT9837A::threadFcn(std::optional<DaqCallback> inCallback,
|
void DT9837A::threadFcn(std::optional<DaqCallback> inCallback,
|
||||||
std::optional<DaqCallback> outCallback) {
|
std::optional<DaqCallback> outCallback) {
|
||||||
|
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
std::unique_ptr<InBufHandler> ibh;
|
std::unique_ptr<InBufHandler> ibh;
|
||||||
@ -371,7 +376,7 @@ void DT9837A::threadFcn(std::optional<DaqCallback> inCallback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const double sleeptime =
|
const double sleeptime =
|
||||||
static_cast<double>(_nFramesPerBlock) / (16 * samplerate());
|
static_cast<double>(_nFramesPerBlock) / (16 * samplerate());
|
||||||
const us sleeptime_us = static_cast<us>(sleeptime * 1e6);
|
const us sleeptime_us = static_cast<us>(sleeptime * 1e6);
|
||||||
|
|
||||||
while (!_stopThread) {
|
while (!_stopThread) {
|
||||||
@ -386,92 +391,92 @@ void DT9837A::threadFcn(std::optional<DaqCallback> inCallback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Daq> createUlDaqDevice(const DeviceInfo &devinfo,
|
std::unique_ptr<Daq> createUlDaqDevice(const DeviceInfo &devinfo,
|
||||||
const DaqConfiguration &config) {
|
const DaqConfiguration &config) {
|
||||||
return std::make_unique<DT9837A>(devinfo, config);
|
return std::make_unique<DT9837A>(devinfo, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
DT9837A::DT9837A(const DeviceInfo &devinfo, const DaqConfiguration &config)
|
DT9837A::DT9837A(const DeviceInfo &devinfo, const DaqConfiguration &config)
|
||||||
: Daq(devinfo, config),
|
: Daq(devinfo, config),
|
||||||
_nFramesPerBlock(availableFramesPerBlock.at(framesPerBlockIndex)) {
|
_nFramesPerBlock(availableFramesPerBlock.at(framesPerBlockIndex)) {
|
||||||
|
|
||||||
// Some sanity checks
|
// Some sanity checks
|
||||||
if (eninchannels.size() != 4) {
|
if (eninchannels.size() != 4) {
|
||||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
throw runtime_error("Invalid length of enabled inChannels vector");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enoutchannels.size() != 1) {
|
if (enoutchannels.size() != 1) {
|
||||||
throw runtime_error("Invalid length of enabled outChannels vector");
|
throw runtime_error("Invalid length of enabled outChannels vector");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_nFramesPerBlock < 24 || _nFramesPerBlock > 8192) {
|
if (_nFramesPerBlock < 24 || _nFramesPerBlock > 8192) {
|
||||||
throw runtime_error("Unsensible number of samples per block chosen");
|
throw runtime_error("Unsensible number of samples per block chosen");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (samplerate() < 10000 || samplerate() > 51000) {
|
if (samplerate() < 10000 || samplerate() > 51000) {
|
||||||
throw runtime_error("Invalid sample rate");
|
throw runtime_error("Invalid sample rate");
|
||||||
}
|
}
|
||||||
|
|
||||||
DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API];
|
DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API];
|
||||||
DaqDeviceDescriptor descriptor;
|
DaqDeviceDescriptor descriptor;
|
||||||
DaqDeviceInterface interfaceType = ANY_IFC;
|
DaqDeviceInterface interfaceType = ANY_IFC;
|
||||||
|
|
||||||
UlError err;
|
UlError err;
|
||||||
|
|
||||||
us numdevs = MAX_DEV_COUNT_PER_API;
|
us numdevs = MAX_DEV_COUNT_PER_API;
|
||||||
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors,
|
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors,
|
||||||
(unsigned *)&numdevs);
|
(unsigned *)&numdevs);
|
||||||
|
if (err != ERR_NO_ERROR) {
|
||||||
|
throw runtime_error("Device inventarization failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((us)api_specific_devindex >= numdevs) {
|
||||||
|
throw runtime_error("Device number {deviceno} too high {err}. This could "
|
||||||
|
"happen when the device is currently not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor = devdescriptors[api_specific_devindex];
|
||||||
|
|
||||||
|
// get a handle to the DAQ device associated with the first descriptor
|
||||||
|
_handle = ulCreateDaqDevice(descriptor);
|
||||||
|
|
||||||
|
if (_handle == 0) {
|
||||||
|
throw runtime_error(
|
||||||
|
"Unable to create a handle to the specified DAQ "
|
||||||
|
"device. Is the device currently in use? Please make sure to set "
|
||||||
|
"the DAQ configuration in duplex mode if simultaneous input and "
|
||||||
|
"output is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ulConnectDaqDevice(_handle);
|
||||||
|
if (err != ERR_NO_ERROR) {
|
||||||
|
ulReleaseDaqDevice(_handle);
|
||||||
|
_handle = 0;
|
||||||
|
throw runtime_error(string("Unable to connect to device: " + showErr(err)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (us ch = 0; ch < 4; ch++) {
|
||||||
|
|
||||||
|
err = ulAISetConfigDbl(_handle, AI_CFG_CHAN_SENSOR_SENSITIVITY, ch, 1.0);
|
||||||
|
showErr(err);
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
throw runtime_error("Device inventarization failed");
|
throw runtime_error("Fatal: could normalize channel sensitivity");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((us)api_specific_devindex >= numdevs) {
|
CouplingMode cm = inputACCouplingMode[ch] ? CM_AC : CM_DC;
|
||||||
throw runtime_error("Device number {deviceno} too high {err}. This could "
|
err = ulAISetConfig(_handle, AI_CFG_CHAN_COUPLING_MODE, ch, cm);
|
||||||
"happen when the device is currently not connected");
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor = devdescriptors[api_specific_devindex];
|
|
||||||
|
|
||||||
// get a handle to the DAQ device associated with the first descriptor
|
|
||||||
_handle = ulCreateDaqDevice(descriptor);
|
|
||||||
|
|
||||||
if (_handle == 0) {
|
|
||||||
throw runtime_error(
|
|
||||||
"Unable to create a handle to the specified DAQ "
|
|
||||||
"device. Is the device currently in use? Please make sure to set "
|
|
||||||
"the DAQ configuration in duplex mode if simultaneous input and "
|
|
||||||
"output is required.");
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ulConnectDaqDevice(_handle);
|
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
ulReleaseDaqDevice(_handle);
|
|
||||||
_handle = 0;
|
|
||||||
throw runtime_error(string("Unable to connect to device: " + showErr(err)));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (us ch = 0; ch < 4; ch++) {
|
|
||||||
|
|
||||||
err = ulAISetConfigDbl(_handle, AI_CFG_CHAN_SENSOR_SENSITIVITY, ch, 1.0);
|
|
||||||
showErr(err);
|
showErr(err);
|
||||||
if (err != ERR_NO_ERROR) {
|
throw runtime_error("Fatal: could not set AC/DC coupling mode");
|
||||||
throw runtime_error("Fatal: could normalize channel sensitivity");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
CouplingMode cm = inputACCouplingMode[ch] ? CM_AC : CM_DC;
|
IepeMode iepe = inputIEPEEnabled[ch] ? IEPE_ENABLED : IEPE_DISABLED;
|
||||||
err = ulAISetConfig(_handle, AI_CFG_CHAN_COUPLING_MODE, ch, cm);
|
err = ulAISetConfig(_handle, AI_CFG_CHAN_IEPE_MODE, ch, iepe);
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
throw runtime_error("Fatal: could not set AC/DC coupling mode");
|
throw runtime_error("Fatal: could not set IEPE mode");
|
||||||
}
|
|
||||||
|
|
||||||
IepeMode iepe = inputIEPEEnabled[ch] ? IEPE_ENABLED : IEPE_DISABLED;
|
|
||||||
err = ulAISetConfig(_handle, AI_CFG_CHAN_IEPE_MODE, ch, iepe);
|
|
||||||
if (err != ERR_NO_ERROR) {
|
|
||||||
showErr(err);
|
|
||||||
throw runtime_error("Fatal: could not set IEPE mode");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void fillUlDaqDeviceInfo(std::vector<DeviceInfo> &devinfolist) {
|
void fillUlDaqDeviceInfo(std::vector<DeviceInfo> &devinfolist) {
|
||||||
|
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
@ -484,7 +489,7 @@ void fillUlDaqDeviceInfo(std::vector<DeviceInfo> &devinfolist) {
|
|||||||
DaqDeviceInterface interfaceType = ANY_IFC;
|
DaqDeviceInterface interfaceType = ANY_IFC;
|
||||||
|
|
||||||
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors,
|
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors,
|
||||||
static_cast<unsigned *>(&numdevs));
|
static_cast<unsigned *>(&numdevs));
|
||||||
|
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
throw runtime_error("UlDaq device inventarization failed");
|
throw runtime_error("UlDaq device inventarization failed");
|
||||||
@ -502,20 +507,20 @@ void fillUlDaqDeviceInfo(std::vector<DeviceInfo> &devinfolist) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (descriptor.devInterface) {
|
switch (descriptor.devInterface) {
|
||||||
case USB_IFC:
|
case USB_IFC:
|
||||||
name = "USB - ";
|
name = "USB - ";
|
||||||
break;
|
break;
|
||||||
case BLUETOOTH_IFC:
|
case BLUETOOTH_IFC:
|
||||||
/* devinfo. */
|
/* devinfo. */
|
||||||
name = "Bluetooth - ";
|
name = "Bluetooth - ";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ETHERNET_IFC:
|
case ETHERNET_IFC:
|
||||||
/* devinfo. */
|
/* devinfo. */
|
||||||
name = "Ethernet - ";
|
name = "Ethernet - ";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
name = "Uknown interface = ";
|
name = "Uknown interface = ";
|
||||||
}
|
}
|
||||||
|
|
||||||
name += string(descriptor.productName) + " " + string(descriptor.uniqueId);
|
name += string(descriptor.productName) + " " + string(descriptor.uniqueId);
|
||||||
@ -527,8 +532,8 @@ void fillUlDaqDeviceInfo(std::vector<DeviceInfo> &devinfolist) {
|
|||||||
devinfo.prefDataTypeIndex = 0;
|
devinfo.prefDataTypeIndex = 0;
|
||||||
|
|
||||||
devinfo.availableSampleRates = {8000, 10000, 11025, 16000, 20000,
|
devinfo.availableSampleRates = {8000, 10000, 11025, 16000, 20000,
|
||||||
22050, 24000, 32000, 44056, 44100,
|
22050, 24000, 32000, 44056, 44100,
|
||||||
47250, 48000, 50000, 50400, 51000};
|
47250, 48000, 50000, 50400, 51000};
|
||||||
|
|
||||||
devinfo.prefSampleRateIndex = 11;
|
devinfo.prefSampleRateIndex = 11;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user