Working in CPP code, with multiple-api-api

This commit is contained in:
Anne de Jong 2020-10-06 21:29:02 +02:00
parent a73ef3d7a8
commit a3963c4595
9 changed files with 624 additions and 865 deletions

View File

@ -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})

View File

@ -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

View File

@ -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);
}
} }

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;