mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-05-23 18:52:28 -04:00
LimeSDR output (1)
This commit is contained in:
parent
4ae889c06a
commit
f447c9f9bd
55
plugins/samplesink/limesdroutput/CMakeLists.txt
Normal file
55
plugins/samplesink/limesdroutput/CMakeLists.txt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
project(limesdroutput)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
|
||||||
|
set(limesdroutput_SOURCES
|
||||||
|
limesdroutputgui.cpp
|
||||||
|
limesdroutput.cpp
|
||||||
|
limesdroutputplugin.cpp
|
||||||
|
limesdroutputsettings.cpp
|
||||||
|
limesdroutputthread.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(limesdroutput_HEADERS
|
||||||
|
limesdroutputgui.h
|
||||||
|
limesdroutput.h
|
||||||
|
limesdroutputplugin.h
|
||||||
|
limesdroutputsettings.h
|
||||||
|
limesdroutputthread.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(limesdroutput_FORMS
|
||||||
|
limesdroutputgui.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
.
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/devices
|
||||||
|
${LIMESUITE_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
#include(${QT_USE_FILE})
|
||||||
|
add_definitions(${QT_DEFINITIONS})
|
||||||
|
add_definitions(-DQT_PLUGIN)
|
||||||
|
add_definitions(-DQT_SHARED)
|
||||||
|
|
||||||
|
#qt4_wrap_cpp(limesdroutput_HEADERS_MOC ${limesdroutput_HEADERS})
|
||||||
|
qt5_wrap_ui(limesdroutput_FORMS_HEADERS ${limesdroutput_FORMS})
|
||||||
|
|
||||||
|
add_library(outputlimesdr SHARED
|
||||||
|
${limesdroutput_SOURCES}
|
||||||
|
${limesdroutput_HEADERS_MOC}
|
||||||
|
${limesdroutput_FORMS_HEADERS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(outputlimesdr
|
||||||
|
${QT_LIBRARIES}
|
||||||
|
${LIMESUITE_LIBRARY}
|
||||||
|
sdrbase
|
||||||
|
limesdrdevice
|
||||||
|
)
|
||||||
|
|
||||||
|
qt5_use_modules(inputlimesdr Core Widgets)
|
||||||
|
|
||||||
|
install(TARGETS inputlimesdr DESTINATION lib/plugins/samplesource)
|
845
plugins/samplesink/limesdroutput/limesdroutput.cpp
Normal file
845
plugins/samplesink/limesdroutput/limesdroutput.cpp
Normal file
@ -0,0 +1,845 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 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 <QMutexLocker>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string.h>
|
||||||
|
#include "lime/LimeSuite.h"
|
||||||
|
|
||||||
|
#include "device/devicesourceapi.h"
|
||||||
|
#include "device/devicesinkapi.h"
|
||||||
|
#include "dsp/dspcommands.h"
|
||||||
|
#include "limesdrinputthread.h"
|
||||||
|
#include "limesdr/devicelimesdrparam.h"
|
||||||
|
#include "limesdr/devicelimesdr.h"
|
||||||
|
#include "limesdroutput.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(LimeSDROutput::MsgConfigureLimeSDR, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(LimeSDROutput::MsgGetStreamInfo, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(LimeSDROutput::MsgSetReferenceConfig, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(LimeSDROutput::MsgReportLimeSDRToGUI, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(LimeSDROutput::MsgReportStreamInfo, Message)
|
||||||
|
|
||||||
|
|
||||||
|
LimeSDROutput::LimeSDROutput(DeviceSinkAPI *deviceAPI) :
|
||||||
|
m_deviceAPI(deviceAPI),
|
||||||
|
m_settings(),
|
||||||
|
m_limeSDROutputThread(0),
|
||||||
|
m_deviceDescription(),
|
||||||
|
m_running(false),
|
||||||
|
m_firstConfig(true)
|
||||||
|
{
|
||||||
|
m_streamId.handle = 0;
|
||||||
|
openDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
LimeSDROutput::~LimeSDROutput()
|
||||||
|
{
|
||||||
|
if (m_running) stop();
|
||||||
|
closeDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LimeSDROutput::openDevice()
|
||||||
|
{
|
||||||
|
// look for Tx buddies and get reference to common parameters
|
||||||
|
// if there is a channel left take the first available
|
||||||
|
if (m_deviceAPI->getSinkBuddies().size() > 0) // look sink sibling first
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::openDevice: look in Ix buddies");
|
||||||
|
|
||||||
|
DeviceSinkAPI *sinkBuddy = m_deviceAPI->getSinkBuddies()[0];
|
||||||
|
m_deviceShared = *((DeviceLimeSDRShared *) sinkBuddy->getBuddySharedPtr()); // copy shared data
|
||||||
|
DeviceLimeSDRParams *deviceParams = m_deviceShared.m_deviceParams; // get device parameters
|
||||||
|
|
||||||
|
if (deviceParams == 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::openDevice: cannot get device parameters from Tx buddy");
|
||||||
|
return false; // the device params should have been created by the buddy
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::openDevice: getting device parameters from Tx buddy");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_deviceAPI->getSinkBuddies().size() == deviceParams->m_nbTxChannels)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::openDevice: no more Tx channels available in device");
|
||||||
|
return false; // no more Tx channels available in device
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::openDevice: at least one more Tx channel is available in device");
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for unused channel number
|
||||||
|
char *busyChannels = new char[deviceParams->m_nbTxChannels];
|
||||||
|
memset(busyChannels, 0, deviceParams->m_nbTxChannels);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++)
|
||||||
|
{
|
||||||
|
DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[i];
|
||||||
|
DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr();
|
||||||
|
busyChannels[buddyShared->m_channel] = 1;
|
||||||
|
|
||||||
|
if (buddyShared->m_thread) { // suspend Tx buddy's thread for proper stream allocation later
|
||||||
|
((LimeSDROutputThread *) buddyShared->m_thread)->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t ch = 0;
|
||||||
|
|
||||||
|
for (;ch < deviceParams->m_nbTxChannels; ch++)
|
||||||
|
{
|
||||||
|
if (busyChannels[ch] == 0) {
|
||||||
|
break; // first available is the good one
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_deviceShared.m_channel = ch;
|
||||||
|
delete[] busyChannels;
|
||||||
|
}
|
||||||
|
// look for Rx buddies and get reference to common parameters
|
||||||
|
// take the first Rx channel
|
||||||
|
else if (m_deviceAPI->getSourceBuddies().size() > 0) // then source
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::openDevice: look in Rx buddies");
|
||||||
|
|
||||||
|
DeviceSourceAPI *sourceBuddy = m_deviceAPI->getSourceBuddies()[0];
|
||||||
|
m_deviceShared = *((DeviceLimeSDRShared *) sourceBuddy->getBuddySharedPtr()); // copy parameters
|
||||||
|
|
||||||
|
if (m_deviceShared.m_deviceParams == 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::openDevice: cannot get device parameters from Rx buddy");
|
||||||
|
return false; // the device params should have been created by the buddy
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::openDevice: getting device parameters from Rx buddy");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_deviceShared.m_channel = 0; // take first channel
|
||||||
|
}
|
||||||
|
// There are no buddies then create the first LimeSDR common parameters
|
||||||
|
// open the device this will also populate common fields
|
||||||
|
// take the first Tx channel
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::openDevice: open device here");
|
||||||
|
|
||||||
|
m_deviceShared.m_deviceParams = new DeviceLimeSDRParams();
|
||||||
|
char serial[256];
|
||||||
|
strcpy(serial, qPrintable(m_deviceAPI->getSampleSinkSerial()));
|
||||||
|
m_deviceShared.m_deviceParams->open(serial);
|
||||||
|
m_deviceShared.m_channel = 0; // take first channel
|
||||||
|
}
|
||||||
|
|
||||||
|
m_deviceAPI->setBuddySharedPtr(&m_deviceShared); // propagate common parameters to API
|
||||||
|
|
||||||
|
// acquire the channel
|
||||||
|
|
||||||
|
if (LMS_EnableChannel(m_deviceShared.m_deviceParams->getDevice(), LMS_CH_TX, m_deviceShared.m_channel, true) != 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::openDevice: cannot enable Tx channel %lu", m_deviceShared.m_channel);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::openDevice: Tx channel %lu enabled", m_deviceShared.m_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up the stream
|
||||||
|
|
||||||
|
m_streamId.channel = m_deviceShared.m_channel; // channel number
|
||||||
|
m_streamId.fifoSize = 1024 * 128; // fifo size in samples
|
||||||
|
m_streamId.throughputVsLatency = 1.0; // optimize for max throughput
|
||||||
|
m_streamId.isTx = true; // TX channel
|
||||||
|
m_streamId.dataFmt = lms_stream_t::LMS_FMT_I12; // 12-bit integers
|
||||||
|
|
||||||
|
if (LMS_SetupStream(m_deviceShared.m_deviceParams->getDevice(), &m_streamId) != 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::start: cannot setup the stream on Tx channel %lu", m_deviceShared.m_channel);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::start: stream set up on Tx channel %lu", m_deviceShared.m_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// resume Tx buddy's threads
|
||||||
|
|
||||||
|
for (int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++)
|
||||||
|
{
|
||||||
|
DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[i];
|
||||||
|
DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr();
|
||||||
|
|
||||||
|
if (buddyShared->m_thread) {
|
||||||
|
((LimeSDROutputThread *) buddyShared->m_thread)->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutput::closeDevice()
|
||||||
|
{
|
||||||
|
if (m_deviceShared.m_deviceParams->getDevice() == 0) { // was never open
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// suspend Tx buddy's threads
|
||||||
|
|
||||||
|
for (int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++)
|
||||||
|
{
|
||||||
|
DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[i];
|
||||||
|
DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr();
|
||||||
|
|
||||||
|
if (buddyShared->m_thread) {
|
||||||
|
((LimeSDROutputThread *) buddyShared->m_thread)->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy the stream
|
||||||
|
LMS_DestroyStream(m_deviceShared.m_deviceParams->getDevice(), &m_streamId);
|
||||||
|
m_streamId.handle = 0;
|
||||||
|
|
||||||
|
// release the channel
|
||||||
|
|
||||||
|
if (LMS_EnableChannel(m_deviceShared.m_deviceParams->getDevice(), LMS_CH_TX, m_deviceShared.m_channel, false) != 0)
|
||||||
|
{
|
||||||
|
qWarning("LimeSDROutput::closeDevice: cannot disable Tx channel %lu", m_deviceShared.m_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_deviceShared.m_channel = -1;
|
||||||
|
|
||||||
|
// resume Tx buddy's threads
|
||||||
|
|
||||||
|
for (int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++)
|
||||||
|
{
|
||||||
|
DeviceSourceAPI *buddy = m_deviceAPI->getSinkBuddies()[i];
|
||||||
|
DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr();
|
||||||
|
|
||||||
|
if (buddyShared->m_thread) {
|
||||||
|
((LimeSDROutputThread *) buddyShared->m_thread)->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No buddies so effectively close the device
|
||||||
|
|
||||||
|
if ((m_deviceAPI->getSourceBuddies().size() == 0) && (m_deviceAPI->getSinkBuddies().size() == 0))
|
||||||
|
{
|
||||||
|
m_deviceShared.m_deviceParams->close();
|
||||||
|
delete m_deviceShared.m_deviceParams;
|
||||||
|
m_deviceShared.m_deviceParams = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LimeSDROutput::start()
|
||||||
|
{
|
||||||
|
if (!m_deviceShared.m_deviceParams->getDevice()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_running) stop();
|
||||||
|
|
||||||
|
// start / stop streaming is done in the thread.
|
||||||
|
|
||||||
|
if ((m_limeSDROutputThread = new LimeSDROutputThread(&m_streamId, &m_sampleSourceFifo)) == 0)
|
||||||
|
{
|
||||||
|
qFatal("LimeSDROutput::start: cannot create thread");
|
||||||
|
stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::start: thread created");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_limeSDROutputThread->setLog2Interpolation(m_settings.m_log2SoftInterp);
|
||||||
|
|
||||||
|
m_limeSDROutputThread->startWork();
|
||||||
|
|
||||||
|
m_deviceShared.m_thread = (void *) m_limeSDROutputThread;
|
||||||
|
m_running = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutput::stop()
|
||||||
|
{
|
||||||
|
if (m_limeSDROutputThread != 0)
|
||||||
|
{
|
||||||
|
m_limeSDROutputThread->stopWork();
|
||||||
|
delete m_limeSDROutputThread;
|
||||||
|
m_limeSDROutputThread = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_deviceShared.m_thread = 0;
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString& LimeSDROutput::getDeviceDescription() const
|
||||||
|
{
|
||||||
|
return m_deviceDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LimeSDROutput::getSampleRate() const
|
||||||
|
{
|
||||||
|
int rate = m_settings.m_devSampleRate;
|
||||||
|
return (rate / (1<<m_settings.m_log2SoftInterp));
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 LimeSDROutput::getCenterFrequency() const
|
||||||
|
{
|
||||||
|
return m_settings.m_centerFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t LimeSDROutput::getChannelIndex()
|
||||||
|
{
|
||||||
|
return m_deviceShared.m_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutput::getLORange(float& minF, float& maxF, float& stepF) const
|
||||||
|
{
|
||||||
|
lms_range_t range = m_deviceShared.m_deviceParams->m_loRangeTx;
|
||||||
|
minF = range.min;
|
||||||
|
maxF = range.max;
|
||||||
|
stepF = range.step;
|
||||||
|
qDebug("LimeSDROutput::getLORange: min: %f max: %f step: %f", range.min, range.max, range.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutput::getSRRange(float& minF, float& maxF, float& stepF) const
|
||||||
|
{
|
||||||
|
lms_range_t range = m_deviceShared.m_deviceParams->m_srRangeTx;
|
||||||
|
minF = range.min;
|
||||||
|
maxF = range.max;
|
||||||
|
stepF = range.step;
|
||||||
|
qDebug("LimeSDROutput::getSRRange: min: %f max: %f step: %f", range.min, range.max, range.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutput::getLPRange(float& minF, float& maxF, float& stepF) const
|
||||||
|
{
|
||||||
|
lms_range_t range = m_deviceShared.m_deviceParams->m_lpfRangeTx;
|
||||||
|
minF = range.min;
|
||||||
|
maxF = range.max;
|
||||||
|
stepF = range.step;
|
||||||
|
qDebug("LimeSDROutput::getLPRange: min: %f max: %f step: %f", range.min, range.max, range.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t LimeSDROutput::getHWLog2Interp() const
|
||||||
|
{
|
||||||
|
return m_deviceShared.m_deviceParams->m_log2OvSRTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LimeSDROutput::handleMessage(const Message& message)
|
||||||
|
{
|
||||||
|
if (MsgConfigureLimeSDR::match(message))
|
||||||
|
{
|
||||||
|
MsgConfigureLimeSDR& conf = (MsgConfigureLimeSDR&) message;
|
||||||
|
qDebug() << "LimeSDROutput::handleMessage: MsgConfigureLimeSDR";
|
||||||
|
|
||||||
|
if (!applySettings(conf.getSettings(), m_firstConfig))
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::handleMessage config error");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_firstConfig = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgSetReferenceConfig::match(message))
|
||||||
|
{
|
||||||
|
MsgSetReferenceConfig& conf = (MsgSetReferenceConfig&) message;
|
||||||
|
qDebug() << "LimeSDROutput::handleMessage: MsgSetReferenceConfig";
|
||||||
|
m_settings = conf.getSettings();
|
||||||
|
m_deviceShared.m_ncoFrequency = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0; // for buddies
|
||||||
|
m_deviceShared.m_centerFrequency = m_settings.m_centerFrequency; // for buddies
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgGetStreamInfo::match(message))
|
||||||
|
{
|
||||||
|
// qDebug() << "LimeSDROutput::handleMessage: MsgGetStreamInfo";
|
||||||
|
lms_stream_status_t status;
|
||||||
|
|
||||||
|
if (m_streamId.handle && (LMS_GetStreamStatus(&m_streamId, &status) == 0))
|
||||||
|
{
|
||||||
|
MsgReportStreamInfo *report = MsgReportStreamInfo::create(
|
||||||
|
true, // Success
|
||||||
|
status.active,
|
||||||
|
status.fifoFilledCount,
|
||||||
|
status.fifoSize,
|
||||||
|
status.underrun,
|
||||||
|
status.overrun,
|
||||||
|
status.droppedPackets,
|
||||||
|
status.sampleRate,
|
||||||
|
status.linkRate,
|
||||||
|
status.timestamp);
|
||||||
|
m_deviceAPI->getDeviceOutputMessageQueue()->push(report);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MsgReportStreamInfo *report = MsgReportStreamInfo::create(
|
||||||
|
false, // Success
|
||||||
|
false, // status.active,
|
||||||
|
0, // status.fifoFilledCount,
|
||||||
|
16384, // status.fifoSize,
|
||||||
|
0, // status.underrun,
|
||||||
|
0, // status.overrun,
|
||||||
|
0, // status.droppedPackets,
|
||||||
|
0, // status.sampleRate,
|
||||||
|
0, // status.linkRate,
|
||||||
|
0); // status.timestamp);
|
||||||
|
m_deviceAPI->getDeviceOutputMessageQueue()->push(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LimeSDROutput::applySettings(const LimeSDROutputSettings& settings, bool force)
|
||||||
|
{
|
||||||
|
bool forwardChangeOwnDSP = false;
|
||||||
|
bool forwardChangeTxDSP = false;
|
||||||
|
bool forwardChangeAllDSP = false;
|
||||||
|
bool suspendOwnThread = false;
|
||||||
|
bool suspendTxThread = false;
|
||||||
|
bool suspendAllThread = false;
|
||||||
|
bool doCalibration = false;
|
||||||
|
// QMutexLocker mutexLocker(&m_mutex);
|
||||||
|
|
||||||
|
// determine if buddies threads or own thread need to be suspended
|
||||||
|
|
||||||
|
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
|
||||||
|
{
|
||||||
|
suspendAllThread = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_log2HardInterp != settings.m_log2HardInterp) ||
|
||||||
|
(m_settings.m_centerFrequency != settings.m_centerFrequency) || force)
|
||||||
|
{
|
||||||
|
suspendTxThread = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_gain != settings.m_gain) ||
|
||||||
|
(m_settings.m_lpfBW != settings.m_lpfBW) ||
|
||||||
|
(m_settings.m_lpfFIRBW != settings.m_lpfFIRBW) ||
|
||||||
|
(m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) ||
|
||||||
|
(m_settings.m_ncoEnable != settings.m_ncoEnable) ||
|
||||||
|
(m_settings.m_ncoFrequency != settings.m_ncoFrequency) || force)
|
||||||
|
{
|
||||||
|
suspendOwnThread = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// suspend buddies threads or own thread
|
||||||
|
|
||||||
|
if (suspendAllThread)
|
||||||
|
{
|
||||||
|
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
|
||||||
|
std::vector<DeviceSourceAPI*>::const_iterator itSource = sourceBuddies.begin();
|
||||||
|
|
||||||
|
for (; itSource != sourceBuddies.end(); ++itSource)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr();
|
||||||
|
if (buddySharedPtr->m_thread)
|
||||||
|
{
|
||||||
|
((LimeSDRInputThread *) buddySharedPtr->m_thread)->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
|
||||||
|
std::vector<DeviceSinkAPI*>::const_iterator itSink = sinkBuddies.begin();
|
||||||
|
|
||||||
|
for (; itSink != sinkBuddies.end(); ++itSink)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
|
||||||
|
if (buddySharedPtr->m_thread)
|
||||||
|
{
|
||||||
|
((LimeSDROutputThread *) buddySharedPtr->m_thread)->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_limeSDROutputThread) {
|
||||||
|
m_limeSDROutputThread->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (suspendTxThread)
|
||||||
|
{
|
||||||
|
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
|
||||||
|
std::vector<DeviceSinkAPI*>::const_iterator itSink = sinkBuddies.begin();
|
||||||
|
|
||||||
|
for (; itSink != sinkBuddies.end(); ++itSink)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
|
||||||
|
if (buddySharedPtr->m_thread)
|
||||||
|
{
|
||||||
|
((LimeSDROutputThread *) buddySharedPtr->m_thread)->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_limeSDROutputThread) {
|
||||||
|
m_limeSDROutputThread->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (suspendOwnThread)
|
||||||
|
{
|
||||||
|
if (m_limeSDROutputThread) {
|
||||||
|
m_limeSDROutputThread->stopWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply settings
|
||||||
|
|
||||||
|
if ((m_settings.m_gain != settings.m_gain) || force)
|
||||||
|
{
|
||||||
|
m_settings.m_gain = settings.m_gain;
|
||||||
|
|
||||||
|
if (m_deviceShared.m_deviceParams->getDevice() != 0)
|
||||||
|
{
|
||||||
|
if (LMS_SetGaindB(m_deviceShared.m_deviceParams->getDevice(),
|
||||||
|
LMS_CH_TX,
|
||||||
|
m_deviceShared.m_channel,
|
||||||
|
m_settings.m_gain) < 0)
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::applySettings: LMS_SetGaindB() failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doCalibration = true;
|
||||||
|
qDebug() << "LimeSDROutput::applySettings: Gain set to " << m_settings.m_gain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_devSampleRate != settings.m_devSampleRate)
|
||||||
|
|| (m_settings.m_log2HardInterp != settings.m_log2HardInterp) || force)
|
||||||
|
{
|
||||||
|
forwardChangeTxDSP = m_settings.m_log2HardInterp != settings.m_log2HardInterp;
|
||||||
|
forwardChangeAllDSP = m_settings.m_devSampleRate != settings.m_devSampleRate;
|
||||||
|
|
||||||
|
m_settings.m_devSampleRate = settings.m_devSampleRate;
|
||||||
|
m_settings.m_log2HardInterp = settings.m_log2HardInterp;
|
||||||
|
|
||||||
|
if (m_deviceShared.m_deviceParams->getDevice() != 0)
|
||||||
|
{
|
||||||
|
if (LMS_SetSampleRateDir(m_deviceShared.m_deviceParams->getDevice(),
|
||||||
|
LMS_CH_TX,
|
||||||
|
m_settings.m_devSampleRate,
|
||||||
|
1<<m_settings.m_log2HardInterp) < 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::applySettings: could not set sample rate to %d with oversampling of %d",
|
||||||
|
m_settings.m_devSampleRate,
|
||||||
|
1<<m_settings.m_log2HardInterp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_deviceShared.m_deviceParams->m_log2OvSRTx = m_settings.m_log2HardInterp;
|
||||||
|
m_deviceShared.m_deviceParams->m_sampleRate = m_settings.m_devSampleRate;
|
||||||
|
doCalibration = true;
|
||||||
|
qDebug("LimeSDROutput::applySettings: set sample rate set to %d with oversampling of %d",
|
||||||
|
m_settings.m_devSampleRate,
|
||||||
|
1<<m_settings.m_log2HardInterp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_lpfBW != settings.m_lpfBW) || force)
|
||||||
|
{
|
||||||
|
m_settings.m_lpfBW = settings.m_lpfBW;
|
||||||
|
|
||||||
|
if (m_deviceShared.m_deviceParams->getDevice() != 0)
|
||||||
|
{
|
||||||
|
if (LMS_SetLPFBW(m_deviceShared.m_deviceParams->getDevice(),
|
||||||
|
LMS_CH_TX,
|
||||||
|
m_deviceShared.m_channel,
|
||||||
|
m_settings.m_lpfBW) < 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::applySettings: could not set LPF to %f Hz", m_settings.m_lpfBW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doCalibration = true;
|
||||||
|
qDebug("LimeSDROutput::applySettings: LPF set to %f Hz", m_settings.m_lpfBW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_lpfFIRBW != settings.m_lpfFIRBW) ||
|
||||||
|
(m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) || force)
|
||||||
|
{
|
||||||
|
m_settings.m_lpfFIRBW = settings.m_lpfFIRBW;
|
||||||
|
m_settings.m_lpfFIREnable = settings.m_lpfFIREnable;
|
||||||
|
|
||||||
|
if (m_deviceShared.m_deviceParams->getDevice() != 0)
|
||||||
|
{
|
||||||
|
if (LMS_SetGFIRLPF(m_deviceShared.m_deviceParams->getDevice(),
|
||||||
|
LMS_CH_TX,
|
||||||
|
m_deviceShared.m_channel,
|
||||||
|
m_settings.m_lpfFIREnable,
|
||||||
|
m_settings.m_lpfFIRBW) < 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::applySettings: could %s and set LPF FIR to %f Hz",
|
||||||
|
m_settings.m_lpfFIREnable ? "enable" : "disable",
|
||||||
|
m_settings.m_lpfFIRBW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doCalibration = true;
|
||||||
|
qDebug("LimeSDROutput::applySettings: %sd and set LPF FIR to %f Hz",
|
||||||
|
m_settings.m_lpfFIREnable ? "enable" : "disable",
|
||||||
|
m_settings.m_lpfFIRBW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_ncoFrequency != settings.m_ncoFrequency) ||
|
||||||
|
(m_settings.m_ncoEnable != settings.m_ncoEnable) || force)
|
||||||
|
{
|
||||||
|
m_settings.m_ncoFrequency = settings.m_ncoFrequency;
|
||||||
|
m_settings.m_ncoEnable = settings.m_ncoEnable;
|
||||||
|
|
||||||
|
if (m_deviceShared.m_deviceParams->getDevice() != 0)
|
||||||
|
{
|
||||||
|
if (DeviceLimeSDR::setNCOFrequency(m_deviceShared.m_deviceParams->getDevice(),
|
||||||
|
LMS_CH_TX,
|
||||||
|
m_deviceShared.m_channel,
|
||||||
|
m_settings.m_ncoEnable,
|
||||||
|
m_settings.m_ncoFrequency))
|
||||||
|
{
|
||||||
|
doCalibration = true;
|
||||||
|
forwardChangeOwnDSP = true;
|
||||||
|
m_deviceShared.m_ncoFrequency = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0; // for buddies
|
||||||
|
qDebug("LimeSDROutput::applySettings: %sd and set NCO to %d Hz",
|
||||||
|
m_settings.m_ncoEnable ? "enable" : "disable",
|
||||||
|
m_settings.m_ncoFrequency);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::applySettings: could not %s and set NCO to %d Hz",
|
||||||
|
m_settings.m_ncoEnable ? "enable" : "disable",
|
||||||
|
m_settings.m_ncoFrequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_log2SoftInterp != settings.m_log2SoftInterp) || force)
|
||||||
|
{
|
||||||
|
m_settings.m_log2SoftInterp = settings.m_log2SoftInterp;
|
||||||
|
forwardChangeOwnDSP = true;
|
||||||
|
|
||||||
|
if (m_limeSDROutputThread != 0)
|
||||||
|
{
|
||||||
|
m_limeSDROutputThread->setLog2Interpolation(m_settings.m_log2SoftInterp);
|
||||||
|
qDebug() << "LimeSDROutput::applySettings: set soft decimation to " << (1<<m_settings.m_log2SoftInterp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force)
|
||||||
|
{
|
||||||
|
m_settings.m_centerFrequency = settings.m_centerFrequency;
|
||||||
|
forwardChangeTxDSP = true;
|
||||||
|
|
||||||
|
if (m_deviceShared.m_deviceParams->getDevice() != 0)
|
||||||
|
{
|
||||||
|
if (LMS_SetLOFrequency(m_deviceShared.m_deviceParams->getDevice(),
|
||||||
|
LMS_CH_TX,
|
||||||
|
m_deviceShared.m_channel, // same for both channels anyway but switches antenna port automatically
|
||||||
|
m_settings.m_centerFrequency) < 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::applySettings: could not set frequency to %lu", m_settings.m_centerFrequency);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doCalibration = true;
|
||||||
|
m_deviceShared.m_centerFrequency = m_settings.m_centerFrequency; // for buddies
|
||||||
|
qDebug("LimeSDROutput::applySettings: frequency set to %lu", m_settings.m_centerFrequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (doCalibration)
|
||||||
|
{
|
||||||
|
if (LMS_Calibrate(m_deviceShared.m_deviceParams->getDevice(),
|
||||||
|
LMS_CH_TX,
|
||||||
|
m_deviceShared.m_channel,
|
||||||
|
m_settings.m_lpfBW,
|
||||||
|
0) < 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutput::applySettings: calibration failed on Rx channel %lu", m_deviceShared.m_channel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::applySettings: calibration successful on Rx channel %lu", m_deviceShared.m_channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resume buddies threads or own thread
|
||||||
|
|
||||||
|
if (suspendAllThread)
|
||||||
|
{
|
||||||
|
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
|
||||||
|
std::vector<DeviceSourceAPI*>::const_iterator itSource = sourceBuddies.begin();
|
||||||
|
|
||||||
|
for (; itSource != sourceBuddies.end(); ++itSource)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr();
|
||||||
|
if (buddySharedPtr->m_thread)
|
||||||
|
{
|
||||||
|
((LimeSDRInputThread *) buddySharedPtr->m_thread)->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
|
||||||
|
std::vector<DeviceSinkAPI*>::const_iterator itSink = sinkBuddies.begin();
|
||||||
|
|
||||||
|
for (; itSink != sinkBuddies.end(); ++itSink)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
|
||||||
|
if (buddySharedPtr->m_thread)
|
||||||
|
{
|
||||||
|
((LimeSDROutputThread *) buddySharedPtr->m_thread)->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_limeSDROutputThread) {
|
||||||
|
m_limeSDROutputThread->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (suspendTxThread)
|
||||||
|
{
|
||||||
|
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
|
||||||
|
std::vector<DeviceSinkAPI*>::const_iterator itSink = sinkBuddies.begin();
|
||||||
|
|
||||||
|
for (; itSink != sinkBuddies.end(); ++itSink)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
|
||||||
|
if (buddySharedPtr->m_thread)
|
||||||
|
{
|
||||||
|
((LimeSDROutputThread *) buddySharedPtr->m_thread)->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_limeSDROutputThread) {
|
||||||
|
m_limeSDROutputThread->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (suspendOwnThread)
|
||||||
|
{
|
||||||
|
if (m_limeSDROutputThread) {
|
||||||
|
m_limeSDROutputThread->startWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// forward changes to buddies or oneself
|
||||||
|
|
||||||
|
if (forwardChangeAllDSP)
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::applySettings: forward change to all buddies");
|
||||||
|
|
||||||
|
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp);
|
||||||
|
int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
|
||||||
|
|
||||||
|
// send to self first
|
||||||
|
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + ncoShift);
|
||||||
|
m_deviceAPI->getDeviceInputMessageQueue()->push(notif);
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
|
||||||
|
uint64_t buddyCenterFreq = buddySharedPtr->m_centerFrequency;
|
||||||
|
int buddyNCOFreq = buddySharedPtr->m_ncoFrequency;
|
||||||
|
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, buddyCenterFreq + buddyNCOFreq); // do not change center frequency
|
||||||
|
(*itSink)->getDeviceInputMessageQueue()->push(notif);
|
||||||
|
MsgReportLimeSDRToGUI *report = MsgReportLimeSDRToGUI::create(
|
||||||
|
m_settings.m_centerFrequency,
|
||||||
|
m_settings.m_devSampleRate,
|
||||||
|
m_settings.m_log2HardInterp);
|
||||||
|
(*itSink)->getDeviceOutputMessageQueue()->push(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr();
|
||||||
|
int buddyNCOFreq = buddySharedPtr->m_ncoFrequency;
|
||||||
|
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + buddyNCOFreq);
|
||||||
|
(*itSource)->getDeviceInputMessageQueue()->push(notif);
|
||||||
|
MsgReportLimeSDRToGUI *report = MsgReportLimeSDRToGUI::create(
|
||||||
|
m_settings.m_centerFrequency,
|
||||||
|
m_settings.m_devSampleRate,
|
||||||
|
m_settings.m_log2HardInterp);
|
||||||
|
(*itSource)->getDeviceOutputMessageQueue()->push(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (forwardChangeTxDSP)
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::applySettings: forward change to Tx buddies");
|
||||||
|
|
||||||
|
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp);
|
||||||
|
int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
|
||||||
|
|
||||||
|
// send to self first
|
||||||
|
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + ncoShift);
|
||||||
|
m_deviceAPI->getDeviceInputMessageQueue()->push(notif);
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr();
|
||||||
|
uint64_t buddyCenterFreq = buddySharedPtr->m_centerFrequency;
|
||||||
|
int buddyNCOFreq = buddySharedPtr->m_ncoFrequency;
|
||||||
|
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, buddyCenterFreq + buddyNCOFreq); // do not change center frequency
|
||||||
|
(*itSink)->getDeviceInputMessageQueue()->push(notif);
|
||||||
|
MsgReportLimeSDRToGUI *report = MsgReportLimeSDRToGUI::create(
|
||||||
|
m_settings.m_centerFrequency,
|
||||||
|
m_settings.m_devSampleRate,
|
||||||
|
m_settings.m_log2HardInterp);
|
||||||
|
(*itSink)->getDeviceOutputMessageQueue()->push(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (forwardChangeOwnDSP)
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutput::applySettings: forward change to self only");
|
||||||
|
|
||||||
|
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp);
|
||||||
|
int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
|
||||||
|
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + ncoShift);
|
||||||
|
m_deviceAPI->getDeviceInputMessageQueue()->push(notif);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "LimeSDROutput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
|
||||||
|
<< " device stream sample rate: " << m_settings.m_devSampleRate << "S/s"
|
||||||
|
<< " sample rate with soft decimation: " << m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftInterp) << "S/s";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
231
plugins/samplesink/limesdroutput/limesdroutput.h
Normal file
231
plugins/samplesink/limesdroutput/limesdroutput.h
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 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_LIMESDROUTPUT_LIMESDROUTPUT_H_
|
||||||
|
#define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUT_H_
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "dsp/devicesamplesink.h"
|
||||||
|
#include "limesdr/devicelimesdrshared.h"
|
||||||
|
#include "limesdroutputsettings.h"
|
||||||
|
|
||||||
|
class DeviceSinkAPI;
|
||||||
|
class LimeSDROutputThread;
|
||||||
|
struct DeviceLimeSDRParams;
|
||||||
|
|
||||||
|
class LimeSDROutput : public DeviceSampleSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class MsgConfigureLimeSDR : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const LimeSDROutputSettings& getSettings() const { return m_settings; }
|
||||||
|
|
||||||
|
static MsgConfigureLimeSDR* create(const LimeSDROutputSettings& settings)
|
||||||
|
{
|
||||||
|
return new MsgConfigureLimeSDR(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LimeSDROutputSettings m_settings;
|
||||||
|
|
||||||
|
MsgConfigureLimeSDR(const LimeSDROutputSettings& settings) :
|
||||||
|
Message(),
|
||||||
|
m_settings(settings)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgSetReferenceConfig : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
const LimeSDROutputSettings& getSettings() const { return m_settings; }
|
||||||
|
|
||||||
|
static MsgSetReferenceConfig* create(const LimeSDROutputSettings& settings)
|
||||||
|
{
|
||||||
|
return new MsgSetReferenceConfig(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LimeSDROutputSettings m_settings;
|
||||||
|
|
||||||
|
MsgSetReferenceConfig(const LimeSDROutputSettings& settings) :
|
||||||
|
Message(),
|
||||||
|
m_settings(settings)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgGetStreamInfo : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
static MsgGetStreamInfo* create()
|
||||||
|
{
|
||||||
|
return new MsgGetStreamInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MsgGetStreamInfo() :
|
||||||
|
Message()
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgReportLimeSDRToGUI : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
float getCenterFrequency() const { return m_centerFrequency; }
|
||||||
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
|
uint32_t getLog2HardInterp() const { return m_log2HardInterp; }
|
||||||
|
|
||||||
|
static MsgReportLimeSDRToGUI* create(float centerFrequency, int sampleRate, uint32_t log2HardInterp)
|
||||||
|
{
|
||||||
|
return new MsgReportLimeSDRToGUI(centerFrequency, sampleRate, log2HardInterp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_centerFrequency;
|
||||||
|
int m_sampleRate;
|
||||||
|
uint32_t m_log2HardInterp;
|
||||||
|
|
||||||
|
MsgReportLimeSDRToGUI(float centerFrequency, int sampleRate, uint32_t log2HardInterp) :
|
||||||
|
Message(),
|
||||||
|
m_centerFrequency(centerFrequency),
|
||||||
|
m_sampleRate(sampleRate),
|
||||||
|
m_log2HardInterp(log2HardInterp)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgReportStreamInfo : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool getSuccess() const { return m_success; }
|
||||||
|
bool getActive() const { return m_active; }
|
||||||
|
uint32_t getFifoFilledCount() const { return m_fifoFilledCount; }
|
||||||
|
uint32_t getFifoSize() const { return m_fifoSize; }
|
||||||
|
uint32_t getUnderrun() const { return m_underrun; }
|
||||||
|
uint32_t getOverrun() const { return m_overrun; }
|
||||||
|
uint32_t getDroppedPackets() const { return m_droppedPackets; }
|
||||||
|
float getSampleRate() const { return m_sampleRate; }
|
||||||
|
float getLinkRate() const { return m_linkRate; }
|
||||||
|
uint64_t getTimestamp() const { return m_timestamp; }
|
||||||
|
|
||||||
|
static MsgReportStreamInfo* create(
|
||||||
|
bool success,
|
||||||
|
bool active,
|
||||||
|
uint32_t fifoFilledCount,
|
||||||
|
uint32_t fifoSize,
|
||||||
|
uint32_t underrun,
|
||||||
|
uint32_t overrun,
|
||||||
|
uint32_t droppedPackets,
|
||||||
|
float sampleRate,
|
||||||
|
float linkRate,
|
||||||
|
uint64_t timestamp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return new MsgReportStreamInfo(
|
||||||
|
success,
|
||||||
|
active,
|
||||||
|
fifoFilledCount,
|
||||||
|
fifoSize,
|
||||||
|
underrun,
|
||||||
|
overrun,
|
||||||
|
droppedPackets,
|
||||||
|
sampleRate,
|
||||||
|
linkRate,
|
||||||
|
timestamp
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_success;
|
||||||
|
// everything from lms_stream_status_t
|
||||||
|
bool m_active; //!< Indicates whether the stream is currently active
|
||||||
|
uint32_t m_fifoFilledCount; //!< Number of samples in FIFO buffer
|
||||||
|
uint32_t m_fifoSize; //!< Size of FIFO buffer
|
||||||
|
uint32_t m_underrun; //!< FIFO underrun count
|
||||||
|
uint32_t m_overrun; //!< FIFO overrun count
|
||||||
|
uint32_t m_droppedPackets; //!< Number of dropped packets by HW
|
||||||
|
float m_sampleRate; //!< Sampling rate of the stream
|
||||||
|
float m_linkRate; //!< Combined data rate of all stream of the same direction (TX or RX)
|
||||||
|
uint64_t m_timestamp; //!< Current HW timestamp
|
||||||
|
|
||||||
|
MsgReportStreamInfo(
|
||||||
|
bool success,
|
||||||
|
bool active,
|
||||||
|
uint32_t fifoFilledCount,
|
||||||
|
uint32_t fifoSize,
|
||||||
|
uint32_t underrun,
|
||||||
|
uint32_t overrun,
|
||||||
|
uint32_t droppedPackets,
|
||||||
|
float sampleRate,
|
||||||
|
float linkRate,
|
||||||
|
uint64_t timestamp
|
||||||
|
) :
|
||||||
|
Message(),
|
||||||
|
m_success(success),
|
||||||
|
m_active(active),
|
||||||
|
m_fifoFilledCount(fifoFilledCount),
|
||||||
|
m_fifoSize(fifoSize),
|
||||||
|
m_underrun(underrun),
|
||||||
|
m_overrun(overrun),
|
||||||
|
m_droppedPackets(droppedPackets),
|
||||||
|
m_sampleRate(sampleRate),
|
||||||
|
m_linkRate(linkRate),
|
||||||
|
m_timestamp(timestamp)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
LimeSDROutput(DeviceSinkAPI *deviceAPI);
|
||||||
|
virtual ~LimeSDROutput();
|
||||||
|
|
||||||
|
virtual bool start();
|
||||||
|
virtual void stop();
|
||||||
|
|
||||||
|
virtual const QString& getDeviceDescription() const;
|
||||||
|
virtual int getSampleRate() const;
|
||||||
|
virtual quint64 getCenterFrequency() const;
|
||||||
|
|
||||||
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
|
std::size_t getChannelIndex();
|
||||||
|
void getLORange(float& minF, float& maxF, float& stepF) const;
|
||||||
|
void getSRRange(float& minF, float& maxF, float& stepF) const;
|
||||||
|
void getLPRange(float& minF, float& maxF, float& stepF) const;
|
||||||
|
uint32_t getHWLog2Interp() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceSinkAPI *m_deviceAPI;
|
||||||
|
QMutex m_mutex;
|
||||||
|
LimeSDROutputSettings m_settings;
|
||||||
|
LimeSDROutputThread* m_limeSDROutputThread;
|
||||||
|
QString m_deviceDescription;
|
||||||
|
bool m_running;
|
||||||
|
DeviceLimeSDRShared m_deviceShared;
|
||||||
|
bool m_firstConfig;
|
||||||
|
|
||||||
|
lms_stream_t m_streamId;
|
||||||
|
|
||||||
|
bool openDevice();
|
||||||
|
void closeDevice();
|
||||||
|
bool applySettings(const LimeSDROutputSettings& settings, bool force);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUT_H_ */
|
825
plugins/samplesink/limesdroutput/limesdroutputgui.ui
Normal file
825
plugins/samplesink/limesdroutput/limesdroutputgui.ui
Normal file
@ -0,0 +1,825 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>LimeSDROutputGUI</class>
|
||||||
|
<widget class="QWidget" name="LimeSDROutputGUI">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>350</width>
|
||||||
|
<height>290</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>290</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Sans Serif</family>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>LimeSDR Input</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="bottomMargin">
|
||||||
|
<number>2</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="../../../sdrbase/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>Monospace</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="cursor">
|
||||||
|
<cursorShape>SizeVerCursor</cursorShape>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::StrongFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Main 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>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="channelNumberText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Channel number</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>#0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="ButtonSwitch" name="ncoEnable">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Enable the TSP NCO</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>NCO</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ncoReset">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reset the NCO to zero frequency</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>R</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ValueDial" name="ncoFrequency" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Monospace</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Center frequency with NCO engaged (kHz)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="ncoUnits">
|
||||||
|
<property name="text">
|
||||||
|
<string>kHz</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>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="QHBoxLayout" name="ncoSampleRateLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="hwInterpLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hw</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="hwInterp">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>TSP hardware interpolation factor</string>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>1</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>2</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>4</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>8</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>16</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>32</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="swInterpLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sw</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="swInterp">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Software interpolation factor</string>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>1</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>2</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>4</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>8</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>16</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>32</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<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="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>Monospace</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Device to host sample rate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="samplerateUnit">
|
||||||
|
<property name="text">
|
||||||
|
<string>S/s</string>
|
||||||
|
</property>
|
||||||
|
</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="lpfLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lpfLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>LP</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ValueDial" name="lpf" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Monospace</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Analog lowpass filer bandwidth (kHz)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lpfUnits">
|
||||||
|
<property name="text">
|
||||||
|
<string>kHz</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ButtonSwitch" name="lpFIREnable">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Enable or disable TSP digital FIR lowpass filters</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>FIR</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="ValueDial" name="lpFIR" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Monospace</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Digital FIR lowpass filers bandwidth (kHz)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lpFIRUnits">
|
||||||
|
<property name="text">
|
||||||
|
<string>kHz</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="gainLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="gainLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Gain</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSlider" name="gain">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Global gain setting (dB)</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>70</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>
|
||||||
|
<widget class="QLabel" name="gainText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Global gain (dB)</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>20dB</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="statusLayout">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="streamStatusLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>24</width>
|
||||||
|
<height>24</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Green when stream is reporting data</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../../../sdrbase/resources/res.qrc">:/stream.png</pixmap>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="underrunLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>12</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Red if underruns</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background:rgb(79,79,79);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>U</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="overrunLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>12</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Red if overruns</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background:rgb(79,79,79);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>O</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="droppedLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>12</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Red if dropped packets</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background:rgb(79,79,79);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>D</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="streamLinkRateText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>90</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Stream link rate (MB/s)</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>000.000 MB/s</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="fifoBar">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>8</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>FIFO fill status</string>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QProgressBar{border: 2px solid rgb(79, 79, 79); text-align: center;}
|
||||||
|
QToolTip{background-color: white; color: black;}</string>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<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_vga2">
|
||||||
|
<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="../../../sdrbase/resources/res.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
130
plugins/samplesink/limesdroutput/limesdroutputplugin.cpp
Normal file
130
plugins/samplesink/limesdroutput/limesdroutputplugin.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||||
|
// //
|
||||||
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU General Public License as published by //
|
||||||
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU General Public License V3 for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU General Public License //
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QtPlugin>
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "lime/LimeSuite.h"
|
||||||
|
#include "plugin/pluginapi.h"
|
||||||
|
#include "util/simpleserializer.h"
|
||||||
|
#include "device/devicesinkapi.h"
|
||||||
|
|
||||||
|
#include "limesdroutputgui.h"
|
||||||
|
#include "limesdroutputplugin.h"
|
||||||
|
|
||||||
|
const PluginDescriptor LimeSDROutputPlugin::m_pluginDescriptor = {
|
||||||
|
QString("LimeSDR Output"),
|
||||||
|
QString("3.4.0"),
|
||||||
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
|
true,
|
||||||
|
QString("https://github.com/f4exb/sdrangel")
|
||||||
|
};
|
||||||
|
|
||||||
|
const QString LimeSDROutputPlugin::m_hardwareID = "LimeSDR";
|
||||||
|
const QString LimeSDROutputPlugin::m_deviceTypeID = LIMESDROUTPUT_DEVICE_TYPE_ID;
|
||||||
|
|
||||||
|
LimeSDROutputPlugin::LimeSDROutputPlugin(QObject* parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const PluginDescriptor& LimeSDROutputPlugin::getPluginDescriptor() const
|
||||||
|
{
|
||||||
|
return m_pluginDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutputPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
|
{
|
||||||
|
pluginAPI->registerSampleSource(m_deviceTypeID, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginInterface::SamplingDevices LimeSDROutputPlugin::enumSampleSinks()
|
||||||
|
{
|
||||||
|
lms_info_str_t* deviceList;
|
||||||
|
int nbDevices;
|
||||||
|
SamplingDevices result;
|
||||||
|
|
||||||
|
if ((nbDevices = LMS_GetDeviceList(0)) <= 0)
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutputPlugin::enumSampleSources: Could not find any LimeSDR device");
|
||||||
|
return result; // empty result
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceList = new lms_info_str_t[nbDevices];
|
||||||
|
|
||||||
|
if (LMS_GetDeviceList(deviceList) < 0)
|
||||||
|
{
|
||||||
|
qDebug("LimeSDROutputPlugin::enumSampleSources: Could not obtain LimeSDR devices information");
|
||||||
|
delete[] deviceList;
|
||||||
|
return result; // empty result
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < nbDevices; i++)
|
||||||
|
{
|
||||||
|
std::string serial("N/D");
|
||||||
|
findSerial((const char *) deviceList[i], serial);
|
||||||
|
|
||||||
|
qDebug("LimeSDROutputPlugin::enumSampleSources: device #%d: %s", i, (char *) deviceList[i]);
|
||||||
|
QString displayedName(QString("LimeSDR[%1] %2").arg(i).arg(serial.c_str()));
|
||||||
|
result.append(SamplingDevice(displayedName,
|
||||||
|
m_hardwareID,
|
||||||
|
m_deviceTypeID,
|
||||||
|
QString(deviceList[i]),
|
||||||
|
i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] deviceList;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginGUI* LimeSDROutputPlugin::createSampleSinkPluginGUI(const QString& sinkId,QWidget **widget, DeviceSinkAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(sinkId == m_deviceTypeID)
|
||||||
|
{
|
||||||
|
LimeSDROutputGUI* gui = new LimeSDROutputGUI(deviceAPI);
|
||||||
|
*widget = gui;
|
||||||
|
return gui;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LimeSDROutputPlugin::findSerial(const char *lmsInfoStr, std::string& serial)
|
||||||
|
{
|
||||||
|
std::regex serial_reg("serial=([0-9,A-F]+)");
|
||||||
|
std::string input(lmsInfoStr);
|
||||||
|
std::smatch result;
|
||||||
|
std::regex_search(input, result, serial_reg);
|
||||||
|
|
||||||
|
if (result[1].str().length()>0)
|
||||||
|
{
|
||||||
|
serial = result[1].str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
50
plugins/samplesink/limesdroutput/limesdroutputplugin.h
Normal file
50
plugins/samplesink/limesdroutput/limesdroutputplugin.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 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_LIMESDROUTPUT_LIMESDROUTPUTPLUGIN_H_
|
||||||
|
#define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTPLUGIN_H_
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
|
class PluginAPI;
|
||||||
|
|
||||||
|
#define LIMESDROUTPUT_DEVICE_TYPE_ID "sdrangel.samplesink.limesdr"
|
||||||
|
|
||||||
|
class LimeSDROutputPlugin : public QObject, public PluginInterface {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(PluginInterface)
|
||||||
|
Q_PLUGIN_METADATA(IID LIMESDROUTPUT_DEVICE_TYPE_ID)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LimeSDROutputPlugin(QObject* parent = 0);
|
||||||
|
|
||||||
|
const PluginDescriptor& getPluginDescriptor() const;
|
||||||
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
|
virtual SamplingDevices enumSampleSinks();
|
||||||
|
virtual PluginGUI* createSampleSinkPluginGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI);
|
||||||
|
|
||||||
|
static const QString m_hardwareID;
|
||||||
|
static const QString m_deviceTypeID;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
static bool findSerial(const char *lmsInfoStr, std::string& serial);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTPLUGIN_H_ */
|
91
plugins/samplesink/limesdroutput/limesdroutputsettings.cpp
Normal file
91
plugins/samplesink/limesdroutput/limesdroutputsettings.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 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 "util/simpleserializer.h"
|
||||||
|
|
||||||
|
#include "limesdroutputsettings.h"
|
||||||
|
|
||||||
|
LimeSDROutputSettings::LimeSDROutputSettings()
|
||||||
|
{
|
||||||
|
resetToDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutputSettings::resetToDefaults()
|
||||||
|
{
|
||||||
|
m_centerFrequency = 435000*1000;
|
||||||
|
m_devSampleRate = 5000000;
|
||||||
|
m_log2HardInterp = 3;
|
||||||
|
m_log2SoftInterp = 0;
|
||||||
|
m_lpfBW = 4.5e6f;
|
||||||
|
m_lpfFIREnable = false;
|
||||||
|
m_lpfFIRBW = 2.5e6f;
|
||||||
|
m_gain = 30;
|
||||||
|
m_ncoEnable = false;
|
||||||
|
m_ncoFrequency = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray LimeSDROutputSettings::serialize() const
|
||||||
|
{
|
||||||
|
SimpleSerializer s(1);
|
||||||
|
|
||||||
|
s.writeS32(1, m_devSampleRate);
|
||||||
|
s.writeU32(2, m_log2HardInterp);
|
||||||
|
s.writeU32(5, m_log2SoftInterp);
|
||||||
|
s.writeFloat(7, m_lpfBW);
|
||||||
|
s.writeBool(8, m_lpfFIREnable);
|
||||||
|
s.writeFloat(9, m_lpfFIRBW);
|
||||||
|
s.writeU32(10, m_gain);
|
||||||
|
s.writeBool(11, m_ncoEnable);
|
||||||
|
s.writeS32(12, m_ncoFrequency);
|
||||||
|
|
||||||
|
return s.final();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LimeSDROutputSettings::deserialize(const QByteArray& data)
|
||||||
|
{
|
||||||
|
SimpleDeserializer d(data);
|
||||||
|
|
||||||
|
if (!d.isValid())
|
||||||
|
{
|
||||||
|
resetToDefaults();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.getVersion() == 1)
|
||||||
|
{
|
||||||
|
int intval;
|
||||||
|
|
||||||
|
d.readS32(1, &m_devSampleRate, 5000000);
|
||||||
|
d.readU32(2, &m_log2HardInterp, 2);
|
||||||
|
d.readU32(5, &m_log2SoftInterp, 0);
|
||||||
|
d.readFloat(7, &m_lpfBW, 1.5e6);
|
||||||
|
d.readBool(8, &m_lpfFIREnable, false);
|
||||||
|
d.readFloat(9, &m_lpfFIRBW, 1.5e6);
|
||||||
|
d.readU32(10, &m_gain, 0);
|
||||||
|
d.readBool(11, &m_ncoEnable, false);
|
||||||
|
d.readS32(12, &m_ncoFrequency, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resetToDefaults();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
54
plugins/samplesink/limesdroutput/limesdroutputsettings.h
Normal file
54
plugins/samplesink/limesdroutput/limesdroutputsettings.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 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_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_
|
||||||
|
#define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are the settings individual to each hardware channel or software Tx chain
|
||||||
|
* Plus the settings to be saved in the presets
|
||||||
|
*/
|
||||||
|
struct LimeSDROutputSettings
|
||||||
|
{
|
||||||
|
typedef enum {
|
||||||
|
FC_POS_INFRA = 0,
|
||||||
|
FC_POS_SUPRA,
|
||||||
|
FC_POS_CENTER
|
||||||
|
} fcPos_t;
|
||||||
|
|
||||||
|
// global settings to be saved
|
||||||
|
uint64_t m_centerFrequency;
|
||||||
|
int m_devSampleRate;
|
||||||
|
uint32_t m_log2HardInterp;
|
||||||
|
// channel settings
|
||||||
|
uint32_t m_log2SoftInterp;
|
||||||
|
float m_lpfBW; //!< LMS amalog lowpass filter bandwidth (Hz)
|
||||||
|
bool m_lpfFIREnable; //!< Enable LMS digital lowpass FIR filters
|
||||||
|
float m_lpfFIRBW; //!< LMS digital lowpass FIR filters bandwidth (Hz)
|
||||||
|
uint32_t m_gain; //!< Optimally distributed gain (dB)
|
||||||
|
bool m_ncoEnable; //!< Enable TSP NCO and mixing
|
||||||
|
int m_ncoFrequency; //!< Actual NCO frequency (the resulting frequency with mixing is displayed)
|
||||||
|
|
||||||
|
LimeSDROutputSettings();
|
||||||
|
void resetToDefaults();
|
||||||
|
QByteArray serialize() const;
|
||||||
|
bool deserialize(const QByteArray& data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ */
|
142
plugins/samplesink/limesdroutput/limesdroutputthread.cpp
Normal file
142
plugins/samplesink/limesdroutput/limesdroutputthread.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 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 <errno.h>
|
||||||
|
|
||||||
|
#include "limesdroutputthread.h"
|
||||||
|
#include "limesdroutputsettings.h"
|
||||||
|
|
||||||
|
LimeSDROutputThread::LimeSDROutputThread(lms_stream_t* stream, SampleSourceFifo* sampleFifo, QObject* parent) :
|
||||||
|
QThread(parent),
|
||||||
|
m_running(false),
|
||||||
|
m_stream(stream),
|
||||||
|
m_sampleFifo(sampleFifo),
|
||||||
|
m_log2Interp(0),
|
||||||
|
m_fcPos(LimeSDROutputSettings::FC_POS_CENTER)
|
||||||
|
{
|
||||||
|
m_sampleFifo->resize(16*LIMESDROUTPUT_BLOCKSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
LimeSDROutputThread::~LimeSDROutputThread()
|
||||||
|
{
|
||||||
|
stopWork();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutputThread::startWork()
|
||||||
|
{
|
||||||
|
if (m_running) return; // return if running already
|
||||||
|
|
||||||
|
m_startWaitMutex.lock();
|
||||||
|
start();
|
||||||
|
while(!m_running)
|
||||||
|
m_startWaiter.wait(&m_startWaitMutex, 100);
|
||||||
|
m_startWaitMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutputThread::stopWork()
|
||||||
|
{
|
||||||
|
if (!m_running) return; // return if not running
|
||||||
|
|
||||||
|
m_running = false;
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutputThread::setLog2Interpolation(unsigned int log2_interp)
|
||||||
|
{
|
||||||
|
m_log2Interp = log2_interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutputThread::setFcPos(int fcPos)
|
||||||
|
{
|
||||||
|
m_fcPos = fcPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimeSDROutputThread::run()
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
lms_stream_meta_t metadata; //Use metadata for additional control over sample receive function behaviour
|
||||||
|
metadata.flushPartialPacket = false; //Do not discard data remainder when read size differs from packet size
|
||||||
|
metadata.waitForTimestamp = false; //Do not wait for specific timestamps
|
||||||
|
|
||||||
|
m_running = true;
|
||||||
|
m_startWaiter.wakeAll();
|
||||||
|
|
||||||
|
if (LMS_StartStream(m_stream) < 0) {
|
||||||
|
qCritical("LimeSDROutputThread::run: could not start stream");
|
||||||
|
} else {
|
||||||
|
qDebug("LimeSDROutputThread::run: stream started");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_running)
|
||||||
|
{
|
||||||
|
callback(m_buf, 2 * res);
|
||||||
|
|
||||||
|
if ((res = LMS_SendStream(m_stream, (void *) m_buf, LIMESDR_BLOCKSIZE, &metadata, 1000)) < 0)
|
||||||
|
{
|
||||||
|
qCritical("LimeSDROutputThread::run write error: %s", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LMS_StopStream(m_stream) < 0) {
|
||||||
|
qCritical("LimeSDROutputThread::run: could not stop stream");
|
||||||
|
} else {
|
||||||
|
qDebug("LimeSDROutputThread::run: stream stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate according to specified log2 (ex: log2=4 => decim=16)
|
||||||
|
void LimeSDROutputThread::callback(const qint16* buf, qint32 len)
|
||||||
|
{
|
||||||
|
SampleVector::iterator beginRead;
|
||||||
|
m_sampleFifo->readAdvance(beginRead, len/(1<<m_log2Interp));
|
||||||
|
beginRead -= len;
|
||||||
|
|
||||||
|
if (m_log2Interp == 0)
|
||||||
|
{
|
||||||
|
m_interpolators.interpolate1(&beginRead, buf, len*2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (m_log2Interp)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
m_interpolators.interpolate2_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_interpolators.interpolate4_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
m_interpolators.interpolate8_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
m_interpolators.interpolate16_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
m_interpolators.interpolate32_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
m_interpolators.interpolate64_cen(&beginRead, buf, len*2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
64
plugins/samplesink/limesdroutput/limesdroutputthread.h
Normal file
64
plugins/samplesink/limesdroutput/limesdroutputthread.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2017 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_LIMESDROUTPUT_LIMESDROUTPUTTHREAD_H_
|
||||||
|
#define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTTHREAD_H_
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
|
||||||
|
#include "lime/LimeSuite.h"
|
||||||
|
|
||||||
|
#include "dsp/samplesourcefifo.h"
|
||||||
|
#include "dsp/interpolators.h"
|
||||||
|
|
||||||
|
#define LIMESDROUTPUT_BLOCKSIZE (1<<14) //complex samples per buffer ~10k (16k)
|
||||||
|
|
||||||
|
class LimeSDROutputThread : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
LimeSDROutputThread(lms_stream_t* stream, SampleSourceFifo* sampleFifo, QObject* parent = 0);
|
||||||
|
~LimeSDROutputThread();
|
||||||
|
|
||||||
|
void startWork();
|
||||||
|
void stopWork();
|
||||||
|
void setLog2Interpolation(unsigned int log2_ioterp);
|
||||||
|
void setFcPos(int fcPos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex m_startWaitMutex;
|
||||||
|
QWaitCondition m_startWaiter;
|
||||||
|
bool m_running;
|
||||||
|
|
||||||
|
lms_stream_t* m_stream;
|
||||||
|
qint16 m_buf[2*LIMESDROUTPUT_BLOCKSIZE]; //must hold I+Q values of each sample hence 2xcomplex size
|
||||||
|
SampleSourceFifo* m_sampleFifo;
|
||||||
|
|
||||||
|
unsigned int m_log2Interp; // soft decimation
|
||||||
|
int m_fcPos;
|
||||||
|
|
||||||
|
Interpolators<qint16, SDR_SAMP_SZ, 12> m_interpolators;
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void callback(const qint16* buf, qint32 len);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTTHREAD_H_ */
|
Loading…
x
Reference in New Issue
Block a user