diff --git a/devices/devices.pro b/devices/devices.pro index 5e4e063f1..ce01b7f01 100644 --- a/devices/devices.pro +++ b/devices/devices.pro @@ -15,7 +15,7 @@ DEFINES += USE_SSSE3=1 QMAKE_CXXFLAGS += -mssse3 DEFINES += USE_SSE4_1=1 QMAKE_CXXFLAGS += -msse4.1 -CONFIG(MINGW32):QMAKE_CXXFLAGS += -std=c++11 +QMAKE_CXXFLAGS += -std=c++11 CONFIG(MINGW32):LIBBLADERFSRC = "D:\softs\bladeRF\host\libraries\libbladeRF\include" CONFIG(MINGW64):LIBBLADERFSRC = "D:\softs\bladeRF\host\libraries\libbladeRF\include" diff --git a/plugins/samplesink/plutosdroutput/plutosdroutput.pro b/plugins/samplesink/plutosdroutput/plutosdroutput.pro new file mode 100644 index 000000000..c79a94ddc --- /dev/null +++ b/plugins/samplesink/plutosdroutput/plutosdroutput.pro @@ -0,0 +1,50 @@ +#-------------------------------------------------------- +# +# Pro file for Android and Windows builds with Qt Creator +# +#-------------------------------------------------------- + +TEMPLATE = lib +CONFIG += plugin + +QT += core gui widgets multimedia opengl + +TARGET = outputplutosdr + +DEFINES += USE_SSE2=1 +QMAKE_CXXFLAGS += -msse2 +DEFINES += USE_SSE4_1=1 +QMAKE_CXXFLAGS += -msse4.1 +QMAKE_CXXFLAGS += -std=c++11 + +CONFIG(MINGW32):LIBIIOSRC = "D:\softs\libiio" +CONFIG(MINGW64):LIBIIOSRC = "D:\softs\libiio" + +INCLUDEPATH += $$PWD +INCLUDEPATH += ../../../sdrbase +INCLUDEPATH += ../../../devices +INCLUDEPATH += ../../../libiio/includemw +INCLUDEPATH += $$LIBIIOSRC + +CONFIG(Release):build_subdir = release +CONFIG(Debug):build_subdir = debug + +SOURCES += plutosdroutputgui.cpp\ + plutosdroutput.cpp\ + plutosdroutputplugin.cpp\ + plutosdroutputsettings.cpp\ + plutosdroutputthread.cpp + +HEADERS += plutosdroutputgui.h\ + plutosdroutput.h\ + plutosdroutputplugin.h\ + plutosdroutputsettings.h\ + plutosdroutputthread.h + +FORMS += plutosdroutputgui.ui + +LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase +LIBS += -L../../../libiio/$${build_subdir} -llibiio +LIBS += -L../../../devices/$${build_subdir} -ldevices + +RESOURCES = ../../../sdrbase/resources/res.qrc diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp index 43a5b3a5d..80d1db9dd 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp @@ -241,7 +241,7 @@ void PlutoSDROutputGUI::displaySettings() ui->lpFIRGain->setEnabled(m_settings.m_lpfFIREnable); ui->att->setValue(m_settings.m_att); - ui->attText->setText(QString("%1").arg(QString::number(m_settings.m_gain*0.25, 'f', 2))); + ui->attText->setText(QString("%1").arg(QString::number(m_settings.m_att*0.25, 'f', 2))); ui->antenna->setCurrentIndex((int) m_settings.m_antennaPath); @@ -280,16 +280,16 @@ void PlutoSDROutputGUI::updateStatus() { switch(state) { - case DSPDeviceSourceEngine::StNotStarted: + case DSPDeviceSinkEngine::StNotStarted: ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); break; - case DSPDeviceSourceEngine::StIdle: + case DSPDeviceSinkEngine::StIdle: ui->startStop->setStyleSheet("QToolButton { background-color : blue; }"); break; - case DSPDeviceSourceEngine::StRunning: + case DSPDeviceSinkEngine::StRunning: ui->startStop->setStyleSheet("QToolButton { background-color : green; }"); break; - case DSPDeviceSourceEngine::StError: + case DSPDeviceSinkEngine::StError: ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); QMessageBox::information(this, tr("Message"), m_deviceAPI->errorMessage()); break; diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h index 6adbcd552..570a9e93e 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h @@ -14,8 +14,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDRINPUTGUI_H_ -#define PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDRINPUTGUI_H_ +#ifndef PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTGUI_H_ +#define PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTGUI_H_ #include #include @@ -91,4 +91,4 @@ private slots: void handleInputMessages(); }; -#endif /* PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDRINPUTGUI_H_ */ +#endif /* PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTGUI_H_ */ diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui b/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui index 73ec1ca82..3a053c35d 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui @@ -76,7 +76,7 @@ - + 54 @@ -255,7 +255,7 @@ 2 - + Sw @@ -265,7 +265,7 @@ - + 50 @@ -538,14 +538,14 @@ - + I - + 50 @@ -648,7 +648,7 @@ - + 40 @@ -774,6 +774,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp index 2f3ecb11f..7e95aac0f 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp @@ -85,7 +85,7 @@ PluginInstanceUI* PlutoSDROutputPlugin::createSampleSinkPluginInstanceGUI(const { if(sinkId == m_deviceTypeID) { - PlutoSDROutputGui* gui = new PlutoSDROutputGui(deviceAPI); + PlutoSDROutputGUI* gui = new PlutoSDROutputGUI(deviceAPI); *widget = gui; return gui; } @@ -95,7 +95,7 @@ PluginInstanceUI* PlutoSDROutputPlugin::createSampleSinkPluginInstanceGUI(const } } -DeviceSampleSink *PlutoSDROutputPlugin::createSampleSourcePluginInstanceInput(const QString& sinkId, DeviceSinkAPI *deviceAPI) +DeviceSampleSink *PlutoSDROutputPlugin::createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI) { if (sinkId == m_deviceTypeID) { diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputthread.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputthread.cpp new file mode 100644 index 000000000..7d7b2c5e5 --- /dev/null +++ b/plugins/samplesink/plutosdroutput/plutosdroutputthread.cpp @@ -0,0 +1,149 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "plutosdr/deviceplutosdrbox.h" +#include "plutosdroutputsettings.h" +#include "iio.h" +#include "plutosdroutputthread.h" + +PlutoSDROutputThread::PlutoSDROutputThread(uint32_t blocksizeSamples, DevicePlutoSDRBox* plutoBox, SampleSourceFifo* sampleFifo, QObject* parent) : + QThread(parent), + m_running(false), + m_plutoBox(plutoBox), + m_blockSizeSamples(blocksizeSamples), + m_sampleFifo(sampleFifo), + m_log2Interp(0) +{ + m_buf = new qint16[blocksizeSamples*(sizeof(Sample)/sizeof(qint16))]; +// m_bufConv = new qint16[blocksizeSamples*(sizeof(Sample)/sizeof(qint16))]; +} + +PlutoSDROutputThread::~PlutoSDROutputThread() +{ + stopWork(); + delete[] m_buf; +} + +void PlutoSDROutputThread::startWork() +{ + if (m_running) return; // return if running already + + m_startWaitMutex.lock(); + start(); + while(!m_running) + m_startWaiter.wait(&m_startWaitMutex, 100); + m_startWaitMutex.unlock(); +} + +void PlutoSDROutputThread::stopWork() +{ + if (!m_running) return; // return if not running + + m_running = false; + wait(); +} + +void PlutoSDROutputThread::setLog2Interpolation(unsigned int log2_interp) +{ + m_log2Interp = log2_interp; +} + +void PlutoSDROutputThread::run() +{ + m_running = true; + m_startWaiter.wakeAll(); + + while (m_running) + { + ssize_t nbytes_tx; + char *p_dat, *p_end; + std::ptrdiff_t p_inc; + int ihs; // half sample index (I then Q to make a sample) + + convert(m_buf, 2*m_blockSizeSamples); // size given in number of int16_t (I and Q interleaved) + + // WRITE: Get pointers to TX buf and write IQ to TX buf port 0 + p_inc = m_plutoBox->txBufferStep(); + p_end = m_plutoBox->txBufferEnd(); + ihs = 0; + + // p_inc is 2 on a char* buffer therefore each iteration processes only the I or Q sample + // I and Q samples are processed one after the other + // conversion is not needed as samples are little endian + + for (p_dat = m_plutoBox->txBufferFirst(), ihs = 0; p_dat < p_end; p_dat += p_inc, ihs++) + { + *((int16_t*)p_dat) = m_buf[ihs] << 4; + } + + // Schedule TX buffer for sending + nbytes_tx = m_plutoBox->txBufferPush(); + + if (nbytes_tx < 0) + { + printf("PlutoSDRInputThread::run: error pushing buf %d\n", (int) nbytes_tx); + usleep(200000); + continue; + } + } + + m_running = false; +} + +// Decimate according to specified log2 (ex: log2=4 => decim=16) +// len is in half samples (I or Q) thus the size up to which buf is filled +// SampleVector contains full (I, Q) samples +void PlutoSDROutputThread::convert(qint16* buf, qint32 len) +{ + // pull samples from baseband generator + SampleVector::iterator beginRead; + m_sampleFifo->readAdvance(beginRead, len/(2*(1<. // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTTHREAD_H_ +#define PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTTHREAD_H_ + +#include +#include +#include + +#include "dsp/samplesourcefifo.h" +#include "dsp/interpolators.h" +#include "plutosdr/deviceplutosdrshared.h" + +class DevicePlutoSDRBox; + +class PlutoSDROutputThread : public QThread, public DevicePlutoSDRShared::ThreadInterface +{ + Q_OBJECT + +public: + PlutoSDROutputThread(uint32_t blocksize, DevicePlutoSDRBox* plutoBox, SampleSourceFifo* sampleFifo, QObject* parent = 0); + ~PlutoSDROutputThread(); + + virtual void startWork(); + virtual void stopWork(); + virtual void setDeviceSampleRate(int sampleRate __attribute__((unused))) {} + virtual bool isRunning() { return m_running; } + void setLog2Interpolation(unsigned int log2_interp); + +private: + QMutex m_startWaitMutex; + QWaitCondition m_startWaiter; + bool m_running; + + DevicePlutoSDRBox *m_plutoBox; + int16_t *m_buf; //!< holds I+Q values of each sample from devce + int16_t *m_bufConv; //!< holds I+Q values of each sample converted to host format via iio_channel_convert + uint32_t m_blockSizeSamples; //!< buffer sizes in number of (I,Q) samples + SampleSourceFifo* m_sampleFifo; //!< DSP sample FIFO (I,Q) + + unsigned int m_log2Interp; // soft interpolation + + Interpolators m_interpolators; + + void run(); + void convert(qint16* buf, qint32 len); + +}; + + +#endif /* PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTTHREAD_H_ */ diff --git a/sdrangel.windows.pro b/sdrangel.windows.pro index e90f378b9..1b1a77d97 100644 --- a/sdrangel.windows.pro +++ b/sdrangel.windows.pro @@ -34,6 +34,7 @@ SUBDIRS += plugins/samplesink/filesink SUBDIRS += plugins/samplesink/bladerfoutput SUBDIRS += plugins/samplesink/hackrfoutput SUBDIRS += plugins/samplesink/limesdroutput +SUBDIRS += plugins/samplesink/plutosdroutput SUBDIRS += plugins/channelrx/chanalyzer SUBDIRS += plugins/channelrx/chanalyzerng SUBDIRS += plugins/channelrx/demodam