Merge pull request #273 from cjcliffe/soapy_refresh

SoapySDR settings refresh support + SSB Optimize/Drift Fix
This commit is contained in:
Charles J. Cliffe 2016-02-03 21:32:29 -05:00
commit c489142c12
13 changed files with 248 additions and 479 deletions

View File

@ -556,7 +556,7 @@ void AppFrame::updateDeviceParams() {
// Build settings menu
wxMenu *newSettingsMenu = new wxMenu;
newSettingsMenu->Append(wxID_SET_FREQ_OFFSET, "Frequency Offset");
if (devInfo->getRxChannel()->hasCORR()) {
if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) {
newSettingsMenu->Append(wxID_SET_PPM, "Device PPM");
}
@ -566,10 +566,11 @@ void AppFrame::updateDeviceParams() {
SoapySDR::ArgInfoList::const_iterator args_i;
int i = 0;
settingArgs = devInfo->getSettingsArgInfo();
SoapySDR::Device *soapyDev = devInfo->getSoapyDevice();
settingArgs = soapyDev->getSettingInfo();
for (args_i = settingArgs.begin(); args_i != settingArgs.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
std::string currentVal = wxGetApp().getSDRThread()->readSetting(arg.key);
std::string currentVal = soapyDev->readSetting(arg.key);
if (arg.type == SoapySDR::ArgInfo::BOOL) {
wxMenuItem *item = newSettingsMenu->AppendCheckItem(wxID_SETTINGS_BASE+i, arg.name, arg.description);
item->Check(currentVal=="true");
@ -610,7 +611,7 @@ void AppFrame::updateDeviceParams() {
settingsMenu = newSettingsMenu;
// Build sample rate menu
sampleRates = devInfo->getRxChannel()->getSampleRates();
sampleRates = devInfo->getSampleRates(SOAPY_SDR_RX, 0);
sampleRateMenuItems.erase(sampleRateMenuItems.begin(),sampleRateMenuItems.end());
wxMenu *newSampleRateMenu = new wxMenu;
@ -637,7 +638,7 @@ void AppFrame::updateDeviceParams() {
if (!wxGetApp().getAGCMode()) {
gainSpacerItem->Show(true);
gainSizerItem->Show(true);
gainSizerItem->SetMinSize(devInfo->getRxChannel()->getGains().size()*50,0);
gainSizerItem->SetMinSize(devInfo->getSoapyDevice()->listGains(SOAPY_SDR_RX,0).size()*50,0);
demodTray->Layout();
gainCanvas->updateGainUI();
gainCanvas->Refresh();
@ -695,7 +696,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
wxGetApp().setAGCMode(false);
gainSpacerItem->Show(true);
gainSizerItem->Show(true);
gainSizerItem->SetMinSize(wxGetApp().getDevice()->getRxChannel()->getGains().size()*40,0);
gainSizerItem->SetMinSize(wxGetApp().getDevice()->getSoapyDevice()->listGains(SOAPY_SDR_RX, 0).size()*40,0);
demodTray->Layout();
gainCanvas->updateGainUI();
gainCanvas->Refresh();
@ -837,14 +838,14 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
break;
}
SDRDeviceChannel *chan = dev->getRxChannel();
std::vector<long> sampleRates = dev->getSampleRates(SOAPY_SDR_RX, 0);
rateLow = 2000000;
rateHigh = 30000000;
if (chan->getSampleRates().size()) {
rateLow = chan->getSampleRates()[0];
rateHigh = chan->getSampleRates()[chan->getSampleRates().size()-1];
if (sampleRates.size()) {
rateLow = sampleRates[0];
rateHigh = sampleRates[sampleRates.size()-1];
}
long bw = wxGetNumberFromUser("\n" + dev->getName() + "\n\n "
@ -1377,11 +1378,8 @@ bool AppFrame::loadSession(std::string fileName) {
SDRDeviceInfo *dev = wxGetApp().getSDRThread()->getDevice();
if (dev) {
SDRDeviceChannel *chan = dev->getRxChannel();
if (chan) {
// Try for a reasonable default sample rate.
sample_rate = chan->getSampleRateNear(sample_rate);
}
// Try for a reasonable default sample rate.
sample_rate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, sample_rate);
wxGetApp().setSampleRate(sample_rate);
deviceChanged.store(true);
} else {

View File

@ -526,45 +526,34 @@ void CubicSDR::setDevice(SDRDeviceInfo *dev) {
DeviceConfig *devConfig = config.getDevice(dev->getDeviceId());
SDRDeviceChannel *chan = dev->getRxChannel();
SoapySDR::Device *soapyDev = dev->getSoapyDevice();
if (chan) {
if (soapyDev) {
long long freqHigh, freqLow;
freqHigh = chan->getRFRange().getHigh();
freqLow = chan->getRFRange().getLow();
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 = chan->getSampleRateNear(DEFAULT_SAMPLE_RATE);
sampleRate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, DEFAULT_SAMPLE_RATE);
sampleRateInitialized.store(true);
} else {
sampleRate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, sampleRate);
}
int rateHigh, rateLow;
rateHigh = rateLow = sampleRate;
if (chan->getSampleRates().size()) {
rateLow = chan->getSampleRates()[0];
rateHigh = chan->getSampleRates()[chan->getSampleRates().size()-1];
}
if (sampleRate > rateHigh) {
sampleRate = rateHigh;
} else if (sampleRate < rateLow) {
sampleRate = rateLow;
}
if (frequency < sampleRate/2) {
frequency = sampleRate/2;
}
setFrequency(frequency);
setSampleRate(sampleRate);
setPPM(devConfig->getPPM());
setOffset(devConfig->getOffset());
t_SDR = new std::thread(&SDRThread::threadMain, sdrThread);
}
}

View File

@ -95,38 +95,41 @@ wxPGProperty *SDRDevicesDialog::addArgInfoProperty(wxPropertyGrid *pg, SoapySDR:
return prop;
}
void SDRDevicesDialog::OnSelectionChanged( wxTreeEvent& event ) {
void SDRDevicesDialog::refreshDeviceProperties() {
SDRDeviceInfo *selDev = getSelectedDevice(devTree->GetSelection());
if (selDev && selDev->isAvailable()) {
dev = selDev;
selId = devTree->GetSelection();
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getName());
m_propertyGrid->Clear();
SoapySDR::ArgInfoList args = dev->getSettingsArgInfo();
SoapySDR::Device *soapyDev = dev->getSoapyDevice();
SoapySDR::ArgInfoList args = soapyDev->getSettingInfo();
SoapySDR::ArgInfoList::const_iterator args_i;
m_propertyGrid->Append(new wxPropertyCategory("General Settings"));
devSettings.erase(devSettings.begin(),devSettings.end());
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()) );
props.erase(props.begin(), props.end());
runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
streamProps.erase(streamProps.begin(), streamProps.end());
if (args.size()) {
m_propertyGrid->Append(new wxPropertyCategory("Run-time Settings"));
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
props.push_back(addArgInfoProperty(m_propertyGrid, arg));
arg.value = soapyDev->readSetting(arg.key);
runtimeProps[arg.key] = addArgInfoProperty(m_propertyGrid, arg);
runtimeArgs[arg.key] = arg;
}
}
if (dev->getRxChannel()) {
args = dev->getRxChannel()->getStreamArgsInfo();
if (dev) {
args = dev->getSoapyDevice()->getStreamArgsInfo(SOAPY_SDR_RX, 0);
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
ConfigSettings devStreamOpts = devConfig->getStreamOpts();
@ -137,13 +140,13 @@ void SDRDevicesDialog::OnSelectionChanged( wxTreeEvent& event ) {
}
}
}
if (args.size()) {
m_propertyGrid->Append(new wxPropertyCategory("Stream Settings"));
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
props.push_back(addArgInfoProperty(m_propertyGrid, arg));
streamProps[arg.key] = addArgInfoProperty(m_propertyGrid, arg);
}
}
}
@ -159,7 +162,9 @@ void SDRDevicesDialog::OnSelectionChanged( wxTreeEvent& event ) {
} else if (selDev && !selDev->isAvailable() && selDev->isManual()) {
m_propertyGrid->Clear();
devSettings.erase(devSettings.begin(),devSettings.end());
props.erase(props.begin(), props.end());
runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
streamProps.erase(streamProps.begin(), streamProps.end());
removeId = devTree->GetSelection();
dev = nullptr;
selId = nullptr;
@ -170,6 +175,10 @@ void SDRDevicesDialog::OnSelectionChanged( wxTreeEvent& event ) {
m_addRemoteButton->SetLabel("Add");
removeId = nullptr;
}
}
void SDRDevicesDialog::OnSelectionChanged( wxTreeEvent& event ) {
refreshDeviceProperties();
event.Skip();
}
@ -181,7 +190,9 @@ void SDRDevicesDialog::OnAddRemote( wxMouseEvent& /* event */) {
SDREnumerator::removeManual(selDev->getDriver(),selDev->getManualParams());
m_propertyGrid->Clear();
devSettings.erase(devSettings.begin(),devSettings.end());
props.erase(props.begin(), props.end());
runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
streamProps.erase(streamProps.begin(), streamProps.end());
dev = nullptr;
selId = nullptr;
editId = nullptr;
@ -233,18 +244,17 @@ SDRDeviceInfo *SDRDevicesDialog::getSelectedDevice(wxTreeItemId selId) {
return NULL;
}
void SDRDevicesDialog::OnUseSelected( wxMouseEvent& /* event */) {
void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event) {
if (dev != NULL) {
int i = 0;
SoapySDR::ArgInfoList::const_iterator args_i;
SoapySDR::ArgInfoList args = dev->getSettingsArgInfo();
SoapySDR::ArgInfoList args = dev->getSoapyDevice()->getSettingInfo();
SoapySDR::Kwargs settingArgs;
SoapySDR::Kwargs streamArgs;
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
wxPGProperty *prop = props[i];
wxPGProperty *prop = runtimeProps[arg.key];
if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
settingArgs[arg.key] = arg.options[prop->GetChoiceSelection()];
@ -253,17 +263,15 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& /* event */) {
} else {
settingArgs[arg.key] = prop->GetValueAsString();
}
i++;
}
if (dev->getRxChannel()) {
args = dev->getRxChannel()->getStreamArgsInfo();
if (dev) {
args = dev->getSoapyDevice()->getStreamArgsInfo(SOAPY_SDR_RX, 0);
if (args.size()) {
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
wxPGProperty *prop = props[i];
wxPGProperty *prop = streamProps[arg.key];
if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
streamArgs[arg.key] = arg.options[prop->GetChoiceSelection()];
@ -272,8 +280,6 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& /* event */) {
} else {
streamArgs[arg.key] = prop->GetValueAsString();
}
i++;
}
}
}
@ -287,6 +293,7 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& /* event */) {
wxGetApp().setDevice(dev);
Close();
}
event.Skip();
}
void SDRDevicesDialog::OnTreeDoubleClick( wxMouseEvent& event ) {
@ -381,10 +388,6 @@ void SDRDevicesDialog::OnRefreshDevices( wxMouseEvent& /* event */) {
}
void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
if (!editId) {
return;
}
SDRDeviceInfo *dev = getSelectedDevice(editId);
if (editId && event.GetProperty() == devSettings["name"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
@ -397,13 +400,36 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
if (devName == "") {
event.GetProperty()->SetValueFromString(devConfig->getDeviceName());
}
}
if (dev && event.GetProperty() == devSettings["offset"]) {
} else if (dev && event.GetProperty() == devSettings["offset"]) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
long offset = event.GetPropertyValue().GetInteger();
devConfig->setOffset(offset);
} else if (editId && dev) {
wxPGProperty *prop = event.GetProperty();
for (std::map<std::string, wxPGProperty *>::iterator rtp = runtimeProps.begin(); rtp != runtimeProps.end(); rtp++) {
if (rtp->second == prop) {
SoapySDR::Device *soapyDev = dev->getSoapyDevice();
std::string settingValue = prop->GetValueAsString().ToStdString();
SoapySDR::ArgInfo arg = runtimeArgs[rtp->first];
if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
settingValue = arg.options[prop->GetChoiceSelection()];
} else if (arg.type == SoapySDR::ArgInfo::BOOL) {
settingValue = (prop->GetValueAsString()=="True")?"true":"false";
} else {
settingValue = prop->GetValueAsString();
}
soapyDev->writeSetting(rtp->first, settingValue);
if (dev->isActive()) {
wxGetApp().getSDRThread()->writeSetting(rtp->first, settingValue);
}
refreshDeviceProperties();
return;
}
}
}
}
@ -413,20 +439,22 @@ void SDRDevicesDialog::OnPropGridFocus( wxFocusEvent& /* event */) {
void SDRDevicesDialog::doRefreshDevices() {
selId = nullptr;
editId = nullptr;
removeId = nullptr;
dev = nullptr;
wxGetApp().stopDevice();
devTree->DeleteAllItems();
devTree->Disable();
m_propertyGrid->Clear();
props.erase(props.begin(),props.end());
runtimeArgs.erase(runtimeArgs.begin(), runtimeArgs.end());
runtimeProps.erase(runtimeProps.begin(), runtimeProps.end());
streamProps.erase(streamProps.begin(), streamProps.end());
devSettings.erase(devSettings.begin(), devSettings.end());
m_refreshButton->Disable();
m_addRemoteButton->Disable();
m_useSelectedButton->Disable();
wxGetApp().reEnumerateDevices();
selId = nullptr;
editId = nullptr;
removeId = nullptr;
dev = nullptr;
refresh = true;
m_addRemoteButton->SetLabel("Add");
}

View File

@ -24,6 +24,7 @@ public:
void OnPropGridFocus( wxFocusEvent& event );
private:
void refreshDeviceProperties();
void doRefreshDevices();
SDRDeviceInfo *getSelectedDevice(wxTreeItemId selId);
@ -35,7 +36,9 @@ private:
std::map<wxTreeItemId, SDRDeviceInfo *> devItems;
std::map<wxTreeItemId, SDRDeviceInfo *>::iterator devItems_i;
SDRDeviceInfo *dev;
std::vector<wxPGProperty *> props;
std::map<std::string, wxPGProperty *> runtimeProps;
std::map<std::string, SoapySDR::ArgInfo> runtimeArgs;
std::map<std::string, wxPGProperty *> streamProps;
std::map<std::string, wxPGProperty *> devSettings;
wxTreeItemId selId;
wxTreeItemId editId;

View File

@ -2,21 +2,11 @@
ModemLSB::ModemLSB() : ModemAnalog() {
// half band filter used for side-band elimination
demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1);
// options
float fc = 0.25f; // filter cutoff frequency
float ft = 0.05f; // filter transition
float As = 90.0f; // stop-band attenuation [dB]
float mu = 0.0f; // fractional timing offset
// estimate required filter length and generate filter
unsigned int h_len = estimate_req_filter_len(ft,As);
float *h = (float *) malloc(h_len * sizeof(float));
liquid_firdes_kaiser(h_len,fc,As,mu,h);
ssbFilt = firfilt_crcf_create(h,h_len);
// demodAM_LSB = ampmodem_create(0.25, 0.25, LIQUID_AMPMODEM_LSB, 1);
ssbFilt = iirfilt_crcf_create_lowpass(6, 0.25);
ssbShift = nco_crcf_create(LIQUID_NCO);
nco_crcf_set_frequency(ssbShift, (2.0 * M_PI) * 0.25);
free(h);
c2rFilt = firhilbf_create(5, 90.0);
}
Modem *ModemLSB::factory() {
@ -28,9 +18,10 @@ std::string ModemLSB::getName() {
}
ModemLSB::~ModemLSB() {
firfilt_crcf_destroy(ssbFilt);
iirfilt_crcf_destroy(ssbFilt);
nco_crcf_destroy(ssbShift);
ampmodem_destroy(demodAM_LSB);
firhilbf_destroy(c2rFilt);
// ampmodem_destroy(demodAM_LSB);
}
int ModemLSB::checkSampleRate(long long sampleRate, int /* audioSampleRate */) {
@ -61,10 +52,11 @@ void ModemLSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *a
for (int i = 0; i < bufSize; i++) { // Reject upper band
nco_crcf_step(ssbShift);
nco_crcf_mix_up(ssbShift, input->data[i], &x);
firfilt_crcf_push(ssbFilt, x);
firfilt_crcf_execute(ssbFilt, &x);
nco_crcf_mix_down(ssbShift, x, &y);
ampmodem_demodulate(demodAM_LSB, y, &demodOutputData[i]);
iirfilt_crcf_execute(ssbFilt, x, &y);
nco_crcf_mix_down(ssbShift, y, &x);
// Liquid-DSP AMPModem SSB drifts with strong signals near baseband (like a carrier?)
// ampmodem_demodulate(demodAM_LSB, y, &demodOutputData[i]);
firhilbf_c2r_execute(c2rFilt, x, &demodOutputData[i]);
}
buildAudioOutput(akit, audioOut, true);

View File

@ -16,7 +16,9 @@ public:
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
firfilt_crcf ssbFilt;
iirfilt_crcf ssbFilt;
firhilbf c2rFilt;
nco_crcf ssbShift;
ampmodem demodAM_LSB;
// firfilt_crcf ssbFilt;
// ampmodem demodAM_LSB;
};

View File

@ -2,21 +2,11 @@
ModemUSB::ModemUSB() : ModemAnalog() {
// half band filter used for side-band elimination
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
// options
float fc = 0.25f; // filter cutoff frequency
float ft = 0.05f; // filter transition
float As = 90.0f; // stop-band attenuation [dB]
float mu = 0.0f; // fractional timing offset
// estimate required filter length and generate filter
unsigned int h_len = estimate_req_filter_len(ft,As);
float *h = (float *) malloc(h_len * sizeof(float));
liquid_firdes_kaiser(h_len,fc,As,mu,h);
ssbFilt = firfilt_crcf_create(h,h_len);
// demodAM_USB = ampmodem_create(0.25, -0.25, LIQUID_AMPMODEM_USB, 1);
ssbFilt = iirfilt_crcf_create_lowpass(6, 0.25);
ssbShift = nco_crcf_create(LIQUID_NCO);
nco_crcf_set_frequency(ssbShift, (2.0 * M_PI) * 0.25);
free(h);
c2rFilt = firhilbf_create(5, 90.0);
}
Modem *ModemUSB::factory() {
@ -28,9 +18,10 @@ std::string ModemUSB::getName() {
}
ModemUSB::~ModemUSB() {
firfilt_crcf_destroy(ssbFilt);
iirfilt_crcf_destroy(ssbFilt);
nco_crcf_destroy(ssbShift);
ampmodem_destroy(demodAM_USB);
firhilbf_destroy(c2rFilt);
// ampmodem_destroy(demodAM_USB);
}
int ModemUSB::checkSampleRate(long long sampleRate, int /* audioSampleRate */) {
@ -61,10 +52,11 @@ void ModemUSB::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *a
for (int i = 0; i < bufSize; i++) { // Reject lower band
nco_crcf_step(ssbShift);
nco_crcf_mix_down(ssbShift, input->data[i], &x);
firfilt_crcf_push(ssbFilt, x);
firfilt_crcf_execute(ssbFilt, &x);
nco_crcf_mix_up(ssbShift, x, &y);
ampmodem_demodulate(demodAM_USB, y, &demodOutputData[i]);
iirfilt_crcf_execute(ssbFilt, x, &y);
nco_crcf_mix_up(ssbShift, y, &x);
// Liquid-DSP AMPModem SSB drifts with strong signals near baseband (like a carrier?)
// ampmodem_demodulate(demodAM_USB, y, &demodOutputData[i]);
firhilbf_c2r_execute(c2rFilt, x, &demodOutputData[i]);
}
buildAudioOutput(akit, audioOut, true);

View File

@ -16,7 +16,8 @@ public:
void demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut);
private:
firfilt_crcf ssbFilt;
iirfilt_crcf ssbFilt;
firhilbf c2rFilt;
nco_crcf ssbShift;
ampmodem demodAM_USB;
};

View File

@ -1,167 +1,14 @@
#include "SDRDeviceInfo.h"
#include <cstdlib>
SDRDeviceRange::SDRDeviceRange() {
low = 0;
high = 0;
SDRDeviceInfo::SDRDeviceInfo() : name(""), serial(""), available(false), remote(false), manual(false), active(false), soapyDevice(nullptr) {
}
SDRDeviceRange::SDRDeviceRange(double low, double high) {
this->low = low;
this->high = high;
}
SDRDeviceRange::SDRDeviceRange(std::string name, double low, double high) : SDRDeviceRange(low, high) {
this->name = name;
}
double SDRDeviceRange::getLow() {
return low;
}
void SDRDeviceRange::setLow(double low) {
this->low = low;
}
double SDRDeviceRange::getHigh() {
return high;
}
void SDRDeviceRange::setHigh(double high) {
this->high = high;
}
std::string SDRDeviceRange::getName() {
return this->name;
}
void SDRDeviceRange::setName(std::string name) {
this->name = name;
}
SDRDeviceChannel::SDRDeviceChannel() {
hardwareDC = false;
hasCorr = false;
}
SDRDeviceChannel::~SDRDeviceChannel() {
}
int SDRDeviceChannel::getChannel() {
return channel;
}
void SDRDeviceChannel::setChannel(int channel) {
this->channel = channel;
}
bool SDRDeviceChannel::isFullDuplex() {
return fullDuplex;
}
void SDRDeviceChannel::setFullDuplex(bool fullDuplex) {
this->fullDuplex = fullDuplex;
}
bool SDRDeviceChannel::isTx() {
return tx;
}
void SDRDeviceChannel::setTx(bool tx) {
this->tx = tx;
}
bool SDRDeviceChannel::isRx() {
return rx;
}
void SDRDeviceChannel::setRx(bool rx) {
this->rx = rx;
}
SDRDeviceRange &SDRDeviceChannel::getGain() {
return rangeGain;
}
SDRDeviceRange &SDRDeviceChannel::getLNAGain() {
return rangeLNA;
}
SDRDeviceRange &SDRDeviceChannel::getFreqRange() {
return rangeFull;
}
SDRDeviceRange &SDRDeviceChannel::getRFRange() {
return rangeRF;
}
void SDRDeviceChannel::addGain(SDRDeviceRange range) {
gainInfo.push_back(range);
}
std::vector<SDRDeviceRange> &SDRDeviceChannel::getGains() {
return gainInfo;
}
void SDRDeviceChannel::addGain(std::string name, SoapySDR::Range range) {
gainInfo.push_back(SDRDeviceRange(name,range.minimum(),range.maximum()));
}
std::vector<long> &SDRDeviceChannel::getSampleRates() {
return sampleRates;
}
long SDRDeviceChannel::getSampleRateNear(long sampleRate_in) {
long returnRate = sampleRates[0];
long sDelta = (long)sampleRate_in-sampleRates[0];
long minDelta = std::abs(sDelta);
for (std::vector<long>::iterator i = sampleRates.begin(); i != sampleRates.end(); i++) {
long thisDelta = std::abs(sampleRate_in - (*i));
if (thisDelta < minDelta) {
minDelta = thisDelta;
returnRate = (*i);
}
SDRDeviceInfo::~SDRDeviceInfo() {
if (soapyDevice != nullptr) {
SoapySDR::Device::unmake(soapyDevice);
}
return returnRate;
}
std::vector<long long> &SDRDeviceChannel::getFilterBandwidths() {
return filterBandwidths;
}
const bool& SDRDeviceChannel::hasHardwareDC() const {
return hardwareDC;
}
void SDRDeviceChannel::setHardwareDC(const bool& hardware) {
hardwareDC = hardware;
}
const bool& SDRDeviceChannel::hasCORR() const {
return hasCorr;
}
void SDRDeviceChannel::setCORR(const bool& hasCorr) {
this->hasCorr = hasCorr;
}
void SDRDeviceChannel::setStreamArgsInfo(SoapySDR::ArgInfoList streamArgs) {
streamArgInfo = streamArgs;
}
SoapySDR::ArgInfoList SDRDeviceChannel::getStreamArgsInfo() {
return streamArgInfo;
}
std::vector<std::string> SDRDeviceChannel::getStreamArgNames() {
std::vector<std::string> names;
for (SoapySDR::ArgInfoList::const_iterator i = streamArgInfo.begin(); i != streamArgInfo.end(); i++) {
names.push_back((*i).key);
}
return names;
}
SDRDeviceInfo::SDRDeviceInfo() : name(""), serial(""), available(false), remote(false), manual(false) {
}
std::string SDRDeviceInfo::getDeviceId() {
@ -190,6 +37,14 @@ void SDRDeviceInfo::setAvailable(bool available) {
this->available = available;
}
bool SDRDeviceInfo::isActive() const {
return active.load();
}
void SDRDeviceInfo::setActive(bool active) {
this->active.store(active);
}
const std::string& SDRDeviceInfo::getName() const {
return name;
}
@ -294,48 +149,66 @@ SoapySDR::Kwargs SDRDeviceInfo::getStreamArgs() {
return streamArgs;
}
void SDRDeviceInfo::setSettingsInfo(SoapySDR::ArgInfoList settingsArgs) {
settingInfo = settingsArgs;
}
SoapySDR::ArgInfoList SDRDeviceInfo::getSettingsArgInfo() {
return settingInfo;
}
std::vector<std::string> SDRDeviceInfo::getSettingNames() {
std::vector<std::string> names;
for (SoapySDR::ArgInfoList::const_iterator i = settingInfo.begin(); i != settingInfo.end(); i++) {
names.push_back((*i).key);
void SDRDeviceInfo::setSoapyDevice(SoapySDR::Device *dev) {
if (soapyDevice) {
SoapySDR::Device::unmake(soapyDevice);
}
return names;
soapyDevice = dev;
}
void SDRDeviceInfo::addChannel(SDRDeviceChannel *chan) {
channels.push_back(chan);
SoapySDR::Device *SDRDeviceInfo::getSoapyDevice() {
if (soapyDevice == nullptr) {
soapyDevice = SoapySDR::Device::make(deviceArgs);
}
return soapyDevice;
}
std::vector<SDRDeviceChannel *> &SDRDeviceInfo::getChannels() {
return channels;
bool SDRDeviceInfo::hasCORR(int direction, size_t channel) {
SoapySDR::Device *dev = getSoapyDevice();
std::vector<std::string> freqs = dev->listFrequencies(direction, channel);
if (std::find(freqs.begin(), freqs.end(), "CORR") != freqs.end()) {
return true;
} else {
return false;
}
}
SDRDeviceChannel * SDRDeviceInfo::getRxChannel() {
std::vector<SDRDeviceChannel *>::iterator channel_i;
for (channel_i = channels.begin(); channel_i != channels.end(); channel_i++) {
if ((*channel_i)->isRx()) {
return (*channel_i);
std::vector<long> SDRDeviceInfo::getSampleRates(int direction, size_t channel) {
SoapySDR::Device *dev = getSoapyDevice();
std::vector<long> result;
std::vector<double> sampleRates = dev->listSampleRates(direction, channel);
for (std::vector<double>::iterator si = sampleRates.begin(); si != sampleRates.end(); si++) {
result.push_back((long)(*si));
}
return result;
}
long SDRDeviceInfo::getSampleRateNear(int direction, size_t channel, long sampleRate_in) {
std::vector<long> sampleRates = getSampleRates(direction, channel);
long returnRate = sampleRates[0];
long sDelta = (long)sampleRate_in-sampleRates[0];
long minDelta = std::abs(sDelta);
for (std::vector<long>::iterator i = sampleRates.begin(); i != sampleRates.end(); i++) {
long thisDelta = std::abs(sampleRate_in - (*i));
if (thisDelta < minDelta) {
minDelta = thisDelta;
returnRate = (*i);
}
}
return NULL;
return returnRate;
}
SDRDeviceChannel * SDRDeviceInfo::getTxChannel() {
std::vector<SDRDeviceChannel *>::iterator channel_i;
for (channel_i = channels.begin(); channel_i != channels.end(); channel_i++) {
if ((*channel_i)->isTx()) {
return (*channel_i);
}
SDRRangeMap SDRDeviceInfo::getGains(int direction, size_t channel) {
SoapySDR::Device *dev = getSoapyDevice();
std::vector<std::string> gainNames = dev->listGains(direction, channel);
std::map<std::string, SoapySDR::Range> gainMap;
for (std::vector<std::string>::iterator gname = gainNames.begin(); gname!= gainNames.end(); gname++) {
gainMap[(*gname)] = dev->getGainRange(direction, channel, (*gname));
}
return NULL;
return gainMap;
}

View File

@ -4,84 +4,19 @@
#include <vector>
#include <SoapySDR/Types.hpp>
#include <SoapySDR/Device.hpp>
typedef struct _SDRManualDef {
std::string factory;
std::string params;
} SDRManualDef;
class SDRDeviceRange {
public:
SDRDeviceRange();
SDRDeviceRange(double low, double high);
SDRDeviceRange(std::string name, double low, double high);
double getLow();
void setLow(double low);
double getHigh();
void setHigh(double high);
std::string getName();
void setName(std::string name);
private:
std::string name;
double low, high;
};
class SDRDeviceChannel {
public:
SDRDeviceChannel();
~SDRDeviceChannel();
int getChannel();
void setChannel(int channel);
bool isFullDuplex();
void setFullDuplex(bool fullDuplex);
bool isTx();
void setTx(bool tx);
bool isRx();
void setRx(bool rx);
void addGain(SDRDeviceRange range);
void addGain(std::string name, SoapySDR::Range range);
std::vector<SDRDeviceRange> &getGains();
SDRDeviceRange &getGain();
SDRDeviceRange &getLNAGain();
SDRDeviceRange &getFreqRange();
SDRDeviceRange &getRFRange();
std::vector<long> &getSampleRates();
long getSampleRateNear(long sampleRate_in);
std::vector<long long> &getFilterBandwidths();
const bool& hasHardwareDC() const;
void setHardwareDC(const bool& hardware);
const bool& hasCORR() const;
void setCORR(const bool& corr);
void setStreamArgsInfo(SoapySDR::ArgInfoList streamArgs);
SoapySDR::ArgInfoList getStreamArgsInfo();
std::vector<std::string> getStreamArgNames();
private:
int channel;
bool fullDuplex, tx, rx, hardwareDC, hasCorr;
SDRDeviceRange rangeGain, rangeLNA, rangeFull, rangeRF;
std::vector<long> sampleRates;
std::vector<long long> filterBandwidths;
SoapySDR::ArgInfoList streamArgInfo;
std::vector<SDRDeviceRange> gainInfo;
};
typedef std::map<std::string, SoapySDR::Range> SDRRangeMap;
class SDRDeviceInfo {
public:
SDRDeviceInfo();
~SDRDeviceInfo();
std::string getDeviceId();
@ -90,7 +25,10 @@ public:
bool isAvailable() const;
void setAvailable(bool available);
bool isActive() const;
void setActive(bool active);
const std::string& getName() const;
void setName(const std::string& name);
@ -123,11 +61,6 @@ public:
void setManualParams(std::string manualParams);
std::string getManualParams();
void addChannel(SDRDeviceChannel *chan);
std::vector<SDRDeviceChannel *> &getChannels();
SDRDeviceChannel * getRxChannel();
SDRDeviceChannel * getTxChannel();
void setDeviceArgs(SoapySDR::Kwargs deviceArgs);
SoapySDR::Kwargs getDeviceArgs();
@ -135,18 +68,29 @@ public:
void setStreamArgs(SoapySDR::Kwargs deviceArgs);
SoapySDR::Kwargs getStreamArgs();
void setSettingsInfo(SoapySDR::ArgInfoList settingsArgs);
SoapySDR::ArgInfoList getSettingsArgInfo();
// void setSettingsInfo(SoapySDR::ArgInfoList settingsArgs);
// SoapySDR::ArgInfoList getSettingsArgInfo();
std::vector<std::string> getSettingNames();
// std::vector<std::string> getSettingNames();
void setSoapyDevice(SoapySDR::Device *dev);
SoapySDR::Device *getSoapyDevice();
bool hasCORR(int direction, size_t channel);
std::vector<long> getSampleRates(int direction, size_t channel);
long getSampleRateNear(int direction, size_t channel, long sampleRate_in);
SDRRangeMap getGains(int direction, size_t channel);
private:
int index;
std::string name, serial, product, manufacturer, tuner;
std::string driver, hardware, manual_params;
bool timestamps, available, remote, manual;
std::atomic_bool active;
SoapySDR::Kwargs deviceArgs, streamArgs;
SoapySDR::ArgInfoList settingInfo;
std::vector<SDRDeviceChannel *> channels;
SoapySDR::Device *soapyDevice;
};

View File

@ -273,67 +273,8 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
}
dev->setDeviceArgs(deviceArgs);
dev->setSettingsInfo(settingsInfo);
int numChan = device->getNumChannels(SOAPY_SDR_RX);
for (int i = 0; i < numChan; i++) {
SDRDeviceChannel *chan = new SDRDeviceChannel();
SoapySDR::RangeList rfRange = device->getFrequencyRange(SOAPY_SDR_RX, i);
double rfMin = rfRange[0].minimum();
double rfMax = rfRange[rfRange.size()-1].maximum();
chan->setChannel(i);
chan->setFullDuplex(device->getFullDuplex(SOAPY_SDR_RX, i));
chan->setRx(true);
chan->setTx(false);
chan->getRFRange().setLow(rfMin);
chan->getRFRange().setHigh(rfMax);
std::vector<std::string> freqs = device->listFrequencies(SOAPY_SDR_RX,i);
if (std::find(freqs.begin(), freqs.end(), "CORR") != freqs.end()) {
chan->setCORR(true);
} else {
chan->setCORR(false);
}
if (device->hasDCOffsetMode(SOAPY_SDR_RX, i)) {
chan->setHardwareDC(true);
} else {
chan->setHardwareDC(false);
}
std::vector<double> rates = device->listSampleRates(SOAPY_SDR_RX, i);
for (std::vector<double>::iterator i = rates.begin(); i != rates.end(); i++) {
chan->getSampleRates().push_back((long)(*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);
for (std::vector<std::string>::iterator gname = gainNames.begin(); gname!= gainNames.end(); gname++) {
chan->addGain((*gname),device->getGainRange(SOAPY_SDR_RX, i, (*gname)));
}
dev->addChannel(chan);
}
SoapySDR::Device::unmake(device);
dev->setAvailable(true);
} catch (const std::exception &ex) {
std::cerr << "Error making device: " << ex.what() << std::endl;
@ -449,6 +390,12 @@ void SDREnumerator::reset() {
soapy_initialized = false;
factories.erase(factories.begin(), factories.end());
modules.erase(modules.begin(), modules.end());
for (std::map< std::string, std::vector<SDRDeviceInfo *> >::iterator di = devs.begin(); di != devs.end(); di++) {
for (std::vector<SDRDeviceInfo *>::iterator i = di->second.begin(); i != di->second.end(); i++) {
(*i)->setSoapyDevice(nullptr);
}
}
devs.erase(devs.begin(), devs.end());
}

View File

@ -73,7 +73,7 @@ void SDRThread::init() {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Initializing device."));
device = SoapySDR::Device::make(args);
device = devInfo->getSoapyDevice();
SoapySDR::Kwargs currentStreamArgs = combineArgs(devInfo->getStreamArgs(),streamArgs);
stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector<size_t>(), currentStreamArgs);
@ -90,17 +90,16 @@ void SDRThread::init() {
device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load());
device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency - offset.load());
device->activateStream(stream);
SDRDeviceChannel *chan = devInfo->getRxChannel();
if (chan->hasCORR()) {
if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) {
hasPPM.store(true);
device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load());
} else {
hasPPM.store(false);
}
if (chan->hasHardwareDC()) {
if (device->hasDCOffsetMode(SOAPY_SDR_RX, 0)) {
hasHardwareDC.store(true);
// wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Found hardware DC offset correction support, internal disabled."));
device->setDCOffsetMode(SOAPY_SDR_RX, chan->getChannel(), true);
device->setDCOffsetMode(SOAPY_SDR_RX, 0, true);
} else {
hasHardwareDC.store(false);
}
@ -138,26 +137,17 @@ void SDRThread::init() {
}
}
setting_value_changed.store(false);
SoapySDR::ArgInfoList devSettings = deviceInfo.load()->getSettingsArgInfo();
if (devSettings.size()) {
for (size_t 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();
updateSettings();
wxGetApp().sdrThreadNotify(SDRThread::SDR_THREAD_INITIALIZED, std::string("Device Initialized."));
}
void SDRThread::deinit() {
device->deactivateStream(stream);
device->closeStream(stream);
SoapySDR::Device::unmake(device);
free(buffs[0]);
}
@ -247,16 +237,18 @@ void SDRThread::updateGains() {
gainValues.erase(gainValues.begin(),gainValues.end());
gainChanged.erase(gainChanged.begin(),gainChanged.end());
std::vector<SDRDeviceRange> gains = devInfo->getRxChannel()->getGains();
for (std::vector<SDRDeviceRange>::iterator gi = gains.begin(); gi != gains.end(); gi++) {
gainValues[(*gi).getName()] = device->getGain(SOAPY_SDR_RX, devInfo->getRxChannel()->getChannel(), (*gi).getName());
gainChanged[(*gi).getName()] = false;
SDRRangeMap gains = devInfo->getGains(SOAPY_SDR_RX, 0);
for (SDRRangeMap::iterator gi = gains.begin(); gi != gains.end(); gi++) {
gainValues[gi->first] = device->getGain(SOAPY_SDR_RX, 0, gi->first);
gainChanged[gi->first] = false;
}
gain_value_changed.store(false);
}
void SDRThread::updateSettings() {
bool doUpdate = false;
if (offset_changed.load()) {
if (!freq_changed.load()) {
frequency.store(frequency.load());
@ -281,6 +273,7 @@ void SDRThread::updateSettings() {
buffs[0] = malloc(mtuElems.load() * 4 * sizeof(float));
numOverflow = 0;
rate_changed.store(false);
doUpdate = true;
}
if (ppm_changed.load() && hasPPM.load()) {
@ -304,22 +297,19 @@ void SDRThread::updateSettings() {
// }
if (agc_mode_changed.load()) {
SDRDeviceInfo *devInfo = deviceInfo.load();
device->setGainMode(SOAPY_SDR_RX,devInfo->getRxChannel()->getChannel(),agc_mode.load());
device->setGainMode(SOAPY_SDR_RX, 0, agc_mode.load());
agc_mode_changed.store(false);
if (!agc_mode.load()) {
updateGains();
}
doUpdate = true;
}
if (gain_value_changed.load() && !agc_mode.load()) {
SDRDeviceInfo *devInfo = deviceInfo.load();
gain_busy.lock();
for (std::map<std::string,bool>::iterator gci = gainChanged.begin(); gci != gainChanged.end(); gci++) {
if (gci->second) {
device->setGain(SOAPY_SDR_RX, devInfo->getRxChannel()->getChannel(), gci->first, gainValues[gci->first]);
device->setGain(SOAPY_SDR_RX, 0, gci->first, gainValues[gci->first]);
gainChanged[gci->first] = false;
}
}
@ -341,6 +331,12 @@ void SDRThread::updateSettings() {
setting_value_changed.store(false);
setting_busy.unlock();
doUpdate = true;
}
if (doUpdate) {
wxGetApp().sdrThreadNotify(SDRThread::SDR_THREAD_INITIALIZED, std::string("Settings updated."));
}
}
@ -355,11 +351,15 @@ void SDRThread::run() {
std::cout << "SDR thread starting." << std::endl;
terminated.store(false);
if (deviceInfo.load() != NULL) {
SDRDeviceInfo *activeDev = deviceInfo.load();
if (activeDev != NULL) {
std::cout << "device init()" << std::endl;
init();
std::cout << "starting readLoop()" << std::endl;
activeDev->setActive(true);
readLoop();
activeDev->setActive(false);
std::cout << "readLoop() ended." << std::endl;
deinit();
std::cout << "device deinit()" << std::endl;

View File

@ -184,8 +184,8 @@ void GainCanvas::updateGainUI() {
SDRDeviceInfo *devInfo = wxGetApp().getDevice();
std::vector<SDRDeviceRange> &gains = devInfo->getRxChannel()->getGains();
std::vector<SDRDeviceRange>::iterator gi;
SDRRangeMap gains = devInfo->getGains(SOAPY_SDR_RX, 0);
SDRRangeMap::iterator gi;
numGains = gains.size();
float i = 0;
@ -217,9 +217,9 @@ void GainCanvas::updateGainUI() {
GainInfo *gInfo = new GainInfo;
float midPos = -1.0+startPos+spacing*i;
gInfo->name = (*gi).getName();
gInfo->low = (*gi).getLow();
gInfo->high = (*gi).getHigh();
gInfo->name = gi->first;
gInfo->low = gi->second.minimum();
gInfo->high = gi->second.maximum();
gInfo->current = wxGetApp().getGain(gInfo->name);
gInfo->panel.setBorderPx(1);
@ -251,7 +251,7 @@ void GainCanvas::updateGainUI() {
gInfo->labelPanel.setSize(spacing/2.0,(15.0/float(ClientSize.y)));
gInfo->labelPanel.setPosition(midPos, -barHeight-(20.0/float(ClientSize.y)));
gInfo->labelPanel.setText((*gi).getName());
gInfo->labelPanel.setText(gi->first);
gInfo->labelPanel.setFill(GLPanel::GLPANEL_FILL_NONE);
bgPanel.addChild(&(gInfo->labelPanel));