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"
|
set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/*.py"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
|
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
|
||||||
"wrappers"
|
"wrappers"
|
||||||
"lasp_rtaudio")
|
"lasp_daq")
|
||||||
|
|
||||||
# )
|
|
||||||
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
|
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
|
||||||
|
|
||||||
# configure_file(${SETUP_PY_IN} ${SETUP_PY})
|
# configure_file(${SETUP_PY_IN} ${SETUP_PY})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
include_directories(/usr/include/rtaudio)
|
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.pyx PROPERTIES CYTHON_IS_CXX TRUE)
|
||||||
set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS
|
set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
#include "lasp_cppdaq.h"
|
#include "lasp_cppdaq.h"
|
||||||
|
#include "lasp_cppuldaq.h"
|
||||||
|
#include <iostream>
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
#define MAX_DEV_COUNT_PER_API 20
|
#define MAX_DEV_COUNT_PER_API 20
|
||||||
|
|
||||||
#ifdef HAS_ULDAQ_LINUX_API
|
#ifdef HAS_ULDAQ_LINUX_API
|
||||||
@ -12,14 +17,13 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo>& devinfolist) {
|
|||||||
DaqDeviceDescriptor descriptor;
|
DaqDeviceDescriptor descriptor;
|
||||||
DaqDeviceInterface interfaceType = ANY_IFC;
|
DaqDeviceInterface interfaceType = ANY_IFC;
|
||||||
|
|
||||||
err = ulGetDaqDeviceInventory(interfaceType,
|
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, &numdevs);
|
||||||
devdescriptors,
|
|
||||||
&numdevs);
|
|
||||||
|
|
||||||
if (err != ERR_NO_ERROR)
|
if (err != ERR_NO_ERROR)
|
||||||
throw std::runtime_error("Device inventarization failed");
|
throw std::runtime_error("UlDaq device inventarization failed");
|
||||||
|
|
||||||
for (unsigned i = 0; i < numdevs; i++) {
|
for (unsigned i = 0; i < numdevs; i++) {
|
||||||
|
|
||||||
descriptor = devdescriptors[i];
|
descriptor = devdescriptors[i];
|
||||||
|
|
||||||
DeviceInfo devinfo;
|
DeviceInfo devinfo;
|
||||||
@ -36,6 +40,7 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo>& devinfolist) {
|
|||||||
/* devinfo. */
|
/* devinfo. */
|
||||||
name = "Ethernet - ";
|
name = "Ethernet - ";
|
||||||
}
|
}
|
||||||
|
|
||||||
name += string(descriptor.productName) + " ";
|
name += string(descriptor.productName) + " ";
|
||||||
name += string(descriptor.uniqueId);
|
name += string(descriptor.uniqueId);
|
||||||
devinfo.name = name;
|
devinfo.name = name;
|
||||||
@ -55,14 +60,12 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo>& devinfolist) {
|
|||||||
devinfo.availableSampleRates.push_back(51000);
|
devinfo.availableSampleRates.push_back(51000);
|
||||||
|
|
||||||
devinfo.prefSampleRateIndex = 5;
|
devinfo.prefSampleRateIndex = 5;
|
||||||
devinfo.prefSampleRate = 48000;
|
|
||||||
|
|
||||||
devinfo.hasInputIEPE = true;
|
devinfo.hasInputIEPE = true;
|
||||||
devinfo.hasInputACCouplingSwitch = true;
|
devinfo.hasInputACCouplingSwitch = true;
|
||||||
devinfo.hasInputTrigger = true;
|
devinfo.hasInputTrigger = true;
|
||||||
|
|
||||||
devinfolist.push_back(devinfo);
|
devinfolist.push_back(devinfo);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,6 +78,7 @@ vector<DeviceInfo> DaqDevices::getDeviceInfo() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_RTAUDIO_ALSA_API
|
#ifdef HAS_RTAUDIO_ALSA_API
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
||||||
@ -85,8 +89,21 @@ vector<DeviceInfo> DaqDevices::getDeviceInfo() {
|
|||||||
return devs;
|
return devs;
|
||||||
}
|
}
|
||||||
|
|
||||||
Daq* DaqDevices::createDevice(const DeviceInfo&) {
|
Daq *DaqDevices::createDevice(const DeviceInfo &devinfo,
|
||||||
|
const DaqConfiguration &config) {
|
||||||
|
|
||||||
|
// Some basic sanity checks
|
||||||
return NULL;
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
#ifndef LASP_CPPDAQ_H
|
||||||
#define LASP_CPPDAQ_H
|
#define LASP_CPPDAQ_H
|
||||||
|
#include <strstream>
|
||||||
|
|
||||||
#ifdef HAS_RTAUDIO
|
#ifdef HAS_RTAUDIO
|
||||||
#include <RtAudio.h>
|
#include <RtAudio.h>
|
||||||
@ -10,23 +11,26 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "lasp_cppqueue.h"
|
#include "lasp_cppqueue.h"
|
||||||
#include "vector"
|
|
||||||
#include "string"
|
#include "string"
|
||||||
using std::vector;
|
#include "vector"
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using std::runtime_error;
|
||||||
|
|
||||||
|
typedef unsigned int us;
|
||||||
|
typedef vector<bool> boolvec;
|
||||||
|
|
||||||
class DataType {
|
class DataType {
|
||||||
public:
|
public:
|
||||||
const string name;
|
string name;
|
||||||
unsigned sw;
|
unsigned sw;
|
||||||
bool is_floating;
|
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_invalid("invalid data type", 0, false);
|
||||||
const DataType dtype_fl64("64-bits floating point", 4, true);
|
const DataType dtype_fl64("64-bits floating point", 4, true);
|
||||||
const DataType dtype_int8("8-bits integers", 1, false);
|
const DataType dtype_int8("8-bits integers", 1, false);
|
||||||
const DataType dtype_int16("16-bits integers", 2, false);
|
const DataType dtype_int16("16-bits integers", 2, false);
|
||||||
@ -45,24 +49,29 @@ class DaqApi {
|
|||||||
unsigned apicode = 0;
|
unsigned apicode = 0;
|
||||||
unsigned api_specific_subcode = 0;
|
unsigned api_specific_subcode = 0;
|
||||||
|
|
||||||
DaqApi(string apiname,
|
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
|
||||||
unsigned apicode,
|
: apiname(apiname), apicode(apicode),
|
||||||
unsigned api_specific_subcode=0):
|
|
||||||
apiname(apiname),
|
|
||||||
apicode(apicode),
|
|
||||||
api_specific_subcode(api_specific_subcode) {}
|
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
|
#ifdef HAS_ULDAQ_LINUX_API
|
||||||
const DaqApi uldaqapi = DaqApi("UlDaq", 0);
|
const DaqApi uldaqapi("UlDaq", 0);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAS_RTAUDIO_ALSA_API
|
||||||
|
const DaqApi rtaudioalsaapi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
|
||||||
|
#endif
|
||||||
|
|
||||||
const vector<DaqApi> compiledApis = {
|
const vector<DaqApi> compiledApis = {
|
||||||
#ifdef HAS_ULDAQ_LINUX_API
|
#ifdef HAS_ULDAQ_LINUX_API
|
||||||
uldaqapi,
|
uldaqapi,
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_RTAUDIO_ALSA_API
|
#ifdef HAS_RTAUDIO_ALSA_API
|
||||||
DaqApi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA),
|
rtaudioalsaapi,
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
||||||
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
|
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
|
||||||
@ -82,9 +91,9 @@ class DeviceInfo {
|
|||||||
|
|
||||||
vector<DataType> availableDataTypes;
|
vector<DataType> availableDataTypes;
|
||||||
vector<double> availableSampleRates;
|
vector<double> availableSampleRates;
|
||||||
unsigned prefSampleRateIndex = 0;
|
vector<us> availableFramesPerBlock;
|
||||||
double prefSampleRate = 0;
|
|
||||||
|
|
||||||
|
int prefSampleRateIndex = -1;
|
||||||
unsigned ninchannels = 0;
|
unsigned ninchannels = 0;
|
||||||
unsigned noutchannels = 0;
|
unsigned noutchannels = 0;
|
||||||
|
|
||||||
@ -92,23 +101,55 @@ class DeviceInfo {
|
|||||||
bool hasInputACCouplingSwitch = false;
|
bool hasInputACCouplingSwitch = false;
|
||||||
bool hasInputTrigger = 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 Daq;
|
||||||
class DaqDevices {
|
class DaqDevices {
|
||||||
public:
|
public:
|
||||||
static vector<DeviceInfo> getDeviceInfo();
|
static vector<DeviceInfo> getDeviceInfo();
|
||||||
static Daq* createDevice(const DeviceInfo&);
|
static Daq *createDevice(const DeviceInfo &, const DaqConfiguration &config);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Daq {
|
class Daq {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual void start(SafeQueue<void *> *inqueue,
|
||||||
virtual void start(
|
|
||||||
SafeQueue<void*> *inqueue,
|
|
||||||
SafeQueue<void *> *outqueue) = 0;
|
SafeQueue<void *> *outqueue) = 0;
|
||||||
|
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
@ -116,7 +157,8 @@ class Daq{
|
|||||||
virtual DataType getDataType() 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
|
#endif // LASP_CPPDAQ_H
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
#include "lasp_cppuldaq.h"
|
#include "lasp_cppuldaq.h"
|
||||||
#include <stdexcept>
|
#include <algorithm>
|
||||||
#include <uldaq.h>
|
#include <atomic>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
|
||||||
#include <cstring>
|
|
||||||
#include <chrono>
|
#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::cerr;
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
using std::runtime_error;
|
using std::runtime_error;
|
||||||
typedef std::lock_guard<std::mutex> mutexlock;
|
typedef std::lock_guard<std::mutex> mutexlock;
|
||||||
/* using std::this_thread; */
|
/* using std::this_thread; */
|
||||||
@ -15,6 +21,55 @@ typedef std::lock_guard<std::mutex> mutexlock;
|
|||||||
const us MAX_DEF_COUNT = 100;
|
const us MAX_DEF_COUNT = 100;
|
||||||
const us UL_ERR_MSG_LEN = 512;
|
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) {
|
inline void showErr(UlError err) {
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
char errmsg[UL_ERR_MSG_LEN];
|
char errmsg[UL_ERR_MSG_LEN];
|
||||||
@ -23,22 +78,15 @@ inline void showErr(UlError err) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DT9837A::DT9837A(
|
DT9837A::DT9837A(us samplesPerBlock, const boolvec &inChannels,
|
||||||
us samplesPerBlock,
|
const boolvec &outChannels, double samplerate,
|
||||||
boolvec& inChannels,
|
bool monitorOutput, us deviceno)
|
||||||
boolvec& outChannels,
|
: samplesPerBlock(samplesPerBlock), _samplerate(samplerate),
|
||||||
double samplerate,
|
inChannels(inChannels), outChannels(outChannels),
|
||||||
bool monitorOutput,
|
monitorOutput(monitorOutput) {
|
||||||
us deviceno
|
|
||||||
):
|
|
||||||
samplesPerBlock(samplesPerBlock),
|
|
||||||
_samplerate(samplerate),
|
|
||||||
inChannels(inChannels),
|
|
||||||
outChannels(outChannels),
|
|
||||||
monitorOutput(monitorOutput)
|
|
||||||
{
|
|
||||||
if (monitorOutput && !(nenoutchannels() > 0)) {
|
if (monitorOutput && !(nenoutchannels() > 0)) {
|
||||||
throw runtime_error("Output monitoring only possible when output is enabled");
|
throw runtime_error(
|
||||||
|
"Output monitoring only possible when output is enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
stopThread = false;
|
stopThread = false;
|
||||||
@ -48,7 +96,6 @@ DT9837A::DT9837A(
|
|||||||
throw runtime_error("Unsensible number of samples per block chosen");
|
throw runtime_error("Unsensible number of samples per block chosen");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Some sanity checks
|
// Some sanity checks
|
||||||
if (inChannels.size() != 4) {
|
if (inChannels.size() != 4) {
|
||||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
throw runtime_error("Invalid length of enabled inChannels vector");
|
||||||
@ -69,15 +116,14 @@ DT9837A::DT9837A(
|
|||||||
UlError err;
|
UlError err;
|
||||||
|
|
||||||
us numdevs = MAX_DEF_COUNT;
|
us numdevs = MAX_DEF_COUNT;
|
||||||
err = ulGetDaqDeviceInventory(interfaceType,
|
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, &numdevs);
|
||||||
devdescriptors,
|
|
||||||
&numdevs);
|
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
throw runtime_error("Device inventarization failed");
|
throw runtime_error("Device inventarization failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceno >= numdevs) {
|
if (deviceno >= numdevs) {
|
||||||
throw runtime_error("Device number {deviceno} too high {err}. This could happen when the device is currently not connected");
|
throw runtime_error("Device number {deviceno} too high {err}. This could "
|
||||||
|
"happen when the device is currently not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor = devdescriptors[deviceno];
|
descriptor = devdescriptors[deviceno];
|
||||||
@ -85,7 +131,8 @@ DT9837A::DT9837A(
|
|||||||
handle = ulCreateDaqDevice(descriptor);
|
handle = ulCreateDaqDevice(descriptor);
|
||||||
|
|
||||||
if (handle == 0) {
|
if (handle == 0) {
|
||||||
throw runtime_error("Unable to create a handle to the specified DAQ device. Is the device currently in use?");
|
throw runtime_error("Unable to create a handle to the specified DAQ "
|
||||||
|
"device. Is the device currently in use?");
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ulConnectDaqDevice(handle);
|
err = ulConnectDaqDevice(handle);
|
||||||
@ -103,8 +150,6 @@ DT9837A::DT9837A(
|
|||||||
throw runtime_error("Fatal: could normalize channel sensitivity");
|
throw runtime_error("Fatal: could normalize channel sensitivity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DT9837A::~DT9837A() {
|
DT9837A::~DT9837A() {
|
||||||
@ -119,17 +164,16 @@ DT9837A::~DT9837A() {
|
|||||||
err = ulReleaseDaqDevice(handle);
|
err = ulReleaseDaqDevice(handle);
|
||||||
showErr(err);
|
showErr(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DT9837A::setIEPEEnabled(boolvec& config) {
|
void DT9837A::setIEPEEnabled(const boolvec &config) {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
throw runtime_error("Cannot change config while sampling is running");
|
throw runtime_error("Cannot change config while sampling is running");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some sanity checks
|
// Some sanity checks
|
||||||
if (config.size() != 4) {
|
if (config.size() != 4) {
|
||||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
throw runtime_error("Invalid length of enabled IEPE config vector");
|
||||||
}
|
}
|
||||||
|
|
||||||
IepeMode iepe;
|
IepeMode iepe;
|
||||||
@ -143,18 +187,17 @@ void DT9837A::setIEPEEnabled(boolvec& config) {
|
|||||||
showErr(err);
|
showErr(err);
|
||||||
throw runtime_error("Fatal: could not set IEPE mode");
|
throw runtime_error("Fatal: could not set IEPE mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DT9837A::setACCouplingMode(boolvec& coupling) {
|
void DT9837A::setACCouplingMode(const boolvec &coupling) {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
throw runtime_error("Cannot change config while sampling is running");
|
throw runtime_error("Cannot change config while sampling is running");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some sanity checks
|
// Some sanity checks
|
||||||
if (coupling.size() != 4) {
|
if (coupling.size() != 4) {
|
||||||
throw runtime_error("Invalid length of enabled inChannels vector");
|
throw runtime_error("Invalid length of enabled AC coupling mode vector");
|
||||||
}
|
}
|
||||||
|
|
||||||
CouplingMode cm;
|
CouplingMode cm;
|
||||||
@ -168,11 +211,10 @@ void DT9837A::setACCouplingMode(boolvec& coupling) {
|
|||||||
showErr(err);
|
showErr(err);
|
||||||
throw runtime_error("Fatal: could not set IEPE mode");
|
throw runtime_error("Fatal: could not set IEPE mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DT9837A::setInputRange(boolvec& high_range) {
|
void DT9837A::setInputRange(const boolvec &high_range) {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
throw runtime_error("Cannot change config while sampling is running");
|
throw runtime_error("Cannot change config while sampling is running");
|
||||||
}
|
}
|
||||||
@ -185,7 +227,6 @@ void DT9837A::setInputRange(boolvec& high_range) {
|
|||||||
this->high_range = high_range;
|
this->high_range = high_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void threadfcn(DT9837A *td) {
|
void threadfcn(DT9837A *td) {
|
||||||
|
|
||||||
std::cerr << "Starting DAQ Thread fcn" << endl;
|
std::cerr << "Starting DAQ Thread fcn" << endl;
|
||||||
@ -202,8 +243,8 @@ void threadfcn(DT9837A* td) {
|
|||||||
double *inbuffer = td->inbuffer;
|
double *inbuffer = td->inbuffer;
|
||||||
double *outbuffer = td->outbuffer;
|
double *outbuffer = td->outbuffer;
|
||||||
|
|
||||||
SafeQueue<double*>* inqueue = td->inqueue;
|
SafeQueue<void *> *inqueue = td->inqueue;
|
||||||
SafeQueue<double*>* outqueue = td->outqueue;
|
SafeQueue<void *> *outqueue = td->outqueue;
|
||||||
|
|
||||||
ScanStatus inscanstat;
|
ScanStatus inscanstat;
|
||||||
ScanStatus outscanstat;
|
ScanStatus outscanstat;
|
||||||
@ -253,22 +294,15 @@ void threadfcn(DT9837A* td) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cerr << "Starting output DAC" << endl;
|
cerr << "Starting output DAC" << endl;
|
||||||
err = ulAOutScan(handle,
|
err = ulAOutScan(handle, 0, 0, BIP10VOLTS,
|
||||||
0,
|
|
||||||
0,
|
|
||||||
BIP10VOLTS,
|
|
||||||
/* BIP60VOLTS, */
|
/* BIP60VOLTS, */
|
||||||
2 * td->samplesPerBlock, // Watch the 2 here!
|
2 * td->samplesPerBlock, // Watch the 2 here!
|
||||||
&samplerate,
|
&samplerate, scanoptions, outscanflags, outbuffer);
|
||||||
scanoptions,
|
|
||||||
outscanflags,
|
|
||||||
outbuffer);
|
|
||||||
|
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize input, if any
|
// Initialize input, if any
|
||||||
@ -283,7 +317,6 @@ void threadfcn(DT9837A* td) {
|
|||||||
indesc[j].range = td->high_range[chin] ? BIP10VOLTS : BIP1VOLTS;
|
indesc[j].range = td->high_range[chin] ? BIP10VOLTS : BIP1VOLTS;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// Overwrite last channel
|
// Overwrite last channel
|
||||||
if (monitorOutput) {
|
if (monitorOutput) {
|
||||||
@ -295,19 +328,13 @@ void threadfcn(DT9837A* td) {
|
|||||||
assert(j == neninchannels);
|
assert(j == neninchannels);
|
||||||
|
|
||||||
cerr << "Starting input ADC" << endl;
|
cerr << "Starting input ADC" << endl;
|
||||||
err = ulDaqInScan(handle,
|
err = ulDaqInScan(handle, indesc, neninchannels,
|
||||||
indesc,
|
|
||||||
neninchannels,
|
|
||||||
2 * td->samplesPerBlock, // Watch the 2 here!
|
2 * td->samplesPerBlock, // Watch the 2 here!
|
||||||
&samplerate,
|
&samplerate, scanoptions, inscanflags, inbuffer);
|
||||||
scanoptions,
|
|
||||||
inscanflags,
|
|
||||||
inbuffer);
|
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs scan status on output, to catch up with position
|
// Runs scan status on output, to catch up with position
|
||||||
@ -334,22 +361,28 @@ void threadfcn(DT9837A* td) {
|
|||||||
assert(outscanstat == SS_RUNNING);
|
assert(outscanstat == SS_RUNNING);
|
||||||
|
|
||||||
if (outxstat.currentScanCount > outTotalCount + 2 * samplesPerBlock) {
|
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;
|
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;
|
outTotalCount = outxstat.currentScanCount;
|
||||||
|
|
||||||
/* std::cerr << "Samples scanned: " << outxstat.currentTotalCount << endl; */
|
/* std::cerr << "Samples scanned: " << outxstat.currentTotalCount << endl;
|
||||||
|
*/
|
||||||
if (outxstat.currentIndex < buffer_mid_idx_out) {
|
if (outxstat.currentIndex < buffer_mid_idx_out) {
|
||||||
topoutenqueued = false;
|
topoutenqueued = false;
|
||||||
if (!botoutenqueued) {
|
if (!botoutenqueued) {
|
||||||
/* cerr << "Copying output buffer to bottom" << endl; */
|
/* cerr << "Copying output buffer to bottom" << endl; */
|
||||||
double *bufcpy;
|
double *bufcpy;
|
||||||
if (!outqueue->empty()) {
|
if (!outqueue->empty()) {
|
||||||
bufcpy = outqueue->dequeue();
|
bufcpy = (double *)outqueue->dequeue();
|
||||||
}
|
} else {
|
||||||
else {
|
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL "
|
||||||
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL QUEUE WITH ZEROS ***********" << endl;
|
"QUEUE WITH ZEROS ***********"
|
||||||
bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*nenoutchannels));
|
<< endl;
|
||||||
|
bufcpy = static_cast<double *>(
|
||||||
|
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||||
bufcpy[sample] = 0;
|
bufcpy[sample] = 0;
|
||||||
}
|
}
|
||||||
@ -361,18 +394,19 @@ void threadfcn(DT9837A* td) {
|
|||||||
free(bufcpy);
|
free(bufcpy);
|
||||||
botoutenqueued = true;
|
botoutenqueued = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
botoutenqueued = false;
|
botoutenqueued = false;
|
||||||
if (!topoutenqueued) {
|
if (!topoutenqueued) {
|
||||||
/* cerr << "Copying output buffer to top" << endl; */
|
/* cerr << "Copying output buffer to top" << endl; */
|
||||||
double *bufcpy;
|
double *bufcpy;
|
||||||
if (!outqueue->empty()) {
|
if (!outqueue->empty()) {
|
||||||
bufcpy = outqueue->dequeue();
|
bufcpy = (double *)outqueue->dequeue();
|
||||||
}
|
} else {
|
||||||
else {
|
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL "
|
||||||
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL QUEUE WITH ZEROS ***********" << endl;
|
"QUEUE WITH ZEROS ***********"
|
||||||
bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*nenoutchannels));
|
<< endl;
|
||||||
|
bufcpy = static_cast<double *>(
|
||||||
|
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||||
bufcpy[sample] = 0;
|
bufcpy[sample] = 0;
|
||||||
}
|
}
|
||||||
@ -395,7 +429,10 @@ void threadfcn(DT9837A* td) {
|
|||||||
}
|
}
|
||||||
assert(inscanstat == SS_RUNNING);
|
assert(inscanstat == SS_RUNNING);
|
||||||
if (inxstat.currentScanCount > inTotalCount + 2 * samplesPerBlock) {
|
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;
|
cerr << "***** ERROR: Missing input sample blocks, count="
|
||||||
|
<< inxstat.currentScanCount
|
||||||
|
<< ", probably due to too small buffer size. Exiting thread. *****"
|
||||||
|
<< endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
inTotalCount = inxstat.currentScanCount;
|
inTotalCount = inxstat.currentScanCount;
|
||||||
@ -404,12 +441,16 @@ void threadfcn(DT9837A* td) {
|
|||||||
topinenqueued = false;
|
topinenqueued = false;
|
||||||
if (!botinenqueued) {
|
if (!botinenqueued) {
|
||||||
/* cerr << "Copying in buffer bot" << endl; */
|
/* cerr << "Copying in buffer bot" << endl; */
|
||||||
double* bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*neninchannels));
|
double *bufcpy = static_cast<double *>(
|
||||||
|
malloc(sizeof(double) * samplesPerBlock * neninchannels));
|
||||||
us monitoroffset = monitorOutput ? 1 : 0;
|
us monitoroffset = monitorOutput ? 1 : 0;
|
||||||
assert(neninchannels > 0);
|
assert(neninchannels > 0);
|
||||||
for(us channel=0;channel<(neninchannels-monitoroffset);channel++) {
|
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
||||||
|
channel++) {
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||||
bufcpy[(monitoroffset+channel)*samplesPerBlock+sample] = inbuffer[buffer_mid_idx_in + sample*neninchannels+channel];
|
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
|
||||||
|
inbuffer[buffer_mid_idx_in + sample * neninchannels +
|
||||||
|
channel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (monitorOutput) {
|
if (monitorOutput) {
|
||||||
@ -417,22 +458,25 @@ void threadfcn(DT9837A* td) {
|
|||||||
// our convention
|
// our convention
|
||||||
us channel = neninchannels - 1;
|
us channel = neninchannels - 1;
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||||
bufcpy[sample] = inbuffer[buffer_mid_idx_in + sample*neninchannels+channel];
|
bufcpy[sample] = inbuffer[buffer_mid_idx_in +
|
||||||
|
sample * neninchannels + channel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inqueue->enqueue(bufcpy);
|
inqueue->enqueue((void *)bufcpy);
|
||||||
botinenqueued = true;
|
botinenqueued = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
botinenqueued = false;
|
botinenqueued = false;
|
||||||
if (!topinenqueued) {
|
if (!topinenqueued) {
|
||||||
double* bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*neninchannels));
|
double *bufcpy = static_cast<double *>(
|
||||||
|
malloc(sizeof(double) * samplesPerBlock * neninchannels));
|
||||||
us monitoroffset = monitorOutput ? 1 : 0;
|
us monitoroffset = monitorOutput ? 1 : 0;
|
||||||
assert(neninchannels > 0);
|
assert(neninchannels > 0);
|
||||||
for(us channel=0;channel<(neninchannels-monitoroffset);channel++) {
|
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
||||||
|
channel++) {
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
||||||
bufcpy[(monitoroffset+channel)*samplesPerBlock+sample] = inbuffer[sample*neninchannels+channel];
|
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
|
||||||
|
inbuffer[sample * neninchannels + channel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (monitorOutput) {
|
if (monitorOutput) {
|
||||||
@ -445,11 +489,10 @@ void threadfcn(DT9837A* td) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* cerr << "Copying in buffer top" << endl; */
|
/* cerr << "Copying in buffer top" << endl; */
|
||||||
inqueue->enqueue(bufcpy);
|
inqueue->enqueue((void *)bufcpy);
|
||||||
topinenqueued = true;
|
topinenqueued = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(sleeptime_us));
|
std::this_thread::sleep_for(std::chrono::microseconds(sleeptime_us));
|
||||||
@ -457,7 +500,6 @@ void threadfcn(DT9837A* td) {
|
|||||||
} // End of while loop
|
} // End of while loop
|
||||||
/* std::cerr << "Exit of while loop" << endl; */
|
/* std::cerr << "Exit of while loop" << endl; */
|
||||||
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
|
||||||
if (hasoutput) {
|
if (hasoutput) {
|
||||||
@ -474,12 +516,12 @@ exit:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(indesc) delete indesc;
|
if (indesc)
|
||||||
|
delete indesc;
|
||||||
std::cerr << "Exit of DAQ thread fcn" << endl;
|
std::cerr << "Exit of DAQ thread fcn" << endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DT9837A::start( SafeQueue<double*> *inqueue, SafeQueue<double*> *outqueue) {
|
void DT9837A::start(SafeQueue<void *> *inqueue, SafeQueue<void *> *outqueue) {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
throw runtime_error("Thread is already running");
|
throw runtime_error("Thread is already running");
|
||||||
}
|
}
|
||||||
@ -497,22 +539,24 @@ void DT9837A::start( SafeQueue<double*> *inqueue, SafeQueue<double*> *outqueue)
|
|||||||
|
|
||||||
if (hasinput) {
|
if (hasinput) {
|
||||||
assert(!inbuffer);
|
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);
|
assert(!outbuffer);
|
||||||
outbuffer = new double[nenoutchannels()*samplesPerBlock*2]; // Watch the 2!
|
outbuffer =
|
||||||
|
new double[nenoutchannels() * samplesPerBlock * 2]; // Watch the 2!
|
||||||
}
|
}
|
||||||
this->inqueue = inqueue;
|
this->inqueue = inqueue;
|
||||||
this->outqueue = outqueue;
|
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}; */
|
/* boolvec couplingmode = {true, true, true, true}; */
|
||||||
/* setACCouplingMode(couplingmode); */
|
/* setACCouplingMode(couplingmode); */
|
||||||
|
|
||||||
stopThread = false;
|
stopThread = false;
|
||||||
thread = new std::thread(threadfcn, this);
|
thread = new std::thread(threadfcn, this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DT9837A::stop() {
|
void DT9837A::stop() {
|
||||||
@ -528,8 +572,10 @@ void DT9837A::stop() {
|
|||||||
|
|
||||||
outqueue = NULL;
|
outqueue = NULL;
|
||||||
inqueue = NULL;
|
inqueue = NULL;
|
||||||
if(inbuffer) delete inbuffer;
|
if (inbuffer)
|
||||||
if(outbuffer) delete outbuffer;
|
delete inbuffer;
|
||||||
|
if (outbuffer)
|
||||||
|
delete outbuffer;
|
||||||
outbuffer = NULL;
|
outbuffer = NULL;
|
||||||
inbuffer = NULL;
|
inbuffer = NULL;
|
||||||
}
|
}
|
||||||
@ -537,7 +583,8 @@ void DT9837A::stop() {
|
|||||||
us DT9837A::neninchannels() const {
|
us DT9837A::neninchannels() const {
|
||||||
mutexlock lock(mutex);
|
mutexlock lock(mutex);
|
||||||
us inch = std::count(inChannels.begin(), inChannels.end(), true);
|
us inch = std::count(inChannels.begin(), inChannels.end(), true);
|
||||||
if(monitorOutput) inch++;
|
if (monitorOutput)
|
||||||
|
inch++;
|
||||||
return inch;
|
return inch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,3 +592,26 @@ us DT9837A::nenoutchannels() const {
|
|||||||
mutexlock lock(mutex);
|
mutexlock lock(mutex);
|
||||||
return std::count(outChannels.begin(), outChannels.end(), true);
|
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 <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
using std::atomic;
|
using std::atomic;
|
||||||
typedef vector<bool> boolvec;
|
|
||||||
typedef unsigned int us;
|
|
||||||
|
|
||||||
class DT9837A: public Daq {
|
Daq* createUlDaqDevice(const DeviceInfo& devinfo,
|
||||||
us samplesPerBlock;
|
const DaqConfiguration& config);
|
||||||
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*);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ULDAQ_H
|
#endif // ULDAQ_H
|
||||||
|
|
||||||
|
@ -1,360 +1,2 @@
|
|||||||
include "lasp_common_decls.pxd"
|
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
|
DEF UL_ERR_MSG_LEN = 512
|
||||||
|
|
||||||
ctypedef unsigned us
|
ctypedef unsigned us
|
||||||
|
ctypedef vector[bool] boolvec
|
||||||
|
|
||||||
cdef extern from "lasp_cppdaq.h" nogil:
|
cdef extern from "lasp_cppdaq.h" nogil:
|
||||||
cdef cppclass Daq:
|
cdef cppclass cppDaq "Daq":
|
||||||
void start(SafeQueue[double*] *inQueue,
|
void start(SafeQueue[void*] *inQueue,
|
||||||
SafeQueue[double*] *outQueue)
|
SafeQueue[void*] *outQueue) except +
|
||||||
void stop()
|
void stop()
|
||||||
double samplerate()
|
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 neninchannels()
|
||||||
us nenoutchannels()
|
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:
|
ctypedef struct PyStreamData:
|
||||||
PyObject* pyCallback
|
PyObject* pyCallback
|
||||||
@ -55,34 +82,27 @@ ctypedef struct PyStreamData:
|
|||||||
|
|
||||||
# If these queue pointers are NULL, it means the stream does not have an
|
# If these queue pointers are NULL, it means the stream does not have an
|
||||||
# input, or output.
|
# input, or output.
|
||||||
SafeQueue[double*] *inQueue
|
SafeQueue[void*] *inQueue
|
||||||
SafeQueue[double*] *outQueue
|
SafeQueue[void*] *outQueue
|
||||||
CPPThread[void*, void (*)(void*)] *thread
|
CPPThread[void*, void (*)(void*)] *thread
|
||||||
|
|
||||||
cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
||||||
cdef:
|
cdef:
|
||||||
PyStreamData* sd
|
PyStreamData* sd = <PyStreamData*> voidsd
|
||||||
cnp.NPY_TYPES npy_format
|
cnp.NPY_TYPES npy_format
|
||||||
|
|
||||||
double* inbuffer = NULL
|
double* inbuffer = NULL
|
||||||
double* outbuffer = NULL
|
double* outbuffer = NULL
|
||||||
|
|
||||||
unsigned noutchannels
|
unsigned noutchannels= sd.noutchannels
|
||||||
unsigned ninchannels
|
unsigned ninchannels= sd.ninchannels
|
||||||
unsigned nBytesPerChan
|
unsigned nBytesPerChan= sd.nBytesPerChan
|
||||||
unsigned nFramesPerBlock
|
unsigned nFramesPerBlock= sd.nFramesPerBlock
|
||||||
|
|
||||||
unsigned sw = sizeof(double)
|
unsigned sw = sizeof(double)
|
||||||
|
|
||||||
sd = <PyStreamData*> voidsd
|
double sleeptime = (<double> sd.nFramesPerBlock)/(4*sd.samplerate);
|
||||||
cdef:
|
|
||||||
double sleeptime = (<double> nFramesPerBlock)/(4*sd.samplerate);
|
|
||||||
us sleeptime_us = <us> (sleeptime*1e6);
|
us sleeptime_us = <us> (sleeptime*1e6);
|
||||||
ninchannels = sd.ninchannels
|
|
||||||
noutchannels = sd.noutchannels
|
|
||||||
|
|
||||||
nBytesPerChan = sd.nBytesPerChan
|
|
||||||
nFramesPerBlock = sd.nFramesPerBlock
|
|
||||||
|
|
||||||
with gil:
|
with gil:
|
||||||
npy_format = cnp.NPY_FLOAT64
|
npy_format = cnp.NPY_FLOAT64
|
||||||
@ -119,7 +139,7 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
|||||||
|
|
||||||
if sd.inQueue and not sd.inQueue.empty():
|
if sd.inQueue and not sd.inQueue.empty():
|
||||||
# Waiting indefinitely on the queue...
|
# Waiting indefinitely on the queue...
|
||||||
inbuffer = sd.inQueue.dequeue()
|
inbuffer = <double*> sd.inQueue.dequeue()
|
||||||
if inbuffer == NULL:
|
if inbuffer == NULL:
|
||||||
printf('Stopping thread...\n')
|
printf('Stopping thread...\n')
|
||||||
return
|
return
|
||||||
@ -153,10 +173,10 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
|
|||||||
|
|
||||||
fprintf(stderr, 'Exiting python thread...\n')
|
fprintf(stderr, 'Exiting python thread...\n')
|
||||||
|
|
||||||
cdef class UlDaq:
|
cdef class Daq:
|
||||||
cdef:
|
cdef:
|
||||||
PyStreamData *sd
|
PyStreamData *sd
|
||||||
Daq* daq_device
|
cppDaq* daq_device
|
||||||
|
|
||||||
def __cinit__(self):
|
def __cinit__(self):
|
||||||
|
|
||||||
@ -206,7 +226,7 @@ cdef class UlDaq:
|
|||||||
bint in_stream=False
|
bint in_stream=False
|
||||||
bint out_stream=False
|
bint out_stream=False
|
||||||
|
|
||||||
DT9837A* daq_device
|
cppDaq* daq_device
|
||||||
|
|
||||||
if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512:
|
if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512:
|
||||||
raise ValueError('Invalid number of nFramesPerBlock')
|
raise ValueError('Invalid number of nFramesPerBlock')
|
||||||
@ -266,7 +286,7 @@ cdef class UlDaq:
|
|||||||
inch_enabled = [True if ch.channel_enabled else False for ch in
|
inch_enabled = [True if ch.channel_enabled else False for ch in
|
||||||
daqconfig.getInputChannels()]
|
daqconfig.getInputChannels()]
|
||||||
|
|
||||||
self.sd.inQueue = new SafeQueue[double*]()
|
self.sd.inQueue = new SafeQueue[void*]()
|
||||||
|
|
||||||
# Create channel maps for output channels
|
# Create channel maps for output channels
|
||||||
outch_enabled = 1*[False]
|
outch_enabled = 1*[False]
|
||||||
@ -275,18 +295,18 @@ cdef class UlDaq:
|
|||||||
outch_enabled = [True if ch.channel_enabled else False for ch in
|
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:
|
# if 'DT9837A' in device.name:
|
||||||
daq_device = new DT9837A(
|
# daq_device = new DT9837A(
|
||||||
daqconfig.nFramesPerBlock,
|
# daqconfig.nFramesPerBlock,
|
||||||
inch_enabled,
|
# inch_enabled,
|
||||||
outch_enabled,
|
# outch_enabled,
|
||||||
samplerate,
|
# samplerate,
|
||||||
monitorOutput,
|
# monitorOutput,
|
||||||
device.index)
|
# device.index)
|
||||||
else:
|
# else:
|
||||||
raise RuntimeError(f'Device {device.name} not found or not configured')
|
# raise RuntimeError(f'Device {device.name} not found or not configured')
|
||||||
|
|
||||||
self.sd.pyCallback = <PyObject*> avstream._audioCallback
|
self.sd.pyCallback = <PyObject*> avstream._audioCallback
|
||||||
self.sd.ninchannels = daq_device.neninchannels()
|
self.sd.ninchannels = daq_device.neninchannels()
|
||||||
@ -361,55 +381,56 @@ cdef class UlDaq:
|
|||||||
devices
|
devices
|
||||||
"""
|
"""
|
||||||
cdef:
|
cdef:
|
||||||
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
|
pass
|
||||||
DaqDeviceDescriptor descriptor
|
# DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
|
||||||
DaqDeviceInterface interfaceType = ANY_IFC
|
# DaqDeviceDescriptor descriptor
|
||||||
DaqDeviceHandle handle
|
# DaqDeviceInterface interfaceType = ANY_IFC
|
||||||
|
# DaqDeviceHandle handle
|
||||||
|
|
||||||
UlError err
|
# UlError err
|
||||||
|
|
||||||
unsigned int numdevs = MAX_DEF_COUNT
|
# unsigned int numdevs = MAX_DEF_COUNT
|
||||||
unsigned deviceno
|
# unsigned deviceno
|
||||||
|
|
||||||
if self.sd is not NULL:
|
# if self.sd is not NULL:
|
||||||
assert self.daq_device is not NULL
|
# assert self.daq_device is not NULL
|
||||||
raise RuntimeError('Cannot acquire device info: stream is already opened.')
|
# raise RuntimeError('Cannot acquire device info: stream is already opened.')
|
||||||
|
|
||||||
err = ulGetDaqDeviceInventory(interfaceType,
|
# err = ulGetDaqDeviceInventory(interfaceType,
|
||||||
devdescriptors,
|
# devdescriptors,
|
||||||
&numdevs)
|
# &numdevs)
|
||||||
if(err != ERR_NO_ERROR):
|
# if(err != ERR_NO_ERROR):
|
||||||
raise RuntimeError(f'Device inventarization failed: {err}')
|
# raise RuntimeError(f'Device inventarization failed: {err}')
|
||||||
|
|
||||||
|
|
||||||
py_devinfo = []
|
# py_devinfo = []
|
||||||
for deviceno in range(numdevs):
|
# for deviceno in range(numdevs):
|
||||||
descriptor = devdescriptors[deviceno]
|
# descriptor = devdescriptors[deviceno]
|
||||||
|
|
||||||
if descriptor.productName == b'DT9837A':
|
# if descriptor.productName == b'DT9837A':
|
||||||
# Create proper interface name
|
# # Create proper interface name
|
||||||
if descriptor.devInterface == DaqDeviceInterface.USB_IFC:
|
# if descriptor.devInterface == DaqDeviceInterface.USB_IFC:
|
||||||
name = 'USB - '
|
# name = 'USB - '
|
||||||
elif descriptor.devInterface == DaqDeviceInterface.BLUETOOTH_IFC:
|
# elif descriptor.devInterface == DaqDeviceInterface.BLUETOOTH_IFC:
|
||||||
name = 'Bluetooth - '
|
# name = 'Bluetooth - '
|
||||||
elif descriptor.devInterface == DaqDeviceInterface.ETHERNET_IFC:
|
# elif descriptor.devInterface == DaqDeviceInterface.ETHERNET_IFC:
|
||||||
name = 'Ethernet - '
|
# name = 'Ethernet - '
|
||||||
|
|
||||||
name += descriptor.productName.decode('utf-8') + ', id ' + \
|
# name += descriptor.productName.decode('utf-8') + ', id ' + \
|
||||||
descriptor.uniqueId.decode('utf-8')
|
# descriptor.uniqueId.decode('utf-8')
|
||||||
|
|
||||||
d = DeviceInfo(
|
# d = DeviceInfo(
|
||||||
api = -1,
|
# api = -1,
|
||||||
index = deviceno,
|
# index = deviceno,
|
||||||
probed = True,
|
# probed = True,
|
||||||
name = name,
|
# name = name,
|
||||||
outputchannels = 1,
|
# outputchannels = 1,
|
||||||
inputchannels = 4,
|
# inputchannels = 4,
|
||||||
duplexchannels = 0,
|
# duplexchannels = 0,
|
||||||
samplerates = [10000, 16000, 20000, 32000, 48000, 50000] ,
|
# samplerates = [10000, 16000, 20000, 32000, 48000, 50000] ,
|
||||||
sampleformats = ['64-bit floats'],
|
# sampleformats = ['64-bit floats'],
|
||||||
prefsamplerate = 48000,
|
# prefsamplerate = 48000,
|
||||||
hasInputIEPE = True)
|
# hasInputIEPE = True)
|
||||||
py_devinfo.append(d)
|
# py_devinfo.append(d)
|
||||||
return py_devinfo
|
# return py_devinfo
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include "lasp_cppuldaq.h"
|
#include "lasp_cppdaq.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <thread>
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
|
||||||
@ -14,13 +16,35 @@ int main() {
|
|||||||
double samplerate = 10000;
|
double samplerate = 10000;
|
||||||
const us samplesPerBlock = 256;
|
const us samplesPerBlock = 256;
|
||||||
|
|
||||||
DT9837A daq(
|
DaqConfiguration config;
|
||||||
samplesPerBlock,
|
config.eninchannels = inChannels;
|
||||||
inChannels,
|
config.enoutchannels = outChannels;
|
||||||
outChannels,
|
config.inputIEPEEnabled = {false, false, false, false};
|
||||||
samplerate,
|
config.inputACCouplingMode = {false, false, false, false};
|
||||||
true // monitor Output
|
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*> inqueue;
|
||||||
SafeQueue<void*> outqueue;
|
SafeQueue<void*> outqueue;
|
||||||
@ -42,19 +66,16 @@ int main() {
|
|||||||
outqueue.enqueue(data);
|
outqueue.enqueue(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
daq.start(&inqueue, &outqueue);
|
daq->start(&inqueue, &outqueue);
|
||||||
/* daq.start(NULL, &outqueue); */
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
|
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
|
||||||
/* std::string a; */
|
|
||||||
/* std::cin >> a; */
|
|
||||||
|
|
||||||
daq.stop();
|
daq->stop();
|
||||||
|
|
||||||
while(!inqueue.empty()) {
|
while(!inqueue.empty()) {
|
||||||
double* buf = (double*) inqueue.dequeue();
|
double* buf = (double*) inqueue.dequeue();
|
||||||
for(us i=0;i<samplesPerBlock;i++) {
|
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 << buf[ch*samplesPerBlock+i] << " ";
|
||||||
}
|
}
|
||||||
cout << endl;
|
cout << endl;
|
||||||
|
Loading…
Reference in New Issue
Block a user