MIMO: copied test source as multiple input. Adaptation of main classes

This commit is contained in:
f4exb 2019-05-18 06:30:37 +02:00
parent 1777eab1e3
commit ddde7a925f
55 changed files with 5362 additions and 52 deletions

View File

@ -2,5 +2,6 @@ project(plugins)
add_subdirectory(channelrx)
add_subdirectory(channeltx)
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,52 @@
project(testmi)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(testmi_SOURCES
testmigui.cpp
testmi.cpp
testmiplugin.cpp
testmithread.cpp
testmisettings.cpp
)
set(testmi_HEADERS
testmigui.h
testmi.h
testmiplugin.h
testmithread.h
testmisettings.h
)
set(testmi_FORMS
testmigui.ui
)
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
qt5_wrap_ui(testmi_FORMS_HEADERS ${testmi_FORMS})
add_library(mimotestmi SHARED
${testmi_SOURCES}
${testmi_HEADERS_MOC}
${testmi_FORMS_HEADERS}
)
target_link_libraries(mimotestmi
${QT_LIBRARIES}
sdrbase
sdrgui
swagger
)
target_link_libraries(mimotestmi Qt5::Core Qt5::Widgets)
install(TARGETS mimotestmi DESTINATION lib/plugins/samplemimo)

View File

@ -0,0 +1,134 @@
<h1>Test source input plugin</h1>
<h2>Introduction</h2>
This input sample source plugin is an internal continuous wave generator that can be used to carry out test of software internals.
<h2>Build</h2>
The plugin is present in the core of the software and thus is always present in the list of sources.
<h2>Interface</h2>
![Test source input plugin GUI](../../../doc/img/TestSourceInput_plugin.png)
<h3>1: Common stream parameters</h3>
![Remote source input stream GUI](../../../doc/img/RemoteInput_plugin_01.png)
<h4>1.1: Frequency</h4>
This is the center frequency of reception in kHz.
<h4>1.2: Start/Stop</h4>
Device start / stop button.
- Blue triangle icon: device is ready and can be started
- Green square icon: device is running and can be stopped
- Magenta (or pink) square icon: an error occurred. In the case the device was accidentally disconnected you may click on the icon, plug back in and start again.
<h4>1.3: Record</h4>
Record baseband I/Q stream toggle button
<h4>1.4: Stream sample rate</h4>
Baseband I/Q sample rate in kS/s. This is the device to host sample rate (3) divided by the decimation factor (4).
<h3>2: Various options</h3>
![Test source input plugin GUI 2](../../../doc/img/TestSourceInput_plugin_2.png)
<h4>2.1: Auto corrections</h4>
This combo box control the local DSP auto correction options:
- **None**: no correction
- **DC**: auto remove DC component
- **DC+IQ**: auto remove DC component and correct I/Q balance.
<h4>2.2: Decimation factor</h4>
The I/Q stream from the generator is downsampled by a power of two before being sent to the passband. Possible values are increasing powers of two: 1 (no decimation), 2, 4, 8, 16, 32. This exercises the decimation chain.
This exercises the decimation chain.
<h4>2.3: Baseband center frequency position relative the center frequency</h4>
- **Cen**: the decimation operation takes place around the center frequency Fs
- **Inf**: the decimation operation takes place around Fs - Fc.
- **Sup**: the decimation operation takes place around Fs + Fc.
With SR as the sample rate before decimation Fc is calculated as:
- if decimation n is 4 or lower: Fc = SR/2^(log2(n)-1). The device center frequency is on the side of the baseband. You need a RF filter bandwidth at least twice the baseband.
- if decimation n is 8 or higher: Fc = SR/n. The device center frequency is half the baseband away from the side of the baseband. You need a RF filter bandwidth at least 3 times the baseband.
<h3>2.4: Sample size</h3>
This is the sample size in number of bits. It corresponds to the actual sample size used by the devices supported:
- **8**: RTL-SDR, HackRF
- **12**: Airspy, BladeRF, LimeSDR, PlutoSDR, SDRplay
- **16**: Airspy HF+, FCD Pro, FCD Pro+
<h3>3: Sample rate</h3>
This controls the generator sample rate in samples per second.
<h3>4: Modulation</h4>
- **No**: No modulation
- **AM**: Amplitude modulation (AM)
- **FM**: Frequency modulation (FM)
- **P0**: Pattern 0 is a binary pattern
- Pulse width: 150 samples
- Sync pattern: 010 at full amplitude
- Binary pattern LSB first on 3 bits from 0 to 7 at 0.3 amplitude
- **P1**: Pattern 1 is a sawtooth pattern
- Pulse width: 1000 samples
- Starts at full amplitude then amplitude decreases linearly down to zero
- **P2**: Pattern 2 is a 50% duty cycle square pattern
- Pulse width: 1000 samples
- Starts with a full amplitude pulse then down to zero for the duration of one pulse
<h3>5: Modulating tone frequency</h3>
This controls the modulating tone frequency in kHz in 10 Hz steps.
<h3>6: Carrier shift from center frequency</h3>
Use this control to set the offset of the carrier from the center frequency of reception.
<h3>7: AM modulation factor</h3>
This controls the AM modulation factor from 0 to 99%
<h3>8: FM deviation</h3>
This controls the frequency modulation deviation in kHz in 100 Hz steps. It cannot exceed the sample rate.
<h3>9: Amplitude coarse control</h3>
This slider controls the number of amplitude bits by steps of 100 bits. The total number of amplitude bits appear on the right.
<h3>10: Amplitude fine control</h3>
This slider controls the number of amplitude bits by steps of 1 bit. The signal power in dB relative to the maximum power (full bit range) appear on the right.
<h3>11: DC bias</h3>
Use this slider to give a DC component in percentage of maximum amplitude.
<h3>12: I bias</h3>
Use this slider to give an in-phase (I) bias in percentage of maximum amplitude.
<h3>13: Q bias</h3>
Use this slider to give an quadrature-phase (Q) bias in percentage of maximum amplitude.
<h3>14: Phase imbalance</h3>
Use this slider to introduce a phase imbalance in percentage of full period (continuous wave) or percentage of I signal injected in Q (AM, FM).

View File

@ -0,0 +1,748 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 "device/deviceapi.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "dsp/devicesamplesource.h"
#include "dsp/filerecord.h"
#include "testmithread.h"
#include "testmi.h"
MESSAGE_CLASS_DEFINITION(TestMI::MsgConfigureTestSource, Message)
MESSAGE_CLASS_DEFINITION(TestMI::MsgFileRecord, Message)
MESSAGE_CLASS_DEFINITION(TestMI::MsgStartStop, Message)
TestMI::TestMI(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_settings(),
m_testSourceThread(0),
m_deviceDescription(),
m_running(false),
m_masterTimer(deviceAPI->getMasterTimer())
{
m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
m_deviceAPI->addAncillarySink(m_fileSink);
m_sampleSinkFifos.push_back(SampleSinkFifo(96000 * 4));
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) {
stop();
}
m_deviceAPI->removeAncillarySink(m_fileSink);
delete m_fileSink;
}
void TestMI::destroy()
{
delete this;
}
void TestMI::init()
{
applySettings(m_settings, true);
}
bool TestMI::start()
{
QMutexLocker mutexLocker(&m_mutex);
if (m_running) stop();
m_testSourceThread = new TestMIThread(&m_sampleSinkFifos[0]);
m_testSourceThread->setSamplerate(m_settings.m_sampleRate);
m_testSourceThread->startStop(true);
mutexLocker.unlock();
applySettings(m_settings, true);
m_running = true;
return true;
}
void TestMI::stop()
{
QMutexLocker mutexLocker(&m_mutex);
if (m_testSourceThread != 0)
{
m_testSourceThread->startStop(false);
m_testSourceThread->deleteLater();
m_testSourceThread = 0;
}
m_running = false;
}
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
{
(void) index;
return m_settings.m_sampleRate/(1<<m_settings.m_log2Decim);
}
quint64 TestMI::getSourceCenterFrequency(int index) const
{
(void) index;
return m_settings.m_centerFrequency;
}
void TestMI::setSourceCenterFrequency(qint64 centerFrequency, int index)
{
(void) index;
TestMISettings settings = m_settings;
settings.m_centerFrequency = centerFrequency;
MsgConfigureTestSource* message = MsgConfigureTestSource::create(settings, false);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureTestSource* messageToGUI = MsgConfigureTestSource::create(settings, false);
m_guiMessageQueue->push(messageToGUI);
}
}
bool TestMI::handleMessage(const Message& message)
{
if (MsgConfigureTestSource::match(message))
{
MsgConfigureTestSource& conf = (MsgConfigureTestSource&) message;
qDebug() << "TestMI::handleMessage: MsgConfigureTestSource";
bool success = applySettings(conf.getSettings(), conf.getForce());
if (!success)
{
qDebug("TestMI::handleMessage: config error");
}
return true;
}
else if (MsgFileRecord::match(message))
{
MsgFileRecord& conf = (MsgFileRecord&) message;
qDebug() << "TestMI::handleMessage: MsgFileRecord: " << conf.getStartStop();
if (conf.getStartStop())
{
if (m_settings.m_fileRecordName.size() != 0) {
m_fileSink->setFileName(m_settings.m_fileRecordName);
} else {
m_fileSink->genUniqueFileName(m_deviceAPI->getDeviceUID());
}
m_fileSink->startRecording();
}
else
{
m_fileSink->stopRecording();
}
return true;
}
else if (MsgStartStop::match(message))
{
MsgStartStop& cmd = (MsgStartStop&) message;
qDebug() << "TestMI::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
if (cmd.getStartStop())
{
if (m_deviceAPI->initDeviceEngine())
{
m_deviceAPI->startDeviceEngine();
}
}
else
{
m_deviceAPI->stopDeviceEngine();
}
if (m_settings.m_useReverseAPI) {
webapiReverseSendStartStop(cmd.getStartStop());
}
return true;
}
else
{
return false;
}
}
bool TestMI::applySettings(const TestMISettings& settings, bool force)
{
QList<QString> reverseAPIKeys;
if ((m_settings.m_autoCorrOptions != settings.m_autoCorrOptions) || force)
{
reverseAPIKeys.append("autoCorrOptions");
switch(settings.m_autoCorrOptions)
{
case TestMISettings::AutoCorrDC:
m_deviceAPI->configureCorrections(true, false);
break;
case TestMISettings::AutoCorrDCAndIQ:
m_deviceAPI->configureCorrections(true, true);
break;
case TestMISettings::AutoCorrNone:
default:
m_deviceAPI->configureCorrections(false, false);
break;
}
}
if ((m_settings.m_sampleRate != settings.m_sampleRate) || force)
{
reverseAPIKeys.append("sampleRate");
if (m_testSourceThread != 0)
{
m_testSourceThread->setSamplerate(settings.m_sampleRate);
qDebug("TestMI::applySettings: sample rate set to %d", settings.m_sampleRate);
}
}
if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
{
reverseAPIKeys.append("log2Decim");
if (m_testSourceThread != 0)
{
m_testSourceThread->setLog2Decimation(settings.m_log2Decim);
qDebug() << "TestMI::applySettings: set decimation to " << (1<<settings.m_log2Decim);
}
}
if ((m_settings.m_centerFrequency != settings.m_centerFrequency)
|| (m_settings.m_fcPos != settings.m_fcPos)
|| (m_settings.m_frequencyShift != settings.m_frequencyShift)
|| (m_settings.m_sampleRate != settings.m_sampleRate)
|| (m_settings.m_log2Decim != settings.m_log2Decim) || force)
{
reverseAPIKeys.append("centerFrequency");
reverseAPIKeys.append("fcPos");
reverseAPIKeys.append("frequencyShift");
qint64 deviceCenterFrequency = DeviceSampleSource::calculateDeviceCenterFrequency(
settings.m_centerFrequency,
0, // no transverter mode
settings.m_log2Decim,
(DeviceSampleSource::fcPos_t) settings.m_fcPos,
settings.m_sampleRate,
DeviceSampleSource::FrequencyShiftScheme::FSHIFT_STD,
false);
int frequencyShift = settings.m_frequencyShift;
quint32 devSampleRate = settings.m_sampleRate;
if (settings.m_log2Decim != 0)
{
frequencyShift += DeviceSampleSource::calculateFrequencyShift(
settings.m_log2Decim,
(DeviceSampleSource::fcPos_t) settings.m_fcPos,
settings.m_sampleRate,
DeviceSampleSource::FSHIFT_STD);
}
if (m_testSourceThread != 0)
{
m_testSourceThread->setFcPos((int) settings.m_fcPos);
m_testSourceThread->setFrequencyShift(frequencyShift);
qDebug() << "TestMI::applySettings:"
<< " center freq: " << settings.m_centerFrequency << " Hz"
<< " device center freq: " << deviceCenterFrequency << " Hz"
<< " device sample rate: " << devSampleRate << "Hz"
<< " Actual sample rate: " << devSampleRate/(1<<m_settings.m_log2Decim) << "Hz"
<< " f shift: " << settings.m_frequencyShift;
}
}
if ((m_settings.m_amplitudeBits != settings.m_amplitudeBits) || force)
{
reverseAPIKeys.append("amplitudeBits");
if (m_testSourceThread != 0) {
m_testSourceThread->setAmplitudeBits(settings.m_amplitudeBits);
}
}
if ((m_settings.m_dcFactor != settings.m_dcFactor) || force)
{
reverseAPIKeys.append("dcFactor");
if (m_testSourceThread != 0) {
m_testSourceThread->setDCFactor(settings.m_dcFactor);
}
}
if ((m_settings.m_iFactor != settings.m_iFactor) || force)
{
reverseAPIKeys.append("iFactor");
if (m_testSourceThread != 0) {
m_testSourceThread->setIFactor(settings.m_iFactor);
}
}
if ((m_settings.m_qFactor != settings.m_qFactor) || force)
{
reverseAPIKeys.append("qFactor");
if (m_testSourceThread != 0) {
m_testSourceThread->setQFactor(settings.m_qFactor);
}
}
if ((m_settings.m_phaseImbalance != settings.m_phaseImbalance) || force)
{
reverseAPIKeys.append("phaseImbalance");
if (m_testSourceThread != 0) {
m_testSourceThread->setPhaseImbalance(settings.m_phaseImbalance);
}
}
if ((m_settings.m_sampleSizeIndex != settings.m_sampleSizeIndex) || force)
{
reverseAPIKeys.append("sampleSizeIndex");
if (m_testSourceThread != 0) {
m_testSourceThread->setBitSize(settings.m_sampleSizeIndex);
}
}
if ((m_settings.m_sampleRate != settings.m_sampleRate)
|| (m_settings.m_centerFrequency != settings.m_centerFrequency)
|| (m_settings.m_log2Decim != settings.m_log2Decim)
|| (m_settings.m_fcPos != settings.m_fcPos) || force)
{
int sampleRate = settings.m_sampleRate/(1<<settings.m_log2Decim);
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, settings.m_centerFrequency);
m_fileSink->handleMessage(*notif); // forward to file sink
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
}
if ((m_settings.m_modulationTone != settings.m_modulationTone) || force)
{
reverseAPIKeys.append("modulationTone");
if (m_testSourceThread != 0) {
m_testSourceThread->setToneFrequency(settings.m_modulationTone * 10);
}
}
if ((m_settings.m_modulation != settings.m_modulation) || force)
{
reverseAPIKeys.append("modulation");
if (m_testSourceThread != 0)
{
m_testSourceThread->setModulation(settings.m_modulation);
if (settings.m_modulation == TestMISettings::ModulationPattern0) {
m_testSourceThread->setPattern0();
} else if (settings.m_modulation == TestMISettings::ModulationPattern1) {
m_testSourceThread->setPattern1();
} else if (settings.m_modulation == TestMISettings::ModulationPattern2) {
m_testSourceThread->setPattern2();
}
}
}
if ((m_settings.m_amModulation != settings.m_amModulation) || force)
{
reverseAPIKeys.append("amModulation");
if (m_testSourceThread != 0) {
m_testSourceThread->setAMModulation(settings.m_amModulation / 100.0f);
}
}
if ((m_settings.m_fmDeviation != settings.m_fmDeviation) || force)
{
reverseAPIKeys.append("fmDeviation");
if (m_testSourceThread != 0) {
m_testSourceThread->setFMDeviation(settings.m_fmDeviation * 100.0f);
}
}
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(reverseAPIKeys, settings, fullUpdate || force);
}
m_settings = settings;
return true;
}
int TestMI::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
int TestMI::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
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;
}
int TestMI::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setTestSourceMiSettings(new SWGSDRangel::SWGTestSourceMISettings());
response.getTestSourceMiSettings()->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;
if (deviceSettingsKeys.contains("centerFrequency")) {
settings.m_centerFrequency = response.getTestSourceMiSettings()->getCenterFrequency();
}
if (deviceSettingsKeys.contains("frequencyShift")) {
settings.m_frequencyShift = response.getTestSourceMiSettings()->getFrequencyShift();
}
if (deviceSettingsKeys.contains("sampleRate")) {
settings.m_sampleRate = response.getTestSourceMiSettings()->getSampleRate();
}
if (deviceSettingsKeys.contains("log2Decim")) {
settings.m_log2Decim = response.getTestSourceMiSettings()->getLog2Decim();
}
if (deviceSettingsKeys.contains("fcPos")) {
int fcPos = response.getTestSourceMiSettings()->getFcPos();
fcPos = fcPos < 0 ? 0 : fcPos > 2 ? 2 : fcPos;
settings.m_fcPos = (TestMISettings::fcPos_t) fcPos;
}
if (deviceSettingsKeys.contains("sampleSizeIndex")) {
int sampleSizeIndex = response.getTestSourceMiSettings()->getSampleSizeIndex();
sampleSizeIndex = sampleSizeIndex < 0 ? 0 : sampleSizeIndex > 1 ? 2 : sampleSizeIndex;
settings.m_sampleSizeIndex = sampleSizeIndex;
}
if (deviceSettingsKeys.contains("amplitudeBits")) {
settings.m_amplitudeBits = response.getTestSourceMiSettings()->getAmplitudeBits();
}
if (deviceSettingsKeys.contains("autoCorrOptions")) {
int autoCorrOptions = response.getTestSourceMiSettings()->getAutoCorrOptions();
autoCorrOptions = autoCorrOptions < 0 ? 0 : autoCorrOptions >= TestMISettings::AutoCorrLast ? TestMISettings::AutoCorrLast-1 : autoCorrOptions;
settings.m_sampleSizeIndex = (TestMISettings::AutoCorrOptions) autoCorrOptions;
}
if (deviceSettingsKeys.contains("modulation")) {
int modulation = response.getTestSourceMiSettings()->getModulation();
modulation = modulation < 0 ? 0 : modulation >= TestMISettings::ModulationLast ? TestMISettings::ModulationLast-1 : modulation;
settings.m_modulation = (TestMISettings::Modulation) modulation;
}
if (deviceSettingsKeys.contains("modulationTone")) {
settings.m_modulationTone = response.getTestSourceMiSettings()->getModulationTone();
}
if (deviceSettingsKeys.contains("amModulation")) {
settings.m_amModulation = response.getTestSourceMiSettings()->getAmModulation();
};
if (deviceSettingsKeys.contains("fmDeviation")) {
settings.m_fmDeviation = response.getTestSourceMiSettings()->getFmDeviation();
};
if (deviceSettingsKeys.contains("dcFactor")) {
settings.m_dcFactor = response.getTestSourceMiSettings()->getDcFactor();
};
if (deviceSettingsKeys.contains("iFactor")) {
settings.m_iFactor = response.getTestSourceMiSettings()->getIFactor();
};
if (deviceSettingsKeys.contains("qFactor")) {
settings.m_qFactor = response.getTestSourceMiSettings()->getQFactor();
};
if (deviceSettingsKeys.contains("phaseImbalance")) {
settings.m_phaseImbalance = response.getTestSourceMiSettings()->getPhaseImbalance();
};
if (deviceSettingsKeys.contains("fileRecordName")) {
settings.m_fileRecordName = *response.getTestSourceMiSettings()->getFileRecordName();
}
if (deviceSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getTestSourceMiSettings()->getUseReverseApi() != 0;
}
if (deviceSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getTestSourceMiSettings()->getReverseApiAddress();
}
if (deviceSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getTestSourceMiSettings()->getReverseApiPort();
}
if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIDeviceIndex = response.getTestSourceMiSettings()->getReverseApiDeviceIndex();
}
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::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const TestMISettings& settings)
{
response.getTestSourceMiSettings()->setCenterFrequency(settings.m_centerFrequency);
response.getTestSourceMiSettings()->setFrequencyShift(settings.m_frequencyShift);
response.getTestSourceMiSettings()->setSampleRate(settings.m_sampleRate);
response.getTestSourceMiSettings()->setLog2Decim(settings.m_log2Decim);
response.getTestSourceMiSettings()->setFcPos((int) settings.m_fcPos);
response.getTestSourceMiSettings()->setSampleSizeIndex((int) settings.m_sampleSizeIndex);
response.getTestSourceMiSettings()->setAmplitudeBits(settings.m_amplitudeBits);
response.getTestSourceMiSettings()->setAutoCorrOptions((int) settings.m_autoCorrOptions);
response.getTestSourceMiSettings()->setModulation((int) settings.m_modulation);
response.getTestSourceMiSettings()->setModulationTone(settings.m_modulationTone);
response.getTestSourceMiSettings()->setAmModulation(settings.m_amModulation);
response.getTestSourceMiSettings()->setFmDeviation(settings.m_fmDeviation);
response.getTestSourceMiSettings()->setDcFactor(settings.m_dcFactor);
response.getTestSourceMiSettings()->setIFactor(settings.m_iFactor);
response.getTestSourceMiSettings()->setQFactor(settings.m_qFactor);
response.getTestSourceMiSettings()->setPhaseImbalance(settings.m_phaseImbalance);
if (response.getTestSourceMiSettings()->getFileRecordName()) {
*response.getTestSourceMiSettings()->getFileRecordName() = settings.m_fileRecordName;
} else {
response.getTestSourceMiSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
}
response.getTestSourceMiSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getTestSourceMiSettings()->getReverseApiAddress()) {
*response.getTestSourceMiSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getTestSourceMiSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getTestSourceMiSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getTestSourceMiSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
}
void TestMI::webapiReverseSendSettings(QList<QString>& 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->setTestSourceMiSettings(new SWGSDRangel::SWGTestSourceMISettings());
SWGSDRangel::SWGTestSourceMISettings *swgTestSourceMISettings = swgDeviceSettings->getTestSourceMiSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (deviceSettingsKeys.contains("centerFrequency") || force) {
swgTestSourceMISettings->setCenterFrequency(settings.m_centerFrequency);
}
if (deviceSettingsKeys.contains("frequencyShift") || force) {
swgTestSourceMISettings->setFrequencyShift(settings.m_frequencyShift);
}
if (deviceSettingsKeys.contains("sampleRate") || force) {
swgTestSourceMISettings->setSampleRate(settings.m_sampleRate);
}
if (deviceSettingsKeys.contains("log2Decim") || force) {
swgTestSourceMISettings->setLog2Decim(settings.m_log2Decim);
}
if (deviceSettingsKeys.contains("fcPos") || force) {
swgTestSourceMISettings->setFcPos((int) settings.m_fcPos);
}
if (deviceSettingsKeys.contains("sampleSizeIndex") || force) {
swgTestSourceMISettings->setSampleSizeIndex(settings.m_sampleSizeIndex);
}
if (deviceSettingsKeys.contains("amplitudeBits") || force) {
swgTestSourceMISettings->setAmplitudeBits(settings.m_amplitudeBits);
}
if (deviceSettingsKeys.contains("autoCorrOptions") || force) {
swgTestSourceMISettings->setAutoCorrOptions((int) settings.m_sampleSizeIndex);
}
if (deviceSettingsKeys.contains("modulation") || force) {
swgTestSourceMISettings->setModulation((int) settings.m_modulation);
}
if (deviceSettingsKeys.contains("modulationTone")) {
swgTestSourceMISettings->setModulationTone(settings.m_modulationTone);
}
if (deviceSettingsKeys.contains("amModulation") || force) {
swgTestSourceMISettings->setAmModulation(settings.m_amModulation);
};
if (deviceSettingsKeys.contains("fmDeviation") || force) {
swgTestSourceMISettings->setFmDeviation(settings.m_fmDeviation);
};
if (deviceSettingsKeys.contains("dcFactor") || force) {
swgTestSourceMISettings->setDcFactor(settings.m_dcFactor);
};
if (deviceSettingsKeys.contains("iFactor") || force) {
swgTestSourceMISettings->setIFactor(settings.m_iFactor);
};
if (deviceSettingsKeys.contains("qFactor") || force) {
swgTestSourceMISettings->setQFactor(settings.m_qFactor);
};
if (deviceSettingsKeys.contains("phaseImbalance") || force) {
swgTestSourceMISettings->setPhaseImbalance(settings.m_phaseImbalance);
};
if (deviceSettingsKeys.contains("fileRecordName") || force) {
swgTestSourceMISettings->setFileRecordName(new QString(settings.m_fileRecordName));
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer=new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgDeviceSettings->asJson().toUtf8());
buffer->seek(0);
// qDebug("TestMI::webapiReverseSendSettings: %s", channelSettingsURL.toStdString().c_str());
// qDebug("TestMI::webapiReverseSendSettings: query:\n%s", swgDeviceSettings->asJson().toStdString().c_str());
// Always use PATCH to avoid passing reverse API settings
m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
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);
if (start) {
m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
} else {
m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
}
}
void TestMI::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "TestMI::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
return;
}
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("TestMI::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}

View File

@ -0,0 +1,165 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef _TESTMI_TESTMI_H_
#define _TESTMI_TESTMI_H_
#include <QString>
#include <QByteArray>
#include <QTimer>
#include <QNetworkRequest>
#include "dsp/devicesamplemimo.h"
#include "testmisettings.h"
class DeviceAPI;
class TestMIThread;
class FileRecord;
class QNetworkAccessManager;
class QNetworkReply;
class TestMI : public DeviceSampleMIMO {
Q_OBJECT
public:
class MsgConfigureTestSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
const TestMISettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureTestSource* create(const TestMISettings& settings, bool force)
{
return new MsgConfigureTestSource(settings, force);
}
private:
TestMISettings m_settings;
bool m_force;
MsgConfigureTestSource(const TestMISettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgFileRecord : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgFileRecord* create(bool startStop) {
return new MsgFileRecord(startStop);
}
protected:
bool m_startStop;
MsgFileRecord(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
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 start();
virtual void stop();
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 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(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
private:
DeviceAPI *m_deviceAPI;
FileRecord *m_fileSink; //!< File sink to record device I/Q output
QMutex m_mutex;
TestMISettings m_settings;
TestMIThread* m_testSourceThread;
QString m_deviceDescription;
bool m_running;
const QTimer& m_masterTimer;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
bool applySettings(const TestMISettings& settings, bool force);
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const TestMISettings& settings);
void webapiReverseSendSettings(QList<QString>& 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,538 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QTime>
#include <QDateTime>
#include <QString>
#include <QMessageBox>
#include "plugin/pluginapi.h"
#include "device/deviceapi.h"
#include "device/deviceuiset.h"
#include "gui/colormapper.h"
#include "gui/glspectrum.h"
#include "gui/crightclickenabler.h"
#include "gui/basicdevicesettingsdialog.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "util/db.h"
#include "mainwindow.h"
#include "ui_testmigui.h"
#include "testmigui.h"
TestMIGui::TestMIGui(DeviceUISet *deviceUISet, QWidget* parent) :
QWidget(parent),
ui(new Ui::TestMIGui),
m_deviceUISet(deviceUISet),
m_settings(),
m_doApplySettings(true),
m_forceSettings(true),
m_sampleMIMO(nullptr),
m_tickCount(0),
m_lastEngineState(DeviceAPI::StNotStarted)
{
qDebug("TestMIGui::TestMIGui");
m_sampleMIMO = m_deviceUISet->m_deviceAPI->getSampleMIMO();
ui->setupUi(this);
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->centerFrequency->setValueRange(7, 0, 9999999);
ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
ui->sampleRate->setValueRange(7, 48000, 9999999);
ui->frequencyShift->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->frequencyShift->setValueRange(false, 7, -9999999, 9999999);
ui->frequencyShiftLabel->setText(QString("%1").arg(QChar(0x94, 0x03)));
displaySettings();
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(500);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
m_sampleMIMO->setMessageQueueToGUI(&m_inputMessageQueue);
CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop);
connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
}
TestMIGui::~TestMIGui()
{
delete ui;
}
void TestMIGui::destroy()
{
delete this;
}
void TestMIGui::setName(const QString& name)
{
setObjectName(name);
}
QString TestMIGui::getName() const
{
return objectName();
}
void TestMIGui::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
qint64 TestMIGui::getCenterFrequency() const
{
return m_settings.m_centerFrequency;
}
void TestMIGui::setCenterFrequency(qint64 centerFrequency)
{
m_settings.m_centerFrequency = centerFrequency;
displaySettings();
sendSettings();
}
QByteArray TestMIGui::serialize() const
{
return m_settings.serialize();
}
bool TestMIGui::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
displaySettings();
m_forceSettings = true;
sendSettings();
return true;
} else {
resetToDefaults();
return false;
}
}
void TestMIGui::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
TestMI::MsgStartStop *message = TestMI::MsgStartStop::create(checked);
m_sampleMIMO->getInputMessageQueue()->push(message);
}
}
void TestMIGui::on_centerFrequency_changed(quint64 value)
{
m_settings.m_centerFrequency = value * 1000;
sendSettings();
}
void TestMIGui::on_autoCorr_currentIndexChanged(int index)
{
if ((index < 0) || (index > TestMISettings::AutoCorrLast)) {
return;
}
m_settings.m_autoCorrOptions = (TestMISettings::AutoCorrOptions) index;
sendSettings();
}
void TestMIGui::on_frequencyShift_changed(qint64 value)
{
m_settings.m_frequencyShift = value;
sendSettings();
}
void TestMIGui::on_decimation_currentIndexChanged(int index)
{
if ((index < 0) || (index > 6)) {
return;
}
m_settings.m_log2Decim = index;
sendSettings();
}
void TestMIGui::on_fcPos_currentIndexChanged(int index)
{
if ((index < 0) || (index > 2)) {
return;
}
m_settings.m_fcPos = (TestMISettings::fcPos_t) index;
sendSettings();
}
void TestMIGui::on_sampleRate_changed(quint64 value)
{
updateFrequencyShiftLimit();
m_settings.m_frequencyShift = ui->frequencyShift->getValueNew();
m_settings.m_sampleRate = value;
sendSettings();
}
void TestMIGui::on_sampleSize_currentIndexChanged(int index)
{
if ((index < 0) || (index > 2)) {
return;
}
updateAmpCoarseLimit();
updateAmpFineLimit();
displayAmplitude();
m_settings.m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
m_settings.m_sampleSizeIndex = index;
sendSettings();
}
void TestMIGui::on_amplitudeCoarse_valueChanged(int value)
{
(void) value;
updateAmpFineLimit();
displayAmplitude();
m_settings.m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
sendSettings();
}
void TestMIGui::on_amplitudeFine_valueChanged(int value)
{
(void) value;
displayAmplitude();
m_settings.m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
sendSettings();
}
void TestMIGui::on_modulation_currentIndexChanged(int index)
{
if ((index < 0) || (index > TestMISettings::ModulationLast)) {
return;
}
m_settings.m_modulation = (TestMISettings::Modulation) index;
sendSettings();
}
void TestMIGui::on_modulationFrequency_valueChanged(int value)
{
m_settings.m_modulationTone = value;
ui->modulationFrequencyText->setText(QString("%1").arg(m_settings.m_modulationTone / 100.0, 0, 'f', 2));
sendSettings();
}
void TestMIGui::on_amModulation_valueChanged(int value)
{
m_settings.m_amModulation = value;
ui->amModulationText->setText(QString("%1").arg(m_settings.m_amModulation));
sendSettings();
}
void TestMIGui::on_fmDeviation_valueChanged(int value)
{
m_settings.m_fmDeviation = value;
ui->fmDeviationText->setText(QString("%1").arg(m_settings.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_dcFactor = value / 100.0f;
sendSettings();
}
void TestMIGui::on_iBias_valueChanged(int value)
{
ui->iBiasText->setText(QString(tr("%1 %").arg(value)));
m_settings.m_iFactor = value / 100.0f;
sendSettings();
}
void TestMIGui::on_qBias_valueChanged(int value)
{
ui->qBiasText->setText(QString(tr("%1 %").arg(value)));
m_settings.m_qFactor = value / 100.0f;
sendSettings();
}
void TestMIGui::on_phaseImbalance_valueChanged(int value)
{
ui->phaseImbalanceText->setText(QString(tr("%1 %").arg(value)));
m_settings.m_phaseImbalance = value / 100.0f;
sendSettings();
}
void TestMIGui::on_record_toggled(bool checked)
{
if (checked) {
ui->record->setStyleSheet("QToolButton { background-color : red; }");
} else {
ui->record->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
}
TestMI::MsgFileRecord* message = TestMI::MsgFileRecord::create(checked);
m_sampleMIMO->getInputMessageQueue()->push(message);
}
void TestMIGui::displayAmplitude()
{
int amplitudeInt = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
double power;
switch (ui->sampleSize->currentIndex())
{
case 0: // 8 bits: 128
power = (double) amplitudeInt*amplitudeInt / (double) (1<<14);
break;
case 1: // 12 bits 2048
power = (double) amplitudeInt*amplitudeInt / (double) (1<<22);
break;
case 2: // 16 bits 32768
default:
power = (double) amplitudeInt*amplitudeInt / (double) (1<<30);
break;
}
ui->amplitudeBits->setText(QString(tr("%1 b").arg(amplitudeInt)));
double powerDb = CalcDb::dbPower(power);
ui->power->setText(QString(tr("%1 dB").arg(QString::number(powerDb, 'f', 1))));
}
void TestMIGui::updateAmpCoarseLimit()
{
switch (ui->sampleSize->currentIndex())
{
case 0: // 8 bits: 128
ui->amplitudeCoarse->setMaximum(1);
break;
case 1: // 12 bits 2048
ui->amplitudeCoarse->setMaximum(20);
break;
case 2: // 16 bits 32768
default:
ui->amplitudeCoarse->setMaximum(327);
break;
}
}
void TestMIGui::updateAmpFineLimit()
{
switch (ui->sampleSize->currentIndex())
{
case 0: // 8 bits: 128
if (ui->amplitudeCoarse->value() == 1) {
ui->amplitudeFine->setMaximum(27);
} else {
ui->amplitudeFine->setMaximum(99);
}
break;
case 1: // 12 bits 2048
if (ui->amplitudeCoarse->value() == 20) {
ui->amplitudeFine->setMaximum(47);
} else {
ui->amplitudeFine->setMaximum(99);
}
break;
case 2: // 16 bits 32768
default:
if (ui->amplitudeCoarse->value() == 327) {
ui->amplitudeFine->setMaximum(67);
} else {
ui->amplitudeFine->setMaximum(99);
}
break;
}
}
void TestMIGui::updateFrequencyShiftLimit()
{
int sampleRate = ui->sampleRate->getValueNew();
ui->frequencyShift->setValueRange(false, 7, -sampleRate, sampleRate);
}
void TestMIGui::displaySettings()
{
blockApplySettings(true);
ui->sampleSize->blockSignals(true);
ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
ui->decimation->setCurrentIndex(m_settings.m_log2Decim);
ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos);
ui->sampleRate->setValue(m_settings.m_sampleRate);
updateFrequencyShiftLimit();
ui->frequencyShift->setValue(m_settings.m_frequencyShift);
ui->sampleSize->setCurrentIndex(m_settings.m_sampleSizeIndex);
updateAmpCoarseLimit();
int amplitudeBits = m_settings.m_amplitudeBits;
ui->amplitudeCoarse->setValue(amplitudeBits/100);
updateAmpFineLimit();
ui->amplitudeFine->setValue(amplitudeBits%100);
displayAmplitude();
int dcBiasPercent = roundf(m_settings.m_dcFactor * 100.0f);
ui->dcBias->setValue((int) dcBiasPercent);
ui->dcBiasText->setText(QString(tr("%1 %").arg(dcBiasPercent)));
int iBiasPercent = roundf(m_settings.m_iFactor * 100.0f);
ui->iBias->setValue((int) iBiasPercent);
ui->iBiasText->setText(QString(tr("%1 %").arg(iBiasPercent)));
int qBiasPercent = roundf(m_settings.m_qFactor * 100.0f);
ui->qBias->setValue((int) qBiasPercent);
ui->qBiasText->setText(QString(tr("%1 %").arg(qBiasPercent)));
int phaseImbalancePercent = roundf(m_settings.m_phaseImbalance * 100.0f);
ui->phaseImbalance->setValue((int) phaseImbalancePercent);
ui->phaseImbalanceText->setText(QString(tr("%1 %").arg(phaseImbalancePercent)));
ui->autoCorr->setCurrentIndex(m_settings.m_autoCorrOptions);
ui->sampleSize->blockSignals(false);
ui->modulation->setCurrentIndex((int) m_settings.m_modulation);
ui->modulationFrequency->setValue(m_settings.m_modulationTone);
ui->modulationFrequencyText->setText(QString("%1").arg(m_settings.m_modulationTone / 100.0, 0, 'f', 2));
ui->amModulation->setValue(m_settings.m_amModulation);
ui->amModulationText->setText(QString("%1").arg(m_settings.m_amModulation));
ui->fmDeviation->setValue(m_settings.m_fmDeviation);
ui->fmDeviationText->setText(QString("%1").arg(m_settings.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 (DSPSignalNotification::match(*message))
{
DSPSignalNotification* notif = (DSPSignalNotification*) message;
m_deviceSampleRate = notif->getSampleRate();
m_deviceCenterFrequency = notif->getCenterFrequency();
qDebug("TestMIGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu",
notif->getSampleRate(),
notif->getCenterFrequency());
updateSampleRateAndFrequency();
delete message;
}
else
{
if (handleMessage(*message))
{
delete message;
}
}
}
}
void TestMIGui::updateSampleRateAndFrequency()
{
m_deviceUISet->getSpectrum()->setSampleRate(m_deviceSampleRate);
m_deviceUISet->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency);
ui->deviceRateText->setText(tr("%1k").arg((float)m_deviceSampleRate / 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,106 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef _TESTMI_TESTMIGUI_H_
#define _TESTMI_TESTMIGUI_H_
#include <plugin/plugininstancegui.h>
#include <QTimer>
#include <QWidget>
#include "util/messagequeue.h"
#include "testmisettings.h"
#include "testmi.h"
class DeviceUISet;
namespace Ui {
class TestMIGui;
}
class TestMIGui : public QWidget, public PluginInstanceGUI {
Q_OBJECT
public:
explicit TestMIGui(DeviceUISet *deviceUISet, QWidget* parent = 0);
virtual ~TestMIGui();
virtual void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
virtual qint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message);
private:
Ui::TestMIGui* ui;
DeviceUISet* m_deviceUISet;
TestMISettings m_settings;
QTimer m_updateTimer;
QTimer m_statusTimer;
bool m_doApplySettings;
bool m_forceSettings;
DeviceSampleMIMO* m_sampleMIMO;
std::size_t m_tickCount;
int m_deviceSampleRate;
quint64 m_deviceCenterFrequency; //!< 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();
private slots:
void handleInputMessages();
void on_startStop_toggled(bool checked);
void on_centerFrequency_changed(quint64 value);
void on_autoCorr_currentIndexChanged(int index);
void on_frequencyShift_changed(qint64 value);
void on_decimation_currentIndexChanged(int index);
void on_fcPos_currentIndexChanged(int index);
void on_sampleRate_changed(quint64 value);
void on_sampleSize_currentIndexChanged(int index);
void on_amplitudeCoarse_valueChanged(int value);
void on_amplitudeFine_valueChanged(int value);
void on_modulation_currentIndexChanged(int index);
void on_modulationFrequency_valueChanged(int value);
void on_amModulation_valueChanged(int value);
void on_fmDeviation_valueChanged(int value);
void on_dcBias_valueChanged(int value);
void on_iBias_valueChanged(int value);
void on_qBias_valueChanged(int value);
void on_phaseImbalance_valueChanged(int value);
void on_record_toggled(bool checked);
void openDeviceSettingsDialog(const QPoint& p);
void updateStatus();
void updateHardware();
};
#endif // _TESTMI_TESTMIGUI_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
const PluginDescriptor TestMIPlugin::m_pluginDescriptor = {
QString("Test Multiple Input"),
QString("4.8.1"),
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);
}
PluginInterface::SamplingDevices TestMIPlugin::enumSampleMIMO()
{
SamplingDevices result;
result.append(SamplingDevice(
"TestMI",
m_hardwareID,
m_deviceTypeID,
QString::null,
0,
PluginInterface::SamplingDevice::BuiltInDevice,
PluginInterface::SamplingDevice::StreamAny,
1,
0));
return result;
}
#ifdef SERVER_MODE
PluginInstanceGUI* TestMIPlugin::createSampleMIMOPluginInstanceGUI(
const QString& sourceId __attribute((unused)),
QWidget **widget __attribute((unused)),
DeviceUISet *deviceUISet __attribute((unused)))
{
return 0;
}
#else
PluginInstanceGUI* TestMIPlugin::createSampleMIMOPluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
if(sourceId == m_deviceTypeID) {
TestMIGui* gui = new TestMIGui(deviceUISet);
*widget = gui;
return gui;
} else {
return 0;
}
}
#endif
DeviceSampleMIMO *TestMIPlugin::createSampleMIMOPluginInstanceMIMO(const QString& mimoId, DeviceAPI *deviceAPI)
{
if (mimoId == m_deviceTypeID)
{
TestMI* input = new TestMI(deviceAPI);
return input;
}
else
{
return nullptr;
}
}

View File

@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 SamplingDevices enumSampleMIMO();
virtual PluginInstanceGUI* createSampleMIMOPluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet);
virtual DeviceSampleMIMO* createSampleMIMOPluginInstanceMIMO(const QString& sourceId, DeviceAPI *deviceAPI);
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,150 @@
///////////////////////////////////////////////////////////////////////////////////
// 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"
TestMISettings::TestMISettings()
{
resetToDefaults();
}
void TestMISettings::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;
m_fileRecordName = "";
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0;
}
QByteArray TestMISettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(2, m_frequencyShift);
s.writeU32(3, m_sampleRate);
s.writeU32(4, m_log2Decim);
s.writeS32(5, (int) m_fcPos);
s.writeU32(6, m_sampleSizeIndex);
s.writeS32(7, m_amplitudeBits);
s.writeS32(8, (int) m_autoCorrOptions);
s.writeFloat(10, m_dcFactor);
s.writeFloat(11, m_iFactor);
s.writeFloat(12, m_qFactor);
s.writeFloat(13, m_phaseImbalance);
s.writeS32(14, (int) m_modulation);
s.writeS32(15, m_modulationTone);
s.writeS32(16, m_amModulation);
s.writeS32(17, m_fmDeviation);
s.writeBool(18, m_useReverseAPI);
s.writeString(19, m_reverseAPIAddress);
s.writeU32(20, m_reverseAPIPort);
s.writeU32(21, m_reverseAPIDeviceIndex);
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.readS32(2, &m_frequencyShift, 0);
d.readU32(3, &m_sampleRate, 768*1000);
d.readU32(4, &m_log2Decim, 4);
d.readS32(5, &intval, 0);
m_fcPos = (fcPos_t) intval;
d.readU32(6, &m_sampleSizeIndex, 0);
d.readS32(7, &m_amplitudeBits, 128);
d.readS32(8, &intval, 0);
if (intval < 0 || intval > (int) AutoCorrLast) {
m_autoCorrOptions = AutoCorrNone;
} else {
m_autoCorrOptions = (AutoCorrOptions) intval;
}
d.readFloat(10, &m_dcFactor, 0.0f);
d.readFloat(11, &m_iFactor, 0.0f);
d.readFloat(12, &m_qFactor, 0.0f);
d.readFloat(13, &m_phaseImbalance, 0.0f);
d.readS32(14, &intval, 0);
if (intval < 0 || intval > (int) ModulationLast) {
m_modulation = ModulationNone;
} else {
m_modulation = (Modulation) intval;
}
d.readS32(15, &m_modulationTone, 44);
d.readS32(16, &m_amModulation, 50);
d.readS32(17, &m_fmDeviation, 50);
d.readBool(18, &m_useReverseAPI, false);
d.readString(19, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(20, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(21, &utmp, 0);
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,79 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 TestMISettings {
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
QString m_fileRecordName;
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
TestMISettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* _TESTMI_TESTMISETTINGS_H_ */

View File

@ -0,0 +1,449 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdio.h>
#include <errno.h>
#include "dsp/samplesinkfifo.h"
#include "testmithread.h"
#define TESTMI_BLOCKSIZE 16384
MESSAGE_CLASS_DEFINITION(TestMIThread::MsgStartStop, Message)
TestMIThread::TestMIThread(SampleSinkFifo* sampleFifo, QObject* parent) :
QThread(parent),
m_running(false),
m_buf(0),
m_bufsize(0),
m_chunksize(0),
m_convertBuffer(TESTMI_BLOCKSIZE),
m_sampleFifo(sampleFifo),
m_frequencyShift(0),
m_toneFrequency(440),
m_modulation(TestMISettings::ModulationNone),
m_amModulation(0.5f),
m_fmDeviationUnit(0.0f),
m_fmPhasor(0.0f),
m_pulseWidth(150),
m_pulseSampleCount(0),
m_pulsePatternCount(0),
m_pulsePatternCycle(8),
m_pulsePatternPlaces(3),
m_samplerate(48000),
m_log2Decim(4),
m_fcPos(0),
m_bitSizeIndex(0),
m_bitShift(8),
m_amplitudeBits(127),
m_dcBias(0.0f),
m_iBias(0.0f),
m_qBias(0.0f),
m_phaseImbalance(0.0f),
m_amplitudeBitsDC(0),
m_amplitudeBitsI(127),
m_amplitudeBitsQ(127),
m_frequency(435*1000),
m_fcPosShift(0),
m_throttlems(TESTMI_THROTTLE_MS),
m_throttleToggle(false),
m_mutex(QMutex::Recursive)
{
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
}
TestMIThread::~TestMIThread()
{
}
void TestMIThread::startWork()
{
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
m_timer.start(50);
m_startWaitMutex.lock();
m_elapsedTimer.start();
start();
while(!m_running)
m_startWaiter.wait(&m_startWaitMutex, 100);
m_startWaitMutex.unlock();
}
void TestMIThread::stopWork()
{
m_running = false;
wait();
m_timer.stop();
disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
}
void TestMIThread::setSamplerate(int samplerate)
{
QMutexLocker mutexLocker(&m_mutex);
m_samplerate = samplerate;
m_chunksize = 4 * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000);
m_throttleToggle = !m_throttleToggle;
m_nco.setFreq(m_frequencyShift, m_samplerate);
m_toneNco.setFreq(m_toneFrequency, m_samplerate);
}
void TestMIThread::setLog2Decimation(unsigned int log2_decim)
{
m_log2Decim = log2_decim;
}
void TestMIThread::setFcPos(int fcPos)
{
m_fcPos = fcPos;
}
void TestMIThread::setBitSize(quint32 bitSizeIndex)
{
switch (bitSizeIndex)
{
case 0:
m_bitShift = 7;
m_bitSizeIndex = 0;
break;
case 1:
m_bitShift = 11;
m_bitSizeIndex = 1;
break;
case 2:
default:
m_bitShift = 15;
m_bitSizeIndex = 2;
break;
}
}
void TestMIThread::setAmplitudeBits(int32_t amplitudeBits)
{
m_amplitudeBits = amplitudeBits;
m_amplitudeBitsDC = m_dcBias * amplitudeBits;
m_amplitudeBitsI = (1.0f + m_iBias) * amplitudeBits;
m_amplitudeBitsQ = (1.0f + m_qBias) * amplitudeBits;
}
void TestMIThread::setDCFactor(float dcFactor)
{
m_dcBias = dcFactor;
m_amplitudeBitsDC = m_dcBias * m_amplitudeBits;
}
void TestMIThread::setIFactor(float iFactor)
{
m_iBias = iFactor;
m_amplitudeBitsI = (1.0f + m_iBias) * m_amplitudeBits;
}
void TestMIThread::setQFactor(float iFactor)
{
m_qBias = iFactor;
m_amplitudeBitsQ = (1.0f + m_qBias) * m_amplitudeBits;
}
void TestMIThread::setPhaseImbalance(float phaseImbalance)
{
m_phaseImbalance = phaseImbalance;
}
void TestMIThread::setFrequencyShift(int shift)
{
m_nco.setFreq(shift, m_samplerate);
}
void TestMIThread::setToneFrequency(int toneFrequency)
{
m_toneNco.setFreq(toneFrequency, m_samplerate);
}
void TestMIThread::setModulation(TestMISettings::Modulation modulation)
{
m_modulation = modulation;
}
void TestMIThread::setAMModulation(float amModulation)
{
m_amModulation = amModulation < 0.0f ? 0.0f : amModulation > 1.0f ? 1.0f : amModulation;
}
void TestMIThread::setFMDeviation(float deviation)
{
float fmDeviationUnit = deviation / (float) m_samplerate;
m_fmDeviationUnit = fmDeviationUnit < 0.0f ? 0.0f : fmDeviationUnit > 0.5f ? 0.5f : fmDeviationUnit;
qDebug("TestMIThread::setFMDeviation: m_fmDeviationUnit: %f", m_fmDeviationUnit);
}
void TestMIThread::startStop(bool start)
{
MsgStartStop *msg = MsgStartStop::create(start);
m_inputMessageQueue.push(msg);
}
void TestMIThread::run()
{
m_running = true;
m_startWaiter.wakeAll();
while (m_running) // actual work is in the tick() function
{
sleep(1);
}
m_running = false;
}
void TestMIThread::setBuffers(quint32 chunksize)
{
if (chunksize > m_bufsize)
{
m_bufsize = chunksize;
if (m_buf == 0)
{
qDebug() << "TestMIThread::setBuffer: Allocate buffer: "
<< " size: " << m_bufsize << " bytes"
<< " #samples: " << (m_bufsize/4);
m_buf = (qint16*) malloc(m_bufsize);
}
else
{
qDebug() << "TestMIThread::setBuffer: Re-allocate buffer: "
<< " size: " << m_bufsize << " bytes"
<< " #samples: " << (m_bufsize/4);
free(m_buf);
m_buf = (qint16*) malloc(m_bufsize);
}
m_convertBuffer.resize(chunksize/4);
}
}
void TestMIThread::generate(quint32 chunksize)
{
int n = chunksize / 2;
setBuffers(chunksize);
for (int i = 0; i < n-1;)
{
switch (m_modulation)
{
case TestMISettings::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 TestMISettings::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 TestMISettings::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 TestMISettings::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 TestMISettings::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 TestMISettings::ModulationNone:
default:
{
Complex c = m_nco.nextIQ(m_phaseImbalance);
m_buf[i++] = (int16_t) (c.real() * (float) m_amplitudeBitsI) + m_amplitudeBitsDC;
m_buf[i++] = (int16_t) (c.imag() * (float) m_amplitudeBitsQ);
}
break;
}
}
callback(m_buf, n);
}
void TestMIThread::pullAF(Real& afSample)
{
afSample = m_toneNco.next();
}
// call appropriate conversion (decimation) routine depending on the number of sample bits
void TestMIThread::callback(const qint16* buf, qint32 len)
{
SampleVector::iterator it = m_convertBuffer.begin();
switch (m_bitSizeIndex)
{
case 0: // 8 bit samples
convert_8(&it, buf, len);
break;
case 1: // 12 bit samples
convert_12(&it, buf, len);
break;
case 2: // 16 bit samples
default:
convert_16(&it, buf, len);
break;
}
m_sampleFifo->write(m_convertBuffer.begin(), it);
}
void TestMIThread::tick()
{
if (m_running)
{
qint64 throttlems = m_elapsedTimer.restart();
if ((throttlems > 45) && (throttlems < 55) && (throttlems != m_throttlems))
{
QMutexLocker mutexLocker(&m_mutex);
m_throttlems = throttlems;
m_chunksize = 4 * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000);
m_throttleToggle = !m_throttleToggle;
}
generate(m_chunksize);
}
}
void TestMIThread::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
if (MsgStartStop::match(*message))
{
MsgStartStop* notif = (MsgStartStop*) message;
qDebug("TestMIThread::handleInputMessages: MsgStartStop: %s", notif->getStartStop() ? "start" : "stop");
if (notif->getStartStop()) {
startWork();
} else {
stopWork();
}
delete message;
}
}
}
void TestMIThread::setPattern0()
{
m_pulseWidth = 150;
m_pulseSampleCount = 0;
m_pulsePatternCount = 0;
m_pulsePatternCycle = 8;
m_pulsePatternPlaces = 3;
}
void TestMIThread::setPattern1()
{
m_pulseWidth = 1000;
m_pulseSampleCount = 0;
}
void TestMIThread::setPattern2()
{
m_pulseWidth = 1000;
m_pulseSampleCount = 0;
}

View File

@ -0,0 +1,385 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef _TESTMI_TESTMITHREAD_H_
#define _TESTMI_TESTMITHREAD_H_
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QTimer>
#include <QElapsedTimer>
#include <QDebug>
#include "dsp/samplesinkfifo.h"
#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 TestMIThread : public QThread {
Q_OBJECT
public:
class MsgStartStop : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgStartStop* create(bool startStop) {
return new MsgStartStop(startStop);
}
protected:
bool m_startStop;
MsgStartStop(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
TestMIThread(SampleSinkFifo* sampleFifo, QObject* parent = 0);
~TestMIThread();
void startStop(bool start);
void setSamplerate(int samplerate);
void setLog2Decimation(unsigned int log2_decim);
void setFcPos(int fcPos);
void setBitSize(uint32_t bitSizeIndex);
void setAmplitudeBits(int32_t amplitudeBits);
void setDCFactor(float iFactor);
void setIFactor(float iFactor);
void setQFactor(float qFactor);
void setPhaseImbalance(float phaseImbalance);
void setFrequencyShift(int shift);
void setToneFrequency(int toneFrequency);
void setModulation(TestMISettings::Modulation modulation);
void setAMModulation(float amModulation);
void setFMDeviation(float deviation);
void setPattern0();
void setPattern1();
void setPattern2();
private:
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
volatile bool m_running;
qint16 *m_buf;
quint32 m_bufsize;
quint32 m_chunksize;
SampleVector m_convertBuffer;
SampleSinkFifo* m_sampleFifo;
NCOF m_nco;
NCOF m_toneNco;
int m_frequencyShift;
int m_toneFrequency;
TestMISettings::Modulation m_modulation;
float m_amModulation;
float m_fmDeviationUnit;
float m_fmPhasor;
uint32_t m_pulseWidth; //!< pulse width in number of samples
uint32_t m_pulseSampleCount;
uint32_t m_pulsePatternCount;
uint32_t m_pulsePatternCycle;
uint32_t m_pulsePatternPlaces;
int m_samplerate;
unsigned int m_log2Decim;
int m_fcPos;
uint32_t m_bitSizeIndex;
uint32_t m_bitShift;
int32_t m_amplitudeBits;
float m_dcBias;
float m_iBias;
float m_qBias;
float m_phaseImbalance;
int32_t m_amplitudeBitsDC;
int32_t m_amplitudeBitsI;
int32_t m_amplitudeBitsQ;
uint64_t m_frequency;
int m_fcPosShift;
int m_throttlems;
QTimer m_timer;
QElapsedTimer m_elapsedTimer;
bool m_throttleToggle;
QMutex m_mutex;
MessageQueue m_inputMessageQueue;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 8> m_decimators_8;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12> m_decimators_12;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators_16;
void startWork();
void stopWork();
void run();
void callback(const qint16* buf, qint32 len);
void setBuffers(quint32 chunksize);
void generate(quint32 chunksize);
void pullAF(Real& afSample);
// Decimate according to specified log2 (ex: log2=4 => decim=16)
inline void convert_8(SampleVector::iterator* it, const qint16* buf, qint32 len)
{
if (m_log2Decim == 0) {
m_decimators_8.decimate1(it, buf, len);
} else {
if (m_fcPos == 0) { // Infradyne
switch (m_log2Decim) {
case 1:
m_decimators_8.decimate2_inf(it, buf, len);
break;
case 2:
m_decimators_8.decimate4_inf(it, buf, len);
break;
case 3:
m_decimators_8.decimate8_inf(it, buf, len);
break;
case 4:
m_decimators_8.decimate16_inf(it, buf, len);
break;
case 5:
m_decimators_8.decimate32_inf(it, buf, len);
break;
case 6:
m_decimators_8.decimate64_inf(it, buf, len);
break;
default:
break;
}
} else if (m_fcPos == 1) {// Supradyne
switch (m_log2Decim) {
case 1:
m_decimators_8.decimate2_sup(it, buf, len);
break;
case 2:
m_decimators_8.decimate4_sup(it, buf, len);
break;
case 3:
m_decimators_8.decimate8_sup(it, buf, len);
break;
case 4:
m_decimators_8.decimate16_sup(it, buf, len);
break;
case 5:
m_decimators_8.decimate32_sup(it, buf, len);
break;
case 6:
m_decimators_8.decimate64_sup(it, buf, len);
break;
default:
break;
}
} else { // Centered
switch (m_log2Decim) {
case 1:
m_decimators_8.decimate2_cen(it, buf, len);
break;
case 2:
m_decimators_8.decimate4_cen(it, buf, len);
break;
case 3:
m_decimators_8.decimate8_cen(it, buf, len);
break;
case 4:
m_decimators_8.decimate16_cen(it, buf, len);
break;
case 5:
m_decimators_8.decimate32_cen(it, buf, len);
break;
case 6:
m_decimators_8.decimate64_cen(it, buf, len);
break;
default:
break;
}
}
}
}
void convert_12(SampleVector::iterator* it, const qint16* buf, qint32 len)
{
if (m_log2Decim == 0) {
m_decimators_12.decimate1(it, buf, len);
} else {
if (m_fcPos == 0) { // Infradyne
switch (m_log2Decim) {
case 1:
m_decimators_12.decimate2_inf(it, buf, len);
break;
case 2:
m_decimators_12.decimate4_inf(it, buf, len);
break;
case 3:
m_decimators_12.decimate8_inf(it, buf, len);
break;
case 4:
m_decimators_12.decimate16_inf(it, buf, len);
break;
case 5:
m_decimators_12.decimate32_inf(it, buf, len);
break;
case 6:
m_decimators_12.decimate64_inf(it, buf, len);
break;
default:
break;
}
} else if (m_fcPos == 1) {// Supradyne
switch (m_log2Decim) {
case 1:
m_decimators_12.decimate2_sup(it, buf, len);
break;
case 2:
m_decimators_12.decimate4_sup(it, buf, len);
break;
case 3:
m_decimators_12.decimate8_sup(it, buf, len);
break;
case 4:
m_decimators_12.decimate16_sup(it, buf, len);
break;
case 5:
m_decimators_12.decimate32_sup(it, buf, len);
break;
case 6:
m_decimators_12.decimate64_sup(it, buf, len);
break;
default:
break;
}
} else { // Centered
switch (m_log2Decim) {
case 1:
m_decimators_12.decimate2_cen(it, buf, len);
break;
case 2:
m_decimators_12.decimate4_cen(it, buf, len);
break;
case 3:
m_decimators_12.decimate8_cen(it, buf, len);
break;
case 4:
m_decimators_12.decimate16_cen(it, buf, len);
break;
case 5:
m_decimators_12.decimate32_cen(it, buf, len);
break;
case 6:
m_decimators_12.decimate64_cen(it, buf, len);
break;
default:
break;
}
}
}
}
void convert_16(SampleVector::iterator* it, const qint16* buf, qint32 len)
{
if (m_log2Decim == 0) {
m_decimators_16.decimate1(it, buf, len);
} else {
if (m_fcPos == 0) { // Infradyne
switch (m_log2Decim) {
case 1:
m_decimators_16.decimate2_inf(it, buf, len);
break;
case 2:
m_decimators_16.decimate4_inf(it, buf, len);
break;
case 3:
m_decimators_16.decimate8_inf(it, buf, len);
break;
case 4:
m_decimators_16.decimate16_inf(it, buf, len);
break;
case 5:
m_decimators_16.decimate32_inf(it, buf, len);
break;
case 6:
m_decimators_16.decimate64_inf(it, buf, len);
break;
default:
break;
}
} else if (m_fcPos == 1) {// Supradyne
switch (m_log2Decim) {
case 1:
m_decimators_16.decimate2_sup(it, buf, len);
break;
case 2:
m_decimators_16.decimate4_sup(it, buf, len);
break;
case 3:
m_decimators_16.decimate8_sup(it, buf, len);
break;
case 4:
m_decimators_16.decimate16_sup(it, buf, len);
break;
case 5:
m_decimators_16.decimate32_sup(it, buf, len);
break;
case 6:
m_decimators_16.decimate64_sup(it, buf, len);
break;
default:
break;
}
} else { // Centered
switch (m_log2Decim) {
case 1:
m_decimators_16.decimate2_cen(it, buf, len);
break;
case 2:
m_decimators_16.decimate4_cen(it, buf, len);
break;
case 3:
m_decimators_16.decimate8_cen(it, buf, len);
break;
case 4:
m_decimators_16.decimate16_cen(it, buf, len);
break;
case 5:
m_decimators_16.decimate32_cen(it, buf, len);
break;
case 6:
m_decimators_16.decimate64_cen(it, buf, len);
break;
default:
break;
}
}
}
}
private slots:
void tick();
void handleInputMessages();
};
#endif // _TESTSOURCE_TESTSOURCETHREAD_H_

View File

@ -0,0 +1,48 @@
#--------------------------------------------------------
#
# Pro file for Android and Windows builds with Qt Creator
#
#--------------------------------------------------------
TEMPLATE = lib
CONFIG += plugin
QT += core gui widgets multimedia opengl
TARGET = mimotestsourcemi
DEFINES += USE_SSE2=1
QMAKE_CXXFLAGS += -msse2
DEFINES += USE_SSE4_1=1
QMAKE_CXXFLAGS += -msse4.1
QMAKE_CXXFLAGS += -std=c++11
macx:QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
INCLUDEPATH += ../../../sdrgui
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
CONFIG(Release):build_subdir = release
CONFIG(Debug):build_subdir = debug
SOURCES += testsourcegui.cpp\
testsourcemiinput.cpp\
testsourcemiplugin.cpp\
testsourcemisettings.cpp\
testsourcemithread.cpp
HEADERS += testsourcemigui.h\
testsourcemiinput.h\
testsourcemiplugin.h\
testsourcemisettings.h\
testsourcemithread.h
FORMS += testsourcemigui.ui
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
LIBS += -L../../../swagger/$${build_subdir} -lswagger
RESOURCES = ../../../sdrgui/resources/res.qrc

View File

@ -19,9 +19,11 @@
#include "plugin/plugininterface.h"
#include "dsp/dspdevicesourceengine.h"
#include "dsp/dspdevicesinkengine.h"
#include "dsp/dspdevicemimoengine.h"
#include "dsp/dspengine.h"
#include "dsp/devicesamplesource.h"
#include "dsp/devicesamplesink.h"
#include "dsp/devicesamplemimo.h"
#include "settings/preset.h"
#include "channel/channelapi.h"
@ -31,7 +33,8 @@ DeviceAPI::DeviceAPI(
StreamType streamType,
int deviceTabIndex,
DSPDeviceSourceEngine *deviceSourceEngine,
DSPDeviceSinkEngine *deviceSinkEngine
DSPDeviceSinkEngine *deviceSinkEngine,
DSPDeviceMIMOEngine *deviceMIMOEngine
) :
m_streamType(streamType),
m_deviceTabIndex(deviceTabIndex),
@ -44,7 +47,8 @@ DeviceAPI::DeviceAPI(
m_buddySharedPtr(0),
m_isBuddyLeader(false),
m_deviceSourceEngine(deviceSourceEngine),
m_deviceSinkEngine(deviceSinkEngine)
m_deviceSinkEngine(deviceSinkEngine),
m_deviceMIMOEngine(deviceMIMOEngine)
{
}
@ -156,6 +160,13 @@ void DeviceAPI::setSampleSink(DeviceSampleSink* sink)
}
}
void DeviceAPI::setSampleMIMO(DeviceSampleMIMO* mimo)
{
if (m_deviceMIMOEngine) {
m_deviceMIMOEngine->setMIMO(mimo);
}
}
DeviceSampleSource *DeviceAPI::getSampleSource()
{
if (m_deviceSourceEngine) {
@ -174,14 +185,25 @@ DeviceSampleSink *DeviceAPI::getSampleSink()
}
}
DeviceSampleMIMO *DeviceAPI::getSampleMIMO()
{
if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->getMIMO();
} else {
return nullptr;
}
}
bool DeviceAPI::initDeviceEngine()
{
if (m_deviceSourceEngine) {
return m_deviceSourceEngine->initAcquisition();
} else if (m_deviceSinkEngine) {
return m_deviceSinkEngine->initGeneration();
} else if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->initProcess();
} else {
return false; // TODO: not implemented
return false;
}
}
@ -191,8 +213,10 @@ bool DeviceAPI::startDeviceEngine()
return m_deviceSourceEngine->startAcquisition();
} else if (m_deviceSinkEngine) {
return m_deviceSinkEngine->startGeneration();
} else if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->startProcess();
} else {
return false; // TODO: not implemented
return false;
}
}
@ -202,6 +226,8 @@ void DeviceAPI::stopDeviceEngine()
m_deviceSourceEngine->stopAcquistion();
} else if (m_deviceSinkEngine) {
m_deviceSinkEngine->stopGeneration();
} else if (m_deviceMIMOEngine) {
m_deviceMIMOEngine->stopProcess();
}
}
@ -211,8 +237,10 @@ DeviceAPI::EngineState DeviceAPI::state() const
return (DeviceAPI::EngineState) m_deviceSourceEngine->state();
} else if (m_deviceSinkEngine) {
return (DeviceAPI::EngineState) m_deviceSinkEngine->state();
} else if (m_deviceMIMOEngine) {
return (DeviceAPI::EngineState) m_deviceMIMOEngine->state();
} else {
return StError; // TODO: not implemented
return StError;
}
}
@ -222,8 +250,10 @@ QString DeviceAPI::errorMessage()
return m_deviceSourceEngine->errorMessage();
} else if (m_deviceSinkEngine) {
return m_deviceSinkEngine->errorMessage();
} else if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->errorMessage();
} else {
return "Not implemented"; // TODO: not implemented
return "Not implemented";
}
}
@ -233,8 +263,10 @@ uint DeviceAPI::getDeviceUID() const
return m_deviceSourceEngine->getUID();
} else if (m_deviceSinkEngine) {
return m_deviceSinkEngine->getUID();
} else if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->getUID();
} else {
return 0; // TODO: not implemented
return 0;
}
}
@ -244,8 +276,10 @@ MessageQueue *DeviceAPI::getDeviceEngineInputMessageQueue()
return m_deviceSourceEngine->getInputMessageQueue();
} else if (m_deviceSinkEngine) {
return m_deviceSinkEngine->getInputMessageQueue();
} else if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->getInputMessageQueue();
} else {
return nullptr; // TODO: not implemented
return nullptr;
}
}
@ -255,8 +289,10 @@ MessageQueue *DeviceAPI::getSamplingDeviceInputMessageQueue()
return m_deviceSourceEngine->getSource()->getInputMessageQueue();
} else if (m_deviceSinkEngine) {
return m_deviceSinkEngine->getSink()->getInputMessageQueue();
} else if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->getMIMO()->getInputMessageQueue();
} else {
return nullptr; // TODO: not implemented
return nullptr;
}
}
@ -266,17 +302,19 @@ MessageQueue *DeviceAPI::getSamplingDeviceGUIMessageQueue()
return m_deviceSourceEngine->getSource()->getMessageQueueToGUI();
} else if (m_deviceSinkEngine) {
return m_deviceSinkEngine->getSink()->getMessageQueueToGUI();
} else if (m_deviceMIMOEngine) {
return m_deviceMIMOEngine->getMIMO()->getMessageQueueToGUI();
} else {
return nullptr; // TODO: not implemented
return nullptr;
}
}
void DeviceAPI::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int streamIndex)
{
(void) streamIndex;
if (m_deviceSourceEngine) {
m_deviceSourceEngine->configureCorrections(dcOffsetCorrection, iqImbalanceCorrection);
} else if (m_deviceMIMOEngine) {
m_deviceMIMOEngine->configureCorrections(dcOffsetCorrection, iqImbalanceCorrection, streamIndex);
}
}

View File

@ -30,11 +30,13 @@ class ThreadedBasebandSampleSource;
class ChannelAPI;
class DeviceSampleSink;
class DeviceSampleSource;
class DeviceSampleMIMO;
class MessageQueue;
class PluginInterface;
class PluginInstanceGUI;
class DSPDeviceSourceEngine;
class DSPDeviceSinkEngine;
class DSPDeviceMIMOEngine;
class Preset;
class SDRBASE_API DeviceAPI : public QObject {
@ -59,7 +61,8 @@ public:
StreamType streamType,
int deviceTabIndex,
DSPDeviceSourceEngine *deviceSourceEngine,
DSPDeviceSinkEngine *deviceSinkEngine
DSPDeviceSinkEngine *deviceSinkEngine,
DSPDeviceMIMOEngine *deviceMIMOEngine
);
~DeviceAPI();
@ -78,8 +81,10 @@ public:
void setSampleSource(DeviceSampleSource* source); //!< Set the device sample source (single Rx)
void setSampleSink(DeviceSampleSink* sink); //!< Set the device sample sink (single Tx)
void setSampleMIMO(DeviceSampleMIMO* mimo); //!< Set the device sample MIMO
DeviceSampleSource *getSampleSource(); //!< Return pointer to the device sample source (single Rx) or nullptr
DeviceSampleSink *getSampleSink(); //!< Return pointer to the device sample sink (single Tx) or nullptr
DeviceSampleMIMO *getSampleMIMO(); //!< Return pointer to the device sample MIMO or nullptr
bool initDeviceEngine(); //!< Init the device engine corresponding to the stream type
bool startDeviceEngine(); //!< Start the device engine corresponding to the stream type
@ -211,6 +216,10 @@ protected:
DSPDeviceSinkEngine *m_deviceSinkEngine;
QList<ChannelAPI*> m_channelSourceAPIs;
// MIMO
DSPDeviceMIMOEngine *m_deviceMIMOEngine;
private:
void renumerateChannels();
};

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2016-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 //
@ -80,6 +80,30 @@ void DeviceEnumerator::enumerateTxDevices(PluginManager *pluginManager)
}
}
void DeviceEnumerator::enumerateMIMODevices(PluginManager *pluginManager)
{
m_mimoEnumeration.clear();
PluginAPI::SamplingDeviceRegistrations& mimoDeviceRegistrations = pluginManager->getMIMODeviceRegistrations();
int index = 0;
for (int i = 0; i < mimoDeviceRegistrations.count(); i++)
{
PluginInterface::SamplingDevices samplingDevices = mimoDeviceRegistrations[i].m_plugin->enumSampleMIMO();
for (int j = 0; j < samplingDevices.count(); j++)
{
m_mimoEnumeration.push_back(
DeviceEnumeration(
samplingDevices[j],
mimoDeviceRegistrations[i].m_plugin,
index
)
);
index++;
}
}
}
void DeviceEnumerator::listRxDeviceNames(QList<QString>& list, std::vector<int>& indexes) const
{
for (DevicesEnumeration::const_iterator it = m_rxEnumeration.begin(); it != m_rxEnumeration.end(); ++it)
@ -104,6 +128,18 @@ void DeviceEnumerator::listTxDeviceNames(QList<QString>& list, std::vector<int>&
}
}
void DeviceEnumerator::listMIMODeviceNames(QList<QString>& list, std::vector<int>& indexes) const
{
for (DevicesEnumeration::const_iterator it = m_mimoEnumeration.begin(); it != m_mimoEnumeration.end(); ++it)
{
if ((it->m_samplingDevice.claimed < 0) || (it->m_samplingDevice.type == PluginInterface::SamplingDevice::BuiltInDevice))
{
list.append(it->m_samplingDevice.displayedName);
indexes.push_back(it->m_index);
}
}
}
void DeviceEnumerator::changeRxSelection(int tabIndex, int deviceIndex)
{
for (DevicesEnumeration::iterator it = m_rxEnumeration.begin(); it != m_rxEnumeration.end(); ++it)
@ -130,6 +166,19 @@ void DeviceEnumerator::changeTxSelection(int tabIndex, int deviceIndex)
}
}
void DeviceEnumerator::changeMIMOSelection(int tabIndex, int deviceIndex)
{
for (DevicesEnumeration::iterator it = m_mimoEnumeration.begin(); it != m_mimoEnumeration.end(); ++it)
{
if (it->m_samplingDevice.claimed == tabIndex) {
it->m_samplingDevice.claimed = -1;
}
if (it->m_index == deviceIndex) {
it->m_samplingDevice.claimed = tabIndex;
}
}
}
void DeviceEnumerator::removeRxSelection(int tabIndex)
{
for (DevicesEnumeration::iterator it = m_rxEnumeration.begin(); it != m_rxEnumeration.end(); ++it)
@ -150,6 +199,16 @@ void DeviceEnumerator::removeTxSelection(int tabIndex)
}
}
void DeviceEnumerator::removeMIMOSelection(int tabIndex)
{
for (DevicesEnumeration::iterator it = m_mimoEnumeration.begin(); it != m_mimoEnumeration.end(); ++it)
{
if (it->m_samplingDevice.claimed == tabIndex) {
it->m_samplingDevice.claimed = -1;
}
}
}
int DeviceEnumerator::getFileSourceDeviceIndex() const
{
for (DevicesEnumeration::const_iterator it = m_rxEnumeration.begin(); it != m_rxEnumeration.end(); ++it)
@ -198,3 +257,14 @@ int DeviceEnumerator::getTxSamplingDeviceIndex(const QString& deviceId, int sequ
return -1;
}
int DeviceEnumerator::getMIMOSamplingDeviceIndex(const QString& deviceId, int sequence)
{
for (DevicesEnumeration::iterator it = m_mimoEnumeration.begin(); it != m_mimoEnumeration.end(); ++it)
{
if ((it->m_samplingDevice.id == deviceId) && (it->m_samplingDevice.sequence == sequence)) {
return it->m_index;
}
}
return -1;
}

View File

@ -35,22 +35,30 @@ public:
void enumerateRxDevices(PluginManager *pluginManager);
void enumerateTxDevices(PluginManager *pluginManager);
void enumerateMIMODevices(PluginManager *pluginManager);
void listRxDeviceNames(QList<QString>& list, std::vector<int>& indexes) const;
void listTxDeviceNames(QList<QString>& list, std::vector<int>& indexes) const;
void listMIMODeviceNames(QList<QString>& list, std::vector<int>& indexes) const;
void changeRxSelection(int tabIndex, int deviceIndex);
void changeTxSelection(int tabIndex, int deviceIndex);
void changeMIMOSelection(int tabIndex, int deviceIndex);
void removeRxSelection(int tabIndex);
void removeTxSelection(int tabIndex);
void removeMIMOSelection(int tabIndex);
int getNbRxSamplingDevices() const { return m_rxEnumeration.size(); }
int getNbTxSamplingDevices() const { return m_txEnumeration.size(); }
int getNbMIMOSamplingDevices() const { return m_mimoEnumeration.size(); }
const PluginInterface::SamplingDevice* getRxSamplingDevice(int deviceIndex) const { return &m_rxEnumeration[deviceIndex].m_samplingDevice; }
const PluginInterface::SamplingDevice* getTxSamplingDevice(int deviceIndex) const { return &m_txEnumeration[deviceIndex].m_samplingDevice; }
const PluginInterface::SamplingDevice* getMIMOSamplingDevice(int deviceIndex) const { return &m_mimoEnumeration[deviceIndex].m_samplingDevice; }
PluginInterface *getRxPluginInterface(int deviceIndex) { return m_rxEnumeration[deviceIndex].m_pluginInterface; }
PluginInterface *getTxPluginInterface(int deviceIndex) { return m_txEnumeration[deviceIndex].m_pluginInterface; }
PluginInterface *getMIMOPluginInterface(int deviceIndex) { return m_mimoEnumeration[deviceIndex].m_pluginInterface; }
int getFileSourceDeviceIndex() const;
int getFileSinkDeviceIndex() const;
int getRxSamplingDeviceIndex(const QString& deviceId, int sequence);
int getTxSamplingDeviceIndex(const QString& deviceId, int sequence);
int getMIMOSamplingDeviceIndex(const QString& deviceId, int sequence);
private:
struct DeviceEnumeration
@ -70,6 +78,7 @@ private:
DevicesEnumeration m_rxEnumeration;
DevicesEnumeration m_txEnumeration;
DevicesEnumeration m_mimoEnumeration;
};
#endif /* SDRBASE_DEVICE_DEVICEENUMERATOR_H_ */

View File

@ -43,18 +43,18 @@ void DeviceSampleMIMO::handleInputMessages()
}
}
SampleSourceFifo* DeviceSampleMIMO::getSampleSourceFifo(int index)
SampleSourceFifo* DeviceSampleMIMO::getSampleSourceFifo(unsigned int index)
{
if ((index < 0) || (index >= m_sampleSourceFifos.size())) {
if (index >= m_sampleSourceFifos.size()) {
return nullptr;
} else {
return &m_sampleSourceFifos[index];
}
}
SampleSinkFifo* DeviceSampleMIMO::getSampleSinkFifo(int index)
SampleSinkFifo* DeviceSampleMIMO::getSampleSinkFifo(unsigned int index)
{
if ((index < 0) || (index >= m_sampleSinkFifos.size())) {
if (index >= m_sampleSinkFifos.size()) {
return nullptr;
} else {
return &m_sampleSinkFifos[index];

View File

@ -124,8 +124,8 @@ public:
unsigned int getNbSourceFifos() const { return m_sampleSourceFifos.size(); } //!< Get the number of Tx FIFOs
unsigned int getNbSinkFifos() const { return m_sampleSinkFifos.size(); } //!< Get the number of Rx FIFOs
SampleSourceFifo* getSampleSourceFifo(int index); //!< Get Tx FIFO at index
SampleSinkFifo* getSampleSinkFifo(int index); //!< Get Rx FIFO at index
SampleSourceFifo* getSampleSourceFifo(unsigned int index); //!< Get Tx FIFO at index
SampleSinkFifo* getSampleSinkFifo(unsigned int index); //!< Get Rx FIFO at index
protected slots:
void handleInputMessages();

View File

@ -776,3 +776,10 @@ void DSPDeviceMIMOEngine::handleInputMessages()
}
}
}
void DSPDeviceMIMOEngine::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int isource)
{
qDebug() << "DSPDeviceMIMOEngine::configureCorrections";
ConfigureCorrection* cmd = new ConfigureCorrection(dcOffsetCorrection, iqImbalanceCorrection, isource);
m_inputMessageQueue.push(cmd);
}

View File

@ -21,6 +21,7 @@
#include <QThread>
#include "util/message.h"
#include "util/messagequeue.h"
#include "util/syncmessenger.h"
#include "util/movingaverage.h"
@ -233,6 +234,7 @@ public:
void setMIMO(DeviceSampleMIMO* mimo); //!< Set the sample MIMO type
DeviceSampleMIMO *getMIMO() { return m_deviceSampleMIMO; }
void setMIMOSequence(int sequence); //!< Set the sample MIMO sequence in type
uint getUID() const { return m_uid; }
void addChannelSource(ThreadedBasebandSampleSource* source, int index = 0); //!< Add a channel source that will run on its own thread
void removeChannelSource(ThreadedBasebandSampleSource* source, int index = 0); //!< Remove a channel source that runs on its own thread
@ -250,6 +252,8 @@ public:
QString errorMessage(); //!< Return the current error message
QString deviceDescription(); //!< Return the device description
void configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection, int isource); //!< Configure source DSP corrections
private:
struct SourceCorrection
{

View File

@ -54,6 +54,17 @@ SampleSinkFifo::SampleSinkFifo(int size, QObject* parent) :
create(size);
}
SampleSinkFifo::SampleSinkFifo(const SampleSinkFifo& other) :
QObject(other.parent()),
m_data(other.m_data)
{
m_suppressed = -1;
m_size = m_data.size();
m_fill = 0;
m_head = 0;
m_tail = 0;
}
SampleSinkFifo::~SampleSinkFifo()
{
QMutexLocker mutexLocker(&m_mutex);

View File

@ -43,8 +43,9 @@ private:
void create(uint s);
public:
SampleSinkFifo(QObject* parent = NULL);
SampleSinkFifo(int size, QObject* parent = NULL);
SampleSinkFifo(QObject* parent = nullptr);
SampleSinkFifo(int size, QObject* parent = nullptr);
SampleSinkFifo(const SampleSinkFifo& other);
~SampleSinkFifo();
bool setSize(int size);

View File

@ -19,7 +19,8 @@
#include <assert.h>
#include "samplesourcefifo.h"
SampleSourceFifo::SampleSourceFifo(uint32_t size) :
SampleSourceFifo::SampleSourceFifo(uint32_t size, QObject* parent) :
QObject(parent),
m_size(size),
m_init(false)
{
@ -27,6 +28,12 @@ SampleSourceFifo::SampleSourceFifo(uint32_t size) :
init();
}
SampleSourceFifo::SampleSourceFifo(const SampleSourceFifo& other) :
QObject(other.parent()),
m_data(other.m_data)
{
init();
}
SampleSourceFifo::~SampleSourceFifo()
{}

View File

@ -29,7 +29,8 @@ class SDRBASE_API SampleSourceFifo : public QObject {
Q_OBJECT
public:
SampleSourceFifo(uint32_t size);
SampleSourceFifo(uint32_t size, QObject* parent = nullptr);
SampleSourceFifo(const SampleSourceFifo& other);
~SampleSourceFifo();
void resize(uint32_t size);

View File

@ -26,6 +26,11 @@ void PluginAPI::registerSampleSink(const QString& sinkName, PluginInterface* plu
m_pluginManager->registerSampleSink(sinkName, plugin);
}
void PluginAPI::registerSampleMIMO(const QString& mimoName, PluginInterface* plugin)
{
m_pluginManager->registerSampleMIMO(mimoName, plugin);
}
PluginAPI::ChannelRegistrations *PluginAPI::getTxChannelRegistrations()
{
return m_pluginManager->getTxChannelRegistrations();

View File

@ -57,6 +57,9 @@ public:
// Sample Sink stuff
void registerSampleSink(const QString& sinkName, PluginInterface* plugin);
// Sample MIMO stuff
void registerSampleMIMO(const QString& sinkName, PluginInterface* plugin);
protected:
PluginManager* m_pluginManager;

View File

@ -1,6 +1,7 @@
#include <plugin/plugininstancegui.h>
#include "dsp/devicesamplesource.h"
#include "dsp/devicesamplesink.h"
#include "dsp/devicesamplemimo.h"
#include "plugin/plugininterface.h"
@ -23,3 +24,13 @@ void PluginInterface::deleteSampleSinkPluginInstanceOutput(DeviceSampleSink *sin
{
if (sink) { sink->destroy(); }
}
void PluginInterface::deleteSampleMIMOPluginInstanceGUI(PluginInstanceGUI *ui)
{
if (ui) { ui->destroy(); }
}
void PluginInterface::deleteSampleMIMOPluginInstanceMIMO(DeviceSampleMIMO *mimo)
{
if (mimo) { mimo->destroy(); }
}

View File

@ -23,6 +23,7 @@ class PluginInstanceGUI;
class QWidget;
class DeviceSampleSource;
class DeviceSampleSink;
class DeviceSampleMIMO;
class BasebandSampleSink;
class BasebandSampleSource;
class ChannelAPI;
@ -185,6 +186,34 @@ public:
virtual void deleteSampleSinkPluginInstanceGUI(PluginInstanceGUI *ui);
virtual void deleteSampleSinkPluginInstanceOutput(DeviceSampleSink *sink);
// device MIMO plugins only
virtual SamplingDevices enumSampleMIMO() { return SamplingDevices(); }
virtual PluginInstanceGUI* createSampleMIMOPluginInstanceGUI(
const QString& mimoId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
(void) mimoId;
(void) widget;
(void) deviceUISet;
return nullptr;
}
virtual DeviceSampleMIMO* createSampleMIMOPluginInstanceMIMO( // creates the MIMO "core"
const QString& mimoId,
DeviceAPI *deviceAPI)
{
(void) mimoId;
(void) deviceAPI;
return nullptr;
}
virtual void deleteSampleMIMOPluginInstanceGUI(PluginInstanceGUI *ui);
virtual void deleteSampleMIMOPluginInstanceMIMO(DeviceSampleMIMO *mimo);
};
Q_DECLARE_INTERFACE(PluginInterface, "SDRangel.PluginInterface/0.1");

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2016-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 //
@ -17,7 +17,6 @@
#include <QCoreApplication>
#include <QPluginLoader>
//#include <QComboBox>
#include <QDebug>
#include <cstdio>
@ -91,6 +90,7 @@ void PluginManager::loadPluginsFinal()
DeviceEnumerator::instance()->enumerateRxDevices(this);
DeviceEnumerator::instance()->enumerateTxDevices(this);
DeviceEnumerator::instance()->enumerateMIMODevices(this);
}
void PluginManager::registerRxChannel(const QString& channelIdURI, const QString& channelId, PluginInterface* plugin)
@ -129,6 +129,15 @@ void PluginManager::registerSampleSink(const QString& sinkName, PluginInterface*
m_sampleSinkRegistrations.append(PluginAPI::SamplingDeviceRegistration(sinkName, plugin));
}
void PluginManager::registerSampleMIMO(const QString& mimoName, PluginInterface* plugin)
{
qDebug() << "PluginManager::registerSampleMIMO "
<< plugin->getPluginDescriptor().displayedName.toStdString().c_str()
<< " with MIMO name " << mimoName.toStdString().c_str();
m_sampleMIMORegistrations.append(PluginAPI::SamplingDeviceRegistration(mimoName, plugin));
}
void PluginManager::loadPluginsDir(const QDir& dir)
{
QDir pluginsDir(dir);

View File

@ -1,3 +1,20 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016-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 INCLUDE_PLUGINMANAGER_H
#define INCLUDE_PLUGINMANAGER_H
@ -50,10 +67,12 @@ public:
void registerRxChannel(const QString& channelIdURI, const QString& channelId, PluginInterface* plugin);
void registerSampleSource(const QString& sourceName, PluginInterface* plugin);
void registerTxChannel(const QString& channelIdURI, const QString& channelId, PluginInterface* plugin);
void registerSampleSink(const QString& sourceName, PluginInterface* plugin);
void registerSampleSink(const QString& sinkName, PluginInterface* plugin);
void registerSampleMIMO(const QString& mimoName, PluginInterface* plugin);
PluginAPI::SamplingDeviceRegistrations& getSourceDeviceRegistrations() { return m_sampleSourceRegistrations; }
PluginAPI::SamplingDeviceRegistrations& getSinkDeviceRegistrations() { return m_sampleSinkRegistrations; }
PluginAPI::SamplingDeviceRegistrations& getMIMODeviceRegistrations() { return m_sampleMIMORegistrations; }
PluginAPI::ChannelRegistrations *getRxChannelRegistrations() { return &m_rxChannelRegistrations; }
PluginAPI::ChannelRegistrations *getTxChannelRegistrations() { return &m_txChannelRegistrations; }
@ -101,6 +120,8 @@ private:
PluginAPI::ChannelRegistrations m_txChannelRegistrations; //!< Channel plugins register here
PluginAPI::SamplingDeviceRegistrations m_sampleSinkRegistrations; //!< Output sink plugins (one per device kind) register here
PluginAPI::SamplingDeviceRegistrations m_sampleMIMORegistrations; //!< MIMO sink plugins (one per device kind) register here
// "Local" sample source device IDs
static const QString m_localInputHardwareID; //!< Local input hardware ID
static const QString m_localInputDeviceTypeID; //!< Local input plugin ID

View File

@ -2335,6 +2335,9 @@ margin-bottom: 20px;
"testSourceSettings" : {
"$ref" : "#/definitions/TestSourceSettings"
},
"testSourceMISettings" : {
"$ref" : "#/definitions/TestSourceMISettings"
},
"xtrxInputSettings" : {
"$ref" : "#/definitions/XtrxInputSettings"
},
@ -3576,6 +3579,9 @@ margin-bottom: 20px;
"ctcssOn" : {
"type" : "integer"
},
"highPass" : {
"type" : "integer"
},
"audioMute" : {
"type" : "integer"
},
@ -5203,6 +5209,80 @@ margin-bottom: 20px;
"type" : "string"
}
}
};
defs.TestSourceMISettings = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "uint64"
},
"frequencyShift" : {
"type" : "integer"
},
"sampleRate" : {
"type" : "integer"
},
"log2Decim" : {
"type" : "integer"
},
"fcPos" : {
"type" : "integer"
},
"sampleSizeIndex" : {
"type" : "integer"
},
"amplitudeBits" : {
"type" : "integer"
},
"autoCorrOptions" : {
"type" : "integer"
},
"modulation" : {
"type" : "integer"
},
"modulationTone" : {
"type" : "integer"
},
"amModulation" : {
"type" : "integer"
},
"fmDeviation" : {
"type" : "integer"
},
"dcFactor" : {
"type" : "number",
"format" : "float"
},
"iFactor" : {
"type" : "number",
"format" : "float"
},
"qFactor" : {
"type" : "number",
"format" : "float"
},
"phaseImbalance" : {
"type" : "number",
"format" : "float"
},
"fileRecordName" : {
"type" : "string"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
}
},
"description" : "TestSourceMI"
};
defs.TestSourceSettings = {
"properties" : {
@ -25000,7 +25080,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2019-05-10T14:58:45.508+02:00
Generated 2019-05-18T03:33:39.922+02:00
</div>
</div>
</div>

View File

@ -29,6 +29,8 @@ NFMDemodSettings:
format: float
ctcssOn:
type: integer
highPass:
type: integer
audioMute:
type: integer
ctcssIndex:

View File

@ -0,0 +1,51 @@
TestSourceMISettings:
description: TestSourceMI
properties:
centerFrequency:
type: integer
format: uint64
frequencyShift:
type: integer
sampleRate:
type: integer
log2Decim:
type: integer
fcPos:
type: integer
sampleSizeIndex:
type: integer
amplitudeBits:
type: integer
autoCorrOptions:
type: integer
modulation:
type: integer
modulationTone:
type: integer
amModulation:
type: integer
fmDeviation:
type: integer
dcFactor:
type: number
format: float
iFactor:
type: number
format: float
qFactor:
type: number
format: float
phaseImbalance:
type: number
format: float
fileRecordName:
type: string
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer

View File

@ -1830,6 +1830,8 @@ definitions:
$ref: "/doc/swagger/include/SoapySDR.yaml#/SoapySDROutputSettings"
testSourceSettings:
$ref: "/doc/swagger/include/TestSource.yaml#/TestSourceSettings"
testSourceMISettings:
$ref: "/doc/swagger/include/TestSourceMI.yaml#/TestSourceMISettings"
xtrxInputSettings:
$ref: "/doc/swagger/include/Xtrx.yaml#/XtrxInputSettings"
xtrxOutputSettings:

View File

@ -39,6 +39,8 @@ SamplingDeviceDialog::SamplingDeviceDialog(int deviceType, int deviceTabIndex, Q
DeviceEnumerator::instance()->listRxDeviceNames(deviceDisplayNames, m_deviceIndexes);
} else if (m_deviceType == 1) { // Single Tx
DeviceEnumerator::instance()->listTxDeviceNames(deviceDisplayNames, m_deviceIndexes);
} else if (m_deviceType == 2) { // MIMO
DeviceEnumerator::instance()->listMIMODeviceNames(deviceDisplayNames, m_deviceIndexes);
}
QStringList devicesNamesList(deviceDisplayNames);
@ -58,6 +60,8 @@ void SamplingDeviceDialog::accept()
DeviceEnumerator::instance()->changeRxSelection(m_deviceTabIndex, m_selectedDeviceIndex);
} else if (m_deviceType == 1) { // Single Tx
DeviceEnumerator::instance()->changeTxSelection(m_deviceTabIndex, m_selectedDeviceIndex);
} else if (m_deviceType == 2) { // MIMO
DeviceEnumerator::instance()->changeMIMOSelection(m_deviceTabIndex, m_selectedDeviceIndex);
}
QDialog::accept();

View File

@ -272,7 +272,7 @@ void MainWindow::addSourceDevice(int deviceIndex)
char tabNameCStr[16];
sprintf(tabNameCStr, "R%d", deviceTabIndex);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleRx, deviceTabIndex, dspDeviceSourceEngine, nullptr);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleRx, deviceTabIndex, dspDeviceSourceEngine, nullptr, nullptr);
m_deviceUIs.back()->m_deviceAPI = deviceAPI;
m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
@ -346,7 +346,7 @@ void MainWindow::addSinkDevice()
char tabNameCStr[16];
sprintf(tabNameCStr, "T%d", deviceTabIndex);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleTx, deviceTabIndex, nullptr, dspDeviceSinkEngine);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleTx, deviceTabIndex, nullptr, dspDeviceSinkEngine, nullptr);
m_deviceUIs.back()->m_deviceAPI = deviceAPI;
m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
@ -840,11 +840,11 @@ bool MainWindow::handleMessage(const Message& cmd)
DeviceUISet *deviceUI = m_deviceUIs[notif.getDeviceSetIndex()];
deviceUI->m_samplingDeviceControl->setSelectedDeviceIndex(notif.getDeviceIndex());
if (notif.isTx()) {
if (notif.getDeviceType() == 1) {
sampleSinkChanged();
} else {
} else if (notif.getDeviceType() == 0) {
sampleSourceChanged();
}
} // TODO: for MIMO
return true;
}

View File

@ -32,7 +32,6 @@
class QLabel;
class QTreeWidgetItem;
class QDir;
class SamplingDeviceControl;
class DSPEngine;
class DSPDeviceSourceEngine;
@ -196,7 +195,7 @@ private:
public:
int getDeviceSetIndex() const { return m_deviceSetIndex; }
int getDeviceIndex() const { return m_deviceIndex; }
bool isTx() const { return m_tx; }
int getDeviceType() const { return m_deviceType; }
static MsgSetDevice* create(int deviceSetIndex, int deviceIndex, bool tx)
{
@ -206,13 +205,13 @@ private:
private:
int m_deviceSetIndex;
int m_deviceIndex;
bool m_tx;
int m_deviceType;
MsgSetDevice(int deviceSetIndex, int deviceIndex, bool tx) :
MsgSetDevice(int deviceSetIndex, int deviceIndex, int deviceType) :
Message(),
m_deviceSetIndex(deviceSetIndex),
m_deviceIndex(deviceIndex),
m_tx(tx)
m_deviceType(deviceType)
{ }
};

View File

@ -1052,7 +1052,7 @@ int WebAPIAdapterGUI::devicesetDevicePut(
continue;
}
MainWindow::MsgSetDevice *msg = MainWindow::MsgSetDevice::create(deviceSetIndex, i, query.getDirection() == 1);
MainWindow::MsgSetDevice *msg = MainWindow::MsgSetDevice::create(deviceSetIndex, i, query.getDirection());
m_mainWindow.m_inputMessageQueue.push(msg);
response.init();

View File

@ -166,11 +166,11 @@ bool MainCore::handleMessage(const Message& cmd)
{
MsgSetDevice& notif = (MsgSetDevice&) cmd;
if (notif.isTx()) {
if (notif.getDeviceType() == 1) {
changeSampleSink(notif.getDeviceSetIndex(), notif.getDeviceIndex());
} else {
} else if (notif.getDeviceType() == 0) {
changeSampleSource(notif.getDeviceSetIndex(), notif.getDeviceIndex());
}
} // TODO: for MIMO
return true;
}
@ -281,7 +281,7 @@ void MainCore::addSinkDevice()
char tabNameCStr[16];
sprintf(tabNameCStr, "T%d", deviceTabIndex);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleTx, deviceTabIndex, nullptr, dspDeviceSinkEngine);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleTx, deviceTabIndex, nullptr, dspDeviceSinkEngine, nullptr);
m_deviceSets.back()->m_deviceAPI = deviceAPI;
QList<QString> channelNames;
@ -324,7 +324,7 @@ void MainCore::addSourceDevice()
char tabNameCStr[16];
sprintf(tabNameCStr, "R%d", deviceTabIndex);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleRx, deviceTabIndex, dspDeviceSourceEngine, nullptr);
DeviceAPI *deviceAPI = new DeviceAPI(DeviceAPI::StreamSingleRx, deviceTabIndex, dspDeviceSourceEngine, nullptr, nullptr);
m_deviceSets.back()->m_deviceAPI = deviceAPI;

View File

@ -197,23 +197,23 @@ private:
public:
int getDeviceSetIndex() const { return m_deviceSetIndex; }
int getDeviceIndex() const { return m_deviceIndex; }
bool isTx() const { return m_tx; }
int getDeviceType() const { return m_deviceType; }
static MsgSetDevice* create(int deviceSetIndex, int deviceIndex, bool tx)
static MsgSetDevice* create(int deviceSetIndex, int deviceIndex, int deviceType)
{
return new MsgSetDevice(deviceSetIndex, deviceIndex, tx);
return new MsgSetDevice(deviceSetIndex, deviceIndex, deviceType);
}
private:
int m_deviceSetIndex;
int m_deviceIndex;
bool m_tx;
int m_deviceType;
MsgSetDevice(int deviceSetIndex, int deviceIndex, bool tx) :
MsgSetDevice(int deviceSetIndex, int deviceIndex, int deviceType) :
Message(),
m_deviceSetIndex(deviceSetIndex),
m_deviceIndex(deviceIndex),
m_tx(tx)
m_deviceType(deviceType)
{ }
};

View File

@ -1139,7 +1139,7 @@ int WebAPIAdapterSrv::devicesetDevicePut(
continue;
}
MainCore::MsgSetDevice *msg = MainCore::MsgSetDevice::create(deviceSetIndex, i, query.getDirection() == 1);
MainCore::MsgSetDevice *msg = MainCore::MsgSetDevice::create(deviceSetIndex, i, query.getDirection());
m_mainCore.m_inputMessageQueue.push(msg);
response.init();

View File

@ -0,0 +1,51 @@
TestSourceMISettings:
description: TestSourceMI
properties:
centerFrequency:
type: integer
format: uint64
frequencyShift:
type: integer
sampleRate:
type: integer
log2Decim:
type: integer
fcPos:
type: integer
sampleSizeIndex:
type: integer
amplitudeBits:
type: integer
autoCorrOptions:
type: integer
modulation:
type: integer
modulationTone:
type: integer
amModulation:
type: integer
fmDeviation:
type: integer
dcFactor:
type: number
format: float
iFactor:
type: number
format: float
qFactor:
type: number
format: float
phaseImbalance:
type: number
format: float
fileRecordName:
type: string
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer

View File

@ -1830,6 +1830,8 @@ definitions:
$ref: "http://localhost:8081/api/swagger/include/SoapySDR.yaml#/SoapySDROutputSettings"
testSourceSettings:
$ref: "http://localhost:8081/api/swagger/include/TestSource.yaml#/TestSourceSettings"
testSourceMISettings:
$ref: "http://localhost:8081/api/swagger/include/TestSourceMI.yaml#/TestSourceMISettings"
xtrxInputSettings:
$ref: "http://localhost:8081/api/swagger/include/Xtrx.yaml#/XtrxInputSettings"
xtrxOutputSettings:

View File

@ -2335,6 +2335,9 @@ margin-bottom: 20px;
"testSourceSettings" : {
"$ref" : "#/definitions/TestSourceSettings"
},
"testSourceMISettings" : {
"$ref" : "#/definitions/TestSourceMISettings"
},
"xtrxInputSettings" : {
"$ref" : "#/definitions/XtrxInputSettings"
},
@ -3576,6 +3579,9 @@ margin-bottom: 20px;
"ctcssOn" : {
"type" : "integer"
},
"highPass" : {
"type" : "integer"
},
"audioMute" : {
"type" : "integer"
},
@ -5203,6 +5209,80 @@ margin-bottom: 20px;
"type" : "string"
}
}
};
defs.TestSourceMISettings = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "uint64"
},
"frequencyShift" : {
"type" : "integer"
},
"sampleRate" : {
"type" : "integer"
},
"log2Decim" : {
"type" : "integer"
},
"fcPos" : {
"type" : "integer"
},
"sampleSizeIndex" : {
"type" : "integer"
},
"amplitudeBits" : {
"type" : "integer"
},
"autoCorrOptions" : {
"type" : "integer"
},
"modulation" : {
"type" : "integer"
},
"modulationTone" : {
"type" : "integer"
},
"amModulation" : {
"type" : "integer"
},
"fmDeviation" : {
"type" : "integer"
},
"dcFactor" : {
"type" : "number",
"format" : "float"
},
"iFactor" : {
"type" : "number",
"format" : "float"
},
"qFactor" : {
"type" : "number",
"format" : "float"
},
"phaseImbalance" : {
"type" : "number",
"format" : "float"
},
"fileRecordName" : {
"type" : "string"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
}
},
"description" : "TestSourceMI"
};
defs.TestSourceSettings = {
"properties" : {
@ -25000,7 +25080,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2019-05-10T14:58:45.508+02:00
Generated 2019-05-18T03:33:39.922+02:00
</div>
</div>
</div>

View File

@ -84,6 +84,8 @@ SWGDeviceSettings::SWGDeviceSettings() {
m_soapy_sdr_output_settings_isSet = false;
test_source_settings = nullptr;
m_test_source_settings_isSet = false;
test_source_mi_settings = nullptr;
m_test_source_mi_settings_isSet = false;
xtrx_input_settings = nullptr;
m_xtrx_input_settings_isSet = false;
xtrx_output_settings = nullptr;
@ -152,6 +154,8 @@ SWGDeviceSettings::init() {
m_soapy_sdr_output_settings_isSet = false;
test_source_settings = new SWGTestSourceSettings();
m_test_source_settings_isSet = false;
test_source_mi_settings = new SWGTestSourceMISettings();
m_test_source_mi_settings_isSet = false;
xtrx_input_settings = new SWGXtrxInputSettings();
m_xtrx_input_settings_isSet = false;
xtrx_output_settings = new SWGXtrxOutputSettings();
@ -240,6 +244,9 @@ SWGDeviceSettings::cleanup() {
if(test_source_settings != nullptr) {
delete test_source_settings;
}
if(test_source_mi_settings != nullptr) {
delete test_source_mi_settings;
}
if(xtrx_input_settings != nullptr) {
delete xtrx_input_settings;
}
@ -315,6 +322,8 @@ SWGDeviceSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&test_source_settings, pJson["testSourceSettings"], "SWGTestSourceSettings", "SWGTestSourceSettings");
::SWGSDRangel::setValue(&test_source_mi_settings, pJson["testSourceMISettings"], "SWGTestSourceMISettings", "SWGTestSourceMISettings");
::SWGSDRangel::setValue(&xtrx_input_settings, pJson["xtrxInputSettings"], "SWGXtrxInputSettings", "SWGXtrxInputSettings");
::SWGSDRangel::setValue(&xtrx_output_settings, pJson["xtrxOutputSettings"], "SWGXtrxOutputSettings", "SWGXtrxOutputSettings");
@ -419,6 +428,9 @@ SWGDeviceSettings::asJsonObject() {
if((test_source_settings != nullptr) && (test_source_settings->isSet())){
toJsonValue(QString("testSourceSettings"), test_source_settings, obj, QString("SWGTestSourceSettings"));
}
if((test_source_mi_settings != nullptr) && (test_source_mi_settings->isSet())){
toJsonValue(QString("testSourceMISettings"), test_source_mi_settings, obj, QString("SWGTestSourceMISettings"));
}
if((xtrx_input_settings != nullptr) && (xtrx_input_settings->isSet())){
toJsonValue(QString("xtrxInputSettings"), xtrx_input_settings, obj, QString("SWGXtrxInputSettings"));
}
@ -709,6 +721,16 @@ SWGDeviceSettings::setTestSourceSettings(SWGTestSourceSettings* test_source_sett
this->m_test_source_settings_isSet = true;
}
SWGTestSourceMISettings*
SWGDeviceSettings::getTestSourceMiSettings() {
return test_source_mi_settings;
}
void
SWGDeviceSettings::setTestSourceMiSettings(SWGTestSourceMISettings* test_source_mi_settings) {
this->test_source_mi_settings = test_source_mi_settings;
this->m_test_source_mi_settings_isSet = true;
}
SWGXtrxInputSettings*
SWGDeviceSettings::getXtrxInputSettings() {
return xtrx_input_settings;
@ -762,6 +784,7 @@ SWGDeviceSettings::isSet(){
if(soapy_sdr_input_settings != nullptr && soapy_sdr_input_settings->isSet()){ isObjectUpdated = true; break;}
if(soapy_sdr_output_settings != nullptr && soapy_sdr_output_settings->isSet()){ isObjectUpdated = true; break;}
if(test_source_settings != nullptr && test_source_settings->isSet()){ isObjectUpdated = true; break;}
if(test_source_mi_settings != nullptr && test_source_mi_settings->isSet()){ isObjectUpdated = true; break;}
if(xtrx_input_settings != nullptr && xtrx_input_settings->isSet()){ isObjectUpdated = true; break;}
if(xtrx_output_settings != nullptr && xtrx_output_settings->isSet()){ isObjectUpdated = true; break;}
}while(false);

View File

@ -46,6 +46,7 @@
#include "SWGSDRPlaySettings.h"
#include "SWGSoapySDRInputSettings.h"
#include "SWGSoapySDROutputSettings.h"
#include "SWGTestSourceMISettings.h"
#include "SWGTestSourceSettings.h"
#include "SWGXtrxInputSettings.h"
#include "SWGXtrxOutputSettings.h"
@ -153,6 +154,9 @@ public:
SWGTestSourceSettings* getTestSourceSettings();
void setTestSourceSettings(SWGTestSourceSettings* test_source_settings);
SWGTestSourceMISettings* getTestSourceMiSettings();
void setTestSourceMiSettings(SWGTestSourceMISettings* test_source_mi_settings);
SWGXtrxInputSettings* getXtrxInputSettings();
void setXtrxInputSettings(SWGXtrxInputSettings* xtrx_input_settings);
@ -247,6 +251,9 @@ private:
SWGTestSourceSettings* test_source_settings;
bool m_test_source_settings_isSet;
SWGTestSourceMISettings* test_source_mi_settings;
bool m_test_source_mi_settings_isSet;
SWGXtrxInputSettings* xtrx_input_settings;
bool m_xtrx_input_settings_isSet;

View File

@ -132,6 +132,7 @@
#include "SWGSoapySDROutputSettings.h"
#include "SWGSoapySDRReport.h"
#include "SWGSuccessResponse.h"
#include "SWGTestSourceMISettings.h"
#include "SWGTestSourceSettings.h"
#include "SWGUDPSinkReport.h"
#include "SWGUDPSinkSettings.h"
@ -503,6 +504,9 @@ namespace SWGSDRangel {
if(QString("SWGSuccessResponse").compare(type) == 0) {
return new SWGSuccessResponse();
}
if(QString("SWGTestSourceMISettings").compare(type) == 0) {
return new SWGTestSourceMISettings();
}
if(QString("SWGTestSourceSettings").compare(type) == 0) {
return new SWGTestSourceSettings();
}

View File

@ -46,6 +46,8 @@ SWGNFMDemodSettings::SWGNFMDemodSettings() {
m_volume_isSet = false;
ctcss_on = 0;
m_ctcss_on_isSet = false;
high_pass = 0;
m_high_pass_isSet = false;
audio_mute = 0;
m_audio_mute_isSet = false;
ctcss_index = 0;
@ -92,6 +94,8 @@ SWGNFMDemodSettings::init() {
m_volume_isSet = false;
ctcss_on = 0;
m_ctcss_on_isSet = false;
high_pass = 0;
m_high_pass_isSet = false;
audio_mute = 0;
m_audio_mute_isSet = false;
ctcss_index = 0;
@ -128,6 +132,7 @@ SWGNFMDemodSettings::cleanup() {
if(title != nullptr) {
delete title;
}
@ -172,6 +177,8 @@ SWGNFMDemodSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&ctcss_on, pJson["ctcssOn"], "qint32", "");
::SWGSDRangel::setValue(&high_pass, pJson["highPass"], "qint32", "");
::SWGSDRangel::setValue(&audio_mute, pJson["audioMute"], "qint32", "");
::SWGSDRangel::setValue(&ctcss_index, pJson["ctcssIndex"], "qint32", "");
@ -235,6 +242,9 @@ SWGNFMDemodSettings::asJsonObject() {
if(m_ctcss_on_isSet){
obj->insert("ctcssOn", QJsonValue(ctcss_on));
}
if(m_high_pass_isSet){
obj->insert("highPass", QJsonValue(high_pass));
}
if(m_audio_mute_isSet){
obj->insert("audioMute", QJsonValue(audio_mute));
}
@ -359,6 +369,16 @@ SWGNFMDemodSettings::setCtcssOn(qint32 ctcss_on) {
this->m_ctcss_on_isSet = true;
}
qint32
SWGNFMDemodSettings::getHighPass() {
return high_pass;
}
void
SWGNFMDemodSettings::setHighPass(qint32 high_pass) {
this->high_pass = high_pass;
this->m_high_pass_isSet = true;
}
qint32
SWGNFMDemodSettings::getAudioMute() {
return audio_mute;
@ -473,6 +493,7 @@ SWGNFMDemodSettings::isSet(){
if(m_squelch_isSet){ isObjectUpdated = true; break;}
if(m_volume_isSet){ isObjectUpdated = true; break;}
if(m_ctcss_on_isSet){ isObjectUpdated = true; break;}
if(m_high_pass_isSet){ isObjectUpdated = true; break;}
if(m_audio_mute_isSet){ isObjectUpdated = true; break;}
if(m_ctcss_index_isSet){ isObjectUpdated = true; break;}
if(m_rgb_color_isSet){ isObjectUpdated = true; break;}

View File

@ -69,6 +69,9 @@ public:
qint32 getCtcssOn();
void setCtcssOn(qint32 ctcss_on);
qint32 getHighPass();
void setHighPass(qint32 high_pass);
qint32 getAudioMute();
void setAudioMute(qint32 audio_mute);
@ -130,6 +133,9 @@ private:
qint32 ctcss_on;
bool m_ctcss_on_isSet;
qint32 high_pass;
bool m_high_pass_isSet;
qint32 audio_mute;
bool m_audio_mute_isSet;

View File

@ -0,0 +1,530 @@
/**
* 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 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.8.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 "SWGTestSourceMISettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGTestSourceMISettings::SWGTestSourceMISettings(QString* json) {
init();
this->fromJson(*json);
}
SWGTestSourceMISettings::SWGTestSourceMISettings() {
center_frequency = 0;
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;
file_record_name = nullptr;
m_file_record_name_isSet = false;
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;
}
SWGTestSourceMISettings::~SWGTestSourceMISettings() {
this->cleanup();
}
void
SWGTestSourceMISettings::init() {
center_frequency = 0;
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;
file_record_name = new QString("");
m_file_record_name_isSet = false;
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;
}
void
SWGTestSourceMISettings::cleanup() {
if(file_record_name != nullptr) {
delete file_record_name;
}
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
}
SWGTestSourceMISettings*
SWGTestSourceMISettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGTestSourceMISettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&center_frequency, pJson["centerFrequency"], "qint32", "");
::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", "");
::SWGSDRangel::setValue(&file_record_name, pJson["fileRecordName"], "QString", "QString");
::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", "");
}
QString
SWGTestSourceMISettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGTestSourceMISettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
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));
}
if(file_record_name != nullptr && *file_record_name != QString("")){
toJsonValue(QString("fileRecordName"), file_record_name, obj, QString("QString"));
}
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));
}
return obj;
}
qint32
SWGTestSourceMISettings::getCenterFrequency() {
return center_frequency;
}
void
SWGTestSourceMISettings::setCenterFrequency(qint32 center_frequency) {
this->center_frequency = center_frequency;
this->m_center_frequency_isSet = true;
}
qint32
SWGTestSourceMISettings::getFrequencyShift() {
return frequency_shift;
}
void
SWGTestSourceMISettings::setFrequencyShift(qint32 frequency_shift) {
this->frequency_shift = frequency_shift;
this->m_frequency_shift_isSet = true;
}
qint32
SWGTestSourceMISettings::getSampleRate() {
return sample_rate;
}
void
SWGTestSourceMISettings::setSampleRate(qint32 sample_rate) {
this->sample_rate = sample_rate;
this->m_sample_rate_isSet = true;
}
qint32
SWGTestSourceMISettings::getLog2Decim() {
return log2_decim;
}
void
SWGTestSourceMISettings::setLog2Decim(qint32 log2_decim) {
this->log2_decim = log2_decim;
this->m_log2_decim_isSet = true;
}
qint32
SWGTestSourceMISettings::getFcPos() {
return fc_pos;
}
void
SWGTestSourceMISettings::setFcPos(qint32 fc_pos) {
this->fc_pos = fc_pos;
this->m_fc_pos_isSet = true;
}
qint32
SWGTestSourceMISettings::getSampleSizeIndex() {
return sample_size_index;
}
void
SWGTestSourceMISettings::setSampleSizeIndex(qint32 sample_size_index) {
this->sample_size_index = sample_size_index;
this->m_sample_size_index_isSet = true;
}
qint32
SWGTestSourceMISettings::getAmplitudeBits() {
return amplitude_bits;
}
void
SWGTestSourceMISettings::setAmplitudeBits(qint32 amplitude_bits) {
this->amplitude_bits = amplitude_bits;
this->m_amplitude_bits_isSet = true;
}
qint32
SWGTestSourceMISettings::getAutoCorrOptions() {
return auto_corr_options;
}
void
SWGTestSourceMISettings::setAutoCorrOptions(qint32 auto_corr_options) {
this->auto_corr_options = auto_corr_options;
this->m_auto_corr_options_isSet = true;
}
qint32
SWGTestSourceMISettings::getModulation() {
return modulation;
}
void
SWGTestSourceMISettings::setModulation(qint32 modulation) {
this->modulation = modulation;
this->m_modulation_isSet = true;
}
qint32
SWGTestSourceMISettings::getModulationTone() {
return modulation_tone;
}
void
SWGTestSourceMISettings::setModulationTone(qint32 modulation_tone) {
this->modulation_tone = modulation_tone;
this->m_modulation_tone_isSet = true;
}
qint32
SWGTestSourceMISettings::getAmModulation() {
return am_modulation;
}
void
SWGTestSourceMISettings::setAmModulation(qint32 am_modulation) {
this->am_modulation = am_modulation;
this->m_am_modulation_isSet = true;
}
qint32
SWGTestSourceMISettings::getFmDeviation() {
return fm_deviation;
}
void
SWGTestSourceMISettings::setFmDeviation(qint32 fm_deviation) {
this->fm_deviation = fm_deviation;
this->m_fm_deviation_isSet = true;
}
float
SWGTestSourceMISettings::getDcFactor() {
return dc_factor;
}
void
SWGTestSourceMISettings::setDcFactor(float dc_factor) {
this->dc_factor = dc_factor;
this->m_dc_factor_isSet = true;
}
float
SWGTestSourceMISettings::getIFactor() {
return i_factor;
}
void
SWGTestSourceMISettings::setIFactor(float i_factor) {
this->i_factor = i_factor;
this->m_i_factor_isSet = true;
}
float
SWGTestSourceMISettings::getQFactor() {
return q_factor;
}
void
SWGTestSourceMISettings::setQFactor(float q_factor) {
this->q_factor = q_factor;
this->m_q_factor_isSet = true;
}
float
SWGTestSourceMISettings::getPhaseImbalance() {
return phase_imbalance;
}
void
SWGTestSourceMISettings::setPhaseImbalance(float phase_imbalance) {
this->phase_imbalance = phase_imbalance;
this->m_phase_imbalance_isSet = true;
}
QString*
SWGTestSourceMISettings::getFileRecordName() {
return file_record_name;
}
void
SWGTestSourceMISettings::setFileRecordName(QString* file_record_name) {
this->file_record_name = file_record_name;
this->m_file_record_name_isSet = true;
}
qint32
SWGTestSourceMISettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGTestSourceMISettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGTestSourceMISettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGTestSourceMISettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGTestSourceMISettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGTestSourceMISettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGTestSourceMISettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGTestSourceMISettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
bool
SWGTestSourceMISettings::isSet(){
bool isObjectUpdated = false;
do{
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;}
if(file_record_name != nullptr && *file_record_name != QString("")){ isObjectUpdated = true; break;}
if(m_use_reverse_api_isSet){ isObjectUpdated = true; break;}
if(reverse_api_address != nullptr && *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;}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,179 @@
/**
* 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 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.8.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.
*/
/*
* SWGTestSourceMISettings.h
*
* TestSourceMI
*/
#ifndef SWGTestSourceMISettings_H_
#define SWGTestSourceMISettings_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGTestSourceMISettings: public SWGObject {
public:
SWGTestSourceMISettings();
SWGTestSourceMISettings(QString* json);
virtual ~SWGTestSourceMISettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGTestSourceMISettings* fromJson(QString &jsonString) override;
qint32 getCenterFrequency();
void setCenterFrequency(qint32 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);
QString* getFileRecordName();
void setFileRecordName(QString* file_record_name);
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);
virtual bool isSet() override;
private:
qint32 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;
QString* file_record_name;
bool m_file_record_name_isSet;
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;
};
}
#endif /* SWGTestSourceMISettings_H_ */