/* #define DEBUGTRACE_ENABLED */ #include "debugtrace.hpp" #include "lasp_config.h" #if LASP_HAS_ULDAQ == 1 #include "lasp_daqconfig.h" #include "lasp_uldaq.h" #include "lasp_uldaq_bufhandler.h" #include "lasp_uldaq_impl.h" using namespace std::literals::chrono_literals; DT9837A::~DT9837A() { DEBUGTRACE_ENTER; UlError err; if (isRunning()) { DEBUGTRACE_PRINT("Stop UlDAQ from destructor"); stop(); } if (_handle) { DEBUGTRACE_PRINT("Disconnecting and releasing DaqDevice"); /* err = ulDisconnectDaqDevice(_handle); */ /* showErr(err); */ err = ulReleaseDaqDevice(_handle); showErr(err); } } DT9837A::DT9837A(const UlDaqDeviceInfo &devinfo, const DaqConfiguration &config) : Daq(devinfo, config), _nFramesPerBlock(availableFramesPerBlock.at(framesPerBlockIndex)) { const DaqDeviceDescriptor &descriptor = devinfo._uldaqDescriptor; DEBUGTRACE_PRINT(string("Device: ") + descriptor.productName); DEBUGTRACE_PRINT(string("Product id: ") + to_string(descriptor.productId)); DEBUGTRACE_PRINT(string("Dev string: ") + descriptor.devString); DEBUGTRACE_PRINT(string("Unique id: ") + descriptor.uniqueId); // get a handle to the DAQ device associated with the first descriptor _handle = ulCreateDaqDevice(descriptor); if (_handle == 0) { throw rte("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."); } UlError err = ulConnectDaqDevice(_handle); if (err != ERR_NO_ERROR) { ulReleaseDaqDevice(_handle); _handle = 0; throw rte("Unable to connect to device: " + getErrMsg(err)); } /// Loop over input channels, set parameters 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 rte("Fatal: could normalize channel sensitivity"); } CouplingMode cm = inchannel_config.at(ch).ACCouplingMode ? CM_AC : CM_DC; err = ulAISetConfig(_handle, AI_CFG_CHAN_COUPLING_MODE, ch, cm); if (err != ERR_NO_ERROR) { showErr(err); throw rte("Fatal: could not set AC/DC coupling mode"); } IepeMode iepe = inchannel_config.at(ch).IEPEEnabled ? IEPE_ENABLED : IEPE_DISABLED; err = ulAISetConfig(_handle, AI_CFG_CHAN_IEPE_MODE, ch, iepe); if (err != ERR_NO_ERROR) { showErr(err); throw rte("Fatal: could not set IEPE mode"); } } } bool DT9837A::isRunning() const { DEBUGTRACE_ENTER; /* return _thread.joinable(); */ StreamStatus status = _streamStatus; return status.isRunning; } void DT9837A::stop() { DEBUGTRACE_ENTER; StreamStatus status = _streamStatus; status.isRunning = true; _streamStatus = status; if (!isRunning()) { throw rte("No data acquisition running"); } // Stop the thread and join it _stopThread = true; assert(_thread.joinable()); _thread.join(); _stopThread = false; // Update stream status status.isRunning = false; _streamStatus = status; } void DT9837A::start(InDaqCallback inCallback, OutDaqCallback outCallback) { DEBUGTRACE_ENTER; if (isRunning()) { throw rte("DAQ is already running"); } if (neninchannels() > 0) { if (!inCallback) throw rte("DAQ requires a callback for input data"); } if (nenoutchannels() > 0) { if (!outCallback) throw rte("DAQ requires a callback for output data"); } assert(neninchannels() + nenoutchannels() > 0); _thread = std::thread(&DT9837A::threadFcn, this, inCallback, outCallback); } void DT9837A::threadFcn(InDaqCallback inCallback, OutDaqCallback outCallback) { DEBUGTRACE_ENTER; try { std::unique_ptr obh; std::unique_ptr ibh; StreamStatus status = _streamStatus; status.isRunning = true; _streamStatus = status; if (nenoutchannels() > 0) { assert(outCallback); obh = std::make_unique(*this, outCallback); } if (neninchannels() > 0) { assert(inCallback); ibh = std::make_unique(*this, inCallback); } if (obh) obh->start(); if (ibh) ibh->start(); const double sleeptime_s = static_cast(_nFramesPerBlock) / (16 * samplerate()); const us sleeptime_us = static_cast(sleeptime_s * 1e6); while (!_stopThread) { if (ibh) { if (!(*ibh)()) { _stopThread = true; break; } } if (obh) { if (!(*obh)()) { _stopThread = true; break; } } std::this_thread::sleep_for(std::chrono::microseconds(sleeptime_us)); } /// Update stream status that we are not running anymore status.isRunning = false; _streamStatus = status; _stopThread = false; } catch (StreamException &e) { StreamStatus status = _streamStatus; // Copy over error type status.errorType = e.e; _streamStatus = status; cerr << "\n******************\n"; cerr << "Catched error in UlDAQ thread: " << e.what() << endl; cerr << "\n******************\n"; } } void DT9837A::sanityChecks() const { // Some sanity checks if (inchannel_config.size() != 4) { throw rte("Invalid length of enabled inChannels vector"); } if (outchannel_config.size() != 1) { throw rte("Invalid length of enabled outChannels vector"); } if (_nFramesPerBlock < 24 || _nFramesPerBlock > 8192) { throw rte("Unsensible number of samples per block chosen"); } if (samplerate() < ULDAQ_SAMPLERATES.at(0) || samplerate() > ULDAQ_SAMPLERATES.at(ULDAQ_SAMPLERATES.size() - 1)) { throw rte("Invalid sample rate"); } } #endif // LASP_HAS_ULDAQ