From 571ccd3f482c8dc602513e48317b1165ab5d5a32 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sun, 6 Dec 2015 00:32:32 -0500 Subject: [PATCH] Save/Load and persist SoapySDR device settings --- src/AppConfig.cpp | 75 +++++++++++++++++++++++++++-- src/AppConfig.h | 14 ++++++ src/AppFrame.cpp | 20 +------- src/forms/SDRDevices/SDRDevices.cpp | 15 +++++- src/sdr/SDREnumerator.cpp | 41 +++++++++++++--- src/sdr/SoapySDRThread.cpp | 19 +++++++- src/util/DataTree.cpp | 25 ++++++++++ src/util/DataTree.h | 1 + 8 files changed, 180 insertions(+), 30 deletions(-) diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index 4d2a360..6269c02 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -47,6 +47,14 @@ void DeviceConfig::save(DataNode *node) { *node->newChild("id") = deviceId; *node->newChild("ppm") = (int)ppm; *node->newChild("offset") = offset; + DataNode *streamOptsNode = node->newChild("streamOpts"); + for (ConfigSettings::const_iterator opt_i = streamOpts.begin(); opt_i != streamOpts.end(); opt_i++) { + *streamOptsNode->newChild(opt_i->first.c_str()) = opt_i->second; + } + DataNode *settingsNode = node->newChild("settings"); + for (ConfigSettings::const_iterator set_i = settings.begin(); set_i != settings.end(); set_i++) { + *settingsNode->newChild(set_i->first.c_str()) = set_i->second; + } busy_lock.unlock(); } @@ -66,9 +74,73 @@ void DeviceConfig::load(DataNode *node) { setOffset(offsetValue); std::cout << "Loaded offset for device '" << deviceId << "' at " << offsetValue << "Hz" << std::endl; } + if (node->hasAnother("streamOpts")) { + DataNode *streamOptsNode = node->getNext("streamOpts"); + for (int i = 0, iMax = streamOptsNode->numChildren(); ichild(i); + std::string keyName = streamOptNode->getName(); + std::string strSettingValue = streamOptNode->element()->toString(); + + if (keyName != "" && strSettingValue != "") { + setStreamOpt(keyName, strSettingValue); + } + } + } + if (node->hasAnother("settings")) { + DataNode *settingsNode = node->getNext("settings"); + for (int i = 0, iMax = settingsNode->numChildren(); ichild(i); + std::string keyName = settingNode->getName(); + std::string strSettingValue = settingNode->element()->toString(); + + if (keyName != "" && strSettingValue != "") { + setSetting(keyName, strSettingValue); + } + } + } busy_lock.unlock(); } +void DeviceConfig::setStreamOpts(ConfigSettings opts) { + streamOpts = opts; +} + +ConfigSettings DeviceConfig::getStreamOpts() { + return streamOpts; +} + +void DeviceConfig::setStreamOpt(std::string key, std::string value) { + streamOpts[key] = value; +} + +std::string DeviceConfig::getStreamOpt(std::string key, std::string defaultValue) { + if (streamOpts.find(key) == streamOpts.end()) { + return defaultValue; + } + + return streamOpts[key]; +} + +void DeviceConfig::setSettings(ConfigSettings settings) { + this->settings = settings; +} + +void DeviceConfig::setSetting(std::string key, std::string value) { + this->settings[key] = value; +} + +std::string DeviceConfig::getSetting(std::string key, std::string defaultValue) { + if (settings.find(key) == settings.end()) { + return defaultValue; + } + return settings[key]; +} + +ConfigSettings DeviceConfig::getSettings() { + return settings; +} + + AppConfig::AppConfig() : configName("") { winX.store(0); winY.store(0); @@ -82,8 +154,6 @@ AppConfig::AppConfig() : configName("") { spectrumAvgSpeed.store(0.65f); } - - DeviceConfig *AppConfig::getDevice(std::string deviceId) { if (deviceConfig.find(deviceId) == deviceConfig.end()) { deviceConfig[deviceId] = new DeviceConfig(); @@ -135,7 +205,6 @@ wxRect *AppConfig::getWindow() { return r; } - void AppConfig::setTheme(int themeId) { this->themeId.store(themeId); } diff --git a/src/AppConfig.h b/src/AppConfig.h index a7daebb..4d69489 100644 --- a/src/AppConfig.h +++ b/src/AppConfig.h @@ -9,6 +9,8 @@ #include "DataTree.h" +typedef std::map ConfigSettings; + class DeviceConfig { public: DeviceConfig(); @@ -23,6 +25,16 @@ public: void setDeviceId(std::string deviceId); std::string getDeviceId(); + void setStreamOpts(ConfigSettings opts); + ConfigSettings getStreamOpts(); + void setStreamOpt(std::string key, std::string value); + std::string getStreamOpt(std::string key, std::string defaultValue); + + void setSettings(ConfigSettings settings); + ConfigSettings getSettings(); + void setSetting(std::string key, std::string value); + std::string getSetting(std::string key, std::string defaultValue); + void save(DataNode *node); void load(DataNode *node); @@ -32,6 +44,8 @@ private: std::atomic_int ppm; std::atomic_llong offset; + ConfigSettings streamOpts; + std::map settings; }; class AppConfig { diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 69cf74e..e9d2fcf 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -1238,25 +1238,7 @@ bool AppFrame::loadSession(std::string fileName) { for (int msi = 0, numSettings = modemSettings->numChildren(); msi < numSettings; msi++) { DataNode *settingNode = modemSettings->child(msi); std::string keyName = settingNode->getName(); - std::string strSettingValue = ""; - - int dataType = settingNode->element()->getDataType(); - - try { - if (dataType == DATA_STRING) { - settingNode->element()->get(strSettingValue); - } else if (dataType == DATA_INT || dataType == DATA_LONG || dataType == DATA_LONGLONG) { - long long intSettingValue = *settingNode; - strSettingValue = std::to_string(intSettingValue); - } else if (dataType == DATA_FLOAT || dataType == DATA_DOUBLE) { - double floatSettingValue = *settingNode; - strSettingValue = std::to_string(floatSettingValue); - } else { - std::cout << "Unhandled setting data type: " << dataType << std::endl; - } - } catch (DataTypeMismatchException e) { - std::cout << "Setting data type mismatch: " << dataType << std::endl; - } + std::string strSettingValue = settingNode->element()->toString(); if (keyName != "" && strSettingValue != "") { mSettings[keyName] = strSettingValue; diff --git a/src/forms/SDRDevices/SDRDevices.cpp b/src/forms/SDRDevices/SDRDevices.cpp index 331c7e7..fdbf465 100644 --- a/src/forms/SDRDevices/SDRDevices.cpp +++ b/src/forms/SDRDevices/SDRDevices.cpp @@ -109,6 +109,16 @@ void SDRDevicesDialog::OnSelectionChanged( wxTreeEvent& event ) { if (dev->getRxChannel()) { args = dev->getRxChannel()->getStreamArgsInfo(); + + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId()); + ConfigSettings devStreamOpts = devConfig->getStreamOpts(); + if (devStreamOpts.size()) { + for (int j = 0, jMax = args.size(); j < jMax; j++) { + if (devStreamOpts.find(args[j].key) != devStreamOpts.end()) { + args[j].value = devStreamOpts[args[j].key]; + } + } + } if (args.size()) { m_propertyGrid->Append(new wxPropertyCategory("Stream Settings")); @@ -202,7 +212,10 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event ) { } } - + AppConfig *cfg = wxGetApp().getConfig(); + DeviceConfig *devConfig = cfg->getDevice(dev->getDeviceId()); + devConfig->setSettings(settingArgs); + devConfig->setStreamOpts(streamArgs); wxGetApp().setDeviceArgs(settingArgs); wxGetApp().setStreamArgs(streamArgs); wxGetApp().setDevice(dev); diff --git a/src/sdr/SDREnumerator.cpp b/src/sdr/SDREnumerator.cpp index 991555a..e19e1bf 100644 --- a/src/sdr/SDREnumerator.cpp +++ b/src/sdr/SDREnumerator.cpp @@ -141,6 +141,8 @@ std::vector *SDREnumerator::enumerate_devices(std::string remot } } + DeviceConfig *cfg = wxGetApp().getConfig()->getDevice(dev->getDeviceId()); + if (deviceArgs.count("remote")) { isRemote = true; } else { @@ -148,12 +150,10 @@ std::vector *SDREnumerator::enumerate_devices(std::string remot } dev->setRemote(isRemote); - - dev->setDeviceArgs(deviceArgs); std::cout << "Make device " << i << std::endl; try { - SoapySDR::Device *device = SoapySDR::Device::make(dev->getDeviceArgs()); + SoapySDR::Device *device = SoapySDR::Device::make(deviceArgs); SoapySDR::Kwargs info = device->getHardwareInfo(); for (SoapySDR::Kwargs::const_iterator it = info.begin(); it != info.end(); ++it) { std::cout << " " << it->first << "=" << it->second << std::endl; @@ -167,7 +167,24 @@ std::vector *SDREnumerator::enumerate_devices(std::string remot } else { wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Querying device #") + std::to_string(i) + ": " + dev->getName()); } + + SoapySDR::ArgInfoList settingsInfo = device->getSettingInfo(); + ConfigSettings devSettings = cfg->getSettings(); + if (devSettings.size()) { + for (ConfigSettings::const_iterator set_i = devSettings.begin(); set_i != devSettings.end(); set_i++) { + deviceArgs[set_i->first] = set_i->second; + } + for (int j = 0; j < settingsInfo.size(); j++) { + if (deviceArgs.find(settingsInfo[j].key) != deviceArgs.end()) { + settingsInfo[j].value = deviceArgs[settingsInfo[j].key]; + } + } + } + + dev->setDeviceArgs(deviceArgs); + dev->setSettingsInfo(settingsInfo); + int numChan = device->getNumChannels(SOAPY_SDR_RX); for (int i = 0; i < numChan; i++) { SDRDeviceChannel *chan = new SDRDeviceChannel(); @@ -200,7 +217,21 @@ std::vector *SDREnumerator::enumerate_devices(std::string remot chan->getSampleRates().push_back((long)(*i)); } - chan->setStreamArgsInfo(device->getStreamArgsInfo(SOAPY_SDR_RX, i)); + ConfigSettings devStreamOpts = cfg->getStreamOpts(); + if (devStreamOpts.size()) { + dev->setStreamArgs(devStreamOpts); + } + + SoapySDR::ArgInfoList optArgs = device->getStreamArgsInfo(SOAPY_SDR_RX, i); + + if (devStreamOpts.size()) { + for (int j = 0, jMax = optArgs.size(); j < jMax; j++) { + if (devStreamOpts.find(optArgs[j].key) != devStreamOpts.end()) { + optArgs[j].value = devStreamOpts[optArgs[j].key]; + } + } + } + chan->setStreamArgsInfo(optArgs); std::vector gainNames = device->listGains(SOAPY_SDR_RX, i); @@ -211,8 +242,6 @@ std::vector *SDREnumerator::enumerate_devices(std::string remot dev->addChannel(chan); } - dev->setSettingsInfo(device->getSettingInfo()); - SoapySDR::Device::unmake(device); dev->setAvailable(true); diff --git a/src/sdr/SoapySDRThread.cpp b/src/sdr/SoapySDRThread.cpp index c499dd4..0fb0c63 100644 --- a/src/sdr/SoapySDRThread.cpp +++ b/src/sdr/SoapySDRThread.cpp @@ -66,7 +66,10 @@ void SDRThread::init() { wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Initializing device.")); device = SoapySDR::Device::make(args); - stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector(), combineArgs(devInfo->getStreamArgs(),streamArgs)); + SoapySDR::Kwargs currentStreamArgs = combineArgs(devInfo->getStreamArgs(),streamArgs); + stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector(), currentStreamArgs); + deviceInfo.load()->setStreamArgs(currentStreamArgs); + deviceConfig.load()->setStreamOpts(currentStreamArgs); wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Activating stream.")); device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load()); @@ -115,6 +118,17 @@ void SDRThread::init() { } } setting_value_changed.store(false); + + SoapySDR::ArgInfoList devSettings = deviceInfo.load()->getSettingsArgInfo(); + if (devSettings.size()) { + for (int j = 0; j < settingsInfo.size(); j++) { + if (settings.find(settingsInfo[j].key) != settings.end()) { + devSettings[j].value = settings[devSettings[j].key]; + } + } + } + deviceInfo.load()->setSettingsInfo(devSettings); + setting_busy.unlock(); wxGetApp().sdrThreadNotify(SDRThread::SDR_THREAD_INITIALIZED, std::string("Device Initialized.")); @@ -404,6 +418,9 @@ void SDRThread::writeSetting(std::string name, std::string value) { settings[name] = value; settingChanged[name] = true; setting_value_changed.store(true); + if (deviceConfig.load() != nullptr) { + deviceConfig.load()->setSetting(name, value); + } setting_busy.unlock(); } diff --git a/src/util/DataTree.cpp b/src/util/DataTree.cpp index 8fc1f85..7d98d8b 100755 --- a/src/util/DataTree.cpp +++ b/src/util/DataTree.cpp @@ -356,6 +356,31 @@ DataElementGetNumericVectorDef(DATA_FLOAT_VECTOR, float, DATA_DOUBLE_VECTOR, DAT DataElementGetNumericVectorDef(DATA_DOUBLE_VECTOR, double, DATA_FLOAT_VECTOR, DATA_LONGDOUBLE_VECTOR); DataElementGetNumericVectorDef(DATA_LONGDOUBLE_VECTOR, long double, DATA_DOUBLE_VECTOR, DATA_FLOAT_VECTOR); +std::string DataElement::toString() { + int dataType = getDataType(); + std::string strValue = ""; + + try { + if (dataType == DATA_STRING) { + get(strValue); + } else if (dataType == DATA_INT || dataType == DATA_LONG || dataType == DATA_LONGLONG) { + long long intSettingValue; + get(intSettingValue); + strValue = std::to_string(intSettingValue); + } else if (dataType == DATA_FLOAT || dataType == DATA_DOUBLE) { + double floatSettingValue; + get(floatSettingValue); + strValue = std::to_string(floatSettingValue); + } else { + std::cout << "Unhandled DataElement toString for type: " << dataType << std::endl; + } + } catch (DataTypeMismatchException e) { + std::cout << "toString() DataTypeMismatch: " << dataType << std::endl; + } + + return strValue; +} + long DataElement::getSerializedSize() { return sizeof(int) + sizeof(long) + data_size; diff --git a/src/util/DataTree.h b/src/util/DataTree.h index 8220e11..81316e0 100755 --- a/src/util/DataTree.h +++ b/src/util/DataTree.h @@ -207,6 +207,7 @@ public: double getDouble() throw (DataTypeMismatchException) { double d_get; get(d_get); return d_get; }; long double getLongDouble() throw (DataTypeMismatchException) { long double d_get; get(d_get); return d_get; }; + std::string toString(); /* serialize functions */ long getSerializedSize();