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;