Initial commit: Antenna support, Enhanced Settings menu, Enhanced SDR device dialog

This commit is contained in:
vsonnier 2017-08-23 23:27:49 +02:00
parent e32e687fe8
commit 1042c62c3b
12 changed files with 316 additions and 37 deletions

View File

@ -39,6 +39,14 @@ long DeviceConfig::getSampleRate() {
return sampleRate.load(); return sampleRate.load();
} }
void DeviceConfig::setAntennaName(const std::string& name) {
antennaName = name;
}
const std::string& DeviceConfig::getAntennaName() {
return antennaName;
}
void DeviceConfig::setAGCMode(bool agcMode) { void DeviceConfig::setAGCMode(bool agcMode) {
this->agcMode.store(agcMode); this->agcMode.store(agcMode);
} }
@ -81,7 +89,9 @@ std::string DeviceConfig::getDeviceName() {
} }
void DeviceConfig::save(DataNode *node) { void DeviceConfig::save(DataNode *node) {
std::lock_guard < std::mutex > lock(busy_lock); std::lock_guard < std::mutex > lock(busy_lock);
*node->newChild("id") = deviceId; *node->newChild("id") = deviceId;
*node->newChild("name") = deviceName; *node->newChild("name") = deviceName;
*node->newChild("ppm") = ppm.load(); *node->newChild("ppm") = ppm.load();
@ -89,6 +99,10 @@ void DeviceConfig::save(DataNode *node) {
*node->newChild("sample_rate") = sampleRate.load(); *node->newChild("sample_rate") = sampleRate.load();
*node->newChild("agc_mode") = agcMode.load()?1:0; *node->newChild("agc_mode") = agcMode.load()?1:0;
if (!antennaName.empty()) {
*node->newChild("antenna") = antennaName;
}
if (streamOpts.size()) { if (streamOpts.size()) {
DataNode *streamOptsNode = node->newChild("streamOpts"); DataNode *streamOptsNode = node->newChild("streamOpts");
for (ConfigSettings::const_iterator opt_i = streamOpts.begin(); opt_i != streamOpts.end(); opt_i++) { for (ConfigSettings::const_iterator opt_i = streamOpts.begin(); opt_i != streamOpts.end(); opt_i++) {
@ -149,6 +163,12 @@ void DeviceConfig::load(DataNode *node) {
sample_rate_node->element()->get(sampleRateValue); sample_rate_node->element()->get(sampleRateValue);
setSampleRate(sampleRateValue); setSampleRate(sampleRateValue);
} }
if (node->hasAnother("antenna")) {
DataNode *antenna_node = node->getNext("antenna");
std::string antennaNameValue;
antenna_node->element()->get(antennaNameValue);
setAntennaName(antennaNameValue);
}
if (node->hasAnother("streamOpts")) { if (node->hasAnother("streamOpts")) {
DataNode *streamOptsNode = node->getNext("streamOpts"); DataNode *streamOptsNode = node->getNext("streamOpts");
for (int i = 0, iMax = streamOptsNode->numChildren(); i<iMax; i++) { for (int i = 0, iMax = streamOptsNode->numChildren(); i<iMax; i++) {

View File

@ -31,6 +31,9 @@ public:
void setSampleRate(long srate); void setSampleRate(long srate);
long getSampleRate(); long getSampleRate();
void setAntennaName(const std::string& name);
const std::string& getAntennaName();
void setAGCMode(bool agcMode); void setAGCMode(bool agcMode);
bool getAGCMode(); bool getAGCMode();
@ -64,12 +67,14 @@ public:
private: private:
std::string deviceId; std::string deviceId;
std::string deviceName; std::string deviceName;
std::mutex busy_lock; std::mutex busy_lock;
std::atomic_int ppm; std::atomic_int ppm;
std::atomic_llong offset; std::atomic_llong offset;
std::atomic_bool agcMode; std::atomic_bool agcMode;
std::atomic_long sampleRate; std::atomic_long sampleRate;
std::string antennaName;
ConfigSettings streamOpts; ConfigSettings streamOpts;
ConfigGains gains; ConfigGains gains;
std::map<std::string, std::string> settings; std::map<std::string, std::string> settings;

View File

@ -752,11 +752,13 @@ void AppFrame::updateDeviceParams() {
newSettingsMenu->AppendSeparator(); newSettingsMenu->AppendSeparator();
newSettingsMenu->Append(wxID_SET_DB_OFFSET, "Power Level Offset"); settingsMenuItems.clear();
newSettingsMenu->Append(wxID_SET_FREQ_OFFSET, "Frequency Offset");
settingsMenuItems[wxID_SET_DB_OFFSET] = newSettingsMenu->Append(wxID_SET_DB_OFFSET, wxT("Power Level Offset : ") + std::to_string(wxGetApp().getConfig()->getDBOffset()) + wxT(" dB"));
settingsMenuItems[wxID_SET_FREQ_OFFSET] = newSettingsMenu->Append(wxID_SET_FREQ_OFFSET, wxT("Frequency Offset : ") + std::to_string(wxGetApp().getOffset()) + wxT(" Hz"));
if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) { if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) {
newSettingsMenu->Append(wxID_SET_PPM, "Device PPM"); settingsMenuItems[wxID_SET_PPM] = newSettingsMenu->Append(wxID_SET_PPM, wxT("Device PPM : ") + std::to_string(wxGetApp().getPPM()) + wxT(" ppm"));
} }
if (devInfo->getDriver() != "rtlsdr") { if (devInfo->getDriver() != "rtlsdr") {
@ -771,7 +773,43 @@ void AppFrame::updateDeviceParams() {
} else if (!wxGetApp().getAGCMode()) { } else if (!wxGetApp().getAGCMode()) {
wxGetApp().setAGCMode(true); wxGetApp().setAGCMode(true);
} }
//Add an Antenna menu if more than one (RX) antenna, to keep the UI free of useless entries
antennaNames.clear();
antennaMenuItems.clear();
std::vector<std::string> availableAntennas = devInfo->getAntennaNames(SOAPY_SDR_RX, 0);
if (availableAntennas.size() > 1) {
newSettingsMenu->AppendSeparator();
antennaNames = availableAntennas;
wxMenu *subMenu = new wxMenu;
int i = 0;
std::string antennaChecked;
for (std::string currentAntenna : availableAntennas) {
antennaMenuItems[wxID_ANTENNAS_BASE + i] = subMenu->AppendRadioItem(wxID_ANTENNAS_BASE + i, currentAntenna);
if (wxGetApp().getAntennaName() == currentAntenna) {
antennaMenuItems[wxID_ANTENNAS_BASE + i]->Check(true);
antennaChecked = currentAntenna;
}
i++;
}
antennaMenuItems[wxID_ANTENNA_CURRENT] = newSettingsMenu->AppendSubMenu(subMenu, "Antenna");
//Change the Antenna label to indicate the current antenna.
if (!antennaChecked.empty()) {
antennaMenuItems[wxID_ANTENNA_CURRENT]->SetItemLabel(wxT("Antenna : ") + antennaChecked);
}
}
//Runtime settings part
SoapySDR::ArgInfoList::const_iterator args_i; SoapySDR::ArgInfoList::const_iterator args_i;
settingArgs = soapyDev->getSettingInfo(); settingArgs = soapyDev->getSettingInfo();
@ -790,15 +828,17 @@ void AppFrame::updateDeviceParams() {
item->Check(currentVal=="true"); item->Check(currentVal=="true");
i++; i++;
} else if (arg.type == SoapySDR::ArgInfo::INT) { } else if (arg.type == SoapySDR::ArgInfo::INT) {
newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description);
settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->Append(wxID_SETTINGS_BASE + i, wxString(arg.name) + " : " + currentVal, arg.description);
i++; i++;
} else if (arg.type == SoapySDR::ArgInfo::FLOAT) { } else if (arg.type == SoapySDR::ArgInfo::FLOAT) {
newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description); settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->Append(wxID_SETTINGS_BASE + i, wxString(arg.name) + " : " + currentVal, arg.description);
i++; i++;
} else if (arg.type == SoapySDR::ArgInfo::STRING) { } else if (arg.type == SoapySDR::ArgInfo::STRING) {
if (arg.options.size()) { if (arg.options.size()) {
wxMenu *subMenu = new wxMenu; wxMenu *subMenu = new wxMenu;
int j = 0; int j = 0;
std::vector<int> subItemsIds;
//for each of this options //for each of this options
for (std::string optName : arg.options) { for (std::string optName : arg.options) {
//by default the option name is the same as the displayed name. //by default the option name is the same as the displayed name.
@ -808,15 +848,21 @@ void AppFrame::updateDeviceParams() {
displayName = arg.optionNames[j]; displayName = arg.optionNames[j];
} }
wxMenuItem *item = subMenu->AppendRadioItem(wxID_SETTINGS_BASE+i, displayName); wxMenuItem *item = subMenu->AppendRadioItem(wxID_SETTINGS_BASE+i, displayName);
subItemsIds.push_back(wxID_SETTINGS_BASE + i);
if (currentVal == optName) { if (currentVal == optName) {
item->Check(true); item->Check(true);
} }
j++; j++;
i++; i++;
} }
newSettingsMenu->AppendSubMenu(subMenu, arg.name, arg.description); settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->AppendSubMenu(subMenu, wxString(arg.name) + " : " + currentVal, arg.description);
//map subitems ids to their parent item !
for (int currentSubId : subItemsIds) {
settingsMenuItems[currentSubId] = settingsMenuItems[wxID_SETTINGS_BASE + i];
}
} else { } else {
newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description); settingsMenuItems[wxID_SETTINGS_BASE + i] = newSettingsMenu->Append(wxID_SETTINGS_BASE + i, wxString(arg.name) + " : " + currentVal, arg.description);
i++; i++;
} }
} }
@ -1104,7 +1150,14 @@ bool AppFrame::actionOnMenuAbout(wxCommandEvent& event) {
bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) { bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
if (event.GetId() >= wxID_SETTINGS_BASE && event.GetId() < settingsIdMax) { if (event.GetId() >= wxID_ANTENNAS_BASE && event.GetId() < wxID_ANTENNAS_BASE + antennaNames.size()) {
wxGetApp().setAntennaName(antennaNames[event.GetId() - wxID_ANTENNAS_BASE]);
antennaMenuItems[wxID_ANTENNA_CURRENT]->SetItemLabel(wxT("Antenna : ") + wxGetApp().getAntennaName());
return true;
}
else if (event.GetId() >= wxID_SETTINGS_BASE && event.GetId() < settingsIdMax) {
int setIdx = event.GetId() - wxID_SETTINGS_BASE; int setIdx = event.GetId() - wxID_SETTINGS_BASE;
int menuIdx = 0; int menuIdx = 0;
@ -1115,6 +1168,9 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size() && setIdx >= menuIdx && setIdx < menuIdx + (int)arg.options.size()) { if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size() && setIdx >= menuIdx && setIdx < menuIdx + (int)arg.options.size()) {
int optIdx = setIdx - menuIdx; int optIdx = setIdx - menuIdx;
wxGetApp().getSDRThread()->writeSetting(arg.key, arg.options[optIdx]); wxGetApp().getSDRThread()->writeSetting(arg.key, arg.options[optIdx]);
//update parent menu item label to display the current value
settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(wxString(arg.name) + " : " + arg.options[optIdx]);
break; break;
} }
else if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) { else if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
@ -1127,6 +1183,9 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
} }
else if (arg.type == SoapySDR::ArgInfo::STRING) { else if (arg.type == SoapySDR::ArgInfo::STRING) {
wxString stringVal = wxGetTextFromUser(arg.description, arg.name, wxGetApp().getSDRThread()->readSetting(arg.key)); wxString stringVal = wxGetTextFromUser(arg.description, arg.name, wxGetApp().getSDRThread()->readSetting(arg.key));
settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(wxString(arg.name) + " : " + stringVal);
if (stringVal.ToStdString() != "") { if (stringVal.ToStdString() != "") {
wxGetApp().getSDRThread()->writeSetting(arg.key, stringVal.ToStdString()); wxGetApp().getSDRThread()->writeSetting(arg.key, stringVal.ToStdString());
} }
@ -1141,6 +1200,9 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
currentVal = 0; currentVal = 0;
} }
int intVal = wxGetNumberFromUser(arg.description, arg.units, arg.name, currentVal, arg.range.minimum(), arg.range.maximum(), this); int intVal = wxGetNumberFromUser(arg.description, arg.units, arg.name, currentVal, arg.range.minimum(), arg.range.maximum(), this);
settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(wxString(arg.name) + " : " + std::to_string(intVal));
if (intVal != -1) { if (intVal != -1) {
wxGetApp().getSDRThread()->writeSetting(arg.key, std::to_string(intVal)); wxGetApp().getSDRThread()->writeSetting(arg.key, std::to_string(intVal));
} }
@ -1154,6 +1216,7 @@ bool AppFrame::actionOnMenuSettings(wxCommandEvent& event) {
catch (std::invalid_argument e) { catch (std::invalid_argument e) {
// ... // ...
} }
settingsMenuItems[menuIdx + wxID_SETTINGS_BASE]->SetItemLabel(wxString(arg.name) + " : " + floatVal);
break; break;
} }
else { else {
@ -1508,6 +1571,8 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
"Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this); "Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this);
if (ofs != -1) { if (ofs != -1) {
wxGetApp().setOffset(ofs); wxGetApp().setOffset(ofs);
settingsMenuItems[wxID_SET_FREQ_OFFSET]->SetItemLabel(wxT("Frequency Offset : ") + std::to_string(wxGetApp().getOffset()) + wxT(" Hz"));
} }
} }
else if (event.GetId() == wxID_SET_DB_OFFSET) { else if (event.GetId() == wxID_SET_DB_OFFSET) {
@ -1515,6 +1580,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
"Power Level Offset", wxGetApp().getConfig()->getDBOffset(), -1000, 1000, this); "Power Level Offset", wxGetApp().getConfig()->getDBOffset(), -1000, 1000, this);
if (ofs != -1) { if (ofs != -1) {
wxGetApp().getConfig()->setDBOffset(ofs); wxGetApp().getConfig()->setDBOffset(ofs);
settingsMenuItems[wxID_SET_DB_OFFSET]->SetItemLabel(wxT("Power Level Offset : ") + std::to_string(wxGetApp().getConfig()->getDBOffset()) + wxT(" dB"));
} }
} }
else if (actionOnMenuAGC(event)) { else if (actionOnMenuAGC(event)) {
@ -1527,6 +1593,8 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
long ofs = wxGetNumberFromUser("Frequency correction for device in PPM.\ni.e. -51 for -51 PPM\n\nNote: you can adjust PPM interactively\nby holding ALT over the frequency tuning bar.\n", "Parts per million (PPM)", long ofs = wxGetNumberFromUser("Frequency correction for device in PPM.\ni.e. -51 for -51 PPM\n\nNote: you can adjust PPM interactively\nby holding ALT over the frequency tuning bar.\n", "Parts per million (PPM)",
"Frequency Correction", wxGetApp().getPPM(), -1000, 1000, this); "Frequency Correction", wxGetApp().getPPM(), -1000, 1000, this);
wxGetApp().setPPM(ofs); wxGetApp().setPPM(ofs);
settingsMenuItems[wxID_SET_PPM]->SetItemLabel(wxT("Device PPM : ") + std::to_string(wxGetApp().getPPM()) + wxT(" ppm"));
} }
else if (actionOnMenuLoadSave(event)) { else if (actionOnMenuLoadSave(event)) {
return; return;
@ -2019,13 +2087,14 @@ void AppFrame::OnAboutDialogClose(wxCommandEvent& event) {
} }
void AppFrame::saveSession(std::string fileName) { void AppFrame::saveSession(std::string fileName) {
DataTree s("cubicsdr_session"); DataTree s("cubicsdr_session");
DataNode *header = s.rootNode()->newChild("header"); DataNode *header = s.rootNode()->newChild("header");
//save as wstring to prevent problems //save as wstring to prevent problems
header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring()); header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring());
*header->newChild("center_freq") = wxGetApp().getFrequency(); *header->newChild("center_freq") = wxGetApp().getFrequency();
*header->newChild("sample_rate") = wxGetApp().getSampleRate(); *header->newChild("sample_rate") = wxGetApp().getSampleRate();
*header->newChild("solo_mode") = wxGetApp().getSoloMode()?1:0; *header->newChild("solo_mode") = wxGetApp().getSoloMode()?1:0;
if (waterfallCanvas->getViewState()) { if (waterfallCanvas->getViewState()) {
@ -2061,6 +2130,7 @@ void AppFrame::saveSession(std::string fileName) {
} }
bool AppFrame::loadSession(std::string fileName) { bool AppFrame::loadSession(std::string fileName) {
DataTree l; DataTree l;
if (!l.LoadFromFileXML(fileName)) { if (!l.LoadFromFileXML(fileName)) {
return false; return false;

View File

@ -64,6 +64,9 @@
#define wxID_SETTINGS_BASE 2300 #define wxID_SETTINGS_BASE 2300
#define wxID_ANTENNA_CURRENT 2500
#define wxID_ANTENNAS_BASE 2501
#define wxID_DEVICE_ID 3500 #define wxID_DEVICE_ID 3500
#define wxID_AUDIO_BANDWIDTH_BASE 9000 #define wxID_AUDIO_BANDWIDTH_BASE 9000
@ -192,6 +195,12 @@ private:
std::map<int,RtAudio::DeviceInfo> outputDevices; std::map<int,RtAudio::DeviceInfo> outputDevices;
std::map<int, wxMenuItem *> outputDeviceMenuItems; std::map<int, wxMenuItem *> outputDeviceMenuItems;
std::map<int, wxMenuItem *> sampleRateMenuItems; std::map<int, wxMenuItem *> sampleRateMenuItems;
std::map<int, wxMenuItem *> antennaMenuItems;
//depending on context, maps the item id to wxMenuItem*,
//OR the submenu item id to its parent wxMenuItem*.
std::map<int, wxMenuItem *> settingsMenuItems;
std::map<int, wxMenuItem *> audioSampleRateMenuItems; std::map<int, wxMenuItem *> audioSampleRateMenuItems;
std::map<int, wxMenuItem *> directSamplingMenuItems; std::map<int, wxMenuItem *> directSamplingMenuItems;
wxMenuBar *menuBar; wxMenuBar *menuBar;
@ -207,6 +216,8 @@ private:
int settingsIdMax; int settingsIdMax;
std::vector<long> sampleRates; std::vector<long> sampleRates;
long manualSampleRate = -1; long manualSampleRate = -1;
std::vector<std::string> antennaNames;
std::string currentSessionFile; std::string currentSessionFile;

View File

@ -629,9 +629,22 @@ long long CubicSDR::getOffset() {
void CubicSDR::setOffset(long long ofs) { void CubicSDR::setOffset(long long ofs) {
offset = ofs; offset = ofs;
sdrThread->setOffset(offset);
SDRDeviceInfo *dev = getDevice(); if (sdrThread && !sdrThread->isTerminated()) {
config.getDevice(dev->getDeviceId())->setOffset(ofs); sdrThread->setOffset(offset);
}
}
void CubicSDR::setAntennaName(const std::string& name) {
antennaName = name;
if (sdrThread && !sdrThread->isTerminated()) {
sdrThread->setAntenna(antennaName);
}
}
const std::string& CubicSDR::getAntennaName() {
return antennaName;
} }
long long CubicSDR::getFrequency() { long long CubicSDR::getFrequency() {
@ -654,12 +667,18 @@ bool CubicSDR::isFrequencyLocked() {
void CubicSDR::unlockFrequency() { void CubicSDR::unlockFrequency() {
frequency_locked.store(false); frequency_locked.store(false);
sdrThread->unlockFrequency(); if (sdrThread && !sdrThread->isTerminated()) {
sdrThread->unlockFrequency();
}
} }
void CubicSDR::setSampleRate(long long rate_in) { void CubicSDR::setSampleRate(long long rate_in) {
sampleRate = rate_in; sampleRate = rate_in;
sdrThread->setSampleRate(sampleRate);
if (sdrThread && !sdrThread->isTerminated()) {
sdrThread->setSampleRate(sampleRate);
}
setFrequency(frequency); setFrequency(frequency);
if (rate_in <= CHANNELIZER_RATE_MAX / 8) { if (rate_in <= CHANNELIZER_RATE_MAX / 8) {
@ -750,13 +769,8 @@ void CubicSDR::setDevice(SDRDeviceInfo *dev, int waitMsForTermination) {
setPPM(devConfig->getPPM()); setPPM(devConfig->getPPM());
setOffset(devConfig->getOffset()); setOffset(devConfig->getOffset());
setAGCMode(devConfig->getAGCMode());
setAntennaName(devConfig->getAntennaName());
if (devConfig->getAGCMode()) {
setAGCMode(true);
} else {
setAGCMode(false);
}
t_SDR = new std::thread(&SDRThread::threadMain, sdrThread); t_SDR = new std::thread(&SDRThread::threadMain, sdrThread);
} }
@ -859,11 +873,8 @@ void CubicSDR::saveConfig() {
void CubicSDR::setPPM(int ppm_in) { void CubicSDR::setPPM(int ppm_in) {
ppm = ppm_in; ppm = ppm_in;
sdrThread->setPPM(ppm); if (sdrThread && !sdrThread->isTerminated()) {
sdrThread->setPPM(ppm);
SDRDeviceInfo *dev = getDevice();
if (dev) {
config.getDevice(dev->getDeviceId())->setPPM(ppm_in);
} }
} }
@ -975,7 +986,10 @@ bool CubicSDR::isDeviceSelectorOpen() {
void CubicSDR::setAGCMode(bool mode) { void CubicSDR::setAGCMode(bool mode) {
agcMode.store(mode); agcMode.store(mode);
sdrThread->setAGCMode(mode);
if (sdrThread && !sdrThread->isTerminated()) {
sdrThread->setAGCMode(mode);
}
} }
bool CubicSDR::getAGCMode() { bool CubicSDR::getAGCMode() {

View File

@ -91,6 +91,9 @@ public:
void setOffset(long long ofs); void setOffset(long long ofs);
long long getOffset(); long long getOffset();
void setAntennaName(const std::string& name);
const std::string& getAntennaName();
void setDBOffset(int ofs); void setDBOffset(int ofs);
int getDBOffset(); int getDBOffset();
@ -98,6 +101,7 @@ public:
void setSampleRate(long long rate_in); void setSampleRate(long long rate_in);
long long getSampleRate(); long long getSampleRate();
std::vector<SDRDeviceInfo *> *getDevices(); std::vector<SDRDeviceInfo *> *getDevices();
void setDevice(SDRDeviceInfo *dev, int waitMsForTermination); void setDevice(SDRDeviceInfo *dev, int waitMsForTermination);
void stopDevice(bool store, int waitMsForTermination); void stopDevice(bool store, int waitMsForTermination);
@ -189,6 +193,7 @@ private:
std::atomic_llong offset; std::atomic_llong offset;
std::atomic_int ppm, snap; std::atomic_int ppm, snap;
std::atomic_llong sampleRate; std::atomic_llong sampleRate;
std::string antennaName;
std::atomic_bool agcMode; std::atomic_bool agcMode;
SDRThread *sdrThread = nullptr; SDRThread *sdrThread = nullptr;

View File

@ -8,6 +8,8 @@
#include "CubicSDR.h" #include "CubicSDR.h"
#include <algorithm>
#ifdef __linux__ #ifdef __linux__
#include "CubicSDR.xpm" #include "CubicSDR.xpm"
#endif #endif
@ -110,6 +112,7 @@ wxPGProperty *SDRDevicesDialog::addArgInfoProperty(wxPropertyGrid *pg, SoapySDR:
} }
void SDRDevicesDialog::refreshDeviceProperties() { void SDRDevicesDialog::refreshDeviceProperties() {
SDRDeviceInfo *selDev = getSelectedDevice(devTree->GetSelection()); SDRDeviceInfo *selDev = getSelectedDevice(devTree->GetSelection());
if (selDev && selDev->isAvailable()) { if (selDev && selDev->isAvailable()) {
dev = selDev; dev = selDev;
@ -120,13 +123,68 @@ void SDRDevicesDialog::refreshDeviceProperties() {
SoapySDR::Device *soapyDev = dev->getSoapyDevice(); SoapySDR::Device *soapyDev = dev->getSoapyDevice();
SoapySDR::ArgInfoList args = soapyDev->getSettingInfo(); SoapySDR::ArgInfoList args = soapyDev->getSettingInfo();
//A) General settings: name, offset, sample rate, agc, antennas (if > 1)
m_propertyGrid->Append(new wxPropertyCategory("General Settings")); m_propertyGrid->Append(new wxPropertyCategory("General Settings"));
devSettings.clear(); devSettings.clear();
//A-1) Name
devSettings["name"] = m_propertyGrid->Append( new wxStringProperty("Name", wxPG_LABEL, devConfig->getDeviceName()) ); devSettings["name"] = m_propertyGrid->Append( new wxStringProperty("Name", wxPG_LABEL, devConfig->getDeviceName()) );
//A-2) Offset
devSettings["offset"] = m_propertyGrid->Append( new wxIntProperty("Offset (Hz)", wxPG_LABEL, devConfig->getOffset()) ); devSettings["offset"] = m_propertyGrid->Append( new wxIntProperty("Offset (Hz)", wxPG_LABEL, devConfig->getOffset()) );
//A-3) ppm
devSettings["ppm"] = m_propertyGrid->Append(new wxIntProperty("Frequency Correction (ppm)", wxPG_LABEL, devConfig->getPPM()));
//A-4) AGC control
SoapySDR::ArgInfo agcArg;
agcArg.type = SoapySDR::ArgInfo::BOOL;
agcArg.units = "";
agcArg.name = "Automatic Gain";
agcArg.key = "agc_mode";
agcArg.value = devConfig->getAGCMode()?"true":"false"; //must be lowercase for addArgInfoProperty
devSettings["agc_mode"] = addArgInfoProperty(m_propertyGrid, agcArg);
//A-5) Antennas, is there are more than 1 RX antenna, else do not expose the setting.
//get the saved setting
const std::string& currentSetAntenna = wxGetApp().getAntennaName();
//compare to the list of existing antennas
SoapySDR::ArgInfo antennasArg;
std::vector<std::string> antennaOpts = selDev->getAntennaNames(SOAPY_SDR_RX, 0);
//only do something if there is more than 1 antenna
if (antennaOpts.size() > 1) {
//by default, choose the first of the list.
std::string antennaToSelect = antennaOpts.front();
auto found_i = std::find(antennaOpts.begin(), antennaOpts.end(), currentSetAntenna);
if (found_i != antennaOpts.end()) {
antennaToSelect = currentSetAntenna;
}
//build device settings
for (std::string antenna : antennaOpts) {
antennasArg.options.push_back(antenna);
antennasArg.optionNames.push_back(antenna);
}
antennasArg.type = SoapySDR::ArgInfo::STRING;
antennasArg.units = "";
antennasArg.name = "Antenna";
antennasArg.key = "antenna";
antennasArg.value = antennaToSelect;
devSettings["antenna"] = addArgInfoProperty(m_propertyGrid, antennasArg);
deviceArgs["antenna"] = antennasArg;
} //end if more than 1 antenna
//A-6) Sample_rate:
long currentSampleRate = wxGetApp().getSampleRate(); long currentSampleRate = wxGetApp().getSampleRate();
long deviceSampleRate = devConfig->getSampleRate(); long deviceSampleRate = devConfig->getSampleRate();
@ -150,11 +208,14 @@ void SDRDevicesDialog::refreshDeviceProperties() {
devSettings["sample_rate"] = addArgInfoProperty(m_propertyGrid, sampleRateArg); devSettings["sample_rate"] = addArgInfoProperty(m_propertyGrid, sampleRateArg);
deviceArgs["sample_rate"] = sampleRateArg; deviceArgs["sample_rate"] = sampleRateArg;
//B) Runtime Settings:
runtimeArgs.clear(); runtimeArgs.clear();
runtimeProps.clear(); runtimeProps.clear();
streamProps.clear(); streamProps.clear();
if (args.size()) { if (args.size()) {
m_propertyGrid->Append(new wxPropertyCategory("Run-time Settings")); m_propertyGrid->Append(new wxPropertyCategory("Run-time Settings"));
@ -439,6 +500,7 @@ void SDRDevicesDialog::OnRefreshDevices( wxMouseEvent& /* event */) {
} }
void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) { void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
if (editId && event.GetProperty() == devSettings["name"]) { if (editId && event.GetProperty() == devSettings["name"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId()); DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
@ -457,7 +519,36 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
long offset = event.GetPropertyValue().GetInteger(); long offset = event.GetPropertyValue().GetInteger();
devConfig->setOffset(offset); devConfig->setOffset(offset);
if (dev->isActive() || !wxGetApp().getDevice()) {
wxGetApp().setOffset(offset);
}
} else if (dev && event.GetProperty() == devSettings["ppm"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
int ppm = event.GetPropertyValue().GetInteger();
devConfig->setPPM(ppm);
if (dev->isActive() || !wxGetApp().getDevice()) {
wxGetApp().setPPM(ppm);
}
}
else if (dev && event.GetProperty() == devSettings["agc_mode"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
bool agcMode = event.GetPropertyValue().GetBool();
devConfig->setAGCMode(agcMode);
if (dev->isActive() || !wxGetApp().getDevice()) {
wxGetApp().setAGCMode(agcMode);
}
} else if (dev && event.GetProperty() == devSettings["sample_rate"]) { } else if (dev && event.GetProperty() == devSettings["sample_rate"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId()); DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
std::string strRate = deviceArgs["sample_rate"].options[event.GetPropertyValue().GetInteger()]; std::string strRate = deviceArgs["sample_rate"].options[event.GetPropertyValue().GetInteger()];
@ -465,15 +556,29 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
try { try {
srate = std::stol(strRate); srate = std::stol(strRate);
devConfig->setSampleRate(srate); devConfig->setSampleRate(srate);
if (dev->isActive() || !wxGetApp().getDevice()) {
if (dev->isActive() || !wxGetApp().getDevice()) {
wxGetApp().setSampleRate(srate); wxGetApp().setSampleRate(srate);
wxGetApp().notifyMainUIOfDeviceChange(); }
}
} catch (std::invalid_argument e) { } catch (std::invalid_argument e) {
// nop // nop
} }
} else if (editId && dev) { } else if (dev && event.GetProperty() == devSettings["antenna"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
std::string strAntennaName = deviceArgs["antenna"].options[event.GetPropertyValue().GetInteger()];
try {
devConfig->setAntennaName(strAntennaName);
if (dev->isActive() || !wxGetApp().getDevice()) {
wxGetApp().setAntennaName(strAntennaName);
}
}
catch (std::invalid_argument e) {
// nop
}
}
else if (editId && dev) {
wxPGProperty *prop = event.GetProperty(); wxPGProperty *prop = event.GetProperty();
//change value of RuntimeProps //change value of RuntimeProps
for (std::map<std::string, wxPGProperty *>::iterator rtp = runtimeProps.begin(); rtp != runtimeProps.end(); rtp++) { for (std::map<std::string, wxPGProperty *>::iterator rtp = runtimeProps.begin(); rtp != runtimeProps.end(); rtp++) {
@ -499,6 +604,8 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
} }
} }
} }
// general refresh.
wxGetApp().notifyMainUIOfDeviceChange();
} }
void SDRDevicesDialog::OnPropGridFocus( wxFocusEvent& /* event */) { void SDRDevicesDialog::OnPropGridFocus( wxFocusEvent& /* event */) {

View File

@ -190,6 +190,13 @@ std::vector<long> SDRDeviceInfo::getSampleRates(int direction, size_t channel) {
return result; return result;
} }
std::vector<std::string> SDRDeviceInfo::getAntennaNames(int direction, size_t channel) {
SoapySDR::Device *dev = getSoapyDevice();
return dev->listAntennas(direction, channel);
}
long SDRDeviceInfo::getSampleRateNear(int direction, size_t channel, long sampleRate_in) { long SDRDeviceInfo::getSampleRateNear(int direction, size_t channel, long sampleRate_in) {
std::vector<long> sampleRates = getSampleRates(direction, channel); std::vector<long> sampleRates = getSampleRates(direction, channel);
long returnRate = sampleRates[0]; long returnRate = sampleRates[0];

View File

@ -83,6 +83,8 @@ public:
bool hasCORR(int direction, size_t channel); bool hasCORR(int direction, size_t channel);
std::vector<long> getSampleRates(int direction, size_t channel); std::vector<long> getSampleRates(int direction, size_t channel);
std::vector<std::string> getAntennaNames(int direction, size_t channel);
long getSampleRateNear(int direction, size_t channel, long sampleRate_in); long getSampleRateNear(int direction, size_t channel, long sampleRate_in);

View File

@ -28,6 +28,7 @@ SDRThread::SDRThread() : IOThread(), buffers("SDRThreadBuffers") {
rate_changed.store(false); rate_changed.store(false);
freq_changed.store(false); freq_changed.store(false);
offset_changed.store(false); offset_changed.store(false);
antenna_changed.store(false);
ppm_changed .store(false); ppm_changed .store(false);
device_changed.store(false); device_changed.store(false);
@ -437,6 +438,13 @@ void SDRThread::updateSettings() {
if (!stream) { if (!stream) {
return; return;
} }
if (antenna_changed.load()) {
device->setAntenna(SOAPY_SDR_RX, 0, antennaName);
antenna_changed.store(false);
}
if (offset_changed.load()) { if (offset_changed.load()) {
if (!freq_changed.load()) { if (!freq_changed.load()) {
@ -524,7 +532,6 @@ void SDRThread::updateSettings() {
gain_value_changed.store(false); gain_value_changed.store(false);
} }
if (setting_value_changed.load()) { if (setting_value_changed.load()) {
std::lock_guard < std::mutex > lock(setting_busy); std::lock_guard < std::mutex > lock(setting_busy);
@ -652,6 +659,12 @@ void SDRThread::unlockFrequency() {
void SDRThread::setOffset(long long ofs) { void SDRThread::setOffset(long long ofs) {
offset.store(ofs); offset.store(ofs);
offset_changed.store(true); offset_changed.store(true);
DeviceConfig *devConfig = deviceConfig.load();
if (devConfig) {
devConfig->setOffset(ofs);
}
// std::cout << "Set offset: " << offset.load() << std::endl; // std::cout << "Set offset: " << offset.load() << std::endl;
} }
@ -659,6 +672,20 @@ long long SDRThread::getOffset() {
return offset.load(); return offset.load();
} }
void SDRThread::setAntenna(const std::string& name) {
antennaName = name;
antenna_changed.store(true);
DeviceConfig *devConfig = deviceConfig.load();
if (devConfig) {
devConfig->setAntennaName(antennaName);
}
}
std::string SDRThread::getAntenna() {
return antennaName;
}
void SDRThread::setSampleRate(long rate) { void SDRThread::setSampleRate(long rate) {
sampleRate.store(rate); sampleRate.store(rate);
rate_changed = true; rate_changed = true;
@ -675,6 +702,12 @@ long SDRThread::getSampleRate() {
void SDRThread::setPPM(int ppm) { void SDRThread::setPPM(int ppm) {
this->ppm.store(ppm); this->ppm.store(ppm);
ppm_changed.store(true); ppm_changed.store(true);
DeviceConfig *devConfig = deviceConfig.load();
if (devConfig) {
devConfig->setPPM(ppm);
}
// std::cout << "Set PPM: " << this->ppm.load() << std::endl; // std::cout << "Set PPM: " << this->ppm.load() << std::endl;
} }

View File

@ -76,6 +76,9 @@ public:
void setOffset(long long ofs); void setOffset(long long ofs);
long long getOffset(); long long getOffset();
void setAntenna(const std::string& name);
std::string getAntenna();
void setSampleRate(long rate); void setSampleRate(long rate);
long getSampleRate(); long getSampleRate();
@ -119,7 +122,8 @@ protected:
std::atomic_llong frequency, offset, lock_freq; std::atomic_llong frequency, offset, lock_freq;
std::atomic_int ppm, numElems, mtuElems, numChannels; std::atomic_int ppm, numElems, mtuElems, numChannels;
std::atomic_bool hasPPM, hasHardwareDC; std::atomic_bool hasPPM, hasHardwareDC;
std::atomic_bool agc_mode, rate_changed, freq_changed, offset_changed, std::string antennaName;
std::atomic_bool agc_mode, rate_changed, freq_changed, offset_changed, antenna_changed,
ppm_changed, device_changed, agc_mode_changed, gain_value_changed, setting_value_changed, frequency_locked, frequency_lock_init, iq_swap; ppm_changed, device_changed, agc_mode_changed, gain_value_changed, setting_value_changed, frequency_locked, frequency_lock_init, iq_swap;
std::mutex gain_busy; std::mutex gain_busy;

View File

@ -245,6 +245,7 @@ void TuningCanvas::StepTuner(ActiveState state, int exponent, bool up) {
} }
wxGetApp().setPPM(currentPPM); wxGetApp().setPPM(currentPPM);
wxGetApp().notifyMainUIOfDeviceChange();
} }
} }