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);
|
||||||
@ -60,18 +60,32 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
|
|||||||
devinfo.availableSampleRates.push_back(51000);
|
devinfo.availableSampleRates.push_back(51000);
|
||||||
|
|
||||||
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,25 +12,29 @@
|
|||||||
#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:
|
||||||
string name;
|
string name;
|
||||||
unsigned sw;
|
unsigned sw;
|
||||||
bool is_floating;
|
bool is_floating;
|
||||||
|
|
||||||
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;
|
||||||
@ -41,26 +44,26 @@ const DataType dtype_int16("16-bits integers", 2, false);
|
|||||||
const DataType dtype_int32("32-bits integers", 4, false);
|
const DataType dtype_int32("32-bits integers", 4, false);
|
||||||
|
|
||||||
const std::vector<DataType> dataTypes = {
|
const std::vector<DataType> dataTypes = {
|
||||||
dtype_int8,
|
dtype_int8,
|
||||||
dtype_int16,
|
dtype_int16,
|
||||||
dtype_int32,
|
dtype_int32,
|
||||||
dtype_fl64,
|
dtype_fl64,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DaqApi {
|
class DaqApi {
|
||||||
public:
|
public:
|
||||||
string apiname = "";
|
string apiname = "";
|
||||||
unsigned apicode = 0;
|
unsigned apicode = 0;
|
||||||
unsigned api_specific_subcode = 0;
|
unsigned api_specific_subcode = 0;
|
||||||
|
|
||||||
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
|
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
|
||||||
: apiname(apiname), apicode(apicode),
|
: apiname(apiname), apicode(apicode),
|
||||||
api_specific_subcode(api_specific_subcode) {}
|
api_specific_subcode(api_specific_subcode) {}
|
||||||
DaqApi() {}
|
DaqApi() {}
|
||||||
bool operator==(const DaqApi &other) const {
|
bool operator==(const DaqApi &other) const {
|
||||||
return (apiname == other.apiname && apicode == other.apicode &&
|
return (apiname == other.apiname && apicode == other.apicode &&
|
||||||
api_specific_subcode == other.api_specific_subcode);
|
api_specific_subcode == other.api_specific_subcode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAS_ULDAQ_LINUX_API
|
#ifdef HAS_ULDAQ_LINUX_API
|
||||||
@ -72,101 +75,134 @@ const DaqApi rtaudioalsaapi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
|
|||||||
|
|
||||||
const vector<DaqApi> compiledApis = {
|
const vector<DaqApi> compiledApis = {
|
||||||
#ifdef HAS_ULDAQ_LINUX_API
|
#ifdef HAS_ULDAQ_LINUX_API
|
||||||
uldaqapi,
|
uldaqapi,
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_RTAUDIO_ALSA_API
|
#ifdef HAS_RTAUDIO_ALSA_API
|
||||||
rtaudioalsaapi,
|
rtaudioalsaapi,
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
|
||||||
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
|
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_RTAUDIO_WIN_WASAPI_API
|
#ifdef HAS_RTAUDIO_WIN_WASAPI_API
|
||||||
DaqApi("RtAudio Windows Wasapi", 3, RtAudio::Api::WINDOWS_WASAPI),
|
DaqApi("RtAudio Windows Wasapi", 3, RtAudio::Api::WINDOWS_WASAPI),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Structure containing device info parameters
|
// Structure containing device info parameters
|
||||||
class DeviceInfo {
|
class DeviceInfo {
|
||||||
public:
|
public:
|
||||||
DaqApi api;
|
DaqApi api;
|
||||||
string name = "";
|
string device_name = "";
|
||||||
unsigned devindex;
|
|
||||||
|
|
||||||
vector<DataType> availableDataTypes;
|
int api_specific_devindex = -1;
|
||||||
vector<double> availableSampleRates;
|
|
||||||
vector<us> availableFramesPerBlock;
|
|
||||||
|
|
||||||
int prefSampleRateIndex = -1;
|
vector<DataType> availableDataTypes;
|
||||||
unsigned ninchannels = 0;
|
int prefDataTypeIndex = 0;
|
||||||
unsigned noutchannels = 0;
|
|
||||||
|
|
||||||
bool hasInputIEPE = false;
|
vector<double> availableSampleRates;
|
||||||
bool hasInputACCouplingSwitch = false;
|
int prefSampleRateIndex = -1;
|
||||||
bool hasInputTrigger = false;
|
|
||||||
vector<double> inputRanges;
|
|
||||||
|
|
||||||
/* DeviceInfo(): */
|
vector<us> availableFramesPerBlock;
|
||||||
/* datatype(dtype_invalid) { } */
|
unsigned prefFramesPerBlockIndex = 0;
|
||||||
|
|
||||||
double prefSampleRate() const {
|
dvec availableInputRanges;
|
||||||
if ((prefSampleRateIndex < availableSampleRates.size()) &&
|
int prefInputRangeIndex = 0;
|
||||||
(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();
|
|
||||||
|
|
||||||
}
|
unsigned ninchannels = 0;
|
||||||
|
unsigned noutchannels = 0;
|
||||||
|
|
||||||
|
bool hasInputIEPE = false;
|
||||||
|
bool hasInputACCouplingSwitch = false;
|
||||||
|
bool hasInputTrigger = false;
|
||||||
|
|
||||||
|
/* DeviceInfo(): */
|
||||||
|
/* datatype(dtype_invalid) { } */
|
||||||
|
|
||||||
|
double prefSampleRate() const {
|
||||||
|
if (((us) 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 + " " << api_specific_devindex
|
||||||
|
<< " number of input channels: " << ninchannels
|
||||||
|
<< " number of output channels: " << noutchannels;
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Device configuration parameters
|
// Device configuration parameters
|
||||||
class DaqConfiguration {
|
class DaqConfiguration {
|
||||||
public:
|
public:
|
||||||
boolvec eninchannels; // Enabled input channels
|
DaqApi api;
|
||||||
boolvec enoutchannels; // Enabled output channels
|
string device_name;
|
||||||
|
|
||||||
unsigned sampleRateIndex; // Index in list of sample rates
|
boolvec eninchannels; // Enabled input channels
|
||||||
DataType
|
boolvec enoutchannels; // Enabled output channels
|
||||||
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;
|
vector<double> inchannel_sensitivities;
|
||||||
|
vector<string> inchannel_names;
|
||||||
|
|
||||||
boolvec inputIEPEEnabled;
|
// This is not necessary at the moment
|
||||||
boolvec inputACCouplingMode;
|
/* vector<double> outchannel_sensitivities; */
|
||||||
boolvec inputHighRange;
|
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
|
||||||
|
|
||||||
|
|
||||||
|
boolvec inputIEPEEnabled;
|
||||||
|
boolvec inputACCouplingMode;
|
||||||
|
|
||||||
|
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 {
|
||||||
public:
|
|
||||||
static vector<DeviceInfo> getDeviceInfo();
|
|
||||||
static Daq *createDevice(const DeviceInfo &, const DaqConfiguration &config);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Daq {
|
mutable std::mutex mutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void start(SafeQueue<void *> *inqueue,
|
static vector<DeviceInfo> getDeviceInfo();
|
||||||
SafeQueue<void *> *outqueue) = 0;
|
|
||||||
|
|
||||||
virtual void stop() = 0;
|
static Daq *createDevice(const DaqConfiguration &config,
|
||||||
virtual double samplerate() const = 0;
|
const std::vector<DeviceInfo> &devinfos);
|
||||||
virtual DataType getDataType() const = 0;
|
|
||||||
|
|
||||||
virtual ~Daq(){};
|
Daq(const DeviceInfo &devinfo, const DaqConfiguration &config);
|
||||||
virtual us neninchannels() const = 0;
|
|
||||||
virtual us nenoutchannels() const = 0;
|
virtual void start(SafeQueue<void *> *inqueue,
|
||||||
|
SafeQueue<void *> *outqueue) = 0;
|
||||||
|
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
virtual bool isRunning() const = 0;
|
||||||
|
|
||||||
|
virtual ~Daq(){};
|
||||||
|
us neninchannels() const;
|
||||||
|
us nenoutchannels() const;
|
||||||
|
|
||||||
|
double samplerate() const;
|
||||||
|
double inputRangeForChannel(us ch) const;
|
||||||
|
DataType dataType() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LASP_CPPDAQ_H
|
#endif // LASP_CPPDAQ_H
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||||
|
@ -10,84 +10,80 @@ 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};
|
DeviceInfo devinfo;
|
||||||
double samplerate = 10000;
|
us i;
|
||||||
const us samplesPerBlock = 256;
|
bool found = false;
|
||||||
|
for(i=0;i<devinfos.size();i++) {
|
||||||
DaqConfiguration config;
|
if(devinfos[i].api == uldaqapi){
|
||||||
config.eninchannels = inChannels;
|
cout << string(devinfos[i]) << endl;
|
||||||
config.enoutchannels = outChannels;
|
devinfo = devinfos[i];
|
||||||
config.inputIEPEEnabled = {false, false, false, false};
|
found = true;
|
||||||
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");
|
if(!found) {
|
||||||
|
throw runtime_error("Could not find UlDaq device");
|
||||||
|
}
|
||||||
|
|
||||||
|
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*> outqueue;
|
||||||
|
|
||||||
|
double totalTime = 5;
|
||||||
|
double t = 0;
|
||||||
|
double freq = 1000;
|
||||||
|
us nblocks = ((us) totalTime*samplerate/samplesPerBlock) + 10;
|
||||||
|
|
||||||
|
for(us i=0;i<nblocks;i++) {
|
||||||
|
|
||||||
|
double* data = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock));
|
||||||
|
for(us sample=0;sample<samplesPerBlock;sample++) {
|
||||||
|
|
||||||
|
data[sample] = sin(2*M_PI*freq*t);
|
||||||
|
t+= 1.0/samplerate;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
outqueue.enqueue(data);
|
||||||
|
}
|
||||||
|
|
||||||
Daq* daq = DaqDevices::createDevice(devinfo, config);
|
daq->start(&inqueue, &outqueue);
|
||||||
|
|
||||||
SafeQueue<void*> inqueue;
|
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
|
||||||
SafeQueue<void*> outqueue;
|
|
||||||
|
|
||||||
double totalTime = 5;
|
daq->stop();
|
||||||
double t = 0;
|
|
||||||
double freq = 1000;
|
|
||||||
us nblocks = ((us) totalTime*samplerate/samplesPerBlock) + 10;
|
|
||||||
|
|
||||||
for(us i=0;i<nblocks;i++) {
|
while(!inqueue.empty()) {
|
||||||
|
double* buf = (double*) inqueue.dequeue();
|
||||||
double* data = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock));
|
for(us i=0;i<samplesPerBlock;i++) {
|
||||||
for(us sample=0;sample<samplesPerBlock;sample++) {
|
for(us ch=0;ch<daq->neninchannels();ch++) {
|
||||||
|
cout << buf[ch*samplesPerBlock+i] << " ";
|
||||||
data[sample] = sin(2*M_PI*freq*t);
|
}
|
||||||
t+= 1.0/samplerate;
|
cout << endl;
|
||||||
|
|
||||||
}
|
|
||||||
outqueue.enqueue(data);
|
|
||||||
}
|
}
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
while(!outqueue.empty()){
|
||||||
|
void* dat = outqueue.dequeue();
|
||||||
|
free(dat);
|
||||||
|
}
|
||||||
|
|
||||||
daq->start(&inqueue, &outqueue);
|
return 0;
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
|
|
||||||
|
|
||||||
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++) {
|
|
||||||
cout << buf[ch*samplesPerBlock+i] << " ";
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
while(!outqueue.empty()){
|
|
||||||
void* dat = outqueue.dequeue();
|
|
||||||
free(dat);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user