diff --git a/CMakeLists.txt b/CMakeLists.txt index 1698e70..f432355 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,8 +144,9 @@ set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py") set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py" "${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py" - "wrappers" - "lasp_daq") + # "wrappers" + # "lasp_device_lib") + ) set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") diff --git a/lasp/device/lasp_daq.h b/lasp/device/lasp_daq.h index db462d6..8027f85 100644 --- a/lasp/device/lasp_daq.h +++ b/lasp/device/lasp_daq.h @@ -9,8 +9,8 @@ #include /** - * @brief Data coming from / going to DAQ. Non-interleaved format, which means - * data in buffer is ordered by channel: _ptr[sample+channel*nsamples] + * @brief Data coming from / going to DAQ. **Non-interleaved format**, which means + * data in buffer is ordered by channel: _ptr[sample+channel*nframes] */ class DaqData { protected: @@ -38,24 +38,13 @@ public: us size_bytes() const { return _data.size(); } }; -/** - * @brief Typed DaqData, in which the type is specified - * - * @tparam T - */ -template class TypedDaqData : public DaqData { - T *data() { return static_cast(_data.data()); } -}; - /** * @brief Callback of DAQ. Called with arguments of a vector of data * spans for each channel, and a datatype descriptor. Callback should return * false for a stop request. */ -using ChannelView = std::vector>; using DaqCallback = - std::function; + std::function)>; /** * @brief Base cass for all DAQ instances diff --git a/lasp/device/lasp_rtaudiodaq.cpp b/lasp/device/lasp_rtaudiodaq.cpp index 8ebea84..d385c57 100644 --- a/lasp/device/lasp_rtaudiodaq.cpp +++ b/lasp/device/lasp_rtaudiodaq.cpp @@ -1,14 +1,17 @@ -#if LASP_HAS_RTAUDIO == 1 #include "lasp_rtaudiodaq.h" +#if LASP_HAS_RTAUDIO == 1 +#include "lasp_daqconfig.h" #include #include #include #include #include +using std::atomic; using std::cerr; using std::endl; -using std::atomic; +using std::runtime_error; +using std::vector; void fillRtAudioDeviceInfo(vector &devinfolist) { @@ -25,6 +28,7 @@ void fillRtAudioDeviceInfo(vector &devinfolist) { // Device capabilities not successfully probed. Continue to next continue; } + // "Our device info struct" DeviceInfo d; switch (api) { case RtAudio::LINUX_ALSA: @@ -66,19 +70,24 @@ void fillRtAudioDeviceInfo(vector &devinfolist) { RtAudioFormat formats = devinfo.nativeFormats; if (formats & RTAUDIO_SINT8) { - d.availableDataTypes.push_back(dtype_int8); + d.availableDataTypes.push_back( + DataTypeDescriptor::DataType::dtype_int8); } 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) { - d.availableDataTypes.push_back(dtype_int24); - } - if (formats & RTAUDIO_SINT32) { - d.availableDataTypes.push_back(dtype_fl32); + d.availableDataTypes.push_back( + DataTypeDescriptor::DataType::dtype_fl32); } if (formats & RTAUDIO_FLOAT64) { - d.availableDataTypes.push_back(dtype_fl64); + d.availableDataTypes.push_back( + DataTypeDescriptor::DataType::dtype_fl64); } if (d.availableDataTypes.size() == 0) { std::cerr << "RtAudio: No data types found in device!" << endl; @@ -86,11 +95,7 @@ void fillRtAudioDeviceInfo(vector &devinfolist) { d.prefDataTypeIndex = d.availableDataTypes.size() - 1; - d.availableFramesPerBlock.push_back(512); - d.availableFramesPerBlock.push_back(1024); - d.availableFramesPerBlock.push_back(2048); - d.availableFramesPerBlock.push_back(4096); - d.availableFramesPerBlock.push_back(8192); + d.availableFramesPerBlock = {512, 1024, 2048, 4096, 8192}; d.prefFramesPerBlockIndex = 1; devinfolist.push_back(d); @@ -103,162 +108,206 @@ int mycallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, void myerrorcallback(RtAudioError::Type, const string &errorText); -class AudioDaq : public Daq { +class RtAudioDaq : public Daq { - SafeQueue *inqueue = NULL; - SafeQueue *outqueue = NULL; - SafeQueue *outDelayqueue = NULL; + RtAudio rtaudio; + const us nFramesPerBlock; - RtAudio *rtaudio = NULL; - RtAudio::StreamParameters *instreamparams = nullptr; - RtAudio::StreamParameters *outstreamparams = nullptr; - - us nFramesPerBlock; + RtAudioDaq(const RtAudioDaq &) = delete; + RtAudioDaq &operator=(const RtAudioDaq &) = delete; public: - AudioDaq(const DeviceInfo &devinfo, const DaqConfiguration &config) - : Daq(devinfo, config) { + RtAudioDaq(const DeviceInfo &devinfo, const DaqConfiguration &config) + : Daq(devinfo, config), + rtaudio(static_cast(devinfo.api.api_specific_subcode)), + nFramesPerBlock(Daq::framesPerBlock()) { - nFramesPerBlock = this->framesPerBlock(); + std::unique_ptr 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) { - instreamparams = new RtAudio::StreamParameters(); - instreamparams->nChannels = getHighestInChannel() + 1; - if (instreamparams->nChannels < 1) { + if (neninchannels() > 0) { + + inParams = std::make_unique(); + + // +1 to get the count. + inParams->nChannels = getHighestInChannel() + 1; + if (inParams->nChannels < 1) { throw runtime_error("Invalid input number of channels"); } - instreamparams->firstChannel = 0; - instreamparams->deviceId = devinfo.api_specific_devindex; - } + inParams->firstChannel = 0; + inParams->deviceId = devinfo.api_specific_devindex; - if (nenoutchannels() > 0) { - outstreamparams = new RtAudio::StreamParameters(); - outstreamparams->nChannels = getHighestOutChannel() + 1; - if (outstreamparams->nChannels < 1) { + } else { + + outParams = std::make_unique(); + + outParams->nChannels = getHighestOutChannel() + 1; + if (outParams->nChannels < 1) { throw runtime_error("Invalid output number of channels"); } - outstreamparams->firstChannel = 0; - outstreamparams->deviceId = devinfo.api_specific_devindex; + outParams->firstChannel = 0; + outParams->deviceId = devinfo.api_specific_devindex; } RtAudio::StreamOptions streamoptions; - streamoptions.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_HOG_DEVICE; + streamoptions.flags = RTAUDIO_HOG_DEVICE; streamoptions.numberOfBuffers = 2; streamoptions.streamName = "RtAudio stream"; streamoptions.priority = 0; RtAudioFormat format; - const DataType dtype = DataType(); + using Dtype = DataTypeDescriptor::DataType; + const Dtype dtype = dataType(); switch (dtype) { - case dtype_fl32: + case Dtype::dtype_fl32: format = RTAUDIO_FLOAT32; break; - case dtype_fl64: + case Dtype::dtype_fl64: format = RTAUDIO_FLOAT64; break; - case dtype_int8: + case Dtype::dtype_int8: format = RTAUDIO_SINT8; break; - case dtype_int16: + case Dtype::dtype_int16: format = RTAUDIO_SINT16; break; - case dtype_int32: + case Dtype::dtype_int32: format = RTAUDIO_SINT32; break; default: - throw runtime_error("Invalid data type"); + throw runtime_error("Invalid data type specified for DAQ stream."); break; } - try { - rtaudio = new RtAudio((RtAudio::Api)devinfo.api.api_specific_subcode); - if (!rtaudio) { - throw runtime_error("RtAudio allocation failed"); + // Copy here, as it is used to return the *actual* number of frames per + // block. + unsigned int nFramesPerBlock_copy = nFramesPerBlock; + + // Final step: open the stream. + rtaudio.openStream(&(*outParams), &(*inParams), format, + static_cast(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(); + + 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 inCallback, + std::optional outCallback) { + + assert(!monitorOutput); + + if (isRunning()) { + throw runtime_error("Stream already running"); } - friend int mycallback(void *outputBuffer, void *inputBuffer, - unsigned int nFrames, double streamTime, - RtAudioStreamStatus status, void *userData); + 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); + rtaudio->startStream(); +} - void start(SafeQueue *inqueue, SafeQueue *outqueue) { - this->inqueue = inqueue; - this->outqueue = outqueue; - if (monitorOutput) { - this->outDelayqueue = new SafeQueue(); - } - - 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"); - } +void stop() { + if (!isRunning()) { + cerr << "Stream is already stopped" << endl; + } else { assert(rtaudio); - rtaudio->startStream(); + rtaudio->stopStream(); } - - void stop() { - - 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; - } + if (inqueue) { + inqueue = nullptr; } - bool isRunning() const { return (rtaudio && rtaudio->isStreamRunning()); } - - ~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 (outqueue) { + outqueue = nullptr; } -}; + 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, const DaqConfiguration &config) { @@ -280,90 +329,15 @@ int mycallback(void *outputBuffervoid, void *inputBuffervoid, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) { - u_int8_t *inputBuffer = (u_int8_t *)inputBuffervoid; - u_int8_t *outputBuffer = (u_int8_t *)outputBuffervoid; + void myerrorcallback(RtAudioError::Type, const string &errorText) { + cerr << errorText << endl; + } + int mycallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, + double streamTime, RtAudioStreamStatus status, + void *userData) { - AudioDaq *daq = (AudioDaq *)userData; - DataType dtype = daq->dataType(); - 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 *inqueue = daq->inqueue; - SafeQueue *outqueue = daq->outqueue; - SafeQueue *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); + return static_cast(userData)->streamCallback( + outputBuffer, inputBuffer, nFrames, streamTime, status); } - 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 diff --git a/lasp/device/lasp_uldaq.cpp b/lasp/device/lasp_uldaq.cpp index a804161..12d437a 100644 --- a/lasp/device/lasp_uldaq.cpp +++ b/lasp/device/lasp_uldaq.cpp @@ -60,9 +60,9 @@ class DT9837A : public Daq { const us _nFramesPerBlock; void threadFcn(std::optional inCallback, - std::optional outcallback); + std::optional outcallback); - public: +public: DT9837A(const DeviceInfo &devinfo, const DaqConfiguration &config); ~DT9837A() { @@ -81,7 +81,7 @@ class DT9837A : public Daq { bool isRunning() const override final { return _thread.joinable(); } virtual void start(std::optional inCallback, - std::optional outCallback) override final; + std::optional outCallback) override final; void stop() override final { DEBUGTRACE_ENTER; @@ -100,7 +100,7 @@ class DT9837A : public Daq { }; void DT9837A::start(std::optional inCallback, - std::optional outCallback) { + std::optional outCallback) { DEBUGTRACE_ENTER; if (isRunning()) { throw runtime_error("DAQ is already running"); @@ -118,37 +118,38 @@ void DT9837A::start(std::optional inCallback, } class BufHandler { - protected: - DaqDeviceHandle _handle; - const DataTypeDescriptor dtype_descr; - us nchannels, nFramesPerBlock; - DaqCallback cb; - double samplerate; - dvec buf; - bool topenqueued, botenqueued; - us increment = 0; - us totalFramesCount = 0; - long long buffer_mid_idx; +protected: + DaqDeviceHandle _handle; + const DataTypeDescriptor dtype_descr; + us nchannels, nFramesPerBlock; + DaqCallback cb; + double samplerate; + dvec buf; + bool topenqueued, botenqueued; + us increment = 0; + us totalFramesCount = 0; + long long buffer_mid_idx; - public: - BufHandler(DaqDeviceHandle handle, const DataTypeDescriptor dtype_descr, - const us nchannels, const us nFramesPerBlock, DaqCallback cb, - const double samplerate) +public: + BufHandler(DaqDeviceHandle handle, const DataTypeDescriptor dtype_descr, + const us nchannels, const us nFramesPerBlock, DaqCallback cb, + const double samplerate) : _handle(handle), dtype_descr(dtype_descr), nchannels(nchannels), - nFramesPerBlock(nFramesPerBlock), cb(cb), samplerate(samplerate), - buf(2 * nchannels * - nFramesPerBlock, // Watch the two here, the top and the bottom! - 0), - buffer_mid_idx(nchannels * nFramesPerBlock) { - assert(nchannels > 0); - } + nFramesPerBlock(nFramesPerBlock), cb(cb), samplerate(samplerate), + buf(2 * nchannels * + nFramesPerBlock, // Watch the two here, the top and the bottom! + 0), + buffer_mid_idx(nchannels * nFramesPerBlock) { + assert(nchannels > 0); + } }; class InBufHandler : public BufHandler { bool monitorOutput; - public: + +public: InBufHandler(DT9837A &daq, DaqCallback cb) - : BufHandler(daq._handle, daq.dtypeDescr(), daq.neninchannels(), - daq._nFramesPerBlock, cb, daq.samplerate()) + : BufHandler(daq._handle, daq.dtypeDescr(), daq.neninchannels(), + daq._nFramesPerBlock, cb, daq.samplerate()) { DEBUGTRACE_ENTER; @@ -196,40 +197,45 @@ class InBufHandler : public BufHandler { assert(indescs.size() == nchannels); DEBUGTRACE_MESSAGE("Starting input scan"); err = ulDaqInScan(_handle, indescs.data(), nchannels, - 2 * nFramesPerBlock, // Watch the 2 here! - &samplerate, scanoptions, inscanflags, buf.data()); + 2 * nFramesPerBlock, // Watch the 2 here! + &samplerate, scanoptions, inscanflags, buf.data()); if (err != ERR_NO_ERROR) { showErr(err); throw std::runtime_error("Could not start input DAQ"); } - botenqueued = false; + botenqueued = false; topenqueued = false; } - void operator()() { - - ChannelView cv(nchannels); + bool operator()() { auto runCallback = ([&](us totalOffset) { - us monitoroffset = monitorOutput ? 1 : 0; - for (us channel = monitoroffset; channel < (nchannels - monitoroffset); - channel++) { - cv[channel] = - gsl::span(reinterpret_cast( - &buf[totalOffset + channel * nFramesPerBlock]), - nFramesPerBlock * sizeof(double)); - } - if (monitorOutput) { + us monitoroffset = monitorOutput ? 1 : 0; - cv[0] = gsl::span( - reinterpret_cast( - &buf[totalOffset + (nchannels - 1) * nFramesPerBlock]), - nFramesPerBlock * sizeof(double)); - } - cb(cv, dtype_descr); - }); + DaqData data(nchannels, nFramesPerBlock, + DataTypeDescriptor::DataType::dtype_fl64); + us ch_no = 0; + if (monitorOutput) { + reinterpret_cast( + &buf[totalOffset + (nchannels - 1) * nFramesPerBlock]), + nFramesPerBlock * sizeof(double)); + } + /* if(mon */ + + /* for (us channel = monitoroffset; channel < (nchannels - monitoroffset); + */ + /* channel++) { */ + /* cv[channel] = */ + /* gsl::span(reinterpret_cast( */ + /* &buf[totalOffset + channel * nFramesPerBlock]), */ + /* nFramesPerBlock * sizeof(double)); */ + /* } */ + + /* cv[0] = gsl::span( */ + /* cb(cv, dtype_descr); */ + }); ScanStatus status; TransferStatus transferStatus; @@ -240,124 +246,123 @@ class InBufHandler : public BufHandler { return; } - increment = transferStatus.currentTotalCount - totalFramesCount; - totalFramesCount += increment; + increment = transferStatus.currentTotalCount - totalFramesCount; + totalFramesCount += increment; - if (increment > nFramesPerBlock) { - cerr << "Error: overrun for input of DAQ!" << endl; - return; - } - assert(status == SS_RUNNING); - - if (transferStatus.currentIndex < (long long)buffer_mid_idx) { - topenqueued = false; - if (!botenqueued) { - runCallback(nchannels * nFramesPerBlock); - botenqueued = true; + if (increment > nFramesPerBlock) { + cerr << "Error: overrun for input of DAQ!" << endl; + return; } - } else { - botenqueued = false; - if (!topenqueued) { - runCallback(0); - topenqueued = true; + assert(status == SS_RUNNING); + + if (transferStatus.currentIndex < (long long)buffer_mid_idx) { + topenqueued = false; + if (!botenqueued) { + runCallback(nchannels * nFramesPerBlock); + botenqueued = true; + } + } else { + botenqueued = false; + if (!topenqueued) { + runCallback(0); + topenqueued = true; + } } } -} -~InBufHandler() { - // At exit of the function, stop scanning. - DEBUGTRACE_ENTER; - UlError err = ulDaqInScanStop(_handle); - if (err != ERR_NO_ERROR) { - showErr(err); + ~InBufHandler() { + // At exit of the function, stop scanning. + DEBUGTRACE_ENTER; + UlError err = ulDaqInScanStop(_handle); + if (err != ERR_NO_ERROR) { + showErr(err); + } } -} - }; class OutBufHandler : public BufHandler { - public: - OutBufHandler(DT9837A &daq, DaqCallback cb) +public: + OutBufHandler(DT9837A &daq, DaqCallback cb) : BufHandler(daq._handle, daq.dtypeDescr(), daq.neninchannels(), - daq._nFramesPerBlock, cb, daq.samplerate()) { + daq._nFramesPerBlock, cb, daq.samplerate()) { - DEBUGTRACE_MESSAGE("Starting output scan"); - AOutScanFlag outscanflags = AOUTSCAN_FF_DEFAULT; - ScanOption scanoptions = SO_CONTINUOUS; - UlError err = - ulAOutScan(_handle, 0, 0, BIP10VOLTS, - 2 * nFramesPerBlock, // Watch the 2 here! - &samplerate, scanoptions, outscanflags, buf.data()); - if (err != ERR_NO_ERROR) { - showErr(err); - throw runtime_error("Unable to start output on DAQ"); - } + DEBUGTRACE_MESSAGE("Starting output scan"); + AOutScanFlag outscanflags = AOUTSCAN_FF_DEFAULT; + ScanOption scanoptions = SO_CONTINUOUS; + UlError err = + ulAOutScan(_handle, 0, 0, BIP10VOLTS, + 2 * nFramesPerBlock, // Watch the 2 here! + &samplerate, scanoptions, outscanflags, buf.data()); + if (err != ERR_NO_ERROR) { + showErr(err); + throw runtime_error("Unable to start output on DAQ"); + } - botenqueued = false, topenqueued = true; + botenqueued = false, topenqueued = true; - // Run callback to first fill top part - ChannelView cv{gsl::span(reinterpret_cast(&buf[0]), - nFramesPerBlock * sizeof(double))}; - cb(cv, dtype_descr); - } - void operator()() { + // Run callback to first fill top part + ChannelView cv{gsl::span(reinterpret_cast(&buf[0]), + nFramesPerBlock * sizeof(double))}; + cb(cv, dtype_descr); + } + void operator()() { - assert(_handle != 0); + assert(_handle != 0); - UlError err = ERR_NO_ERROR; + UlError err = ERR_NO_ERROR; - ScanStatus status; - TransferStatus transferStatus; + ScanStatus status; + TransferStatus transferStatus; - err = ulAOutScanStatus(_handle, &status, &transferStatus); - if (err != ERR_NO_ERROR) { - showErr(err); - return; - } - if (status != SS_RUNNING) { - return; - } - increment = transferStatus.currentTotalCount - totalFramesCount; - totalFramesCount += increment; + err = ulAOutScanStatus(_handle, &status, &transferStatus); + if (err != ERR_NO_ERROR) { + showErr(err); + return; + } + if (status != SS_RUNNING) { + return; + } + increment = transferStatus.currentTotalCount - totalFramesCount; + totalFramesCount += increment; - if (increment > nFramesPerBlock) { - cerr << "Error: underrun for output of DAQ!" << endl; - return; - } + if (increment > nFramesPerBlock) { + cerr << "Error: underrun for output of DAQ!" << endl; + return; + } - if (transferStatus.currentIndex < buffer_mid_idx) { - topenqueued = false; - if (!botenqueued) { + if (transferStatus.currentIndex < buffer_mid_idx) { + topenqueued = false; + if (!botenqueued) { - ChannelView cv{ + ChannelView cv{ gsl::span(reinterpret_cast(&buf[buffer_mid_idx]), - nFramesPerBlock * sizeof(double))}; - cb(cv, dtype_descr); - botenqueued = true; - } - } else { - botenqueued = false; - if (!topenqueued) { + nFramesPerBlock * sizeof(double))}; + cb(cv, dtype_descr); + botenqueued = true; + } + } else { + botenqueued = false; + if (!topenqueued) { - ChannelView cv{gsl::span(reinterpret_cast(&buf[0]), - nFramesPerBlock * sizeof(double))}; - cb(cv, dtype_descr); + ChannelView cv{gsl::span(reinterpret_cast(&buf[0]), + nFramesPerBlock * sizeof(double))}; + cb(cv, dtype_descr); - topenqueued = true; - } + topenqueued = true; } } + } - ~OutBufHandler() { - DEBUGTRACE_ENTER; - UlError err = ulAOutScanStop(_handle); - if (err != ERR_NO_ERROR) { - showErr(err); - } + ~OutBufHandler() { + DEBUGTRACE_ENTER; + UlError err = ulAOutScanStop(_handle); + if (err != ERR_NO_ERROR) { + showErr(err); } + } }; void DT9837A::threadFcn(std::optional inCallback, - std::optional outCallback) { + std::optional outCallback) { DEBUGTRACE_ENTER; std::unique_ptr ibh; @@ -371,7 +376,7 @@ void DT9837A::threadFcn(std::optional inCallback, } const double sleeptime = - static_cast(_nFramesPerBlock) / (16 * samplerate()); + static_cast(_nFramesPerBlock) / (16 * samplerate()); const us sleeptime_us = static_cast(sleeptime * 1e6); while (!_stopThread) { @@ -386,92 +391,92 @@ void DT9837A::threadFcn(std::optional inCallback, } std::unique_ptr createUlDaqDevice(const DeviceInfo &devinfo, - const DaqConfiguration &config) { + const DaqConfiguration &config) { return std::make_unique(devinfo, config); } DT9837A::DT9837A(const DeviceInfo &devinfo, const DaqConfiguration &config) - : Daq(devinfo, config), - _nFramesPerBlock(availableFramesPerBlock.at(framesPerBlockIndex)) { + : Daq(devinfo, config), + _nFramesPerBlock(availableFramesPerBlock.at(framesPerBlockIndex)) { - // Some sanity checks - if (eninchannels.size() != 4) { - throw runtime_error("Invalid length of enabled inChannels vector"); - } + // Some sanity checks + if (eninchannels.size() != 4) { + throw runtime_error("Invalid length of enabled inChannels vector"); + } - if (enoutchannels.size() != 1) { - throw runtime_error("Invalid length of enabled outChannels vector"); - } + if (enoutchannels.size() != 1) { + throw runtime_error("Invalid length of enabled outChannels vector"); + } - if (_nFramesPerBlock < 24 || _nFramesPerBlock > 8192) { - throw runtime_error("Unsensible number of samples per block chosen"); - } + if (_nFramesPerBlock < 24 || _nFramesPerBlock > 8192) { + throw runtime_error("Unsensible number of samples per block chosen"); + } - if (samplerate() < 10000 || samplerate() > 51000) { - throw runtime_error("Invalid sample rate"); - } + if (samplerate() < 10000 || samplerate() > 51000) { + throw runtime_error("Invalid sample rate"); + } - DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API]; - DaqDeviceDescriptor descriptor; - DaqDeviceInterface interfaceType = ANY_IFC; + DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API]; + DaqDeviceDescriptor descriptor; + DaqDeviceInterface interfaceType = ANY_IFC; - UlError err; + UlError err; - us numdevs = MAX_DEV_COUNT_PER_API; - err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, - (unsigned *)&numdevs); + us numdevs = MAX_DEV_COUNT_PER_API; + err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, + (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) { - throw runtime_error("Device inventarization failed"); + throw runtime_error("Fatal: could normalize channel sensitivity"); } - 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); + CouplingMode cm = inputACCouplingMode[ch] ? CM_AC : CM_DC; + err = ulAISetConfig(_handle, AI_CFG_CHAN_COUPLING_MODE, ch, cm); 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) { - throw runtime_error("Fatal: could normalize channel sensitivity"); - } + throw runtime_error("Fatal: could not set AC/DC coupling mode"); + } - CouplingMode cm = inputACCouplingMode[ch] ? CM_AC : CM_DC; - err = ulAISetConfig(_handle, AI_CFG_CHAN_COUPLING_MODE, ch, cm); - if (err != ERR_NO_ERROR) { - showErr(err); - throw runtime_error("Fatal: could not set AC/DC coupling 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"); - } + 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 &devinfolist) { DEBUGTRACE_ENTER; @@ -484,7 +489,7 @@ void fillUlDaqDeviceInfo(std::vector &devinfolist) { DaqDeviceInterface interfaceType = ANY_IFC; err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, - static_cast(&numdevs)); + static_cast(&numdevs)); if (err != ERR_NO_ERROR) { throw runtime_error("UlDaq device inventarization failed"); @@ -502,20 +507,20 @@ void fillUlDaqDeviceInfo(std::vector &devinfolist) { } switch (descriptor.devInterface) { - case USB_IFC: - name = "USB - "; - break; - case BLUETOOTH_IFC: - /* devinfo. */ - name = "Bluetooth - "; - break; + case USB_IFC: + name = "USB - "; + break; + case BLUETOOTH_IFC: + /* devinfo. */ + name = "Bluetooth - "; + break; - case ETHERNET_IFC: - /* devinfo. */ - name = "Ethernet - "; - break; - default: - name = "Uknown interface = "; + case ETHERNET_IFC: + /* devinfo. */ + name = "Ethernet - "; + break; + default: + name = "Uknown interface = "; } name += string(descriptor.productName) + " " + string(descriptor.uniqueId); @@ -527,8 +532,8 @@ void fillUlDaqDeviceInfo(std::vector &devinfolist) { devinfo.prefDataTypeIndex = 0; devinfo.availableSampleRates = {8000, 10000, 11025, 16000, 20000, - 22050, 24000, 32000, 44056, 44100, - 47250, 48000, 50000, 50400, 51000}; + 22050, 24000, 32000, 44056, 44100, + 47250, 48000, 50000, 50400, 51000}; devinfo.prefSampleRateIndex = 11;