mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-07-30 12:42:25 -04:00
Build AirspyHF and BladeRF server plugins. Removed AirspyHFi
This commit is contained in:
parent
275a020818
commit
cc3483aabe
@ -1,78 +0,0 @@
|
||||
project(airspyhfi)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
|
||||
set(airspyhfi_SOURCES
|
||||
airspyhfigui.cpp
|
||||
airspyhfiinput.cpp
|
||||
airspyhfiplugin.cpp
|
||||
airspyhfisettings.cpp
|
||||
airspyhfithread.cpp
|
||||
)
|
||||
|
||||
set(airspyhfi_HEADERS
|
||||
airspyhfigui.h
|
||||
airspyhfiinput.h
|
||||
airspyhfiplugin.h
|
||||
airspyhfisettings.h
|
||||
airspyhfithread.h
|
||||
)
|
||||
|
||||
set(airspyhfi_FORMS
|
||||
airspyhfigui.ui
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${LIBAIRSPYHFSRC}
|
||||
${LIBAIRSPYHFSRC}/libairspyhf/src
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${LIBAIRSPYHF_INCLUDE_DIR}
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
#include(${QT_USE_FILE})
|
||||
#add_definitions(${QT_DEFINITIONS})
|
||||
add_definitions("${QT_DEFINITIONS} -DLIBAIRSPY_DYN_RATES")
|
||||
add_definitions(-DQT_PLUGIN)
|
||||
add_definitions(-DQT_SHARED)
|
||||
|
||||
#qt4_wrap_cpp(airspyhf_HEADERS_MOC ${airspyhf_HEADERS})
|
||||
qt5_wrap_ui(airspyhfi_FORMS_HEADERS ${airspyhfi_FORMS})
|
||||
|
||||
add_library(inputairspyhfi SHARED
|
||||
${airspyhfi_SOURCES}
|
||||
${airspyhfi_HEADERS_MOC}
|
||||
${airspyhfi_FORMS_HEADERS}
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
target_link_libraries(inputairspyhfi
|
||||
${QT_LIBRARIES}
|
||||
airspyhf
|
||||
sdrbase
|
||||
sdrgui
|
||||
swagger
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
target_link_libraries(inputairspyhfi
|
||||
${QT_LIBRARIES}
|
||||
${LIBAIRSPYHF_LIBRARIES}
|
||||
sdrbase
|
||||
sdrgui
|
||||
swagger
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
|
||||
qt5_use_modules(inputairspyhfi Core Widgets)
|
||||
|
||||
install(TARGETS inputairspyhfi DESTINATION lib/plugins/samplesource)
|
@ -1,50 +0,0 @@
|
||||
#--------------------------------------------------------
|
||||
#
|
||||
# Pro file for Android and Windows builds with Qt Creator
|
||||
#
|
||||
#--------------------------------------------------------
|
||||
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin
|
||||
|
||||
QT += core gui widgets multimedia opengl
|
||||
|
||||
TARGET = inputairspyhfi
|
||||
|
||||
CONFIG(MINGW32):LIBAIRSPYHFSRC = "D:\softs\airspyhf"
|
||||
CONFIG(MINGW64):LIBAIRSPYHFSRC = "D:\softs\airspyhf"
|
||||
INCLUDEPATH += $$PWD
|
||||
INCLUDEPATH += ../../../sdrbase
|
||||
INCLUDEPATH += ../../../sdrgui
|
||||
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
|
||||
INCLUDEPATH += $$LIBAIRSPYHFSRC
|
||||
|
||||
DEFINES += USE_SSE2=1
|
||||
QMAKE_CXXFLAGS += -msse2
|
||||
DEFINES += USE_SSE4_1=1
|
||||
QMAKE_CXXFLAGS += -msse4.1
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
|
||||
CONFIG(Release):build_subdir = release
|
||||
CONFIG(Debug):build_subdir = debug
|
||||
|
||||
SOURCES += airspyhfigui.cpp\
|
||||
airspyhfiinput.cpp\
|
||||
airspyhfiplugin.cpp\
|
||||
airspyhfisettings.cpp\
|
||||
airspyhfithread.cpp
|
||||
|
||||
HEADERS += airspyhfigui.h\
|
||||
airspyhfiinput.h\
|
||||
airspyhfiplugin.h\
|
||||
airspyhfisettings.h\
|
||||
airspyhfithread.h
|
||||
|
||||
FORMS += airspyhfigui.ui
|
||||
|
||||
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
|
||||
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
|
||||
LIBS += -L../../../swagger/$${build_subdir} -lswagger
|
||||
LIBS += -L../../../libairspyhf/$${build_subdir} -llibairspyhf
|
||||
|
||||
RESOURCES = ../../../sdrgui/resources/res.qrc
|
@ -1,409 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <QDebug>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <libairspyhf/airspyhf.h>
|
||||
|
||||
#include <device/devicesourceapi.h>
|
||||
#include "device/deviceuiset.h"
|
||||
#include <dsp/filerecord.h>
|
||||
|
||||
#include "ui_airspyhfigui.h"
|
||||
#include "gui/colormapper.h"
|
||||
#include "gui/glspectrum.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "airspyhfigui.h"
|
||||
|
||||
AirspyHFIGui::AirspyHFIGui(DeviceUISet *deviceUISet, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::AirspyHFIGui),
|
||||
m_deviceUISet(deviceUISet),
|
||||
m_doApplySettings(true),
|
||||
m_forceSettings(true),
|
||||
m_settings(),
|
||||
m_sampleSource(0),
|
||||
m_lastEngineState((DSPDeviceSourceEngine::State)-1)
|
||||
{
|
||||
m_sampleSource = (AirspyHFIInput*) m_deviceUISet->m_deviceSourceAPI->getSampleSource();
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||
updateFrequencyLimits();
|
||||
|
||||
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
|
||||
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
|
||||
m_statusTimer.start(500);
|
||||
|
||||
displaySettings();
|
||||
|
||||
m_rates = ((AirspyHFIInput*) m_sampleSource)->getSampleRates();
|
||||
displaySampleRates();
|
||||
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
|
||||
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
AirspyHFIGui::~AirspyHFIGui()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AirspyHFIGui::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void AirspyHFIGui::setName(const QString& name)
|
||||
{
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
QString AirspyHFIGui::getName() const
|
||||
{
|
||||
return objectName();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::resetToDefaults()
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
displaySettings();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
qint64 AirspyHFIGui::getCenterFrequency() const
|
||||
{
|
||||
return m_settings.m_centerFrequency;
|
||||
}
|
||||
|
||||
void AirspyHFIGui::setCenterFrequency(qint64 centerFrequency)
|
||||
{
|
||||
m_settings.m_centerFrequency = centerFrequency;
|
||||
displaySettings();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
QByteArray AirspyHFIGui::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool AirspyHFIGui::deserialize(const QByteArray& data)
|
||||
{
|
||||
if(m_settings.deserialize(data)) {
|
||||
displaySettings();
|
||||
m_forceSettings = true;
|
||||
sendSettings();
|
||||
return true;
|
||||
} else {
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AirspyHFIGui::handleMessage(const Message& message)
|
||||
{
|
||||
if (AirspyHFIInput::MsgConfigureAirspyHFI::match(message))
|
||||
{
|
||||
const AirspyHFIInput::MsgConfigureAirspyHFI& cfg = (AirspyHFIInput::MsgConfigureAirspyHFI&) message;
|
||||
m_settings = cfg.getSettings();
|
||||
blockApplySettings(true);
|
||||
displaySettings();
|
||||
blockApplySettings(false);
|
||||
return true;
|
||||
}
|
||||
else if (AirspyHFIInput::MsgStartStop::match(message))
|
||||
{
|
||||
AirspyHFIInput::MsgStartStop& notif = (AirspyHFIInput::MsgStartStop&) message;
|
||||
blockApplySettings(true);
|
||||
ui->startStop->setChecked(notif.getStartStop());
|
||||
blockApplySettings(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AirspyHFIGui::handleInputMessages()
|
||||
{
|
||||
Message* message;
|
||||
|
||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||
{
|
||||
qDebug("AirspyHFGui::handleInputMessages: message: %s", message->getIdentifier());
|
||||
|
||||
if (DSPSignalNotification::match(*message))
|
||||
{
|
||||
DSPSignalNotification* notif = (DSPSignalNotification*) message;
|
||||
m_sampleRate = notif->getSampleRate();
|
||||
m_deviceCenterFrequency = notif->getCenterFrequency();
|
||||
qDebug("AirspyGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency());
|
||||
updateSampleRateAndFrequency();
|
||||
|
||||
delete message;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (handleMessage(*message))
|
||||
{
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AirspyHFIGui::updateSampleRateAndFrequency()
|
||||
{
|
||||
m_deviceUISet->getSpectrum()->setSampleRate(m_sampleRate);
|
||||
m_deviceUISet->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency);
|
||||
ui->deviceRateText->setText(tr("%1k").arg((float)m_sampleRate / 1000));
|
||||
}
|
||||
|
||||
void AirspyHFIGui::updateFrequencyLimits()
|
||||
{
|
||||
// values in kHz
|
||||
qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0;
|
||||
|
||||
qint64 minLimit;
|
||||
qint64 maxLimit;
|
||||
|
||||
switch(m_settings.m_bandIndex)
|
||||
{
|
||||
case 1:
|
||||
minLimit = AirspyHFIInput::loLowLimitFreqVHF/1000 + deltaFrequency;
|
||||
maxLimit = AirspyHFIInput::loHighLimitFreqVHF/1000 + deltaFrequency;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
minLimit = AirspyHFIInput::loLowLimitFreqHF/1000 + deltaFrequency;
|
||||
maxLimit = AirspyHFIInput::loHighLimitFreqHF/1000 + deltaFrequency;
|
||||
break;
|
||||
}
|
||||
|
||||
minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit;
|
||||
maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit;
|
||||
|
||||
qDebug("AirspyHFGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit);
|
||||
|
||||
ui->centerFrequency->setValueRange(7, minLimit, maxLimit);
|
||||
}
|
||||
|
||||
void AirspyHFIGui::displaySettings()
|
||||
{
|
||||
blockApplySettings(true);
|
||||
ui->band->blockSignals(true);
|
||||
m_settings.m_bandIndex = m_settings.m_centerFrequency <= 31000000UL ? 0 : 1; // override
|
||||
ui->band->setCurrentIndex(m_settings.m_bandIndex);
|
||||
updateFrequencyLimits();
|
||||
ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency);
|
||||
ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode);
|
||||
ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
|
||||
ui->LOppm->setValue(m_settings.m_LOppmTenths);
|
||||
ui->LOppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1)));
|
||||
ui->autoCorr->setCurrentIndex(m_settings.m_autoCorrOptions);
|
||||
ui->sampleRate->setCurrentIndex(m_settings.m_devSampleRateIndex);
|
||||
ui->decim->setCurrentIndex(m_settings.m_log2Decim);
|
||||
ui->band->blockSignals(false);
|
||||
blockApplySettings(false);
|
||||
}
|
||||
|
||||
void AirspyHFIGui::displaySampleRates()
|
||||
{
|
||||
unsigned int savedIndex = m_settings.m_devSampleRateIndex;
|
||||
ui->sampleRate->blockSignals(true);
|
||||
|
||||
if (m_rates.size() > 0)
|
||||
{
|
||||
ui->sampleRate->clear();
|
||||
|
||||
for (unsigned int i = 0; i < m_rates.size(); i++)
|
||||
{
|
||||
int sampleRate = m_rates[i]/1000;
|
||||
ui->sampleRate->addItem(QString("%1").arg(QString("%1").arg(sampleRate, 5, 10, QChar(' '))));
|
||||
}
|
||||
}
|
||||
|
||||
ui->sampleRate->blockSignals(false);
|
||||
|
||||
if (savedIndex < m_rates.size())
|
||||
{
|
||||
ui->sampleRate->setCurrentIndex(savedIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->sampleRate->setCurrentIndex((int) m_rates.size()-1);
|
||||
}
|
||||
}
|
||||
|
||||
void AirspyHFIGui::sendSettings()
|
||||
{
|
||||
if(!m_updateTimer.isActive())
|
||||
m_updateTimer.start(100);
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_centerFrequency_changed(quint64 value)
|
||||
{
|
||||
m_settings.m_centerFrequency = value * 1000;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_LOppm_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_LOppmTenths = value;
|
||||
ui->LOppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1)));
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_resetLOppm_clicked()
|
||||
{
|
||||
ui->LOppm->setValue(0);
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_autoCorr_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > AirspyHFISettings::AutoCorrLast)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.m_autoCorrOptions = (AirspyHFISettings::AutoCorrOptions) index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_sampleRate_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_devSampleRateIndex = index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_decim_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > 5))
|
||||
return;
|
||||
m_settings.m_log2Decim = index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_startStop_toggled(bool checked)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
AirspyHFIInput::MsgStartStop *message = AirspyHFIInput::MsgStartStop::create(checked);
|
||||
m_sampleSource->getInputMessageQueue()->push(message);
|
||||
}
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_record_toggled(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
ui->record->setStyleSheet("QToolButton { background-color : red; }");
|
||||
} else {
|
||||
ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
}
|
||||
|
||||
AirspyHFIInput::MsgFileRecord* message = AirspyHFIInput::MsgFileRecord::create(checked);
|
||||
m_sampleSource->getInputMessageQueue()->push(message);
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_transverter_clicked()
|
||||
{
|
||||
m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive();
|
||||
m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency();
|
||||
qDebug("AirspyHFGui::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off");
|
||||
updateFrequencyLimits();
|
||||
m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::on_band_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.m_bandIndex = index;
|
||||
updateFrequencyLimits();
|
||||
qDebug("AirspyHFGui::on_band_currentIndexChanged: freq: %llu", ui->centerFrequency->getValueNew() * 1000);
|
||||
m_settings.m_centerFrequency = ui->centerFrequency->getValueNew() * 1000;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::updateHardware()
|
||||
{
|
||||
qDebug() << "AirspyHFGui::updateHardware";
|
||||
AirspyHFIInput::MsgConfigureAirspyHFI* message = AirspyHFIInput::MsgConfigureAirspyHFI::create(m_settings, m_forceSettings);
|
||||
m_sampleSource->getInputMessageQueue()->push(message);
|
||||
m_forceSettings = false;
|
||||
m_updateTimer.stop();
|
||||
}
|
||||
|
||||
void AirspyHFIGui::updateStatus()
|
||||
{
|
||||
int state = m_deviceUISet->m_deviceSourceAPI->state();
|
||||
|
||||
if(m_lastEngineState != state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case DSPDeviceSourceEngine::StNotStarted:
|
||||
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
break;
|
||||
case DSPDeviceSourceEngine::StIdle:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
|
||||
break;
|
||||
case DSPDeviceSourceEngine::StRunning:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
|
||||
break;
|
||||
case DSPDeviceSourceEngine::StError:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
|
||||
QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceSourceAPI->errorMessage());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_lastEngineState = state;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AirspyHFIGui::getDevSampleRate(unsigned int rate_index)
|
||||
{
|
||||
if (rate_index < m_rates.size())
|
||||
{
|
||||
return m_rates[rate_index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_rates[0];
|
||||
}
|
||||
}
|
||||
|
||||
int AirspyHFIGui::getDevSampleRateIndex(uint32_t sampeRate)
|
||||
{
|
||||
for (unsigned int i=0; i < m_rates.size(); i++)
|
||||
{
|
||||
if (sampeRate == m_rates[i])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 INCLUDE_AIRSPYHFIGUI_H
|
||||
#define INCLUDE_AIRSPYHFIGUI_H
|
||||
|
||||
#include <plugin/plugininstancegui.h>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "util/messagequeue.h"
|
||||
|
||||
#include "airspyhfiinput.h"
|
||||
|
||||
class DeviceUISet;
|
||||
|
||||
namespace Ui {
|
||||
class AirspyHFIGui;
|
||||
class AirspyHFISampleRates;
|
||||
}
|
||||
|
||||
class AirspyHFIGui : public QWidget, public PluginInstanceGUI {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AirspyHFIGui(DeviceUISet *deviceUISet, QWidget* parent = 0);
|
||||
virtual ~AirspyHFIGui();
|
||||
virtual void destroy();
|
||||
|
||||
void setName(const QString& name);
|
||||
QString getName() const;
|
||||
|
||||
void resetToDefaults();
|
||||
virtual qint64 getCenterFrequency() const;
|
||||
virtual void setCenterFrequency(qint64 centerFrequency);
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
virtual MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||
virtual bool handleMessage(const Message& message);
|
||||
uint32_t getDevSampleRate(unsigned int index);
|
||||
int getDevSampleRateIndex(uint32_t sampleRate);
|
||||
|
||||
private:
|
||||
Ui::AirspyHFIGui* ui;
|
||||
|
||||
DeviceUISet* m_deviceUISet;
|
||||
bool m_doApplySettings;
|
||||
bool m_forceSettings;
|
||||
AirspyHFISettings m_settings;
|
||||
QTimer m_updateTimer;
|
||||
QTimer m_statusTimer;
|
||||
std::vector<uint32_t> m_rates;
|
||||
DeviceSampleSource* m_sampleSource;
|
||||
int m_sampleRate;
|
||||
quint64 m_deviceCenterFrequency; //!< Center frequency in device
|
||||
int m_lastEngineState;
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
void blockApplySettings(bool block) { m_doApplySettings = !block; }
|
||||
void displaySettings();
|
||||
void displaySampleRates();
|
||||
void sendSettings();
|
||||
void updateSampleRateAndFrequency();
|
||||
void updateFrequencyLimits();
|
||||
|
||||
private slots:
|
||||
void on_centerFrequency_changed(quint64 value);
|
||||
void on_LOppm_valueChanged(int value);
|
||||
void on_resetLOppm_clicked();
|
||||
void on_autoCorr_currentIndexChanged(int index);
|
||||
void on_sampleRate_currentIndexChanged(int index);
|
||||
void on_decim_currentIndexChanged(int index);
|
||||
void on_startStop_toggled(bool checked);
|
||||
void on_record_toggled(bool checked);
|
||||
void on_transverter_clicked();
|
||||
void on_band_currentIndexChanged(int index);
|
||||
void updateHardware();
|
||||
void updateStatus();
|
||||
void handleInputMessages();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AIRSPYHFIGUI_H
|
@ -1,494 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AirspyHFIGui</class>
|
||||
<widget class="QWidget" name="AirspyHFIGui">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>324</width>
|
||||
<height>174</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>132</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Sans Serif</family>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>AirspyHF</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_freq">
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="deviceUILayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="deviceButtonsLayout">
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="startStop">
|
||||
<property name="toolTip">
|
||||
<string>start/stop acquisition</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/play.png</normaloff>
|
||||
<normalon>:/stop.png</normalon>:/play.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="record">
|
||||
<property name="toolTip">
|
||||
<string>Toggle record I/Q samples from device</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/record_off.png</normaloff>:/record_off.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="deviceRateLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="deviceRateText">
|
||||
<property name="toolTip">
|
||||
<string>I/Q sample rate kS/s</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00000k</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="freqLeftSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ValueDial" name="centerFrequency" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>DejaVu Sans Mono</family>
|
||||
<pointsize>20</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Tuner center frequency in kHz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="freqUnits">
|
||||
<property name="text">
|
||||
<string> kHz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="freqRightlSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="loCorrectionLayout">
|
||||
<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 ppm correction</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</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>36</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>LO correction value (ppm)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-00.0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="resetLOppm">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Rest LO ppm correction</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>R</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="autoCorrLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="autoCorrLabel">
|
||||
<property name="text">
|
||||
<string>Corr</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="autoCorr">
|
||||
<property name="toolTip">
|
||||
<string>DC offset and IQ correction options</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DC</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>DC+IQ</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_freq">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="bandLabel">
|
||||
<property name="text">
|
||||
<string>Band</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="band">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>56</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Band select</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>HF</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>VHF</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sampleRateLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>S/R</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="sampleRate">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Device sample rate in MS/s</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>0000</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="rateLabel">
|
||||
<property name="text">
|
||||
<string>k</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="fcPosRightSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_decim">
|
||||
<property name="text">
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="decim">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Decimation factor</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>32</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="TransverterButton" name="transverter">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Transverter frequency translation dialog</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="paddingLayout">
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ValueDial</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/valuedial.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TransverterButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>gui/transverterbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,507 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include "SWGDeviceSettings.h"
|
||||
#include "SWGDeviceState.h"
|
||||
|
||||
#include <device/devicesourceapi.h>
|
||||
#include <dsp/filerecord.h>
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "dsp/dspengine.h"
|
||||
|
||||
#include "airspyhfisettings.h"
|
||||
#include "airspyhfiinput.h"
|
||||
|
||||
#include "airspyhfiplugin.h"
|
||||
#include "airspyhfithread.h"
|
||||
#include "airspyhfigui.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(AirspyHFIInput::MsgConfigureAirspyHFI, Message)
|
||||
MESSAGE_CLASS_DEFINITION(AirspyHFIInput::MsgStartStop, Message)
|
||||
MESSAGE_CLASS_DEFINITION(AirspyHFIInput::MsgFileRecord, Message)
|
||||
|
||||
const qint64 AirspyHFIInput::loLowLimitFreqHF = 9000L;
|
||||
const qint64 AirspyHFIInput::loHighLimitFreqHF = 31000000L;
|
||||
const qint64 AirspyHFIInput::loLowLimitFreqVHF = 60000000L;
|
||||
const qint64 AirspyHFIInput::loHighLimitFreqVHF = 260000000L;
|
||||
|
||||
AirspyHFIInput::AirspyHFIInput(DeviceSourceAPI *deviceAPI) :
|
||||
m_deviceAPI(deviceAPI),
|
||||
m_settings(),
|
||||
m_dev(0),
|
||||
m_airspyHFThread(0),
|
||||
m_deviceDescription("AirspyHFI"),
|
||||
m_running(false)
|
||||
{
|
||||
openDevice();
|
||||
|
||||
char recFileNameCStr[30];
|
||||
sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceAPI->getDeviceUID());
|
||||
m_fileSink = new FileRecord(std::string(recFileNameCStr));
|
||||
m_deviceAPI->addSink(m_fileSink);
|
||||
}
|
||||
|
||||
AirspyHFIInput::~AirspyHFIInput()
|
||||
{
|
||||
if (m_running) { stop(); }
|
||||
m_deviceAPI->removeSink(m_fileSink);
|
||||
delete m_fileSink;
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
void AirspyHFIInput::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool AirspyHFIInput::openDevice()
|
||||
{
|
||||
if (m_dev != 0)
|
||||
{
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
airspyhf_error rc;
|
||||
|
||||
if (!m_sampleFifo.setSize(1<<19))
|
||||
{
|
||||
qCritical("AirspyHFInput::start: could not allocate SampleFifo");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_dev = open_airspyhf_from_serial(m_deviceAPI->getSampleSourceSerial())) == 0)
|
||||
{
|
||||
qCritical("AirspyHFInput::start: could not open Airspy with serial %s", qPrintable(m_deviceAPI->getSampleSourceSerial()));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("AirspyHFInput::start: opened Airspy with serial %s", qPrintable(m_deviceAPI->getSampleSourceSerial()));
|
||||
}
|
||||
|
||||
uint32_t nbSampleRates;
|
||||
uint32_t *sampleRates;
|
||||
|
||||
rc = (airspyhf_error) airspyhf_get_samplerates(m_dev, &nbSampleRates, 0);
|
||||
|
||||
if (rc == AIRSPYHF_SUCCESS)
|
||||
{
|
||||
qDebug("AirspyHFInput::start: %d sample rates for AirspyHF", nbSampleRates);
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical("AirspyHFInput::start: could not obtain the number of AirspyHF sample rates");
|
||||
return false;
|
||||
}
|
||||
|
||||
sampleRates = new uint32_t[nbSampleRates];
|
||||
|
||||
rc = (airspyhf_error) airspyhf_get_samplerates(m_dev, sampleRates, nbSampleRates);
|
||||
|
||||
if (rc == AIRSPYHF_SUCCESS)
|
||||
{
|
||||
qDebug("AirspyHFInput::start: obtained AirspyHF sample rates");
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical("AirspyHFInput::start: could not obtain AirspyHF sample rates");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleRates.clear();
|
||||
|
||||
for (unsigned int i = 0; i < nbSampleRates; i++)
|
||||
{
|
||||
m_sampleRates.push_back(sampleRates[i]);
|
||||
qDebug("AirspyHFInput::start: sampleRates[%d] = %u Hz", i, sampleRates[i]);
|
||||
}
|
||||
|
||||
delete[] sampleRates;
|
||||
|
||||
airspyhf_set_sample_type(m_dev, AIRSPYHF_SAMPLE_INT16_NDSP_IQ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AirspyHFIInput::init()
|
||||
{
|
||||
applySettings(m_settings, true);
|
||||
}
|
||||
|
||||
bool AirspyHFIInput::start()
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
if (!m_dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_running) { stop(); }
|
||||
|
||||
if ((m_airspyHFThread = new AirspyHFIThread(m_dev, &m_sampleFifo)) == 0)
|
||||
{
|
||||
qCritical("AirspyHFInput::start: out of memory");
|
||||
stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_airspyHFThread->setSamplerate(m_sampleRates[m_settings.m_devSampleRateIndex]);
|
||||
m_airspyHFThread->setLog2Decimation(m_settings.m_log2Decim);
|
||||
|
||||
m_airspyHFThread->startWork();
|
||||
|
||||
mutexLocker.unlock();
|
||||
|
||||
applySettings(m_settings, true);
|
||||
|
||||
qDebug("AirspyHFInput::startInput: started");
|
||||
m_running = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AirspyHFIInput::closeDevice()
|
||||
{
|
||||
if (m_dev != 0)
|
||||
{
|
||||
airspyhf_stop(m_dev);
|
||||
airspyhf_close(m_dev);
|
||||
m_dev = 0;
|
||||
}
|
||||
|
||||
m_deviceDescription.clear();
|
||||
}
|
||||
|
||||
void AirspyHFIInput::stop()
|
||||
{
|
||||
qDebug("AirspyHFInput::stop");
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
if (m_airspyHFThread != 0)
|
||||
{
|
||||
m_airspyHFThread->stopWork();
|
||||
delete m_airspyHFThread;
|
||||
m_airspyHFThread = 0;
|
||||
}
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
QByteArray AirspyHFIInput::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool AirspyHFIInput::deserialize(const QByteArray& data)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (!m_settings.deserialize(data))
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
success = false;
|
||||
}
|
||||
|
||||
MsgConfigureAirspyHFI* message = MsgConfigureAirspyHFI::create(m_settings, true);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
MsgConfigureAirspyHFI* messageToGUI = MsgConfigureAirspyHFI::create(m_settings, true);
|
||||
m_guiMessageQueue->push(messageToGUI);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
const QString& AirspyHFIInput::getDeviceDescription() const
|
||||
{
|
||||
return m_deviceDescription;
|
||||
}
|
||||
|
||||
int AirspyHFIInput::getSampleRate() const
|
||||
{
|
||||
int rate = m_sampleRates[m_settings.m_devSampleRateIndex];
|
||||
return (rate / (1<<m_settings.m_log2Decim));
|
||||
}
|
||||
|
||||
quint64 AirspyHFIInput::getCenterFrequency() const
|
||||
{
|
||||
return m_settings.m_centerFrequency;
|
||||
}
|
||||
|
||||
void AirspyHFIInput::setCenterFrequency(qint64 centerFrequency)
|
||||
{
|
||||
AirspyHFISettings settings = m_settings;
|
||||
settings.m_centerFrequency = centerFrequency;
|
||||
|
||||
MsgConfigureAirspyHFI* message = MsgConfigureAirspyHFI::create(settings, false);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
MsgConfigureAirspyHFI* messageToGUI = MsgConfigureAirspyHFI::create(settings, false);
|
||||
m_guiMessageQueue->push(messageToGUI);
|
||||
}
|
||||
}
|
||||
|
||||
bool AirspyHFIInput::handleMessage(const Message& message)
|
||||
{
|
||||
if (MsgConfigureAirspyHFI::match(message))
|
||||
{
|
||||
MsgConfigureAirspyHFI& conf = (MsgConfigureAirspyHFI&) message;
|
||||
qDebug() << "MsgConfigureAirspyHF::handleMessage: MsgConfigureAirspyHF";
|
||||
|
||||
bool success = applySettings(conf.getSettings(), conf.getForce());
|
||||
|
||||
if (!success)
|
||||
{
|
||||
qDebug("MsgConfigureAirspyHF::handleMessage: AirspyHF config error");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MsgStartStop::match(message))
|
||||
{
|
||||
MsgStartStop& cmd = (MsgStartStop&) message;
|
||||
qDebug() << "AirspyHFInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
|
||||
|
||||
if (cmd.getStartStop())
|
||||
{
|
||||
if (m_deviceAPI->initAcquisition())
|
||||
{
|
||||
m_deviceAPI->startAcquisition();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_deviceAPI->stopAcquisition();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MsgFileRecord::match(message))
|
||||
{
|
||||
MsgFileRecord& conf = (MsgFileRecord&) message;
|
||||
qDebug() << "AirspyHFInput::handleMessage: MsgFileRecord: " << conf.getStartStop();
|
||||
|
||||
if (conf.getStartStop()) {
|
||||
m_fileSink->startRecording();
|
||||
} else {
|
||||
m_fileSink->stopRecording();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AirspyHFIInput::setDeviceCenterFrequency(quint64 freq_hz, const AirspyHFISettings& settings)
|
||||
{
|
||||
switch(settings.m_bandIndex)
|
||||
{
|
||||
case 1:
|
||||
freq_hz = freq_hz < loLowLimitFreqVHF ? loLowLimitFreqVHF : freq_hz > loHighLimitFreqVHF ? loHighLimitFreqVHF : freq_hz;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
freq_hz = freq_hz < loLowLimitFreqHF ? loLowLimitFreqHF : freq_hz > loHighLimitFreqHF ? loHighLimitFreqHF : freq_hz;
|
||||
break;
|
||||
}
|
||||
|
||||
airspyhf_error rc = (airspyhf_error) airspyhf_set_freq(m_dev, static_cast<uint32_t>(freq_hz));
|
||||
|
||||
if (rc == AIRSPYHF_SUCCESS) {
|
||||
qDebug("AirspyHFInput::setDeviceCenterFrequency: frequency set to %llu Hz", freq_hz);
|
||||
} else {
|
||||
qWarning("AirspyHFInput::setDeviceCenterFrequency: could not frequency to %llu Hz", freq_hz);
|
||||
}
|
||||
}
|
||||
|
||||
bool AirspyHFIInput::applySettings(const AirspyHFISettings& settings, bool force)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
bool forwardChange = false;
|
||||
airspyhf_error rc;
|
||||
int sampleRateIndex = settings.m_devSampleRateIndex;
|
||||
|
||||
qDebug() << "AirspyHFInput::applySettings";
|
||||
|
||||
if ((m_settings.m_autoCorrOptions != settings.m_autoCorrOptions) || force)
|
||||
{
|
||||
switch(settings.m_autoCorrOptions)
|
||||
{
|
||||
case AirspyHFISettings::AutoCorrDC:
|
||||
m_deviceAPI->configureCorrections(true, false);
|
||||
break;
|
||||
case AirspyHFISettings::AutoCorrDCAndIQ:
|
||||
m_deviceAPI->configureCorrections(true, true);
|
||||
break;
|
||||
case AirspyHFISettings::AutoCorrNone:
|
||||
default:
|
||||
m_deviceAPI->configureCorrections(false, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_devSampleRateIndex != settings.m_devSampleRateIndex) || force)
|
||||
{
|
||||
forwardChange = true;
|
||||
|
||||
if (settings.m_devSampleRateIndex >= m_sampleRates.size()) {
|
||||
sampleRateIndex = m_sampleRates.size() - 1;
|
||||
}
|
||||
|
||||
if (m_dev != 0)
|
||||
{
|
||||
rc = (airspyhf_error) airspyhf_set_samplerate(m_dev, sampleRateIndex);
|
||||
|
||||
if (rc != AIRSPYHF_SUCCESS)
|
||||
{
|
||||
qCritical("AirspyHFInput::applySettings: could not set sample rate index %u (%d S/s)", sampleRateIndex, m_sampleRates[sampleRateIndex]);
|
||||
}
|
||||
else if (m_airspyHFThread != 0)
|
||||
{
|
||||
qDebug("AirspyHFInput::applySettings: sample rate set to index: %u (%d S/s)", sampleRateIndex, m_sampleRates[sampleRateIndex]);
|
||||
m_airspyHFThread->setSamplerate(m_sampleRates[sampleRateIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
|
||||
{
|
||||
forwardChange = true;
|
||||
|
||||
if (m_airspyHFThread != 0)
|
||||
{
|
||||
m_airspyHFThread->setLog2Decimation(settings.m_log2Decim);
|
||||
qDebug() << "AirspyInput: set decimation to " << (1<<settings.m_log2Decim);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force)
|
||||
{
|
||||
if (m_dev != 0)
|
||||
{
|
||||
rc = (airspyhf_error) airspyhf_set_calibration(m_dev, settings.m_LOppmTenths * 100);
|
||||
|
||||
if (rc != AIRSPYHF_SUCCESS)
|
||||
{
|
||||
qCritical("AirspyHFInput::applySettings: could not set LO ppm correction to %f", settings.m_LOppmTenths / 10.0f);
|
||||
}
|
||||
else if (m_airspyHFThread != 0)
|
||||
{
|
||||
qDebug("AirspyHFInput::applySettings: LO ppm correction set to %f", settings.m_LOppmTenths / 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency)
|
||||
|| (m_settings.m_transverterMode != settings.m_transverterMode)
|
||||
|| (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency))
|
||||
{
|
||||
qint64 deviceCenterFrequency = settings.m_centerFrequency;
|
||||
deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0;
|
||||
deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency;
|
||||
qint64 f_img = deviceCenterFrequency;
|
||||
quint32 devSampleRate = m_sampleRates[sampleRateIndex];
|
||||
|
||||
if (m_dev != 0)
|
||||
{
|
||||
setDeviceCenterFrequency(deviceCenterFrequency, settings);
|
||||
|
||||
qDebug() << "AirspyHFInput::applySettings: center freq: " << settings.m_centerFrequency << " Hz"
|
||||
<< " device center freq: " << deviceCenterFrequency << " Hz"
|
||||
<< " device sample rate: " << devSampleRate << "Hz"
|
||||
<< " Actual sample rate: " << devSampleRate/(1<<m_settings.m_log2Decim) << "Hz"
|
||||
<< " img: " << f_img << "Hz";
|
||||
}
|
||||
|
||||
forwardChange = true;
|
||||
}
|
||||
|
||||
if (forwardChange)
|
||||
{
|
||||
int sampleRate = m_sampleRates[sampleRateIndex]/(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);
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
m_settings.m_devSampleRateIndex = sampleRateIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
airspyhf_device_t *AirspyHFIInput::open_airspyhf_from_serial(const QString& serialStr)
|
||||
{
|
||||
airspyhf_device_t *devinfo;
|
||||
bool ok;
|
||||
airspyhf_error rc;
|
||||
|
||||
uint64_t serial = serialStr.toULongLong(&ok, 16);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
qCritical("AirspyHFInput::open_airspyhf_from_serial: invalid serial %s", qPrintable(serialStr));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = (airspyhf_error) airspyhf_open_sn(&devinfo, serial);
|
||||
|
||||
if (rc == AIRSPYHF_SUCCESS) {
|
||||
return devinfo;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AirspyHFIInput::webapiRunGet(
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage __attribute__((unused)))
|
||||
{
|
||||
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
|
||||
return 200;
|
||||
}
|
||||
|
||||
int AirspyHFIInput::webapiRun(
|
||||
bool run,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage __attribute__((unused)))
|
||||
{
|
||||
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
|
||||
MsgStartStop *message = MsgStartStop::create(run);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue) // forward to GUI if any
|
||||
{
|
||||
MsgStartStop *msgToGUI = MsgStartStop::create(run);
|
||||
m_guiMessageQueue->push(msgToGUI);
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
@ -1,147 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 INCLUDE_AIRSPYHFIINPUT_H
|
||||
#define INCLUDE_AIRSPYHFIINPUT_H
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
|
||||
#include <libairspyhf/airspyhf.h>
|
||||
#include <dsp/devicesamplesource.h>
|
||||
|
||||
#include "airspyhfisettings.h"
|
||||
|
||||
class DeviceSourceAPI;
|
||||
class AirspyHFIThread;
|
||||
class FileRecord;
|
||||
|
||||
class AirspyHFIInput : public DeviceSampleSource {
|
||||
public:
|
||||
class MsgConfigureAirspyHFI : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
const AirspyHFISettings& getSettings() const { return m_settings; }
|
||||
bool getForce() const { return m_force; }
|
||||
|
||||
static MsgConfigureAirspyHFI* create(const AirspyHFISettings& settings, bool force)
|
||||
{
|
||||
return new MsgConfigureAirspyHFI(settings, force);
|
||||
}
|
||||
|
||||
private:
|
||||
AirspyHFISettings m_settings;
|
||||
bool m_force;
|
||||
|
||||
MsgConfigureAirspyHFI(const AirspyHFISettings& settings, bool force) :
|
||||
Message(),
|
||||
m_settings(settings),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgFileRecord : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgFileRecord* create(bool startStop) {
|
||||
return new MsgFileRecord(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgFileRecord(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgStartStop : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgStartStop* create(bool startStop) {
|
||||
return new MsgStartStop(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgStartStop(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
AirspyHFIInput(DeviceSourceAPI *deviceAPI);
|
||||
virtual ~AirspyHFIInput();
|
||||
virtual void destroy();
|
||||
|
||||
virtual void init();
|
||||
virtual bool start();
|
||||
virtual void stop();
|
||||
|
||||
virtual QByteArray serialize() const;
|
||||
virtual bool deserialize(const QByteArray& data);
|
||||
|
||||
virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
|
||||
virtual const QString& getDeviceDescription() const;
|
||||
virtual int getSampleRate() const;
|
||||
virtual quint64 getCenterFrequency() const;
|
||||
virtual void setCenterFrequency(qint64 centerFrequency);
|
||||
const std::vector<uint32_t>& getSampleRates() const { return m_sampleRates; }
|
||||
|
||||
virtual bool handleMessage(const Message& message);
|
||||
|
||||
virtual int webapiRunGet(
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiRun(
|
||||
bool run,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage);
|
||||
|
||||
static const qint64 loLowLimitFreqHF;
|
||||
static const qint64 loHighLimitFreqHF;
|
||||
static const qint64 loLowLimitFreqVHF;
|
||||
static const qint64 loHighLimitFreqVHF;
|
||||
|
||||
private:
|
||||
bool openDevice();
|
||||
void closeDevice();
|
||||
bool applySettings(const AirspyHFISettings& settings, bool force);
|
||||
airspyhf_device_t *open_airspyhf_from_serial(const QString& serialStr);
|
||||
void setDeviceCenterFrequency(quint64 freq, const AirspyHFISettings& settings);
|
||||
|
||||
DeviceSourceAPI *m_deviceAPI;
|
||||
QMutex m_mutex;
|
||||
AirspyHFISettings m_settings;
|
||||
airspyhf_device_t* m_dev;
|
||||
AirspyHFIThread* m_airspyHFThread;
|
||||
QString m_deviceDescription;
|
||||
std::vector<uint32_t> m_sampleRates;
|
||||
bool m_running;
|
||||
FileRecord *m_fileSink; //!< File sink to record device I/Q output
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AIRSPYHFIINPUT_H
|
@ -1,127 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <QtPlugin>
|
||||
#include <QAction>
|
||||
#include <libairspyhf/airspyhf.h>
|
||||
|
||||
#include <device/devicesourceapi.h>
|
||||
#include "plugin/pluginapi.h"
|
||||
#include "util/simpleserializer.h"
|
||||
#include "airspyhfiplugin.h"
|
||||
|
||||
#include "airspyhfigui.h"
|
||||
|
||||
|
||||
const PluginDescriptor AirspyHFIPlugin::m_pluginDescriptor = {
|
||||
QString("AirspyHF Input (int)"),
|
||||
QString("3.12.0"),
|
||||
QString("(c) Edouard Griffiths, F4EXB"),
|
||||
QString("https://github.com/f4exb/sdrangel"),
|
||||
true,
|
||||
QString("https://github.com/f4exb/sdrangel")
|
||||
};
|
||||
|
||||
const QString AirspyHFIPlugin::m_hardwareID = "AirspyHFI";
|
||||
const QString AirspyHFIPlugin::m_deviceTypeID = AIRSPYHFI_DEVICE_TYPE_ID;
|
||||
const int AirspyHFIPlugin::m_maxDevices = 32;
|
||||
|
||||
AirspyHFIPlugin::AirspyHFIPlugin(QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
const PluginDescriptor& AirspyHFIPlugin::getPluginDescriptor() const
|
||||
{
|
||||
return m_pluginDescriptor;
|
||||
}
|
||||
|
||||
void AirspyHFIPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||
{
|
||||
pluginAPI->registerSampleSource(m_deviceTypeID, this);
|
||||
}
|
||||
|
||||
PluginInterface::SamplingDevices AirspyHFIPlugin::enumSampleSources()
|
||||
{
|
||||
SamplingDevices result;
|
||||
int nbDevices;
|
||||
uint64_t deviceSerials[m_maxDevices];
|
||||
|
||||
nbDevices = airspyhf_list_devices(deviceSerials, m_maxDevices);
|
||||
|
||||
if (nbDevices < 0)
|
||||
{
|
||||
qCritical("AirspyHFIPlugin::enumSampleSources: failed to list Airspy HF devices");
|
||||
}
|
||||
|
||||
for (int i = 0; i < nbDevices; i++)
|
||||
{
|
||||
if (deviceSerials[i])
|
||||
{
|
||||
QString serial_str = QString::number(deviceSerials[i], 16);
|
||||
QString displayedName(QString("AirspyHF(int)[%1] %2").arg(i).arg(serial_str));
|
||||
|
||||
result.append(SamplingDevice(displayedName,
|
||||
m_hardwareID,
|
||||
m_deviceTypeID,
|
||||
serial_str,
|
||||
i,
|
||||
PluginInterface::SamplingDevice::PhysicalDevice,
|
||||
true,
|
||||
1,
|
||||
0));
|
||||
|
||||
qDebug("AirspyHFIPlugin::enumSampleSources: enumerated Airspy device #%d", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("AirspyHFIPlugin::enumSampleSources: finished to enumerate Airspy HF. %d devices found", i);
|
||||
break; // finished
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PluginInstanceGUI* AirspyHFIPlugin::createSampleSourcePluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet)
|
||||
{
|
||||
if (sourceId == m_deviceTypeID)
|
||||
{
|
||||
AirspyHFIGui* gui = new AirspyHFIGui(deviceUISet);
|
||||
*widget = gui;
|
||||
return gui;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceSampleSource *AirspyHFIPlugin::createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI)
|
||||
{
|
||||
if (sourceId == m_deviceTypeID)
|
||||
{
|
||||
AirspyHFIInput* input = new AirspyHFIInput(deviceAPI);
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 INCLUDE_AIRSPYHFIPLUGIN_H
|
||||
#define INCLUDE_AIRSPYHFIPLUGIN_H
|
||||
|
||||
#include <QObject>
|
||||
#include "plugin/plugininterface.h"
|
||||
|
||||
#define AIRSPYHFI_DEVICE_TYPE_ID "sdrangel.samplesource.airspyhfi"
|
||||
|
||||
class PluginAPI;
|
||||
|
||||
class AirspyHFIPlugin : public QObject, public PluginInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(PluginInterface)
|
||||
Q_PLUGIN_METADATA(IID AIRSPYHFI_DEVICE_TYPE_ID)
|
||||
|
||||
public:
|
||||
explicit AirspyHFIPlugin(QObject* parent = 0);
|
||||
|
||||
const PluginDescriptor& getPluginDescriptor() const;
|
||||
void initPlugin(PluginAPI* pluginAPI);
|
||||
|
||||
virtual SamplingDevices enumSampleSources();
|
||||
virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet);
|
||||
virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI);
|
||||
|
||||
static const QString m_hardwareID;
|
||||
static const QString m_deviceTypeID;
|
||||
static const int m_maxDevices;
|
||||
|
||||
private:
|
||||
static const PluginDescriptor m_pluginDescriptor;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AIRSPYHFIPLUGIN_H
|
@ -1,91 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 "airspyhfisettings.h"
|
||||
|
||||
AirspyHFISettings::AirspyHFISettings()
|
||||
{
|
||||
resetToDefaults();
|
||||
}
|
||||
|
||||
void AirspyHFISettings::resetToDefaults()
|
||||
{
|
||||
m_centerFrequency = 7150*1000;
|
||||
m_LOppmTenths = 0;
|
||||
m_devSampleRateIndex = 0;
|
||||
m_log2Decim = 0;
|
||||
m_transverterMode = false;
|
||||
m_transverterDeltaFrequency = 0;
|
||||
m_bandIndex = 0;
|
||||
m_autoCorrOptions = AutoCorrNone;
|
||||
}
|
||||
|
||||
QByteArray AirspyHFISettings::serialize() const
|
||||
{
|
||||
SimpleSerializer s(1);
|
||||
|
||||
s.writeU32(1, m_devSampleRateIndex);
|
||||
s.writeS32(2, m_LOppmTenths);
|
||||
s.writeU32(3, m_log2Decim);
|
||||
s.writeS32(4, (int) m_autoCorrOptions);
|
||||
s.writeBool(7, m_transverterMode);
|
||||
s.writeS64(8, m_transverterDeltaFrequency);
|
||||
s.writeU32(9, m_bandIndex);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
|
||||
bool AirspyHFISettings::deserialize(const QByteArray& data)
|
||||
{
|
||||
SimpleDeserializer d(data);
|
||||
|
||||
if (!d.isValid())
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d.getVersion() == 1)
|
||||
{
|
||||
int intval;
|
||||
quint32 uintval;
|
||||
|
||||
d.readU32(1, &m_devSampleRateIndex, 0);
|
||||
d.readS32(2, &m_LOppmTenths, 0);
|
||||
d.readU32(3, &m_log2Decim, 0);
|
||||
d.readS32(4, &intval, 0);
|
||||
|
||||
if (intval < 0 || intval > (int) AutoCorrLast) {
|
||||
m_autoCorrOptions = AutoCorrNone;
|
||||
} else {
|
||||
m_autoCorrOptions = (AutoCorrOptions) intval;
|
||||
}
|
||||
|
||||
d.readBool(7, &m_transverterMode, false);
|
||||
d.readS64(8, &m_transverterDeltaFrequency, 0);
|
||||
d.readU32(9, &uintval, 0);
|
||||
m_bandIndex = uintval > 1 ? 1 : uintval;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 _AIRSPYHF_AIRSPYHFISETTINGS_H_
|
||||
#define _AIRSPYHF_AIRSPYHFISETTINGS_H_
|
||||
|
||||
struct AirspyHFISettings
|
||||
{
|
||||
typedef enum {
|
||||
AutoCorrNone,
|
||||
AutoCorrDC,
|
||||
AutoCorrDCAndIQ,
|
||||
AutoCorrLast,
|
||||
} AutoCorrOptions;
|
||||
|
||||
quint64 m_centerFrequency;
|
||||
qint32 m_LOppmTenths;
|
||||
quint32 m_devSampleRateIndex;
|
||||
quint32 m_log2Decim;
|
||||
bool m_transverterMode;
|
||||
qint64 m_transverterDeltaFrequency;
|
||||
quint32 m_bandIndex;
|
||||
AutoCorrOptions m_autoCorrOptions;
|
||||
|
||||
AirspyHFISettings();
|
||||
void resetToDefaults();
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
};
|
||||
|
||||
#endif /* _AIRSPYHF_AIRSPYHFISETTINGS_H_ */
|
@ -1,142 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "dsp/samplesinkfifo.h"
|
||||
#include "airspyhfithread.h"
|
||||
|
||||
AirspyHFIThread *AirspyHFIThread::m_this = 0;
|
||||
|
||||
AirspyHFIThread::AirspyHFIThread(airspyhf_device_t* dev, SampleSinkFifo* sampleFifo, QObject* parent) :
|
||||
QThread(parent),
|
||||
m_running(false),
|
||||
m_dev(dev),
|
||||
m_convertBuffer(AIRSPYHFI_BLOCKSIZE),
|
||||
m_sampleFifo(sampleFifo),
|
||||
m_samplerate(10),
|
||||
m_log2Decim(0)
|
||||
{
|
||||
m_this = this;
|
||||
}
|
||||
|
||||
AirspyHFIThread::~AirspyHFIThread()
|
||||
{
|
||||
stopWork();
|
||||
m_this = 0;
|
||||
}
|
||||
|
||||
void AirspyHFIThread::startWork()
|
||||
{
|
||||
m_startWaitMutex.lock();
|
||||
start();
|
||||
while(!m_running)
|
||||
m_startWaiter.wait(&m_startWaitMutex, 100);
|
||||
m_startWaitMutex.unlock();
|
||||
}
|
||||
|
||||
void AirspyHFIThread::stopWork()
|
||||
{
|
||||
qDebug("AirspyThread::stopWork");
|
||||
m_running = false;
|
||||
wait();
|
||||
}
|
||||
|
||||
void AirspyHFIThread::setSamplerate(uint32_t samplerate)
|
||||
{
|
||||
m_samplerate = samplerate;
|
||||
}
|
||||
|
||||
void AirspyHFIThread::setLog2Decimation(unsigned int log2_decim)
|
||||
{
|
||||
m_log2Decim = log2_decim;
|
||||
}
|
||||
|
||||
void AirspyHFIThread::run()
|
||||
{
|
||||
airspyhf_error rc;
|
||||
|
||||
m_running = true;
|
||||
m_startWaiter.wakeAll();
|
||||
|
||||
rc = (airspyhf_error) airspyhf_start(m_dev, rx_callback, 0);
|
||||
|
||||
if (rc != AIRSPYHF_SUCCESS)
|
||||
{
|
||||
qCritical("AirspyHFThread::run: failed to start Airspy Rx");
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((m_running) && (airspyhf_is_streaming(m_dev) != 0))
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
rc = (airspyhf_error) airspyhf_stop(m_dev);
|
||||
|
||||
if (rc == AIRSPYHF_SUCCESS) {
|
||||
qDebug("AirspyHFThread::run: stopped Airspy Rx");
|
||||
} else {
|
||||
qDebug("AirspyHFThread::run: failed to stop Airspy Rx");
|
||||
}
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
// Decimate according to specified log2 (ex: log2=4 => decim=16)
|
||||
void AirspyHFIThread::callback(const qint16* buf, qint32 len)
|
||||
{
|
||||
SampleVector::iterator it = m_convertBuffer.begin();
|
||||
|
||||
switch (m_log2Decim)
|
||||
{
|
||||
case 0:
|
||||
m_decimators.decimate1(&it, buf, len);
|
||||
break;
|
||||
case 1:
|
||||
m_decimators.decimate2_cen(&it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators.decimate4_cen(&it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators.decimate8_cen(&it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators.decimate16_cen(&it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators.decimate32_cen(&it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators.decimate64_cen(&it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_sampleFifo->write(m_convertBuffer.begin(), it);
|
||||
}
|
||||
|
||||
|
||||
int AirspyHFIThread::rx_callback(airspyhf_transfer_t* transfer)
|
||||
{
|
||||
qint32 bytes_to_write = transfer->sample_count * sizeof(qint16);
|
||||
m_this->callback((qint16 *) transfer->samples, bytes_to_write);
|
||||
return 0;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 INCLUDE_AIRSPYHFITHREAD_H
|
||||
#define INCLUDE_AIRSPYHFITHREAD_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <libairspyhf/airspyhf.h>
|
||||
|
||||
#include "dsp/samplesinkfifo.h"
|
||||
#include "dsp/decimators.h"
|
||||
|
||||
#define AIRSPYHFI_BLOCKSIZE (1<<17)
|
||||
|
||||
class AirspyHFIThread : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AirspyHFIThread(airspyhf_device_t* dev, SampleSinkFifo* sampleFifo, QObject* parent = 0);
|
||||
~AirspyHFIThread();
|
||||
|
||||
void startWork();
|
||||
void stopWork();
|
||||
void setSamplerate(uint32_t samplerate);
|
||||
void setLog2Decimation(unsigned int log2_decim);
|
||||
|
||||
private:
|
||||
QMutex m_startWaitMutex;
|
||||
QWaitCondition m_startWaiter;
|
||||
bool m_running;
|
||||
|
||||
airspyhf_device_t* m_dev;
|
||||
qint16 m_buf[2*AIRSPYHFI_BLOCKSIZE];
|
||||
SampleVector m_convertBuffer;
|
||||
SampleSinkFifo* m_sampleFifo;
|
||||
|
||||
int m_samplerate;
|
||||
unsigned int m_log2Decim;
|
||||
static AirspyHFIThread *m_this;
|
||||
|
||||
#ifdef SDR_RX_SAMPLE_24BIT
|
||||
Decimators<qint64, qint16, SDR_RX_SAMP_SZ, 16> m_decimators;
|
||||
#else
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators;
|
||||
#endif
|
||||
|
||||
void run();
|
||||
void callback(const qint16* buf, qint32 len);
|
||||
static int rx_callback(airspyhf_transfer_t* transfer);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AIRSPYHFITHREAD_H
|
@ -1,105 +0,0 @@
|
||||
<h1>AirspyHF input plugin</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This input sample source plugin gets its samples from a [Airspy HF+ device](https://airspy.com/airspy-hf-plus/).
|
||||
|
||||
<h2>Build</h2>
|
||||
|
||||
The plugin will be built only if the [Airspy HF library](https://github.com/f4exb/airspyhf) is installed in your system. Please note that you should use my fork as it deals with integer samples. The branch to check out is `intsamples` but this is the default in Github.
|
||||
|
||||
If you build it from source and install it in a custom location say: `/opt/install/libairspyhf` you will have to add `-DLIBRTLSDR_INCLUDE_DIR=/opt/install/libairspyhf/include -DLIBRTLSDR_LIBRARIES=/opt/install/libairspyhf/lib/libairspyhf.so` to the cmake command line.
|
||||
|
||||
Note: if you use binary distributions this is included in the bundle.
|
||||
|
||||
<h2>Interface</h2>
|
||||
|
||||
It has very few controls compared to other source interfaces. This is because a lot of things are handled automatically with the AirspyHF+:
|
||||
|
||||
- gains (hardware)
|
||||
- DC and IQ correction (library software)
|
||||
|
||||

|
||||
|
||||
<h3>1: Common stream parameters</h3>
|
||||
|
||||

|
||||
|
||||
<h4>1.1: Frequency</h4>
|
||||
|
||||
This is the center frequency of reception in kHz.
|
||||
|
||||
<h4>1.2: Start/Stop</h4>
|
||||
|
||||
Device start / stop button.
|
||||
|
||||
- Blue triangle icon: device is ready and can be started
|
||||
- Green square icon: device is running and can be stopped
|
||||
- Magenta (or pink) square icon: an error occured. In the case the device was accidentally disconnected you may click on the icon, plug back in and start again.
|
||||
|
||||
<h4>1.3: Record</h4>
|
||||
|
||||
Record baseband I/Q stream toggle button
|
||||
|
||||
<h4>1.4: Stream sample rate</h4>
|
||||
|
||||
Baseband I/Q sample rate in kS/s. This is the device to host sample rate (3) divided by the decimation factor (4).
|
||||
|
||||
<h3>2: Lo ppm correction</h3>
|
||||
|
||||
This is the correction factor in ppm applied to the local oscillator. The Airspy HF LO has 1 kHz increments so anything in between is obtained by mixing the signal with a Hz precision NCO. This is actually done in the AirspyHF library.
|
||||
|
||||
On HF band the LO correction is not necessary because the LO is largely precise enough for the frequencies involved. You can disable the NCO in AirspyHF library by setting the value to zero. Since the LO control in SDRangel has a 1 kHz step the NCO correction will always be zero. In AirspyHF library (my fork) the NCO is not active (no extra complex multiplication) if the correction is zero. On HF band it is recommended not to use the LO correction (set it or leave it at 0).
|
||||
|
||||
You can reset the ppm value anytime by pressing on button (3)
|
||||
|
||||
<h3>3: Reset LO ppm correction</h3>
|
||||
|
||||
THis resets the LO ppm correction (zero the value). By doing so the LO trimming NCO in AirspyHF libray is disabled.
|
||||
|
||||
<h3>4: Band select</h3>
|
||||
|
||||
Use this combo box to select the HF or VHF range. This will set the limits of the frequency dial (1.1) appropriately and possibly move the current frequency inside the limits. Limits are given by the AirspyHF+ specifications:
|
||||
|
||||
- HF: 9 kHz to 31 MHz
|
||||
- VHF: 60 to 260 MHz
|
||||
|
||||
<h3>5: Device to hast sample rate</h3>
|
||||
|
||||
This is the device to host sample rate in samples per second (S/s).
|
||||
|
||||
Although the combo box is there to present a choice of sample rates at present the AirspyHF+ deals only with 768 kS/s. However the support library has provision to get a list of sample rates from the device incase of future developments.
|
||||
|
||||
<h3>6: Decimation factor</h3>
|
||||
|
||||
The I/Q stream from the AirspyHF to host is downsampled by a power of two before being sent to the passband. Possible values are increasing powers of two: 1 (no decimation), 2, 4, 8, 16, 32, 64. When using audio channel plugins (AM, DSD, NFM, SSB...) please make sure that the sample rate is not less than 48 kHz (no decimation by 32 or 64).
|
||||
|
||||
<h3>7: Transverter mode open dialog</h3>
|
||||
|
||||
This button opens a dialog to set the transverter mode frequency translation options:
|
||||
|
||||

|
||||
|
||||
Note that if you mouse over the button a tooltip appears that displays the translating frequency and if translation is enabled or disabled. When the frequency translation is enabled the button is lit.
|
||||
|
||||
<h4>7a.1: Translating frequency</h4>
|
||||
|
||||
You can set the translating frequency in Hz with this dial. Use the wheels to adjust the sample rate. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arroews. Pressing shift simultanoeusly moves digit by 5 and pressing control moves it by 2.
|
||||
|
||||
The frequency set in the device is the frequency on the main dial (1) minus this frequency. Thus it is positive for down converters and negative for up converters.
|
||||
|
||||
For example with the DX Patrol that has a mixer at 120 MHz for HF operation you would set the value to -120,000,000 Hz so that if the main dial frequency is set at 7,130 kHz the RTLSDR of the DX Patrol will be set to 127.130 MHz.
|
||||
|
||||
If you use a down converter to receive the 6 cm band narrowband center frequency of 5670 MHz at 432 MHz you would set the translating frequency to 5760 - 432 = 5328 MHz thus dial +5,328,000,000 Hz.
|
||||
|
||||
For bands even higher in the frequency spectrum the GHz digits are not really significant so you can have them set at 1 GHz. Thus to receive the 10368 MHz frequency at 432 MHz you would set the translating frequency to 1368 - 432 = 936 MHz. Note that in this case the frequency of the LO used in the mixer of the transverter is set at 9936 MHz.
|
||||
|
||||
The Hz precision allows a fine tuning of the transverter LO offset
|
||||
|
||||
<h4>7a.2: Translating frequency enable/disable</h4>
|
||||
|
||||
Use this toggle button to activate or deactivate the frequency translation
|
||||
|
||||
<h4>7a.3: Confirmation buttons</h4>
|
||||
|
||||
Use these buttons to confirm ("OK") or dismiss ("Cancel") your changes.
|
@ -2,6 +2,11 @@ project(samplesink)
|
||||
|
||||
find_package(LibUSB)
|
||||
|
||||
find_package(LibBLADERF)
|
||||
if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
|
||||
add_subdirectory(bladerfoutput)
|
||||
endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
|
||||
|
||||
find_package(LibHACKRF)
|
||||
if(LIBUSB_FOUND AND LIBHACKRF_FOUND)
|
||||
add_subdirectory(hackrfoutput)
|
||||
|
68
pluginssrv/samplesink/bladerfoutput/CMakeLists.txt
Normal file
68
pluginssrv/samplesink/bladerfoutput/CMakeLists.txt
Normal file
@ -0,0 +1,68 @@
|
||||
project(bladerfoutput)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(PLUGIN_PREFIX "../../../plugins/samplesink/bladerfoutput")
|
||||
|
||||
set(bladerfoutput_SOURCES
|
||||
${PLUGIN_PREFIX}/bladerfoutput.cpp
|
||||
${PLUGIN_PREFIX}/bladerfoutputplugin.cpp
|
||||
${PLUGIN_PREFIX}/bladerfoutputsettings.cpp
|
||||
${PLUGIN_PREFIX}/bladerfoutputthread.cpp
|
||||
)
|
||||
|
||||
set(bladerfoutput_HEADERS
|
||||
${PLUGIN_PREFIX}/bladerfoutput.h
|
||||
${PLUGIN_PREFIX}/bladerfoutputplugin.h
|
||||
${PLUGIN_PREFIX}/bladerfoutputsettings.h
|
||||
${PLUGIN_PREFIX}/bladerfoutputthread.h
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${CMAKE_SOURCE_DIR}/devices
|
||||
${LIBBLADERFLIBSRC}/include
|
||||
${LIBBLADERFLIBSRC}/src
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${CMAKE_SOURCE_DIR}/devices
|
||||
${LIBBLADERF_INCLUDE_DIR}
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
add_definitions(-DQT_PLUGIN)
|
||||
add_definitions(-DQT_SHARED)
|
||||
|
||||
add_library(outputbladerfsrv SHARED
|
||||
${bladerfoutput_SOURCES}
|
||||
${bladerfoutput_HEADERS_MOC}
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
target_link_libraries(outputbladerfsrv
|
||||
${QT_LIBRARIES}
|
||||
bladerf
|
||||
sdrbase
|
||||
swagger
|
||||
bladerfdevice
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
target_link_libraries(outputbladerfsrv
|
||||
${QT_LIBRARIES}
|
||||
${LIBBLADERF_LIBRARIES}
|
||||
sdrbase
|
||||
swagger
|
||||
bladerfdevice
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
qt5_use_modules(outputbladerfsrv Core Widgets)
|
||||
|
||||
install(TARGETS outputbladerfsrv DESTINATION lib/pluginssrv/samplesink)
|
@ -8,11 +8,21 @@ if(V4L-RTL)
|
||||
# add_subdirectory(v4l-rtl)
|
||||
endif()
|
||||
if(V4L-MSI)
|
||||
FIND_LIBRARY (LIBV4L2 v4l2)
|
||||
FIND_LIBRARY (LIBV4L2 v4l2)
|
||||
FIND_PATH (LIBV4L2H libv4l2.h)
|
||||
# add_subdirectory(v4l-msi)
|
||||
endif()
|
||||
|
||||
find_package(LibAIRSPYHF)
|
||||
if(LIBUSB_FOUND AND LIBAIRSPYHF_FOUND)
|
||||
add_subdirectory(airspyhf)
|
||||
endif(LIBUSB_FOUND AND LIBAIRSPYHF_FOUND)
|
||||
|
||||
find_package(LibBLADERF)
|
||||
if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
|
||||
add_subdirectory(bladerfinput)
|
||||
endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
|
||||
|
||||
find_package(LibHACKRF)
|
||||
if(LIBUSB_FOUND AND LIBHACKRF_FOUND)
|
||||
add_subdirectory(hackrfinput)
|
||||
@ -29,6 +39,7 @@ if(LIBUSB_FOUND AND LIBRTLSDR_FOUND)
|
||||
endif(LIBUSB_FOUND AND LIBRTLSDR_FOUND)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
add_subdirectory(airspyhf)
|
||||
add_subdirectory(hackrfinput)
|
||||
add_subdirectory(limesdrinput)
|
||||
add_subdirectory(rtlsdr)
|
||||
|
64
pluginssrv/samplesource/airspyhf/CMakeLists.txt
Normal file
64
pluginssrv/samplesource/airspyhf/CMakeLists.txt
Normal file
@ -0,0 +1,64 @@
|
||||
project(airspyhf)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(PLUGIN_PREFIX "../../../plugins/samplesource/airspyhf")
|
||||
|
||||
set(airspyhf_SOURCES
|
||||
${PLUGIN_PREFIX}/airspyhfinput.cpp
|
||||
${PLUGIN_PREFIX}/airspyhfplugin.cpp
|
||||
${PLUGIN_PREFIX}/airspyhfsettings.cpp
|
||||
${PLUGIN_PREFIX}/airspyhfthread.cpp
|
||||
)
|
||||
|
||||
set(airspyhf_HEADERS
|
||||
${PLUGIN_PREFIX}/airspyhfinput.h
|
||||
${PLUGIN_PREFIX}/airspyhfplugin.h
|
||||
${PLUGIN_PREFIX}/airspyhfsettings.h
|
||||
${PLUGIN_PREFIX}/airspyhfthread.h
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${LIBAIRSPYHFSRC}
|
||||
${LIBAIRSPYHFSRC}/libairspyhf/src
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${LIBAIRSPYHF_INCLUDE_DIR}
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
add_definitions("${QT_DEFINITIONS} -DLIBAIRSPY_DYN_RATES")
|
||||
add_definitions(-DQT_PLUGIN)
|
||||
add_definitions(-DQT_SHARED)
|
||||
|
||||
add_library(inputairspyhfsrv SHARED
|
||||
${airspyhf_SOURCES}
|
||||
${airspyhf_HEADERS_MOC}
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
target_link_libraries(inputairspyhfsrv
|
||||
${QT_LIBRARIES}
|
||||
airspyhf
|
||||
sdrbase
|
||||
swagger
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
target_link_libraries(inputairspyhfsrv
|
||||
${QT_LIBRARIES}
|
||||
${LIBAIRSPYHF_LIBRARIES}
|
||||
sdrbase
|
||||
swagger
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
qt5_use_modules(inputairspyhfsrv Core Widgets)
|
||||
|
||||
install(TARGETS inputairspyhfsrv DESTINATION lib/pluginssrv/samplesource)
|
68
pluginssrv/samplesource/bladerfinput/CMakeLists.txt
Normal file
68
pluginssrv/samplesource/bladerfinput/CMakeLists.txt
Normal file
@ -0,0 +1,68 @@
|
||||
project(bladerfinput)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(PLUGIN_PREFIX "../../../plugins/samplesource/bladerfinput")
|
||||
|
||||
set(bladerfinput_SOURCES
|
||||
${PLUGIN_PREFIX}/bladerfinput.cpp
|
||||
${PLUGIN_PREFIX}/bladerfinputplugin.cpp
|
||||
${PLUGIN_PREFIX}/bladerfinputsettings.cpp
|
||||
${PLUGIN_PREFIX}/bladerfinputthread.cpp
|
||||
)
|
||||
|
||||
set(bladerfinput_HEADERS
|
||||
${PLUGIN_PREFIX}/bladerfinput.h
|
||||
${PLUGIN_PREFIX}/bladerfinputplugin.h
|
||||
${PLUGIN_PREFIX}/bladerfinputsettings.h
|
||||
${PLUGIN_PREFIX}/bladerfinputthread.h
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${CMAKE_SOURCE_DIR}/devices
|
||||
${LIBBLADERFLIBSRC}/include
|
||||
${LIBBLADERFLIBSRC}/src
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${CMAKE_SOURCE_DIR}/devices
|
||||
${LIBBLADERF_INCLUDE_DIR}
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
add_definitions(-DQT_PLUGIN)
|
||||
add_definitions(-DQT_SHARED)
|
||||
|
||||
add_library(inputbladerfsrv SHARED
|
||||
${bladerfinput_SOURCES}
|
||||
${bladerfinput_HEADERS_MOC}
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
target_link_libraries(inputbladerfsrv
|
||||
${QT_LIBRARIES}
|
||||
bladerf
|
||||
sdrbase
|
||||
swagger
|
||||
bladerfdevice
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
target_link_libraries(inputbladerfsrv
|
||||
${QT_LIBRARIES}
|
||||
${LIBBLADERF_LIBRARIES}
|
||||
sdrbase
|
||||
swagger
|
||||
bladerfdevice
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
qt5_use_modules(inputbladerfsrv Core Widgets)
|
||||
|
||||
install(TARGETS inputbladerfsrv DESTINATION lib/pluginssrv/samplesource)
|
Loading…
x
Reference in New Issue
Block a user