BladeRF output (1) and some cosmetic changes

This commit is contained in:
f4exb 2018-09-29 05:49:14 +02:00
parent 21bfd71331
commit c27acf086e
32 changed files with 3253 additions and 26 deletions

View File

@ -23,6 +23,7 @@
class SampleSinkFifo;
class SampleSourceFifo;
class BladeRF2Input;
class BladeRF2Output;
/**
* Structure shared by a buddy with other buddies
@ -77,6 +78,7 @@ public:
DeviceBladeRF2 *m_dev;
int m_channel; //!< allocated channel (-1 if none)
BladeRF2Input *m_source;
BladeRF2Output *m_sink;
};

View File

@ -5,6 +5,7 @@ find_package(LibUSB)
find_package(LibBLADERF)
if(LIBUSB_FOUND AND LIBBLADERF_FOUND)
add_subdirectory(bladerf1output)
add_subdirectory(bladerf2output)
endif(LIBUSB_FOUND AND LIBBLADERF_FOUND)
find_package(LibHACKRF)
@ -29,6 +30,7 @@ endif(CM256CC_FOUND)
if (BUILD_DEBIAN)
add_subdirectory(bladerf1output)
add_subdirectory(bladerf2output)
add_subdirectory(hackrfoutput)
add_subdirectory(limesdroutput)
add_subdirectory(plutosdroutput)

View File

@ -23,12 +23,11 @@
#include "SWGDeviceSettings.h"
#include "SWGDeviceState.h"
#include "util/simpleserializer.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "device/devicesinkapi.h"
#include "device/devicesourceapi.h"
#include "../../../devices/bladerf1/devicebladerf1shared.h"
#include "bladerf1/devicebladerf1shared.h"
#include "bladerf1outputthread.h"
MESSAGE_CLASS_DEFINITION(Bladerf1Output::MsgConfigureBladerf1, Message)

View File

@ -36,7 +36,6 @@ public:
void startWork();
void stopWork();
void setLog2Interpolation(unsigned int log2_interp);
void setFcPos(int fcPos);
bool isRunning() const { return m_running; }
private:

View File

@ -0,0 +1,80 @@
project(bladerf2output)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(bladerf2output_SOURCES
# bladerf2outputgui.cpp
bladerf2output.cpp
# bladerf2outputplugin.cpp
bladerf2outputsettings.cpp
bladerf2outputthread.cpp
)
set(bladerf2output_HEADERS
# bladerf2outputgui.h
bladerf2output.h
# bladerf1soutputplugin.h
bladerf2outputsettings.h
bladerf2outputthread.h
)
set(bladerf2output_FORMS
bladerf2outputgui.ui
)
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)
#include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
#qt4_wrap_cpp(bladerf2output_HEADERS_MOC ${bladerf2output_HEADERS})
qt5_wrap_ui(bladerf2output_FORMS_HEADERS ${bladerf2output_FORMS})
add_library(outputbladerf2 SHARED
${bladerf2output_SOURCES}
${bladerf2output_HEADERS_MOC}
${bladerf2output_FORMS_HEADERS}
)
if (BUILD_DEBIAN)
target_link_libraries(outputbladerf2
${QT_LIBRARIES}
bladerf
sdrbase
sdrgui
swagger
bladerf2device
)
else (BUILD_DEBIAN)
target_link_libraries(outputbladerf2
${QT_LIBRARIES}
${LIBBLADERF_LIBRARIES}
sdrbase
sdrgui
swagger
bladerf2device
)
endif (BUILD_DEBIAN)
target_link_libraries(outputbladerf2 Qt5::Core Qt5::Widgets)
install(TARGETS outputbladerf2 DESTINATION lib/plugins/samplesink)

View File

@ -0,0 +1,991 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 "SWGDeviceState.h"
#include "SWGDeviceSettings.h"
#include "SWGBladeRF2InputSettings.h"
#include "SWGDeviceReport.h"
#include "SWGBladeRF2OutputReport.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "device/devicesinkapi.h"
#include "device/devicesourceapi.h"
#include "bladerf2/devicebladerf2shared.h"
#include "bladerf2/devicebladerf2.h"
#include "bladerf2outputthread.h"
#include "bladerf2output.h"
MESSAGE_CLASS_DEFINITION(BladeRF2Output::MsgConfigureBladeRF2, Message)
MESSAGE_CLASS_DEFINITION(BladeRF2Output::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(BladeRF2Output::MsgReportGainRange, Message)
BladeRF2Output::BladeRF2Output(DeviceSinkAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_settings(),
m_dev(0),
m_thread(0),
m_deviceDescription("BladeRF2Output"),
m_running(false)
{
openDevice();
if (m_deviceShared.m_dev)
{
const bladerf_gain_modes *modes = 0;
int nbModes = m_deviceShared.m_dev->getGainModesRx(&modes);
if (modes)
{
for (int i = 0; i < nbModes; i++) {
m_gainModes.push_back(GainMode{QString(modes[i].name), modes[i].mode});
}
}
}
}
BladeRF2Output::~BladeRF2Output()
{
if (m_running) {
stop();
}
closeDevice();
}
void BladeRF2Output::destroy()
{
delete this;
}
bool BladeRF2Output::openDevice()
{
m_sampleSourceFifo.resize(m_settings.m_devSampleRate/(1<<(m_settings.m_log2Interp <= 4 ? m_settings.m_log2Interp : 4)));
// look for Tx buddies and get reference to the device object
if (m_deviceAPI->getSinkBuddies().size() > 0) // look sink sibling first
{
qDebug("BladeRF2Output::openDevice: look in Tx buddies");
DeviceSinkAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0];
DeviceBladeRF2Shared *deviceBladeRF2Shared = (DeviceBladeRF2Shared*) sinkBuddy->getBuddySharedPtr();
if (deviceBladeRF2Shared == 0)
{
qCritical("BladeRF2Output::openDevice: the sink buddy shared pointer is null");
return false;
}
DeviceBladeRF2 *device = deviceBladeRF2Shared->m_dev;
if (device == 0)
{
qCritical("BladeRF2Output::openDevice: cannot get device pointer from Tx buddy");
return false;
}
m_deviceShared.m_dev = device;
}
// look for Rx buddies and get reference to the device object
else if (m_deviceAPI->getSourceBuddies().size() > 0) // then source
{
qDebug("BladeRF2Output::openDevice: look in Rx buddies");
DeviceSourceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0];
DeviceBladeRF2Shared *deviceBladeRF2Shared = (DeviceBladeRF2Shared*) sourceBuddy->getBuddySharedPtr();
if (deviceBladeRF2Shared == 0)
{
qCritical("BladeRF2Output::openDevice: the source buddy shared pointer is null");
return false;
}
DeviceBladeRF2 *device = deviceBladeRF2Shared->m_dev;
if (device == 0)
{
qCritical("BladeRF2Output::openDevice: cannot get device pointer from Rx buddy");
return false;
}
m_deviceShared.m_dev = device;
}
// There are no buddies then create the first BladeRF2 device
else
{
qDebug("BladeRF2Output::openDevice: open device here");
m_deviceShared.m_dev = new DeviceBladeRF2();
char serial[256];
strcpy(serial, qPrintable(m_deviceAPI->getSampleSinkSerial()));
if (!m_deviceShared.m_dev->open(serial))
{
qCritical("BladeRF2Output::openDevice: cannot open BladeRF2 device");
return false;
}
}
m_deviceShared.m_channel = m_deviceAPI->getItemIndex(); // publicly allocate channel
m_deviceShared.m_sink = this;
m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API
return true;
}
void BladeRF2Output::closeDevice()
{
if (m_deviceShared.m_dev == 0) { // was never open
return;
}
if (m_running) {
stop();
}
if (m_thread) { // stills own the thread => transfer to a buddy
moveThreadToBuddy();
}
m_deviceShared.m_channel = -1; // publicly release channel
m_deviceShared.m_sink = 0;
// No buddies so effectively close the device
if ((m_deviceAPI->getSinkBuddies().size() == 0) && (m_deviceAPI->getSourceBuddies().size() == 0))
{
m_deviceShared.m_dev->close();
delete m_deviceShared.m_dev;
m_deviceShared.m_dev = 0;
}
}
void BladeRF2Output::init()
{
applySettings(m_settings, true);
}
BladeRF2OutputThread *BladeRF2Output::findThread()
{
if (m_thread == 0) // this does not own the thread
{
BladeRF2OutputThread *BladeRF2OutputThread = 0;
// find a buddy that has allocated the thread
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
std::vector<DeviceSinkAPI*>::const_iterator it = sinkBuddies.begin();
for (; it != sinkBuddies.end(); ++it)
{
BladeRF2Output *buddySink = ((DeviceBladeRF2Shared*) (*it)->getBuddySharedPtr())->m_sink;
if (buddySink)
{
BladeRF2OutputThread = buddySink->getThread();
if (BladeRF2OutputThread) {
break;
}
}
}
return BladeRF2OutputThread;
}
else
{
return m_thread; // own thread
}
}
void BladeRF2Output::moveThreadToBuddy()
{
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
std::vector<DeviceSinkAPI*>::const_iterator it = sinkBuddies.begin();
for (; it != sinkBuddies.end(); ++it)
{
BladeRF2Output *buddySink = ((DeviceBladeRF2Shared*) (*it)->getBuddySharedPtr())->m_sink;
if (buddySink)
{
buddySink->setThread(m_thread);
m_thread = 0; // zero for others
}
}
}
bool BladeRF2Output::start()
{
// There is a single thread per physical device (Tx side). This thread is unique and referenced by a unique
// buddy in the group of sink buddies associated with this physical device.
//
// This start method is responsible for managing the thread and channel enabling when the streaming of a Tx channel is started
//
// It checks the following conditions
// - the thread is allocated or not (by itself or one of its buddies). If it is it grabs the thread pointer.
// - the requested channel is the first (0) or the following (just 1 in BladeRF 2 case)
//
// The BladeRF support library lets you work in two possible modes:
// - Single Output (SO) with only one channel streaming. This HAS to be channel 0.
// - Multiple Output (MO) with two channels streaming using interleaved samples. It MUST be in this configuration if channel 1
// is used. When we will run with only channel 1 streaming from the client perspective the channel 0 will actually be enabled
// and streaming but zero samples will be sent to it.
//
// It manages the transition form SO where only one channel (the first or channel 0) should be running to the
// Multiple Output (MO) if the requested channel is 1. More generally it checks if the requested channel is within the current
// channel range allocated in the thread or past it. To perform the transition it stops the thread, deletes it and creates a new one.
// It marks the thread as needing start.
//
// If the requested channel is within the thread channel range (this thread being already allocated) it simply removes its FIFO reference
// so that the samples are not taken from the FIFO anymore and leaves the thread unchanged (no stop, no delete/new)
//
// If there is no thread allocated it creates a new one with a number of channels that fits the requested channel. That is
// 1 if channel 0 is requested (SO mode) and 2 if channel 1 is requested (MO mode). It marks the thread as needing start.
//
// Eventually it registers the FIFO in the thread. If the thread has to be started it enables the channels up to the number of channels
// allocated in the thread and starts the thread.
if (!m_deviceShared.m_dev)
{
qDebug("BladeRF2Output::start: no device object");
return false;
}
int requestedChannel = m_deviceAPI->getItemIndex();
BladeRF2OutputThread *bladeRF2OutputThread = findThread();
bool needsStart = false;
if (bladeRF2OutputThread) // if thread is already allocated
{
qDebug("BladeRF2Output::start: thread is already allocated");
int nbOriginalChannels = bladeRF2OutputThread->getNbChannels();
if (requestedChannel+1 > nbOriginalChannels) // expansion by deleting and re-creating the thread
{
qDebug("BladeRF2Output::start: expand channels. Re-allocate thread and take ownership");
SampleSourceFifo **fifos = new SampleSourceFifo*[nbOriginalChannels];
unsigned int *log2Interps = new unsigned int[nbOriginalChannels];
for (int i = 0; i < nbOriginalChannels; i++) // save original FIFO references and data
{
fifos[i] = bladeRF2OutputThread->getFifo(i);
log2Interps[i] = bladeRF2OutputThread->getLog2Interpolation(i);
}
bladeRF2OutputThread->stopWork();
delete bladeRF2OutputThread;
bladeRF2OutputThread = new BladeRF2OutputThread(m_deviceShared.m_dev->getDev(), requestedChannel+1);
m_thread = bladeRF2OutputThread; // take ownership
for (int i = 0; i < nbOriginalChannels; i++) // restore original FIFO references
{
bladeRF2OutputThread->setFifo(i, fifos[i]);
bladeRF2OutputThread->setLog2Interpolation(i, log2Interps[i]);
}
// remove old thread address from buddies (reset in all buddies)
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
std::vector<DeviceSinkAPI*>::const_iterator it = sinkBuddies.begin();
for (; it != sinkBuddies.end(); ++it) {
((DeviceBladeRF2Shared*) (*it)->getBuddySharedPtr())->m_sink->setThread(0);
}
needsStart = true;
}
else
{
qDebug("BladeRF2Output::start: keep buddy thread");
}
}
else // first allocation
{
qDebug("BladeRF2Output::start: allocate thread and take ownership");
bladeRF2OutputThread = new BladeRF2OutputThread(m_deviceShared.m_dev->getDev(), requestedChannel+1);
m_thread = bladeRF2OutputThread; // take ownership
needsStart = true;
}
bladeRF2OutputThread->setFifo(requestedChannel, &m_sampleSourceFifo);
bladeRF2OutputThread->setLog2Interpolation(requestedChannel, m_settings.m_log2Interp);
if (needsStart)
{
qDebug("BladeRF2Output::start: enabling channel(s) and (re)sart buddy thread");
int nbChannels = bladeRF2OutputThread->getNbChannels();
for (int i = 0; i < nbChannels; i++)
{
if (!m_deviceShared.m_dev->openTx(i)) {
qCritical("BladeRF2Output::start: channel %u cannot be enabled", i);
}
}
bladeRF2OutputThread->startWork();
}
applySettings(m_settings, true);
qDebug("BladeRF2Output::start: started");
m_running = true;
return true;
}
void BladeRF2Output::stop()
{
// This stop method is responsible for managing the thread and channel disabling when the streaming of
// a Tx channel is stopped
//
// If the thread is currently managing only one channel (SO mode). The thread can be just stopped and deleted.
// Then the channel is closed (disabled).
//
// If the thread is currently managing many channels (MO mode) and we are removing the last channel. The transition
// from MO to SO or reduction of MO size is handled by stopping the thread, deleting it and creating a new one
// with one channel less if (and only if) there is still a channel active.
//
// If the thread is currently managing many channels (MO mode) but the channel being stopped is not the last
// channel then the FIFO reference is simply removed from the thread so that this FIFO will not be used anymore.
// In this case the channel is not closed (disabled) so that other channels can continue with the
// same configuration. The device continues streaming on this channel but the samples are set to all zeros.
if (!m_running) {
return;
}
int requestedChannel = m_deviceAPI->getItemIndex();
BladeRF2OutputThread *bladeRF2OutputThread = findThread();
if (bladeRF2OutputThread == 0) { // no thread allocated
return;
}
int nbOriginalChannels = bladeRF2OutputThread->getNbChannels();
if (nbOriginalChannels == 1) // SO mode => just stop and delete the thread
{
qDebug("BladeRF2Output::stop: SO mode. Just stop and delete the thread");
bladeRF2OutputThread->stopWork();
delete bladeRF2OutputThread;
m_thread = 0;
// remove old thread address from buddies (reset in all buddies)
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
std::vector<DeviceSinkAPI*>::const_iterator it = sinkBuddies.begin();
for (; it != sinkBuddies.end(); ++it) {
((DeviceBladeRF2Shared*) (*it)->getBuddySharedPtr())->m_sink->setThread(0);
}
m_deviceShared.m_dev->closeTx(0); // close the unique channel
}
else if (requestedChannel == nbOriginalChannels - 1) // remove last MO channel => reduce by deleting and re-creating the thread
{
qDebug("BladeRF2Output::stop: MO mode. Reduce by deleting and re-creating the thread");
bladeRF2OutputThread->stopWork();
SampleSourceFifo **fifos = new SampleSourceFifo*[nbOriginalChannels-1];
unsigned int *log2Interps = new unsigned int[nbOriginalChannels-1];
bool stillActiveFIFO = false;
for (int i = 0; i < nbOriginalChannels-1; i++) // save original FIFO references
{
fifos[i] = bladeRF2OutputThread->getFifo(i);
stillActiveFIFO = stillActiveFIFO || (bladeRF2OutputThread->getFifo(i) != 0);
log2Interps[i] = bladeRF2OutputThread->getLog2Interpolation(i);
}
delete bladeRF2OutputThread;
m_thread = 0;
if (stillActiveFIFO)
{
bladeRF2OutputThread = new BladeRF2OutputThread(m_deviceShared.m_dev->getDev(), nbOriginalChannels-1);
m_thread = bladeRF2OutputThread; // take ownership
for (int i = 0; i < nbOriginalChannels-1; i++) // restore original FIFO references
{
bladeRF2OutputThread->setFifo(i, fifos[i]);
bladeRF2OutputThread->setLog2Interpolation(i, log2Interps[i]);
}
}
else
{
qDebug("BladeRF2Output::stop: do not re-create thread as there are no more FIFOs active");
}
// remove old thread address from buddies (reset in all buddies)
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
std::vector<DeviceSinkAPI*>::const_iterator it = sinkBuddies.begin();
for (; it != sinkBuddies.end(); ++it) {
((DeviceBladeRF2Shared*) (*it)->getBuddySharedPtr())->m_sink->setThread(0);
}
m_deviceShared.m_dev->closeTx(requestedChannel); // close the last channel
if (stillActiveFIFO) {
bladeRF2OutputThread->startWork();
}
}
else // remove channel from existing thread
{
qDebug("BladeRF2Output::stop: MO mode. Not changing MO configuration. Just remove FIFO reference");
bladeRF2OutputThread->setFifo(requestedChannel, 0); // remove FIFO
}
m_running = false;
}
QByteArray BladeRF2Output::serialize() const
{
return m_settings.serialize();
}
bool BladeRF2Output::deserialize(const QByteArray& data)
{
bool success = true;
if (!m_settings.deserialize(data))
{
m_settings.resetToDefaults();
success = false;
}
MsgConfigureBladeRF2* message = MsgConfigureBladeRF2::create(m_settings, true);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureBladeRF2* messageToGUI = MsgConfigureBladeRF2::create(m_settings, true);
m_guiMessageQueue->push(messageToGUI);
}
return success;
}
const QString& BladeRF2Output::getDeviceDescription() const
{
return m_deviceDescription;
}
int BladeRF2Output::getSampleRate() const
{
int rate = m_settings.m_devSampleRate;
return (rate / (1<<m_settings.m_log2Interp));
}
quint64 BladeRF2Output::getCenterFrequency() const
{
return m_settings.m_centerFrequency;
}
void BladeRF2Output::setCenterFrequency(qint64 centerFrequency)
{
BladeRF2OutputSettings settings = m_settings;
settings.m_centerFrequency = centerFrequency;
MsgConfigureBladeRF2* message = MsgConfigureBladeRF2::create(settings, false);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureBladeRF2* messageToGUI = MsgConfigureBladeRF2::create(settings, false);
m_guiMessageQueue->push(messageToGUI);
}
}
void BladeRF2Output::getFrequencyRange(uint64_t& min, uint64_t& max, int& step)
{
if (m_deviceShared.m_dev) {
m_deviceShared.m_dev->getFrequencyRangeTx(min, max, step);
}
}
void BladeRF2Output::getSampleRateRange(int& min, int& max, int& step)
{
if (m_deviceShared.m_dev) {
m_deviceShared.m_dev->getSampleRateRangeTx(min, max, step);
}
}
void BladeRF2Output::getBandwidthRange(int& min, int& max, int& step)
{
if (m_deviceShared.m_dev) {
m_deviceShared.m_dev->getBandwidthRangeTx(min, max, step);
}
}
void BladeRF2Output::getGlobalGainRange(int& min, int& max, int& step)
{
if (m_deviceShared.m_dev) {
m_deviceShared.m_dev->getGlobalGainRangeTx(min, max, step);
}
}
bool BladeRF2Output::handleMessage(const Message& message)
{
if (MsgConfigureBladeRF2::match(message))
{
MsgConfigureBladeRF2& conf = (MsgConfigureBladeRF2&) message;
qDebug() << "BladeRF2Output::handleMessage: MsgConfigureBladeRF2";
if (!applySettings(conf.getSettings(), conf.getForce()))
{
qDebug("BladeRF2Output::handleMessage: MsgConfigureBladeRF2 config error");
}
return true;
}
else if (DeviceBladeRF2Shared::MsgReportBuddyChange::match(message))
{
DeviceBladeRF2Shared::MsgReportBuddyChange& report = (DeviceBladeRF2Shared::MsgReportBuddyChange&) message;
struct bladerf *dev = m_deviceShared.m_dev->getDev();
BladeRF2OutputSettings settings = m_settings;
int status;
unsigned int tmp_uint;
bool tmp_bool;
// evaluate changes that may have been introduced by changes in a buddy
if (dev) // The BladeRF device must have been open to do so
{
int requestedChannel = m_deviceAPI->getItemIndex();
if (report.getRxElseTx()) // Rx buddy change: check for sample rate change only
{
status = bladerf_get_sample_rate(dev, BLADERF_CHANNEL_TX(requestedChannel), &tmp_uint);
if (status < 0) {
qCritical("BladeRF2Output::handleMessage: MsgReportBuddyChange: bladerf_get_sample_rate error: %s", bladerf_strerror(status));
} else {
settings.m_devSampleRate = tmp_uint+1;
}
}
else // Tx buddy change: check for: frequency, gain mode and value, bias tee, sample rate, bandwidth
{
settings.m_devSampleRate = report.getDevSampleRate();
settings.m_centerFrequency = report.getCenterFrequency();
status = bladerf_get_bandwidth(dev, BLADERF_CHANNEL_TX(requestedChannel), &tmp_uint);
if (status < 0) {
qCritical("BladeRF2Output::handleMessage: MsgReportBuddyChange: bladerf_get_bandwidth error: %s", bladerf_strerror(status));
} else {
settings.m_bandwidth = tmp_uint;
}
status = bladerf_get_bias_tee(dev, BLADERF_CHANNEL_TX(requestedChannel), &tmp_bool);
if (status < 0) {
qCritical("BladeRF2Output::handleMessage: MsgReportBuddyChange: bladerf_get_bias_tee error: %s", bladerf_strerror(status));
} else {
settings.m_biasTee = tmp_bool;
}
}
// change DSP settings if buddy change introduced a change in center frequency or base rate
if ((settings.m_centerFrequency != m_settings.m_centerFrequency) || (settings.m_devSampleRate != m_settings.m_devSampleRate))
{
int sampleRate = settings.m_devSampleRate/(1<<settings.m_log2Interp);
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, settings.m_centerFrequency);
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
}
m_settings = settings; // acknowledge the new settings
// propagate settings to GUI if any
if (getMessageQueueToGUI())
{
MsgConfigureBladeRF2 *reportToGUI = MsgConfigureBladeRF2::create(m_settings, false);
getMessageQueueToGUI()->push(reportToGUI);
}
}
return true;
}
else if (MsgStartStop::match(message))
{
MsgStartStop& cmd = (MsgStartStop&) message;
qDebug() << "BladeRF2Input::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
if (cmd.getStartStop())
{
if (m_deviceAPI->initGeneration())
{
m_deviceAPI->startGeneration();
}
}
else
{
m_deviceAPI->stopGeneration();
}
return true;
}
else
{
return false;
}
}
bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool force)
{
bool forwardChangeOwnDSP = false;
bool forwardChangeRxBuddies = false;
bool forwardChangeTxBuddies = false;
struct bladerf *dev = m_deviceShared.m_dev->getDev();
int requestedChannel = m_deviceAPI->getItemIndex();
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
{
forwardChangeOwnDSP = true;
forwardChangeRxBuddies = true;
forwardChangeTxBuddies = true;
if (dev != 0)
{
unsigned int actualSamplerate;
int status = bladerf_set_sample_rate(dev, BLADERF_CHANNEL_TX(requestedChannel), settings.m_devSampleRate, &actualSamplerate);
if (status < 0)
{
qCritical("BladeRF2Output::applySettings: could not set sample rate: %d: %s",
settings.m_devSampleRate, bladerf_strerror(status));
}
else
{
qDebug() << "BladeRF2Output::applySettings: bladerf_set_sample_rate(BLADERF_MODULE_RX) actual sample rate is " << actualSamplerate;
}
}
}
if ((m_settings.m_bandwidth != settings.m_bandwidth) || force)
{
forwardChangeTxBuddies = true;
if (dev != 0)
{
unsigned int actualBandwidth;
int status = bladerf_set_bandwidth(dev, BLADERF_CHANNEL_TX(requestedChannel), settings.m_bandwidth, &actualBandwidth);
if(status < 0)
{
qCritical("BladeRF2Output::applySettings: could not set bandwidth: %d: %s",
settings.m_bandwidth, bladerf_strerror(status));
}
else
{
qDebug() << "BladeRF2Output::applySettings: bladerf_set_bandwidth(BLADERF_MODULE_RX) actual bandwidth is " << actualBandwidth;
}
}
}
if ((m_settings.m_log2Interp != settings.m_log2Interp) || force)
{
forwardChangeOwnDSP = true;
BladeRF2OutputThread *outputThread = findThread();
if (outputThread != 0)
{
outputThread->setLog2Interpolation(requestedChannel, settings.m_log2Interp);
qDebug() << "BladeRF2Output::applySettings: set interpolation to " << (1<<settings.m_log2Interp);
}
}
if ((m_settings.m_centerFrequency != settings.m_centerFrequency)
|| (m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
{
forwardChangeOwnDSP = true;
forwardChangeTxBuddies = true;
if (dev != 0)
{
int status = bladerf_set_frequency(dev, BLADERF_CHANNEL_TX(requestedChannel), settings.m_centerFrequency);
if (status < 0) {
qWarning("BladeRF2Output::applySettings: bladerf_set_frequency(%lld) failed: %s",
settings.m_centerFrequency, bladerf_strerror(status));
}
else
{
qDebug("BladeRF2Output::applySettings: bladerf_set_frequency(%lld)", settings.m_centerFrequency);
if (getMessageQueueToGUI())
{
int min, max, step;
getGlobalGainRange(min, max, step);
MsgReportGainRange *msg = MsgReportGainRange::create(min, max, step);
getMessageQueueToGUI()->push(msg);
}
}
}
}
if ((m_settings.m_biasTee != settings.m_biasTee) || force)
{
forwardChangeTxBuddies = true;
m_deviceShared.m_dev->setBiasTeeTx(settings.m_biasTee);
}
if ((m_settings.m_gainMode != settings.m_gainMode) || force)
{
forwardChangeTxBuddies = true;
if (dev)
{
int status = bladerf_set_gain_mode(dev, BLADERF_CHANNEL_TX(requestedChannel), (bladerf_gain_mode) settings.m_gainMode);
if (status < 0) {
qWarning("BladeRF2Output::applySettings: bladerf_set_gain_mode(%d) failed: %s",
settings.m_gainMode, bladerf_strerror(status));
} else {
qDebug("BladeRF2Output::applySettings: bladerf_set_gain_mode(%d)", settings.m_gainMode);
}
}
}
if ((m_settings.m_globalGain != settings.m_globalGain)
|| ((m_settings.m_gainMode != settings.m_gainMode) && (settings.m_gainMode == BLADERF_GAIN_MANUAL)) || force)
{
forwardChangeTxBuddies = true;
if (dev)
{
// qDebug("BladeRF2Output::applySettings: channel: %d gain: %d", requestedChannel, settings.m_globalGain);
int status = bladerf_set_gain(dev, BLADERF_CHANNEL_TX(requestedChannel), settings.m_globalGain);
if (status < 0) {
qWarning("BladeRF2Output::applySettings: bladerf_set_gain(%d) failed: %s",
settings.m_globalGain, bladerf_strerror(status));
} else {
qDebug("BladeRF2Output::applySettings: bladerf_set_gain(%d)", settings.m_globalGain);
}
}
}
if (forwardChangeOwnDSP)
{
int sampleRate = settings.m_devSampleRate/(1<<settings.m_log2Interp);
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, settings.m_centerFrequency);
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
}
if (forwardChangeRxBuddies)
{
// send to source buddies
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
std::vector<DeviceSourceAPI*>::const_iterator itSource = sourceBuddies.begin();
for (; itSource != sourceBuddies.end(); ++itSource)
{
DeviceBladeRF2Shared::MsgReportBuddyChange *report = DeviceBladeRF2Shared::MsgReportBuddyChange::create(
settings.m_centerFrequency,
0,
settings.m_devSampleRate,
false);
(*itSource)->getSampleSourceInputMessageQueue()->push(report);
}
}
if (forwardChangeTxBuddies)
{
// send to sink buddies
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
std::vector<DeviceSinkAPI*>::const_iterator itSink = sinkBuddies.begin();
for (; itSink != sinkBuddies.end(); ++itSink)
{
DeviceBladeRF2Shared::MsgReportBuddyChange *report = DeviceBladeRF2Shared::MsgReportBuddyChange::create(
settings.m_centerFrequency,
0,
settings.m_devSampleRate,
false);
(*itSink)->getSampleSinkInputMessageQueue()->push(report);
}
}
m_settings = settings;
qDebug() << "BladeRF2Output::applySettings: "
<< " m_centerFrequency: " << m_settings.m_centerFrequency << " Hz"
<< " m_bandwidth: " << m_settings.m_bandwidth
<< " m_log2Interp: " << m_settings.m_log2Interp
<< " m_devSampleRate: " << m_settings.m_devSampleRate
<< " m_globalGain: " << m_settings.m_globalGain
<< " m_gainMode: " << m_settings.m_gainMode
<< " m_biasTee: " << m_settings.m_biasTee;
return true;
}
int BladeRF2Output::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
{
response.setBladeRf2OutputSettings(new SWGSDRangel::SWGBladeRF2OutputSettings());
response.getBladeRf2OutputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int BladeRF2Output::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
{
BladeRF2OutputSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
settings.m_centerFrequency = response.getBladeRf2OutputSettings()->getCenterFrequency();
}
if (deviceSettingsKeys.contains("devSampleRate")) {
settings.m_devSampleRate = response.getBladeRf2OutputSettings()->getDevSampleRate();
}
if (deviceSettingsKeys.contains("bandwidth")) {
settings.m_bandwidth = response.getBladeRf2OutputSettings()->getBandwidth();
}
if (deviceSettingsKeys.contains("log2Interp")) {
settings.m_log2Interp = response.getBladeRf2OutputSettings()->getLog2Interp();
}
if (deviceSettingsKeys.contains("biasTee")) {
settings.m_biasTee = response.getBladeRf2OutputSettings()->getBiasTee() != 0;
}
if (deviceSettingsKeys.contains("gainMode")) {
settings.m_gainMode = response.getBladeRf2OutputSettings()->getGainMode();
}
if (deviceSettingsKeys.contains("globalGain")) {
settings.m_globalGain = response.getBladeRf2OutputSettings()->getGlobalGain();
}
MsgConfigureBladeRF2 *msg = MsgConfigureBladeRF2::create(settings, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureBladeRF2 *msgToGUI = MsgConfigureBladeRF2::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatDeviceSettings(response, settings);
return 200;
}
int BladeRF2Output::webapiReportGet(SWGSDRangel::SWGDeviceReport& response, QString& errorMessage __attribute__((unused)))
{
response.setBladeRf2OutputReport(new SWGSDRangel::SWGBladeRF2OutputReport());
response.getBladeRf2OutputReport()->init();
webapiFormatDeviceReport(response);
return 200;
}
void BladeRF2Output::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF2OutputSettings& settings)
{
response.getBladeRf2OutputSettings()->setCenterFrequency(settings.m_centerFrequency);
response.getBladeRf2OutputSettings()->setDevSampleRate(settings.m_devSampleRate);
response.getBladeRf2OutputSettings()->setBandwidth(settings.m_bandwidth);
response.getBladeRf2OutputSettings()->setLog2Interp(settings.m_log2Interp);
response.getBladeRf2OutputSettings()->setBiasTee(settings.m_biasTee ? 1 : 0);
response.getBladeRf2OutputSettings()->setGainMode(settings.m_gainMode);
response.getBladeRf2OutputSettings()->setGlobalGain(settings.m_globalGain);
}
void BladeRF2Output::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response)
{
DeviceBladeRF2 *device = m_deviceShared.m_dev;
if (device)
{
int min, max, step;
uint64_t f_min, f_max;
device->getBandwidthRangeTx(min, max, step);
response.getBladeRf2OutputReport()->setBandwidthRange(new SWGSDRangel::SWGRange);
response.getBladeRf2OutputReport()->getBandwidthRange()->setMin(min);
response.getBladeRf2OutputReport()->getBandwidthRange()->setMax(max);
response.getBladeRf2OutputReport()->getBandwidthRange()->setStep(step);
device->getFrequencyRangeTx(f_min, f_max, step);
response.getBladeRf2OutputReport()->setFrequencyRange(new SWGSDRangel::SWGFrequencyRange);
response.getBladeRf2OutputReport()->getFrequencyRange()->setMin(f_min);
response.getBladeRf2OutputReport()->getFrequencyRange()->setMax(f_max);
response.getBladeRf2OutputReport()->getFrequencyRange()->setStep(step);
device->getGlobalGainRangeTx(min, max, step);
response.getBladeRf2OutputReport()->setGlobalGainRange(new SWGSDRangel::SWGRange);
response.getBladeRf2OutputReport()->getGlobalGainRange()->setMin(min);
response.getBladeRf2OutputReport()->getGlobalGainRange()->setMax(max);
response.getBladeRf2OutputReport()->getGlobalGainRange()->setStep(step);
device->getSampleRateRangeTx(min, max, step);
response.getBladeRf2OutputReport()->setSampleRateRange(new SWGSDRangel::SWGRange);
response.getBladeRf2OutputReport()->getSampleRateRange()->setMin(min);
response.getBladeRf2OutputReport()->getSampleRateRange()->setMax(max);
response.getBladeRf2OutputReport()->getSampleRateRange()->setStep(step);
response.getBladeRf2OutputReport()->setGainModes(new QList<SWGSDRangel::SWGNamedEnum*>);
const std::vector<GainMode>& modes = getGainModes();
std::vector<GainMode>::const_iterator it = modes.begin();
for (; it != modes.end(); ++it)
{
response.getBladeRf2OutputReport()->getGainModes()->append(new SWGSDRangel::SWGNamedEnum);
response.getBladeRf2OutputReport()->getGainModes()->back()->setName(new QString(it->m_name));
response.getBladeRf2OutputReport()->getGainModes()->back()->setValue(it->m_value);
}
}
}
int BladeRF2Output::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
{
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
int BladeRF2Output::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;
}

View File

@ -0,0 +1,176 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUT_H_
#define PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUT_H_
#include <QString>
#include <libbladeRF.h>
#include "dsp/devicesamplesink.h"
#include "bladerf2/devicebladerf2shared.h"
#include "bladerf2outputsettings.h"
class DeviceSinkAPI;
class BladeRF2OutputThread;
struct bladerf_gain_modes;
class BladeRF2Output : public DeviceSampleSink {
public:
class MsgConfigureBladeRF2 : public Message {
MESSAGE_CLASS_DECLARATION
public:
const BladeRF2OutputSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureBladeRF2* create(const BladeRF2OutputSettings& settings, bool force)
{
return new MsgConfigureBladeRF2(settings, force);
}
private:
BladeRF2OutputSettings m_settings;
bool m_force;
MsgConfigureBladeRF2(const BladeRF2OutputSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
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)
{ }
};
class MsgReportGainRange : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getMin() const { return m_min; }
int getMax() const { return m_max; }
int getStep() const { return m_step; }
static MsgReportGainRange* create(int min, int max, int step) {
return new MsgReportGainRange(min, max, step);
}
protected:
int m_min;
int m_max;
int m_step;
MsgReportGainRange(int min, int max, int step) :
Message(),
m_min(min),
m_max(max),
m_step(step)
{}
};
struct GainMode
{
QString m_name;
int m_value;
};
BladeRF2Output(DeviceSinkAPI *deviceAPI);
virtual ~BladeRF2Output();
virtual void destroy();
virtual void init();
virtual bool start();
virtual void stop();
BladeRF2OutputThread *getThread() { return m_thread; }
void setThread(BladeRF2OutputThread *thread) { m_thread = thread; }
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);
void getFrequencyRange(uint64_t& min, uint64_t& max, int& step);
void getSampleRateRange(int& min, int& max, int& step);
void getBandwidthRange(int& min, int& max, int& step);
void getGlobalGainRange(int& min, int& max, int& step);
const std::vector<GainMode>& getGainModes() { return m_gainModes; }
virtual bool handleMessage(const Message& message);
virtual int webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage);
virtual int webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
private:
bool openDevice();
void closeDevice();
BladeRF2OutputThread *findThread();
void moveThreadToBuddy();
bool applySettings(const BladeRF2OutputSettings& settings, bool force);
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF2OutputSettings& settings);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
DeviceSinkAPI *m_deviceAPI;
QMutex m_mutex;
BladeRF2OutputSettings m_settings;
struct bladerf* m_dev;
BladeRF2OutputThread* m_thread;
QString m_deviceDescription;
DeviceBladeRF2Shared m_deviceShared;
bool m_running;
std::vector<GainMode> m_gainModes;
};
#endif /* PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUT_H_ */

View File

@ -0,0 +1,464 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Bladerf2OutputGui</class>
<widget class="QWidget" name="Bladerf2OutputGui">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<height>200</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>350</width>
<height>200</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>BladeRF2</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>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="deviceRateLayout">
<item>
<widget class="QLabel" name="deviceRateLabel">
<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>Liberation 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>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_corr">
<item row="0" column="3">
<widget class="QLabel" name="bandwidthUnit">
<property name="text">
<string>kHz</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="bandwidthLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>BW </string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="ValueDial" name="bandwidth" 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>Liberation Mono</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>RF bandwidth</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="ButtonSwitch" name="biasTee">
<property name="toolTip">
<string>Bias Tee</string>
</property>
<property name="text">
<string>BT</string>
</property>
</widget>
</item>
<item row="0" column="4">
<spacer name="horizontalSpacer_2">
<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="sampleRateLayout">
<property name="topMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<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>SR</string>
</property>
</widget>
</item>
<item>
<widget class="ValueDial" name="sampleRate" 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>Liberation Mono</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Device sample rate</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="samplerateUnit">
<property name="text">
<string>S/s</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<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>I</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>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_decim" columnstretch="0,0,0,0">
<property name="spacing">
<number>3</number>
</property>
<item row="0" column="2">
<widget class="QSlider" name="gain">
<property name="toolTip">
<string>Gain value</string>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gainMode">
<property name="toolTip">
<string>Gain mode</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="gainLabel">
<property name="text">
<string>Gain</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="gainText">
<property name="minimumSize">
<size>
<width>45</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>000 dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_lna">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="padLayout">
<item>
<spacer name="verticalPadSpacer">
<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>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,157 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <libbladeRF.h>
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "device/devicesourceapi.h"
#include "bladerf2outputplugin.h"
#ifdef SERVER_MODE
#include "bladerf2output.h"
#else
#include "bladerf2outputgui.h"
#endif
const PluginDescriptor Bladerf2OutputPlugin::m_pluginDescriptor = {
QString("BladeRF2 Output"),
QString("4.2.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
const QString Bladerf2OutputPlugin::m_hardwareID = "BladeRF2";
const QString Bladerf2OutputPlugin::m_deviceTypeID = BLADERF2OUTPUT_DEVICE_TYPE_ID;
Bladerf2OutputPlugin::Bladerf1OutputPlugin(QObject* parent) :
QObject(parent)
{
}
const PluginDescriptor& Bladerf2OutputPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void Bladerf2OutputPlugin::initPlugin(PluginAPI* pluginAPI)
{
pluginAPI->registerSampleSink(m_deviceTypeID, this);
}
PluginInterface::SamplingDevices Bladerf2OutputPlugin::enumSampleSinks()
{
SamplingDevices result;
struct bladerf_devinfo *devinfo = 0;
int count = bladerf_get_device_list(&devinfo);
if (devinfo)
{
for(int i = 0; i < count; i++)
{
struct bladerf *dev;
int status = bladerf_open_with_devinfo(&dev, &devinfo[i]);
if (status == BLADERF_ERR_NODEV)
{
qCritical("Bladerf2OutputPlugin::enumSampleSinks: No device at index %d", i);
continue;
}
else if (status != 0)
{
qCritical("Bladerf2OutputPlugin::enumSampleSinks: Failed to open device at index %d", i);
continue;
}
const char *boardName = bladerf_get_board_name(dev);
if (strcmp(boardName, "bladerf2") == 0)
{
unsigned int nbTxChannels = bladerf_get_channel_count(dev, BLADERF_TX);
for (unsigned int j = 0; j < nbTxChannels; j++)
{
qDebug("Blderf2InputPlugin::enumSampleSinks: device #%d (%s) channel %u", i, devinfo[i].serial, j);
QString displayedName(QString("BladeRF2[%1:%2] %3").arg(devinfo[i].instance).arg(j).arg(devinfo[i].serial));
result.append(SamplingDevice(displayedName,
m_hardwareID,
m_deviceTypeID,
QString(devinfo[i].serial),
i,
PluginInterface::SamplingDevice::PhysicalDevice,
false,
nbTxChannels,
j));
}
}
bladerf_close(dev);
}
bladerf_free_device_list(devinfo); // Valgrind memcheck
}
return result;
}
#ifdef SERVER_MODE
PluginInstanceGUI* Bladerf2OutputPlugin::createSampleSinkPluginInstanceGUI(
const QString& sinkId __attribute__((unused)),
QWidget **widget __attribute__((unused)),
DeviceUISet *deviceUISet __attribute__((unused)))
{
return 0;
}
#else
PluginInstanceGUI* Bladerf2OutputPlugin::createSampleSinkPluginInstanceGUI(
const QString& sinkId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
if(sinkId == m_deviceTypeID)
{
Bladerf2OutputGui* gui = new Bladerf2OutputGui(deviceUISet);
*widget = gui;
return gui;
}
else
{
return 0;
}
}
#endif
DeviceSampleSink* Bladerf2OutputPlugin::createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI)
{
if(sinkId == m_deviceTypeID)
{
Bladerf2Output* output = new Bladerf2Output(deviceAPI);
return output;
}
else
{
return 0;
}
}

View File

@ -0,0 +1,54 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTPLUGIN_H_
#define PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTPLUGIN_H_
#include <QObject>
#include "plugin/plugininterface.h"
class PluginAPI;
#define BLADERF2OUTPUT_DEVICE_TYPE_ID "sdrangel.samplesource.bladerf2output"
class Bladerf2OutputPlugin : public QObject, public PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID BLADERF2OUTPUT_DEVICE_TYPE_ID)
public:
explicit Bladerf2OutputPlugin(QObject* parent = 0);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual SamplingDevices enumSampleSinks();
virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(
const QString& sinkId,
QWidget **widget,
DeviceUISet *deviceUISet);
virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI);
static const QString m_hardwareID;
static const QString m_deviceTypeID;
private:
static const PluginDescriptor m_pluginDescriptor;
};
#endif /* PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTPLUGIN_H_ */

View File

@ -0,0 +1,85 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 "bladerf2outputsettings.h"
#include <QtGlobal>
#include "util/simpleserializer.h"
BladeRF2OutputSettings::BladeRF2OutputSettings()
{
resetToDefaults();
}
void BladeRF2OutputSettings::resetToDefaults()
{
m_centerFrequency = 435000*1000;
m_devSampleRate = 3072000;
m_bandwidth = 1500000;
m_gainMode = 0;
m_globalGain = 0;
m_biasTee = false;
m_log2Interp = 0;
}
QByteArray BladeRF2OutputSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_devSampleRate);
s.writeS32(2, m_bandwidth);
s.writeS32(3, m_gainMode);
s.writeS32(4, m_globalGain);
s.writeBool(5, m_biasTee);
s.writeU32(6, m_log2Interp);
return s.final();
}
bool BladeRF2OutputSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
int intval;
d.readS32(1, &m_devSampleRate);
d.readS32(2, &m_bandwidth);
d.readS32(3, &m_gainMode);
d.readS32(4, &m_globalGain);
d.readBool(5, &m_biasTee);
d.readU32(6, &m_log2Interp);
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

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

View File

@ -0,0 +1,223 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <algorithm>
#include "dsp/samplesourcefifo.h"
#include "bladerf2outputthread.h"
BladeRF2OutputThread::BladeRF2OutputThread(struct bladerf* dev, unsigned int nbTxChannels, QObject* parent) :
QThread(parent),
m_running(false),
m_dev(dev),
m_nbChannels(nbTxChannels)
{
qDebug("BladeRF2OutputThread::BladeRF2OutputThread");
m_channels = new Channel[nbTxChannels];
m_buf = new qint16[2*DeviceBladeRF2::blockSize*nbTxChannels];
}
BladeRF2OutputThread::~BladeRF2OutputThread()
{
qDebug("BladeRF2OutputThread::~BladeRF2OutputThread");
if (m_running) {
stopWork();
}
delete[] m_buf;
delete[] m_channels;
}
void BladeRF2OutputThread::startWork()
{
m_startWaitMutex.lock();
start();
while(!m_running) {
m_startWaiter.wait(&m_startWaitMutex, 100);
}
m_startWaitMutex.unlock();
}
void BladeRF2OutputThread::stopWork()
{
m_running = false;
wait();
}
void BladeRF2OutputThread::run()
{
int res;
m_running = true;
m_startWaiter.wakeAll();
unsigned int nbFifos = getNbFifos();
if ((m_nbChannels > 0) && (nbFifos > 0))
{
int status;
if (m_nbChannels > 1) {
status = bladerf_sync_config(m_dev, BLADERF_TX_X2, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000);
} else {
status = bladerf_sync_config(m_dev, BLADERF_TX_X1, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000);
}
if (status < 0)
{
qCritical("BladeRF2OutputThread::run: cannot configure streams: %s", bladerf_strerror(status));
}
else
{
qDebug("BladeRF2OutputThread::run: start running loop");
while (m_running)
{
if (m_nbChannels > 1) {
callbackMO(m_buf, DeviceBladeRF2::blockSize);
} else {
callbackSO(m_buf, 2*DeviceBladeRF2::blockSize);
}
res = bladerf_sync_tx(m_dev, m_buf, DeviceBladeRF2::blockSize, NULL, 10000);
if (res < 0)
{
qCritical("BladeRF2OutputThread::run sync Rx error: %s", bladerf_strerror(res));
break;
}
}
qDebug("BladeRF2OutputThread::run: stop running loop");
}
}
else
{
qWarning("BladeRF2OutputThread::run: no channels or FIFO allocated. Aborting");
}
m_running = false;
}
unsigned int BladeRF2OutputThread::getNbFifos()
{
unsigned int fifoCount = 0;
for (unsigned int i = 0; i < m_nbChannels; i++)
{
if (m_channels[i].m_sampleFifo) {
fifoCount++;
}
}
return fifoCount;
}
void BladeRF2OutputThread::setLog2Interpolation(unsigned int channel, unsigned int log2_interp)
{
if (channel < m_nbChannels) {
m_channels[channel].m_log2Interp = log2_interp;
}
}
unsigned int BladeRF2OutputThread::getLog2Interpolation(unsigned int channel) const
{
if (channel < m_nbChannels) {
return m_channels[channel].m_log2Interp;
} else {
return 0;
}
}
void BladeRF2OutputThread::setFifo(unsigned int channel, SampleSourceFifo *sampleFifo)
{
if (channel < m_nbChannels) {
m_channels[channel].m_sampleFifo = sampleFifo;
}
}
SampleSourceFifo *BladeRF2OutputThread::getFifo(unsigned int channel)
{
if (channel < m_nbChannels) {
return m_channels[channel].m_sampleFifo;
} else {
return 0;
}
}
void BladeRF2OutputThread::callbackMO(qint16* buf, qint32 samplesPerChannel)
{
for (unsigned int channel = 0; channel < m_nbChannels; channel++)
{
if (m_channels[channel].m_sampleFifo) {
callbackSO(&buf[2*samplesPerChannel*channel], 2*samplesPerChannel, channel);
} else {
std::fill(&buf[2*samplesPerChannel*channel], &buf[2*samplesPerChannel*channel]+2*samplesPerChannel, 0); // fill with zero samples
}
}
// TODO: write a set of interpolators that can write interleaved samples in output directly
int status = bladerf_interleave_stream_buffer(BLADERF_TX_X2, BLADERF_FORMAT_SC16_Q11 , samplesPerChannel*m_nbChannels, (void *) buf);
if (status < 0)
{
qCritical("BladeRF2OutputThread::callbackMI: cannot interleave buffer: %s", bladerf_strerror(status));
return;
}
}
// Interpolate according to specified log2 (ex: log2=4 => decim=16)
void BladeRF2OutputThread::callbackSO(qint16* buf, qint32 len, unsigned int channel)
{
SampleVector::iterator beginRead;
m_channels[channel].m_sampleFifo->readAdvance(beginRead, len/(1<<m_channels[channel].m_log2Interp));
beginRead -= len;
if (m_channels[channel].m_log2Interp == 0)
{
m_channels[channel].m_interpolators.interpolate1(&beginRead, buf, len*2);
}
else
{
switch (m_channels[channel].m_log2Interp)
{
case 1:
m_channels[channel].m_interpolators.interpolate2_cen(&beginRead, buf, len*2);
break;
case 2:
m_channels[channel].m_interpolators.interpolate4_cen(&beginRead, buf, len*2);
break;
case 3:
m_channels[channel].m_interpolators.interpolate8_cen(&beginRead, buf, len*2);
break;
case 4:
m_channels[channel].m_interpolators.interpolate16_cen(&beginRead, buf, len*2);
break;
case 5:
m_channels[channel].m_interpolators.interpolate32_cen(&beginRead, buf, len*2);
break;
case 6:
m_channels[channel].m_interpolators.interpolate64_cen(&beginRead, buf, len*2);
break;
default:
break;
}
}
}

View File

@ -0,0 +1,81 @@
///////////////////////////////////////////////////////////////////////////////////
// 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_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTTHREAD_H_
#define PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTTHREAD_H_
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <libbladeRF.h>
#include "bladerf2/devicebladerf2shared.h"
#include "dsp/interpolators.h"
class SampleSinkFifo;
class BladeRF2OutputThread : public QThread {
Q_OBJECT
public:
BladeRF2OutputThread(struct bladerf* dev, unsigned int nbTxChannels, QObject* parent = 0);
~BladeRF2OutputThread();
void startWork();
void stopWork();
bool isRunning() const { return m_running; }
unsigned int getNbChannels() const { return m_nbChannels; }
void setLog2Interpolation(unsigned int channel, unsigned int log2_interp);
unsigned int getLog2Interpolation(unsigned int channel) const;
void setFcPos(unsigned int channel, int fcPos);
int getFcPos(unsigned int channel) const;
void setFifo(unsigned int channel, SampleSourceFifo *sampleFifo);
SampleSourceFifo *getFifo(unsigned int channel);
private:
struct Channel
{
SampleSourceFifo* m_sampleFifo;
unsigned int m_log2Interp;
Interpolators<qint16, SDR_TX_SAMP_SZ, 12> m_interpolators;
Channel() :
m_sampleFifo(0),
m_log2Interp(0)
{}
~Channel()
{}
};
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
struct bladerf* m_dev;
Channel *m_channels; //!< Array of channels dynamically allocated for the given number of Rx channels
qint16 *m_buf; //!< Full buffer for SISO or MIMO operation
unsigned int m_nbChannels;
void run();
unsigned int getNbFifos();
void callbackSO(qint16* buf, qint32 len, unsigned int channel = 0);
void callbackMO(qint16* buf, qint32 samplesPerChannel);
};
#endif /* PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTTHREAD_H_ */

View File

@ -96,7 +96,6 @@ bool BladeRF2Input::openDevice()
}
// look for Rx buddies and get reference to the device object
// if there is a channel left take the first available
if (m_deviceAPI->getSourceBuddies().size() > 0) // look source sibling first
{
qDebug("BladeRF2Input::openDevice: look in Rx buddies");
@ -121,7 +120,6 @@ bool BladeRF2Input::openDevice()
m_deviceShared.m_dev = device;
}
// look for Tx buddies and get reference to the device object
// allocate the Rx channel unconditionally
else if (m_deviceAPI->getSinkBuddies().size() > 0) // then sink
{
qDebug("BladeRF2Input::openDevice: look in Tx buddies");
@ -139,14 +137,13 @@ bool BladeRF2Input::openDevice()
if (device == 0)
{
qCritical("BladeRF2Input::openDevice: cannot get device pointer from Rx buddy");
qCritical("BladeRF2Input::openDevice: cannot get device pointer from Tx buddy");
return false;
}
m_deviceShared.m_dev = device;
}
// There are no buddies then create the first BladeRF2 device
// allocate the Rx channel unconditionally
else
{
qDebug("BladeRF2Input::openDevice: open device here");
@ -283,7 +280,7 @@ bool BladeRF2Input::start()
if (!m_deviceShared.m_dev)
{
qDebug("BladerfInput::start: no device object");
qDebug("BladeRF2Input::start: no device object");
return false;
}
@ -293,13 +290,13 @@ bool BladeRF2Input::start()
if (bladerf2InputThread) // if thread is already allocated
{
qDebug("BladerfInput::start: thread is already allocated");
qDebug("BladeRF2Input::start: thread is already allocated");
int nbOriginalChannels = bladerf2InputThread->getNbChannels();
if (requestedChannel+1 > nbOriginalChannels) // expansion by deleting and re-creating the thread
{
qDebug("BladerfInput::start: expand channels. Re-allocate thread and take ownership");
qDebug("BladeRF2Input::start: expand channels. Re-allocate thread and take ownership");
SampleSinkFifo **fifos = new SampleSinkFifo*[nbOriginalChannels];
unsigned int *log2Decims = new unsigned int[nbOriginalChannels];
@ -336,12 +333,12 @@ bool BladeRF2Input::start()
}
else
{
qDebug("BladerfInput::start: keep buddy thread");
qDebug("BladeRF2Input::start: keep buddy thread");
}
}
else // first allocation
{
qDebug("BladerfInput::start: allocate thread and take ownership");
qDebug("BladeRF2Input::start: allocate thread and take ownership");
bladerf2InputThread = new BladeRF2InputThread(m_deviceShared.m_dev->getDev(), requestedChannel+1);
m_thread = bladerf2InputThread; // take ownership
needsStart = true;
@ -353,7 +350,7 @@ bool BladeRF2Input::start()
if (needsStart)
{
qDebug("BladerfInput::start: enabling channel(s) and (re)sart buddy thread");
qDebug("BladeRF2Input::start: enabling channel(s) and (re)sart buddy thread");
int nbChannels = bladerf2InputThread->getNbChannels();

View File

@ -14,6 +14,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsp/samplesinkfifo.h"
#include "bladerf2inputthread.h"
BladeRF2InputThread::BladeRF2InputThread(struct bladerf* dev, unsigned int nbRxChannels, QObject* parent) :

View File

@ -29,9 +29,10 @@
#include <libbladeRF.h>
#include "bladerf2/devicebladerf2shared.h"
#include "dsp/samplesinkfifo.h"
#include "dsp/decimators.h"
class SampleSinkFifo;
class BladeRF2InputThread : public QThread {
Q_OBJECT
@ -39,16 +40,16 @@ public:
BladeRF2InputThread(struct bladerf* dev, unsigned int nbRxChannels, QObject* parent = NULL);
~BladeRF2InputThread();
virtual void startWork();
virtual void stopWork();
virtual bool isRunning() const { return m_running; }
virtual unsigned int getNbChannels() const { return m_nbChannels; }
virtual void setLog2Decimation(unsigned int channel, unsigned int log2_decim);
virtual unsigned int getLog2Decimation(unsigned int channel) const;
virtual void setFcPos(unsigned int channel, int fcPos);
virtual int getFcPos(unsigned int channel) const;
virtual void setFifo(unsigned int channel, SampleSinkFifo *sampleFifo);
virtual SampleSinkFifo *getFifo(unsigned int channel);
void startWork();
void stopWork();
bool isRunning() const { return m_running; }
unsigned int getNbChannels() const { return m_nbChannels; }
void setLog2Decimation(unsigned int channel, unsigned int log2_decim);
unsigned int getLog2Decimation(unsigned int channel) const;
void setFcPos(unsigned int channel, int fcPos);
int getFcPos(unsigned int channel) const;
void setFifo(unsigned int channel, SampleSinkFifo *sampleFifo);
SampleSinkFifo *getFifo(unsigned int channel);
private:
struct Channel

View File

@ -1363,6 +1363,56 @@ margin-bottom: 20px;
}
},
"description" : "BladeRF2"
};
defs.BladeRF2OutputReport = {
"properties" : {
"frequencyRange" : {
"$ref" : "#/definitions/FrequencyRange"
},
"sampleRateRange" : {
"$ref" : "#/definitions/Range"
},
"bandwidthRange" : {
"$ref" : "#/definitions/Range"
},
"globalGainRange" : {
"$ref" : "#/definitions/Range"
},
"gainModes" : {
"type" : "array",
"items" : {
"$ref" : "#/definitions/NamedEnum"
}
}
},
"description" : "BladeRF2"
};
defs.BladeRF2OutputSettings = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "int64"
},
"devSampleRate" : {
"type" : "integer"
},
"bandwidth" : {
"type" : "integer"
},
"gainMode" : {
"type" : "integer"
},
"globalGain" : {
"type" : "integer"
},
"biasTee" : {
"type" : "integer"
},
"log2Interp" : {
"type" : "integer"
}
},
"description" : "BladeRF2"
};
defs.CWKeyerSettings = {
"properties" : {
@ -1903,6 +1953,9 @@ margin-bottom: 20px;
"bladeRF2InputReport" : {
"$ref" : "#/definitions/BladeRF2InputReport"
},
"bladeRF2OutputReport" : {
"$ref" : "#/definitions/BladeRF2OutputReport"
},
"fileSourceReport" : {
"$ref" : "#/definitions/FileSourceReport"
},
@ -2003,6 +2056,9 @@ margin-bottom: 20px;
"bladeRF1OutputSettings" : {
"$ref" : "#/definitions/BladeRF1OutputSettings"
},
"bladeRF2OutputSettings" : {
"$ref" : "#/definitions/BladeRF2OutputSettings"
},
"fcdProSettings" : {
"$ref" : "#/definitions/FCDProSettings"
},
@ -23175,7 +23231,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2018-09-25T16:51:16.493+02:00
Generated 2018-09-29T05:36:53.044+02:00
</div>
</div>
</div>

View File

@ -40,3 +40,38 @@ BladeRF2InputReport:
type: array
items:
$ref: "/doc/swagger/include/Structs.yaml#/NamedEnum"
BladeRF2OutputSettings:
description: BladeRF2
properties:
centerFrequency:
type: integer
format: int64
devSampleRate:
type: integer
bandwidth:
type: integer
gainMode:
type: integer
globalGain:
type: integer
biasTee:
type: integer
log2Interp:
type: integer
BladeRF2OutputReport:
description: BladeRF2
properties:
frequencyRange:
$ref: "/doc/swagger/include/Structs.yaml#/FrequencyRange"
sampleRateRange:
$ref: "/doc/swagger/include/Structs.yaml#/Range"
bandwidthRange:
$ref: "/doc/swagger/include/Structs.yaml#/Range"
globalGainRange:
$ref: "/doc/swagger/include/Structs.yaml#/Range"
gainModes:
type: array
items:
$ref: "/doc/swagger/include/Structs.yaml#/NamedEnum"

View File

@ -1769,6 +1769,8 @@ definitions:
$ref: "/doc/swagger/include/BladeRF2.yaml#/BladeRF2InputSettings"
bladeRF1OutputSettings:
$ref: "/doc/swagger/include/BladeRF1.yaml#/BladeRF1OutputSettings"
bladeRF2OutputSettings:
$ref: "/doc/swagger/include/BladeRF2.yaml#/BladeRF2OutputSettings"
fcdProSettings:
$ref: "/doc/swagger/include/FCDPro.yaml#/FCDProSettings"
fcdProPlusSettings:
@ -1820,6 +1822,8 @@ definitions:
$ref: "/doc/swagger/include/AirspyHF.yaml#/AirspyHFReport"
bladeRF2InputReport:
$ref: "/doc/swagger/include/BladeRF2.yaml#/BladeRF2InputReport"
bladeRF2OutputReport:
$ref: "/doc/swagger/include/BladeRF2.yaml#/BladeRF2OutputReport"
fileSourceReport:
$ref: "/doc/swagger/include/FileSource.yaml#/FileSourceReport"
limeSdrInputReport:

View File

@ -40,3 +40,38 @@ BladeRF2InputReport:
type: array
items:
$ref: "http://localhost:8081/api/swagger/include/Structs.yaml#/NamedEnum"
BladeRF2OutputSettings:
description: BladeRF2
properties:
centerFrequency:
type: integer
format: int64
devSampleRate:
type: integer
bandwidth:
type: integer
gainMode:
type: integer
globalGain:
type: integer
biasTee:
type: integer
log2Interp:
type: integer
BladeRF2OutputReport:
description: BladeRF2
properties:
frequencyRange:
$ref: "http://localhost:8081/api/swagger/include/Structs.yaml#/FrequencyRange"
sampleRateRange:
$ref: "http://localhost:8081/api/swagger/include/Structs.yaml#/Range"
bandwidthRange:
$ref: "http://localhost:8081/api/swagger/include/Structs.yaml#/Range"
globalGainRange:
$ref: "http://localhost:8081/api/swagger/include/Structs.yaml#/Range"
gainModes:
type: array
items:
$ref: "http://localhost:8081/api/swagger/include/Structs.yaml#/NamedEnum"

View File

@ -1769,6 +1769,8 @@ definitions:
$ref: "http://localhost:8081/api/swagger/include/BladeRF2.yaml#/BladeRF2InputSettings"
bladeRF1OutputSettings:
$ref: "http://localhost:8081/api/swagger/include/BladeRF1.yaml#/BladeRF1OutputSettings"
bladeRF2OutputSettings:
$ref: "http://localhost:8081/api/swagger/include/BladeRF2.yaml#/BladeRF2OutputSettings"
fcdProSettings:
$ref: "http://localhost:8081/api/swagger/include/FCDPro.yaml#/FCDProSettings"
fcdProPlusSettings:
@ -1820,6 +1822,8 @@ definitions:
$ref: "http://localhost:8081/api/swagger/include/AirspyHF.yaml#/AirspyHFReport"
bladeRF2InputReport:
$ref: "http://localhost:8081/api/swagger/include/BladeRF2.yaml#/BladeRF2InputReport"
bladeRF2OutputReport:
$ref: "http://localhost:8081/api/swagger/include/BladeRF2.yaml#/BladeRF2OutputReport"
fileSourceReport:
$ref: "http://localhost:8081/api/swagger/include/FileSource.yaml#/FileSourceReport"
limeSdrInputReport:

View File

@ -1363,6 +1363,56 @@ margin-bottom: 20px;
}
},
"description" : "BladeRF2"
};
defs.BladeRF2OutputReport = {
"properties" : {
"frequencyRange" : {
"$ref" : "#/definitions/FrequencyRange"
},
"sampleRateRange" : {
"$ref" : "#/definitions/Range"
},
"bandwidthRange" : {
"$ref" : "#/definitions/Range"
},
"globalGainRange" : {
"$ref" : "#/definitions/Range"
},
"gainModes" : {
"type" : "array",
"items" : {
"$ref" : "#/definitions/NamedEnum"
}
}
},
"description" : "BladeRF2"
};
defs.BladeRF2OutputSettings = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "int64"
},
"devSampleRate" : {
"type" : "integer"
},
"bandwidth" : {
"type" : "integer"
},
"gainMode" : {
"type" : "integer"
},
"globalGain" : {
"type" : "integer"
},
"biasTee" : {
"type" : "integer"
},
"log2Interp" : {
"type" : "integer"
}
},
"description" : "BladeRF2"
};
defs.CWKeyerSettings = {
"properties" : {
@ -1903,6 +1953,9 @@ margin-bottom: 20px;
"bladeRF2InputReport" : {
"$ref" : "#/definitions/BladeRF2InputReport"
},
"bladeRF2OutputReport" : {
"$ref" : "#/definitions/BladeRF2OutputReport"
},
"fileSourceReport" : {
"$ref" : "#/definitions/FileSourceReport"
},
@ -2003,6 +2056,9 @@ margin-bottom: 20px;
"bladeRF1OutputSettings" : {
"$ref" : "#/definitions/BladeRF1OutputSettings"
},
"bladeRF2OutputSettings" : {
"$ref" : "#/definitions/BladeRF2OutputSettings"
},
"fcdProSettings" : {
"$ref" : "#/definitions/FCDProSettings"
},
@ -23175,7 +23231,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2018-09-25T16:51:16.493+02:00
Generated 2018-09-29T05:36:53.044+02:00
</div>
</div>
</div>

View File

@ -0,0 +1,204 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.2.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGBladeRF2OutputReport.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGBladeRF2OutputReport::SWGBladeRF2OutputReport(QString* json) {
init();
this->fromJson(*json);
}
SWGBladeRF2OutputReport::SWGBladeRF2OutputReport() {
frequency_range = nullptr;
m_frequency_range_isSet = false;
sample_rate_range = nullptr;
m_sample_rate_range_isSet = false;
bandwidth_range = nullptr;
m_bandwidth_range_isSet = false;
global_gain_range = nullptr;
m_global_gain_range_isSet = false;
gain_modes = nullptr;
m_gain_modes_isSet = false;
}
SWGBladeRF2OutputReport::~SWGBladeRF2OutputReport() {
this->cleanup();
}
void
SWGBladeRF2OutputReport::init() {
frequency_range = new SWGFrequencyRange();
m_frequency_range_isSet = false;
sample_rate_range = new SWGRange();
m_sample_rate_range_isSet = false;
bandwidth_range = new SWGRange();
m_bandwidth_range_isSet = false;
global_gain_range = new SWGRange();
m_global_gain_range_isSet = false;
gain_modes = new QList<SWGNamedEnum*>();
m_gain_modes_isSet = false;
}
void
SWGBladeRF2OutputReport::cleanup() {
if(frequency_range != nullptr) {
delete frequency_range;
}
if(sample_rate_range != nullptr) {
delete sample_rate_range;
}
if(bandwidth_range != nullptr) {
delete bandwidth_range;
}
if(global_gain_range != nullptr) {
delete global_gain_range;
}
if(gain_modes != nullptr) {
auto arr = gain_modes;
for(auto o: *arr) {
delete o;
}
delete gain_modes;
}
}
SWGBladeRF2OutputReport*
SWGBladeRF2OutputReport::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGBladeRF2OutputReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&frequency_range, pJson["frequencyRange"], "SWGFrequencyRange", "SWGFrequencyRange");
::SWGSDRangel::setValue(&sample_rate_range, pJson["sampleRateRange"], "SWGRange", "SWGRange");
::SWGSDRangel::setValue(&bandwidth_range, pJson["bandwidthRange"], "SWGRange", "SWGRange");
::SWGSDRangel::setValue(&global_gain_range, pJson["globalGainRange"], "SWGRange", "SWGRange");
::SWGSDRangel::setValue(&gain_modes, pJson["gainModes"], "QList", "SWGNamedEnum");
}
QString
SWGBladeRF2OutputReport::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGBladeRF2OutputReport::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if((frequency_range != nullptr) && (frequency_range->isSet())){
toJsonValue(QString("frequencyRange"), frequency_range, obj, QString("SWGFrequencyRange"));
}
if((sample_rate_range != nullptr) && (sample_rate_range->isSet())){
toJsonValue(QString("sampleRateRange"), sample_rate_range, obj, QString("SWGRange"));
}
if((bandwidth_range != nullptr) && (bandwidth_range->isSet())){
toJsonValue(QString("bandwidthRange"), bandwidth_range, obj, QString("SWGRange"));
}
if((global_gain_range != nullptr) && (global_gain_range->isSet())){
toJsonValue(QString("globalGainRange"), global_gain_range, obj, QString("SWGRange"));
}
if(gain_modes->size() > 0){
toJsonArray((QList<void*>*)gain_modes, obj, "gainModes", "SWGNamedEnum");
}
return obj;
}
SWGFrequencyRange*
SWGBladeRF2OutputReport::getFrequencyRange() {
return frequency_range;
}
void
SWGBladeRF2OutputReport::setFrequencyRange(SWGFrequencyRange* frequency_range) {
this->frequency_range = frequency_range;
this->m_frequency_range_isSet = true;
}
SWGRange*
SWGBladeRF2OutputReport::getSampleRateRange() {
return sample_rate_range;
}
void
SWGBladeRF2OutputReport::setSampleRateRange(SWGRange* sample_rate_range) {
this->sample_rate_range = sample_rate_range;
this->m_sample_rate_range_isSet = true;
}
SWGRange*
SWGBladeRF2OutputReport::getBandwidthRange() {
return bandwidth_range;
}
void
SWGBladeRF2OutputReport::setBandwidthRange(SWGRange* bandwidth_range) {
this->bandwidth_range = bandwidth_range;
this->m_bandwidth_range_isSet = true;
}
SWGRange*
SWGBladeRF2OutputReport::getGlobalGainRange() {
return global_gain_range;
}
void
SWGBladeRF2OutputReport::setGlobalGainRange(SWGRange* global_gain_range) {
this->global_gain_range = global_gain_range;
this->m_global_gain_range_isSet = true;
}
QList<SWGNamedEnum*>*
SWGBladeRF2OutputReport::getGainModes() {
return gain_modes;
}
void
SWGBladeRF2OutputReport::setGainModes(QList<SWGNamedEnum*>* gain_modes) {
this->gain_modes = gain_modes;
this->m_gain_modes_isSet = true;
}
bool
SWGBladeRF2OutputReport::isSet(){
bool isObjectUpdated = false;
do{
if(frequency_range != nullptr && frequency_range->isSet()){ isObjectUpdated = true; break;}
if(sample_rate_range != nullptr && sample_rate_range->isSet()){ isObjectUpdated = true; break;}
if(bandwidth_range != nullptr && bandwidth_range->isSet()){ isObjectUpdated = true; break;}
if(global_gain_range != nullptr && global_gain_range->isSet()){ isObjectUpdated = true; break;}
if(gain_modes->size() > 0){ isObjectUpdated = true; break;}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,86 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.2.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGBladeRF2OutputReport.h
*
* BladeRF2
*/
#ifndef SWGBladeRF2OutputReport_H_
#define SWGBladeRF2OutputReport_H_
#include <QJsonObject>
#include "SWGFrequencyRange.h"
#include "SWGNamedEnum.h"
#include "SWGRange.h"
#include <QList>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGBladeRF2OutputReport: public SWGObject {
public:
SWGBladeRF2OutputReport();
SWGBladeRF2OutputReport(QString* json);
virtual ~SWGBladeRF2OutputReport();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGBladeRF2OutputReport* fromJson(QString &jsonString) override;
SWGFrequencyRange* getFrequencyRange();
void setFrequencyRange(SWGFrequencyRange* frequency_range);
SWGRange* getSampleRateRange();
void setSampleRateRange(SWGRange* sample_rate_range);
SWGRange* getBandwidthRange();
void setBandwidthRange(SWGRange* bandwidth_range);
SWGRange* getGlobalGainRange();
void setGlobalGainRange(SWGRange* global_gain_range);
QList<SWGNamedEnum*>* getGainModes();
void setGainModes(QList<SWGNamedEnum*>* gain_modes);
virtual bool isSet() override;
private:
SWGFrequencyRange* frequency_range;
bool m_frequency_range_isSet;
SWGRange* sample_rate_range;
bool m_sample_rate_range_isSet;
SWGRange* bandwidth_range;
bool m_bandwidth_range_isSet;
SWGRange* global_gain_range;
bool m_global_gain_range_isSet;
QList<SWGNamedEnum*>* gain_modes;
bool m_gain_modes_isSet;
};
}
#endif /* SWGBladeRF2OutputReport_H_ */

View File

@ -0,0 +1,232 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.2.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGBladeRF2OutputSettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGBladeRF2OutputSettings::SWGBladeRF2OutputSettings(QString* json) {
init();
this->fromJson(*json);
}
SWGBladeRF2OutputSettings::SWGBladeRF2OutputSettings() {
center_frequency = 0L;
m_center_frequency_isSet = false;
dev_sample_rate = 0;
m_dev_sample_rate_isSet = false;
bandwidth = 0;
m_bandwidth_isSet = false;
gain_mode = 0;
m_gain_mode_isSet = false;
global_gain = 0;
m_global_gain_isSet = false;
bias_tee = 0;
m_bias_tee_isSet = false;
log2_interp = 0;
m_log2_interp_isSet = false;
}
SWGBladeRF2OutputSettings::~SWGBladeRF2OutputSettings() {
this->cleanup();
}
void
SWGBladeRF2OutputSettings::init() {
center_frequency = 0L;
m_center_frequency_isSet = false;
dev_sample_rate = 0;
m_dev_sample_rate_isSet = false;
bandwidth = 0;
m_bandwidth_isSet = false;
gain_mode = 0;
m_gain_mode_isSet = false;
global_gain = 0;
m_global_gain_isSet = false;
bias_tee = 0;
m_bias_tee_isSet = false;
log2_interp = 0;
m_log2_interp_isSet = false;
}
void
SWGBladeRF2OutputSettings::cleanup() {
}
SWGBladeRF2OutputSettings*
SWGBladeRF2OutputSettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGBladeRF2OutputSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&center_frequency, pJson["centerFrequency"], "qint64", "");
::SWGSDRangel::setValue(&dev_sample_rate, pJson["devSampleRate"], "qint32", "");
::SWGSDRangel::setValue(&bandwidth, pJson["bandwidth"], "qint32", "");
::SWGSDRangel::setValue(&gain_mode, pJson["gainMode"], "qint32", "");
::SWGSDRangel::setValue(&global_gain, pJson["globalGain"], "qint32", "");
::SWGSDRangel::setValue(&bias_tee, pJson["biasTee"], "qint32", "");
::SWGSDRangel::setValue(&log2_interp, pJson["log2Interp"], "qint32", "");
}
QString
SWGBladeRF2OutputSettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGBladeRF2OutputSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_center_frequency_isSet){
obj->insert("centerFrequency", QJsonValue(center_frequency));
}
if(m_dev_sample_rate_isSet){
obj->insert("devSampleRate", QJsonValue(dev_sample_rate));
}
if(m_bandwidth_isSet){
obj->insert("bandwidth", QJsonValue(bandwidth));
}
if(m_gain_mode_isSet){
obj->insert("gainMode", QJsonValue(gain_mode));
}
if(m_global_gain_isSet){
obj->insert("globalGain", QJsonValue(global_gain));
}
if(m_bias_tee_isSet){
obj->insert("biasTee", QJsonValue(bias_tee));
}
if(m_log2_interp_isSet){
obj->insert("log2Interp", QJsonValue(log2_interp));
}
return obj;
}
qint64
SWGBladeRF2OutputSettings::getCenterFrequency() {
return center_frequency;
}
void
SWGBladeRF2OutputSettings::setCenterFrequency(qint64 center_frequency) {
this->center_frequency = center_frequency;
this->m_center_frequency_isSet = true;
}
qint32
SWGBladeRF2OutputSettings::getDevSampleRate() {
return dev_sample_rate;
}
void
SWGBladeRF2OutputSettings::setDevSampleRate(qint32 dev_sample_rate) {
this->dev_sample_rate = dev_sample_rate;
this->m_dev_sample_rate_isSet = true;
}
qint32
SWGBladeRF2OutputSettings::getBandwidth() {
return bandwidth;
}
void
SWGBladeRF2OutputSettings::setBandwidth(qint32 bandwidth) {
this->bandwidth = bandwidth;
this->m_bandwidth_isSet = true;
}
qint32
SWGBladeRF2OutputSettings::getGainMode() {
return gain_mode;
}
void
SWGBladeRF2OutputSettings::setGainMode(qint32 gain_mode) {
this->gain_mode = gain_mode;
this->m_gain_mode_isSet = true;
}
qint32
SWGBladeRF2OutputSettings::getGlobalGain() {
return global_gain;
}
void
SWGBladeRF2OutputSettings::setGlobalGain(qint32 global_gain) {
this->global_gain = global_gain;
this->m_global_gain_isSet = true;
}
qint32
SWGBladeRF2OutputSettings::getBiasTee() {
return bias_tee;
}
void
SWGBladeRF2OutputSettings::setBiasTee(qint32 bias_tee) {
this->bias_tee = bias_tee;
this->m_bias_tee_isSet = true;
}
qint32
SWGBladeRF2OutputSettings::getLog2Interp() {
return log2_interp;
}
void
SWGBladeRF2OutputSettings::setLog2Interp(qint32 log2_interp) {
this->log2_interp = log2_interp;
this->m_log2_interp_isSet = true;
}
bool
SWGBladeRF2OutputSettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_center_frequency_isSet){ isObjectUpdated = true; break;}
if(m_dev_sample_rate_isSet){ isObjectUpdated = true; break;}
if(m_bandwidth_isSet){ isObjectUpdated = true; break;}
if(m_gain_mode_isSet){ isObjectUpdated = true; break;}
if(m_global_gain_isSet){ isObjectUpdated = true; break;}
if(m_bias_tee_isSet){ isObjectUpdated = true; break;}
if(m_log2_interp_isSet){ isObjectUpdated = true; break;}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,94 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.2.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGBladeRF2OutputSettings.h
*
* BladeRF2
*/
#ifndef SWGBladeRF2OutputSettings_H_
#define SWGBladeRF2OutputSettings_H_
#include <QJsonObject>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGBladeRF2OutputSettings: public SWGObject {
public:
SWGBladeRF2OutputSettings();
SWGBladeRF2OutputSettings(QString* json);
virtual ~SWGBladeRF2OutputSettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGBladeRF2OutputSettings* fromJson(QString &jsonString) override;
qint64 getCenterFrequency();
void setCenterFrequency(qint64 center_frequency);
qint32 getDevSampleRate();
void setDevSampleRate(qint32 dev_sample_rate);
qint32 getBandwidth();
void setBandwidth(qint32 bandwidth);
qint32 getGainMode();
void setGainMode(qint32 gain_mode);
qint32 getGlobalGain();
void setGlobalGain(qint32 global_gain);
qint32 getBiasTee();
void setBiasTee(qint32 bias_tee);
qint32 getLog2Interp();
void setLog2Interp(qint32 log2_interp);
virtual bool isSet() override;
private:
qint64 center_frequency;
bool m_center_frequency_isSet;
qint32 dev_sample_rate;
bool m_dev_sample_rate_isSet;
qint32 bandwidth;
bool m_bandwidth_isSet;
qint32 gain_mode;
bool m_gain_mode_isSet;
qint32 global_gain;
bool m_global_gain_isSet;
qint32 bias_tee;
bool m_bias_tee_isSet;
qint32 log2_interp;
bool m_log2_interp_isSet;
};
}
#endif /* SWGBladeRF2OutputSettings_H_ */

View File

@ -38,6 +38,8 @@ SWGDeviceReport::SWGDeviceReport() {
m_airspy_hf_report_isSet = false;
blade_rf2_input_report = nullptr;
m_blade_rf2_input_report_isSet = false;
blade_rf2_output_report = nullptr;
m_blade_rf2_output_report_isSet = false;
file_source_report = nullptr;
m_file_source_report_isSet = false;
lime_sdr_input_report = nullptr;
@ -76,6 +78,8 @@ SWGDeviceReport::init() {
m_airspy_hf_report_isSet = false;
blade_rf2_input_report = new SWGBladeRF2InputReport();
m_blade_rf2_input_report_isSet = false;
blade_rf2_output_report = new SWGBladeRF2OutputReport();
m_blade_rf2_output_report_isSet = false;
file_source_report = new SWGFileSourceReport();
m_file_source_report_isSet = false;
lime_sdr_input_report = new SWGLimeSdrInputReport();
@ -113,6 +117,9 @@ SWGDeviceReport::cleanup() {
if(blade_rf2_input_report != nullptr) {
delete blade_rf2_input_report;
}
if(blade_rf2_output_report != nullptr) {
delete blade_rf2_output_report;
}
if(file_source_report != nullptr) {
delete file_source_report;
}
@ -166,6 +173,8 @@ SWGDeviceReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&blade_rf2_input_report, pJson["bladeRF2InputReport"], "SWGBladeRF2InputReport", "SWGBladeRF2InputReport");
::SWGSDRangel::setValue(&blade_rf2_output_report, pJson["bladeRF2OutputReport"], "SWGBladeRF2OutputReport", "SWGBladeRF2OutputReport");
::SWGSDRangel::setValue(&file_source_report, pJson["fileSourceReport"], "SWGFileSourceReport", "SWGFileSourceReport");
::SWGSDRangel::setValue(&lime_sdr_input_report, pJson["limeSdrInputReport"], "SWGLimeSdrInputReport", "SWGLimeSdrInputReport");
@ -217,6 +226,9 @@ SWGDeviceReport::asJsonObject() {
if((blade_rf2_input_report != nullptr) && (blade_rf2_input_report->isSet())){
toJsonValue(QString("bladeRF2InputReport"), blade_rf2_input_report, obj, QString("SWGBladeRF2InputReport"));
}
if((blade_rf2_output_report != nullptr) && (blade_rf2_output_report->isSet())){
toJsonValue(QString("bladeRF2OutputReport"), blade_rf2_output_report, obj, QString("SWGBladeRF2OutputReport"));
}
if((file_source_report != nullptr) && (file_source_report->isSet())){
toJsonValue(QString("fileSourceReport"), file_source_report, obj, QString("SWGFileSourceReport"));
}
@ -301,6 +313,16 @@ SWGDeviceReport::setBladeRf2InputReport(SWGBladeRF2InputReport* blade_rf2_input_
this->m_blade_rf2_input_report_isSet = true;
}
SWGBladeRF2OutputReport*
SWGDeviceReport::getBladeRf2OutputReport() {
return blade_rf2_output_report;
}
void
SWGDeviceReport::setBladeRf2OutputReport(SWGBladeRF2OutputReport* blade_rf2_output_report) {
this->blade_rf2_output_report = blade_rf2_output_report;
this->m_blade_rf2_output_report_isSet = true;
}
SWGFileSourceReport*
SWGDeviceReport::getFileSourceReport() {
return file_source_report;
@ -411,6 +433,7 @@ SWGDeviceReport::isSet(){
if(airspy_report != nullptr && airspy_report->isSet()){ isObjectUpdated = true; break;}
if(airspy_hf_report != nullptr && airspy_hf_report->isSet()){ isObjectUpdated = true; break;}
if(blade_rf2_input_report != nullptr && blade_rf2_input_report->isSet()){ isObjectUpdated = true; break;}
if(blade_rf2_output_report != nullptr && blade_rf2_output_report->isSet()){ isObjectUpdated = true; break;}
if(file_source_report != nullptr && file_source_report->isSet()){ isObjectUpdated = true; break;}
if(lime_sdr_input_report != nullptr && lime_sdr_input_report->isSet()){ isObjectUpdated = true; break;}
if(lime_sdr_output_report != nullptr && lime_sdr_output_report->isSet()){ isObjectUpdated = true; break;}

View File

@ -25,6 +25,7 @@
#include "SWGAirspyHFReport.h"
#include "SWGAirspyReport.h"
#include "SWGBladeRF2InputReport.h"
#include "SWGBladeRF2OutputReport.h"
#include "SWGFileSourceReport.h"
#include "SWGLimeSdrInputReport.h"
#include "SWGLimeSdrOutputReport.h"
@ -70,6 +71,9 @@ public:
SWGBladeRF2InputReport* getBladeRf2InputReport();
void setBladeRf2InputReport(SWGBladeRF2InputReport* blade_rf2_input_report);
SWGBladeRF2OutputReport* getBladeRf2OutputReport();
void setBladeRf2OutputReport(SWGBladeRF2OutputReport* blade_rf2_output_report);
SWGFileSourceReport* getFileSourceReport();
void setFileSourceReport(SWGFileSourceReport* file_source_report);
@ -119,6 +123,9 @@ private:
SWGBladeRF2InputReport* blade_rf2_input_report;
bool m_blade_rf2_input_report_isSet;
SWGBladeRF2OutputReport* blade_rf2_output_report;
bool m_blade_rf2_output_report_isSet;
SWGFileSourceReport* file_source_report;
bool m_file_source_report_isSet;

View File

@ -42,6 +42,8 @@ SWGDeviceSettings::SWGDeviceSettings() {
m_blade_rf2_input_settings_isSet = false;
blade_rf1_output_settings = nullptr;
m_blade_rf1_output_settings_isSet = false;
blade_rf2_output_settings = nullptr;
m_blade_rf2_output_settings_isSet = false;
fcd_pro_settings = nullptr;
m_fcd_pro_settings_isSet = false;
fcd_pro_plus_settings = nullptr;
@ -94,6 +96,8 @@ SWGDeviceSettings::init() {
m_blade_rf2_input_settings_isSet = false;
blade_rf1_output_settings = new SWGBladeRF1OutputSettings();
m_blade_rf1_output_settings_isSet = false;
blade_rf2_output_settings = new SWGBladeRF2OutputSettings();
m_blade_rf2_output_settings_isSet = false;
fcd_pro_settings = new SWGFCDProSettings();
m_fcd_pro_settings_isSet = false;
fcd_pro_plus_settings = new SWGFCDProPlusSettings();
@ -147,6 +151,9 @@ SWGDeviceSettings::cleanup() {
if(blade_rf1_output_settings != nullptr) {
delete blade_rf1_output_settings;
}
if(blade_rf2_output_settings != nullptr) {
delete blade_rf2_output_settings;
}
if(fcd_pro_settings != nullptr) {
delete fcd_pro_settings;
}
@ -219,6 +226,8 @@ SWGDeviceSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&blade_rf1_output_settings, pJson["bladeRF1OutputSettings"], "SWGBladeRF1OutputSettings", "SWGBladeRF1OutputSettings");
::SWGSDRangel::setValue(&blade_rf2_output_settings, pJson["bladeRF2OutputSettings"], "SWGBladeRF2OutputSettings", "SWGBladeRF2OutputSettings");
::SWGSDRangel::setValue(&fcd_pro_settings, pJson["fcdProSettings"], "SWGFCDProSettings", "SWGFCDProSettings");
::SWGSDRangel::setValue(&fcd_pro_plus_settings, pJson["fcdProPlusSettings"], "SWGFCDProPlusSettings", "SWGFCDProPlusSettings");
@ -286,6 +295,9 @@ SWGDeviceSettings::asJsonObject() {
if((blade_rf1_output_settings != nullptr) && (blade_rf1_output_settings->isSet())){
toJsonValue(QString("bladeRF1OutputSettings"), blade_rf1_output_settings, obj, QString("SWGBladeRF1OutputSettings"));
}
if((blade_rf2_output_settings != nullptr) && (blade_rf2_output_settings->isSet())){
toJsonValue(QString("bladeRF2OutputSettings"), blade_rf2_output_settings, obj, QString("SWGBladeRF2OutputSettings"));
}
if((fcd_pro_settings != nullptr) && (fcd_pro_settings->isSet())){
toJsonValue(QString("fcdProSettings"), fcd_pro_settings, obj, QString("SWGFCDProSettings"));
}
@ -405,6 +417,16 @@ SWGDeviceSettings::setBladeRf1OutputSettings(SWGBladeRF1OutputSettings* blade_rf
this->m_blade_rf1_output_settings_isSet = true;
}
SWGBladeRF2OutputSettings*
SWGDeviceSettings::getBladeRf2OutputSettings() {
return blade_rf2_output_settings;
}
void
SWGDeviceSettings::setBladeRf2OutputSettings(SWGBladeRF2OutputSettings* blade_rf2_output_settings) {
this->blade_rf2_output_settings = blade_rf2_output_settings;
this->m_blade_rf2_output_settings_isSet = true;
}
SWGFCDProSettings*
SWGDeviceSettings::getFcdProSettings() {
return fcd_pro_settings;
@ -567,6 +589,7 @@ SWGDeviceSettings::isSet(){
if(blade_rf1_input_settings != nullptr && blade_rf1_input_settings->isSet()){ isObjectUpdated = true; break;}
if(blade_rf2_input_settings != nullptr && blade_rf2_input_settings->isSet()){ isObjectUpdated = true; break;}
if(blade_rf1_output_settings != nullptr && blade_rf1_output_settings->isSet()){ isObjectUpdated = true; break;}
if(blade_rf2_output_settings != nullptr && blade_rf2_output_settings->isSet()){ isObjectUpdated = true; break;}
if(fcd_pro_settings != nullptr && fcd_pro_settings->isSet()){ isObjectUpdated = true; break;}
if(fcd_pro_plus_settings != nullptr && fcd_pro_plus_settings->isSet()){ isObjectUpdated = true; break;}
if(file_source_settings != nullptr && file_source_settings->isSet()){ isObjectUpdated = true; break;}

View File

@ -27,6 +27,7 @@
#include "SWGBladeRF1InputSettings.h"
#include "SWGBladeRF1OutputSettings.h"
#include "SWGBladeRF2InputSettings.h"
#include "SWGBladeRF2OutputSettings.h"
#include "SWGFCDProPlusSettings.h"
#include "SWGFCDProSettings.h"
#include "SWGFileSourceSettings.h"
@ -83,6 +84,9 @@ public:
SWGBladeRF1OutputSettings* getBladeRf1OutputSettings();
void setBladeRf1OutputSettings(SWGBladeRF1OutputSettings* blade_rf1_output_settings);
SWGBladeRF2OutputSettings* getBladeRf2OutputSettings();
void setBladeRf2OutputSettings(SWGBladeRF2OutputSettings* blade_rf2_output_settings);
SWGFCDProSettings* getFcdProSettings();
void setFcdProSettings(SWGFCDProSettings* fcd_pro_settings);
@ -153,6 +157,9 @@ private:
SWGBladeRF1OutputSettings* blade_rf1_output_settings;
bool m_blade_rf1_output_settings_isSet;
SWGBladeRF2OutputSettings* blade_rf2_output_settings;
bool m_blade_rf2_output_settings_isSet;
SWGFCDProSettings* fcd_pro_settings;
bool m_fcd_pro_settings_isSet;

View File

@ -34,6 +34,8 @@
#include "SWGBladeRF1OutputSettings.h"
#include "SWGBladeRF2InputReport.h"
#include "SWGBladeRF2InputSettings.h"
#include "SWGBladeRF2OutputReport.h"
#include "SWGBladeRF2OutputSettings.h"
#include "SWGCWKeyerSettings.h"
#include "SWGChannel.h"
#include "SWGChannelListItem.h"
@ -182,6 +184,12 @@ namespace SWGSDRangel {
if(QString("SWGBladeRF2InputSettings").compare(type) == 0) {
return new SWGBladeRF2InputSettings();
}
if(QString("SWGBladeRF2OutputReport").compare(type) == 0) {
return new SWGBladeRF2OutputReport();
}
if(QString("SWGBladeRF2OutputSettings").compare(type) == 0) {
return new SWGBladeRF2OutputSettings();
}
if(QString("SWGCWKeyerSettings").compare(type) == 0) {
return new SWGCWKeyerSettings();
}