From cefca72c53f80dd483ac53a405b9e8870c1da10e Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Sun, 3 Nov 2019 16:22:04 -0500 Subject: [PATCH 1/3] Override setGain and getGainRange to avoid changing RFGR. SDRPlay's "RFGR" is actually a mode selector for the front-end LNA. It does *not* have units of dB. (In fact, it is frequency-dependent.) As a result, the default gain allocation algorithm does not apply and only IFGR should be used for adjusting the overall system gain. --- Settings.cpp | 18 ++++++++++++++++++ SoapySDRPlay.hpp | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/Settings.cpp b/Settings.cpp index 8f6d5c6..0f929d1 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -653,6 +653,12 @@ void SoapySDRPlay::setGain(const int direction, const size_t channel, const std: } } +void SoapySDRPlay::setGain(const int direction, const size_t channel, const double value) +{ + // Only IFGR should be used for adjusting the overall system gain. + this->setGain(direction, channel, "IFGR", value); +} + double SoapySDRPlay::getGain(const int direction, const size_t channel, const std::string &name) const { std::lock_guard lock(_general_state_mutex); @@ -669,6 +675,12 @@ double SoapySDRPlay::getGain(const int direction, const size_t channel, const st return 0; } +double SoapySDRPlay::getGain(const int direction, const size_t channel) const +{ + // Only IFGR should be used for adjusting the overall system gain. + return this->getGain(direction, channel, "IFGR"); +} + SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t channel, const std::string &name) const { if (name == "IFGR") @@ -698,6 +710,12 @@ SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t cha return SoapySDR::Range(20, 59); } +SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t channel) const +{ + // Only IFGR should be used for adjusting the overall system gain. + return this->getGainRange(direction, channel, "IFGR"); +} + /******************************************************************* * Frequency API ******************************************************************/ diff --git a/SoapySDRPlay.hpp b/SoapySDRPlay.hpp index 086e73e..5009356 100644 --- a/SoapySDRPlay.hpp +++ b/SoapySDRPlay.hpp @@ -146,10 +146,16 @@ class SoapySDRPlay: public SoapySDR::Device void setGain(const int direction, const size_t channel, const std::string &name, const double value); + void setGain(const int direction, const size_t channel, const double value); + double getGain(const int direction, const size_t channel, const std::string &name) const; + double getGain(const int direction, const size_t channel) const; + SoapySDR::Range getGainRange(const int direction, const size_t channel, const std::string &name) const; + SoapySDR::Range getGainRange(const int direction, const size_t channel) const; + /******************************************************************* * Frequency API ******************************************************************/ From cb350d848a57057a06d5fc8b3632cfd7044b8746 Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Mon, 4 Nov 2019 18:43:48 -0500 Subject: [PATCH 2/3] Rename IFGR to IF gain, and negate it. SoapySDR gains are expected to be positive for increased amplification. The cleanest way to handle this is to treat the SDRPlay gain reduction value as the negative of the SoapySDR IF gain. --- Settings.cpp | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/Settings.cpp b/Settings.cpp index 0f929d1..c3bbc86 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -591,7 +591,7 @@ std::vector SoapySDRPlay::listGains(const int direction, const size //the functions below have a "name" parameter std::vector results; - results.push_back("IFGR"); + results.push_back("IF"); results.push_back("RFGR"); return results; @@ -630,12 +630,15 @@ void SoapySDRPlay::setGain(const int direction, const size_t channel, const std: bool doUpdate = false; - if (name == "IFGR" && chParams->ctrlParams.agc.enable == sdrplay_api_AGC_DISABLE) + if (name == "IF" && chParams->ctrlParams.agc.enable == sdrplay_api_AGC_DISABLE) { - //apply the change if the required value is different from gRdB - if (chParams->tunerParams.gain.gRdB != (int)value) + int new_gRdB = -((int)value); + //apply the change if the required value is different from gRdB + // gRdB is a gain *reduction*, so we negate the SoapySDR "IF gain" + // in order to obtain the new gRdB. + if (chParams->tunerParams.gain.gRdB != new_gRdB) { - chParams->tunerParams.gain.gRdB = (int)value; + chParams->tunerParams.gain.gRdB = new_gRdB; doUpdate = true; } } @@ -655,17 +658,18 @@ void SoapySDRPlay::setGain(const int direction, const size_t channel, const std: void SoapySDRPlay::setGain(const int direction, const size_t channel, const double value) { - // Only IFGR should be used for adjusting the overall system gain. - this->setGain(direction, channel, "IFGR", value); + // Only IF should be used for adjusting the overall system gain. + this->setGain(direction, channel, "IF", value); } double SoapySDRPlay::getGain(const int direction, const size_t channel, const std::string &name) const { std::lock_guard lock(_general_state_mutex); - if (name == "IFGR") + if (name == "IF") { - return chParams->tunerParams.gain.gRdB; + // gRdB is a gain *reduction*, so we negate it to obtain the SoapySDR "IF gain". + return -chParams->tunerParams.gain.gRdB; } else if (name == "RFGR") { @@ -677,17 +681,13 @@ double SoapySDRPlay::getGain(const int direction, const size_t channel, const st double SoapySDRPlay::getGain(const int direction, const size_t channel) const { - // Only IFGR should be used for adjusting the overall system gain. - return this->getGain(direction, channel, "IFGR"); + // Only IF should be used for adjusting the overall system gain. + return this->getGain(direction, channel, "IF"); } SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t channel, const std::string &name) const { - if (name == "IFGR") - { - return SoapySDR::Range(20, 59); - } - else if ((name == "RFGR") && (device.hwVer == SDRPLAY_RSP1_ID)) + if ((name == "RFGR") && (device.hwVer == SDRPLAY_RSP1_ID)) { return SoapySDR::Range(0, 3); } @@ -707,13 +707,16 @@ SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t cha { return SoapySDR::Range(0, 27); } - return SoapySDR::Range(20, 59); + else // IF gain + { + return SoapySDR::Range(-59, -20); + } } SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t channel) const { - // Only IFGR should be used for adjusting the overall system gain. - return this->getGainRange(direction, channel, "IFGR"); + // Only IF should be used for adjusting the overall system gain. + return this->getGainRange(direction, channel, "IF"); } /******************************************************************* From 6b5c2abfb4dc91636a67b720cd8a76645e34813e Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Mon, 4 Nov 2019 20:06:54 -0500 Subject: [PATCH 3/3] Remove RF gain unless it is specified as build option. The SDRPlay LNA state is a setting which is: 1. Not actually a gain in dB 2. Not adjusted by automatic gain control We will always show it as a setting (e.g. a CubicSDR menu option). Users can enable the LNA_STATE_AS_GAIN build option if they wish for it to be duplicated as a SoapySDR gain (the "RF gain"). --- CMakeLists.txt | 9 ++- Settings.cpp | 194 +++++++++++------------------------------------ SoapySDRPlay.hpp | 1 + 3 files changed, 49 insertions(+), 155 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 268a02a..755f310 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,11 +32,12 @@ if(CMAKE_COMPILER_IS_GNUCXX) add_definitions(-Wno-unused-parameter) endif(CMAKE_COMPILER_IS_GNUCXX) -# Configurable feature set -SET (RF_GAIN_IN_MENU ON CACHE BOOL "Add Rf gain as a setting, additionally to the IFGR gain control") +# The SDRPlay LNA state, aka "RF gain", is more properly a setting than a gain. +# However, some users may prefer to also expose it as a SoapySDR gain. +SET (LNA_STATE_AS_GAIN OFF CACHE BOOL "Duplicate the lna_state setting as a SoapySDR gain.") -IF(RF_GAIN_IN_MENU) - ADD_DEFINITIONS( -DRF_GAIN_IN_MENU=1 ) +IF(LNA_STATE_AS_GAIN) + ADD_DEFINITIONS( -DLNA_STATE_AS_GAIN=1 ) ENDIF() SET (STREAMING_USB_MODE_BULK OFF CACHE BOOL "Use USB bulk mode instead of isochronous") diff --git a/Settings.cpp b/Settings.cpp index c3bbc86..7cc2e96 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -74,6 +74,12 @@ SoapySDRPlay::SoapySDRPlay(const SoapySDR::Kwargs &args) unsigned int idx = 0; for (unsigned int i = 0; i < nDevs; ++i) { + maxLnaState = 3; // SDRPLAY_RSP1_ID (default) + if (rspDevs[i].hwVer == SDRPLAY_RSP2_ID) maxLnaState = 8; + if (rspDevs[i].hwVer == SDRPLAY_RSPduo_ID) maxLnaState = 9; + if (rspDevs[i].hwVer == SDRPLAY_RSP1A_ID) maxLnaState = 9; + if (rspDevs[i].hwVer == SDRPLAY_RSPdx_ID) maxLnaState = 27; + switch (rspDevs[i].hwVer) { case SDRPLAY_RSP1_ID: @@ -591,8 +597,10 @@ std::vector SoapySDRPlay::listGains(const int direction, const size //the functions below have a "name" parameter std::vector results; +#ifdef LNA_STATE_AS_GAIN + results.push_back("RF"); +#endif results.push_back("IF"); - results.push_back("RFGR"); return results; } @@ -642,15 +650,19 @@ void SoapySDRPlay::setGain(const int direction, const size_t channel, const std: doUpdate = true; } } - else if (name == "RFGR") +#ifdef LNA_STATE_AS_GAIN + else if (name == "RF") { - if (chParams->tunerParams.gain.LNAstate != (int)value) { + // The RF gain is negated to obtain the LNA state. + int newLnaState = -((int)value); + if (chParams->tunerParams.gain.LNAstate != newLnaState) { - chParams->tunerParams.gain.LNAstate = (int)value; + chParams->tunerParams.gain.LNAstate = newLnaState; doUpdate = true; } } - if ((doUpdate == true) && (streamActive)) +#endif + if (doUpdate && streamActive) { sdrplay_api_Update(device.dev, device.tuner, sdrplay_api_Update_Tuner_Gr, sdrplay_api_Update_Ext1_None); } @@ -671,10 +683,15 @@ double SoapySDRPlay::getGain(const int direction, const size_t channel, const st // gRdB is a gain *reduction*, so we negate it to obtain the SoapySDR "IF gain". return -chParams->tunerParams.gain.gRdB; } - else if (name == "RFGR") +#ifdef LNA_STATE_AS_GAIN + else if (name == "RF") { - return chParams->tunerParams.gain.LNAstate; + // LNA state 0 is the minimum numeric value but corresponds to maximum gain. + // We define the RF gain as the negative of the LNA state so that any gain + // adjustment controls (e.g. CubicSDR sliders) operate in the correct direction. + return -chParams->tunerParams.gain.LNAstate; } +#endif return 0; } @@ -687,30 +704,14 @@ double SoapySDRPlay::getGain(const int direction, const size_t channel) const SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t channel, const std::string &name) const { - if ((name == "RFGR") && (device.hwVer == SDRPLAY_RSP1_ID)) - { - return SoapySDR::Range(0, 3); - } - else if ((name == "RFGR") && (device.hwVer == SDRPLAY_RSP2_ID)) - { - return SoapySDR::Range(0, 8); - } - else if ((name == "RFGR") && (device.hwVer == SDRPLAY_RSPduo_ID)) +#ifdef LNA_STATE_AS_GAIN + if (name == "RF") { - return SoapySDR::Range(0, 9); - } - else if ((name == "RFGR") && (device.hwVer == SDRPLAY_RSP1A_ID)) - { - return SoapySDR::Range(0, 9); - } - else if ((name == "RFGR") && (device.hwVer == SDRPLAY_RSPdx_ID)) - { - return SoapySDR::Range(0, 27); - } - else // IF gain - { - return SoapySDR::Range(-59, -20); + return SoapySDR::Range(-maxLnaState, 0); } +#endif + // IF gain + return SoapySDR::Range(-59, -20); } SoapySDR::Range SoapySDRPlay::getGainRange(const int direction, const size_t channel) const @@ -1197,119 +1198,16 @@ SoapySDR::ArgInfoList SoapySDRPlay::getSettingInfo(void) const non_const_this->selectDevice(); } -#ifdef RF_GAIN_IN_MENU - if (device.hwVer == SDRPLAY_RSP2_ID) - { - SoapySDR::ArgInfo RfGainArg; - RfGainArg.key = "rfgain_sel"; - RfGainArg.value = "4"; - RfGainArg.name = "RF Gain Select"; - RfGainArg.description = "RF Gain Select"; - RfGainArg.type = SoapySDR::ArgInfo::STRING; - RfGainArg.options.push_back("0"); - RfGainArg.options.push_back("1"); - RfGainArg.options.push_back("2"); - RfGainArg.options.push_back("3"); - RfGainArg.options.push_back("4"); - RfGainArg.options.push_back("5"); - RfGainArg.options.push_back("6"); - RfGainArg.options.push_back("7"); - RfGainArg.options.push_back("8"); - setArgs.push_back(RfGainArg); - } - else if (device.hwVer == SDRPLAY_RSPduo_ID) - { - SoapySDR::ArgInfo RfGainArg; - RfGainArg.key = "rfgain_sel"; - RfGainArg.value = "4"; - RfGainArg.name = "RF Gain Select"; - RfGainArg.description = "RF Gain Select"; - RfGainArg.type = SoapySDR::ArgInfo::STRING; - RfGainArg.options.push_back("0"); - RfGainArg.options.push_back("1"); - RfGainArg.options.push_back("2"); - RfGainArg.options.push_back("3"); - RfGainArg.options.push_back("4"); - RfGainArg.options.push_back("5"); - RfGainArg.options.push_back("6"); - RfGainArg.options.push_back("7"); - RfGainArg.options.push_back("8"); - RfGainArg.options.push_back("9"); - setArgs.push_back(RfGainArg); - } - else if (device.hwVer == SDRPLAY_RSP1A_ID) - { - SoapySDR::ArgInfo RfGainArg; - RfGainArg.key = "rfgain_sel"; - RfGainArg.value = "4"; - RfGainArg.name = "RF Gain Select"; - RfGainArg.description = "RF Gain Select"; - RfGainArg.type = SoapySDR::ArgInfo::STRING; - RfGainArg.options.push_back("0"); - RfGainArg.options.push_back("1"); - RfGainArg.options.push_back("2"); - RfGainArg.options.push_back("3"); - RfGainArg.options.push_back("4"); - RfGainArg.options.push_back("5"); - RfGainArg.options.push_back("6"); - RfGainArg.options.push_back("7"); - RfGainArg.options.push_back("8"); - RfGainArg.options.push_back("9"); - setArgs.push_back(RfGainArg); + SoapySDR::ArgInfo LnaStateArg; + LnaStateArg.key = "lna_state"; + LnaStateArg.value = std::to_string(maxLnaState / 2); + LnaStateArg.name = "RF Gain Select"; + LnaStateArg.description = "SDRPlay LNA State"; + LnaStateArg.type = SoapySDR::ArgInfo::STRING; + for (int i = 0; i <= maxLnaState; i++) { + LnaStateArg.options.push_back(std::to_string(i)); } - else if (device.hwVer == SDRPLAY_RSPdx_ID) - { - SoapySDR::ArgInfo RfGainArg; - RfGainArg.key = "rfgain_sel"; - RfGainArg.value = "4"; - RfGainArg.name = "RF Gain Select"; - RfGainArg.description = "RF Gain Select"; - RfGainArg.type = SoapySDR::ArgInfo::STRING; - RfGainArg.options.push_back("0"); - RfGainArg.options.push_back("1"); - RfGainArg.options.push_back("2"); - RfGainArg.options.push_back("3"); - RfGainArg.options.push_back("4"); - RfGainArg.options.push_back("5"); - RfGainArg.options.push_back("6"); - RfGainArg.options.push_back("7"); - RfGainArg.options.push_back("8"); - RfGainArg.options.push_back("9"); - RfGainArg.options.push_back("10"); - RfGainArg.options.push_back("11"); - RfGainArg.options.push_back("12"); - RfGainArg.options.push_back("13"); - RfGainArg.options.push_back("14"); - RfGainArg.options.push_back("15"); - RfGainArg.options.push_back("16"); - RfGainArg.options.push_back("17"); - RfGainArg.options.push_back("18"); - RfGainArg.options.push_back("19"); - RfGainArg.options.push_back("20"); - RfGainArg.options.push_back("21"); - RfGainArg.options.push_back("22"); - RfGainArg.options.push_back("23"); - RfGainArg.options.push_back("24"); - RfGainArg.options.push_back("25"); - RfGainArg.options.push_back("26"); - RfGainArg.options.push_back("27"); - setArgs.push_back(RfGainArg); - } - else - { - SoapySDR::ArgInfo RfGainArg; - RfGainArg.key = "rfgain_sel"; - RfGainArg.value = "1"; - RfGainArg.name = "RF Gain Select"; - RfGainArg.description = "RF Gain Select"; - RfGainArg.type = SoapySDR::ArgInfo::STRING; - RfGainArg.options.push_back("0"); - RfGainArg.options.push_back("1"); - RfGainArg.options.push_back("2"); - RfGainArg.options.push_back("3"); - setArgs.push_back(RfGainArg); - } -#endif + setArgs.push_back(LnaStateArg); SoapySDR::ArgInfo IQcorrArg; IQcorrArg.key = "iqcorr_ctrl"; @@ -1448,15 +1346,12 @@ void SoapySDRPlay::writeSetting(const std::string &key, const std::string &value { std::lock_guard lock(_general_state_mutex); -#ifdef RF_GAIN_IN_MENU - if (key == "rfgain_sel") + if (key == "lna_state") { chParams->tunerParams.gain.LNAstate = static_cast(stoul(value)); sdrplay_api_Update(device.dev, device.tuner, sdrplay_api_Update_Tuner_Gr, sdrplay_api_Update_Ext1_None); } - else -#endif - if (key == "iqcorr_ctrl") + else if (key == "iqcorr_ctrl") { if (value == "false") chParams->ctrlParams.dcOffset.IQenable = 0; else chParams->ctrlParams.dcOffset.IQenable = 1; @@ -1623,14 +1518,11 @@ std::string SoapySDRPlay::readSetting(const std::string &key) const { std::lock_guard lock(_general_state_mutex); -#ifdef RF_GAIN_IN_MENU - if (key == "rfgain_sel") + if (key == "lna_state") { return std::to_string(static_cast(chParams->tunerParams.gain.LNAstate)); } - else -#endif - if (key == "iqcorr_ctrl") + else if (key == "iqcorr_ctrl") { if (chParams->ctrlParams.dcOffset.IQenable == 0) return "false"; else return "true"; diff --git a/SoapySDRPlay.hpp b/SoapySDRPlay.hpp index 5009356..1619eb6 100644 --- a/SoapySDRPlay.hpp +++ b/SoapySDRPlay.hpp @@ -262,6 +262,7 @@ class SoapySDRPlay: public SoapySDR::Device sdrplay_api_DeviceParamsT *deviceParams; sdrplay_api_RxChannelParamsT *chParams; std::string hardwareKey; + int maxLnaState; //cached settings double outputSampleRate;