From 209be94947015a97054588ea2f6dab599040f2ed Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Fri, 23 Oct 2020 13:12:37 +0100 Subject: [PATCH 1/9] USRP driver improvements. Set bit size to be 16 for interpolators and decimators. Match buffer size to UHD. Don't destroy TX stream, as there appears to be a bug when recreating it. Catch exception when checking for TX underflow. Increase RX FIFO size, to reduce overflows at high sample rates. Allow RX to continue streaming after receiving timeout. --- devices/usrp/deviceusrp.h | 2 - plugins/samplesink/usrpoutput/usrpoutput.cpp | 53 +++++++++------ plugins/samplesink/usrpoutput/usrpoutput.h | 1 + .../usrpoutput/usrpoutputthread.cpp | 27 +++++--- .../samplesink/usrpoutput/usrpoutputthread.h | 5 +- plugins/samplesource/usrpinput/usrpinput.cpp | 10 ++- plugins/samplesource/usrpinput/usrpinput.h | 1 + .../usrpinput/usrpinputthread.cpp | 67 +++++++++++++------ .../samplesource/usrpinput/usrpinputthread.h | 8 ++- 9 files changed, 115 insertions(+), 59 deletions(-) diff --git a/devices/usrp/deviceusrp.h b/devices/usrp/deviceusrp.h index c447a422f..497129e72 100644 --- a/devices/usrp/deviceusrp.h +++ b/devices/usrp/deviceusrp.h @@ -33,8 +33,6 @@ public: /** Enumeration of USRP hardware devices */ static void enumOriginDevices(const QString& hardwareId, PluginInterface::OriginDevices& originDevices); - /** Block size used for transferring IQ samples to and from the device. This perhaps needs tuning. */ - static const unsigned int blockSize = (1<<15); }; #endif /* DEVICES_USRP_DEVICEUSRP_H_ */ diff --git a/plugins/samplesink/usrpoutput/usrpoutput.cpp b/plugins/samplesink/usrpoutput/usrpoutput.cpp index 5cbbbc047..0b2b5d33e 100644 --- a/plugins/samplesink/usrpoutput/usrpoutput.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutput.cpp @@ -51,6 +51,7 @@ USRPOutput::USRPOutput(DeviceAPI *deviceAPI) : m_deviceAPI(deviceAPI), m_settings(), m_usrpOutputThread(nullptr), + m_bufSamples(0), m_deviceDescription("USRPOutput"), m_running(false), m_channelAcquired(false) @@ -288,22 +289,28 @@ bool USRPOutput::acquireChannel() suspendRxBuddies(); suspendTxBuddies(); - try + if (m_streamId == nullptr) { - // set up the stream - std::string cpu_format("sc16"); - std::string wire_format("sc16"); - std::vector channel_nums; - channel_nums.push_back(m_deviceShared.m_channel); + try + { + // set up the stream + std::string cpu_format("sc16"); + std::string wire_format("sc16"); + std::vector channel_nums; + channel_nums.push_back(m_deviceShared.m_channel); - uhd::stream_args_t stream_args(cpu_format, wire_format); - stream_args.channels = channel_nums; + uhd::stream_args_t stream_args(cpu_format, wire_format); + stream_args.channels = channel_nums; - m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_tx_stream(stream_args); - } - catch (std::exception& e) - { - qDebug() << "USRPOutput::acquireChannel: exception: " << e.what(); + m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_tx_stream(stream_args); + + // Match our transmit buffer size to what UHD uses + m_bufSamples = m_streamId->get_max_num_samps(); + } + catch (std::exception& e) + { + qDebug() << "USRPOutput::acquireChannel: exception: " << e.what(); + } } resumeTxBuddies(); @@ -319,8 +326,14 @@ void USRPOutput::releaseChannel() suspendRxBuddies(); suspendTxBuddies(); - // destroy the stream - FIXME: Better way to do this? - m_streamId = nullptr; + // FIXME: Currently we do not try to destroy the stream, as there seems to be + // an issue when we re-acquire the stream, the output spectrum will not be correct + // The transmitter output will be disabled when we stop sending data to it anyway + if (false) + { + // destroy the stream + m_streamId = nullptr; + } resumeTxBuddies(); resumeRxBuddies(); @@ -346,9 +359,7 @@ bool USRPOutput::start() return false; } - // start / stop streaming is done in the thread. - - m_usrpOutputThread = new USRPOutputThread(m_streamId, &m_sampleSourceFifo); + m_usrpOutputThread = new USRPOutputThread(m_streamId, m_bufSamples, &m_sampleSourceFifo); qDebug("USRPOutput::start: thread created"); applySettings(m_settings, true); @@ -563,7 +574,7 @@ bool USRPOutput::handleMessage(const Message& message) { if (m_deviceAPI->getSamplingDeviceGUIMessageQueue()) { - if (m_streamId != nullptr) + if ((m_streamId != nullptr) && m_channelAcquired) { bool active; quint32 underflows; @@ -1023,8 +1034,8 @@ void USRPOutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response bool active = false; quint32 underflows = 0; quint32 droppedPackets = 0; - - if (m_streamId != nullptr) + + if ((m_streamId != nullptr) && m_channelAcquired) { m_usrpOutputThread->getStreamStatus(active, underflows, droppedPackets); success = true; diff --git a/plugins/samplesink/usrpoutput/usrpoutput.h b/plugins/samplesink/usrpoutput/usrpoutput.h index 999b0adde..7ebec32d0 100644 --- a/plugins/samplesink/usrpoutput/usrpoutput.h +++ b/plugins/samplesink/usrpoutput/usrpoutput.h @@ -226,6 +226,7 @@ private: DeviceUSRPShared m_deviceShared; bool m_channelAcquired; uhd::tx_streamer::sptr m_streamId; + size_t m_bufSamples; QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; diff --git a/plugins/samplesink/usrpoutput/usrpoutputthread.cpp b/plugins/samplesink/usrpoutput/usrpoutputthread.cpp index 9537cab0d..2b6edd6cf 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputthread.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputthread.cpp @@ -26,19 +26,23 @@ #include "usrpoutputthread.h" #include "usrpoutputsettings.h" -USRPOutputThread::USRPOutputThread(uhd::tx_streamer::sptr stream, SampleSourceFifo* sampleFifo, QObject* parent) : +USRPOutputThread::USRPOutputThread(uhd::tx_streamer::sptr stream, size_t bufSamples, SampleSourceFifo* sampleFifo, QObject* parent) : QThread(parent), m_running(false), m_stream(stream), + m_bufSamples(bufSamples), m_sampleFifo(sampleFifo), m_log2Interp(0) { - std::fill(m_buf, m_buf + 2*DeviceUSRP::blockSize, 0); + // *2 as samples are I+Q + m_buf = new qint16[2*bufSamples]; + std::fill(m_buf, m_buf + 2*bufSamples, 0); } USRPOutputThread::~USRPOutputThread() { stopWork(); + delete m_buf; } void USRPOutputThread::startWork() @@ -66,8 +70,15 @@ void USRPOutputThread::stopWork() m_running = false; wait(); - // Get message indicating underflow, so it doesn't appear if we restart - m_stream->recv_async_msg(md); + try + { + // Get message indicating underflow, so it doesn't appear if we restart + m_stream->recv_async_msg(md); + } + catch (std::exception& e) + { + qDebug() << "USRPOutputThread::stopWork: exception: " << e.what(); + } qDebug("USRPOutputThread::stopWork: stream stopped"); } @@ -90,15 +101,15 @@ void USRPOutputThread::run() while (m_running) { - callback(m_buf, DeviceUSRP::blockSize); + callback(m_buf, m_bufSamples); try { - const size_t samples_sent = m_stream->send(m_buf, DeviceUSRP::blockSize, md); + const size_t samples_sent = m_stream->send(m_buf, m_bufSamples, md); m_packets++; - if (samples_sent != DeviceUSRP::blockSize) + if (samples_sent != m_bufSamples) { - qDebug("USRPOutputThread::run written %ld/%d samples", samples_sent, DeviceUSRP::blockSize); + qDebug("USRPOutputThread::run written %ld/%d samples", samples_sent, m_bufSamples); } } catch (std::exception& e) diff --git a/plugins/samplesink/usrpoutput/usrpoutputthread.h b/plugins/samplesink/usrpoutput/usrpoutputthread.h index fcd59a5ad..c1a8f658b 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputthread.h +++ b/plugins/samplesink/usrpoutput/usrpoutputthread.h @@ -37,7 +37,7 @@ class USRPOutputThread : public QThread, public DeviceUSRPShared::ThreadInterfac Q_OBJECT public: - USRPOutputThread(uhd::tx_streamer::sptr stream, SampleSourceFifo* sampleFifo, QObject* parent = 0); + USRPOutputThread(uhd::tx_streamer::sptr stream, size_t bufSamples, SampleSourceFifo* sampleFifo, QObject* parent = 0); ~USRPOutputThread(); virtual void startWork(); @@ -57,7 +57,8 @@ private: quint32 m_droppedPackets; uhd::tx_streamer::sptr m_stream; - qint16 m_buf[2*DeviceUSRP::blockSize]; //must hold I+Q values of each sample hence 2xcomplex size + qint16 *m_buf; + size_t m_bufSamples; SampleSourceFifo* m_sampleFifo; unsigned int m_log2Interp; // soft decimation diff --git a/plugins/samplesource/usrpinput/usrpinput.cpp b/plugins/samplesource/usrpinput/usrpinput.cpp index 05ac35aae..d7598aa02 100644 --- a/plugins/samplesource/usrpinput/usrpinput.cpp +++ b/plugins/samplesource/usrpinput/usrpinput.cpp @@ -51,6 +51,7 @@ USRPInput::USRPInput(DeviceAPI *deviceAPI) : m_deviceAPI(deviceAPI), m_settings(), m_usrpInputThread(nullptr), + m_bufSamples(0), m_deviceDescription("USRPInput"), m_running(false), m_channelAcquired(false) @@ -91,7 +92,9 @@ void USRPInput::destroy() bool USRPInput::openDevice() { - if (!m_sampleFifo.setSize(96000 * 4)) + // B210 supports up to 50MSa/s, so a fairly large FIFO is probably a good idea + // Should it be bigger still? + if (!m_sampleFifo.setSize(2000000)) { qCritical("USRPInput::openDevice: could not allocate SampleFifo"); return false; @@ -325,6 +328,9 @@ bool USRPInput::acquireChannel() stream_args.channels = channel_nums; m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_rx_stream(stream_args); + + // Match our receive buffer size to what UHD uses + m_bufSamples = m_streamId->get_max_num_samps(); } catch (std::exception& e) { @@ -375,7 +381,7 @@ bool USRPInput::start() // start / stop streaming is done in the thread. - m_usrpInputThread = new USRPInputThread(m_streamId, &m_sampleFifo); + m_usrpInputThread = new USRPInputThread(m_streamId, m_bufSamples, &m_sampleFifo); qDebug("USRPInput::start: thread created"); applySettings(m_settings, true); diff --git a/plugins/samplesource/usrpinput/usrpinput.h b/plugins/samplesource/usrpinput/usrpinput.h index b84ec2028..82cbefa85 100644 --- a/plugins/samplesource/usrpinput/usrpinput.h +++ b/plugins/samplesource/usrpinput/usrpinput.h @@ -227,6 +227,7 @@ private: DeviceUSRPShared m_deviceShared; bool m_channelAcquired; uhd::rx_streamer::sptr m_streamId; + size_t m_bufSamples; QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; diff --git a/plugins/samplesource/usrpinput/usrpinputthread.cpp b/plugins/samplesource/usrpinput/usrpinputthread.cpp index 54b81aab5..4935c8576 100644 --- a/plugins/samplesource/usrpinput/usrpinputthread.cpp +++ b/plugins/samplesource/usrpinput/usrpinputthread.cpp @@ -26,20 +26,35 @@ #include "usrpinputsettings.h" #include "usrpinputthread.h" -USRPInputThread::USRPInputThread(uhd::rx_streamer::sptr stream, SampleSinkFifo* sampleFifo, QObject* parent) : +USRPInputThread::USRPInputThread(uhd::rx_streamer::sptr stream, size_t bufSamples, SampleSinkFifo* sampleFifo, QObject* parent) : QThread(parent), m_running(false), m_stream(stream), - m_convertBuffer(DeviceUSRP::blockSize), + m_bufSamples(bufSamples), + m_convertBuffer(bufSamples), m_sampleFifo(sampleFifo), m_log2Decim(0) { - std::fill(m_buf, m_buf + 2*DeviceUSRP::blockSize, 0); + // *2 as samples are I+Q + m_buf = new qint16[2*bufSamples]; + std::fill(m_buf, m_buf + 2*bufSamples, 0); } USRPInputThread::~USRPInputThread() { stopWork(); + delete m_buf; +} + +void USRPInputThread::issueStreamCmd(bool start) +{ + uhd::stream_cmd_t stream_cmd(start ? uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS : uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + stream_cmd.num_samps = size_t(0); + stream_cmd.stream_now = true; + stream_cmd.time_spec = uhd::time_spec_t(); + + m_stream->issue_stream_cmd(stream_cmd); + qDebug() << "USRPInputThread::issueStreamCmd " << (start ? "start" : "stop"); } void USRPInputThread::startWork() @@ -48,12 +63,8 @@ void USRPInputThread::startWork() try { - uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - stream_cmd.num_samps = size_t(0); - stream_cmd.stream_now = true; - stream_cmd.time_spec = uhd::time_spec_t(); - - m_stream->issue_stream_cmd(stream_cmd); + // Start streaming + issueStreamCmd(true); // Reset stats m_packets = 0; @@ -84,18 +95,20 @@ void USRPInputThread::stopWork() try { uhd::rx_metadata_t md; - uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); - stream_cmd.stream_now = true; - m_stream->issue_stream_cmd(stream_cmd); + + // Stop streaming + issueStreamCmd(false); // Clear out any data left in the stream, otherwise we'll get an // exception 'recv buffer smaller than vrt packet offset' when restarting - while (!md.end_of_burst) + md.end_of_burst = false; + md.error_code = uhd::rx_metadata_t::ERROR_CODE_NONE; + while (!md.end_of_burst && (md.error_code != uhd::rx_metadata_t::ERROR_CODE_TIMEOUT)) { try { - //qDebug() << "USRPInputThread::stopWork: recing until end of burst"; - m_stream->recv(m_buf, DeviceUSRP::blockSize, md); + md.reset(); + m_stream->recv(m_buf, m_bufSamples, md); } catch (std::exception& e) { @@ -127,27 +140,39 @@ void USRPInputThread::run() { while (m_running) { - const size_t samples_received = m_stream->recv(m_buf, DeviceUSRP::blockSize, md); + md.reset(); + const size_t samples_received = m_stream->recv(m_buf, m_bufSamples, md); m_packets++; - if (samples_received != DeviceUSRP::blockSize) + if (samples_received != m_bufSamples) { - qDebug("USRPInputThread::run - received %ld/%d samples", samples_received, DeviceUSRP::blockSize); + qDebug("USRPInputThread::run - received %ld/%d samples", samples_received, m_bufSamples); } if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) { qDebug("USRPInputThread::run - timeout - ending thread"); m_timeouts++; - // It seems we can't recover after a timeout, so stop thread - m_running = false; + // Restart streaming + issueStreamCmd(false); + issueStreamCmd(true); + qDebug("USRPInputThread::run - timeout - restarting"); } else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) { qDebug("USRPInputThread::run - overflow"); m_overflows++; } + else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_LATE_COMMAND) + qDebug("USRPInputThread::run - late command error"); + else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_BROKEN_CHAIN) + qDebug("USRPInputThread::run - broken chain error"); + else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_ALIGNMENT) + qDebug("USRPInputThread::run - alignment error"); + else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_BAD_PACKET) + qDebug("USRPInputThread::run - bad packet error"); - callbackIQ(m_buf, 2 * samples_received); + if (samples_received > 0) + callbackIQ(m_buf, 2 * samples_received); } } catch (std::exception& e) diff --git a/plugins/samplesource/usrpinput/usrpinputthread.h b/plugins/samplesource/usrpinput/usrpinputthread.h index f6d049844..9894f3141 100644 --- a/plugins/samplesource/usrpinput/usrpinputthread.h +++ b/plugins/samplesource/usrpinput/usrpinputthread.h @@ -36,7 +36,7 @@ class USRPInputThread : public QThread, public DeviceUSRPShared::ThreadInterface Q_OBJECT public: - USRPInputThread(uhd::rx_streamer::sptr stream, SampleSinkFifo* sampleFifo, QObject* parent = 0); + USRPInputThread(uhd::rx_streamer::sptr stream, size_t bufSamples, SampleSinkFifo* sampleFifo, QObject* parent = 0); ~USRPInputThread(); virtual void startWork(); @@ -45,6 +45,7 @@ public: virtual bool isRunning() { return m_running; } void setLog2Decimation(unsigned int log2_decim); void getStreamStatus(bool& active, quint32& overflows, quint32& m_timeouts); + void issueStreamCmd(bool start); private: QMutex m_startWaitMutex; @@ -56,13 +57,14 @@ private: quint32 m_timeouts; uhd::rx_streamer::sptr m_stream; - qint16 m_buf[2*DeviceUSRP::blockSize]; //must hold I+Q values of each sample hence 2xcomplex size + qint16 *m_buf; + size_t m_bufSamples; SampleVector m_convertBuffer; SampleSinkFifo* m_sampleFifo; unsigned int m_log2Decim; // soft decimation - Decimators m_decimatorsIQ; + Decimators m_decimatorsIQ; void run(); void callbackIQ(const qint16* buf, qint32 len); From d8ae6fc765fb0f8ebf2932aef4a75bcf44e09f70 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Sun, 25 Oct 2020 11:57:48 +0000 Subject: [PATCH 2/9] Import USRP support. Add LO offset support. Only set tx/rx_bandwidth after getting tx stream, to reduce TX LO leakage for <10MHz bandwidths. Check for reference and LO lock before getting streams. --- devices/usrp/deviceusrp.cpp | 28 +++++ devices/usrp/deviceusrp.h | 2 + devices/usrp/deviceusrpshared.h | 6 + plugins/samplesink/usrpoutput/usrpoutput.cpp | 70 +++++++----- plugins/samplesink/usrpoutput/usrpoutput.h | 2 +- .../samplesink/usrpoutput/usrpoutputgui.cpp | 13 +++ plugins/samplesink/usrpoutput/usrpoutputgui.h | 1 + .../samplesink/usrpoutput/usrpoutputgui.ui | 55 +++++++++ .../usrpoutput/usrpoutputsettings.cpp | 5 +- .../usrpoutput/usrpoutputsettings.h | 1 + plugins/samplesource/usrpinput/usrpinput.cpp | 105 +++++++++++------- plugins/samplesource/usrpinput/usrpinput.h | 2 +- .../samplesource/usrpinput/usrpinputgui.cpp | 15 ++- plugins/samplesource/usrpinput/usrpinputgui.h | 1 + .../samplesource/usrpinput/usrpinputgui.ui | 57 ++++++++++ .../usrpinput/usrpinputsettings.cpp | 5 +- .../usrpinput/usrpinputsettings.h | 1 + 17 files changed, 299 insertions(+), 70 deletions(-) diff --git a/devices/usrp/deviceusrp.cpp b/devices/usrp/deviceusrp.cpp index d5ef1ba4b..5d3e59307 100644 --- a/devices/usrp/deviceusrp.cpp +++ b/devices/usrp/deviceusrp.cpp @@ -69,3 +69,31 @@ void DeviceUSRP::enumOriginDevices(const QString& hardwareId, PluginInterface::O qDebug() << "DeviceUSRP::enumOriginDevices: exception: " << e.what(); } } + +void DeviceUSRP::waitForLock(uhd::usrp::multi_usrp::sptr usrp, const QString& clockSource, int channel) +{ + int tries; + const int maxTries = 100; + + // Wait for Ref lock + std::vector sensor_names; + sensor_names = usrp->get_tx_sensor_names(channel); + if (clockSource == "external") + { + if (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end()) + { + for (tries = 0; !usrp->get_mboard_sensor("ref_locked", 0).to_bool() && (tries < maxTries); tries++) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + if (tries == maxTries) + qCritical("USRPInput::acquireChannel: Failed to lock ref"); + } + } + // Wait for LO lock + if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked") != sensor_names.end()) + { + for (tries = 0; !usrp->get_tx_sensor("lo_locked", channel).to_bool() && (tries < maxTries); tries++) + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + if (tries == maxTries) + qCritical("USRPInput::acquireChannel: Failed to lock LO"); + } +} diff --git a/devices/usrp/deviceusrp.h b/devices/usrp/deviceusrp.h index 497129e72..e79e1d14c 100644 --- a/devices/usrp/deviceusrp.h +++ b/devices/usrp/deviceusrp.h @@ -33,6 +33,8 @@ public: /** Enumeration of USRP hardware devices */ static void enumOriginDevices(const QString& hardwareId, PluginInterface::OriginDevices& originDevices); + /** Wait for ref clock and LO to lock */ + static void waitForLock(uhd::usrp::multi_usrp::sptr usrp, const QString& clockSource, int channel); }; #endif /* DEVICES_USRP_DEVICEUSRP_H_ */ diff --git a/devices/usrp/deviceusrpshared.h b/devices/usrp/deviceusrpshared.h index 6d71db1f2..7ee429759 100644 --- a/devices/usrp/deviceusrpshared.h +++ b/devices/usrp/deviceusrpshared.h @@ -36,31 +36,37 @@ public: public: int getDevSampleRate() const { return m_devSampleRate; } uint64_t getCenterFrequency() const { return m_centerFrequency; } + int getLOOffset() const { return m_loOffset; } bool getRxElseTx() const { return m_rxElseTx; } static MsgReportBuddyChange* create( int devSampleRate, uint64_t centerFrequency, + int loOffset, bool rxElseTx) { return new MsgReportBuddyChange( devSampleRate, centerFrequency, + loOffset, rxElseTx); } private: int m_devSampleRate; //!< device/host sample rate uint64_t m_centerFrequency; //!< Center frequency + int m_loOffset; //!< LO offset bool m_rxElseTx; //!< tells which side initiated the message MsgReportBuddyChange( int devSampleRate, uint64_t centerFrequency, + int loOffset, bool rxElseTx) : Message(), m_devSampleRate(devSampleRate), m_centerFrequency(centerFrequency), + m_loOffset(loOffset), m_rxElseTx(rxElseTx) { } }; diff --git a/plugins/samplesink/usrpoutput/usrpoutput.cpp b/plugins/samplesink/usrpoutput/usrpoutput.cpp index 0b2b5d33e..b175136e3 100644 --- a/plugins/samplesink/usrpoutput/usrpoutput.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutput.cpp @@ -293,6 +293,13 @@ bool USRPOutput::acquireChannel() { try { + uhd::usrp::multi_usrp::sptr usrp = m_deviceShared.m_deviceParams->getDevice(); + + // Apply settings before creating stream + // However, don't set LPF to <10MHz at this stage, otherwise there is massive TX LO leakage + applySettings(m_settings, true, true); + usrp->set_tx_bandwidth(56000000, m_deviceShared.m_channel); + // set up the stream std::string cpu_format("sc16"); std::string wire_format("sc16"); @@ -302,10 +309,16 @@ bool USRPOutput::acquireChannel() uhd::stream_args_t stream_args(cpu_format, wire_format); stream_args.channels = channel_nums; - m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_tx_stream(stream_args); + m_streamId = usrp->get_tx_stream(stream_args); // Match our transmit buffer size to what UHD uses m_bufSamples = m_streamId->get_max_num_samps(); + + // Wait for reference and LO to lock + DeviceUSRP::waitForLock(usrp, m_settings.m_clockSource, m_deviceShared.m_channel); + + // Now we can set desired bandwidth + usrp->set_tx_bandwidth(m_settings.m_lpfBW, m_deviceShared.m_channel); } catch (std::exception& e) { @@ -326,14 +339,8 @@ void USRPOutput::releaseChannel() suspendRxBuddies(); suspendTxBuddies(); - // FIXME: Currently we do not try to destroy the stream, as there seems to be - // an issue when we re-acquire the stream, the output spectrum will not be correct - // The transmitter output will be disabled when we stop sending data to it anyway - if (false) - { - // destroy the stream - m_streamId = nullptr; - } + // destroy the stream + m_streamId = nullptr; resumeTxBuddies(); resumeRxBuddies(); @@ -343,7 +350,7 @@ void USRPOutput::releaseChannel() void USRPOutput::init() { - applySettings(m_settings, true); + applySettings(m_settings, false, true); } bool USRPOutput::start() @@ -362,8 +369,6 @@ bool USRPOutput::start() m_usrpOutputThread = new USRPOutputThread(m_streamId, m_bufSamples, &m_sampleSourceFifo); qDebug("USRPOutput::start: thread created"); - applySettings(m_settings, true); - m_usrpOutputThread->setLog2Interpolation(m_settings.m_log2SoftInterp); m_usrpOutputThread->startWork(); @@ -494,7 +499,7 @@ bool USRPOutput::handleMessage(const Message& message) MsgConfigureUSRP& conf = (MsgConfigureUSRP&) message; qDebug() << "USRPOutput::handleMessage: MsgConfigureUSRP"; - if (!applySettings(conf.getSettings(), conf.getForce())) + if (!applySettings(conf.getSettings(), false, conf.getForce())) { qDebug("USRPOutput::handleMessage config error"); } @@ -542,6 +547,7 @@ bool USRPOutput::handleMessage(const Message& message) { m_settings.m_devSampleRate = report.getDevSampleRate(); m_settings.m_centerFrequency = report.getCenterFrequency(); + m_settings.m_loOffset = report.getLOOffset(); } DSPSignalNotification *notif = new DSPSignalNotification( @@ -550,7 +556,7 @@ bool USRPOutput::handleMessage(const Message& message) m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif); DeviceUSRPShared::MsgReportBuddyChange *reportToGUI = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, false); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); getMessageQueueToGUI()->push(reportToGUI); return true; @@ -604,7 +610,7 @@ bool USRPOutput::handleMessage(const Message& message) } } -bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) +bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetStream, bool force) { bool forwardChangeOwnDSP = false; bool forwardChangeTxDSP = false; @@ -626,7 +632,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) { reverseAPIKeys.append("clockSource"); - if (m_deviceShared.m_deviceParams->getDevice()) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { try { @@ -656,7 +662,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) reverseAPIKeys.append("devSampleRate"); forwardChangeAllDSP = true; - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_tx_rate(settings.m_devSampleRate, m_deviceShared.m_channel); double actualSampleRate = m_deviceShared.m_deviceParams->getDevice()->get_tx_rate(m_deviceShared.m_channel); @@ -667,6 +673,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) } if ((m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_loOffset != settings.m_loOffset) || (m_settings.m_transverterMode != settings.m_transverterMode) || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency) || force) @@ -676,12 +683,20 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) reverseAPIKeys.append("transverterDeltaFrequency"); forwardChangeTxDSP = true; - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { - uhd::tune_request_t tune_request(deviceCenterFrequency); - m_deviceShared.m_deviceParams->getDevice()->set_tx_freq(tune_request, m_deviceShared.m_channel); + if (settings.m_loOffset != 0) + { + uhd::tune_request_t tune_request(deviceCenterFrequency, settings.m_loOffset); + m_deviceShared.m_deviceParams->getDevice()->set_tx_freq(tune_request, m_deviceShared.m_channel); + } + else + { + uhd::tune_request_t tune_request(deviceCenterFrequency); + m_deviceShared.m_deviceParams->getDevice()->set_tx_freq(tune_request, m_deviceShared.m_channel); + } m_deviceShared.m_centerFrequency = deviceCenterFrequency; // for buddies - qDebug("USRPOutput::applySettings: frequency set to %lld", deviceCenterFrequency); + qDebug("USRPOutput::applySettings: frequency set to %lld with LO offset %d", deviceCenterFrequency, settings.m_loOffset); } } @@ -707,7 +722,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) { reverseAPIKeys.append("gain"); - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_tx_gain(settings.m_gain, m_deviceShared.m_channel); qDebug() << "USRPOutput::applySettings: Gain set to " << settings.m_gain; @@ -718,6 +733,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) { reverseAPIKeys.append("lpfBW"); + // Don't set bandwidth before get_tx_stream (See above) if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) { m_deviceShared.m_deviceParams->getDevice()->set_tx_bandwidth(settings.m_lpfBW, m_deviceShared.m_channel); @@ -742,7 +758,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) { reverseAPIKeys.append("antennaPath"); - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_tx_antenna(settings.m_antennaPath.toStdString(), m_deviceShared.m_channel); qDebug("USRPOutput::applySettings: set antenna path to %s on channel %d", qPrintable(settings.m_antennaPath), m_deviceShared.m_channel); @@ -779,7 +795,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) for (; itSink != sinkBuddies.end(); ++itSink) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, false); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); (*itSink)->getSamplingDeviceInputMessageQueue()->push(report); } @@ -790,7 +806,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) for (; itSource != sourceBuddies.end(); ++itSource) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, false); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); (*itSource)->getSamplingDeviceInputMessageQueue()->push(report); } } @@ -811,7 +827,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool force) for (; itSink != sinkBuddies.end(); ++itSink) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, false); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); (*itSink)->getSamplingDeviceInputMessageQueue()->push(report); } } @@ -1035,7 +1051,7 @@ void USRPOutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response quint32 underflows = 0; quint32 droppedPackets = 0; - if ((m_streamId != nullptr) && m_channelAcquired) + if ((m_streamId != nullptr) && (m_usrpOutputThread != nullptr) && m_channelAcquired) { m_usrpOutputThread->getStreamStatus(active, underflows, droppedPackets); success = true; diff --git a/plugins/samplesink/usrpoutput/usrpoutput.h b/plugins/samplesink/usrpoutput/usrpoutput.h index 7ebec32d0..e61581903 100644 --- a/plugins/samplesink/usrpoutput/usrpoutput.h +++ b/plugins/samplesink/usrpoutput/usrpoutput.h @@ -238,7 +238,7 @@ private: void resumeRxBuddies(); void suspendTxBuddies(); void resumeTxBuddies(); - bool applySettings(const USRPOutputSettings& settings, bool force = false); + bool applySettings(const USRPOutputSettings& settings, bool preGetStream, bool force = false); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); void webapiReverseSendSettings(QList& deviceSettingsKeys, const USRPOutputSettings& settings, bool force); void webapiReverseSendStartStop(bool start); diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.cpp b/plugins/samplesink/usrpoutput/usrpoutputgui.cpp index f4874ec24..bdf013cf2 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.cpp @@ -57,6 +57,9 @@ USRPOutputGUI::USRPOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); ui->sampleRate->setValueRange(8, (uint32_t) minF, (uint32_t) maxF); + ui->loOffset->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); + ui->loOffset->setValueRange(false, 5, (int32_t)-maxF/2/1000, (int32_t)maxF/2/1000); // LO offset shouldn't be greater than half the sample rate + m_usrpOutput->getLPRange(minF, maxF); ui->lpf->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); ui->lpf->setValueRange(5, (minF/1000)+1, maxF/1000); @@ -181,6 +184,7 @@ bool USRPOutputGUI::handleMessage(const Message& message) if (!report.getRxElseTx()) { m_settings.m_centerFrequency = report.getCenterFrequency(); + m_settings.m_loOffset = report.getLOOffset(); } blockApplySettings(true); @@ -293,6 +297,8 @@ void USRPOutputGUI::updateSampleRate() } else { ui->sampleRateLabel->setText(tr("%1M").arg(QString::number(sr / 1000000.0f, 'g', 5))); } + // LO offset shouldn't be greater than half the sample rate + ui->loOffset->setValueRange(false, 5, -(int32_t)sr/2/1000, (int32_t)sr/2/1000); } void USRPOutputGUI::displaySampleRate() @@ -343,6 +349,7 @@ void USRPOutputGUI::displaySettings() updateSampleRate(); ui->lpf->setValue(m_settings.m_lpfBW / 1000); + ui->loOffset->setValue(m_settings.m_loOffset / 1000); ui->gain->setValue(m_settings.m_gain); ui->gainText->setText(tr("%1dB").arg(m_settings.m_gain)); @@ -497,6 +504,12 @@ void USRPOutputGUI::on_lpf_changed(quint64 value) sendSettings(); } +void USRPOutputGUI::on_loOffset_changed(qint64 value) +{ + m_settings.m_loOffset = value * 1000; + sendSettings(); +} + void USRPOutputGUI::on_gain_valueChanged(int value) { m_settings.m_gain = value; diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.h b/plugins/samplesink/usrpoutput/usrpoutputgui.h index 1429b9c0a..1f337e40f 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.h +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.h @@ -88,6 +88,7 @@ private slots: void on_sampleRate_changed(quint64 value); void on_swInterp_currentIndexChanged(int index); void on_lpf_changed(quint64 value); + void on_loOffset_changed(qint64 value); void on_gain_valueChanged(int value); void on_antenna_currentIndexChanged(int index); void on_clockSource_currentIndexChanged(int index); diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.ui b/plugins/samplesink/usrpoutput/usrpoutputgui.ui index 5b740bd57..49abaea36 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.ui +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.ui @@ -562,6 +562,55 @@ + + + + Qt::Vertical + + + + + + + LO + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + LO frequency offset. This should not be greater than half the sample rate. + + + + + + + kHz + + + @@ -684,6 +733,12 @@
gui/valuedial.h
1 + + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
TransverterButton QPushButton diff --git a/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp b/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp index 4c40887a8..941962b9b 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp @@ -29,8 +29,9 @@ void USRPOutputSettings::resetToDefaults() { m_centerFrequency = 435000*1000; m_devSampleRate = 3000000; + m_loOffset = 0; m_log2SoftInterp = 0; - m_lpfBW = 5.5e6f; + m_lpfBW = 10e6f; m_gain = 50; m_antennaPath = "TX/RX"; m_clockSource = "internal"; @@ -58,6 +59,7 @@ QByteArray USRPOutputSettings::serialize() const s.writeString(10, m_reverseAPIAddress); s.writeU32(11, m_reverseAPIPort); s.writeU32(12, m_reverseAPIDeviceIndex); + s.writeS32(13, m_loOffset); return s.final(); } @@ -97,6 +99,7 @@ bool USRPOutputSettings::deserialize(const QByteArray& data) d.readU32(12, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; + d.readS32(13, &m_loOffset, 0); return true; } diff --git a/plugins/samplesink/usrpoutput/usrpoutputsettings.h b/plugins/samplesink/usrpoutput/usrpoutputsettings.h index 410dbbdd5..899a60c72 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputsettings.h +++ b/plugins/samplesink/usrpoutput/usrpoutputsettings.h @@ -33,6 +33,7 @@ struct USRPOutputSettings // global settings to be saved uint64_t m_centerFrequency; int m_devSampleRate; + int m_loOffset; // channel settings uint32_t m_log2SoftInterp; float m_lpfBW; //!< Analog lowpass filter bandwidth (Hz) diff --git a/plugins/samplesource/usrpinput/usrpinput.cpp b/plugins/samplesource/usrpinput/usrpinput.cpp index d7598aa02..cdd14a0aa 100644 --- a/plugins/samplesource/usrpinput/usrpinput.cpp +++ b/plugins/samplesource/usrpinput/usrpinput.cpp @@ -316,25 +316,41 @@ bool USRPInput::acquireChannel() suspendRxBuddies(); suspendTxBuddies(); - try + if (m_streamId == nullptr) { - // set up the stream - std::string cpu_format("sc16"); - std::string wire_format("sc16"); - std::vector channel_nums; - channel_nums.push_back(m_deviceShared.m_channel); + try + { + uhd::usrp::multi_usrp::sptr usrp = m_deviceShared.m_deviceParams->getDevice(); - uhd::stream_args_t stream_args(cpu_format, wire_format); - stream_args.channels = channel_nums; + // Apply settings before creating stream + // However, don't set LPF to <10MHz at this stage, otherwise there is massive TX LO leakage + applySettings(m_settings, true, true); + usrp->set_rx_bandwidth(56000000, m_deviceShared.m_channel); - m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_rx_stream(stream_args); + // set up the stream + std::string cpu_format("sc16"); + std::string wire_format("sc16"); + std::vector channel_nums; + channel_nums.push_back(m_deviceShared.m_channel); - // Match our receive buffer size to what UHD uses - m_bufSamples = m_streamId->get_max_num_samps(); - } - catch (std::exception& e) - { - qDebug() << "USRPInput::acquireChannel: exception: " << e.what(); + uhd::stream_args_t stream_args(cpu_format, wire_format); + stream_args.channels = channel_nums; + + m_streamId = m_deviceShared.m_deviceParams->getDevice()->get_rx_stream(stream_args); + + // Match our receive buffer size to what UHD uses + m_bufSamples = m_streamId->get_max_num_samps(); + + // Wait for reference and LO to lock + DeviceUSRP::waitForLock(usrp, m_settings.m_clockSource, m_deviceShared.m_channel); + + // Now we can set desired bandwidth + usrp->set_rx_bandwidth(m_settings.m_lpfBW, m_deviceShared.m_channel); + } + catch (std::exception& e) + { + qDebug() << "USRPInput::acquireChannel: exception: " << e.what(); + } } resumeTxBuddies(); @@ -350,7 +366,7 @@ void USRPInput::releaseChannel() suspendRxBuddies(); suspendTxBuddies(); - // destroy the stream - FIXME: Better way to do this? + // destroy the stream m_streamId = nullptr; resumeTxBuddies(); @@ -363,7 +379,7 @@ void USRPInput::releaseChannel() void USRPInput::init() { - applySettings(m_settings, true); + applySettings(m_settings, false, true); } bool USRPInput::start() @@ -384,8 +400,6 @@ bool USRPInput::start() m_usrpInputThread = new USRPInputThread(m_streamId, m_bufSamples, &m_sampleFifo); qDebug("USRPInput::start: thread created"); - applySettings(m_settings, true); - m_usrpInputThread->setLog2Decimation(m_settings.m_log2SoftDecim); m_usrpInputThread->startWork(); @@ -521,7 +535,7 @@ bool USRPInput::handleMessage(const Message& message) MsgConfigureUSRP& conf = (MsgConfigureUSRP&) message; qDebug() << "USRPInput::handleMessage: MsgConfigureUSRP"; - if (!applySettings(conf.getSettings(), conf.getForce())) + if (!applySettings(conf.getSettings(), false, conf.getForce())) { qDebug("USRPInput::handleMessage config error"); } @@ -536,6 +550,7 @@ bool USRPInput::handleMessage(const Message& message) { m_settings.m_devSampleRate = report.getDevSampleRate(); m_settings.m_centerFrequency = report.getCenterFrequency(); + m_settings.m_loOffset = report.getLOOffset(); } else if (m_running) { @@ -556,7 +571,7 @@ bool USRPInput::handleMessage(const Message& message) if (getMessageQueueToGUI()) { DeviceUSRPShared::MsgReportBuddyChange *reportToGUI = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, true); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, true); getMessageQueueToGUI()->push(reportToGUI); } @@ -633,7 +648,7 @@ bool USRPInput::handleMessage(const Message& message) } } -bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) +bool USRPInput::applySettings(const USRPInputSettings& settings, bool preGetStream, bool force) { bool forwardChangeOwnDSP = false; bool forwardChangeRxDSP = false; @@ -655,7 +670,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) { reverseAPIKeys.append("clockSource"); - if (m_deviceShared.m_deviceParams->getDevice()) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { try { @@ -686,7 +701,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) reverseAPIKeys.append("devSampleRate"); forwardChangeAllDSP = true; - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_rx_rate(settings.m_devSampleRate, m_deviceShared.m_channel); double actualSampleRate = m_deviceShared.m_deviceParams->getDevice()->get_rx_rate(m_deviceShared.m_channel); @@ -698,6 +713,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) } if ((m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_loOffset != settings.m_loOffset) || (m_settings.m_transverterMode != settings.m_transverterMode) || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency) || force) @@ -707,26 +723,34 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) reverseAPIKeys.append("transverterDeltaFrequency"); forwardChangeRxDSP = true; - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { - uhd::tune_request_t tune_request(deviceCenterFrequency); - m_deviceShared.m_deviceParams->getDevice()->set_rx_freq(tune_request, m_deviceShared.m_channel); + if (settings.m_loOffset != 0) + { + uhd::tune_request_t tune_request(deviceCenterFrequency, settings.m_loOffset); + m_deviceShared.m_deviceParams->getDevice()->set_rx_freq(tune_request, m_deviceShared.m_channel); + } + else + { + uhd::tune_request_t tune_request(deviceCenterFrequency); + m_deviceShared.m_deviceParams->getDevice()->set_rx_freq(tune_request, m_deviceShared.m_channel); + } m_deviceShared.m_centerFrequency = deviceCenterFrequency; // for buddies - qDebug("USRPInput::applySettings: frequency set to %lld", deviceCenterFrequency); + qDebug("USRPInput::applySettings: frequency set to %lld with LO offset %d", deviceCenterFrequency, settings.m_loOffset); } } if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) { reverseAPIKeys.append("dcBlock"); - if (m_deviceShared.m_deviceParams->getDevice()) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) m_deviceShared.m_deviceParams->getDevice()->set_rx_dc_offset(settings.m_dcBlock, m_deviceShared.m_channel); } if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) { reverseAPIKeys.append("iqCorrection"); - if (m_deviceShared.m_deviceParams->getDevice()) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) m_deviceShared.m_deviceParams->getDevice()->set_rx_iq_balance(settings.m_iqCorrection, m_deviceShared.m_channel); } @@ -734,7 +758,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) { reverseAPIKeys.append("gainMode"); - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { if (settings.m_gainMode == USRPInputSettings::GAIN_AUTO) { @@ -754,7 +778,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) { reverseAPIKeys.append("gain"); - if ((settings.m_gainMode != USRPInputSettings::GAIN_AUTO) && m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if ((settings.m_gainMode != USRPInputSettings::GAIN_AUTO) && m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_rx_gain(settings.m_gain, m_deviceShared.m_channel); qDebug() << "USRPInput::applySettings: Gain set to " << settings.m_gain << " for channel " << m_deviceShared.m_channel; @@ -764,8 +788,13 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) if ((m_settings.m_lpfBW != settings.m_lpfBW) || force) { reverseAPIKeys.append("lpfBW"); - m_deviceShared.m_deviceParams->getDevice()->set_rx_bandwidth(settings.m_lpfBW, m_deviceShared.m_channel); - qDebug("USRPOutput::applySettings: LPF BW: %f for channel %d", settings.m_lpfBW, m_deviceShared.m_channel); + + // Don't set bandwidth before get_rx_stream (See above) + if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + { + m_deviceShared.m_deviceParams->getDevice()->set_rx_bandwidth(settings.m_lpfBW, m_deviceShared.m_channel); + qDebug("USRPInput::applySettings: LPF BW: %f for channel %d", settings.m_lpfBW, m_deviceShared.m_channel); + } } if ((m_settings.m_log2SoftDecim != settings.m_log2SoftDecim) || force) @@ -785,7 +814,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) { reverseAPIKeys.append("antennaPath"); - if (m_deviceShared.m_deviceParams->getDevice() && m_channelAcquired) + if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_rx_antenna(settings.m_antennaPath.toStdString(), m_deviceShared.m_channel); qDebug("USRPInput::applySettings: set antenna path to %s on channel %d", qPrintable(settings.m_antennaPath), m_deviceShared.m_channel); @@ -835,7 +864,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) for (; itSource != sourceBuddies.end(); ++itSource) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, true); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, true); (*itSource)->getSamplingDeviceInputMessageQueue()->push(report); } @@ -846,7 +875,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) for (; itSink != sinkBuddies.end(); ++itSink) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, true); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, true); (*itSink)->getSamplingDeviceInputMessageQueue()->push(report); } } @@ -867,7 +896,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool force) for (; itSource != sourceBuddies.end(); ++itSource) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, true); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, true); (*itSource)->getSamplingDeviceInputMessageQueue()->push(report); } } diff --git a/plugins/samplesource/usrpinput/usrpinput.h b/plugins/samplesource/usrpinput/usrpinput.h index 82cbefa85..0190f5ab6 100644 --- a/plugins/samplesource/usrpinput/usrpinput.h +++ b/plugins/samplesource/usrpinput/usrpinput.h @@ -239,7 +239,7 @@ private: void resumeRxBuddies(); void suspendTxBuddies(); void resumeTxBuddies(); - bool applySettings(const USRPInputSettings& settings, bool force = false); + bool applySettings(const USRPInputSettings& settings, bool preGetStream, bool force = false); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); void webapiReverseSendSettings(QList& deviceSettingsKeys, const USRPInputSettings& settings, bool force); void webapiReverseSendStartStop(bool start); diff --git a/plugins/samplesource/usrpinput/usrpinputgui.cpp b/plugins/samplesource/usrpinput/usrpinputgui.cpp index ab107e7a2..e63b48f3b 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.cpp +++ b/plugins/samplesource/usrpinput/usrpinputgui.cpp @@ -61,6 +61,9 @@ USRPInputGUI::USRPInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); ui->sampleRate->setValueRange(8, (uint32_t) minF, (uint32_t) maxF); + ui->loOffset->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); + ui->loOffset->setValueRange(false, 5, (int32_t)-maxF/2/1000, (int32_t)maxF/2/1000); // LO offset shouldn't be greater than half the sample rate + m_usrpInput->getLPRange(minF, maxF); ui->lpf->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); ui->lpf->setValueRange(5, (minF/1000)+1, maxF/1000); @@ -164,6 +167,7 @@ bool USRPInputGUI::handleMessage(const Message& message) if (report.getRxElseTx()) { m_settings.m_centerFrequency = report.getCenterFrequency(); + m_settings.m_loOffset = report.getLOOffset(); } blockApplySettings(true); @@ -174,7 +178,7 @@ bool USRPInputGUI::handleMessage(const Message& message) } else if (DeviceUSRPShared::MsgReportClockSourceChange::match(message)) { -qDebug("USRPInputGUI::handleMessage MsgReportClockSourceChange"); + qDebug("USRPInputGUI::handleMessage MsgReportClockSourceChange"); DeviceUSRPShared::MsgReportClockSourceChange& report = (DeviceUSRPShared::MsgReportClockSourceChange&) message; m_settings.m_clockSource = report.getClockSource(); @@ -289,6 +293,8 @@ void USRPInputGUI::updateSampleRate() } else { ui->sampleRateLabel->setText(tr("%1M").arg(QString::number(sr / 1000000.0f, 'g', 5))); } + // LO offset shouldn't be greater than half the sample rate + ui->loOffset->setValueRange(false, 5, -(int32_t)sr/2/1000, (int32_t)sr/2/1000); } void USRPInputGUI::updateSampleRateAndFrequency() @@ -350,6 +356,7 @@ void USRPInputGUI::displaySettings() updateSampleRate(); ui->lpf->setValue(m_settings.m_lpfBW / 1000); + ui->loOffset->setValue(m_settings.m_loOffset / 1000); ui->gain->setValue(m_settings.m_gain); ui->gainText->setText(tr("%1").arg(m_settings.m_gain)); @@ -527,6 +534,12 @@ void USRPInputGUI::on_lpf_changed(quint64 value) sendSettings(); } +void USRPInputGUI::on_loOffset_changed(qint64 value) +{ + m_settings.m_loOffset = value * 1000; + sendSettings(); +} + void USRPInputGUI::on_gainMode_currentIndexChanged(int index) { m_settings.m_gainMode = (USRPInputSettings::GainMode) index; diff --git a/plugins/samplesource/usrpinput/usrpinputgui.h b/plugins/samplesource/usrpinput/usrpinputgui.h index cfa1e8aa7..9790d7fb2 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.h +++ b/plugins/samplesource/usrpinput/usrpinputgui.h @@ -89,6 +89,7 @@ private slots: void on_sampleRate_changed(quint64 value); void on_swDecim_currentIndexChanged(int index); void on_lpf_changed(quint64 value); + void on_loOffset_changed(qint64 value); void on_gainMode_currentIndexChanged(int index); void on_gain_valueChanged(int value); void on_antenna_currentIndexChanged(int index); diff --git a/plugins/samplesource/usrpinput/usrpinputgui.ui b/plugins/samplesource/usrpinput/usrpinputgui.ui index 959d08a75..c599ad659 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.ui +++ b/plugins/samplesource/usrpinput/usrpinputgui.ui @@ -626,6 +626,57 @@
+ + + + Qt::Vertical + + + + + + + LO + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + 50 + false + + + + PointingHandCursor + + + LO offset (kHz) + + + + + + + kHz + + + @@ -753,6 +804,12 @@ QPushButton
gui/transverterbutton.h
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
diff --git a/plugins/samplesource/usrpinput/usrpinputsettings.cpp b/plugins/samplesource/usrpinput/usrpinputsettings.cpp index e16f9b94f..0a8adf6b4 100644 --- a/plugins/samplesource/usrpinput/usrpinputsettings.cpp +++ b/plugins/samplesource/usrpinput/usrpinputsettings.cpp @@ -28,10 +28,11 @@ void USRPInputSettings::resetToDefaults() { m_centerFrequency = 435000*1000; m_devSampleRate = 3000000; + m_loOffset = 0; m_dcBlock = false; m_iqCorrection = false; m_log2SoftDecim = 0; - m_lpfBW = 5.5e6f; + m_lpfBW = 10e6f; m_gain = 50; m_antennaPath = "TX/RX"; m_gainMode = GAIN_AUTO; @@ -63,6 +64,7 @@ QByteArray USRPInputSettings::serialize() const s.writeString(13, m_reverseAPIAddress); s.writeU32(14, m_reverseAPIPort); s.writeU32(15, m_reverseAPIDeviceIndex); + s.writeS32(16, m_loOffset); return s.final(); } @@ -105,6 +107,7 @@ bool USRPInputSettings::deserialize(const QByteArray& data) d.readU32(15, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; + d.readS32(16, &m_loOffset, 0); return true; } diff --git a/plugins/samplesource/usrpinput/usrpinputsettings.h b/plugins/samplesource/usrpinput/usrpinputsettings.h index 3774db555..a485d2e80 100644 --- a/plugins/samplesource/usrpinput/usrpinputsettings.h +++ b/plugins/samplesource/usrpinput/usrpinputsettings.h @@ -37,6 +37,7 @@ struct USRPInputSettings // global settings to be saved uint64_t m_centerFrequency; int m_devSampleRate; + int m_loOffset; // channel settings bool m_dcBlock; bool m_iqCorrection; From 035a0ab2cb392c26f7888655dd87a125667b175a Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Sun, 25 Oct 2020 19:58:32 +0000 Subject: [PATCH 3/9] Add header to avoid compilation failure on Linux --- devices/usrp/deviceusrp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/devices/usrp/deviceusrp.cpp b/devices/usrp/deviceusrp.cpp index 5d3e59307..0eb5a1116 100644 --- a/devices/usrp/deviceusrp.cpp +++ b/devices/usrp/deviceusrp.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include From 35380d4f3665c46d5b6901374f5eb57071c1b7a7 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Sun, 25 Oct 2020 20:08:57 +0000 Subject: [PATCH 4/9] Document LO offset options --- plugins/samplesink/usrpoutput/readme.md | 4 ++++ plugins/samplesource/usrpinput/readme.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/plugins/samplesink/usrpoutput/readme.md b/plugins/samplesink/usrpoutput/readme.md index 15795fc07..3500ad751 100644 --- a/plugins/samplesink/usrpoutput/readme.md +++ b/plugins/samplesink/usrpoutput/readme.md @@ -105,6 +105,10 @@ Use this slider to adjust the global gain of the Tx chain. The allowable values This is the Tx hardware filter bandwidth in kHz in the AD936x device for the given channel. Use the wheels to adjust the value. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2. +

Tx LO offset

+ +This adjusts the Tx local oscillator (LO) frequency from the centre frequency by the given amount in kHz, and the NCOs are used to digitally shift the signal to the set centre frequency. This can be used to push the Tx LO leakage (which for the AD396x is -50dBc) out of band. The shift should be less than half of the sample rate. +

12: Stream status indicator

This label turns green when data has been transmitted to the device. diff --git a/plugins/samplesource/usrpinput/readme.md b/plugins/samplesource/usrpinput/readme.md index 55e0b0203..4521041fe 100644 --- a/plugins/samplesource/usrpinput/readme.md +++ b/plugins/samplesource/usrpinput/readme.md @@ -118,6 +118,10 @@ Check this button to enable IQ imbalance correction. This is the Rx hardware IF filter bandwidth in kHz for the given channel. Use the wheels to adjust the value. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2. +

Rx LO offset

+ +This adjusts the Rx local oscillator (LO) frequency from the centre frequency by the given amount in kHz, and the NCOs are used to digitally shift the signal to compensate. The shift should be less than half of the sample rate. +

15: Stream status indicator

This label turns green when data is being received from the device. From 636c014427d4c0464ef329e1b4c182491292d2d6 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Mon, 26 Oct 2020 09:03:23 +0000 Subject: [PATCH 5/9] Add loOffset to API --- plugins/samplesink/usrpoutput/usrpoutput.cpp | 7 ++++++ plugins/samplesource/usrpinput/usrpinput.cpp | 7 ++++++ sdrbase/resources/webapi/doc/html2/index.html | 8 ++++++- .../sdrangel/api/swagger/include/USRP.yaml | 4 ++++ swagger/sdrangel/code/html2/index.html | 8 ++++++- .../code/qt5/client/SWGUSRPInputSettings.cpp | 23 +++++++++++++++++++ .../code/qt5/client/SWGUSRPInputSettings.h | 6 +++++ .../code/qt5/client/SWGUSRPOutputSettings.cpp | 23 +++++++++++++++++++ .../code/qt5/client/SWGUSRPOutputSettings.h | 6 +++++ 9 files changed, 90 insertions(+), 2 deletions(-) diff --git a/plugins/samplesink/usrpoutput/usrpoutput.cpp b/plugins/samplesink/usrpoutput/usrpoutput.cpp index b175136e3..b389c67da 100644 --- a/plugins/samplesink/usrpoutput/usrpoutput.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutput.cpp @@ -951,6 +951,9 @@ void USRPOutput::webapiUpdateDeviceSettings( if (deviceSettingsKeys.contains("devSampleRate")) { settings.m_devSampleRate = response.getUsrpOutputSettings()->getDevSampleRate(); } + if (deviceSettingsKeys.contains("loOffset")) { + settings.m_loOffset = response.getUsrpOutputSettings()->getLoOffset(); + } if (deviceSettingsKeys.contains("clockSource")) { settings.m_clockSource = *response.getUsrpOutputSettings()->getClockSource(); } @@ -998,6 +1001,7 @@ void USRPOutput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& resp response.getUsrpOutputSettings()->setAntennaPath(new QString(settings.m_antennaPath)); response.getUsrpOutputSettings()->setCenterFrequency(settings.m_centerFrequency); response.getUsrpOutputSettings()->setDevSampleRate(settings.m_devSampleRate); + response.getUsrpOutputSettings()->setLoOffset(settings.m_loOffset); response.getUsrpOutputSettings()->setClockSource(new QString(settings.m_clockSource)); response.getUsrpOutputSettings()->setGain(settings.m_gain); response.getUsrpOutputSettings()->setLog2SoftInterp(settings.m_log2SoftInterp); @@ -1083,6 +1087,9 @@ void USRPOutput::webapiReverseSendSettings(QList& deviceSettingsKeys, c if (deviceSettingsKeys.contains("devSampleRate") || force) { swgUsrpOutputSettings->setDevSampleRate(settings.m_devSampleRate); } + if (deviceSettingsKeys.contains("loOffset") || force) { + swgUsrpOutputSettings->setLoOffset(settings.m_loOffset); + } if (deviceSettingsKeys.contains("clockSource") || force) { swgUsrpOutputSettings->setClockSource(new QString(settings.m_clockSource)); } diff --git a/plugins/samplesource/usrpinput/usrpinput.cpp b/plugins/samplesource/usrpinput/usrpinput.cpp index cdd14a0aa..52d26c3b3 100644 --- a/plugins/samplesource/usrpinput/usrpinput.cpp +++ b/plugins/samplesource/usrpinput/usrpinput.cpp @@ -1025,6 +1025,9 @@ void USRPInput::webapiUpdateDeviceSettings( if (deviceSettingsKeys.contains("centerFrequency")) { settings.m_centerFrequency = response.getUsrpInputSettings()->getCenterFrequency(); } + if (deviceSettingsKeys.contains("loOffset")) { + settings.m_loOffset = response.getUsrpInputSettings()->getLoOffset(); + } if (deviceSettingsKeys.contains("dcBlock")) { settings.m_dcBlock = response.getUsrpInputSettings()->getDcBlock() != 0; } @@ -1075,6 +1078,7 @@ void USRPInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& respo response.getUsrpInputSettings()->setCenterFrequency(settings.m_centerFrequency); response.getUsrpInputSettings()->setDcBlock(settings.m_dcBlock ? 1 : 0); response.getUsrpInputSettings()->setDevSampleRate(settings.m_devSampleRate); + response.getUsrpInputSettings()->setLoOffset(settings.m_loOffset); response.getUsrpInputSettings()->setClockSource(new QString(settings.m_clockSource)); response.getUsrpInputSettings()->setGain(settings.m_gain); response.getUsrpInputSettings()->setGainMode((int) settings.m_gainMode); @@ -1171,6 +1175,9 @@ void USRPInput::webapiReverseSendSettings(QList& deviceSettingsKeys, co if (deviceSettingsKeys.contains("centerFrequency") || force) { swgUsrpInputSettings->setCenterFrequency(settings.m_centerFrequency); } + if (deviceSettingsKeys.contains("loOffset") || force) { + swgUsrpInputSettings->setLoOffset(settings.m_loOffset); + } if (deviceSettingsKeys.contains("dcBlock") || force) { swgUsrpInputSettings->setDcBlock(settings.m_dcBlock ? 1 : 0); } diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index 2dd81cdeb..daacfd4b1 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -7583,6 +7583,9 @@ margin-bottom: 20px; "devSampleRate" : { "type" : "integer" }, + "loOffset" : { + "type" : "integer" + }, "dcBlock" : { "type" : "integer" }, @@ -7659,6 +7662,9 @@ margin-bottom: 20px; "devSampleRate" : { "type" : "integer" }, + "loOffset" : { + "type" : "integer" + }, "log2SoftInterp" : { "type" : "integer" }, @@ -39969,7 +39975,7 @@ except ApiException as e:
- Generated 2020-10-11T08:49:12.690+02:00 + Generated 2020-10-25T21:28:04.207+01:00
diff --git a/swagger/sdrangel/api/swagger/include/USRP.yaml b/swagger/sdrangel/api/swagger/include/USRP.yaml index 05d22351c..e388f288f 100644 --- a/swagger/sdrangel/api/swagger/include/USRP.yaml +++ b/swagger/sdrangel/api/swagger/include/USRP.yaml @@ -6,6 +6,8 @@ USRPInputSettings: format: int64 devSampleRate: type: integer + loOffset: + type: integer dcBlock: type: integer iqCorrection: @@ -46,6 +48,8 @@ USRPOutputSettings: format: int64 devSampleRate: type: integer + loOffset: + type: integer log2SoftInterp: type: integer lpfBW: diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index 2dd81cdeb..daacfd4b1 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -7583,6 +7583,9 @@ margin-bottom: 20px; "devSampleRate" : { "type" : "integer" }, + "loOffset" : { + "type" : "integer" + }, "dcBlock" : { "type" : "integer" }, @@ -7659,6 +7662,9 @@ margin-bottom: 20px; "devSampleRate" : { "type" : "integer" }, + "loOffset" : { + "type" : "integer" + }, "log2SoftInterp" : { "type" : "integer" }, @@ -39969,7 +39975,7 @@ except ApiException as e:
- Generated 2020-10-11T08:49:12.690+02:00 + Generated 2020-10-25T21:28:04.207+01:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.cpp index 61f39674b..963cdf5fa 100644 --- a/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.cpp @@ -32,6 +32,8 @@ SWGUSRPInputSettings::SWGUSRPInputSettings() { m_center_frequency_isSet = false; dev_sample_rate = 0; m_dev_sample_rate_isSet = false; + lo_offset = 0; + m_lo_offset_isSet = false; dc_block = 0; m_dc_block_isSet = false; iq_correction = 0; @@ -72,6 +74,8 @@ SWGUSRPInputSettings::init() { m_center_frequency_isSet = false; dev_sample_rate = 0; m_dev_sample_rate_isSet = false; + lo_offset = 0; + m_lo_offset_isSet = false; dc_block = 0; m_dc_block_isSet = false; iq_correction = 0; @@ -110,6 +114,7 @@ SWGUSRPInputSettings::cleanup() { + if(antenna_path != nullptr) { delete antenna_path; } @@ -143,6 +148,8 @@ SWGUSRPInputSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&dev_sample_rate, pJson["devSampleRate"], "qint32", ""); + ::SWGSDRangel::setValue(&lo_offset, pJson["loOffset"], "qint32", ""); + ::SWGSDRangel::setValue(&dc_block, pJson["dcBlock"], "qint32", ""); ::SWGSDRangel::setValue(&iq_correction, pJson["iqCorrection"], "qint32", ""); @@ -193,6 +200,9 @@ SWGUSRPInputSettings::asJsonObject() { if(m_dev_sample_rate_isSet){ obj->insert("devSampleRate", QJsonValue(dev_sample_rate)); } + if(m_lo_offset_isSet){ + obj->insert("loOffset", QJsonValue(lo_offset)); + } if(m_dc_block_isSet){ obj->insert("dcBlock", QJsonValue(dc_block)); } @@ -259,6 +269,16 @@ SWGUSRPInputSettings::setDevSampleRate(qint32 dev_sample_rate) { this->m_dev_sample_rate_isSet = true; } +qint32 +SWGUSRPInputSettings::getLoOffset() { + return lo_offset; +} +void +SWGUSRPInputSettings::setLoOffset(qint32 lo_offset) { + this->lo_offset = lo_offset; + this->m_lo_offset_isSet = true; +} + qint32 SWGUSRPInputSettings::getDcBlock() { return dc_block; @@ -410,6 +430,9 @@ SWGUSRPInputSettings::isSet(){ if(m_dev_sample_rate_isSet){ isObjectUpdated = true; break; } + if(m_lo_offset_isSet){ + isObjectUpdated = true; break; + } if(m_dc_block_isSet){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.h b/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.h index b4c6d20d4..5e8cabbc4 100644 --- a/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGUSRPInputSettings.h @@ -48,6 +48,9 @@ public: qint32 getDevSampleRate(); void setDevSampleRate(qint32 dev_sample_rate); + qint32 getLoOffset(); + void setLoOffset(qint32 lo_offset); + qint32 getDcBlock(); void setDcBlock(qint32 dc_block); @@ -100,6 +103,9 @@ private: qint32 dev_sample_rate; bool m_dev_sample_rate_isSet; + qint32 lo_offset; + bool m_lo_offset_isSet; + qint32 dc_block; bool m_dc_block_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.cpp index 46be95fae..5e666d639 100644 --- a/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.cpp @@ -32,6 +32,8 @@ SWGUSRPOutputSettings::SWGUSRPOutputSettings() { m_center_frequency_isSet = false; dev_sample_rate = 0; m_dev_sample_rate_isSet = false; + lo_offset = 0; + m_lo_offset_isSet = false; log2_soft_interp = 0; m_log2_soft_interp_isSet = false; lpf_bw = 0; @@ -66,6 +68,8 @@ SWGUSRPOutputSettings::init() { m_center_frequency_isSet = false; dev_sample_rate = 0; m_dev_sample_rate_isSet = false; + lo_offset = 0; + m_lo_offset_isSet = false; log2_soft_interp = 0; m_log2_soft_interp_isSet = false; lpf_bw = 0; @@ -97,6 +101,7 @@ SWGUSRPOutputSettings::cleanup() { + if(antenna_path != nullptr) { delete antenna_path; } @@ -128,6 +133,8 @@ SWGUSRPOutputSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&dev_sample_rate, pJson["devSampleRate"], "qint32", ""); + ::SWGSDRangel::setValue(&lo_offset, pJson["loOffset"], "qint32", ""); + ::SWGSDRangel::setValue(&log2_soft_interp, pJson["log2SoftInterp"], "qint32", ""); ::SWGSDRangel::setValue(&lpf_bw, pJson["lpfBW"], "qint32", ""); @@ -172,6 +179,9 @@ SWGUSRPOutputSettings::asJsonObject() { if(m_dev_sample_rate_isSet){ obj->insert("devSampleRate", QJsonValue(dev_sample_rate)); } + if(m_lo_offset_isSet){ + obj->insert("loOffset", QJsonValue(lo_offset)); + } if(m_log2_soft_interp_isSet){ obj->insert("log2SoftInterp", QJsonValue(log2_soft_interp)); } @@ -229,6 +239,16 @@ SWGUSRPOutputSettings::setDevSampleRate(qint32 dev_sample_rate) { this->m_dev_sample_rate_isSet = true; } +qint32 +SWGUSRPOutputSettings::getLoOffset() { + return lo_offset; +} +void +SWGUSRPOutputSettings::setLoOffset(qint32 lo_offset) { + this->lo_offset = lo_offset; + this->m_lo_offset_isSet = true; +} + qint32 SWGUSRPOutputSettings::getLog2SoftInterp() { return log2_soft_interp; @@ -350,6 +370,9 @@ SWGUSRPOutputSettings::isSet(){ if(m_dev_sample_rate_isSet){ isObjectUpdated = true; break; } + if(m_lo_offset_isSet){ + isObjectUpdated = true; break; + } if(m_log2_soft_interp_isSet){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.h b/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.h index 586ef560c..1955f9bdd 100644 --- a/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGUSRPOutputSettings.h @@ -48,6 +48,9 @@ public: qint32 getDevSampleRate(); void setDevSampleRate(qint32 dev_sample_rate); + qint32 getLoOffset(); + void setLoOffset(qint32 lo_offset); + qint32 getLog2SoftInterp(); void setLog2SoftInterp(qint32 log2_soft_interp); @@ -91,6 +94,9 @@ private: qint32 dev_sample_rate; bool m_dev_sample_rate_isSet; + qint32 lo_offset; + bool m_lo_offset_isSet; + qint32 log2_soft_interp; bool m_log2_soft_interp_isSet; From 2400c4643c5343013e3faf3342d8a532ef337913 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Mon, 26 Oct 2020 14:39:12 +0000 Subject: [PATCH 6/9] Add master clock rate display to GUI. Calculate full range of sample rates supported, by varying master clock. Check if requested sample rate can be met. --- devices/usrp/deviceusrp.cpp | 2 +- devices/usrp/deviceusrpparam.cpp | 84 +++++++++++++------ devices/usrp/deviceusrpparam.h | 12 +-- devices/usrp/deviceusrpshared.h | 6 ++ plugins/samplesink/usrpoutput/usrpoutput.cpp | 70 +++++++++++----- .../samplesink/usrpoutput/usrpoutputgui.cpp | 11 ++- .../samplesink/usrpoutput/usrpoutputgui.ui | 10 +++ .../usrpoutput/usrpoutputsettings.cpp | 1 + .../usrpoutput/usrpoutputsettings.h | 1 + plugins/samplesource/usrpinput/usrpinput.cpp | 53 +++++++----- .../samplesource/usrpinput/usrpinputgui.cpp | 11 ++- .../samplesource/usrpinput/usrpinputgui.ui | 20 +++-- .../usrpinput/usrpinputsettings.cpp | 1 + .../usrpinput/usrpinputsettings.h | 1 + 14 files changed, 198 insertions(+), 85 deletions(-) diff --git a/devices/usrp/deviceusrp.cpp b/devices/usrp/deviceusrp.cpp index 0eb5a1116..843027958 100644 --- a/devices/usrp/deviceusrp.cpp +++ b/devices/usrp/deviceusrp.cpp @@ -52,7 +52,7 @@ void DeviceUSRP::enumOriginDevices(const QString& hardwareId, PluginInterface::O qDebug() << "DeviceUSRP::enumOriginDevices: found USRP device " << displayedName; DeviceUSRPParams usrpParams; - usrpParams.open(id.toStdString().c_str()); + usrpParams.open(id.toStdString().c_str(), true); usrpParams.close(); originDevices.append(PluginInterface::OriginDevice( diff --git a/devices/usrp/deviceusrpparam.cpp b/devices/usrp/deviceusrpparam.cpp index 3d68c54b9..c54ec22a9 100644 --- a/devices/usrp/deviceusrpparam.cpp +++ b/devices/usrp/deviceusrpparam.cpp @@ -19,7 +19,7 @@ #include #include "deviceusrpparam.h" -bool DeviceUSRPParams::open(const char *deviceStr) +bool DeviceUSRPParams::open(const char *deviceStr, bool channelNumOnly) { qDebug("DeviceUSRPParams::open: %s", (const char *) deviceStr); @@ -32,37 +32,71 @@ bool DeviceUSRPParams::open(const char *deviceStr) m_nbRxChannels = m_dev->get_rx_num_channels(); m_nbTxChannels = m_dev->get_tx_num_channels(); - m_lpfRangeRx = m_dev->get_rx_bandwidth_range(); - m_lpfRangeTx = m_dev->get_tx_bandwidth_range(); + // Speed up program initialisation, by not getting all properties + // If we could find out number of channles without ::make ing the device + // that would be even better + if (!channelNumOnly) + { + m_lpfRangeRx = m_dev->get_rx_bandwidth_range(); + m_lpfRangeTx = m_dev->get_tx_bandwidth_range(); - m_loRangeRx = m_dev->get_fe_rx_freq_range(); - m_loRangeTx = m_dev->get_fe_tx_freq_range(); + m_loRangeRx = m_dev->get_fe_rx_freq_range(); + m_loRangeTx = m_dev->get_fe_tx_freq_range(); - m_srRangeRx = m_dev->get_rx_rates(); - m_srRangeTx = m_dev->get_tx_rates(); + // For some devices (B210), rx/tx_rates vary with master_clock_rate + // Note master_clock_rate is rate between FPGA and RFIC + // tx/rx_rate is rate between PC and FPGA + uhd::meta_range_t clockRange = m_dev->get_master_clock_rate_range(); + if (clockRange.start() == clockRange.stop()) + { + m_srRangeRx = m_dev->get_rx_rates(); + m_srRangeTx = m_dev->get_tx_rates(); + } + else + { + // Find max and min sample rate, for max and min master clock rates + m_dev->set_master_clock_rate(clockRange.start()); + uhd::meta_range_t rxLow = m_dev->get_rx_rates(); + uhd::meta_range_t txLow = m_dev->get_tx_rates(); - m_gainRangeRx = m_dev->get_rx_gain_range(); - m_gainRangeTx = m_dev->get_tx_gain_range(); + m_dev->set_master_clock_rate(clockRange.stop()); + uhd::meta_range_t rxHigh = m_dev->get_rx_rates(); + uhd::meta_range_t txHigh = m_dev->get_tx_rates(); - std::vector txAntennas = m_dev->get_tx_antennas(); - m_txAntennas.reserve(txAntennas.size()); - for(size_t i = 0, l = txAntennas.size(); i < l; ++i) - m_txAntennas << QString::fromStdString(txAntennas[i]); + m_srRangeRx = uhd::meta_range_t(std::min(rxLow.start(), rxHigh.start()), std::max(rxLow.stop(), rxHigh.stop())); + m_srRangeTx = uhd::meta_range_t(std::min(txLow.start(), txHigh.start()), std::max(txLow.stop(), txHigh.stop())); - std::vector rxAntennas = m_dev->get_rx_antennas(); - m_rxAntennas.reserve(rxAntennas.size()); - for(size_t i = 0, l = rxAntennas.size(); i < l; ++i) - m_rxAntennas << QString::fromStdString(rxAntennas[i]); + // Need to restore automatic clock rate + uhd::property_tree::sptr properties = m_dev->get_tree(); + if (properties->exists("/mboards/0/auto_tick_rate")) + { + properties->access("/mboards/0/auto_tick_rate").set(true); + } + } - std::vector rxGainNames = m_dev->get_rx_gain_names(); - m_rxGainNames.reserve(rxGainNames.size()); - for(size_t i = 0, l = rxGainNames.size(); i < l; ++i) - m_rxGainNames << QString::fromStdString(rxGainNames[i]); + m_gainRangeRx = m_dev->get_rx_gain_range(); + m_gainRangeTx = m_dev->get_tx_gain_range(); - std::vector clockSources = m_dev->get_clock_sources(0); - m_clockSources.reserve(clockSources.size()); - for(size_t i = 0, l = clockSources.size(); i < l; ++i) - m_clockSources << QString::fromStdString(clockSources[i]); + std::vector txAntennas = m_dev->get_tx_antennas(); + m_txAntennas.reserve(txAntennas.size()); + for(size_t i = 0, l = txAntennas.size(); i < l; ++i) + m_txAntennas << QString::fromStdString(txAntennas[i]); + + std::vector rxAntennas = m_dev->get_rx_antennas(); + m_rxAntennas.reserve(rxAntennas.size()); + for(size_t i = 0, l = rxAntennas.size(); i < l; ++i) + m_rxAntennas << QString::fromStdString(rxAntennas[i]); + + std::vector rxGainNames = m_dev->get_rx_gain_names(); + m_rxGainNames.reserve(rxGainNames.size()); + for(size_t i = 0, l = rxGainNames.size(); i < l; ++i) + m_rxGainNames << QString::fromStdString(rxGainNames[i]); + + std::vector clockSources = m_dev->get_clock_sources(0); + m_clockSources.reserve(clockSources.size()); + for(size_t i = 0, l = clockSources.size(); i < l; ++i) + m_clockSources << QString::fromStdString(clockSources[i]); + } return true; } diff --git a/devices/usrp/deviceusrpparam.h b/devices/usrp/deviceusrpparam.h index 1a8eaf112..e61b982fb 100644 --- a/devices/usrp/deviceusrpparam.h +++ b/devices/usrp/deviceusrpparam.h @@ -47,11 +47,6 @@ struct DEVICES_API DeviceUSRPParams uhd::meta_range_t m_srRangeTx; //!< Sample rate range uhd::gain_range_t m_gainRangeRx; //!< Gain range for Rx uhd::gain_range_t m_gainRangeTx; //!< Gain range for Tx - float m_sampleRate; //!< Sample rate between host and device - int m_log2OvSRRx; //!< log2 of Rx oversampling (0..5) - int m_log2OvSRTx; //!< log2 of Tx oversampling (0..5) - float m_rxFrequency; //!< Rx frequency - float m_txFrequency; //!< Tx frequency QStringList m_txAntennas; //!< List of Tx antenna names QStringList m_rxAntennas; //!< List of Rx antenna names QStringList m_rxGainNames; //!< List of Rx gain stages - Currently this seems limited to "PGA" @@ -61,11 +56,6 @@ struct DEVICES_API DeviceUSRPParams m_dev(), m_nbRxChannels(0), m_nbTxChannels(0), - m_sampleRate(1e6), - m_log2OvSRRx(0), - m_log2OvSRTx(0), - m_rxFrequency(1e6), - m_txFrequency(1e6), m_lpfRangeRx(), m_lpfRangeTx(), m_loRangeRx(), @@ -84,7 +74,7 @@ struct DEVICES_API DeviceUSRPParams /** * Opens and initialize the device and obtain information (# channels, ranges, ...) */ - bool open(const char *deviceStr); + bool open(const char *deviceStr, bool channelNumOnly); void close(); uhd::usrp::multi_usrp::sptr getDevice() { return m_dev; } diff --git a/devices/usrp/deviceusrpshared.h b/devices/usrp/deviceusrpshared.h index 7ee429759..109661348 100644 --- a/devices/usrp/deviceusrpshared.h +++ b/devices/usrp/deviceusrpshared.h @@ -37,18 +37,21 @@ public: int getDevSampleRate() const { return m_devSampleRate; } uint64_t getCenterFrequency() const { return m_centerFrequency; } int getLOOffset() const { return m_loOffset; } + int getMasterClockRate() const { return m_masterClockRate; } bool getRxElseTx() const { return m_rxElseTx; } static MsgReportBuddyChange* create( int devSampleRate, uint64_t centerFrequency, int loOffset, + int masterClockRate, bool rxElseTx) { return new MsgReportBuddyChange( devSampleRate, centerFrequency, loOffset, + masterClockRate, rxElseTx); } @@ -56,17 +59,20 @@ public: int m_devSampleRate; //!< device/host sample rate uint64_t m_centerFrequency; //!< Center frequency int m_loOffset; //!< LO offset + int m_masterClockRate; //!< FPGA/RFIC sample rate bool m_rxElseTx; //!< tells which side initiated the message MsgReportBuddyChange( int devSampleRate, uint64_t centerFrequency, int loOffset, + int masterClockRate, bool rxElseTx) : Message(), m_devSampleRate(devSampleRate), m_centerFrequency(centerFrequency), m_loOffset(loOffset), + m_masterClockRate(masterClockRate), m_rxElseTx(rxElseTx) { } }; diff --git a/plugins/samplesink/usrpoutput/usrpoutput.cpp b/plugins/samplesink/usrpoutput/usrpoutput.cpp index b389c67da..a8ecc8261 100644 --- a/plugins/samplesink/usrpoutput/usrpoutput.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutput.cpp @@ -175,7 +175,7 @@ bool USRPOutput::openDevice() m_deviceShared.m_deviceParams = new DeviceUSRPParams(); char serial[256]; strcpy(serial, qPrintable(m_deviceAPI->getSamplingDeviceSerial())); - m_deviceShared.m_deviceParams->open(serial); + m_deviceShared.m_deviceParams->open(serial, false); m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel } @@ -533,31 +533,31 @@ bool USRPOutput::handleMessage(const Message& message) { DeviceUSRPShared::MsgReportBuddyChange& report = (DeviceUSRPShared::MsgReportBuddyChange&) message; - if (report.getRxElseTx() && m_running) - { - double host_Hz; - - host_Hz = m_deviceShared.m_deviceParams->getDevice()->get_tx_rate(m_deviceShared.m_channel); - m_settings.m_devSampleRate = roundf(host_Hz); - - qDebug() << "USRPOutput::handleMessage: MsgReportBuddyChange:" - << " m_devSampleRate: " << m_settings.m_devSampleRate; - } - else + if (!report.getRxElseTx()) { + // Tx buddy changed settings, we need to copy m_settings.m_devSampleRate = report.getDevSampleRate(); m_settings.m_centerFrequency = report.getCenterFrequency(); m_settings.m_loOffset = report.getLOOffset(); } + // Master clock rate is common between all buddies + int masterClockRate = report.getMasterClockRate(); + if (masterClockRate > 0) + m_settings.m_masterClockRate = masterClockRate; + qDebug() << "USRPOutput::handleMessage MsgReportBuddyChange"; + qDebug() << "m_masterClockRate " << m_settings.m_masterClockRate; DSPSignalNotification *notif = new DSPSignalNotification( m_settings.m_devSampleRate/(1<getDeviceEngineInputMessageQueue()->push(notif); - DeviceUSRPShared::MsgReportBuddyChange *reportToGUI = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); - getMessageQueueToGUI()->push(reportToGUI); + if (getMessageQueueToGUI()) + { + DeviceUSRPShared::MsgReportBuddyChange *reportToGUI = DeviceUSRPShared::MsgReportBuddyChange::create( + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, false); + getMessageQueueToGUI()->push(reportToGUI); + } return true; } @@ -617,6 +617,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetSt bool forwardChangeAllDSP = false; bool forwardClockSource = false; bool ownThreadWasRunning = false; + bool checkRates = false; QList reverseAPIKeys; try @@ -665,10 +666,8 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetSt if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_tx_rate(settings.m_devSampleRate, m_deviceShared.m_channel); - double actualSampleRate = m_deviceShared.m_deviceParams->getDevice()->get_tx_rate(m_deviceShared.m_channel); - qDebug("USRPOutput::applySettings: set sample rate set to %d - actual rate %f", settings.m_devSampleRate, - actualSampleRate); - m_deviceShared.m_deviceParams->m_sampleRate = m_settings.m_devSampleRate; + qDebug("USRPOutput::applySettings: set sample rate set to %d", settings.m_devSampleRate); + checkRates = true; } } @@ -776,6 +775,17 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetSt m_settings = settings; + if (checkRates) + { + // Check if requested rate could actually be met and what master clock rate we ended up with + double actualSampleRate = m_deviceShared.m_deviceParams->getDevice()->get_tx_rate(m_deviceShared.m_channel); + qDebug("USRPOutput::applySettings: actual sample rate %f", actualSampleRate); + double masterClockRate = m_deviceShared.m_deviceParams->getDevice()->get_master_clock_rate(); + qDebug("USRPOutput::applySettings: master_clock_rate %f", masterClockRate); + m_settings.m_devSampleRate = actualSampleRate; + m_settings.m_masterClockRate = masterClockRate; + } + // forward changes to buddies or oneself if (forwardChangeAllDSP) @@ -795,7 +805,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetSt for (; itSink != sinkBuddies.end(); ++itSink) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, false); (*itSink)->getSamplingDeviceInputMessageQueue()->push(report); } @@ -806,9 +816,17 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetSt for (; itSource != sourceBuddies.end(); ++itSource) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, false); (*itSource)->getSamplingDeviceInputMessageQueue()->push(report); } + + // send to GUI so it can see master clock rate and if actual rate differs + if (m_deviceAPI->getSamplingDeviceGUIMessageQueue()) + { + DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, false); + m_deviceAPI->getSamplingDeviceGUIMessageQueue()->push(report); + } } else if (forwardChangeTxDSP) { @@ -827,7 +845,7 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetSt for (; itSink != sinkBuddies.end(); ++itSink) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, false); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, false); (*itSink)->getSamplingDeviceInputMessageQueue()->push(report); } } @@ -856,6 +874,14 @@ bool USRPOutput::applySettings(const USRPOutputSettings& settings, bool preGetSt } } + // send to GUI in case requested clock isn't detected + if (m_deviceAPI->getSamplingDeviceGUIMessageQueue()) + { + DeviceUSRPShared::MsgReportClockSourceChange *report = DeviceUSRPShared::MsgReportClockSourceChange::create( + m_settings.m_clockSource); + m_deviceAPI->getSamplingDeviceGUIMessageQueue()->push(report); + } + // send to source buddies const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); std::vector::const_iterator itSource = sourceBuddies.begin(); diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.cpp b/plugins/samplesink/usrpoutput/usrpoutputgui.cpp index bdf013cf2..ac82612db 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.cpp @@ -180,9 +180,10 @@ bool USRPOutputGUI::handleMessage(const Message& message) else if (DeviceUSRPShared::MsgReportBuddyChange::match(message)) { DeviceUSRPShared::MsgReportBuddyChange& report = (DeviceUSRPShared::MsgReportBuddyChange&) message; - m_settings.m_devSampleRate = report.getDevSampleRate(); + m_settings.m_masterClockRate = report.getMasterClockRate(); if (!report.getRxElseTx()) { + m_settings.m_devSampleRate = report.getDevSampleRate(); m_settings.m_centerFrequency = report.getCenterFrequency(); m_settings.m_loOffset = report.getLOOffset(); } @@ -291,12 +292,20 @@ void USRPOutputGUI::updateSampleRateAndFrequency() void USRPOutputGUI::updateSampleRate() { uint32_t sr = m_settings.m_devSampleRate; + int cr = m_settings.m_masterClockRate; if (sr < 100000000) { ui->sampleRateLabel->setText(tr("%1k").arg(QString::number(sr / 1000.0f, 'g', 5))); } else { ui->sampleRateLabel->setText(tr("%1M").arg(QString::number(sr / 1000000.0f, 'g', 5))); } + if (cr < 0) { + ui->masterClockRateLabel->setText("-"); + } else if (cr < 100000000) { + ui->masterClockRateLabel->setText(tr("%1k").arg(QString::number(cr / 1000.0f, 'g', 5))); + } else { + ui->masterClockRateLabel->setText(tr("%1M").arg(QString::number(cr / 1000000.0f, 'g', 5))); + } // LO offset shouldn't be greater than half the sample rate ui->loOffset->setValueRange(false, 5, -(int32_t)sr/2/1000, (int32_t)sr/2/1000); } diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.ui b/plugins/samplesink/usrpoutput/usrpoutputgui.ui index 49abaea36..acb0c037e 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.ui +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.ui @@ -75,6 +75,16 @@
+ + + + Master clock rate (sample rate between FPGA and RFIC) (k or MS/s) + + + 00000k + + + diff --git a/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp b/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp index 941962b9b..c342eb25f 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputsettings.cpp @@ -27,6 +27,7 @@ USRPOutputSettings::USRPOutputSettings() void USRPOutputSettings::resetToDefaults() { + m_masterClockRate = -1; // Calculated by UHD m_centerFrequency = 435000*1000; m_devSampleRate = 3000000; m_loOffset = 0; diff --git a/plugins/samplesink/usrpoutput/usrpoutputsettings.h b/plugins/samplesink/usrpoutput/usrpoutputsettings.h index 899a60c72..80e20d281 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputsettings.h +++ b/plugins/samplesink/usrpoutput/usrpoutputsettings.h @@ -30,6 +30,7 @@ */ struct USRPOutputSettings { + int m_masterClockRate; // global settings to be saved uint64_t m_centerFrequency; int m_devSampleRate; diff --git a/plugins/samplesource/usrpinput/usrpinput.cpp b/plugins/samplesource/usrpinput/usrpinput.cpp index 52d26c3b3..f81b67d0a 100644 --- a/plugins/samplesource/usrpinput/usrpinput.cpp +++ b/plugins/samplesource/usrpinput/usrpinput.cpp @@ -202,7 +202,7 @@ bool USRPInput::openDevice() m_deviceShared.m_deviceParams = new DeviceUSRPParams(); char serial[256]; strcpy(serial, qPrintable(m_deviceAPI->getSamplingDeviceSerial())); - m_deviceShared.m_deviceParams->open(serial); + m_deviceShared.m_deviceParams->open(serial, false); m_deviceShared.m_channel = requestedChannel; // acknowledge the requested channel } @@ -548,20 +548,17 @@ bool USRPInput::handleMessage(const Message& message) if (report.getRxElseTx()) { + // Rx buddy changed settings, we need to copy m_settings.m_devSampleRate = report.getDevSampleRate(); m_settings.m_centerFrequency = report.getCenterFrequency(); m_settings.m_loOffset = report.getLOOffset(); } - else if (m_running) - { - double host_Hz; - - host_Hz = m_deviceShared.m_deviceParams->getDevice()->get_rx_rate(m_deviceShared.m_channel); - m_settings.m_devSampleRate = roundf(host_Hz); - - qDebug() << "USRPInput::handleMessage: MsgReportBuddyChange:" - << " m_devSampleRate: " << m_settings.m_devSampleRate; - } + // Master clock rate is common between all buddies + int masterClockRate = report.getMasterClockRate(); + if (masterClockRate > 0) + m_settings.m_masterClockRate = masterClockRate; + qDebug() << "USRPInput::handleMessage MsgReportBuddyChange"; + qDebug() << "m_masterClockRate " << m_settings.m_masterClockRate; DSPSignalNotification *notif = new DSPSignalNotification( m_settings.m_devSampleRate/(1<push(reportToGUI); } @@ -656,6 +653,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool preGetStre bool forwardClockSource = false; bool ownThreadWasRunning = false; bool reapplySomeSettings = false; + bool checkRates = false; QList reverseAPIKeys; try @@ -704,10 +702,8 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool preGetStre if (m_deviceShared.m_deviceParams->getDevice() && (m_channelAcquired || preGetStream)) { m_deviceShared.m_deviceParams->getDevice()->set_rx_rate(settings.m_devSampleRate, m_deviceShared.m_channel); - double actualSampleRate = m_deviceShared.m_deviceParams->getDevice()->get_rx_rate(m_deviceShared.m_channel); - qDebug("USRPInput::applySettings: set sample rate set to %d - actual rate %f", settings.m_devSampleRate, - actualSampleRate); - m_deviceShared.m_deviceParams->m_sampleRate = m_settings.m_devSampleRate; + qDebug("USRPInput::applySettings: set sample rate set to %d", settings.m_devSampleRate); + checkRates = true; reapplySomeSettings = true; } } @@ -845,6 +841,17 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool preGetStre m_settings = settings; + if (checkRates) + { + // Check if requested rate could actually be met and what master clock rate we ended up with + double actualSampleRate = m_deviceShared.m_deviceParams->getDevice()->get_rx_rate(m_deviceShared.m_channel); + qDebug("USRPInput::applySettings: actual sample rate %f", actualSampleRate); + double masterClockRate = m_deviceShared.m_deviceParams->getDevice()->get_master_clock_rate(); + qDebug("USRPInput::applySettings: master_clock_rate %f", masterClockRate); + m_settings.m_devSampleRate = actualSampleRate; + m_settings.m_masterClockRate = masterClockRate; + } + // forward changes to buddies or oneself if (forwardChangeAllDSP) @@ -864,7 +871,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool preGetStre for (; itSource != sourceBuddies.end(); ++itSource) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, true); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, true); (*itSource)->getSamplingDeviceInputMessageQueue()->push(report); } @@ -875,9 +882,17 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool preGetStre for (; itSink != sinkBuddies.end(); ++itSink) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, true); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, true); (*itSink)->getSamplingDeviceInputMessageQueue()->push(report); } + + // send to GUI so it can see master clock rate and if actual rate differs + if (m_deviceAPI->getSamplingDeviceGUIMessageQueue()) + { + DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, true); + m_deviceAPI->getSamplingDeviceGUIMessageQueue()->push(report); + } } else if (forwardChangeRxDSP) { @@ -896,7 +911,7 @@ bool USRPInput::applySettings(const USRPInputSettings& settings, bool preGetStre for (; itSource != sourceBuddies.end(); ++itSource) { DeviceUSRPShared::MsgReportBuddyChange *report = DeviceUSRPShared::MsgReportBuddyChange::create( - m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, true); + m_settings.m_devSampleRate, m_settings.m_centerFrequency, m_settings.m_loOffset, m_settings.m_masterClockRate, true); (*itSource)->getSamplingDeviceInputMessageQueue()->push(report); } } diff --git a/plugins/samplesource/usrpinput/usrpinputgui.cpp b/plugins/samplesource/usrpinput/usrpinputgui.cpp index e63b48f3b..485d9ef1e 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.cpp +++ b/plugins/samplesource/usrpinput/usrpinputgui.cpp @@ -163,9 +163,10 @@ bool USRPInputGUI::handleMessage(const Message& message) else if (DeviceUSRPShared::MsgReportBuddyChange::match(message)) { DeviceUSRPShared::MsgReportBuddyChange& report = (DeviceUSRPShared::MsgReportBuddyChange&) message; - m_settings.m_devSampleRate = report.getDevSampleRate(); + m_settings.m_masterClockRate = report.getMasterClockRate(); if (report.getRxElseTx()) { + m_settings.m_devSampleRate = report.getDevSampleRate(); m_settings.m_centerFrequency = report.getCenterFrequency(); m_settings.m_loOffset = report.getLOOffset(); } @@ -287,12 +288,20 @@ void USRPInputGUI::handleInputMessages() void USRPInputGUI::updateSampleRate() { uint32_t sr = m_settings.m_devSampleRate; + int cr = m_settings.m_masterClockRate; if (sr < 100000000) { ui->sampleRateLabel->setText(tr("%1k").arg(QString::number(sr / 1000.0f, 'g', 5))); } else { ui->sampleRateLabel->setText(tr("%1M").arg(QString::number(sr / 1000000.0f, 'g', 5))); } + if (cr < 0) { + ui->masterClockRateLabel->setText("-"); + } else if (cr < 100000000) { + ui->masterClockRateLabel->setText(tr("%1k").arg(QString::number(cr / 1000.0f, 'g', 5))); + } else { + ui->masterClockRateLabel->setText(tr("%1M").arg(QString::number(cr / 1000000.0f, 'g', 5))); + } // LO offset shouldn't be greater than half the sample rate ui->loOffset->setValueRange(false, 5, -(int32_t)sr/2/1000, (int32_t)sr/2/1000); } diff --git a/plugins/samplesource/usrpinput/usrpinputgui.ui b/plugins/samplesource/usrpinput/usrpinputgui.ui index c599ad659..9ac893c4f 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.ui +++ b/plugins/samplesource/usrpinput/usrpinputgui.ui @@ -75,6 +75,16 @@ + + + + Master clock rate (sample rate between FPGA and RFIC) (k or MS/s) + + + 00000k + + + @@ -799,17 +809,17 @@
gui/valuedial.h
1 - - TransverterButton - QPushButton -
gui/transverterbutton.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + TransverterButton + QPushButton +
gui/transverterbutton.h
+
diff --git a/plugins/samplesource/usrpinput/usrpinputsettings.cpp b/plugins/samplesource/usrpinput/usrpinputsettings.cpp index 0a8adf6b4..1a7c0b2be 100644 --- a/plugins/samplesource/usrpinput/usrpinputsettings.cpp +++ b/plugins/samplesource/usrpinput/usrpinputsettings.cpp @@ -26,6 +26,7 @@ USRPInputSettings::USRPInputSettings() void USRPInputSettings::resetToDefaults() { + m_masterClockRate = -1; // Calculated by UHD m_centerFrequency = 435000*1000; m_devSampleRate = 3000000; m_loOffset = 0; diff --git a/plugins/samplesource/usrpinput/usrpinputsettings.h b/plugins/samplesource/usrpinput/usrpinputsettings.h index a485d2e80..9f6aa5372 100644 --- a/plugins/samplesource/usrpinput/usrpinputsettings.h +++ b/plugins/samplesource/usrpinput/usrpinputsettings.h @@ -34,6 +34,7 @@ struct USRPInputSettings GAIN_MANUAL } GainMode; + int m_masterClockRate; // global settings to be saved uint64_t m_centerFrequency; int m_devSampleRate; From b7fac21297bff784bf53d74b2e7ba25154575fa3 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Mon, 26 Oct 2020 14:50:00 +0000 Subject: [PATCH 7/9] Fix compiler warning --- plugins/samplesink/usrpoutput/usrpoutputthread.cpp | 2 +- plugins/samplesource/usrpinput/usrpinputthread.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/samplesink/usrpoutput/usrpoutputthread.cpp b/plugins/samplesink/usrpoutput/usrpoutputthread.cpp index 2b6edd6cf..7ca7c8a17 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputthread.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputthread.cpp @@ -109,7 +109,7 @@ void USRPOutputThread::run() m_packets++; if (samples_sent != m_bufSamples) { - qDebug("USRPOutputThread::run written %ld/%d samples", samples_sent, m_bufSamples); + qDebug("USRPOutputThread::run written %ld/%ld samples", samples_sent, m_bufSamples); } } catch (std::exception& e) diff --git a/plugins/samplesource/usrpinput/usrpinputthread.cpp b/plugins/samplesource/usrpinput/usrpinputthread.cpp index 4935c8576..c96fb2f2e 100644 --- a/plugins/samplesource/usrpinput/usrpinputthread.cpp +++ b/plugins/samplesource/usrpinput/usrpinputthread.cpp @@ -146,7 +146,7 @@ void USRPInputThread::run() m_packets++; if (samples_received != m_bufSamples) { - qDebug("USRPInputThread::run - received %ld/%d samples", samples_received, m_bufSamples); + qDebug("USRPInputThread::run - received %ld/%ld samples", samples_received, m_bufSamples); } if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) { From a9b6af06485c4ee621a295b5f61b8d07541f140d Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 27 Oct 2020 09:56:15 +0000 Subject: [PATCH 8/9] Fix compilation with UHD 3.15. Add dependency info to readme. --- devices/usrp/deviceusrpparam.cpp | 2 +- plugins/samplesource/usrpinput/readme.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/devices/usrp/deviceusrpparam.cpp b/devices/usrp/deviceusrpparam.cpp index c54ec22a9..2acea29a5 100644 --- a/devices/usrp/deviceusrpparam.cpp +++ b/devices/usrp/deviceusrpparam.cpp @@ -67,7 +67,7 @@ bool DeviceUSRPParams::open(const char *deviceStr, bool channelNumOnly) m_srRangeTx = uhd::meta_range_t(std::min(txLow.start(), txHigh.start()), std::max(txLow.stop(), txHigh.stop())); // Need to restore automatic clock rate - uhd::property_tree::sptr properties = m_dev->get_tree(); + uhd::property_tree::sptr properties = m_dev->get_device()->get_tree(); if (properties->exists("/mboards/0/auto_tick_rate")) { properties->access("/mboards/0/auto_tick_rate").set(true); diff --git a/plugins/samplesource/usrpinput/readme.md b/plugins/samplesource/usrpinput/readme.md index 4521041fe..be639aa92 100644 --- a/plugins/samplesource/usrpinput/readme.md +++ b/plugins/samplesource/usrpinput/readme.md @@ -132,3 +132,10 @@ This label turns green when data is being received from the device. - **T**: turns red if stream experiences timeouts The stream warning indicators are reset when the acqusition is started. + +

Dependendices

+ +On Ubuntu 20, the libuhd-dev package should be installed. The FPGA images then need to be downloaded with: + +sudo /usr/lib/uhd/utils/uhd_images_downloader.py + From 8cd3bb9b475b2bbd9abd6f50eb8381db202ed654 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 27 Oct 2020 09:57:28 +0000 Subject: [PATCH 9/9] Widen combo box, so TX/RX fits in --- plugins/samplesink/usrpoutput/usrpoutputgui.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.ui b/plugins/samplesink/usrpoutput/usrpoutputgui.ui index acb0c037e..2ac70316e 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.ui +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.ui @@ -230,7 +230,7 @@ - 60 + 70 0