mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-06-03 06:24:48 -04:00
BladerRF2 input support (2)
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
project(bladerf2input)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
|
||||
set(bladerf2input_SOURCES
|
||||
#bladerf2inputgui.cpp
|
||||
bladerf2input.cpp
|
||||
#bladerf2inputplugin.cpp
|
||||
bladerf2inputsettings.cpp
|
||||
bladerf2inputthread.cpp
|
||||
)
|
||||
|
||||
set(bladerf2input_HEADERS
|
||||
#bladerf2inputgui.h
|
||||
bladerf2input.h
|
||||
#bladerf2inputplugin.h
|
||||
bladerf2inputsettings.h
|
||||
bladerf2inputthread.h
|
||||
)
|
||||
|
||||
set(bladerf2input_FORMS
|
||||
bladerf2inputgui.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)
|
||||
|
||||
qt5_wrap_ui(bladerf2input_FORMS_HEADERS ${bladerf2input_FORMS})
|
||||
|
||||
add_library(inputbladerf2 SHARED
|
||||
${bladerf2input_SOURCES}
|
||||
${bladerf2input_HEADERS_MOC}
|
||||
${bladerf2input_FORMS_HEADERS}
|
||||
)
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
target_link_libraries(inputbladerf2
|
||||
${QT_LIBRARIES}
|
||||
bladerf
|
||||
sdrbase
|
||||
sdrgui
|
||||
swagger
|
||||
bladerf2device
|
||||
)
|
||||
else (BUILD_DEBIAN)
|
||||
target_link_libraries(inputbladerf2
|
||||
${QT_LIBRARIES}
|
||||
${LIBBLADERF_LIBRARIES}
|
||||
sdrbase
|
||||
sdrgui
|
||||
swagger
|
||||
bladerf2device
|
||||
)
|
||||
endif (BUILD_DEBIAN)
|
||||
|
||||
target_link_libraries(inputbladerf2 Qt5::Core Qt5::Widgets)
|
||||
|
||||
install(TARGETS inputbladerf2 DESTINATION lib/plugins/samplesource)
|
||||
@@ -0,0 +1,220 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "SWGDeviceSettings.h"
|
||||
#include "SWGBladeRF2InputSettings.h"
|
||||
#include "SWGDeviceState.h"
|
||||
#include "SWGDeviceReport.h"
|
||||
#include "SWGBladeRF2InputReport.h"
|
||||
|
||||
#include "device/devicesourceapi.h"
|
||||
#include "device/devicesinkapi.h"
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "dsp/filerecord.h"
|
||||
#include "dsp/dspengine.h"
|
||||
|
||||
#include "bladerf2/devicebladerf2shared.h"
|
||||
#include "bladerf2/devicebladerf2.h"
|
||||
#include "bladerf2input.h"
|
||||
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(BladeRF2Input::MsgConfigureBladeRF2, Message)
|
||||
MESSAGE_CLASS_DEFINITION(BladeRF2Input::MsgFileRecord, Message)
|
||||
MESSAGE_CLASS_DEFINITION(BladeRF2Input::MsgStartStop, Message)
|
||||
|
||||
BladeRF2Input::BladeRF2Input(DeviceSourceAPI *deviceAPI) :
|
||||
m_deviceAPI(deviceAPI),
|
||||
m_settings(),
|
||||
m_deviceDescription("BladeRF2Input"),
|
||||
m_running(false)
|
||||
{
|
||||
openDevice();
|
||||
|
||||
m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
|
||||
m_deviceAPI->addSink(m_fileSink);
|
||||
}
|
||||
|
||||
BladeRF2Input::~BladeRF2Input()
|
||||
{
|
||||
if (m_running) {
|
||||
stop();
|
||||
}
|
||||
|
||||
m_deviceAPI->removeSink(m_fileSink);
|
||||
delete m_fileSink;
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
void BladeRF2Input::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool BladeRF2Input::openDevice()
|
||||
{
|
||||
if (!m_sampleFifo.setSize(96000 * 4))
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: could not allocate SampleFifo");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("BladeRF2Input::openDevice: allocated SampleFifo");
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
DeviceSourceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0];
|
||||
DeviceBladeRF2Shared *deviceBladeRF2Shared = (DeviceBladeRF2Shared*) sourceBuddy->getBuddySharedPtr();
|
||||
|
||||
if (deviceBladeRF2Shared == 0)
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: the source buddy shared pointer is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
DeviceBladeRF2 *device = deviceBladeRF2Shared->m_dev;
|
||||
|
||||
if (device == 0)
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: cannot get device pointer from Rx buddy");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_deviceShared.m_dev = device;
|
||||
int requestedChannel = m_deviceAPI->getItemIndex();
|
||||
|
||||
if (requestedChannel == deviceBladeRF2Shared->m_channel)
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: channel %u already in use", requestedChannel);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!device->openRx(requestedChannel))
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: channel %u cannot be enabled", requestedChannel);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_deviceShared.m_channel = requestedChannel;
|
||||
qDebug("BladeRF2Input::openDevice: channel %u enabled", requestedChannel);
|
||||
}
|
||||
}
|
||||
// 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");
|
||||
|
||||
DeviceSinkAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0];
|
||||
DeviceBladeRF2Shared *deviceBladeRF2Shared = (DeviceBladeRF2Shared*) sinkBuddy->getBuddySharedPtr();
|
||||
|
||||
if (deviceBladeRF2Shared == 0)
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: the sink buddy shared pointer is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
DeviceBladeRF2 *device = deviceBladeRF2Shared->m_dev;
|
||||
|
||||
if (device == 0)
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: cannot get device pointer from Rx buddy");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_deviceShared.m_dev = device;
|
||||
int requestedChannel = m_deviceAPI->getItemIndex();
|
||||
|
||||
if (!device->openRx(requestedChannel))
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: channel %u cannot be enabled", requestedChannel);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_deviceShared.m_channel = requestedChannel;
|
||||
qDebug("BladeRF2Input::openDevice: channel %u enabled", requestedChannel);
|
||||
}
|
||||
}
|
||||
// There are no buddies then create the first BladeRF2 device
|
||||
// allocate the Rx channel unconditionally
|
||||
else
|
||||
{
|
||||
qDebug("BladeRF2Input::openDevice: open device here");
|
||||
|
||||
m_deviceShared.m_dev = new DeviceBladeRF2();
|
||||
char serial[256];
|
||||
strcpy(serial, qPrintable(m_deviceAPI->getSampleSourceSerial()));
|
||||
|
||||
if (!m_deviceShared.m_dev->open(serial))
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: cannot open BladeRF2 device");
|
||||
return false;
|
||||
}
|
||||
|
||||
int requestedChannel = m_deviceAPI->getItemIndex();
|
||||
|
||||
if (!m_deviceShared.m_dev->openRx(requestedChannel))
|
||||
{
|
||||
qCritical("BladeRF2Input::openDevice: channel %u cannot be enabled", requestedChannel);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_deviceShared.m_channel = requestedChannel;
|
||||
qDebug("BladeRF2Input::openDevice: channel %u enabled", requestedChannel);
|
||||
}
|
||||
}
|
||||
|
||||
m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API
|
||||
return true;
|
||||
}
|
||||
|
||||
void BladeRF2Input::closeDevice()
|
||||
{
|
||||
if (m_deviceShared.m_dev == 0) { // was never open
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_running) {
|
||||
stop();
|
||||
}
|
||||
|
||||
m_deviceShared.m_channel = -1;
|
||||
|
||||
// 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 BladeRF2Input::init()
|
||||
{
|
||||
applySettings(m_settings, true);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUT_H_
|
||||
#define PLUGINS_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUT_H_
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dsp/devicesamplesource.h"
|
||||
#include "bladerf2/devicebladerf2shared.h"
|
||||
#include "bladerf2inputsettings.h"
|
||||
|
||||
class DeviceSourceAPI;
|
||||
class LimeSDRInputThread;
|
||||
class FileRecord;
|
||||
|
||||
class BladeRF2Input : public DeviceSampleSource
|
||||
{
|
||||
public:
|
||||
class MsgConfigureBladeRF2 : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
const BladeRF2InputSettings& getSettings() const { return m_settings; }
|
||||
bool getForce() const { return m_force; }
|
||||
|
||||
static MsgConfigureBladeRF2* create(const BladeRF2InputSettings& settings, bool force)
|
||||
{
|
||||
return new MsgConfigureBladeRF2(settings, force);
|
||||
}
|
||||
|
||||
private:
|
||||
BladeRF2InputSettings m_settings;
|
||||
bool m_force;
|
||||
|
||||
MsgConfigureBladeRF2(const BladeRF2InputSettings& settings, bool force) :
|
||||
Message(),
|
||||
m_settings(settings),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgFileRecord : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgFileRecord* create(bool startStop) {
|
||||
return new MsgFileRecord(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgFileRecord(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgStartStop : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgStartStop* create(bool startStop) {
|
||||
return new MsgStartStop(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgStartStop(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
BladeRF2Input(DeviceSourceAPI *deviceAPI);
|
||||
virtual ~BladeRF2Input();
|
||||
virtual void destroy();
|
||||
|
||||
virtual void init();
|
||||
virtual bool start();
|
||||
virtual void stop();
|
||||
|
||||
virtual QByteArray serialize() const;
|
||||
virtual bool deserialize(const QByteArray& data);
|
||||
|
||||
virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
|
||||
virtual const QString& getDeviceDescription() const;
|
||||
virtual int getSampleRate() const;
|
||||
virtual quint64 getCenterFrequency() const;
|
||||
virtual void setCenterFrequency(qint64 centerFrequency);
|
||||
|
||||
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:
|
||||
DeviceSourceAPI *m_deviceAPI;
|
||||
QMutex m_mutex;
|
||||
BladeRF2InputSettings m_settings;
|
||||
QString m_deviceDescription;
|
||||
bool m_running;
|
||||
DeviceBladeRF2Shared m_deviceShared;
|
||||
FileRecord *m_fileSink; //!< File sink to record device I/Q output
|
||||
|
||||
bool openDevice();
|
||||
void closeDevice();
|
||||
bool applySettings(const BladeRF2InputSettings& settings, bool force = false);
|
||||
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF2InputSettings& settings);
|
||||
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
|
||||
};
|
||||
|
||||
#endif /* PLUGINS_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUT_H_ */
|
||||
@@ -0,0 +1,727 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Bladerf2InputGui</class>
|
||||
<widget class="QWidget" name="Bladerf2InputGui">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>310</width>
|
||||
<height>265</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>310</width>
|
||||
<height>250</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>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="record">
|
||||
<property name="toolTip">
|
||||
<string>Toggle record I/Q samples from device</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/record_off.png</normaloff>
|
||||
<normalon>:/record_on.png</normalon>:/record_off.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="2">
|
||||
<widget class="ButtonSwitch" name="iqImbalance">
|
||||
<property name="toolTip">
|
||||
<string>Automatic IQ imbalance correction</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>IQ</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="ButtonSwitch" name="dcOffset">
|
||||
<property name="toolTip">
|
||||
<string>Automatic DC offset removal</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>DC</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<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>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="corrLabel">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="xb200Label">
|
||||
<property name="text">
|
||||
<string>xb200</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QComboBox" name="xb200">
|
||||
<property name="toolTip">
|
||||
<string>XB200 board mode</string>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string>None</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maxVisibleItems">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bypass</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Auto 1dB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Auto 3dB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Custom</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>50M</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>144M</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>222M</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</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>
|
||||
</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>Dec</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="decim">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Decimation factor</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>32</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>64</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_decim" columnstretch="0,0,0,0,0,0,0,0,0,0,0,0">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="4">
|
||||
<spacer name="fcPosRightSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<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="QLabel" name="label_fcPos">
|
||||
<property name="text">
|
||||
<string>Fp</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QComboBox" name="fcPos">
|
||||
<property name="toolTip">
|
||||
<string>Relative position of device center frequency</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Inf</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Sup</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Cen</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="9">
|
||||
<widget class="QLabel" name="lnaGainLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LNA </string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="10">
|
||||
<widget class="QComboBox" name="lna">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>6</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="11">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>dB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="7">
|
||||
<widget class="QLabel" name="bandwidthUnit">
|
||||
<property name="text">
|
||||
<string>kHz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6">
|
||||
<widget class="QComboBox" name="bandwidth">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>IF bandwidth in kHz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="8">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<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_lna">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_vga1">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="vga1">
|
||||
<property name="toolTip">
|
||||
<string>Amplifier before filtering gain (dB)</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="vga1Text">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>20</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="vga1Label">
|
||||
<property name="text">
|
||||
<string>VGA1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_vga1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_vga2" columnstretch="0,0,0">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="vga2Label">
|
||||
<property name="text">
|
||||
<string>VGA2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="vga2">
|
||||
<property name="toolTip">
|
||||
<string>Amplifier before ADC gain (dB)</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="vga2Text">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>9</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
<item>
|
||||
<widget class="Line" name="line_vga2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
@@ -85,17 +85,22 @@ PluginInterface::SamplingDevices Blderf2InputPlugin::enumSampleSources()
|
||||
|
||||
if (strcmp(boardName, "bladerf2") == 0)
|
||||
{
|
||||
QString displayedName(QString("BladeRF2[%1] %2").arg(devinfo[i].instance).arg(devinfo[i].serial));
|
||||
unsigned int nbRxChannels = bladerf_get_channel_count(dev, BLADERF_RX);
|
||||
|
||||
result.append(SamplingDevice(displayedName,
|
||||
m_hardwareID,
|
||||
m_deviceTypeID,
|
||||
QString(devinfo[i].serial),
|
||||
i,
|
||||
PluginInterface::SamplingDevice::PhysicalDevice,
|
||||
true,
|
||||
1,
|
||||
0));
|
||||
for (int j = 0; j < nbRxChannels; j++)
|
||||
{
|
||||
qDebug("Blderf2InputPlugin::enumSampleSources: 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,
|
||||
true,
|
||||
1,
|
||||
j));
|
||||
}
|
||||
}
|
||||
|
||||
bladerf_close(dev);
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 "bladerf2inputthread.h"
|
||||
|
||||
Bladerf2InputThread::Bladerf2InputThread(struct bladerf* dev, unsigned int nbRxChannels, QObject* parent) :
|
||||
QThread(parent),
|
||||
m_running(false),
|
||||
m_dev(dev),
|
||||
m_nbChannels(nbRxChannels)
|
||||
{
|
||||
m_channels = new Channel[nbRxChannels];
|
||||
m_buf = new qint16[2*DeviceBladeRF2::blockSize*nbRxChannels];
|
||||
}
|
||||
|
||||
Bladerf2InputThread::~Bladerf2InputThread()
|
||||
{
|
||||
if (m_running) {
|
||||
stopWork();
|
||||
}
|
||||
|
||||
delete[] m_buf;
|
||||
delete[] m_channels;
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::startWork()
|
||||
{
|
||||
m_startWaitMutex.lock();
|
||||
start();
|
||||
|
||||
while(!m_running) {
|
||||
m_startWaiter.wait(&m_startWaitMutex, 100);
|
||||
}
|
||||
|
||||
m_startWaitMutex.unlock();
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::stopWork()
|
||||
{
|
||||
m_running = false;
|
||||
wait();
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::run()
|
||||
{
|
||||
int res;
|
||||
|
||||
m_running = true;
|
||||
m_startWaiter.wakeAll();
|
||||
|
||||
unsigned int nbFifos = getNbFifos();
|
||||
|
||||
if (nbFifos > 0)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (nbFifos > 1) {
|
||||
status = bladerf_sync_config(m_dev, BLADERF_RX_X2, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000);
|
||||
} else {
|
||||
status = bladerf_sync_config(m_dev, BLADERF_RX_X1, BLADERF_FORMAT_SC16_Q11, 64, 8192, 32, 10000);
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
qCritical("Bladerf2InputThread::run: cannot configure streams: %s", bladerf_strerror(status));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (m_running)
|
||||
{
|
||||
res = bladerf_sync_rx(m_dev, m_buf, DeviceBladeRF2::blockSize, NULL, 10000);
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
qCritical("BladerfThread::run sync Rx error: %s", bladerf_strerror(res));
|
||||
break;
|
||||
}
|
||||
|
||||
if (nbFifos > 1) {
|
||||
callbackMI(m_buf, DeviceBladeRF2::blockSize);
|
||||
} else {
|
||||
callbackSI(m_buf, 2*DeviceBladeRF2::blockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning("Bladerf2InputThread::run: no sample FIFOs registered. Aborting");
|
||||
}
|
||||
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
unsigned int Bladerf2InputThread::getNbFifos()
|
||||
{
|
||||
unsigned int fifoCount = 0;
|
||||
|
||||
for (int i = 0; i < m_nbChannels; i++)
|
||||
{
|
||||
if (m_channels[i].m_sampleFifo) {
|
||||
fifoCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return fifoCount;
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::setLog2Decimation(unsigned int channel, unsigned int log2_decim)
|
||||
{
|
||||
if ((channel >= 0) && (channel < m_nbChannels)) {
|
||||
m_channels[channel].m_log2Decim = log2_decim;
|
||||
}
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::setFcPos(unsigned int channel, int fcPos)
|
||||
{
|
||||
if ((channel >= 0) && (channel < m_nbChannels)) {
|
||||
m_channels[channel].m_fcPos = fcPos;
|
||||
}
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::setFifo(unsigned int channel, SampleSinkFifo *sampleFifo)
|
||||
{
|
||||
if ((channel >= 0) && (channel < m_nbChannels)) {
|
||||
m_channels[channel].m_sampleFifo = sampleFifo;
|
||||
}
|
||||
}
|
||||
|
||||
SampleSinkFifo *Bladerf2InputThread::getFifo(unsigned int channel)
|
||||
{
|
||||
if ((channel >= 0) && (channel < m_nbChannels)) {
|
||||
return m_channels[channel].m_sampleFifo;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::callbackMI(const qint16* buf, qint32 samplesPerChannel)
|
||||
{
|
||||
// TODO: write a set of decimators that can take interleaved samples in input directly
|
||||
int status = bladerf_deinterleave_stream_buffer(BLADERF_RX_X2, BLADERF_FORMAT_SC16_Q11 , samplesPerChannel*m_nbChannels, (void *) buf);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
qCritical("Bladerf2InputThread::callbackMI: cannot de-interleave buffer: %s", bladerf_strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int channel = 0; channel < m_nbChannels; channel++)
|
||||
{
|
||||
if (m_channels[channel].m_sampleFifo) {
|
||||
callbackSI(&buf[2*samplesPerChannel*channel], 2*samplesPerChannel, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bladerf2InputThread::callbackSI(const qint16* buf, qint32 len, unsigned int channel)
|
||||
{
|
||||
SampleVector::iterator it = m_channels[channel].m_convertBuffer.begin();
|
||||
|
||||
if (m_channels[channel].m_log2Decim == 0)
|
||||
{
|
||||
m_channels[channel].m_decimators.decimate1(&it, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_channels[channel].m_fcPos == 0) // Infra
|
||||
{
|
||||
switch (m_channels[channel].m_log2Decim)
|
||||
{
|
||||
case 1:
|
||||
m_channels[channel].m_decimators.decimate2_inf(&it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_channels[channel].m_decimators.decimate4_inf(&it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_channels[channel].m_decimators.decimate8_inf(&it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_channels[channel].m_decimators.decimate16_inf(&it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_channels[channel].m_decimators.decimate32_inf(&it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_channels[channel].m_decimators.decimate64_inf(&it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (m_channels[channel].m_fcPos == 1) // Supra
|
||||
{
|
||||
switch (m_channels[channel].m_log2Decim)
|
||||
{
|
||||
case 1:
|
||||
m_channels[channel].m_decimators.decimate2_sup(&it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_channels[channel].m_decimators.decimate4_sup(&it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_channels[channel].m_decimators.decimate8_sup(&it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_channels[channel].m_decimators.decimate16_sup(&it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_channels[channel].m_decimators.decimate32_sup(&it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_channels[channel].m_decimators.decimate64_sup(&it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (m_channels[channel].m_fcPos == 2) // Center
|
||||
{
|
||||
switch (m_channels[channel].m_log2Decim)
|
||||
{
|
||||
case 1:
|
||||
m_channels[channel].m_decimators.decimate2_cen(&it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_channels[channel].m_decimators.decimate4_cen(&it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_channels[channel].m_decimators.decimate8_cen(&it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_channels[channel].m_decimators.decimate16_cen(&it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_channels[channel].m_decimators.decimate32_cen(&it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_channels[channel].m_decimators.decimate64_cen(&it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_channels[channel].m_sampleFifo->write(m_channels[channel].m_convertBuffer.begin(), it);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// 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_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUTTHREAD_H_
|
||||
#define PLUGINS_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUTTHREAD_H_
|
||||
|
||||
// BladerRF2 is a SISO/MIMO device with a single stream supporting one or two Rx
|
||||
// Therefore only one thread can be allocated for the Rx side
|
||||
// All FIFOs must be registered before calling startWork() else SISO/MIMO switch will not work properly
|
||||
// with unpredicatable results
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include <libbladeRF.h>
|
||||
|
||||
#include "bladerf2/devicebladerf2shared.h"
|
||||
#include "dsp/samplesinkfifo.h"
|
||||
#include "dsp/decimators.h"
|
||||
|
||||
class Bladerf2InputThread : public QThread, public DeviceBladeRF2Shared::InputThreadInterface {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Bladerf2InputThread(struct bladerf* dev, unsigned int nbRxChannels, QObject* parent = NULL);
|
||||
virtual ~Bladerf2InputThread();
|
||||
|
||||
virtual void startWork();
|
||||
virtual void stopWork();
|
||||
virtual bool isRunning() const { return m_running; }
|
||||
void setLog2Decimation(unsigned int channel, unsigned int log2_decim);
|
||||
void setFcPos(unsigned int channel, int fcPos);
|
||||
virtual void setFifo(unsigned int channel, SampleSinkFifo *sampleFifo);
|
||||
virtual SampleSinkFifo *getFifo(unsigned int channel);
|
||||
|
||||
private:
|
||||
struct Channel
|
||||
{
|
||||
SampleVector m_convertBuffer;
|
||||
SampleSinkFifo* m_sampleFifo;
|
||||
unsigned int m_log2Decim;
|
||||
int m_fcPos;
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12> m_decimators;
|
||||
|
||||
Channel() :
|
||||
m_sampleFifo(0),
|
||||
m_log2Decim(0),
|
||||
m_fcPos(0)
|
||||
{}
|
||||
|
||||
~Channel()
|
||||
{
|
||||
if (m_sampleFifo) {
|
||||
delete[] m_sampleFifo;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 callbackSI(const qint16* buf, qint32 len, unsigned int channel = 0);
|
||||
void callbackMI(const qint16* buf, qint32 samplesPerChannel);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* PLUGINS_SAMPLESOURCE_BLADERF2INPUT_BLADERF2INPUTTHREAD_H_ */
|
||||
Reference in New Issue
Block a user