mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-17 13:51:47 -05:00
Removed MIMO plugins and related code
This commit is contained in:
parent
bbba942eba
commit
e33ed72059
@ -34,6 +34,5 @@ endif()
|
||||
|
||||
add_subdirectory(channelrx)
|
||||
add_subdirectory(channeltx)
|
||||
add_subdirectory(samplemimo)
|
||||
add_subdirectory(samplesource)
|
||||
add_subdirectory(samplesink)
|
||||
|
@ -1,3 +0,0 @@
|
||||
project(samplemimo)
|
||||
|
||||
add_subdirectory(testmi)
|
@ -1,56 +0,0 @@
|
||||
project(testmi)
|
||||
|
||||
set(testmi_SOURCES
|
||||
testmi.cpp
|
||||
testmiplugin.cpp
|
||||
testmithread.cpp
|
||||
testmisettings.cpp
|
||||
testmiwebapiadapter.cpp
|
||||
)
|
||||
|
||||
set(testmi_HEADERS
|
||||
testmi.h
|
||||
testmiplugin.h
|
||||
testmithread.h
|
||||
testmisettings.h
|
||||
testmiwebapiadapter.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
)
|
||||
|
||||
if (NOT SERVER_MODE)
|
||||
set (testmi_SOURCES
|
||||
${testmi_SOURCES}
|
||||
testmigui.cpp
|
||||
testmigui.ui
|
||||
)
|
||||
set(testmi_HEADERS
|
||||
${testmi_HEADERS}
|
||||
testsourcegui.h
|
||||
)
|
||||
set(TARGET_NAME mimotestmi)
|
||||
set(TARGET_LIB "Qt5::Widgets")
|
||||
set(TARGET_LIB_GUI "sdrgui")
|
||||
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
||||
else()
|
||||
set(TARGET_NAME mimotestmisrv)
|
||||
set(TARGET_LIB "")
|
||||
set(TARGET_LIB_GUI "")
|
||||
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
|
||||
endif()
|
||||
|
||||
add_library(${TARGET_NAME} SHARED
|
||||
${testmi_SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(${TARGET_NAME}
|
||||
Qt5::Core
|
||||
${TARGET_LIB}
|
||||
sdrbase
|
||||
${TARGET_LIB_GUI}
|
||||
swagger
|
||||
)
|
||||
|
||||
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
|
@ -1,134 +0,0 @@
|
||||
<h1>Test source input plugin</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This input sample source plugin is an internal continuous wave generator that can be used to carry out test of software internals.
|
||||
|
||||
<h2>Build</h2>
|
||||
|
||||
The plugin is present in the core of the software and thus is always present in the list of sources.
|
||||
|
||||
<h2>Interface</h2>
|
||||
|
||||
![Test source input plugin GUI](../../../doc/img/TestSourceInput_plugin.png)
|
||||
|
||||
<h3>1: Common stream parameters</h3>
|
||||
|
||||
![Remote source input stream GUI](../../../doc/img/RemoteInput_plugin_01.png)
|
||||
|
||||
<h4>1.1: Frequency</h4>
|
||||
|
||||
This is the center frequency of reception in kHz.
|
||||
|
||||
<h4>1.2: Start/Stop</h4>
|
||||
|
||||
Device start / stop button.
|
||||
|
||||
- Blue triangle icon: device is ready and can be started
|
||||
- Green square icon: device is running and can be stopped
|
||||
- Magenta (or pink) square icon: an error occurred. In the case the device was accidentally disconnected you may click on the icon, plug back in and start again.
|
||||
|
||||
<h4>1.3: Record</h4>
|
||||
|
||||
Record baseband I/Q stream toggle button
|
||||
|
||||
<h4>1.4: Stream sample rate</h4>
|
||||
|
||||
Baseband I/Q sample rate in kS/s. This is the device to host sample rate (3) divided by the decimation factor (4).
|
||||
|
||||
<h3>2: Various options</h3>
|
||||
|
||||
![Test source input plugin GUI 2](../../../doc/img/TestSourceInput_plugin_2.png)
|
||||
|
||||
<h4>2.1: Auto corrections</h4>
|
||||
|
||||
This combo box control the local DSP auto correction options:
|
||||
|
||||
- **None**: no correction
|
||||
- **DC**: auto remove DC component
|
||||
- **DC+IQ**: auto remove DC component and correct I/Q balance.
|
||||
|
||||
<h4>2.2: Decimation factor</h4>
|
||||
|
||||
The I/Q stream from the generator is downsampled by a power of two before being sent to the passband. Possible values are increasing powers of two: 1 (no decimation), 2, 4, 8, 16, 32. This exercises the decimation chain.
|
||||
|
||||
This exercises the decimation chain.
|
||||
|
||||
<h4>2.3: Baseband center frequency position relative the center frequency</h4>
|
||||
|
||||
- **Cen**: the decimation operation takes place around the center frequency Fs
|
||||
- **Inf**: the decimation operation takes place around Fs - Fc.
|
||||
- **Sup**: the decimation operation takes place around Fs + Fc.
|
||||
|
||||
With SR as the sample rate before decimation Fc is calculated as:
|
||||
|
||||
- if decimation n is 4 or lower: Fc = SR/2^(log2(n)-1). The device center frequency is on the side of the baseband. You need a RF filter bandwidth at least twice the baseband.
|
||||
- if decimation n is 8 or higher: Fc = SR/n. The device center frequency is half the baseband away from the side of the baseband. You need a RF filter bandwidth at least 3 times the baseband.
|
||||
|
||||
<h3>2.4: Sample size</h3>
|
||||
|
||||
This is the sample size in number of bits. It corresponds to the actual sample size used by the devices supported:
|
||||
|
||||
- **8**: RTL-SDR, HackRF
|
||||
- **12**: Airspy, BladeRF, LimeSDR, PlutoSDR, SDRplay
|
||||
- **16**: Airspy HF+, FCD Pro, FCD Pro+
|
||||
|
||||
<h3>3: Sample rate</h3>
|
||||
|
||||
This controls the generator sample rate in samples per second.
|
||||
|
||||
<h3>4: Modulation</h4>
|
||||
|
||||
- **No**: No modulation
|
||||
- **AM**: Amplitude modulation (AM)
|
||||
- **FM**: Frequency modulation (FM)
|
||||
- **P0**: Pattern 0 is a binary pattern
|
||||
- Pulse width: 150 samples
|
||||
- Sync pattern: 010 at full amplitude
|
||||
- Binary pattern LSB first on 3 bits from 0 to 7 at 0.3 amplitude
|
||||
- **P1**: Pattern 1 is a sawtooth pattern
|
||||
- Pulse width: 1000 samples
|
||||
- Starts at full amplitude then amplitude decreases linearly down to zero
|
||||
- **P2**: Pattern 2 is a 50% duty cycle square pattern
|
||||
- Pulse width: 1000 samples
|
||||
- Starts with a full amplitude pulse then down to zero for the duration of one pulse
|
||||
|
||||
<h3>5: Modulating tone frequency</h3>
|
||||
|
||||
This controls the modulating tone frequency in kHz in 10 Hz steps.
|
||||
|
||||
<h3>6: Carrier shift from center frequency</h3>
|
||||
|
||||
Use this control to set the offset of the carrier from the center frequency of reception.
|
||||
|
||||
<h3>7: AM modulation factor</h3>
|
||||
|
||||
This controls the AM modulation factor from 0 to 99%
|
||||
|
||||
<h3>8: FM deviation</h3>
|
||||
|
||||
This controls the frequency modulation deviation in kHz in 100 Hz steps. It cannot exceed the sample rate.
|
||||
|
||||
<h3>9: Amplitude coarse control</h3>
|
||||
|
||||
This slider controls the number of amplitude bits by steps of 100 bits. The total number of amplitude bits appear on the right.
|
||||
|
||||
<h3>10: Amplitude fine control</h3>
|
||||
|
||||
This slider controls the number of amplitude bits by steps of 1 bit. The signal power in dB relative to the maximum power (full bit range) appear on the right.
|
||||
|
||||
<h3>11: DC bias</h3>
|
||||
|
||||
Use this slider to give a DC component in percentage of maximum amplitude.
|
||||
|
||||
<h3>12: I bias</h3>
|
||||
|
||||
Use this slider to give an in-phase (I) bias in percentage of maximum amplitude.
|
||||
|
||||
<h3>13: Q bias</h3>
|
||||
|
||||
Use this slider to give an quadrature-phase (Q) bias in percentage of maximum amplitude.
|
||||
|
||||
<h3>14: Phase imbalance</h3>
|
||||
|
||||
Use this slider to introduce a phase imbalance in percentage of full period (continuous wave) or percentage of I signal injected in Q (AM, FM).
|
@ -1,906 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QBuffer>
|
||||
|
||||
#include "SWGDeviceSettings.h"
|
||||
#include "SWGDeviceState.h"
|
||||
#include "SWGTestMISettings.h"
|
||||
|
||||
#include "device/deviceapi.h"
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "dsp/dspdevicemimoengine.h"
|
||||
#include "dsp/devicesamplesource.h"
|
||||
#include "dsp/filerecord.h"
|
||||
|
||||
#include "testmithread.h"
|
||||
#include "testmi.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(TestMI::MsgConfigureTestSource, Message)
|
||||
MESSAGE_CLASS_DEFINITION(TestMI::MsgFileRecord, Message)
|
||||
MESSAGE_CLASS_DEFINITION(TestMI::MsgStartStop, Message)
|
||||
|
||||
|
||||
TestMI::TestMI(DeviceAPI *deviceAPI) :
|
||||
m_deviceAPI(deviceAPI),
|
||||
m_settings(),
|
||||
m_deviceDescription("TestMI"),
|
||||
m_running(false),
|
||||
m_masterTimer(deviceAPI->getMasterTimer())
|
||||
{
|
||||
m_mimoType = MIMOAsynchronous;
|
||||
m_sampleMIFifo.init(2, 96000 * 4);
|
||||
//m_sampleSinkVectors.resize(2);
|
||||
m_deviceAPI->setNbSourceStreams(2);
|
||||
m_networkManager = new QNetworkAccessManager();
|
||||
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||
}
|
||||
|
||||
TestMI::~TestMI()
|
||||
{
|
||||
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
|
||||
delete m_networkManager;
|
||||
|
||||
if (m_running) {
|
||||
stopRx();
|
||||
}
|
||||
|
||||
std::vector<FileRecord*>::iterator it = m_fileSinks.begin();
|
||||
int istream = 0;
|
||||
|
||||
for (; it != m_fileSinks.end(); ++it, istream++)
|
||||
{
|
||||
m_deviceAPI->removeAncillarySink(*it, istream);
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMI::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void TestMI::init()
|
||||
{
|
||||
m_fileSinks.push_back(new FileRecord(QString("test_0_%1.sdriq").arg(m_deviceAPI->getDeviceUID())));
|
||||
m_fileSinks.push_back(new FileRecord(QString("test_1_%1.sdriq").arg(m_deviceAPI->getDeviceUID())));
|
||||
m_deviceAPI->addAncillarySink(m_fileSinks[0], 0);
|
||||
m_deviceAPI->addAncillarySink(m_fileSinks[1], 1);
|
||||
|
||||
applySettings(m_settings, true);
|
||||
}
|
||||
|
||||
bool TestMI::startRx()
|
||||
{
|
||||
qDebug("TestMI::startRx");
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
if (m_running) {
|
||||
stopRx();
|
||||
}
|
||||
|
||||
m_testSourceThreads.push_back(new TestMIThread(&m_sampleMIFifo, 0));
|
||||
m_testSourceThreads.back()->setSamplerate(m_settings.m_streams[0].m_sampleRate);
|
||||
m_testSourceThreads.back()->startStop(true);
|
||||
|
||||
m_testSourceThreads.push_back(new TestMIThread(&m_sampleMIFifo, 1));
|
||||
m_testSourceThreads.back()->setSamplerate(m_settings.m_streams[1].m_sampleRate);
|
||||
m_testSourceThreads.back()->startStop(true);
|
||||
|
||||
mutexLocker.unlock();
|
||||
|
||||
applySettings(m_settings, true);
|
||||
m_running = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestMI::startTx()
|
||||
{
|
||||
qDebug("TestMI::startTx");
|
||||
return false;
|
||||
}
|
||||
|
||||
void TestMI::stopRx()
|
||||
{
|
||||
qDebug("TestMI::stopRx");
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
std::vector<TestMIThread*>::iterator it = m_testSourceThreads.begin();
|
||||
|
||||
for (; it != m_testSourceThreads.end(); ++it)
|
||||
{
|
||||
(*it)->startStop(false);
|
||||
(*it)->deleteLater();
|
||||
}
|
||||
|
||||
m_testSourceThreads.clear();
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
void TestMI::stopTx()
|
||||
{
|
||||
qDebug("TestMI::stopTx");
|
||||
}
|
||||
|
||||
QByteArray TestMI::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool TestMI::deserialize(const QByteArray& data)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (!m_settings.deserialize(data))
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
success = false;
|
||||
}
|
||||
|
||||
MsgConfigureTestSource* message = MsgConfigureTestSource::create(m_settings, true);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
MsgConfigureTestSource* messageToGUI = MsgConfigureTestSource::create(m_settings, true);
|
||||
m_guiMessageQueue->push(messageToGUI);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
const QString& TestMI::getDeviceDescription() const
|
||||
{
|
||||
return m_deviceDescription;
|
||||
}
|
||||
|
||||
int TestMI::getSourceSampleRate(int index) const
|
||||
{
|
||||
if (index < (int) m_settings.m_streams.size()) {
|
||||
return m_settings.m_streams[index].m_sampleRate/(1<<m_settings.m_streams[index].m_log2Decim);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
quint64 TestMI::getSourceCenterFrequency(int index) const
|
||||
{
|
||||
if (index < (int) m_settings.m_streams.size()) {
|
||||
return m_settings.m_streams[index].m_centerFrequency;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMI::setSourceCenterFrequency(qint64 centerFrequency, int index)
|
||||
{
|
||||
TestMISettings settings = m_settings; // note: calls copy constructor
|
||||
|
||||
if (index < (int) settings.m_streams.size())
|
||||
{
|
||||
settings.m_streams[index].m_centerFrequency = centerFrequency;
|
||||
|
||||
MsgConfigureTestSource* message = MsgConfigureTestSource::create(settings, false);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue)
|
||||
{
|
||||
MsgConfigureTestSource* messageToGUI = MsgConfigureTestSource::create(settings, false);
|
||||
m_guiMessageQueue->push(messageToGUI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TestMI::handleMessage(const Message& message)
|
||||
{
|
||||
if (MsgConfigureTestSource::match(message))
|
||||
{
|
||||
MsgConfigureTestSource& conf = (MsgConfigureTestSource&) message;
|
||||
qDebug() << "TestMI::handleMessage: MsgConfigureTestSource";
|
||||
|
||||
bool success = applySettings(conf.getSettings(), conf.getForce());
|
||||
|
||||
if (!success)
|
||||
{
|
||||
qDebug("TestMI::handleMessage: config error");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MsgFileRecord::match(message))
|
||||
{
|
||||
MsgFileRecord& conf = (MsgFileRecord&) message;
|
||||
qDebug() << "TestMI::handleMessage: MsgFileRecord: " << conf.getStartStop();
|
||||
int istream = conf.getStreamIndex();
|
||||
|
||||
if (conf.getStartStop())
|
||||
{
|
||||
if (m_settings.m_fileRecordName.size() != 0) {
|
||||
m_fileSinks[istream]->setFileName(m_settings.m_fileRecordName + "_0.sdriq");
|
||||
} else {
|
||||
m_fileSinks[istream]->genUniqueFileName(m_deviceAPI->getDeviceUID(), istream);
|
||||
}
|
||||
|
||||
m_fileSinks[istream]->startRecording();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fileSinks[istream]->stopRecording();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MsgStartStop::match(message))
|
||||
{
|
||||
MsgStartStop& cmd = (MsgStartStop&) message;
|
||||
qDebug() << "TestMI::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
|
||||
|
||||
if (cmd.getStartStop())
|
||||
{
|
||||
if (m_deviceAPI->initDeviceEngine())
|
||||
{
|
||||
m_deviceAPI->startDeviceEngine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_deviceAPI->stopDeviceEngine();
|
||||
}
|
||||
|
||||
if (m_settings.m_useReverseAPI) {
|
||||
webapiReverseSendStartStop(cmd.getStartStop());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestMI::applySettings(const TestMISettings& settings, bool force)
|
||||
{
|
||||
DeviceSettingsKeys deviceSettingsKeys;
|
||||
|
||||
qDebug() << "TestMI::applySettings: common: "
|
||||
<< " m_fileRecordName: " << settings.m_fileRecordName
|
||||
<< " m_useReverseAPI: " << settings.m_useReverseAPI
|
||||
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
|
||||
<< " m_reverseAPIPort: " << settings.m_reverseAPIPort
|
||||
<< " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex;
|
||||
|
||||
for (unsigned int istream = 0; (istream < m_settings.m_streams.size()) && (istream < settings.m_streams.size()); istream++)
|
||||
{
|
||||
qDebug() << "TestMI::applySettings: stream #" << istream << ": "
|
||||
<< " m_centerFrequency: " << settings.m_streams[istream].m_centerFrequency
|
||||
<< " m_frequencyShift: " << settings.m_streams[istream].m_frequencyShift
|
||||
<< " m_sampleRate: " << settings.m_streams[istream].m_sampleRate
|
||||
<< " m_log2Decim: " << settings.m_streams[istream].m_log2Decim
|
||||
<< " m_fcPos: " << settings.m_streams[istream].m_fcPos
|
||||
<< " m_amplitudeBits: " << settings.m_streams[istream].m_amplitudeBits
|
||||
<< " m_sampleSizeIndex: " << settings.m_streams[istream].m_sampleSizeIndex
|
||||
<< " m_autoCorrOptions: " << settings.m_streams[istream].m_autoCorrOptions
|
||||
<< " m_dcFactor: " << settings.m_streams[istream].m_dcFactor
|
||||
<< " m_iFactor: " << settings.m_streams[istream].m_iFactor
|
||||
<< " m_qFactor: " << settings.m_streams[istream].m_qFactor
|
||||
<< " m_phaseImbalance: " << settings.m_streams[istream].m_phaseImbalance
|
||||
<< " m_modulation: " << settings.m_streams[istream].m_modulation
|
||||
<< " m_amModulation: " << settings.m_streams[istream].m_amModulation
|
||||
<< " m_fmDeviation: " << settings.m_streams[istream].m_fmDeviation
|
||||
<< " m_modulationTone: " << settings.m_streams[istream].m_modulationTone;
|
||||
|
||||
deviceSettingsKeys.m_streamsSettingsKeys.push_back(QList<QString>());
|
||||
QList<QString>& reverseAPIKeys = deviceSettingsKeys.m_streamsSettingsKeys.back();
|
||||
|
||||
if ((m_settings.m_streams[istream].m_autoCorrOptions != settings.m_streams[istream].m_autoCorrOptions) || force)
|
||||
{
|
||||
reverseAPIKeys.append("autoCorrOptions");
|
||||
|
||||
switch(settings.m_streams[istream].m_autoCorrOptions)
|
||||
{
|
||||
case TestMIStreamSettings::AutoCorrDC:
|
||||
m_deviceAPI->configureCorrections(true, false, istream);
|
||||
break;
|
||||
case TestMIStreamSettings::AutoCorrDCAndIQ:
|
||||
m_deviceAPI->configureCorrections(true, true, istream);
|
||||
break;
|
||||
case TestMIStreamSettings::AutoCorrNone:
|
||||
default:
|
||||
m_deviceAPI->configureCorrections(false, false, istream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_sampleRate != settings.m_streams[istream].m_sampleRate) || force)
|
||||
{
|
||||
reverseAPIKeys.append("sampleRate");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream]))
|
||||
{
|
||||
m_testSourceThreads[istream]->setSamplerate(settings.m_streams[istream].m_sampleRate);
|
||||
qDebug("TestMI::applySettings: thread on stream: %u sample rate set to %d",
|
||||
istream, settings.m_streams[istream].m_sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_log2Decim != settings.m_streams[istream].m_log2Decim) || force)
|
||||
{
|
||||
reverseAPIKeys.append("log2Decim");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream]))
|
||||
{
|
||||
m_testSourceThreads[istream]->setLog2Decimation(settings.m_streams[istream].m_log2Decim);
|
||||
qDebug("TestMI::applySettings: thread on stream: %u set decimation to %d",
|
||||
istream, (1<<settings.m_streams[istream].m_log2Decim));
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_centerFrequency != settings.m_streams[istream].m_centerFrequency)
|
||||
|| (m_settings.m_streams[istream].m_fcPos != settings.m_streams[istream].m_fcPos)
|
||||
|| (m_settings.m_streams[istream].m_frequencyShift != settings.m_streams[istream].m_frequencyShift)
|
||||
|| (m_settings.m_streams[istream].m_sampleRate != settings.m_streams[istream].m_sampleRate)
|
||||
|| (m_settings.m_streams[istream].m_log2Decim != settings.m_streams[istream].m_log2Decim) || force)
|
||||
{
|
||||
reverseAPIKeys.append("centerFrequency");
|
||||
reverseAPIKeys.append("fcPos");
|
||||
reverseAPIKeys.append("frequencyShift");
|
||||
|
||||
qint64 deviceCenterFrequency = DeviceSampleSource::calculateDeviceCenterFrequency(
|
||||
settings.m_streams[istream].m_centerFrequency,
|
||||
0, // no transverter mode
|
||||
settings.m_streams[istream].m_log2Decim,
|
||||
(DeviceSampleSource::fcPos_t) settings.m_streams[istream].m_fcPos,
|
||||
settings.m_streams[istream].m_sampleRate,
|
||||
DeviceSampleSource::FrequencyShiftScheme::FSHIFT_STD,
|
||||
false);
|
||||
|
||||
int frequencyShift = settings.m_streams[istream].m_frequencyShift;
|
||||
quint32 devSampleRate = settings.m_streams[istream].m_sampleRate;
|
||||
|
||||
if (settings.m_streams[istream].m_log2Decim != 0)
|
||||
{
|
||||
frequencyShift += DeviceSampleSource::calculateFrequencyShift(
|
||||
settings.m_streams[istream].m_log2Decim,
|
||||
(DeviceSampleSource::fcPos_t) settings.m_streams[istream].m_fcPos,
|
||||
settings.m_streams[istream].m_sampleRate,
|
||||
DeviceSampleSource::FSHIFT_STD);
|
||||
}
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream]))
|
||||
{
|
||||
m_testSourceThreads[istream]->setFcPos((int) settings.m_streams[istream].m_fcPos);
|
||||
m_testSourceThreads[istream]->setFrequencyShift(frequencyShift);
|
||||
qDebug() << "TestMI::applySettings:"
|
||||
<< " thread on istream: " << istream
|
||||
<< " center freq: " << settings.m_streams[istream].m_centerFrequency << " Hz"
|
||||
<< " device center freq: " << deviceCenterFrequency << " Hz"
|
||||
<< " device sample rate: " << devSampleRate << "Hz"
|
||||
<< " Actual sample rate: " << devSampleRate/(1<<m_settings.m_streams[istream].m_log2Decim) << "Hz"
|
||||
<< " f shift: " << settings.m_streams[istream].m_frequencyShift;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_amplitudeBits != settings.m_streams[istream].m_amplitudeBits) || force)
|
||||
{
|
||||
reverseAPIKeys.append("amplitudeBits");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setAmplitudeBits(settings.m_streams[istream].m_amplitudeBits);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_dcFactor != settings.m_streams[istream].m_dcFactor) || force)
|
||||
{
|
||||
reverseAPIKeys.append("dcFactor");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setDCFactor(settings.m_streams[istream].m_dcFactor);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_iFactor != settings.m_streams[istream].m_iFactor) || force)
|
||||
{
|
||||
reverseAPIKeys.append("iFactor");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setIFactor(settings.m_streams[istream].m_iFactor);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_qFactor != settings.m_streams[istream].m_qFactor) || force)
|
||||
{
|
||||
reverseAPIKeys.append("qFactor");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setQFactor(settings.m_streams[istream].m_qFactor);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_phaseImbalance != settings.m_streams[istream].m_phaseImbalance) || force)
|
||||
{
|
||||
reverseAPIKeys.append("phaseImbalance");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setPhaseImbalance(settings.m_streams[istream].m_phaseImbalance);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_sampleSizeIndex != settings.m_streams[istream].m_sampleSizeIndex) || force)
|
||||
{
|
||||
reverseAPIKeys.append("sampleSizeIndex");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setBitSize(settings.m_streams[istream].m_sampleSizeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_sampleRate != settings.m_streams[istream].m_sampleRate)
|
||||
|| (m_settings.m_streams[istream].m_centerFrequency != settings.m_streams[istream].m_centerFrequency)
|
||||
|| (m_settings.m_streams[istream].m_log2Decim != settings.m_streams[istream].m_log2Decim)
|
||||
|| (m_settings.m_streams[istream].m_fcPos != settings.m_streams[istream].m_fcPos) || force)
|
||||
{
|
||||
int sampleRate = settings.m_streams[istream].m_sampleRate/(1<<settings.m_streams[istream].m_log2Decim);
|
||||
DSPSignalNotification notif(sampleRate, settings.m_streams[istream].m_centerFrequency);
|
||||
m_fileSinks[istream]->handleMessage(notif); // forward to file sink
|
||||
DSPMIMOSignalNotification *engineNotif = new DSPMIMOSignalNotification(
|
||||
sampleRate, settings.m_streams[istream].m_centerFrequency, true, istream);
|
||||
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(engineNotif);
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_modulationTone != settings.m_streams[istream].m_modulationTone) || force)
|
||||
{
|
||||
reverseAPIKeys.append("modulationTone");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setToneFrequency(settings.m_streams[istream].m_modulationTone * 10);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_modulation != settings.m_streams[istream].m_modulation) || force)
|
||||
{
|
||||
reverseAPIKeys.append("modulation");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream]))
|
||||
{
|
||||
m_testSourceThreads[istream]->setModulation(settings.m_streams[istream].m_modulation);
|
||||
|
||||
if (settings.m_streams[istream].m_modulation == TestMIStreamSettings::ModulationPattern0) {
|
||||
m_testSourceThreads[istream]->setPattern0();
|
||||
} else if (settings.m_streams[istream].m_modulation == TestMIStreamSettings::ModulationPattern1) {
|
||||
m_testSourceThreads[istream]->setPattern1();
|
||||
} else if (settings.m_streams[istream].m_modulation == TestMIStreamSettings::ModulationPattern2) {
|
||||
m_testSourceThreads[istream]->setPattern2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_amModulation != settings.m_streams[istream].m_amModulation) || force)
|
||||
{
|
||||
reverseAPIKeys.append("amModulation");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setAMModulation(settings.m_streams[istream].m_amModulation / 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_streams[istream].m_fmDeviation != settings.m_streams[istream].m_fmDeviation) || force)
|
||||
{
|
||||
reverseAPIKeys.append("fmDeviation");
|
||||
|
||||
if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) {
|
||||
m_testSourceThreads[istream]->setFMDeviation(settings.m_streams[istream].m_fmDeviation * 100.0f);
|
||||
}
|
||||
}
|
||||
} // for each stream index
|
||||
|
||||
if (settings.m_useReverseAPI)
|
||||
{
|
||||
qDebug("TestMI::applySettings: call webapiReverseSendSettings");
|
||||
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
|
||||
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
|
||||
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
|
||||
(m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex);
|
||||
webapiReverseSendSettings(deviceSettingsKeys, settings, fullUpdate || force);
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
return true;
|
||||
}
|
||||
|
||||
int TestMI::webapiRunGet(
|
||||
int subsystemIndex,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
if (subsystemIndex == 0)
|
||||
{
|
||||
m_deviceAPI->getDeviceEngineStateStr(*response.getState()); // Rx only
|
||||
return 200;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = QString("Subsystem index invalid: expect 0 (Rx) only");
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
|
||||
int TestMI::webapiRun(
|
||||
bool run,
|
||||
int subsystemIndex,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
if (subsystemIndex == 0)
|
||||
{
|
||||
m_deviceAPI->getDeviceEngineStateStr(*response.getState()); // Rx only
|
||||
MsgStartStop *message = MsgStartStop::create(run);
|
||||
m_inputMessageQueue.push(message);
|
||||
|
||||
if (m_guiMessageQueue) // forward to GUI if any
|
||||
{
|
||||
MsgStartStop *msgToGUI = MsgStartStop::create(run);
|
||||
m_guiMessageQueue->push(msgToGUI);
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = QString("Subsystem index invalid: expect 0 (Rx) only");
|
||||
return 404;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int TestMI::webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
response.setTestMiSettings(new SWGSDRangel::SWGTestMISettings());
|
||||
response.getTestMiSettings()->init();
|
||||
webapiFormatDeviceSettings(response, m_settings);
|
||||
return 200;
|
||||
}
|
||||
|
||||
int TestMI::webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
TestMISettings settings = m_settings;
|
||||
webapiUpdateDeviceSettings(settings, deviceSettingsKeys, response);
|
||||
|
||||
MsgConfigureTestSource *msg = MsgConfigureTestSource::create(settings, force);
|
||||
m_inputMessageQueue.push(msg);
|
||||
|
||||
if (m_guiMessageQueue) // forward to GUI if any
|
||||
{
|
||||
MsgConfigureTestSource *msgToGUI = MsgConfigureTestSource::create(settings, force);
|
||||
m_guiMessageQueue->push(msgToGUI);
|
||||
}
|
||||
|
||||
webapiFormatDeviceSettings(response, settings);
|
||||
return 200;
|
||||
}
|
||||
|
||||
void TestMI::webapiUpdateDeviceSettings(
|
||||
TestMISettings& settings,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response)
|
||||
{
|
||||
if (deviceSettingsKeys.contains("streams"))
|
||||
{
|
||||
QList<SWGSDRangel::SWGTestMiStreamSettings*> *streamsSettings = response.getTestMiSettings()->getStreams();
|
||||
QList<SWGSDRangel::SWGTestMiStreamSettings*>::const_iterator it = streamsSettings->begin();
|
||||
|
||||
for (; it != streamsSettings->end(); ++it)
|
||||
{
|
||||
int istream = (*it)->getStreamIndex();
|
||||
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].centerFrequency").arg(istream))) {
|
||||
settings.m_streams[istream].m_centerFrequency = (*it)->getCenterFrequency();
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].frequencyShift").arg(istream))) {
|
||||
settings.m_streams[istream].m_frequencyShift = (*it)->getFrequencyShift();
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].sampleRate").arg(istream))) {
|
||||
settings.m_streams[istream].m_sampleRate = (*it)->getSampleRate();
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].log2Decim").arg(istream))) {
|
||||
settings.m_streams[istream].m_log2Decim = (*it)->getLog2Decim();
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].fcPos").arg(istream))) {
|
||||
int fcPos = (*it)->getFcPos();
|
||||
fcPos = fcPos < 0 ? 0 : fcPos > 2 ? 2 : fcPos;
|
||||
settings.m_streams[istream].m_fcPos = (TestMIStreamSettings::fcPos_t) fcPos;
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].sampleSizeIndex").arg(istream))) {
|
||||
int sampleSizeIndex = (*it)->getSampleSizeIndex();
|
||||
sampleSizeIndex = sampleSizeIndex < 0 ? 0 : sampleSizeIndex > 1 ? 2 : sampleSizeIndex;
|
||||
settings.m_streams[istream].m_sampleSizeIndex = sampleSizeIndex;
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].amplitudeBits").arg(istream))) {
|
||||
settings.m_streams[istream].m_amplitudeBits = (*it)->getAmplitudeBits();
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].autoCorrOptions").arg(istream))) {
|
||||
int autoCorrOptions = (*it)->getAutoCorrOptions();
|
||||
autoCorrOptions = autoCorrOptions < 0 ? 0 : autoCorrOptions >= TestMIStreamSettings::AutoCorrLast ? TestMIStreamSettings::AutoCorrLast-1 : autoCorrOptions;
|
||||
settings.m_streams[istream].m_sampleSizeIndex = (TestMIStreamSettings::AutoCorrOptions) autoCorrOptions;
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].modulation").arg(istream))) {
|
||||
int modulation = (*it)->getModulation();
|
||||
modulation = modulation < 0 ? 0 : modulation >= TestMIStreamSettings::ModulationLast ? TestMIStreamSettings::ModulationLast-1 : modulation;
|
||||
settings.m_streams[istream].m_modulation = (TestMIStreamSettings::Modulation) modulation;
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].modulationTone").arg(istream))) {
|
||||
settings.m_streams[istream].m_modulationTone = (*it)->getModulationTone();
|
||||
}
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].amModulation").arg(istream))) {
|
||||
settings.m_streams[istream].m_amModulation = (*it)->getAmModulation();
|
||||
};
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].fmDeviation").arg(istream))) {
|
||||
settings.m_streams[istream].m_fmDeviation = (*it)->getFmDeviation();
|
||||
};
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].dcFactor").arg(istream))) {
|
||||
settings.m_streams[istream].m_dcFactor = (*it)->getDcFactor();
|
||||
};
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].iFactor").arg(istream))) {
|
||||
settings.m_streams[istream].m_iFactor = (*it)->getIFactor();
|
||||
};
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].qFactor").arg(istream))) {
|
||||
settings.m_streams[istream].m_qFactor = (*it)->getQFactor();
|
||||
};
|
||||
if (deviceSettingsKeys.contains(QString("streams[%1].phaseImbalance").arg(istream))) {
|
||||
settings.m_streams[istream].m_phaseImbalance = (*it)->getPhaseImbalance();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (deviceSettingsKeys.contains("fileRecordName")) {
|
||||
settings.m_fileRecordName = *response.getTestMiSettings()->getFileRecordName();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("useReverseAPI")) {
|
||||
settings.m_useReverseAPI = response.getTestMiSettings()->getUseReverseApi() != 0;
|
||||
}
|
||||
if (deviceSettingsKeys.contains("reverseAPIAddress")) {
|
||||
settings.m_reverseAPIAddress = *response.getTestMiSettings()->getReverseApiAddress();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("reverseAPIPort")) {
|
||||
settings.m_reverseAPIPort = response.getTestMiSettings()->getReverseApiPort();
|
||||
}
|
||||
if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
|
||||
settings.m_reverseAPIDeviceIndex = response.getTestMiSettings()->getReverseApiDeviceIndex();
|
||||
}
|
||||
}
|
||||
|
||||
void TestMI::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const TestMISettings& settings)
|
||||
{
|
||||
std::vector<TestMIStreamSettings>::const_iterator it = settings.m_streams.begin();
|
||||
int istream = 0;
|
||||
|
||||
for (; it != settings.m_streams.end(); ++it, istream++)
|
||||
{
|
||||
QList<SWGSDRangel::SWGTestMiStreamSettings*> *streams = response.getTestMiSettings()->getStreams();
|
||||
streams->append(new SWGSDRangel::SWGTestMiStreamSettings);
|
||||
streams->back()->init();
|
||||
streams->back()->setStreamIndex(istream);
|
||||
streams->back()->setCenterFrequency(it->m_centerFrequency);
|
||||
streams->back()->setFrequencyShift(it->m_frequencyShift);
|
||||
streams->back()->setSampleRate(it->m_sampleRate);
|
||||
streams->back()->setLog2Decim(it->m_log2Decim);
|
||||
streams->back()->setFcPos((int) it->m_fcPos);
|
||||
streams->back()->setSampleSizeIndex((int) it->m_sampleSizeIndex);
|
||||
streams->back()->setAmplitudeBits(it->m_amplitudeBits);
|
||||
streams->back()->setAutoCorrOptions((int) it->m_autoCorrOptions);
|
||||
streams->back()->setModulation((int) it->m_modulation);
|
||||
streams->back()->setModulationTone(it->m_modulationTone);
|
||||
streams->back()->setAmModulation(it->m_amModulation);
|
||||
streams->back()->setFmDeviation(it->m_fmDeviation);
|
||||
streams->back()->setDcFactor(it->m_dcFactor);
|
||||
streams->back()->setIFactor(it->m_iFactor);
|
||||
streams->back()->setQFactor(it->m_qFactor);
|
||||
streams->back()->setPhaseImbalance(it->m_phaseImbalance);
|
||||
}
|
||||
|
||||
if (response.getTestMiSettings()->getFileRecordName()) {
|
||||
*response.getTestMiSettings()->getFileRecordName() = settings.m_fileRecordName;
|
||||
} else {
|
||||
response.getTestMiSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
|
||||
}
|
||||
|
||||
response.getTestMiSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||
|
||||
if (response.getTestMiSettings()->getReverseApiAddress()) {
|
||||
*response.getTestMiSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||
} else {
|
||||
response.getTestMiSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||
}
|
||||
|
||||
response.getTestMiSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||
response.getTestMiSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
|
||||
}
|
||||
|
||||
void TestMI::webapiReverseSendSettings(const DeviceSettingsKeys& deviceSettingsKeys, const TestMISettings& settings, bool force)
|
||||
{
|
||||
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
|
||||
swgDeviceSettings->setDirection(0); // single Rx
|
||||
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
|
||||
swgDeviceSettings->setDeviceHwType(new QString("TestSource"));
|
||||
swgDeviceSettings->setTestMiSettings(new SWGSDRangel::SWGTestMISettings());
|
||||
SWGSDRangel::SWGTestMISettings *swgTestMISettings = swgDeviceSettings->getTestMiSettings();
|
||||
|
||||
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||
|
||||
QList<QList<QString>>::const_iterator it = deviceSettingsKeys.m_streamsSettingsKeys.begin();
|
||||
int istream = 0;
|
||||
|
||||
for (; it != deviceSettingsKeys.m_streamsSettingsKeys.end(); ++it, istream++)
|
||||
{
|
||||
if ((it->size() > 0) || force)
|
||||
{
|
||||
QList<SWGSDRangel::SWGTestMiStreamSettings*> *streams = swgTestMISettings->getStreams();
|
||||
streams->append(new SWGSDRangel::SWGTestMiStreamSettings);
|
||||
streams->back()->init();
|
||||
streams->back()->setStreamIndex(istream);
|
||||
const QList<QString>& streamSettingsKeys = *it;
|
||||
|
||||
if (streamSettingsKeys.contains("centerFrequency") || force) {
|
||||
streams->back()->setCenterFrequency(settings.m_streams[istream].m_centerFrequency);
|
||||
}
|
||||
if (streamSettingsKeys.contains("frequencyShift") || force) {
|
||||
streams->back()->setFrequencyShift(settings.m_streams[istream].m_frequencyShift);
|
||||
}
|
||||
if (streamSettingsKeys.contains("sampleRate") || force) {
|
||||
streams->back()->setSampleRate(settings.m_streams[istream].m_sampleRate);
|
||||
}
|
||||
if (streamSettingsKeys.contains("log2Decim") || force) {
|
||||
streams->back()->setLog2Decim(settings.m_streams[istream].m_log2Decim);
|
||||
}
|
||||
if (streamSettingsKeys.contains("fcPos") || force) {
|
||||
streams->back()->setFcPos((int) settings.m_streams[istream].m_fcPos);
|
||||
}
|
||||
if (streamSettingsKeys.contains("sampleSizeIndex") || force) {
|
||||
streams->back()->setSampleSizeIndex(settings.m_streams[istream].m_sampleSizeIndex);
|
||||
}
|
||||
if (streamSettingsKeys.contains("amplitudeBits") || force) {
|
||||
streams->back()->setAmplitudeBits(settings.m_streams[istream].m_amplitudeBits);
|
||||
}
|
||||
if (streamSettingsKeys.contains("autoCorrOptions") || force) {
|
||||
streams->back()->setAutoCorrOptions((int) settings.m_streams[istream].m_sampleSizeIndex);
|
||||
}
|
||||
if (streamSettingsKeys.contains("modulation") || force) {
|
||||
streams->back()->setModulation((int) settings.m_streams[istream].m_modulation);
|
||||
}
|
||||
if (streamSettingsKeys.contains("modulationTone")) {
|
||||
streams->back()->setModulationTone(settings.m_streams[istream].m_modulationTone);
|
||||
}
|
||||
if (streamSettingsKeys.contains("amModulation") || force) {
|
||||
streams->back()->setAmModulation(settings.m_streams[istream].m_amModulation);
|
||||
};
|
||||
if (streamSettingsKeys.contains("fmDeviation") || force) {
|
||||
streams->back()->setFmDeviation(settings.m_streams[istream].m_fmDeviation);
|
||||
};
|
||||
if (streamSettingsKeys.contains("dcFactor") || force) {
|
||||
streams->back()->setDcFactor(settings.m_streams[istream].m_dcFactor);
|
||||
};
|
||||
if (streamSettingsKeys.contains("iFactor") || force) {
|
||||
streams->back()->setIFactor(settings.m_streams[istream].m_iFactor);
|
||||
};
|
||||
if (streamSettingsKeys.contains("qFactor") || force) {
|
||||
streams->back()->setQFactor(settings.m_streams[istream].m_qFactor);
|
||||
};
|
||||
if (streamSettingsKeys.contains("phaseImbalance") || force) {
|
||||
streams->back()->setPhaseImbalance(settings.m_streams[istream].m_phaseImbalance);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceSettingsKeys.m_commonSettingsKeys.contains("fileRecordName") || force) {
|
||||
swgTestMISettings->setFileRecordName(new QString(settings.m_fileRecordName));
|
||||
}
|
||||
|
||||
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
|
||||
.arg(settings.m_reverseAPIAddress)
|
||||
.arg(settings.m_reverseAPIPort)
|
||||
.arg(settings.m_reverseAPIDeviceIndex);
|
||||
m_networkRequest.setUrl(QUrl(channelSettingsURL));
|
||||
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QBuffer *buffer = new QBuffer();
|
||||
buffer->open((QBuffer::ReadWrite));
|
||||
buffer->write(swgDeviceSettings->asJson().toUtf8());
|
||||
buffer->seek(0);
|
||||
|
||||
// Always use PATCH to avoid passing reverse API settings
|
||||
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||
buffer->setParent(reply);
|
||||
|
||||
delete swgDeviceSettings;
|
||||
}
|
||||
|
||||
void TestMI::webapiReverseSendStartStop(bool start)
|
||||
{
|
||||
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
|
||||
swgDeviceSettings->setDirection(0); // single Rx
|
||||
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
|
||||
swgDeviceSettings->setDeviceHwType(new QString("TestSource"));
|
||||
|
||||
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
|
||||
.arg(m_settings.m_reverseAPIAddress)
|
||||
.arg(m_settings.m_reverseAPIPort)
|
||||
.arg(m_settings.m_reverseAPIDeviceIndex);
|
||||
m_networkRequest.setUrl(QUrl(channelSettingsURL));
|
||||
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QBuffer *buffer = new QBuffer();
|
||||
buffer->open((QBuffer::ReadWrite));
|
||||
buffer->write(swgDeviceSettings->asJson().toUtf8());
|
||||
buffer->seek(0);
|
||||
QNetworkReply *reply;
|
||||
|
||||
if (start) {
|
||||
reply = m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
|
||||
} else {
|
||||
reply = m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
|
||||
}
|
||||
|
||||
buffer->setParent(reply);
|
||||
delete swgDeviceSettings;
|
||||
}
|
||||
|
||||
void TestMI::networkManagerFinished(QNetworkReply *reply)
|
||||
{
|
||||
QNetworkReply::NetworkError replyError = reply->error();
|
||||
|
||||
if (replyError)
|
||||
{
|
||||
qWarning() << "TestMI::networkManagerFinished:"
|
||||
<< " error(" << (int) replyError
|
||||
<< "): " << replyError
|
||||
<< ": " << reply->errorString();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString answer = reply->readAll();
|
||||
answer.chop(1); // remove last \n
|
||||
qDebug("TestMI::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
bool TestMI::isRecording(unsigned int istream) const
|
||||
{
|
||||
if (istream < m_fileSinks.size()) {
|
||||
return m_fileSinks[istream]->isRecording();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 _TESTMI_TESTMI_H_
|
||||
#define _TESTMI_TESTMI_H_
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QTimer>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
#include "dsp/devicesamplemimo.h"
|
||||
#include "testmisettings.h"
|
||||
|
||||
class DeviceAPI;
|
||||
class TestMIThread;
|
||||
class FileRecord;
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
class TestMI : public DeviceSampleMIMO {
|
||||
Q_OBJECT
|
||||
public:
|
||||
class MsgConfigureTestSource : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
const TestMISettings& getSettings() const { return m_settings; }
|
||||
bool getForce() const { return m_force; }
|
||||
|
||||
static MsgConfigureTestSource* create(const TestMISettings& settings, bool force)
|
||||
{
|
||||
return new MsgConfigureTestSource(settings, force);
|
||||
}
|
||||
|
||||
private:
|
||||
TestMISettings m_settings;
|
||||
bool m_force;
|
||||
|
||||
MsgConfigureTestSource(const TestMISettings& settings, bool force) :
|
||||
Message(),
|
||||
m_settings(settings),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgFileRecord : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
int getStreamIndex() const { return m_streamIndex; }
|
||||
|
||||
static MsgFileRecord* create(bool startStop, int streamIndex) {
|
||||
return new MsgFileRecord(startStop, streamIndex);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
int m_streamIndex;
|
||||
|
||||
MsgFileRecord(bool startStop, int streamIndex) :
|
||||
Message(),
|
||||
m_startStop(startStop),
|
||||
m_streamIndex(streamIndex)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgStartStop : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgStartStop* create(bool startStop) {
|
||||
return new MsgStartStop(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgStartStop(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
TestMI(DeviceAPI *deviceAPI);
|
||||
virtual ~TestMI();
|
||||
virtual void destroy();
|
||||
|
||||
virtual void init();
|
||||
virtual bool startRx();
|
||||
virtual void stopRx();
|
||||
virtual bool startTx();
|
||||
virtual void stopTx();
|
||||
|
||||
virtual QByteArray serialize() const;
|
||||
virtual bool deserialize(const QByteArray& data);
|
||||
|
||||
virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
|
||||
virtual const QString& getDeviceDescription() const;
|
||||
|
||||
virtual int getSourceSampleRate(int index) const;
|
||||
virtual void setSourceSampleRate(int sampleRate, int index) { (void) sampleRate; (void) index; }
|
||||
virtual quint64 getSourceCenterFrequency(int index) const;
|
||||
virtual void setSourceCenterFrequency(qint64 centerFrequency, int index);
|
||||
|
||||
virtual int getSinkSampleRate(int index) const { return 0; (void) index; }
|
||||
virtual void setSinkSampleRate(int sampleRate, int index) { (void) sampleRate; (void) index; }
|
||||
virtual quint64 getSinkCenterFrequency(int index) const { return 0; (void) index; }
|
||||
virtual void setSinkCenterFrequency(qint64 centerFrequency, int index) { (void) centerFrequency; (void) index; }
|
||||
|
||||
virtual quint64 getMIMOCenterFrequency() const { return getSourceCenterFrequency(0); }
|
||||
virtual unsigned int getMIMOSampleRate() const { return getSourceSampleRate(0); }
|
||||
|
||||
virtual bool handleMessage(const Message& message);
|
||||
|
||||
virtual int webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiRunGet(
|
||||
int subsystemIndex,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiRun(
|
||||
bool run,
|
||||
int subsystemIndex,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage);
|
||||
|
||||
static void webapiFormatDeviceSettings(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
const TestMISettings& settings);
|
||||
|
||||
static void webapiUpdateDeviceSettings(
|
||||
TestMISettings& settings,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response);
|
||||
|
||||
bool isRecording(unsigned int istream) const;
|
||||
|
||||
private:
|
||||
struct DeviceSettingsKeys
|
||||
{
|
||||
QList<QString> m_commonSettingsKeys;
|
||||
QList<QList<QString>> m_streamsSettingsKeys;
|
||||
};
|
||||
|
||||
DeviceAPI *m_deviceAPI;
|
||||
std::vector<FileRecord *> m_fileSinks; //!< File sinks to record device I/Q output
|
||||
QMutex m_mutex;
|
||||
TestMISettings m_settings;
|
||||
std::vector<TestMIThread*> m_testSourceThreads;
|
||||
QString m_deviceDescription;
|
||||
bool m_running;
|
||||
const QTimer& m_masterTimer;
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
||||
bool applySettings(const TestMISettings& settings, bool force);
|
||||
void webapiReverseSendSettings(const DeviceSettingsKeys& deviceSettingsKeys, const TestMISettings& settings, bool force);
|
||||
void webapiReverseSendStartStop(bool start);
|
||||
|
||||
private slots:
|
||||
void networkManagerFinished(QNetworkReply *reply);
|
||||
};
|
||||
|
||||
#endif // _TESTMI_TESTMI_H_
|
@ -1,605 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "plugin/pluginapi.h"
|
||||
#include "device/deviceapi.h"
|
||||
#include "device/deviceuiset.h"
|
||||
#include "gui/colormapper.h"
|
||||
#include "gui/glspectrum.h"
|
||||
#include "gui/crightclickenabler.h"
|
||||
#include "gui/basicdevicesettingsdialog.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "dsp/dspdevicemimoengine.h"
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "util/db.h"
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include "ui_testmigui.h"
|
||||
#include "testmigui.h"
|
||||
|
||||
TestMIGui::TestMIGui(DeviceUISet *deviceUISet, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::TestMIGui),
|
||||
m_deviceUISet(deviceUISet),
|
||||
m_settings(),
|
||||
m_doApplySettings(true),
|
||||
m_forceSettings(true),
|
||||
m_sampleMIMO(nullptr),
|
||||
m_tickCount(0),
|
||||
m_lastEngineState(DeviceAPI::StNotStarted)
|
||||
{
|
||||
qDebug("TestMIGui::TestMIGui");
|
||||
m_sampleMIMO = m_deviceUISet->m_deviceAPI->getSampleMIMO();
|
||||
m_streamIndex = 0;
|
||||
m_deviceCenterFrequencies.push_back(m_settings.m_streams[0].m_centerFrequency);
|
||||
m_deviceCenterFrequencies.push_back(m_settings.m_streams[1].m_centerFrequency);
|
||||
m_deviceSampleRates.push_back(m_settings.m_streams[0].m_sampleRate / (1<<m_settings.m_streams[0].m_log2Decim));
|
||||
m_deviceSampleRates.push_back(m_settings.m_streams[1].m_sampleRate / (1<<m_settings.m_streams[1].m_log2Decim));
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->spectrumSource->addItem("0");
|
||||
ui->spectrumSource->addItem("1");
|
||||
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||
ui->centerFrequency->setValueRange(7, 0, 9999999);
|
||||
ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
|
||||
ui->sampleRate->setValueRange(7, 48000, 9999999);
|
||||
ui->frequencyShift->setColorMapper(ColorMapper(ColorMapper::GrayGold));
|
||||
ui->frequencyShift->setValueRange(false, 7, -9999999, 9999999);
|
||||
ui->frequencyShiftLabel->setText(QString("%1").arg(QChar(0x94, 0x03)));
|
||||
|
||||
displaySettings();
|
||||
|
||||
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
|
||||
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
|
||||
m_statusTimer.start(500);
|
||||
|
||||
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
|
||||
m_sampleMIMO->setMessageQueueToGUI(&m_inputMessageQueue);
|
||||
|
||||
CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop);
|
||||
connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
|
||||
}
|
||||
|
||||
TestMIGui::~TestMIGui()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TestMIGui::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void TestMIGui::setName(const QString& name)
|
||||
{
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
QString TestMIGui::getName() const
|
||||
{
|
||||
return objectName();
|
||||
}
|
||||
|
||||
void TestMIGui::resetToDefaults()
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
displaySettings();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
qint64 TestMIGui::getCenterFrequency() const
|
||||
{
|
||||
return m_settings.m_streams[m_streamIndex].m_centerFrequency;
|
||||
}
|
||||
|
||||
void TestMIGui::setCenterFrequency(qint64 centerFrequency)
|
||||
{
|
||||
m_settings.m_streams[m_streamIndex].m_centerFrequency = centerFrequency;
|
||||
displaySettings();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
QByteArray TestMIGui::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool TestMIGui::deserialize(const QByteArray& data)
|
||||
{
|
||||
if(m_settings.deserialize(data)) {
|
||||
displaySettings();
|
||||
m_forceSettings = true;
|
||||
sendSettings();
|
||||
return true;
|
||||
} else {
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::on_startStop_toggled(bool checked)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
TestMI::MsgStartStop *message = TestMI::MsgStartStop::create(checked);
|
||||
m_sampleMIMO->getInputMessageQueue()->push(message);
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::on_streamIndex_currentIndexChanged(int index)
|
||||
{
|
||||
if (ui->streamLock->isChecked())
|
||||
{
|
||||
m_spectrumStreamIndex = index;
|
||||
m_deviceUISet->m_spectrum->setDisplayedStream(true, index);
|
||||
m_deviceUISet->m_deviceAPI->setSpectrumSinkInput(true, m_spectrumStreamIndex);
|
||||
ui->spectrumSource->blockSignals(true);
|
||||
ui->spectrumSource->setCurrentIndex(index);
|
||||
ui->spectrumSource->blockSignals(false);
|
||||
}
|
||||
|
||||
m_streamIndex = index;
|
||||
updateFileRecordStatus();
|
||||
updateSampleRateAndFrequency();
|
||||
displaySettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_spectrumSource_currentIndexChanged(int index)
|
||||
{
|
||||
m_spectrumStreamIndex = index;
|
||||
m_deviceUISet->m_spectrum->setDisplayedStream(true, index);
|
||||
m_deviceUISet->m_deviceAPI->setSpectrumSinkInput(true, m_spectrumStreamIndex);
|
||||
updateSampleRateAndFrequency();
|
||||
|
||||
if (ui->streamLock->isChecked())
|
||||
{
|
||||
ui->streamIndex->blockSignals(true);
|
||||
ui->streamIndex->setCurrentIndex(index);
|
||||
ui->streamIndex->blockSignals(false);
|
||||
m_streamIndex = index;
|
||||
updateFileRecordStatus();
|
||||
displaySettings();
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::on_streamLock_toggled(bool checked)
|
||||
{
|
||||
if (checked && (ui->streamIndex->currentIndex() != ui->spectrumSource->currentIndex())) {
|
||||
ui->spectrumSource->setCurrentIndex(ui->streamIndex->currentIndex());
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::on_centerFrequency_changed(quint64 value)
|
||||
{
|
||||
m_settings.m_streams[m_streamIndex].m_centerFrequency = value * 1000;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_autoCorr_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > TestMIStreamSettings::AutoCorrLast)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.m_streams[m_streamIndex].m_autoCorrOptions = (TestMIStreamSettings::AutoCorrOptions) index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_frequencyShift_changed(qint64 value)
|
||||
{
|
||||
m_settings.m_streams[m_streamIndex].m_frequencyShift = value;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_decimation_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > 6)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.m_streams[m_streamIndex].m_log2Decim = index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_fcPos_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.m_streams[m_streamIndex].m_fcPos = (TestMIStreamSettings::fcPos_t) index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_sampleRate_changed(quint64 value)
|
||||
{
|
||||
updateFrequencyShiftLimit();
|
||||
m_settings.m_streams[m_streamIndex].m_frequencyShift = ui->frequencyShift->getValueNew();
|
||||
m_settings.m_streams[m_streamIndex].m_sampleRate = value;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_sampleSize_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateAmpCoarseLimit();
|
||||
updateAmpFineLimit();
|
||||
displayAmplitude();
|
||||
m_settings.m_streams[m_streamIndex].m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
|
||||
m_settings.m_streams[m_streamIndex].m_sampleSizeIndex = index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_amplitudeCoarse_valueChanged(int value)
|
||||
{
|
||||
(void) value;
|
||||
updateAmpFineLimit();
|
||||
displayAmplitude();
|
||||
m_settings.m_streams[m_streamIndex].m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_amplitudeFine_valueChanged(int value)
|
||||
{
|
||||
(void) value;
|
||||
displayAmplitude();
|
||||
m_settings.m_streams[m_streamIndex].m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_modulation_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index < 0) || (index > TestMIStreamSettings::ModulationLast)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.m_streams[m_streamIndex].m_modulation = (TestMIStreamSettings::Modulation) index;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_modulationFrequency_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_streams[m_streamIndex].m_modulationTone = value;
|
||||
ui->modulationFrequencyText->setText(QString("%1").arg(m_settings.m_streams[m_streamIndex].m_modulationTone / 100.0, 0, 'f', 2));
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_amModulation_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_streams[m_streamIndex].m_amModulation = value;
|
||||
ui->amModulationText->setText(QString("%1").arg(m_settings.m_streams[m_streamIndex].m_amModulation));
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_fmDeviation_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_streams[m_streamIndex].m_fmDeviation = value;
|
||||
ui->fmDeviationText->setText(QString("%1").arg(m_settings.m_streams[m_streamIndex].m_fmDeviation / 10.0, 0, 'f', 1));
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_dcBias_valueChanged(int value)
|
||||
{
|
||||
ui->dcBiasText->setText(QString(tr("%1 %").arg(value)));
|
||||
m_settings.m_streams[m_streamIndex].m_dcFactor = value / 100.0f;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_iBias_valueChanged(int value)
|
||||
{
|
||||
ui->iBiasText->setText(QString(tr("%1 %").arg(value)));
|
||||
m_settings.m_streams[m_streamIndex].m_iFactor = value / 100.0f;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_qBias_valueChanged(int value)
|
||||
{
|
||||
ui->qBiasText->setText(QString(tr("%1 %").arg(value)));
|
||||
m_settings.m_streams[m_streamIndex].m_qFactor = value / 100.0f;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_phaseImbalance_valueChanged(int value)
|
||||
{
|
||||
ui->phaseImbalanceText->setText(QString(tr("%1 %").arg(value)));
|
||||
m_settings.m_streams[m_streamIndex].m_phaseImbalance = value / 100.0f;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void TestMIGui::on_record_toggled(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
ui->record->setStyleSheet("QToolButton { background-color : red; }");
|
||||
} else {
|
||||
ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
}
|
||||
|
||||
TestMI::MsgFileRecord* message = TestMI::MsgFileRecord::create(checked, m_streamIndex);
|
||||
m_sampleMIMO->getInputMessageQueue()->push(message);
|
||||
}
|
||||
|
||||
void TestMIGui::displayAmplitude()
|
||||
{
|
||||
int amplitudeInt = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
|
||||
double power;
|
||||
|
||||
switch (ui->sampleSize->currentIndex())
|
||||
{
|
||||
case 0: // 8 bits: 128
|
||||
power = (double) amplitudeInt*amplitudeInt / (double) (1<<14);
|
||||
break;
|
||||
case 1: // 12 bits 2048
|
||||
power = (double) amplitudeInt*amplitudeInt / (double) (1<<22);
|
||||
break;
|
||||
case 2: // 16 bits 32768
|
||||
default:
|
||||
power = (double) amplitudeInt*amplitudeInt / (double) (1<<30);
|
||||
break;
|
||||
}
|
||||
|
||||
ui->amplitudeBits->setText(QString(tr("%1 b").arg(amplitudeInt)));
|
||||
double powerDb = CalcDb::dbPower(power);
|
||||
ui->power->setText(QString(tr("%1 dB").arg(QString::number(powerDb, 'f', 1))));
|
||||
}
|
||||
|
||||
void TestMIGui::updateAmpCoarseLimit()
|
||||
{
|
||||
switch (ui->sampleSize->currentIndex())
|
||||
{
|
||||
case 0: // 8 bits: 128
|
||||
ui->amplitudeCoarse->setMaximum(1);
|
||||
break;
|
||||
case 1: // 12 bits 2048
|
||||
ui->amplitudeCoarse->setMaximum(20);
|
||||
break;
|
||||
case 2: // 16 bits 32768
|
||||
default:
|
||||
ui->amplitudeCoarse->setMaximum(327);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::updateAmpFineLimit()
|
||||
{
|
||||
switch (ui->sampleSize->currentIndex())
|
||||
{
|
||||
case 0: // 8 bits: 128
|
||||
if (ui->amplitudeCoarse->value() == 1) {
|
||||
ui->amplitudeFine->setMaximum(27);
|
||||
} else {
|
||||
ui->amplitudeFine->setMaximum(99);
|
||||
}
|
||||
break;
|
||||
case 1: // 12 bits 2048
|
||||
if (ui->amplitudeCoarse->value() == 20) {
|
||||
ui->amplitudeFine->setMaximum(47);
|
||||
} else {
|
||||
ui->amplitudeFine->setMaximum(99);
|
||||
}
|
||||
break;
|
||||
case 2: // 16 bits 32768
|
||||
default:
|
||||
if (ui->amplitudeCoarse->value() == 327) {
|
||||
ui->amplitudeFine->setMaximum(67);
|
||||
} else {
|
||||
ui->amplitudeFine->setMaximum(99);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::updateFrequencyShiftLimit()
|
||||
{
|
||||
qint64 sampleRate = ui->sampleRate->getValueNew();
|
||||
ui->frequencyShift->setValueRange(false, 7, -sampleRate, sampleRate);
|
||||
ui->frequencyShift->setValue(m_settings.m_streams[m_streamIndex].m_frequencyShift);
|
||||
}
|
||||
|
||||
void TestMIGui::updateFileRecordStatus()
|
||||
{
|
||||
if (((TestMI*) m_sampleMIMO)->isRecording(m_streamIndex)) {
|
||||
ui->record->setStyleSheet("QToolButton { background-color : red; }");
|
||||
} else {
|
||||
ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::displaySettings()
|
||||
{
|
||||
blockApplySettings(true);
|
||||
ui->sampleSize->blockSignals(true);
|
||||
|
||||
ui->streamIndex->setCurrentIndex(m_streamIndex);
|
||||
ui->centerFrequency->setValue(m_settings.m_streams[m_streamIndex].m_centerFrequency / 1000);
|
||||
ui->decimation->setCurrentIndex(m_settings.m_streams[m_streamIndex].m_log2Decim);
|
||||
ui->fcPos->setCurrentIndex((int) m_settings.m_streams[m_streamIndex].m_fcPos);
|
||||
ui->sampleRate->setValue(m_settings.m_streams[m_streamIndex].m_sampleRate);
|
||||
updateFrequencyShiftLimit();
|
||||
ui->frequencyShift->setValue(m_settings.m_streams[m_streamIndex].m_frequencyShift);
|
||||
ui->sampleSize->setCurrentIndex(m_settings.m_streams[m_streamIndex].m_sampleSizeIndex);
|
||||
updateAmpCoarseLimit();
|
||||
int amplitudeBits = m_settings.m_streams[m_streamIndex].m_amplitudeBits;
|
||||
ui->amplitudeCoarse->setValue(amplitudeBits/100);
|
||||
updateAmpFineLimit();
|
||||
ui->amplitudeFine->setValue(amplitudeBits%100);
|
||||
displayAmplitude();
|
||||
int dcBiasPercent = roundf(m_settings.m_streams[m_streamIndex].m_dcFactor * 100.0f);
|
||||
ui->dcBias->setValue((int) dcBiasPercent);
|
||||
ui->dcBiasText->setText(QString(tr("%1 %").arg(dcBiasPercent)));
|
||||
int iBiasPercent = roundf(m_settings.m_streams[m_streamIndex].m_iFactor * 100.0f);
|
||||
ui->iBias->setValue((int) iBiasPercent);
|
||||
ui->iBiasText->setText(QString(tr("%1 %").arg(iBiasPercent)));
|
||||
int qBiasPercent = roundf(m_settings.m_streams[m_streamIndex].m_qFactor * 100.0f);
|
||||
ui->qBias->setValue((int) qBiasPercent);
|
||||
ui->qBiasText->setText(QString(tr("%1 %").arg(qBiasPercent)));
|
||||
int phaseImbalancePercent = roundf(m_settings.m_streams[m_streamIndex].m_phaseImbalance * 100.0f);
|
||||
ui->phaseImbalance->setValue((int) phaseImbalancePercent);
|
||||
ui->phaseImbalanceText->setText(QString(tr("%1 %").arg(phaseImbalancePercent)));
|
||||
ui->autoCorr->setCurrentIndex(m_settings.m_streams[m_streamIndex].m_autoCorrOptions);
|
||||
ui->sampleSize->blockSignals(false);
|
||||
ui->modulation->setCurrentIndex((int) m_settings.m_streams[m_streamIndex].m_modulation);
|
||||
ui->modulationFrequency->setValue(m_settings.m_streams[m_streamIndex].m_modulationTone);
|
||||
ui->modulationFrequencyText->setText(QString("%1").arg(m_settings.m_streams[m_streamIndex].m_modulationTone / 100.0, 0, 'f', 2));
|
||||
ui->amModulation->setValue(m_settings.m_streams[m_streamIndex].m_amModulation);
|
||||
ui->amModulationText->setText(QString("%1").arg(m_settings.m_streams[m_streamIndex].m_amModulation));
|
||||
ui->fmDeviation->setValue(m_settings.m_streams[m_streamIndex].m_fmDeviation);
|
||||
ui->fmDeviationText->setText(QString("%1").arg(m_settings.m_streams[m_streamIndex].m_fmDeviation / 10.0, 0, 'f', 1));
|
||||
blockApplySettings(false);
|
||||
}
|
||||
|
||||
void TestMIGui::sendSettings()
|
||||
{
|
||||
if(!m_updateTimer.isActive()) {
|
||||
m_updateTimer.start(100);
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::updateHardware()
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
TestMI::MsgConfigureTestSource* message = TestMI::MsgConfigureTestSource::create(m_settings, m_forceSettings);
|
||||
m_sampleMIMO->getInputMessageQueue()->push(message);
|
||||
m_forceSettings = false;
|
||||
m_updateTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::updateStatus()
|
||||
{
|
||||
int state = m_deviceUISet->m_deviceAPI->state();
|
||||
|
||||
if(m_lastEngineState != state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case DeviceAPI::StNotStarted:
|
||||
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
break;
|
||||
case DeviceAPI::StIdle:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
|
||||
break;
|
||||
case DeviceAPI::StRunning:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
|
||||
break;
|
||||
case DeviceAPI::StError:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
|
||||
QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceAPI->errorMessage());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_lastEngineState = state;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestMIGui::handleMessage(const Message& message)
|
||||
{
|
||||
if (TestMI::MsgConfigureTestSource::match(message))
|
||||
{
|
||||
qDebug("TestMIGui::handleMessage: MsgConfigureTestSource");
|
||||
const TestMI::MsgConfigureTestSource& cfg = (TestMI::MsgConfigureTestSource&) message;
|
||||
m_settings = cfg.getSettings();
|
||||
displaySettings();
|
||||
return true;
|
||||
}
|
||||
else if (TestMI::MsgStartStop::match(message))
|
||||
{
|
||||
qDebug("TestMIGui::handleMessage: MsgStartStop");
|
||||
TestMI::MsgStartStop& notif = (TestMI::MsgStartStop&) message;
|
||||
blockApplySettings(true);
|
||||
ui->startStop->setChecked(notif.getStartStop());
|
||||
blockApplySettings(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::handleInputMessages()
|
||||
{
|
||||
Message* message;
|
||||
|
||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||
{
|
||||
if (DSPMIMOSignalNotification::match(*message))
|
||||
{
|
||||
DSPMIMOSignalNotification* notif = (DSPMIMOSignalNotification*) message;
|
||||
int istream = notif->getIndex();
|
||||
bool sourceOrSink = notif->getSourceOrSink();
|
||||
m_deviceSampleRates[istream] = notif->getSampleRate();
|
||||
m_deviceCenterFrequencies[istream] = notif->getCenterFrequency();
|
||||
// Do not consider multiple sources at this time
|
||||
qDebug("TestMIGui::handleInputMessages: DSPMIMOSignalNotification: %s stream: %d SampleRate:%d, CenterFrequency:%llu",
|
||||
sourceOrSink ? "source" : "sink",
|
||||
istream,
|
||||
notif->getSampleRate(),
|
||||
notif->getCenterFrequency());
|
||||
updateSampleRateAndFrequency();
|
||||
|
||||
delete message;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (handleMessage(*message))
|
||||
{
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIGui::updateSampleRateAndFrequency()
|
||||
{
|
||||
m_deviceUISet->getSpectrum()->setSampleRate(m_deviceSampleRates[m_spectrumStreamIndex]);
|
||||
m_deviceUISet->getSpectrum()->setCenterFrequency(m_deviceCenterFrequencies[m_spectrumStreamIndex]);
|
||||
ui->deviceRateText->setText(tr("%1k").arg((float) m_deviceSampleRates[m_streamIndex] / 1000));
|
||||
}
|
||||
|
||||
void TestMIGui::openDeviceSettingsDialog(const QPoint& p)
|
||||
{
|
||||
BasicDeviceSettingsDialog dialog(this);
|
||||
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
|
||||
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
|
||||
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
|
||||
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
|
||||
|
||||
dialog.move(p);
|
||||
dialog.exec();
|
||||
|
||||
m_settings.m_useReverseAPI = dialog.useReverseAPI();
|
||||
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
|
||||
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
|
||||
m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
|
||||
|
||||
sendSettings();
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 _TESTMI_TESTMIGUI_H_
|
||||
#define _TESTMI_TESTMIGUI_H_
|
||||
|
||||
#include <plugin/plugininstancegui.h>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "util/messagequeue.h"
|
||||
|
||||
#include "testmisettings.h"
|
||||
#include "testmi.h"
|
||||
|
||||
class DeviceUISet;
|
||||
|
||||
namespace Ui {
|
||||
class TestMIGui;
|
||||
}
|
||||
|
||||
class TestMIGui : public QWidget, public PluginInstanceGUI {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TestMIGui(DeviceUISet *deviceUISet, QWidget* parent = 0);
|
||||
virtual ~TestMIGui();
|
||||
virtual void destroy();
|
||||
|
||||
void setName(const QString& name);
|
||||
QString getName() const;
|
||||
|
||||
void resetToDefaults();
|
||||
virtual qint64 getCenterFrequency() const;
|
||||
virtual void setCenterFrequency(qint64 centerFrequency);
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||
virtual bool handleMessage(const Message& message);
|
||||
|
||||
private:
|
||||
Ui::TestMIGui* ui;
|
||||
|
||||
DeviceUISet* m_deviceUISet;
|
||||
TestMISettings m_settings;
|
||||
int m_streamIndex; //!< Current stream index being dealt with
|
||||
int m_spectrumStreamIndex; //!< Index of the stream displayed on main spectrum
|
||||
QTimer m_updateTimer;
|
||||
QTimer m_statusTimer;
|
||||
bool m_doApplySettings;
|
||||
bool m_forceSettings;
|
||||
DeviceSampleMIMO* m_sampleMIMO;
|
||||
std::size_t m_tickCount;
|
||||
std::vector<int> m_deviceSampleRates;
|
||||
std::vector<quint64> m_deviceCenterFrequencies; //!< Center frequency in device
|
||||
int m_lastEngineState;
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
void blockApplySettings(bool block) { m_doApplySettings = !block; }
|
||||
void displaySettings();
|
||||
void sendSettings();
|
||||
void updateSampleRateAndFrequency();
|
||||
void displayAmplitude();
|
||||
void updateAmpCoarseLimit();
|
||||
void updateAmpFineLimit();
|
||||
void updateFrequencyShiftLimit();
|
||||
void updateFileRecordStatus();
|
||||
|
||||
private slots:
|
||||
void handleInputMessages();
|
||||
void on_startStop_toggled(bool checked);
|
||||
void on_streamIndex_currentIndexChanged(int index);
|
||||
void on_spectrumSource_currentIndexChanged(int index);
|
||||
void on_streamLock_toggled(bool checked);
|
||||
void on_centerFrequency_changed(quint64 value);
|
||||
void on_autoCorr_currentIndexChanged(int index);
|
||||
void on_frequencyShift_changed(qint64 value);
|
||||
void on_decimation_currentIndexChanged(int index);
|
||||
void on_fcPos_currentIndexChanged(int index);
|
||||
void on_sampleRate_changed(quint64 value);
|
||||
void on_sampleSize_currentIndexChanged(int index);
|
||||
void on_amplitudeCoarse_valueChanged(int value);
|
||||
void on_amplitudeFine_valueChanged(int value);
|
||||
void on_modulation_currentIndexChanged(int index);
|
||||
void on_modulationFrequency_valueChanged(int value);
|
||||
void on_amModulation_valueChanged(int value);
|
||||
void on_fmDeviation_valueChanged(int value);
|
||||
void on_dcBias_valueChanged(int value);
|
||||
void on_iBias_valueChanged(int value);
|
||||
void on_qBias_valueChanged(int value);
|
||||
void on_phaseImbalance_valueChanged(int value);
|
||||
void on_record_toggled(bool checked);
|
||||
void openDeviceSettingsDialog(const QPoint& p);
|
||||
void updateStatus();
|
||||
void updateHardware();
|
||||
};
|
||||
|
||||
#endif // _TESTMI_TESTMIGUI_H_
|
File diff suppressed because it is too large
Load Diff
@ -1,144 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QtPlugin>
|
||||
|
||||
#include "plugin/pluginapi.h"
|
||||
#include "util/simpleserializer.h"
|
||||
|
||||
#ifdef SERVER_MODE
|
||||
#include "testmi.h"
|
||||
#else
|
||||
#include "testmigui.h"
|
||||
#endif
|
||||
#include "testmiplugin.h"
|
||||
#include "testmiwebapiadapter.h"
|
||||
|
||||
const PluginDescriptor TestMIPlugin::m_pluginDescriptor = {
|
||||
QString("TestMI"),
|
||||
QString("Test Multiple Input"),
|
||||
QString("4.12.3"),
|
||||
QString("(c) Edouard Griffiths, F4EXB"),
|
||||
QString("https://github.com/f4exb/sdrangel"),
|
||||
true,
|
||||
QString("https://github.com/f4exb/sdrangel")
|
||||
};
|
||||
|
||||
const QString TestMIPlugin::m_hardwareID = "TestMI";
|
||||
const QString TestMIPlugin::m_deviceTypeID = TESTMI_DEVICE_TYPE_ID;
|
||||
|
||||
TestMIPlugin::TestMIPlugin(QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
const PluginDescriptor& TestMIPlugin::getPluginDescriptor() const
|
||||
{
|
||||
return m_pluginDescriptor;
|
||||
}
|
||||
|
||||
void TestMIPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||
{
|
||||
pluginAPI->registerSampleMIMO(m_deviceTypeID, this);
|
||||
}
|
||||
|
||||
void TestMIPlugin::enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices)
|
||||
{
|
||||
if (listedHwIds.contains(m_hardwareID)) { // check if it was done
|
||||
return;
|
||||
}
|
||||
|
||||
originDevices.append(OriginDevice(
|
||||
"TestMI", // Displayable name
|
||||
m_hardwareID, // Hardware ID
|
||||
QString(), // Serial
|
||||
0, // Sequence
|
||||
2, // Number of Rx streams
|
||||
0 // Number of Tx streams
|
||||
));
|
||||
|
||||
listedHwIds.append(m_hardwareID);
|
||||
}
|
||||
|
||||
PluginInterface::SamplingDevices TestMIPlugin::enumSampleMIMO(const OriginDevices& originDevices)
|
||||
{
|
||||
SamplingDevices result;
|
||||
|
||||
for (OriginDevices::const_iterator it = originDevices.begin(); it != originDevices.end(); ++it)
|
||||
{
|
||||
if (it->hardwareId == m_hardwareID)
|
||||
{
|
||||
result.append(SamplingDevice(
|
||||
"TestMI",
|
||||
m_hardwareID,
|
||||
m_deviceTypeID,
|
||||
it->serial,
|
||||
it->sequence,
|
||||
PluginInterface::SamplingDevice::BuiltInDevice,
|
||||
PluginInterface::SamplingDevice::StreamMIMO,
|
||||
1, // MIMO is always considered as a single device
|
||||
0));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef SERVER_MODE
|
||||
PluginInstanceGUI* TestMIPlugin::createSampleMIMOPluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet)
|
||||
{
|
||||
(void) sourceId;
|
||||
(void) widget;
|
||||
(void) deviceUISet;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
PluginInstanceGUI* TestMIPlugin::createSampleMIMOPluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet)
|
||||
{
|
||||
if (sourceId == m_deviceTypeID) {
|
||||
TestMIGui* gui = new TestMIGui(deviceUISet);
|
||||
*widget = gui;
|
||||
return gui;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DeviceSampleMIMO *TestMIPlugin::createSampleMIMOPluginInstance(const QString& mimoId, DeviceAPI *deviceAPI)
|
||||
{
|
||||
if (mimoId == m_deviceTypeID)
|
||||
{
|
||||
TestMI* input = new TestMI(deviceAPI);
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceWebAPIAdapter *TestMIPlugin::createDeviceWebAPIAdapter() const
|
||||
{
|
||||
return new TestMIWebAPIAdapter();
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 _TESTMI_TESTMIPLUGIN_H
|
||||
#define _TESTMI_TESTMIPLUGIN_H
|
||||
|
||||
#include <QObject>
|
||||
#include "plugin/plugininterface.h"
|
||||
|
||||
class PluginAPI;
|
||||
|
||||
#define TESTMI_DEVICE_TYPE_ID "sdrangel.samplemimo.testmi"
|
||||
|
||||
class TestMIPlugin : public QObject, public PluginInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(PluginInterface)
|
||||
Q_PLUGIN_METADATA(IID TESTMI_DEVICE_TYPE_ID)
|
||||
|
||||
public:
|
||||
explicit TestMIPlugin(QObject* parent = NULL);
|
||||
|
||||
const PluginDescriptor& getPluginDescriptor() const;
|
||||
void initPlugin(PluginAPI* pluginAPI);
|
||||
|
||||
virtual void enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices);
|
||||
virtual SamplingDevices enumSampleMIMO(const OriginDevices& originDevices);
|
||||
virtual PluginInstanceGUI* createSampleMIMOPluginInstanceGUI(
|
||||
const QString& sourceId,
|
||||
QWidget **widget,
|
||||
DeviceUISet *deviceUISet);
|
||||
virtual DeviceSampleMIMO* createSampleMIMOPluginInstance(const QString& sourceId, DeviceAPI *deviceAPI);
|
||||
virtual DeviceWebAPIAdapter* createDeviceWebAPIAdapter() const;
|
||||
|
||||
static const QString m_hardwareID;
|
||||
static const QString m_deviceTypeID;
|
||||
|
||||
private:
|
||||
static const PluginDescriptor m_pluginDescriptor;
|
||||
};
|
||||
|
||||
#endif // _TESTMI_TESTMIPLUGIN_H
|
@ -1,181 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 <QtGlobal>
|
||||
#include "util/simpleserializer.h"
|
||||
#include "testmisettings.h"
|
||||
|
||||
TestMIStreamSettings::TestMIStreamSettings()
|
||||
{
|
||||
resetToDefaults();
|
||||
}
|
||||
|
||||
void TestMIStreamSettings::resetToDefaults()
|
||||
{
|
||||
m_centerFrequency = 435000*1000;
|
||||
m_frequencyShift = 0;
|
||||
m_sampleRate = 768*1000;
|
||||
m_log2Decim = 4;
|
||||
m_fcPos = FC_POS_CENTER;
|
||||
m_sampleSizeIndex = 0;
|
||||
m_amplitudeBits = 127;
|
||||
m_autoCorrOptions = AutoCorrNone;
|
||||
m_modulation = ModulationNone;
|
||||
m_modulationTone = 44; // 440 Hz
|
||||
m_amModulation = 50; // 50%
|
||||
m_fmDeviation = 50; // 5 kHz
|
||||
m_dcFactor = 0.0f;
|
||||
m_iFactor = 0.0f;
|
||||
m_qFactor = 0.0f;
|
||||
m_phaseImbalance = 0.0f;
|
||||
}
|
||||
|
||||
TestMISettings::TestMISettings()
|
||||
{
|
||||
m_fileRecordName = "";
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "127.0.0.1";
|
||||
m_reverseAPIPort = 8888;
|
||||
m_reverseAPIDeviceIndex = 0;
|
||||
m_streams.push_back(TestMIStreamSettings());
|
||||
m_streams.push_back(TestMIStreamSettings());
|
||||
}
|
||||
|
||||
TestMISettings::TestMISettings(const TestMISettings& other) :
|
||||
m_streams(other.m_streams)
|
||||
{
|
||||
m_fileRecordName = other.m_fileRecordName;
|
||||
m_useReverseAPI = other.m_useReverseAPI;
|
||||
m_reverseAPIAddress = other.m_reverseAPIAddress;
|
||||
m_reverseAPIPort = other.m_reverseAPIPort;
|
||||
m_reverseAPIDeviceIndex = other.m_reverseAPIDeviceIndex;
|
||||
}
|
||||
|
||||
void TestMISettings::resetToDefaults()
|
||||
{
|
||||
for (unsigned int i = 0; i < m_streams.size(); i++) {
|
||||
m_streams[i].resetToDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray TestMISettings::serialize() const
|
||||
{
|
||||
SimpleSerializer s(1);
|
||||
|
||||
s.writeBool(1, m_useReverseAPI);
|
||||
s.writeString(2, m_reverseAPIAddress);
|
||||
s.writeU32(3, m_reverseAPIPort);
|
||||
s.writeU32(4, m_reverseAPIDeviceIndex);
|
||||
|
||||
for (unsigned int i = 0; i < m_streams.size(); i++)
|
||||
{
|
||||
s.writeS32(10 + 30*i, m_streams[i].m_frequencyShift);
|
||||
s.writeU32(11 + 30*i, m_streams[i].m_sampleRate);
|
||||
s.writeU32(12 + 30*i, m_streams[i].m_log2Decim);
|
||||
s.writeS32(13 + 30*i, (int) m_streams[i].m_fcPos);
|
||||
s.writeU32(14 + 30*i, m_streams[i].m_sampleSizeIndex);
|
||||
s.writeS32(15 + 30*i, m_streams[i].m_amplitudeBits);
|
||||
s.writeS32(16 + 30*i, (int) m_streams[i].m_autoCorrOptions);
|
||||
s.writeFloat(17 + 30*i, m_streams[i].m_dcFactor);
|
||||
s.writeFloat(18 + 30*i, m_streams[i].m_iFactor);
|
||||
s.writeFloat(19 + 30*i, m_streams[i].m_qFactor);
|
||||
s.writeFloat(20 + 30*i, m_streams[i].m_phaseImbalance);
|
||||
s.writeS32(21 + 30*i, (int) m_streams[i].m_modulation);
|
||||
s.writeS32(22 + 30*i, m_streams[i].m_modulationTone);
|
||||
s.writeS32(23 + 30*i, m_streams[i].m_amModulation);
|
||||
s.writeS32(24 + 30*i, m_streams[i].m_fmDeviation);
|
||||
}
|
||||
|
||||
return s.final();
|
||||
}
|
||||
|
||||
bool TestMISettings::deserialize(const QByteArray& data)
|
||||
{
|
||||
SimpleDeserializer d(data);
|
||||
|
||||
if (!d.isValid())
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d.getVersion() == 1)
|
||||
{
|
||||
int intval;
|
||||
uint32_t utmp;
|
||||
|
||||
d.readBool(1, &m_useReverseAPI, false);
|
||||
d.readString(2, &m_reverseAPIAddress, "127.0.0.1");
|
||||
d.readU32(3, &utmp, 0);
|
||||
|
||||
if ((utmp > 1023) && (utmp < 65535)) {
|
||||
m_reverseAPIPort = utmp;
|
||||
} else {
|
||||
m_reverseAPIPort = 8888;
|
||||
}
|
||||
|
||||
d.readU32(4, &utmp, 0);
|
||||
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
|
||||
|
||||
for (unsigned int i = 0; i < m_streams.size(); i++)
|
||||
{
|
||||
d.readS32(10 + 30*i, &m_streams[i].m_frequencyShift, 0);
|
||||
d.readU32(11 + 30*i, &m_streams[i].m_sampleRate, 768*1000);
|
||||
d.readU32(12 + 30*i, &m_streams[i].m_log2Decim, 4);
|
||||
d.readS32(13 + 30*i, &intval, 0);
|
||||
m_streams[i].m_fcPos = (TestMIStreamSettings::fcPos_t) intval;
|
||||
d.readU32(14 + 30*i, &m_streams[i].m_sampleSizeIndex, 0);
|
||||
d.readS32(15 + 30*i, &m_streams[i].m_amplitudeBits, 128);
|
||||
d.readS32(16 + 30*i, &intval, 0);
|
||||
|
||||
if (intval < 0 || intval > (int) TestMIStreamSettings::AutoCorrLast) {
|
||||
m_streams[i].m_autoCorrOptions = TestMIStreamSettings::AutoCorrNone;
|
||||
} else {
|
||||
m_streams[i].m_autoCorrOptions = (TestMIStreamSettings::AutoCorrOptions) intval;
|
||||
}
|
||||
|
||||
d.readFloat(17 + 30*i, &m_streams[i].m_dcFactor, 0.0f);
|
||||
d.readFloat(18 + 30*i, &m_streams[i].m_iFactor, 0.0f);
|
||||
d.readFloat(19 + 30*i, &m_streams[i].m_qFactor, 0.0f);
|
||||
d.readFloat(20 + 30*i, &m_streams[i].m_phaseImbalance, 0.0f);
|
||||
d.readS32(21 + 30*i, &intval, 0);
|
||||
|
||||
if (intval < 0 || intval > (int) TestMIStreamSettings::ModulationLast) {
|
||||
m_streams[i].m_modulation = TestMIStreamSettings::ModulationNone;
|
||||
} else {
|
||||
m_streams[i].m_modulation = (TestMIStreamSettings::Modulation) intval;
|
||||
}
|
||||
|
||||
d.readS32(22 + 30*i, &m_streams[i].m_modulationTone, 44);
|
||||
d.readS32(23 + 30*i, &m_streams[i].m_amModulation, 50);
|
||||
d.readS32(24 + 30*i, &m_streams[i].m_fmDeviation, 50);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 _TESTMI_TESTMISETTINGS_H_
|
||||
#define _TESTMI_TESTMISETTINGS_H_
|
||||
|
||||
#include <QString>
|
||||
|
||||
struct TestMIStreamSettings {
|
||||
typedef enum {
|
||||
FC_POS_INFRA = 0,
|
||||
FC_POS_SUPRA,
|
||||
FC_POS_CENTER
|
||||
} fcPos_t;
|
||||
|
||||
typedef enum {
|
||||
AutoCorrNone,
|
||||
AutoCorrDC,
|
||||
AutoCorrDCAndIQ,
|
||||
AutoCorrLast,
|
||||
} AutoCorrOptions;
|
||||
|
||||
typedef enum {
|
||||
ModulationNone,
|
||||
ModulationAM,
|
||||
ModulationFM,
|
||||
ModulationPattern0,
|
||||
ModulationPattern1,
|
||||
ModulationPattern2,
|
||||
ModulationLast
|
||||
} Modulation;
|
||||
|
||||
quint64 m_centerFrequency;
|
||||
qint32 m_frequencyShift;
|
||||
quint32 m_sampleRate;
|
||||
quint32 m_log2Decim;
|
||||
fcPos_t m_fcPos;
|
||||
quint32 m_sampleSizeIndex;
|
||||
qint32 m_amplitudeBits;
|
||||
AutoCorrOptions m_autoCorrOptions;
|
||||
Modulation m_modulation;
|
||||
int m_modulationTone; //!< 10'Hz
|
||||
int m_amModulation; //!< percent
|
||||
int m_fmDeviation; //!< 100'Hz
|
||||
float m_dcFactor; //!< -1.0 < x < 1.0
|
||||
float m_iFactor; //!< -1.0 < x < 1.0
|
||||
float m_qFactor; //!< -1.0 < x < 1.0
|
||||
float m_phaseImbalance; //!< -1.0 < x < 1.0
|
||||
|
||||
TestMIStreamSettings();
|
||||
void resetToDefaults();
|
||||
};
|
||||
|
||||
struct TestMISettings {
|
||||
QString m_fileRecordName;
|
||||
bool m_useReverseAPI;
|
||||
QString m_reverseAPIAddress;
|
||||
uint16_t m_reverseAPIPort;
|
||||
uint16_t m_reverseAPIDeviceIndex;
|
||||
std::vector<TestMIStreamSettings> m_streams;
|
||||
|
||||
TestMISettings();
|
||||
TestMISettings(const TestMISettings& other);
|
||||
void resetToDefaults();
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
};
|
||||
|
||||
|
||||
#endif /* _TESTMI_TESTMISETTINGS_H_ */
|
@ -1,451 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "dsp/samplemififo.h"
|
||||
|
||||
#include "testmithread.h"
|
||||
|
||||
#define TESTMI_BLOCKSIZE 16384
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(TestMIThread::MsgStartStop, Message)
|
||||
|
||||
TestMIThread::TestMIThread(SampleMIFifo* sampleFifo, int streamIndex, QObject* parent) :
|
||||
QThread(parent),
|
||||
m_running(false),
|
||||
m_buf(0),
|
||||
m_bufsize(0),
|
||||
m_chunksize(0),
|
||||
m_convertBuffer(TESTMI_BLOCKSIZE),
|
||||
m_sampleFifo(sampleFifo),
|
||||
m_streamIndex(streamIndex),
|
||||
m_frequencyShift(0),
|
||||
m_toneFrequency(440),
|
||||
m_modulation(TestMIStreamSettings::ModulationNone),
|
||||
m_amModulation(0.5f),
|
||||
m_fmDeviationUnit(0.0f),
|
||||
m_fmPhasor(0.0f),
|
||||
m_pulseWidth(150),
|
||||
m_pulseSampleCount(0),
|
||||
m_pulsePatternCount(0),
|
||||
m_pulsePatternCycle(8),
|
||||
m_pulsePatternPlaces(3),
|
||||
m_samplerate(48000),
|
||||
m_log2Decim(4),
|
||||
m_fcPos(0),
|
||||
m_bitSizeIndex(0),
|
||||
m_bitShift(8),
|
||||
m_amplitudeBits(127),
|
||||
m_dcBias(0.0f),
|
||||
m_iBias(0.0f),
|
||||
m_qBias(0.0f),
|
||||
m_phaseImbalance(0.0f),
|
||||
m_amplitudeBitsDC(0),
|
||||
m_amplitudeBitsI(127),
|
||||
m_amplitudeBitsQ(127),
|
||||
m_frequency(435*1000),
|
||||
m_fcPosShift(0),
|
||||
m_throttlems(TESTMI_THROTTLE_MS),
|
||||
m_throttleToggle(false),
|
||||
m_mutex(QMutex::Recursive)
|
||||
{
|
||||
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
TestMIThread::~TestMIThread()
|
||||
{
|
||||
}
|
||||
|
||||
void TestMIThread::startWork()
|
||||
{
|
||||
m_timer.setTimerType(Qt::PreciseTimer);
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
|
||||
m_timer.start(50);
|
||||
m_startWaitMutex.lock();
|
||||
m_elapsedTimer.start();
|
||||
start();
|
||||
while(!m_running)
|
||||
m_startWaiter.wait(&m_startWaitMutex, 100);
|
||||
m_startWaitMutex.unlock();
|
||||
}
|
||||
|
||||
void TestMIThread::stopWork()
|
||||
{
|
||||
m_running = false;
|
||||
wait();
|
||||
m_timer.stop();
|
||||
disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
|
||||
}
|
||||
|
||||
void TestMIThread::setSamplerate(int samplerate)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
m_samplerate = samplerate;
|
||||
m_chunksize = 4 * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000);
|
||||
m_throttleToggle = !m_throttleToggle;
|
||||
m_nco.setFreq(m_frequencyShift, m_samplerate);
|
||||
m_toneNco.setFreq(m_toneFrequency, m_samplerate);
|
||||
}
|
||||
|
||||
void TestMIThread::setLog2Decimation(unsigned int log2_decim)
|
||||
{
|
||||
m_log2Decim = log2_decim;
|
||||
}
|
||||
|
||||
void TestMIThread::setFcPos(int fcPos)
|
||||
{
|
||||
m_fcPos = fcPos;
|
||||
}
|
||||
|
||||
void TestMIThread::setBitSize(quint32 bitSizeIndex)
|
||||
{
|
||||
switch (bitSizeIndex)
|
||||
{
|
||||
case 0:
|
||||
m_bitShift = 7;
|
||||
m_bitSizeIndex = 0;
|
||||
break;
|
||||
case 1:
|
||||
m_bitShift = 11;
|
||||
m_bitSizeIndex = 1;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
m_bitShift = 15;
|
||||
m_bitSizeIndex = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIThread::setAmplitudeBits(int32_t amplitudeBits)
|
||||
{
|
||||
m_amplitudeBits = amplitudeBits;
|
||||
m_amplitudeBitsDC = m_dcBias * amplitudeBits;
|
||||
m_amplitudeBitsI = (1.0f + m_iBias) * amplitudeBits;
|
||||
m_amplitudeBitsQ = (1.0f + m_qBias) * amplitudeBits;
|
||||
}
|
||||
|
||||
void TestMIThread::setDCFactor(float dcFactor)
|
||||
{
|
||||
m_dcBias = dcFactor;
|
||||
m_amplitudeBitsDC = m_dcBias * m_amplitudeBits;
|
||||
}
|
||||
|
||||
void TestMIThread::setIFactor(float iFactor)
|
||||
{
|
||||
m_iBias = iFactor;
|
||||
m_amplitudeBitsI = (1.0f + m_iBias) * m_amplitudeBits;
|
||||
}
|
||||
|
||||
void TestMIThread::setQFactor(float iFactor)
|
||||
{
|
||||
m_qBias = iFactor;
|
||||
m_amplitudeBitsQ = (1.0f + m_qBias) * m_amplitudeBits;
|
||||
}
|
||||
|
||||
void TestMIThread::setPhaseImbalance(float phaseImbalance)
|
||||
{
|
||||
m_phaseImbalance = phaseImbalance;
|
||||
}
|
||||
|
||||
void TestMIThread::setFrequencyShift(int shift)
|
||||
{
|
||||
m_nco.setFreq(shift, m_samplerate);
|
||||
}
|
||||
|
||||
void TestMIThread::setToneFrequency(int toneFrequency)
|
||||
{
|
||||
m_toneNco.setFreq(toneFrequency, m_samplerate);
|
||||
}
|
||||
|
||||
void TestMIThread::setModulation(TestMIStreamSettings::Modulation modulation)
|
||||
{
|
||||
m_modulation = modulation;
|
||||
}
|
||||
|
||||
void TestMIThread::setAMModulation(float amModulation)
|
||||
{
|
||||
m_amModulation = amModulation < 0.0f ? 0.0f : amModulation > 1.0f ? 1.0f : amModulation;
|
||||
}
|
||||
|
||||
void TestMIThread::setFMDeviation(float deviation)
|
||||
{
|
||||
float fmDeviationUnit = deviation / (float) m_samplerate;
|
||||
m_fmDeviationUnit = fmDeviationUnit < 0.0f ? 0.0f : fmDeviationUnit > 0.5f ? 0.5f : fmDeviationUnit;
|
||||
qDebug("TestMIThread::setFMDeviation: m_fmDeviationUnit: %f", m_fmDeviationUnit);
|
||||
}
|
||||
|
||||
void TestMIThread::startStop(bool start)
|
||||
{
|
||||
MsgStartStop *msg = MsgStartStop::create(start);
|
||||
m_inputMessageQueue.push(msg);
|
||||
}
|
||||
|
||||
void TestMIThread::run()
|
||||
{
|
||||
m_running = true;
|
||||
m_startWaiter.wakeAll();
|
||||
|
||||
while (m_running) // actual work is in the tick() function
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
void TestMIThread::setBuffers(quint32 chunksize)
|
||||
{
|
||||
if (chunksize > m_bufsize)
|
||||
{
|
||||
m_bufsize = chunksize;
|
||||
|
||||
if (m_buf == 0)
|
||||
{
|
||||
qDebug() << "TestMIThread::setBuffer: Allocate buffer: "
|
||||
<< " size: " << m_bufsize << " bytes"
|
||||
<< " #samples: " << (m_bufsize/4);
|
||||
m_buf = (qint16*) malloc(m_bufsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "TestMIThread::setBuffer: Re-allocate buffer: "
|
||||
<< " size: " << m_bufsize << " bytes"
|
||||
<< " #samples: " << (m_bufsize/4);
|
||||
free(m_buf);
|
||||
m_buf = (qint16*) malloc(m_bufsize);
|
||||
}
|
||||
|
||||
m_convertBuffer.resize(chunksize/4);
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIThread::generate(quint32 chunksize)
|
||||
{
|
||||
int n = chunksize / 2;
|
||||
setBuffers(chunksize);
|
||||
|
||||
for (int i = 0; i < n-1;)
|
||||
{
|
||||
switch (m_modulation)
|
||||
{
|
||||
case TestMIStreamSettings::ModulationAM:
|
||||
{
|
||||
Complex c = m_nco.nextIQ();
|
||||
Real t, re, im;
|
||||
pullAF(t);
|
||||
t = (t*m_amModulation + 1.0f)*0.5f;
|
||||
re = c.real()*t;
|
||||
im = c.imag()*t + m_phaseImbalance*re;
|
||||
m_buf[i++] = (int16_t) (re * (float) m_amplitudeBitsI) + m_amplitudeBitsDC;
|
||||
m_buf[i++] = (int16_t) (im * (float) m_amplitudeBitsQ);
|
||||
}
|
||||
break;
|
||||
case TestMIStreamSettings::ModulationFM:
|
||||
{
|
||||
Complex c = m_nco.nextIQ();
|
||||
Real t, re, im;
|
||||
pullAF(t);
|
||||
m_fmPhasor += m_fmDeviationUnit * t;
|
||||
m_fmPhasor = m_fmPhasor < -1.0f ? -m_fmPhasor - 1.0f : m_fmPhasor > 1.0f ? m_fmPhasor - 1.0f : m_fmPhasor;
|
||||
re = c.real()*cos(m_fmPhasor*M_PI) - c.imag()*sin(m_fmPhasor*M_PI);
|
||||
im = (c.real()*sin(m_fmPhasor*M_PI) + c.imag()*cos(m_fmPhasor*M_PI)) + m_phaseImbalance*re;
|
||||
m_buf[i++] = (int16_t) (re * (float) m_amplitudeBitsI) + m_amplitudeBitsDC;
|
||||
m_buf[i++] = (int16_t) (im * (float) m_amplitudeBitsQ);
|
||||
}
|
||||
break;
|
||||
case TestMIStreamSettings::ModulationPattern0: // binary pattern
|
||||
{
|
||||
if (m_pulseSampleCount < m_pulseWidth) // sync pattern: 0
|
||||
{
|
||||
m_buf[i++] = m_amplitudeBitsDC;
|
||||
m_buf[i++] = 0;
|
||||
}
|
||||
else if (m_pulseSampleCount < 2*m_pulseWidth) // sync pattern: 1
|
||||
{
|
||||
m_buf[i++] = (int16_t) (m_amplitudeBitsI + m_amplitudeBitsDC);
|
||||
m_buf[i++] = (int16_t) (m_phaseImbalance * (float) m_amplitudeBitsQ);
|
||||
}
|
||||
else if (m_pulseSampleCount < 3*m_pulseWidth) // sync pattern: 0
|
||||
{
|
||||
m_buf[i++] = m_amplitudeBitsDC;
|
||||
m_buf[i++] = 0;
|
||||
}
|
||||
else if (m_pulseSampleCount < (3+m_pulsePatternPlaces)*m_pulseWidth) // binary pattern
|
||||
{
|
||||
uint32_t patPulseSampleCount = m_pulseSampleCount - 3*m_pulseWidth;
|
||||
uint32_t patPulseIndex = patPulseSampleCount / m_pulseWidth;
|
||||
float patFigure = (m_pulsePatternCount & (1<<patPulseIndex)) != 0 ? 0.3 : 0.0; // make binary pattern ~-10dB vs sync pattern
|
||||
m_buf[i++] = (int16_t) (patFigure * (float) m_amplitudeBitsI) + m_amplitudeBitsDC;
|
||||
m_buf[i++] = (int16_t) (patFigure * (float) m_phaseImbalance * m_amplitudeBitsQ);
|
||||
}
|
||||
|
||||
if (m_pulseSampleCount < (4+m_pulsePatternPlaces)*m_pulseWidth - 1)
|
||||
{
|
||||
m_pulseSampleCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pulsePatternCount < m_pulsePatternCycle - 1) {
|
||||
m_pulsePatternCount++;
|
||||
} else {
|
||||
m_pulsePatternCount = 0;
|
||||
}
|
||||
|
||||
m_pulseSampleCount = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TestMIStreamSettings::ModulationPattern1: // sawtooth pattern
|
||||
{
|
||||
Real re, im;
|
||||
re = (float) (m_pulseWidth - m_pulseSampleCount) / (float) m_pulseWidth;
|
||||
im = m_phaseImbalance*re;
|
||||
m_buf[i++] = (int16_t) (re * (float) m_amplitudeBitsI) + m_amplitudeBitsDC;
|
||||
m_buf[i++] = (int16_t) (im * (float) m_amplitudeBitsQ);
|
||||
|
||||
if (m_pulseSampleCount < m_pulseWidth - 1) {
|
||||
m_pulseSampleCount++;
|
||||
} else {
|
||||
m_pulseSampleCount = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TestMIStreamSettings::ModulationPattern2: // 50% duty cycle square pattern
|
||||
{
|
||||
if (m_pulseSampleCount < m_pulseWidth) // 1
|
||||
{
|
||||
m_buf[i++] = (int16_t) (m_amplitudeBitsI + m_amplitudeBitsDC);
|
||||
m_buf[i++] = (int16_t) (m_phaseImbalance * (float) m_amplitudeBitsQ);
|
||||
} else { // 0
|
||||
m_buf[i++] = m_amplitudeBitsDC;
|
||||
m_buf[i++] = 0;
|
||||
}
|
||||
|
||||
if (m_pulseSampleCount < 2*m_pulseWidth - 1) {
|
||||
m_pulseSampleCount++;
|
||||
} else {
|
||||
m_pulseSampleCount = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TestMIStreamSettings::ModulationNone:
|
||||
default:
|
||||
{
|
||||
Complex c = m_nco.nextIQ(m_phaseImbalance);
|
||||
m_buf[i++] = (int16_t) (c.real() * (float) m_amplitudeBitsI) + m_amplitudeBitsDC;
|
||||
m_buf[i++] = (int16_t) (c.imag() * (float) m_amplitudeBitsQ);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
callback(m_buf, n);
|
||||
}
|
||||
|
||||
void TestMIThread::pullAF(Real& afSample)
|
||||
{
|
||||
afSample = m_toneNco.next();
|
||||
}
|
||||
|
||||
// call appropriate conversion (decimation) routine depending on the number of sample bits
|
||||
void TestMIThread::callback(const qint16* buf, qint32 len)
|
||||
{
|
||||
SampleVector::iterator it = m_convertBuffer.begin();
|
||||
|
||||
switch (m_bitSizeIndex)
|
||||
{
|
||||
case 0: // 8 bit samples
|
||||
convert_8(&it, buf, len);
|
||||
break;
|
||||
case 1: // 12 bit samples
|
||||
convert_12(&it, buf, len);
|
||||
break;
|
||||
case 2: // 16 bit samples
|
||||
default:
|
||||
convert_16(&it, buf, len);
|
||||
break;
|
||||
}
|
||||
|
||||
m_sampleFifo->writeAsync(m_convertBuffer.begin(), it - m_convertBuffer.begin(), m_streamIndex);
|
||||
}
|
||||
|
||||
void TestMIThread::tick()
|
||||
{
|
||||
if (m_running)
|
||||
{
|
||||
qint64 throttlems = m_elapsedTimer.restart();
|
||||
|
||||
if ((throttlems > 45) && (throttlems < 55) && (throttlems != m_throttlems))
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
m_throttlems = throttlems;
|
||||
m_chunksize = 4 * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000);
|
||||
m_throttleToggle = !m_throttleToggle;
|
||||
}
|
||||
|
||||
generate(m_chunksize);
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIThread::handleInputMessages()
|
||||
{
|
||||
Message* message;
|
||||
|
||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||
{
|
||||
if (MsgStartStop::match(*message))
|
||||
{
|
||||
MsgStartStop* notif = (MsgStartStop*) message;
|
||||
qDebug("TestMIThread::handleInputMessages: MsgStartStop: %s", notif->getStartStop() ? "start" : "stop");
|
||||
|
||||
if (notif->getStartStop()) {
|
||||
startWork();
|
||||
} else {
|
||||
stopWork();
|
||||
}
|
||||
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestMIThread::setPattern0()
|
||||
{
|
||||
m_pulseWidth = 150;
|
||||
m_pulseSampleCount = 0;
|
||||
m_pulsePatternCount = 0;
|
||||
m_pulsePatternCycle = 8;
|
||||
m_pulsePatternPlaces = 3;
|
||||
}
|
||||
|
||||
void TestMIThread::setPattern1()
|
||||
{
|
||||
m_pulseWidth = 1000;
|
||||
m_pulseSampleCount = 0;
|
||||
}
|
||||
|
||||
void TestMIThread::setPattern2()
|
||||
{
|
||||
m_pulseWidth = 1000;
|
||||
m_pulseSampleCount = 0;
|
||||
}
|
@ -1,387 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 _TESTMI_TESTMITHREAD_H_
|
||||
#define _TESTMI_TESTMITHREAD_H_
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QDebug>
|
||||
|
||||
#include "dsp/decimators.h"
|
||||
#include "dsp/ncof.h"
|
||||
#include "util/message.h"
|
||||
#include "util/messagequeue.h"
|
||||
|
||||
#include "testmisettings.h"
|
||||
|
||||
#define TESTMI_THROTTLE_MS 50
|
||||
|
||||
class SampleMIFifo;
|
||||
|
||||
class TestMIThread : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
class MsgStartStop : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgStartStop* create(bool startStop) {
|
||||
return new MsgStartStop(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgStartStop(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
TestMIThread(SampleMIFifo* sampleFifo, int streamIndex, QObject* parent = nullptr);
|
||||
~TestMIThread();
|
||||
|
||||
void startStop(bool start);
|
||||
void setSamplerate(int samplerate);
|
||||
void setLog2Decimation(unsigned int log2_decim);
|
||||
void setFcPos(int fcPos);
|
||||
void setBitSize(uint32_t bitSizeIndex);
|
||||
void setAmplitudeBits(int32_t amplitudeBits);
|
||||
void setDCFactor(float iFactor);
|
||||
void setIFactor(float iFactor);
|
||||
void setQFactor(float qFactor);
|
||||
void setPhaseImbalance(float phaseImbalance);
|
||||
void setFrequencyShift(int shift);
|
||||
void setToneFrequency(int toneFrequency);
|
||||
void setModulation(TestMIStreamSettings::Modulation modulation);
|
||||
void setAMModulation(float amModulation);
|
||||
void setFMDeviation(float deviation);
|
||||
void setPattern0();
|
||||
void setPattern1();
|
||||
void setPattern2();
|
||||
|
||||
private:
|
||||
QMutex m_startWaitMutex;
|
||||
QWaitCondition m_startWaiter;
|
||||
volatile bool m_running;
|
||||
|
||||
qint16 *m_buf;
|
||||
quint32 m_bufsize;
|
||||
quint32 m_chunksize;
|
||||
SampleVector m_convertBuffer;
|
||||
SampleMIFifo* m_sampleFifo;
|
||||
int m_streamIndex;
|
||||
NCOF m_nco;
|
||||
NCOF m_toneNco;
|
||||
int m_frequencyShift;
|
||||
int m_toneFrequency;
|
||||
TestMIStreamSettings::Modulation m_modulation;
|
||||
float m_amModulation;
|
||||
float m_fmDeviationUnit;
|
||||
float m_fmPhasor;
|
||||
uint32_t m_pulseWidth; //!< pulse width in number of samples
|
||||
uint32_t m_pulseSampleCount;
|
||||
uint32_t m_pulsePatternCount;
|
||||
uint32_t m_pulsePatternCycle;
|
||||
uint32_t m_pulsePatternPlaces;
|
||||
|
||||
int m_samplerate;
|
||||
unsigned int m_log2Decim;
|
||||
int m_fcPos;
|
||||
uint32_t m_bitSizeIndex;
|
||||
uint32_t m_bitShift;
|
||||
int32_t m_amplitudeBits;
|
||||
float m_dcBias;
|
||||
float m_iBias;
|
||||
float m_qBias;
|
||||
float m_phaseImbalance;
|
||||
int32_t m_amplitudeBitsDC;
|
||||
int32_t m_amplitudeBitsI;
|
||||
int32_t m_amplitudeBitsQ;
|
||||
|
||||
uint64_t m_frequency;
|
||||
int m_fcPosShift;
|
||||
|
||||
int m_throttlems;
|
||||
QTimer m_timer;
|
||||
QElapsedTimer m_elapsedTimer;
|
||||
bool m_throttleToggle;
|
||||
QMutex m_mutex;
|
||||
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 8> m_decimators_8;
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12> m_decimators_12;
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators_16;
|
||||
|
||||
void startWork();
|
||||
void stopWork();
|
||||
void run();
|
||||
void callback(const qint16* buf, qint32 len);
|
||||
void setBuffers(quint32 chunksize);
|
||||
void generate(quint32 chunksize);
|
||||
void pullAF(Real& afSample);
|
||||
|
||||
// Decimate according to specified log2 (ex: log2=4 => decim=16)
|
||||
inline void convert_8(SampleVector::iterator* it, const qint16* buf, qint32 len)
|
||||
{
|
||||
if (m_log2Decim == 0) {
|
||||
m_decimators_8.decimate1(it, buf, len);
|
||||
} else {
|
||||
if (m_fcPos == 0) { // Infradyne
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_8.decimate2_inf(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_8.decimate4_inf(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_8.decimate8_inf(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_8.decimate16_inf(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_8.decimate32_inf(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_8.decimate64_inf(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (m_fcPos == 1) {// Supradyne
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_8.decimate2_sup(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_8.decimate4_sup(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_8.decimate8_sup(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_8.decimate16_sup(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_8.decimate32_sup(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_8.decimate64_sup(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else { // Centered
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_8.decimate2_cen(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_8.decimate4_cen(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_8.decimate8_cen(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_8.decimate16_cen(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_8.decimate32_cen(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_8.decimate64_cen(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convert_12(SampleVector::iterator* it, const qint16* buf, qint32 len)
|
||||
{
|
||||
if (m_log2Decim == 0) {
|
||||
m_decimators_12.decimate1(it, buf, len);
|
||||
} else {
|
||||
if (m_fcPos == 0) { // Infradyne
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_12.decimate2_inf(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_12.decimate4_inf(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_12.decimate8_inf(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_12.decimate16_inf(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_12.decimate32_inf(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_12.decimate64_inf(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (m_fcPos == 1) {// Supradyne
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_12.decimate2_sup(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_12.decimate4_sup(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_12.decimate8_sup(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_12.decimate16_sup(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_12.decimate32_sup(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_12.decimate64_sup(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else { // Centered
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_12.decimate2_cen(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_12.decimate4_cen(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_12.decimate8_cen(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_12.decimate16_cen(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_12.decimate32_cen(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_12.decimate64_cen(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convert_16(SampleVector::iterator* it, const qint16* buf, qint32 len)
|
||||
{
|
||||
if (m_log2Decim == 0) {
|
||||
m_decimators_16.decimate1(it, buf, len);
|
||||
} else {
|
||||
if (m_fcPos == 0) { // Infradyne
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_16.decimate2_inf(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_16.decimate4_inf(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_16.decimate8_inf(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_16.decimate16_inf(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_16.decimate32_inf(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_16.decimate64_inf(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (m_fcPos == 1) {// Supradyne
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_16.decimate2_sup(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_16.decimate4_sup(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_16.decimate8_sup(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_16.decimate16_sup(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_16.decimate32_sup(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_16.decimate64_sup(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else { // Centered
|
||||
switch (m_log2Decim) {
|
||||
case 1:
|
||||
m_decimators_16.decimate2_cen(it, buf, len);
|
||||
break;
|
||||
case 2:
|
||||
m_decimators_16.decimate4_cen(it, buf, len);
|
||||
break;
|
||||
case 3:
|
||||
m_decimators_16.decimate8_cen(it, buf, len);
|
||||
break;
|
||||
case 4:
|
||||
m_decimators_16.decimate16_cen(it, buf, len);
|
||||
break;
|
||||
case 5:
|
||||
m_decimators_16.decimate32_cen(it, buf, len);
|
||||
break;
|
||||
case 6:
|
||||
m_decimators_16.decimate64_cen(it, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private slots:
|
||||
void tick();
|
||||
void handleInputMessages();
|
||||
};
|
||||
|
||||
#endif // _TESTSOURCE_TESTSOURCETHREAD_H_
|
@ -1,51 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||
// //
|
||||
// Implementation of static web API adapters used for preset serialization and //
|
||||
// deserialization //
|
||||
// //
|
||||
// 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 "SWGDeviceSettings.h"
|
||||
#include "testmi.h"
|
||||
#include "testmiwebapiadapter.h"
|
||||
|
||||
TestMIWebAPIAdapter::TestMIWebAPIAdapter()
|
||||
{}
|
||||
|
||||
TestMIWebAPIAdapter::~TestMIWebAPIAdapter()
|
||||
{}
|
||||
|
||||
int TestMIWebAPIAdapter::webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
response.setTestMiSettings(new SWGSDRangel::SWGTestMISettings());
|
||||
response.getTestMiSettings()->init();
|
||||
TestMI::webapiFormatDeviceSettings(response, m_settings);
|
||||
return 200;
|
||||
}
|
||||
|
||||
int TestMIWebAPIAdapter::webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
TestMI::webapiUpdateDeviceSettings(m_settings, deviceSettingsKeys, response);
|
||||
return 200;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
|
||||
// //
|
||||
// Implementation of static web API adapters used for preset serialization and //
|
||||
// deserialization //
|
||||
// //
|
||||
// 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 //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// 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 "device/devicewebapiadapter.h"
|
||||
#include "testmisettings.h"
|
||||
|
||||
class TestMIWebAPIAdapter : public DeviceWebAPIAdapter
|
||||
{
|
||||
public:
|
||||
TestMIWebAPIAdapter();
|
||||
virtual ~TestMIWebAPIAdapter();
|
||||
virtual QByteArray serialize() { return m_settings.serialize(); }
|
||||
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
|
||||
|
||||
virtual int webapiSettingsGet(
|
||||
SWGSDRangel::SWGDeviceSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& deviceSettingsKeys,
|
||||
SWGSDRangel::SWGDeviceSettings& response, // query + response
|
||||
QString& errorMessage);
|
||||
|
||||
private:
|
||||
TestMISettings m_settings;
|
||||
};
|
@ -1,48 +0,0 @@
|
||||
#--------------------------------------------------------
|
||||
#
|
||||
# Pro file for Android and Windows builds with Qt Creator
|
||||
#
|
||||
#--------------------------------------------------------
|
||||
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin
|
||||
|
||||
QT += core gui widgets multimedia opengl
|
||||
|
||||
TARGET = mimotestsourcemi
|
||||
|
||||
DEFINES += USE_SSE2=1
|
||||
QMAKE_CXXFLAGS += -msse2
|
||||
DEFINES += USE_SSE4_1=1
|
||||
QMAKE_CXXFLAGS += -msse4.1
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
macx:QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
INCLUDEPATH += ../../../exports
|
||||
INCLUDEPATH += ../../../sdrbase
|
||||
INCLUDEPATH += ../../../sdrgui
|
||||
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
|
||||
|
||||
CONFIG(Release):build_subdir = release
|
||||
CONFIG(Debug):build_subdir = debug
|
||||
|
||||
SOURCES += testsourcegui.cpp\
|
||||
testsourcemiinput.cpp\
|
||||
testsourcemiplugin.cpp\
|
||||
testsourcemisettings.cpp\
|
||||
testsourcemithread.cpp
|
||||
|
||||
HEADERS += testsourcemigui.h\
|
||||
testsourcemiinput.h\
|
||||
testsourcemiplugin.h\
|
||||
testsourcemisettings.h\
|
||||
testsourcemithread.h
|
||||
|
||||
FORMS += testsourcemigui.ui
|
||||
|
||||
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
|
||||
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
|
||||
LIBS += -L../../../swagger/$${build_subdir} -lswagger
|
||||
|
||||
RESOURCES = ../../../sdrgui/resources/res.qrc
|
@ -388,18 +388,6 @@ int DeviceEnumerator::getFileSinkDeviceIndex() const
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DeviceEnumerator::getTestMIMODeviceIndex() const
|
||||
{
|
||||
for (DevicesEnumeration::const_iterator it = m_mimoEnumeration.begin(); it != m_mimoEnumeration.end(); ++it)
|
||||
{
|
||||
if (it->m_samplingDevice.id == PluginManager::getTestMIMODeviceId()) {
|
||||
return it->m_index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DeviceEnumerator::getRxSamplingDeviceIndex(const QString& deviceId, int sequence)
|
||||
{
|
||||
for (DevicesEnumeration::iterator it = m_rxEnumeration.begin(); it != m_rxEnumeration.end(); ++it)
|
||||
|
@ -58,7 +58,6 @@ public:
|
||||
PluginInterface *getMIMOPluginInterface(int deviceIndex) { return m_mimoEnumeration[deviceIndex].m_pluginInterface; }
|
||||
int getFileInputDeviceIndex() const; //!< Get Rx default device
|
||||
int getFileSinkDeviceIndex() const; //!< Get Tx default device
|
||||
int getTestMIMODeviceIndex() const; //!< Get MIMO default device
|
||||
int getRxSamplingDeviceIndex(const QString& deviceId, int sequence);
|
||||
int getTxSamplingDeviceIndex(const QString& deviceId, int sequence);
|
||||
int getMIMOSamplingDeviceIndex(const QString& deviceId, int sequence);
|
||||
|
@ -44,9 +44,6 @@ const QString PluginManager::m_remoteOutputDeviceTypeID = "sdrangel.samplesink.r
|
||||
const QString PluginManager::m_fileSinkHardwareID = "FileSink";
|
||||
const QString PluginManager::m_fileSinkDeviceTypeID = "sdrangel.samplesink.filesink";
|
||||
|
||||
const QString PluginManager::m_testMIMOHardwareID = "TestMI";
|
||||
const QString PluginManager::m_testMIMODeviceTypeID = "sdrangel.samplemimo.testmi";
|
||||
|
||||
PluginManager::PluginManager(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_pluginAPI(this)
|
||||
|
@ -92,7 +92,6 @@ public:
|
||||
|
||||
static const QString& getFileInputDeviceId() { return m_fileInputDeviceTypeID; }
|
||||
static const QString& getFileSinkDeviceId() { return m_fileSinkDeviceTypeID; }
|
||||
static const QString& getTestMIMODeviceId() { return m_testMIMODeviceTypeID; }
|
||||
|
||||
private:
|
||||
struct SamplingDevice { //!< This is the device registration
|
||||
@ -147,10 +146,6 @@ private:
|
||||
static const QString m_fileSinkHardwareID; //!< FileSink sink hardware ID
|
||||
static const QString m_fileSinkDeviceTypeID; //!< FileSink sink plugin ID
|
||||
|
||||
// "Local" sample MIMO device IDs
|
||||
static const QString m_testMIMOHardwareID; //!< Test MIMO hardware ID
|
||||
static const QString m_testMIMODeviceTypeID; //!< Test MIMO plugin ID
|
||||
|
||||
void loadPluginsDir(const QDir& dir);
|
||||
};
|
||||
|
||||
|
@ -51,7 +51,6 @@
|
||||
<file>webapi/doc/swagger/include/SSBMod.yaml</file>
|
||||
<file>webapi/doc/swagger/include/Structs.yaml</file>
|
||||
<file>webapi/doc/swagger/include/TestSource.yaml</file>
|
||||
<file>webapi/doc/swagger/include/TestMI.yaml</file>
|
||||
<file>webapi/doc/swagger/include/UDPSource.yaml</file>
|
||||
<file>webapi/doc/swagger/include/UDPSink.yaml</file>
|
||||
<file>webapi/doc/swagger/include/WFMDemod.yaml</file>
|
||||
|
@ -68,8 +68,6 @@ DeviceSettings:
|
||||
$ref: "/doc/swagger/include/SoapySDR.yaml#/SoapySDROutputSettings"
|
||||
testSourceSettings:
|
||||
$ref: "/doc/swagger/include/TestSource.yaml#/TestSourceSettings"
|
||||
testMISettings:
|
||||
$ref: "/doc/swagger/include/TestMI.yaml#/TestMISettings"
|
||||
xtrxInputSettings:
|
||||
$ref: "/doc/swagger/include/Xtrx.yaml#/XtrxInputSettings"
|
||||
xtrxOutputSettings:
|
||||
|
@ -117,7 +117,6 @@ const QMap<QString, QString> WebAPIRequestMapper::m_deviceIdToSettingsKey = {
|
||||
{"sdrangel.samplesource.soapysdrinput", "soapySDRInputSettings"},
|
||||
{"sdrangel.samplesink.soapysdroutput", "soapySDROutputSettings"},
|
||||
{"sdrangel.samplesource.testsource", "testSourceSettings"},
|
||||
{"sdrangel.samplemimo.testmi", "testMISettings"},
|
||||
{"sdrangel.samplesource.xtrx", "XtrxInputSettings"},
|
||||
{"sdrangel.samplesink.xtrx", "XtrxOutputSettings"}
|
||||
};
|
||||
@ -183,10 +182,6 @@ const QMap<QString, QString> WebAPIRequestMapper::m_sinkDeviceHwIdToSettingsKey
|
||||
{"XTRX", "XtrxOutputSettings"}
|
||||
};
|
||||
|
||||
const QMap<QString, QString> WebAPIRequestMapper::m_mimoDeviceHwIdToSettingsKey= {
|
||||
{"TestMI", "testMISettings"}
|
||||
};
|
||||
|
||||
WebAPIRequestMapper::WebAPIRequestMapper(QObject* parent) :
|
||||
HttpRequestHandler(parent),
|
||||
m_adapter(0)
|
||||
@ -2156,14 +2151,6 @@ bool WebAPIRequestMapper::validateDeviceSettings(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (deviceSettings.getDirection() == 2) // MIMO
|
||||
{
|
||||
if (m_mimoDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
|
||||
deviceSettingsKey = m_mimoDeviceHwIdToSettingsKey[*deviceHwType];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
|
@ -164,7 +164,6 @@ private:
|
||||
static const QMap<QString, QString> m_channelTypeToSettingsKey;
|
||||
static const QMap<QString, QString> m_sourceDeviceHwIdToSettingsKey;
|
||||
static const QMap<QString, QString> m_sinkDeviceHwIdToSettingsKey;
|
||||
static const QMap<QString, QString> m_mimoDeviceHwIdToSettingsKey;
|
||||
};
|
||||
|
||||
#endif /* SDRBASE_WEBAPI_WEBAPIREQUESTMAPPER_H_ */
|
||||
|
@ -431,92 +431,6 @@ void MainWindow::addSinkDevice()
|
||||
setDeviceGUI(deviceTabIndex, gui, m_deviceUIs.back()->m_deviceAPI->getSamplingDeviceDisplayName(), 1);
|
||||
}
|
||||
|
||||
void MainWindow::addMIMODevice()
|
||||
{
|
||||
DSPDeviceMIMOEngine *dspDeviceMIMOEngine = m_dspEngine->addDeviceMIMOEngine();
|
||||
dspDeviceMIMOEngine->start();
|
||||
|
||||
uint dspDeviceMIMOEngineUID = dspDeviceMIMOEngine->getUID();
|
||||
char uidCStr[16];
|
||||
sprintf(uidCStr, "UID:%d", dspDeviceMIMOEngineUID);
|
||||
|
||||
int deviceTabIndex = m_deviceUIs.size();
|
||||
m_deviceUIs.push_back(new DeviceUISet(deviceTabIndex, 2, m_masterTimer));
|
||||
m_deviceUIs.back()->m_deviceSourceEngine = nullptr;
|
||||
m_deviceUIs.back()->m_deviceSinkEngine = nullptr;
|
||||
m_deviceUIs.back()->m_deviceMIMOEngine = dspDeviceMIMOEngine;
|
||||
|
||||
char tabNameCStr[16];
|
||||
sprintf(tabNameCStr, "M%d", deviceTabIndex);
|
||||
|
||||
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamMIMO, deviceTabIndex, nullptr, nullptr, dspDeviceMIMOEngine);
|
||||
|
||||
m_deviceUIs.back()->m_deviceAPI = deviceAPI;
|
||||
m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
|
||||
QComboBox *channelSelector = m_deviceUIs.back()->m_samplingDeviceControl->getChannelSelector();
|
||||
// Add Rx channels
|
||||
QList<QString> rxChannelNames;
|
||||
m_pluginManager->listRxChannels(rxChannelNames);
|
||||
QStringList rxChannelNamesList(rxChannelNames);
|
||||
channelSelector->addItems(rxChannelNamesList);
|
||||
m_deviceUIs.back()->setNumberOfAvailableRxChannels(rxChannelNamesList.size());
|
||||
// Add Tx channels
|
||||
QList<QString> txChannelNames;
|
||||
m_pluginManager->listTxChannels(txChannelNames);
|
||||
QStringList txChannelNamesList(txChannelNames);
|
||||
channelSelector->addItems(txChannelNamesList);
|
||||
m_deviceUIs.back()->setNumberOfAvailableTxChannels(txChannelNamesList.size());
|
||||
|
||||
connect(m_deviceUIs.back()->m_samplingDeviceControl->getAddChannelButton(), SIGNAL(clicked(bool)), this, SLOT(channelAddClicked(bool)));
|
||||
|
||||
dspDeviceMIMOEngine->addSpectrumSink(m_deviceUIs.back()->m_spectrumVis);
|
||||
ui->tabSpectra->addTab(m_deviceUIs.back()->m_spectrum, tabNameCStr);
|
||||
ui->tabSpectraGUI->addTab(m_deviceUIs.back()->m_spectrumGUI, tabNameCStr);
|
||||
ui->tabChannels->addTab(m_deviceUIs.back()->m_channelWindow, tabNameCStr);
|
||||
|
||||
connect(m_deviceUIs.back()->m_samplingDeviceControl, SIGNAL(changed()), this, SLOT(sampleMIMOChanged()));
|
||||
|
||||
ui->tabInputsSelect->addTab(m_deviceUIs.back()->m_samplingDeviceControl, tabNameCStr);
|
||||
ui->tabInputsSelect->setTabToolTip(deviceTabIndex, QString(uidCStr));
|
||||
|
||||
// create a test MIMO by default
|
||||
int testMIMODeviceIndex = DeviceEnumerator::instance()->getTestMIMODeviceIndex();
|
||||
const PluginInterface::SamplingDevice *samplingDevice = DeviceEnumerator::instance()->getMIMOSamplingDevice(testMIMODeviceIndex);
|
||||
m_deviceUIs.back()->m_deviceAPI->setSamplingDeviceSequence(samplingDevice->sequence);
|
||||
m_deviceUIs.back()->m_deviceAPI->setDeviceNbItems(samplingDevice->deviceNbItems);
|
||||
m_deviceUIs.back()->m_deviceAPI->setDeviceItemIndex(samplingDevice->deviceItemIndex);
|
||||
m_deviceUIs.back()->m_deviceAPI->setHardwareId(samplingDevice->hardwareId);
|
||||
m_deviceUIs.back()->m_deviceAPI->setSamplingDeviceId(samplingDevice->id);
|
||||
m_deviceUIs.back()->m_deviceAPI->setSamplingDeviceSerial(samplingDevice->serial);
|
||||
m_deviceUIs.back()->m_deviceAPI->setSamplingDeviceDisplayName(samplingDevice->displayedName);
|
||||
m_deviceUIs.back()->m_deviceAPI->setSamplingDevicePluginInterface(DeviceEnumerator::instance()->getMIMOPluginInterface(testMIMODeviceIndex));
|
||||
|
||||
QString userArgs = m_settings.getDeviceUserArgs().findUserArgs(samplingDevice->hardwareId, samplingDevice->sequence);
|
||||
|
||||
if (userArgs.size() > 0) {
|
||||
m_deviceUIs.back()->m_deviceAPI->setHardwareUserArguments(userArgs);
|
||||
}
|
||||
|
||||
m_deviceUIs.back()->m_samplingDeviceControl->setSelectedDeviceIndex(testMIMODeviceIndex);
|
||||
|
||||
// delete previous plugin GUI if it exists
|
||||
m_deviceUIs.back()->m_deviceAPI->getPluginInterface()->deleteSampleSourcePluginInstanceGUI(
|
||||
m_deviceUIs.back()->m_deviceAPI->getSamplingDevicePluginInstanceGUI());
|
||||
|
||||
DeviceSampleMIMO *mimo = m_deviceUIs.back()->m_deviceAPI->getPluginInterface()->createSampleMIMOPluginInstance(
|
||||
m_deviceUIs.back()->m_deviceAPI->getSamplingDeviceId(), m_deviceUIs.back()->m_deviceAPI);
|
||||
m_deviceUIs.back()->m_deviceAPI->setSampleMIMO(mimo);
|
||||
QWidget *gui;
|
||||
PluginInstanceGUI *pluginUI = m_deviceUIs.back()->m_deviceAPI->getPluginInterface()->createSampleMIMOPluginInstanceGUI(
|
||||
m_deviceUIs.back()->m_deviceAPI->getSamplingDeviceId(),
|
||||
&gui,
|
||||
m_deviceUIs.back());
|
||||
m_deviceUIs.back()->m_deviceAPI->getSampleMIMO()->setMessageQueueToGUI(pluginUI->getInputMessageQueue());
|
||||
m_deviceUIs.back()->m_deviceAPI->setSamplingDevicePluginInstanceGUI(pluginUI);
|
||||
m_deviceUIs.back()->m_deviceAPI->getSampleMIMO()->init();
|
||||
setDeviceGUI(deviceTabIndex, gui, m_deviceUIs.back()->m_deviceAPI->getSamplingDeviceDisplayName(), 2);
|
||||
}
|
||||
|
||||
void MainWindow::removeLastDevice()
|
||||
{
|
||||
if (m_deviceUIs.back()->m_deviceSourceEngine) // source tab
|
||||
@ -1012,8 +926,6 @@ bool MainWindow::handleMessage(const Message& cmd)
|
||||
addSinkDevice();
|
||||
} else if (direction == 0) { // Single stream Rx
|
||||
addSourceDevice(-1); // create with file source device by default
|
||||
} else if (direction == 2) { // MIMO
|
||||
addMIMODevice();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1987,11 +1899,7 @@ void MainWindow::on_action_addSinkDevice_triggered()
|
||||
|
||||
void MainWindow::on_action_addMIMODevice_triggered()
|
||||
{
|
||||
if (m_dspEngine->getMIMOSupport()) {
|
||||
addMIMODevice();
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Message"), tr("MIMO not supported in this version"));
|
||||
}
|
||||
QMessageBox::information(this, tr("Message"), tr("MIMO not supported in this version"));
|
||||
}
|
||||
|
||||
void MainWindow::on_action_removeLastDevice_triggered()
|
||||
|
@ -361,7 +361,6 @@ private:
|
||||
|
||||
void addSourceDevice(int deviceIndex);
|
||||
void addSinkDevice();
|
||||
void addMIMODevice();
|
||||
void removeLastDevice();
|
||||
void deleteChannel(int deviceSetIndex, int channelIndex);
|
||||
|
||||
|
@ -145,8 +145,6 @@ bool MainCore::handleMessage(const Message& cmd)
|
||||
addSinkDevice();
|
||||
} else if (direction == 0) { // Single stream Rx
|
||||
addSourceDevice();
|
||||
} else if (direction == 2) { // MIMO
|
||||
addMIMODevice();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -362,49 +360,6 @@ void MainCore::addSourceDevice()
|
||||
m_deviceSets.back()->m_deviceAPI->setSampleSource(source);
|
||||
}
|
||||
|
||||
void MainCore::addMIMODevice()
|
||||
{
|
||||
DSPDeviceMIMOEngine *dspDeviceMIMOEngine = m_dspEngine->addDeviceMIMOEngine();
|
||||
dspDeviceMIMOEngine->start();
|
||||
|
||||
uint dspDeviceMIMOEngineUID = dspDeviceMIMOEngine->getUID();
|
||||
char uidCStr[16];
|
||||
sprintf(uidCStr, "UID:%d", dspDeviceMIMOEngineUID);
|
||||
|
||||
int deviceTabIndex = m_deviceSets.size();
|
||||
m_deviceSets.push_back(new DeviceSet(deviceTabIndex));
|
||||
m_deviceSets.back()->m_deviceSourceEngine = nullptr;
|
||||
m_deviceSets.back()->m_deviceSinkEngine = nullptr;
|
||||
m_deviceSets.back()->m_deviceMIMOEngine = dspDeviceMIMOEngine;
|
||||
|
||||
char tabNameCStr[16];
|
||||
sprintf(tabNameCStr, "M%d", deviceTabIndex);
|
||||
|
||||
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamMIMO, deviceTabIndex, nullptr, nullptr, dspDeviceMIMOEngine);
|
||||
|
||||
// create a test MIMO by default
|
||||
int testMIMODeviceIndex = DeviceEnumerator::instance()->getTestMIMODeviceIndex();
|
||||
const PluginInterface::SamplingDevice *samplingDevice = DeviceEnumerator::instance()->getMIMOSamplingDevice(testMIMODeviceIndex);
|
||||
m_deviceSets.back()->m_deviceAPI->setSamplingDeviceSequence(samplingDevice->sequence);
|
||||
m_deviceSets.back()->m_deviceAPI->setDeviceNbItems(samplingDevice->deviceNbItems);
|
||||
m_deviceSets.back()->m_deviceAPI->setDeviceItemIndex(samplingDevice->deviceItemIndex);
|
||||
m_deviceSets.back()->m_deviceAPI->setHardwareId(samplingDevice->hardwareId);
|
||||
m_deviceSets.back()->m_deviceAPI->setSamplingDeviceId(samplingDevice->id);
|
||||
m_deviceSets.back()->m_deviceAPI->setSamplingDeviceSerial(samplingDevice->serial);
|
||||
m_deviceSets.back()->m_deviceAPI->setSamplingDeviceDisplayName(samplingDevice->displayedName);
|
||||
m_deviceSets.back()->m_deviceAPI->setSamplingDevicePluginInterface(DeviceEnumerator::instance()->getMIMOPluginInterface(testMIMODeviceIndex));
|
||||
|
||||
QString userArgs = m_settings.getDeviceUserArgs().findUserArgs(samplingDevice->hardwareId, samplingDevice->sequence);
|
||||
|
||||
if (userArgs.size() > 0) {
|
||||
m_deviceSets.back()->m_deviceAPI->setHardwareUserArguments(userArgs);
|
||||
}
|
||||
|
||||
DeviceSampleMIMO *mimo = m_deviceSets.back()->m_deviceAPI->getPluginInterface()->createSampleMIMOPluginInstance(
|
||||
m_deviceSets.back()->m_deviceAPI->getSamplingDeviceId(), m_deviceSets.back()->m_deviceAPI);
|
||||
m_deviceSets.back()->m_deviceAPI->setSampleMIMO(mimo);
|
||||
}
|
||||
|
||||
void MainCore::removeLastDevice()
|
||||
{
|
||||
if (m_deviceSets.back()->m_deviceSourceEngine) // source set
|
||||
|
@ -61,7 +61,6 @@ public:
|
||||
|
||||
void addSourceDevice();
|
||||
void addSinkDevice();
|
||||
void addMIMODevice();
|
||||
void removeLastDevice();
|
||||
void changeSampleSource(int deviceSetIndex, int selectedDeviceIndex);
|
||||
void changeSampleSink(int deviceSetIndex, int selectedDeviceIndex);
|
||||
|
@ -68,8 +68,6 @@ DeviceSettings:
|
||||
$ref: "http://localhost:8081/api/swagger/include/SoapySDR.yaml#/SoapySDROutputSettings"
|
||||
testSourceSettings:
|
||||
$ref: "http://localhost:8081/api/swagger/include/TestSource.yaml#/TestSourceSettings"
|
||||
testMISettings:
|
||||
$ref: "http://localhost:8081/api/swagger/include/TestMI.yaml#/TestMISettings"
|
||||
xtrxInputSettings:
|
||||
$ref: "http://localhost:8081/api/swagger/include/Xtrx.yaml#/XtrxInputSettings"
|
||||
xtrxOutputSettings:
|
||||
|
@ -1,64 +0,0 @@
|
||||
TestMISettings:
|
||||
description: TestMISettings
|
||||
properties:
|
||||
fileRecordName:
|
||||
type: string
|
||||
useReverseAPI:
|
||||
description: Synchronize with reverse API (1 for yes, 0 for no)
|
||||
type: integer
|
||||
reverseAPIAddress:
|
||||
type: string
|
||||
reverseAPIPort:
|
||||
type: integer
|
||||
reverseAPIDeviceIndex:
|
||||
type: integer
|
||||
streams:
|
||||
description: Settings for each of the streams
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/TestMiStreamSettings"
|
||||
|
||||
definitions:
|
||||
TestMiStreamSettings:
|
||||
description: TestMiStreamSettings
|
||||
properties:
|
||||
streamIndex:
|
||||
description: Index of the stream to which the settings apply
|
||||
type: integer
|
||||
centerFrequency:
|
||||
type: integer
|
||||
format: uint64
|
||||
frequencyShift:
|
||||
type: integer
|
||||
sampleRate:
|
||||
type: integer
|
||||
log2Decim:
|
||||
type: integer
|
||||
fcPos:
|
||||
type: integer
|
||||
sampleSizeIndex:
|
||||
type: integer
|
||||
amplitudeBits:
|
||||
type: integer
|
||||
autoCorrOptions:
|
||||
type: integer
|
||||
modulation:
|
||||
type: integer
|
||||
modulationTone:
|
||||
type: integer
|
||||
amModulation:
|
||||
type: integer
|
||||
fmDeviation:
|
||||
type: integer
|
||||
dcFactor:
|
||||
type: number
|
||||
format: float
|
||||
iFactor:
|
||||
type: number
|
||||
format: float
|
||||
qFactor:
|
||||
type: number
|
||||
format: float
|
||||
phaseImbalance:
|
||||
type: number
|
||||
format: float
|
@ -15,7 +15,7 @@ info:
|
||||
|
||||
---
|
||||
|
||||
version: "4.11.6"
|
||||
version: "4.12.5"
|
||||
title: SDRangel
|
||||
contact:
|
||||
url: "https://github.com/f4exb/sdrangel"
|
||||
|
Loading…
Reference in New Issue
Block a user