MIMO: Multiple input test source

This commit is contained in:
f4exb 2020-11-10 14:28:37 +01:00
parent 25acf953a7
commit 7e0c835f8d
31 changed files with 5531 additions and 4 deletions

View File

@ -41,5 +41,6 @@ endif()
add_subdirectory(channelrx)
add_subdirectory(channeltx)
add_subdirectory(feature)
add_subdirectory(samplemimo)
add_subdirectory(samplesource)
add_subdirectory(samplesink)

View File

@ -0,0 +1,3 @@
project(samplemimo)
add_subdirectory(testmi)

View File

@ -0,0 +1,56 @@
project(testmi)
set(testmi_SOURCES
testmi.cpp
testmiplugin.cpp
testmiworker.cpp
testmisettings.cpp
testmiwebapiadapter.cpp
)
set(testmi_HEADERS
testmi.h
testmiplugin.h
testmiworker.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})

View File

@ -0,0 +1,137 @@
<h1>Test source input plugin</h1>
<h2>Introduction</h2>
This is a v5 only plugin.
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>
- Left click: record baseband I/Q stream toggle button
- Right click: choose record file
<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).

View File

@ -0,0 +1,872 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 "testmiworker.h"
#include "testmi.h"
MESSAGE_CLASS_DEFINITION(TestMI::MsgConfigureTestSource, 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_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();
}
}
void TestMI::destroy()
{
delete this;
}
void TestMI::init()
{
applySettings(m_settings, true);
}
bool TestMI::startRx()
{
qDebug("TestMI::startRx");
QMutexLocker mutexLocker(&m_mutex);
if (m_running) {
stopRx();
}
m_testSourceWorkers.push_back(new TestMIWorker(&m_sampleMIFifo, 0));
m_testSourceWorkerThreads.push_back(new QThread());
m_testSourceWorkers.back()->moveToThread(m_testSourceWorkerThreads.back());
m_testSourceWorkers.back()->setSamplerate(m_settings.m_streams[0].m_sampleRate);
m_testSourceWorkers.push_back(new TestMIWorker(&m_sampleMIFifo, 1));
m_testSourceWorkerThreads.push_back(new QThread());
m_testSourceWorkers.back()->moveToThread(m_testSourceWorkerThreads.back());
m_testSourceWorkers.back()->setSamplerate(m_settings.m_streams[1].m_sampleRate);
startWorkers();
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);
stopWorkers();
std::vector<TestMIWorker*>::iterator itW = m_testSourceWorkers.begin();
std::vector<QThread*>::iterator itT = m_testSourceWorkerThreads.begin();
for (; (itW != m_testSourceWorkers.end()) && (itT != m_testSourceWorkerThreads.end()); ++itW, ++itT)
{
(*itW)->deleteLater();
delete (*itT);
}
m_testSourceWorkers.clear();
m_testSourceWorkerThreads.clear();
m_running = false;
}
void TestMI::stopTx()
{
qDebug("TestMI::stopTx");
}
void TestMI::startWorkers()
{
std::vector<TestMIWorker*>::iterator itW = m_testSourceWorkers.begin();
std::vector<QThread*>::iterator itT = m_testSourceWorkerThreads.begin();
for (; (itW != m_testSourceWorkers.end()) && (itT != m_testSourceWorkerThreads.end()); ++itW, ++itT)
{
(*itW)->startWork();
(*itT)->start();
}
}
void TestMI::stopWorkers()
{
std::vector<TestMIWorker*>::iterator itW = m_testSourceWorkers.begin();
std::vector<QThread*>::iterator itT = m_testSourceWorkerThreads.begin();
for (; (itW != m_testSourceWorkers.end()) && (itT != m_testSourceWorkerThreads.end()); ++itW, ++itT)
{
(*itW)->stopWork();
(*itT)->quit();
(*itT)->wait();
}
}
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 (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_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_testSourceWorkers.size()) && (m_testSourceWorkers[istream]))
{
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream]))
{
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream]))
{
m_testSourceWorkers[istream]->setFcPos((int) settings.m_streams[istream].m_fcPos);
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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);
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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream]))
{
m_testSourceWorkers[istream]->setModulation(settings.m_streams[istream].m_modulation);
if (settings.m_streams[istream].m_modulation == TestMIStreamSettings::ModulationPattern0) {
m_testSourceWorkers[istream]->setPattern0();
} else if (settings.m_streams[istream].m_modulation == TestMIStreamSettings::ModulationPattern1) {
m_testSourceWorkers[istream]->setPattern1();
} else if (settings.m_streams[istream].m_modulation == TestMIStreamSettings::ModulationPattern2) {
m_testSourceWorkers[istream]->setPattern2();
}
}
}
if ((m_settings.m_streams[istream].m_amModulation != settings.m_streams[istream].m_amModulation) || force)
{
reverseAPIKeys.append("amModulation");
if ((istream < m_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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_testSourceWorkers.size()) && (m_testSourceWorkers[istream])) {
m_testSourceWorkers[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("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);
}
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);
};
}
}
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();
}

View File

@ -0,0 +1,169 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <QThread>
#include "dsp/devicesamplemimo.h"
#include "testmisettings.h"
class DeviceAPI;
class TestMIWorker;
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 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);
private:
struct DeviceSettingsKeys
{
QList<QString> m_commonSettingsKeys;
QList<QList<QString>> m_streamsSettingsKeys;
};
DeviceAPI *m_deviceAPI;
QMutex m_mutex;
TestMISettings m_settings;
std::vector<TestMIWorker*> m_testSourceWorkers;
std::vector<QThread*> m_testSourceWorkerThreads;
QString m_deviceDescription;
bool m_running;
const QTimer& m_masterTimer;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void startWorkers();
void stopWorkers();
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_

View File

@ -0,0 +1,561 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <QFileDialog>
#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) :
DeviceGUI(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::resetToDefaults()
{
m_settings.resetToDefaults();
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;
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;
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::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::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();
}

View File

@ -0,0 +1,105 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <device/devicegui.h>
#include <QTimer>
#include <QWidget>
#include "util/messagequeue.h"
#include "testmisettings.h"
#include "testmi.h"
class DeviceUISet;
namespace Ui {
class TestMIGui;
}
class TestMIGui : public DeviceGUI {
Q_OBJECT
public:
explicit TestMIGui(DeviceUISet *deviceUISet, QWidget* parent = 0);
virtual ~TestMIGui();
virtual void destroy();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
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();
bool handleMessage(const Message& message);
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 openDeviceSettingsDialog(const QPoint& p);
void updateStatus();
void updateHardware();
};
#endif // _TESTMI_TESTMIGUI_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
///////////////////////////////////////////////////////////////////////////////////
// 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("6.0.0"),
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
DeviceGUI* TestMIPlugin::createSampleMIMOPluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
(void) sourceId;
(void) widget;
(void) deviceUISet;
return 0;
}
#else
DeviceGUI* 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();
}

View File

@ -0,0 +1,55 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 DeviceGUI* 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

View File

@ -0,0 +1,179 @@
///////////////////////////////////////////////////////////////////////////////////
// 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_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_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;
}
}

View File

@ -0,0 +1,83 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 {
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_ */

View File

@ -0,0 +1,51 @@
///////////////////////////////////////////////////////////////////////////////////
// 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;
}

View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////////////
// 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;
};

View File

@ -0,0 +1,406 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <cmath>
#include <stdio.h>
#include <errno.h>
#include "dsp/samplemififo.h"
#include "testmiworker.h"
#define TESTMI_BLOCKSIZE 16384
TestMIWorker::TestMIWorker(SampleMIFifo* sampleFifo, int streamIndex, QObject* parent) :
QObject(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);
}
TestMIWorker::~TestMIWorker()
{
}
void TestMIWorker::startWork()
{
m_timer.setTimerType(Qt::PreciseTimer);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
m_timer.start(50);
m_elapsedTimer.start();
m_running = true;
}
void TestMIWorker::stopWork()
{
m_running = false;
m_timer.stop();
disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
}
void TestMIWorker::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 TestMIWorker::setLog2Decimation(unsigned int log2_decim)
{
m_log2Decim = log2_decim;
}
void TestMIWorker::setFcPos(int fcPos)
{
m_fcPos = fcPos;
}
void TestMIWorker::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 TestMIWorker::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 TestMIWorker::setDCFactor(float dcFactor)
{
m_dcBias = dcFactor;
m_amplitudeBitsDC = m_dcBias * m_amplitudeBits;
}
void TestMIWorker::setIFactor(float iFactor)
{
m_iBias = iFactor;
m_amplitudeBitsI = (1.0f + m_iBias) * m_amplitudeBits;
}
void TestMIWorker::setQFactor(float iFactor)
{
m_qBias = iFactor;
m_amplitudeBitsQ = (1.0f + m_qBias) * m_amplitudeBits;
}
void TestMIWorker::setPhaseImbalance(float phaseImbalance)
{
m_phaseImbalance = phaseImbalance;
}
void TestMIWorker::setFrequencyShift(int shift)
{
m_nco.setFreq(shift, m_samplerate);
}
void TestMIWorker::setToneFrequency(int toneFrequency)
{
m_toneNco.setFreq(toneFrequency, m_samplerate);
}
void TestMIWorker::setModulation(TestMIStreamSettings::Modulation modulation)
{
m_modulation = modulation;
}
void TestMIWorker::setAMModulation(float amModulation)
{
m_amModulation = amModulation < 0.0f ? 0.0f : amModulation > 1.0f ? 1.0f : amModulation;
}
void TestMIWorker::setFMDeviation(float deviation)
{
float fmDeviationUnit = deviation / (float) m_samplerate;
m_fmDeviationUnit = fmDeviationUnit < 0.0f ? 0.0f : fmDeviationUnit > 0.5f ? 0.5f : fmDeviationUnit;
qDebug("TestMIWorker::setFMDeviation: m_fmDeviationUnit: %f", m_fmDeviationUnit);
}
void TestMIWorker::setBuffers(quint32 chunksize)
{
if (chunksize > m_bufsize)
{
m_bufsize = chunksize;
if (m_buf == 0)
{
qDebug() << "TestMIWorker::setBuffer: Allocate buffer: "
<< " size: " << m_bufsize << " bytes"
<< " #samples: " << (m_bufsize/4);
m_buf = (qint16*) malloc(m_bufsize);
}
else
{
qDebug() << "TestMIWorker::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 TestMIWorker::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 TestMIWorker::pullAF(Real& afSample)
{
afSample = m_toneNco.next();
}
// call appropriate conversion (decimation) routine depending on the number of sample bits
void TestMIWorker::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 TestMIWorker::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 TestMIWorker::handleInputMessages()
{
}
void TestMIWorker::setPattern0()
{
m_pulseWidth = 150;
m_pulseSampleCount = 0;
m_pulsePatternCount = 0;
m_pulsePatternCycle = 8;
m_pulsePatternPlaces = 3;
}
void TestMIWorker::setPattern1()
{
m_pulseWidth = 1000;
m_pulseSampleCount = 0;
}
void TestMIWorker::setPattern2()
{
m_pulseWidth = 1000;
m_pulseSampleCount = 0;
}

View File

@ -0,0 +1,362 @@
///////////////////////////////////////////////////////////////////////////////////
// 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_TESTMIWORKER_H_
#define _TESTMI_TESTMIWORKER_H_
#include <QObject>
#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 TestMIWorker : public QObject {
Q_OBJECT
public:
TestMIWorker(SampleMIFifo* sampleFifo, int streamIndex, QObject* parent = nullptr);
~TestMIWorker();
void startWork();
void stopWork();
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:
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, true> m_decimators_8;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12, true> m_decimators_12;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16, true> m_decimators_16;
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 // _TESTMI_TESTMIWORKER_H_

View File

@ -3592,6 +3592,9 @@ margin-bottom: 20px;
"soapySDROutputSettings" : {
"$ref" : "#/definitions/SoapySDROutputSettings"
},
"testMISettings" : {
"$ref" : "#/definitions/TestMISettings"
},
"testSourceSettings" : {
"$ref" : "#/definitions/TestSourceSettings"
},
@ -8022,6 +8025,93 @@ margin-bottom: 20px;
"type" : "string"
}
}
};
defs.TestMISettings = {
"properties" : {
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
},
"streams" : {
"type" : "array",
"description" : "Settings for each of the streams",
"items" : {
"$ref" : "#/definitions/TestMiStreamSettings"
}
}
},
"description" : "TestMISettings"
};
defs.TestMiStreamSettings = {
"properties" : {
"streamIndex" : {
"type" : "integer",
"description" : "Index of the stream to which the settings apply"
},
"centerFrequency" : {
"type" : "integer",
"format" : "int64"
},
"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"
}
},
"description" : "TestMiStreamSettings"
};
defs.TestSourceSettings = {
"properties" : {
@ -40916,7 +41006,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-11-10T09:45:26.359+01:00
Generated 2020-11-10T14:08:40.270+01:00
</div>
</div>
</div>

View File

@ -70,6 +70,8 @@ DeviceSettings:
$ref: "/doc/swagger/include/SoapySDR.yaml#/SoapySDRInputSettings"
soapySDROutputSettings:
$ref: "/doc/swagger/include/SoapySDR.yaml#/SoapySDROutputSettings"
testMISettings:
$ref: "/doc/swagger/include/TestMI.yaml#/TestMISettings"
testSourceSettings:
$ref: "/doc/swagger/include/TestSource.yaml#/TestSourceSettings"
usrpInputSettings:

View File

@ -1,8 +1,6 @@
TestMISettings:
description: TestMISettings
properties:
fileRecordName:
type: string
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer

View File

@ -3919,6 +3919,15 @@ bool WebAPIRequestMapper::getDeviceSettings(
deviceSettings->setTestSourceSettings(new SWGSDRangel::SWGTestSourceSettings());
deviceSettings->getTestSourceSettings()->fromJsonObject(settingsJsonObject);
}
else if (deviceSettingsKey == "testMISettings")
{
if (deviceSettingsKeys.contains("streams") && settingsJsonObject["streams"].isArray()) {
appendSettingsArrayKeys(settingsJsonObject, "streams", deviceSettingsKeys);
}
deviceSettings->setTestMiSettings(new SWGSDRangel::SWGTestMISettings());
deviceSettings->getTestMiSettings()->fromJsonObject(settingsJsonObject);
}
else if (deviceSettingsKey == "usrpInputSettings")
{
deviceSettings->setUsrpInputSettings(new SWGSDRangel::SWGUSRPInputSettings());

View File

@ -70,6 +70,8 @@ DeviceSettings:
$ref: "http://swgserver:8081/api/swagger/include/SoapySDR.yaml#/SoapySDRInputSettings"
soapySDROutputSettings:
$ref: "http://swgserver:8081/api/swagger/include/SoapySDR.yaml#/SoapySDROutputSettings"
testMISettings:
$ref: "http://swgserver:8081/api/swagger/include/TestMI.yaml#/TestMISettings"
testSourceSettings:
$ref: "http://swgserver:8081/api/swagger/include/TestSource.yaml#/TestSourceSettings"
usrpInputSettings:

View File

@ -0,0 +1,62 @@
TestMISettings:
description: TestMISettings
properties:
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: int64
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

View File

@ -3592,6 +3592,9 @@ margin-bottom: 20px;
"soapySDROutputSettings" : {
"$ref" : "#/definitions/SoapySDROutputSettings"
},
"testMISettings" : {
"$ref" : "#/definitions/TestMISettings"
},
"testSourceSettings" : {
"$ref" : "#/definitions/TestSourceSettings"
},
@ -8022,6 +8025,93 @@ margin-bottom: 20px;
"type" : "string"
}
}
};
defs.TestMISettings = {
"properties" : {
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
},
"streams" : {
"type" : "array",
"description" : "Settings for each of the streams",
"items" : {
"$ref" : "#/definitions/TestMiStreamSettings"
}
}
},
"description" : "TestMISettings"
};
defs.TestMiStreamSettings = {
"properties" : {
"streamIndex" : {
"type" : "integer",
"description" : "Index of the stream to which the settings apply"
},
"centerFrequency" : {
"type" : "integer",
"format" : "int64"
},
"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"
}
},
"description" : "TestMiStreamSettings"
};
defs.TestSourceSettings = {
"properties" : {
@ -40916,7 +41006,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-11-10T09:45:26.359+01:00
Generated 2020-11-10T14:08:40.270+01:00
</div>
</div>
</div>

View File

@ -90,6 +90,8 @@ SWGDeviceSettings::SWGDeviceSettings() {
m_soapy_sdr_input_settings_isSet = false;
soapy_sdr_output_settings = nullptr;
m_soapy_sdr_output_settings_isSet = false;
test_mi_settings = nullptr;
m_test_mi_settings_isSet = false;
test_source_settings = nullptr;
m_test_source_settings_isSet = false;
usrp_input_settings = nullptr;
@ -170,6 +172,8 @@ SWGDeviceSettings::init() {
m_soapy_sdr_input_settings_isSet = false;
soapy_sdr_output_settings = new SWGSoapySDROutputSettings();
m_soapy_sdr_output_settings_isSet = false;
test_mi_settings = new SWGTestMISettings();
m_test_mi_settings_isSet = false;
test_source_settings = new SWGTestSourceSettings();
m_test_source_settings_isSet = false;
usrp_input_settings = new SWGUSRPInputSettings();
@ -273,6 +277,9 @@ SWGDeviceSettings::cleanup() {
if(soapy_sdr_output_settings != nullptr) {
delete soapy_sdr_output_settings;
}
if(test_mi_settings != nullptr) {
delete test_mi_settings;
}
if(test_source_settings != nullptr) {
delete test_source_settings;
}
@ -363,6 +370,8 @@ SWGDeviceSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&soapy_sdr_output_settings, pJson["soapySDROutputSettings"], "SWGSoapySDROutputSettings", "SWGSoapySDROutputSettings");
::SWGSDRangel::setValue(&test_mi_settings, pJson["testMISettings"], "SWGTestMISettings", "SWGTestMISettings");
::SWGSDRangel::setValue(&test_source_settings, pJson["testSourceSettings"], "SWGTestSourceSettings", "SWGTestSourceSettings");
::SWGSDRangel::setValue(&usrp_input_settings, pJson["usrpInputSettings"], "SWGUSRPInputSettings", "SWGUSRPInputSettings");
@ -482,6 +491,9 @@ SWGDeviceSettings::asJsonObject() {
if((soapy_sdr_output_settings != nullptr) && (soapy_sdr_output_settings->isSet())){
toJsonValue(QString("soapySDROutputSettings"), soapy_sdr_output_settings, obj, QString("SWGSoapySDROutputSettings"));
}
if((test_mi_settings != nullptr) && (test_mi_settings->isSet())){
toJsonValue(QString("testMISettings"), test_mi_settings, obj, QString("SWGTestMISettings"));
}
if((test_source_settings != nullptr) && (test_source_settings->isSet())){
toJsonValue(QString("testSourceSettings"), test_source_settings, obj, QString("SWGTestSourceSettings"));
}
@ -811,6 +823,16 @@ SWGDeviceSettings::setSoapySdrOutputSettings(SWGSoapySDROutputSettings* soapy_sd
this->m_soapy_sdr_output_settings_isSet = true;
}
SWGTestMISettings*
SWGDeviceSettings::getTestMiSettings() {
return test_mi_settings;
}
void
SWGDeviceSettings::setTestMiSettings(SWGTestMISettings* test_mi_settings) {
this->test_mi_settings = test_mi_settings;
this->m_test_mi_settings_isSet = true;
}
SWGTestSourceSettings*
SWGDeviceSettings::getTestSourceSettings() {
return test_source_settings;
@ -959,6 +981,9 @@ SWGDeviceSettings::isSet(){
if(soapy_sdr_output_settings && soapy_sdr_output_settings->isSet()){
isObjectUpdated = true; break;
}
if(test_mi_settings && test_mi_settings->isSet()){
isObjectUpdated = true; break;
}
if(test_source_settings && test_source_settings->isSet()){
isObjectUpdated = true; break;
}

View File

@ -50,6 +50,7 @@
#include "SWGSigMFFileInputSettings.h"
#include "SWGSoapySDRInputSettings.h"
#include "SWGSoapySDROutputSettings.h"
#include "SWGTestMISettings.h"
#include "SWGTestSourceSettings.h"
#include "SWGUSRPInputSettings.h"
#include "SWGUSRPOutputSettings.h"
@ -168,6 +169,9 @@ public:
SWGSoapySDROutputSettings* getSoapySdrOutputSettings();
void setSoapySdrOutputSettings(SWGSoapySDROutputSettings* soapy_sdr_output_settings);
SWGTestMISettings* getTestMiSettings();
void setTestMiSettings(SWGTestMISettings* test_mi_settings);
SWGTestSourceSettings* getTestSourceSettings();
void setTestSourceSettings(SWGTestSourceSettings* test_source_settings);
@ -280,6 +284,9 @@ private:
SWGSoapySDROutputSettings* soapy_sdr_output_settings;
bool m_soapy_sdr_output_settings_isSet;
SWGTestMISettings* test_mi_settings;
bool m_test_mi_settings_isSet;
SWGTestSourceSettings* test_source_settings;
bool m_test_source_settings_isSet;

View File

@ -198,6 +198,8 @@
#include "SWGSoapySDROutputSettings.h"
#include "SWGSoapySDRReport.h"
#include "SWGSuccessResponse.h"
#include "SWGTestMISettings.h"
#include "SWGTestMiStreamSettings.h"
#include "SWGTestSourceSettings.h"
#include "SWGTraceData.h"
#include "SWGTriggerData.h"
@ -773,6 +775,12 @@ namespace SWGSDRangel {
if(QString("SWGSuccessResponse").compare(type) == 0) {
return new SWGSuccessResponse();
}
if(QString("SWGTestMISettings").compare(type) == 0) {
return new SWGTestMISettings();
}
if(QString("SWGTestMiStreamSettings").compare(type) == 0) {
return new SWGTestMiStreamSettings();
}
if(QString("SWGTestSourceSettings").compare(type) == 0) {
return new SWGTestSourceSettings();
}

View File

@ -0,0 +1,208 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGTestMISettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGTestMISettings::SWGTestMISettings(QString* json) {
init();
this->fromJson(*json);
}
SWGTestMISettings::SWGTestMISettings() {
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = nullptr;
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
streams = nullptr;
m_streams_isSet = false;
}
SWGTestMISettings::~SWGTestMISettings() {
this->cleanup();
}
void
SWGTestMISettings::init() {
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = new QString("");
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
streams = new QList<SWGTestMiStreamSettings*>();
m_streams_isSet = false;
}
void
SWGTestMISettings::cleanup() {
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
if(streams != nullptr) {
auto arr = streams;
for(auto o: *arr) {
delete o;
}
delete streams;
}
}
SWGTestMISettings*
SWGTestMISettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGTestMISettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
::SWGSDRangel::setValue(&streams, pJson["streams"], "QList", "SWGTestMiStreamSettings");
}
QString
SWGTestMISettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGTestMISettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
}
if(m_reverse_api_port_isSet){
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
}
if(m_reverse_api_device_index_isSet){
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
}
if(streams && streams->size() > 0){
toJsonArray((QList<void*>*)streams, obj, "streams", "SWGTestMiStreamSettings");
}
return obj;
}
qint32
SWGTestMISettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGTestMISettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGTestMISettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGTestMISettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGTestMISettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGTestMISettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGTestMISettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGTestMISettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
QList<SWGTestMiStreamSettings*>*
SWGTestMISettings::getStreams() {
return streams;
}
void
SWGTestMISettings::setStreams(QList<SWGTestMiStreamSettings*>* streams) {
this->streams = streams;
this->m_streams_isSet = true;
}
bool
SWGTestMISettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_use_reverse_api_isSet){
isObjectUpdated = true; break;
}
if(reverse_api_address && *reverse_api_address != QString("")){
isObjectUpdated = true; break;
}
if(m_reverse_api_port_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_device_index_isSet){
isObjectUpdated = true; break;
}
if(streams && (streams->size() > 0)){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,85 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGTestMISettings.h
*
* TestMISettings
*/
#ifndef SWGTestMISettings_H_
#define SWGTestMISettings_H_
#include <QJsonObject>
#include "SWGTestMiStreamSettings.h"
#include <QList>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGTestMISettings: public SWGObject {
public:
SWGTestMISettings();
SWGTestMISettings(QString* json);
virtual ~SWGTestMISettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGTestMISettings* fromJson(QString &jsonString) override;
qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api);
QString* getReverseApiAddress();
void setReverseApiAddress(QString* reverse_api_address);
qint32 getReverseApiPort();
void setReverseApiPort(qint32 reverse_api_port);
qint32 getReverseApiDeviceIndex();
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
QList<SWGTestMiStreamSettings*>* getStreams();
void setStreams(QList<SWGTestMiStreamSettings*>* streams);
virtual bool isSet() override;
private:
qint32 use_reverse_api;
bool m_use_reverse_api_isSet;
QString* reverse_api_address;
bool m_reverse_api_address_isSet;
qint32 reverse_api_port;
bool m_reverse_api_port_isSet;
qint32 reverse_api_device_index;
bool m_reverse_api_device_index_isSet;
QList<SWGTestMiStreamSettings*>* streams;
bool m_streams_isSet;
};
}
#endif /* SWGTestMISettings_H_ */

View File

@ -0,0 +1,476 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGTestMiStreamSettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGTestMiStreamSettings::SWGTestMiStreamSettings(QString* json) {
init();
this->fromJson(*json);
}
SWGTestMiStreamSettings::SWGTestMiStreamSettings() {
stream_index = 0;
m_stream_index_isSet = false;
center_frequency = 0L;
m_center_frequency_isSet = false;
frequency_shift = 0;
m_frequency_shift_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
log2_decim = 0;
m_log2_decim_isSet = false;
fc_pos = 0;
m_fc_pos_isSet = false;
sample_size_index = 0;
m_sample_size_index_isSet = false;
amplitude_bits = 0;
m_amplitude_bits_isSet = false;
auto_corr_options = 0;
m_auto_corr_options_isSet = false;
modulation = 0;
m_modulation_isSet = false;
modulation_tone = 0;
m_modulation_tone_isSet = false;
am_modulation = 0;
m_am_modulation_isSet = false;
fm_deviation = 0;
m_fm_deviation_isSet = false;
dc_factor = 0.0f;
m_dc_factor_isSet = false;
i_factor = 0.0f;
m_i_factor_isSet = false;
q_factor = 0.0f;
m_q_factor_isSet = false;
phase_imbalance = 0.0f;
m_phase_imbalance_isSet = false;
}
SWGTestMiStreamSettings::~SWGTestMiStreamSettings() {
this->cleanup();
}
void
SWGTestMiStreamSettings::init() {
stream_index = 0;
m_stream_index_isSet = false;
center_frequency = 0L;
m_center_frequency_isSet = false;
frequency_shift = 0;
m_frequency_shift_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
log2_decim = 0;
m_log2_decim_isSet = false;
fc_pos = 0;
m_fc_pos_isSet = false;
sample_size_index = 0;
m_sample_size_index_isSet = false;
amplitude_bits = 0;
m_amplitude_bits_isSet = false;
auto_corr_options = 0;
m_auto_corr_options_isSet = false;
modulation = 0;
m_modulation_isSet = false;
modulation_tone = 0;
m_modulation_tone_isSet = false;
am_modulation = 0;
m_am_modulation_isSet = false;
fm_deviation = 0;
m_fm_deviation_isSet = false;
dc_factor = 0.0f;
m_dc_factor_isSet = false;
i_factor = 0.0f;
m_i_factor_isSet = false;
q_factor = 0.0f;
m_q_factor_isSet = false;
phase_imbalance = 0.0f;
m_phase_imbalance_isSet = false;
}
void
SWGTestMiStreamSettings::cleanup() {
}
SWGTestMiStreamSettings*
SWGTestMiStreamSettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGTestMiStreamSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", "");
::SWGSDRangel::setValue(&center_frequency, pJson["centerFrequency"], "qint64", "");
::SWGSDRangel::setValue(&frequency_shift, pJson["frequencyShift"], "qint32", "");
::SWGSDRangel::setValue(&sample_rate, pJson["sampleRate"], "qint32", "");
::SWGSDRangel::setValue(&log2_decim, pJson["log2Decim"], "qint32", "");
::SWGSDRangel::setValue(&fc_pos, pJson["fcPos"], "qint32", "");
::SWGSDRangel::setValue(&sample_size_index, pJson["sampleSizeIndex"], "qint32", "");
::SWGSDRangel::setValue(&amplitude_bits, pJson["amplitudeBits"], "qint32", "");
::SWGSDRangel::setValue(&auto_corr_options, pJson["autoCorrOptions"], "qint32", "");
::SWGSDRangel::setValue(&modulation, pJson["modulation"], "qint32", "");
::SWGSDRangel::setValue(&modulation_tone, pJson["modulationTone"], "qint32", "");
::SWGSDRangel::setValue(&am_modulation, pJson["amModulation"], "qint32", "");
::SWGSDRangel::setValue(&fm_deviation, pJson["fmDeviation"], "qint32", "");
::SWGSDRangel::setValue(&dc_factor, pJson["dcFactor"], "float", "");
::SWGSDRangel::setValue(&i_factor, pJson["iFactor"], "float", "");
::SWGSDRangel::setValue(&q_factor, pJson["qFactor"], "float", "");
::SWGSDRangel::setValue(&phase_imbalance, pJson["phaseImbalance"], "float", "");
}
QString
SWGTestMiStreamSettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGTestMiStreamSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_stream_index_isSet){
obj->insert("streamIndex", QJsonValue(stream_index));
}
if(m_center_frequency_isSet){
obj->insert("centerFrequency", QJsonValue(center_frequency));
}
if(m_frequency_shift_isSet){
obj->insert("frequencyShift", QJsonValue(frequency_shift));
}
if(m_sample_rate_isSet){
obj->insert("sampleRate", QJsonValue(sample_rate));
}
if(m_log2_decim_isSet){
obj->insert("log2Decim", QJsonValue(log2_decim));
}
if(m_fc_pos_isSet){
obj->insert("fcPos", QJsonValue(fc_pos));
}
if(m_sample_size_index_isSet){
obj->insert("sampleSizeIndex", QJsonValue(sample_size_index));
}
if(m_amplitude_bits_isSet){
obj->insert("amplitudeBits", QJsonValue(amplitude_bits));
}
if(m_auto_corr_options_isSet){
obj->insert("autoCorrOptions", QJsonValue(auto_corr_options));
}
if(m_modulation_isSet){
obj->insert("modulation", QJsonValue(modulation));
}
if(m_modulation_tone_isSet){
obj->insert("modulationTone", QJsonValue(modulation_tone));
}
if(m_am_modulation_isSet){
obj->insert("amModulation", QJsonValue(am_modulation));
}
if(m_fm_deviation_isSet){
obj->insert("fmDeviation", QJsonValue(fm_deviation));
}
if(m_dc_factor_isSet){
obj->insert("dcFactor", QJsonValue(dc_factor));
}
if(m_i_factor_isSet){
obj->insert("iFactor", QJsonValue(i_factor));
}
if(m_q_factor_isSet){
obj->insert("qFactor", QJsonValue(q_factor));
}
if(m_phase_imbalance_isSet){
obj->insert("phaseImbalance", QJsonValue(phase_imbalance));
}
return obj;
}
qint32
SWGTestMiStreamSettings::getStreamIndex() {
return stream_index;
}
void
SWGTestMiStreamSettings::setStreamIndex(qint32 stream_index) {
this->stream_index = stream_index;
this->m_stream_index_isSet = true;
}
qint64
SWGTestMiStreamSettings::getCenterFrequency() {
return center_frequency;
}
void
SWGTestMiStreamSettings::setCenterFrequency(qint64 center_frequency) {
this->center_frequency = center_frequency;
this->m_center_frequency_isSet = true;
}
qint32
SWGTestMiStreamSettings::getFrequencyShift() {
return frequency_shift;
}
void
SWGTestMiStreamSettings::setFrequencyShift(qint32 frequency_shift) {
this->frequency_shift = frequency_shift;
this->m_frequency_shift_isSet = true;
}
qint32
SWGTestMiStreamSettings::getSampleRate() {
return sample_rate;
}
void
SWGTestMiStreamSettings::setSampleRate(qint32 sample_rate) {
this->sample_rate = sample_rate;
this->m_sample_rate_isSet = true;
}
qint32
SWGTestMiStreamSettings::getLog2Decim() {
return log2_decim;
}
void
SWGTestMiStreamSettings::setLog2Decim(qint32 log2_decim) {
this->log2_decim = log2_decim;
this->m_log2_decim_isSet = true;
}
qint32
SWGTestMiStreamSettings::getFcPos() {
return fc_pos;
}
void
SWGTestMiStreamSettings::setFcPos(qint32 fc_pos) {
this->fc_pos = fc_pos;
this->m_fc_pos_isSet = true;
}
qint32
SWGTestMiStreamSettings::getSampleSizeIndex() {
return sample_size_index;
}
void
SWGTestMiStreamSettings::setSampleSizeIndex(qint32 sample_size_index) {
this->sample_size_index = sample_size_index;
this->m_sample_size_index_isSet = true;
}
qint32
SWGTestMiStreamSettings::getAmplitudeBits() {
return amplitude_bits;
}
void
SWGTestMiStreamSettings::setAmplitudeBits(qint32 amplitude_bits) {
this->amplitude_bits = amplitude_bits;
this->m_amplitude_bits_isSet = true;
}
qint32
SWGTestMiStreamSettings::getAutoCorrOptions() {
return auto_corr_options;
}
void
SWGTestMiStreamSettings::setAutoCorrOptions(qint32 auto_corr_options) {
this->auto_corr_options = auto_corr_options;
this->m_auto_corr_options_isSet = true;
}
qint32
SWGTestMiStreamSettings::getModulation() {
return modulation;
}
void
SWGTestMiStreamSettings::setModulation(qint32 modulation) {
this->modulation = modulation;
this->m_modulation_isSet = true;
}
qint32
SWGTestMiStreamSettings::getModulationTone() {
return modulation_tone;
}
void
SWGTestMiStreamSettings::setModulationTone(qint32 modulation_tone) {
this->modulation_tone = modulation_tone;
this->m_modulation_tone_isSet = true;
}
qint32
SWGTestMiStreamSettings::getAmModulation() {
return am_modulation;
}
void
SWGTestMiStreamSettings::setAmModulation(qint32 am_modulation) {
this->am_modulation = am_modulation;
this->m_am_modulation_isSet = true;
}
qint32
SWGTestMiStreamSettings::getFmDeviation() {
return fm_deviation;
}
void
SWGTestMiStreamSettings::setFmDeviation(qint32 fm_deviation) {
this->fm_deviation = fm_deviation;
this->m_fm_deviation_isSet = true;
}
float
SWGTestMiStreamSettings::getDcFactor() {
return dc_factor;
}
void
SWGTestMiStreamSettings::setDcFactor(float dc_factor) {
this->dc_factor = dc_factor;
this->m_dc_factor_isSet = true;
}
float
SWGTestMiStreamSettings::getIFactor() {
return i_factor;
}
void
SWGTestMiStreamSettings::setIFactor(float i_factor) {
this->i_factor = i_factor;
this->m_i_factor_isSet = true;
}
float
SWGTestMiStreamSettings::getQFactor() {
return q_factor;
}
void
SWGTestMiStreamSettings::setQFactor(float q_factor) {
this->q_factor = q_factor;
this->m_q_factor_isSet = true;
}
float
SWGTestMiStreamSettings::getPhaseImbalance() {
return phase_imbalance;
}
void
SWGTestMiStreamSettings::setPhaseImbalance(float phase_imbalance) {
this->phase_imbalance = phase_imbalance;
this->m_phase_imbalance_isSet = true;
}
bool
SWGTestMiStreamSettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_stream_index_isSet){
isObjectUpdated = true; break;
}
if(m_center_frequency_isSet){
isObjectUpdated = true; break;
}
if(m_frequency_shift_isSet){
isObjectUpdated = true; break;
}
if(m_sample_rate_isSet){
isObjectUpdated = true; break;
}
if(m_log2_decim_isSet){
isObjectUpdated = true; break;
}
if(m_fc_pos_isSet){
isObjectUpdated = true; break;
}
if(m_sample_size_index_isSet){
isObjectUpdated = true; break;
}
if(m_amplitude_bits_isSet){
isObjectUpdated = true; break;
}
if(m_auto_corr_options_isSet){
isObjectUpdated = true; break;
}
if(m_modulation_isSet){
isObjectUpdated = true; break;
}
if(m_modulation_tone_isSet){
isObjectUpdated = true; break;
}
if(m_am_modulation_isSet){
isObjectUpdated = true; break;
}
if(m_fm_deviation_isSet){
isObjectUpdated = true; break;
}
if(m_dc_factor_isSet){
isObjectUpdated = true; break;
}
if(m_i_factor_isSet){
isObjectUpdated = true; break;
}
if(m_q_factor_isSet){
isObjectUpdated = true; break;
}
if(m_phase_imbalance_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,154 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGTestMiStreamSettings.h
*
* TestMiStreamSettings
*/
#ifndef SWGTestMiStreamSettings_H_
#define SWGTestMiStreamSettings_H_
#include <QJsonObject>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGTestMiStreamSettings: public SWGObject {
public:
SWGTestMiStreamSettings();
SWGTestMiStreamSettings(QString* json);
virtual ~SWGTestMiStreamSettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGTestMiStreamSettings* fromJson(QString &jsonString) override;
qint32 getStreamIndex();
void setStreamIndex(qint32 stream_index);
qint64 getCenterFrequency();
void setCenterFrequency(qint64 center_frequency);
qint32 getFrequencyShift();
void setFrequencyShift(qint32 frequency_shift);
qint32 getSampleRate();
void setSampleRate(qint32 sample_rate);
qint32 getLog2Decim();
void setLog2Decim(qint32 log2_decim);
qint32 getFcPos();
void setFcPos(qint32 fc_pos);
qint32 getSampleSizeIndex();
void setSampleSizeIndex(qint32 sample_size_index);
qint32 getAmplitudeBits();
void setAmplitudeBits(qint32 amplitude_bits);
qint32 getAutoCorrOptions();
void setAutoCorrOptions(qint32 auto_corr_options);
qint32 getModulation();
void setModulation(qint32 modulation);
qint32 getModulationTone();
void setModulationTone(qint32 modulation_tone);
qint32 getAmModulation();
void setAmModulation(qint32 am_modulation);
qint32 getFmDeviation();
void setFmDeviation(qint32 fm_deviation);
float getDcFactor();
void setDcFactor(float dc_factor);
float getIFactor();
void setIFactor(float i_factor);
float getQFactor();
void setQFactor(float q_factor);
float getPhaseImbalance();
void setPhaseImbalance(float phase_imbalance);
virtual bool isSet() override;
private:
qint32 stream_index;
bool m_stream_index_isSet;
qint64 center_frequency;
bool m_center_frequency_isSet;
qint32 frequency_shift;
bool m_frequency_shift_isSet;
qint32 sample_rate;
bool m_sample_rate_isSet;
qint32 log2_decim;
bool m_log2_decim_isSet;
qint32 fc_pos;
bool m_fc_pos_isSet;
qint32 sample_size_index;
bool m_sample_size_index_isSet;
qint32 amplitude_bits;
bool m_amplitude_bits_isSet;
qint32 auto_corr_options;
bool m_auto_corr_options_isSet;
qint32 modulation;
bool m_modulation_isSet;
qint32 modulation_tone;
bool m_modulation_tone_isSet;
qint32 am_modulation;
bool m_am_modulation_isSet;
qint32 fm_deviation;
bool m_fm_deviation_isSet;
float dc_factor;
bool m_dc_factor_isSet;
float i_factor;
bool m_i_factor_isSet;
float q_factor;
bool m_q_factor_isSet;
float phase_imbalance;
bool m_phase_imbalance_isSet;
};
}
#endif /* SWGTestMiStreamSettings_H_ */