Working in CPP code, with multiple-api-api
This commit is contained in:
parent
a73ef3d7a8
commit
a3963c4595
@ -167,9 +167,8 @@ set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
|
||||
set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
|
||||
"wrappers"
|
||||
"lasp_rtaudio")
|
||||
"lasp_daq")
|
||||
|
||||
# )
|
||||
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
|
||||
|
||||
# configure_file(${SETUP_PY_IN} ${SETUP_PY})
|
||||
|
@ -1,6 +1,7 @@
|
||||
include_directories(/usr/include/rtaudio)
|
||||
|
||||
add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp lasp_cpprtaudio.cpp)
|
||||
# add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp lasp_cpprtaudio.cpp)
|
||||
add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp )
|
||||
|
||||
set_source_files_properties(lasp_daq.pyx PROPERTIES CYTHON_IS_CXX TRUE)
|
||||
set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS
|
||||
|
@ -1,80 +1,84 @@
|
||||
#include "lasp_cppdaq.h"
|
||||
#include "lasp_cppuldaq.h"
|
||||
#include <iostream>
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
#define MAX_DEV_COUNT_PER_API 20
|
||||
|
||||
#ifdef HAS_ULDAQ_LINUX_API
|
||||
void fillUlDaqDeviceInfo(vector<DeviceInfo>& devinfolist) {
|
||||
void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
||||
|
||||
UlError err;
|
||||
unsigned int numdevs = MAX_DEV_COUNT_PER_API;
|
||||
unsigned deviceno;
|
||||
UlError err;
|
||||
unsigned int numdevs = MAX_DEV_COUNT_PER_API;
|
||||
unsigned deviceno;
|
||||
|
||||
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;
|
||||
|
||||
err = ulGetDaqDeviceInventory(interfaceType,
|
||||
devdescriptors,
|
||||
&numdevs);
|
||||
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, &numdevs);
|
||||
|
||||
if(err != ERR_NO_ERROR)
|
||||
throw std::runtime_error("Device inventarization failed");
|
||||
if (err != ERR_NO_ERROR)
|
||||
throw std::runtime_error("UlDaq device inventarization failed");
|
||||
|
||||
for(unsigned i =0; i<numdevs; i++) {
|
||||
descriptor = devdescriptors[i];
|
||||
for (unsigned i = 0; i < numdevs; i++) {
|
||||
|
||||
DeviceInfo devinfo;
|
||||
devinfo.api = uldaqapi;
|
||||
string name, interface;
|
||||
descriptor = devdescriptors[i];
|
||||
|
||||
if(string(descriptor.productName) == "DT9837A") {
|
||||
if(descriptor.devInterface == USB_IFC) {
|
||||
name = "USB - ";
|
||||
} else if(descriptor.devInterface == BLUETOOTH_IFC) {
|
||||
/* devinfo. */
|
||||
name = "Bluetooth - ";
|
||||
} else if(descriptor.devInterface == ETHERNET_IFC) {
|
||||
/* devinfo. */
|
||||
name = "Ethernet - ";
|
||||
}
|
||||
name += string(descriptor.productName) + " ";
|
||||
name += string(descriptor.uniqueId);
|
||||
devinfo.name = name;
|
||||
DeviceInfo devinfo;
|
||||
devinfo.api = uldaqapi;
|
||||
string name, interface;
|
||||
|
||||
devinfo.devindex = i;
|
||||
devinfo.availableDataTypes.push_back(dtype_fl64);
|
||||
if (string(descriptor.productName) == "DT9837A") {
|
||||
if (descriptor.devInterface == USB_IFC) {
|
||||
name = "USB - ";
|
||||
} else if (descriptor.devInterface == BLUETOOTH_IFC) {
|
||||
/* devinfo. */
|
||||
name = "Bluetooth - ";
|
||||
} else if (descriptor.devInterface == ETHERNET_IFC) {
|
||||
/* devinfo. */
|
||||
name = "Ethernet - ";
|
||||
}
|
||||
|
||||
devinfo.ninchannels = 4;
|
||||
devinfo.noutchannels = 1;
|
||||
name += string(descriptor.productName) + " ";
|
||||
name += string(descriptor.uniqueId);
|
||||
devinfo.name = name;
|
||||
|
||||
devinfo.availableSampleRates.push_back(10000);
|
||||
devinfo.availableSampleRates.push_back(12000);
|
||||
devinfo.availableSampleRates.push_back(20000);
|
||||
devinfo.availableSampleRates.push_back(24000);
|
||||
devinfo.availableSampleRates.push_back(32000);
|
||||
devinfo.availableSampleRates.push_back(48000);
|
||||
devinfo.availableSampleRates.push_back(51000);
|
||||
devinfo.devindex = i;
|
||||
devinfo.availableDataTypes.push_back(dtype_fl64);
|
||||
|
||||
devinfo.prefSampleRateIndex = 5;
|
||||
devinfo.prefSampleRate = 48000;
|
||||
devinfo.ninchannels = 4;
|
||||
devinfo.noutchannels = 1;
|
||||
|
||||
devinfo.hasInputIEPE = true;
|
||||
devinfo.hasInputACCouplingSwitch = true;
|
||||
devinfo.hasInputTrigger = true;
|
||||
devinfo.availableSampleRates.push_back(10000);
|
||||
devinfo.availableSampleRates.push_back(12000);
|
||||
devinfo.availableSampleRates.push_back(20000);
|
||||
devinfo.availableSampleRates.push_back(24000);
|
||||
devinfo.availableSampleRates.push_back(32000);
|
||||
devinfo.availableSampleRates.push_back(48000);
|
||||
devinfo.availableSampleRates.push_back(51000);
|
||||
|
||||
devinfolist.push_back(devinfo);
|
||||
devinfo.prefSampleRateIndex = 5;
|
||||
|
||||
}
|
||||
devinfo.hasInputIEPE = true;
|
||||
devinfo.hasInputACCouplingSwitch = true;
|
||||
devinfo.hasInputTrigger = true;
|
||||
|
||||
devinfolist.push_back(devinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vector<DeviceInfo> DaqDevices::getDeviceInfo() {
|
||||
vector<DeviceInfo> devs;
|
||||
vector<DeviceInfo> devs;
|
||||
#ifdef HAS_ULDAQ_LINUX_API
|
||||
fillUlDaqDeviceInfo(devs);
|
||||
fillUlDaqDeviceInfo(devs);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_RTAUDIO_ALSA_API
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
||||
@ -82,11 +86,24 @@ vector<DeviceInfo> DaqDevices::getDeviceInfo() {
|
||||
|
||||
#ifdef HAS_RTAUDIO_WIN_WASAPI_API
|
||||
#endif
|
||||
return devs;
|
||||
return devs;
|
||||
}
|
||||
|
||||
Daq* DaqDevices::createDevice(const DeviceInfo&) {
|
||||
Daq *DaqDevices::createDevice(const DeviceInfo &devinfo,
|
||||
const DaqConfiguration &config) {
|
||||
|
||||
// Some basic sanity checks
|
||||
if ((devinfo.ninchannels != config.eninchannels.size())) {
|
||||
throw runtime_error("Invalid length of enabled input channels specified");
|
||||
}
|
||||
if ((devinfo.noutchannels != config.enoutchannels.size())) {
|
||||
throw runtime_error("outvalid length of enabled output channels specified");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
if (devinfo.api == uldaqapi) {
|
||||
return createUlDaqDevice(devinfo, config);
|
||||
} else {
|
||||
throw std::runtime_error(string("Unable to match API: ") +
|
||||
devinfo.api.apiname);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#ifndef LASP_CPPDAQ_H
|
||||
#define LASP_CPPDAQ_H
|
||||
#include <strstream>
|
||||
|
||||
#ifdef HAS_RTAUDIO
|
||||
#include <RtAudio.h>
|
||||
@ -10,27 +11,30 @@
|
||||
#endif
|
||||
|
||||
#include "lasp_cppqueue.h"
|
||||
#include "vector"
|
||||
#include "string"
|
||||
using std::vector;
|
||||
#include "vector"
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::runtime_error;
|
||||
|
||||
typedef unsigned int us;
|
||||
typedef vector<bool> boolvec;
|
||||
|
||||
class DataType {
|
||||
public:
|
||||
const string name;
|
||||
string name;
|
||||
unsigned sw;
|
||||
bool is_floating;
|
||||
DataType(const char* name,unsigned sw,bool is_floating):
|
||||
name(name),
|
||||
sw(sw),
|
||||
is_floating(is_floating) {}
|
||||
|
||||
DataType(const char *name, unsigned sw, bool is_floating)
|
||||
: name(name), sw(sw), is_floating(is_floating) {}
|
||||
};
|
||||
|
||||
const DataType dtype_fl64("64-bits floating point",4,true);
|
||||
const DataType dtype_int8("8-bits integers",1,false);
|
||||
const DataType dtype_int16("16-bits integers",2,false);
|
||||
const DataType dtype_int32("32-bits integers",4,false);
|
||||
const DataType dtype_invalid("invalid data type", 0, false);
|
||||
const DataType dtype_fl64("64-bits floating point", 4, true);
|
||||
const DataType dtype_int8("8-bits integers", 1, false);
|
||||
const DataType dtype_int16("16-bits integers", 2, false);
|
||||
const DataType dtype_int32("32-bits integers", 4, false);
|
||||
|
||||
const std::vector<DataType> dataTypes = {
|
||||
dtype_int8,
|
||||
@ -45,27 +49,32 @@ class DaqApi {
|
||||
unsigned apicode = 0;
|
||||
unsigned api_specific_subcode = 0;
|
||||
|
||||
DaqApi(string apiname,
|
||||
unsigned apicode,
|
||||
unsigned api_specific_subcode=0):
|
||||
apiname(apiname),
|
||||
apicode(apicode),
|
||||
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
|
||||
: apiname(apiname), apicode(apicode),
|
||||
api_specific_subcode(api_specific_subcode) {}
|
||||
DaqApi(){}
|
||||
DaqApi() {}
|
||||
bool operator==(const DaqApi &other) const {
|
||||
return (apiname == other.apiname && apicode == other.apicode &&
|
||||
api_specific_subcode == other.api_specific_subcode);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef HAS_ULDAQ_LINUX_API
|
||||
const DaqApi uldaqapi = DaqApi("UlDaq", 0);
|
||||
const DaqApi uldaqapi("UlDaq", 0);
|
||||
#endif
|
||||
#ifdef HAS_RTAUDIO_ALSA_API
|
||||
const DaqApi rtaudioalsaapi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
|
||||
#endif
|
||||
|
||||
const vector<DaqApi> compiledApis = {
|
||||
#ifdef HAS_ULDAQ_LINUX_API
|
||||
uldaqapi,
|
||||
#endif
|
||||
#ifdef HAS_RTAUDIO_ALSA_API
|
||||
DaqApi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA),
|
||||
rtaudioalsaapi,
|
||||
#endif
|
||||
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
||||
DaqApi("RtAudio Linux Pulseaudio",2, RtAudio::Api::LINUX_PULSE),
|
||||
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
|
||||
#endif
|
||||
#ifdef HAS_RTAUDIO_WIN_WASAPI_API
|
||||
DaqApi("RtAudio Windows Wasapi", 3, RtAudio::Api::WINDOWS_WASAPI),
|
||||
@ -82,41 +91,74 @@ class DeviceInfo {
|
||||
|
||||
vector<DataType> availableDataTypes;
|
||||
vector<double> availableSampleRates;
|
||||
unsigned prefSampleRateIndex = 0;
|
||||
double prefSampleRate = 0;
|
||||
vector<us> availableFramesPerBlock;
|
||||
|
||||
unsigned ninchannels =0;
|
||||
unsigned noutchannels =0;
|
||||
int prefSampleRateIndex = -1;
|
||||
unsigned ninchannels = 0;
|
||||
unsigned noutchannels = 0;
|
||||
|
||||
bool hasInputIEPE = false;
|
||||
bool hasInputACCouplingSwitch = false;
|
||||
bool hasInputTrigger = false;
|
||||
|
||||
double prefSampleRate() const {
|
||||
if ((prefSampleRateIndex < availableSampleRates.size()) &&
|
||||
(prefSampleRateIndex >= 0)) {
|
||||
return availableSampleRates[prefSampleRateIndex];
|
||||
} else {
|
||||
throw std::runtime_error("No prefered sample rate available");
|
||||
}
|
||||
}
|
||||
operator string() const {
|
||||
std::stringstream str;
|
||||
str << api.apiname + " " << devindex <<
|
||||
" number of input channels: " << ninchannels <<
|
||||
" number of output channels: " << noutchannels;
|
||||
return str.str();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Device configuration parameters
|
||||
class DaqConfiguration {
|
||||
public:
|
||||
boolvec eninchannels; // Enabled input channels
|
||||
boolvec enoutchannels; // Enabled output channels
|
||||
|
||||
unsigned sampleRateIndex; // Index in list of sample rates
|
||||
DataType
|
||||
datatype = dtype_invalid; // Required datatype for output, should be present in the list
|
||||
bool monitorOutput; // Whether the first output channel should be replicated
|
||||
// to the input as the first channel
|
||||
|
||||
unsigned nFramesPerBlock;
|
||||
|
||||
boolvec inputIEPEEnabled;
|
||||
boolvec inputACCouplingMode;
|
||||
boolvec inputHighRange;
|
||||
|
||||
};
|
||||
|
||||
class Daq;
|
||||
class DaqDevices {
|
||||
public:
|
||||
static vector<DeviceInfo> getDeviceInfo();
|
||||
static Daq* createDevice(const DeviceInfo&);
|
||||
|
||||
static Daq *createDevice(const DeviceInfo &, const DaqConfiguration &config);
|
||||
};
|
||||
|
||||
|
||||
class Daq{
|
||||
class Daq {
|
||||
|
||||
public:
|
||||
|
||||
virtual void start(
|
||||
SafeQueue<void*> *inqueue,
|
||||
SafeQueue<void*> *outqueue) = 0;
|
||||
virtual void start(SafeQueue<void *> *inqueue,
|
||||
SafeQueue<void *> *outqueue) = 0;
|
||||
|
||||
virtual void stop() = 0;
|
||||
virtual double samplerate() const = 0;
|
||||
virtual DataType getDataType() const = 0;
|
||||
|
||||
virtual ~Daq() {};
|
||||
|
||||
virtual ~Daq(){};
|
||||
virtual us neninchannels() const = 0;
|
||||
virtual us nenoutchannels() const = 0;
|
||||
};
|
||||
|
||||
#endif // LASP_CPPDAQ_H
|
||||
|
@ -1,13 +1,19 @@
|
||||
#include "lasp_cppuldaq.h"
|
||||
#include <stdexcept>
|
||||
#include <uldaq.h>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <uldaq.h>
|
||||
#include <vector>
|
||||
|
||||
using std::endl;
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::runtime_error;
|
||||
typedef std::lock_guard<std::mutex> mutexlock;
|
||||
/* using std::this_thread; */
|
||||
@ -15,178 +21,213 @@ typedef std::lock_guard<std::mutex> mutexlock;
|
||||
const us MAX_DEF_COUNT = 100;
|
||||
const us UL_ERR_MSG_LEN = 512;
|
||||
|
||||
class DT9837A : public Daq {
|
||||
us samplesPerBlock;
|
||||
double _samplerate;
|
||||
boolvec inChannels;
|
||||
boolvec high_range;
|
||||
boolvec outChannels;
|
||||
bool monitorOutput;
|
||||
atomic<bool> stopThread;
|
||||
DaqDeviceHandle handle = 0;
|
||||
|
||||
std::thread *thread = NULL;
|
||||
mutable std::mutex mutex;
|
||||
SafeQueue<void *> *inqueue = NULL;
|
||||
SafeQueue<void *> *outqueue = NULL;
|
||||
|
||||
double *inbuffer = NULL;
|
||||
double *outbuffer = NULL;
|
||||
|
||||
public:
|
||||
double samplerate() const { return this->_samplerate; }
|
||||
|
||||
DT9837A(us samplesPerBlock, const boolvec &inChannels,
|
||||
const boolvec &outChannels, double samplerate, bool monitorOutput,
|
||||
us device_no = 0);
|
||||
DT9837A(const DT9837A &) = delete;
|
||||
|
||||
~DT9837A();
|
||||
|
||||
void setIEPEEnabled(const boolvec &config);
|
||||
|
||||
// Coupling_ac: true, means AC coupling, false means DC coupling
|
||||
void setACCouplingMode(const boolvec &coupling_ac);
|
||||
|
||||
void setInputRange(const boolvec &high_range);
|
||||
|
||||
us neninchannels() const final;
|
||||
us nenoutchannels() const final;
|
||||
|
||||
bool isRunning() const { return bool(thread); }
|
||||
|
||||
virtual void start(SafeQueue<void *> *inqueue,
|
||||
SafeQueue<void *> *outqueue) final;
|
||||
|
||||
virtual void stop() final;
|
||||
DataType getDataType() const final { return dtype_fl64; }
|
||||
|
||||
friend void threadfcn(DT9837A *);
|
||||
};
|
||||
|
||||
inline void showErr(UlError err) {
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
char errmsg[UL_ERR_MSG_LEN];
|
||||
ulGetErrMsg(err, errmsg);
|
||||
std::cerr << "UlError: " << errmsg << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
DT9837A::DT9837A(
|
||||
us samplesPerBlock,
|
||||
boolvec& inChannels,
|
||||
boolvec& outChannels,
|
||||
double samplerate,
|
||||
bool monitorOutput,
|
||||
us deviceno
|
||||
):
|
||||
samplesPerBlock(samplesPerBlock),
|
||||
_samplerate(samplerate),
|
||||
inChannels(inChannels),
|
||||
outChannels(outChannels),
|
||||
monitorOutput(monitorOutput)
|
||||
{
|
||||
if(monitorOutput && !(nenoutchannels() > 0)) {
|
||||
throw runtime_error("Output monitoring only possible when output is enabled");
|
||||
}
|
||||
DT9837A::DT9837A(us samplesPerBlock, const boolvec &inChannels,
|
||||
const boolvec &outChannels, double samplerate,
|
||||
bool monitorOutput, us deviceno)
|
||||
: samplesPerBlock(samplesPerBlock), _samplerate(samplerate),
|
||||
inChannels(inChannels), outChannels(outChannels),
|
||||
monitorOutput(monitorOutput) {
|
||||
if (monitorOutput && !(nenoutchannels() > 0)) {
|
||||
throw runtime_error(
|
||||
"Output monitoring only possible when output is enabled");
|
||||
}
|
||||
|
||||
stopThread = false;
|
||||
high_range = boolvec({false, false, false, false});
|
||||
stopThread = false;
|
||||
high_range = boolvec({false, false, false, false});
|
||||
|
||||
if(samplesPerBlock < 24 || samplesPerBlock > 8192) {
|
||||
throw runtime_error("Unsensible number of samples per block chosen");
|
||||
}
|
||||
if (samplesPerBlock < 24 || samplesPerBlock > 8192) {
|
||||
throw runtime_error("Unsensible number of samples per block chosen");
|
||||
}
|
||||
|
||||
// Some sanity checks
|
||||
if (inChannels.size() != 4) {
|
||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
||||
}
|
||||
|
||||
// Some sanity checks
|
||||
if(inChannels.size() != 4) {
|
||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
||||
}
|
||||
// Some sanity checks
|
||||
if (outChannels.size() != 1) {
|
||||
throw runtime_error("Invalid length of enabled outChannels vector");
|
||||
}
|
||||
if (samplerate < 10000 || samplerate > 51000) {
|
||||
throw runtime_error("Invalid sample rate");
|
||||
}
|
||||
|
||||
// Some sanity checks
|
||||
if(outChannels.size() != 1) {
|
||||
throw runtime_error("Invalid length of enabled outChannels vector");
|
||||
}
|
||||
if(samplerate < 10000 || samplerate > 51000) {
|
||||
throw runtime_error("Invalid sample rate");
|
||||
}
|
||||
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT];
|
||||
DaqDeviceDescriptor descriptor;
|
||||
DaqDeviceInterface interfaceType = ANY_IFC;
|
||||
|
||||
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT];
|
||||
DaqDeviceDescriptor descriptor;
|
||||
DaqDeviceInterface interfaceType = ANY_IFC;
|
||||
UlError err;
|
||||
|
||||
UlError err;
|
||||
us numdevs = MAX_DEF_COUNT;
|
||||
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, &numdevs);
|
||||
if (err != ERR_NO_ERROR) {
|
||||
throw runtime_error("Device inventarization failed");
|
||||
}
|
||||
|
||||
us numdevs = MAX_DEF_COUNT;
|
||||
err = ulGetDaqDeviceInventory(interfaceType,
|
||||
devdescriptors,
|
||||
&numdevs);
|
||||
if(err != ERR_NO_ERROR){
|
||||
throw runtime_error("Device inventarization failed");
|
||||
}
|
||||
if (deviceno >= numdevs) {
|
||||
throw runtime_error("Device number {deviceno} too high {err}. This could "
|
||||
"happen when the device is currently not connected");
|
||||
}
|
||||
|
||||
if (deviceno >= numdevs) {
|
||||
throw runtime_error("Device number {deviceno} too high {err}. This could happen when the device is currently not connected");
|
||||
}
|
||||
descriptor = devdescriptors[deviceno];
|
||||
// get a handle to the DAQ device associated with the first descriptor
|
||||
handle = ulCreateDaqDevice(descriptor);
|
||||
|
||||
descriptor = devdescriptors[deviceno];
|
||||
// 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?");
|
||||
}
|
||||
|
||||
if (handle == 0) {
|
||||
throw runtime_error("Unable to create a handle to the specified DAQ device. Is the device currently in use?");
|
||||
}
|
||||
err = ulConnectDaqDevice(handle);
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
ulReleaseDaqDevice(handle);
|
||||
handle = 0;
|
||||
throw runtime_error("Unable to connect to device: {err}");
|
||||
}
|
||||
|
||||
err = ulConnectDaqDevice(handle);
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
ulReleaseDaqDevice(handle);
|
||||
handle = 0;
|
||||
throw runtime_error("Unable to connect to device: {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");
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
DT9837A::~DT9837A() {
|
||||
UlError err;
|
||||
if(isRunning()) {
|
||||
if (isRunning()) {
|
||||
stop();
|
||||
}
|
||||
|
||||
if(handle) {
|
||||
if (handle) {
|
||||
err = ulDisconnectDaqDevice(handle);
|
||||
showErr(err);
|
||||
err = ulReleaseDaqDevice(handle);
|
||||
showErr(err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DT9837A::setIEPEEnabled(boolvec& config) {
|
||||
if(isRunning()) {
|
||||
void DT9837A::setIEPEEnabled(const boolvec &config) {
|
||||
if (isRunning()) {
|
||||
throw runtime_error("Cannot change config while sampling is running");
|
||||
}
|
||||
|
||||
// Some sanity checks
|
||||
if(config.size() != 4) {
|
||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
||||
if (config.size() != 4) {
|
||||
throw runtime_error("Invalid length of enabled IEPE config vector");
|
||||
}
|
||||
|
||||
IepeMode iepe;
|
||||
UlError err;
|
||||
|
||||
for(us i=0; i< config.size(); i++) {
|
||||
for (us i = 0; i < config.size(); i++) {
|
||||
|
||||
iepe = config[i] ? IEPE_ENABLED : IEPE_DISABLED;
|
||||
err = ulAISetConfig(handle, AI_CFG_CHAN_IEPE_MODE, i, iepe);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
throw runtime_error("Fatal: could not set IEPE mode");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DT9837A::setACCouplingMode(boolvec& coupling) {
|
||||
if(isRunning()) {
|
||||
void DT9837A::setACCouplingMode(const boolvec &coupling) {
|
||||
if (isRunning()) {
|
||||
throw runtime_error("Cannot change config while sampling is running");
|
||||
}
|
||||
|
||||
// Some sanity checks
|
||||
if(coupling.size() != 4) {
|
||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
||||
if (coupling.size() != 4) {
|
||||
throw runtime_error("Invalid length of enabled AC coupling mode vector");
|
||||
}
|
||||
|
||||
CouplingMode cm;
|
||||
UlError err;
|
||||
|
||||
for(us i=0; i< coupling.size(); i++) {
|
||||
for (us i = 0; i < coupling.size(); i++) {
|
||||
cm = coupling[i] ? CM_AC : CM_DC;
|
||||
|
||||
err = ulAISetConfig(handle, AI_CFG_CHAN_COUPLING_MODE, i, cm);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
throw runtime_error("Fatal: could not set IEPE mode");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DT9837A::setInputRange(boolvec& high_range) {
|
||||
if(isRunning()) {
|
||||
void DT9837A::setInputRange(const boolvec &high_range) {
|
||||
if (isRunning()) {
|
||||
throw runtime_error("Cannot change config while sampling is running");
|
||||
}
|
||||
|
||||
// Some sanity checks
|
||||
if(high_range.size() != 4) {
|
||||
if (high_range.size() != 4) {
|
||||
throw runtime_error("Invalid length of enabled high range vector");
|
||||
}
|
||||
|
||||
this->high_range = high_range;
|
||||
}
|
||||
|
||||
|
||||
void threadfcn(DT9837A* td) {
|
||||
void threadfcn(DT9837A *td) {
|
||||
|
||||
std::cerr << "Starting DAQ Thread fcn" << endl;
|
||||
|
||||
@ -199,11 +240,11 @@ void threadfcn(DT9837A* td) {
|
||||
|
||||
bool monitorOutput = td->monitorOutput;
|
||||
|
||||
double* inbuffer = td->inbuffer;
|
||||
double* outbuffer = td->outbuffer;
|
||||
double *inbuffer = td->inbuffer;
|
||||
double *outbuffer = td->outbuffer;
|
||||
|
||||
SafeQueue<double*>* inqueue = td->inqueue;
|
||||
SafeQueue<double*>* outqueue = td->outqueue;
|
||||
SafeQueue<void *> *inqueue = td->inqueue;
|
||||
SafeQueue<void *> *outqueue = td->outqueue;
|
||||
|
||||
ScanStatus inscanstat;
|
||||
ScanStatus outscanstat;
|
||||
@ -211,16 +252,16 @@ void threadfcn(DT9837A* td) {
|
||||
|
||||
double samplerate = td->samplerate();
|
||||
|
||||
const double sleeptime = ((double) samplesPerBlock)/(4*samplerate);
|
||||
const us sleeptime_us = (us) (sleeptime*1e6);
|
||||
const double sleeptime = ((double)samplesPerBlock) / (4 * samplerate);
|
||||
const us sleeptime_us = (us)(sleeptime * 1e6);
|
||||
/* cerr << "Sleep time in loop: " << sleeptime_us << "us." << endl; */
|
||||
if(sleeptime_us < 10) {
|
||||
if (sleeptime_us < 10) {
|
||||
cerr << "ERROR: Too small buffer size (samplesPerBlock) chosen!" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
const us buffer_mid_idx_in = neninchannels*samplesPerBlock;
|
||||
const us buffer_mid_idx_out = nenoutchannels*samplesPerBlock;
|
||||
const us buffer_mid_idx_in = neninchannels * samplesPerBlock;
|
||||
const us buffer_mid_idx_out = nenoutchannels * samplesPerBlock;
|
||||
|
||||
DaqDeviceHandle handle = td->handle;
|
||||
assert(handle);
|
||||
@ -243,142 +284,135 @@ void threadfcn(DT9837A* td) {
|
||||
size_t outTotalCount = 0;
|
||||
|
||||
// initialize output, if any
|
||||
if(hasoutput) {
|
||||
if (hasoutput) {
|
||||
assert(nenoutchannels == 1);
|
||||
assert(outqueue);
|
||||
|
||||
// Initialize the buffer with zeros, before pushing any data.
|
||||
for(us sample=0;sample<2*samplesPerBlock;sample++) {
|
||||
for (us sample = 0; sample < 2 * samplesPerBlock; sample++) {
|
||||
outbuffer[sample] = 0;
|
||||
}
|
||||
|
||||
cerr << "Starting output DAC" << endl;
|
||||
err = ulAOutScan(handle,
|
||||
0,
|
||||
0,
|
||||
BIP10VOLTS,
|
||||
err = ulAOutScan(handle, 0, 0, BIP10VOLTS,
|
||||
/* BIP60VOLTS, */
|
||||
2*td->samplesPerBlock, // Watch the 2 here!
|
||||
&samplerate,
|
||||
scanoptions,
|
||||
outscanflags,
|
||||
outbuffer);
|
||||
2 * td->samplesPerBlock, // Watch the 2 here!
|
||||
&samplerate, scanoptions, outscanflags, outbuffer);
|
||||
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Initialize input, if any
|
||||
if(hasinput) {
|
||||
if (hasinput) {
|
||||
|
||||
indesc = new DaqInChanDescriptor[neninchannels];
|
||||
us j = 0;
|
||||
for(us chin=0; chin < 4; chin++) {
|
||||
if(td->inChannels[chin] == true) {
|
||||
for (us chin = 0; chin < 4; chin++) {
|
||||
if (td->inChannels[chin] == true) {
|
||||
indesc[j].type = DAQI_ANALOG_SE;
|
||||
indesc[j].channel = chin;
|
||||
indesc[j].range = td->high_range[chin] ? BIP10VOLTS : BIP1VOLTS;
|
||||
j++;
|
||||
}
|
||||
|
||||
}
|
||||
// Overwrite last channel
|
||||
if(monitorOutput) {
|
||||
if (monitorOutput) {
|
||||
indesc[j].type = DAQI_DAC;
|
||||
indesc[j].channel = 0;
|
||||
indesc[j].range = BIP10VOLTS;
|
||||
j++;
|
||||
}
|
||||
assert(j==neninchannels);
|
||||
assert(j == neninchannels);
|
||||
|
||||
cerr << "Starting input ADC" << endl;
|
||||
err = ulDaqInScan(handle,
|
||||
indesc,
|
||||
neninchannels,
|
||||
2*td->samplesPerBlock, // Watch the 2 here!
|
||||
&samplerate,
|
||||
scanoptions,
|
||||
inscanflags,
|
||||
inbuffer);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
err = ulDaqInScan(handle, indesc, neninchannels,
|
||||
2 * td->samplesPerBlock, // Watch the 2 here!
|
||||
&samplerate, scanoptions, inscanflags, inbuffer);
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Runs scan status on output, to catch up with position
|
||||
if(hasoutput) {
|
||||
if (hasoutput) {
|
||||
err = ulAOutScanStatus(handle, &outscanstat, &outxstat);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
outTotalCount = outxstat.currentScanCount;
|
||||
assert(outscanstat == SS_RUNNING);
|
||||
}
|
||||
|
||||
/* std::cerr << "Entering while loop" << endl; */
|
||||
/* std::cerr << "hasinput: " << hasinput << endl; */
|
||||
while(!td->stopThread && err == ERR_NO_ERROR) {
|
||||
while (!td->stopThread && err == ERR_NO_ERROR) {
|
||||
/* std::cerr << "While..." << endl; */
|
||||
if(hasoutput) {
|
||||
if (hasoutput) {
|
||||
err = ulAOutScanStatus(handle, &outscanstat, &outxstat);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
assert(outscanstat == SS_RUNNING);
|
||||
|
||||
if(outxstat.currentScanCount > outTotalCount+2*samplesPerBlock) {
|
||||
cerr << "***** WARNING: Missing output sample blocks, DAQ Scan count=" << outxstat.currentScanCount << " while loop count = " << outTotalCount <<", probably due to too small buffer size. *****" << endl;
|
||||
if (outxstat.currentScanCount > outTotalCount + 2 * samplesPerBlock) {
|
||||
cerr << "***** WARNING: Missing output sample blocks, DAQ Scan count="
|
||||
<< outxstat.currentScanCount
|
||||
<< " while loop count = " << outTotalCount
|
||||
<< ", probably due to too small buffer size. *****" << endl;
|
||||
}
|
||||
outTotalCount = outxstat.currentScanCount;
|
||||
|
||||
/* std::cerr << "Samples scanned: " << outxstat.currentTotalCount << endl; */
|
||||
if(outxstat.currentIndex < buffer_mid_idx_out) {
|
||||
/* std::cerr << "Samples scanned: " << outxstat.currentTotalCount << endl;
|
||||
*/
|
||||
if (outxstat.currentIndex < buffer_mid_idx_out) {
|
||||
topoutenqueued = false;
|
||||
if(!botoutenqueued) {
|
||||
if (!botoutenqueued) {
|
||||
/* cerr << "Copying output buffer to bottom" << endl; */
|
||||
double* bufcpy;
|
||||
if(!outqueue->empty()) {
|
||||
bufcpy = outqueue->dequeue();
|
||||
}
|
||||
else {
|
||||
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL QUEUE WITH ZEROS ***********" << endl;
|
||||
bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*nenoutchannels));
|
||||
for(us sample=0;sample< samplesPerBlock;sample++) {
|
||||
double *bufcpy;
|
||||
if (!outqueue->empty()) {
|
||||
bufcpy = (double *)outqueue->dequeue();
|
||||
} else {
|
||||
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL "
|
||||
"QUEUE WITH ZEROS ***********"
|
||||
<< endl;
|
||||
bufcpy = static_cast<double *>(
|
||||
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
bufcpy[sample] = 0;
|
||||
}
|
||||
}
|
||||
assert(nenoutchannels > 0);
|
||||
for(us sample=0;sample< samplesPerBlock;sample++) {
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
outbuffer[buffer_mid_idx_out + sample] = bufcpy[sample];
|
||||
}
|
||||
free(bufcpy);
|
||||
botoutenqueued = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
botoutenqueued = false;
|
||||
if(!topoutenqueued) {
|
||||
if (!topoutenqueued) {
|
||||
/* cerr << "Copying output buffer to top" << endl; */
|
||||
double* bufcpy;
|
||||
if(!outqueue->empty()) {
|
||||
bufcpy = outqueue->dequeue();
|
||||
}
|
||||
else {
|
||||
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL QUEUE WITH ZEROS ***********" << endl;
|
||||
bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*nenoutchannels));
|
||||
for(us sample=0;sample< samplesPerBlock;sample++) {
|
||||
double *bufcpy;
|
||||
if (!outqueue->empty()) {
|
||||
bufcpy = (double *)outqueue->dequeue();
|
||||
} else {
|
||||
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL "
|
||||
"QUEUE WITH ZEROS ***********"
|
||||
<< endl;
|
||||
bufcpy = static_cast<double *>(
|
||||
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
bufcpy[sample] = 0;
|
||||
}
|
||||
}
|
||||
assert(nenoutchannels > 0);
|
||||
for(us sample=0;sample<samplesPerBlock;sample++) {
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
outbuffer[sample] = bufcpy[sample];
|
||||
}
|
||||
free(bufcpy);
|
||||
@ -387,69 +421,78 @@ void threadfcn(DT9837A* td) {
|
||||
}
|
||||
}
|
||||
|
||||
if(hasinput) {
|
||||
if (hasinput) {
|
||||
err = ulDaqInScanStatus(handle, &inscanstat, &inxstat);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
goto exit;
|
||||
}
|
||||
assert(inscanstat == SS_RUNNING);
|
||||
if(inxstat.currentScanCount > inTotalCount+2*samplesPerBlock) {
|
||||
cerr << "***** ERROR: Missing input sample blocks, count=" << inxstat.currentScanCount << ", probably due to too small buffer size. Exiting thread. *****" << endl;
|
||||
if (inxstat.currentScanCount > inTotalCount + 2 * samplesPerBlock) {
|
||||
cerr << "***** ERROR: Missing input sample blocks, count="
|
||||
<< inxstat.currentScanCount
|
||||
<< ", probably due to too small buffer size. Exiting thread. *****"
|
||||
<< endl;
|
||||
break;
|
||||
}
|
||||
inTotalCount = inxstat.currentScanCount;
|
||||
|
||||
if(inxstat.currentIndex < buffer_mid_idx_in) {
|
||||
if (inxstat.currentIndex < buffer_mid_idx_in) {
|
||||
topinenqueued = false;
|
||||
if(!botinenqueued) {
|
||||
if (!botinenqueued) {
|
||||
/* cerr << "Copying in buffer bot" << endl; */
|
||||
double* bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*neninchannels));
|
||||
us monitoroffset = monitorOutput ? 1: 0;
|
||||
double *bufcpy = static_cast<double *>(
|
||||
malloc(sizeof(double) * samplesPerBlock * neninchannels));
|
||||
us monitoroffset = monitorOutput ? 1 : 0;
|
||||
assert(neninchannels > 0);
|
||||
for(us channel=0;channel<(neninchannels-monitoroffset);channel++) {
|
||||
for(us sample=0;sample< samplesPerBlock;sample++) {
|
||||
bufcpy[(monitoroffset+channel)*samplesPerBlock+sample] = inbuffer[buffer_mid_idx_in + sample*neninchannels+channel];
|
||||
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
||||
channel++) {
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
|
||||
inbuffer[buffer_mid_idx_in + sample * neninchannels +
|
||||
channel];
|
||||
}
|
||||
}
|
||||
if(monitorOutput) {
|
||||
if (monitorOutput) {
|
||||
// Monitor output goes to first channel, that is
|
||||
// our convention
|
||||
us channel = neninchannels - 1;
|
||||
for(us sample=0;sample< samplesPerBlock;sample++) {
|
||||
bufcpy[sample] = inbuffer[buffer_mid_idx_in + sample*neninchannels+channel];
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
bufcpy[sample] = inbuffer[buffer_mid_idx_in +
|
||||
sample * neninchannels + channel];
|
||||
}
|
||||
}
|
||||
inqueue->enqueue(bufcpy);
|
||||
inqueue->enqueue((void *)bufcpy);
|
||||
botinenqueued = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
botinenqueued = false;
|
||||
if(!topinenqueued) {
|
||||
double* bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*neninchannels));
|
||||
us monitoroffset = monitorOutput ? 1: 0;
|
||||
if (!topinenqueued) {
|
||||
double *bufcpy = static_cast<double *>(
|
||||
malloc(sizeof(double) * samplesPerBlock * neninchannels));
|
||||
us monitoroffset = monitorOutput ? 1 : 0;
|
||||
assert(neninchannels > 0);
|
||||
for(us channel=0;channel<(neninchannels-monitoroffset);channel++) {
|
||||
for(us sample=0;sample< samplesPerBlock;sample++) {
|
||||
bufcpy[(monitoroffset+channel)*samplesPerBlock+sample] = inbuffer[sample*neninchannels+channel];
|
||||
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
||||
channel++) {
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
|
||||
inbuffer[sample * neninchannels + channel];
|
||||
}
|
||||
}
|
||||
if(monitorOutput) {
|
||||
if (monitorOutput) {
|
||||
// Monitor output goes to first channel, that is
|
||||
// our convention
|
||||
us channel = neninchannels - 1;
|
||||
for(us sample=0;sample< samplesPerBlock;sample++) {
|
||||
bufcpy[sample] = inbuffer[sample*neninchannels+channel];
|
||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||
bufcpy[sample] = inbuffer[sample * neninchannels + channel];
|
||||
}
|
||||
}
|
||||
|
||||
/* cerr << "Copying in buffer top" << endl; */
|
||||
inqueue->enqueue(bufcpy);
|
||||
inqueue->enqueue((void *)bufcpy);
|
||||
topinenqueued = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(sleeptime_us));
|
||||
@ -457,66 +500,67 @@ void threadfcn(DT9837A* td) {
|
||||
} // End of while loop
|
||||
/* std::cerr << "Exit of while loop" << endl; */
|
||||
|
||||
|
||||
exit:
|
||||
|
||||
if(hasoutput) {
|
||||
if (hasoutput) {
|
||||
ulAOutScanStop(handle);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
}
|
||||
}
|
||||
|
||||
if(hasinput) {
|
||||
if (hasinput) {
|
||||
ulDaqInScanStop(handle);
|
||||
if(err != ERR_NO_ERROR) {
|
||||
if (err != ERR_NO_ERROR) {
|
||||
showErr(err);
|
||||
}
|
||||
}
|
||||
|
||||
if(indesc) delete indesc;
|
||||
if (indesc)
|
||||
delete indesc;
|
||||
std::cerr << "Exit of DAQ thread fcn" << endl;
|
||||
|
||||
}
|
||||
|
||||
void DT9837A::start( SafeQueue<double*> *inqueue, SafeQueue<double*> *outqueue) {
|
||||
if(isRunning()) {
|
||||
void DT9837A::start(SafeQueue<void *> *inqueue, SafeQueue<void *> *outqueue) {
|
||||
if (isRunning()) {
|
||||
throw runtime_error("Thread is already running");
|
||||
}
|
||||
|
||||
bool hasinput = neninchannels() > 0;
|
||||
bool hasoutput = nenoutchannels() > 0;
|
||||
|
||||
if(neninchannels() > 0 && !inqueue) {
|
||||
if (neninchannels() > 0 && !inqueue) {
|
||||
throw runtime_error("Inqueue not given, while input is enabled");
|
||||
}
|
||||
|
||||
if(nenoutchannels() > 0 && !outqueue) {
|
||||
if (nenoutchannels() > 0 && !outqueue) {
|
||||
throw runtime_error("outqueue not given, while output is enabled");
|
||||
}
|
||||
|
||||
if(hasinput) {
|
||||
if (hasinput) {
|
||||
assert(!inbuffer);
|
||||
inbuffer = new double[neninchannels()*samplesPerBlock*2]; // Watch the 2!
|
||||
inbuffer =
|
||||
new double[neninchannels() * samplesPerBlock * 2]; // Watch the 2!
|
||||
}
|
||||
if(hasoutput) {
|
||||
if (hasoutput) {
|
||||
assert(!outbuffer);
|
||||
outbuffer = new double[nenoutchannels()*samplesPerBlock*2]; // Watch the 2!
|
||||
outbuffer =
|
||||
new double[nenoutchannels() * samplesPerBlock * 2]; // Watch the 2!
|
||||
}
|
||||
this->inqueue = inqueue;
|
||||
this->outqueue = outqueue;
|
||||
|
||||
/* std::cerr << "************************ WARNING: Forcing coupling mode to AC **************************" << endl; */
|
||||
/* std::cerr << "************************ WARNING: Forcing coupling mode to AC
|
||||
* **************************" << endl; */
|
||||
/* boolvec couplingmode = {true, true, true, true}; */
|
||||
/* setACCouplingMode(couplingmode); */
|
||||
|
||||
stopThread = false;
|
||||
thread = new std::thread(threadfcn, this);
|
||||
|
||||
}
|
||||
|
||||
void DT9837A::stop() {
|
||||
if(!isRunning()) {
|
||||
if (!isRunning()) {
|
||||
throw runtime_error("No data acquisition running");
|
||||
}
|
||||
assert(thread);
|
||||
@ -528,8 +572,10 @@ void DT9837A::stop() {
|
||||
|
||||
outqueue = NULL;
|
||||
inqueue = NULL;
|
||||
if(inbuffer) delete inbuffer;
|
||||
if(outbuffer) delete outbuffer;
|
||||
if (inbuffer)
|
||||
delete inbuffer;
|
||||
if (outbuffer)
|
||||
delete outbuffer;
|
||||
outbuffer = NULL;
|
||||
inbuffer = NULL;
|
||||
}
|
||||
@ -537,7 +583,8 @@ void DT9837A::stop() {
|
||||
us DT9837A::neninchannels() const {
|
||||
mutexlock lock(mutex);
|
||||
us inch = std::count(inChannels.begin(), inChannels.end(), true);
|
||||
if(monitorOutput) inch++;
|
||||
if (monitorOutput)
|
||||
inch++;
|
||||
return inch;
|
||||
}
|
||||
|
||||
@ -545,3 +592,26 @@ us DT9837A::nenoutchannels() const {
|
||||
mutexlock lock(mutex);
|
||||
return std::count(outChannels.begin(), outChannels.end(), true);
|
||||
}
|
||||
|
||||
|
||||
Daq *createUlDaqDevice(const DeviceInfo &devinfo,
|
||||
const DaqConfiguration &config) {
|
||||
|
||||
DT9837A *daq = NULL;
|
||||
try {
|
||||
daq = new DT9837A(config.nFramesPerBlock, config.eninchannels,
|
||||
config.enoutchannels,
|
||||
devinfo.availableSampleRates[config.sampleRateIndex],
|
||||
config.monitorOutput, devinfo.devindex);
|
||||
|
||||
daq->setACCouplingMode(config.inputACCouplingMode);
|
||||
daq->setIEPEEnabled(config.inputIEPEEnabled);
|
||||
daq->setInputRange(config.inputHighRange);
|
||||
|
||||
} catch (runtime_error &e) {
|
||||
if (daq)
|
||||
delete daq;
|
||||
throw;
|
||||
}
|
||||
return daq;
|
||||
}
|
||||
|
@ -9,64 +9,10 @@
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
using std::vector;
|
||||
using std::atomic;
|
||||
typedef vector<bool> boolvec;
|
||||
typedef unsigned int us;
|
||||
|
||||
class DT9837A: public Daq {
|
||||
us samplesPerBlock;
|
||||
double _samplerate;
|
||||
boolvec inChannels;
|
||||
boolvec high_range;
|
||||
boolvec outChannels;
|
||||
bool monitorOutput;
|
||||
atomic<bool> stopThread;
|
||||
DaqDeviceHandle handle = 0;
|
||||
|
||||
std::thread* thread = NULL;
|
||||
mutable std::mutex mutex;
|
||||
SafeQueue<double*> *inqueue = NULL;
|
||||
SafeQueue<double*> *outqueue = NULL;
|
||||
|
||||
double* inbuffer = NULL;
|
||||
double* outbuffer = NULL;
|
||||
|
||||
public:
|
||||
double samplerate() const {return this->_samplerate;}
|
||||
DT9837A(
|
||||
us samplesPerBlock,
|
||||
boolvec& inChannels,
|
||||
boolvec& outChannels,
|
||||
double samplerate,
|
||||
bool monitorOutput,
|
||||
us device_no = 0
|
||||
);
|
||||
DT9837A(const DT9837A&) = delete;
|
||||
|
||||
~DT9837A();
|
||||
|
||||
void setIEPEEnabled(boolvec& config);
|
||||
|
||||
// Coupling_ac: true, means AC coupling, false means DC coupling
|
||||
void setACCouplingMode(boolvec& coupling_ac);
|
||||
|
||||
void setInputRange(boolvec& high_range);
|
||||
|
||||
us neninchannels() const;
|
||||
us nenoutchannels() const;
|
||||
|
||||
bool isRunning() const { return bool(thread); }
|
||||
|
||||
virtual void start(
|
||||
SafeQueue<void*> *inqueue,
|
||||
SafeQueue<void*> *outqueue) final;
|
||||
|
||||
virtual void stop() final;
|
||||
|
||||
|
||||
friend void threadfcn(DT9837A*);
|
||||
};
|
||||
Daq* createUlDaqDevice(const DeviceInfo& devinfo,
|
||||
const DaqConfiguration& config);
|
||||
|
||||
#endif // ULDAQ_H
|
||||
|
||||
|
@ -1,360 +1,2 @@
|
||||
include "lasp_common_decls.pxd"
|
||||
|
||||
cdef extern from "uldaq.h" nogil:
|
||||
|
||||
ctypedef enum DaqDeviceInterface:
|
||||
USB_IFC
|
||||
BLUETOOTH_IFC
|
||||
ETHERNET_IFC
|
||||
ANY_IFC
|
||||
|
||||
ctypedef struct DaqDeviceDescriptor:
|
||||
char productName[64]
|
||||
unsigned int productId
|
||||
DaqDeviceInterface devInterface
|
||||
char devString[64]
|
||||
char uniqueId[64]
|
||||
char reserved[512]
|
||||
|
||||
ctypedef long long DaqDeviceHandle
|
||||
|
||||
ctypedef struct TransferStatus:
|
||||
unsigned long long currentScanCount
|
||||
unsigned long long currentTotalCount
|
||||
long long currentIndex
|
||||
char reserved[64]
|
||||
|
||||
UlError ulGetErrMsg(UlError, char* errMsg)
|
||||
|
||||
ctypedef enum UlError:
|
||||
ERR_NO_ERROR
|
||||
ERR_UNHANDLED_EXCEPTION
|
||||
ERR_BAD_DEV_HANDLE
|
||||
ERR_BAD_DEV_TYPE
|
||||
ERR_USB_DEV_NO_PERMISSION
|
||||
ERR_USB_INTERFACE_CLAIMED
|
||||
ERR_DEV_NOT_FOUND
|
||||
ERR_DEV_NOT_CONNECTED
|
||||
ERR_DEAD_DEV
|
||||
ERR_BAD_BUFFER_SIZE
|
||||
ERR_BAD_BUFFER
|
||||
ERR_BAD_MEM_TYPE
|
||||
ERR_BAD_MEM_REGION
|
||||
ERR_BAD_RANGE
|
||||
ERR_BAD_AI_CHAN
|
||||
ERR_BAD_INPUT_MODE
|
||||
ERR_ALREADY_ACTIVE
|
||||
ERR_BAD_TRIG_TYPE
|
||||
ERR_OVERRUN
|
||||
ERR_UNDERRUN
|
||||
ERR_TIMEDOUT
|
||||
ERR_BAD_OPTION
|
||||
ERR_BAD_RATE
|
||||
ERR_BAD_BURSTIO_COUNT
|
||||
ERR_CONFIG_NOT_SUPPORTED
|
||||
ERR_BAD_CONFIG_VAL
|
||||
ERR_BAD_AI_CHAN_TYPE
|
||||
ERR_ADC_OVERRUN
|
||||
ERR_BAD_TC_TYPE
|
||||
ERR_BAD_UNIT
|
||||
ERR_BAD_QUEUE_SIZE
|
||||
ERR_BAD_CONFIG_ITEM
|
||||
ERR_BAD_INFO_ITEM
|
||||
ERR_BAD_FLAG
|
||||
ERR_BAD_SAMPLE_COUNT
|
||||
ERR_INTERNAL
|
||||
ERR_BAD_COUPLING_MODE
|
||||
ERR_BAD_SENSOR_SENSITIVITY
|
||||
ERR_BAD_IEPE_MODE
|
||||
ERR_BAD_AI_CHAN_QUEUE
|
||||
ERR_BAD_AI_GAIN_QUEUE
|
||||
ERR_BAD_AI_MODE_QUEUE
|
||||
ERR_FPGA_FILE_NOT_FOUND
|
||||
ERR_UNABLE_TO_READ_FPGA_FILE
|
||||
ERR_NO_FPGA
|
||||
ERR_BAD_ARG
|
||||
ERR_MIN_SLOPE_VAL_REACHED
|
||||
ERR_MAX_SLOPE_VAL_REACHED
|
||||
ERR_MIN_OFFSET_VAL_REACHED
|
||||
ERR_MAX_OFFSET_VAL_REACHED
|
||||
ERR_BAD_PORT_TYPE
|
||||
ERR_WRONG_DIG_CONFIG
|
||||
ERR_BAD_BIT_NUM
|
||||
ERR_BAD_PORT_VAL
|
||||
ERR_BAD_RETRIG_COUNT
|
||||
ERR_BAD_AO_CHAN
|
||||
ERR_BAD_DA_VAL
|
||||
ERR_BAD_TMR
|
||||
ERR_BAD_FREQUENCY
|
||||
ERR_BAD_DUTY_CYCLE
|
||||
ERR_BAD_INITIAL_DELAY
|
||||
ERR_BAD_CTR
|
||||
ERR_BAD_CTR_VAL
|
||||
ERR_BAD_DAQI_CHAN_TYPE
|
||||
ERR_BAD_NUM_CHANS
|
||||
ERR_BAD_CTR_REG
|
||||
ERR_BAD_CTR_MEASURE_TYPE
|
||||
ERR_BAD_CTR_MEASURE_MODE
|
||||
ERR_BAD_DEBOUNCE_TIME
|
||||
ERR_BAD_DEBOUNCE_MODE
|
||||
ERR_BAD_EDGE_DETECTION
|
||||
ERR_BAD_TICK_SIZE
|
||||
ERR_BAD_DAQO_CHAN_TYPE
|
||||
ERR_NO_CONNECTION_ESTABLISHED
|
||||
ERR_BAD_EVENT_TYPE
|
||||
ERR_EVENT_ALREADY_ENABLED
|
||||
ERR_BAD_EVENT_PARAMETER
|
||||
ERR_BAD_CALLBACK_FUCNTION
|
||||
ERR_BAD_MEM_ADDRESS
|
||||
ERR_MEM_ACCESS_DENIED
|
||||
ERR_DEV_UNAVAILABLE
|
||||
ERR_BAD_RETRIG_TRIG_TYPE
|
||||
ERR_BAD_DEV_VER
|
||||
ERR_BAD_DIG_OPERATION
|
||||
ERR_BAD_PORT_INDEX
|
||||
ERR_OPEN_CONNECTION
|
||||
ERR_DEV_NOT_READY
|
||||
ERR_PACER_OVERRUN
|
||||
ERR_BAD_TRIG_CHANNEL
|
||||
ERR_BAD_TRIG_LEVEL
|
||||
ERR_BAD_CHAN_ORDER
|
||||
ERR_TEMP_OUT_OF_RANGE
|
||||
ERR_TRIG_THRESHOLD_OUT_OF_RANGE
|
||||
ERR_INCOMPATIBLE_FIRMWARE
|
||||
ERR_BAD_NET_IFC
|
||||
ERR_BAD_NET_HOST
|
||||
ERR_BAD_NET_PORT
|
||||
ERR_NET_IFC_UNAVAILABLE
|
||||
ERR_NET_CONNECTION_FAILED
|
||||
ERR_BAD_CONNECTION_CODE
|
||||
ERR_CONNECTION_CODE_IGNORED
|
||||
ERR_NET_DEV_IN_USE
|
||||
ERR_BAD_NET_FRAME
|
||||
ERR_NET_TIMEOUT
|
||||
ERR_DATA_SOCKET_CONNECTION_FAILED
|
||||
ERR_PORT_USED_FOR_ALARM
|
||||
ERR_BIT_USED_FOR_ALARM
|
||||
ERR_CMR_EXCEEDED
|
||||
ERR_NET_BUFFER_OVERRUN
|
||||
ERR_BAD_NET_BUFFER
|
||||
|
||||
ctypedef enum Range:
|
||||
BIP10VOLTS
|
||||
BIP5VOLTS
|
||||
BIP4VOLTS
|
||||
BIP2PT5VOLTS
|
||||
BIP2VOLTS
|
||||
BIP1PT25VOLTS
|
||||
BIP1VOLTS
|
||||
BIPPT625VOLTS
|
||||
BIPPT5VOLTS
|
||||
BIPPT25VOLTS
|
||||
BIPPT125VOLTS
|
||||
BIPPT2VOLTS
|
||||
BIPPT1VOLTS
|
||||
BIPPT078VOLTS
|
||||
BIPPT05VOLTS
|
||||
BIPPT01VOLTS
|
||||
BIPPT005VOLTS
|
||||
BIP3VOLTS
|
||||
BIPPT312VOLTS
|
||||
BIPPT156VOLTS
|
||||
UNI15VOLTS
|
||||
UNI20VOLTS
|
||||
UNI10VOLTS
|
||||
UNI5VOLTS
|
||||
UNI4VOLTS
|
||||
UNI2PT5VOLTS
|
||||
UNI2VOLTS
|
||||
UNI1PT25VOLTS
|
||||
UNI1VOLTS
|
||||
UNIPT625VOLTS
|
||||
UNIPT5VOLTS
|
||||
UNIPT25VOLTS
|
||||
UNIPT125VOLTS
|
||||
UNIPT2VOLTS
|
||||
UNIPT1VOLTS
|
||||
UNIPT078VOLTS
|
||||
UNIPT05VOLTS
|
||||
UNIPT01VOLTS
|
||||
UNIPT005VOLTS
|
||||
MA0TO20
|
||||
|
||||
ctypedef enum AdcTimingMode:
|
||||
ADC_TM_AUTO
|
||||
ADC_TM_HIGH_RES
|
||||
ADC_TM_HIGH_SPEED
|
||||
|
||||
ctypedef enum IepeMode:
|
||||
IEPE_ENABLED
|
||||
IEPE_DISABLED
|
||||
|
||||
ctypedef enum CouplingMode:
|
||||
CM_DC
|
||||
CM_AC
|
||||
|
||||
ctypedef enum TriggerType:
|
||||
TRIG_NONE
|
||||
TRIG_POS_EDGE
|
||||
TRIG_NEG_EDGE
|
||||
TRIG_HIGH
|
||||
TRIG_LOW
|
||||
GATE_HIGH
|
||||
GATE_LOW
|
||||
TRIG_RISING
|
||||
TRIG_FALLING
|
||||
TRIG_ABOVE
|
||||
TRIG_BELOW
|
||||
GATE_ABOVE
|
||||
GATE_BELOW
|
||||
GATE_IN_WINDOW
|
||||
GATE_OUT_WINDOW
|
||||
TRIG_PATTERN_EQ
|
||||
TRIG_PATTERN_NE
|
||||
TRIG_PATTERN_ABOVE
|
||||
TRIG_PATTERN_BELOW
|
||||
|
||||
ctypedef enum ScanStatus:
|
||||
SS_IDLE
|
||||
SS_RUNNING
|
||||
|
||||
ctypedef enum ScanOption:
|
||||
SO_DEFAULTIO
|
||||
SO_SINGLEIO
|
||||
SO_BLOCKIO
|
||||
SO_BURSTIO
|
||||
SO_CONTINUOUS
|
||||
SO_EXTCLOCK
|
||||
SO_EXTTRIGGER
|
||||
SO_RETRIGGER
|
||||
SO_BURSTMODE
|
||||
SO_PACEROUT
|
||||
SO_EXTTIMEBASE
|
||||
SO_TIMEBASEOUT
|
||||
|
||||
ctypedef enum DaqInScanFlag:
|
||||
DAQINSCAN_FF_DEFAULT
|
||||
DAQINSCAN_FF_NOSCALEDATA
|
||||
DAQINSCAN_FF_NOCALIBRATEDATA
|
||||
DAQINSCAN_FF_NOCLEAR
|
||||
|
||||
ctypedef enum AOutScanFlag:
|
||||
AOUTSCAN_FF_DEFAULT
|
||||
AOUTSCAN_FF_NOSCALEDATA
|
||||
AOUTSCAN_FF_NOCALIBRATEDATA
|
||||
AOUTSCAN_FF_NOCLEAR
|
||||
|
||||
ctypedef enum DaqInChanType:
|
||||
DAQI_ANALOG_DIFF
|
||||
DAQI_ANALOG_SE
|
||||
DAQI_DIGITAL
|
||||
DAQI_CTR16
|
||||
DAQI_CTR32
|
||||
DAQI_CTR48
|
||||
DAQI_DAC
|
||||
|
||||
ctypedef struct DaqInChanDescriptor:
|
||||
int channel
|
||||
DaqInChanType type
|
||||
Range range
|
||||
|
||||
ctypedef enum DaqEventType:
|
||||
DE_NONE
|
||||
DE_ON_DATA_AVAILABLE
|
||||
DE_ON_INPUT_SCAN_ERROR
|
||||
DE_ON_END_OF_INPUT_SCAN
|
||||
DE_ON_OUTPUT_SCAN_ERROR
|
||||
DE_ON_END_OF_OUTPUT_SCAN
|
||||
|
||||
ctypedef enum WaitType:
|
||||
WAIT_UNTIL_DONE
|
||||
|
||||
ctypedef enum DevInfoItem:
|
||||
DEV_INFO_HAS_AI_DEV
|
||||
DEV_INFO_HAS_AO_DEV
|
||||
DEV_INFO_HAS_DIO_DEV
|
||||
DEV_INFO_HAS_CTR_DEV
|
||||
DEV_INFO_HAS_TMR_DEV
|
||||
DEV_INFO_HAS_DAQI_DEV
|
||||
DEV_INFO_HAS_DAQO_DEV
|
||||
DEV_INFO_DAQ_EVENT_TYPES
|
||||
DEV_INFO_MEM_REGIONS
|
||||
|
||||
ctypedef enum AiInfoItem:
|
||||
AI_INFO_RESOLUTION
|
||||
AI_INFO_NUM_CHANS
|
||||
AI_INFO_NUM_CHANS_BY_MODE
|
||||
AI_INFO_NUM_CHANS_BY_TYPE
|
||||
AI_INFO_CHAN_TYPES
|
||||
AI_INFO_SCAN_OPTIONS
|
||||
AI_INFO_HAS_PACER
|
||||
AI_INFO_NUM_DIFF_RANGES
|
||||
AI_INFO_NUM_SE_RANGES
|
||||
AI_INFO_DIFF_RANGE
|
||||
AI_INFO_SE_RANGE
|
||||
AI_INFO_TRIG_TYPES
|
||||
AI_INFO_MAX_QUEUE_LENGTH_BY_MODE
|
||||
AI_INFO_QUEUE_TYPES
|
||||
AI_INFO_QUEUE_LIMITS
|
||||
AI_INFO_FIFO_SIZE
|
||||
AI_INFO_IEPE_SUPPORTED
|
||||
|
||||
ctypedef enum AiConfigItem:
|
||||
AI_CFG_CHAN_TYPE
|
||||
AI_CFG_CHAN_TC_TYPE
|
||||
AI_CFG_SCAN_CHAN_TEMP_UNIT
|
||||
AI_CFG_SCAN_TEMP_UNIT
|
||||
AI_CFG_ADC_TIMING_MODE
|
||||
AI_CFG_AUTO_ZERO_MODE
|
||||
AI_CFG_CAL_DATE
|
||||
AI_CFG_CHAN_IEPE_MODE
|
||||
AI_CFG_CHAN_COUPLING_MODE
|
||||
AI_CFG_CHAN_SENSOR_CONNECTION_TYPE
|
||||
AI_CFG_CHAN_OTD_MODE
|
||||
AI_CFG_OTD_MODE
|
||||
AI_CFG_CAL_TABLE_TYPE
|
||||
AI_CFG_REJECT_FREQ_TYPE
|
||||
AI_CFG_EXP_CAL_DATE
|
||||
|
||||
ctypedef enum AoConfigItem:
|
||||
AO_CFG_SYNC_MODE
|
||||
AO_CFG_CHAN_SENSE_MODE
|
||||
|
||||
ctypedef enum AiConfigItemDbl:
|
||||
AI_CFG_CHAN_SLOPE
|
||||
AI_CFG_CHAN_OFFSET
|
||||
AI_CFG_CHAN_SENSOR_SENSITIVITY
|
||||
AI_CFG_CHAN_DATA_RATE
|
||||
|
||||
ctypedef enum AInScanFlag:
|
||||
AINSCAN_FF_DEFAULT
|
||||
AINSCAN_FF_NOSCALEDATA
|
||||
AINSCAN_FF_NOCALIBRATEDATA
|
||||
|
||||
UlError ulGetDaqDeviceInventory(DaqDeviceInterface interfaceTypes, DaqDeviceDescriptor daqDevDescriptors[], unsigned int* numDescriptors )
|
||||
|
||||
DaqDeviceHandle ulCreateDaqDevice(DaqDeviceDescriptor daqDevDescriptor)
|
||||
UlError ulConnectDaqDevice(DaqDeviceHandle daqDeviceHandle);
|
||||
|
||||
UlError ulDisconnectDaqDevice(DaqDeviceHandle daqDeviceHandle);
|
||||
UlError ulReleaseDaqDevice(DaqDeviceHandle daqDeviceHandle);
|
||||
|
||||
UlError ulAISetConfig(DaqDeviceHandle daqDeviceHandle, AiConfigItem configItem, unsigned int index, long long configValue)
|
||||
UlError ulAISetConfigDbl(DaqDeviceHandle daqDeviceHandle, AiConfigItemDbl configItem, unsigned int index, double configValue)
|
||||
UlError ulAIGetConfig(DaqDeviceHandle daqDeviceHandle, AiConfigItem configItem, unsigned int index, long long* configValue);
|
||||
|
||||
UlError ulDaqInScan(DaqDeviceHandle daqDeviceHandle, DaqInChanDescriptor chanDescriptors[], int numChans, int samplesPerChan, double* rate, ScanOption options, DaqInScanFlag flags, double data[]);
|
||||
UlError ulDaqInScanStatus(DaqDeviceHandle daqDeviceHandle, ScanStatus* status, TransferStatus* xferStatus);
|
||||
UlError ulDaqInScanStop(DaqDeviceHandle daqDeviceHandle);
|
||||
UlError ulDaqInScanWait(DaqDeviceHandle daqDeviceHandle, WaitType waitType, long long waitParam, double timeout);
|
||||
|
||||
ctypedef void (*DaqEventCallback)(DaqDeviceHandle, DaqEventType, unsigned long long, void*)
|
||||
|
||||
UlError ulEnableEvent(DaqDeviceHandle daqDeviceHandle, DaqEventType eventTypes, unsigned long long eventParameter, DaqEventCallback eventCallbackFunction, void* userData);
|
||||
UlError ulDisableEvent(DaqDeviceHandle daqDeviceHandle, DaqEventType eventTypes)
|
||||
|
||||
UlError ulAOutScan(DaqDeviceHandle daqDeviceHandle,int lowChan,int highChan,Range range,int samplesPerChan,double * rate,ScanOption options,AOutScanFlag flags,double data[])
|
||||
UlError ulAOutScanStatus(DaqDeviceHandle daqDeviceHandle,ScanStatus * status,TransferStatus * xferStatus)
|
||||
UlError ulAOutScanStop(DaqDeviceHandle daqDeviceHandle)
|
||||
UlError ulAOutScanWait(DaqDeviceHandle daqDeviceHandle,WaitType waitType,long long waitParam,double timeout)
|
||||
UlError ulAOutSetTrigger(DaqDeviceHandle daqDeviceHandle,TriggerType type,int trigChan,double level,double variance,unsigned int retriggerSampleCount)
|
||||
|
@ -10,31 +10,58 @@ DEF MAX_DEF_COUNT = 100
|
||||
DEF UL_ERR_MSG_LEN = 512
|
||||
|
||||
ctypedef unsigned us
|
||||
ctypedef vector[bool] boolvec
|
||||
|
||||
cdef extern from "lasp_cppdaq.h" nogil:
|
||||
cdef cppclass Daq:
|
||||
void start(SafeQueue[double*] *inQueue,
|
||||
SafeQueue[double*] *outQueue)
|
||||
cdef cppclass cppDaq "Daq":
|
||||
void start(SafeQueue[void*] *inQueue,
|
||||
SafeQueue[void*] *outQueue) except +
|
||||
void stop()
|
||||
double samplerate()
|
||||
|
||||
|
||||
cdef extern from "lasp_cppuldaq.h":
|
||||
cdef cppclass DT9837A(Daq):
|
||||
DT9837A(us samplesPerBlock,
|
||||
vector[bool] inChannels,
|
||||
vector[bool] outChannels,
|
||||
double samplerate,
|
||||
bint monitorOutput,
|
||||
us deviceno) except +
|
||||
void start(SafeQueue[double*] *inQueue,
|
||||
SafeQueue[double*] *outQueue) except +
|
||||
void stop() except +
|
||||
void setACCouplingMode(vector[bool] accoupling) except +
|
||||
void setInputRange(vector[bool] accoupling) except +
|
||||
void setIEPEEnabled(vector[bool] iepe) except +
|
||||
us neninchannels()
|
||||
us nenoutchannels()
|
||||
DataType getDataType()
|
||||
|
||||
cdef cppclass DaqApi:
|
||||
string apiname
|
||||
unsigned apicode
|
||||
unsigned api_specific_subcode
|
||||
|
||||
cdef cppclass DataType:
|
||||
string name
|
||||
unsigned sw
|
||||
bool is_floating
|
||||
DataType dtype_fl64
|
||||
|
||||
cdef cppclass cppDeviceInfo "DeviceInfo":
|
||||
DaqApi api
|
||||
string name
|
||||
unsigned devindex
|
||||
vector[DataType] availableDataTypes
|
||||
vector[double] availableSampleRates
|
||||
int prefSampleRateIndex
|
||||
unsigned ninchannels
|
||||
unsigned noutchannels
|
||||
bool hasInputIEPE
|
||||
bool hasInputACCouplingSwitch
|
||||
bool hasInputTrigger
|
||||
|
||||
cdef cppclass DaqConfiguration:
|
||||
boolvec eninchannels
|
||||
boolvec enoutchannels
|
||||
unsigned sampleRateIndex
|
||||
DataType datatype
|
||||
bool monitorOutput
|
||||
unsigned nFramesPerBlock;
|
||||
|
||||
boolvec inputIEPEEnabled;
|
||||
boolvec inputACCouplingMode;
|
||||
boolvec inputHighRange;
|
||||
|
||||
cdef cppclass DaqDevices:
|
||||
@staticmethod
|
||||
cppDaq* createDaqDevice(cppDeviceInfo&, DaqConfiguration&)
|
||||
|
||||
|
||||
ctypedef struct PyStreamData:
|
||||
PyObject* pyCallback
|
||||
@ -55,34 +82,27 @@ ctypedef struct PyStreamData:
|
||||
|
||||
# If these queue pointers are NULL, it means the stream does not have an
|
||||
# input, or output.
|
||||
SafeQueue[double*] *inQueue
|
||||
SafeQueue[double*] *outQueue
|
||||
SafeQueue[void*] *inQueue
|
||||
SafeQueue[void*] *outQueue
|
||||
CPPThread[void*, void (*)(void*)] *thread
|
||||
|
||||
cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
||||
cdef:
|
||||
PyStreamData* sd
|
||||
PyStreamData* sd = <PyStreamData*> voidsd
|
||||
cnp.NPY_TYPES npy_format
|
||||
|
||||
double* inbuffer = NULL
|
||||
double* outbuffer = NULL
|
||||
|
||||
unsigned noutchannels
|
||||
unsigned ninchannels
|
||||
unsigned nBytesPerChan
|
||||
unsigned nFramesPerBlock
|
||||
unsigned noutchannels= sd.noutchannels
|
||||
unsigned ninchannels= sd.ninchannels
|
||||
unsigned nBytesPerChan= sd.nBytesPerChan
|
||||
unsigned nFramesPerBlock= sd.nFramesPerBlock
|
||||
|
||||
unsigned sw = sizeof(double)
|
||||
|
||||
sd = <PyStreamData*> voidsd
|
||||
cdef:
|
||||
double sleeptime = (<double> nFramesPerBlock)/(4*sd.samplerate);
|
||||
double sleeptime = (<double> sd.nFramesPerBlock)/(4*sd.samplerate);
|
||||
us sleeptime_us = <us> (sleeptime*1e6);
|
||||
ninchannels = sd.ninchannels
|
||||
noutchannels = sd.noutchannels
|
||||
|
||||
nBytesPerChan = sd.nBytesPerChan
|
||||
nFramesPerBlock = sd.nFramesPerBlock
|
||||
|
||||
with gil:
|
||||
npy_format = cnp.NPY_FLOAT64
|
||||
@ -97,18 +117,18 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
||||
outbuffer = <double*> malloc(sizeof(double)*nBytesPerChan*noutchannels)
|
||||
|
||||
npy_output = <object> data_to_ndarray(
|
||||
outbuffer,
|
||||
nFramesPerBlock,
|
||||
noutchannels,
|
||||
npy_format,
|
||||
False, # Do not transfer ownership
|
||||
True) # F-contiguous
|
||||
outbuffer,
|
||||
nFramesPerBlock,
|
||||
noutchannels,
|
||||
npy_format,
|
||||
False, # Do not transfer ownership
|
||||
True) # F-contiguous
|
||||
try:
|
||||
|
||||
rval = callback(None,
|
||||
npy_output,
|
||||
nFramesPerBlock,
|
||||
)
|
||||
npy_output,
|
||||
nFramesPerBlock,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print('exception in Cython callback for audio output: ', str(e))
|
||||
@ -119,24 +139,24 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
||||
|
||||
if sd.inQueue and not sd.inQueue.empty():
|
||||
# Waiting indefinitely on the queue...
|
||||
inbuffer = sd.inQueue.dequeue()
|
||||
inbuffer = <double*> sd.inQueue.dequeue()
|
||||
if inbuffer == NULL:
|
||||
printf('Stopping thread...\n')
|
||||
return
|
||||
|
||||
try:
|
||||
npy_input = <object> data_to_ndarray(
|
||||
inbuffer,
|
||||
nFramesPerBlock,
|
||||
ninchannels,
|
||||
npy_format,
|
||||
True, # Do transfer ownership
|
||||
True) # F-contiguous is True: data is Fortran-cont.
|
||||
inbuffer,
|
||||
nFramesPerBlock,
|
||||
ninchannels,
|
||||
npy_format,
|
||||
True, # Do transfer ownership
|
||||
True) # F-contiguous is True: data is Fortran-cont.
|
||||
|
||||
rval = callback(npy_input,
|
||||
None,
|
||||
nFramesPerBlock,
|
||||
)
|
||||
None,
|
||||
nFramesPerBlock,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print('exception in cython callback for audio input: ', str(e))
|
||||
@ -153,10 +173,10 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
||||
|
||||
fprintf(stderr, 'Exiting python thread...\n')
|
||||
|
||||
cdef class UlDaq:
|
||||
cdef class Daq:
|
||||
cdef:
|
||||
PyStreamData *sd
|
||||
Daq* daq_device
|
||||
cppDaq* daq_device
|
||||
|
||||
def __cinit__(self):
|
||||
|
||||
@ -201,12 +221,12 @@ cdef class UlDaq:
|
||||
|
||||
unsigned int nFramesPerBlock = daqconfig.nFramesPerBlock
|
||||
unsigned int samplerate
|
||||
|
||||
|
||||
int i
|
||||
bint in_stream=False
|
||||
bint out_stream=False
|
||||
|
||||
DT9837A* daq_device
|
||||
cppDaq* daq_device
|
||||
|
||||
if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512:
|
||||
raise ValueError('Invalid number of nFramesPerBlock')
|
||||
@ -226,12 +246,12 @@ cdef class UlDaq:
|
||||
if duplex_mode:
|
||||
fprintf(stderr, 'Duplex mode enabled\n')
|
||||
out_stream = True
|
||||
elif avtype == AvType.audio_output:
|
||||
sampleformat = daqconfig.en_output_sample_format
|
||||
samplerate = int(daqconfig.en_output_rate)
|
||||
out_stream = True
|
||||
else:
|
||||
raise ValueError(f'Invalid stream type {avtype}')
|
||||
elif avtype == AvType.audio_output:
|
||||
sampleformat = daqconfig.en_output_sample_format
|
||||
samplerate = int(daqconfig.en_output_rate)
|
||||
out_stream = True
|
||||
else:
|
||||
raise ValueError(f'Invalid stream type {avtype}')
|
||||
|
||||
if out_stream and daqconfig.firstEnabledOutputChannelNumber() == -1:
|
||||
raise RuntimeError('No output channels enabled')
|
||||
@ -264,29 +284,29 @@ cdef class UlDaq:
|
||||
inch_enabled = 4*[False]
|
||||
if in_stream:
|
||||
inch_enabled = [True if ch.channel_enabled else False for ch in
|
||||
daqconfig.getInputChannels()]
|
||||
daqconfig.getInputChannels()]
|
||||
|
||||
self.sd.inQueue = new SafeQueue[void*]()
|
||||
|
||||
self.sd.inQueue = new SafeQueue[double*]()
|
||||
|
||||
# Create channel maps for output channels
|
||||
outch_enabled = 1*[False]
|
||||
if out_stream:
|
||||
print('Stream is output stream')
|
||||
outch_enabled = [True if ch.channel_enabled else False for ch in
|
||||
daqconfig.getOutputChannels()]
|
||||
daqconfig.getOutputChannels()]
|
||||
|
||||
self.sd.outQueue = new SafeQueue[double*]()
|
||||
self.sd.outQueue = new SafeQueue[void*]()
|
||||
|
||||
if 'DT9837A' in device.name:
|
||||
daq_device = new DT9837A(
|
||||
daqconfig.nFramesPerBlock,
|
||||
inch_enabled,
|
||||
outch_enabled,
|
||||
samplerate,
|
||||
monitorOutput,
|
||||
device.index)
|
||||
else:
|
||||
raise RuntimeError(f'Device {device.name} not found or not configured')
|
||||
# if 'DT9837A' in device.name:
|
||||
# daq_device = new DT9837A(
|
||||
# daqconfig.nFramesPerBlock,
|
||||
# inch_enabled,
|
||||
# outch_enabled,
|
||||
# samplerate,
|
||||
# monitorOutput,
|
||||
# device.index)
|
||||
# else:
|
||||
# raise RuntimeError(f'Device {device.name} not found or not configured')
|
||||
|
||||
self.sd.pyCallback = <PyObject*> avstream._audioCallback
|
||||
self.sd.ninchannels = daq_device.neninchannels()
|
||||
@ -299,14 +319,14 @@ cdef class UlDaq:
|
||||
|
||||
with nogil:
|
||||
self.sd.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction,
|
||||
<void*> self.sd)
|
||||
<void*> self.sd)
|
||||
|
||||
# Allow it to start
|
||||
CPPsleep_ms(500)
|
||||
|
||||
self.daq_device.start(
|
||||
self.sd.inQueue,
|
||||
self.sd.outQueue)
|
||||
self.sd.inQueue,
|
||||
self.sd.outQueue)
|
||||
|
||||
return nFramesPerBlock, self.daq_device.samplerate()
|
||||
|
||||
@ -342,12 +362,12 @@ cdef class UlDaq:
|
||||
if sd.outQueue:
|
||||
while not sd.outQueue.empty():
|
||||
free(sd.outQueue.dequeue())
|
||||
del sd.outQueue
|
||||
if sd.inQueue:
|
||||
while not sd.inQueue.empty():
|
||||
free(sd.inQueue.dequeue())
|
||||
del sd.inQueue
|
||||
fprintf(stderr, "End cleanup stream queues...\n")
|
||||
del sd.outQueue
|
||||
if sd.inQueue:
|
||||
while not sd.inQueue.empty():
|
||||
free(sd.inQueue.dequeue())
|
||||
del sd.inQueue
|
||||
fprintf(stderr, "End cleanup stream queues...\n")
|
||||
|
||||
if sd.pyCallback:
|
||||
Py_DECREF(<object> sd.pyCallback)
|
||||
@ -361,55 +381,56 @@ cdef class UlDaq:
|
||||
devices
|
||||
"""
|
||||
cdef:
|
||||
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
|
||||
DaqDeviceDescriptor descriptor
|
||||
DaqDeviceInterface interfaceType = ANY_IFC
|
||||
DaqDeviceHandle handle
|
||||
pass
|
||||
# DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
|
||||
# DaqDeviceDescriptor descriptor
|
||||
# DaqDeviceInterface interfaceType = ANY_IFC
|
||||
# DaqDeviceHandle handle
|
||||
|
||||
UlError err
|
||||
# UlError err
|
||||
|
||||
unsigned int numdevs = MAX_DEF_COUNT
|
||||
unsigned deviceno
|
||||
# unsigned int numdevs = MAX_DEF_COUNT
|
||||
# unsigned deviceno
|
||||
|
||||
if self.sd is not NULL:
|
||||
assert self.daq_device is not NULL
|
||||
raise RuntimeError('Cannot acquire device info: stream is already opened.')
|
||||
# if self.sd is not NULL:
|
||||
# assert self.daq_device is not NULL
|
||||
# raise RuntimeError('Cannot acquire device info: stream is already opened.')
|
||||
|
||||
err = ulGetDaqDeviceInventory(interfaceType,
|
||||
devdescriptors,
|
||||
&numdevs)
|
||||
if(err != ERR_NO_ERROR):
|
||||
raise RuntimeError(f'Device inventarization failed: {err}')
|
||||
# err = ulGetDaqDeviceInventory(interfaceType,
|
||||
# devdescriptors,
|
||||
# &numdevs)
|
||||
# if(err != ERR_NO_ERROR):
|
||||
# raise RuntimeError(f'Device inventarization failed: {err}')
|
||||
|
||||
|
||||
py_devinfo = []
|
||||
for deviceno in range(numdevs):
|
||||
descriptor = devdescriptors[deviceno]
|
||||
|
||||
if descriptor.productName == b'DT9837A':
|
||||
# Create proper interface name
|
||||
if descriptor.devInterface == DaqDeviceInterface.USB_IFC:
|
||||
name = 'USB - '
|
||||
elif descriptor.devInterface == DaqDeviceInterface.BLUETOOTH_IFC:
|
||||
name = 'Bluetooth - '
|
||||
elif descriptor.devInterface == DaqDeviceInterface.ETHERNET_IFC:
|
||||
name = 'Ethernet - '
|
||||
# py_devinfo = []
|
||||
# for deviceno in range(numdevs):
|
||||
# descriptor = devdescriptors[deviceno]
|
||||
|
||||
name += descriptor.productName.decode('utf-8') + ', id ' + \
|
||||
descriptor.uniqueId.decode('utf-8')
|
||||
# if descriptor.productName == b'DT9837A':
|
||||
# # Create proper interface name
|
||||
# if descriptor.devInterface == DaqDeviceInterface.USB_IFC:
|
||||
# name = 'USB - '
|
||||
# elif descriptor.devInterface == DaqDeviceInterface.BLUETOOTH_IFC:
|
||||
# name = 'Bluetooth - '
|
||||
# elif descriptor.devInterface == DaqDeviceInterface.ETHERNET_IFC:
|
||||
# name = 'Ethernet - '
|
||||
|
||||
d = DeviceInfo(
|
||||
api = -1,
|
||||
index = deviceno,
|
||||
probed = True,
|
||||
name = name,
|
||||
outputchannels = 1,
|
||||
inputchannels = 4,
|
||||
duplexchannels = 0,
|
||||
samplerates = [10000, 16000, 20000, 32000, 48000, 50000] ,
|
||||
sampleformats = ['64-bit floats'],
|
||||
prefsamplerate = 48000,
|
||||
hasInputIEPE = True)
|
||||
py_devinfo.append(d)
|
||||
return py_devinfo
|
||||
# name += descriptor.productName.decode('utf-8') + ', id ' + \
|
||||
# descriptor.uniqueId.decode('utf-8')
|
||||
|
||||
# d = DeviceInfo(
|
||||
# api = -1,
|
||||
# index = deviceno,
|
||||
# probed = True,
|
||||
# name = name,
|
||||
# outputchannels = 1,
|
||||
# inputchannels = 4,
|
||||
# duplexchannels = 0,
|
||||
# samplerates = [10000, 16000, 20000, 32000, 48000, 50000] ,
|
||||
# sampleformats = ['64-bit floats'],
|
||||
# prefsamplerate = 48000,
|
||||
# hasInputIEPE = True)
|
||||
# py_devinfo.append(d)
|
||||
# return py_devinfo
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "lasp_cppuldaq.h"
|
||||
#include "lasp_cppdaq.h"
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
|
||||
@ -14,13 +16,35 @@ int main() {
|
||||
double samplerate = 10000;
|
||||
const us samplesPerBlock = 256;
|
||||
|
||||
DT9837A daq(
|
||||
samplesPerBlock,
|
||||
inChannels,
|
||||
outChannels,
|
||||
samplerate,
|
||||
true // monitor Output
|
||||
);
|
||||
DaqConfiguration config;
|
||||
config.eninchannels = inChannels;
|
||||
config.enoutchannels = outChannels;
|
||||
config.inputIEPEEnabled = {false, false, false, false};
|
||||
config.inputACCouplingMode = {false, false, false, false};
|
||||
config.inputHighRange = {false, false, false, false};
|
||||
config.sampleRateIndex = 0;
|
||||
config.datatype = dtype_fl64;
|
||||
config.monitorOutput = true;
|
||||
config.inputIEPEEnabled = {false, false, false, false};
|
||||
config.nFramesPerBlock = samplesPerBlock;
|
||||
cout << "Inchannnels size: " <<config.eninchannels.size() << endl;
|
||||
|
||||
vector<DeviceInfo> devinfos = DaqDevices::getDeviceInfo();
|
||||
DeviceInfo devinfo;
|
||||
us i;
|
||||
bool found = false;
|
||||
for(i=0;i<devinfos.size();i++) {
|
||||
if(devinfos[i].api == uldaqapi){
|
||||
cout << string(devinfos[i]) << endl;
|
||||
devinfo = devinfos[i];
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
throw runtime_error("Could not find UlDaq device");
|
||||
}
|
||||
|
||||
Daq* daq = DaqDevices::createDevice(devinfo, config);
|
||||
|
||||
SafeQueue<void*> inqueue;
|
||||
SafeQueue<void*> outqueue;
|
||||
@ -42,19 +66,16 @@ int main() {
|
||||
outqueue.enqueue(data);
|
||||
}
|
||||
|
||||
daq.start(&inqueue, &outqueue);
|
||||
/* daq.start(NULL, &outqueue); */
|
||||
daq->start(&inqueue, &outqueue);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
|
||||
/* std::string a; */
|
||||
/* std::cin >> a; */
|
||||
|
||||
daq.stop();
|
||||
daq->stop();
|
||||
|
||||
while(!inqueue.empty()) {
|
||||
double* buf = (double*) inqueue.dequeue();
|
||||
for(us i=0;i<samplesPerBlock;i++) {
|
||||
for(us ch=0;ch<daq.neninchannels();ch++) {
|
||||
for(us ch=0;ch<daq->neninchannels();ch++) {
|
||||
cout << buf[ch*samplesPerBlock+i] << " ";
|
||||
}
|
||||
cout << endl;
|
||||
|
Loading…
Reference in New Issue
Block a user