Save sample rate, gain levels and AGC state per-device, add sample rate to device dialog

This commit is contained in:
Charles J. Cliffe 2016-05-11 22:37:25 -04:00
parent 6df9bfd167
commit 68b095ef8d
10 changed files with 206 additions and 34 deletions

View File

@ -4,6 +4,8 @@
DeviceConfig::DeviceConfig() : deviceId("") {
ppm.store(0);
offset.store(0);
agcMode.store(true);
sampleRate.store(0);
}
DeviceConfig::DeviceConfig(std::string deviceId) : DeviceConfig() {
@ -26,6 +28,24 @@ long long DeviceConfig::getOffset() {
return offset.load();
}
void DeviceConfig::setSampleRate(long srate) {
sampleRate.store(srate);
}
long DeviceConfig::getSampleRate() {
return sampleRate.load();
}
void DeviceConfig::setAGCMode(bool agcMode) {
this->agcMode.store(agcMode);
}
bool DeviceConfig::getAGCMode() {
return agcMode.load();
}
void DeviceConfig::setDeviceId(std::string deviceId) {
busy_lock.lock();
this->deviceId = deviceId;
@ -62,21 +82,38 @@ void DeviceConfig::save(DataNode *node) {
busy_lock.lock();
*node->newChild("id") = deviceId;
*node->newChild("name") = deviceName;
*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;
*node->newChild("ppm") = (int)ppm.load();
*node->newChild("offset") = offset.load();
*node->newChild("sample_rate") = sampleRate.load();
*node->newChild("agc_mode") = agcMode.load()?1:0;
if (streamOpts.size()) {
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;
if (settings.size()) {
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;
}
}
DataNode *rigIFs = node->newChild("rig_ifs");
for (std::map<int, long long>::const_iterator rigIF_i = rigIF.begin(); rigIF_i != rigIF.end(); rigIF_i++) {
DataNode *ifNode = rigIFs->newChild("rig_if");
*ifNode->newChild("model") = rigIF_i->first;
*ifNode->newChild("sdr_if") = rigIF_i->second;
if (rigIF.size()) {
DataNode *rigIFs = node->newChild("rig_ifs");
for (std::map<int, long long>::const_iterator rigIF_i = rigIF.begin(); rigIF_i != rigIF.end(); rigIF_i++) {
DataNode *ifNode = rigIFs->newChild("rig_if");
*ifNode->newChild("model") = rigIF_i->first;
*ifNode->newChild("sdr_if") = rigIF_i->second;
}
}
if (gains.size()) {
DataNode *gainsNode = node->newChild("gains");
for (ConfigGains::const_iterator gain_i = gains.begin(); gain_i != gains.end(); gain_i++) {
DataNode *gainNode = gainsNode->newChild("gain");
*gainNode->newChild("id") = gain_i->first;
*gainNode->newChild("value") = gain_i->second;
}
}
busy_lock.unlock();
}
@ -91,14 +128,24 @@ void DeviceConfig::load(DataNode *node) {
int ppmValue = 0;
ppm_node->element()->get(ppmValue);
setPPM(ppmValue);
std::cout << "Loaded PPM for device '" << deviceId << "' at " << ppmValue << "ppm" << std::endl;
}
if (node->hasAnother("offset")) {
DataNode *offset_node = node->getNext("offset");
long long offsetValue = 0;
offset_node->element()->get(offsetValue);
setOffset(offsetValue);
std::cout << "Loaded offset for device '" << deviceId << "' at " << offsetValue << "Hz" << std::endl;
}
if (node->hasAnother("agc_mode")) {
DataNode *agc_node = node->getNext("agc_mode");
int agcModeValue = 0;
agc_node->element()->get(agcModeValue);
setAGCMode(agcModeValue?true:false);
}
if (node->hasAnother("sample_rate")) {
DataNode *sample_rate_node = node->getNext("sample_rate");
long sampleRateValue = 0;
sample_rate_node->element()->get(sampleRateValue);
setSampleRate(sampleRateValue);
}
if (node->hasAnother("streamOpts")) {
DataNode *streamOptsNode = node->getNext("streamOpts");
@ -139,6 +186,21 @@ void DeviceConfig::load(DataNode *node) {
}
}
}
if (node->hasAnother("gains")) {
DataNode *gainsNode = node->getNext("gains");
while (gainsNode->hasAnother("gain")) {
DataNode *gainNode = gainsNode->getNext("gain");
std::string keyName;
float fltSettingValue;
gainNode->getNext("id")->element()->get(keyName);
gainNode->getNext("value")->element()->get(fltSettingValue);
if (keyName != "" && !(fltSettingValue!=fltSettingValue)) {
setGain(keyName, fltSettingValue);
}
}
}
busy_lock.unlock();
}
@ -181,6 +243,27 @@ ConfigSettings DeviceConfig::getSettings() {
return settings;
}
void DeviceConfig::setGains(ConfigGains gains) {
this->gains = gains;
}
ConfigGains DeviceConfig::getGains() {
return gains;
}
void DeviceConfig::setGain(std::string key, float value) {
gains[key] = value;
}
float DeviceConfig::getGain(std::string key, float defaultValue) {
if (gains.find(key) != gains.end()) {
return gains[key];
}
return defaultValue;
}
void DeviceConfig::setRigIF(int rigType, long long freq) {
rigIF[rigType] = freq;
}

View File

@ -12,6 +12,7 @@
#include "SDRDeviceInfo.h"
typedef std::map<std::string, std::string> ConfigSettings;
typedef std::map<std::string, float> ConfigGains;
class DeviceConfig {
public:
@ -24,6 +25,12 @@ public:
void setOffset(long long offset);
long long getOffset();
void setSampleRate(long srate);
long getSampleRate();
void setAGCMode(bool agcMode);
bool getAGCMode();
void setDeviceId(std::string deviceId);
std::string getDeviceId();
@ -39,7 +46,12 @@ public:
ConfigSettings getSettings();
void setSetting(std::string key, std::string value);
std::string getSetting(std::string key, std::string defaultValue);
void setGains(ConfigGains gains);
ConfigGains getGains();
void setGain(std::string key, float value);
float getGain(std::string key, float defaultValue);
void setRigIF(int rigType, long long freq);
long long getRigIF(int rigType);
@ -53,7 +65,10 @@ private:
std::atomic_int ppm;
std::atomic_llong offset;
std::atomic_bool agcMode;
std::atomic_long sampleRate;
ConfigSettings streamOpts;
ConfigGains gains;
std::map<std::string, std::string> settings;
std::map<int, long long> rigIF;
};

View File

@ -1597,7 +1597,9 @@ bool AppFrame::loadSession(std::string fileName) {
long long center_freq = *header->getNext("center_freq");
std::cout << "\tCenter Frequency: " << center_freq << std::endl;
wxGetApp().setFrequency(center_freq);
if (header->hasAnother("sample_rate")) {
int sample_rate = *header->getNext("sample_rate");
@ -1613,8 +1615,6 @@ bool AppFrame::loadSession(std::string fileName) {
}
wxGetApp().setFrequency(center_freq);
DataNode *demodulators = l.rootNode()->getNext("demodulators");
int numDemodulators = 0;

View File

@ -544,14 +544,11 @@ void CubicSDR::setDevice(SDRDeviceInfo *dev) {
SoapySDR::Device *soapyDev = dev->getSoapyDevice();
if (soapyDev) {
//long long freqHigh, freqLow;
if (long devSampleRate = devConfig->getSampleRate()) {
sampleRate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, devSampleRate);
sampleRateInitialized.store(true);
}
//SoapySDR::RangeList freqRange = soapyDev->getFrequencyRange(SOAPY_SDR_RX, 0);
//freqLow = freqRange[0].minimum();
//freqHigh = freqRange[freqRange.size()-1].maximum();
// Try for a reasonable default sample rate.
if (!sampleRateInitialized.load()) {
sampleRate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, DEFAULT_SAMPLE_RATE);
sampleRateInitialized.store(true);
@ -568,9 +565,16 @@ void CubicSDR::setDevice(SDRDeviceInfo *dev) {
setPPM(devConfig->getPPM());
setOffset(devConfig->getOffset());
if (devConfig->getAGCMode()) {
setAGCMode(true);
} else {
setAGCMode(false);
}
t_SDR = new std::thread(&SDRThread::threadMain, sdrThread);
}
}
stoppedDev = nullptr;
}

View File

@ -113,6 +113,30 @@ void SDRDevicesDialog::refreshDeviceProperties() {
devSettings["name"] = m_propertyGrid->Append( new wxStringProperty("Name", wxPG_LABEL, devConfig->getDeviceName()) );
devSettings["offset"] = m_propertyGrid->Append( new wxIntProperty("Offset (Hz)", wxPG_LABEL, devConfig->getOffset()) );
int currentSampleRate = wxGetApp().getSampleRate();
int deviceSampleRate = devConfig->getSampleRate();
if (!deviceSampleRate) {
deviceSampleRate = selDev->getSampleRateNear(SOAPY_SDR_RX, 0, currentSampleRate);
}
SoapySDR::ArgInfo sampleRateArg;
std::vector<long> rateOpts = selDev->getSampleRates(SOAPY_SDR_RX, 0);
for (std::vector<long>::iterator rate_i = rateOpts.begin(); rate_i != rateOpts.end(); rate_i++) {
sampleRateArg.options.push_back(std::to_string(*rate_i));
sampleRateArg.optionNames.push_back(frequencyToStr(*rate_i));
}
sampleRateArg.type = SoapySDR::ArgInfo::STRING;
sampleRateArg.units = "Hz";
sampleRateArg.name = "Sample Rate";
sampleRateArg.key = "sample_rate";
sampleRateArg.value = std::to_string(deviceSampleRate);
devSettings["sample_rate"] = addArgInfoProperty(m_propertyGrid, sampleRateArg);
deviceArgs["sample_rate"] = sampleRateArg;
runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
streamProps.erase(streamProps.begin(), streamProps.end());
@ -291,6 +315,7 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event) {
wxGetApp().setDeviceArgs(settingArgs);
wxGetApp().setStreamArgs(streamArgs);
wxGetApp().setDevice(dev);
Close();
}
event.Skip();
@ -406,6 +431,21 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
long offset = event.GetPropertyValue().GetInteger();
devConfig->setOffset(offset);
} else if (dev && event.GetProperty() == devSettings["sample_rate"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
std::string strRate = deviceArgs["sample_rate"].options[event.GetPropertyValue().GetInteger()];
int srate = 0;
try {
srate = std::stoi(strRate);
devConfig->setSampleRate(srate);
if (dev->isActive() || !wxGetApp().getDevice()) {
wxGetApp().setSampleRate(srate);
}
} catch (std::invalid_argument e) {
// nop
}
} else if (editId && dev) {
wxPGProperty *prop = event.GetProperty();

View File

@ -36,6 +36,7 @@ private:
std::map<wxTreeItemId, SDRDeviceInfo *> devItems;
std::map<wxTreeItemId, SDRDeviceInfo *>::iterator devItems_i;
SDRDeviceInfo *dev;
std::map<std::string, SoapySDR::ArgInfo> deviceArgs;
std::map<std::string, wxPGProperty *> runtimeProps;
std::map<std::string, SoapySDR::ArgInfo> runtimeArgs;
std::map<std::string, wxPGProperty *> streamProps;

View File

@ -302,6 +302,15 @@ void SDRThread::updateSettings() {
agc_mode_changed.store(false);
if (!agc_mode.load()) {
updateGains();
DeviceConfig *devConfig = deviceConfig.load();
ConfigGains gains = devConfig->getGains();
if (gains.size()) {
for (ConfigGains::iterator gain_i = gains.begin(); gain_i != gains.end(); gain_i++) {
setGain(gain_i->first, gain_i->second);
}
}
}
doUpdate = true;
}
@ -394,7 +403,7 @@ int SDRThread::getOptimalElementCount(long long sampleRate, int fps) {
int elemCount = (int)floor((double)sampleRate/(double)fps);
int nch = numChannels.load();
elemCount = int(ceil((double)elemCount/(double)nch))*nch;
std::cout << "Calculated optimal " << numChannels.load() << " channel element count of " << elemCount << std::endl;
// std::cout << "Calculated optimal " << numChannels.load() << " channel element count of " << elemCount << std::endl;
return elemCount;
}
@ -450,7 +459,7 @@ void SDRThread::unlockFrequency() {
void SDRThread::setOffset(long long ofs) {
offset.store(ofs);
offset_changed.store(true);
std::cout << "Set offset: " << offset.load() << std::endl;
// std::cout << "Set offset: " << offset.load() << std::endl;
}
long long SDRThread::getOffset() {
@ -460,7 +469,11 @@ long long SDRThread::getOffset() {
void SDRThread::setSampleRate(int rate) {
sampleRate.store(rate);
rate_changed = true;
std::cout << "Set sample rate: " << sampleRate.load() << std::endl;
DeviceConfig *devConfig = deviceConfig.load();
if (devConfig) {
devConfig->setSampleRate(rate);
}
// std::cout << "Set sample rate: " << sampleRate.load() << std::endl;
}
int SDRThread::getSampleRate() {
return sampleRate.load();
@ -469,7 +482,7 @@ int SDRThread::getSampleRate() {
void SDRThread::setPPM(int ppm) {
this->ppm.store(ppm);
ppm_changed.store(true);
std::cout << "Set PPM: " << this->ppm.load() << std::endl;
// std::cout << "Set PPM: " << this->ppm.load() << std::endl;
}
int SDRThread::getPPM() {
@ -479,6 +492,10 @@ int SDRThread::getPPM() {
void SDRThread::setAGCMode(bool mode) {
agc_mode.store(mode);
agc_mode_changed.store(true);
DeviceConfig *devConfig = deviceConfig.load();
if (devConfig) {
devConfig->setAGCMode(mode);
}
}
bool SDRThread::getAGCMode() {
@ -499,6 +516,11 @@ void SDRThread::setGain(std::string name, float value) {
gainChanged[name] = true;
gain_value_changed.store(true);
gain_busy.unlock();
DeviceConfig *devConfig = deviceConfig.load();
if (devConfig) {
devConfig->setGain(name, value);
}
}
float SDRThread::getGain(std::string name) {

View File

@ -371,6 +371,8 @@ std::string DataElement::toString() {
double floatSettingValue;
get(floatSettingValue);
strValue = std::to_string(floatSettingValue);
} else if (dataType == DATA_NULL) {
strValue = "";
} else {
std::cout << "Unhandled DataElement toString for type: " << dataType << std::endl;
}

View File

@ -36,6 +36,7 @@ GainCanvas::GainCanvas(wxWindow *parent, int *dispAttrs) :
barWidth = (1.0/numGains)*0.8;
startPos = spacing/2.0;
barHeight = 0.8;
refreshCounter = 0;
}
GainCanvas::~GainCanvas() {
@ -186,8 +187,9 @@ void GainCanvas::updateGainUI() {
const wxSize ClientSize = GetClientSize();
SDRDeviceInfo *devInfo = wxGetApp().getDevice();
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devInfo->getDeviceId());
SDRRangeMap gains = devInfo->getGains(SOAPY_SDR_RX, 0);
gains = devInfo->getGains(SOAPY_SDR_RX, 0);
SDRRangeMap::iterator gi;
numGains = gains.size();
@ -223,7 +225,8 @@ void GainCanvas::updateGainUI() {
gInfo->name = gi->first;
gInfo->low = gi->second.minimum();
gInfo->high = gi->second.maximum();
gInfo->current = wxGetApp().getGain(gInfo->name);
gInfo->current = devConfig->getGain(gInfo->name,wxGetApp().getGain(gInfo->name));
gInfo->changed = false;
gInfo->panel.setBorderPx(1);
gInfo->panel.setFill(GLPanel::GLPANEL_FILL_GRAD_BAR_X);

View File

@ -10,7 +10,7 @@
#include "MouseTracker.h"
#include "GLPanel.h"
#include "PrimaryGLContext.h"
#include "SDRDeviceInfo.h"
#include "Timer.h"
class GainInfo {
@ -53,8 +53,10 @@ private:
std::string helpTip;
std::vector<GainInfo *> gainInfo;
GLPanel bgPanel;
SDRRangeMap gains;
float spacing, barWidth, startPos, barHeight, numGains;
int refreshCounter;
wxSize clientSize;
//
wxDECLARE_EVENT_TABLE();