SoapySDR support: input: center frequency and sample rate handling

pull/263/head
f4exb 2018-11-02 02:33:04 +01:00
rodzic 5acac7b9fa
commit ea98f2e1c9
12 zmienionych plików z 527 dodań i 14 usunięć

Wyświetl plik

@ -31,6 +31,42 @@ DeviceSoapySDRParams::DeviceSoapySDRParams(SoapySDR::Device *device) :
DeviceSoapySDRParams::~DeviceSoapySDRParams()
{}
std::string DeviceSoapySDRParams::getRxChannelMainTunableElementName(uint32_t index)
{
if (index < m_nbRx)
{
return std::string("RF");
}
else
{
const ChannelSettings& channelSettings = m_RxChannelsSettings[index];
if (channelSettings.m_frequencySettings.size() > 0) {
return channelSettings.m_frequencySettings.front().m_name;
} else {
return std::string("RF");
}
}
}
std::string DeviceSoapySDRParams::getTxChannelMainTunableElementName(uint32_t index)
{
if (index < m_nbRx)
{
return std::string("RF");
}
else
{
const ChannelSettings& channelSettings = m_RxChannelsSettings[index];
if (channelSettings.m_frequencySettings.size() > 0) {
return channelSettings.m_frequencySettings.front().m_name;
} else {
return std::string("RF");
}
}
}
void DeviceSoapySDRParams::fillParams()
{
m_deviceSettingsArgs = m_device->getSettingInfo();

Wyświetl plik

@ -86,6 +86,9 @@ public:
}
}
std::string getRxChannelMainTunableElementName(uint32_t index);
std::string getTxChannelMainTunableElementName(uint32_t index);
private:
void fillParams();
void fillChannelParams(std::vector<ChannelSettings>& channelSettings, int direction, unsigned int ichan);

Wyświetl plik

@ -16,6 +16,8 @@
#include "devicesoapysdrshared.h"
MESSAGE_CLASS_DEFINITION(DeviceSoapySDRShared::MsgReportBuddyChange, Message)
DeviceSoapySDRShared::DeviceSoapySDRShared() :
m_device(0),
m_channel(-1),

Wyświetl plik

@ -19,6 +19,7 @@
#include <SoapySDR/Device.hpp>
#include "util/message.h"
#include "export.h"
#include "devicesoapysdrparams.h"
@ -31,6 +32,53 @@ class SoapySDROutput;
class DEVICES_API DeviceSoapySDRShared
{
public:
class MsgReportBuddyChange : public Message {
MESSAGE_CLASS_DECLARATION
public:
uint64_t getCenterFrequency() const { return m_centerFrequency; }
int getLOppmTenths() const { return m_LOppmTenths; }
int getFcPos() const { return m_fcPos; }
int getDevSampleRate() const { return m_devSampleRate; }
bool getRxElseTx() const { return m_rxElseTx; }
static MsgReportBuddyChange* create(
uint64_t centerFrequency,
int LOppmTenths,
int fcPos,
int devSampleRate,
bool rxElseTx)
{
return new MsgReportBuddyChange(
centerFrequency,
LOppmTenths,
fcPos,
devSampleRate,
rxElseTx);
}
private:
uint64_t m_centerFrequency; //!< Center frequency
int m_LOppmTenths; //!< LO soft correction in tenths of ppm
int m_fcPos; //!< Center frequency position
int m_devSampleRate; //!< device/host sample rate
bool m_rxElseTx; //!< tells which side initiated the message
MsgReportBuddyChange(
uint64_t centerFrequency,
int LOppmTenths,
int fcPos,
int devSampleRate,
bool rxElseTx) :
Message(),
m_centerFrequency(centerFrequency),
m_LOppmTenths(LOppmTenths),
m_fcPos(fcPos),
m_devSampleRate(devSampleRate),
m_rxElseTx(rxElseTx)
{ }
};
DeviceSoapySDRShared();
~DeviceSoapySDRShared();

Wyświetl plik

@ -538,9 +538,9 @@ void BladeRF2Input::setCenterFrequency(qint64 centerFrequency)
}
}
bool BladeRF2Input::setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz)
bool BladeRF2Input::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_RX(requestedChannel), freq_hz);
@ -661,7 +661,7 @@ bool BladeRF2Input::handleMessage(const Message& message)
(DeviceSampleSource::fcPos_t) settings.m_fcPos,
settings.m_devSampleRate);
if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency))
if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths))
{
if (getMessageQueueToGUI())
{
@ -846,7 +846,7 @@ bool BladeRF2Input::applySettings(const BladeRF2InputSettings& settings, bool fo
if (dev != 0)
{
if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency))
if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths))
{
if (getMessageQueueToGUI())
{

Wyświetl plik

@ -192,7 +192,7 @@ private:
BladeRF2InputThread *findThread();
void moveThreadToBuddy();
bool applySettings(const BladeRF2InputSettings& settings, bool force = false);
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 BladeRF2InputSettings& settings);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
};

Wyświetl plik

@ -14,6 +14,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include "util/simpleserializer.h"
#include "device/devicesourceapi.h"
@ -26,17 +28,27 @@
#include "soapysdrinputthread.h"
#include "soapysdrinput.h"
MESSAGE_CLASS_DEFINITION(SoapySDRInput::MsgConfigureSoapySDRInput, Message)
MESSAGE_CLASS_DEFINITION(SoapySDRInput::MsgFileRecord, Message)
MESSAGE_CLASS_DEFINITION(SoapySDRInput::MsgStartStop, Message)
SoapySDRInput::SoapySDRInput(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_thread(0),
m_settings(),
m_deviceDescription("SoapySDRInput"),
m_running(false)
m_running(false),
m_thread(0)
{
openDevice();
m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
m_deviceAPI->addSink(m_fileSink);
}
SoapySDRInput::~SoapySDRInput()
{
m_deviceAPI->removeSink(m_fileSink);
delete m_fileSink;
}
void SoapySDRInput::destroy()
@ -195,6 +207,38 @@ void SoapySDRInput::init()
{
}
SoapySDRInputThread *SoapySDRInput::findThread()
{
if (m_thread == 0) // this does not own the thread
{
SoapySDRInputThread *soapySDRInputThread = 0;
// find a buddy that has allocated the thread
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)
{
soapySDRInputThread = buddySource->getThread();
if (soapySDRInputThread) {
break;
}
}
}
return soapySDRInputThread;
}
else
{
return m_thread; // own thread
}
}
void SoapySDRInput::moveThreadToBuddy()
{
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
@ -251,7 +295,256 @@ void SoapySDRInput::setCenterFrequency(qint64 centerFrequency __attribute__((unu
{
}
bool SoapySDRInput::setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths)
{
qint64 df = ((qint64)freq_hz * loPpmTenths) / 10000000LL;
freq_hz += df;
try
{
dev->setFrequency(SOAPY_SDR_RX,
requestedChannel,
m_deviceShared.m_deviceParams->getRxChannelMainTunableElementName(requestedChannel),
freq_hz);
qDebug("SoapySDRInput::setDeviceCenterFrequency: setFrequency(%llu)", freq_hz);
return true;
}
catch (const std::exception &ex)
{
qCritical("SoapySDRInput::applySettings: could not set frequency: %llu: %s", freq_hz, ex.what());
return false;
}
}
bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused)))
{
return false;
if (MsgConfigureSoapySDRInput::match(message))
{
MsgConfigureSoapySDRInput& conf = (MsgConfigureSoapySDRInput&) message;
qDebug() << "SoapySDRInput::handleMessage: MsgConfigureSoapySDRInput";
if (!applySettings(conf.getSettings(), conf.getForce())) {
qDebug("SoapySDRInput::handleMessage: MsgConfigureSoapySDRInput config error");
}
return true;
}
else if (MsgFileRecord::match(message))
{
MsgFileRecord& conf = (MsgFileRecord&) message;
qDebug() << "SoapySDRInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
if (conf.getStartStop())
{
if (m_settings.m_fileRecordName.size() != 0) {
m_fileSink->setFileName(m_settings.m_fileRecordName);
} else {
m_fileSink->genUniqueFileName(m_deviceAPI->getDeviceUID());
}
m_fileSink->startRecording();
}
else
{
m_fileSink->stopRecording();
}
return true;
}
else if (MsgStartStop::match(message))
{
MsgStartStop& cmd = (MsgStartStop&) message;
qDebug() << "SoapySDRInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
if (cmd.getStartStop())
{
if (m_deviceAPI->initAcquisition())
{
m_deviceAPI->startAcquisition();
}
}
else
{
m_deviceAPI->stopAcquisition();
}
return true;
}
else if (DeviceSoapySDRShared::MsgReportBuddyChange::match(message))
{
int requestedChannel = m_deviceAPI->getItemIndex();
DeviceSoapySDRShared::MsgReportBuddyChange& report = (DeviceSoapySDRShared::MsgReportBuddyChange&) message;
SoapySDRInputSettings settings = m_settings;
settings.m_fcPos = (SoapySDRInputSettings::fcPos_t) report.getFcPos();
settings.m_centerFrequency = m_deviceShared.m_device->getFrequency(
SOAPY_SDR_RX,
requestedChannel,
m_deviceShared.m_deviceParams->getRxChannelMainTunableElementName(requestedChannel));
settings.m_devSampleRate = m_deviceShared.m_device->getSampleRate(SOAPY_SDR_RX, requestedChannel);
SoapySDRInputThread *inputThread = findThread();
if (inputThread)
{
inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos);
}
m_settings = settings;
return true;
}
else
{
return false;
}
}
bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool force)
{
bool forwardChangeOwnDSP = false;
bool forwardChangeToBuddies = false;
SoapySDR::Device *dev = m_deviceShared.m_device;
SoapySDRInputThread *inputThread = 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_dcBlock != settings.m_dcBlock) ||
(m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
{
m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection);
}
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
{
forwardChangeOwnDSP = true;
forwardChangeToBuddies = true;
if (dev != 0)
{
try
{
dev->setSampleRate(SOAPY_SDR_RX, requestedChannel, settings.m_devSampleRate);
qDebug() << "SoapySDRInput::applySettings: setSampleRate OK: " << settings.m_devSampleRate;
if (inputThread)
{
bool wasRunning = inputThread->isRunning();
inputThread->stopWork();
inputThread->setSampleRate(settings.m_devSampleRate);
if (wasRunning) {
inputThread->startWork();
}
}
}
catch (const std::exception &ex)
{
qCritical("SoapySDRInput::applySettings: could not set sample rate: %d: %s",
settings.m_devSampleRate, ex.what());
}
}
}
if ((m_settings.m_fcPos != settings.m_fcPos) || force)
{
SoapySDRInputThread *inputThread = findThread();
if (inputThread != 0)
{
inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos);
qDebug() << "SoapySDRInput::applySettings: set fc pos (enum) to " << (int) settings.m_fcPos;
}
}
if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
{
forwardChangeOwnDSP = true;
SoapySDRInputThread *inputThread = findThread();
if (inputThread != 0)
{
inputThread->setLog2Decimation(requestedChannel, settings.m_log2Decim);
qDebug() << "SoapySDRInput::applySettings: set decimation to " << (1<<settings.m_log2Decim);
}
}
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_fcPos != settings.m_fcPos)
|| (m_settings.m_log2Decim != settings.m_log2Decim) || force)
{
qint64 deviceCenterFrequency = DeviceSampleSource::calculateDeviceCenterFrequency(
xlatedDeviceCenterFrequency,
0,
settings.m_log2Decim,
(DeviceSampleSource::fcPos_t) settings.m_fcPos,
settings.m_devSampleRate);
forwardChangeOwnDSP = true;
forwardChangeToBuddies = true;
if (dev != 0) {
setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths);
}
}
if (forwardChangeOwnDSP)
{
int sampleRate = settings.m_devSampleRate/(1<<settings.m_log2Decim);
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, settings.m_centerFrequency);
m_fileSink->handleMessage(*notif); // forward to file sink
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,
(int) settings.m_fcPos,
settings.m_devSampleRate,
true);
itSource->getSampleSourceInputMessageQueue()->push(report);
}
for (const auto &itSink : sinkBuddies)
{
DeviceSoapySDRShared::MsgReportBuddyChange *report = DeviceSoapySDRShared::MsgReportBuddyChange::create(
settings.m_centerFrequency,
settings.m_LOppmTenths,
(int) settings.m_fcPos,
settings.m_devSampleRate,
true);
itSink->getSampleSinkInputMessageQueue()->push(report);
}
}
m_settings = settings;
qDebug() << "SoapySDRInput::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_log2Decim: " << m_settings.m_log2Decim
<< " m_fcPos: " << m_settings.m_fcPos
<< " m_devSampleRate: " << m_settings.m_devSampleRate
<< " m_dcBlock: " << m_settings.m_dcBlock
<< " m_iqCorrection: " << m_settings.m_iqCorrection;
return true;
}

Wyświetl plik

@ -28,6 +28,12 @@
class DeviceSourceAPI;
class SoapySDRInputThread;
class FileRecord;
namespace SoapySDR
{
class Device;
}
class SoapySDRInput : public DeviceSampleSource
{
@ -119,14 +125,20 @@ public:
private:
DeviceSourceAPI *m_deviceAPI;
DeviceSoapySDRShared m_deviceShared;
SoapySDRInputThread *m_thread;
QMutex m_mutex;
SoapySDRInputSettings m_settings;
QString m_deviceDescription;
bool m_running;
SoapySDRInputThread *m_thread;
DeviceSoapySDRShared m_deviceShared;
FileRecord *m_fileSink; //!< File sink to record device I/Q output
bool openDevice();
void closeDevice();
SoapySDRInputThread *findThread();
void moveThreadToBuddy();
bool applySettings(const SoapySDRInputSettings& settings, bool force = false);
bool setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths);
};

Wyświetl plik

@ -49,6 +49,17 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000);
createRangesControl(m_sampleSource->getRateRanges(), "SR", "kS/s");
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(500);
displaySettings();
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue);
sendSettings();
}
SoapySDRInputGui::~SoapySDRInputGui()
@ -170,17 +181,59 @@ bool SoapySDRInputGui::deserialize(const QByteArray& data __attribute__((unused)
bool SoapySDRInputGui::handleMessage(const Message& message __attribute__((unused)))
{
return false;
if (SoapySDRInput::MsgStartStop::match(message))
{
SoapySDRInput::MsgStartStop& notif = (SoapySDRInput::MsgStartStop&) message;
blockApplySettings(true);
ui->startStop->setChecked(notif.getStartStop());
blockApplySettings(false);
return true;
}
else
{
return false;
}
}
void SoapySDRInputGui::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
qDebug("SoapySDRInputGui::handleInputMessages: message: %s", message->getIdentifier());
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification* notif = (DSPSignalNotification*) message;
m_sampleRate = notif->getSampleRate();
m_deviceCenterFrequency = notif->getCenterFrequency();
qDebug("SoapySDRInputGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency());
updateSampleRateAndFrequency();
delete message;
}
else
{
if (handleMessage(*message))
{
delete message;
}
}
}
}
void SoapySDRInputGui::sampleRateChanged(double sampleRate)
{
qDebug("SoapySDRInputGui::sampleRateChanged: %lf", sampleRate);
m_settings.m_devSampleRate = sampleRate;
sendSettings();
}
void SoapySDRInputGui::on_centerFrequency_changed(quint64 value)
{
qDebug("SoapySDRInputGui::on_centerFrequency_changed: %llu", value);
m_settings.m_centerFrequency = value * 1000;
sendSettings();
}
void SoapySDRInputGui::on_dcOffset_toggled(bool checked)
@ -227,6 +280,13 @@ void SoapySDRInputGui::on_transverter_clicked()
sendSettings();
}
void SoapySDRInputGui::on_LOppm_valueChanged(int value)
{
ui->LOppmText->setText(QString("%1").arg(QString::number(value/10.0, 'f', 1)));
m_settings.m_LOppmTenths = value;
sendSettings();
}
void SoapySDRInputGui::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
@ -261,6 +321,9 @@ void SoapySDRInputGui::displaySettings()
ui->decim->setCurrentIndex(m_settings.m_log2Decim);
ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos);
ui->LOppm->setValue(m_settings.m_LOppmTenths);
ui->LOppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1)));
blockApplySettings(false);
}

Wyświetl plik

@ -79,7 +79,9 @@ private:
void blockApplySettings(bool block);
private slots:
void handleInputMessages();
void on_centerFrequency_changed(quint64 value);
void on_LOppm_valueChanged(int value);
void sampleRateChanged(double sampleRate);
void on_dcOffset_toggled(bool checked);
void on_iqImbalance_toggled(bool checked);

Wyświetl plik

@ -167,7 +167,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<layout class="QHBoxLayout" name="horizontalLayout_common">
<property name="topMargin">
<number>6</number>
</property>
@ -319,6 +319,52 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_ppm">
<item>
<widget class="QLabel" name="LOppmLabel">
<property name="text">
<string>LO ppm</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="LOppm">
<property name="toolTip">
<string>Local Oscillator software ppm correction</string>
</property>
<property name="minimum">
<number>-1000</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="LOppmText">
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>-100.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_freq">
<property name="orientation">

Wyświetl plik

@ -57,6 +57,10 @@ SoapySDRInputThread::~SoapySDRInputThread()
void SoapySDRInputThread::startWork()
{
if (m_running) {
return;
}
m_startWaitMutex.lock();
start();
@ -69,6 +73,10 @@ void SoapySDRInputThread::startWork()
void SoapySDRInputThread::stopWork()
{
if (!m_running) {
return;
}
m_running = false;
wait();
}