diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 0a91952d9..bbe7745ec 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -2,5 +2,6 @@ project(plugins) add_subdirectory(channelrx) add_subdirectory(channeltx) +add_subdirectory(samplemimo) add_subdirectory(samplesource) add_subdirectory(samplesink) diff --git a/plugins/samplemimo/CMakeLists.txt b/plugins/samplemimo/CMakeLists.txt new file mode 100644 index 000000000..acc069928 --- /dev/null +++ b/plugins/samplemimo/CMakeLists.txt @@ -0,0 +1,3 @@ +project(samplemimo) + +add_subdirectory(testmi) diff --git a/plugins/samplemimo/testmi/CMakeLists.txt b/plugins/samplemimo/testmi/CMakeLists.txt new file mode 100644 index 000000000..c2caa7034 --- /dev/null +++ b/plugins/samplemimo/testmi/CMakeLists.txt @@ -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) diff --git a/plugins/samplemimo/testmi/readme.md b/plugins/samplemimo/testmi/readme.md new file mode 100644 index 000000000..979a42991 --- /dev/null +++ b/plugins/samplemimo/testmi/readme.md @@ -0,0 +1,134 @@ +

Test source input plugin

+ +

Introduction

+ +This input sample source plugin is an internal continuous wave generator that can be used to carry out test of software internals. + +

Build

+ +The plugin is present in the core of the software and thus is always present in the list of sources. + +

Interface

+ +![Test source input plugin GUI](../../../doc/img/TestSourceInput_plugin.png) + +

1: Common stream parameters

+ +![Remote source input stream GUI](../../../doc/img/RemoteInput_plugin_01.png) + +

1.1: Frequency

+ +This is the center frequency of reception in kHz. + +

1.2: Start/Stop

+ +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. + +

1.3: Record

+ +Record baseband I/Q stream toggle button + +

1.4: Stream sample rate

+ +Baseband I/Q sample rate in kS/s. This is the device to host sample rate (3) divided by the decimation factor (4). + +

2: Various options

+ +![Test source input plugin GUI 2](../../../doc/img/TestSourceInput_plugin_2.png) + +

2.1: Auto corrections

+ +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. + +

2.2: Decimation factor

+ +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. + +

2.3: Baseband center frequency position relative the center frequency

+ + - **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. + +

2.4: Sample size

+ +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+ + +

3: Sample rate

+ +This controls the generator sample rate in samples per second. + +

4: Modulation

+ + - **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 + +

5: Modulating tone frequency

+ +This controls the modulating tone frequency in kHz in 10 Hz steps. + +

6: Carrier shift from center frequency

+ +Use this control to set the offset of the carrier from the center frequency of reception. + +

7: AM modulation factor

+ +This controls the AM modulation factor from 0 to 99% + +

8: FM deviation

+ +This controls the frequency modulation deviation in kHz in 100 Hz steps. It cannot exceed the sample rate. + +

9: Amplitude coarse control

+ +This slider controls the number of amplitude bits by steps of 100 bits. The total number of amplitude bits appear on the right. + +

10: Amplitude fine control

+ +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. + +

11: DC bias

+ +Use this slider to give a DC component in percentage of maximum amplitude. + +

12: I bias

+ +Use this slider to give an in-phase (I) bias in percentage of maximum amplitude. + +

13: Q bias

+ +Use this slider to give an quadrature-phase (Q) bias in percentage of maximum amplitude. + +

14: Phase imbalance

+ +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). diff --git a/plugins/samplemimo/testmi/testmi.cpp b/plugins/samplemimo/testmi/testmi.cpp new file mode 100644 index 000000000..7f236d073 --- /dev/null +++ b/plugins/samplemimo/testmi/testmi.cpp @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include +#include +#include + +#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<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 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<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<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<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& 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()); +} diff --git a/plugins/samplemimo/testmi/testmi.h b/plugins/samplemimo/testmi/testmi.h new file mode 100644 index 000000000..be13a535b --- /dev/null +++ b/plugins/samplemimo/testmi/testmi.h @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef _TESTMI_TESTMI_H_ +#define _TESTMI_TESTMI_H_ + +#include +#include +#include +#include + +#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& deviceSettingsKeys, const TestMISettings& settings, bool force); + void webapiReverseSendStartStop(bool start); + +private slots: + void networkManagerFinished(QNetworkReply *reply); +}; + +#endif // _TESTMI_TESTMI_H_ diff --git a/plugins/samplemimo/testmi/testmigui.cpp b/plugins/samplemimo/testmi/testmigui.cpp new file mode 100644 index 000000000..032ee23d1 --- /dev/null +++ b/plugins/samplemimo/testmi/testmigui.cpp @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include + +#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(); +} \ No newline at end of file diff --git a/plugins/samplemimo/testmi/testmigui.h b/plugins/samplemimo/testmi/testmigui.h new file mode 100644 index 000000000..95d6b8a64 --- /dev/null +++ b/plugins/samplemimo/testmi/testmigui.h @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef _TESTMI_TESTMIGUI_H_ +#define _TESTMI_TESTMIGUI_H_ + +#include +#include +#include + +#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_ diff --git a/plugins/samplemimo/testmi/testmigui.ui b/plugins/samplemimo/testmi/testmigui.ui new file mode 100644 index 000000000..d03340371 --- /dev/null +++ b/plugins/samplemimo/testmi/testmigui.ui @@ -0,0 +1,1012 @@ + + + TestMIGui + + + + 0 + 0 + 360 + 300 + + + + + 0 + 0 + + + + + 360 + 300 + + + + + Liberation Sans + 9 + 50 + false + false + + + + Test Multiple Input + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 4 + + + + + + + + + start/stop acquisition + + + + + + + :/play.png + :/stop.png:/play.png + + + + + + + Toggle record I/Q samples from device + + + + + + + :/record_off.png:/record_off.png + + + + + + + + + + + + 58 + 0 + + + + I/Q sample rate kS/s + + + 0000.00k + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 20 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Tuner center frequency in kHz + + + + + + + kHz + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + + + + + + Corr + + + + + + + DC offset and IQ correction options + + + + None + + + + + DC + + + + + DC+IQ + + + + + + + + Dec + + + + + + + + 45 + 16777215 + + + + Decimation factor + + + + 1 + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + + + 32 + + + + + 64 + + + + + + + + Fp + + + + + + + + 50 + 16777215 + + + + Relative position of generator center frequency + + + 2 + + + + Inf + + + + + Sup + + + + + Cen + + + + + + + + Sz + + + + + + + + 45 + 16777215 + + + + Sample size + + + 0 + + + + 8 + + + + + 12 + + + + + 16 + + + + + + + + bits + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 16 + 0 + + + + SR + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Generator sample rate (S/s) + + + + + + + S/s + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Mod + + + + + + + + 50 + 16777215 + + + + Modulation + + + + No + + + + + AM + + + + + FM + + + + + P0 + + + + + P1 + + + + + P2 + + + + + + + + + 22 + 22 + + + + Modulation tone (kHz) + + + 1 + + + 999 + + + 1 + + + + + + + + 35 + 0 + + + + Modulation tone value (kHz) + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + 16 + 0 + + + + D + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Shift from center frequency + + + + + + + Hz + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + AM + + + + + + + + 22 + 22 + + + + AM modulation (%) + + + 1 + + + + + + + AM modulation value (%) + + + 00 + + + + + + + Qt::Vertical + + + + + + + FM + + + + + + + + 22 + 22 + + + + FM deviation (kHz) + + + 1 + + + 999 + + + 1 + + + + + + + + 35 + 0 + + + + FM deviation value (kHz) + + + 00.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + + + Amp fine + + + + + + + + 0 + 0 + + + + Amp coarse + + + + + + + true + + + Amplitude coarse (x100) + + + 327 + + + 1 + + + Qt::Horizontal + + + + + + + Amplitude in bits + + + 32768 b + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 52 + 0 + + + + Power + + + -100 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Amplitude fine (x1) + + + 1 + + + Qt::Horizontal + + + + + + + + + + + -99 + + + 1 + + + Qt::Horizontal + + + + + + + -100 % + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Q bias + + + + + + + + + + + + + + + - + + + + + + + I bias + + + + + + + - + + + + + + + -99 + + + 1 + + + Qt::Horizontal + + + + + + + -100 % + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + DC bias + + + + + + + - + + + + + + + -99 + + + 1 + + + Qt::Horizontal + + + + + + + + + + + + + + + -100 % + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Phase + + + + + + + - + + + + + + + + + + + + + + + + 45 + 0 + + + + -100 % + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + -99 + + + 1 + + + Qt::Horizontal + + + + + + + + + + + + + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+
+ + + + +
diff --git a/plugins/samplemimo/testmi/testmiplugin.cpp b/plugins/samplemimo/testmi/testmiplugin.cpp new file mode 100644 index 000000000..942a422a4 --- /dev/null +++ b/plugins/samplemimo/testmi/testmiplugin.cpp @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#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; + } +} + diff --git a/plugins/samplemimo/testmi/testmiplugin.h b/plugins/samplemimo/testmi/testmiplugin.h new file mode 100644 index 000000000..66d8df81f --- /dev/null +++ b/plugins/samplemimo/testmi/testmiplugin.h @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef _TESTMI_TESTMIPLUGIN_H +#define _TESTMI_TESTMIPLUGIN_H + +#include +#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 diff --git a/plugins/samplemimo/testmi/testmisettings.cpp b/plugins/samplemimo/testmi/testmisettings.cpp new file mode 100644 index 000000000..d36a858c2 --- /dev/null +++ b/plugins/samplemimo/testmi/testmisettings.cpp @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#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; + } +} + + + + + + diff --git a/plugins/samplemimo/testmi/testmisettings.h b/plugins/samplemimo/testmi/testmisettings.h new file mode 100644 index 000000000..9a5daa8be --- /dev/null +++ b/plugins/samplemimo/testmi/testmisettings.h @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef _TESTMI_TESTMISETTINGS_H_ +#define _TESTMI_TESTMISETTINGS_H_ + +#include + +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_ */ diff --git a/plugins/samplemimo/testmi/testmithread.cpp b/plugins/samplemimo/testmi/testmithread.cpp new file mode 100644 index 000000000..e9d9ef913 --- /dev/null +++ b/plugins/samplemimo/testmi/testmithread.cpp @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#define _USE_MATH_DEFINES +#include +#include +#include + +#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<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; +} diff --git a/plugins/samplemimo/testmi/testmithread.h b/plugins/samplemimo/testmi/testmithread.h new file mode 100644 index 000000000..27f094c83 --- /dev/null +++ b/plugins/samplemimo/testmi/testmithread.h @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef _TESTMI_TESTMITHREAD_H_ +#define _TESTMI_TESTMITHREAD_H_ + +#include +#include +#include +#include +#include +#include + +#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 m_decimators_8; + Decimators m_decimators_12; + Decimators 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_ diff --git a/plugins/samplemimo/testmi/testsourcemi.pro b/plugins/samplemimo/testmi/testsourcemi.pro new file mode 100644 index 000000000..92f455cfc --- /dev/null +++ b/plugins/samplemimo/testmi/testsourcemi.pro @@ -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 diff --git a/sdrbase/device/deviceapi.cpp b/sdrbase/device/deviceapi.cpp index 5f79b0436..0ce097d16 100644 --- a/sdrbase/device/deviceapi.cpp +++ b/sdrbase/device/deviceapi.cpp @@ -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); } } diff --git a/sdrbase/device/deviceapi.h b/sdrbase/device/deviceapi.h index 2c801a5ab..bcda31ed9 100644 --- a/sdrbase/device/deviceapi.h +++ b/sdrbase/device/deviceapi.h @@ -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 m_channelSourceAPIs; + // MIMO + + DSPDeviceMIMOEngine *m_deviceMIMOEngine; + private: void renumerateChannels(); }; diff --git a/sdrbase/device/deviceenumerator.cpp b/sdrbase/device/deviceenumerator.cpp index d8ef40728..d506af397 100644 --- a/sdrbase/device/deviceenumerator.cpp +++ b/sdrbase/device/deviceenumerator.cpp @@ -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& list, std::vector& indexes) const { for (DevicesEnumeration::const_iterator it = m_rxEnumeration.begin(); it != m_rxEnumeration.end(); ++it) @@ -104,6 +128,18 @@ void DeviceEnumerator::listTxDeviceNames(QList& list, std::vector& } } +void DeviceEnumerator::listMIMODeviceNames(QList& list, std::vector& 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; +} diff --git a/sdrbase/device/deviceenumerator.h b/sdrbase/device/deviceenumerator.h index 9062007d5..973f3ec0f 100644 --- a/sdrbase/device/deviceenumerator.h +++ b/sdrbase/device/deviceenumerator.h @@ -35,22 +35,30 @@ public: void enumerateRxDevices(PluginManager *pluginManager); void enumerateTxDevices(PluginManager *pluginManager); + void enumerateMIMODevices(PluginManager *pluginManager); void listRxDeviceNames(QList& list, std::vector& indexes) const; void listTxDeviceNames(QList& list, std::vector& indexes) const; + void listMIMODeviceNames(QList& list, std::vector& 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_ */ diff --git a/sdrbase/dsp/devicesamplemimo.cpp b/sdrbase/dsp/devicesamplemimo.cpp index b1b351686..08a0e933b 100644 --- a/sdrbase/dsp/devicesamplemimo.cpp +++ b/sdrbase/dsp/devicesamplemimo.cpp @@ -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]; diff --git a/sdrbase/dsp/devicesamplemimo.h b/sdrbase/dsp/devicesamplemimo.h index 251137cc4..5f84adf3d 100644 --- a/sdrbase/dsp/devicesamplemimo.h +++ b/sdrbase/dsp/devicesamplemimo.h @@ -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(); diff --git a/sdrbase/dsp/dspdevicemimoengine.cpp b/sdrbase/dsp/dspdevicemimoengine.cpp index 478fe3d60..4172e6f02 100644 --- a/sdrbase/dsp/dspdevicemimoengine.cpp +++ b/sdrbase/dsp/dspdevicemimoengine.cpp @@ -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); +} diff --git a/sdrbase/dsp/dspdevicemimoengine.h b/sdrbase/dsp/dspdevicemimoengine.h index a05ad8d78..f7003c480 100644 --- a/sdrbase/dsp/dspdevicemimoengine.h +++ b/sdrbase/dsp/dspdevicemimoengine.h @@ -21,6 +21,7 @@ #include +#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 { diff --git a/sdrbase/dsp/samplesinkfifo.cpp b/sdrbase/dsp/samplesinkfifo.cpp index 1ae77ea92..f769a202b 100644 --- a/sdrbase/dsp/samplesinkfifo.cpp +++ b/sdrbase/dsp/samplesinkfifo.cpp @@ -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); diff --git a/sdrbase/dsp/samplesinkfifo.h b/sdrbase/dsp/samplesinkfifo.h index 5ea42fe15..4d71b6a79 100644 --- a/sdrbase/dsp/samplesinkfifo.h +++ b/sdrbase/dsp/samplesinkfifo.h @@ -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); diff --git a/sdrbase/dsp/samplesourcefifo.cpp b/sdrbase/dsp/samplesourcefifo.cpp index 47ef02ed2..edfd6044e 100644 --- a/sdrbase/dsp/samplesourcefifo.cpp +++ b/sdrbase/dsp/samplesourcefifo.cpp @@ -19,7 +19,8 @@ #include #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() {} diff --git a/sdrbase/dsp/samplesourcefifo.h b/sdrbase/dsp/samplesourcefifo.h index 6878160b6..672f95282 100644 --- a/sdrbase/dsp/samplesourcefifo.h +++ b/sdrbase/dsp/samplesourcefifo.h @@ -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); diff --git a/sdrbase/plugin/pluginapi.cpp b/sdrbase/plugin/pluginapi.cpp index ae9198394..963d00ae2 100644 --- a/sdrbase/plugin/pluginapi.cpp +++ b/sdrbase/plugin/pluginapi.cpp @@ -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(); diff --git a/sdrbase/plugin/pluginapi.h b/sdrbase/plugin/pluginapi.h index 3f9206014..b4d1090fb 100644 --- a/sdrbase/plugin/pluginapi.h +++ b/sdrbase/plugin/pluginapi.h @@ -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; diff --git a/sdrbase/plugin/plugininterface.cpp b/sdrbase/plugin/plugininterface.cpp index 458379fd6..857e5fb1e 100644 --- a/sdrbase/plugin/plugininterface.cpp +++ b/sdrbase/plugin/plugininterface.cpp @@ -1,6 +1,7 @@ #include #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(); } +} diff --git a/sdrbase/plugin/plugininterface.h b/sdrbase/plugin/plugininterface.h index 352ce42f5..1cb68bee6 100644 --- a/sdrbase/plugin/plugininterface.h +++ b/sdrbase/plugin/plugininterface.h @@ -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"); diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp index 20e278fc8..869228a18 100644 --- a/sdrbase/plugin/pluginmanager.cpp +++ b/sdrbase/plugin/pluginmanager.cpp @@ -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 #include -//#include #include #include @@ -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); diff --git a/sdrbase/plugin/pluginmanager.h b/sdrbase/plugin/pluginmanager.h index b220bbdb9..98f71c7f2 100644 --- a/sdrbase/plugin/pluginmanager.h +++ b/sdrbase/plugin/pluginmanager.h @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + #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 diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index 35ecdf5f6..fa2d2107c 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -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:
- Generated 2019-05-10T14:58:45.508+02:00 + Generated 2019-05-18T03:33:39.922+02:00
diff --git a/sdrbase/resources/webapi/doc/swagger/include/NFMDemod.yaml b/sdrbase/resources/webapi/doc/swagger/include/NFMDemod.yaml index 660d4201a..f1e6e43be 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/NFMDemod.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/NFMDemod.yaml @@ -29,6 +29,8 @@ NFMDemodSettings: format: float ctcssOn: type: integer + highPass: + type: integer audioMute: type: integer ctcssIndex: diff --git a/sdrbase/resources/webapi/doc/swagger/include/TestSourceMI.yaml b/sdrbase/resources/webapi/doc/swagger/include/TestSourceMI.yaml new file mode 100644 index 000000000..763108033 --- /dev/null +++ b/sdrbase/resources/webapi/doc/swagger/include/TestSourceMI.yaml @@ -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 diff --git a/sdrbase/resources/webapi/doc/swagger/swagger.yaml b/sdrbase/resources/webapi/doc/swagger/swagger.yaml index b311cd066..ffd01094e 100644 --- a/sdrbase/resources/webapi/doc/swagger/swagger.yaml +++ b/sdrbase/resources/webapi/doc/swagger/swagger.yaml @@ -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: diff --git a/sdrgui/gui/samplingdevicedialog.cpp b/sdrgui/gui/samplingdevicedialog.cpp index 9210bca63..59dddba6b 100644 --- a/sdrgui/gui/samplingdevicedialog.cpp +++ b/sdrgui/gui/samplingdevicedialog.cpp @@ -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(); diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 8657a35a9..ea6e840bb 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -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; } diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index a06337e12..77d8f4fed 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -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) { } }; diff --git a/sdrgui/webapi/webapiadaptergui.cpp b/sdrgui/webapi/webapiadaptergui.cpp index 1e1256c16..554b0c353 100644 --- a/sdrgui/webapi/webapiadaptergui.cpp +++ b/sdrgui/webapi/webapiadaptergui.cpp @@ -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(); diff --git a/sdrsrv/maincore.cpp b/sdrsrv/maincore.cpp index c4112352f..204b6d493 100644 --- a/sdrsrv/maincore.cpp +++ b/sdrsrv/maincore.cpp @@ -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 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; diff --git a/sdrsrv/maincore.h b/sdrsrv/maincore.h index a2a5e0e28..2e746d6a9 100644 --- a/sdrsrv/maincore.h +++ b/sdrsrv/maincore.h @@ -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) { } }; diff --git a/sdrsrv/webapi/webapiadaptersrv.cpp b/sdrsrv/webapi/webapiadaptersrv.cpp index b3635b7c4..32cdf67b9 100644 --- a/sdrsrv/webapi/webapiadaptersrv.cpp +++ b/sdrsrv/webapi/webapiadaptersrv.cpp @@ -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(); diff --git a/swagger/sdrangel/api/swagger/include/TestSourceMI.yaml b/swagger/sdrangel/api/swagger/include/TestSourceMI.yaml new file mode 100644 index 000000000..763108033 --- /dev/null +++ b/swagger/sdrangel/api/swagger/include/TestSourceMI.yaml @@ -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 diff --git a/swagger/sdrangel/api/swagger/swagger.yaml b/swagger/sdrangel/api/swagger/swagger.yaml index 0a1a4ce71..6d068632f 100644 --- a/swagger/sdrangel/api/swagger/swagger.yaml +++ b/swagger/sdrangel/api/swagger/swagger.yaml @@ -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: diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index 35ecdf5f6..fa2d2107c 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -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:
- Generated 2019-05-10T14:58:45.508+02:00 + Generated 2019-05-18T03:33:39.922+02:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.cpp index be54847f6..743715512 100644 --- a/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.cpp @@ -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); diff --git a/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.h b/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.h index f4277cff3..e61638c93 100644 --- a/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGDeviceSettings.h @@ -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; diff --git a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h index 0614c131e..a81b6130e 100644 --- a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h +++ b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h @@ -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(); } diff --git a/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.cpp index e1beb433a..9bb0f0e19 100644 --- a/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.cpp @@ -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;} diff --git a/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.h b/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.h index c2a6767c4..9e2dfa268 100644 --- a/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGNFMDemodSettings.h @@ -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; diff --git a/swagger/sdrangel/code/qt5/client/SWGTestSourceMISettings.cpp b/swagger/sdrangel/code/qt5/client/SWGTestSourceMISettings.cpp new file mode 100644 index 000000000..58c523da0 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGTestSourceMISettings.cpp @@ -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 +#include +#include +#include + +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(¢er_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(&litude_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; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGTestSourceMISettings.h b/swagger/sdrangel/code/qt5/client/SWGTestSourceMISettings.h new file mode 100644 index 000000000..709e5c19b --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGTestSourceMISettings.h @@ -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 + + +#include + +#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_ */