SoapySDR support: input: settings and thread output: settings

This commit is contained in:
f4exb 2018-10-30 20:31:16 +01:00
parent 6cede7a667
commit 0d09958483
17 changed files with 994 additions and 12 deletions

View File

@ -33,6 +33,8 @@ public:
uint32_t getNbDevices() const { return m_scanner.getNbDevices(); }
const std::vector<DeviceSoapySDRScan::SoapySDRDeviceEnum>& getDevicesEnumeration() const { return m_scanner.getDevicesEnumeration(); }
static const unsigned int blockSize = (1<<14);
protected:
DeviceSoapySDR();
DeviceSoapySDR(const DeviceSoapySDR&) {}

View File

@ -0,0 +1,27 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "devicesoapysdrshared.h"
DeviceSoapySDRShared::DeviceSoapySDRShared() :
m_device(0),
m_channel(-1),
m_source(0),
m_sink(0)
{}
DeviceSoapySDRShared::~DeviceSoapySDRShared()
{}

View File

@ -0,0 +1,43 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef DEVICES_SOAPYSDR_DEVICESOAPYSDRSHARED_H_
#define DEVICES_SOAPYSDR_DEVICESOAPYSDRSHARED_H_
#include <SoapySDR/Device.hpp>
#include "export.h"
class SoapySDRInput;
class SoapySDROutput;
/**
* Structure shared by a buddy with other buddies
*/
class DEVICES_API DeviceSoapySDRShared
{
public:
DeviceSoapySDRShared();
~DeviceSoapySDRShared();
SoapySDR::Device *m_device;
int m_channel; //!< allocated channel (-1 if none)
SoapySDRInput *m_source;
SoapySDROutput *m_sink;
};
#endif /* DEVICES_SOAPYSDR_DEVICESOAPYSDRSHARED_H_ */

View File

@ -18,7 +18,6 @@
#define PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTSETTINGS_H_
#include <QtGlobal>
#include <libbladeRF.h>
struct BladeRF2OutputSettings {
quint64 m_centerFrequency;

View File

@ -6,7 +6,7 @@ set(soapysdroutput_SOURCES
soapysdroutputgui.cpp
soapysdroutput.cpp
soapysdroutputplugin.cpp
# soapysdroutputsettings.cpp
soapysdroutputsettings.cpp
# soapysdroutputthread.cpp
)
@ -14,7 +14,7 @@ set(soapysdroutput_HEADERS
soapysdroutputgui.h
soapysdroutput.h
soapysdroutputplugin.h
# soapysdroutputsettings.h
soapysdroutputsettings.h
# soapysdroutputthread.h
)

View File

@ -41,7 +41,7 @@ void SoapySDROutput::destroy()
bool SoapySDROutput::openDevice()
{
m_sampleSourceFifo.resize(96000 * 4);
m_sampleSourceFifo.resize(m_settings.m_devSampleRate/(1<<(m_settings.m_log2Interp <= 4 ? m_settings.m_log2Interp : 4)));
// look for Tx buddies and get reference to the device object
if (m_deviceAPI->getSinkBuddies().size() > 0) // look sink sibling first

View File

@ -22,6 +22,8 @@
#include "dsp/devicesamplesink.h"
#include "soapysdr/devicesoapysdrshared.h"
#include "soapysdroutputsettings.h"
class DeviceSinkAPI;
class SoapySDROutput : public DeviceSampleSink {
@ -47,6 +49,7 @@ public:
private:
DeviceSinkAPI *m_deviceAPI;
SoapySDROutputSettings m_settings;
QString m_deviceDescription;
DeviceSoapySDRShared m_deviceShared;
bool m_running;

View File

@ -0,0 +1,75 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QtGlobal>
#include "util/simpleserializer.h"
#include "soapysdroutputsettings.h"
SoapySDROutputSettings::SoapySDROutputSettings()
{
resetToDefaults();
}
void SoapySDROutputSettings::resetToDefaults()
{
m_centerFrequency = 435000*1000;
m_LOppmTenths = 0;
m_devSampleRate = 1024000;
m_log2Interp = 0;
m_transverterMode = false;
m_transverterDeltaFrequency = 0;
}
QByteArray SoapySDROutputSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_devSampleRate);
s.writeS32(2, m_LOppmTenths);
s.writeU32(3, m_log2Interp);
s.writeBool(4, m_transverterMode);
s.writeS64(5, m_transverterDeltaFrequency);
return s.final();
}
bool SoapySDROutputSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
d.readS32(1, &m_devSampleRate);
d.readS32(2, &m_LOppmTenths);
d.readU32(3, &m_log2Interp);
d.readBool(4, &m_transverterMode, false);
d.readS64(5, &m_transverterDeltaFrequency, 0);
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,36 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESINK_SOAPYSDROUTPUT_SOAPYSDROUTPUTSETTINGS_H_
#define PLUGINS_SAMPLESINK_SOAPYSDROUTPUT_SOAPYSDROUTPUTSETTINGS_H_
#include <QtGlobal>
struct SoapySDROutputSettings {
quint64 m_centerFrequency;
int m_LOppmTenths;
qint32 m_devSampleRate;
quint32 m_log2Interp;
bool m_transverterMode;
qint64 m_transverterDeltaFrequency;
SoapySDROutputSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_SAMPLESINK_SOAPYSDROUTPUT_SOAPYSDROUTPUTSETTINGS_H_ */

View File

@ -19,7 +19,6 @@
#include <QtGlobal>
#include <QString>
#include <libbladeRF.h>
struct BladeRF2InputSettings {
typedef enum {

View File

@ -6,16 +6,16 @@ set(soapysdrinput_SOURCES
soapysdrinputgui.cpp
soapysdrinput.cpp
soapysdrinputplugin.cpp
# soapysdrinputsettings.cpp
# soapysdrinputthread.cpp
soapysdrinputsettings.cpp
soapysdrinputthread.cpp
)
set(soapysdrinput_HEADERS
soapysdrinputgui.h
soapysdrinput.h
soapysdrinputplugin.h
# soapysdrinputsettings.h
# soapysdrinputthread.h
soapysdrinputsettings.h
soapysdrinputthread.h
)
set(soapysdrinput_FORMS

View File

@ -23,10 +23,12 @@
#include "dsp/dspengine.h"
#include "soapysdr/devicesoapysdr.h"
#include "soapysdrinputthread.h"
#include "soapysdrinput.h"
SoapySDRInput::SoapySDRInput(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_thread(0),
m_deviceDescription("SoapySDRInput"),
m_running(false)
{
@ -131,9 +133,9 @@ void SoapySDRInput::closeDevice()
stop();
}
// if (m_thread) { // stills own the thread => transfer to a buddy
// moveThreadToBuddy();
// }
if (m_thread) { // stills own the thread => transfer to a buddy
moveThreadToBuddy();
}
m_deviceShared.m_channel = -1; // publicly release channel
m_deviceShared.m_source = 0;
@ -152,6 +154,23 @@ void SoapySDRInput::init()
{
}
void SoapySDRInput::moveThreadToBuddy()
{
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
std::vector<DeviceSourceAPI*>::const_iterator it = sourceBuddies.begin();
for (; it != sourceBuddies.end(); ++it)
{
SoapySDRInput *buddySource = ((DeviceSoapySDRShared*) (*it)->getBuddySharedPtr())->m_source;
if (buddySource)
{
buddySource->setThread(m_thread);
m_thread = 0; // zero for others
}
}
}
bool SoapySDRInput::start()
{
return false;

View File

@ -25,6 +25,7 @@
#include "dsp/devicesamplesource.h"
class DeviceSourceAPI;
class SoapySDRInputThread;
class SoapySDRInput : public DeviceSampleSource
{
@ -36,6 +37,8 @@ public:
virtual void init();
virtual bool start();
virtual void stop();
SoapySDRInputThread *getThread() { return m_thread; }
void setThread(SoapySDRInputThread *thread) { m_thread = thread; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
@ -51,11 +54,13 @@ public:
private:
DeviceSourceAPI *m_deviceAPI;
DeviceSoapySDRShared m_deviceShared;
SoapySDRInputThread *m_thread;
QString m_deviceDescription;
bool m_running;
bool openDevice();
void closeDevice();
void moveThreadToBuddy();
};

View File

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "util/simpleserializer.h"
#include "soapysdrinputsettings.h"
SoapySDRInputSettings::SoapySDRInputSettings()
{
resetToDefaults();
}
void SoapySDRInputSettings::resetToDefaults()
{
m_centerFrequency = 435000*1000;
m_LOppmTenths = 0;
m_devSampleRate = 1024000;
m_log2Decim = 0;
m_fcPos = FC_POS_CENTER;
m_dcBlock = false;
m_iqCorrection = false;
m_transverterMode = false;
m_transverterDeltaFrequency = 0;
m_fileRecordName = "";
}
QByteArray SoapySDRInputSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_devSampleRate);
s.writeU32(2, m_log2Decim);
s.writeS32(3, (int) m_fcPos);
s.writeBool(4, m_dcBlock);
s.writeBool(5, m_iqCorrection);
s.writeS32(6, m_LOppmTenths);
s.writeBool(7, m_transverterMode);
s.writeS64(8, m_transverterDeltaFrequency);
return s.final();
}
bool SoapySDRInputSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
int intval;
d.readS32(1, &m_devSampleRate, 1024000);
d.readU32(2, &m_log2Decim);
d.readS32(3, &intval, (int) FC_POS_CENTER);
m_fcPos = (fcPos_t) intval;
d.readBool(4, &m_dcBlock);
d.readBool(5, &m_iqCorrection);
d.readS32(6, &m_LOppmTenths);
d.readBool(7, &m_transverterMode, false);
d.readS64(8, &m_transverterDeltaFrequency, 0);
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,47 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_SOAPYSDRINPUTSETTINGS_H_
#define PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_SOAPYSDRINPUTSETTINGS_H_
#include <QtGlobal>
#include <QString>
struct SoapySDRInputSettings {
typedef enum {
FC_POS_INFRA = 0,
FC_POS_SUPRA,
FC_POS_CENTER
} fcPos_t;
quint64 m_centerFrequency;
qint32 m_LOppmTenths;
qint32 m_devSampleRate;
quint32 m_log2Decim;
fcPos_t m_fcPos;
bool m_dcBlock;
bool m_iqCorrection;
bool m_transverterMode;
qint64 m_transverterDeltaFrequency;
QString m_fileRecordName;
SoapySDRInputSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_SOAPYSDRINPUTSETTINGS_H_ */

View File

@ -0,0 +1,532 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <vector>
#include <algorithm>
#include <SoapySDR/Formats.hpp>
#include <SoapySDR/Errors.hpp>
#include "dsp/samplesinkfifo.h"
#include "soapysdr/devicesoapysdr.h"
#include "soapysdrinputthread.h"
SoapySDRInputThread::SoapySDRInputThread(SoapySDR::Device* dev, unsigned int nbRxChannels, QObject* parent) :
QThread(parent),
m_running(false),
m_dev(dev),
m_sampleRate(0),
m_nbChannels(nbRxChannels),
m_decimatorType(DecimatorFloat)
{
qDebug("SoapySDRInputThread::SoapySDRInputThread");
m_channels = new Channel[nbRxChannels];
for (unsigned int i = 0; i < nbRxChannels; i++) {
m_channels[i].m_convertBuffer.resize(DeviceSoapySDR::blockSize, Sample{0,0});
}
m_buf = new qint16[2*DeviceSoapySDR::blockSize*nbRxChannels];
}
SoapySDRInputThread::~SoapySDRInputThread()
{
qDebug("SoapySDRInputThread::~SoapySDRInputThread");
if (m_running) {
stopWork();
}
delete[] m_buf;
delete[] m_channels;
}
void SoapySDRInputThread::startWork()
{
m_startWaitMutex.lock();
start();
while(!m_running) {
m_startWaiter.wait(&m_startWaitMutex, 100);
}
m_startWaitMutex.unlock();
}
void SoapySDRInputThread::stopWork()
{
m_running = false;
wait();
}
void SoapySDRInputThread::run()
{
m_running = true;
m_startWaiter.wakeAll();
unsigned int nbFifos = getNbFifos();
if ((m_nbChannels > 0) && (nbFifos > 0))
{
// build channels list
std::vector<std::size_t> channels(m_nbChannels);
std::iota(channels.begin(), channels.end(), 0); // Fill with 0, 1, ..., m_nbChannels-1.
//initialize the sample rate for all channels
for (const auto &it : channels) {
m_dev->setSampleRate(SOAPY_SDR_RX, it, m_sampleRate);
}
// Determine sample format to be used
double fullScale(0.0);
std::string format = m_dev->getNativeStreamFormat(SOAPY_SDR_RX, channels.front(), fullScale);
if ((format == "CF8") && (fullScale == 128.0)) { // 8 bit signed - native
m_decimatorType = Decimator8;
} else if ((format == "CF16") && (fullScale == 2048.0)) { // 12 bit signed - native
m_decimatorType = Decimator12;
} else if ((format == "CF16") && (fullScale == 32768.0)) { // 16 bit signed - native
m_decimatorType = Decimator16;
} else { // for other types make a conversion to float
m_decimatorType = DecimatorFloat;
format = "CF32";
}
unsigned int elemSize = SoapySDR::formatToSize(format); // sample (I+Q) size in bytes
SoapySDR::Stream *stream = m_dev->setupStream(SOAPY_SDR_RX, format, channels);
//allocate buffers for the stream read/write
const unsigned int numElems = m_dev->getStreamMTU(stream); // number of samples (I+Q)
std::vector<std::vector<char>> buffMem(m_nbChannels, std::vector<char>(elemSize*numElems));
std::vector<void *> buffs(m_nbChannels);
for (std::size_t i = 0; i < m_nbChannels; i++) {
buffs[i] = buffMem[i].data();
}
qDebug("SoapySDRInputThread::run: start running loop");
m_dev->activateStream(stream);
int flags(0);
long long timeNs(0);
while (m_running)
{
int ret = m_dev->readStream(stream, buffs.data(), numElems, flags, timeNs);
if (ret < 0)
{
qCritical("SoapySDRInputThread::run: Unexpected read stream error: %s", SoapySDR::errToStr(ret));
break;
}
if (m_nbChannels > 1)
{
callbackMI(buffs, (elemSize/2)*numElems);
}
else
{
switch (m_decimatorType)
{
case Decimator8:
callbackSI8((const qint8*) buffs[0], (elemSize/2)*numElems);
break;
case Decimator12:
callbackSI12((const qint16*) buffs[0], (elemSize/2)*numElems);
break;
case Decimator16:
callbackSI16((const qint16*) buffs[0], (elemSize/2)*numElems);
break;
case DecimatorFloat:
default:
callbackSIF((const float*) buffs[0], (elemSize/2)*numElems);
}
}
}
qDebug("SoapySDRInputThread::run: stop running loop");
m_dev->deactivateStream(stream);
}
else
{
qWarning("SoapySDRInputThread::run: no channels or FIFO allocated. Aborting");
}
m_running = false;
}
unsigned int SoapySDRInputThread::getNbFifos()
{
unsigned int fifoCount = 0;
for (unsigned int i = 0; i < m_nbChannels; i++)
{
if (m_channels[i].m_sampleFifo) {
fifoCount++;
}
}
return fifoCount;
}
void SoapySDRInputThread::setLog2Decimation(unsigned int channel, unsigned int log2_decim)
{
if (channel < m_nbChannels) {
m_channels[channel].m_log2Decim = log2_decim;
}
}
unsigned int SoapySDRInputThread::getLog2Decimation(unsigned int channel) const
{
if (channel < m_nbChannels) {
return m_channels[channel].m_log2Decim;
} else {
return 0;
}
}
void SoapySDRInputThread::setFcPos(unsigned int channel, int fcPos)
{
if (channel < m_nbChannels) {
m_channels[channel].m_fcPos = fcPos;
}
}
int SoapySDRInputThread::getFcPos(unsigned int channel) const
{
if (channel < m_nbChannels) {
return m_channels[channel].m_fcPos;
} else {
return 0;
}
}
void SoapySDRInputThread::setFifo(unsigned int channel, SampleSinkFifo *sampleFifo)
{
if (channel < m_nbChannels) {
m_channels[channel].m_sampleFifo = sampleFifo;
}
}
SampleSinkFifo *SoapySDRInputThread::getFifo(unsigned int channel)
{
if (channel < m_nbChannels) {
return m_channels[channel].m_sampleFifo;
} else {
return 0;
}
}
void SoapySDRInputThread::callbackMI(std::vector<void *>& buffs, qint32 samplesPerChannel)
{
for(unsigned int ichan = 0; ichan < m_nbChannels; ichan++)
{
switch (m_decimatorType)
{
case Decimator8:
callbackSI8((const qint8*) buffs[ichan], samplesPerChannel, ichan);
break;
case Decimator12:
callbackSI12((const qint16*) buffs[ichan], samplesPerChannel, ichan);
break;
case Decimator16:
callbackSI16((const qint16*) buffs[ichan], samplesPerChannel, ichan);
break;
case DecimatorFloat:
default:
callbackSIF((const float*) buffs[ichan], samplesPerChannel, ichan);
}
}
}
void SoapySDRInputThread::callbackSI8(const qint8* buf, qint32 len, unsigned int channel)
{
SampleVector::iterator it = m_channels[channel].m_convertBuffer.begin();
if (m_channels[channel].m_log2Decim == 0)
{
m_channels[channel].m_decimators8.decimate1(&it, buf, len);
}
else
{
if (m_channels[channel].m_fcPos == 0) // Infra
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators8.decimate2_inf(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators8.decimate4_inf(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators8.decimate8_inf(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators8.decimate16_inf(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators8.decimate32_inf(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators8.decimate64_inf(&it, buf, len);
break;
default:
break;
}
}
else if (m_channels[channel].m_fcPos == 1) // Supra
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators8.decimate2_sup(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators8.decimate4_sup(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators8.decimate8_sup(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators8.decimate16_sup(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators8.decimate32_sup(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators8.decimate64_sup(&it, buf, len);
break;
default:
break;
}
}
else if (m_channels[channel].m_fcPos == 2) // Center
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators8.decimate2_cen(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators8.decimate4_cen(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators8.decimate8_cen(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators8.decimate16_cen(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators8.decimate32_cen(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators8.decimate64_cen(&it, buf, len);
break;
default:
break;
}
}
}
m_channels[channel].m_sampleFifo->write(m_channels[channel].m_convertBuffer.begin(), it);
}
void SoapySDRInputThread::callbackSI12(const qint16* buf, qint32 len, unsigned int channel)
{
SampleVector::iterator it = m_channels[channel].m_convertBuffer.begin();
if (m_channels[channel].m_log2Decim == 0)
{
m_channels[channel].m_decimators12.decimate1(&it, buf, len);
}
else
{
if (m_channels[channel].m_fcPos == 0) // Infra
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators12.decimate2_inf(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators12.decimate4_inf(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators12.decimate8_inf(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators12.decimate16_inf(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators12.decimate32_inf(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators12.decimate64_inf(&it, buf, len);
break;
default:
break;
}
}
else if (m_channels[channel].m_fcPos == 1) // Supra
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators12.decimate2_sup(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators12.decimate4_sup(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators12.decimate8_sup(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators12.decimate16_sup(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators12.decimate32_sup(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators12.decimate64_sup(&it, buf, len);
break;
default:
break;
}
}
else if (m_channels[channel].m_fcPos == 2) // Center
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators12.decimate2_cen(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators12.decimate4_cen(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators12.decimate8_cen(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators12.decimate16_cen(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators12.decimate32_cen(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators12.decimate64_cen(&it, buf, len);
break;
default:
break;
}
}
}
m_channels[channel].m_sampleFifo->write(m_channels[channel].m_convertBuffer.begin(), it);
}
void SoapySDRInputThread::callbackSI16(const qint16* buf, qint32 len, unsigned int channel)
{
SampleVector::iterator it = m_channels[channel].m_convertBuffer.begin();
if (m_channels[channel].m_log2Decim == 0)
{
m_channels[channel].m_decimators16.decimate1(&it, buf, len);
}
else
{
if (m_channels[channel].m_fcPos == 0) // Infra
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators16.decimate2_inf(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators16.decimate4_inf(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators16.decimate8_inf(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators16.decimate16_inf(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators16.decimate32_inf(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators16.decimate64_inf(&it, buf, len);
break;
default:
break;
}
}
else if (m_channels[channel].m_fcPos == 1) // Supra
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators16.decimate2_sup(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators16.decimate4_sup(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators16.decimate8_sup(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators16.decimate16_sup(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators16.decimate32_sup(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators16.decimate64_sup(&it, buf, len);
break;
default:
break;
}
}
else if (m_channels[channel].m_fcPos == 2) // Center
{
switch (m_channels[channel].m_log2Decim)
{
case 1:
m_channels[channel].m_decimators16.decimate2_cen(&it, buf, len);
break;
case 2:
m_channels[channel].m_decimators16.decimate4_cen(&it, buf, len);
break;
case 3:
m_channels[channel].m_decimators16.decimate8_cen(&it, buf, len);
break;
case 4:
m_channels[channel].m_decimators16.decimate16_cen(&it, buf, len);
break;
case 5:
m_channels[channel].m_decimators16.decimate32_cen(&it, buf, len);
break;
case 6:
m_channels[channel].m_decimators16.decimate64_cen(&it, buf, len);
break;
default:
break;
}
}
}
m_channels[channel].m_sampleFifo->write(m_channels[channel].m_convertBuffer.begin(), it);
}

View File

@ -0,0 +1,108 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_SOAPYSDRINPUTTHREAD_H_
#define PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_SOAPYSDRINPUTTHREAD_H_
// SoapySDR is a device wrapper with a single stream supporting one or many Rx
// Therefore only one thread can be allocated for the Rx side
// All FIFOs must be registered before calling startWork()
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <SoapySDR/Device.hpp>
#include "soapysdr/devicesoapysdrshared.h"
#include "dsp/decimators.h"
#include "dsp/decimatorsfi.h"
class SampleSinkFifo;
class SoapySDRInputThread : public QThread {
Q_OBJECT
public:
SoapySDRInputThread(SoapySDR::Device* dev, unsigned int nbRxChannels, QObject* parent = NULL);
~SoapySDRInputThread();
void startWork();
void stopWork();
bool isRunning() const { return m_running; }
unsigned int getNbChannels() const { return m_nbChannels; }
void setLog2Decimation(unsigned int channel, unsigned int log2_decim);
unsigned int getLog2Decimation(unsigned int channel) const;
void setSampleRate(unsigned int sampleRate) { m_sampleRate = sampleRate; }
unsigned int getSampleRate() const { return m_sampleRate; }
void setFcPos(unsigned int channel, int fcPos);
int getFcPos(unsigned int channel) const;
void setFifo(unsigned int channel, SampleSinkFifo *sampleFifo);
SampleSinkFifo *getFifo(unsigned int channel);
private:
struct Channel
{
SampleVector m_convertBuffer;
SampleSinkFifo* m_sampleFifo;
unsigned int m_log2Decim;
int m_fcPos;
Decimators<qint32, qint8, SDR_RX_SAMP_SZ, 8> m_decimators8;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12> m_decimators12;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators16;
DecimatorsFI m_decimatorsFloat;
Channel() :
m_sampleFifo(0),
m_log2Decim(0),
m_fcPos(0)
{}
~Channel()
{}
};
enum DecimatorType
{
Decimator8,
Decimator12,
Decimator16,
DecimatorFloat
};
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
SoapySDR::Device* m_dev;
Channel *m_channels; //!< Array of channels dynamically allocated for the given number of Rx channels
unsigned int m_sampleRate;
qint16 *m_buf; //!< Full buffer for SISO or MIMO operation
unsigned int m_nbChannels;
DecimatorType m_decimatorType;
void run();
unsigned int getNbFifos();
void callbackSI8(const qint8* buf, qint32 len, unsigned int channel = 0);
void callbackSI12(const qint16* buf, qint32 len, unsigned int channel = 0);
void callbackSI16(const qint16* buf, qint32 len, unsigned int channel = 0);
void callbackSIF(const float* buf, qint32 len, unsigned int channel = 0);
void callbackMI(std::vector<void *>& buffs, qint32 samplesPerChannel);
};
#endif /* PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_SOAPYSDRINPUTTHREAD_H_ */