From c1f713c8fbdebb6eab838dc5f061df5cedfedf4a Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Sat, 31 Oct 2020 20:51:35 +0100 Subject: [PATCH] Inbetween state. GUI crashes on channelConfig.set() --- lasp/device/lasp_common_decls.pxd | 3 + lasp/device/lasp_cppdaq.cpp | 4 + lasp/device/lasp_cppdaq.h | 6 +- lasp/device/lasp_cpprtaudio.cpp | 7 ++ lasp/device/lasp_daqconfig.pyx | 170 +++++++++++++++++++++++------- lasp/device/lasp_device_common.py | 28 +++-- lasp/device/lasp_deviceinfo.pyx | 12 +++ lasp/lasp_common.py | 3 +- 8 files changed, 183 insertions(+), 50 deletions(-) diff --git a/lasp/device/lasp_common_decls.pxd b/lasp/device/lasp_common_decls.pxd index ec4f583..88bcfd3 100644 --- a/lasp/device/lasp_common_decls.pxd +++ b/lasp/device/lasp_common_decls.pxd @@ -100,8 +100,11 @@ cdef extern from "lasp_cppdaq.h" nogil: vector[double] inchannel_sensitivities vector[string] inchannel_names + vector[string] inchannel_metadata vector[string] outchannel_names + vector[double] outchannel_sensitivities + vector[string] outchannel_metadata us sampleRateIndex diff --git a/lasp/device/lasp_cppdaq.cpp b/lasp/device/lasp_cppdaq.cpp index 4b01812..97d2ace 100644 --- a/lasp/device/lasp_cppdaq.cpp +++ b/lasp/device/lasp_cppdaq.cpp @@ -51,12 +51,16 @@ DaqConfiguration::DaqConfiguration(const DeviceInfo &device) { enoutchannels.resize(device.noutchannels, false); inchannel_sensitivities.resize(device.ninchannels, 1.0); + inchannel_metadata.resize(device.ninchannels, ""); for (us i = 0; i < eninchannels.size(); i++) { std::stringstream chname; chname << "Unnamed input channel " << i; inchannel_names.push_back(chname.str()); + } + outchannel_metadata.resize(device.noutchannels, ""); + outchannel_sensitivities.resize(device.noutchannels, 1.0); for (us i = 0; i < enoutchannels.size(); i++) { std::stringstream chname; chname << "Unnamed output channel " << i; diff --git a/lasp/device/lasp_cppdaq.h b/lasp/device/lasp_cppdaq.h index 2d26ab4..0e6c946 100644 --- a/lasp/device/lasp_cppdaq.h +++ b/lasp/device/lasp_cppdaq.h @@ -146,11 +146,11 @@ public: vector inchannel_sensitivities; vector inchannel_names; - vector inchannel_qtys; + vector inchannel_metadata; - // This is not necessary at the moment - /* vector outchannel_sensitivities; */ + vector outchannel_sensitivities; vector outchannel_names; + vector outchannel_metadata; us sampleRateIndex = 0; // Index in list of sample rates diff --git a/lasp/device/lasp_cpprtaudio.cpp b/lasp/device/lasp_cpprtaudio.cpp index f2176e5..7e1affe 100644 --- a/lasp/device/lasp_cpprtaudio.cpp +++ b/lasp/device/lasp_cpprtaudio.cpp @@ -74,6 +74,13 @@ void fillRtAudioDeviceInfo(vector &devinfolist) { d.prefDataTypeIndex = d.availableDataTypes.size() - 1; + d.availableFramesPerBlock.push_back(512); + d.availableFramesPerBlock.push_back(1024); + d.availableFramesPerBlock.push_back(2048); + d.availableFramesPerBlock.push_back(4096); + d.availableFramesPerBlock.push_back(8192); + d.prefFramesPerBlockIndex = 1; + devinfolist.push_back(d); } diff --git a/lasp/device/lasp_daqconfig.pyx b/lasp/device/lasp_daqconfig.pyx index be054a4..6d1c9bc 100644 --- a/lasp/device/lasp_daqconfig.pyx +++ b/lasp/device/lasp_daqconfig.pyx @@ -8,11 +8,65 @@ Description: Data Acquistiion (DAQ) device descriptors, and the DAQ devices themselves """ -__all__ = ['DaqChannel', 'DaqConfiguration'] +__all__ = ['DaqChannel', 'DaqConfiguration', 'DaqConfigurations'] from ..lasp_common import lasp_shelve, SIQtys, Qty from .lasp_device_common import DaqChannel import json +cdef class DaqConfigurations: + cdef public: + object input_config, output_config, duplex_mode + + def __init__(self, duplex_mode, DaqConfiguration input_config, + DaqConfiguration output_config): + + self.input_config = input_config + self.output_config = output_config + self.duplex_mode = duplex_mode + + def to_json(self): + return json.dumps( + dict( + duplex_mode = self.duplex_mode, + input_config = self.input_config.to_json(), + output_config = self.output_config.to_json(), + ) + ) + + @staticmethod + def from_json(daq_configs_json): + configs_dict = json.loads(daq_configs_json) + input_config = DaqConfiguration.from_json(configs_dict['input_config']) + output_config = DaqConfiguration.from_json(configs_dict['output_config']) + return DaqConfigurations(configs_dict['duplex_mode'], + input_config, + output_config) + + @staticmethod + def loadConfigs(): + """ + Returns a list of currently available configurations + """ + with lasp_shelve() as sh: + configs_json = sh.load('daqconfigs', {}) + configs = {} + for name, val in configs_json.items(): + configs[name] = DaqConfigurations.from_json(val) + return configs + + def saveConfigs(self, name): + with lasp_shelve() as sh: + configs_json = sh.load('daqconfigs', {}) + configs_json[name] = self.to_json() + sh.store('daqconfigs', configs_json) + + @staticmethod + def deleteConfig(name): + with lasp_shelve() as sh: + configs_json = sh.load('daqconfigs', {}) + del configs_json[name] + sh.store('daqconfigs', configs_json) + cdef class DaqConfiguration: """ @@ -60,6 +114,10 @@ cdef class DaqConfiguration: config.inputIEPEEnabled = pydict['inputIEPEEnabled'] config.inputACCouplingMode = pydict['inputACCouplingMode'] config.inputRangeIndices = pydict['inputRangeIndices'] + config.inchannel_metadata = [inchmeta.encode('utf-8') for inchmeta in + pydict['inchannel_metadata']] + config.outchannel_metadata = [outchmeta.encode('utf-8') for outchmeta in + pydict['outchannel_metadata']] pydaqcfg = DaqConfiguration() pydaqcfg.config = config @@ -76,8 +134,10 @@ cdef class DaqConfiguration: inchannel_names = [name.decode('utf-8') for name in self.config.inchannel_names], + outchannel_names = [name.decode('utf-8') for name in self.config.outchannel_names], + sampleRateIndex = self.config.sampleRateIndex, dataTypeIndex = self.config.dataTypeIndex, framesPerBlockIndex = self.config.framesPerBlockIndex, @@ -86,6 +146,11 @@ cdef class DaqConfiguration: inputIEPEEnabled = self.config.inputIEPEEnabled, inputACCouplingMode = self.config.inputACCouplingMode, inputRangeIndices = self.config.inputRangeIndices, + + inchannel_metadata = [inchmeta.decode('utf-8') for inchmeta in + self.config.inchannel_metadata], + outchannel_metadata = [outchmeta.decode('utf-8') for outchmeta in + self.config.outchannel_metadata] )) def getInChannel(self, i:int): @@ -95,24 +160,43 @@ cdef class DaqConfiguration: sensitivity=self.config.inchannel_sensitivities[i], range_index=self.config.inputRangeIndices[i], ACCoupling_enabled=self.config.inputACCouplingMode[i], - IEPE_enabled=self.config.inputIEPEEnabled[i] + IEPE_enabled=self.config.inputIEPEEnabled[i], + channel_metadata=self.config.inchannel_metadata[i].decode('utf-8'), ) def getOutChannel(self, i:int): return DaqChannel( channel_enabled=self.config.enoutchannels[i], channel_name=self.config.outchannel_names[i].decode('utf-8'), + channel_metadata=self.config.outchannel_metadata[i].decode('utf-8'), ) - def setInChannel(self, i:int, daqchannel: DaqChannel): - self.config.eninchannels[i] = daqchannel.channel_enabled - self.config.inchannel_names[i] = daqchannel.channel_name.encode('utf-8') - self.config.inchannel_sensitivities[i] = daqchannel.sensitivity - self.config.inputRangeIndices[i] = daqchannel.range_index - self.config.inputACCouplingMode[i] = daqchannel.ACCoupling_enabled - self.config.inputIEPEEnabled[i] = daqchannel.IEPE_enabled - def setOutChannel(self, i:int, daqchannel: DaqChannel): - self.config.enoutchannels[i] = daqchannel.channel_enabled - self.config.outchannel_names[i] = daqchannel.channel_name + def setInChannel(self, i:int, ch: DaqChannel): + self.config.eninchannels[i] = ch.channel_enabled + self.config.inchannel_names[i] = ch.channel_name.encode('utf-8') + self.config.inchannel_sensitivities[i] = ch.sensitivity + self.config.inputRangeIndices[i] = ch.range_index + self.config.inputACCouplingMode[i] = ch.ACCoupling_enabled + self.config.inputIEPEEnabled[i] = ch.IEPE_enabled + self.config.inchannel_metadata[i] = ch.channel_metadata.encode('utf-8') + + def setOutChannel(self, i:int, ch: DaqChannel): + self.config.enoutchannels[i] = ch.channel_enabled + self.config.outchannel_names[i] = ch.channel_name.encode('utf-8') + self.config.outchannel_metadata[i] = ch.channel_metadata.encode('utf-8') + + @property + def api(self): + return self.config.api.apiname.decode('utf-8') + + @api.setter + def api(self, apitxt): + cdef: + vector[DaqApi] apis = DaqApi.getAvailableApis() + for api in apis: + if api.apiname.decode('utf-8') == apitxt: + self.config.api = api + return + raise RuntimeError(f'Api {apitxt} unavailable') def eninchannels(self): return self.config.eninchannels @@ -120,33 +204,43 @@ cdef class DaqConfiguration: def enoutchannels(self): return self.config.enoutchannels - @staticmethod - def loadConfigsJSON(): - with lasp_shelve() as sh: - configs_json = sh.load('daqconfigs', {}) - return configs_json + @property + def sampleRateIndex(self): + return self.config.sampleRateIndex - @staticmethod - def loadConfigs(): - """ - Returns a list of currently available configurations - """ - configs_json = DaqConfiguration.loadConfigsJSON() - configs = {} - for name, val in configs_json.items(): - configs[name] = DaqConfiguration.from_json(val) - return configs + @sampleRateIndex.setter + def sampleRateIndex(self, int idx): + self.config.sampleRateIndex = idx - def saveConfig(self, name): - configs_json = DaqConfiguration.loadConfigsJSON() + @property + def dataTypeIndex(self): + return self.config.dataTypeIndex - with lasp_shelve() as sh: - configs_json[name] = self.to_json() - sh.store('daqconfigs', configs_json) + @dataTypeIndex.setter + def dataTypeIndex(self, int idx): + self.config.dataTypeIndex = idx + + @property + def framesPerBlockIndex(self): + return self.config.framesPerBlockIndex + + @framesPerBlockIndex.setter + def framesPerBlockIndex(self, int idx): + self.config.framesPerBlockIndex = idx + + @property + def monitorOutput(self): + return self.config.monitorOutput + + @monitorOutput.setter + def monitorOutput(self, bool idx): + self.config.monitorOutput = idx + + @property + def device_name(self): + return self.config.device_name.decode('utf-8') + + @device_name.setter + def device_name(self, idx): + self.config.device_name = idx.encode('utf-8') - @staticmethod - def deleteConfig(name): - with lasp_shelve() as sh: - cur_configs = DaqConfiguration.loadConfigs() - del cur_configs[name] - sh.store('daqconfigs', cur_configs) diff --git a/lasp/device/lasp_device_common.py b/lasp/device/lasp_device_common.py index e4ab424..5cedd8e 100644 --- a/lasp/device/lasp_device_common.py +++ b/lasp/device/lasp_device_common.py @@ -1,7 +1,9 @@ __all__ = ['AvType', 'DaqChannel'] +from ..lasp_common import Qty, SIQtys from dataclasses import dataclass, field from dataclasses_json import dataclass_json from typing import List +import json class AvType: """Specificying the type of data, for adding and removing callbacks from @@ -19,16 +21,26 @@ class DaqChannel: range_index: int = 0 ACCoupling_enabled: bool = False IEPE_enabled: bool = False + channel_metadata: str = '' -class CouplingMode: - ac = 'AC' - dc = 'DC' - undefined = 'Undefined' + def __post_init__(self): + self.qty = SIQtys.default -class Range: - oneV = '+/- 1 V' - tenV = '+/- 10 V' - undefined = 'Undefined' + @property + def qty(self): + return self._qty + @qty.setter + def qty(self, newqty): + self._qty = newqty + self._store('qty', newqty) + def _store(self, name, val): + if len(self.channel_metadata) > 0: + meta = json.loads(self.channel_metadata) + else: + meta = {} + + meta[name] = val.to_json() + self.channel_metadata = json.dumps(meta) diff --git a/lasp/device/lasp_deviceinfo.pyx b/lasp/device/lasp_deviceinfo.pyx index 469c93d..1a6a670 100644 --- a/lasp/device/lasp_deviceinfo.pyx +++ b/lasp/device/lasp_deviceinfo.pyx @@ -5,6 +5,9 @@ cdef class DeviceInfo: def __cinit__(self): pass + def __init__(self): + pass + @property def api(self): return self.devinfo.api.apiname.decode('utf-8') @@ -23,6 +26,10 @@ cdef class DeviceInfo: @property def availableSampleRates(self): return self.devinfo.availableSampleRates + @property + def availableFramesPerBlock(self): + return self.devinfo.availableFramesPerBlock + @property def availableDataTypes(self): pydtypes = [] @@ -73,3 +80,8 @@ cdef class DeviceInfo: pydevinfos.append(d) return pydevinfos + + @property + def availableInputRanges(self): + return self.devinfo.availableInputRanges + diff --git a/lasp/lasp_common.py b/lasp/lasp_common.py index 421c9dd..38bbb0d 100644 --- a/lasp/lasp_common.py +++ b/lasp/lasp_common.py @@ -17,7 +17,8 @@ Common definitions used throughout the code. """ __all__ = [ - 'P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime', 'getFreq', + 'P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime', 'getFreq', 'Qty', + 'SIQtys', 'lasp_shelve', 'this_lasp_shelve', 'W_REF', 'U_REF', 'I_REF', 'dBFS_REF', ]