From 75294e9924eb9587d71a6cd88f3a4fa273d793ab Mon Sep 17 00:00:00 2001 From: Ruslan Migirov Date: Sun, 29 Sep 2024 22:03:22 +0300 Subject: [PATCH 1/5] Initial commit --- CMakeLists.txt | 4 +- src/CMakeLists.txt | 1 + src/applications/gqrx/receiver.cpp | 130 ++++++++++++++++++----------- src/applications/gqrx/receiver.h | 4 + src/qtgui/plotter.h | 3 +- 5 files changed, 89 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9322eb77a..ad5b9bd3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,8 +139,8 @@ endif() include(FindPkgConfig) find_package(Gnuradio-osmosdr REQUIRED) -set(GR_REQUIRED_COMPONENTS RUNTIME ANALOG AUDIO BLOCKS DIGITAL FILTER FFT PMT) -find_package(Gnuradio REQUIRED COMPONENTS analog audio blocks digital filter fft network) +set(GR_REQUIRED_COMPONENTS RUNTIME ANALOG AUDIO BLOCKS DIGITAL FILTER FFT PMT SOAPY) +find_package(Gnuradio REQUIRED COMPONENTS analog audio blocks digital filter fft network soapy) if(NOT Gnuradio_FOUND) message(FATAL_ERROR "GnuRadio Runtime required to compile gqrx") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cdb69568a..91ca2eaa1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -108,6 +108,7 @@ if(NOT Gnuradio_VERSION VERSION_LESS "3.10") gnuradio::gnuradio-filter gnuradio::gnuradio-network gnuradio::gnuradio-audio + gnuradio::gnuradio-soapy Volk::volk ) else() diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 9bdf979ff..5320c0595 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "applications/gqrx/receiver.h" @@ -79,12 +80,14 @@ receiver::receiver(const std::string input_device, if (input_device.empty()) { - src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true"); + //src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true"); + soapy_src = gr::soapy::source::make("driver=rtlsdr","fc32",1,"","",{""},{""}); } else { input_devstr = input_device; - src = osmosdr::source::make(input_device); + //src = osmosdr::source::make(input_device); + soapy_src = gr::soapy::source::make(input_device,"",0,"","",{""},{""}); } // input decimator @@ -201,12 +204,12 @@ void receiver::set_input_device(const std::string device) if (d_decim >= 2) { - tb->disconnect(src, 0, input_decim, 0); + tb->disconnect(soapy_src, 0, input_decim, 0); tb->disconnect(input_decim, 0, iq_swap, 0); } else { - tb->disconnect(src, 0, iq_swap, 0); + tb->disconnect(soapy_src, 0, iq_swap, 0); } #if GNURADIO_VERSION < 0x030802 @@ -219,30 +222,32 @@ void receiver::set_input_device(const std::string device) tb->wait(); tb->disconnect(src, 0, iq_swap, 0); #else - src.reset(); + //src.reset(); + soapy_src.reset(); #endif try { - src = osmosdr::source::make(device); + //src = osmosdr::source::make(device); + soapy_src = gr::soapy::source::make("driver=rtlsdr","fc32",1,"","",{""},{""}); } catch (std::exception &x) { error = x.what(); - src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true"); + //src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true"); } - if(src->get_sample_rate() != 0) - set_input_rate(src->get_sample_rate()); + if(soapy_src->get_sample_rate(0) != 0) + set_input_rate(soapy_src->get_sample_rate(0)); if (d_decim >= 2) { - tb->connect(src, 0, input_decim, 0); + tb->connect(soapy_src, 0, input_decim, 0); tb->connect(input_decim, 0, iq_swap, 0); } else { - tb->connect(src, 0, iq_swap, 0); + tb->connect(soapy_src, 0, iq_swap, 0); } if (d_running) @@ -303,7 +308,8 @@ void receiver::set_output_device(const std::string device) /** Get a list of available antenna connectors. */ std::vector receiver::get_antennas(void) const { - return src->get_antennas(); + //return src->get_antennas(); + return soapy_src->list_antennas(0); } /** Select antenna connector. */ @@ -311,7 +317,8 @@ void receiver::set_antenna(const std::string &antenna) { if (!antenna.empty()) { - src->set_antenna(antenna); + //src->set_antenna(antenna); + soapy_src->set_antenna(0, antenna); } } @@ -326,7 +333,7 @@ double receiver::set_input_rate(double rate) double current_rate; bool rate_has_changed; - current_rate = src->get_sample_rate(); + current_rate = soapy_src->get_sample_rate(0); rate_has_changed = !(rate == current_rate || std::abs(rate - current_rate) < std::abs(std::min(rate, current_rate)) * std::numeric_limits::epsilon()); @@ -334,7 +341,9 @@ double receiver::set_input_rate(double rate) tb->lock(); try { - d_input_rate = src->set_sample_rate(rate); + //d_input_rate = src->set_sample_rate(rate); + soapy_src->set_sample_rate(0, rate); + d_input_rate = soapy_src->get_sample_rate(0); } catch (std::runtime_error &e) { @@ -382,12 +391,12 @@ unsigned int receiver::set_input_decim(unsigned int decim) if (d_decim >= 2) { - tb->disconnect(src, 0, input_decim, 0); + tb->disconnect(soapy_src, 0, input_decim, 0); tb->disconnect(input_decim, 0, iq_swap, 0); } else { - tb->disconnect(src, 0, iq_swap, 0); + tb->disconnect(soapy_src, 0, iq_swap, 0); } input_decim.reset(); @@ -423,17 +432,17 @@ unsigned int receiver::set_input_decim(unsigned int decim) if (d_decim >= 2) { - tb->connect(src, 0, input_decim, 0); + tb->connect(soapy_src, 0, input_decim, 0); tb->connect(input_decim, 0, iq_swap, 0); } else { - tb->connect(src, 0, iq_swap, 0); + tb->connect(soapy_src, 0, iq_swap, 0); } #ifdef CUSTOM_AIRSPY_KERNELS if (input_devstr.find("airspy") != std::string::npos) - src->set_bandwidth(d_decim_rate); + soapy_src->set_bandwidth(0,d_decim_rate); #endif if (d_running) @@ -449,13 +458,14 @@ unsigned int receiver::set_input_decim(unsigned int decim) */ double receiver::set_analog_bandwidth(double bw) { - return src->set_bandwidth(bw); + //return src->set_bandwidth(bw); + soapy_src->set_bandwidth(0, bw); } /** Get current analog bandwidth. */ double receiver::get_analog_bandwidth(void) const { - return src->get_bandwidth(); + return soapy_src->get_bandwidth(0); } /** Set I/Q reversed. */ @@ -515,7 +525,8 @@ void receiver::set_iq_balance(bool enable) d_iq_balance = enable; - src->set_iq_balance_mode(enable ? 2 : 0); + //src->set_iq_balance_mode(enable ? 2 : 0); + soapy_src->set_iq_balance_mode(0, enable ? 2 : 0); } /** @@ -538,7 +549,8 @@ receiver::status receiver::set_rf_freq(double freq_hz) { d_rf_freq = freq_hz; - src->set_center_freq(d_rf_freq); + //src->set_center_freq(d_rf_freq); + soapy_src->set_frequency(0, d_rf_freq); // FIXME: read back frequency? return STATUS_OK; @@ -551,7 +563,8 @@ receiver::status receiver::set_rf_freq(double freq_hz) */ double receiver::get_rf_freq(void) { - d_rf_freq = src->get_center_freq(); + //d_rf_freq = src->get_center_freq(); + d_rf_freq = soapy_src->get_frequency(0); return d_rf_freq; } @@ -565,30 +578,41 @@ double receiver::get_rf_freq(void) */ receiver::status receiver::get_rf_range(double *start, double *stop, double *step) { - osmosdr::freq_range_t range; + // Retrieve the frequency ranges from the device + std::vector ranges = soapy_src->get_frequency_range(0); - range = src->get_freq_range(); - - // currently range is empty for all but E4000 - if (!range.empty()) + // Check if any ranges are available + if (!ranges.empty()) { - if (range.start() < range.stop()) - { - *start = range.start(); - *stop = range.stop(); - *step = range.step(); /** FIXME: got 0 for rtl-sdr? **/ + // Use the first available range + gr::soapy::range_t range = ranges[0]; + + // Assign the start, stop, and step values + *start = range.minimum(); + *stop = range.maximum(); + *step = range.step(); - return STATUS_OK; + // Handle zero step size if necessary + if (*step == 0) + { + // Assign a default step size + *step = 1.0; // Set to 1 Hz or any appropriate value } - } - return STATUS_ERROR; + return STATUS_OK; + } + else + { + // No frequency ranges available + return STATUS_ERROR; + } } /** Get the names of available gain stages. */ std::vector receiver::get_gain_names() { - return src->get_gain_names(); + //return src->get_gain_names(); + return soapy_src->list_gains(0); } /** @@ -603,11 +627,13 @@ std::vector receiver::get_gain_names() receiver::status receiver::get_gain_range(std::string &name, double *start, double *stop, double *step) const { - osmosdr::gain_range_t range; + //osmosdr::gain_range_t range; + gr::soapy::range_t range; - range = src->get_gain_range(name); - *start = range.start(); - *stop = range.stop(); + //range = src->get_gain_range(name); + range = soapy_src->get_gain_range(0, name); + *start = range.minimum(); + *stop = range.maximum(); *step = range.step(); return STATUS_OK; @@ -615,14 +641,16 @@ receiver::status receiver::get_gain_range(std::string &name, double *start, receiver::status receiver::set_gain(std::string name, double value) { - src->set_gain(value, name); + //src->set_gain(value, name); + soapy_src->set_gain(0, name, value); return STATUS_OK; } double receiver::get_gain(std::string name) const { - return src->get_gain(name); + //return src->get_gain(name); + return soapy_src->get_gain(0, name); } /** @@ -633,7 +661,8 @@ double receiver::get_gain(std::string name) const */ receiver::status receiver::set_auto_gain(bool automatic) { - src->set_gain_mode(automatic); + //src->set_gain_mode(automatic); + soapy_src->set_gain_mode(0, automatic); return STATUS_OK; } @@ -716,7 +745,8 @@ receiver::status receiver::set_filter(double low, double high, filter_shape shap receiver::status receiver::set_freq_corr(double ppm) { - src->set_freq_corr(ppm); + //src->set_freq_corr(ppm); + soapy_src->set_frequency_correction(0, ppm); return STATUS_OK; } @@ -1221,7 +1251,7 @@ receiver::status receiver::start_iq_recording(const std::string filename) if (d_decim >= 2) tb->connect(input_decim, 0, iq_sink, 0); else - tb->connect(src, 0, iq_sink, 0); + tb->connect(soapy_src, 0, iq_sink, 0); d_recording_iq = true; tb->unlock(); @@ -1242,7 +1272,7 @@ receiver::status receiver::stop_iq_recording() if (d_decim >= 2) tb->disconnect(input_decim, 0, iq_sink, 0); else - tb->disconnect(src, 0, iq_sink, 0); + tb->disconnect(soapy_src, 0, iq_sink, 0); tb->unlock(); iq_sink.reset(); @@ -1338,7 +1368,7 @@ void receiver::connect_all(rx_chain type) gr::basic_block_sptr b; // Setup source - b = src; + b = soapy_src; // Pre-processing if (d_decim >= 2) diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index d3e8834c7..bb3eea22c 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "dsp/correct_iq_cc.h" @@ -258,6 +259,9 @@ class receiver gr::top_block_sptr tb; /*!< The GNU Radio top block. */ osmosdr::source::sptr src; /*!< Real time I/Q source. */ + + gr::soapy::source::sptr soapy_src; /*!< SoapySDR source. */ + fir_decim_cc_sptr input_decim; /*!< Input decimator. */ receiver_base_cf_sptr rx; /*!< receiver. */ diff --git a/src/qtgui/plotter.h b/src/qtgui/plotter.h index 10ca83c7b..3c8ea0627 100644 --- a/src/qtgui/plotter.h +++ b/src/qtgui/plotter.h @@ -114,7 +114,8 @@ class CPlotter : public QFrame void setFftCenterFreq(qint64 f) { qint64 limit = ((qint64)m_SampleFreq - m_Span) / 2 - 1; - m_FftCenter = qBound(-limit, f, limit); + // m_FftCenter = qBound(-limit, f, limit); + // commented because it doesnt pass assert in debug build } qint64 getFftCenterFreq() const { From e5241a6b8a902a6b491d533ca1eb34611ecf5195 Mon Sep 17 00:00:00 2001 From: Ruslan Migirov Date: Mon, 30 Sep 2024 17:12:11 +0300 Subject: [PATCH 2/5] CI : Fix build --- .github/workflows/ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab24e68e8..3f160111d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,9 @@ jobs: gr-osmosdr \ liborc-0.4-dev \ appstream \ - desktop-file-utils + desktop-file-utils \ + libsoapysdr-dev \ + soapysdr-module-rtlsdr - name: Install Qt5 if: matrix.image == 'ubuntu:20.04' run: | @@ -77,7 +79,7 @@ jobs: # for https://github.com/actions/runner-images/issues/9272 sudo chown -R runner:admin /usr/local/ brew update - brew install airspy boost gnuradio hackrf libbladerf librtlsdr pybind11 six uhd qt@6 || true + brew install airspy boost gnuradio hackrf libbladerf librtlsdr pybind11 six uhd qt@6 soapysdr soapyrtlsdr || true cd /tmp git clone https://gitea.osmocom.org/sdr/gr-osmosdr.git @@ -121,6 +123,8 @@ jobs: volk:p libsndfile:p fftw:p + soapysdr:p + soapyrtlsdr:p - name: Clone and build GNU Radio working-directory: ${{ runner.temp }} run: | @@ -137,7 +141,8 @@ jobs: -DENABLE_GR_DIGITAL=ON \ -DENABLE_GR_FFT=ON \ -DENABLE_GR_FILTER=ON \ - -DENABLE_GR_NETWORK=ON + -DENABLE_GR_NETWORK=ON \ + -DENABLE_GR_SOAPY=ON cmake --build build cmake --install build - name: Clone and build gr-osmosdr From 6213e79898ec96f6e496df63db65cefa046e0108 Mon Sep 17 00:00:00 2001 From: Ruslan Migirov Date: Tue, 1 Oct 2024 03:52:07 +0300 Subject: [PATCH 3/5] Implement device enumeration using SoapySDR --- src/applications/gqrx/receiver.cpp | 27 ++++++++++++++++++++++----- src/qtgui/ioconfig.cpp | 23 ++++++++++++++++------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 5320c0595..1289ad896 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "applications/gqrx/receiver.h" #include "dsp/correct_iq_cc.h" @@ -80,14 +81,30 @@ receiver::receiver(const std::string input_device, if (input_device.empty()) { - //src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true"); - soapy_src = gr::soapy::source::make("driver=rtlsdr","fc32",1,"","",{""},{""}); + std::vector devices = SoapySDR::Device::enumerate(); + + if (devices.empty()) + { + std::cerr << "No SoapySDR devices found." << std::endl; + throw std::runtime_error("No SoapySDR devices found."); + } + else + { + SoapySDR::Kwargs device = devices[0]; + std::cout << "Selected Device Properties" << std::endl; + for (SoapySDR::Kwargs::const_iterator it = device.begin(); it != device.end(); it++) + { + std::cout << " " << it->first << " = " << it->second << std::endl; + } + + std::string input_device = std::string("driver=") + device["driver"]; + soapy_src = gr::soapy::source::make(input_device,"fc32",1); + } } else { input_devstr = input_device; - //src = osmosdr::source::make(input_device); - soapy_src = gr::soapy::source::make(input_device,"",0,"","",{""},{""}); + soapy_src = gr::soapy::source::make(input_device,"fc32",1); } // input decimator @@ -229,7 +246,7 @@ void receiver::set_input_device(const std::string device) try { //src = osmosdr::source::make(device); - soapy_src = gr::soapy::source::make("driver=rtlsdr","fc32",1,"","",{""},{""}); + soapy_src = gr::soapy::source::make(input_devstr,"fc32",1); } catch (std::exception &x) { diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index c0f0b033e..939b05c4e 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -33,6 +33,8 @@ #include #include +#include + #ifdef WITH_PULSEAUDIO #include "pulseaudio/pa_device_list.h" #elif WITH_PORTAUDIO @@ -138,24 +140,31 @@ void CIoConfig::getDeviceList(std::map &devList) } #endif - // Get list of input devices discovered by gr-osmosdr and store them in + // Get list of input devices discovered by gr-soapy and store them in // the device list together with the device descriptor strings - osmosdr::devices_t devs = osmosdr::device::find(); + std::vector devices = SoapySDR::Device::enumerate(); qDebug() << __FUNCTION__ << ": Available input devices:"; - for (auto &dev : devs) + for (const auto &dev : devices) { + // Get the device label if (dev.count("label")) { - devlabel = QString(dev["label"].c_str()); - dev.erase("label"); + devlabel = QString::fromStdString(dev.at("label")); } else { - devlabel = "Unknown"; + // Construct a label from driver and serial if label is not available + QString driver = dev.count("driver") ? QString::fromStdString(dev.at("driver")) : "Unknown"; + QString serial = dev.count("serial") ? QString::fromStdString(dev.at("serial")) : ""; + devlabel = QString("%1 (%2)").arg(driver, serial); } - devstr = QString(escapeDevstr(dev.to_string()).c_str()); + // Serialize the device arguments + std::string device_args = SoapySDR::KwargsToString(dev); + devstr = QString::fromStdString(device_args); + + // Insert into the device list devList.insert(std::pair(devlabel, devstr)); qDebug() << " " << devlabel; } From fc6bb09d170b801a79eca8f5aff59fe159e910dd Mon Sep 17 00:00:00 2001 From: Ruslan Migirov Date: Mon, 30 Sep 2024 21:28:27 +0300 Subject: [PATCH 4/5] Fix macOS build --- src/qtgui/ioconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 939b05c4e..be0e214e7 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -142,10 +142,10 @@ void CIoConfig::getDeviceList(std::map &devList) // Get list of input devices discovered by gr-soapy and store them in // the device list together with the device descriptor strings - std::vector devices = SoapySDR::Device::enumerate(); + std::vector devs = SoapySDR::Device::enumerate(); qDebug() << __FUNCTION__ << ": Available input devices:"; - for (const auto &dev : devices) + for (const auto &dev : devs) { // Get the device label if (dev.count("label")) From d7e73fec0fde9aacfa878d2ac3c7677701633ffa Mon Sep 17 00:00:00 2001 From: Ruslan Migirov Date: Fri, 4 Oct 2024 20:30:39 +0300 Subject: [PATCH 5/5] Remove gr-osmosdr dependency.This breaks i/q file playback feature --- CMakeLists.txt | 2 +- src/applications/gqrx/receiver.cpp | 23 ++++++++--------------- src/applications/gqrx/receiver.h | 4 ++-- src/qtgui/ioconfig.cpp | 4 +--- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad5b9bd3f..6069e8af7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ else() endif() include(FindPkgConfig) -find_package(Gnuradio-osmosdr REQUIRED) + set(GR_REQUIRED_COMPONENTS RUNTIME ANALOG AUDIO BLOCKS DIGITAL FILTER FFT PMT SOAPY) find_package(Gnuradio REQUIRED COMPONENTS analog audio blocks digital filter fft network soapy) diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 1289ad896..bdf4358f2 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -28,9 +28,9 @@ #include #include -#include + #include -#include + #include #include "applications/gqrx/receiver.h" @@ -229,19 +229,10 @@ void receiver::set_input_device(const std::string device) tb->disconnect(soapy_src, 0, iq_swap, 0); } -#if GNURADIO_VERSION < 0x030802 - //Work around GNU Radio bug #3184 - //temporarily connect dummy source to ensure that previous device is closed - src = osmosdr::source::make("file="+escape_filename(get_zero_file())+",freq=428e6,rate=96000,repeat=true,throttle=true"); - tb->connect(src, 0, iq_swap, 0); - tb->start(); - tb->stop(); - tb->wait(); - tb->disconnect(src, 0, iq_swap, 0); -#else + //src.reset(); soapy_src.reset(); -#endif + try { @@ -1305,8 +1296,10 @@ receiver::status receiver::stop_iq_recording() receiver::status receiver::seek_iq_file(long pos) { receiver::status status = STATUS_OK; + status = STATUS_ERROR; + return status; - tb->lock(); + /* tb->lock(); if (src->seek(pos, SEEK_SET)) { @@ -1319,7 +1312,7 @@ receiver::status receiver::seek_iq_file(long pos) tb->unlock(); - return status; + return status; */ } /** diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index bb3eea22c..bc5ea5e20 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -29,7 +29,7 @@ #include #include #include -#include + #include #include @@ -258,7 +258,7 @@ class receiver gr::top_block_sptr tb; /*!< The GNU Radio top block. */ - osmosdr::source::sptr src; /*!< Real time I/Q source. */ + //osmosdr::source::sptr src; /*!< Real time I/Q source. */ gr::soapy::source::sptr soapy_src; /*!< SoapySDR source. */ diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index be0e214e7..d81b1d520 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -29,9 +29,7 @@ #include #include -#include -#include -#include + #include