Working C++ multiple API sit
This commit is contained in:
parent
a43857070b
commit
29662c82e3
@ -5,6 +5,7 @@ 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_deviceinfo.pyx PROPERTIES CYTHON_IS_CXX TRUE)
|
set_source_files_properties(lasp_deviceinfo.pyx PROPERTIES CYTHON_IS_CXX TRUE)
|
||||||
|
set_source_files_properties(lasp_daqconfig.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
|
||||||
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
|
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
|
||||||
@ -12,12 +13,19 @@ set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS
|
|||||||
set_source_files_properties(lasp_deviceinfo.cxx PROPERTIES COMPILE_FLAGS
|
set_source_files_properties(lasp_deviceinfo.cxx PROPERTIES COMPILE_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
|
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
|
||||||
|
|
||||||
|
set_source_files_properties(lasp_daqconfig.cxx PROPERTIES COMPILE_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
|
||||||
|
|
||||||
cython_add_module(lasp_daq lasp_daq.pyx)
|
cython_add_module(lasp_daq lasp_daq.pyx)
|
||||||
cython_add_module(lasp_deviceinfo lasp_deviceinfo.pyx)
|
cython_add_module(lasp_deviceinfo lasp_deviceinfo.pyx)
|
||||||
|
cython_add_module(lasp_daqconfig lasp_daqconfig.pyx)
|
||||||
|
|
||||||
target_link_libraries(lasp_daq cpp_daq uldaq rtaudio pthread)
|
target_link_libraries(lasp_daq cpp_daq uldaq rtaudio pthread)
|
||||||
target_link_libraries(lasp_deviceinfo cpp_daq uldaq rtaudio pthread)
|
target_link_libraries(lasp_deviceinfo cpp_daq uldaq rtaudio pthread)
|
||||||
|
target_link_libraries(lasp_daqconfig cpp_daq uldaq rtaudio pthread)
|
||||||
if(win32)
|
if(win32)
|
||||||
target_link_libraries(lasp_daq python37)
|
target_link_libraries(lasp_daq python37)
|
||||||
|
target_link_libraries(lasp_deviceinfo python37)
|
||||||
|
target_link_libraries(lasp_daqconfig python37)
|
||||||
endif(win32)
|
endif(win32)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
from .lasp_daqconfig import *
|
from .lasp_device_common import *
|
||||||
from .lasp_avtype import *
|
|
||||||
from .lasp_daq import *
|
from .lasp_daq import *
|
||||||
from .lasp_deviceinfo import *
|
from .lasp_deviceinfo import *
|
||||||
|
from .lasp_daqconfig import *
|
||||||
|
|
||||||
|
@ -39,16 +39,10 @@ cdef extern from "lasp_pyarray.h":
|
|||||||
|
|
||||||
ctypedef unsigned us
|
ctypedef unsigned us
|
||||||
ctypedef vector[bool] boolvec
|
ctypedef vector[bool] boolvec
|
||||||
|
ctypedef vector[double] dvec
|
||||||
|
ctypedef vector[us] usvec
|
||||||
|
|
||||||
cdef extern from "lasp_cppdaq.h" nogil:
|
cdef extern from "lasp_cppdaq.h" nogil:
|
||||||
cdef cppclass cppDaq "Daq":
|
|
||||||
void start(SafeQueue[void*] *inQueue,
|
|
||||||
SafeQueue[void*] *outQueue) except +
|
|
||||||
void stop()
|
|
||||||
double samplerate()
|
|
||||||
us neninchannels()
|
|
||||||
us nenoutchannels()
|
|
||||||
DataType getDataType()
|
|
||||||
|
|
||||||
cdef cppclass DaqApi:
|
cdef cppclass DaqApi:
|
||||||
string apiname
|
string apiname
|
||||||
@ -63,21 +57,27 @@ cdef extern from "lasp_cppdaq.h" nogil:
|
|||||||
|
|
||||||
cdef cppclass cppDeviceInfo "DeviceInfo":
|
cdef cppclass cppDeviceInfo "DeviceInfo":
|
||||||
DaqApi api
|
DaqApi api
|
||||||
string name
|
string device_name
|
||||||
unsigned devindex
|
unsigned devindex
|
||||||
vector[DataType] availableDataTypes
|
vector[DataType] availableDataTypes
|
||||||
vector[double] availableSampleRates
|
vector[double] availableSampleRates
|
||||||
|
vector[us] availableFramesPerBlock
|
||||||
|
|
||||||
int prefSampleRateIndex
|
int prefSampleRateIndex
|
||||||
|
int prefInputRangeIndex
|
||||||
|
int prefFramesPerBlockIndex
|
||||||
unsigned ninchannels
|
unsigned ninchannels
|
||||||
unsigned noutchannels
|
unsigned noutchannels
|
||||||
bool hasInputIEPE
|
bool hasInputIEPE
|
||||||
bool hasInputACCouplingSwitch
|
bool hasInputACCouplingSwitch
|
||||||
bool hasInputTrigger
|
bool hasInputTrigger
|
||||||
vector[double] inputRanges
|
vector[double] availableInputRanges
|
||||||
|
|
||||||
cdef cppclass DaqConfiguration:
|
cdef cppclass DaqConfiguration:
|
||||||
boolvec eninchannels
|
boolvec eninchannels
|
||||||
boolvec enoutchannels
|
boolvec enoutchannels
|
||||||
|
vector[string] channel_names
|
||||||
|
vector[double] channel_sensitivities
|
||||||
unsigned sampleRateIndex
|
unsigned sampleRateIndex
|
||||||
DataType datatype
|
DataType datatype
|
||||||
bool monitorOutput
|
bool monitorOutput
|
||||||
@ -85,12 +85,19 @@ cdef extern from "lasp_cppdaq.h" nogil:
|
|||||||
|
|
||||||
boolvec inputIEPEEnabled;
|
boolvec inputIEPEEnabled;
|
||||||
boolvec inputACCouplingMode;
|
boolvec inputACCouplingMode;
|
||||||
boolvec inputHighRange;
|
usvec inputRangeIndices;
|
||||||
|
|
||||||
|
cdef cppclass cppDaq "Daq":
|
||||||
|
void start(SafeQueue[void*] *inQueue,
|
||||||
|
SafeQueue[void*] *outQueue) except +
|
||||||
|
void stop()
|
||||||
|
double samplerate()
|
||||||
|
us neninchannels()
|
||||||
|
us nenoutchannels()
|
||||||
|
DataType getDataType()
|
||||||
|
|
||||||
cdef cppclass DaqDevices:
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cppDaq* createDaqDevice(cppDeviceInfo&, DaqConfiguration&)
|
cppDaq* createDaqDevice(cppDeviceInfo&, DaqConfiguration&)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
vector[cppDeviceInfo] getDeviceInfo()
|
vector[cppDeviceInfo] getDeviceInfo()
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#include "lasp_cppdaq.h"
|
#include "lasp_cppdaq.h"
|
||||||
#include "lasp_cppuldaq.h"
|
#include "lasp_cppuldaq.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <strstream>
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
@ -11,7 +14,6 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
|||||||
|
|
||||||
UlError err;
|
UlError err;
|
||||||
unsigned int numdevs = MAX_DEV_COUNT_PER_API;
|
unsigned int numdevs = MAX_DEV_COUNT_PER_API;
|
||||||
unsigned deviceno;
|
|
||||||
|
|
||||||
DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API];
|
DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API];
|
||||||
DaqDeviceDescriptor descriptor;
|
DaqDeviceDescriptor descriptor;
|
||||||
@ -43,13 +45,11 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
|||||||
|
|
||||||
name += string(descriptor.productName) + " ";
|
name += string(descriptor.productName) + " ";
|
||||||
name += string(descriptor.uniqueId);
|
name += string(descriptor.uniqueId);
|
||||||
devinfo.name = name;
|
devinfo.device_name = name;
|
||||||
|
|
||||||
devinfo.devindex = i;
|
devinfo.api_specific_devindex = i;
|
||||||
devinfo.availableDataTypes.push_back(dtype_fl64);
|
devinfo.availableDataTypes.push_back(dtype_fl64);
|
||||||
|
devinfo.prefDataTypeIndex = 0;
|
||||||
devinfo.ninchannels = 4;
|
|
||||||
devinfo.noutchannels = 1;
|
|
||||||
|
|
||||||
devinfo.availableSampleRates.push_back(10000);
|
devinfo.availableSampleRates.push_back(10000);
|
||||||
devinfo.availableSampleRates.push_back(12000);
|
devinfo.availableSampleRates.push_back(12000);
|
||||||
@ -61,17 +61,31 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
|||||||
|
|
||||||
devinfo.prefSampleRateIndex = 5;
|
devinfo.prefSampleRateIndex = 5;
|
||||||
|
|
||||||
|
devinfo.availableFramesPerBlock.push_back(512);
|
||||||
|
devinfo.availableFramesPerBlock.push_back(1024);
|
||||||
|
devinfo.availableFramesPerBlock.push_back(2048);
|
||||||
|
devinfo.availableFramesPerBlock.push_back(4096);
|
||||||
|
devinfo.availableFramesPerBlock.push_back(8192);
|
||||||
|
devinfo.prefFramesPerBlockIndex = 1;
|
||||||
|
|
||||||
|
devinfo.availableInputRanges = {1.0, 10.0};
|
||||||
|
devinfo.prefInputRangeIndex = 0;
|
||||||
|
|
||||||
|
devinfo.ninchannels = 4;
|
||||||
|
devinfo.noutchannels = 1;
|
||||||
|
|
||||||
devinfo.hasInputIEPE = true;
|
devinfo.hasInputIEPE = true;
|
||||||
devinfo.hasInputACCouplingSwitch = true;
|
devinfo.hasInputACCouplingSwitch = true;
|
||||||
devinfo.hasInputTrigger = true;
|
devinfo.hasInputTrigger = true;
|
||||||
|
|
||||||
|
// Finally, this devinfo is pushed back in list
|
||||||
devinfolist.push_back(devinfo);
|
devinfolist.push_back(devinfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vector<DeviceInfo> DaqDevices::getDeviceInfo() {
|
vector<DeviceInfo> Daq::getDeviceInfo() {
|
||||||
vector<DeviceInfo> devs;
|
vector<DeviceInfo> devs;
|
||||||
#ifdef HAS_ULDAQ_LINUX_API
|
#ifdef HAS_ULDAQ_LINUX_API
|
||||||
fillUlDaqDeviceInfo(devs);
|
fillUlDaqDeviceInfo(devs);
|
||||||
@ -89,8 +103,57 @@ vector<DeviceInfo> DaqDevices::getDeviceInfo() {
|
|||||||
return devs;
|
return devs;
|
||||||
}
|
}
|
||||||
|
|
||||||
Daq *DaqDevices::createDevice(const DeviceInfo &devinfo,
|
DaqConfiguration::DaqConfiguration(const DeviceInfo &device) {
|
||||||
const DaqConfiguration &config) {
|
|
||||||
|
api = device.api;
|
||||||
|
device_name = device.device_name;
|
||||||
|
|
||||||
|
eninchannels.resize(device.ninchannels, false);
|
||||||
|
enoutchannels.resize(device.noutchannels, false);
|
||||||
|
|
||||||
|
inchannel_sensitivities.resize(device.ninchannels, 1.0);
|
||||||
|
for (us i = 0; i < eninchannels.size(); i++) {
|
||||||
|
std::strstream chname;
|
||||||
|
chname << "Unnamed input channel " << i;
|
||||||
|
inchannel_names.push_back(chname.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (us i = 0; i < enoutchannels.size(); i++) {
|
||||||
|
std::strstream chname;
|
||||||
|
chname << "Unnamed output channel " << i;
|
||||||
|
outchannel_names.push_back(chname.str());
|
||||||
|
}
|
||||||
|
sampleRateIndex = device.prefSampleRateIndex;
|
||||||
|
dataTypeIndex = device.prefDataTypeIndex;
|
||||||
|
framesPerBlockIndex = device.prefFramesPerBlockIndex;
|
||||||
|
|
||||||
|
monitorOutput = false;
|
||||||
|
|
||||||
|
inputIEPEEnabled.resize(device.ninchannels, false);
|
||||||
|
inputACCouplingMode.resize(device.ninchannels, false);
|
||||||
|
inputRangeIndices.resize(device.ninchannels, device.prefInputRangeIndex);
|
||||||
|
|
||||||
|
assert(match(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DaqConfiguration::match(const DeviceInfo& dev) const {
|
||||||
|
return (dev.device_name == device_name && dev.api == api);
|
||||||
|
}
|
||||||
|
|
||||||
|
Daq *Daq::createDevice(const DaqConfiguration &config,
|
||||||
|
const vector<DeviceInfo> &devinfos) {
|
||||||
|
|
||||||
|
bool match;
|
||||||
|
DeviceInfo devinfo;
|
||||||
|
for (auto cur_devinfo : devinfos) {
|
||||||
|
if ((match = config.match(cur_devinfo))) {
|
||||||
|
devinfo = cur_devinfo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!match) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Some basic sanity checks
|
// Some basic sanity checks
|
||||||
if ((devinfo.ninchannels != config.eninchannels.size())) {
|
if ((devinfo.ninchannels != config.eninchannels.size())) {
|
||||||
@ -107,3 +170,52 @@ Daq *DaqDevices::createDevice(const DeviceInfo &devinfo,
|
|||||||
devinfo.api.apiname);
|
devinfo.api.apiname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Daq::Daq(const DeviceInfo &devinfo, const DaqConfiguration &config)
|
||||||
|
: DaqConfiguration(config), DeviceInfo(devinfo) {
|
||||||
|
|
||||||
|
if (monitorOutput && !(nenoutchannels() > 0)) {
|
||||||
|
throw runtime_error(
|
||||||
|
"Output monitoring only possible when output is enabled");
|
||||||
|
}
|
||||||
|
// Some sanity checks
|
||||||
|
if (eninchannels.size() != 4) {
|
||||||
|
throw runtime_error("Invalid length of enabled inChannels vector");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enoutchannels.size() != 1) {
|
||||||
|
throw runtime_error("Invalid length of enabled outChannels vector");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double Daq::samplerate() const {
|
||||||
|
assert(sampleRateIndex < availableSampleRates.size());
|
||||||
|
return availableSampleRates[sampleRateIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DataType Daq::dataType() const {
|
||||||
|
|
||||||
|
assert((us)dataTypeIndex < availableDataTypes.size());
|
||||||
|
return availableDataTypes[dataTypeIndex];
|
||||||
|
}
|
||||||
|
double Daq::inputRangeForChannel(us ch) const {
|
||||||
|
if (!(ch < ninchannels)) {
|
||||||
|
throw runtime_error("Invalid channel number");
|
||||||
|
}
|
||||||
|
assert(inputRangeIndices.size() == eninchannels.size());
|
||||||
|
return availableInputRanges[inputRangeIndices[ch]];
|
||||||
|
}
|
||||||
|
us Daq::neninchannels() const {
|
||||||
|
mutexlock lock(mutex);
|
||||||
|
us inch = std::count(eninchannels.begin(), eninchannels.end(), true);
|
||||||
|
if (monitorOutput)
|
||||||
|
inch++;
|
||||||
|
return inch;
|
||||||
|
}
|
||||||
|
us Daq::nenoutchannels() const {
|
||||||
|
mutexlock lock(mutex);
|
||||||
|
return std::count(enoutchannels.begin(), enoutchannels.end(), true);
|
||||||
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#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>
|
||||||
@ -13,12 +12,19 @@
|
|||||||
#include "lasp_cppqueue.h"
|
#include "lasp_cppqueue.h"
|
||||||
#include "string"
|
#include "string"
|
||||||
#include "vector"
|
#include "vector"
|
||||||
|
#include <mutex>
|
||||||
|
using std::cerr;
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
|
using std::runtime_error;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::runtime_error;
|
|
||||||
|
|
||||||
typedef unsigned int us;
|
typedef unsigned int us;
|
||||||
typedef vector<bool> boolvec;
|
typedef vector<bool> boolvec;
|
||||||
|
typedef vector<double> dvec;
|
||||||
|
typedef vector<us> usvec;
|
||||||
|
typedef std::lock_guard<std::mutex> mutexlock;
|
||||||
|
|
||||||
class DataType {
|
class DataType {
|
||||||
public:
|
public:
|
||||||
@ -28,10 +34,7 @@ class DataType {
|
|||||||
|
|
||||||
DataType(const char *name, unsigned sw, bool is_floating)
|
DataType(const char *name, unsigned sw, bool is_floating)
|
||||||
: name(name), sw(sw), is_floating(is_floating) {}
|
: name(name), sw(sw), is_floating(is_floating) {}
|
||||||
DataType():
|
DataType() : name("invalid data type"), sw(0), is_floating(false) {}
|
||||||
name("invalid data type"),
|
|
||||||
sw(0),
|
|
||||||
is_floating(false) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const DataType dtype_invalid;
|
const DataType dtype_invalid;
|
||||||
@ -90,83 +93,116 @@ const vector<DaqApi> compiledApis = {
|
|||||||
class DeviceInfo {
|
class DeviceInfo {
|
||||||
public:
|
public:
|
||||||
DaqApi api;
|
DaqApi api;
|
||||||
string name = "";
|
string device_name = "";
|
||||||
unsigned devindex;
|
|
||||||
|
int api_specific_devindex = -1;
|
||||||
|
|
||||||
vector<DataType> availableDataTypes;
|
vector<DataType> availableDataTypes;
|
||||||
vector<double> availableSampleRates;
|
int prefDataTypeIndex = 0;
|
||||||
vector<us> availableFramesPerBlock;
|
|
||||||
|
|
||||||
|
vector<double> availableSampleRates;
|
||||||
int prefSampleRateIndex = -1;
|
int prefSampleRateIndex = -1;
|
||||||
|
|
||||||
|
vector<us> availableFramesPerBlock;
|
||||||
|
unsigned prefFramesPerBlockIndex = 0;
|
||||||
|
|
||||||
|
dvec availableInputRanges;
|
||||||
|
int prefInputRangeIndex = 0;
|
||||||
|
|
||||||
unsigned ninchannels = 0;
|
unsigned ninchannels = 0;
|
||||||
unsigned noutchannels = 0;
|
unsigned noutchannels = 0;
|
||||||
|
|
||||||
bool hasInputIEPE = false;
|
bool hasInputIEPE = false;
|
||||||
bool hasInputACCouplingSwitch = false;
|
bool hasInputACCouplingSwitch = false;
|
||||||
bool hasInputTrigger = false;
|
bool hasInputTrigger = false;
|
||||||
vector<double> inputRanges;
|
|
||||||
|
|
||||||
/* DeviceInfo(): */
|
/* DeviceInfo(): */
|
||||||
/* datatype(dtype_invalid) { } */
|
/* datatype(dtype_invalid) { } */
|
||||||
|
|
||||||
double prefSampleRate() const {
|
double prefSampleRate() const {
|
||||||
if ((prefSampleRateIndex < availableSampleRates.size()) &&
|
if (((us) prefSampleRateIndex < availableSampleRates.size()) &&
|
||||||
(prefSampleRateIndex >= 0)) {
|
(prefSampleRateIndex >= 0)) {
|
||||||
return availableSampleRates[prefSampleRateIndex];
|
return availableSampleRates[prefSampleRateIndex];
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("No prefered sample rate available");
|
throw std::runtime_error("No prefered sample rate available");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator string() const {
|
operator string() const {
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << api.apiname + " " << devindex <<
|
str << api.apiname + " " << api_specific_devindex
|
||||||
" number of input channels: " << ninchannels <<
|
<< " number of input channels: " << ninchannels
|
||||||
" number of output channels: " << noutchannels;
|
<< " number of output channels: " << noutchannels;
|
||||||
return str.str();
|
return str.str();
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Device configuration parameters
|
// Device configuration parameters
|
||||||
class DaqConfiguration {
|
class DaqConfiguration {
|
||||||
public:
|
public:
|
||||||
|
DaqApi api;
|
||||||
|
string device_name;
|
||||||
|
|
||||||
boolvec eninchannels; // Enabled input channels
|
boolvec eninchannels; // Enabled input channels
|
||||||
boolvec enoutchannels; // Enabled output channels
|
boolvec enoutchannels; // Enabled output channels
|
||||||
|
|
||||||
unsigned sampleRateIndex; // Index in list of sample rates
|
vector<double> inchannel_sensitivities;
|
||||||
DataType
|
vector<string> inchannel_names;
|
||||||
datatype = dtype_invalid; // Required datatype for output, should be present in the list
|
|
||||||
bool monitorOutput; // Whether the first output channel should be replicated
|
// This is not necessary at the moment
|
||||||
|
/* vector<double> outchannel_sensitivities; */
|
||||||
|
vector<string> outchannel_names;
|
||||||
|
|
||||||
|
us sampleRateIndex = 0; // Index in list of sample rates
|
||||||
|
|
||||||
|
us dataTypeIndex = 0; // Required datatype for output, should be
|
||||||
|
// present in the list
|
||||||
|
|
||||||
|
us framesPerBlockIndex = 0;
|
||||||
|
|
||||||
|
bool monitorOutput = false; // Whether the first output channel should be replicated
|
||||||
// to the input as the first channel
|
// to the input as the first channel
|
||||||
|
|
||||||
unsigned nFramesPerBlock;
|
|
||||||
|
|
||||||
boolvec inputIEPEEnabled;
|
boolvec inputIEPEEnabled;
|
||||||
boolvec inputACCouplingMode;
|
boolvec inputACCouplingMode;
|
||||||
boolvec inputHighRange;
|
|
||||||
|
|
||||||
|
usvec inputRangeIndices;
|
||||||
|
|
||||||
|
// Create a default configuration, with all channels disabled on both
|
||||||
|
// input and output, and default channel names
|
||||||
|
DaqConfiguration(const DeviceInfo &device);
|
||||||
|
|
||||||
|
bool match(const DeviceInfo &devinfo) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Daq;
|
class Daq;
|
||||||
class DaqDevices {
|
class Daq : public DaqConfiguration,public DeviceInfo {
|
||||||
|
|
||||||
|
mutable std::mutex mutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static vector<DeviceInfo> getDeviceInfo();
|
static vector<DeviceInfo> getDeviceInfo();
|
||||||
static Daq *createDevice(const DeviceInfo &, const DaqConfiguration &config);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Daq {
|
static Daq *createDevice(const DaqConfiguration &config,
|
||||||
|
const std::vector<DeviceInfo> &devinfos);
|
||||||
|
|
||||||
|
Daq(const DeviceInfo &devinfo, const DaqConfiguration &config);
|
||||||
|
|
||||||
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;
|
||||||
virtual double samplerate() const = 0;
|
|
||||||
virtual DataType getDataType() const = 0;
|
virtual bool isRunning() const = 0;
|
||||||
|
|
||||||
virtual ~Daq(){};
|
virtual ~Daq(){};
|
||||||
virtual us neninchannels() const = 0;
|
us neninchannels() const;
|
||||||
virtual us nenoutchannels() const = 0;
|
us nenoutchannels() const;
|
||||||
|
|
||||||
|
double samplerate() const;
|
||||||
|
double inputRangeForChannel(us ch) const;
|
||||||
|
DataType dataType() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LASP_CPPDAQ_H
|
#endif // LASP_CPPDAQ_H
|
||||||
|
@ -1,75 +1,18 @@
|
|||||||
#include "lasp_cppuldaq.h"
|
#include "lasp_cppuldaq.h"
|
||||||
#include <algorithm>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstring>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <uldaq.h>
|
#include <uldaq.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using std::cerr;
|
using std::atomic;
|
||||||
using std::cout;
|
|
||||||
using std::endl;
|
|
||||||
using std::runtime_error;
|
|
||||||
typedef std::lock_guard<std::mutex> mutexlock;
|
|
||||||
/* using std::this_thread; */
|
|
||||||
|
|
||||||
|
/* using std::this_thread; */
|
||||||
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];
|
||||||
@ -78,34 +21,36 @@ inline void showErr(UlError err) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DT9837A::DT9837A(us samplesPerBlock, const boolvec &inChannels,
|
class DT9837A;
|
||||||
const boolvec &outChannels, double samplerate,
|
void threadfcn(DT9837A *td);
|
||||||
bool monitorOutput, us deviceno)
|
|
||||||
: samplesPerBlock(samplesPerBlock), _samplerate(samplerate),
|
class DT9837A : public Daq {
|
||||||
inChannels(inChannels), outChannels(outChannels),
|
|
||||||
monitorOutput(monitorOutput) {
|
atomic<bool> stopThread;
|
||||||
if (monitorOutput && !(nenoutchannels() > 0)) {
|
DaqDeviceHandle handle = 0;
|
||||||
throw runtime_error(
|
|
||||||
"Output monitoring only possible when output is enabled");
|
std::thread *thread = NULL;
|
||||||
}
|
SafeQueue<void *> *inqueue = NULL;
|
||||||
|
SafeQueue<void *> *outqueue = NULL;
|
||||||
|
|
||||||
|
double *inbuffer = NULL;
|
||||||
|
double *outbuffer = NULL;
|
||||||
|
|
||||||
|
us nFramesPerBlock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DT9837A(const DeviceInfo &devinfo, const DaqConfiguration &config)
|
||||||
|
: Daq(devinfo, config) {
|
||||||
|
|
||||||
stopThread = false;
|
stopThread = false;
|
||||||
high_range = boolvec({false, false, false, false});
|
|
||||||
|
|
||||||
if (samplesPerBlock < 24 || samplesPerBlock > 8192) {
|
nFramesPerBlock = availableFramesPerBlock[framesPerBlockIndex];
|
||||||
|
|
||||||
|
if (nFramesPerBlock < 24 || nFramesPerBlock > 8192) {
|
||||||
throw runtime_error("Unsensible number of samples per block chosen");
|
throw runtime_error("Unsensible number of samples per block chosen");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some sanity checks
|
if (samplerate() < 10000 || samplerate() > 51000) {
|
||||||
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");
|
throw runtime_error("Invalid sample rate");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,12 +66,13 @@ DT9837A::DT9837A(us samplesPerBlock, const boolvec &inChannels,
|
|||||||
throw runtime_error("Device inventarization failed");
|
throw runtime_error("Device inventarization failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceno >= numdevs) {
|
if ((us) api_specific_devindex >= numdevs) {
|
||||||
throw runtime_error("Device number {deviceno} too high {err}. This could "
|
throw runtime_error("Device number {deviceno} too high {err}. This could "
|
||||||
"happen when the device is currently not connected");
|
"happen when the device is currently not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor = devdescriptors[deviceno];
|
descriptor = devdescriptors[api_specific_devindex];
|
||||||
|
|
||||||
// get a handle to the DAQ device associated with the first descriptor
|
// get a handle to the DAQ device associated with the first descriptor
|
||||||
handle = ulCreateDaqDevice(descriptor);
|
handle = ulCreateDaqDevice(descriptor);
|
||||||
|
|
||||||
@ -144,15 +90,32 @@ DT9837A::DT9837A(us samplesPerBlock, const boolvec &inChannels,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (us ch = 0; ch < 4; ch++) {
|
for (us ch = 0; ch < 4; ch++) {
|
||||||
|
|
||||||
err = ulAISetConfigDbl(handle, AI_CFG_CHAN_SENSOR_SENSITIVITY, ch, 1.0);
|
err = ulAISetConfigDbl(handle, AI_CFG_CHAN_SENSOR_SENSITIVITY, ch, 1.0);
|
||||||
showErr(err);
|
showErr(err);
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
throw runtime_error("Fatal: could normalize channel sensitivity");
|
throw runtime_error("Fatal: could normalize channel sensitivity");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CouplingMode cm = inputACCouplingMode[ch] ? CM_AC : CM_DC;
|
||||||
|
err = ulAISetConfig(handle, AI_CFG_CHAN_COUPLING_MODE, ch, cm);
|
||||||
|
if (err != ERR_NO_ERROR) {
|
||||||
|
showErr(err);
|
||||||
|
throw runtime_error("Fatal: could not set AC/DC coupling mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
IepeMode iepe = inputIEPEEnabled[ch] ? IEPE_ENABLED : IEPE_DISABLED;
|
||||||
|
err = ulAISetConfig(handle, AI_CFG_CHAN_IEPE_MODE, ch, iepe);
|
||||||
|
if (err != ERR_NO_ERROR) {
|
||||||
|
showErr(err);
|
||||||
|
throw runtime_error("Fatal: could not set IEPE mode");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DT9837A::~DT9837A() {
|
DT9837A(const DT9837A &) = delete;
|
||||||
|
|
||||||
|
~DT9837A() {
|
||||||
UlError err;
|
UlError err;
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
stop();
|
stop();
|
||||||
@ -164,68 +127,72 @@ DT9837A::~DT9837A() {
|
|||||||
err = ulReleaseDaqDevice(handle);
|
err = ulReleaseDaqDevice(handle);
|
||||||
showErr(err);
|
showErr(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DT9837A::setIEPEEnabled(const boolvec &config) {
|
bool isRunning() const { return bool(thread); }
|
||||||
|
|
||||||
|
void start(SafeQueue<void *> *inqueue, SafeQueue<void *> *outqueue) {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
throw runtime_error("Cannot change config while sampling is running");
|
throw runtime_error("Thread is already running");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some sanity checks
|
bool hasinput = neninchannels() > 0;
|
||||||
if (config.size() != 4) {
|
bool hasoutput = nenoutchannels() > 0;
|
||||||
throw runtime_error("Invalid length of enabled IEPE config vector");
|
|
||||||
|
if (neninchannels() > 0 && !inqueue) {
|
||||||
|
throw runtime_error("Inqueue not given, while input is enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
IepeMode iepe;
|
if (nenoutchannels() > 0 && !outqueue) {
|
||||||
UlError err;
|
throw runtime_error("outqueue not given, while output is enabled");
|
||||||
|
|
||||||
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) {
|
|
||||||
showErr(err);
|
|
||||||
throw runtime_error("Fatal: could not set IEPE mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DT9837A::setACCouplingMode(const boolvec &coupling) {
|
|
||||||
if (isRunning()) {
|
|
||||||
throw runtime_error("Cannot change config while sampling is running");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some sanity checks
|
if (hasinput) {
|
||||||
if (coupling.size() != 4) {
|
assert(!inbuffer);
|
||||||
throw runtime_error("Invalid length of enabled AC coupling mode vector");
|
inbuffer =
|
||||||
|
new double[neninchannels() * nFramesPerBlock * 2]; // Watch the 2!
|
||||||
|
}
|
||||||
|
if (hasoutput) {
|
||||||
|
assert(!outbuffer);
|
||||||
|
outbuffer =
|
||||||
|
new double[nenoutchannels() * nFramesPerBlock * 2]; // Watch the 2!
|
||||||
|
}
|
||||||
|
this->inqueue = inqueue;
|
||||||
|
this->outqueue = outqueue;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
CouplingMode cm;
|
void stop() {
|
||||||
UlError err;
|
if (!isRunning()) {
|
||||||
|
throw runtime_error("No data acquisition running");
|
||||||
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) {
|
|
||||||
showErr(err);
|
|
||||||
throw runtime_error("Fatal: could not set IEPE mode");
|
|
||||||
}
|
}
|
||||||
}
|
assert(thread);
|
||||||
}
|
|
||||||
|
|
||||||
void DT9837A::setInputRange(const boolvec &high_range) {
|
stopThread = true;
|
||||||
if (isRunning()) {
|
thread->join();
|
||||||
throw runtime_error("Cannot change config while sampling is running");
|
delete thread;
|
||||||
|
thread = NULL;
|
||||||
|
|
||||||
|
outqueue = NULL;
|
||||||
|
inqueue = NULL;
|
||||||
|
if (inbuffer)
|
||||||
|
delete inbuffer;
|
||||||
|
if (outbuffer)
|
||||||
|
delete outbuffer;
|
||||||
|
outbuffer = NULL;
|
||||||
|
inbuffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some sanity checks
|
friend void threadfcn(DT9837A *);
|
||||||
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) {
|
||||||
|
|
||||||
@ -233,7 +200,7 @@ void threadfcn(DT9837A *td) {
|
|||||||
|
|
||||||
const us nenoutchannels = td->nenoutchannels();
|
const us nenoutchannels = td->nenoutchannels();
|
||||||
us neninchannels = td->neninchannels();
|
us neninchannels = td->neninchannels();
|
||||||
const us samplesPerBlock = td->samplesPerBlock;
|
const us nFramesPerBlock = td->nFramesPerBlock;
|
||||||
|
|
||||||
const bool hasinput = neninchannels > 0;
|
const bool hasinput = neninchannels > 0;
|
||||||
const bool hasoutput = nenoutchannels > 0;
|
const bool hasoutput = nenoutchannels > 0;
|
||||||
@ -252,16 +219,16 @@ void threadfcn(DT9837A *td) {
|
|||||||
|
|
||||||
double samplerate = td->samplerate();
|
double samplerate = td->samplerate();
|
||||||
|
|
||||||
const double sleeptime = ((double)samplesPerBlock) / (4 * samplerate);
|
const double sleeptime = ((double)nFramesPerBlock) / (4 * samplerate);
|
||||||
const us sleeptime_us = (us)(sleeptime * 1e6);
|
const us sleeptime_us = (us)(sleeptime * 1e6);
|
||||||
/* cerr << "Sleep time in loop: " << sleeptime_us << "us." << endl; */
|
/* 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;
|
cerr << "ERROR: Too small buffer size (nFramesPerBlock) chosen!" << endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const us buffer_mid_idx_in = neninchannels * samplesPerBlock;
|
const us buffer_mid_idx_in = neninchannels * nFramesPerBlock;
|
||||||
const us buffer_mid_idx_out = nenoutchannels * samplesPerBlock;
|
const us buffer_mid_idx_out = nenoutchannels * nFramesPerBlock;
|
||||||
|
|
||||||
DaqDeviceHandle handle = td->handle;
|
DaqDeviceHandle handle = td->handle;
|
||||||
assert(handle);
|
assert(handle);
|
||||||
@ -289,14 +256,14 @@ void threadfcn(DT9837A *td) {
|
|||||||
assert(outqueue);
|
assert(outqueue);
|
||||||
|
|
||||||
// Initialize the buffer with zeros, before pushing any data.
|
// Initialize the buffer with zeros, before pushing any data.
|
||||||
for (us sample = 0; sample < 2 * samplesPerBlock; sample++) {
|
for (us sample = 0; sample < 2 * nFramesPerBlock; sample++) {
|
||||||
outbuffer[sample] = 0;
|
outbuffer[sample] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cerr << "Starting output DAC" << endl;
|
cerr << "Starting output DAC" << endl;
|
||||||
err = ulAOutScan(handle, 0, 0, BIP10VOLTS,
|
err = ulAOutScan(handle, 0, 0, BIP10VOLTS,
|
||||||
/* BIP60VOLTS, */
|
/* BIP60VOLTS, */
|
||||||
2 * td->samplesPerBlock, // Watch the 2 here!
|
2 * td->nFramesPerBlock, // Watch the 2 here!
|
||||||
&samplerate, scanoptions, outscanflags, outbuffer);
|
&samplerate, scanoptions, outscanflags, outbuffer);
|
||||||
|
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
@ -307,14 +274,24 @@ void threadfcn(DT9837A *td) {
|
|||||||
|
|
||||||
// Initialize input, if any
|
// Initialize input, if any
|
||||||
if (hasinput) {
|
if (hasinput) {
|
||||||
|
|
||||||
indesc = new DaqInChanDescriptor[neninchannels];
|
indesc = new DaqInChanDescriptor[neninchannels];
|
||||||
us j = 0;
|
us j = 0;
|
||||||
for (us chin = 0; chin < 4; chin++) {
|
for (us chin = 0; chin < 4; chin++) {
|
||||||
if (td->inChannels[chin] == true) {
|
if (td->eninchannels[chin] == true) {
|
||||||
indesc[j].type = DAQI_ANALOG_SE;
|
indesc[j].type = DAQI_ANALOG_SE;
|
||||||
indesc[j].channel = chin;
|
indesc[j].channel = chin;
|
||||||
indesc[j].range = td->high_range[chin] ? BIP10VOLTS : BIP1VOLTS;
|
|
||||||
|
double rangeval = td->inputRangeForChannel(chin);
|
||||||
|
Range rangenum;
|
||||||
|
if (abs(rangeval - 1.0) < 1e-8) {
|
||||||
|
rangenum = BIP1VOLTS;
|
||||||
|
} else if (abs(rangeval - 10.0) < 1e-8) {
|
||||||
|
rangenum = BIP10VOLTS;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Fatal: input range value is invalid" << endl;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
indesc[j].range = rangenum;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,7 +306,7 @@ void threadfcn(DT9837A *td) {
|
|||||||
|
|
||||||
cerr << "Starting input ADC" << endl;
|
cerr << "Starting input ADC" << endl;
|
||||||
err = ulDaqInScan(handle, indesc, neninchannels,
|
err = ulDaqInScan(handle, indesc, neninchannels,
|
||||||
2 * td->samplesPerBlock, // Watch the 2 here!
|
2 * td->nFramesPerBlock, // Watch the 2 here!
|
||||||
&samplerate, scanoptions, inscanflags, inbuffer);
|
&samplerate, scanoptions, inscanflags, inbuffer);
|
||||||
if (err != ERR_NO_ERROR) {
|
if (err != ERR_NO_ERROR) {
|
||||||
showErr(err);
|
showErr(err);
|
||||||
@ -360,7 +337,7 @@ void threadfcn(DT9837A *td) {
|
|||||||
}
|
}
|
||||||
assert(outscanstat == SS_RUNNING);
|
assert(outscanstat == SS_RUNNING);
|
||||||
|
|
||||||
if (outxstat.currentScanCount > outTotalCount + 2 * samplesPerBlock) {
|
if (outxstat.currentScanCount > outTotalCount + 2 * nFramesPerBlock) {
|
||||||
cerr << "***** WARNING: Missing output sample blocks, DAQ Scan count="
|
cerr << "***** WARNING: Missing output sample blocks, DAQ Scan count="
|
||||||
<< outxstat.currentScanCount
|
<< outxstat.currentScanCount
|
||||||
<< " while loop count = " << outTotalCount
|
<< " while loop count = " << outTotalCount
|
||||||
@ -368,7 +345,8 @@ void threadfcn(DT9837A *td) {
|
|||||||
}
|
}
|
||||||
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;
|
||||||
@ -382,13 +360,13 @@ void threadfcn(DT9837A *td) {
|
|||||||
"QUEUE WITH ZEROS ***********"
|
"QUEUE WITH ZEROS ***********"
|
||||||
<< endl;
|
<< endl;
|
||||||
bufcpy = static_cast<double *>(
|
bufcpy = static_cast<double *>(
|
||||||
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
|
malloc(sizeof(double) * nFramesPerBlock * nenoutchannels));
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
bufcpy[sample] = 0;
|
bufcpy[sample] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(nenoutchannels > 0);
|
assert(nenoutchannels > 0);
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
outbuffer[buffer_mid_idx_out + sample] = bufcpy[sample];
|
outbuffer[buffer_mid_idx_out + sample] = bufcpy[sample];
|
||||||
}
|
}
|
||||||
free(bufcpy);
|
free(bufcpy);
|
||||||
@ -406,13 +384,13 @@ void threadfcn(DT9837A *td) {
|
|||||||
"QUEUE WITH ZEROS ***********"
|
"QUEUE WITH ZEROS ***********"
|
||||||
<< endl;
|
<< endl;
|
||||||
bufcpy = static_cast<double *>(
|
bufcpy = static_cast<double *>(
|
||||||
malloc(sizeof(double) * samplesPerBlock * nenoutchannels));
|
malloc(sizeof(double) * nFramesPerBlock * nenoutchannels));
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
bufcpy[sample] = 0;
|
bufcpy[sample] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(nenoutchannels > 0);
|
assert(nenoutchannels > 0);
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
outbuffer[sample] = bufcpy[sample];
|
outbuffer[sample] = bufcpy[sample];
|
||||||
}
|
}
|
||||||
free(bufcpy);
|
free(bufcpy);
|
||||||
@ -428,10 +406,11 @@ void threadfcn(DT9837A *td) {
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
assert(inscanstat == SS_RUNNING);
|
assert(inscanstat == SS_RUNNING);
|
||||||
if (inxstat.currentScanCount > inTotalCount + 2 * samplesPerBlock) {
|
if (inxstat.currentScanCount > inTotalCount + 2 * nFramesPerBlock) {
|
||||||
cerr << "***** ERROR: Missing input sample blocks, count="
|
cerr << "***** ERROR: Missing input sample blocks, count="
|
||||||
<< inxstat.currentScanCount
|
<< inxstat.currentScanCount
|
||||||
<< ", probably due to too small buffer size. Exiting thread. *****"
|
<< ", probably due to too small buffer size. Exiting thread. "
|
||||||
|
"*****"
|
||||||
<< endl;
|
<< endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -442,13 +421,13 @@ void threadfcn(DT9837A *td) {
|
|||||||
if (!botinenqueued) {
|
if (!botinenqueued) {
|
||||||
/* cerr << "Copying in buffer bot" << endl; */
|
/* cerr << "Copying in buffer bot" << endl; */
|
||||||
double *bufcpy = static_cast<double *>(
|
double *bufcpy = static_cast<double *>(
|
||||||
malloc(sizeof(double) * samplesPerBlock * neninchannels));
|
malloc(sizeof(double) * nFramesPerBlock * neninchannels));
|
||||||
us monitoroffset = monitorOutput ? 1 : 0;
|
us monitoroffset = monitorOutput ? 1 : 0;
|
||||||
assert(neninchannels > 0);
|
assert(neninchannels > 0);
|
||||||
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
||||||
channel++) {
|
channel++) {
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
|
bufcpy[(monitoroffset + channel) * nFramesPerBlock + sample] =
|
||||||
inbuffer[buffer_mid_idx_in + sample * neninchannels +
|
inbuffer[buffer_mid_idx_in + sample * neninchannels +
|
||||||
channel];
|
channel];
|
||||||
}
|
}
|
||||||
@ -457,7 +436,7 @@ void threadfcn(DT9837A *td) {
|
|||||||
// Monitor output goes to first channel, that is
|
// Monitor output goes to first channel, that is
|
||||||
// our convention
|
// our convention
|
||||||
us channel = neninchannels - 1;
|
us channel = neninchannels - 1;
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
bufcpy[sample] = inbuffer[buffer_mid_idx_in +
|
bufcpy[sample] = inbuffer[buffer_mid_idx_in +
|
||||||
sample * neninchannels + channel];
|
sample * neninchannels + channel];
|
||||||
}
|
}
|
||||||
@ -469,13 +448,13 @@ void threadfcn(DT9837A *td) {
|
|||||||
botinenqueued = false;
|
botinenqueued = false;
|
||||||
if (!topinenqueued) {
|
if (!topinenqueued) {
|
||||||
double *bufcpy = static_cast<double *>(
|
double *bufcpy = static_cast<double *>(
|
||||||
malloc(sizeof(double) * samplesPerBlock * neninchannels));
|
malloc(sizeof(double) * nFramesPerBlock * neninchannels));
|
||||||
us monitoroffset = monitorOutput ? 1 : 0;
|
us monitoroffset = monitorOutput ? 1 : 0;
|
||||||
assert(neninchannels > 0);
|
assert(neninchannels > 0);
|
||||||
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
for (us channel = 0; channel < (neninchannels - monitoroffset);
|
||||||
channel++) {
|
channel++) {
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
bufcpy[(monitoroffset + channel) * samplesPerBlock + sample] =
|
bufcpy[(monitoroffset + channel) * nFramesPerBlock + sample] =
|
||||||
inbuffer[sample * neninchannels + channel];
|
inbuffer[sample * neninchannels + channel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,7 +462,7 @@ void threadfcn(DT9837A *td) {
|
|||||||
// Monitor output goes to first channel, that is
|
// Monitor output goes to first channel, that is
|
||||||
// our convention
|
// our convention
|
||||||
us channel = neninchannels - 1;
|
us channel = neninchannels - 1;
|
||||||
for (us sample = 0; sample < samplesPerBlock; sample++) {
|
for (us sample = 0; sample < nFramesPerBlock; sample++) {
|
||||||
bufcpy[sample] = inbuffer[sample * neninchannels + channel];
|
bufcpy[sample] = inbuffer[sample * neninchannels + channel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -521,92 +500,13 @@ exit:
|
|||||||
std::cerr << "Exit of DAQ thread fcn" << endl;
|
std::cerr << "Exit of DAQ thread fcn" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
throw runtime_error("Inqueue not given, while input is enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nenoutchannels() > 0 && !outqueue) {
|
|
||||||
throw runtime_error("outqueue not given, while output is enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasinput) {
|
|
||||||
assert(!inbuffer);
|
|
||||||
inbuffer =
|
|
||||||
new double[neninchannels() * samplesPerBlock * 2]; // Watch the 2!
|
|
||||||
}
|
|
||||||
if (hasoutput) {
|
|
||||||
assert(!outbuffer);
|
|
||||||
outbuffer =
|
|
||||||
new double[nenoutchannels() * samplesPerBlock * 2]; // Watch the 2!
|
|
||||||
}
|
|
||||||
this->inqueue = inqueue;
|
|
||||||
this->outqueue = outqueue;
|
|
||||||
|
|
||||||
/* 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()) {
|
|
||||||
throw runtime_error("No data acquisition running");
|
|
||||||
}
|
|
||||||
assert(thread);
|
|
||||||
|
|
||||||
stopThread = true;
|
|
||||||
thread->join();
|
|
||||||
delete thread;
|
|
||||||
thread = NULL;
|
|
||||||
|
|
||||||
outqueue = NULL;
|
|
||||||
inqueue = NULL;
|
|
||||||
if (inbuffer)
|
|
||||||
delete inbuffer;
|
|
||||||
if (outbuffer)
|
|
||||||
delete outbuffer;
|
|
||||||
outbuffer = NULL;
|
|
||||||
inbuffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
us DT9837A::neninchannels() const {
|
|
||||||
mutexlock lock(mutex);
|
|
||||||
us inch = std::count(inChannels.begin(), inChannels.end(), true);
|
|
||||||
if (monitorOutput)
|
|
||||||
inch++;
|
|
||||||
return inch;
|
|
||||||
}
|
|
||||||
|
|
||||||
us DT9837A::nenoutchannels() const {
|
|
||||||
mutexlock lock(mutex);
|
|
||||||
return std::count(outChannels.begin(), outChannels.end(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Daq *createUlDaqDevice(const DeviceInfo &devinfo,
|
Daq *createUlDaqDevice(const DeviceInfo &devinfo,
|
||||||
const DaqConfiguration &config) {
|
const DaqConfiguration &config) {
|
||||||
|
|
||||||
DT9837A *daq = NULL;
|
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);
|
try {
|
||||||
daq->setIEPEEnabled(config.inputIEPEEnabled);
|
daq = new DT9837A(devinfo, config);
|
||||||
daq->setInputRange(config.inputHighRange);
|
|
||||||
|
|
||||||
} catch (runtime_error &e) {
|
} catch (runtime_error &e) {
|
||||||
if (daq)
|
if (daq)
|
||||||
|
@ -2,14 +2,6 @@
|
|||||||
#define ULDAQ_H
|
#define ULDAQ_H
|
||||||
#include "lasp_cppqueue.h"
|
#include "lasp_cppqueue.h"
|
||||||
#include "lasp_cppdaq.h"
|
#include "lasp_cppdaq.h"
|
||||||
#include <uldaq.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <vector>
|
|
||||||
#include <mutex>
|
|
||||||
#include <atomic>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using std::atomic;
|
|
||||||
|
|
||||||
Daq* createUlDaqDevice(const DeviceInfo& devinfo,
|
Daq* createUlDaqDevice(const DeviceInfo& devinfo,
|
||||||
const DaqConfiguration& config);
|
const DaqConfiguration& config);
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
cimport cython
|
cimport cython
|
||||||
from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF
|
from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF
|
||||||
from .lasp_daqconfig import (Range as pyRange,
|
from .lasp_device_common import AvType
|
||||||
DAQChannel)
|
|
||||||
from .lasp_avtype import AvType
|
|
||||||
|
|
||||||
__all__ = ['Daq']
|
__all__ = ['Daq']
|
||||||
|
|
||||||
|
0
lasp/device/lasp_daqconfig.pxd
Normal file
0
lasp/device/lasp_daqconfig.pxd
Normal file
@ -8,10 +8,7 @@ cdef class DeviceInfo:
|
|||||||
def api(self): return self.devinfo.api.apiname.decode('utf-8')
|
def api(self): return self.devinfo.api.apiname.decode('utf-8')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self): return self.devinfo.name.decode('utf-8')
|
def name(self): return self.devinfo.device_name.decode('utf-8')
|
||||||
|
|
||||||
@property
|
|
||||||
def devindex(self): return self.devinfo.devindex
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ninchannels(self): return self.devinfo.ninchannels
|
def ninchannels(self): return self.devinfo.ninchannels
|
||||||
@ -47,7 +44,7 @@ cdef class DeviceInfo:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def inputRanges(self):
|
def inputRanges(self):
|
||||||
return self.devinfo.inputRanges
|
return self.devinfo.availableInputRanges
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getDeviceInfo():
|
def getDeviceInfo():
|
||||||
@ -60,7 +57,7 @@ cdef class DeviceInfo:
|
|||||||
us numdevs, devno
|
us numdevs, devno
|
||||||
cppDeviceInfo* devinfo
|
cppDeviceInfo* devinfo
|
||||||
|
|
||||||
devinfos = DaqDevices.getDeviceInfo()
|
devinfos = cppDaq.getDeviceInfo()
|
||||||
numdevs = devinfos.size()
|
numdevs = devinfos.size()
|
||||||
|
|
||||||
pydevinfos = []
|
pydevinfos = []
|
||||||
|
@ -8,8 +8,11 @@ from .lasp_atomic import Atomic
|
|||||||
from threading import Thread, Condition, Lock
|
from threading import Thread, Condition, Lock
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
class DAQConfiguration:
|
||||||
|
pass
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from .device import (Daq, DeviceInfo, DAQConfiguration,
|
from .device import (Daq, DeviceInfo,
|
||||||
# get_numpy_dtype_from_format_string,
|
# get_numpy_dtype_from_format_string,
|
||||||
# get_sampwidth_from_format_string,
|
# get_sampwidth_from_format_string,
|
||||||
AvType,
|
AvType,
|
||||||
|
@ -11,25 +11,7 @@ using std::endl;
|
|||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
/* boolvec inChannels = {true, false, false, false}; */
|
/* boolvec inChannels = {true, false, false, false}; */
|
||||||
boolvec inChannels = {true, true, false, false};
|
auto devinfos = Daq::getDeviceInfo();
|
||||||
boolvec outChannels = {true};
|
|
||||||
double samplerate = 10000;
|
|
||||||
const us samplesPerBlock = 256;
|
|
||||||
|
|
||||||
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;
|
DeviceInfo devinfo;
|
||||||
us i;
|
us i;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -44,7 +26,21 @@ int main() {
|
|||||||
throw runtime_error("Could not find UlDaq device");
|
throw runtime_error("Could not find UlDaq device");
|
||||||
}
|
}
|
||||||
|
|
||||||
Daq* daq = DaqDevices::createDevice(devinfo, config);
|
DaqConfiguration config(devinfos[0]);
|
||||||
|
boolvec inChannels = {true, true, false, false};
|
||||||
|
boolvec outChannels = {true};
|
||||||
|
double samplerate = 10000;
|
||||||
|
const us samplesPerBlock = 256;
|
||||||
|
|
||||||
|
config.eninchannels = inChannels;
|
||||||
|
config.enoutchannels = outChannels;
|
||||||
|
config.sampleRateIndex = 0;
|
||||||
|
config.monitorOutput = true;
|
||||||
|
config.inputIEPEEnabled = {false, false, false, false};
|
||||||
|
cout << "Inchannnels size: " << config.eninchannels.size() << endl;
|
||||||
|
|
||||||
|
|
||||||
|
Daq* daq = Daq::createDevice(config, devinfos);
|
||||||
|
|
||||||
SafeQueue<void*> inqueue;
|
SafeQueue<void*> inqueue;
|
||||||
SafeQueue<void*> outqueue;
|
SafeQueue<void*> outqueue;
|
||||||
|
Loading…
Reference in New Issue
Block a user