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"
"${CMAKE_CURRENT_SOURCE_DIR}/lasp/*.py"
"wrappers"
"lasp_rtaudio")
"lasp_daq")
# )
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
# configure_file(${SETUP_PY_IN} ${SETUP_PY})

View File

@ -1,6 +1,7 @@
include_directories(/usr/include/rtaudio)
add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp lasp_cpprtaudio.cpp)
# add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp lasp_cpprtaudio.cpp)
add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp )
set_source_files_properties(lasp_daq.pyx PROPERTIES CYTHON_IS_CXX TRUE)
set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS

View File

@ -1,80 +1,84 @@
#include "lasp_cppdaq.h"
#include "lasp_cppuldaq.h"
#include <iostream>
using std::cout;
using std::endl;
#define MAX_DEV_COUNT_PER_API 20
#ifdef HAS_ULDAQ_LINUX_API
void fillUlDaqDeviceInfo(vector<DeviceInfo>& devinfolist) {
void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
UlError err;
unsigned int numdevs = MAX_DEV_COUNT_PER_API;
unsigned deviceno;
UlError err;
unsigned int numdevs = MAX_DEV_COUNT_PER_API;
unsigned deviceno;
DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API];
DaqDeviceDescriptor descriptor;
DaqDeviceInterface interfaceType = ANY_IFC;
DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API];
DaqDeviceDescriptor descriptor;
DaqDeviceInterface interfaceType = ANY_IFC;
err = ulGetDaqDeviceInventory(interfaceType,
devdescriptors,
&numdevs);
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, &numdevs);
if(err != ERR_NO_ERROR)
throw std::runtime_error("Device inventarization failed");
if (err != ERR_NO_ERROR)
throw std::runtime_error("UlDaq device inventarization failed");
for(unsigned i =0; i<numdevs; i++) {
descriptor = devdescriptors[i];
for (unsigned i = 0; i < numdevs; i++) {
DeviceInfo devinfo;
devinfo.api = uldaqapi;
string name, interface;
descriptor = devdescriptors[i];
if(string(descriptor.productName) == "DT9837A") {
if(descriptor.devInterface == USB_IFC) {
name = "USB - ";
} else if(descriptor.devInterface == BLUETOOTH_IFC) {
/* devinfo. */
name = "Bluetooth - ";
} else if(descriptor.devInterface == ETHERNET_IFC) {
/* devinfo. */
name = "Ethernet - ";
}
name += string(descriptor.productName) + " ";
name += string(descriptor.uniqueId);
devinfo.name = name;
DeviceInfo devinfo;
devinfo.api = uldaqapi;
string name, interface;
devinfo.devindex = i;
devinfo.availableDataTypes.push_back(dtype_fl64);
if (string(descriptor.productName) == "DT9837A") {
if (descriptor.devInterface == USB_IFC) {
name = "USB - ";
} else if (descriptor.devInterface == BLUETOOTH_IFC) {
/* devinfo. */
name = "Bluetooth - ";
} else if (descriptor.devInterface == ETHERNET_IFC) {
/* devinfo. */
name = "Ethernet - ";
}
devinfo.ninchannels = 4;
devinfo.noutchannels = 1;
name += string(descriptor.productName) + " ";
name += string(descriptor.uniqueId);
devinfo.name = name;
devinfo.availableSampleRates.push_back(10000);
devinfo.availableSampleRates.push_back(12000);
devinfo.availableSampleRates.push_back(20000);
devinfo.availableSampleRates.push_back(24000);
devinfo.availableSampleRates.push_back(32000);
devinfo.availableSampleRates.push_back(48000);
devinfo.availableSampleRates.push_back(51000);
devinfo.devindex = i;
devinfo.availableDataTypes.push_back(dtype_fl64);
devinfo.prefSampleRateIndex = 5;
devinfo.prefSampleRate = 48000;
devinfo.ninchannels = 4;
devinfo.noutchannels = 1;
devinfo.hasInputIEPE = true;
devinfo.hasInputACCouplingSwitch = true;
devinfo.hasInputTrigger = true;
devinfo.availableSampleRates.push_back(10000);
devinfo.availableSampleRates.push_back(12000);
devinfo.availableSampleRates.push_back(20000);
devinfo.availableSampleRates.push_back(24000);
devinfo.availableSampleRates.push_back(32000);
devinfo.availableSampleRates.push_back(48000);
devinfo.availableSampleRates.push_back(51000);
devinfolist.push_back(devinfo);
devinfo.prefSampleRateIndex = 5;
}
devinfo.hasInputIEPE = true;
devinfo.hasInputACCouplingSwitch = true;
devinfo.hasInputTrigger = true;
devinfolist.push_back(devinfo);
}
}
}
#endif
vector<DeviceInfo> DaqDevices::getDeviceInfo() {
vector<DeviceInfo> devs;
vector<DeviceInfo> devs;
#ifdef HAS_ULDAQ_LINUX_API
fillUlDaqDeviceInfo(devs);
fillUlDaqDeviceInfo(devs);
#endif
#ifdef HAS_RTAUDIO_ALSA_API
#endif
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
@ -82,11 +86,24 @@ vector<DeviceInfo> DaqDevices::getDeviceInfo() {
#ifdef HAS_RTAUDIO_WIN_WASAPI_API
#endif
return devs;
return devs;
}
Daq* DaqDevices::createDevice(const DeviceInfo&) {
Daq *DaqDevices::createDevice(const DeviceInfo &devinfo,
const DaqConfiguration &config) {
// Some basic sanity checks
if ((devinfo.ninchannels != config.eninchannels.size())) {
throw runtime_error("Invalid length of enabled input channels specified");
}
if ((devinfo.noutchannels != config.enoutchannels.size())) {
throw runtime_error("outvalid length of enabled output channels specified");
}
return NULL;
if (devinfo.api == uldaqapi) {
return createUlDaqDevice(devinfo, config);
} else {
throw std::runtime_error(string("Unable to match API: ") +
devinfo.api.apiname);
}
}

View File

@ -1,5 +1,6 @@
#ifndef LASP_CPPDAQ_H
#define LASP_CPPDAQ_H
#include <strstream>
#ifdef HAS_RTAUDIO
#include <RtAudio.h>
@ -10,27 +11,30 @@
#endif
#include "lasp_cppqueue.h"
#include "vector"
#include "string"
using std::vector;
#include "vector"
using std::string;
using std::vector;
using std::runtime_error;
typedef unsigned int us;
typedef vector<bool> boolvec;
class DataType {
public:
const string name;
string name;
unsigned sw;
bool is_floating;
DataType(const char* name,unsigned sw,bool is_floating):
name(name),
sw(sw),
is_floating(is_floating) {}
DataType(const char *name, unsigned sw, bool is_floating)
: name(name), sw(sw), is_floating(is_floating) {}
};
const DataType dtype_fl64("64-bits floating point",4,true);
const DataType dtype_int8("8-bits integers",1,false);
const DataType dtype_int16("16-bits integers",2,false);
const DataType dtype_int32("32-bits integers",4,false);
const DataType dtype_invalid("invalid data type", 0, false);
const DataType dtype_fl64("64-bits floating point", 4, true);
const DataType dtype_int8("8-bits integers", 1, false);
const DataType dtype_int16("16-bits integers", 2, false);
const DataType dtype_int32("32-bits integers", 4, false);
const std::vector<DataType> dataTypes = {
dtype_int8,
@ -45,27 +49,32 @@ class DaqApi {
unsigned apicode = 0;
unsigned api_specific_subcode = 0;
DaqApi(string apiname,
unsigned apicode,
unsigned api_specific_subcode=0):
apiname(apiname),
apicode(apicode),
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
: apiname(apiname), apicode(apicode),
api_specific_subcode(api_specific_subcode) {}
DaqApi(){}
DaqApi() {}
bool operator==(const DaqApi &other) const {
return (apiname == other.apiname && apicode == other.apicode &&
api_specific_subcode == other.api_specific_subcode);
}
};
#ifdef HAS_ULDAQ_LINUX_API
const DaqApi uldaqapi = DaqApi("UlDaq", 0);
const DaqApi uldaqapi("UlDaq", 0);
#endif
#ifdef HAS_RTAUDIO_ALSA_API
const DaqApi rtaudioalsaapi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
#endif
const vector<DaqApi> compiledApis = {
#ifdef HAS_ULDAQ_LINUX_API
uldaqapi,
#endif
#ifdef HAS_RTAUDIO_ALSA_API
DaqApi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA),
rtaudioalsaapi,
#endif
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
DaqApi("RtAudio Linux Pulseaudio",2, RtAudio::Api::LINUX_PULSE),
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
#endif
#ifdef HAS_RTAUDIO_WIN_WASAPI_API
DaqApi("RtAudio Windows Wasapi", 3, RtAudio::Api::WINDOWS_WASAPI),
@ -82,41 +91,74 @@ class DeviceInfo {
vector<DataType> availableDataTypes;
vector<double> availableSampleRates;
unsigned prefSampleRateIndex = 0;
double prefSampleRate = 0;
vector<us> availableFramesPerBlock;
unsigned ninchannels =0;
unsigned noutchannels =0;
int prefSampleRateIndex = -1;
unsigned ninchannels = 0;
unsigned noutchannels = 0;
bool hasInputIEPE = false;
bool hasInputACCouplingSwitch = false;
bool hasInputTrigger = false;
double prefSampleRate() const {
if ((prefSampleRateIndex < availableSampleRates.size()) &&
(prefSampleRateIndex >= 0)) {
return availableSampleRates[prefSampleRateIndex];
} else {
throw std::runtime_error("No prefered sample rate available");
}
}
operator string() const {
std::stringstream str;
str << api.apiname + " " << devindex <<
" number of input channels: " << ninchannels <<
" number of output channels: " << noutchannels;
return str.str();
}
};
// Device configuration parameters
class DaqConfiguration {
public:
boolvec eninchannels; // Enabled input channels
boolvec enoutchannels; // Enabled output channels
unsigned sampleRateIndex; // Index in list of sample rates
DataType
datatype = dtype_invalid; // Required datatype for output, should be present in the list
bool monitorOutput; // Whether the first output channel should be replicated
// to the input as the first channel
unsigned nFramesPerBlock;
boolvec inputIEPEEnabled;
boolvec inputACCouplingMode;
boolvec inputHighRange;
};
class Daq;
class DaqDevices {
public:
static vector<DeviceInfo> getDeviceInfo();
static Daq* createDevice(const DeviceInfo&);
static Daq *createDevice(const DeviceInfo &, const DaqConfiguration &config);
};
class Daq{
class Daq {
public:
virtual void start(
SafeQueue<void*> *inqueue,
SafeQueue<void*> *outqueue) = 0;
virtual void start(SafeQueue<void *> *inqueue,
SafeQueue<void *> *outqueue) = 0;
virtual void stop() = 0;
virtual double samplerate() const = 0;
virtual DataType getDataType() const = 0;
virtual ~Daq() {};
virtual ~Daq(){};
virtual us neninchannels() const = 0;
virtual us nenoutchannels() const = 0;
};
#endif // LASP_CPPDAQ_H

View File

@ -1,13 +1,19 @@
#include "lasp_cppuldaq.h"
#include <stdexcept>
#include <uldaq.h>
#include <algorithm>
#include <atomic>
#include <cassert>
#include <iostream>
#include <cstring>
#include <chrono>
#include <cstring>
#include <iostream>
#include <mutex>
#include <stdexcept>
#include <thread>
#include <uldaq.h>
#include <vector>
using std::endl;
using std::cerr;
using std::cout;
using std::endl;
using std::runtime_error;
typedef std::lock_guard<std::mutex> mutexlock;
/* using std::this_thread; */
@ -15,178 +21,213 @@ typedef std::lock_guard<std::mutex> mutexlock;
const us MAX_DEF_COUNT = 100;
const us UL_ERR_MSG_LEN = 512;
class DT9837A : public Daq {
us samplesPerBlock;
double _samplerate;
boolvec inChannels;
boolvec high_range;
boolvec outChannels;
bool monitorOutput;
atomic<bool> stopThread;
DaqDeviceHandle handle = 0;
std::thread *thread = NULL;
mutable std::mutex mutex;
SafeQueue<void *> *inqueue = NULL;
SafeQueue<void *> *outqueue = NULL;
double *inbuffer = NULL;
double *outbuffer = NULL;
public:
double samplerate() const { return this->_samplerate; }
DT9837A(us samplesPerBlock, const boolvec &inChannels,
const boolvec &outChannels, double samplerate, bool monitorOutput,
us device_no = 0);
DT9837A(const DT9837A &) = delete;
~DT9837A();
void setIEPEEnabled(const boolvec &config);
// Coupling_ac: true, means AC coupling, false means DC coupling
void setACCouplingMode(const boolvec &coupling_ac);
void setInputRange(const boolvec &high_range);
us neninchannels() const final;
us nenoutchannels() const final;
bool isRunning() const { return bool(thread); }
virtual void start(SafeQueue<void *> *inqueue,
SafeQueue<void *> *outqueue) final;
virtual void stop() final;
DataType getDataType() const final { return dtype_fl64; }
friend void threadfcn(DT9837A *);
};
inline void showErr(UlError err) {
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
char errmsg[UL_ERR_MSG_LEN];
ulGetErrMsg(err, errmsg);
std::cerr << "UlError: " << errmsg << std::endl;
}
}
DT9837A::DT9837A(
us samplesPerBlock,
boolvec& inChannels,
boolvec& outChannels,
double samplerate,
bool monitorOutput,
us deviceno
):
samplesPerBlock(samplesPerBlock),
_samplerate(samplerate),
inChannels(inChannels),
outChannels(outChannels),
monitorOutput(monitorOutput)
{
if(monitorOutput && !(nenoutchannels() > 0)) {
throw runtime_error("Output monitoring only possible when output is enabled");
}
DT9837A::DT9837A(us samplesPerBlock, const boolvec &inChannels,
const boolvec &outChannels, double samplerate,
bool monitorOutput, us deviceno)
: samplesPerBlock(samplesPerBlock), _samplerate(samplerate),
inChannels(inChannels), outChannels(outChannels),
monitorOutput(monitorOutput) {
if (monitorOutput && !(nenoutchannels() > 0)) {
throw runtime_error(
"Output monitoring only possible when output is enabled");
}
stopThread = false;
high_range = boolvec({false, false, false, false});
stopThread = false;
high_range = boolvec({false, false, false, false});
if(samplesPerBlock < 24 || samplesPerBlock > 8192) {
throw runtime_error("Unsensible number of samples per block chosen");
}
if (samplesPerBlock < 24 || samplesPerBlock > 8192) {
throw runtime_error("Unsensible number of samples per block chosen");
}
// Some sanity checks
if (inChannels.size() != 4) {
throw runtime_error("Invalid length of enabled inChannels vector");
}
// Some sanity checks
if(inChannels.size() != 4) {
throw runtime_error("Invalid length of enabled inChannels vector");
}
// Some sanity checks
if (outChannels.size() != 1) {
throw runtime_error("Invalid length of enabled outChannels vector");
}
if (samplerate < 10000 || samplerate > 51000) {
throw runtime_error("Invalid sample rate");
}
// Some sanity checks
if(outChannels.size() != 1) {
throw runtime_error("Invalid length of enabled outChannels vector");
}
if(samplerate < 10000 || samplerate > 51000) {
throw runtime_error("Invalid sample rate");
}
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT];
DaqDeviceDescriptor descriptor;
DaqDeviceInterface interfaceType = ANY_IFC;
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT];
DaqDeviceDescriptor descriptor;
DaqDeviceInterface interfaceType = ANY_IFC;
UlError err;
UlError err;
us numdevs = MAX_DEF_COUNT;
err = ulGetDaqDeviceInventory(interfaceType, devdescriptors, &numdevs);
if (err != ERR_NO_ERROR) {
throw runtime_error("Device inventarization failed");
}
us numdevs = MAX_DEF_COUNT;
err = ulGetDaqDeviceInventory(interfaceType,
devdescriptors,
&numdevs);
if(err != ERR_NO_ERROR){
throw runtime_error("Device inventarization failed");
}
if (deviceno >= numdevs) {
throw runtime_error("Device number {deviceno} too high {err}. This could "
"happen when the device is currently not connected");
}
if (deviceno >= numdevs) {
throw runtime_error("Device number {deviceno} too high {err}. This could happen when the device is currently not connected");
}
descriptor = devdescriptors[deviceno];
// get a handle to the DAQ device associated with the first descriptor
handle = ulCreateDaqDevice(descriptor);
descriptor = devdescriptors[deviceno];
// get a handle to the DAQ device associated with the first descriptor
handle = ulCreateDaqDevice(descriptor);
if (handle == 0) {
throw runtime_error("Unable to create a handle to the specified DAQ "
"device. Is the device currently in use?");
}
if (handle == 0) {
throw runtime_error("Unable to create a handle to the specified DAQ device. Is the device currently in use?");
}
err = ulConnectDaqDevice(handle);
if (err != ERR_NO_ERROR) {
showErr(err);
ulReleaseDaqDevice(handle);
handle = 0;
throw runtime_error("Unable to connect to device: {err}");
}
err = ulConnectDaqDevice(handle);
if (err != ERR_NO_ERROR) {
showErr(err);
ulReleaseDaqDevice(handle);
handle = 0;
throw runtime_error("Unable to connect to device: {err}");
}
for(us ch=0; ch<4; ch++) {
err = ulAISetConfigDbl(handle, AI_CFG_CHAN_SENSOR_SENSITIVITY, ch, 1.0);
showErr(err);
if(err != ERR_NO_ERROR) {
throw runtime_error("Fatal: could normalize channel sensitivity");
for (us ch = 0; ch < 4; ch++) {
err = ulAISetConfigDbl(handle, AI_CFG_CHAN_SENSOR_SENSITIVITY, ch, 1.0);
showErr(err);
if (err != ERR_NO_ERROR) {
throw runtime_error("Fatal: could normalize channel sensitivity");
}
}
}
}
DT9837A::~DT9837A() {
UlError err;
if(isRunning()) {
if (isRunning()) {
stop();
}
if(handle) {
if (handle) {
err = ulDisconnectDaqDevice(handle);
showErr(err);
err = ulReleaseDaqDevice(handle);
showErr(err);
}
}
void DT9837A::setIEPEEnabled(boolvec& config) {
if(isRunning()) {
void DT9837A::setIEPEEnabled(const boolvec &config) {
if (isRunning()) {
throw runtime_error("Cannot change config while sampling is running");
}
// Some sanity checks
if(config.size() != 4) {
throw runtime_error("Invalid length of enabled inChannels vector");
if (config.size() != 4) {
throw runtime_error("Invalid length of enabled IEPE config vector");
}
IepeMode iepe;
UlError err;
for(us i=0; i< config.size(); i++) {
for (us i = 0; i < config.size(); i++) {
iepe = config[i] ? IEPE_ENABLED : IEPE_DISABLED;
err = ulAISetConfig(handle, AI_CFG_CHAN_IEPE_MODE, i, iepe);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
throw runtime_error("Fatal: could not set IEPE mode");
}
}
}
void DT9837A::setACCouplingMode(boolvec& coupling) {
if(isRunning()) {
void DT9837A::setACCouplingMode(const boolvec &coupling) {
if (isRunning()) {
throw runtime_error("Cannot change config while sampling is running");
}
// Some sanity checks
if(coupling.size() != 4) {
throw runtime_error("Invalid length of enabled inChannels vector");
if (coupling.size() != 4) {
throw runtime_error("Invalid length of enabled AC coupling mode vector");
}
CouplingMode cm;
UlError err;
for(us i=0; i< coupling.size(); i++) {
for (us i = 0; i < coupling.size(); i++) {
cm = coupling[i] ? CM_AC : CM_DC;
err = ulAISetConfig(handle, AI_CFG_CHAN_COUPLING_MODE, i, cm);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
throw runtime_error("Fatal: could not set IEPE mode");
}
}
}
void DT9837A::setInputRange(boolvec& high_range) {
if(isRunning()) {
void DT9837A::setInputRange(const boolvec &high_range) {
if (isRunning()) {
throw runtime_error("Cannot change config while sampling is running");
}
// Some sanity checks
if(high_range.size() != 4) {
if (high_range.size() != 4) {
throw runtime_error("Invalid length of enabled high range vector");
}
this->high_range = high_range;
}
void threadfcn(DT9837A* td) {
void threadfcn(DT9837A *td) {
std::cerr << "Starting DAQ Thread fcn" << endl;
@ -199,11 +240,11 @@ void threadfcn(DT9837A* td) {
bool monitorOutput = td->monitorOutput;
double* inbuffer = td->inbuffer;
double* outbuffer = td->outbuffer;
double *inbuffer = td->inbuffer;
double *outbuffer = td->outbuffer;
SafeQueue<double*>* inqueue = td->inqueue;
SafeQueue<double*>* outqueue = td->outqueue;
SafeQueue<void *> *inqueue = td->inqueue;
SafeQueue<void *> *outqueue = td->outqueue;
ScanStatus inscanstat;
ScanStatus outscanstat;
@ -211,16 +252,16 @@ void threadfcn(DT9837A* td) {
double samplerate = td->samplerate();
const double sleeptime = ((double) samplesPerBlock)/(4*samplerate);
const us sleeptime_us = (us) (sleeptime*1e6);
const double sleeptime = ((double)samplesPerBlock) / (4 * samplerate);
const us sleeptime_us = (us)(sleeptime * 1e6);
/* cerr << "Sleep time in loop: " << sleeptime_us << "us." << endl; */
if(sleeptime_us < 10) {
if (sleeptime_us < 10) {
cerr << "ERROR: Too small buffer size (samplesPerBlock) chosen!" << endl;
return;
}
const us buffer_mid_idx_in = neninchannels*samplesPerBlock;
const us buffer_mid_idx_out = nenoutchannels*samplesPerBlock;
const us buffer_mid_idx_in = neninchannels * samplesPerBlock;
const us buffer_mid_idx_out = nenoutchannels * samplesPerBlock;
DaqDeviceHandle handle = td->handle;
assert(handle);
@ -243,142 +284,135 @@ void threadfcn(DT9837A* td) {
size_t outTotalCount = 0;
// initialize output, if any
if(hasoutput) {
if (hasoutput) {
assert(nenoutchannels == 1);
assert(outqueue);
// Initialize the buffer with zeros, before pushing any data.
for(us sample=0;sample<2*samplesPerBlock;sample++) {
for (us sample = 0; sample < 2 * samplesPerBlock; sample++) {
outbuffer[sample] = 0;
}
cerr << "Starting output DAC" << endl;
err = ulAOutScan(handle,
0,
0,
BIP10VOLTS,
err = ulAOutScan(handle, 0, 0, BIP10VOLTS,
/* BIP60VOLTS, */
2*td->samplesPerBlock, // Watch the 2 here!
&samplerate,
scanoptions,
outscanflags,
outbuffer);
2 * td->samplesPerBlock, // Watch the 2 here!
&samplerate, scanoptions, outscanflags, outbuffer);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
goto exit;
}
}
// Initialize input, if any
if(hasinput) {
if (hasinput) {
indesc = new DaqInChanDescriptor[neninchannels];
us j = 0;
for(us chin=0; chin < 4; chin++) {
if(td->inChannels[chin] == true) {
for (us chin = 0; chin < 4; chin++) {
if (td->inChannels[chin] == true) {
indesc[j].type = DAQI_ANALOG_SE;
indesc[j].channel = chin;
indesc[j].range = td->high_range[chin] ? BIP10VOLTS : BIP1VOLTS;
j++;
}
}
// Overwrite last channel
if(monitorOutput) {
if (monitorOutput) {
indesc[j].type = DAQI_DAC;
indesc[j].channel = 0;
indesc[j].range = BIP10VOLTS;
j++;
}
assert(j==neninchannels);
assert(j == neninchannels);
cerr << "Starting input ADC" << endl;
err = ulDaqInScan(handle,
indesc,
neninchannels,
2*td->samplesPerBlock, // Watch the 2 here!
&samplerate,
scanoptions,
inscanflags,
inbuffer);
if(err != ERR_NO_ERROR) {
err = ulDaqInScan(handle, indesc, neninchannels,
2 * td->samplesPerBlock, // Watch the 2 here!
&samplerate, scanoptions, inscanflags, inbuffer);
if (err != ERR_NO_ERROR) {
showErr(err);
goto exit;
}
}
// Runs scan status on output, to catch up with position
if(hasoutput) {
if (hasoutput) {
err = ulAOutScanStatus(handle, &outscanstat, &outxstat);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
goto exit;
}
}
outTotalCount = outxstat.currentScanCount;
assert(outscanstat == SS_RUNNING);
}
/* std::cerr << "Entering while loop" << endl; */
/* std::cerr << "hasinput: " << hasinput << endl; */
while(!td->stopThread && err == ERR_NO_ERROR) {
while (!td->stopThread && err == ERR_NO_ERROR) {
/* std::cerr << "While..." << endl; */
if(hasoutput) {
if (hasoutput) {
err = ulAOutScanStatus(handle, &outscanstat, &outxstat);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
goto exit;
}
}
assert(outscanstat == SS_RUNNING);
if(outxstat.currentScanCount > outTotalCount+2*samplesPerBlock) {
cerr << "***** WARNING: Missing output sample blocks, DAQ Scan count=" << outxstat.currentScanCount << " while loop count = " << outTotalCount <<", probably due to too small buffer size. *****" << endl;
if (outxstat.currentScanCount > outTotalCount + 2 * samplesPerBlock) {
cerr << "***** WARNING: Missing output sample blocks, DAQ Scan count="
<< outxstat.currentScanCount
<< " while loop count = " << outTotalCount
<< ", probably due to too small buffer size. *****" << endl;
}
outTotalCount = outxstat.currentScanCount;
/* std::cerr << "Samples scanned: " << outxstat.currentTotalCount << endl; */
if(outxstat.currentIndex < buffer_mid_idx_out) {
/* std::cerr << "Samples scanned: " << outxstat.currentTotalCount << endl;
*/
if (outxstat.currentIndex < buffer_mid_idx_out) {
topoutenqueued = false;
if(!botoutenqueued) {
if (!botoutenqueued) {
/* cerr << "Copying output buffer to bottom" << endl; */
double* bufcpy;
if(!outqueue->empty()) {
bufcpy = outqueue->dequeue();
}
else {
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL QUEUE WITH ZEROS ***********" << endl;
bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*nenoutchannels));
for(us sample=0;sample< samplesPerBlock;sample++) {
double *bufcpy;
if (!outqueue->empty()) {
bufcpy = (double *)outqueue->dequeue();
} else {
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL "
"QUEUE WITH ZEROS ***********"
<< endl;
bufcpy = static_cast<double *>(
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
for (us sample = 0; sample < samplesPerBlock; sample++) {
bufcpy[sample] = 0;
}
}
assert(nenoutchannels > 0);
for(us sample=0;sample< samplesPerBlock;sample++) {
for (us sample = 0; sample < samplesPerBlock; sample++) {
outbuffer[buffer_mid_idx_out + sample] = bufcpy[sample];
}
free(bufcpy);
botoutenqueued = true;
}
}
else {
} else {
botoutenqueued = false;
if(!topoutenqueued) {
if (!topoutenqueued) {
/* cerr << "Copying output buffer to top" << endl; */
double* bufcpy;
if(!outqueue->empty()) {
bufcpy = outqueue->dequeue();
}
else {
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL QUEUE WITH ZEROS ***********" << endl;
bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*nenoutchannels));
for(us sample=0;sample< samplesPerBlock;sample++) {
double *bufcpy;
if (!outqueue->empty()) {
bufcpy = (double *)outqueue->dequeue();
} else {
cerr << "******* WARNING: OUTPUTQUEUE UNDERFLOW, FILLING SIGNAL "
"QUEUE WITH ZEROS ***********"
<< endl;
bufcpy = static_cast<double *>(
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
for (us sample = 0; sample < samplesPerBlock; sample++) {
bufcpy[sample] = 0;
}
}
assert(nenoutchannels > 0);
for(us sample=0;sample<samplesPerBlock;sample++) {
for (us sample = 0; sample < samplesPerBlock; sample++) {
outbuffer[sample] = bufcpy[sample];
}
free(bufcpy);
@ -387,69 +421,78 @@ void threadfcn(DT9837A* td) {
}
}
if(hasinput) {
if (hasinput) {
err = ulDaqInScanStatus(handle, &inscanstat, &inxstat);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
goto exit;
}
assert(inscanstat == SS_RUNNING);
if(inxstat.currentScanCount > inTotalCount+2*samplesPerBlock) {
cerr << "***** ERROR: Missing input sample blocks, count=" << inxstat.currentScanCount << ", probably due to too small buffer size. Exiting thread. *****" << endl;
if (inxstat.currentScanCount > inTotalCount + 2 * samplesPerBlock) {
cerr << "***** ERROR: Missing input sample blocks, count="
<< inxstat.currentScanCount
<< ", probably due to too small buffer size. Exiting thread. *****"
<< endl;
break;
}
inTotalCount = inxstat.currentScanCount;
if(inxstat.currentIndex < buffer_mid_idx_in) {
if (inxstat.currentIndex < buffer_mid_idx_in) {
topinenqueued = false;
if(!botinenqueued) {
if (!botinenqueued) {
/* cerr << "Copying in buffer bot" << endl; */
double* bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*neninchannels));
us monitoroffset = monitorOutput ? 1: 0;
double *bufcpy = static_cast<double *>(
malloc(sizeof(double) * samplesPerBlock * neninchannels));
us monitoroffset = monitorOutput ? 1 : 0;
assert(neninchannels > 0);
for(us channel=0;channel<(neninchannels-monitoroffset);channel++) {
for(us sample=0;sample< samplesPerBlock;sample++) {
bufcpy[(monitoroffset+channel)*samplesPerBlock+sample] = inbuffer[buffer_mid_idx_in + sample*neninchannels+channel];
for (us channel = 0; channel < (neninchannels - monitoroffset);
channel++) {
for (us sample = 0; sample < samplesPerBlock; sample++) {
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
inbuffer[buffer_mid_idx_in + sample * neninchannels +
channel];
}
}
if(monitorOutput) {
if (monitorOutput) {
// Monitor output goes to first channel, that is
// our convention
us channel = neninchannels - 1;
for(us sample=0;sample< samplesPerBlock;sample++) {
bufcpy[sample] = inbuffer[buffer_mid_idx_in + sample*neninchannels+channel];
for (us sample = 0; sample < samplesPerBlock; sample++) {
bufcpy[sample] = inbuffer[buffer_mid_idx_in +
sample * neninchannels + channel];
}
}
inqueue->enqueue(bufcpy);
inqueue->enqueue((void *)bufcpy);
botinenqueued = true;
}
}
else {
} else {
botinenqueued = false;
if(!topinenqueued) {
double* bufcpy = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock*neninchannels));
us monitoroffset = monitorOutput ? 1: 0;
if (!topinenqueued) {
double *bufcpy = static_cast<double *>(
malloc(sizeof(double) * samplesPerBlock * neninchannels));
us monitoroffset = monitorOutput ? 1 : 0;
assert(neninchannels > 0);
for(us channel=0;channel<(neninchannels-monitoroffset);channel++) {
for(us sample=0;sample< samplesPerBlock;sample++) {
bufcpy[(monitoroffset+channel)*samplesPerBlock+sample] = inbuffer[sample*neninchannels+channel];
for (us channel = 0; channel < (neninchannels - monitoroffset);
channel++) {
for (us sample = 0; sample < samplesPerBlock; sample++) {
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
inbuffer[sample * neninchannels + channel];
}
}
if(monitorOutput) {
if (monitorOutput) {
// Monitor output goes to first channel, that is
// our convention
us channel = neninchannels - 1;
for(us sample=0;sample< samplesPerBlock;sample++) {
bufcpy[sample] = inbuffer[sample*neninchannels+channel];
for (us sample = 0; sample < samplesPerBlock; sample++) {
bufcpy[sample] = inbuffer[sample * neninchannels + channel];
}
}
/* cerr << "Copying in buffer top" << endl; */
inqueue->enqueue(bufcpy);
inqueue->enqueue((void *)bufcpy);
topinenqueued = true;
}
}
}
std::this_thread::sleep_for(std::chrono::microseconds(sleeptime_us));
@ -457,66 +500,67 @@ void threadfcn(DT9837A* td) {
} // End of while loop
/* std::cerr << "Exit of while loop" << endl; */
exit:
if(hasoutput) {
if (hasoutput) {
ulAOutScanStop(handle);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
}
}
if(hasinput) {
if (hasinput) {
ulDaqInScanStop(handle);
if(err != ERR_NO_ERROR) {
if (err != ERR_NO_ERROR) {
showErr(err);
}
}
if(indesc) delete indesc;
if (indesc)
delete indesc;
std::cerr << "Exit of DAQ thread fcn" << endl;
}
void DT9837A::start( SafeQueue<double*> *inqueue, SafeQueue<double*> *outqueue) {
if(isRunning()) {
void DT9837A::start(SafeQueue<void *> *inqueue, SafeQueue<void *> *outqueue) {
if (isRunning()) {
throw runtime_error("Thread is already running");
}
bool hasinput = neninchannels() > 0;
bool hasoutput = nenoutchannels() > 0;
if(neninchannels() > 0 && !inqueue) {
if (neninchannels() > 0 && !inqueue) {
throw runtime_error("Inqueue not given, while input is enabled");
}
if(nenoutchannels() > 0 && !outqueue) {
if (nenoutchannels() > 0 && !outqueue) {
throw runtime_error("outqueue not given, while output is enabled");
}
if(hasinput) {
if (hasinput) {
assert(!inbuffer);
inbuffer = new double[neninchannels()*samplesPerBlock*2]; // Watch the 2!
inbuffer =
new double[neninchannels() * samplesPerBlock * 2]; // Watch the 2!
}
if(hasoutput) {
if (hasoutput) {
assert(!outbuffer);
outbuffer = new double[nenoutchannels()*samplesPerBlock*2]; // Watch the 2!
outbuffer =
new double[nenoutchannels() * samplesPerBlock * 2]; // Watch the 2!
}
this->inqueue = inqueue;
this->outqueue = outqueue;
/* std::cerr << "************************ WARNING: Forcing coupling mode to AC **************************" << endl; */
/* std::cerr << "************************ WARNING: Forcing coupling mode to AC
* **************************" << endl; */
/* boolvec couplingmode = {true, true, true, true}; */
/* setACCouplingMode(couplingmode); */
stopThread = false;
thread = new std::thread(threadfcn, this);
}
void DT9837A::stop() {
if(!isRunning()) {
if (!isRunning()) {
throw runtime_error("No data acquisition running");
}
assert(thread);
@ -528,8 +572,10 @@ void DT9837A::stop() {
outqueue = NULL;
inqueue = NULL;
if(inbuffer) delete inbuffer;
if(outbuffer) delete outbuffer;
if (inbuffer)
delete inbuffer;
if (outbuffer)
delete outbuffer;
outbuffer = NULL;
inbuffer = NULL;
}
@ -537,7 +583,8 @@ void DT9837A::stop() {
us DT9837A::neninchannels() const {
mutexlock lock(mutex);
us inch = std::count(inChannels.begin(), inChannels.end(), true);
if(monitorOutput) inch++;
if (monitorOutput)
inch++;
return inch;
}
@ -545,3 +592,26 @@ us DT9837A::nenoutchannels() const {
mutexlock lock(mutex);
return std::count(outChannels.begin(), outChannels.end(), true);
}
Daq *createUlDaqDevice(const DeviceInfo &devinfo,
const DaqConfiguration &config) {
DT9837A *daq = NULL;
try {
daq = new DT9837A(config.nFramesPerBlock, config.eninchannels,
config.enoutchannels,
devinfo.availableSampleRates[config.sampleRateIndex],
config.monitorOutput, devinfo.devindex);
daq->setACCouplingMode(config.inputACCouplingMode);
daq->setIEPEEnabled(config.inputIEPEEnabled);
daq->setInputRange(config.inputHighRange);
} catch (runtime_error &e) {
if (daq)
delete daq;
throw;
}
return daq;
}

View File

@ -9,64 +9,10 @@
#include <atomic>
#include <thread>
using std::vector;
using std::atomic;
typedef vector<bool> boolvec;
typedef unsigned int us;
class DT9837A: public Daq {
us samplesPerBlock;
double _samplerate;
boolvec inChannels;
boolvec high_range;
boolvec outChannels;
bool monitorOutput;
atomic<bool> stopThread;
DaqDeviceHandle handle = 0;
std::thread* thread = NULL;
mutable std::mutex mutex;
SafeQueue<double*> *inqueue = NULL;
SafeQueue<double*> *outqueue = NULL;
double* inbuffer = NULL;
double* outbuffer = NULL;
public:
double samplerate() const {return this->_samplerate;}
DT9837A(
us samplesPerBlock,
boolvec& inChannels,
boolvec& outChannels,
double samplerate,
bool monitorOutput,
us device_no = 0
);
DT9837A(const DT9837A&) = delete;
~DT9837A();
void setIEPEEnabled(boolvec& config);
// Coupling_ac: true, means AC coupling, false means DC coupling
void setACCouplingMode(boolvec& coupling_ac);
void setInputRange(boolvec& high_range);
us neninchannels() const;
us nenoutchannels() const;
bool isRunning() const { return bool(thread); }
virtual void start(
SafeQueue<void*> *inqueue,
SafeQueue<void*> *outqueue) final;
virtual void stop() final;
friend void threadfcn(DT9837A*);
};
Daq* createUlDaqDevice(const DeviceInfo& devinfo,
const DaqConfiguration& config);
#endif // ULDAQ_H

View File

@ -1,360 +1,2 @@
include "lasp_common_decls.pxd"
cdef extern from "uldaq.h" nogil:
ctypedef enum DaqDeviceInterface:
USB_IFC
BLUETOOTH_IFC
ETHERNET_IFC
ANY_IFC
ctypedef struct DaqDeviceDescriptor:
char productName[64]
unsigned int productId
DaqDeviceInterface devInterface
char devString[64]
char uniqueId[64]
char reserved[512]
ctypedef long long DaqDeviceHandle
ctypedef struct TransferStatus:
unsigned long long currentScanCount
unsigned long long currentTotalCount
long long currentIndex
char reserved[64]
UlError ulGetErrMsg(UlError, char* errMsg)
ctypedef enum UlError:
ERR_NO_ERROR
ERR_UNHANDLED_EXCEPTION
ERR_BAD_DEV_HANDLE
ERR_BAD_DEV_TYPE
ERR_USB_DEV_NO_PERMISSION
ERR_USB_INTERFACE_CLAIMED
ERR_DEV_NOT_FOUND
ERR_DEV_NOT_CONNECTED
ERR_DEAD_DEV
ERR_BAD_BUFFER_SIZE
ERR_BAD_BUFFER
ERR_BAD_MEM_TYPE
ERR_BAD_MEM_REGION
ERR_BAD_RANGE
ERR_BAD_AI_CHAN
ERR_BAD_INPUT_MODE
ERR_ALREADY_ACTIVE
ERR_BAD_TRIG_TYPE
ERR_OVERRUN
ERR_UNDERRUN
ERR_TIMEDOUT
ERR_BAD_OPTION
ERR_BAD_RATE
ERR_BAD_BURSTIO_COUNT
ERR_CONFIG_NOT_SUPPORTED
ERR_BAD_CONFIG_VAL
ERR_BAD_AI_CHAN_TYPE
ERR_ADC_OVERRUN
ERR_BAD_TC_TYPE
ERR_BAD_UNIT
ERR_BAD_QUEUE_SIZE
ERR_BAD_CONFIG_ITEM
ERR_BAD_INFO_ITEM
ERR_BAD_FLAG
ERR_BAD_SAMPLE_COUNT
ERR_INTERNAL
ERR_BAD_COUPLING_MODE
ERR_BAD_SENSOR_SENSITIVITY
ERR_BAD_IEPE_MODE
ERR_BAD_AI_CHAN_QUEUE
ERR_BAD_AI_GAIN_QUEUE
ERR_BAD_AI_MODE_QUEUE
ERR_FPGA_FILE_NOT_FOUND
ERR_UNABLE_TO_READ_FPGA_FILE
ERR_NO_FPGA
ERR_BAD_ARG
ERR_MIN_SLOPE_VAL_REACHED
ERR_MAX_SLOPE_VAL_REACHED
ERR_MIN_OFFSET_VAL_REACHED
ERR_MAX_OFFSET_VAL_REACHED
ERR_BAD_PORT_TYPE
ERR_WRONG_DIG_CONFIG
ERR_BAD_BIT_NUM
ERR_BAD_PORT_VAL
ERR_BAD_RETRIG_COUNT
ERR_BAD_AO_CHAN
ERR_BAD_DA_VAL
ERR_BAD_TMR
ERR_BAD_FREQUENCY
ERR_BAD_DUTY_CYCLE
ERR_BAD_INITIAL_DELAY
ERR_BAD_CTR
ERR_BAD_CTR_VAL
ERR_BAD_DAQI_CHAN_TYPE
ERR_BAD_NUM_CHANS
ERR_BAD_CTR_REG
ERR_BAD_CTR_MEASURE_TYPE
ERR_BAD_CTR_MEASURE_MODE
ERR_BAD_DEBOUNCE_TIME
ERR_BAD_DEBOUNCE_MODE
ERR_BAD_EDGE_DETECTION
ERR_BAD_TICK_SIZE
ERR_BAD_DAQO_CHAN_TYPE
ERR_NO_CONNECTION_ESTABLISHED
ERR_BAD_EVENT_TYPE
ERR_EVENT_ALREADY_ENABLED
ERR_BAD_EVENT_PARAMETER
ERR_BAD_CALLBACK_FUCNTION
ERR_BAD_MEM_ADDRESS
ERR_MEM_ACCESS_DENIED
ERR_DEV_UNAVAILABLE
ERR_BAD_RETRIG_TRIG_TYPE
ERR_BAD_DEV_VER
ERR_BAD_DIG_OPERATION
ERR_BAD_PORT_INDEX
ERR_OPEN_CONNECTION
ERR_DEV_NOT_READY
ERR_PACER_OVERRUN
ERR_BAD_TRIG_CHANNEL
ERR_BAD_TRIG_LEVEL
ERR_BAD_CHAN_ORDER
ERR_TEMP_OUT_OF_RANGE
ERR_TRIG_THRESHOLD_OUT_OF_RANGE
ERR_INCOMPATIBLE_FIRMWARE
ERR_BAD_NET_IFC
ERR_BAD_NET_HOST
ERR_BAD_NET_PORT
ERR_NET_IFC_UNAVAILABLE
ERR_NET_CONNECTION_FAILED
ERR_BAD_CONNECTION_CODE
ERR_CONNECTION_CODE_IGNORED
ERR_NET_DEV_IN_USE
ERR_BAD_NET_FRAME
ERR_NET_TIMEOUT
ERR_DATA_SOCKET_CONNECTION_FAILED
ERR_PORT_USED_FOR_ALARM
ERR_BIT_USED_FOR_ALARM
ERR_CMR_EXCEEDED
ERR_NET_BUFFER_OVERRUN
ERR_BAD_NET_BUFFER
ctypedef enum Range:
BIP10VOLTS
BIP5VOLTS
BIP4VOLTS
BIP2PT5VOLTS
BIP2VOLTS
BIP1PT25VOLTS
BIP1VOLTS
BIPPT625VOLTS
BIPPT5VOLTS
BIPPT25VOLTS
BIPPT125VOLTS
BIPPT2VOLTS
BIPPT1VOLTS
BIPPT078VOLTS
BIPPT05VOLTS
BIPPT01VOLTS
BIPPT005VOLTS
BIP3VOLTS
BIPPT312VOLTS
BIPPT156VOLTS
UNI15VOLTS
UNI20VOLTS
UNI10VOLTS
UNI5VOLTS
UNI4VOLTS
UNI2PT5VOLTS
UNI2VOLTS
UNI1PT25VOLTS
UNI1VOLTS
UNIPT625VOLTS
UNIPT5VOLTS
UNIPT25VOLTS
UNIPT125VOLTS
UNIPT2VOLTS
UNIPT1VOLTS
UNIPT078VOLTS
UNIPT05VOLTS
UNIPT01VOLTS
UNIPT005VOLTS
MA0TO20
ctypedef enum AdcTimingMode:
ADC_TM_AUTO
ADC_TM_HIGH_RES
ADC_TM_HIGH_SPEED
ctypedef enum IepeMode:
IEPE_ENABLED
IEPE_DISABLED
ctypedef enum CouplingMode:
CM_DC
CM_AC
ctypedef enum TriggerType:
TRIG_NONE
TRIG_POS_EDGE
TRIG_NEG_EDGE
TRIG_HIGH
TRIG_LOW
GATE_HIGH
GATE_LOW
TRIG_RISING
TRIG_FALLING
TRIG_ABOVE
TRIG_BELOW
GATE_ABOVE
GATE_BELOW
GATE_IN_WINDOW
GATE_OUT_WINDOW
TRIG_PATTERN_EQ
TRIG_PATTERN_NE
TRIG_PATTERN_ABOVE
TRIG_PATTERN_BELOW
ctypedef enum ScanStatus:
SS_IDLE
SS_RUNNING
ctypedef enum ScanOption:
SO_DEFAULTIO
SO_SINGLEIO
SO_BLOCKIO
SO_BURSTIO
SO_CONTINUOUS
SO_EXTCLOCK
SO_EXTTRIGGER
SO_RETRIGGER
SO_BURSTMODE
SO_PACEROUT
SO_EXTTIMEBASE
SO_TIMEBASEOUT
ctypedef enum DaqInScanFlag:
DAQINSCAN_FF_DEFAULT
DAQINSCAN_FF_NOSCALEDATA
DAQINSCAN_FF_NOCALIBRATEDATA
DAQINSCAN_FF_NOCLEAR
ctypedef enum AOutScanFlag:
AOUTSCAN_FF_DEFAULT
AOUTSCAN_FF_NOSCALEDATA
AOUTSCAN_FF_NOCALIBRATEDATA
AOUTSCAN_FF_NOCLEAR
ctypedef enum DaqInChanType:
DAQI_ANALOG_DIFF
DAQI_ANALOG_SE
DAQI_DIGITAL
DAQI_CTR16
DAQI_CTR32
DAQI_CTR48
DAQI_DAC
ctypedef struct DaqInChanDescriptor:
int channel
DaqInChanType type
Range range
ctypedef enum DaqEventType:
DE_NONE
DE_ON_DATA_AVAILABLE
DE_ON_INPUT_SCAN_ERROR
DE_ON_END_OF_INPUT_SCAN
DE_ON_OUTPUT_SCAN_ERROR
DE_ON_END_OF_OUTPUT_SCAN
ctypedef enum WaitType:
WAIT_UNTIL_DONE
ctypedef enum DevInfoItem:
DEV_INFO_HAS_AI_DEV
DEV_INFO_HAS_AO_DEV
DEV_INFO_HAS_DIO_DEV
DEV_INFO_HAS_CTR_DEV
DEV_INFO_HAS_TMR_DEV
DEV_INFO_HAS_DAQI_DEV
DEV_INFO_HAS_DAQO_DEV
DEV_INFO_DAQ_EVENT_TYPES
DEV_INFO_MEM_REGIONS
ctypedef enum AiInfoItem:
AI_INFO_RESOLUTION
AI_INFO_NUM_CHANS
AI_INFO_NUM_CHANS_BY_MODE
AI_INFO_NUM_CHANS_BY_TYPE
AI_INFO_CHAN_TYPES
AI_INFO_SCAN_OPTIONS
AI_INFO_HAS_PACER
AI_INFO_NUM_DIFF_RANGES
AI_INFO_NUM_SE_RANGES
AI_INFO_DIFF_RANGE
AI_INFO_SE_RANGE
AI_INFO_TRIG_TYPES
AI_INFO_MAX_QUEUE_LENGTH_BY_MODE
AI_INFO_QUEUE_TYPES
AI_INFO_QUEUE_LIMITS
AI_INFO_FIFO_SIZE
AI_INFO_IEPE_SUPPORTED
ctypedef enum AiConfigItem:
AI_CFG_CHAN_TYPE
AI_CFG_CHAN_TC_TYPE
AI_CFG_SCAN_CHAN_TEMP_UNIT
AI_CFG_SCAN_TEMP_UNIT
AI_CFG_ADC_TIMING_MODE
AI_CFG_AUTO_ZERO_MODE
AI_CFG_CAL_DATE
AI_CFG_CHAN_IEPE_MODE
AI_CFG_CHAN_COUPLING_MODE
AI_CFG_CHAN_SENSOR_CONNECTION_TYPE
AI_CFG_CHAN_OTD_MODE
AI_CFG_OTD_MODE
AI_CFG_CAL_TABLE_TYPE
AI_CFG_REJECT_FREQ_TYPE
AI_CFG_EXP_CAL_DATE
ctypedef enum AoConfigItem:
AO_CFG_SYNC_MODE
AO_CFG_CHAN_SENSE_MODE
ctypedef enum AiConfigItemDbl:
AI_CFG_CHAN_SLOPE
AI_CFG_CHAN_OFFSET
AI_CFG_CHAN_SENSOR_SENSITIVITY
AI_CFG_CHAN_DATA_RATE
ctypedef enum AInScanFlag:
AINSCAN_FF_DEFAULT
AINSCAN_FF_NOSCALEDATA
AINSCAN_FF_NOCALIBRATEDATA
UlError ulGetDaqDeviceInventory(DaqDeviceInterface interfaceTypes, DaqDeviceDescriptor daqDevDescriptors[], unsigned int* numDescriptors )
DaqDeviceHandle ulCreateDaqDevice(DaqDeviceDescriptor daqDevDescriptor)
UlError ulConnectDaqDevice(DaqDeviceHandle daqDeviceHandle);
UlError ulDisconnectDaqDevice(DaqDeviceHandle daqDeviceHandle);
UlError ulReleaseDaqDevice(DaqDeviceHandle daqDeviceHandle);
UlError ulAISetConfig(DaqDeviceHandle daqDeviceHandle, AiConfigItem configItem, unsigned int index, long long configValue)
UlError ulAISetConfigDbl(DaqDeviceHandle daqDeviceHandle, AiConfigItemDbl configItem, unsigned int index, double configValue)
UlError ulAIGetConfig(DaqDeviceHandle daqDeviceHandle, AiConfigItem configItem, unsigned int index, long long* configValue);
UlError ulDaqInScan(DaqDeviceHandle daqDeviceHandle, DaqInChanDescriptor chanDescriptors[], int numChans, int samplesPerChan, double* rate, ScanOption options, DaqInScanFlag flags, double data[]);
UlError ulDaqInScanStatus(DaqDeviceHandle daqDeviceHandle, ScanStatus* status, TransferStatus* xferStatus);
UlError ulDaqInScanStop(DaqDeviceHandle daqDeviceHandle);
UlError ulDaqInScanWait(DaqDeviceHandle daqDeviceHandle, WaitType waitType, long long waitParam, double timeout);
ctypedef void (*DaqEventCallback)(DaqDeviceHandle, DaqEventType, unsigned long long, void*)
UlError ulEnableEvent(DaqDeviceHandle daqDeviceHandle, DaqEventType eventTypes, unsigned long long eventParameter, DaqEventCallback eventCallbackFunction, void* userData);
UlError ulDisableEvent(DaqDeviceHandle daqDeviceHandle, DaqEventType eventTypes)
UlError ulAOutScan(DaqDeviceHandle daqDeviceHandle,int lowChan,int highChan,Range range,int samplesPerChan,double * rate,ScanOption options,AOutScanFlag flags,double data[])
UlError ulAOutScanStatus(DaqDeviceHandle daqDeviceHandle,ScanStatus * status,TransferStatus * xferStatus)
UlError ulAOutScanStop(DaqDeviceHandle daqDeviceHandle)
UlError ulAOutScanWait(DaqDeviceHandle daqDeviceHandle,WaitType waitType,long long waitParam,double timeout)
UlError ulAOutSetTrigger(DaqDeviceHandle daqDeviceHandle,TriggerType type,int trigChan,double level,double variance,unsigned int retriggerSampleCount)

View File

@ -10,31 +10,58 @@ DEF MAX_DEF_COUNT = 100
DEF UL_ERR_MSG_LEN = 512
ctypedef unsigned us
ctypedef vector[bool] boolvec
cdef extern from "lasp_cppdaq.h" nogil:
cdef cppclass Daq:
void start(SafeQueue[double*] *inQueue,
SafeQueue[double*] *outQueue)
cdef cppclass cppDaq "Daq":
void start(SafeQueue[void*] *inQueue,
SafeQueue[void*] *outQueue) except +
void stop()
double samplerate()
cdef extern from "lasp_cppuldaq.h":
cdef cppclass DT9837A(Daq):
DT9837A(us samplesPerBlock,
vector[bool] inChannels,
vector[bool] outChannels,
double samplerate,
bint monitorOutput,
us deviceno) except +
void start(SafeQueue[double*] *inQueue,
SafeQueue[double*] *outQueue) except +
void stop() except +
void setACCouplingMode(vector[bool] accoupling) except +
void setInputRange(vector[bool] accoupling) except +
void setIEPEEnabled(vector[bool] iepe) except +
us neninchannels()
us nenoutchannels()
DataType getDataType()
cdef cppclass DaqApi:
string apiname
unsigned apicode
unsigned api_specific_subcode
cdef cppclass DataType:
string name
unsigned sw
bool is_floating
DataType dtype_fl64
cdef cppclass cppDeviceInfo "DeviceInfo":
DaqApi api
string name
unsigned devindex
vector[DataType] availableDataTypes
vector[double] availableSampleRates
int prefSampleRateIndex
unsigned ninchannels
unsigned noutchannels
bool hasInputIEPE
bool hasInputACCouplingSwitch
bool hasInputTrigger
cdef cppclass DaqConfiguration:
boolvec eninchannels
boolvec enoutchannels
unsigned sampleRateIndex
DataType datatype
bool monitorOutput
unsigned nFramesPerBlock;
boolvec inputIEPEEnabled;
boolvec inputACCouplingMode;
boolvec inputHighRange;
cdef cppclass DaqDevices:
@staticmethod
cppDaq* createDaqDevice(cppDeviceInfo&, DaqConfiguration&)
ctypedef struct PyStreamData:
PyObject* pyCallback
@ -55,34 +82,27 @@ ctypedef struct PyStreamData:
# If these queue pointers are NULL, it means the stream does not have an
# input, or output.
SafeQueue[double*] *inQueue
SafeQueue[double*] *outQueue
SafeQueue[void*] *inQueue
SafeQueue[void*] *outQueue
CPPThread[void*, void (*)(void*)] *thread
cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
cdef:
PyStreamData* sd
PyStreamData* sd = <PyStreamData*> voidsd
cnp.NPY_TYPES npy_format
double* inbuffer = NULL
double* outbuffer = NULL
unsigned noutchannels
unsigned ninchannels
unsigned nBytesPerChan
unsigned nFramesPerBlock
unsigned noutchannels= sd.noutchannels
unsigned ninchannels= sd.ninchannels
unsigned nBytesPerChan= sd.nBytesPerChan
unsigned nFramesPerBlock= sd.nFramesPerBlock
unsigned sw = sizeof(double)
sd = <PyStreamData*> voidsd
cdef:
double sleeptime = (<double> nFramesPerBlock)/(4*sd.samplerate);
double sleeptime = (<double> sd.nFramesPerBlock)/(4*sd.samplerate);
us sleeptime_us = <us> (sleeptime*1e6);
ninchannels = sd.ninchannels
noutchannels = sd.noutchannels
nBytesPerChan = sd.nBytesPerChan
nFramesPerBlock = sd.nFramesPerBlock
with gil:
npy_format = cnp.NPY_FLOAT64
@ -97,18 +117,18 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
outbuffer = <double*> malloc(sizeof(double)*nBytesPerChan*noutchannels)
npy_output = <object> data_to_ndarray(
outbuffer,
nFramesPerBlock,
noutchannels,
npy_format,
False, # Do not transfer ownership
True) # F-contiguous
outbuffer,
nFramesPerBlock,
noutchannels,
npy_format,
False, # Do not transfer ownership
True) # F-contiguous
try:
rval = callback(None,
npy_output,
nFramesPerBlock,
)
npy_output,
nFramesPerBlock,
)
except Exception as e:
print('exception in Cython callback for audio output: ', str(e))
@ -119,24 +139,24 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
if sd.inQueue and not sd.inQueue.empty():
# Waiting indefinitely on the queue...
inbuffer = sd.inQueue.dequeue()
inbuffer = <double*> sd.inQueue.dequeue()
if inbuffer == NULL:
printf('Stopping thread...\n')
return
try:
npy_input = <object> data_to_ndarray(
inbuffer,
nFramesPerBlock,
ninchannels,
npy_format,
True, # Do transfer ownership
True) # F-contiguous is True: data is Fortran-cont.
inbuffer,
nFramesPerBlock,
ninchannels,
npy_format,
True, # Do transfer ownership
True) # F-contiguous is True: data is Fortran-cont.
rval = callback(npy_input,
None,
nFramesPerBlock,
)
None,
nFramesPerBlock,
)
except Exception as e:
print('exception in cython callback for audio input: ', str(e))
@ -153,10 +173,10 @@ cdef void audioCallbackPythonThreadFunction(void* voidsd) nogil:
fprintf(stderr, 'Exiting python thread...\n')
cdef class UlDaq:
cdef class Daq:
cdef:
PyStreamData *sd
Daq* daq_device
cppDaq* daq_device
def __cinit__(self):
@ -201,12 +221,12 @@ cdef class UlDaq:
unsigned int nFramesPerBlock = daqconfig.nFramesPerBlock
unsigned int samplerate
int i
bint in_stream=False
bint out_stream=False
DT9837A* daq_device
cppDaq* daq_device
if daqconfig.nFramesPerBlock > 8192 or daqconfig.nFramesPerBlock < 512:
raise ValueError('Invalid number of nFramesPerBlock')
@ -226,12 +246,12 @@ cdef class UlDaq:
if duplex_mode:
fprintf(stderr, 'Duplex mode enabled\n')
out_stream = True
elif avtype == AvType.audio_output:
sampleformat = daqconfig.en_output_sample_format
samplerate = int(daqconfig.en_output_rate)
out_stream = True
else:
raise ValueError(f'Invalid stream type {avtype}')
elif avtype == AvType.audio_output:
sampleformat = daqconfig.en_output_sample_format
samplerate = int(daqconfig.en_output_rate)
out_stream = True
else:
raise ValueError(f'Invalid stream type {avtype}')
if out_stream and daqconfig.firstEnabledOutputChannelNumber() == -1:
raise RuntimeError('No output channels enabled')
@ -264,29 +284,29 @@ cdef class UlDaq:
inch_enabled = 4*[False]
if in_stream:
inch_enabled = [True if ch.channel_enabled else False for ch in
daqconfig.getInputChannels()]
daqconfig.getInputChannels()]
self.sd.inQueue = new SafeQueue[void*]()
self.sd.inQueue = new SafeQueue[double*]()
# Create channel maps for output channels
outch_enabled = 1*[False]
if out_stream:
print('Stream is output stream')
outch_enabled = [True if ch.channel_enabled else False for ch in
daqconfig.getOutputChannels()]
daqconfig.getOutputChannels()]
self.sd.outQueue = new SafeQueue[double*]()
self.sd.outQueue = new SafeQueue[void*]()
if 'DT9837A' in device.name:
daq_device = new DT9837A(
daqconfig.nFramesPerBlock,
inch_enabled,
outch_enabled,
samplerate,
monitorOutput,
device.index)
else:
raise RuntimeError(f'Device {device.name} not found or not configured')
# if 'DT9837A' in device.name:
# daq_device = new DT9837A(
# daqconfig.nFramesPerBlock,
# inch_enabled,
# outch_enabled,
# samplerate,
# monitorOutput,
# device.index)
# else:
# raise RuntimeError(f'Device {device.name} not found or not configured')
self.sd.pyCallback = <PyObject*> avstream._audioCallback
self.sd.ninchannels = daq_device.neninchannels()
@ -299,14 +319,14 @@ cdef class UlDaq:
with nogil:
self.sd.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction,
<void*> self.sd)
<void*> self.sd)
# Allow it to start
CPPsleep_ms(500)
self.daq_device.start(
self.sd.inQueue,
self.sd.outQueue)
self.sd.inQueue,
self.sd.outQueue)
return nFramesPerBlock, self.daq_device.samplerate()
@ -342,12 +362,12 @@ cdef class UlDaq:
if sd.outQueue:
while not sd.outQueue.empty():
free(sd.outQueue.dequeue())
del sd.outQueue
if sd.inQueue:
while not sd.inQueue.empty():
free(sd.inQueue.dequeue())
del sd.inQueue
fprintf(stderr, "End cleanup stream queues...\n")
del sd.outQueue
if sd.inQueue:
while not sd.inQueue.empty():
free(sd.inQueue.dequeue())
del sd.inQueue
fprintf(stderr, "End cleanup stream queues...\n")
if sd.pyCallback:
Py_DECREF(<object> sd.pyCallback)
@ -361,55 +381,56 @@ cdef class UlDaq:
devices
"""
cdef:
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
DaqDeviceDescriptor descriptor
DaqDeviceInterface interfaceType = ANY_IFC
DaqDeviceHandle handle
pass
# DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
# DaqDeviceDescriptor descriptor
# DaqDeviceInterface interfaceType = ANY_IFC
# DaqDeviceHandle handle
UlError err
# UlError err
unsigned int numdevs = MAX_DEF_COUNT
unsigned deviceno
# unsigned int numdevs = MAX_DEF_COUNT
# unsigned deviceno
if self.sd is not NULL:
assert self.daq_device is not NULL
raise RuntimeError('Cannot acquire device info: stream is already opened.')
# if self.sd is not NULL:
# assert self.daq_device is not NULL
# raise RuntimeError('Cannot acquire device info: stream is already opened.')
err = ulGetDaqDeviceInventory(interfaceType,
devdescriptors,
&numdevs)
if(err != ERR_NO_ERROR):
raise RuntimeError(f'Device inventarization failed: {err}')
# err = ulGetDaqDeviceInventory(interfaceType,
# devdescriptors,
# &numdevs)
# if(err != ERR_NO_ERROR):
# raise RuntimeError(f'Device inventarization failed: {err}')
py_devinfo = []
for deviceno in range(numdevs):
descriptor = devdescriptors[deviceno]
if descriptor.productName == b'DT9837A':
# Create proper interface name
if descriptor.devInterface == DaqDeviceInterface.USB_IFC:
name = 'USB - '
elif descriptor.devInterface == DaqDeviceInterface.BLUETOOTH_IFC:
name = 'Bluetooth - '
elif descriptor.devInterface == DaqDeviceInterface.ETHERNET_IFC:
name = 'Ethernet - '
# py_devinfo = []
# for deviceno in range(numdevs):
# descriptor = devdescriptors[deviceno]
name += descriptor.productName.decode('utf-8') + ', id ' + \
descriptor.uniqueId.decode('utf-8')
# if descriptor.productName == b'DT9837A':
# # Create proper interface name
# if descriptor.devInterface == DaqDeviceInterface.USB_IFC:
# name = 'USB - '
# elif descriptor.devInterface == DaqDeviceInterface.BLUETOOTH_IFC:
# name = 'Bluetooth - '
# elif descriptor.devInterface == DaqDeviceInterface.ETHERNET_IFC:
# name = 'Ethernet - '
d = DeviceInfo(
api = -1,
index = deviceno,
probed = True,
name = name,
outputchannels = 1,
inputchannels = 4,
duplexchannels = 0,
samplerates = [10000, 16000, 20000, 32000, 48000, 50000] ,
sampleformats = ['64-bit floats'],
prefsamplerate = 48000,
hasInputIEPE = True)
py_devinfo.append(d)
return py_devinfo
# name += descriptor.productName.decode('utf-8') + ', id ' + \
# descriptor.uniqueId.decode('utf-8')
# d = DeviceInfo(
# api = -1,
# index = deviceno,
# probed = True,
# name = name,
# outputchannels = 1,
# inputchannels = 4,
# duplexchannels = 0,
# samplerates = [10000, 16000, 20000, 32000, 48000, 50000] ,
# sampleformats = ['64-bit floats'],
# prefsamplerate = 48000,
# hasInputIEPE = True)
# py_devinfo.append(d)
# return py_devinfo

View File

@ -1,8 +1,10 @@
#include "lasp_cppuldaq.h"
#include "lasp_cppdaq.h"
#include <chrono>
#include <iostream>
#include <cmath>
#include <thread>
using std::cout;
using std::cerr;
using std::endl;
@ -14,13 +16,35 @@ int main() {
double samplerate = 10000;
const us samplesPerBlock = 256;
DT9837A daq(
samplesPerBlock,
inChannels,
outChannels,
samplerate,
true // monitor Output
);
DaqConfiguration config;
config.eninchannels = inChannels;
config.enoutchannels = outChannels;
config.inputIEPEEnabled = {false, false, false, false};
config.inputACCouplingMode = {false, false, false, false};
config.inputHighRange = {false, false, false, false};
config.sampleRateIndex = 0;
config.datatype = dtype_fl64;
config.monitorOutput = true;
config.inputIEPEEnabled = {false, false, false, false};
config.nFramesPerBlock = samplesPerBlock;
cout << "Inchannnels size: " <<config.eninchannels.size() << endl;
vector<DeviceInfo> devinfos = DaqDevices::getDeviceInfo();
DeviceInfo devinfo;
us i;
bool found = false;
for(i=0;i<devinfos.size();i++) {
if(devinfos[i].api == uldaqapi){
cout << string(devinfos[i]) << endl;
devinfo = devinfos[i];
found = true;
}
}
if(!found) {
throw runtime_error("Could not find UlDaq device");
}
Daq* daq = DaqDevices::createDevice(devinfo, config);
SafeQueue<void*> inqueue;
SafeQueue<void*> outqueue;
@ -42,19 +66,16 @@ int main() {
outqueue.enqueue(data);
}
daq.start(&inqueue, &outqueue);
/* daq.start(NULL, &outqueue); */
daq->start(&inqueue, &outqueue);
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
/* std::string a; */
/* std::cin >> a; */
daq.stop();
daq->stop();
while(!inqueue.empty()) {
double* buf = (double*) inqueue.dequeue();
for(us i=0;i<samplesPerBlock;i++) {
for(us ch=0;ch<daq.neninchannels();ch++) {
for(us ch=0;ch<daq->neninchannels();ch++) {
cout << buf[ch*samplesPerBlock+i] << " ";
}
cout << endl;