major rework and move to CMake
This commit is contained in:
parent
aad7684645
commit
cb5ca682c2
|
@ -1,10 +1 @@
|
|||
tmp
|
||||
Makefile
|
||||
local.pri
|
||||
sdrangelove
|
||||
*.o
|
||||
*.pro.user
|
||||
|
||||
portaudio
|
||||
dsp/kiss_fft129
|
||||
hardware/unused
|
||||
CMakeLists.txt.user
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||
|
||||
project(sdrangelove)
|
||||
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
|
||||
set(QT_USE_QTOPENGL TRUE)
|
||||
|
||||
find_package(Qt4 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(PkgConfig)
|
||||
find_package(LibOsmoSDR REQUIRED)
|
||||
find_package(Portaudio REQUIRED)
|
||||
|
||||
set(sdrangelove_SOURCES
|
||||
main.cpp
|
||||
mainwindow.cpp
|
||||
osdrupgrade.cpp
|
||||
settings.cpp
|
||||
|
||||
dsp/channelizer.cpp
|
||||
dsp/dspengine.cpp
|
||||
dsp/fftwindow.cpp
|
||||
dsp/interpolator.cpp
|
||||
dsp/lowpass.cpp
|
||||
dsp/nco.cpp
|
||||
dsp/pidcontroller.cpp
|
||||
dsp/samplesink.cpp
|
||||
dsp/spectrum.cpp
|
||||
|
||||
gui/glspectrum.cpp
|
||||
gui/indicator.cpp
|
||||
gui/scale.cpp
|
||||
gui/scaleengine.cpp
|
||||
gui/valuedial.cpp
|
||||
gui/viewtoolbox.cpp
|
||||
|
||||
hardware/audiofifo.cpp
|
||||
hardware/audiooutput.cpp
|
||||
hardware/osmosdrinput.cpp
|
||||
hardware/osmosdrthread.cpp
|
||||
hardware/samplefifo.cpp
|
||||
hardware/samplesource.cpp
|
||||
hardware/soundcardinfo.cpp
|
||||
)
|
||||
|
||||
set(sdrangelove_HEADERS
|
||||
mainwindow.h
|
||||
osdrupgrade.h
|
||||
settings.h
|
||||
|
||||
dsp/channelizer.h
|
||||
dsp/dspengine.h
|
||||
dsp/dsptypes.h
|
||||
dsp/fftwindow.h
|
||||
dsp/interpolator.h
|
||||
dsp/kissfft.h
|
||||
dsp/lowpass.h
|
||||
dsp/nco.h
|
||||
dsp/pidcontroller.h
|
||||
dsp/samplesink.h
|
||||
dsp/spectrum.h
|
||||
|
||||
gui/glspectrum.h
|
||||
gui/indicator.h
|
||||
gui/physicalunit.h
|
||||
gui/scale.h
|
||||
gui/scaleengine.h
|
||||
gui/valuedial.h
|
||||
gui/viewtoolbox.h
|
||||
|
||||
hardware/audiofifo.h
|
||||
hardware/audiooutput.h
|
||||
hardware/osmosdrinput.h
|
||||
hardware/osmosdrthread.h
|
||||
hardware/samplefifo.h
|
||||
hardware/samplesource.h
|
||||
hardware/soundcardinfo.h
|
||||
)
|
||||
|
||||
set(sdrangelove_FORMS
|
||||
mainwindow.ui
|
||||
osdrupgrade.ui
|
||||
|
||||
gui/viewtoolbox.ui
|
||||
)
|
||||
|
||||
set(sdrangelove_RESOURCES
|
||||
resources/res.qrc
|
||||
)
|
||||
|
||||
include_directories(
|
||||
.
|
||||
portaudio/include
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
${LIBOSMOSDR_INCLUDE_DIR}
|
||||
${PORTAUDIO_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
include(${QT_USE_FILE})
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
|
||||
qt4_wrap_cpp(sdrangelove_HEADERS_MOC ${sdrangelove_HEADERS})
|
||||
qt4_wrap_cpp(sdrangelove_HEADERS_MOC ${sdrangelove_HEADERS})
|
||||
qt4_wrap_ui(sdrangelove_FORMS_HEADERS ${sdrangelove_FORMS})
|
||||
qt4_add_resources(sdrangelove_RESOURCES_RCC ${sdrangelove_RESOURCES})
|
||||
|
||||
add_executable(sdrangelove
|
||||
${sdrangelove_SOURCES}
|
||||
${sdrangelove_HEADERS_MOC}
|
||||
${sdrangelove_HEADERS_MOC}
|
||||
${sdrangelove_FORMS_HEADERS}
|
||||
${sdrangelove_RESOURCES_RCC}
|
||||
)
|
||||
|
||||
target_link_libraries(sdrangelove
|
||||
${QT_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${LIBOSMOSDR_LIBRARIES}
|
||||
${PORTAUDIO_LIBRARIES}
|
||||
)
|
|
@ -0,0 +1,27 @@
|
|||
if(NOT LIBOSMOSDR_FOUND)
|
||||
pkg_check_modules (LIBOSMOSDR_PKG libosmosdr)
|
||||
find_path(LIBOSMOSDR_INCLUDE_DIR NAMES osmosdr.h
|
||||
PATHS
|
||||
${LIBOSMOSDR_PKG_INCLUDE_DIRS}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
find_library(LIBOSMOSDR_LIBRARIES NAMES osmosdr
|
||||
PATHS
|
||||
${LIBOSMOSDR_PKG_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
if(LIBOSMOSDR_INCLUDE_DIR AND LIBOSMOSDR_LIBRARIES)
|
||||
set(LIBOSMOSDR_FOUND TRUE CACHE INTERNAL "libosmosdr found")
|
||||
message(STATUS "Found libosmosdr: ${LIBOSMOSDR_INCLUDE_DIR}, ${LIBOSMOSDR_LIBRARIES}")
|
||||
else(LIBOSMOSDR_INCLUDE_DIR AND LIBOSMOSDR_LIBRARIES)
|
||||
set(LIBOSMOSDR_FOUND FALSE CACHE INTERNAL "libosmosdr found")
|
||||
message(STATUS "libosmosdr not found.")
|
||||
endif(LIBOSMOSDR_INCLUDE_DIR AND LIBOSMOSDR_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LIBOSMOSDR_INCLUDE_DIR LIBOSMOSDR_LIBRARIES)
|
||||
|
||||
endif(NOT LIBOSMOSDR_FOUND)
|
|
@ -0,0 +1,35 @@
|
|||
# - Try to find Portaudio
|
||||
# Once done this will define
|
||||
#
|
||||
# PORTAUDIO_FOUND - system has Portaudio
|
||||
# PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory
|
||||
# PORTAUDIO_LIBRARIES - Link these to use Portaudio
|
||||
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(PC_PORTAUDIO portaudio)
|
||||
|
||||
find_path(PORTAUDIO_INCLUDE_DIRS
|
||||
NAMES
|
||||
portaudio.h
|
||||
PATHS
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
HINTS
|
||||
${PC_PORTAUDIO_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
find_library(PORTAUDIO_LIBRARIES
|
||||
NAMES
|
||||
portaudio
|
||||
PATHS
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
HINTS
|
||||
${PC_PORTAUDIO_LIBDIR}
|
||||
)
|
||||
|
||||
mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PORTAUDIO DEFAULT_MSG PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES)
|
|
@ -1,5 +1,122 @@
|
|||
#include <QTime>
|
||||
#include <stdio.h>
|
||||
#include "channelizer.h"
|
||||
#include "hardware/audiooutput.h"
|
||||
|
||||
Channelizer::Channelizer()
|
||||
{
|
||||
m_spectrum.configure(128 , 25, FFTWindow::Bartlett);
|
||||
m_buffer.resize(2048);
|
||||
m_bufferFill = 0;
|
||||
m_nco.setFreq(125000, 500000);
|
||||
m_interpolator.create(51, 32, 32 * 500000, 150000 / 2);
|
||||
m_distance = 500000.0 / 176400.0;
|
||||
|
||||
m_interpolator2.create(19, 8, 8 * 176400, 16000 / 2);
|
||||
m_distance2 = 4;
|
||||
|
||||
m_audioFifo.setSize(4, 44100 / 2 * 4);
|
||||
m_audioOutput = new AudioOutput;
|
||||
m_audioOutput->start(0, 44100, &m_audioFifo);
|
||||
m_resampler = 1.0;
|
||||
|
||||
m_resamplerCtrl.setup(0.00001, 0, -0.00001);
|
||||
}
|
||||
|
||||
Channelizer::~Channelizer()
|
||||
{
|
||||
m_audioOutput->stop();
|
||||
delete m_audioOutput;
|
||||
}
|
||||
|
||||
void Channelizer::setGLSpectrum(GLSpectrum* glSpectrum)
|
||||
{
|
||||
m_spectrum.setGLSpectrum(glSpectrum);
|
||||
}
|
||||
|
||||
size_t Channelizer::workUnitSize()
|
||||
{
|
||||
return m_buffer.size();
|
||||
}
|
||||
|
||||
size_t Channelizer::work(SampleVector::const_iterator begin, SampleVector::const_iterator end)
|
||||
{
|
||||
int buffered = m_audioOutput->bufferedSamples();
|
||||
|
||||
if(m_audioFifo.fill() < (m_audioFifo.size() / 6)) {
|
||||
while(m_audioFifo.fill() < (m_audioFifo.size() / 2)) {
|
||||
quint32 d = 0;
|
||||
m_audioFifo.write((quint8*)&d, 4);
|
||||
}
|
||||
qDebug("underflow - fill %d (vs %d)", m_audioFifo.fill(), m_audioFifo.size() / 4 / 2);
|
||||
}
|
||||
|
||||
|
||||
buffered = m_audioOutput->bufferedSamples();
|
||||
int fill = m_audioFifo.fill() / 4 + buffered;
|
||||
float err = (float)fill / ((m_audioFifo.size() / 4) / 2);
|
||||
|
||||
float ctrl = m_resamplerCtrl.feed(err);
|
||||
//float resamplerRate = (ctrl / 1.0);
|
||||
float resamplerRate = err;
|
||||
|
||||
if(resamplerRate < 0.9999)
|
||||
resamplerRate = 0.9999;
|
||||
else if(resamplerRate > 1.0001)
|
||||
resamplerRate = 1.0001;
|
||||
m_resampler = m_resampler * 0.99 + resamplerRate * 0.01;
|
||||
//m_resampler = resamplerRate;
|
||||
|
||||
if(m_resampler < 0.995)
|
||||
m_resampler = 0.995;
|
||||
else if(m_resampler > 1.005)
|
||||
m_resampler = 1.005;
|
||||
|
||||
//qDebug("%lld %5d %f %f %f", QDateTime::currentMSecsSinceEpoch(), fill, ctrl, m_resampler, err);
|
||||
|
||||
struct AudioSample {
|
||||
qint16 l;
|
||||
qint16 r;
|
||||
};
|
||||
|
||||
size_t count = end - begin;
|
||||
Complex ci;
|
||||
bool consumed;
|
||||
bool consumed2;
|
||||
|
||||
for(SampleVector::const_iterator it = begin; it < end; it++) {
|
||||
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
|
||||
//c *= m_nco.nextIQ();
|
||||
|
||||
consumed = false;
|
||||
if(m_interpolator.interpolate(&m_distance, c, &consumed, &ci)) {
|
||||
|
||||
Complex d = ci * conj(m_lastSample);
|
||||
m_lastSample = ci;
|
||||
//Complex demod(atan2(d.imag(), d.real()) * 0.5, 0);
|
||||
Real demod = atan2(d.imag(), d.real()) / M_PI;
|
||||
|
||||
consumed2 = false;
|
||||
c = Complex(demod, 0);
|
||||
while(!consumed2) {
|
||||
if(m_interpolator2.interpolate(&m_distance2, c, &consumed2, &ci)) {
|
||||
m_buffer[m_bufferFill++] = Sample(ci.real() * 32767.0, 0.0);
|
||||
|
||||
AudioSample s;
|
||||
s.l = ci.real() * 32767.0;
|
||||
s.r = s.l;
|
||||
m_audioFifo.write((quint8*)&s, 4, 1);
|
||||
|
||||
if(m_bufferFill >= m_buffer.size()) {
|
||||
m_spectrum.feed(m_buffer.begin(), m_buffer.end());
|
||||
m_bufferFill = 0;
|
||||
}
|
||||
m_distance2 += 4.0 * m_resampler;
|
||||
}
|
||||
}
|
||||
m_distance += 500000 / 176400.0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,42 @@
|
|||
#ifndef INCLUDE_CHANNELIZER_H
|
||||
#define INCLUDE_CHANNELIZER_H
|
||||
|
||||
class Channelizer {
|
||||
#include "samplesink.h"
|
||||
#include "spectrum.h"
|
||||
#include "nco.h"
|
||||
#include "interpolator.h"
|
||||
#include "pidcontroller.h"
|
||||
#include "hardware/audiofifo.h"
|
||||
|
||||
class AudioOutput;
|
||||
|
||||
class Channelizer : public SampleSink {
|
||||
public:
|
||||
Channelizer();
|
||||
~Channelizer();
|
||||
|
||||
void setGLSpectrum(GLSpectrum* glSpectrum);
|
||||
|
||||
size_t workUnitSize();
|
||||
size_t work(SampleVector::const_iterator begin, SampleVector::const_iterator end);
|
||||
|
||||
private:
|
||||
NCO m_nco;
|
||||
Interpolator m_interpolator;
|
||||
Real m_distance;
|
||||
Interpolator m_interpolator2;
|
||||
Real m_distance2;
|
||||
|
||||
SampleVector m_buffer;
|
||||
size_t m_bufferFill;
|
||||
Complex m_lastSample;
|
||||
|
||||
AudioOutput* m_audioOutput;
|
||||
AudioFifo m_audioFifo;
|
||||
Real m_resampler;
|
||||
PIDController m_resamplerCtrl;
|
||||
|
||||
Spectrum m_spectrum;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_CHANNELIZER_H
|
||||
|
|
|
@ -18,44 +18,20 @@
|
|||
#include <stdio.h>
|
||||
#include "dspengine.h"
|
||||
#include "settings.h"
|
||||
#include "channelizer.h"
|
||||
#include "hardware/osmosdrinput.h"
|
||||
#include "hardware/samplefifo.h"
|
||||
#include "gui/glspectrum.h"
|
||||
|
||||
#if 0
|
||||
static int isqrt(int n)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if(n <= 0)
|
||||
return 0;
|
||||
|
||||
if(n > 0xffffff)
|
||||
i = n >> 16;
|
||||
else if(n > 0xffff)
|
||||
i = n >> 12;
|
||||
else if(n > 0xff)
|
||||
i = n >> 8;
|
||||
else i = n >> 4;
|
||||
if(i <= 0)
|
||||
i = 1;
|
||||
|
||||
do {
|
||||
j = i;
|
||||
i = (j + n / j) / 2;
|
||||
} while (((i - j) >= 2) || ((j-i) >= 2));
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
DSPEngine::DSPEngine(Settings* settings, QObject* parent) :
|
||||
QThread(parent),
|
||||
m_debugEvent(false),
|
||||
m_settings(settings),
|
||||
m_state(StNotStarted),
|
||||
m_nextState(StIdle),
|
||||
m_sampleFifo(NULL),
|
||||
m_channelizerToAdd(NULL),
|
||||
m_channelizerToRemove(NULL),
|
||||
m_sampleFifo(),
|
||||
m_sampleSource(NULL)
|
||||
{
|
||||
moveToThread(this);
|
||||
|
@ -114,6 +90,32 @@ void DSPEngine::stopAcquistion()
|
|||
m_stateWaitMutex.unlock();
|
||||
}
|
||||
|
||||
bool DSPEngine::addChannelizer(Channelizer* channelizer)
|
||||
{
|
||||
if(!isRunning())
|
||||
return false;
|
||||
|
||||
m_stateWaitMutex.lock();
|
||||
m_channelizerToAdd = channelizer;
|
||||
while(m_channelizerToAdd != NULL)
|
||||
m_stateWaiter.wait(&m_stateWaitMutex, 100);
|
||||
m_stateWaitMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSPEngine::removeChannelizer(Channelizer* channelizer)
|
||||
{
|
||||
if(!isRunning())
|
||||
return false;
|
||||
|
||||
m_stateWaitMutex.lock();
|
||||
m_channelizerToRemove = channelizer;
|
||||
while(m_channelizerToRemove != NULL)
|
||||
m_stateWaiter.wait(&m_stateWaitMutex, 100);
|
||||
m_stateWaitMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSPEngine::triggerDebug()
|
||||
{
|
||||
m_debugEvent = true;
|
||||
|
@ -127,8 +129,18 @@ QString DSPEngine::errorMsg()
|
|||
return res;
|
||||
}
|
||||
|
||||
QString DSPEngine::deviceDesc()
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_deviceDescMutex);
|
||||
QString res = m_deviceDesc;
|
||||
res.detach();
|
||||
return res;
|
||||
}
|
||||
|
||||
void DSPEngine::run()
|
||||
{
|
||||
connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData()), Qt::QueuedConnection);
|
||||
|
||||
m_ready = createMembers();
|
||||
|
||||
m_state = StIdle;
|
||||
|
@ -193,7 +205,7 @@ void DSPEngine::imbalance(SampleVector::iterator begin, SampleVector::iterator e
|
|||
|
||||
// calculate imbalance as Q15.16
|
||||
if(m_qRange != 0)
|
||||
m_imbalance = (m_iRange << 16) / m_qRange;
|
||||
m_imbalance = ((uint)m_iRange << 16) / (uint)m_qRange;
|
||||
|
||||
// correct imbalance and convert back to signed int 16
|
||||
for(SampleVector::iterator it = begin; it < end; it++)
|
||||
|
@ -204,40 +216,79 @@ void DSPEngine::work()
|
|||
{
|
||||
size_t wus;
|
||||
size_t maxWorkUnitSize = 0;
|
||||
int count = 0;
|
||||
size_t samplesDone = 0;
|
||||
|
||||
wus = m_spectrum.workUnitSize();
|
||||
if(wus > maxWorkUnitSize)
|
||||
maxWorkUnitSize = wus;
|
||||
for(Channelizers::const_iterator it = m_channelizers.begin(); it != m_channelizers.end(); it++) {
|
||||
wus = (*it)->workUnitSize();
|
||||
if(wus > maxWorkUnitSize)
|
||||
maxWorkUnitSize = wus;
|
||||
}
|
||||
|
||||
while((m_sampleFifo->fill() > maxWorkUnitSize) && (m_state == m_nextState) && (count < m_sampleRate)) {
|
||||
while((m_sampleFifo.fill() > maxWorkUnitSize) && (m_state == m_nextState) && (samplesDone < m_sampleRate)) {
|
||||
SampleVector::iterator part1begin;
|
||||
SampleVector::iterator part1end;
|
||||
SampleVector::iterator part2begin;
|
||||
SampleVector::iterator part2end;
|
||||
|
||||
size_t count = m_sampleFifo->readBegin(m_sampleFifo->fill(), &part1begin, &part1end, &part2begin, &part2end);
|
||||
size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end);
|
||||
|
||||
// first part of FIFO data
|
||||
if(part1begin != part1end) {
|
||||
// correct stuff
|
||||
if(m_settings.dcOffsetCorrection())
|
||||
dcOffset(part1begin, part1end);
|
||||
if(m_settings.iqImbalanceCorrection())
|
||||
imbalance(part1begin, part1end);
|
||||
// feed data to handlers
|
||||
m_spectrum.feed(part1begin, part1end);
|
||||
for(Channelizers::const_iterator it = m_channelizers.begin(); it != m_channelizers.end(); it++)
|
||||
(*it)->feed(part1begin, part1end);
|
||||
}
|
||||
// second part of FIFO data (used when block wraps around)
|
||||
if(part2begin != part2end) {
|
||||
// correct stuff
|
||||
if(m_settings.dcOffsetCorrection())
|
||||
dcOffset(part2begin, part2end);
|
||||
if(m_settings.iqImbalanceCorrection())
|
||||
imbalance(part2begin, part2end);
|
||||
// feed data to handlers
|
||||
m_spectrum.feed(part2begin, part2end);
|
||||
for(Channelizers::const_iterator it = m_channelizers.begin(); it != m_channelizers.end(); it++)
|
||||
(*it)->feed(part1begin, part1end);
|
||||
}
|
||||
|
||||
m_sampleFifo->readCommit(count);
|
||||
// adjust FIFO pointers
|
||||
m_sampleFifo.readCommit(count);
|
||||
samplesDone += count;
|
||||
}
|
||||
|
||||
// check if the center frequency has changed (has to be responsive)
|
||||
if(m_settings.isModifiedCenterFreq())
|
||||
m_sampleSource->setCenterFrequency(m_settings.centerFreq());
|
||||
// check if decimation has changed (needed to be done here, because to high a sample rate can clog the switch)
|
||||
if(m_settings.isModifiedDecimation()) {
|
||||
m_sampleSource->setDecimation(m_settings.decimation());
|
||||
m_sampleRate = 4000000 / (1 << m_settings.decimation());
|
||||
qDebug("New rate: %d", m_sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
void DSPEngine::applyChannelizers()
|
||||
{
|
||||
// check for channelizers to add or remove
|
||||
if(m_channelizerToAdd != NULL) {
|
||||
m_channelizers.push_back(m_channelizerToAdd);
|
||||
m_channelizerToAdd = NULL;
|
||||
m_stateWaiter.wakeAll();
|
||||
}
|
||||
if(m_channelizerToRemove != NULL) {
|
||||
m_channelizers.remove(m_channelizerToRemove);
|
||||
m_channelizerToRemove = NULL;
|
||||
m_stateWaiter.wakeAll();
|
||||
}
|
||||
}
|
||||
|
||||
void DSPEngine::applyConfig()
|
||||
|
@ -246,12 +297,6 @@ void DSPEngine::applyConfig()
|
|||
if(m_settings.isModifiedIQSwap())
|
||||
m_sampleSource->setIQSwap(m_settings.iqSwap());
|
||||
|
||||
if(m_settings.isModifiedDecimation()) {
|
||||
m_sampleSource->setDecimation(m_settings.decimation());
|
||||
m_sampleRate = 4000000 / (1 << m_settings.decimation());
|
||||
qDebug("New rate: %d", m_sampleRate);
|
||||
}
|
||||
|
||||
if(m_settings.isModifiedFFTSize() || m_settings.isModifiedFFTOverlap() || m_settings.isModifiedFFTWindow()) {
|
||||
m_spectrum.configure(m_settings.fftSize(), m_settings.fftOverlap(), (FFTWindow::Function)m_settings.fftWindow());
|
||||
}
|
||||
|
@ -285,6 +330,14 @@ void DSPEngine::applyConfig()
|
|||
((OsmoSDRInput*)m_sampleSource)->setE4000ifStageGain(5, m_settings.e4000if5());
|
||||
if(m_settings.isModifiedE4000if6())
|
||||
((OsmoSDRInput*)m_sampleSource)->setE4000ifStageGain(6, m_settings.e4000if6());
|
||||
|
||||
if(m_settings.isModifiedFilterI1() || m_settings.isModifiedFilterI2() || m_settings.isModifiedFilterQ1() || m_settings.isModifiedFilterQ2()) {
|
||||
((OsmoSDRInput*)m_sampleSource)->setFilter(
|
||||
m_settings.filterI1(),
|
||||
m_settings.filterI2(),
|
||||
m_settings.filterQ1(),
|
||||
m_settings.filterQ2());
|
||||
}
|
||||
}
|
||||
|
||||
void DSPEngine::changeState()
|
||||
|
@ -330,6 +383,9 @@ DSPEngine::State DSPEngine::gotoIdle()
|
|||
return StIdle;
|
||||
|
||||
m_sampleSource->stopInput();
|
||||
m_deviceDescMutex.lock();
|
||||
m_deviceDesc.clear();
|
||||
m_deviceDescMutex.unlock();
|
||||
|
||||
return StIdle;
|
||||
}
|
||||
|
@ -366,6 +422,10 @@ DSPEngine::State DSPEngine::gotoRunning()
|
|||
m_settings.isModifiedE4000if4();
|
||||
m_settings.isModifiedE4000if5();
|
||||
m_settings.isModifiedE4000if6();
|
||||
m_settings.isModifiedFilterI1();
|
||||
m_settings.isModifiedFilterI2();
|
||||
m_settings.isModifiedFilterQ1();
|
||||
m_settings.isModifiedFilterQ2();
|
||||
|
||||
m_sampleRate = 4000000 / (1 << m_settings.decimation());
|
||||
qDebug("current rate: %d", m_sampleRate);
|
||||
|
@ -377,11 +437,15 @@ DSPEngine::State DSPEngine::gotoRunning()
|
|||
m_iRange = 1 << 16;
|
||||
m_qRange = 1 << 16;
|
||||
|
||||
if(!m_sampleFifo->setSize(2 * 500000))
|
||||
return gotoError("could not allocate SampleFifo");
|
||||
if(!m_sampleFifo.setSize(2 * 500000))
|
||||
return gotoError("Could not allocate SampleFifo");
|
||||
|
||||
if(!m_sampleSource->startInput(0, 4000000))
|
||||
return gotoError("could not start OsmoSDR");
|
||||
return gotoError("Could not start OsmoSDR");
|
||||
|
||||
m_deviceDescMutex.lock();
|
||||
m_deviceDesc = m_sampleSource->deviceDesc();
|
||||
m_deviceDescMutex.unlock();
|
||||
|
||||
m_sampleSource->setCenterFrequency(m_settings.centerFreq());
|
||||
m_sampleSource->setIQSwap(m_settings.iqSwap());
|
||||
|
@ -395,6 +459,11 @@ DSPEngine::State DSPEngine::gotoRunning()
|
|||
((OsmoSDRInput*)m_sampleSource)->setE4000ifStageGain(4, m_settings.e4000if4());
|
||||
((OsmoSDRInput*)m_sampleSource)->setE4000ifStageGain(5, m_settings.e4000if5());
|
||||
((OsmoSDRInput*)m_sampleSource)->setE4000ifStageGain(6, m_settings.e4000if6());
|
||||
((OsmoSDRInput*)m_sampleSource)->setFilter(
|
||||
m_settings.filterI1(),
|
||||
m_settings.filterI2(),
|
||||
m_settings.filterQ1(),
|
||||
m_settings.filterQ2());
|
||||
|
||||
return StRunning;
|
||||
}
|
||||
|
@ -404,21 +473,20 @@ DSPEngine::State DSPEngine::gotoError(const QString& errorMsg)
|
|||
QMutexLocker mutexLocker(&m_errorMsgMutex);
|
||||
m_errorMsg = errorMsg;
|
||||
m_state = StError;
|
||||
m_deviceDescMutex.lock();
|
||||
m_deviceDesc.clear();
|
||||
m_deviceDescMutex.unlock();
|
||||
return StError;
|
||||
}
|
||||
|
||||
bool DSPEngine::createMembers()
|
||||
{
|
||||
if((m_sampleFifo = new SampleFifo(this)) == NULL)
|
||||
return false;
|
||||
connect(m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData()), Qt::QueuedConnection);
|
||||
|
||||
if((m_timer = new QTimer(this)) == NULL)
|
||||
return false;
|
||||
connect(m_timer, SIGNAL(timeout()), this, SLOT(tick()));
|
||||
m_timer->start(250);
|
||||
|
||||
if((m_sampleSource = new OsmoSDRInput(m_sampleFifo)) == NULL)
|
||||
if((m_sampleSource = new OsmoSDRInput(&m_sampleFifo)) == NULL)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -430,10 +498,9 @@ void DSPEngine::destroyMembers()
|
|||
delete m_sampleSource;
|
||||
m_sampleSource = NULL;
|
||||
}
|
||||
if(m_sampleFifo != NULL) {
|
||||
delete m_sampleFifo;
|
||||
m_sampleFifo = NULL;
|
||||
}
|
||||
m_deviceDescMutex.lock();
|
||||
m_deviceDesc.clear();
|
||||
m_deviceDescMutex.unlock();
|
||||
}
|
||||
|
||||
void DSPEngine::handleData()
|
||||
|
@ -456,6 +523,8 @@ void DSPEngine::tick()
|
|||
qDebug("New state: %d: %s", m_state, stateNames[m_state]);
|
||||
}
|
||||
|
||||
applyChannelizers();
|
||||
|
||||
switch(m_state) {
|
||||
case StNotStarted:
|
||||
exit();
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
#include "kissfft.h"
|
||||
#include "fftwindow.h"
|
||||
#include "settings.h"
|
||||
#include "hardware/samplefifo.h"
|
||||
#include "spectrum.h"
|
||||
|
||||
class SampleSource;
|
||||
class SampleFifo;
|
||||
class GLSpectrum;
|
||||
class Channelizer;
|
||||
|
||||
class DSPEngine : public QThread {
|
||||
Q_OBJECT
|
||||
|
@ -54,15 +56,19 @@ public:
|
|||
bool startAcquisition();
|
||||
void stopAcquistion();
|
||||
|
||||
bool addChannelizer(Channelizer* channelizer);
|
||||
bool removeChannelizer(Channelizer* channelizer);
|
||||
|
||||
void triggerDebug();
|
||||
|
||||
State state() const { return m_state; }
|
||||
QString errorMsg();
|
||||
|
||||
private:
|
||||
typedef kissfft<Real, Complex> KissFFT;
|
||||
QString deviceDesc();
|
||||
|
||||
private:
|
||||
bool m_debugEvent;
|
||||
|
||||
Settings m_settings;
|
||||
|
||||
State m_state;
|
||||
|
@ -75,8 +81,16 @@ private:
|
|||
QMutex m_errorMsgMutex;
|
||||
QString m_errorMsg;
|
||||
|
||||
QMutex m_deviceDescMutex;
|
||||
QString m_deviceDesc;
|
||||
|
||||
Channelizer* m_channelizerToAdd;
|
||||
Channelizer* m_channelizerToRemove;
|
||||
typedef std::list<Channelizer*> Channelizers;
|
||||
SampleFifo m_sampleFifo;
|
||||
Channelizers m_channelizers;
|
||||
|
||||
QTimer* m_timer;
|
||||
SampleFifo* m_sampleFifo;
|
||||
SampleSource* m_sampleSource;
|
||||
|
||||
int m_sampleRate;
|
||||
|
@ -95,6 +109,7 @@ private:
|
|||
void imbalance(SampleVector::iterator begin, SampleVector::iterator end);
|
||||
void work();
|
||||
|
||||
void applyChannelizers();
|
||||
void applyConfig();
|
||||
void changeState();
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ void FFTWindow::create(Function function, int n)
|
|||
{
|
||||
Real (*wFunc)(Real n, Real i);
|
||||
|
||||
m_window.resize(n);
|
||||
m_window.clear();
|
||||
|
||||
switch(function) {
|
||||
case Flattop:
|
||||
|
@ -51,7 +51,7 @@ void FFTWindow::create(Function function, int n)
|
|||
}
|
||||
|
||||
for(int i = 0; i < n; i++)
|
||||
m_window[i] = wFunc(n, i);
|
||||
m_window.push_back(wFunc(n, i));
|
||||
}
|
||||
|
||||
void FFTWindow::apply(const std::vector<Real>& in, std::vector<Real>* out)
|
||||
|
|
|
@ -15,7 +15,7 @@ void Interpolator::create(int nTaps, int phaseSteps, double sampleRate, double c
|
|||
Real sum;
|
||||
|
||||
// make room
|
||||
m_samples.resize(nTaps);
|
||||
m_samples.resize(nTaps * 2);
|
||||
for(int i = 0; i < nTaps; i++)
|
||||
m_samples[i] = 0;
|
||||
m_ptr = 0;
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
}
|
||||
interpolate((int)floor(*distance * m_phaseSteps), result);
|
||||
doInterpolate((int)floor(*distance * (Real)m_phaseSteps), result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ private:
|
|||
m_samples[m_ptr] = next;
|
||||
}
|
||||
|
||||
void interpolate(int phase, Complex* result)
|
||||
void doInterpolate(int phase, Complex* result)
|
||||
{
|
||||
int sample = m_ptr;
|
||||
const Real* coeff = &m_taps[phase * m_nTaps];
|
||||
|
|
|
@ -25,12 +25,10 @@ bool NCO::m_tableInitialized = false;
|
|||
|
||||
void NCO::initTable()
|
||||
{
|
||||
int i;
|
||||
|
||||
if(m_tableInitialized)
|
||||
return;
|
||||
|
||||
for(i = 0; i < TableSize; i++)
|
||||
for(int i = 0; i < TableSize; i++)
|
||||
m_table[i] = cos((2.0 * M_PI * i) / TableSize);
|
||||
|
||||
m_tableInitialized = true;
|
||||
|
@ -51,7 +49,7 @@ void NCO::setFreq(Real freq, Real sampleRate)
|
|||
float NCO::next()
|
||||
{
|
||||
m_phase += m_phaseIncrement;
|
||||
while(m_phase > TableSize)
|
||||
while(m_phase >= TableSize)
|
||||
m_phase -= TableSize;
|
||||
while(m_phase < 0)
|
||||
m_phase += TableSize;
|
||||
|
@ -62,7 +60,7 @@ float NCO::next()
|
|||
Complex NCO::nextIQ()
|
||||
{
|
||||
m_phase += m_phaseIncrement;
|
||||
while(m_phase > TableSize)
|
||||
while(m_phase >= TableSize)
|
||||
m_phase -= TableSize;
|
||||
while(m_phase < 0)
|
||||
m_phase += TableSize;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#include "pidcontroller.h"
|
||||
|
||||
PIDController::PIDController() :
|
||||
m_p(0.0),
|
||||
m_i(0.0),
|
||||
m_d(0.0),
|
||||
m_int(0.0),
|
||||
m_diff(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
void PIDController::setup(Real p, Real i, Real d)
|
||||
{
|
||||
m_p = p;
|
||||
m_i = i;
|
||||
m_d = d;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef INCLUDE_PIDCONTROLLER_H
|
||||
#define INCLUDE_PIDCONTROLLER_H
|
||||
|
||||
#include "dsptypes.h"
|
||||
|
||||
class PIDController {
|
||||
private:
|
||||
Real m_p;
|
||||
Real m_i;
|
||||
Real m_d;
|
||||
Real m_int;
|
||||
Real m_diff;
|
||||
|
||||
public:
|
||||
PIDController();
|
||||
|
||||
void setup(Real p, Real i, Real d);
|
||||
|
||||
Real feed(Real v)
|
||||
{
|
||||
m_int += v * m_i;
|
||||
Real d = m_d * (m_diff - v);
|
||||
m_diff = v;
|
||||
return (v * m_p) + m_int + d;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INCLUDE_PIDCONTROLLER_H
|
|
@ -1,8 +1,8 @@
|
|||
#include "samplesink.h"
|
||||
|
||||
SampleSink::SampleSink() :
|
||||
m_buffer(),
|
||||
m_bufferFill(0)
|
||||
m_sinkBuffer(),
|
||||
m_sinkBufferFill(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -11,44 +11,44 @@ void SampleSink::feed(SampleVector::const_iterator begin, SampleVector::const_it
|
|||
size_t wus = workUnitSize();
|
||||
|
||||
// make sure our buffer is big enough for at least one work unit
|
||||
if(m_buffer.size() < wus)
|
||||
m_buffer.resize(wus);
|
||||
if(m_sinkBuffer.size() < wus)
|
||||
m_sinkBuffer.resize(wus);
|
||||
|
||||
while(begin < end) {
|
||||
// if the buffer contains something, keep filling it until it contains one complete work unit
|
||||
if((m_bufferFill > 0) && (m_bufferFill < wus)) {
|
||||
if((m_sinkBufferFill > 0) && (m_sinkBufferFill < wus)) {
|
||||
// check number if missing samples, but don't copy more than we have
|
||||
size_t len = wus - m_bufferFill;
|
||||
size_t len = wus - m_sinkBufferFill;
|
||||
if(len > (size_t)(end - begin))
|
||||
len = end - begin;
|
||||
// copy
|
||||
std::copy(begin, begin + len, m_buffer.begin() + m_bufferFill);
|
||||
std::copy(begin, begin + len, m_sinkBuffer.begin() + m_sinkBufferFill);
|
||||
// adjust pointers
|
||||
m_bufferFill += len;
|
||||
m_sinkBufferFill += len;
|
||||
begin += len;
|
||||
}
|
||||
|
||||
// if one complete work unit is in the buffer, feed it to the worker
|
||||
if(m_bufferFill >= wus) {
|
||||
if(m_sinkBufferFill >= wus) {
|
||||
size_t done = 0;
|
||||
while(m_bufferFill - done >= wus)
|
||||
done += work(m_buffer.begin() + done, m_buffer.begin() + done + wus);
|
||||
while(m_sinkBufferFill - done >= wus)
|
||||
done += work(m_sinkBuffer.begin() + done, m_sinkBuffer.begin() + done + wus);
|
||||
// now copy the remaining data to the front of the buffer (should be zero)
|
||||
if(m_bufferFill - done > 0) {
|
||||
if(m_sinkBufferFill - done > 0) {
|
||||
qDebug("error in SampleSink buffer management");
|
||||
std::copy(m_buffer.begin() + done, m_buffer.begin() + m_bufferFill, m_buffer.begin());
|
||||
std::copy(m_sinkBuffer.begin() + done, m_sinkBuffer.begin() + m_sinkBufferFill, m_sinkBuffer.begin());
|
||||
}
|
||||
m_bufferFill -= done;
|
||||
m_sinkBufferFill -= done;
|
||||
}
|
||||
|
||||
// if no remainder from last run is buffered and we have at least one work unit left, feed the data to the worker
|
||||
if(m_bufferFill == 0) {
|
||||
if(m_sinkBufferFill == 0) {
|
||||
while((size_t)(end - begin) > wus)
|
||||
begin += work(begin, begin + wus);
|
||||
// copy any remaining data to the buffer
|
||||
std::copy(begin, end, m_buffer.begin());
|
||||
m_bufferFill = end - begin;
|
||||
begin += m_bufferFill;
|
||||
std::copy(begin, end, m_sinkBuffer.begin());
|
||||
m_sinkBufferFill = end - begin;
|
||||
begin += m_sinkBufferFill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ public:
|
|||
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end);
|
||||
virtual size_t work(SampleVector::const_iterator begin, SampleVector::const_iterator end) = 0;
|
||||
|
||||
protected:
|
||||
SampleVector m_buffer;
|
||||
size_t m_bufferFill;
|
||||
private:
|
||||
SampleVector m_sinkBuffer;
|
||||
size_t m_sinkBufferFill;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SAMPLESINK_H
|
||||
|
|
|
@ -46,7 +46,7 @@ GLSpectrum::GLSpectrum(QWidget* parent) :
|
|||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
setMouseTracking(true);
|
||||
|
||||
setMinimumHeight(200);
|
||||
setMinimumSize(200, 200);
|
||||
|
||||
m_waterfallShare = 0.5;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ static double trunc(double d)
|
|||
|
||||
QString ScaleEngine::formatTick(double value, int decimalPlaces, bool fancyTime)
|
||||
{
|
||||
if((m_physicalUnit != Unit::Time) || (!fancyTime)) {
|
||||
if((m_physicalUnit != Unit::Time) || (!fancyTime) || 1) {
|
||||
return QString("%1").arg(value, 0, 'f', decimalPlaces);
|
||||
} else {
|
||||
QString str;
|
||||
|
@ -158,7 +158,15 @@ void ScaleEngine::calcScaleFactor()
|
|||
m_unitStr = QString("°");
|
||||
|
||||
case Unit::Time:
|
||||
m_unitStr = QString("s");
|
||||
if(median < 0.001) {
|
||||
m_unitStr = QString("µs");
|
||||
m_scale = 0.000001;
|
||||
} else if(median < 1.0) {
|
||||
m_unitStr = QString("ms");
|
||||
m_scale = 0.001;
|
||||
} else {
|
||||
m_unitStr = QString("s");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +187,7 @@ double ScaleEngine::calcMajorTickUnits(double distance, int* retDecimalPlaces)
|
|||
exponent = floor(log10x);
|
||||
base = pow(10.0, log10x - exponent);
|
||||
decimalPlaces = (int)(-exponent);
|
||||
|
||||
/*
|
||||
if((m_physicalUnit == Unit::Time) && (distance >= 1.0)) {
|
||||
if(retDecimalPlaces != NULL)
|
||||
*retDecimalPlaces = 0;
|
||||
|
@ -224,7 +232,7 @@ double ScaleEngine::calcMajorTickUnits(double distance, int* retDecimalPlaces)
|
|||
else if(distance < 30.0 * 86000.0)
|
||||
return 30.0 * 86000.0;
|
||||
else return 90.0 * 86000.0;
|
||||
} else {
|
||||
} else {*/
|
||||
if(base <= 1.0) {
|
||||
base = 1.0;
|
||||
} else if(base <= 2.0) {
|
||||
|
@ -237,8 +245,8 @@ double ScaleEngine::calcMajorTickUnits(double distance, int* retDecimalPlaces)
|
|||
base = 5.0;
|
||||
} else {
|
||||
base = 10.0;
|
||||
}
|
||||
}
|
||||
}/*
|
||||
}*/
|
||||
|
||||
if(retDecimalPlaces != NULL) {
|
||||
if(decimalPlaces < 0)
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include "viewtoolbox.h"
|
||||
#include "ui_viewtoolbox.h"
|
||||
|
||||
ViewToolBox::ViewToolBox(QWidget* parent) :
|
||||
QWidget(parent, Qt::Tool),
|
||||
ui(new Ui::ViewToolBox)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// align the QComboBox exactly below the QCheckBox
|
||||
QStyleOption o;
|
||||
ui->wfDirectionSpacer->changeSize(
|
||||
style()->subElementRect(QStyle::SE_CheckBoxIndicator, &o, this).width() - style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &o, this),
|
||||
0,
|
||||
QSizePolicy::Fixed,
|
||||
QSizePolicy::Fixed);
|
||||
|
||||
setFixedSize(sizeHint());
|
||||
}
|
||||
|
||||
ViewToolBox::~ViewToolBox()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ViewToolBox::setViewWaterfall(bool checked)
|
||||
{
|
||||
ui->viewWaterfall->setChecked(checked);
|
||||
if(checked)
|
||||
ui->waterfallUpward->setEnabled(true);
|
||||
else ui->waterfallUpward->setEnabled(false);
|
||||
}
|
||||
|
||||
void ViewToolBox::setWaterfallUpward(bool checked)
|
||||
{
|
||||
if(checked)
|
||||
ui->waterfallUpward->setCurrentIndex(0);
|
||||
else ui->waterfallUpward->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void ViewToolBox::setViewHistogram(bool checked)
|
||||
{
|
||||
ui->viewHistogram->setChecked(checked);
|
||||
}
|
||||
|
||||
void ViewToolBox::setViewLiveSpectrum(bool checked)
|
||||
{
|
||||
ui->viewLiveSpectrum->setChecked(checked);
|
||||
}
|
||||
|
||||
void ViewToolBox::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
emit closed();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void ViewToolBox::on_viewWaterfall_toggled(bool checked)
|
||||
{
|
||||
if(checked)
|
||||
ui->waterfallUpward->setEnabled(true);
|
||||
else ui->waterfallUpward->setEnabled(false);
|
||||
|
||||
emit viewWaterfall(checked);
|
||||
}
|
||||
|
||||
void ViewToolBox::on_waterfallUpward_currentIndexChanged(int index)
|
||||
{
|
||||
if(index == 0)
|
||||
emit waterfallUpward(true);
|
||||
else emit waterfallUpward(false);
|
||||
}
|
||||
|
||||
void ViewToolBox::on_viewHistogram_toggled(bool checked)
|
||||
{
|
||||
emit viewHistogram(checked);
|
||||
}
|
||||
|
||||
void ViewToolBox::on_viewLiveSpectrum_toggled(bool checked)
|
||||
{
|
||||
emit viewLiveSpectrum(checked);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_VIEWTOOLBOX_H
|
||||
#define INCLUDE_VIEWTOOLBOX_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class ViewToolBox;
|
||||
}
|
||||
|
||||
class ViewToolBox : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewToolBox(QWidget* parent = NULL);
|
||||
~ViewToolBox();
|
||||
|
||||
void setViewWaterfall(bool checked);
|
||||
void setWaterfallUpward(bool checked);
|
||||
void setViewHistogram(bool checked);
|
||||
void setViewLiveSpectrum(bool checked);
|
||||
|
||||
signals:
|
||||
void closed();
|
||||
void viewWaterfall(bool checked);
|
||||
void waterfallUpward(bool checked);
|
||||
void viewHistogram(bool checked);
|
||||
void viewLiveSpectrum(bool checked);
|
||||
|
||||
private slots:
|
||||
void on_viewWaterfall_toggled(bool checked);
|
||||
void on_waterfallUpward_currentIndexChanged(int index);
|
||||
void on_viewHistogram_toggled(bool checked);
|
||||
void on_viewLiveSpectrum_toggled(bool checked);
|
||||
|
||||
private:
|
||||
Ui::ViewToolBox* ui;
|
||||
|
||||
void closeEvent(QCloseEvent*);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_VIEWTOOLBOX_H
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ViewToolBox</class>
|
||||
<widget class="QWidget" name="ViewToolBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>191</width>
|
||||
<height>117</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>View Toolbox</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="0">
|
||||
<spacer name="wfDirectionSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QComboBox" name="waterfallUpward">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Downward</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Upward</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="4">
|
||||
<widget class="QCheckBox" name="viewHistogram">
|
||||
<property name="text">
|
||||
<string>Display &Histogram</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="4">
|
||||
<widget class="QCheckBox" name="viewLiveSpectrum">
|
||||
<property name="text">
|
||||
<string>Paint &Live Spectrum</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QCheckBox" name="viewWaterfall">
|
||||
<property name="text">
|
||||
<string>Display &Waterfall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>viewWaterfall</tabstop>
|
||||
<tabstop>waterfallUpward</tabstop>
|
||||
<tabstop>viewHistogram</tabstop>
|
||||
<tabstop>viewLiveSpectrum</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,211 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string.h>
|
||||
#include <QTime>
|
||||
#include "audiofifo.h"
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
bool AudioFifo::create(uint sampleSize, uint size)
|
||||
{
|
||||
if(m_fifo != NULL) {
|
||||
delete[] m_fifo;
|
||||
m_fifo = NULL;
|
||||
}
|
||||
|
||||
m_sampleSize = sampleSize;
|
||||
m_size = 0;
|
||||
m_fill = 0;
|
||||
m_head = 0;
|
||||
m_tail = 0;
|
||||
|
||||
// only allow space for full samples
|
||||
size -= size % sampleSize;
|
||||
|
||||
if((m_fifo = new qint8[size]) == NULL) {
|
||||
qDebug("out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_size = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
AudioFifo::AudioFifo() :
|
||||
m_fifo(NULL)
|
||||
{
|
||||
m_size = 0;
|
||||
m_fill = 0;
|
||||
m_head = 0;
|
||||
m_tail = 0;
|
||||
}
|
||||
|
||||
AudioFifo::AudioFifo(uint sampleSize, uint size) :
|
||||
m_fifo(NULL)
|
||||
{
|
||||
create(sampleSize, size);
|
||||
}
|
||||
|
||||
AudioFifo::~AudioFifo()
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
if(m_fifo != NULL) {
|
||||
delete[] m_fifo;
|
||||
m_fifo = NULL;
|
||||
}
|
||||
|
||||
m_writeWaitCondition.wakeOne();
|
||||
m_readWaitCondition.wakeOne();
|
||||
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
bool AudioFifo::setSize(uint sampleSize, uint size)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
return create(sampleSize, size);
|
||||
}
|
||||
|
||||
uint AudioFifo::write(const quint8* data, uint len, int timeout)
|
||||
{
|
||||
QTime time;
|
||||
uint total;
|
||||
uint remaining;
|
||||
uint copyLen;
|
||||
|
||||
if(m_fifo == NULL)
|
||||
return 0;
|
||||
|
||||
time.start();
|
||||
m_mutex.lock();
|
||||
|
||||
if(timeout == 0)
|
||||
total = MIN(len, m_size - m_fill);
|
||||
else total = len;
|
||||
|
||||
// make sure, only complete samples are handled
|
||||
total -= total % m_sampleSize;
|
||||
|
||||
remaining = total;
|
||||
while(remaining > 0) {
|
||||
if(isFull()) {
|
||||
if(time.elapsed() < timeout) {
|
||||
m_writeWaitLock.lock();
|
||||
m_mutex.unlock();
|
||||
int ms = timeout - time.elapsed();
|
||||
if(ms < 1)
|
||||
ms = 1;
|
||||
bool ok = m_writeWaitCondition.wait(&m_writeWaitLock, ms);
|
||||
m_writeWaitLock.unlock();
|
||||
if(!ok)
|
||||
return total - remaining;
|
||||
m_mutex.lock();
|
||||
if(m_fifo == NULL) {
|
||||
m_mutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
m_mutex.unlock();
|
||||
return total - remaining;
|
||||
}
|
||||
}
|
||||
copyLen = MIN(remaining, m_size - m_fill);
|
||||
copyLen = MIN(copyLen, m_size - m_tail);
|
||||
memcpy(m_fifo + m_tail, data, copyLen);
|
||||
m_tail += copyLen;
|
||||
m_tail %= m_size;
|
||||
m_fill += copyLen;
|
||||
data += copyLen;
|
||||
remaining -= copyLen;
|
||||
m_readWaitCondition.wakeOne();
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
return total;
|
||||
}
|
||||
|
||||
uint AudioFifo::read(quint8* data, uint len, int timeout)
|
||||
{
|
||||
QTime time;
|
||||
uint total;
|
||||
uint remaining;
|
||||
uint copyLen;
|
||||
|
||||
if(m_fifo == NULL)
|
||||
return 0;
|
||||
|
||||
time.start();
|
||||
m_mutex.lock();
|
||||
|
||||
if(timeout == 0)
|
||||
total = MIN(len, m_fill);
|
||||
else total = len;
|
||||
|
||||
remaining = total;
|
||||
while(remaining > 0) {
|
||||
if(isEmpty()) {
|
||||
if(time.elapsed() < timeout) {
|
||||
m_readWaitLock.lock();
|
||||
m_mutex.unlock();
|
||||
int ms = timeout - time.elapsed();
|
||||
if(ms < 1)
|
||||
ms = 1;
|
||||
bool ok = m_readWaitCondition.wait(&m_readWaitLock, ms);
|
||||
m_readWaitLock.unlock();
|
||||
if(!ok)
|
||||
return total - remaining;
|
||||
m_mutex.lock();
|
||||
if(m_fifo == NULL) {
|
||||
m_mutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
m_mutex.unlock();
|
||||
return total - remaining;
|
||||
}
|
||||
}
|
||||
|
||||
copyLen = MIN(remaining, m_fill);
|
||||
copyLen = MIN(copyLen, m_size - m_head);
|
||||
memcpy(data, m_fifo + m_head, copyLen);
|
||||
m_head += copyLen;
|
||||
m_head %= m_size;
|
||||
m_fill -= copyLen;
|
||||
data += copyLen;
|
||||
remaining -= copyLen;
|
||||
m_writeWaitCondition.wakeOne();
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
return total;
|
||||
}
|
||||
|
||||
uint AudioFifo::drain(uint len)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
if(len > m_fill)
|
||||
len = m_fill;
|
||||
m_head = (m_head + len) % m_size;
|
||||
m_fill -= len;
|
||||
|
||||
m_writeWaitCondition.wakeOne();
|
||||
return len;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_AUDIOFIFO_H
|
||||
#define INCLUDE_AUDIOFIFO_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
|
||||
class AudioFifo {
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
|
||||
qint8* m_fifo;
|
||||
|
||||
uint m_sampleSize;
|
||||
|
||||
uint m_size;
|
||||
uint m_fill;
|
||||
uint m_head;
|
||||
uint m_tail;
|
||||
|
||||
QMutex m_writeWaitLock;
|
||||
QMutex m_readWaitLock;
|
||||
QWaitCondition m_writeWaitCondition;
|
||||
QWaitCondition m_readWaitCondition;
|
||||
|
||||
bool create(uint sampleSize, uint size);
|
||||
|
||||
public:
|
||||
AudioFifo();
|
||||
AudioFifo(uint sampleSize, uint size);
|
||||
~AudioFifo();
|
||||
|
||||
bool setSize(uint sampleSize, uint size);
|
||||
|
||||
uint write(const quint8* data, uint len, int timeout = INT_MAX);
|
||||
uint read(quint8* data, uint len, int timeout = INT_MAX);
|
||||
|
||||
uint drain(uint count);
|
||||
|
||||
inline uint flush() { return drain(m_fill); }
|
||||
inline int fill() const { return m_fill; }
|
||||
inline bool isEmpty() const { return m_fill == 0; }
|
||||
inline bool isFull() const { return m_fill == m_size; }
|
||||
inline uint size() const { return m_size; }
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AUDIOFIFO_H
|
|
@ -0,0 +1,124 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QMessageBox>
|
||||
#include "audiooutput.h"
|
||||
#include "audiofifo.h"
|
||||
|
||||
int AudioOutput::callbackHelper(
|
||||
const void *inputBuffer,
|
||||
void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData)
|
||||
{
|
||||
AudioOutput* audioOutput = (AudioOutput*)userData;
|
||||
|
||||
if(outputBuffer == NULL)
|
||||
return 0;
|
||||
|
||||
return audioOutput->callback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags);
|
||||
}
|
||||
|
||||
int AudioOutput::callback(
|
||||
const void* inputBuffer,
|
||||
void* outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo*
|
||||
timeInfo, PaStreamCallbackFlags statusFlags)
|
||||
{
|
||||
Q_UNUSED(inputBuffer);
|
||||
Q_UNUSED(timeInfo);
|
||||
Q_UNUSED(statusFlags);
|
||||
|
||||
int needed = framesPerBuffer * 4;
|
||||
int done = m_audioFifo->read((quint8*)outputBuffer, needed, 1);
|
||||
|
||||
memset(((quint8*)outputBuffer) + done, 0x00, needed - done);
|
||||
|
||||
m_streamStartTime += (PaTime)framesPerBuffer / (PaTime)m_sampleRate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AudioOutput::AudioOutput() :
|
||||
m_stream(NULL),
|
||||
m_audioFifo(NULL),
|
||||
m_sampleRate(0)
|
||||
{
|
||||
}
|
||||
|
||||
AudioOutput::~AudioOutput()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
bool AudioOutput::start(int device, int rate, AudioFifo* audioFifo)
|
||||
{
|
||||
if(m_stream != NULL)
|
||||
stop();
|
||||
|
||||
PaStreamParameters outputParameters;
|
||||
const PaStreamInfo* streamInfo;
|
||||
PaError err;
|
||||
|
||||
m_audioFifo = audioFifo;
|
||||
|
||||
outputParameters.device = device;
|
||||
outputParameters.channelCount = 2;
|
||||
outputParameters.sampleFormat = paInt16;
|
||||
outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
|
||||
outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
qDebug("AudioOutput: open");
|
||||
if((err = Pa_OpenStream(&m_stream, NULL, &outputParameters, rate, 1024, paClipOff, callbackHelper, this)) != paNoError)
|
||||
goto failed;
|
||||
|
||||
qDebug("AudioOutput: start");
|
||||
m_streamStartTime = Pa_GetStreamTime(m_stream);
|
||||
if((err = Pa_StartStream(m_stream)) != paNoError)
|
||||
goto failed;
|
||||
|
||||
streamInfo = Pa_GetStreamInfo(m_stream);
|
||||
m_sampleRate = streamInfo->sampleRate;
|
||||
|
||||
qDebug("AudioOutput: playback has started (%s @ %d Hz)", Pa_GetDeviceInfo(outputParameters.device)->name, rate);
|
||||
return true;
|
||||
|
||||
failed:
|
||||
qCritical("AudioOutput: playback failed: %s (%d)", Pa_GetErrorText(err), err);
|
||||
Pa_CloseStream(m_stream);
|
||||
m_stream = NULL;
|
||||
m_sampleRate = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioOutput::stop()
|
||||
{
|
||||
if(m_stream != NULL) {
|
||||
Pa_StopStream(m_stream);
|
||||
Pa_CloseStream(m_stream);
|
||||
m_stream = NULL;
|
||||
m_sampleRate = 0;
|
||||
qDebug("AudioOutput: stopped");
|
||||
}
|
||||
}
|
||||
|
||||
int AudioOutput::bufferedSamples()
|
||||
{
|
||||
return (Pa_GetStreamTime(m_stream) - m_streamStartTime) * m_sampleRate;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_AUDIOOUTPUT_H
|
||||
#define INCLUDE_AUDIOOUTPUT_H
|
||||
|
||||
#include <QMutex>
|
||||
#include "portaudio.h"
|
||||
|
||||
class AudioFifo;
|
||||
|
||||
class AudioOutput {
|
||||
private:
|
||||
PaStream* m_stream;
|
||||
AudioFifo* m_audioFifo;
|
||||
|
||||
int m_sampleRate;
|
||||
PaTime m_streamStartTime;
|
||||
|
||||
static int callbackHelper(
|
||||
const void* inputBuffer,
|
||||
void* outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void* userData);
|
||||
|
||||
int callback(
|
||||
const void* inputBuffer,
|
||||
void* outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags);
|
||||
|
||||
public:
|
||||
AudioOutput();
|
||||
~AudioOutput();
|
||||
|
||||
bool start(int device, int rate, AudioFifo* audioFifo);
|
||||
void stop();
|
||||
|
||||
int bufferedSamples();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_AUDIOOUTPUT_H
|
|
@ -23,7 +23,8 @@
|
|||
OsmoSDRInput::OsmoSDRInput(SampleFifo* sampleFifo) :
|
||||
SampleSource(sampleFifo),
|
||||
m_dev(NULL),
|
||||
m_osmoSDRThread(NULL)
|
||||
m_osmoSDRThread(NULL),
|
||||
m_deviceDesc()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,6 +56,7 @@ bool OsmoSDRInput::startInput(int device, int rate)
|
|||
goto failed;
|
||||
}
|
||||
qDebug("OsmoSDRInput open: %s %s, SN: %s", vendor, product, serial);
|
||||
m_deviceDesc = QString("%1 (SN %2)").arg(product).arg(serial);
|
||||
|
||||
if((res = osmosdr_set_sample_rate(m_dev, rate)) < 0) {
|
||||
qCritical("error setting sample rate");
|
||||
|
@ -96,6 +98,7 @@ void OsmoSDRInput::stopInput()
|
|||
osmosdr_close(m_dev);
|
||||
m_dev = NULL;
|
||||
}
|
||||
m_deviceDesc.clear();
|
||||
}
|
||||
|
||||
bool OsmoSDRInput::setCenterFrequency(qint64 freq)
|
||||
|
@ -119,6 +122,11 @@ bool OsmoSDRInput::setDecimation(int dec)
|
|||
return osmosdr_set_fpga_decimation(m_dev, dec);
|
||||
}
|
||||
|
||||
const QString& OsmoSDRInput::deviceDesc() const
|
||||
{
|
||||
return m_deviceDesc;
|
||||
}
|
||||
|
||||
bool OsmoSDRInput::setE4000LNAGain(int gain)
|
||||
{
|
||||
if(m_dev == NULL)
|
||||
|
@ -146,3 +154,10 @@ bool OsmoSDRInput::setE4000ifStageGain(int stage, int gain)
|
|||
return false;
|
||||
return osmosdr_set_tuner_if_gain(m_dev, stage, gain);
|
||||
}
|
||||
|
||||
bool OsmoSDRInput::setFilter(quint8 i1, quint8 i2, quint8 q1, quint8 q2)
|
||||
{
|
||||
if(m_dev == NULL)
|
||||
return false;
|
||||
return osmosdr_set_iq_amp(m_dev, i1, i2, q1, q2);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "samplesource.h"
|
||||
#include <osmosdr.h>
|
||||
#include <QString>
|
||||
|
||||
class OsmoSDRThread;
|
||||
|
||||
|
@ -35,14 +36,18 @@ public:
|
|||
bool setIQSwap(bool sw);
|
||||
bool setDecimation(int dec);
|
||||
|
||||
const QString& deviceDesc() const;
|
||||
|
||||
bool setE4000LNAGain(int gain);
|
||||
bool setE4000MixerGain(int gain);
|
||||
bool setE4000MixerEnh(int gain);
|
||||
bool setE4000ifStageGain(int stage, int gain);
|
||||
bool setFilter(quint8 i1, quint8 i2, quint8 q1, quint8 q2);
|
||||
|
||||
private:
|
||||
osmosdr_dev_t* m_dev;
|
||||
OsmoSDRThread* m_osmoSDRThread;
|
||||
QString m_deviceDesc;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_OSMOSDRINPUT_H
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "osmosdrthread.h"
|
||||
#include "samplefifo.h"
|
||||
|
@ -54,6 +55,8 @@ void OsmoSDRThread::run()
|
|||
m_running = true;
|
||||
m_startWaiter.wakeAll();
|
||||
|
||||
//m_f = fopen("/tmp/samples.bin", "wb");
|
||||
|
||||
while(m_running) {
|
||||
if((res = osmosdr_read_async(m_dev, &OsmoSDRThread::callbackHelper, this, 8, sizeof(Sample) * 16384)) < 0) {
|
||||
qCritical("OsmoSDRThread: async error: %s", strerror(errno));
|
||||
|
@ -66,7 +69,17 @@ void OsmoSDRThread::run()
|
|||
|
||||
void OsmoSDRThread::callback(quint8* buf, qint32 len)
|
||||
{
|
||||
m_sampleFifo->write((SampleVector::const_iterator)((Sample*)buf), (SampleVector::const_iterator)((Sample*)(buf + len)));
|
||||
/*
|
||||
qDebug("%d", len);
|
||||
|
||||
for(int i = 0; i < len / 2; i += 2) {
|
||||
((qint16*)buf)[i] = sin((float)(cntr) * 16384* 2.0 * M_PI / 65536.0) * 5000.0;
|
||||
((qint16*)buf)[i + 1] = -cos((float)(cntr++) * 16384*2.0 * M_PI / 65536.0) * 5000.0;
|
||||
}*/
|
||||
|
||||
//m_sampleFifo->write((SampleVector::const_iterator)((Sample*)buf), (SampleVector::const_iterator)((Sample*)(buf + len)));
|
||||
//fwrite(buf, 1, len, m_f);
|
||||
m_sampleFifo->write(buf, len);
|
||||
if(!m_running)
|
||||
osmosdr_cancel_async(m_dev);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
QMutex m_startWaitMutex;
|
||||
QWaitCondition m_startWaiter;
|
||||
bool m_running;
|
||||
FILE* m_f;
|
||||
|
||||
osmosdr_dev_t* m_dev;
|
||||
SampleFifo* m_sampleFifo;
|
||||
|
|
|
@ -67,6 +67,49 @@ bool SampleFifo::setSize(int size)
|
|||
return m_data.size() == (size_t)size;
|
||||
}
|
||||
|
||||
size_t SampleFifo::write(const quint8* data, size_t count)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
size_t total;
|
||||
int remaining;
|
||||
int len;
|
||||
const Sample* begin = (const Sample*)data;
|
||||
count /= 4;
|
||||
|
||||
total = MIN(count, m_size - m_fill);
|
||||
if(total < count) {
|
||||
if(m_suppressed < 0) {
|
||||
m_suppressed = 0;
|
||||
m_msgRateTimer.start();
|
||||
qCritical("SampleFifo: overflow - dropping %d samples", count - total);
|
||||
} else {
|
||||
if(m_msgRateTimer.elapsed() > 2500) {
|
||||
qCritical("SampleFifo: %d messages dropped", m_suppressed);
|
||||
qCritical("SampleFifo: overflow - dropping %d samples", count - total);
|
||||
m_suppressed = -1;
|
||||
} else {
|
||||
m_suppressed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remaining = total;
|
||||
while(remaining > 0) {
|
||||
len = MIN(remaining, m_size - m_tail);
|
||||
std::copy(begin, begin + len, m_data.begin() + m_tail);
|
||||
m_tail += len;
|
||||
m_tail %= m_size;
|
||||
m_fill += len;
|
||||
begin += len;
|
||||
remaining -= len;
|
||||
}
|
||||
|
||||
if(m_fill > 0)
|
||||
emit dataReady();
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t SampleFifo::write(SampleVector::const_iterator begin, SampleVector::const_iterator end)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
|
|
@ -45,9 +45,13 @@ public:
|
|||
SampleFifo(int size, QObject* parent = NULL);
|
||||
~SampleFifo();
|
||||
|
||||
SampleFifo(const SampleFifo&);
|
||||
SampleFifo& operator=(const SampleFifo&);
|
||||
|
||||
bool setSize(int size);
|
||||
inline size_t fill() const { return m_fill; }
|
||||
|
||||
size_t write(const quint8* data, size_t count);
|
||||
size_t write(SampleVector::const_iterator begin, SampleVector::const_iterator end);
|
||||
|
||||
size_t read(SampleVector::iterator begin, SampleVector::iterator end);
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
virtual bool setIQSwap(bool sw) = 0;
|
||||
virtual bool setDecimation(int dec) = 0;
|
||||
|
||||
virtual const QString& deviceDesc() const = 0;
|
||||
|
||||
protected:
|
||||
SampleFifo* m_sampleFifo;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QMessageBox>
|
||||
#include "soundcardinfo.h"
|
||||
#include "portaudio.h"
|
||||
|
||||
SoundcardInfo::SoundcardInfo()
|
||||
{
|
||||
const PaDeviceInfo *deviceInfo;
|
||||
const PaHostApiInfo *apiInfo;
|
||||
PaError err;
|
||||
int numDevices;
|
||||
int i;
|
||||
QString name;
|
||||
|
||||
if((numDevices = Pa_GetDeviceCount()) < 0) {
|
||||
err = numDevices;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
m_devices.clear();
|
||||
qDebug("Audio initialisation: %d devices found", numDevices);
|
||||
|
||||
for(i = 0; i < numDevices; i++) {
|
||||
deviceInfo = Pa_GetDeviceInfo(i);
|
||||
apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
|
||||
|
||||
name = QString("%1 (record %2, playblack %3, API %4)").
|
||||
arg(QString::fromLatin1(deviceInfo->name)).
|
||||
arg(deviceInfo->maxInputChannels).
|
||||
arg(deviceInfo->maxOutputChannels).
|
||||
arg(QString::fromLatin1(apiInfo->name));
|
||||
|
||||
m_devices.append(name);
|
||||
|
||||
qDebug(" Device #%d: %s", i, qPrintable(name));
|
||||
}
|
||||
return;
|
||||
|
||||
failed:
|
||||
if(err != paNoError)
|
||||
qCritical("Audio initialisation failed: %s (%d)", Pa_GetErrorText(err), err);
|
||||
}
|
||||
#if 0
|
||||
int SoundcardInfo::getInputDevice()
|
||||
{
|
||||
// find device
|
||||
for(i = 0; i < m_soundCardInfo->getDeviceCount(); i++) {
|
||||
if(m_soundCardInfo->getDevice(i) == dev) {
|
||||
device = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if no device is found or configured, find first DirectSound input device
|
||||
if(device < 0) {
|
||||
int numHostApis = Pa_GetHostApiCount();
|
||||
const PaHostApiInfo *apiInfo;
|
||||
int i;
|
||||
for(i = 0; i < numHostApis; i++) {
|
||||
apiInfo = Pa_GetHostApiInfo(i);
|
||||
if(strcmp(apiInfo->name, defaultDev) == 0) {
|
||||
device = apiInfo->defaultInputDevice;
|
||||
if(device >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(device < 0)
|
||||
device = Pa_GetDefaultInputDevice();
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_SOUNDCARDINFO_H
|
||||
#define INCLUDE_SOUNDCARDINFO_H
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
class SoundcardInfo {
|
||||
private:
|
||||
QStringList m_devices;
|
||||
|
||||
public:
|
||||
SoundcardInfo();
|
||||
|
||||
inline const QStringList& getDevices() { return m_devices; }
|
||||
|
||||
inline const QString& getDevice(int idx) { return m_devices.at(idx); }
|
||||
inline int getDeviceCount() { return m_devices.count(); }
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SOUNDCARDINFO_H
|
8
main.cpp
8
main.cpp
|
@ -19,9 +19,8 @@
|
|||
#include <QTextCodec>
|
||||
#include <QMessageBox>
|
||||
#include "mainwindow.h"
|
||||
//#include "portaudio.h"
|
||||
#include "portaudio.h"
|
||||
|
||||
#if 0
|
||||
static void initPortAudio()
|
||||
{
|
||||
PaError err;
|
||||
|
@ -29,10 +28,9 @@ static void initPortAudio()
|
|||
if((err = Pa_Initialize()) != paNoError) {
|
||||
qCritical("PortAudio: could not initialise: %s (%d)", Pa_GetErrorText(err), err);
|
||||
QString error = QObject::tr("PortAudio could not be initialised: %1 (%2)").arg(Pa_GetErrorText(err)).arg(err);
|
||||
QMessageBox::critical(NULL, "PortAudio", error);
|
||||
QMessageBox::critical(NULL, "PortAudio failure", error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
@ -41,7 +39,7 @@ int main(int argc, char* argv[])
|
|||
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
//initPortAudio();
|
||||
initPortAudio();
|
||||
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
|
138
mainwindow.cpp
138
mainwindow.cpp
|
@ -18,17 +18,27 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include "gui/indicator.h"
|
||||
#include "gui/viewtoolbox.h"
|
||||
#include "dsp/channelizer.h"
|
||||
#include "osdrupgrade.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow),
|
||||
m_settings(),
|
||||
m_dspEngine(&m_settings)
|
||||
m_dspEngine(&m_settings),
|
||||
m_startOSDRUpdateAfterStop(false)
|
||||
{
|
||||
m_settings.load();
|
||||
|
||||
ui->setupUi(this);
|
||||
createStatusBar();
|
||||
m_viewToolBox = new ViewToolBox(this);
|
||||
connect(m_viewToolBox, SIGNAL(closed()), this, SLOT(viewToolBoxClosed()));
|
||||
connect(m_viewToolBox, SIGNAL(viewWaterfall(bool)), this, SLOT(on_action_View_Waterfall_toggled(bool)));
|
||||
connect(m_viewToolBox, SIGNAL(waterfallUpward(bool)), this, SLOT(viewToolBoxWaterfallUpward(bool)));
|
||||
connect(m_viewToolBox, SIGNAL(viewHistogram(bool)), this, SLOT(on_action_View_Histogram_toggled(bool)));
|
||||
connect(m_viewToolBox, SIGNAL(viewLiveSpectrum(bool)), this, SLOT(on_action_View_LiveSpectrum_toggled(bool)));
|
||||
|
||||
m_dspEngine.setGLSpectrum(ui->glSpectrum);
|
||||
m_dspEngine.start();
|
||||
|
@ -37,8 +47,6 @@ MainWindow::MainWindow(QWidget* parent) :
|
|||
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
|
||||
m_statusTimer.start(500);
|
||||
|
||||
statusBar()->showMessage("Welcome to SDRangelove", 3000);
|
||||
|
||||
ui->centerFrequency->setValueRange(7, 20000U, 2200000U);
|
||||
|
||||
for(int i = 0; i < ui->fftSize->count(); i++) {
|
||||
|
@ -49,17 +57,20 @@ MainWindow::MainWindow(QWidget* parent) :
|
|||
}
|
||||
ui->fftWindow->setCurrentIndex(m_settings.fftWindow());
|
||||
|
||||
ui->dispWaterfall->setChecked(m_settings.displayWaterfall());
|
||||
ui->action_View_Waterfall->setChecked(m_settings.displayWaterfall());
|
||||
m_viewToolBox->setViewWaterfall(m_settings.displayWaterfall());
|
||||
ui->glSpectrum->setDisplayWaterfall(m_settings.displayWaterfall());
|
||||
ui->waterfallInverted->setChecked(m_settings.invertedWaterfall());
|
||||
m_viewToolBox->setWaterfallUpward(m_settings.invertedWaterfall());
|
||||
ui->glSpectrum->setInvertedWaterfall(m_settings.invertedWaterfall());
|
||||
ui->dispLiveSpectrum->setChecked(m_settings.displayLiveSpectrum());
|
||||
ui->action_View_LiveSpectrum->setChecked(m_settings.displayLiveSpectrum());
|
||||
m_viewToolBox->setViewLiveSpectrum(m_settings.displayLiveSpectrum());
|
||||
ui->glSpectrum->setDisplayLiveSpectrum(m_settings.displayLiveSpectrum());
|
||||
ui->dispHistogram->setChecked(m_settings.displayHistogram());
|
||||
ui->action_View_Histogram->setChecked(m_settings.displayHistogram());
|
||||
m_viewToolBox->setViewHistogram(m_settings.displayHistogram());
|
||||
ui->glSpectrum->setDisplayHistogram(m_settings.displayHistogram());
|
||||
|
||||
ui->iqSwap->setChecked(m_settings.iqSwap());
|
||||
ui->decimation->setCurrentIndex(m_settings.decimation() - 2);
|
||||
ui->decimation->setCurrentIndex(m_settings.decimation());
|
||||
ui->dcOffset->setChecked(m_settings.dcOffsetCorrection());
|
||||
ui->iqImbalance->setChecked(m_settings.iqImbalanceCorrection());
|
||||
ui->e4000LNAGain->setCurrentIndex((m_settings.e4000LNAGain() + 50) / 25);
|
||||
|
@ -74,9 +85,18 @@ MainWindow::MainWindow(QWidget* parent) :
|
|||
ui->e4000if4->setCurrentIndex(m_settings.e4000if4() / 10);
|
||||
ui->e4000if5->setCurrentIndex(m_settings.e4000if5() / 30 - 1);
|
||||
ui->e4000if6->setCurrentIndex(m_settings.e4000if6() / 30 - 1);
|
||||
ui->filterI1->setValue(m_settings.filterI1());
|
||||
ui->filterI2->setValue(m_settings.filterI2());
|
||||
ui->filterQ1->setValue(m_settings.filterQ1());
|
||||
ui->filterQ2->setValue(m_settings.filterQ2());
|
||||
|
||||
updateSampleRate();
|
||||
updateCenterFreqDisplay();
|
||||
/*
|
||||
Channelizer* channelizer = new Channelizer;
|
||||
channelizer->setGLSpectrum(ui->chanSpectrum);
|
||||
m_dspEngine.addChannelizer(channelizer);
|
||||
*/
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
|
@ -89,6 +109,10 @@ MainWindow::~MainWindow()
|
|||
|
||||
void MainWindow::createStatusBar()
|
||||
{
|
||||
m_sampleRateWidget = new QLabel(tr("Rate: 0 kHz"), this);
|
||||
m_sampleRateWidget->setToolTip(tr("Sample Rate"));
|
||||
statusBar()->addPermanentWidget(m_sampleRateWidget);
|
||||
|
||||
m_engineIdle = new Indicator(tr("Idle"), this);
|
||||
m_engineIdle->setToolTip(tr("DSP engine is idle"));
|
||||
statusBar()->addPermanentWidget(m_engineIdle);
|
||||
|
@ -113,13 +137,14 @@ void MainWindow::updateSampleRate()
|
|||
{
|
||||
m_sampleRate = 4000000 / (1 << m_settings.decimation());
|
||||
ui->glSpectrum->setSampleRate(m_sampleRate);
|
||||
ui->sampleRate->setText(tr("%1k").arg((float)m_sampleRate / 1000));
|
||||
m_sampleRateWidget->setText(tr("Rate: %1 kHz").arg((float)m_sampleRate / 1000));
|
||||
}
|
||||
|
||||
void MainWindow::updateStatus()
|
||||
{
|
||||
if(m_lastEngineState != m_dspEngine.state()) {
|
||||
switch(m_dspEngine.state()) {
|
||||
DSPEngine::State state = m_dspEngine.state();
|
||||
if(m_lastEngineState != state) {
|
||||
switch(state) {
|
||||
case DSPEngine::StNotStarted:
|
||||
m_engineIdle->setColor(Qt::gray);
|
||||
m_engineRunning->setColor(Qt::gray);
|
||||
|
@ -132,26 +157,41 @@ void MainWindow::updateStatus()
|
|||
m_engineRunning->setColor(Qt::gray);
|
||||
m_engineError->setColor(Qt::gray);
|
||||
statusBar()->clearMessage();
|
||||
if(m_startOSDRUpdateAfterStop)
|
||||
on_actionOsmoSDR_Firmware_Upgrade_triggered();
|
||||
break;
|
||||
|
||||
case DSPEngine::StRunning:
|
||||
m_engineIdle->setColor(Qt::gray);
|
||||
m_engineRunning->setColor(Qt::green);
|
||||
m_engineError->setColor(Qt::gray);
|
||||
statusBar()->clearMessage();
|
||||
statusBar()->showMessage(tr("Sampling from %1").arg(m_dspEngine.deviceDesc()));
|
||||
break;
|
||||
|
||||
case DSPEngine::StError:
|
||||
m_engineIdle->setColor(Qt::gray);
|
||||
m_engineRunning->setColor(Qt::gray);
|
||||
m_engineError->setColor(Qt::red);
|
||||
statusBar()->showMessage(m_dspEngine.errorMsg());
|
||||
statusBar()->showMessage(tr("Error: %1").arg(m_dspEngine.errorMsg()));
|
||||
if(m_startOSDRUpdateAfterStop)
|
||||
on_actionOsmoSDR_Firmware_Upgrade_triggered();
|
||||
break;
|
||||
}
|
||||
m_lastEngineState = m_dspEngine.state();
|
||||
m_lastEngineState = state;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::viewToolBoxClosed()
|
||||
{
|
||||
ui->action_View_Toolbox->setChecked(false);
|
||||
}
|
||||
|
||||
void MainWindow::viewToolBoxWaterfallUpward(bool checked)
|
||||
{
|
||||
ui->glSpectrum->setInvertedWaterfall(checked);
|
||||
m_settings.setInvertedWaterfall(checked);
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Start_triggered()
|
||||
{
|
||||
m_dspEngine.startAcquisition();
|
||||
|
@ -179,7 +219,7 @@ void MainWindow::on_iqSwap_toggled(bool checked)
|
|||
|
||||
void MainWindow::on_decimation_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.setDecimation(index + 2);
|
||||
m_settings.setDecimation(index);
|
||||
updateSampleRate();
|
||||
}
|
||||
|
||||
|
@ -251,26 +291,74 @@ void MainWindow::on_iqImbalance_toggled(bool checked)
|
|||
m_settings.setIQImbalanceCorrection(checked);
|
||||
}
|
||||
|
||||
void MainWindow::on_dispLiveSpectrum_toggled(bool checked)
|
||||
void MainWindow::on_filterI1_valueChanged(int value)
|
||||
{
|
||||
ui->glSpectrum->setDisplayLiveSpectrum(checked);
|
||||
m_settings.setDisplayLiveSpectrum(checked);
|
||||
m_settings.setFilterI1(value);
|
||||
}
|
||||
|
||||
void MainWindow::on_dispHistogram_toggled(bool checked)
|
||||
void MainWindow::on_filterI2_valueChanged(int value)
|
||||
{
|
||||
ui->glSpectrum->setDisplayHistogram(checked);
|
||||
m_settings.setDisplayHistogram(checked);
|
||||
m_settings.setFilterI2(value);
|
||||
}
|
||||
|
||||
void MainWindow::on_dispWaterfall_toggled(bool checked)
|
||||
void MainWindow::on_filterQ1_valueChanged(int value)
|
||||
{
|
||||
m_settings.setFilterQ1(value);
|
||||
}
|
||||
|
||||
void MainWindow::on_filterQ2_valueChanged(int value)
|
||||
{
|
||||
m_settings.setFilterQ2(value);
|
||||
}
|
||||
|
||||
void MainWindow::on_action_View_Waterfall_toggled(bool checked)
|
||||
{
|
||||
ui->action_View_Waterfall->setChecked(checked);
|
||||
m_viewToolBox->setViewWaterfall(checked);
|
||||
ui->glSpectrum->setDisplayWaterfall(checked);
|
||||
m_settings.setDisplayWaterfall(checked);
|
||||
}
|
||||
|
||||
void MainWindow::on_waterfallInverted_toggled(bool checked)
|
||||
void MainWindow::on_action_View_Histogram_toggled(bool checked)
|
||||
{
|
||||
ui->glSpectrum->setInvertedWaterfall(checked);
|
||||
m_settings.setInvertedWaterfall(checked);
|
||||
ui->action_View_Histogram->setChecked(checked);
|
||||
m_viewToolBox->setViewHistogram(checked);
|
||||
ui->glSpectrum->setDisplayHistogram(checked);
|
||||
m_settings.setDisplayHistogram(checked);
|
||||
}
|
||||
|
||||
void MainWindow::on_action_View_LiveSpectrum_toggled(bool checked)
|
||||
{
|
||||
ui->action_View_LiveSpectrum->setChecked(checked);
|
||||
m_viewToolBox->setViewLiveSpectrum(checked);
|
||||
ui->glSpectrum->setDisplayLiveSpectrum(checked);
|
||||
m_settings.setDisplayLiveSpectrum(checked);
|
||||
}
|
||||
|
||||
void MainWindow::on_action_View_Toolbox_toggled(bool checked)
|
||||
{
|
||||
if(checked)
|
||||
m_viewToolBox->show();
|
||||
else m_viewToolBox->hide();
|
||||
}
|
||||
|
||||
void MainWindow::on_action_View_Fullscreen_toggled(bool checked)
|
||||
{
|
||||
if(checked)
|
||||
showFullScreen();
|
||||
else showNormal();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOsmoSDR_Firmware_Upgrade_triggered()
|
||||
{
|
||||
DSPEngine::State engineState = m_dspEngine.state();
|
||||
if((engineState != DSPEngine::StIdle) && (engineState != DSPEngine::StError)) {
|
||||
m_startOSDRUpdateAfterStop = true;
|
||||
m_dspEngine.stopAcquistion();
|
||||
return;
|
||||
}
|
||||
m_startOSDRUpdateAfterStop = false;
|
||||
|
||||
OSDRUpgrade osdrUpgrade;
|
||||
osdrUpgrade.exec();
|
||||
}
|
||||
|
|
22
mainwindow.h
22
mainwindow.h
|
@ -23,8 +23,10 @@
|
|||
#include "settings.h"
|
||||
#include "dsp/dspengine.h"
|
||||
|
||||
class QLabel;
|
||||
class DSPEngine;
|
||||
class Indicator;
|
||||
class ViewToolBox;
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
|
@ -47,18 +49,24 @@ private:
|
|||
|
||||
DSPEngine::State m_lastEngineState;
|
||||
|
||||
QLabel* m_sampleRateWidget;
|
||||
Indicator* m_engineIdle;
|
||||
Indicator* m_engineRunning;
|
||||
Indicator* m_engineError;
|
||||
ViewToolBox* m_viewToolBox;
|
||||
|
||||
int m_sampleRate;
|
||||
|
||||
bool m_startOSDRUpdateAfterStop;
|
||||
|
||||
void createStatusBar();
|
||||
void updateCenterFreqDisplay();
|
||||
void updateSampleRate();
|
||||
|
||||
private slots:
|
||||
void updateStatus();
|
||||
void viewToolBoxClosed();
|
||||
void viewToolBoxWaterfallUpward(bool checked);
|
||||
void on_action_Start_triggered();
|
||||
void on_action_Stop_triggered();
|
||||
void on_fftSize_currentIndexChanged(const QString& str);
|
||||
|
@ -78,10 +86,16 @@ private slots:
|
|||
void on_action_Debug_triggered();
|
||||
void on_dcOffset_toggled(bool checked);
|
||||
void on_iqImbalance_toggled(bool checked);
|
||||
void on_dispLiveSpectrum_toggled(bool checked);
|
||||
void on_dispHistogram_toggled(bool checked);
|
||||
void on_dispWaterfall_toggled(bool checked);
|
||||
void on_waterfallInverted_toggled(bool checked);
|
||||
void on_filterI1_valueChanged(int value);
|
||||
void on_filterI2_valueChanged(int value);
|
||||
void on_filterQ1_valueChanged(int value);
|
||||
void on_filterQ2_valueChanged(int value);
|
||||
void on_action_View_Waterfall_toggled(bool checked);
|
||||
void on_action_View_Histogram_toggled(bool checked);
|
||||
void on_action_View_LiveSpectrum_toggled(bool checked);
|
||||
void on_action_View_Toolbox_toggled(bool checked);
|
||||
void on_action_View_Fullscreen_toggled(bool checked);
|
||||
void on_actionOsmoSDR_Firmware_Upgrade_triggered();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_MAINWINDOW_H
|
||||
|
|
315
mainwindow.ui
315
mainwindow.ui
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>920</width>
|
||||
<height>660</height>
|
||||
<width>936</width>
|
||||
<height>707</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -39,7 +39,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>920</width>
|
||||
<width>936</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -49,13 +49,11 @@
|
|||
</property>
|
||||
<addaction name="action_Exit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Settings">
|
||||
<widget class="QMenu" name="menu_Options">
|
||||
<property name="title">
|
||||
<string>&Settings</string>
|
||||
<string>&Options</string>
|
||||
</property>
|
||||
<addaction name="actionE4000_Stages"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Hardware"/>
|
||||
<addaction name="actionOsmoSDR_Firmware_Upgrade"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Acquisition">
|
||||
<property name="title">
|
||||
|
@ -66,9 +64,22 @@
|
|||
<addaction name="separator"/>
|
||||
<addaction name="action_Debug"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_View">
|
||||
<property name="title">
|
||||
<string>&View</string>
|
||||
</property>
|
||||
<addaction name="action_View_Fullscreen"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_View_Waterfall"/>
|
||||
<addaction name="action_View_Histogram"/>
|
||||
<addaction name="action_View_LiveSpectrum"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_View_Toolbox"/>
|
||||
</widget>
|
||||
<addaction name="menu_File"/>
|
||||
<addaction name="menu_Acquisition"/>
|
||||
<addaction name="menu_Settings"/>
|
||||
<addaction name="menu_View"/>
|
||||
<addaction name="menu_Options"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
<attribute name="toolBarArea">
|
||||
|
@ -289,6 +300,16 @@
|
|||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="decimation">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1:1 (none)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1:2</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1:4</string>
|
||||
|
@ -309,11 +330,6 @@
|
|||
<string>1:32</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1:64</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
|
@ -355,7 +371,7 @@
|
|||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="4">
|
||||
<item row="0" column="8">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>IF4</string>
|
||||
|
@ -365,7 +381,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="0" column="5">
|
||||
<widget class="QComboBox" name="e4000LNAGain">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -450,7 +466,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<item row="0" column="6">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>IF1</string>
|
||||
|
@ -460,7 +476,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="2" column="5">
|
||||
<widget class="QComboBox" name="e4000MixerEnh">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -495,7 +511,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="2" column="4">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>MixerEnh</string>
|
||||
|
@ -505,7 +521,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<item row="0" column="7">
|
||||
<widget class="QComboBox" name="e4000if1">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -525,7 +541,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="1" column="5">
|
||||
<widget class="QComboBox" name="e4000MixerGain">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -545,7 +561,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>LNA</string>
|
||||
|
@ -555,7 +571,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Mixer</string>
|
||||
|
@ -565,7 +581,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<item row="0" column="9">
|
||||
<widget class="QComboBox" name="e4000if4">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -590,7 +606,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<item row="1" column="6">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>IF2</string>
|
||||
|
@ -600,7 +616,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<item row="1" column="7">
|
||||
<widget class="QComboBox" name="e4000if2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -630,7 +646,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<item row="1" column="8">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>IF5</string>
|
||||
|
@ -640,7 +656,37 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<item row="2" column="7">
|
||||
<widget class="QComboBox" name="e4000if3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>6</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>9</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="9">
|
||||
<widget class="QComboBox" name="e4000if5">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -675,47 +721,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>IF3</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QComboBox" name="e4000if3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>3</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>6</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>9</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<item row="2" column="8">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>IF6</string>
|
||||
|
@ -725,7 +731,17 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<item row="2" column="6">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>IF3</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="9">
|
||||
<widget class="QComboBox" name="e4000if6">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -760,59 +776,80 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="10" rowspan="3">
|
||||
<widget class="QSlider" name="filterI1">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="11" rowspan="3">
|
||||
<widget class="QSlider" name="filterI2">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="12" rowspan="3">
|
||||
<widget class="QSlider" name="filterQ1">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="13" rowspan="3">
|
||||
<widget class="QSlider" name="filterQ2">
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="dockWidget_2">
|
||||
<widget class="QDockWidget" name="dockWidget_3">
|
||||
<property name="windowTitle">
|
||||
<string>Spectrum Display</string>
|
||||
<string>Channel</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>8</number>
|
||||
<number>2</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_4">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<widget class="QWidget" name="dockWidgetContents_5">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="dispLiveSpectrum">
|
||||
<property name="text">
|
||||
<string>Live Spectrum</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="sampleRate">
|
||||
<property name="text">
|
||||
<string>0k</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="dispHistogram">
|
||||
<property name="text">
|
||||
<string>Histogram</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="dispWaterfall">
|
||||
<property name="text">
|
||||
<string>Waterfall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="waterfallInverted">
|
||||
<property name="text">
|
||||
<string>Inverted Waterf.</string>
|
||||
<item>
|
||||
<widget class="GLSpectrum" name="chanSpectrum" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -861,6 +898,54 @@
|
|||
<string>F10</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_View_Waterfall">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Waterfall</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_View_Histogram">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Histogram</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_View_LiveSpectrum">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Live Spectrum</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_View_Toolbox">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Toolbox</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_View_Fullscreen">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Fullscreen</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F11</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOsmoSDR_Firmware_Upgrade">
|
||||
<property name="text">
|
||||
<string>OsmoSDR &Firmware Upgrade...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
@ -894,10 +979,6 @@
|
|||
<tabstop>e4000if4</tabstop>
|
||||
<tabstop>e4000if5</tabstop>
|
||||
<tabstop>e4000if6</tabstop>
|
||||
<tabstop>dispWaterfall</tabstop>
|
||||
<tabstop>waterfallInverted</tabstop>
|
||||
<tabstop>dispLiveSpectrum</tabstop>
|
||||
<tabstop>dispHistogram</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="resources/res.qrc"/>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#include "osdrupgrade.h"
|
||||
#include "ui_osdrupgrade.h"
|
||||
|
||||
OSDRUpgrade::OSDRUpgrade(QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::OSDRUpgrade)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
OSDRUpgrade::~OSDRUpgrade()
|
||||
{
|
||||
delete ui;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef INCLUDE_OSDRUPGRADE_H
|
||||
#define INCLUDE_OSDRUPGRADE_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class OSDRUpgrade;
|
||||
}
|
||||
|
||||
class OSDRUpgrade : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OSDRUpgrade(QWidget* parent = NULL);
|
||||
~OSDRUpgrade();
|
||||
|
||||
private:
|
||||
Ui::OSDRUpgrade* ui;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_OSDRUPGRADE_H
|
|
@ -0,0 +1,128 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OSDRUpgrade</class>
|
||||
<widget class="QDialog" name="OSDRUpgrade">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>324</width>
|
||||
<height>250</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>OsmoSDR Firmware Upgrade</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Firmware Archive</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="filename">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Firmware</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Radio App</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>FPGA Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>DFU App</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Signed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QPushButton" name="flash">
|
||||
<property name="text">
|
||||
<string>Flash!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<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="QPushButton" name="close">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1,97 +0,0 @@
|
|||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2012-05-19T10:01:31
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
|
||||
!exists(local.pri) {
|
||||
warning(Please create a local.pri)
|
||||
}
|
||||
exists(local.pri) {
|
||||
include(local.pri)
|
||||
}
|
||||
|
||||
include(local.pri)
|
||||
|
||||
QT += core gui opengl
|
||||
|
||||
CONFIG += silent
|
||||
|
||||
UI_DIR = tmp
|
||||
MOC_DIR = tmp
|
||||
RCC_DIR = tmp
|
||||
OBJECTS_DIR = tmp
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = sdrangelove
|
||||
TEMPLATE = app
|
||||
|
||||
|
||||
SOURCES += main.cpp\
|
||||
mainwindow.cpp \
|
||||
hardware/samplefifo.cpp \
|
||||
dsp/dspengine.cpp \
|
||||
gui/indicator.cpp \
|
||||
dsp/fftwindow.cpp \
|
||||
dsp/lowpass.cpp \
|
||||
dsp/interpolator.cpp \
|
||||
dsp/channelizer.cpp \
|
||||
dsp/spectrum.cpp \
|
||||
dsp/samplesink.cpp \
|
||||
settings.cpp \
|
||||
hardware/osmosdrinput.cpp \
|
||||
hardware/osmosdrthread.cpp \
|
||||
hardware/samplesource.cpp \
|
||||
gui/scale.cpp \
|
||||
dsp/nco.cpp \
|
||||
gui/glspectrum.cpp \
|
||||
gui/scaleengine.cpp \
|
||||
gui/valuedial.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
hardware/samplefifo.h \
|
||||
dsp/dspengine.h \
|
||||
gui/indicator.h \
|
||||
dsp/kissfft.h \
|
||||
dsp/dsptypes.h \
|
||||
dsp/fftwindow.h \
|
||||
dsp/lowpass.h \
|
||||
dsp/interpolator.h \
|
||||
dsp/channelizer.h \
|
||||
dsp/spectrum.h \
|
||||
dsp/samplesink.h \
|
||||
settings.h \
|
||||
hardware/osmosdrinput.h \
|
||||
hardware/osmosdrthread.h \
|
||||
hardware/samplesource.h \
|
||||
gui/scale.h \
|
||||
gui/physicalunit.h \
|
||||
dsp/nco.h \
|
||||
gui/glspectrum.h \
|
||||
gui/scaleengine.h \
|
||||
gui/valuedial.h
|
||||
|
||||
FORMS += mainwindow.ui
|
||||
|
||||
RESOURCES += \
|
||||
resources/res.qrc
|
||||
RC_FILE = resources/sdrangelove.rc
|
||||
|
||||
unix {
|
||||
LIBS += -lrt -lGLU
|
||||
}
|
||||
|
||||
# Portaudio - currently not in use
|
||||
unix:portaudio {
|
||||
LIBS += -lasound
|
||||
LIBS += portaudio/libportaudio.a
|
||||
INCLUDEPATH += portaudio/portaudio/include
|
||||
}
|
||||
|
||||
# libosmosdr
|
||||
unix {
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += libosmosdr
|
||||
}
|
118
settings.cpp
118
settings.cpp
|
@ -35,7 +35,7 @@ Settings::Settings(Settings* reference) :
|
|||
void Settings::defaults()
|
||||
{
|
||||
m_fftSize = 1024;
|
||||
m_fftOverlap = 25;
|
||||
m_fftOverlap = 10;
|
||||
m_fftWindow = 3;
|
||||
m_displayWaterfall = true;
|
||||
m_invertedWaterfall = false;
|
||||
|
@ -55,6 +55,10 @@ void Settings::defaults()
|
|||
m_e4000if4 = 20;
|
||||
m_e4000if5 = 150;
|
||||
m_e4000if6 = 150;
|
||||
m_filterI1 = 255;
|
||||
m_filterI2 = 255;
|
||||
m_filterQ1 = 255;
|
||||
m_filterQ2 = 255;
|
||||
}
|
||||
|
||||
void Settings::load()
|
||||
|
@ -66,7 +70,7 @@ void Settings::load()
|
|||
return;
|
||||
|
||||
m_fftSize = s.value("fftsize", 512).toInt();
|
||||
m_fftOverlap = s.value("fftoverlap", 25).toInt();
|
||||
m_fftOverlap = s.value("fftoverlap", 10).toInt();
|
||||
m_fftWindow = s.value("fftwindow", 3).toInt();
|
||||
m_displayWaterfall = s.value("displaywaterfall", true).toBool();
|
||||
m_invertedWaterfall = s.value("invertedwaterfall", false).toBool();
|
||||
|
@ -86,6 +90,10 @@ void Settings::load()
|
|||
m_e4000if4 = s.value("e4000_if4", 20).toInt();
|
||||
m_e4000if5 = s.value("e4000_if5", 150).toInt();
|
||||
m_e4000if6 = s.value("e4000_if6", 150).toInt();
|
||||
m_filterI1 = s.value("filter_i1", 255).toInt();
|
||||
m_filterI2 = s.value("filter_i2", 255).toInt();
|
||||
m_filterQ1 = s.value("filter_q1", 255).toInt();
|
||||
m_filterQ2 = s.value("filter_q2", 255).toInt();
|
||||
|
||||
s.remove("livespectrumalpha");
|
||||
}
|
||||
|
@ -117,6 +125,10 @@ void Settings::save()
|
|||
s.setValue("e4000_if4", m_e4000if4);
|
||||
s.setValue("e4000_if5", m_e4000if5);
|
||||
s.setValue("e4000_if6", m_e4000if6);
|
||||
s.setValue("filter_i1", m_filterI1);
|
||||
s.setValue("filter_i2", m_filterI2);
|
||||
s.setValue("filter_q1", m_filterQ1);
|
||||
s.setValue("filter_q2", m_filterQ2);
|
||||
}
|
||||
|
||||
int Settings::fftSize() const
|
||||
|
@ -189,8 +201,10 @@ bool Settings::displayWaterfall() const
|
|||
|
||||
void Settings::setDisplayWaterfall(bool v)
|
||||
{
|
||||
m_displayWaterfall = v;
|
||||
m_changed = true;
|
||||
if(v != m_displayWaterfall) {
|
||||
m_displayWaterfall = v;
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::isModifiedDisplayWaterfall()
|
||||
|
@ -210,8 +224,10 @@ bool Settings::invertedWaterfall() const
|
|||
|
||||
void Settings::setInvertedWaterfall(bool v)
|
||||
{
|
||||
m_invertedWaterfall = v;
|
||||
m_changed = true;
|
||||
if(v != m_invertedWaterfall) {
|
||||
m_invertedWaterfall = v;
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::isModifiedInvertedWaterfall()
|
||||
|
@ -231,8 +247,10 @@ bool Settings::displayLiveSpectrum() const
|
|||
|
||||
void Settings::setDisplayLiveSpectrum(bool v)
|
||||
{
|
||||
m_displayLiveSpectrum = v;
|
||||
m_changed = true;
|
||||
if(v != m_displayLiveSpectrum) {
|
||||
m_displayLiveSpectrum = v;
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::isModifiedDisplayLiveSpectrum()
|
||||
|
@ -559,3 +577,87 @@ bool Settings::isModifiedE4000if6()
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
quint8 Settings::filterI1() const
|
||||
{
|
||||
return m_filterI1;
|
||||
}
|
||||
|
||||
void Settings::setFilterI1(quint8 v)
|
||||
{
|
||||
m_filterI1 = v;
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
bool Settings::isModifiedFilterI1()
|
||||
{
|
||||
if(m_reference->m_filterI1 != m_filterI1) {
|
||||
m_filterI1 = m_reference->m_filterI1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
quint8 Settings::filterI2() const
|
||||
{
|
||||
return m_filterI2;
|
||||
}
|
||||
|
||||
void Settings::setFilterI2(quint8 v)
|
||||
{
|
||||
m_filterI2 = v;
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
bool Settings::isModifiedFilterI2()
|
||||
{
|
||||
if(m_reference->m_filterI2 != m_filterI2) {
|
||||
m_filterI2 = m_reference->m_filterI2;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
quint8 Settings::filterQ1() const
|
||||
{
|
||||
return m_filterQ1;
|
||||
}
|
||||
|
||||
void Settings::setFilterQ1(quint8 v)
|
||||
{
|
||||
m_filterQ1 = v;
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
bool Settings::isModifiedFilterQ1()
|
||||
{
|
||||
if(m_reference->m_filterQ1 != m_filterQ1) {
|
||||
m_filterQ1 = m_reference->m_filterQ1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
quint8 Settings::filterQ2() const
|
||||
{
|
||||
return m_filterQ2;
|
||||
}
|
||||
|
||||
void Settings::setFilterQ2(quint8 v)
|
||||
{
|
||||
m_filterQ2 = v;
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
bool Settings::isModifiedFilterQ2()
|
||||
{
|
||||
if(m_reference->m_filterQ2 != m_filterQ2) {
|
||||
m_filterQ2 = m_reference->m_filterQ2;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
21
settings.h
21
settings.h
|
@ -113,6 +113,22 @@ public:
|
|||
void setE4000if6(int v);
|
||||
bool isModifiedE4000if6();
|
||||
|
||||
quint8 filterI1() const;
|
||||
void setFilterI1(quint8 v);
|
||||
bool isModifiedFilterI1();
|
||||
|
||||
quint8 filterI2() const;
|
||||
void setFilterI2(quint8 v);
|
||||
bool isModifiedFilterI2();
|
||||
|
||||
quint8 filterQ1() const;
|
||||
void setFilterQ1(quint8 v);
|
||||
bool isModifiedFilterQ1();
|
||||
|
||||
quint8 filterQ2() const;
|
||||
void setFilterQ2(quint8 v);
|
||||
bool isModifiedFilterQ2();
|
||||
|
||||
private:
|
||||
bool m_changed;
|
||||
const Settings* m_reference;
|
||||
|
@ -139,6 +155,11 @@ private:
|
|||
int m_e4000if4;
|
||||
int m_e4000if5;
|
||||
int m_e4000if6;
|
||||
|
||||
quint8 m_filterI1;
|
||||
quint8 m_filterI2;
|
||||
quint8 m_filterQ1;
|
||||
quint8 m_filterQ2;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SETTINGS_H
|
||||
|
|
Loading…
Reference in New Issue