From 564a99d14e10817782e9c1f2d3cb82246af84589 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 4 Nov 2018 18:42:51 +0100 Subject: [PATCH] SoapySDR support: fixes --- debian/changelog | 3 +- .../bladerf2output/bladerf2output.cpp | 6 +- .../bladerf2output/bladerf2output.h | 2 +- .../bladerf2output/bladerf2outputplugin.cpp | 2 +- .../soapysdroutput/soapysdroutput.cpp | 209 +++++++++++++++++- .../soapysdroutput/soapysdroutputthread.cpp | 57 +++-- .../soapysdroutput/soapysdroutputthread.h | 2 + .../bladerf2input/bladerf2inputplugin.cpp | 2 +- .../soapysdrinput/soapysdrinput.cpp | 29 ++- 9 files changed, 277 insertions(+), 35 deletions(-) diff --git a/debian/changelog b/debian/changelog index b3dec420b..91461fb1d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,9 @@ sdrangel (4.3.0-1) unstable; urgency=medium * SoapySDR support + * BladeRF2 corrections - -- Edouard Griffiths, F4EXB Sun, 04 Nov 2018 21:14:18 +0200 + -- Edouard Griffiths, F4EXB Sun, 18 Nov 2018 21:14:18 +0100 sdrangel (4.2.4-1) unstable; urgency=medium diff --git a/plugins/samplesink/bladerf2output/bladerf2output.cpp b/plugins/samplesink/bladerf2output/bladerf2output.cpp index 9b9085357..8ebec2a37 100644 --- a/plugins/samplesink/bladerf2output/bladerf2output.cpp +++ b/plugins/samplesink/bladerf2output/bladerf2output.cpp @@ -520,9 +520,9 @@ void BladeRF2Output::setCenterFrequency(qint64 centerFrequency) } } -bool BladeRF2Output::setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz) +bool BladeRF2Output::setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths) { - qint64 df = ((qint64)freq_hz * m_settings.m_LOppmTenths) / 10000000LL; + qint64 df = ((qint64)freq_hz * loPpmTenths) / 10000000LL; freq_hz += df; int status = bladerf_set_frequency(dev, BLADERF_CHANNEL_TX(requestedChannel), freq_hz); @@ -789,7 +789,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool if (dev != 0) { - if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency)) + if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths)) { if (getMessageQueueToGUI()) { diff --git a/plugins/samplesink/bladerf2output/bladerf2output.h b/plugins/samplesink/bladerf2output/bladerf2output.h index 9bc83a61a..9b501aeaa 100644 --- a/plugins/samplesink/bladerf2output/bladerf2output.h +++ b/plugins/samplesink/bladerf2output/bladerf2output.h @@ -153,7 +153,7 @@ private: void moveThreadToBuddy(); bool applySettings(const BladeRF2OutputSettings& settings, bool force); int getNbChannels(); - bool setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz); + bool setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths); void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF2OutputSettings& settings); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); diff --git a/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp b/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp index c65b66fa5..32c222514 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp +++ b/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp @@ -30,7 +30,7 @@ const PluginDescriptor BladeRF2OutputPlugin::m_pluginDescriptor = { QString("BladeRF2 Output"), - QString("4.2.1"), + QString("4.3.0"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesink/soapysdroutput/soapysdroutput.cpp b/plugins/samplesink/soapysdroutput/soapysdroutput.cpp index c0e60b784..325cd09a3 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutput.cpp +++ b/plugins/samplesink/soapysdroutput/soapysdroutput.cpp @@ -14,6 +14,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include "util/simpleserializer.h" #include "dsp/dspcommands.h" #include "dsp/dspengine.h" @@ -77,6 +79,7 @@ bool SoapySDROutput::openDevice() } m_deviceShared.m_device = device; + m_deviceShared.m_deviceParams = deviceSoapySDRShared->m_deviceParams; } // look for Rx buddies and get reference to the device object else if (m_deviceAPI->getSourceBuddies().size() > 0) // then source @@ -101,6 +104,7 @@ bool SoapySDROutput::openDevice() } m_deviceShared.m_device = device; + m_deviceShared.m_deviceParams = deviceSoapySDRShared->m_deviceParams; } // There are no buddies then create the first BladeRF2 device else @@ -114,6 +118,8 @@ bool SoapySDROutput::openDevice() qCritical("SoapySDROutput::openDevice: cannot open SoapySDR device"); return false; } + + m_deviceShared.m_deviceParams = new DeviceSoapySDRParams(m_deviceShared.m_device); } m_deviceShared.m_channel = m_deviceAPI->getItemIndex(); // publicly allocate channel @@ -341,11 +347,10 @@ bool SoapySDROutput::start() if (needsStart) { qDebug("SoapySDROutput::start: (re)sart buddy thread"); + soapySDROutputThread->setSampleRate(m_settings.m_devSampleRate); soapySDROutputThread->startWork(); } - applySettings(m_settings, true); // re-apply forcibly to set sample rate with the new number of channels - qDebug("SoapySDROutput::start: started"); m_running = true; @@ -518,10 +523,206 @@ void SoapySDROutput::setCenterFrequency(qint64 centerFrequency) } } -bool SoapySDROutput::handleMessage(const Message& message __attribute__((unused))) +bool SoapySDROutput::setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths) { - return false; + qint64 df = ((qint64)freq_hz * loPpmTenths) / 10000000LL; + freq_hz += df; + + try + { + dev->setFrequency(SOAPY_SDR_TX, + requestedChannel, + m_deviceShared.m_deviceParams->getTxChannelMainTunableElementName(requestedChannel), + freq_hz); + qDebug("SoapySDROutput::setDeviceCenterFrequency: setFrequency(%llu)", freq_hz); + return true; + } + catch (const std::exception &ex) + { + qCritical("SoapySDROutput::applySettings: could not set frequency: %llu: %s", freq_hz, ex.what()); + return false; + } } +bool SoapySDROutput::handleMessage(const Message& message) +{ + if (MsgConfigureSoapySDROutput::match(message)) + { + MsgConfigureSoapySDROutput& conf = (MsgConfigureSoapySDROutput&) message; + qDebug() << "SoapySDROutput::handleMessage: MsgConfigureSoapySDROutput"; + if (!applySettings(conf.getSettings(), conf.getForce())) { + qDebug("SoapySDROutput::handleMessage: MsgConfigureSoapySDROutput config error"); + } + return true; + } + else if (MsgStartStop::match(message)) + { + MsgStartStop& cmd = (MsgStartStop&) message; + qDebug() << "SoapySDROutput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop"); + + if (cmd.getStartStop()) + { + if (m_deviceAPI->initGeneration()) + { + m_deviceAPI->startGeneration(); + } + } + else + { + m_deviceAPI->stopGeneration(); + } + + return true; + } + else if (DeviceSoapySDRShared::MsgReportBuddyChange::match(message)) + { + int requestedChannel = m_deviceAPI->getItemIndex(); + //DeviceSoapySDRShared::MsgReportBuddyChange& report = (DeviceSoapySDRShared::MsgReportBuddyChange&) message; + SoapySDROutputSettings settings = m_settings; + //bool fromRxBuddy = report.getRxElseTx(); + + settings.m_centerFrequency = m_deviceShared.m_device->getFrequency( + SOAPY_SDR_TX, + requestedChannel, + m_deviceShared.m_deviceParams->getTxChannelMainTunableElementName(requestedChannel)); + + settings.m_devSampleRate = m_deviceShared.m_device->getSampleRate(SOAPY_SDR_TX, requestedChannel); + + //SoapySDROutputThread *outputThread = findThread(); + + m_settings = settings; + + // propagate settings to GUI if any + if (getMessageQueueToGUI()) + { + MsgConfigureSoapySDROutput *reportToGUI = MsgConfigureSoapySDROutput::create(m_settings, false); + getMessageQueueToGUI()->push(reportToGUI); + } + + return true; + } + else + { + return false; + } +} + +bool SoapySDROutput::applySettings(const SoapySDROutputSettings& settings, bool force) +{ + bool forwardChangeOwnDSP = false; + bool forwardChangeToBuddies = false; + + SoapySDR::Device *dev = m_deviceShared.m_device; + SoapySDROutputThread *outputThread = findThread(); + int requestedChannel = m_deviceAPI->getItemIndex(); + qint64 xlatedDeviceCenterFrequency = settings.m_centerFrequency; + xlatedDeviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0; + xlatedDeviceCenterFrequency = xlatedDeviceCenterFrequency < 0 ? 0 : xlatedDeviceCenterFrequency; + + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) + { + forwardChangeOwnDSP = true; + forwardChangeToBuddies = true; + + if (dev != 0) + { + try + { + dev->setSampleRate(SOAPY_SDR_TX, requestedChannel, settings.m_devSampleRate); + qDebug() << "SoapySDROutput::applySettings: setSampleRate OK: " << settings.m_devSampleRate; + + if (outputThread) + { + bool wasRunning = outputThread->isRunning(); + outputThread->stopWork(); + outputThread->setSampleRate(settings.m_devSampleRate); + + if (wasRunning) { + outputThread->startWork(); + } + } + } + catch (const std::exception &ex) + { + qCritical("SoapySDROutput::applySettings: could not set sample rate: %d: %s", + settings.m_devSampleRate, ex.what()); + } + } + } + + if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) + { + forwardChangeOwnDSP = true; + + if (outputThread != 0) + { + outputThread->setLog2Interpolation(requestedChannel, settings.m_log2Interp); + qDebug() << "SoapySDROutput::applySettings: set decimation to " << (1<getDeviceEngineInputMessageQueue()->push(notif); + } + + if (forwardChangeToBuddies) + { + // send to source buddies + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + + for (const auto &itSource : sourceBuddies) + { + DeviceSoapySDRShared::MsgReportBuddyChange *report = DeviceSoapySDRShared::MsgReportBuddyChange::create( + settings.m_centerFrequency, + settings.m_LOppmTenths, + 2, + settings.m_devSampleRate, + false); + itSource->getSampleSourceInputMessageQueue()->push(report); + } + + for (const auto &itSink : sinkBuddies) + { + DeviceSoapySDRShared::MsgReportBuddyChange *report = DeviceSoapySDRShared::MsgReportBuddyChange::create( + settings.m_centerFrequency, + settings.m_LOppmTenths, + 2, + settings.m_devSampleRate, + false); + itSink->getSampleSinkInputMessageQueue()->push(report); + } + } + + m_settings = settings; + + qDebug() << "SoapySDROutput::applySettings: " + << " m_transverterMode: " << m_settings.m_transverterMode + << " m_transverterDeltaFrequency: " << m_settings.m_transverterDeltaFrequency + << " m_centerFrequency: " << m_settings.m_centerFrequency << " Hz" + << " m_LOppmTenths: " << m_settings.m_LOppmTenths + << " m_log2Interp: " << m_settings.m_log2Interp + << " m_devSampleRate: " << m_settings.m_devSampleRate; + + return true; +} diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputthread.cpp b/plugins/samplesink/soapysdroutput/soapysdroutputthread.cpp index f90ea6f56..b7303d401 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputthread.cpp +++ b/plugins/samplesink/soapysdroutput/soapysdroutputthread.cpp @@ -86,6 +86,7 @@ void SoapySDROutputThread::run() std::iota(channels.begin(), channels.end(), 0); // Fill with 0, 1, ..., m_nbChannels-1. //initialize the sample rate for all channels + qDebug("SoapySDROutputThread::run: m_sampleRate: %u", m_sampleRate); for (const auto &it : channels) { m_dev->setSampleRate(SOAPY_SDR_TX, it, m_sampleRate); } @@ -144,20 +145,20 @@ void SoapySDROutputThread::run() if (m_nbChannels > 1) { - callbackMO(buffs, numElems*2); // size given in number of I or Q samples (2 items per sample) + callbackMO(buffs, numElems); // size given in number of samples (1 item per sample) } else { switch (m_interpolatorType) { case Interpolator8: - callbackSO8((qint8*) buffs[0], numElems*2); + callbackSO8((qint8*) buffs[0], numElems); break; case Interpolator12: - callbackSO12((qint16*) buffs[0], numElems*2); + callbackSO12((qint16*) buffs[0], numElems); break; case Interpolator16: - callbackSO16((qint16*) buffs[0], numElems*2); + callbackSO16((qint16*) buffs[0], numElems); break; case InterpolatorFloat: default: @@ -230,21 +231,41 @@ void SoapySDROutputThread::callbackMO(std::vector& buffs, qint32 samples { for(unsigned int ichan = 0; ichan < m_nbChannels; ichan++) { - switch (m_interpolatorType) + if (m_channels[ichan].m_sampleFifo) { - case Interpolator8: - callbackSO8((qint8*) buffs[ichan], samplesPerChannel, ichan); - break; - case Interpolator12: - callbackSO12((qint16*) buffs[ichan], samplesPerChannel, ichan); - break; - case Interpolator16: - callbackSO16((qint16*) buffs[ichan], samplesPerChannel, ichan); - break; - case InterpolatorFloat: - default: - // TODO - break; + switch (m_interpolatorType) + { + case Interpolator8: + callbackSO8((qint8*) buffs[ichan], samplesPerChannel, ichan); + break; + case Interpolator12: + callbackSO12((qint16*) buffs[ichan], samplesPerChannel, ichan); + break; + case Interpolator16: + callbackSO16((qint16*) buffs[ichan], samplesPerChannel, ichan); + break; + case InterpolatorFloat: + default: + // TODO + break; + } + } + else // no FIFO for this channel means channel is unused: fill with zeros + { + switch (m_interpolatorType) + { + case Interpolator8: + std::fill((qint8*) buffs[ichan], (qint8*) buffs[ichan] + 2*samplesPerChannel, 0); + break; + case Interpolator12: + case Interpolator16: + std::fill((qint16*) buffs[ichan], (qint16*) buffs[ichan] + 2*samplesPerChannel, 0); + break; + case InterpolatorFloat: + default: + // TODO + break; + } } } } diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputthread.h b/plugins/samplesink/soapysdroutput/soapysdroutputthread.h index 76cdde042..559d98817 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputthread.h +++ b/plugins/samplesink/soapysdroutput/soapysdroutputthread.h @@ -42,6 +42,8 @@ public: unsigned int getNbChannels() const { return m_nbChannels; } void setLog2Interpolation(unsigned int channel, unsigned int log2_interp); unsigned int getLog2Interpolation(unsigned int channel) const; + void setSampleRate(unsigned int sampleRate) { m_sampleRate = sampleRate; } + unsigned int getSampleRate() const { return m_sampleRate; } void setFifo(unsigned int channel, SampleSourceFifo *sampleFifo); SampleSourceFifo *getFifo(unsigned int channel); diff --git a/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp b/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp index 59e13c0dd..2008e9bd7 100644 --- a/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp +++ b/plugins/samplesource/bladerf2input/bladerf2inputplugin.cpp @@ -30,7 +30,7 @@ const PluginDescriptor Blderf2InputPlugin::m_pluginDescriptor = { QString("BladeRF2 Input"), - QString("4.2.1"), + QString("4.3.0"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/soapysdrinput/soapysdrinput.cpp b/plugins/samplesource/soapysdrinput/soapysdrinput.cpp index 173791905..5f57035f5 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinput.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinput.cpp @@ -372,11 +372,10 @@ bool SoapySDRInput::start() if (needsStart) { qDebug("SoapySDRInput::start: (re)sart buddy thread"); + soapySDRInputThread->setSampleRate(m_settings.m_devSampleRate); soapySDRInputThread->startWork(); } - applySettings(m_settings, true); - qDebug("SoapySDRInput::start: started"); m_running = true; @@ -514,16 +513,28 @@ const QString& SoapySDRInput::getDeviceDescription() const int SoapySDRInput::getSampleRate() const { - return 0; + int rate = m_settings.m_devSampleRate; + return (rate / (1<push(messageToGUI); + } } bool SoapySDRInput::setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths) @@ -607,6 +618,7 @@ bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused)) DeviceSoapySDRShared::MsgReportBuddyChange& report = (DeviceSoapySDRShared::MsgReportBuddyChange&) message; SoapySDRInputSettings settings = m_settings; settings.m_fcPos = (SoapySDRInputSettings::fcPos_t) report.getFcPos(); + //bool fromRxBuddy = report.getRxElseTx(); settings.m_centerFrequency = m_deviceShared.m_device->getFrequency( SOAPY_SDR_RX, @@ -624,6 +636,13 @@ bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused)) m_settings = settings; + // propagate settings to GUI if any + if (getMessageQueueToGUI()) + { + MsgConfigureSoapySDRInput *reportToGUI = MsgConfigureSoapySDRInput::create(m_settings, false); + getMessageQueueToGUI()->push(reportToGUI); + } + return true; } else @@ -683,8 +702,6 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo if ((m_settings.m_fcPos != settings.m_fcPos) || force) { - SoapySDRInputThread *inputThread = findThread(); - if (inputThread != 0) { inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos);