1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-04-25 08:53:59 -04:00

SigMF file sink: more GUI changes

This commit is contained in:
f4exb 2020-07-15 10:57:24 +02:00
parent 80ea534840
commit ed3a300829
11 changed files with 412 additions and 178 deletions

View File

@ -38,7 +38,6 @@
#include "sigmffilesink.h"
MESSAGE_CLASS_DEFINITION(SigMFFileSink::MsgConfigureSigMFFileSink, Message)
MESSAGE_CLASS_DEFINITION(SigMFFileSink::MsgBasebandSampleRateNotification, Message)
const QString SigMFFileSink::m_channelIdURI = "sdrangel.channel.sigmffilesink";
const QString SigMFFileSink::m_channelId = "SigMFFileSink";
@ -52,9 +51,8 @@ SigMFFileSink::SigMFFileSink(DeviceAPI *deviceAPI) :
{
setObjectName(m_channelId);
m_thread = new QThread(this);
m_basebandSink = new SigMFFileSinkBaseband();
m_basebandSink->moveToThread(m_thread);
m_basebandSink->moveToThread(&m_thread);
applySettings(m_settings, true);
@ -71,8 +69,12 @@ SigMFFileSink::~SigMFFileSink()
delete m_networkManager;
m_deviceAPI->removeChannelSinkAPI(this);
m_deviceAPI->removeChannelSink(this);
if (m_basebandSink->isRunning()) {
stop();
}
delete m_basebandSink;
delete m_thread;
}
uint32_t SigMFFileSink::getNumberOfDeviceStreams() const
@ -90,38 +92,43 @@ void SigMFFileSink::start()
{
qDebug("SigMFFileSink::start");
m_basebandSink->reset();
m_thread->start();
m_basebandSink->startWork();
m_thread.start();
DSPSignalNotification *dspMsg = new DSPSignalNotification(m_basebandSampleRate, m_centerFrequency);
m_basebandSink->getInputMessageQueue()->push(dspMsg);
SigMFFileSinkBaseband::MsgConfigureSigMFFileSinkBaseband *msg = SigMFFileSinkBaseband::MsgConfigureSigMFFileSinkBaseband::create(m_settings, true);
m_basebandSink->getInputMessageQueue()->push(msg);
}
void SigMFFileSink::stop()
{
qDebug("SigMFFileSink::stop");
m_thread->exit();
m_thread->wait();
m_basebandSink->stopWork();
m_thread.exit();
m_thread.wait();
}
bool SigMFFileSink::handleMessage(const Message& cmd)
{
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
DSPSignalNotification& cfg = (DSPSignalNotification&) cmd;
qDebug() << "SigMFFileSink::handleMessage: DSPSignalNotification:"
<< " inputSampleRate: " << notif.getSampleRate()
<< " centerFrequency: " << notif.getCenterFrequency();
<< " inputSampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
m_basebandSampleRate = notif.getSampleRate();
m_centerFrequency = notif.getCenterFrequency();
calculateFrequencyOffset(m_settings.m_log2Decim, m_settings.m_filterChainHash); // This is when device sample rate changes
DSPSignalNotification *msg = new DSPSignalNotification(notif.getSampleRate(), notif.getCenterFrequency());
m_basebandSink->getInputMessageQueue()->push(msg);
m_basebandSampleRate = cfg.getSampleRate();
m_centerFrequency = cfg.getCenterFrequency();
DSPSignalNotification *notif = new DSPSignalNotification(cfg);
m_basebandSink->getInputMessageQueue()->push(notif);
if (getMessageQueueToGUI())
{
MsgBasebandSampleRateNotification *msg = MsgBasebandSampleRateNotification::create(notif.getSampleRate());
getMessageQueueToGUI()->push(msg);
DSPSignalNotification *notifToGUI = new DSPSignalNotification(cfg);
getMessageQueueToGUI()->push(notifToGUI);
}
return true;
@ -214,22 +221,16 @@ DeviceSampleSource *SigMFFileSink::getLocalDevice(uint32_t index)
void SigMFFileSink::applySettings(const SigMFFileSinkSettings& settings, bool force)
{
qDebug() << "SigMFFileSink::applySettings:"
<< "force: " << force;
<< "m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< "m_log2Decim: " << settings.m_log2Decim
<< "m_fileRecordName: " << settings.m_fileRecordName
<< "force: " << force;
QList<QString> reverseAPIKeys;
if ((settings.m_log2Decim != m_settings.m_log2Decim) || force) {
reverseAPIKeys.append("log2Decim");
}
if ((settings.m_filterChainHash != m_settings.m_filterChainHash) || force) {
reverseAPIKeys.append("filterChainHash");
}
if ((settings.m_log2Decim != m_settings.m_log2Decim)
|| (settings.m_filterChainHash != m_settings.m_filterChainHash) || force)
{
calculateFrequencyOffset(settings.m_log2Decim, settings.m_filterChainHash);
}
} // TOOO: the rest
SigMFFileSinkBaseband::MsgConfigureSigMFFileSinkBaseband *msg = SigMFFileSinkBaseband::MsgConfigureSigMFFileSinkBaseband::create(settings, force);
m_basebandSink->getInputMessageQueue()->push(msg);
@ -253,23 +254,6 @@ void SigMFFileSink::record(bool record)
m_basebandSink->getInputMessageQueue()->push(msg);
}
void SigMFFileSink::validateFilterChainHash(SigMFFileSinkSettings& settings)
{
unsigned int s = 1;
for (unsigned int i = 0; i < settings.m_log2Decim; i++) {
s *= 3;
}
settings.m_filterChainHash = settings.m_filterChainHash >= s ? s-1 : settings.m_filterChainHash;
}
void SigMFFileSink::calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash)
{
double shiftFactor = HBFilterChainConverter::getShiftFactor(log2Decim, filterChainHash);
m_frequencyOffset = m_basebandSampleRate * shiftFactor;
}
int SigMFFileSink::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
@ -320,13 +304,6 @@ void SigMFFileSink::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("log2Decim")) {
settings.m_log2Decim = response.getLocalSinkSettings()->getLog2Decim();
}
if (channelSettingsKeys.contains("filterChainHash"))
{
settings.m_filterChainHash = response.getLocalSinkSettings()->getFilterChainHash();
validateFilterChainHash(settings);
}
if (channelSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getLocalSinkSettings()->getUseReverseApi() != 0;
}
@ -355,7 +332,6 @@ void SigMFFileSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings&
}
response.getLocalSinkSettings()->setLog2Decim(settings.m_log2Decim);
response.getLocalSinkSettings()->setFilterChainHash(settings.m_filterChainHash);
response.getLocalSinkSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getLocalSinkSettings()->getReverseApiAddress()) {
@ -390,9 +366,6 @@ void SigMFFileSink::webapiReverseSendSettings(QList<QString>& channelSettingsKey
if (channelSettingsKeys.contains("log2Decim") || force) {
swgLocalSinkSettings->setLog2Decim(settings.m_log2Decim);
}
if (channelSettingsKeys.contains("filterChainHash") || force) {
swgLocalSinkSettings->setFilterChainHash(settings.m_filterChainHash);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)

View File

@ -19,6 +19,7 @@
#define INCLUDE_SIGMFFILESINK_H_
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QNetworkRequest>
@ -29,7 +30,6 @@
class QNetworkAccessManager;
class QNetworkReply;
class QThread;
class DeviceAPI;
class DeviceSampleSource;
@ -61,26 +61,6 @@ public:
{ }
};
class MsgBasebandSampleRateNotification : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgBasebandSampleRateNotification* create(int sampleRate) {
return new MsgBasebandSampleRateNotification(sampleRate);
}
int getSampleRate() const { return m_sampleRate; }
private:
MsgBasebandSampleRateNotification(int sampleRate) :
Message(),
m_sampleRate(sampleRate)
{ }
int m_sampleRate;
};
SigMFFileSink(DeviceAPI *deviceAPI);
virtual ~SigMFFileSink();
virtual void destroy() { delete this; }
@ -135,7 +115,7 @@ public:
private:
DeviceAPI *m_deviceAPI;
QThread *m_thread;
QThread m_thread;
SigMFFileSinkBaseband *m_basebandSink;
SigMFFileSinkSettings m_settings;
@ -148,8 +128,6 @@ private:
void applySettings(const SigMFFileSinkSettings& settings, bool force = false);
void propagateSampleRateAndFrequency(uint32_t index, uint32_t log2Decim);
static void validateFilterChainHash(SigMFFileSinkSettings& settings);
void calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash);
DeviceSampleSource *getLocalDevice(uint32_t index);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SigMFFileSinkSettings& settings, bool force);

View File

@ -27,12 +27,31 @@ MESSAGE_CLASS_DEFINITION(SigMFFileSinkBaseband::MsgConfigureSigMFFileSinkBaseban
MESSAGE_CLASS_DEFINITION(SigMFFileSinkBaseband::MsgConfigureSigMFFileSinkWork, Message)
SigMFFileSinkBaseband::SigMFFileSinkBaseband() :
m_running(false),
m_mutex(QMutex::Recursive)
{
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000));
m_channelizer = new DownChannelizer(&m_sink);
qDebug("SigMFFileSinkBaseband::SigMFFileSinkBaseband");
}
SigMFFileSinkBaseband::~SigMFFileSinkBaseband()
{
m_inputMessageQueue.clear();
delete m_channelizer;
}
void SigMFFileSinkBaseband::reset()
{
QMutexLocker mutexLocker(&m_mutex);
m_inputMessageQueue.clear();
m_sampleFifo.reset();
}
void SigMFFileSinkBaseband::startWork()
{
QMutexLocker mutexLocker(&m_mutex);
QObject::connect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
@ -40,19 +59,21 @@ SigMFFileSinkBaseband::SigMFFileSinkBaseband() :
&SigMFFileSinkBaseband::handleData,
Qt::QueuedConnection
);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_running = true;
}
SigMFFileSinkBaseband::~SigMFFileSinkBaseband()
{
delete m_channelizer;
}
void SigMFFileSinkBaseband::reset()
void SigMFFileSinkBaseband::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
m_sampleFifo.reset();
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
QObject::disconnect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
this,
&SigMFFileSinkBaseband::handleData
);
m_running = false;
}
void SigMFFileSinkBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
@ -115,10 +136,19 @@ bool SigMFFileSinkBaseband::handleMessage(const Message& cmd)
{
QMutexLocker mutexLocker(&m_mutex);
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
qDebug() << "SigMFFileSinkBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
qDebug() << "SigMFFileSinkBaseband::handleMessage: DSPSignalNotification:"
<< " basebandSampleRate: " << notif.getSampleRate()
<< " cnterFrequency: " << notif.getCenterFrequency();
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate()));
m_channelizer->setBasebandSampleRate(notif.getSampleRate(), true); // apply decimation
m_sink.setSampleRate(getChannelSampleRate());
m_centerFrequency = notif.getCenterFrequency();
m_channelizer->setBasebandSampleRate(notif.getSampleRate());
int desiredSampleRate = m_channelizer->getBasebandSampleRate() / (1<<m_settings.m_log2Decim);
m_channelizer->setChannelization(desiredSampleRate, m_settings.m_inputFrequencyOffset);
m_sink.applyChannelSettings(
m_channelizer->getChannelSampleRate(),
desiredSampleRate,
m_channelizer->getChannelFrequencyOffset(),
m_centerFrequency + m_settings.m_inputFrequencyOffset);
return true;
}
@ -146,17 +176,24 @@ void SigMFFileSinkBaseband::applySettings(const SigMFFileSinkSettings& settings,
{
qDebug() << "SigMFFileSinkBaseband::applySettings:"
<< "m_log2Decim:" << settings.m_log2Decim
<< "m_filterChainHash:" << settings.m_filterChainHash
<< " force: " << force;
<< "m_inputFrequencyOffset:" << settings.m_inputFrequencyOffset
<< "m_fileRecordName: " << settings.m_fileRecordName
<< "m_centerFrequency: " << m_centerFrequency
<< "force: " << force;
if ((settings.m_log2Decim != m_settings.m_log2Decim)
|| (settings.m_filterChainHash != m_settings.m_filterChainHash) || force)
|| (settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
{
m_channelizer->setDecimation(settings.m_log2Decim, settings.m_filterChainHash);
m_sink.setSampleRate(getChannelSampleRate());
int desiredSampleRate = m_channelizer->getBasebandSampleRate() / (1<<settings.m_log2Decim);
m_channelizer->setChannelization(desiredSampleRate, settings.m_inputFrequencyOffset);
m_sink.applyChannelSettings(
m_channelizer->getChannelSampleRate(),
desiredSampleRate,
m_channelizer->getChannelFrequencyOffset(),
m_centerFrequency + settings.m_inputFrequencyOffset);
}
//m_source.applySettings(settings, force);
m_sink.applySettings(settings, force);
m_settings = settings;
}

View File

@ -81,10 +81,13 @@ public:
~SigMFFileSinkBaseband();
void reset();
void startWork();
void stopWork();
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
int getChannelSampleRate() const;
void setBasebandSampleRate(int sampleRate);
bool isRunning() const { return m_running; }
private:
SampleSinkFifo m_sampleFifo;
@ -92,6 +95,8 @@ private:
SigMFFileSinkSink m_sink;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
SigMFFileSinkSettings m_settings;
int64_t m_centerFrequency;
bool m_running;
QMutex m_mutex;
bool handleMessage(const Message& cmd);

View File

@ -16,11 +16,13 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QLocale>
#include <QFileDialog>
#include "device/deviceuiset.h"
#include "gui/basicchannelsettingsdialog.h"
#include "gui/devicestreamselectiondialog.h"
#include "dsp/hbfilterchainconverter.h"
#include "dsp/dspcommands.h"
#include "mainwindow.h"
#include "sigmffilesinkgui.h"
@ -86,12 +88,22 @@ bool SigMFFileSinkGUI::deserialize(const QByteArray& data)
bool SigMFFileSinkGUI::handleMessage(const Message& message)
{
if (SigMFFileSink::MsgBasebandSampleRateNotification::match(message))
if (DSPSignalNotification::match(message))
{
SigMFFileSink::MsgBasebandSampleRateNotification& notif = (SigMFFileSink::MsgBasebandSampleRateNotification&) message;
//m_channelMarker.setBandwidth(notif.getSampleRate());
DSPSignalNotification notif = (const DSPSignalNotification&) message;
m_basebandSampleRate = notif.getSampleRate();
displayRateAndShift();
displayRate();
if (m_fixedPosition)
{
setFrequencyFromPos();
applySettings();
}
else
{
setPosFromFrequency();
}
return true;
}
else if (SigMFFileSink::MsgConfigureSigMFFileSink::match(message))
@ -114,7 +126,10 @@ SigMFFileSinkGUI::SigMFFileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISe
ui(new Ui::SigMFFileSinkGUI),
m_pluginAPI(pluginAPI),
m_deviceUISet(deviceUISet),
m_channelMarker(this),
m_fixedShiftIndex(0),
m_basebandSampleRate(0),
m_fixedPosition(false),
m_tickCount(0)
{
ui->setupUi(this);
@ -132,6 +147,7 @@ SigMFFileSinkGUI::SigMFFileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISe
m_channelMarker.blockSignals(true);
m_channelMarker.setColor(m_settings.m_rgbColor);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setBandwidth(m_basebandSampleRate);
m_channelMarker.setTitle("SigMF File Sink");
m_channelMarker.blockSignals(false);
m_channelMarker.setVisible(true); // activate signal on the last setting only
@ -142,8 +158,9 @@ SigMFFileSinkGUI::SigMFFileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISe
m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this);
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
//connect(&(m_deviceUISet->m_deviceSourceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick()));
displaySettings();
applySettings(true);
@ -175,10 +192,9 @@ void SigMFFileSinkGUI::applySettings(bool force)
void SigMFFileSinkGUI::displaySettings()
{
m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setTitle(m_settings.m_title);
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
m_channelMarker.setBandwidth(m_basebandSampleRate / (1<<m_settings.m_log2Decim));
m_channelMarker.setMovable(false); // do not let user move the center arbitrarily
m_channelMarker.setTitle(m_settings.m_title);
m_channelMarker.blockSignals(false);
m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only
@ -187,9 +203,11 @@ void SigMFFileSinkGUI::displaySettings()
blockApplySettings(true);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
ui->fileNameText->setText(m_settings.m_fileRecordName);
ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim);
applyDecimation();
displayStreamIndex();
setPosFromFrequency();
blockApplySettings(false);
}
@ -203,18 +221,19 @@ void SigMFFileSinkGUI::displayStreamIndex()
}
}
void SigMFFileSinkGUI::displayRateAndShift()
void SigMFFileSinkGUI::displayRate()
{
int shift = m_shiftFrequencyFactor * m_basebandSampleRate;
ui->deltaFrequency->setValue(shift);
//QLocale loc;
//ui->offsetFrequencyText->setText(tr("%1 Hz").arg(loc.toString(shift)));
double channelSampleRate = ((double) m_basebandSampleRate) / (1<<m_settings.m_log2Decim);
ui->channelRateText->setText(tr("%1k").arg(QString::number(channelSampleRate / 1000.0, 'g', 5)));
m_channelMarker.setCenterFrequency(shift);
m_channelMarker.setBandwidth(channelSampleRate);
}
void SigMFFileSinkGUI::displayPos()
{
ui->position->setValue(m_fixedShiftIndex);
ui->filterChainIndex->setText(tr("%1").arg(m_fixedShiftIndex));
}
void SigMFFileSinkGUI::leaveEvent(QEvent*)
{
m_channelMarker.setHighlighted(false);
@ -225,6 +244,23 @@ void SigMFFileSinkGUI::enterEvent(QEvent*)
m_channelMarker.setHighlighted(true);
}
void SigMFFileSinkGUI::channelMarkerChangedByCursor()
{
if (m_fixedPosition) {
return;
}
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
setPosFromFrequency();
applySettings();
}
void SigMFFileSinkGUI::channelMarkerHighlightedByCursor()
{
setHighlighted(m_channelMarker.getHighlighted());
}
void SigMFFileSinkGUI::handleSourceMessages()
{
Message* message;
@ -289,46 +325,119 @@ void SigMFFileSinkGUI::onMenuDialogCalled(const QPoint &p)
resetContextMenuType();
}
void SigMFFileSinkGUI::on_deltaFrequency_changed(qint64 value)
{
if (!m_fixedPosition)
{
m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
setPosFromFrequency();
applySettings();
}
}
void SigMFFileSinkGUI::on_decimationFactor_currentIndexChanged(int index)
{
m_settings.m_log2Decim = index;
applyDecimation();
displayRate();
displayPos();
if (m_fixedPosition)
{
setFrequencyFromPos();
applySettings();
}
else
{
setPosFromFrequency();
}
}
void SigMFFileSinkGUI::on_fixedPosition_toggled(bool checked)
{
m_fixedPosition = checked;
m_channelMarker.setMovable(!checked);
ui->deltaFrequency->setEnabled(!checked);
ui->position->setEnabled(checked);
if (m_fixedPosition)
{
setFrequencyFromPos();
applySettings();
}
}
void SigMFFileSinkGUI::on_position_valueChanged(int value)
{
m_settings.m_filterChainHash = value;
applyPosition();
m_fixedShiftIndex = value;
displayPos();
if (m_fixedPosition)
{
setFrequencyFromPos();
applySettings();
}
}
void SigMFFileSinkGUI::on_record_toggled(bool checked)
{
if (checked) {
ui->record->setStyleSheet("QToolButton { background-color : red; }");
} else {
ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
}
m_sigMFFileSink->record(checked);
}
void SigMFFileSinkGUI::applyDecimation()
void SigMFFileSinkGUI::on_showFileDialog_clicked(bool checked)
{
uint32_t maxHash = 1;
(void) checked;
QFileDialog fileDialog(
this,
tr("Save SigMF record file"),
m_settings.m_fileRecordName,
tr("SigMF Files (*.sigmf-meta)")
);
for (uint32_t i = 0; i < m_settings.m_log2Decim; i++) {
maxHash *= 3;
fileDialog.setOptions(QFileDialog::DontUseNativeDialog);
fileDialog.setFileMode(QFileDialog::AnyFile);
QStringList fileNames;
if (fileDialog.exec())
{
fileNames = fileDialog.selectedFiles();
if (fileNames.size() > 0)
{
m_settings.m_fileRecordName = fileNames.at(0);
ui->fileNameText->setText(m_settings.m_fileRecordName);
applySettings();
}
}
ui->position->setMaximum(maxHash-1);
ui->position->setValue(m_settings.m_filterChainHash);
m_settings.m_filterChainHash = ui->position->value();
applyPosition();
}
void SigMFFileSinkGUI::applyPosition()
void SigMFFileSinkGUI::setFrequencyFromPos()
{
ui->filterChainIndex->setText(tr("%1").arg(m_settings.m_filterChainHash));
QString s;
m_shiftFrequencyFactor = HBFilterChainConverter::convertToString(m_settings.m_log2Decim, m_settings.m_filterChainHash, s);
ui->filterChainText->setText(s);
int inputFrequencyOffset = SigMFFileSinkSettings::getOffsetFromFixedShiftIndex(
m_basebandSampleRate,
m_settings.m_log2Decim,
m_fixedShiftIndex);
m_channelMarker.setCenterFrequency(inputFrequencyOffset);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
}
displayRateAndShift();
applySettings();
void SigMFFileSinkGUI::setPosFromFrequency()
{
int fshift = SigMFFileSinkSettings::getHalfBand(m_basebandSampleRate, m_settings.m_log2Decim + 1);
m_fixedShiftIndex = SigMFFileSinkSettings::getFixedShiftIndexFromOffset(
m_basebandSampleRate,
m_settings.m_log2Decim,
m_settings.m_inputFrequencyOffset + (m_settings.m_inputFrequencyOffset < 0 ? -fshift : fshift)
);
displayPos();
}
void SigMFFileSinkGUI::tick()
@ -337,3 +446,10 @@ void SigMFFileSinkGUI::tick()
m_tickCount = 0;
}
}
void SigMFFileSinkGUI::applyDecimation()
{
ui->position->setMaximum(SigMFFileSinkSettings::getNbFixedShiftIndexes(m_settings.m_log2Decim)-1);
ui->position->setValue(m_fixedShiftIndex);
m_fixedShiftIndex = ui->position->value();
}

View File

@ -55,14 +55,20 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message);
public slots:
void channelMarkerChangedByCursor();
void channelMarkerHighlightedByCursor();
private:
Ui::SigMFFileSinkGUI* ui;
PluginAPI* m_pluginAPI;
DeviceUISet* m_deviceUISet;
ChannelMarker m_channelMarker;
SigMFFileSinkSettings m_settings;
int m_fixedShiftIndex;
int m_basebandSampleRate;
double m_shiftFrequencyFactor; //!< Channel frequency shift factor
bool m_fixedPosition;
bool m_doApplySettings;
SigMFFileSink* m_sigMFFileSink;
@ -75,22 +81,25 @@ private:
void blockApplySettings(bool block);
void applySettings(bool force = false);
void applyDecimation();
void displaySettings();
void displayStreamIndex();
void displayRateAndShift();
void updateLocalDevices();
void displayRate();
void displayPos();
void setFrequencyFromPos();
void setPosFromFrequency();
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
void applyDecimation();
void applyPosition();
private slots:
void handleSourceMessages();
void on_deltaFrequency_changed(qint64 value);
void on_decimationFactor_currentIndexChanged(int index);
void on_fixedPosition_toggled(bool checked);
void on_position_valueChanged(int value);
void on_record_toggled(bool checked);
void on_showFileDialog_clicked(bool checked);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void tick();

View File

@ -80,7 +80,7 @@
<item>
<widget class="ValueDialZ" name="deltaFrequency" native="true">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
@ -125,13 +125,6 @@
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="nco">
<property name="text">
<string>NCO</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="decimationLabel">
<property name="text">
@ -227,7 +220,10 @@
<number>10</number>
</property>
<item>
<widget class="QLabel" name="positionLabel">
<widget class="QCheckBox" name="fixedPosition">
<property name="toolTip">
<string>Use fixed frequency shift positions for little performance improvement</string>
</property>
<property name="text">
<string>Pos</string>
</property>
@ -268,22 +264,6 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="filterChainText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Filter chain stages left to right (L: low, C: center, H: high) </string>
</property>
<property name="text">
<string>LLLLLL</string>
</property>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -35,7 +35,6 @@ void SigMFFileSinkSettings::resetToDefaults()
m_rgbColor = QColor(140, 4, 4).rgb();
m_title = "SigMF File Sink";
m_log2Decim = 0;
m_filterChainHash = 0;
m_channelMarker = nullptr;
m_streamIndex = 0;
m_useReverseAPI = false;
@ -60,7 +59,6 @@ QByteArray SigMFFileSinkSettings::serialize() const
s.writeU32(10, m_reverseAPIDeviceIndex);
s.writeU32(11, m_reverseAPIChannelIndex);
s.writeU32(12, m_log2Decim);
s.writeU32(13, m_filterChainHash);
return s.final();
}
@ -102,7 +100,6 @@ bool SigMFFileSinkSettings::deserialize(const QByteArray& data)
m_reverseAPIChannelIndex = tmp > 99 ? 99 : tmp;
d.readU32(12, &tmp, 0);
m_log2Decim = tmp > 6 ? 6 : tmp;
d.readU32(13, &m_filterChainHash, 0);
return true;
}
@ -113,7 +110,34 @@ bool SigMFFileSinkSettings::deserialize(const QByteArray& data)
}
}
unsigned int SigMFFileSinkSettings::getNbFixedShiftIndexes(int log2Decim)
{
int decim = (1<<log2Decim);
return 2*decim - 1;
}
int SigMFFileSinkSettings::getHalfBand(int sampleRate, int log2Decim)
{
int decim = (1<<log2Decim);
return sampleRate / (2*decim);
}
unsigned int SigMFFileSinkSettings::getFixedShiftIndexFromOffset(int sampleRate, int log2Decim, int frequencyOffset)
{
if (sampleRate == 0) {
return 0;
}
int decim = (1<<log2Decim);
int mid = decim - 1;
return ((frequencyOffset*2*decim) / sampleRate) + mid;
}
int SigMFFileSinkSettings::getOffsetFromFixedShiftIndex(int sampleRate, int log2Decim, int shiftIndex)
{
int decim = (1<<log2Decim);
int mid = decim - 1;
return ((shiftIndex - mid) * sampleRate) / (2*decim);
}

View File

@ -31,7 +31,6 @@ struct SigMFFileSinkSettings
quint32 m_rgbColor;
QString m_title;
uint32_t m_log2Decim;
uint32_t m_filterChainHash;
int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx).
bool m_useReverseAPI;
QString m_reverseAPIAddress;
@ -46,6 +45,11 @@ struct SigMFFileSinkSettings
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
static unsigned int getNbFixedShiftIndexes(int log2Decim);
static int getHalfBand(int sampleRate, int log2Decim);
static unsigned int getFixedShiftIndexFromOffset(int sampleRate, int log2Decim, int frequencyOffset);
static int getOffsetFromFixedShiftIndex(int sampleRate, int log2Decim, int shiftIndex);
};
#endif /* INCLUDE_SIFMFFILESINKSETTINGS_H_ */

View File

@ -15,11 +15,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsp/filerecord.h"
#include <QDebug>
#include "dsp/dspcommands.h"
#include "dsp/sigmffilerecord.h"
#include "sigmffilesinksink.h"
SigMFFileSinkSink::SigMFFileSinkSink() :
m_recordEnabled(false),
m_record(false)
{}
@ -28,12 +32,8 @@ SigMFFileSinkSink::~SigMFFileSinkSink()
void SigMFFileSinkSink::startRecording()
{
QString fileBase;
FileRecordInterface::RecordType recordType = FileRecordInterface::guessTypeFromFileName(m_settings.m_fileRecordName, fileBase);
if (recordType == FileRecordInterface::RecordTypeSigMF)
if (m_recordEnabled)
{
m_fileSink.setFileName(fileBase);
m_fileSink.startRecording();
m_record = true;
}
@ -47,11 +47,105 @@ void SigMFFileSinkSink::stopRecording()
void SigMFFileSinkSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{
for (SampleVector::const_iterator it = begin; it < end; ++it)
{
Complex c(it->real(), it->imag());
c *= m_nco.nextIQ();
if (m_interpolatorDistance == 1)
{
m_sampleBuffer.push_back(Sample(c.real(), c.imag()));
}
else
{
Complex ci;
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
{
m_sampleBuffer.push_back(Sample(ci.real(), ci.imag()));
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
}
if (m_record) {
m_fileSink.feed(begin, end, true);
m_fileSink.feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), true);
}
m_sampleBuffer.clear();
}
void SigMFFileSinkSink::setSampleRate(int sampleRate)
void SigMFFileSinkSink::applyChannelSettings(
int channelSampleRate,
int sinkSampleRate,
int channelFrequencyOffset,
int64_t centerFrequency,
bool force)
{
qDebug() << "SigMFFileSinkSink::applyChannelSettings:"
<< " channelSampleRate: " << channelSampleRate
<< " sinkSampleRate: " << sinkSampleRate
<< " channelFrequencyOffset: " << channelFrequencyOffset
<< " centerFrequency: " << centerFrequency
<< " force: " << force;
if ((m_channelFrequencyOffset != channelFrequencyOffset) ||
(m_channelSampleRate != channelSampleRate) || force)
{
m_nco.setFreq(-channelFrequencyOffset, channelSampleRate);
}
if ((m_channelSampleRate != channelSampleRate)
|| (m_sinkSampleRate != sinkSampleRate) || force)
{
m_interpolator.create(16, channelSampleRate, channelSampleRate / 2.2f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) channelSampleRate / (Real) sinkSampleRate;
}
if ((m_centerFrequency != centerFrequency)
|| (m_channelFrequencyOffset != channelFrequencyOffset)
|| (m_sinkSampleRate != sinkSampleRate) || force)
{
DSPSignalNotification *notif = new DSPSignalNotification(sinkSampleRate, centerFrequency + m_settings.m_inputFrequencyOffset);
m_fileSink.getInputMessageQueue()->push(notif);
}
m_channelSampleRate = channelSampleRate;
m_channelFrequencyOffset = channelFrequencyOffset;
m_sinkSampleRate = sinkSampleRate;
m_centerFrequency = centerFrequency;
}
void SigMFFileSinkSink::applySettings(const SigMFFileSinkSettings& settings, bool force)
{
qDebug() << "SigMFFileSinkSink::applySettings:"
<< "m_log2Decim:" << settings.m_log2Decim
<< "m_inputFrequencyOffset:" << settings.m_inputFrequencyOffset
<< "m_fileRecordName: " << settings.m_fileRecordName
<< "force: " << force;
if ((settings.m_fileRecordName != m_settings.m_fileRecordName) || force)
{
QString fileBase;
FileRecordInterface::RecordType recordType = FileRecordInterface::guessTypeFromFileName(settings.m_fileRecordName, fileBase);
if (recordType == FileRecordInterface::RecordTypeSigMF)
{
m_fileSink.setFileName(fileBase);
m_recordEnabled = true;
}
else
{
m_recordEnabled = false;
}
}
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
{
DSPSignalNotification *notif = new DSPSignalNotification(m_sinkSampleRate, m_centerFrequency + m_settings.m_inputFrequencyOffset);
m_fileSink.getInputMessageQueue()->push(notif);
}
m_settings = settings;
}

View File

@ -20,6 +20,8 @@
#include "dsp/channelsamplesink.h"
#include "dsp/sigmffilerecord.h"
#include "dsp/interpolator.h"
#include "dsp/ncof.h"
#include "sigmffilesinksettings.h"
@ -37,15 +39,27 @@ public:
void stopRecording();
void setDeviceHwId(const QString& hwId) { m_deviceHwId = hwId; }
void setDeviceUId(int uid) { m_deviceUId = uid; }
void setSampleRate(int sampleRate);
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
void applyChannelSettings(
int channelSampleRate,
int sinkSampleRate,
int channelFrequencyOffset,
int64_t centerFrequency,
bool force = false);
void applySettings(const SigMFFileSinkSettings& settings, bool force = false);
private:
int m_channelSampleRate;
int m_channelFrequencyOffset;
int m_sinkSampleRate;
int64_t m_centerFrequency;
NCOF m_nco;
Interpolator m_interpolator;
Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain;
SampleVector m_sampleBuffer;
SigMFFileSinkSettings m_settings;
SigMFFileRecord m_fileSink;
bool m_recordEnabled;
bool m_record;
QString m_deviceHwId;
int m_deviceUId;