1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-22 16:08:39 -05:00

Deep redesign: Better support for FCD dongles #6: have two distinct plugins for Pro and Pro+. Only Pro+ is active at the moment

This commit is contained in:
f4exb 2015-09-04 04:10:38 +02:00
parent 410b6d15c0
commit 5453d63431
26 changed files with 1333 additions and 124 deletions

View File

@ -18,7 +18,7 @@ if(LIBUSB_FOUND AND UNIX)
FIND_LIBRARY (LIBASOUND asound) FIND_LIBRARY (LIBASOUND asound)
endif() endif()
if(LIBASOUND AND ASOUNDH) if(LIBASOUND AND ASOUNDH)
add_subdirectory(fcdpro) add_subdirectory(fcdproplus)
endif() endif()
find_package(LibRTLSDR) find_package(LibRTLSDR)

View File

@ -206,8 +206,6 @@ void BladerfInput::stop()
bladerf_close(m_dev); bladerf_close(m_dev);
m_dev = 0; m_dev = 0;
} }
m_deviceDescription.clear();
} }
const QString& BladerfInput::getDeviceDescription() const const QString& BladerfInput::getDeviceDescription() const

View File

@ -1,23 +1,23 @@
project(fcdpro) project(fcdpro)
set(fcdpro_SOURCES set(fcdpro_SOURCES
fcdgui.cpp fcdprogui.cpp
fcdinput.cpp fcdproinput.cpp
fcdplugin.cpp fcdproplugin.cpp
fcdserializer.cpp fcdproserializer.cpp
fcdthread.cpp fcdprothread.cpp
) )
set(fcdpro_HEADERS set(fcdpro_HEADERS
fcdgui.h fcdprogui.h
fcdinput.h fcdproinput.h
fcdplugin.h fcdproplugin.h
fcdserializer.h fcdproserializer.h
fcdthread.h fcdprothread.h
) )
set(fcdpro_FORMS set(fcdpro_FORMS
fcdgui.ui fcdprogui.ui
) )
include_directories( include_directories(

View File

@ -1,12 +1,12 @@
#include "fcdgui.h" #include "ui_fcdprogui.h"
#include "ui_fcdgui.h"
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "gui/colormapper.h" #include "gui/colormapper.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "fcdprogui.h"
FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) : FCDProGui::FCDProGui(PluginAPI* pluginAPI, QWidget* parent) :
QWidget(parent), QWidget(parent),
ui(new Ui::FCDGui), ui(new Ui::FCDProGui),
m_pluginAPI(pluginAPI), m_pluginAPI(pluginAPI),
m_settings(), m_settings(),
m_sampleSource(NULL) m_sampleSource(NULL)
@ -17,48 +17,48 @@ FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) :
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
displaySettings(); displaySettings();
m_sampleSource = new FCDInput(); m_sampleSource = new FCDProInput();
DSPEngine::instance()->setSource(m_sampleSource); DSPEngine::instance()->setSource(m_sampleSource);
} }
FCDGui::~FCDGui() FCDProGui::~FCDProGui()
{ {
delete ui; delete ui;
} }
void FCDGui::destroy() void FCDProGui::destroy()
{ {
delete this; delete this;
} }
void FCDGui::setName(const QString& name) void FCDProGui::setName(const QString& name)
{ {
setObjectName(name); setObjectName(name);
} }
QString FCDGui::getName() const QString FCDProGui::getName() const
{ {
return objectName(); return objectName();
} }
void FCDGui::resetToDefaults() void FCDProGui::resetToDefaults()
{ {
m_settings.resetToDefaults(); m_settings.resetToDefaults();
displaySettings(); displaySettings();
sendSettings(); sendSettings();
} }
qint64 FCDGui::getCenterFrequency() const qint64 FCDProGui::getCenterFrequency() const
{ {
return m_settings.centerFrequency; return m_settings.centerFrequency;
} }
QByteArray FCDGui::serialize() const QByteArray FCDProGui::serialize() const
{ {
return m_settings.serialize(); return m_settings.serialize();
} }
bool FCDGui::deserialize(const QByteArray& data) bool FCDProGui::deserialize(const QByteArray& data)
{ {
if(m_settings.deserialize(data)) if(m_settings.deserialize(data))
{ {
@ -73,12 +73,12 @@ bool FCDGui::deserialize(const QByteArray& data)
} }
} }
bool FCDGui::handleMessage(const Message& message) bool FCDProGui::handleMessage(const Message& message)
{ {
return false; return false;
} }
void FCDGui::displaySettings() void FCDProGui::displaySettings()
{ {
ui->centerFrequency->setValue(m_settings.centerFrequency / 1000); ui->centerFrequency->setValue(m_settings.centerFrequency / 1000);
ui->checkBoxR->setChecked(m_settings.range); ui->checkBoxR->setChecked(m_settings.range);
@ -86,26 +86,26 @@ void FCDGui::displaySettings()
ui->checkBoxB->setChecked(m_settings.bias); ui->checkBoxB->setChecked(m_settings.bias);
} }
void FCDGui::sendSettings() void FCDProGui::sendSettings()
{ {
if(!m_updateTimer.isActive()) if(!m_updateTimer.isActive())
m_updateTimer.start(100); m_updateTimer.start(100);
} }
void FCDGui::on_centerFrequency_changed(quint64 value) void FCDProGui::on_centerFrequency_changed(quint64 value)
{ {
m_settings.centerFrequency = value * 1000; m_settings.centerFrequency = value * 1000;
sendSettings(); sendSettings();
} }
void FCDGui::updateHardware() void FCDProGui::updateHardware()
{ {
FCDInput::MsgConfigureFCD* message = FCDInput::MsgConfigureFCD::create(m_settings); FCDProInput::MsgConfigureFCD* message = FCDProInput::MsgConfigureFCD::create(m_settings);
m_sampleSource->getInputMessageQueue()->push(message); m_sampleSource->getInputMessageQueue()->push(message);
m_updateTimer.stop(); m_updateTimer.stop();
} }
void FCDGui::on_checkBoxR_stateChanged(int state) void FCDProGui::on_checkBoxR_stateChanged(int state)
{ {
if (state == Qt::Checked) // FIXME: this is for the Pro+ version only! if (state == Qt::Checked) // FIXME: this is for the Pro+ version only!
{ {
@ -125,7 +125,7 @@ void FCDGui::on_checkBoxR_stateChanged(int state)
sendSettings(); sendSettings();
} }
void FCDGui::on_checkBoxG_stateChanged(int state) void FCDProGui::on_checkBoxG_stateChanged(int state)
{ {
if (state == Qt::Checked) if (state == Qt::Checked)
{ {
@ -139,7 +139,7 @@ void FCDGui::on_checkBoxG_stateChanged(int state)
sendSettings(); sendSettings();
} }
void FCDGui::on_checkBoxB_stateChanged(int state) void FCDProGui::on_checkBoxB_stateChanged(int state)
{ {
if (state == Qt::Checked) if (state == Qt::Checked)
{ {

View File

@ -0,0 +1,53 @@
#ifndef INCLUDE_FCDPROGUI_H
#define INCLUDE_FCDPROGUI_H
#include <QTimer>
#include "fcdproinput.h"
#include "plugin/plugingui.h"
class PluginAPI;
namespace Ui {
class FCDProGui;
}
class FCDProGui : public QWidget, public PluginGUI {
Q_OBJECT
public:
explicit FCDProGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
virtual ~FCDProGui();
void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
qint64 getCenterFrequency() const;
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual bool handleMessage(const Message& message);
private:
Ui::FCDProGui* ui;
PluginAPI* m_pluginAPI;
FCDProInput::Settings m_settings;
QTimer m_updateTimer;
std::vector<int> m_gains;
SampleSource* m_sampleSource;
void displaySettings();
void sendSettings();
private slots:
void on_centerFrequency_changed(quint64 value);
void on_checkBoxR_stateChanged(int state);
void on_checkBoxG_stateChanged(int state);
void on_checkBoxB_stateChanged(int state);
void updateHardware();
};
#endif // INCLUDE_FCDPROGUI_H

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>FCDGui</class> <class>FCDProGui</class>
<widget class="QWidget" name="FCDGui"> <widget class="QWidget" name="FCDProGui">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>132</width> <width>165</width>
<height>119</height> <height>119</height>
</rect> </rect>
</property> </property>

View File

@ -0,0 +1,289 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// //
// 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/>. //
///////////////////////////////////////////////////////////////////////////////////
// FIXME: FCD is handled very badly!
#include <QDebug>
#include <string.h>
#include <errno.h>
#include "dsp/dspcommands.h"
#include "fcdproinput.h"
#include "fcdprogui.h"
#include "fcdproserializer.h"
#include "fcdprothread.h"
MESSAGE_CLASS_DEFINITION(FCDProInput::MsgConfigureFCD, Message)
/*
const uint16_t FCDInput::m_vendorId = 0x04D8;
const uint16_t FCDInput::m_productId = 0xFB31;
const int FCDInput::m_sampleRate = 192000;
const std::string FCDInput::m_deviceName("hw:CARD=V20");
const uint16_t FCDInput::m_productId = 0xFB56;
const int FCDInput::m_sampleRate = 96000;
const std::string FCDInput::m_deviceName("hw:CARD=V10");
*/
FCDProInput::Settings::Settings() :
centerFrequency(435000000),
range(0),
gain(0),
bias(0)
{
}
void FCDProInput::Settings::resetToDefaults()
{
centerFrequency = 435000000;
range = 0;
gain = 0;
bias = 0;
}
QByteArray FCDProInput::Settings::serialize() const
{
FCDProSerializer::FCDData data;
data.m_data.m_lnaGain = gain;
data.m_data.m_frequency = centerFrequency;
data.m_range = range;
data.m_bias = bias;
QByteArray byteArray;
FCDProSerializer::writeSerializedData(data, byteArray);
return byteArray;
/*
SimpleSerializer s(1);
s.writeU64(1, centerFrequency);
s.writeS32(2, range);
s.writeS32(3, gain);
s.writeS32(4, bias);
return s.final();*/
}
bool FCDProInput::Settings::deserialize(const QByteArray& serializedData)
{
FCDProSerializer::FCDData data;
bool valid = FCDProSerializer::readSerializedData(serializedData, data);
gain = data.m_data.m_lnaGain;
centerFrequency = data.m_data.m_frequency;
range = data.m_range;
bias = data.m_bias;
return valid;
/*
SimpleDeserializer d(data);
if (d.isValid() && d.getVersion() == 1)
{
d.readU64(1, &centerFrequency, 435000000);
d.readS32(2, &range, 0);
d.readS32(3, &gain, 0);
d.readS32(4, &bias, 0);
return true;
}
resetToDefaults();
return true;*/
}
FCDProInput::FCDProInput() :
m_dev(0),
m_settings(),
m_FCDThread(0),
m_deviceDescription("Funcube Dongle Pro")
{
}
FCDProInput::~FCDProInput()
{
stop();
}
bool FCDProInput::init(const Message& cmd)
{
return false;
}
bool FCDProInput::start(int device)
{
qDebug() << "FCDProInput::start with device #" << device;
QMutexLocker mutexLocker(&m_mutex);
if (m_FCDThread)
{
return false;
}
m_dev = fcdOpen(0x04D8, 0xFB56, device);
if (m_dev == 0)
{
qCritical("FCDProInput::start: could not open FCD");
return false;
}
/* Apply settings before streaming to avoid bus contention;
* there is very little spare bandwidth on a full speed USB device.
* Failure is harmless if no device is found
* ... This is rubbish...*/
//applySettings(m_settings, true);
if(!m_sampleFifo.setSize(96000*4))
{
qCritical("Could not allocate SampleFifo");
return false;
}
if ((m_FCDThread = new FCDProThread(&m_sampleFifo)) == NULL)
{
qFatal("out of memory");
return false;
}
m_FCDThread->startWork();
mutexLocker.unlock();
applySettings(m_settings, true);
qDebug("FCDProInput::started");
return true;
}
void FCDProInput::stop()
{
QMutexLocker mutexLocker(&m_mutex);
if (m_FCDThread)
{
m_FCDThread->stopWork();
// wait for thread to quit ?
delete m_FCDThread;
m_FCDThread = 0;
}
fcdClose(m_dev);
m_dev = 0;
}
const QString& FCDProInput::getDeviceDescription() const
{
return m_deviceDescription;
}
int FCDProInput::getSampleRate() const
{
return 96000;
}
quint64 FCDProInput::getCenterFrequency() const
{
return m_settings.centerFrequency;
}
bool FCDProInput::handleMessage(const Message& message)
{
if(MsgConfigureFCD::match(message))
{
qDebug() << "FCDProInput::handleMessage: MsgConfigureFCD";
MsgConfigureFCD& conf = (MsgConfigureFCD&) message;
applySettings(conf.getSettings(), false);
return true;
}
else
{
return false;
}
}
void FCDProInput::applySettings(const Settings& settings, bool force)
{
bool signalChange = false;
if ((m_settings.centerFrequency != settings.centerFrequency) || force)
{
qDebug() << "FCDProInput::applySettings: fc: " << settings.centerFrequency;
m_settings.centerFrequency = settings.centerFrequency;
if (m_dev != 0)
{
set_center_freq((double) m_settings.centerFrequency);
}
signalChange = true;
}
if ((m_settings.gain != settings.gain) || force)
{
m_settings.gain = settings.gain;
if (m_dev != 0)
{
set_lna_gain(settings.gain > 0);
}
}
if ((m_settings.bias != settings.bias) || force)
{
m_settings.bias = settings.bias;
if (m_dev != 0)
{
set_bias_t(settings.bias > 0);
}
}
if (signalChange)
{
DSPSignalNotification *notif = new DSPSignalNotification(96000, m_settings.centerFrequency);
getOutputMessageQueue()->push(notif);
}
}
void FCDProInput::set_center_freq(double freq)
{
if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE)
{
qDebug("No FCD HID found for frquency change");
}
}
void FCDProInput::set_bias_t(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(m_dev, FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1);
}
void FCDProInput::set_lna_gain(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(m_dev, FCD_CMD_APP_SET_LNA_GAIN, &cmd, 1);
}

View File

@ -0,0 +1,93 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// //
// 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_FCDPROINPUT_H
#define INCLUDE_FCDPROINPUT_H
#include "dsp/samplesource.h"
#include "fcdhid.h"
#include <QString>
#include <inttypes.h>
struct fcd_buffer {
void *start;
std::size_t length;
};
class FCDProThread;
class FCDProInput : public SampleSource {
public:
struct Settings {
Settings();
quint64 centerFrequency;
qint32 range;
qint32 gain;
qint32 bias;
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
class MsgConfigureFCD : public Message {
MESSAGE_CLASS_DECLARATION
public:
const Settings& getSettings() const { return m_settings; }
static MsgConfigureFCD* create(const Settings& settings)
{
return new MsgConfigureFCD(settings);
}
private:
Settings m_settings;
MsgConfigureFCD(const Settings& settings) :
Message(),
m_settings(settings)
{ }
};
FCDProInput();
virtual ~FCDProInput();
virtual bool init(const Message& cmd);
virtual bool start(int device);
virtual void stop();
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual quint64 getCenterFrequency() const;
virtual bool handleMessage(const Message& message);
void set_center_freq(double freq);
void set_bias_t(bool on);
void set_lna_gain(bool on);
private:
void applySettings(const Settings& settings, bool force);
hid_device *m_dev;
QMutex m_mutex;
Settings m_settings;
FCDProThread* m_FCDThread;
QString m_deviceDescription;
};
#endif // INCLUDE_FCDPROINPUT_H

View File

@ -18,10 +18,10 @@
#include <QAction> #include <QAction>
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "util/simpleserializer.h" #include "util/simpleserializer.h"
#include "fcdplugin.h" #include "fcdproplugin.h"
#include "fcdgui.h" #include "fcdprogui.h"
const PluginDescriptor FCDPlugin::m_pluginDescriptor = { const PluginDescriptor FCDProPlugin::m_pluginDescriptor = {
QString("FunCube Pro Input"), QString("FunCube Pro Input"),
QString("---"), QString("---"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
@ -30,24 +30,24 @@ const PluginDescriptor FCDPlugin::m_pluginDescriptor = {
QString("https://github.com/f4exb/sdrangel") QString("https://github.com/f4exb/sdrangel")
}; };
FCDPlugin::FCDPlugin(QObject* parent) : FCDProPlugin::FCDProPlugin(QObject* parent) :
QObject(parent) QObject(parent)
{ {
} }
const PluginDescriptor& FCDPlugin::getPluginDescriptor() const const PluginDescriptor& FCDProPlugin::getPluginDescriptor() const
{ {
return m_pluginDescriptor; return m_pluginDescriptor;
} }
void FCDPlugin::initPlugin(PluginAPI* pluginAPI) void FCDProPlugin::initPlugin(PluginAPI* pluginAPI)
{ {
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.fcdpro", this); m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.fcdpro", this);
} }
PluginInterface::SampleSourceDevices FCDPlugin::enumSampleSources() PluginInterface::SampleSourceDevices FCDProPlugin::enumSampleSources()
{ {
SampleSourceDevices result; SampleSourceDevices result;
@ -59,11 +59,11 @@ PluginInterface::SampleSourceDevices FCDPlugin::enumSampleSources()
return result; return result;
} }
PluginGUI* FCDPlugin::createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address) PluginGUI* FCDProPlugin::createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address)
{ {
if(sourceName == "org.osmocom.sdr.samplesource.fcdpro") if(sourceName == "org.osmocom.sdr.samplesource.fcdpro")
{ {
FCDGui* gui = new FCDGui(m_pluginAPI); FCDProGui* gui = new FCDProGui(m_pluginAPI);
m_pluginAPI->setInputGUI(gui); m_pluginAPI->setInputGUI(gui);
return gui; return gui;
} }

View File

@ -1,16 +1,16 @@
#ifndef INCLUDE_FCDPLUGIN_H #ifndef INCLUDE_FCDPROPLUGIN_H
#define INCLUDE_FCDPLUGIN_H #define INCLUDE_FCDPROPLUGIN_H
#include <QObject> #include <QObject>
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class FCDPlugin : public QObject, public PluginInterface { class FCDProPlugin : public QObject, public PluginInterface {
Q_OBJECT Q_OBJECT
Q_INTERFACES(PluginInterface) Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.fcdpro") Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.fcdpro")
public: public:
explicit FCDPlugin(QObject* parent = NULL); explicit FCDProPlugin(QObject* parent = NULL);
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);

View File

@ -14,9 +14,9 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "fcdserializer.h" #include "fcdproserializer.h"
void FCDSerializer::writeSerializedData(const FCDData& data, QByteArray& serializedData) void FCDProSerializer::writeSerializedData(const FCDData& data, QByteArray& serializedData)
{ {
QByteArray sampleSourceSerialized; QByteArray sampleSourceSerialized;
SampleSourceSerializer::writeSerializedData(data.m_data, sampleSourceSerialized); SampleSourceSerializer::writeSerializedData(data.m_data, sampleSourceSerialized);
@ -30,7 +30,7 @@ void FCDSerializer::writeSerializedData(const FCDData& data, QByteArray& seriali
serializedData = s.final(); serializedData = s.final();
} }
bool FCDSerializer::readSerializedData(const QByteArray& serializedData, FCDData& data) bool FCDProSerializer::readSerializedData(const QByteArray& serializedData, FCDData& data)
{ {
bool valid = SampleSourceSerializer::readSerializedData(serializedData, data.m_data); bool valid = SampleSourceSerializer::readSerializedData(serializedData, data.m_data);
@ -61,7 +61,7 @@ bool FCDSerializer::readSerializedData(const QByteArray& serializedData, FCDData
} }
} }
void FCDSerializer::setDefaults(FCDData& data) void FCDProSerializer::setDefaults(FCDData& data)
{ {
data.m_range = 0; data.m_range = 0;
data.m_bias = 0; data.m_bias = 0;

View File

@ -14,12 +14,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ #ifndef PLUGINS_SAMPLESOURCE_FCD_FCDPROSERIALIZER_H_
#define PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ #define PLUGINS_SAMPLESOURCE_FCD_FCDPROSERIALIZER_H_
#include "util/samplesourceserializer.h" #include "util/samplesourceserializer.h"
class FCDSerializer class FCDProSerializer
{ {
public: public:
struct FCDData struct FCDData
@ -36,4 +36,4 @@ public:
#endif /* PLUGINS_SAMPLESOURCE_FCD_FCDSERIALIZER_H_ */ #endif /* PLUGINS_SAMPLESOURCE_FCD_FCDPROSERIALIZER_H_ */

View File

@ -18,11 +18,11 @@
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include "fcdthread.h"
#include "fcdinput.h"
#include "dsp/samplefifo.h" #include "dsp/samplefifo.h"
#include "fcdprothread.h"
#include "fcdproinput.h"
FCDThread::FCDThread(SampleFifo* sampleFifo, QObject* parent) : FCDProThread::FCDProThread(SampleFifo* sampleFifo, QObject* parent) :
QThread(parent), QThread(parent),
fcd_handle(NULL), fcd_handle(NULL),
m_running(false), m_running(false),
@ -32,11 +32,11 @@ FCDThread::FCDThread(SampleFifo* sampleFifo, QObject* parent) :
start(); start();
} }
FCDThread::~FCDThread() FCDProThread::~FCDProThread()
{ {
} }
void FCDThread::startWork() void FCDProThread::startWork()
{ {
m_startWaitMutex.lock(); m_startWaitMutex.lock();
@ -50,15 +50,15 @@ void FCDThread::startWork()
m_startWaitMutex.unlock(); m_startWaitMutex.unlock();
} }
void FCDThread::stopWork() void FCDProThread::stopWork()
{ {
m_running = false; m_running = false;
wait(); wait();
} }
void FCDThread::run() void FCDProThread::run()
{ {
if ( !OpenSource("hw:CARD=V20") ) if ( !OpenSource("hw:CARD=V10") )
{ {
qCritical() << "FCDThread::run: cannot open FCD sound card"; qCritical() << "FCDThread::run: cannot open FCD sound card";
return; return;
@ -78,7 +78,7 @@ void FCDThread::run()
CloseSource(); CloseSource();
} }
bool FCDThread::OpenSource(const char* cardname) bool FCDProThread::OpenSource(const char* cardname)
{ {
bool fail = false; bool fail = false;
snd_pcm_hw_params_t* params; snd_pcm_hw_params_t* params;
@ -133,7 +133,7 @@ bool FCDThread::OpenSource(const char* cardname)
return true; return true;
} }
void FCDThread::CloseSource() void FCDProThread::CloseSource()
{ {
if (fcd_handle) if (fcd_handle)
{ {
@ -143,7 +143,7 @@ void FCDThread::CloseSource()
fcd_handle = NULL; fcd_handle = NULL;
} }
int FCDThread::work(int n_items) int FCDProThread::work(int n_items)
{ {
int l; int l;
SampleVector::iterator it; SampleVector::iterator it;

View File

@ -0,0 +1,55 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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_FCDPROTHREAD_H
#define INCLUDE_FCDPROTHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include "dsp/samplefifo.h"
#include "dsp/inthalfbandfilter.h"
#include <alsa/asoundlib.h>
#define FCDPP_RATE 192000
#define FCD_BLOCKSIZE (1<<11)
class FCDProThread : public QThread {
Q_OBJECT
public:
FCDProThread(SampleFifo* sampleFifo, QObject* parent = NULL);
~FCDProThread();
void startWork();
void stopWork();
bool OpenSource(const char *filename);
void CloseSource();
private:
snd_pcm_t* fcd_handle;
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
SampleVector m_convertBuffer;
SampleFifo* m_sampleFifo;
void run();
int work(int n_items);
};
#endif // INCLUDE_FCDPROTHREAD_H

View File

@ -0,0 +1,53 @@
project(fcdproplus)
set(fcdproplus_SOURCES
fcdproplusgui.cpp
fcdproplusinput.cpp
fcdproplusplugin.cpp
fcdproplusserializer.cpp
fcdproplusthread.cpp
)
set(fcdproplus_HEADERS
fcdproplusgui.h
fcdproplusinput.h
fcdproplusplugin.h
fcdproplusserializer.h
fcdproplusthread.h
)
set(fcdproplus_FORMS
fcdproplusgui.ui
)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/include-gpl
${CMAKE_SOURCE_DIR}/fcdhid
)
#include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
#qt4_wrap_cpp(fcdproplus_HEADERS_MOC ${fcdproplus_HEADERS})
qt5_wrap_ui(fcdproplus_FORMS_HEADERS ${fcdproplus_FORMS})
add_library(inputfcdproplus SHARED
${fcdproplus_SOURCES}
${fcdproplus_HEADERS_MOC}
${fcdproplus_FORMS_HEADERS}
)
target_link_libraries(inputfcdproplus
${QT_LIBRARIES}
${LIBUSB_LIBRARIES}
asound
fcdhid
sdrbase
)
qt5_use_modules(inputfcdproplus Core Widgets OpenGL Multimedia)

View File

@ -0,0 +1,154 @@
#include "ui_fcdproplusgui.h"
#include "plugin/pluginapi.h"
#include "gui/colormapper.h"
#include "dsp/dspengine.h"
#include "fcdproplusgui.h"
FCDProPlusGui::FCDProPlusGui(PluginAPI* pluginAPI, QWidget* parent) :
QWidget(parent),
ui(new Ui::FCDProPlusGui),
m_pluginAPI(pluginAPI),
m_settings(),
m_sampleSource(NULL)
{
ui->setupUi(this);
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
ui->centerFrequency->setValueRange(7, 64000U, 1700000U);
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
displaySettings();
m_sampleSource = new FCDProPlusInput();
DSPEngine::instance()->setSource(m_sampleSource);
}
FCDProPlusGui::~FCDProPlusGui()
{
delete ui;
}
void FCDProPlusGui::destroy()
{
delete this;
}
void FCDProPlusGui::setName(const QString& name)
{
setObjectName(name);
}
QString FCDProPlusGui::getName() const
{
return objectName();
}
void FCDProPlusGui::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
qint64 FCDProPlusGui::getCenterFrequency() const
{
return m_settings.centerFrequency;
}
QByteArray FCDProPlusGui::serialize() const
{
return m_settings.serialize();
}
bool FCDProPlusGui::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data))
{
displaySettings();
sendSettings();
return true;
}
else
{
resetToDefaults();
return false;
}
}
bool FCDProPlusGui::handleMessage(const Message& message)
{
return false;
}
void FCDProPlusGui::displaySettings()
{
ui->centerFrequency->setValue(m_settings.centerFrequency / 1000);
ui->checkBoxR->setChecked(m_settings.range);
ui->checkBoxG->setChecked(m_settings.gain);
ui->checkBoxB->setChecked(m_settings.bias);
}
void FCDProPlusGui::sendSettings()
{
if(!m_updateTimer.isActive())
m_updateTimer.start(100);
}
void FCDProPlusGui::on_centerFrequency_changed(quint64 value)
{
m_settings.centerFrequency = value * 1000;
sendSettings();
}
void FCDProPlusGui::updateHardware()
{
FCDProPlusInput::MsgConfigureFCD* message = FCDProPlusInput::MsgConfigureFCD::create(m_settings);
m_sampleSource->getInputMessageQueue()->push(message);
m_updateTimer.stop();
}
void FCDProPlusGui::on_checkBoxR_stateChanged(int state)
{
if (state == Qt::Checked) // FIXME: this is for the Pro+ version only!
{
ui->centerFrequency->setValueRange(7, 150U, 240000U);
ui->centerFrequency->setValue(7000);
m_settings.centerFrequency = 7000 * 1000;
m_settings.range = 1;
}
else
{
ui->centerFrequency->setValueRange(7, 64000U, 1900000U);
ui->centerFrequency->setValue(435000);
m_settings.centerFrequency = 435000 * 1000;
m_settings.range = 0;
}
sendSettings();
}
void FCDProPlusGui::on_checkBoxG_stateChanged(int state)
{
if (state == Qt::Checked)
{
m_settings.gain = 1;
}
else
{
m_settings.gain = 0;
}
sendSettings();
}
void FCDProPlusGui::on_checkBoxB_stateChanged(int state)
{
if (state == Qt::Checked)
{
m_settings.bias = 1;
}
else
{
m_settings.bias = 0;
}
sendSettings();
}

View File

@ -2,21 +2,22 @@
#define INCLUDE_FCDGUI_H #define INCLUDE_FCDGUI_H
#include <QTimer> #include <QTimer>
#include "fcdproplusinput.h"
#include "plugin/plugingui.h" #include "plugin/plugingui.h"
#include "fcdinput.h"
class PluginAPI; class PluginAPI;
namespace Ui { namespace Ui {
class FCDGui; class FCDProPlusGui;
} }
class FCDGui : public QWidget, public PluginGUI { class FCDProPlusGui : public QWidget, public PluginGUI {
Q_OBJECT Q_OBJECT
public: public:
explicit FCDGui(PluginAPI* pluginAPI, QWidget* parent = NULL); explicit FCDProPlusGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
virtual ~FCDGui(); virtual ~FCDProPlusGui();
void destroy(); void destroy();
void setName(const QString& name); void setName(const QString& name);
@ -30,10 +31,10 @@ public:
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
private: private:
Ui::FCDGui* ui; Ui::FCDProPlusGui* ui;
PluginAPI* m_pluginAPI; PluginAPI* m_pluginAPI;
FCDInput::Settings m_settings; FCDProPlusInput::Settings m_settings;
QTimer m_updateTimer; QTimer m_updateTimer;
std::vector<int> m_gains; std::vector<int> m_gains;
SampleSource* m_sampleSource; SampleSource* m_sampleSource;

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FCDProPlusGui</class>
<widget class="QWidget" name="FCDProPlusGui">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>165</width>
<height>119</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>FunCubeDongle</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_3">
<item>
<spacer name="horizontalSpacer">
<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>Monospace</family>
<pointsize>20</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Tuner center frequency in kHz</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<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>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayoutR">
<item>
<widget class="QCheckBox" name="checkBoxR">
<property name="text">
<string>Low Range</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayoutG">
<item>
<widget class="QCheckBox" name="checkBoxG">
<property name="text">
<string>LNA Gain</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxB">
<property name="text">
<string>Bias T</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -20,13 +20,14 @@
#include <QDebug> #include <QDebug>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "fcdinput.h"
#include "fcdthread.h"
#include "fcdgui.h"
#include "dsp/dspcommands.h" #include "dsp/dspcommands.h"
#include "fcdserializer.h" #include "fcdproplusinput.h"
MESSAGE_CLASS_DEFINITION(FCDInput::MsgConfigureFCD, Message) #include "fcdproplusgui.h"
#include "fcdproplusserializer.h"
#include "fcdproplusthread.h"
MESSAGE_CLASS_DEFINITION(FCDProPlusInput::MsgConfigureFCD, Message)
//MESSAGE_CLASS_DEFINITION(FCDInput::MsgReportFCD, Message) //MESSAGE_CLASS_DEFINITION(FCDInput::MsgReportFCD, Message)
/* /*
@ -40,7 +41,7 @@ const int FCDInput::m_sampleRate = 96000;
const std::string FCDInput::m_deviceName("hw:CARD=V10"); const std::string FCDInput::m_deviceName("hw:CARD=V10");
*/ */
FCDInput::Settings::Settings() : FCDProPlusInput::Settings::Settings() :
centerFrequency(435000000), centerFrequency(435000000),
range(0), range(0),
gain(0), gain(0),
@ -48,7 +49,7 @@ FCDInput::Settings::Settings() :
{ {
} }
void FCDInput::Settings::resetToDefaults() void FCDProPlusInput::Settings::resetToDefaults()
{ {
centerFrequency = 435000000; centerFrequency = 435000000;
range = 0; range = 0;
@ -56,9 +57,9 @@ void FCDInput::Settings::resetToDefaults()
bias = 0; bias = 0;
} }
QByteArray FCDInput::Settings::serialize() const QByteArray FCDProPlusInput::Settings::serialize() const
{ {
FCDSerializer::FCDData data; FCDProPlusSerializer::FCDData data;
data.m_data.m_lnaGain = gain; data.m_data.m_lnaGain = gain;
data.m_data.m_frequency = centerFrequency; data.m_data.m_frequency = centerFrequency;
@ -67,7 +68,7 @@ QByteArray FCDInput::Settings::serialize() const
QByteArray byteArray; QByteArray byteArray;
FCDSerializer::writeSerializedData(data, byteArray); FCDProPlusSerializer::writeSerializedData(data, byteArray);
return byteArray; return byteArray;
@ -80,11 +81,11 @@ QByteArray FCDInput::Settings::serialize() const
return s.final();*/ return s.final();*/
} }
bool FCDInput::Settings::deserialize(const QByteArray& serializedData) bool FCDProPlusInput::Settings::deserialize(const QByteArray& serializedData)
{ {
FCDSerializer::FCDData data; FCDProPlusSerializer::FCDData data;
bool valid = FCDSerializer::readSerializedData(serializedData, data); bool valid = FCDProPlusSerializer::readSerializedData(serializedData, data);
gain = data.m_data.m_lnaGain; gain = data.m_data.m_lnaGain;
centerFrequency = data.m_data.m_frequency; centerFrequency = data.m_data.m_frequency;
@ -109,27 +110,27 @@ bool FCDInput::Settings::deserialize(const QByteArray& serializedData)
return true;*/ return true;*/
} }
FCDInput::FCDInput() : FCDProPlusInput::FCDProPlusInput() :
m_dev(0), m_dev(0),
m_settings(), m_settings(),
m_FCDThread(0), m_FCDThread(0),
m_deviceDescription() m_deviceDescription("Funcube Dongle Pro+")
{ {
} }
FCDInput::~FCDInput() FCDProPlusInput::~FCDProPlusInput()
{ {
stop(); stop();
} }
bool FCDInput::init(const Message& cmd) bool FCDProPlusInput::init(const Message& cmd)
{ {
return false; return false;
} }
bool FCDInput::start(int device) bool FCDProPlusInput::start(int device)
{ {
qDebug() << "FCDInput::start with device #" << device; qDebug() << "FCDProPlusInput::start with device #" << device;
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
@ -142,12 +143,10 @@ bool FCDInput::start(int device)
if (m_dev == 0) if (m_dev == 0)
{ {
qCritical("FCDInput::start: could not open FCD"); qCritical("FCDProPlusInput::start: could not open FCD");
return false; return false;
} }
m_deviceDescription = QString("Funcube Dongle");
/* Apply settings before streaming to avoid bus contention; /* Apply settings before streaming to avoid bus contention;
* there is very little spare bandwidth on a full speed USB device. * there is very little spare bandwidth on a full speed USB device.
* Failure is harmless if no device is found * Failure is harmless if no device is found
@ -161,7 +160,7 @@ bool FCDInput::start(int device)
return false; return false;
} }
if ((m_FCDThread = new FCDThread(&m_sampleFifo)) == NULL) if ((m_FCDThread = new FCDProPlusThread(&m_sampleFifo)) == NULL)
{ {
qFatal("out of memory"); qFatal("out of memory");
return false; return false;
@ -172,11 +171,11 @@ bool FCDInput::start(int device)
mutexLocker.unlock(); mutexLocker.unlock();
applySettings(m_settings, true); applySettings(m_settings, true);
qDebug("FCDInput::started"); qDebug("FCDProPlusInput::started");
return true; return true;
} }
void FCDInput::stop() void FCDProPlusInput::stop()
{ {
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
@ -190,30 +189,28 @@ void FCDInput::stop()
fcdClose(m_dev); fcdClose(m_dev);
m_dev = 0; m_dev = 0;
m_deviceDescription.clear();
} }
const QString& FCDInput::getDeviceDescription() const const QString& FCDProPlusInput::getDeviceDescription() const
{ {
return m_deviceDescription; return m_deviceDescription;
} }
int FCDInput::getSampleRate() const int FCDProPlusInput::getSampleRate() const
{ {
return 192000; return 192000;
} }
quint64 FCDInput::getCenterFrequency() const quint64 FCDProPlusInput::getCenterFrequency() const
{ {
return m_settings.centerFrequency; return m_settings.centerFrequency;
} }
bool FCDInput::handleMessage(const Message& message) bool FCDProPlusInput::handleMessage(const Message& message)
{ {
if(MsgConfigureFCD::match(message)) if(MsgConfigureFCD::match(message))
{ {
qDebug() << "FCDInput::handleMessage: MsgConfigureFCD"; qDebug() << "FCDProPlusInput::handleMessage: MsgConfigureFCD";
MsgConfigureFCD& conf = (MsgConfigureFCD&) message; MsgConfigureFCD& conf = (MsgConfigureFCD&) message;
applySettings(conf.getSettings(), false); applySettings(conf.getSettings(), false);
return true; return true;
@ -224,13 +221,13 @@ bool FCDInput::handleMessage(const Message& message)
} }
} }
void FCDInput::applySettings(const Settings& settings, bool force) void FCDProPlusInput::applySettings(const Settings& settings, bool force)
{ {
bool signalChange = false; bool signalChange = false;
if ((m_settings.centerFrequency != settings.centerFrequency) || force) if ((m_settings.centerFrequency != settings.centerFrequency) || force)
{ {
qDebug() << "FCDInput::applySettings: fc: " << settings.centerFrequency; qDebug() << "FCDProPlusInput::applySettings: fc: " << settings.centerFrequency;
m_settings.centerFrequency = settings.centerFrequency; m_settings.centerFrequency = settings.centerFrequency;
if (m_dev != 0) if (m_dev != 0)
@ -268,7 +265,7 @@ void FCDInput::applySettings(const Settings& settings, bool force)
} }
} }
void FCDInput::set_center_freq(double freq) void FCDProPlusInput::set_center_freq(double freq)
{ {
if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE) if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE)
{ {
@ -276,14 +273,14 @@ void FCDInput::set_center_freq(double freq)
} }
} }
void FCDInput::set_bias_t(bool on) void FCDProPlusInput::set_bias_t(bool on)
{ {
quint8 cmd = on ? 1 : 0; quint8 cmd = on ? 1 : 0;
fcdAppSetParam(m_dev, FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1); fcdAppSetParam(m_dev, FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1);
} }
void FCDInput::set_lna_gain(bool on) void FCDProPlusInput::set_lna_gain(bool on)
{ {
quint8 cmd = on ? 1 : 0; quint8 cmd = on ? 1 : 0;

View File

@ -28,9 +28,9 @@ struct fcd_buffer {
std::size_t length; std::size_t length;
}; };
class FCDThread; class FCDProPlusThread;
class FCDInput : public SampleSource { class FCDProPlusInput : public SampleSource {
public: public:
struct Settings { struct Settings {
Settings(); Settings();
@ -63,8 +63,8 @@ public:
{ } { }
}; };
FCDInput(); FCDProPlusInput();
virtual ~FCDInput(); virtual ~FCDProPlusInput();
virtual bool init(const Message& cmd); virtual bool init(const Message& cmd);
virtual bool start(int device); virtual bool start(int device);
@ -86,7 +86,7 @@ private:
hid_device *m_dev; hid_device *m_dev;
QMutex m_mutex; QMutex m_mutex;
Settings m_settings; Settings m_settings;
FCDThread* m_FCDThread; FCDProPlusThread* m_FCDThread;
QString m_deviceDescription; QString m_deviceDescription;
}; };

View File

@ -0,0 +1,74 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "fcdproplusplugin.h"
#include "fcdproplusgui.h"
const PluginDescriptor FCDProPlusPlugin::m_pluginDescriptor = {
QString("FunCube Pro+ Input"),
QString("---"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
FCDProPlusPlugin::FCDProPlusPlugin(QObject* parent) :
QObject(parent)
{
}
const PluginDescriptor& FCDProPlusPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void FCDProPlusPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
m_pluginAPI->registerSampleSource("org.osmocom.sdr.samplesource.fcdproplus", this);
}
PluginInterface::SampleSourceDevices FCDProPlusPlugin::enumSampleSources()
{
SampleSourceDevices result;
QString displayedName(QString("FunCube Pro+ #1"));
SimpleSerializer s(1);
s.writeS32(1, 0);
result.append(SampleSourceDevice(displayedName, "org.osmocom.sdr.samplesource.fcdproplus", s.final()));
return result;
}
PluginGUI* FCDProPlusPlugin::createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address)
{
if(sourceName == "org.osmocom.sdr.samplesource.fcdproplus")
{
FCDProPlusGui* gui = new FCDProPlusGui(m_pluginAPI);
m_pluginAPI->setInputGUI(gui);
return gui;
}
else
{
return NULL;
}
}

View File

@ -0,0 +1,27 @@
#ifndef INCLUDE_FCDPROPLUSPLUGIN_H
#define INCLUDE_FCDPROPLUSPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class FCDProPlusPlugin : public QObject, public PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "org.osmocom.sdr.samplesource.fcdproplus")
public:
explicit FCDProPlusPlugin(QObject* parent = NULL);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
SampleSourceDevices enumSampleSources();
PluginGUI* createSampleSourcePluginGUI(const QString& sourceName, const QByteArray& address);
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
};
#endif // INCLUDE_FCDPROPLUSPLUGIN_H

View File

@ -0,0 +1,68 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 "fcdproplusserializer.h"
void FCDProPlusSerializer::writeSerializedData(const FCDData& data, QByteArray& serializedData)
{
QByteArray sampleSourceSerialized;
SampleSourceSerializer::writeSerializedData(data.m_data, sampleSourceSerialized);
SimpleSerializer s(1);
s.writeBlob(1, sampleSourceSerialized);
s.writeS32(2, data.m_bias);
s.writeS32(3, data.m_range);
serializedData = s.final();
}
bool FCDProPlusSerializer::readSerializedData(const QByteArray& serializedData, FCDData& data)
{
bool valid = SampleSourceSerializer::readSerializedData(serializedData, data.m_data);
QByteArray sampleSourceSerialized;
SimpleDeserializer d(serializedData);
if (!d.isValid())
{
setDefaults(data);
return false;
}
if (d.getVersion() == SampleSourceSerializer::getSerializerVersion())
{
int intval;
d.readBlob(1, &sampleSourceSerialized);
d.readS32(2, &data.m_bias);
d.readS32(3, &data.m_range);
return SampleSourceSerializer::readSerializedData(sampleSourceSerialized, data.m_data);
}
else
{
setDefaults(data);
return false;
}
}
void FCDProPlusSerializer::setDefaults(FCDData& data)
{
data.m_range = 0;
data.m_bias = 0;
}

View File

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_FCD_FCDPROPLUSSERIALIZER_H_
#define PLUGINS_SAMPLESOURCE_FCD_FCDPROPLUSSERIALIZER_H_
#include "util/samplesourceserializer.h"
class FCDProPlusSerializer
{
public:
struct FCDData
{
SampleSourceSerializer::Data m_data;
qint32 m_bias;
qint32 m_range;
};
static void writeSerializedData(const FCDData& data, QByteArray& serializedData);
static bool readSerializedData(const QByteArray& serializedData, FCDData& data);
static void setDefaults(FCDData& data);
};
#endif /* PLUGINS_SAMPLESOURCE_FCD_FCDPROPLUSSERIALIZER_H_ */

View File

@ -0,0 +1,164 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// //
// 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 <stdio.h>
#include <errno.h>
#include "dsp/samplefifo.h"
#include "fcdproplusthread.h"
#include "fcdproplusinput.h"
FCDProPlusThread::FCDProPlusThread(SampleFifo* sampleFifo, QObject* parent) :
QThread(parent),
fcd_handle(NULL),
m_running(false),
m_convertBuffer(FCD_BLOCKSIZE),
m_sampleFifo(sampleFifo)
{
start();
}
FCDProPlusThread::~FCDProPlusThread()
{
}
void FCDProPlusThread::startWork()
{
m_startWaitMutex.lock();
start();
while(!m_running)
{
m_startWaiter.wait(&m_startWaitMutex, 100);
}
m_startWaitMutex.unlock();
}
void FCDProPlusThread::stopWork()
{
m_running = false;
wait();
}
void FCDProPlusThread::run()
{
if ( !OpenSource("hw:CARD=V20") )
{
qCritical() << "FCDThread::run: cannot open FCD sound card";
return;
}
// TODO: fallback to original fcd
m_running = true;
while(m_running)
{
if (work(FCD_BLOCKSIZE) < 0)
{
break;
}
}
CloseSource();
}
bool FCDProPlusThread::OpenSource(const char* cardname)
{
bool fail = false;
snd_pcm_hw_params_t* params;
//fcd_rate = FCDPP_RATE;
//fcd_channels =2;
//fcd_format = SND_PCM_SFMT_U16_LE;
snd_pcm_stream_t fcd_stream = SND_PCM_STREAM_CAPTURE;
if (fcd_handle)
{
return false;
}
if (snd_pcm_open(&fcd_handle, cardname, fcd_stream, 0) < 0)
{
qCritical("FCDThread::OpenSource: cannot open %s", cardname);
return false;
}
snd_pcm_hw_params_alloca(&params);
if (snd_pcm_hw_params_any(fcd_handle, params) < 0)
{
qCritical("FCDProPlusThread::OpenSource: snd_pcm_hw_params_any failed");
fail = true;
}
else if (snd_pcm_hw_params(fcd_handle, params) < 0)
{
qCritical("FCDProPlusThread::OpenSource: snd_pcm_hw_params failed");
fail = true;
// TODO: check actual samplerate, may be crippled firmware
}
else
{
if (snd_pcm_start(fcd_handle) < 0)
{
qCritical("FCDProPlusThread::OpenSource: snd_pcm_start failed");
fail = true;
}
}
if (fail)
{
snd_pcm_close( fcd_handle );
return false;
}
else
{
qDebug("FCDProPlusThread::OpenSource: Funcube stream started");
}
return true;
}
void FCDProPlusThread::CloseSource()
{
if (fcd_handle)
{
snd_pcm_close( fcd_handle );
}
fcd_handle = NULL;
}
int FCDProPlusThread::work(int n_items)
{
int l;
SampleVector::iterator it;
void *out;
it = m_convertBuffer.begin();
out = (void *)&it[0];
l = snd_pcm_mmap_readi(fcd_handle, out, (snd_pcm_uframes_t)n_items);
if (l > 0)
m_sampleFifo->write(it, it + l);
if (l == -EPIPE) {
qDebug("FCDProPlusThread::work: Overrun detected");
return 0;
}
return l;
}

View File

@ -25,15 +25,15 @@
#include "dsp/inthalfbandfilter.h" #include "dsp/inthalfbandfilter.h"
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#define FCDPP_RATE 192000 // FIXME: The Pro / Pro+ switch should be handled better than this! #define FCDPP_RATE 192000
#define FCD_BLOCKSIZE (1<<11) #define FCD_BLOCKSIZE (1<<11)
class FCDThread : public QThread { class FCDProPlusThread : public QThread {
Q_OBJECT Q_OBJECT
public: public:
FCDThread(SampleFifo* sampleFifo, QObject* parent = NULL); FCDProPlusThread(SampleFifo* sampleFifo, QObject* parent = NULL);
~FCDThread(); ~FCDProPlusThread();
void startWork(); void startWork();
void stopWork(); void stopWork();