Added pickling functionality for deviceInfo C++ object. Ugly but working implementation.
This commit is contained in:
parent
466a6f5cc1
commit
ff5afb8eb1
@ -87,6 +87,9 @@ cdef extern from "lasp_cppdaq.h" nogil:
|
|||||||
unsigned ninchannels
|
unsigned ninchannels
|
||||||
unsigned noutchannels
|
unsigned noutchannels
|
||||||
|
|
||||||
|
string serialize()
|
||||||
|
|
||||||
|
cppDeviceInfo deserialize(string)
|
||||||
bool hasInputIEPE
|
bool hasInputIEPE
|
||||||
bool hasInputACCouplingSwitch
|
bool hasInputACCouplingSwitch
|
||||||
bool hasInputTrigger
|
bool hasInputTrigger
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
using std::getline;
|
||||||
using std::runtime_error;
|
using std::runtime_error;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
@ -78,106 +79,213 @@ const DaqApi uldaqapi("UlDaq", 0);
|
|||||||
#ifdef HAS_RTAUDIO_API
|
#ifdef HAS_RTAUDIO_API
|
||||||
const DaqApi rtaudioAlsaApi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
|
const DaqApi rtaudioAlsaApi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
|
||||||
const DaqApi rtaudioPulseaudioApi("RtAudio Linux Pulseaudio", 2,
|
const DaqApi rtaudioPulseaudioApi("RtAudio Linux Pulseaudio", 2,
|
||||||
RtAudio::Api::LINUX_PULSE);
|
RtAudio::Api::LINUX_PULSE);
|
||||||
const DaqApi rtaudioWasapiApi("RtAudio Windows Wasapi", 3,
|
const DaqApi rtaudioWasapiApi("RtAudio Windows Wasapi", 3,
|
||||||
RtAudio::Api::WINDOWS_WASAPI);
|
RtAudio::Api::WINDOWS_WASAPI);
|
||||||
const DaqApi rtaudioDsApi("RtAudio Windows DirectSound", 4,
|
const DaqApi rtaudioDsApi("RtAudio Windows DirectSound", 4,
|
||||||
RtAudio::Api::WINDOWS_DS);
|
RtAudio::Api::WINDOWS_DS);
|
||||||
const DaqApi rtaudioAsioApi("RtAudio Windows ASIO", 5,
|
const DaqApi rtaudioAsioApi("RtAudio Windows ASIO", 5,
|
||||||
RtAudio::Api::WINDOWS_ASIO);
|
RtAudio::Api::WINDOWS_ASIO);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Structure containing device info parameters
|
// Structure containing device info parameters
|
||||||
class DeviceInfo {
|
class DeviceInfo {
|
||||||
public:
|
public:
|
||||||
DaqApi api;
|
DaqApi api;
|
||||||
string device_name = "";
|
string device_name = "";
|
||||||
|
|
||||||
int api_specific_devindex = -1;
|
int api_specific_devindex = -1;
|
||||||
|
|
||||||
vector<DataType> availableDataTypes;
|
vector<DataType> availableDataTypes;
|
||||||
int prefDataTypeIndex = 0;
|
int prefDataTypeIndex = 0;
|
||||||
|
|
||||||
vector<double> availableSampleRates;
|
vector<double> availableSampleRates;
|
||||||
int prefSampleRateIndex = -1;
|
int prefSampleRateIndex = -1;
|
||||||
|
|
||||||
vector<us> availableFramesPerBlock;
|
vector<us> availableFramesPerBlock;
|
||||||
unsigned prefFramesPerBlockIndex = 0;
|
unsigned prefFramesPerBlockIndex = 0;
|
||||||
|
|
||||||
dvec availableInputRanges;
|
dvec availableInputRanges;
|
||||||
int prefInputRangeIndex = 0;
|
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;
|
||||||
|
|
||||||
/* DeviceInfo(): */
|
/* DeviceInfo(): */
|
||||||
/* datatype(dtype_invalid) { } */
|
/* datatype(dtype_invalid) { } */
|
||||||
|
|
||||||
double prefSampleRate() const {
|
double prefSampleRate() const {
|
||||||
if (((us)prefSampleRateIndex < availableSampleRates.size()) &&
|
if (((us)prefSampleRateIndex < availableSampleRates.size()) &&
|
||||||
(prefSampleRateIndex >= 0)) {
|
(prefSampleRateIndex >= 0)) {
|
||||||
return availableSampleRates.at(prefSampleRateIndex);
|
return availableSampleRates.at(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 + " " << api_specific_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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string serialize() const {
|
||||||
|
// Simple serializer for this object, used because we found a bit late that
|
||||||
|
// this object needs to be send over the wire. We do not want to make this
|
||||||
|
// implementation in Python, as these objects are created here, in the C++
|
||||||
|
// code. The Python wrapper is just a readonly wrapper.
|
||||||
|
std::stringstream str;
|
||||||
|
|
||||||
|
str << api.apiname << "\t";
|
||||||
|
str << api.apicode << "\t";
|
||||||
|
str << api.api_specific_subcode << "\t";
|
||||||
|
str << device_name << "\t";
|
||||||
|
|
||||||
|
str << availableDataTypes.size() << "\t";
|
||||||
|
for(const DataType& dtype: availableDataTypes) {
|
||||||
|
// WARNING: THIS GOES COMPLETELY WRONG WHEN NAMES contain A TAB!!!
|
||||||
|
str << dtype.name << "\t";
|
||||||
|
str << dtype.sw << "\t";
|
||||||
|
str << dtype.is_floating << "\t";
|
||||||
|
}
|
||||||
|
str << prefDataTypeIndex << "\t";
|
||||||
|
|
||||||
|
str << availableSampleRates.size() << "\t";
|
||||||
|
for(const double& fs: availableSampleRates) {
|
||||||
|
// WARNING: THIS GOES COMPLETELY WRONG WHEN NAMES contain A TAB!!!
|
||||||
|
str << fs << "\t";
|
||||||
|
}
|
||||||
|
str << prefSampleRateIndex << "\t";
|
||||||
|
|
||||||
|
str << availableFramesPerBlock.size() << "\t";
|
||||||
|
for(const us& fb: availableFramesPerBlock) {
|
||||||
|
// WARNING: THIS GOES COMPLETELY WRONG WHEN NAMES contain A TAB!!!
|
||||||
|
str << fb << "\t";
|
||||||
|
}
|
||||||
|
str << prefFramesPerBlockIndex << "\t";
|
||||||
|
|
||||||
|
str << availableInputRanges.size() << "\t";
|
||||||
|
for(const double& fs: availableInputRanges) {
|
||||||
|
// WARNING: THIS GOES COMPLETELY WRONG WHEN NAMES contain A TAB!!!
|
||||||
|
str << fs << "\t";
|
||||||
|
}
|
||||||
|
str << prefInputRangeIndex << "\t";
|
||||||
|
|
||||||
|
str << ninchannels << "\t";
|
||||||
|
str << noutchannels << "\t";
|
||||||
|
str << int(hasInputIEPE) << "\t";
|
||||||
|
str << int(hasInputACCouplingSwitch) << "\t";
|
||||||
|
str << int(hasInputTrigger) << "\t";
|
||||||
|
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DeviceInfo deserialize(const string& dstr) {
|
||||||
|
DeviceInfo devinfo;
|
||||||
|
|
||||||
|
std::stringstream str(dstr);
|
||||||
|
string tmp;
|
||||||
|
us N;
|
||||||
|
auto nexts = [&]() { getline(str, tmp, '\t'); return tmp; };
|
||||||
|
auto nexti = [&]() { getline(str, tmp, '\t'); return std::atoi(tmp.c_str()); };
|
||||||
|
auto nextf = [&]() { getline(str, tmp, '\t'); return std::atof(tmp.c_str()); };
|
||||||
|
|
||||||
|
// Api
|
||||||
|
string apiname = nexts();
|
||||||
|
auto apicode = nexti();
|
||||||
|
auto api_specific_subcode = nexti();
|
||||||
|
DaqApi api(apiname, apicode, api_specific_subcode);
|
||||||
|
devinfo.api = api;
|
||||||
|
|
||||||
|
devinfo.device_name = nexts();
|
||||||
|
|
||||||
|
N = us(nexti());
|
||||||
|
for(us i=0;i<N; i++) {
|
||||||
|
DataType dtype;
|
||||||
|
dtype.name = nexts();
|
||||||
|
dtype.sw =nexti();
|
||||||
|
dtype.is_floating = bool(nexti());
|
||||||
|
devinfo.availableDataTypes.push_back(dtype);
|
||||||
|
}
|
||||||
|
devinfo.prefDataTypeIndex = nexti();
|
||||||
|
|
||||||
|
N = us(nexti());
|
||||||
|
for(us i=0;i<N; i++) {
|
||||||
|
devinfo.availableSampleRates.push_back(nextf());
|
||||||
|
}
|
||||||
|
devinfo.prefSampleRateIndex = nexti();
|
||||||
|
|
||||||
|
N = us(nexti());
|
||||||
|
for(us i=0;i<N; i++) {
|
||||||
|
devinfo.availableSampleRates.push_back(nextf());
|
||||||
|
}
|
||||||
|
devinfo.prefSampleRateIndex = nexti();
|
||||||
|
|
||||||
|
N = us(nexti());
|
||||||
|
for(us i=0;i<N; i++) {
|
||||||
|
devinfo.availableFramesPerBlock.push_back(nexti());
|
||||||
|
}
|
||||||
|
devinfo.prefFramesPerBlockIndex = nexti();
|
||||||
|
|
||||||
|
devinfo.ninchannels = nexti();
|
||||||
|
devinfo.noutchannels = nexti();
|
||||||
|
devinfo.hasInputIEPE = bool(nexti());
|
||||||
|
devinfo.hasInputACCouplingSwitch = bool(nexti());
|
||||||
|
devinfo.hasInputTrigger = bool(nexti());
|
||||||
|
|
||||||
|
return devinfo;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Device configuration parameters
|
// Device configuration parameters
|
||||||
class DaqConfiguration {
|
class DaqConfiguration {
|
||||||
public:
|
public:
|
||||||
DaqApi api;
|
DaqApi api;
|
||||||
string device_name;
|
string device_name;
|
||||||
|
|
||||||
boolvec eninchannels; // Enabled input channelsvice(const DeviceInfo& devinfo,
|
boolvec eninchannels; // Enabled input channelsvice(const DeviceInfo& devinfo,
|
||||||
boolvec enoutchannels; // Enabled output channels
|
boolvec enoutchannels; // Enabled output channels
|
||||||
|
|
||||||
vector<double> inchannel_sensitivities;
|
vector<double> inchannel_sensitivities;
|
||||||
vector<string> inchannel_names;
|
vector<string> inchannel_names;
|
||||||
vector<string> inchannel_metadata;
|
vector<string> inchannel_metadata;
|
||||||
|
|
||||||
vector<double> outchannel_sensitivities;
|
vector<double> outchannel_sensitivities;
|
||||||
vector<string> outchannel_names;
|
vector<string> outchannel_names;
|
||||||
vector<string> outchannel_metadata;
|
vector<string> outchannel_metadata;
|
||||||
|
|
||||||
us sampleRateIndex = 0; // Index in list of sample rates
|
us sampleRateIndex = 0; // Index in list of sample rates
|
||||||
|
|
||||||
us dataTypeIndex = 0; // Required datatype for output, should be
|
us dataTypeIndex = 0; // Required datatype for output, should be
|
||||||
// present in the list
|
// present in the list
|
||||||
|
|
||||||
us framesPerBlockIndex = 0;
|
us framesPerBlockIndex = 0;
|
||||||
|
|
||||||
bool monitorOutput = false;
|
bool monitorOutput = false;
|
||||||
|
|
||||||
boolvec inputIEPEEnabled;
|
boolvec inputIEPEEnabled;
|
||||||
boolvec inputACCouplingMode;
|
boolvec inputACCouplingMode;
|
||||||
|
|
||||||
usvec inputRangeIndices;
|
usvec inputRangeIndices;
|
||||||
|
|
||||||
// Create a default configuration, with all channels disabled on both
|
// Create a default configuration, with all channels disabled on both
|
||||||
// input and output, and default channel names
|
// input and output, and default channel names
|
||||||
DaqConfiguration(const DeviceInfo &device);
|
DaqConfiguration(const DeviceInfo &device);
|
||||||
DaqConfiguration() {}
|
DaqConfiguration() {}
|
||||||
|
|
||||||
bool match(const DeviceInfo &devinfo) const;
|
bool match(const DeviceInfo &devinfo) const;
|
||||||
|
|
||||||
int getHighestInChannel() const;
|
int getHighestInChannel() const;
|
||||||
int getHighestOutChannel() const;
|
int getHighestOutChannel() const;
|
||||||
|
|
||||||
int getLowestInChannel() const;
|
int getLowestInChannel() const;
|
||||||
int getLowestOutChannel() const;
|
int getLowestOutChannel() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Daq;
|
class Daq;
|
||||||
@ -185,7 +293,7 @@ class Daq : public DaqConfiguration, public DeviceInfo {
|
|||||||
|
|
||||||
mutable std::mutex mutex;
|
mutable std::mutex mutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static vector<DeviceInfo> getDeviceInfo();
|
static vector<DeviceInfo> getDeviceInfo();
|
||||||
|
|
||||||
static Daq *createDaq(const DeviceInfo &, const DaqConfiguration &config);
|
static Daq *createDaq(const DeviceInfo &, const DaqConfiguration &config);
|
||||||
@ -193,7 +301,7 @@ public:
|
|||||||
Daq(const DeviceInfo &devinfo, const DaqConfiguration &config);
|
Daq(const DeviceInfo &devinfo, const DaqConfiguration &config);
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -9,6 +9,10 @@ DeviceInfo C++ object wrapper
|
|||||||
"""
|
"""
|
||||||
__all__ = ['DeviceInfo']
|
__all__ = ['DeviceInfo']
|
||||||
|
|
||||||
|
def pickle(dat):
|
||||||
|
dev = DeviceInfo()
|
||||||
|
dev.devinfo.deserialize(dat)
|
||||||
|
return dev
|
||||||
|
|
||||||
cdef class DeviceInfo:
|
cdef class DeviceInfo:
|
||||||
def __cinit__(self):
|
def __cinit__(self):
|
||||||
@ -17,6 +21,9 @@ cdef class DeviceInfo:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def __reduce__(self):
|
||||||
|
return (pickle, (self.devinfo.serialize(),))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def api(self): return self.devinfo.api.apiname.decode('utf-8')
|
def api(self): return self.devinfo.api.apiname.decode('utf-8')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user