1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 09:18:54 -05:00

SoapySDR support: fixes

This commit is contained in:
f4exb 2018-11-04 18:42:51 +01:00
parent 6a9607c8fc
commit 564a99d14e
9 changed files with 277 additions and 35 deletions

3
debian/changelog vendored
View File

@ -1,8 +1,9 @@
sdrangel (4.3.0-1) unstable; urgency=medium sdrangel (4.3.0-1) unstable; urgency=medium
* SoapySDR support * SoapySDR support
* BladeRF2 corrections
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 04 Nov 2018 21:14:18 +0200 -- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Sun, 18 Nov 2018 21:14:18 +0100
sdrangel (4.2.4-1) unstable; urgency=medium sdrangel (4.2.4-1) unstable; urgency=medium

View File

@ -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; freq_hz += df;
int status = bladerf_set_frequency(dev, BLADERF_CHANNEL_TX(requestedChannel), freq_hz); 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 (dev != 0)
{ {
if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency)) if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths))
{ {
if (getMessageQueueToGUI()) if (getMessageQueueToGUI())
{ {

View File

@ -153,7 +153,7 @@ private:
void moveThreadToBuddy(); void moveThreadToBuddy();
bool applySettings(const BladeRF2OutputSettings& settings, bool force); bool applySettings(const BladeRF2OutputSettings& settings, bool force);
int getNbChannels(); 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 webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF2OutputSettings& settings);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);

View File

@ -30,7 +30,7 @@
const PluginDescriptor BladeRF2OutputPlugin::m_pluginDescriptor = { const PluginDescriptor BladeRF2OutputPlugin::m_pluginDescriptor = {
QString("BladeRF2 Output"), QString("BladeRF2 Output"),
QString("4.2.1"), QString("4.3.0"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,

View File

@ -14,6 +14,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include "util/simpleserializer.h" #include "util/simpleserializer.h"
#include "dsp/dspcommands.h" #include "dsp/dspcommands.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
@ -77,6 +79,7 @@ bool SoapySDROutput::openDevice()
} }
m_deviceShared.m_device = device; m_deviceShared.m_device = device;
m_deviceShared.m_deviceParams = deviceSoapySDRShared->m_deviceParams;
} }
// look for Rx buddies and get reference to the device object // look for Rx buddies and get reference to the device object
else if (m_deviceAPI->getSourceBuddies().size() > 0) // then source else if (m_deviceAPI->getSourceBuddies().size() > 0) // then source
@ -101,6 +104,7 @@ bool SoapySDROutput::openDevice()
} }
m_deviceShared.m_device = device; m_deviceShared.m_device = device;
m_deviceShared.m_deviceParams = deviceSoapySDRShared->m_deviceParams;
} }
// There are no buddies then create the first BladeRF2 device // There are no buddies then create the first BladeRF2 device
else else
@ -114,6 +118,8 @@ bool SoapySDROutput::openDevice()
qCritical("SoapySDROutput::openDevice: cannot open SoapySDR device"); qCritical("SoapySDROutput::openDevice: cannot open SoapySDR device");
return false; return false;
} }
m_deviceShared.m_deviceParams = new DeviceSoapySDRParams(m_deviceShared.m_device);
} }
m_deviceShared.m_channel = m_deviceAPI->getItemIndex(); // publicly allocate channel m_deviceShared.m_channel = m_deviceAPI->getItemIndex(); // publicly allocate channel
@ -341,11 +347,10 @@ bool SoapySDROutput::start()
if (needsStart) if (needsStart)
{ {
qDebug("SoapySDROutput::start: (re)sart buddy thread"); qDebug("SoapySDROutput::start: (re)sart buddy thread");
soapySDROutputThread->setSampleRate(m_settings.m_devSampleRate);
soapySDROutputThread->startWork(); soapySDROutputThread->startWork();
} }
applySettings(m_settings, true); // re-apply forcibly to set sample rate with the new number of channels
qDebug("SoapySDROutput::start: started"); qDebug("SoapySDROutput::start: started");
m_running = true; 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<<settings.m_log2Interp);
}
}
if ((m_settings.m_centerFrequency != settings.m_centerFrequency)
|| (m_settings.m_transverterMode != settings.m_transverterMode)
|| (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)
|| (m_settings.m_LOppmTenths != settings.m_LOppmTenths)
|| (m_settings.m_devSampleRate != settings.m_devSampleRate)
|| (m_settings.m_log2Interp != settings.m_log2Interp) || force)
{
forwardChangeOwnDSP = true;
forwardChangeToBuddies = true;
if (dev != 0) {
setDeviceCenterFrequency(dev, requestedChannel, settings.m_centerFrequency, settings.m_LOppmTenths);
}
}
if (forwardChangeOwnDSP)
{
int sampleRate = settings.m_devSampleRate/(1<<settings.m_log2Interp);
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, settings.m_centerFrequency);
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
}
if (forwardChangeToBuddies)
{
// send to source buddies
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
const std::vector<DeviceSinkAPI*>& 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;
}

View File

@ -86,6 +86,7 @@ void SoapySDROutputThread::run()
std::iota(channels.begin(), channels.end(), 0); // Fill with 0, 1, ..., m_nbChannels-1. std::iota(channels.begin(), channels.end(), 0); // Fill with 0, 1, ..., m_nbChannels-1.
//initialize the sample rate for all channels //initialize the sample rate for all channels
qDebug("SoapySDROutputThread::run: m_sampleRate: %u", m_sampleRate);
for (const auto &it : channels) { for (const auto &it : channels) {
m_dev->setSampleRate(SOAPY_SDR_TX, it, m_sampleRate); m_dev->setSampleRate(SOAPY_SDR_TX, it, m_sampleRate);
} }
@ -144,20 +145,20 @@ void SoapySDROutputThread::run()
if (m_nbChannels > 1) 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 else
{ {
switch (m_interpolatorType) switch (m_interpolatorType)
{ {
case Interpolator8: case Interpolator8:
callbackSO8((qint8*) buffs[0], numElems*2); callbackSO8((qint8*) buffs[0], numElems);
break; break;
case Interpolator12: case Interpolator12:
callbackSO12((qint16*) buffs[0], numElems*2); callbackSO12((qint16*) buffs[0], numElems);
break; break;
case Interpolator16: case Interpolator16:
callbackSO16((qint16*) buffs[0], numElems*2); callbackSO16((qint16*) buffs[0], numElems);
break; break;
case InterpolatorFloat: case InterpolatorFloat:
default: default:
@ -230,21 +231,41 @@ void SoapySDROutputThread::callbackMO(std::vector<void *>& buffs, qint32 samples
{ {
for(unsigned int ichan = 0; ichan < m_nbChannels; ichan++) for(unsigned int ichan = 0; ichan < m_nbChannels; ichan++)
{ {
switch (m_interpolatorType) if (m_channels[ichan].m_sampleFifo)
{ {
case Interpolator8: switch (m_interpolatorType)
callbackSO8((qint8*) buffs[ichan], samplesPerChannel, ichan); {
break; case Interpolator8:
case Interpolator12: callbackSO8((qint8*) buffs[ichan], samplesPerChannel, ichan);
callbackSO12((qint16*) buffs[ichan], samplesPerChannel, ichan); break;
break; case Interpolator12:
case Interpolator16: callbackSO12((qint16*) buffs[ichan], samplesPerChannel, ichan);
callbackSO16((qint16*) buffs[ichan], samplesPerChannel, ichan); break;
break; case Interpolator16:
case InterpolatorFloat: callbackSO16((qint16*) buffs[ichan], samplesPerChannel, ichan);
default: break;
// TODO case InterpolatorFloat:
break; 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;
}
} }
} }
} }

View File

@ -42,6 +42,8 @@ public:
unsigned int getNbChannels() const { return m_nbChannels; } unsigned int getNbChannels() const { return m_nbChannels; }
void setLog2Interpolation(unsigned int channel, unsigned int log2_interp); void setLog2Interpolation(unsigned int channel, unsigned int log2_interp);
unsigned int getLog2Interpolation(unsigned int channel) const; 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); void setFifo(unsigned int channel, SampleSourceFifo *sampleFifo);
SampleSourceFifo *getFifo(unsigned int channel); SampleSourceFifo *getFifo(unsigned int channel);

View File

@ -30,7 +30,7 @@
const PluginDescriptor Blderf2InputPlugin::m_pluginDescriptor = { const PluginDescriptor Blderf2InputPlugin::m_pluginDescriptor = {
QString("BladeRF2 Input"), QString("BladeRF2 Input"),
QString("4.2.1"), QString("4.3.0"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,

View File

@ -372,11 +372,10 @@ bool SoapySDRInput::start()
if (needsStart) if (needsStart)
{ {
qDebug("SoapySDRInput::start: (re)sart buddy thread"); qDebug("SoapySDRInput::start: (re)sart buddy thread");
soapySDRInputThread->setSampleRate(m_settings.m_devSampleRate);
soapySDRInputThread->startWork(); soapySDRInputThread->startWork();
} }
applySettings(m_settings, true);
qDebug("SoapySDRInput::start: started"); qDebug("SoapySDRInput::start: started");
m_running = true; m_running = true;
@ -514,16 +513,28 @@ const QString& SoapySDRInput::getDeviceDescription() const
int SoapySDRInput::getSampleRate() const int SoapySDRInput::getSampleRate() const
{ {
return 0; int rate = m_settings.m_devSampleRate;
return (rate / (1<<m_settings.m_log2Decim));
} }
quint64 SoapySDRInput::getCenterFrequency() const quint64 SoapySDRInput::getCenterFrequency() const
{ {
return 0; return m_settings.m_centerFrequency;
} }
void SoapySDRInput::setCenterFrequency(qint64 centerFrequency __attribute__((unused))) void SoapySDRInput::setCenterFrequency(qint64 centerFrequency __attribute__((unused)))
{ {
SoapySDRInputSettings settings = m_settings;
settings.m_centerFrequency = centerFrequency;
MsgConfigureSoapySDRInput *message = MsgConfigureSoapySDRInput::create(settings, false);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureSoapySDRInput* messageToGUI = MsgConfigureSoapySDRInput::create(settings, false);
m_guiMessageQueue->push(messageToGUI);
}
} }
bool SoapySDRInput::setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths) 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; DeviceSoapySDRShared::MsgReportBuddyChange& report = (DeviceSoapySDRShared::MsgReportBuddyChange&) message;
SoapySDRInputSettings settings = m_settings; SoapySDRInputSettings settings = m_settings;
settings.m_fcPos = (SoapySDRInputSettings::fcPos_t) report.getFcPos(); settings.m_fcPos = (SoapySDRInputSettings::fcPos_t) report.getFcPos();
//bool fromRxBuddy = report.getRxElseTx();
settings.m_centerFrequency = m_deviceShared.m_device->getFrequency( settings.m_centerFrequency = m_deviceShared.m_device->getFrequency(
SOAPY_SDR_RX, SOAPY_SDR_RX,
@ -624,6 +636,13 @@ bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused))
m_settings = settings; m_settings = settings;
// propagate settings to GUI if any
if (getMessageQueueToGUI())
{
MsgConfigureSoapySDRInput *reportToGUI = MsgConfigureSoapySDRInput::create(m_settings, false);
getMessageQueueToGUI()->push(reportToGUI);
}
return true; return true;
} }
else else
@ -683,8 +702,6 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
if ((m_settings.m_fcPos != settings.m_fcPos) || force) if ((m_settings.m_fcPos != settings.m_fcPos) || force)
{ {
SoapySDRInputThread *inputThread = findThread();
if (inputThread != 0) if (inputThread != 0)
{ {
inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos); inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos);