Save/Load and persist SoapySDR device settings

This commit is contained in:
Charles J. Cliffe 2015-12-06 00:32:32 -05:00
parent f91a508da6
commit 571ccd3f48
8 changed files with 180 additions and 30 deletions

View File

@ -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(); i<iMax; i++) {
DataNode *streamOptNode = streamOptsNode->child(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(); i<iMax; i++) {
DataNode *settingNode = settingsNode->child(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);
}

View File

@ -9,6 +9,8 @@
#include "DataTree.h"
typedef std::map<std::string, std::string> 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<std::string, std::string> settings;
};
class AppConfig {

View File

@ -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;

View File

@ -110,6 +110,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);

View File

@ -141,6 +141,8 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
}
}
DeviceConfig *cfg = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
if (deviceArgs.count("remote")) {
isRemote = true;
} else {
@ -149,11 +151,9 @@ std::vector<SDRDeviceInfo *> *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;
@ -168,6 +168,23 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
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<SDRDeviceInfo *> *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<std::string> gainNames = device->listGains(SOAPY_SDR_RX, i);
@ -211,8 +242,6 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
dev->addChannel(chan);
}
dev->setSettingsInfo(device->getSettingInfo());
SoapySDR::Device::unmake(device);
dev->setAvailable(true);

View File

@ -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<size_t>(), combineArgs(devInfo->getStreamArgs(),streamArgs));
SoapySDR::Kwargs currentStreamArgs = combineArgs(devInfo->getStreamArgs(),streamArgs);
stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector<size_t>(), 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();
}

View File

@ -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;

View File

@ -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();